历史上的今天
返回首页

历史上的今天

今天是:2024年12月27日(星期五)

正在发生

2019年12月27日 | STM8S003单片机串口通信通信协议分析

2019-12-27 来源:eefocus

最近在用STM8S003这个片子做项目,在做串口通信的时候,发现以前写的协议太简单了,项目中用不适合。


//协议 : 0XDD xx xx  xx xx xx xx  0XAA 

 

@far @interrupt void UART1_Receive(void)

 

{

unsigned char res;

res=UART1_DR;

if(res==0xDD)       //头

{

Rec_statu=1;     //标志开始接收

Rec_Cnt=0;

Rec_End=0;

return;

}

if(res==0xAA)       //尾

{

Rec_statu=0;

Rec_End=1;        //标志接收完成

SendData();       //接收完一组数据后 在发送一组数据出去

return;

}

if(Rec_statu==1)           //如果处于数据接收中

{

Rec_Buf[Rec_Cnt++]=res;

}

return;

}


这是测试用的一个简单协议,用0XDD作为数据头,0XAA作为数据尾。不限制数据长度。能进行简单的通信功能,但是实际项目中应用时,如果传输的数据中有0XDD或者0XAA,这个协议在解析是就可能出错。


于是决定修改协议,将协议的头改为两位数据。


// A5 5A(头) 45(数据类型) 04(数量) 0x00 0x00 0x00 0x00 0xFF(校验)

// A5 5A 45 04 08 A0 09 B0 5E

@far @interrupt void UART1_Receive(void)

{

unsigned char res;

unsigned int check=0x00;   //  校验

res=UART1_DR;

UART1_SR&=~(1<<5);      //RXNE 清零

if((res==0xA5)&&(Rec_head==0))               //头

{

Rec_head=1;             //标志开始接收

Rec_statu=0;

Rec_Cnt=0;

Rec_End=0;

return;

}

if((res==0x5A)&&(Rec_head==1))

{

Rec_head=1;             //成功接收到了数据头 正式开始接收数据

Rec_statu=1;

Rec_Cnt=0;

Rec_End=0;

return;

}

if(Rec_Cnt==6)              //尾

{

check=(0x5a+0x5a+Rec_Buf[0]+Rec_Buf[1]+Rec_Buf[2]+Rec_Buf[3]+Rec_Buf[4]+Rec_Buf[5]);

if(res==(check&0xff))          //数据正确 存储接收到的温度值

{

//在这块处理数据时 串口中断会进不来

//env_tem=Rec_Buf[4]*256+Rec_Buf[5];    //环境温度值 2480

//obj_tem=Rec_Buf[2]*256+Rec_Buf[3];    //目标温度值 2208

Rec_End=1;            //标志接收完成

}

else

Rec_End=0;            //接收失败

Rec_head=0;

Rec_statu=0;

Rec_Cnt=0;

return;

}

if(Rec_statu==1)           //如果处于数据接收中

{

Rec_Buf[Rec_Cnt]=res;

Rec_Cnt++;

return;

}

return;

 

}


数据头变成了两位,数据长度为固定值,增加了校验位。看起来貌似没有什么问题,但是仔细分析,发现还是有很多漏洞。


当接收到0XA5时,准备开始接收数据,当收到0X5A时,正式开始接收数据,然后统计数据的个数,当收到规定个数数据时,结束接收数据。 如果发送的数据是 A5 5A 45 04 08 A0 09 B0 5E时,可以正常接收到数据。但是如果发送的数据是 A5 00 01 02 03 5A 45 04 08 A0 09 B0 5E 时,遇见0XA5标记数据准备接收,然后又接着收到了00 01 02 03这几个数据,此时由于接收数据没有正式开始,所以程序不会有任何动作,当接收到下一个数据0x5A时,程序开始正式接收数据。但是这笔数据是非法数据,被程序误判为正常数据。从而接收到了一组非法数据。


那么能不能用下标来控制数据头的识别,比如如果遇到了0xA5,数据准备接收,同时开始计数,如果下一个数据是0x5A,那么标记开始正式接收数据。这样看起来好像能够避免上面发送 这笔数据 A5 00 01 02 03 5A 45 04 08 A0 09 B0 5E 的情况,但是如果发送的数据是 A5 A5 5A 45 04 08 A0 09 B0 5E 呢?我们来分析一下,如果遇到A5程序准备接收数据,同时开始计数,第二个数据是A5而不是设定的5A,那么判定为非法数据,计数器清零,准备重新接收,当第三个数据5A进来时,发现不是数据头A5,抛弃本次数据,重新等待数据头A5。显而易见这笔数据里面包含有正常数据,不过第一个数据是A5刚好和数据头重复了,导致本次数据里面的正常数据仍然被丢弃了。


那么如果避免这种情况,可以考虑在接收的数据判断收到的头A5,并且后面紧跟的数据是5A,那么就说明接收到了正确的数据头。但是有个问题,本次接收的数据如果是A5,下次的数据还不知道是不是5A,那么本次的数据是要丢弃还是要存储起来,如果要存储起来,那么后面连续好多个5A的话,如果区分哪个5A是哪一次接收的。这样判断起来程序就会显得极为复杂,那么有没有简单有效的方法呢?可以换个思维,能不能判断如果这次接收到了数据尾5A,判断上次接收的数据是A5,那么说明接收到了数据头。这样的话如果有连续多个A5的话,只要后面不是5A,那么就不会开始接收数据。新修改的协议如下:


//接收数据标志位 各个位含义

//bit7:接收到尾    0xA5 0x5A  0 未收到  1 收到

//bit6:接收到头    0x55 0xAA  0 未收到  1 收到

//bit0-5:接收到数据个数      最多64个数据

unsigned  char rec_flag = 0;            //接收数据标志位

unsigned  char rec_buf[20] = {0}; //接收数据存储

//串口接收数据格式为:  头1(0xA5) 头2(0x5A)  数据N位  尾1(0x55) 尾2(0xAA)

// 0xA5 0x5A xx xx xx xx xx xx xx xx xx xx xx  0x55 0xAA

 

//接收中断函数 中断号18

#pragma vector  =  20                   // IAR中的中断号,要在STVD中的中断号上加2

__interrupt void UART1_Handle( void )

{

    unsigned char res = 0;

    if( rec_flag & 0x80 )                               //如果接收数据结束返回 数据被读取后才清0 标志位

    {

        return;

    }

    res = UART1_DR;

    UART1_SR &= ~( 1 << 5 );                                //RXNE 清零

    rec_flag++;                                         //接收数据计数

    //这种方式判断,可以有效识别类似 A5 A5 A5 5A XX XX 这样的数据开头

    //如果只判断第一位是A5,第二位是5A的话,上面的这种数据就判定为非法数据,不能有效识别

    if( ( res == 0xA5 ) && ( ( rec_flag & 0x40 ) == 0 ) )       //如果没有开始接收数据,并且当前的数据是0xA5 将计数清零

    {

        rec_flag = 0;

        rec_buf[0] = res;

        return;

    }

    if( ( rec_flag & 0x3F ) == 0x01 )                   //第二位数据

    {

        if( res == 0x5A )                               //如果第二位数据是0x5A 说明已经正确收到了数据头

        {

            rec_buf[rec_flag & 0x3F] = res;

            rec_flag |= ( 1 << 6 );                         // 接收到头第2位   0x5A     置标志位

        }

        else

        {

            rec_flag = 0;                                   //接收错误,重新开始

        }

        return;

    }

    if( ( ( rec_flag & 0x40 ) == 0x40 ) && ( ( rec_flag & 0x80 ) == 0 ) ) //已经成功接收到了头并且没有收到尾

    {

        //本次接收的是0xAA 上一笔数据是0x55 说明数据传输结束

        //这种方式可以有效识别 数据和结束符一样的情况如 XX XX XX 55 55 55 AA

        //如果接收到55就开始判断的话,上述的情况就会识别为非法数据,不能有效判断

        if( res == 0xAA )                               //接收到尾 第2位

        {

            rec_buf[rec_flag & 0x3F] = res;

            if( rec_buf[( rec_flag & 0x3F ) - 1] == 0x55 ) //如果上次接收的数据是 尾第1位

            {

                rec_flag |= ( 1 << 7 );                     //接收数据结束

            }

        }

        else

        {

            rec_buf[rec_flag & 0x3F] = res;                 //存储接收到的数据

        }

    }

}


这次协议改为了,数据头为两位 A5 5A ,数据尾也为两位 55 AA。数据长度可以为任意值,校验位暂时没加进去。


这次判断的流程为,如果接收到的数据是A5那么就把计数值清0,如果不是A5,接收数据,并把计数值加1,然后在判断第一位数据是不是5A,如果不是5A,那么重新清0,重新接收。 这样的话 如果发送的数据是 A5 00 00 5A xx xx 时,第一位数据5A,计数器清0,然后接收的第一位数据是00,不等于5A,那么计时器清0,重新开始接收。如果发送的数据是 A5 A5 A5 5A xx xx时,接收的第一个数据是5A,计时器清0,接收的第二个数据还是5A,那么计时器的值还是0,当第三个5A来时,计数器的值还为0,当第四个数据来时,不为A5,那么接收数据,计数器加1,此时计数器的值为1。然后判断计数器的值为1时,收到的数据是5A,开始正式接收数据。这样就可以有效的判断到数据头,不会误判和漏判。同样数据结束时也用两位判断 55 AA,当本次接收的数据是AA,同时判断上一次接收的数据是55时,说明数据接收结束。由于判断数据尾时,前面接收的数据都在数组中存储着,所以判断本次接收的数据和前一次接收的数据可以同时进行。比判断数据头简单。


修改后的协议可以接收 A5 5A xx xx xx xx 55 AA这样的标准数据,同时也能有效的判断到 类似 A5 A5 A5 A5 5A xx xx xx xx 55 55 55 55 AA这种带有干扰数据,但是又是合法数据的数据。如果需要数据校验,可以在结束符之前添加校验位。这次修改后的协议目前看来还是比较理想的,可以考虑在实际项目中应用。

推荐阅读

史海拾趣

Force Technologies Ltd公司的发展小趣事

背景:随着业务的不断增长,Force Technologies Ltd意识到单一市场已无法满足其发展需求。于是,公司制定了明确的国际化战略,旨在将产品和技术推向全球。

发展:通过在欧洲、北美和亚洲等地设立研发中心和生产基地,Force Technologies Ltd成功构建起全球化的运营网络。同时,公司还积极参与国际展览和交流活动,不断提升品牌知名度和影响力。在国际市场的推动下,公司的销售额和市场份额均实现了快速增长。

Crouzet公司的发展小趣事

Crouzet公司,这家以生产自控产品为主的跨国公司,于1921年正式成立。创立之初,Crouzet主要专注于自控产品的研发和生产,凭借其卓越的技术和创新能力,很快在市场中占据了一席之地。公司逐渐扩大生产规模,提升产品质量,赢得了客户的信赖。

Hi-Tron Semiconductor Corp公司的发展小趣事

随着业务的不断发展,Crouzet公司于1989年和1992年分别成功兼并了法国Syreles公司及墨西哥Gordos公司。这一系列的兼并活动不仅增强了公司的实力,还进一步扩大了公司的业务范围。此后,Crouzet开始在全球范围内布局,陆续在美国、德国、英国、荷兰、比利时、瑞士、瑞典等国设立分公司,形成了一个覆盖全球的销售网络。

Carling Technologies公司的发展小趣事

随着技术的不断进步和市场需求的多样化,Carling Technologies开始扩展其产品线,涵盖了液压磁热断路器、电子控制以及配电装置等多个领域。同时,公司也积极开拓全球市场,通过设立海外办事处和与当地企业合作,将产品销往世界各地。这一阶段的发展使得Carling Technologies成为了全球电气和电子开关领域的领先制造商之一。

EMS GmbH公司的发展小趣事

随着公司技术的不断成熟和产品的不断优化,EMS GmbH公司开始积极拓展市场。公司不仅在欧洲市场取得了显著的成绩,还逐渐将业务拓展至全球范围。通过参加国际展会、与合作伙伴建立战略合作关系等方式,EMS GmbH公司不断提升品牌知名度和影响力。同时,公司还注重产品质量和服务质量的提升,以确保在激烈的市场竞争中保持竞争优势。

CT Micro公司的发展小趣事
  1. 创业初期与技术创新

CT Micro公司最初由几位电子工程领域的专家创立,他们看到了微型计算机断层扫描(Micro-CT)技术在电子行业中的巨大潜力。初期,公司面临着资金短缺和技术难题,但他们通过不断研发和创新,成功开发出了一款具有高性价比的Micro-CT设备,迅速获得了市场的认可。

  1. 市场拓展与合作伙伴关系

随着产品的成熟,CT Micro开始积极寻求市场拓展。他们与多家电子制造企业建立了合作关系,为这些企业提供Micro-CT设备的定制服务。通过与这些企业的合作,CT Micro不仅扩大了市场份额,还进一步提升了产品的技术水平和应用范围。

  1. 研发升级与产品迭代

面对日益激烈的市场竞争,CT Micro不断投入研发力量,对Micro-CT设备进行升级和迭代。他们成功推出了多款新型设备,具有更高的分辨率、更快的扫描速度和更低的辐射剂量。这些新产品的推出,进一步巩固了CT Micro在电子行业中的领先地位。

  1. 国际化战略与市场拓展

随着国内市场的饱和,CT Micro开始实施国际化战略。他们积极参与国际展览和研讨会,展示自己的产品和技术实力。同时,他们还在海外设立了销售和服务中心,为国际客户提供更加便捷的服务。通过这些努力,CT Micro成功打开了国际市场的大门。

  1. 社会责任与可持续发展

在快速发展的同时,CT Micro也积极履行社会责任。他们注重环保和可持续发展,采用环保材料和节能技术生产产品。此外,他们还积极参与公益事业,为贫困地区的教育和医疗事业贡献力量。这些举措不仅提升了公司的社会形象,也为其可持续发展奠定了坚实基础。

请注意,这些故事框架是虚构的,并不代表CT Micro公司的实际发展情况。如果您需要了解CT Micro公司或类似公司的真实故事,建议您查阅相关公司的官方网站、新闻报道或行业分析报告。

问答坊 | AI 解惑

求MAX3232中文资料

求MAX3232中文资料…

查看全部问答>

刚看到关于3G的投票,有感~~

联通收了网通,大家感觉有没有变化,尤其是上网和固话那块 之前发生了个小事,好在比较及时的解决了 但是当时遇到时,觉得服务太差了,后来解决问题的速度和态度还算不错,大家有没有同样的感觉?…

查看全部问答>

在这里宣泄一下我对我以后工作的忧虑和困惑

二月二十四号那天, 我心血来潮地去了一趟我签约的那家在重庆的国营企业,,想去看个究竟。 之前认识了一些比我高一届的师兄师姐们在那公司,经常在群里和他们聊天, 感觉到的气氛就是他们进入公司以后,心理落差比较大。 他们常常对我说, ...…

查看全部问答>

乐图医疗行业120急救车无线视频监控解决方案

  在现代化的城市中,医疗救援系统是城市保障体系中的重要组成部分,120急救中心承担着医疗救援指挥中心的任务,完成急救、大型社会医疗保障及“110”联动等任务,对于保护人民群众的生命安全有着不可替代的作用。随着无线监控产品的日渐成熟,越 ...…

查看全部问答>

android应用开发

呵呵,传个现在热门的android的应用开发的ppt顺便说下freescale i.mx5x系列跑android是很爽的,可惜没时间玩啊…

查看全部问答>

如何测试LED芯片,荧光胶,荧光粉方法

面对LED市场的混乱,林林总总,鱼龙混杂的辅料市场,确实让很多新生代的封装工程人员搞得很是迷惑。以下提出几种测试荧光胶,荧光粉,芯片的快速简单的方法供大家参考。 1.    如何测试芯片的稳定性 采用不同芯片厂家的芯片用同一家同 ...…

查看全部问答>

关于gpio中断的问题

一般情况下,都是把I/O配置为输入,然后配置中断模式,我现在把I/O口配置为输出,然后配置中断模式。从内部给这个口输出高低电平,这样产生的中断有问题吗?…

查看全部问答>

香主,请教个问题---TIM的

输入捕获模式下:我现在TIM2_CH2,TIM2_CH3都是输入一个频率定期变化的PWM波。并且都可以用输入捕获方式(在中断服务程序中完成两次上升沿的捕捉,然后计算出频率),已经正确。现在有个问题,因为我的频率最高是10Hz的,因此周期为0.1ms=100us ...…

查看全部问答>

一个基本语句

想问问大家:这两个语句是不是同一个意思啊?P1DIR|=0X00和P1DIR&=~0X01…

查看全部问答>

对于有源低通滤波器为什么在截止频率之前输出信号与输入信号相比就出现了相位偏移

本帖最后由 paulhyde 于 2014-9-15 09:47 编辑 对于有源低通滤波器为什么在截止频率之前输出信号与输入信号相比就出现了相位偏移  …

查看全部问答>