定长数据的发送与接收函数(老朋友)
发送:
HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
接收:
HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
对阻塞型的中断发送或接收函数的说明----CPU不停工作直至完成,再去忙别的
1.对于HAL_UART_Transmit和HAL_UART_Receive,可以注意到其最后一个参数是阻塞发送的时间。当以下两情况其一发生时才会结束阻塞状态:超出设定的阻塞时间、所需发送或接收的数据发送完毕;而最后一个参数设为HAL_MAX_Delay时,这两个函数会无限等待直至数据发送或接收完毕。
2.无对应事件的中断回调处理函数。
对后缀含IT的中断发送或接收函数的说明----CPU两头来回奔波,完成工作后可以选择进行某种仪式
1.对于HAL_UART_Transmit_IT和HAL_UART_Receive_IT,调用后会使能“串口发送或接收寄存器非空中断”,即每发送完一字节数据后会导致串口发送寄存器为空或接收寄存器为非空,此时便触发了该中断从而呼回CPU启动下一字节数据的发送或接收,然后CPU随即离开去处理其他任务,直到下一次串口发送或接收寄存器为空时再次触发该中断呼回CPU,如此反复。当串口传输完成时会触发串口传输完成中断,这个中断标志位会被HAL_UART_RxCpltCallback和HAL_UART_TxCpltCallback捕获从而触发中断回调处理函数。
2.若对所发送或接收的数据还有进一步处理的需求,则可以再复写相关中断回调处理函数。即:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //接收完成中断回调处理函数
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); //发送完成中断回调处理函数
对后缀含DMA的中断发送或接收函数的说明----CPU吩咐下属完成工作,自己继续忙自己的;下属工作完成后可以选择进行某种仪式
1.对于HAL_UART_Transmit_DMA和HAL_UART_Receive_DMA,调用后系统会启动CubeMX中预配置的DMA通道绕过CPU进行数据的搬运。至此之后CPU完全不用操手串口的发送与接收工作。当DMA传输完成时会触发DMA传输完成中断,这个中断标志位会被HAL_UART_RxCpltCallback和HAL_UART_TxCpltCallback捕获从而触发中断回调处理函数。
2.若对所发送或接收的数据还有进一步处理的需求,则可以再复写相关中断回调处理函数。即:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //接收完成中断回调处理函数
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); //发送完成中断回调处理函数
总结:对于定长数据接收的中断回调处理函数,它们都共用相同的中断回调处理函数"HAL_xxCpltCallback(); ".
对DMA具体配置的解读
DMA1的第2通道专门设计为UART3的发送通道,方向是内存到寄存器,优先级是低。由于寄存器只有一个字节因此地址不自增;而内存数据要逐步读取因此设置地址自增。
不定长数据的接收函数(略微陌生)
HAL_UARTEx_ReceiveToIdle(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint16_t *RxLen, uint32_t Timeout);
HAL_UARTEx_ReceiveToIdle_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
Ps:" Ex"表示为hal库的扩展函数;“Idle”意为“空闲”。整句话意思是“从接收到空闲状态”。
对不定长数据接收函数的说明:
1.上述三个函数在数据接收完毕时皆可以触发“串口接收空闲中断”;
2.同理,想要对相应中断做出一定处理就需要重定义不定长数据接收的专属弱函数,即:
__weak void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size);
当该中断被触发就会使程序运行到这个串口接收空闲回调处理函数中,从而完成一些中断处理操作。由于中断触发的特性是“空闲”二字,故可以利用这个特性收发不定长数据。例如可以在这个中断回调处理函数中调用HAL_UIART_Transmit_DMA();将这个不定长的数据发回从机。由于接收的数据是不定长的,故在填写这个DMA发送函数的入参时要与函数的Size入参保持一致。
(注意最后一步同样要用HAL_UARTEx_ReceiveToIdle_DMA();去重新开启串口接收空闲中断)
在使用DMA的串口空闲接收中断的注意点
这个中断有一个特性,就是在传输数据达到总数据的一半时还会触发“传输数据过半中断”,而这个中断也会触发RxEventCallback回调函数,故我们还需额外关闭这个传输过半中断。用到的函数是:
__HAL_DMA_DISABLE_IT(&hdma_usart3_rx,DMA_IT_HT); //关闭USART3_RX的DMA接收过半中断.
参数说明:1.对应串口的接收功能; 2.DMA传输过半中断(Half Transfer)
(本人为大学二年级嵌入式入门小菜鸡一只,理解上必然少不了各种谬误,恳请各路前辈大佬多多包涵赐教!)