论文部分内容阅读
[摘要]首先分析数据通信协议数据包的一般格式,然后采用有限状态机的算法实现单片机与上位机之间的串行通信协议,包含上下位机的数据发送接受和协议的解析实现,并给出具体的实现方法。
[关键词]51单片机串口通信协议上位机下位机
中图分类号:TN91文献标识码:A文章编号:1671-7597(2009)0710022-01
一、引言
数据协议是建立在物理层之上的通信数据包格式。所谓通信的物理层就是指我们通常所用到的RS232、RS485、红外、光纤、无线等等通信方式。在这个层面上,底层软件提供两个基本的操作函数:发送一个字节数据、接收一个字节数据。所有的数据协议全部建立在这两个操作方法之上。通信中的数据往往以数据包的形式进行传送的,我们把这样的一个数据包称作为一帧数据。类似于网络通信中的TCP/IP协议一般,比较可靠的通信协议往往包含有以下几个组成部分:帧头、地址信息、数据类型、数据长度、数据块、校验码、帧尾[1][2]。现在大部分的仪器设备都要求能过通过上位机软件来操作,这样方便调试,利于操作。其中就涉及到通信的过程,本文给出了串行通信协议的具体实现,总结出了通信程序的通用写法,包括上位机端和下位机端等。
二、上位机和下位机中的数据发送
物理通信层中提供了两个基本的操作函数,发送一个字节数据则为数据发送的基础。数据包的发送即把数据包中的左右字节按照顺序一个一个的发送[3]。在单片机系统中,比较常用的方法是直接调用串口发送单个字节数据的函数。另外一种方法是采用中断发送的方式,所有需要发送的数据被送入一个缓冲区,利用发送中断将缓冲区中的数据发送出去[4]。对于51系列单片机,比较倾向于采用直接发送的方式,采用中断发送的方式比较占用RAM资源,而且对比直接发送来说也没有太多的优点。以下是51系列单片机中发送单个字节的函数[5]。
void SendByte(unsigned char ch){
SBUF = ch;
while(TI ==0);TI = 0;
}
上位机中关于串口通信的方式也有多种,这种方式不是指数据有没有缓冲的问题,而是操作串口的方式不同,因为PC上数据发送基本上都会被缓冲后再发送。对于编程来说操作串口有三种方式:1.使用windows系统中自带的串口通信控件,这种方式使用起来比较简单,需要注意的是接收时的阻塞处理和线程机制。2.使用系统的API直接进行串口数据的读取,在windows和linux系统中,设备被虚拟为文件,只需要利用系统提供的API函数即可进行串口数据的发送和读取。3.使用串口类进行串口操作。在此只介绍windows环境下利用串口类编程的方式。CSerialPort是比较好用的串口类。它提供如下的串口操作方法:
void WriteToPort(char* string, int len);
串口初始化成功后,调用此函数即可向串口发送数据。为了避免串口缓冲所带来的延时,可以开启串口的冲刷机制。
三、下位机中的数据接收和协议解析
下位机接收数据也有两种方式:1.等待接收,处理器一直查询串口状态,来判断是否接收到数据。2.中断接收。如果协议比较简单,整个系统只是处理一些简单的命令,那么可以直接把数据包的解析过程放入到中断处理函数中,当收到正确的数据包的时候,置位相应的标志,在主程序中再对命令进行处理[6]。以下给出具体的实例。在这个系统中,串口的命令非常简单。所有的协议全部在串口中断中进行。数据包的格式如下:
0x55, 0xAA, 0x7E, 0x12, 0xF0, 0x02, 0x23, 0x45, SUM, XOR, 0x0D
其中0x55,0xAA,0x7E为数据帧的帧头,0x0D为帧尾,0x12为设备的目的地址,0xF0为源地址,0x02为数据长度,后面接着两个数据0x23,0x45,从目的地址开始结算累加、异或校验和,到数据的最后一位结束。协议解析的目的,首先判断数据包的完整性,正确性,然后提取数据类型,数据等数据,存放起来用于主程序处理。
此过程中,使用了一个变量state_machine作为有限协议状态机的转换状态,用于确定当前字节处于一帧数据中的那个部位,同时在接收过程中自动对接收数据进行校验和处理,在数据包接收完的同时也进行了校验的比较。因此当帧尾结束符接收到的时候,则表示一帧数据已经接收完毕,并且通过了校验,关键数据也保存到了缓冲去中。主程序即可通过retval的标志位来进行协议的解析处理。接收过程中,只要哪一步收到的数据不是预期值,则直接将状态机复位,用于下一帧数据的判断,因此系统出现状态死锁的情况非常少,系统比较稳定,如果出现丢失数据包的情况也可由上位机进行命令的补发。对于主程序中进行协议处理的过程与此类似,主程序循环中不断的读取串口缓冲区的数据,此数据即参与到主循环中的协议处理过程中。
四、上位机中的数据接收和命令处理
上位机中数据接收的过程与下位机可以做到完全一致,不过针对不同的串口操作方法有所不同。对于阻塞式的串口读函数,例如直接进行API操作或者调用windows的串口通信控件,最好能够开启一个线程专门用于监视串口的数据接收,每接收到一个数据可以向系统发送一个消息。CSerialPo
Rt打开串口后开启线程监视串口的数据接收,将接收的数据保存到缓冲区,并向父进程发送接收数据的消息,数据将随消息一起发送到父进程。父进程中开启此消息的处理函数,从中获取串口数据后就可以进行数据接收和命令处理。
五、总结
本文给出的是串口通信系统的基本雏形,虽然简单,但是可行。实际的通信系统中协议比这个要复杂,而且涉及到数据包响应、命令错误、延时等等一系列的问题,在这样的一个基础上可以克服这些困难并且实现出较为稳定可靠的系统。在实际系统中,问题会出现在任何地方,有些特别的问题需要特别的方法才能解决。如何实现一个强壮的通信系统还需要继续深入的研究。
参考文献:
[1]J.Satran,"Internet Protocol Small Computer System Interface (iSCSI) Cyclic Redundancy.Check (CRC)/Checksum Considerations",RFC 3385,2002.
[2]ITU-T V.41,"Code-independent error-control system",1989.
[3]郭梯云,数据传输(修订本)[M].人民邮电出版社,1998.
[4]顾上杰、薛质,计算机通信网基础[M].电子工业出版,2005.7.
[5]丁元杰,单片微机原理及应用[M].机械工业出版社,2003.7.
[6]冯博鉴,计算机原理与接口应用技术[M].清华大学出版社,2004.8.
[关键词]51单片机串口通信协议上位机下位机
中图分类号:TN91文献标识码:A文章编号:1671-7597(2009)0710022-01
一、引言
数据协议是建立在物理层之上的通信数据包格式。所谓通信的物理层就是指我们通常所用到的RS232、RS485、红外、光纤、无线等等通信方式。在这个层面上,底层软件提供两个基本的操作函数:发送一个字节数据、接收一个字节数据。所有的数据协议全部建立在这两个操作方法之上。通信中的数据往往以数据包的形式进行传送的,我们把这样的一个数据包称作为一帧数据。类似于网络通信中的TCP/IP协议一般,比较可靠的通信协议往往包含有以下几个组成部分:帧头、地址信息、数据类型、数据长度、数据块、校验码、帧尾[1][2]。现在大部分的仪器设备都要求能过通过上位机软件来操作,这样方便调试,利于操作。其中就涉及到通信的过程,本文给出了串行通信协议的具体实现,总结出了通信程序的通用写法,包括上位机端和下位机端等。
二、上位机和下位机中的数据发送
物理通信层中提供了两个基本的操作函数,发送一个字节数据则为数据发送的基础。数据包的发送即把数据包中的左右字节按照顺序一个一个的发送[3]。在单片机系统中,比较常用的方法是直接调用串口发送单个字节数据的函数。另外一种方法是采用中断发送的方式,所有需要发送的数据被送入一个缓冲区,利用发送中断将缓冲区中的数据发送出去[4]。对于51系列单片机,比较倾向于采用直接发送的方式,采用中断发送的方式比较占用RAM资源,而且对比直接发送来说也没有太多的优点。以下是51系列单片机中发送单个字节的函数[5]。
void SendByte(unsigned char ch){
SBUF = ch;
while(TI ==0);TI = 0;
}
上位机中关于串口通信的方式也有多种,这种方式不是指数据有没有缓冲的问题,而是操作串口的方式不同,因为PC上数据发送基本上都会被缓冲后再发送。对于编程来说操作串口有三种方式:1.使用windows系统中自带的串口通信控件,这种方式使用起来比较简单,需要注意的是接收时的阻塞处理和线程机制。2.使用系统的API直接进行串口数据的读取,在windows和linux系统中,设备被虚拟为文件,只需要利用系统提供的API函数即可进行串口数据的发送和读取。3.使用串口类进行串口操作。在此只介绍windows环境下利用串口类编程的方式。CSerialPort是比较好用的串口类。它提供如下的串口操作方法:
void WriteToPort(char* string, int len);
串口初始化成功后,调用此函数即可向串口发送数据。为了避免串口缓冲所带来的延时,可以开启串口的冲刷机制。
三、下位机中的数据接收和协议解析
下位机接收数据也有两种方式:1.等待接收,处理器一直查询串口状态,来判断是否接收到数据。2.中断接收。如果协议比较简单,整个系统只是处理一些简单的命令,那么可以直接把数据包的解析过程放入到中断处理函数中,当收到正确的数据包的时候,置位相应的标志,在主程序中再对命令进行处理[6]。以下给出具体的实例。在这个系统中,串口的命令非常简单。所有的协议全部在串口中断中进行。数据包的格式如下:
0x55, 0xAA, 0x7E, 0x12, 0xF0, 0x02, 0x23, 0x45, SUM, XOR, 0x0D
其中0x55,0xAA,0x7E为数据帧的帧头,0x0D为帧尾,0x12为设备的目的地址,0xF0为源地址,0x02为数据长度,后面接着两个数据0x23,0x45,从目的地址开始结算累加、异或校验和,到数据的最后一位结束。协议解析的目的,首先判断数据包的完整性,正确性,然后提取数据类型,数据等数据,存放起来用于主程序处理。
此过程中,使用了一个变量state_machine作为有限协议状态机的转换状态,用于确定当前字节处于一帧数据中的那个部位,同时在接收过程中自动对接收数据进行校验和处理,在数据包接收完的同时也进行了校验的比较。因此当帧尾结束符接收到的时候,则表示一帧数据已经接收完毕,并且通过了校验,关键数据也保存到了缓冲去中。主程序即可通过retval的标志位来进行协议的解析处理。接收过程中,只要哪一步收到的数据不是预期值,则直接将状态机复位,用于下一帧数据的判断,因此系统出现状态死锁的情况非常少,系统比较稳定,如果出现丢失数据包的情况也可由上位机进行命令的补发。对于主程序中进行协议处理的过程与此类似,主程序循环中不断的读取串口缓冲区的数据,此数据即参与到主循环中的协议处理过程中。
四、上位机中的数据接收和命令处理
上位机中数据接收的过程与下位机可以做到完全一致,不过针对不同的串口操作方法有所不同。对于阻塞式的串口读函数,例如直接进行API操作或者调用windows的串口通信控件,最好能够开启一个线程专门用于监视串口的数据接收,每接收到一个数据可以向系统发送一个消息。CSerialPo
Rt打开串口后开启线程监视串口的数据接收,将接收的数据保存到缓冲区,并向父进程发送接收数据的消息,数据将随消息一起发送到父进程。父进程中开启此消息的处理函数,从中获取串口数据后就可以进行数据接收和命令处理。
五、总结
本文给出的是串口通信系统的基本雏形,虽然简单,但是可行。实际的通信系统中协议比这个要复杂,而且涉及到数据包响应、命令错误、延时等等一系列的问题,在这样的一个基础上可以克服这些困难并且实现出较为稳定可靠的系统。在实际系统中,问题会出现在任何地方,有些特别的问题需要特别的方法才能解决。如何实现一个强壮的通信系统还需要继续深入的研究。
参考文献:
[1]J.Satran,"Internet Protocol Small Computer System Interface (iSCSI) Cyclic Redundancy.Check (CRC)/Checksum Considerations",RFC 3385,2002.
[2]ITU-T V.41,"Code-independent error-control system",1989.
[3]郭梯云,数据传输(修订本)[M].人民邮电出版社,1998.
[4]顾上杰、薛质,计算机通信网基础[M].电子工业出版,2005.7.
[5]丁元杰,单片微机原理及应用[M].机械工业出版社,2003.7.
[6]冯博鉴,计算机原理与接口应用技术[M].清华大学出版社,2004.8.