Í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
O que é RTOS?
RTOS é a sigla para “Sistema Operacional de Tempo Real” (Real Time Operating System). Um sistema operacional é um programa que gerencia as funções básicas de um computador e oferece serviços para outros programas que rodam nele. Em um sistema operacional, vários programas são executados ao mesmo tempo. Cada núcleo do processador executa uma única tarefa (ou thread) que é escolhida pelo planejador. O planejador decide qual programa será executado em cada momento, alternando rapidamente entre eles para dar a ilusão de que todos estão rodando simultaneamente. O RTOS é um tipo especial de sistema operacional projetado para gerenciar o tempo de resposta de tarefas em ambientes onde a precisão e a previsibilidade são cruciais, priorizando, assim, a execução de tarefas dentro de prazos definidos. Isso é importante em sistemas embarcados, como em dispositivos médicos, automóveis e equipamentos industriais, onde atrasos ou variações no tempo de resposta podem resultar em falhas críticas ou perigosas.
O que é Azure RTOS?
O Azure RTOS é uma classe de RTOS, sendo um pacote de middleware de nível profissional com um conjunto de componentes desenvolvidos pela Microsoft para aplicar em sistemas embarcados e dispositivos de IoT (Internet das Coisas). A Azure RTOS está integrada no ecossistema STM32Cube e pode ser facilmente implementada no firmware das placas da STM.
Os componentes principais do Azure RTOS são:
- ThreadX: núcleo principal do Azure RTOS.
- FileX: sistema de arquivos de alto desempenho que oferece suporte para várias estruturas de diretório e tipos de arquivo.
- GUIX: biblioteca de interface gráfica de usuário (GUI) que facilita a criação de interfaces gráficas sofisticadas para dispositivos embarcados.
- NetX Duo: protocolos de rede que fornecem suporte para conectividade de rede, incluindo TCP/IP, adequadas para dispositivos conectados à Internet.
- USBX: conjunto de componentes que oferece suporte para USB host, dispositivo e On-The-Go (OTG), permitindo a comunicação com periféricos USB.
Descrição Projeto
Neste artigo, vamos aprender a trabalhar com o ThreadX configurando o Azure RTOS usando a ferramenta CubeMX. Nosso objetivo é controlar o LED conectado ao pino PB6 ao pressionar o BOTÃO conectado ao pino PA8 e exibir o status do LED via UART. Para isso, criaremos duas tarefas e utilizaremos uma fila para a comunicação entre essas tarefas. Não será necessário nenhum hardware adicional além da Franzininho C0.
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.
Configurando CubeMX
- Abra STM32Cube , crie um novo projeto e selecione o microcontrolador de destino “STM32C011F6P6”.
- Entre na página de configurações de relógio e ajuste HCLK para 48 MHz.
- Volte para a página de configuração dos pinos. Em “System Core” > “SYS”, habilite os pinos PA9 e PA10. Em seguida, selecione “TIM16” como a base de tempo (timebase source). Ao usar o Azure RTOS, a fonte de base de tempo não pode ser o clock interno do microcontrolador. Deve-se usar um temporizador (timer) específico para garantir precisão e estabilidade nas operações de tempo real.
- Depois, vamos configurar nossa 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.
- Em seguida, habilite o ThreadX do Azure RTOS. Para fazer isso, vá para “Middleware and Software,” procure por “THREADX,” e habilite a opção “Core.”
- Na sequência, configuraremos as entradas e saídas. Para configurar a entrada, selecione o pino “PA8”, defina seu modo como “Input Mode” e ative o resistor de Pull-up. Depois, selecione o pino “PB6”, defina seu modo como “Output Mode” e renomeie-o para “LED”.
- Por fim, gere o código em “Project” > “Generate Code”.
Implementação código
Ao gerar o código, serão incluídos dois arquivos específicos para trabalhar com o Azure RTOS.
Primeiro, acesse o arquivo main.c, e inclua MX_ThreadX_Init() na função principal int main:
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 |
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_USART1_UART_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ MX_ThreadX_Init(); /* We should never get here as control is now taken by the scheduler */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } |
Depois, acesse o arquivo app_threadx.c e realize as seguintes modificações:
- Inclua stdio.h e main.h
1 2 |
#include <stdio.h> #include "main.h" |
- Crie as definições a seguir:
1 2 3 4 5 6 |
/* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define BTN_STATUS_STACK_SIZE 512 #define LED_STATUS_STACK_SIZE 512 #define QUEUE_STACK_SIZE 16 /* USER CODE END PD */ |
- Crie as seguintes variáveis e protótipos das funções (tarefas):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ extern UART_HandleTypeDef huart1; uint8_t btn_status_stack[BTN_STATUS_STACK_SIZE]; uint8_t led_status_stack[LED_STATUS_STACK_SIZE]; uint8_t queue_stack[QUEUE_STACK_SIZE]; TX_THREAD btn_status_ptr; TX_THREAD led_status_ptr; TX_QUEUE queue_ptr; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN PFP */ VOID btn_status(ULONG initial_input); VOID led_status(ULONG initial_input); /* USER CODE END PFP */ |
- Procure por App_ThreadX_Init e inclua a criação das tarefas e fila.
1 2 3 4 5 6 7 8 9 10 11 12 |
UINT App_ThreadX_Init(VOID *memory_ptr) { UINT ret = TX_SUCCESS; /* USER CODE BEGIN App_ThreadX_MEM_POOL */ /* USER CODE END App_ThreadX_MEM_POOL */ /* USER CODE BEGIN App_ThreadX_Init */ tx_queue_create(&queue_ptr, "message_btn_status", TX_1_ULONG ,queue_stack,QUEUE_STACK_SIZE); tx_thread_create(&btn_status_ptr,"btn_status",btn_status,0,btn_status_stack, BTN_STATUS_STACK_SIZE,15,15,1,TX_AUTO_START); tx_thread_create(&led_status_ptr,"led_status",led_status,0,led_status_stack, LED_STATUS_STACK_SIZE,15,15,1,TX_AUTO_START); /* USER CODE END App_ThreadX_Init */ return ret; } |
A função tx_thread_create cria e inicia uma nova thread (tarefa). Seus parâmetros são:
- &btn_status_ptr: Ponteiro para a estrutura da thread.
- “btn_status”: Nome da thread (tarefa).
- btn_status: Ponteiro para a função da thread.
- 0: Valor passado como argumento para a função da thread (não utilizado nesta implementação).
- btn_status_stack: Ponteiro para o stack da thread.
- BTN_STATUS_STACK_SIZE: Tamanho do stack da thread.
- 15: Prioridade da thread (quanto menor o valor, maior a prioridade).
- 15: Sub-prioridade da thread (em sistemas com preempção de múltiplos níveis, geralmente igual à prioridade principal).
- 1: Time-slice para a thread (quantidade de ticks que a thread pode rodar antes de outra thread com a mesma prioridade ser executada).
- TX_AUTO_START: Opção de auto-start para a thread (a thread começa a rodar automaticamente após ser criada).
A função tx_queue_create cria a fila que será usada para passar mensagens entre as tarefas btn_status e led_status. A criação da fila possui os seguintes parâmetros:
- queue_ptr: Ponteiro para a fila.
- “message_btn_status”: Nome da fila.
- TX_1_ULONG: Tipo de mensagem (um ULONG).
- queue_stack: Array utilizado como armazenamento da fila.
- QUEUE_STACK_SIZE: Tamanho do array queue_stack.
- Crie a função da thread btn_status (ULONG initial_input). Esta tarefa lê o estado de um botão conectado ao pino GPIOA, GPIO_PIN_8 e envia uma mensagem para a fila queue_ptr sempre que o estado do botão muda.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
VOID btn_status (ULONG initial_input) { ULONG message_pin_status = DISABLE; ULONG message_pin_status_new = DISABLE; while(1) { tx_thread_sleep(10); if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == GPIO_PIN_RESET) { message_pin_status_new = ENABLE; } else { message_pin_status_new = DISABLE; } if (message_pin_status != message_pin_status_new) { message_pin_status = message_pin_status_new; tx_queue_send(&queue_ptr, &message_pin_status, TX_NO_WAIT); } } } |
- Crie a função da thread led_status(ULONG initial_input). Esta tarefa recebe mensagens da fila queue_ptr e aciona um LED conectado ao LED_GPIO_Port e LED_Pin com base nas mensagens recebidas. Também transmite mensagens pela UART para indicar o estado do LED.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
VOID led_status(ULONG initial_input) { ULONG message_status; uint8_t msg_led_on[] = "The LED is ON\r\n"; uint8_t msg_led_off[] = "The LED is OFF\r\n"; while(1) { tx_queue_receive(&queue_ptr, &message_status, TX_WAIT_FOREVER); if(message_status == ENABLE) { HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); HAL_UART_Transmit(&huart1, msg_led_on, sizeof(msg_led_on) - 1, 1000); } else { HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); HAL_UART_Transmit(&huart1, msg_led_off, sizeof(msg_led_off) - 1, 1000); } } } |
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 Azure RTOS para controlar um LED com um botão utilizando a placa Franzininho C0 com a ferramenta STM32CubeMX. Através da integração do ThreadX, parte do Azure RTOS, configuramos duas tarefas principais para monitorar o estado de um botão e controlar um LED com base nas leituras do botão.