历史上的今天
今天是:2025年12月14日(星期日)
2022年12月14日 | STM32串口通信详解以及通信异常或者卡死常见问题分析
2022-12-14 来源:zhihu
异常一:数据传输中会出现乱码
数据传输中会出现乱码,很有可能是数组溢出,或者定义的数组长度不够。或者中断被打断。
异常二:程序卡在中断函数里面无法跳出执行主函数的逻辑
中断标志位没有被清除,在这里要注意一点,串口中断标志位自动清空的前提是软件需要先读USART_SR寄存器,然后读USART_DR寄存器来自动清除。即串口中断事件发生后,如果使能的接收中断,而中断函数里面什么都不执行的话,接收中断标志位是无法自动清空的,故而,函数会一直卡在中断函数里面。
比如一下这个函数,该函数没有逻辑问题,但会引发以上问题,代码如下
extern unsigned char star_time_led ; //计时开始变量
unsigned char recv_flag = 0;//定义接受标志位
unsigned long recv_cnt = 0;//串口1接收数据缓存
unsigned char recv_buf[MAX_REV_NUM];//串口1接收数据缓存
extern unsigned char star_time;
extern unsigned char recv_time_cnt;
/*
以下写法有严重问题
如果没有这句函数→USART_ClearFlag(USART1,USART_FLAG_RXNE); //清空中断标志位
串口接收中断标志位将文法被清空,会导致函数卡在中断函数里面一直循环,无法正常运行主函数
原因分析:
中断条件成立后,中断标志位将会标记,程序将会进入中断函数运行,软件自动轻触中断标志位的条件是
先读USART_SR寄存器,再读USART_DR寄存器。
void USART1_IRQHandler(void) //串口1中断服务程序
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //是否发送中断事件
{
star_time = 1; //接受到一帧数据的时候,打开软件定时器,去计数
if(recv_cnt < MAX_REV_NUM)//数组长度是否超过缓存区
{
recv_buf[recv_cnt] =USART_ReceiveData(USART1);//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
recv_cnt++;
}
else
{
recv_cnt = MAX_REV_NUM
;//限制数组长度,超过缓存区则不再接收
}
recv_time_cnt = 0; //每接收到一帧数据,把定时计数器清零,相当于喂狗
//但是在定时器中断里面会不断的累加
USART_ClearFlag(USART1,USART_FLAG_RXNE); //清空中断标志位
}
}
*/
上述代码优化后如下
void USART1_IRQHandler(void) //串口1中断服务程序
{
static char ch;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //是否发送中断事件
{
ch = USART_ReceiveData(USART1);//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
star_time = 1; //接受到一帧数据的时候,打开软件定时器,去计数
if(recv_cnt < MAX_REV_NUM)//数组长度是否超过缓存区
{
recv_buf[recv_cnt] =ch;//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
recv_cnt++;
}
else
{
recv_cnt = MAX_REV_NUM
;//限制数组长度,超过缓存区则不再接收
}
recv_time_cnt = 0; //每接收到一帧数据,把定时计数器清零,相当于喂狗
//但是在定时器中断里面会不断的累加
USART_ClearFlag(USART1,USART_FLAG_RXNE); //清空中断标志位
}
}
异常三:数据发送中间歇性数据异常漏发乱发等
对于这些奇奇怪怪的问题,首先要了解一下发送函数是怎么发送的
USART_DR 包含了已发送的数据或者接收到的数据。USART_DR 实际是包含了两个寄存器,一个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。当进行发送操作时,往 USART_DR 写入数据会自动存储在 TDR 内;当进行读取操作时,向 USART_DR读取数据会自动提取 RDR 数据。
TDR 和 RDR 都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的,发送时把 TDR 内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接收时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到 RDR。
当 TDR 内容转移到发送移位寄存器,还没有发送出去的,就再次把TDR 内容转移到发送移位寄存器里,就会出现少发的现象。
什么时候会有这种情况呢?错误操作代码如下:
void USART2_IRQHandler(void) //串口2中断服务程序
{
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //是否发送中断事件
{
Usart1RecBuf[RxCounter] =USART_ReceiveData(USART2);//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
RxCounter++;//指向数组地址自加
if(RxCounter==2)
{
USART_SendData(USART1, Usart1RecBuf[0]);//发送Usart1RecBuf[0]
USART_SendData(USART1, Usart1RecBuf[1]);//发送Usart1RecBuf[1]
USART_SendData(USART1, Usart1RecBuf[2]);//发送Usart1RecBuf[2]
}
}
}
上述代码连续运行了3次USART_SendData(USART1, Usart1RecBuf);这个函数,这种情况一般都会出现只有最后一个数据发送成功出去。原因可能就是数据还没有发送出去,发送移位寄存器就更新了。
史海拾趣
|
公司找的外包软件公司需要direct3d功能,对此不了解,所以有几个问题想请教一下: 1、外包公司一直提到direct3d.dll,而WINCE5.0中有d3dm.dll,两者之间的关系是类似于MDD与PDD之间的关系还是同等关系? 2、看他们软件介绍是需要Pocket PC\\Windo ...… 查看全部问答> |
|
我按照网上查到的方法 用自己的程序替换掉了explorer.exe [HKEY_LOCAL_MACHINE\\Init] \"Launch50\"=\"myapp.exe\" \"Depend50\"=hex:14,00,1e,00 编译的系统能够运行,并且程序全屏。 我的疑问是,我想在程序的界面中输入东西怎么办? 我看不 ...… 查看全部问答> |
|
我现在在做一个频率计,用FPGA做数据采集,51单片机做显示,数据通信上我说一下我的思路,当P3-0口为低电平,其他为高电平时,FPGA的数据口传送给P1口一组8位数据,当P3-1口为低电平,其他为高电平时,FPGA的数据口再传送给P1口一组8位数据,一共四 ...… 查看全部问答> |
|
[手机远程无线温湿度监控系统] [无线温湿度监控系统] 【手机温湿度监控系统】 农业大棚温湿度监控系统方案 本文编辑 九纯健刘重庆 本方案主要是针对手机检测大棚温湿度所开发设计 ...… 查看全部问答> |
|
由于我电路设计失误,导致VCCA本来应该2.5V的供电现在大约2.3V,不知道这个影响FPGA的工作吗? 我程序烧写是正常的,但是程序不是立刻执行,过了得有半分钟才开始执行? 这个和电压不够有关系吗? 谢谢啊… 查看全部问答> |




