通信程序的通用写法

发布者:cocolang最新更新时间:2018-03-07 来源: eefocus关键字:通信程序  通用写法 手机看文章 扫描二维码
随时随地手机看文章

    现在大部分的仪器设备都要求能过通过上位机软件来操作,这样方便调试,利于操作。其中就涉及到通信的过程。在实际制作的几个设备中,笔者总结出了通信程序的通用写法,包括上位机端和下位机端等

    1. 自定义数据通信协议

    这里所说的数据协议是建立在物理层之上的通信数据包格式。所谓通信的物理层就是指我们通常所用到的RS232、RS485、红外、光纤、无线等等通信方式。在这个层面上,底层软件提供两个基本的操作函数:发送一个字节数据、接收一个字节数据。所有的数据协议全部建立在这两个操作方法之上。


    通信中的数据往往以数据包的形式进行传送的,我们把这样的一个数据包称作为一帧数据。类似于网络通信中的TCPIP协议一般,比较可靠的通信协议往往包含有以下几个组成部分:帧头、地址信息、数据类型、数据长度、数据块、校验码、帧尾。

    帧头和帧尾用于数据包完整性的判别,通常选择一定长度的固定字节组成,要求是在整个数据链中判别数据包的误码率越低越好。减小固定字节数据的匹配机会,也就是说使帧头和帧尾的特征字节在整个数据链中能够匹配的机会最小。通常有两种做法,一、减小特征字节的匹配几率。二、增加特征字节的长度。通常选取第一种方法的情况是整个数据链路中的数据不具有随即性,数据可预测,可以通过人为选择帧头和帧尾的特征字来避开,从而减小特征字节的匹配几率。使用第二种方法的情况更加通用,适合于数据随即的场合。通过增加特征字节的长度减小匹配几率,虽然不能够完全的避免匹配的情况,但可以使匹配几率大大减小,如果碰到匹配的情况也可以由校验码来进行检测,因此这种情况在绝大多说情况下比较可靠。

    地址信息主要用于多机通信中,通过地址信息的不同来识别不同的通信终端。在一对多的通信系统中,可以只包含目的地址信息。同时包含源地址和目的地址则适用于多对多的通信系统。

    数据类型、数据长度和数据块是主要的数据部分。数据类型可以标识后面紧接着的是命令还是数据。数据长度用于指示有效数据的个数。

    校验码则用来检验数据的完整性和正确性。通常对数据类型、数据长度和数据块三个部分进行相关的运算得到。最简单的做法可是对数据段作累加和,复杂的也可以对数据进行CRC运算等等,可以根据运算速度、容错度等要求来选取。

    2. 上位机和下位机中的数据发送

    物理通信层中提供了两个基本的操作函数,发送一个字节数据则为数据发送的基础。数据包的发送即把数据包中的左右字节按照顺序一个一个的发送数据而已。当然发送的方法也有不同。

    在单片机系统中,比较常用的方法是直接调用串口发送单个字节数据的函数。这种方法的缺点是需要处理器在发送过程中全程参与,优点是所要发送的数据能够立即的出现在通信线路上,能够立即被接收端接收到。另外一种方法是采用中断发送的方式,所有需要发送的数据被送入一个缓冲区,利用发送中断将缓冲区中的数据发送出去。这种方法的优点是占用处理器资源小,但是可能出现需要发送的数据不能立即被发送的情况,不过这种时延相当的小。对于51系列单片机,比较倾向于采用直接发送的方式,采用中断发送的方式比较占用RAM资源,而且对比直接发送来说也没有太多的优点。以下是51系列单片机中发送单个字节的函数。

    void SendByte(unsigned char ch)

    {

    SBUF = ch;

    while(TI == 0);

    TI = 0;

    }

    上位机中关于串口通信的方式也有多种,这种方式不是指数据有没有缓冲的问题,而是操作串口的方式不同,因为PC上数据发送基本上都会被缓冲后再发送。对于编程来说操作串口有三种方式,一、使用Windows系统中自带的串口通信控件,这种方式使用起来比较简单,需要注意的是接收时的阻塞处理和线程机制。二、使用系统的API直接进行串口数据的读取,在windows和linux系统中,设备被虚拟为文件,只需要利用系统提供的API函数即可进行串口数据的发送和读取。三、使用串口类进行串口操作。在此只介绍windows环境下利用串口类编程的方式。

    CSERialport是比较好用的串口类。它提供如下的串口操作方法:

    void WriteToPort(char* string, int len);

    串口初始化成功后,调用此函数即可向串口发送数据。为了避免串口缓冲所带来的延时,可以开启串口的冲刷机制。

    3. 下位机中的数据接收和协议解析

    下位机接收数据也有两种方式,一、等待接收,处理器一直查询串口状态,来判断是否接收到数据。二、中断接收。两种方法的优缺点在此前的一篇关于串口通信的文章中详细讨论过。得出的结论是采用中断接收的方法比较好。

    数据包的解析过程可以设置到不同的位置。如果协议比较简单,整个系统只是处理一些简单的命令,那么可以直接把数据包的解析过程放入到中断处理函数中,当收到正确的数据包的时候,置位相应的标志,在主程序中再对命令进行处理。如果协议稍微复杂,比较好的方式是将接收的数据存放于缓冲区中,主程序读取数据后进行解析。也有两种方式交叉使用的,比如一对多的系统中,首先在接收中断中解析“连接”命令,连接命令接收到后主程序进入设置状态,采用查询的方式来解析其余的协议。

    以下给出具体的实例。在这个系统中,串口的命令非常简单。所有的协议全部在串口中断中进行。数据包的格式如下:

    0x55, 0xAA, 0x7E, 0x12, 0xF0, 0x02, 0x23, 0x45, SUM, XOR, 0x0D

    其中0x55, 0xAA, 0x7E为数据帧的帧头,0x0D为帧尾,0x12为设备的目的地址,0xF0为源地址,0x02为数据长度,后面接着两个数据0x23, 0x45,从目的地址开始结算累加、异或校验和,到数据的最后一位结束。


    协议解析的目的,首先判断数据包的完整性,正确性,然后提取数据类型,数据等数据,存放起来用于主程序处理。代码如下:

    if(state_machine == 0) // 协议解析状态机

    {

    if(rcvdat == 0x55) // 接收到帧头第一个数据

    state_machine = 1;

    else

    state_machine = 0; // 状态机复位

    }

    else if(state_machine == 1)

    {

    if(rcvdat == 0xAA) // 接收到帧头第二个数据

    state_machine = 2;

    else

    state_machine = 0; // 状态机复位

    }

    else if(state_machine == 2)

    {

    if(rcvdat == 0x7E) // 接收到帧头第三个数据

    state_machine = 3;

    else

    state_machine = 0; // 状态机复位

    }

    else if(state_machine == 3)

    {

    sumchkm = rcvdat; // 开始计算累加、异或校验和

    xorchkm = rcvdat;

    if(rcvdat == m_SRCAdr) // 判断目的地址是否正确

    state_machine = 4;

    else

    state_machine = 0;

    }

    else if(state_machine == 4)

    {

    sumchkm += rcvdat;

    xorchkm ^= rcvdat;

    if(rcvdat == m_DstAdr) // 判断源地址是否正确

    state_machine = 5;

    else

    state_machine = 0;

    }

    else if(state_machine == 5)

    {

    lencnt = 0; // 接收数据计数器

    rcvcount = rcvdat; // 接收数据长度

    sumchkm += rcvdat;

    xorchkm ^= rcvdat;

    state_machine = 6;

    }

    else if(state _machine == 6 || state _machine == 7)

    {

    m_ucData[lencnt++] = rcvdat; // 数据保存

    sumchkm += rcvdat;

    xorchkm ^= rcvdat;

    if(lencnt == rcvcount) // 判断数据是否接收完毕

    state_machine = 8;

    else

    state_machine = 7;

    }

    else if(state_machine == 8)

    {

    if(sumchkm == rcvdat) // 判断累加和是否相等

    state_machine = 9;

    else

    state_machine = 0;

    }

    else if(state_machine == 9)

    {

    if(xorchkm == rcvdat) // 判断异或校验和是否相等

    state_machine = 10;

    else

    state_machine = 0;

    }

    else if(state_machine == 10)

    {

    if(0x0D == rcvdat) // 判断是否接收到帧尾结束符

    {

    retval = 0xaa; // 置标志,表示一个数据包接收到

    }

    state_machine = 0; // 复位状态机

    }

    此过程中,使用了一个变量state_machine作为协议状态机的转换状态,用于确定当前字节处于一帧数据中的那个部位,同时在接收过程中自动对接收数据进行校验和处理,在数据包接收完的同时也进行了校验的比较。因此当帧尾结束符接收到的时候,则表示一帧数据已经接收完毕,并且通过了校验,关键数据也保存到了缓冲去中。主程序即可通过retval的标志位来进行协议的解析处理。

    接收过程中,只要哪一步收到的数据不是预期值,则直接将状态机复位,用于下一帧数据的判断,因此系统出现状态死锁的情况非常少,系统比较稳定,如果出现丢失数据包的情况也可由上位机进行命令的补发,不过这种情况笔者还没有碰到。

    对于主程序中进行协议处理的过程与此类似,主程序循环中不断的读取串口缓冲区的数据,此数据即参与到主循环中的协议处理过程中,代码与上面所述完全一样。


    4. 上位机中的数据接收和命令处理

    上位机中数据接收的过程与下位机可以做到完全一致,不过针对不同的串口操作方法有所不同。对于阻赛式的串口读函数,例如直接进行API操作或者调用Windows的串口通信控件,最好能够开启一个线程专门用于监视串口的数据接收,每接收到一个数据可以向系统发送一个消息。笔者常用的CSerialPort类中就是这样的处理过程。CSerialPort打开串口后开启线程监视串口的数据接收,将接收的数据保存到缓冲区,并向父进程发送接收数据的消息,数据将随消息一起发送到父进程。父进程中开启此消息的处理函数,从中获取串口数据后就可以把以上的代码拷贝过来使用。


    CSerialPort向父类发送的消息号如下:

    #define WM_COMM_RXCHAR WM_USER+7 // A character was received and placed in the input buffer.

    因此需要手动添加此消息的响应函数:

    afx_msg LONG OnCommunICation(WPARAM ch, LPARAM port);

    ON_MESSAGE(WM_COMM_RXCHAR, OnCommunication)

    响应函数的具体代码如下:

    LONG CWellInfoView::OnCommunication(WPARAM ch, LPARAM port)

    {

    int retval = 0;

    rcvdat = (BYTE)ch;

    if(state_machine == 0) // 协议解析状态机

    {

    if(rcvdat == 0x55) // 接收到帧头第一个数据

    state_machine = 1;

    else

    state_machine = 0; // 状态机复位

    }

    else if(state_machine == 1)

    {

    if(rcvdat == 0xAA) // 接收到帧头第二个数据

    state_machine = 2;

    else

    state_machine = 0; // 状态机复位

    ......

    5. 总结

    以上给出的是通信系统运作的基本雏形,虽然简单,但是可行。实际的通信系统中协议比这个要复杂,而且涉及到数据包响应、命令错误、延时等等一系列的问题,在这样的一个基础上可以克服这些困难并且实现出较为稳定可靠的系统。


关键字:通信程序  通用写法 引用地址:通信程序的通用写法

上一篇:kinetis的UART串口(DMA模式)
下一篇:STC单片机免断电下载程序的更简单的方法

推荐阅读最新更新时间:2024-03-16 15:56

51单片机串口通信Bad Apple视频播放源程序(LCD12864显示)
程序源自我的团队的一个参赛项目,项目文件是一个大工程有很多内容由其他队员编写我也不好直接发上来,所以我只好截取了其中我写的一个小模块放上来供大家分享。 这个程序主要可以实现“任意图片显示”以及“任意视频播放”两个功能,数据都通过串口进行传输(波特率4800,蓝牙或USB均可),当然发送的数据只能是处理好的图像取模数据。(LCD驱动是st7920) 上电后直接显示以下图像: 此时发送53 FF(十六进制发送)即可使用显示单张图片的预设,这时再通过串口发送取模数据就可以实时显示图像。 显示完图片后发送 01 0E即可跳回就绪状态(如果无法退出就定时循环发送01 0E)。 如果在就绪状态下发送53 53就可以进行视频流播放,此
[单片机]
51单片机串口<font color='red'>通信</font>Bad Apple视频播放源<font color='red'>程序</font>(LCD12864显示)
PIC单片机双机异步通信程序详解
1 单片机PIC1编程(发送部分) #include /*该程序实现单片机双机异步通信功能,该程序是发送部分*/ unsigned char tran ; /*定义一个数组存储发送数据*/ unsigned char k,data; /*定义通用寄存器*/ cONST char table ={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0XD8,0x80, 0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x7f,0xbf,0x89,0xff}; /*不带小数点的显示段码表*/ /*SPI显示初始化子程序*/ void SPIINIT() {
[单片机]
STM32 串口通信识别程序
代码现象:从串口发一个数据,串口能够返回相应的值, #include stm32f10x.h #include stm32f10x_gpio.h #include stm32f10x_rcc.h #include stm32f10x_usart.h #include misc.h #include string.h #define RX_BUF_SIZE 80 volatile char RX_FLAG_END_LINE = 0; volatile char RXi; volatile char RXc; char RX_BUF = {''}; //此处我删去了vola
[单片机]
#51单片机# UART串口通信的基本应用、模块介绍和串口程序
UART串口通信的基本应用 通信的三种基本类型: 单工通信:值允许一方向另一方传送星系,另一方不能回传信息。例:电视遥控器、收音机广播 半双工通信:数据可在双方之间相互传播,但同一时刻只能一方传给另一方。例:对讲机 全双工通信:发送数据的同时也可接收数据,两者同步进行。例:电话 UART模块介绍 通常情况下,我们关心的是通信的结果而非过程。51单片机内部存在UART模块,可自动接收数据,接收完毕,会发出通知信号。要使用这个模块,需要配置对应的具有特殊功能的寄存器。 51单片机的UART串口结构由串行口控制寄存器SCON、发送和接收电路三部分构成。 先来了解串口控制寄存器SCON SCON——串行控制寄存
[单片机]
#51单片机# UART串口<font color='red'>通信</font>的基本应用、模块介绍和串口<font color='red'>程序</font>
51单片机与PC串口通信程序及硬件电路图
#include reg51.h #define BUFFERLEGTH 10 //----------------------------------------------------------------- void UART_init(); //串口初始化函数 void COM_send(void); //串口发送函数 char str ; char j; //------------------------------------------------------------------- void main(void) { unsigned char i; UART_init
[单片机]
51单片机与PC串口<font color='red'>通信</font><font color='red'>程序</font>及硬件电路图
AWR帮助Auriga准确地对雷达和通信应用程序进行复杂
AWR帮助Auriga准确地对雷达和通信应用程序进行复杂的和非线性性能的MMIC及模块仿真 EL SEGUNDO, Calif. – 2013年6月12日 内容:AWR, 高频EDA软件行业创新领跑者,发布了一个来自Auriga Microwave的一个新的成功案例,他们是在高性能射频解决方案领域的国际领导者。这个案例详细描述了Auriga公司的设计者如何利用Microwave Office®, Visual System Simulator™ (VSS), 及AXIEM®的精确性、技术能力和一体化来优化非线性电路的电磁(EM)仿真。AWR同时提供给Auriga系统级和电路级分析软件,使设计人员能够计算各种调制波形的相邻信道功
[网络通信]
单片机 RS485 通信接口、控制线、原理图及程序实例
RS232 标准是诞生于 RS485 之前的,但是 RS232 有几处不足的地方: 接口的信号电平值较高,达到十几 V,使用不当容易损坏接口芯片,电平标准也与 TTL 电平不兼容。 传输速率有局限,不可以过高,一般到一两百千比特每秒(Kb/s)就到极限了。 接口使用信号线和 GND 与其它设备形成共地模式的通信,这种共地模式传输容易产生干扰,并且抗干扰性能也比较弱。 传输距离有限,最多只能通信几十米。 通信的时候只能两点之间进行通信,不能够实现多机联网通信。 针对 RS232 接口的不足,就不断出现了一些新的接口标准,RS485 就是其中之一,它具备以下的特点: 采用差分信号。我们在讲 A/D 的时候,讲过差分信号输
[单片机]
单片机 RS485 <font color='red'>通信</font>接口、控制线、原理图及<font color='red'>程序</font>实例
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved