Das diversas funcionalidades presentes nos MCUs, os temporizadores e contadores possibilitam monitorar uma variedade de eventos, dando destaque a estes módulos. O MCU STM32F429 possui 17 temporizadores com variadas possibilidades de configurações e usos, resumidos na Tabela 1 abaixo.
Tabela 1. Resumo dos temporizadores/contadores presentes no STM32F429.
Fonte: Adaptado de (STM32F429, 2022).
A Tabela 1 resume as características de cada temporizador/contador disponível no STM32F429. Estes módulo podem ser usados para contagens progressivas ou regressivas, com resolução de 16 ou 32 bits e podem inclusive gerar sinal de clock para pinos especificados.
A função básica de qualquer contador é a de contabilizar a quantidade de eventos ocorridos. Estes eventos podem ter duas origens: um pulso recebido em um pino ou de uma base de tempo derivada do clock do sistema interno. Quando o módulo recebe um sinal externo, dá-se o nome de contador, significando que este está contabilizando a quantidade de eventos ocorridos no pino especificado. Quando os pulsos pelo módulo são oriundos de uma base de tempo (clocck interno ou externo), dá-se o nome de temporizador, significando que o módulo está contabilizando pulsos de uma base de tempo conhecida e que pode ser usada por exemplo, para implementar um relógio de tempo real (Real Time Clock - RTC).
Este exemplo descreve como utilizar o TM3 como temporizador para trocar o estado de um LED a cada 500ms. Após criar um projeto, o TM3 deve ser configurado como visto na Figura 1. Na configuração foi definido um pré-escaler(divisor) igual a 720, ou seja, dividir a frequência do oscilador por 720 e em seguida, limitar a contagem do TM3 à 10.000. Para estes valores o timer3 vai gerar uma interrupção a cada 100ms, considerando que a frequência do MCU esteja à 72MHz.
Figura 1. Configurações para o TM3.
Fonte: Adaptado pelo autor.
A Figura 1 mostra as configurações disponíveis para os timers. A fonte do clock, chama de Clock Source, deve ser selecionada como Internal Clock (derivado do clock do MCU) ara este exemplo. Na seção Counter Settings, têm-se as configurações descritas a serguir:
Prescaler - trata de um divisor da frequência de origem permitindo alcançar temporizações maiores do que usando o clock do MCU diretamente. Ex.: Fosc=72 MHz/720= 100.000 kHz ou T=1/F= 10 us. Desta forma o TM3 gera interrupções a cada 10u*65536=0,66 se. O projetista pode inserir um valor entre 0 e 65535.
Counter Mode - os principais modos de contagem são Up e Down. Significa que o timer incrementa ou decrementa o valor a cada evento. Os demais modos não são abordados no momento.
Counter Period - este é o valor máximo que o timer pode atingir, se for estiver no modo UP, ou o valor inicial e decrementando até zero, no modo Down, representando a quantidade de contagens que o timer deve fazer. Quando o timer ultrapassar a quantidade de contagens ocorre o estouro do timer que pode gerar uma interrupção se estiver habilitada.
Internal Clock Division - permite dividir a frequência do sinal quando a origem deste for por externo.
Ao gerar o código faz-se necessário adicionar o código a seguir dentro da função de tratamento de interrupção dos timer, chamada HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim).
Código exemplo1
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
/* USER CODE END Callback 0 */
if (htim->Instance == TIM6) {
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
if(htim->Instance==TIM3){
gi_cnt++;
if(gi_cnt==5){
gi_cnt=0;
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_13);
}
}
/* USER CODE END Callback 1 */
}
O projetista não precisa adicionar esta função, visto que o TM6, por padrão, é usado pelo MCU para gerar uma base de tempo para eventos internos (como para HAL_Delay), bastando assim, adicionar um teste para verificar se a interrupção foi gerada pelo TM3 ou outro. Além disto, foi adicionada uma variável global, que é incrementada a cada interrupção deste timer e ao atingir 5 contagens, significa que transcorreram 500ms e o LED tem seu estado alterado.
Como vantagem desta implementação o laço principal fica vazio, liberando-o para outras tarefas. Também foi implementado um timer com uma base de tempo de 100ms que pode ser usado pelo projetista para temporizar diversos eventos internos da aplicação. Esta é uma técnica utilizada por exemplo, para implementar sistemas operacionais de tempo real para MCUs. O projetista precisa acionar o timer na função main antes do loop principal adicionando a instrução: HAL_TIM_Base_Start_IT(&htim3).
Nesta modalidade o estouro do timer precisa ser verificado, ao contrário do caso anterior. Uma forma de implementação é mostrada no trecho a seguir. A função __HAL_TIM_GET_FLAG(&htim3, TIM_FLAG_UPDATE) retorna o estado do Flag que indica o estouro do timer. Quando o valor de retorno for diferente de 0, significa que o timer gerou um evento de estouro. No código abaixo, este evento é utilizado para inverter o estado do LED do usuário. Quando este evento é detectado o flag precisa ser apagado pelo programa utilizando a função __HAL_TIM_CLEAR_IT(&htim3, TIM_IT_UPDATE). Este exemplo implementa o método polling do timer e pode ser implementado dentro de uma função para substituir a rotina HAL_Delay(), por exemplo.
int main(void) {
/* USER CODE BEGIN 1 */
uint16_t i_cnt;
/* 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_TIM3_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim3);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
i_cnt = __HAL_TIM_GetCounter(&htim3);
if (__HAL_TIM_GET_FLAG(&htim3, TIM_FLAG_UPDATE) != RESET) {
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_13);
__HAL_TIM_CLEAR_IT(&htim3, TIM_IT_UPDATE);
}
}
/* USER CODE END 3 */
}
Referências:
STM32F429 . STM32F427xx STM32F429xx 32b Arm ® Cortex Datasheet -production data. [s.l: s.n.]. Disponível em: <https://www.st.com/resource/en/datasheet/stm32f427vg.pdf>. Acesso em: 25 nov. 2022.