目录
最近调串口接收是费了我很久的时间,软件没写过现学,硬件还出了问题【后面证明的】。
有一个点需要加深印象,当你串口能接收到数据,但是数据误码率很高的情况下。
首先,判断通信双方的波特率是否匹配、硬件是否支持这么高的波特率。
其次,大概率是硬件内部的干扰。 比如 我遇到的问题是,使用232通信,但硬件连接上出现了【1对多】的情况。
把【1对多】修改成【1对1】数据误码率瞬间就下降了。
下面总结使用 STM32 使用中断接收 上位机发送的定长数据,使用到的相关代码。
上位机一般下发的都是命令数据,时不时才发一回。因此暂时先不追求效率。
主要参考博客:STM32串口接收中断——基于HAL库 - 山无言 - 博客园 (cnblogs.com)
博客最后这段话是最受益的,我认为写在前面更合适。
【看完本文,大家可能对回调函数和中断处理函数的关系产生了疑问。其实是这样的,单片机每完成接收一个字符,就会进入一次中断处理函数,而在中断处理函数中,我们又调用了函数 void HAL_UART_IRQHandler ( UART_HandleTypeDef * huart ),该函数会间接调用回调函数,也就是说回调函数是由中断处理函数间接调用的。而函数 HAL_UART_Receive_IT ( UART_HandleTypeDef *huart, uint8_t * pData, uint16_t Size)决定了中断处理函数调用回调函数的频率,若Size为1,则每进入一次中断处理函数都会调用一次回调函数;若Size为10,则每第十次进入中断处理函数时,才会调用回调函数。方法2使用了标准库中断处理数据的思想。】
上面那段话好好Get一下啥意思,再往下看。
没学会的时候很懵逼,学会以后,其实简单得要死。 要实现<串口中断接收上位机发送的定长数据>这个功能,只需要修改两处代码。
第一处:main.c
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim3);
userinit();
HAL_UART_Receive_IT(&huart1,&value,1); // 【这一句最关键,就这一句!】
// 也可以写到MX_USART1_UART_Init();这个函数里面去
// 免得你看到烦
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
usermain();
}
/* USER CODE END 3 */
第二处:"AngelaDecode.c"
// 此文件专门用于接收并处理上位机数据, 你可自己定义串口接收源文件a.c b.c,随便你。 你写在main.c里面也可以。 好好看注释就行,我不必多说。
#include "usart.h" // 这必须包含!
#include "AngelaDecode.h"
unsigned char value; // main.c要包含AngelaDecode.h,value的定义在这里,.h里面定义了extern
unsigned char AngelaRx[128]={0x00};
short AngelaRxCNT = 0;
// 这函数本来有定义,但它前面有个关键字【__weak】,意思是自己可以重新定义一个同名函数,并且会被优先调用
。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1) // 由于所有的串口中断都会调用这个回调函数,因此要判断是串口几调用的
{
AngelaRx[AngelaRxCNT] = value; // 这时候value里面已经保持的有数据了
AngelaRxCNT++;
HAL_UART_Receive_IT(&huart1, &value,1); // 再次使能中断
if(AngelaRxCNT==128){ // 这128就是我定的“长”。集齐了128字节就召唤神龙!
AngelaCmdDecode(); // 数据有128字节后,开始解析上位机发过来是什么命令。
AngelaRxCNT = 0; // CNT重新置零。 以便接收下一个128字节的命令包
}
}
}