串口收发三种方式全理解透

一、选择端口,设置引脚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传输过半中断。别忘记在最开始也关闭此中断。

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值