Este exemplo detalha o fluxo completo de um callback de conclusão de transmissão UART utilizando a HAL (Hardware Abstraction Layer) do STM32, desde a inicialização até a ativação do callback. O código base é gerado pelo CubeMX, com acréscimos de comentários explicativos.
Inicialização de Hardware (Geração CubeMX)
No arquivo main.c, a rotina de inicialização gerada pelo CubeMX inclui:
// Inicialização do clock do sistema, GPIO, UART, etc.
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART2_UART_Init(); // Inicializa UART2
// ... outros códigos
}
Configuração da UART (Parâmetros Essenciais)
Dentro de MX_USART2_UART_Init(), os parâmetros da UART são definidos. A função HAL_UART_MspInit é chamada implicitamente:
UART_HandleTypeDef huart2;
void MX_USART2_UART_Init(void) {
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
// Chama a inicialização da HAL para a UART, que por sua vez chama HAL_UART_MspInit()
HAL_UART_Init(&huart2);
}
Sobrescrita da Função de Callback pelo Usuário
No arquivo de código do usuário (e.g., main.c), a função de callback definida como __weak, HAL_UART_TxCpltCallback, é sobrescrita:
// Sobrescreve a função de callback de conclusão de transmissão UART
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
// Verifica qual instância da UART gerou o callback
if (huart->Instance == USART2) {
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); // Operação personalizada: inverte o estado do LED
printf("Transmissao UART concluida!\\r\\n");
}
}
Início da Transmissão UART (Acionando o Callback)
Na função main(), a transmissão UART é iniciada no modo de interrupção:
uint8_t txData[] = "Ola, STM32 HAL Callback!\r\n";
int main(void) {
// ... código de inicialização ...
// Inicia a transmissão UART no modo de interrupção
HAL_UART_Transmit_IT(&huart2, txData, sizeof(txData) - 1);
while (1) {
// O loop principal pode executar outras tarefas
}
}
Acionamento da Interrupção e Fluxo do Callback
Cadeia completa de acionamento:
-
Início da Transmissão:
HAL_UART_Transmit_IT()inicia a transmissão e habilita a interrupção de conclusão de transmissão (TCIE) da UART. -
Interrupção de Hardware: Ao concluir a transmissão do último byte, o hardware aciona o vetor de interrupção
USART2_IRQHandler. -
Processamento pela HAL: ```
// Definição da rotina de tratamento de interrupção em stm32xx_it.c void USART2_IRQHandler(void) { // A HAL processa a interrupção da UART de forma unificada HAL_UART_IRQHandler(&huart2); }
-
Chamada do Callback: Dentro de
HAL_UART_IRQHandler(), ao detectar a flag de conclusão de transmissão (TC), a HAL chama automaticamenteHAL_UART_TxCpltCallback().
Pontos Chave
- Callbacks com Definição Fraca (
__weak): A HAL fornece implemnetações padrão como__weak void HAL_UART_TxCpltCallback(...), que o usuário pode sobrescrever para adicionar sua lógica personalizada. - Identificação do Periférico: Dentro da função de callback, é crucial verificar
huart->Instancepara distinguir qual periférico (e.g., USART1, USART2) originou o evento, especialmente em sistemas com múltiplas UARTs. - Configuração de Interrupção: A função
HAL_UART_Init(), através deHAL_UART_MspInit(), é responsável por configurar o NVIC (prioridade e habilitação da interrupção) para o periférico UART correspondente. - Sem Registro Explícito: O usuário simplesmente sobrescreve a função de callback; não é necessário registrar pontieros de função explicitamente.
Comportamento em Execução
- Condição de Acionamento: O callback é executado após a conclusão bem-sucedida da transmissão pela UART (o último byte é enviado pelo registrador de deslocamento).
- Lógica do Usuário: Neste exemplo, a lógica personalizada inverte o estado de um LED e exibe uma mensagem na saída serial.
- Natureza Assíncrona: O loop principal
while(1)não precisa verificar o status da transmissão, permitindo operações não bloqueantes e otimização do uso do processador.
Comparação com Caso Sem Sobrescrita de Callback
- Se o usuário não sobrescrever
HAL_UART_TxCpltCallback, a função padrão (fraca), que é vazia, será executada sem realizar nanhuma ação. - Para implementar lógica personalizada em resposta a eventos de transmissão, o usuário deve obrigatoriamente sobrescrever a função de callback. A vantagem é que a HAL cuida dos detalhes de baixo nível, como a limpeza de flags de interrupção.
Fluxo de Trabalho Geral dos Callbacks na HAL
- Inicialização do Periférico: A configuração do hardware é realizada, geralmente via código gerado pelo CubeMX.
- Implementação do Callback: O usuário define a lógica de resposta para eventos específicos sobrescrevendo as funções de callback apropriadas.
- Início de Operações Assíncronas: Funções como
HAL_UART_Transmit_IT()são chamadas para iniciar operações que podem ser concluídas posteriormente. - Acionamento Automático do Callback: O sistema de interrupção e a HAL orquestram a chamada da função de callback do usuário quando o evento correspondente ocorre.
Este mecanismo permite desacoplar a lógica de hardware das rotinas de aplicação, simplificando o desenvolvimento e a manutenção do código.