OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4698|回复: 5

串口接收问题

[复制链接]

23

主题

130

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
314
金钱
314
注册时间
2015-1-25
在线时间
83 小时
发表于 2017-6-9 11:34:55 | 显示全部楼层 |阅读模式
5金钱

在串口中断内,判断接收到的数据是否正确,头,尾和 数量
怎么也无法实现?求帮助

发送的数据  历程   16进制    7b 00 00 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 7d

USART_RX_STA功能有小改变。

串口接收中断处理的问题

void USART1_IRQHandler(void)                        //串口1中断服务程序
        {
                u8 Res;
                /*
                        判断头尾
                        //接收状态
                        //bit15,        接收完成标志                0x8000                                1000
                        //bit14,        接收到0x7d                 0x4000                尾                0100
                        //bit13                接收到0x7a                0x2000                头                0010
                        //bit12~0,        接收到的有效字节数目
                        u16 USART_RX_STA=0;       //接收状态标记       
                */               
                if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
                {
                               
                        Res =USART_ReceiveData(USART1);//(USART1->DR);        //读取接收到的数据
                        USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除中断标志
                        if((USART_RX_STA&0x8000)==0)//接收未完成
                        {
                                if(USART_RX_STA&0x6000)//接收到了tou  wei
                                        {
                                                if((USART_RX_STA&0X1FFF)>USART_REC_LEN-1)
                                                {
                                                        USART_RX_STA=0;//接收错误,重新开始
                                                }
                                                else
                                                {
                                                        USART_RX_STA|=0x8000;
                                                }        //接收完成了
                                        }
                                else // 收到0x7d
                                        {       
                                                if(USART_RX_BUF[0]==0x7b)   //tou
                                                        {
                                                                USART_RX_STA|=0x2000;
                                                        }               
                                                if(USART_RX_BUF[USART_REC_LEN-1]=0x7d)        // wei
                                                        {
                                                                USART_RX_STA|=0x4000;
                                                        }
                                        else
                                                {
                                                        USART_RX_BUF[USART_RX_STA&0X1FFF]=Res ;
                                                        USART_RX_STA++;
                                                        if((USART_RX_STA&0X1FFF)>(USART_REC_LEN-1))
                                                        {
                                                                USART_RX_STA=0;
                                                        }//接收数据错误,重新开始接收          
                                                }                 
                                        }
                        }
                }
        }       





主函数 判断

if(USART_RX_STA&0x8000)               
{
.......

}

最佳答案

查看完整内容[请看2#楼]

就放上来的这段代码,有个大问题。当主函数在处理数据时,中断可能还在发生。所以你处理的数据,可能一半是上一次发的,一半是这一次发的。 这种问题有两个方案: 1、做个全局互锁开关,通讯完毕了打开开关,只要开关开着,就不能再接收数据。主函数判断开关,如果开着就处理数据,处理完了就关掉开关。 2、做两个缓存数组,一个用于实时接收,接收完毕了用memcpy函数拷贝到另一个数组。主函数永远只能处理另一个数组的数据。如 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

13

帖子

0

精华

初级会员

Rank: 2

积分
83
金钱
83
注册时间
2015-6-12
在线时间
14 小时
发表于 2017-6-9 11:34:56 | 显示全部楼层
本帖最后由 hh312 于 2017-6-11 18:58 编辑

就放上来的这段代码,有个大问题。当主函数在处理数据时,中断可能还在发生。所以你处理的数据,可能一半是上一次发的,一半是这一次发的。
这种问题有两个方案:
1、做个全局互锁开关,通讯完毕了打开开关,只要开关开着,就不能再接收数据。主函数判断开关,如果开着就处理数据,处理完了就关掉开关。
2、做两个缓存数组,一个用于实时接收,接收完毕了用memcpy函数拷贝到另一个数组。主函数永远只能处理另一个数组的数据。如果缓存太大怕memcpy函数执行太久影响中断,就做指针切换也行。接收完了指针就切换过去,主函数永远通过这个指针去取数组。
补充说明一下,第二个方案只适合于主函数运行足够快,能够实时处理完每一帧数据的情况,即,在处理数据时,那边又开始接受数据,这没问题,但是在接收完成数据开始memcpy时,就得考虑主函数是否已经处理完了。如果这个无法保证,就必定会有冲突,只能使用第一个方案,放弃某些帧。如果主函数轮询太慢,可以考虑设置软中断,接收完一帧后触发软中断去处理数据,这样最节约时间。
回复

使用道具 举报

13

主题

54

帖子

0

精华

初级会员

Rank: 2

积分
144
金钱
144
注册时间
2016-9-3
在线时间
26 小时
发表于 2017-6-9 15:10:32 | 显示全部楼层
本帖最后由 stm32zzq 于 2017-6-9 15:28 编辑

USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除中断标志 这句话是多余的,因为在上一句中读取DR寄存器的时候已经清除标志位了,另外你的逻辑有些错误,你可以先把你的想法按步骤一步一步注释下,然后跟着节奏走,我可以给你个参考,bit15和bit14两个标志位就OK了,另外你的头数据写错了,写成了0x7B,你上面的注释是0x7A//程序如下

void USART1_IRQHandler(void)
{
        u8 Res;            
         if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收到数据
        {         
                Res = USART_ReceiveData(USART1);         //读取接收到的数据
                if(!(USART_RX_STA & 0x8000))//接收未完成,未接收到0x7D
                {
                        if(USART_RX_STA > (USART_REC_LEN - 1))USART_RX_STA = 0;//数据量超标,直接清空,这里最好加个清空缓冲区的操作
                        USART_RX_BUF[USART_RX_STA & 0x3FFF] = Res;                //记录接收到的值
                        USART_RX_STA++;                                                //接收数据增加1
                        if(USART_RX_STA & 0x4000)//已经接收到0x7A头
                        {
                                if(0x7D == Res)//现在接收到尾0x7D
                                {
                                        USART_RX_STA |= 0x8000;        //接收完成了
                                }
                        }
                        else //刚才还没收到0x7A
                        {        
                                if(0x7A == Res)//现在收到0x7A
                                {
                                        USART_RX_STA |= 0x4000;//标志着接收到头
                                }
                        }
                }   
        }                                                                                          
}




回复

使用道具 举报

15

主题

866

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
7705
金钱
7705
注册时间
2016-11-30
在线时间
651 小时
发表于 2017-6-10 09:27:04 | 显示全部楼层
楼上的方案很细腻!
回复

使用道具 举报

5

主题

266

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1526
金钱
1526
注册时间
2016-7-20
在线时间
155 小时
发表于 2017-6-10 09:27:45 | 显示全部楼层
在中断里处理这么多事情?不怕出事?
我是可以什么都不说 ,但不可以什么都不做。
回复

使用道具 举报

23

主题

130

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
314
金钱
314
注册时间
2015-1-25
在线时间
83 小时
 楼主| 发表于 2017-6-14 10:04:10 | 显示全部楼层
将中断处理函数改为以下,每次接收开启定时器,超过10ms认为无数据,在主函数判断数据的正确性

发现以下问题  if((USART_RX_STA&0x8000)==0)这句不执行
改为以下  if(!(USART_RX_STA&0x8000))   就可以,想不明白为什么,求指教


void USART1_IRQHandler(void)                        //串口1中断服务程序
        {
                u8 Res;
                if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//接收到数据
                {         
                        Res =USART_ReceiveData(USART1);

                        if(!(USART_RX_STA&0x8000))
//                        if((USART_RX_STA&0x8000)==0)//这句不执行?
                        {
                                if(USART_RX_STA<USART_REC_LEN)        //还可以接收数据
                                {
                                        TIM_SetCounter(TIM6,0);//计数器清空                                         
                                        if(USART_RX_STA==0)                                 //
                                        {
                                                TIM_Cmd(TIM6,ENABLE);//使能定时器6
                                        }
                                        USART_RX_BUF[USART_RX_STA++]=Res;        //记录接收到的值         
                                }
                                else
                                {
//                                        if(USART_RX_STA>USART_REC_LEN-1)
//                                        {
//                                                USART_RX_STA=0;
//                                        }
//                                        else
                                        USART_RX_STA|=0x8000;                                //强制标记接收完成
                                }
                        }
        }

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-8-18 11:23

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表