ÍNDICE DE CONTEÚDO
- Como instalar o STM32CubeIDE: Guia de Primeiros Passos
- Franzininho C0: Entradas e Saídas no STMcubeIDE
- Franzininho C0: aprenda a trabalhar com Timers
- Aprendendo a trabalhar com interrupções externas e USART na Franzininho C0
- Medindo Intervalos de Tempo com a Franzininho C0: Integrando Timer, Interrupções e USART
- Como gravar a Franzininho C0 via USB/Serial usando o STM32CubeProgrammer
- Como usar display 7 segmentos com a Franzininho C0
- Trabalhando com ADC no Franzininho C0: Tutorial Completo no STM32CubeIDE
- Entendendo o Controle PWM e Aplicando no Franzininho C0
- Projeto Prático: Utilizando o Módulo GPS GY-NEO6MV2 com a Franzininho C0
- Projeto Iluminação Automatizada com LDR e Franzininho C0
- Trabalhando com o sensor de temperatura interno da Franzininho C0
- Como Utilizar o RTC (Relógio de Tempo Real) da Franzininho C0 para Capturar Data e Hora
- Configuração da Interface I2C na Franzininho C0 para Utilização de Display OLED
- Monitoramento de Temperatura e Umidade com DHT11 e Franzininho C0 e Exibição em Display OLED
- Controle de LED com Botão usando Azure RTOS na Franzininho C0
- Leitura dos Eixos X, Y e Z do acelerômetro LIS3DH com a Franzininho C0 via SPI
- Medição de ângulo com acelerômetro LIS3DH e Franzininho C0
- Detecção de Queda Livre com acelerômetro LIS3DH e Franzininho C0
Introdução
Neste artigo, você aprenderá a configurar a Franzininho C0 para trabalhar com protocolo de comunicação SPI e realizar leituras do acelerômetro LIS3DH.
Materiais necessários:
- 1 Franzininho C0
- 1 Módulo LIS3DH
Esquema de montagem:
- PA6 – SD0 (MISO)
- PA1 – SCL (SCK)
- PA2 – SDA (MOSI)
- P4 – CS
Protocolo SPI
SPI é um protocolo de comunicação serial síncrono , full -duplex , baseado em mestre-escravo. Foi implementado pela primeira vez em 1970 pela Motorola.
O protocolo de comunicação SPI (Serial Peripheral Interface) utiliza quatro fios principais: SCK (Clock Serial), MISO (Master-In Slave-Out), MOSI (Master-Out Slave-In) e CS (Chip Select). Diferente do protocolo I2C, que utiliza endereços para comunicação entre dispositivos, o SPI utiliza o pino CS para selecionar o escravo com o qual o mestre deseja se comunicar. Quando o mestre precisa iniciar uma comunicação com um escravo específico, ele ativa o pino CS desse escravo, levando-o para o nível lógico baixo (0). Isso estabelece o canal de comunicação exclusivo entre o mestre e o escravo selecionado.
Além disso, é preciso configurar corretamente os parâmetros CPOL (Clock Polarity) e CPHA (Clock Phase). O CPOL define o estado inativo do clock, enquanto o CPHA determina em qual borda do clock os dados serão amostrados, garantindo que a sincronização dos sinais entre mestre e escravo.
Seminário Linux Embarcado 2024: Evento Presencial em São Paulo
Participe do Seminário Linux Embarcado 2024 em São Paulo. Conhecimento técnico, palestras, workshops e oportunidade de networking com profissionais experientes.
Para mais informações detalhadas deste protocolo recomendo a leitura de https://embarcados.com.br/spi-parte-1/ e https://embarcados.com.br/comunicacao-spi-parte-2/
LIS3DH
O LIS3DH é um acelerômetro linear de três eixos, de alta performance e ultra baixa potência, com interface digital I²C/SPI. Oferece modos de ultra baixa potência, funções inteligentes e escalas selecionáveis de ±2g/±4g/±8g/±16g, medindo acelerações de 1 Hz a 5,3 kHz. Possui auto-teste, geradores de interrupção configuráveis, e um buffer FIFO de 32 níveis para otimizar a eficiência.
Características:
- Tensão de alimentação: 1,71 V a 3,6 V
- Consumo em ultra baixa potência: até 2 μA
- Escala selecionável: ±2g/±4g/±8g/±16g
- Interface comunicação I²C/SPI
- Saída de dados de 16 bits
- 2 geradores de interrupção programável (queda livre e movimento)
- Detecção de orientação 6D/4D, queda livre e movimento
- Sensor de temperatura e auto-teste embutidos
- FIFO de 32 níveis, alta resistência a choques (até 10000 g)
Aplicações:
- Funções por movimento, detecção de queda livre
- Pedômetros, orientação de display
- Dispositivos para jogos e realidade virtual
- Economia de energia inteligente para portáteis
- Reconhecimento e registro de impactos, monitoramento de vibrações
Acesse o datasheet em: https://www.st.com/resource/en/datasheet/lis3dh.pdf
Configuração CubeMX
- Abra STM32Cube, crie um novo projeto e selecione o microcontrolador “STM32C011F6P6”.
- Vá para a página de configurações de relógio e em HCLK digite 48 MHz para a frequência de saída desejada do sistema. Depois volte para a página de configuração dos pinos, selecione “Trace and Debug” e habilite “Serial Wire.
- Para a configuração do SPI, neste exemplo, vá em “Connectivity’ > “SPI”, habilite o modo “FullDuplex Master” e mude o “Clock Parameter” > “Prescaler (Baud Rate)” para 32. Os demais parâmetros de configuração não será necessário modificar.
- Perceba que ao habilitar o SPI, o CubeMx ativa automaticamente os pinos de SCK, MOSI e MISO. O pino de CS é necessário configurar manualmente, para isso, selecione o PA4 como “GPIO_Output”.
- Para configurar a UART, selecione o pino PA10 como “USART1_RX” e PA9 como “USART1_TX”. Em “Connectivity” selecione a opção “USART1” e em Mode escolha o “Asynchronous”. As demais configurações deixe padrão.
- Por fim, gere o código em “Project” > “Generate Code”.
Implementação Código
- Inicialmente, criaremos dois arquivos novos. Em “Inc” crie “lis3dh.h” e em “Src” crie “lis3dh.c”.
- Após criar esses novos arquivos, acesse o arquivo lis3dh.h. Neste arquivo, vamos adicionar algumas definições (#define) dos registradores do acelerômetro LIS3DH, assim como os protótipos das funções que implementaremos em lis3dh.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <stdint.h> // Definições dos registradores do acelerômetro LIS3DH #define LIS3DH_CTRL_REG1 0x20 #define LIS3DH_CTRL_REG4 0x23 #define LIS3DH_WHO_AM_I 0x0F #define LIS3DH_OUT_X_L 0x28 #define LIS3DH_OUT_X_H 0x29 #define LIS3DH_OUT_Y_L 0x2A #define LIS3DH_OUT_Y_H 0x2B #define LIS3DH_OUT_Z_L 0x2C #define LIS3DH_OUT_Z_H 0x2D // Protótipos das funções para manipulação do acelerômetro void LIS3DH_Init(void); uint8_t LIS3DH_ReadReg(uint8_t address); void LIS3DH_WriteReg(uint8_t address, uint8_t data); void LIS3DH_ReadAccel(int16_t *acceleration); |
- Acesse o arquivo lis3dh.c, inclua as bibliotecas necessárias e faça referência às interfaces SPI e UART que foram configuradas previamente.
1 2 3 4 5 6 |
#include "stm32c0xx.h" #include "lis3dh.h" #include "stdio.h" #include "string.h" extern SPI_HandleTypeDef hspi1; extern UART_HandleTypeDef huart1; |
- Ainda em lis3dh.c, criaremos as funções de leitura e escrita na SPI. Em ambas as funções, é necessário ativar e desativar o CS (Chip Select) entre as leituras ou escritas SPI, conforme explicado ao longo do artigo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
/** @brief Reads given amount of data from sensor * @param reg: Register address to read from * @retval data receive */ uint8_t LIS3DH_ReadReg(uint8_t address) { uint8_t txData[2]; uint8_t rxData[2]; txData[0] = address | 0x80 ; // Set read bit (MSB = 1) txData[1] = 0x00; // Dummy byte HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // CS low // delay to ensure CS is correctly registered HAL_Delay(1); if (HAL_SPI_TransmitReceive(&hspi1, txData, rxData, 2, HAL_MAX_DELAY) != HAL_OK) { char error_msg[] = "SPI Transmit/Receive Error\r\n"; HAL_UART_Transmit(&huart1, (uint8_t *)error_msg, strlen(error_msg), 1000); } HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // CS high return rxData[1]; // The second byte received is the actual data } /** @brief Writes given amount of data to sensor * @param reg: Register address to write to * @param value: Number of bytes to be written * @retval Zero on success, -1 otherwise */ void LIS3DH_WriteReg(uint8_t address, uint8_t data) { uint8_t txData[2]; txData[0] = address; txData[1] = data; HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // CS low // delay to ensure CS is correctly registered HAL_Delay(1); if (HAL_SPI_Transmit(&hspi1, txData, 2, HAL_MAX_DELAY) != HAL_OK) { char error_msg[] = "SPI Write Error\r\n"; HAL_UART_Transmit(&huart1, (uint8_t *)error_msg, strlen(error_msg), 1000); } HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // CS high } |
- Mantenha-se em lis3dh.c, adicione a função de inicialização do acelerômetro, nela vamos configurar os registradores LIS3DH_CTRL_REG1 e LIS3DH_CTRL_REG4. No LIS3DH_CTRL_REG1, ajustamos a taxa de dados e habilitamos os eixos. No LIS3DH_CTRL_REG4, configuramos o modo de comunicação (3 ou 4 fios), a escala e a resolução, conforme mostrado nas tabelas abaixo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/** @brief Initializes LIS3DH device with following configuration: * 100Hz sampling rate * Enable all axis * @retval None */ void LIS3DH_Init(void) { // delay to ensure LIS3DH is ready after power-up HAL_Delay(10); // Write to CTRL_REG1 to set data rate and enable all axes LIS3DH_WriteReg(LIS3DH_CTRL_REG1, 0x57); // 100Hz, enable X, Y, Z // Write to CTRL_REG4 to set scale default 2g and high-resolution mode LIS3DH_WriteReg(LIS3DH_CTRL_REG4, 0xC8); uint8_t who_am_i = LIS3DH_ReadReg(LIS3DH_WHO_AM_I); char status[50]; sprintf(status, "WHO_AM_I: 0x%02X\r\n", who_am_i); HAL_UART_Transmit(&huart1, (uint8_t *)status, strlen(status), 1000); } |
valor configurado no código: 0x57 = 01010111
valor configurado no código: 0xC8 = 11001000
- Por fim, no arquivo lis3dh.c, adicione a função de leitura de dados. Esta função lerá os valores de cada eixo do acelerômetro (vertical e horizontal) e os armazenará no array fornecido. A função faz a leitura dos registradores de saída de dados do acelerômetro e combina os bytes alto e baixo para formar os valores de 16 bits de cada eixo.
1 2 3 4 5 6 7 8 9 10 11 |
void LIS3DH_ReadAccel(int16_t *acceleration) { uint8_t x_l = LIS3DH_ReadReg(LIS3DH_OUT_X_L); uint8_t x_h = LIS3DH_ReadReg(LIS3DH_OUT_X_H); uint8_t y_l = LIS3DH_ReadReg(LIS3DH_OUT_Y_L); uint8_t y_h = LIS3DH_ReadReg(LIS3DH_OUT_Y_H); uint8_t z_l = LIS3DH_ReadReg(LIS3DH_OUT_Z_L); uint8_t z_h = LIS3DH_ReadReg(LIS3DH_OUT_Z_H); acceleration[0] = ((int16_t)x_h << 8) | x_l; // X-axis acceleration[1] = ((int16_t)y_h << 8) | y_l; // Y-axis acceleration[2] = ((int16_t)z_h << 8) | z_l; // Z-axis } |
- Veja na imagem abaixo o código como todo do arquivo lis3dh.c
- Entre no arquivo main.c, faça a inclusão das seguintes bibliotecas e variáveis.
1 2 3 4 5 |
#include "lis3dh.h" #include "stdio.h" #include "string.h" char uart_buf[50]; char acel_buf[50]; |
- Depois, modifique a função principal int main de main.c com o seguinte:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_SPI1_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ /* Initialize LIS3DH device */ // CS pin should default high // teste uart sprintf(uart_buf, "SPI Test\r\n"); HAL_UART_Transmit(&huart1, (uint8_t *)uart_buf, strlen(uart_buf), 1000); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); HAL_Delay(500); LIS3DH_Init(); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ int16_t accel[3]; LIS3DH_ReadAccel(accel); // Print values via UART sprintf(acel_buf, "Leitura Bruta - X: %i, Y: %i, Z: %i\r\n", accel[0], accel[1], accel[2]); HAL_UART_Transmit(&huart1, (uint8_t *)acel_buf, strlen(acel_buf), 1000); HAL_Delay(1000); // Conversão para mg (miligravidade) int32_t accel_x_mg = (int32_t)accel[0] * 1000 / 16384; int32_t accel_y_mg = (int32_t)accel[1] * 1000 / 16384; int32_t accel_z_mg = (int32_t)accel[2] * 1000 / 16384; sprintf(acel_buf, "Aceleracao (mg) - X: %ld, Y: %ld, Z: %ld\r\n", accel_x_mg, accel_y_mg, accel_z_mg); HAL_UART_Transmit(&huart1, (uint8_t *)acel_buf, strlen(acel_buf), 1000); HAL_Delay(1000); } /* USER CODE END 3 */ } |
Neste código, estamos inicializando o acelerômetro LIS3DH. No loop principal, lemos os valores brutos do acelerômetro, os convertendo em valores em miligramas (mg) e, em seguida, imprimimos essas informações pela interface serial. Abaixo temos a tabela de conversão que explica o motivo pelo qual foi utilizado 16384 na conversão da aceleração sabendo que a sensibilidade foi configurada em 2g.
- A imagem abaixo mostra o código main.c modificado.
Gravação
Ao finalizar o código, partiremos para gravação. Nessa etapa você pode utilizar o ST-Link seguindo as conexões da imagem abaixo e clicando em “run” no STM32CubeIde.
Ou você pode optar por utilizar um cabo usb e gravar conforme explicado no seguinte tutorial: gravar-franzininho-c0-via-stm32cubeprogrammer
Funcionamento
Conclusão
Neste artigo, demonstramos como configurar e utilizar o acelerômetro LIS3DH com a Franzininho C0 via SPI. Detalhamos a configuração do SPI e a implementação do código para inicializar o acelerômetro, ler os valores dos eixos X, Y e Z, e converter esses valores para unidades de miligravidade (mg).