咱们以51单片机为例。51中一般针对串口通讯编程,一般采纳中止承受查询发送的方法。中止函数在承受数据抵达时被重复调用,其实是个重复入栈的进程,所以不宜将函数写的太长,函数太长一般会导致栈太深占用体系资源,二是处理时刻过长,或许导致通讯犯错。为了避免在处理数据进程中不受搅扰,一般在处理承受数据前封闭中止,处理完后再开。
一般的的编程方法如下:
staTIc void UartInterruptService(void) interrupt 4
{
ES = 0;
RI = 0;
uart_process(SBUF);
ES=1;
}
下面要点介绍数据处理函数 uart_process(SBUF);
其实许多时分,关于通讯传输的数据处理才是要害,特别关于规划通讯协议而言。笔者在刚刚做的一个体系上就碰到这样的问题,当体系巨大了,资源非常有限的情况下,数据处理一旦占用资源太多,功率太低将导致体系溃散而无法运转。
到了这儿,许多工程师或许会考虑开个大的缓冲区FIFO将接纳到的数据保存在缓冲区,然后对其进行解析、判别进行下一步程序编写,当然这在体系资源比较丰富的情况下是没有问题的,ARM上采纳的便是这样的方法。但怎么体系巨大呢,留给的资源缺少则不可。这样做的一个很大缺陷有必要是将数据帧接纳完了才能够判别,降低了功率和运转速度。
其实还有别的的方法,能够采纳在每接纳一个字节就对其解析,解析完判别转到下一个状况,并将其间的有用数据存储在相应的数据结构中去,能够采纳状况机完成。
将状况机规划为两个操控状况,一是串口状况——uart_state ,一是指令类型状况——cmd_state 。
(1)状况机开端状况:串口状况为CMD_NO
(2)承受到STX_CMD,状况变为CMD_START.
(3)接下来将主动进入承受指令帧的状况,再敞开指令状况的状况机,对发送来的有用数据进行解析,保存,校验等。处理结束后将uart_state设为CMD_END状况进行下一步的承受结束判别,将cmd_state设置为初始的NO_CMD状况。
(4)最终进行ETX_CMD判别,判别数据接纳是否结束。
void uart_process(U8 u8)
{
if(uart_state == CMD_NO)
{
if(u8 == STX_CMD)
{
uart_state = CMD_START;
}
}
else if(uart_state == CMD_START)
{
switch(cmd_state)
{
case NO_CMD:
cmd_state = u8;
break;
case COST_CMD:
//解析存储有用数据到相应数据结构中
//进行CRC校验
……
uart_state = CMD_END;
cmd_state = NO_CMD;
CRC = 0;
break;
……
}
……
}
else if(uart_state == CMD_END)
{
uart_state = CMD_NO;
if(u8 == ETX_CMD)
{
//承受结束
//能够考虑抛出一个音讯main函数循环中进行呼应处理。
}
}
}
接下来咱们要评论解析后咱们数据存储的问题,其实在资源比较满足的情况下或许能够挤出data区的情况下能够考虑用结构体,咱们结构好相应结构体,将接纳到的数据存储进去,要使用的时分就非常便利。但这也有个对立,一般c51界说的结构体都被存储在data区,一般通讯的字节量大空间必定不行,存在一个对立,能够选用联合体union进行存储作用会好一点。当然也能够在保存数据时选用界说在xdata区(片外)的buffer来存储。这样在必定程序上优化了程序的履行功率,在程序处理当即抛出音讯处理,提高了通讯数据的处理速度。关于一般资源比较丰富的体系,比方ARM上一般采纳的做法是这样的,将数据存在缓冲区,接纳完一帧数据后再转换成相应的数据结构,再进行剖析、校验。
整体来说,这种采纳状况机实时解析串口通讯数据的方法在必定程序提高了程序运转功率,使软件架构明晰明晰,程序可扩展性大,有利于后续开发。