一、选择端口,设置引脚T/R和DMA
这一部分参考CUBEMX配置
二、阻塞式(轮询)收发定长数据
//发送数据
#include<string.h>
//串口初始化
MX_USART2_UART_Init();
char message[] = "Hello World";
//串口发送函数
HAL_UART_Transmit(&huart1,(uint8_t*)message,strlen(message), 100);
//接受数据
#include<string.h>
//串口初始化
MX_USART2_UART_Init();
uint8_t receiveData[2];
//串口接收函数
HAL_UART_Receive(&huart1, receiveData, 2, HAL_MAX_DELAY);
HAL_UART_Transmit(&huart1, receiveData, 2, 100);
缺点
必须阻塞住程序的执行,直到完成发送或接收,或等待超时。
接收时需要接收固定长度数据
三、中断(非阻塞式)收发定长数据
HAL_UART_Transmit(&huart1, message, 5, 100)函数中的message数据由发送数据寄存器(TDR)中数据通过 发送位移寄存器 经由TX接口变成高低电平发送出去。CPU需要不断查询TDR寄存器。
HAL_UART_Receive(&huart1, receiveData, 5, 100)函数中的receiveData数据由数据通过 接收位移寄存器 经由RX接口将高低电平接收 接收到数据寄存器(RDR)中。CPU需要不断查询RDR寄存器。
轮询会造成一直占用CPU,造成堵塞。中断则可以在不需要查询时做别的工作。
打开串口全局中断。USART1 global interrupt
//中断发送数据
#include<string.h>
//串口初始化
MX_USART2_UART_Init();
uint8_t receiveData[2];
//串口接收函数
HAL_UART_Receive(&huart1, receiveData, 2, HAL_MAX_DELAY);
//HAL_UART_Transmit(&huart1, receiveData, 2, 100); 此为轮询方式
HAL_UART_Transmit_IT(&huart1, receiveData, 2); 此为中断方式
//中断接收数据
#include<string.h>
//串口初始化
MX_USART2_UART_Init();
uint8_t receiveData[2];
/*此函数放在循环前调用一次,否则可能会在循环中再次中断,导致数据接收不全,不能在数据接收后立刻进行分析,因为数据可能接收未完成*/
HAL_UART_Receive_IT(&huart1, receiveData, 2); 此为中断方式
while(1)
{
//串口接收函数
//HAL_UART_Receive(&huart1, receiveData, 2, HAL_MAX_DELAY); 此为轮询方式
//HAL_UART_Transmit(&huart1, receiveData, 2, 100); 此为轮询方式
HAL_UART_Transmit_IT(&huart1, receiveData, 2); 此为中断方式
}
//中断处理函数 每个USART中只有一个中断向量. 但有许多中断函数共用USART1_IRQHandler中断处理函数,就需要简单的判断来确定因何原因产生的中断。简单的判断使用回调函数来实现。
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}
//串口接收完成回调函数,在此函数中处理数据完成后再打开接收中断。在此处实现需要的逻辑函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Transmit_IT(&huart1, receiveData, 2);
//这一步很重要,否则只能有一次中断接收
HAL_UART_Receive_IT(&huart1, receiveData, 2);
}
四、DMA收发不定长数据
首先打开串口DMA,设置好方向,模式
//DMA接收数据
#include<string.h>
//串口初始化
MX_USART2_UART_Init();
uint8_t receiveData[2];
/*此函数放在循环前调用一次,打开DMA接收*/
HAL_UART_Receive_DMA(&huart1, receiveData, 2); 此为中断方式
while(1)
{
//串口接收函数
//HAL_UART_Receive(&huart1, receiveData, 2, HAL_MAX_DELAY); 此为轮询方式
//HAL_UART_Transmit(&huart1, receiveData, 2, 100); 此为轮询方式
HAL_UART_Transmit_IT(&huart1, receiveData, 2); 此为中断方式
}
//中断处理函数 每个USART中只有一个中断向量. 但有许多中断函数共用USART1_IRQHandler中断处理函数,就需要简单的判断来确定因何原因产生的中断。简单的判断使用回调函数来实现。
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}
//串口接收完成回调函数,在此函数中处理数据完成后再打开接收中断。在此处实现需要的逻辑函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Transmit_DMA(&huart1, receiveData, 2);
//再次打开DMA接收。这一步很重要,否则只能有一次DMA接收
HAL_UART_Receive_DMA(&huart1, receiveData, 2);
}
接收不定长数据--串口不定长中断
//DMA接收数据
#include<string.h>
//串口初始化
MX_USART2_UART_Init();
uint8_t receiveData[50];
/*此函数放在循环前调用一次,打开DMA接收*/
//HAL_UART_Receive_DMA(&huart1, receiveData, 2); 此为中断方式
//第三个参数选择数组最大接收长度避免数组越界
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, receiveData, 50); /*使用此函数后不再使用HAL_UART_RxCpltCallback()回调,而是使用HAL_UARTEx_RxEventCallback()回调*/
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);//关闭传输过半中断
while(1)
{
//串口接收函数
//HAL_UART_Receive(&huart1, receiveData, 2, HAL_MAX_DELAY); 此为轮询方式
//HAL_UART_Transmit(&huart1, receiveData, 2, 100); 此为轮询方式
HAL_UART_Transmit_IT(&huart1, receiveData, 2); 此为中断方式
}
//中断处理函数 每个USART中只有一个中断向量. 但有许多中断函数共用USART1_IRQHandler中断处理函数,就需要简单的判断来确定因何原因产生的中断。简单的判断使用回调函数来实现。
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}
//串口接收完成回调函数,在此函数中处理数据完成后再打开接收中断。在此处实现需要的逻辑函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Transmit_DMA(&huart1, receiveData, 2);
//再次打开DMA接收。这一步很重要,否则只能有一次DMA接收
HAL_UART_Receive_DMA(&huart1, receiveData, 2);
}
//DMA传输过半中断也会触发此回调函数,故关闭DMA传输过半中断,此函数第三个参数是接收数据大小,直接入参即可。
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if(huart == &huart1)
{
HAL_UART_Transmit_DMA(&huart1, receiveData, Size);
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, receiveData, sizeof(receiveData));
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);//关闭传输过半中断
}
}
HAL_UARTEx_ReceiveToIdle()和HAL_UARTEx_ReceiveToIdle_IT都没问题,但是HAL_UARTEx_ReceiveToIdle_DMA模式除了串口空闲中断以外还有DMA传输过半中断。这样可能会使数据不完整。所以在HAL_UARTEx_RxEventCallback()回调中关闭DMA传输过半中断。别忘记在最开始也关闭此中断。