APP下载

单片机通用软件架构在数据采集中的应用*

2015-01-20杨振龙付国家孙天澳

现代矿业 2015年12期
关键词:缓冲区中断命令

杨振龙 张 伟 付国家 孙天澳

(丹东东方测控技术股份有限公司)

单片机通用软件架构在数据采集中的应用*

杨振龙 张 伟 付国家 孙天澳

(丹东东方测控技术股份有限公司)

常规的单片机系统由于灵活性较差、过于复杂,用户使用不方便。基于通用的软件架构设计,用户可实现自行设计、开发单片机系统。介绍了一种单片机软件架构的基本设计思想,阐述了事件的记录与检测、类型与产生方式、处理过程、产生实例、定时器中断服务程序等,并对部分代码进行说明。基于该架构的单片机时序逻辑控制系统具有较高的实时性能,同时降低了程序开发的复杂度,提高了系统健壮性,缩短了程序开发周期,使利用单片机开发复杂的控制系统变得相对简单、轻松。

单片机 软件架构 数据采集

单片机做为一种轻量级的微机系统具有廉价、方便、开发周期短等特点,在实时控制领域具有极其广泛的应用。与PC系统不同,单片机是一种完全开放的硬件系统,没有相对固定的标准外设。根据具体应用的不同,用户需要自主定制系统外设。这在增加系统灵活性的同时也使得各种单片机系统软件结构千差万别,用户必须针对不同的应用重新考虑相应的软件结构,无形中增加了系统开发的难度,加大了开发周期。

近年来,虽然已经开发出一些相对成熟的单片机操作系统,例如Keil公司的RTX51等,但应用范围仍然较小,主要与其灵活性及复杂度有关。这些操作系统大多过于复杂,很多支持多任务等功能,用户需要花费相当多的时间和精力去学习和掌握使用技巧。另外操作系统的灵活性有待提高,用户的编程方式受到了一定程度的限制。

分析认为,单片机系统开发并不需要一套额外的软件系统,而是一个相对灵活、通用的软件框架和程序开发准则。基于该框架和准则,对于任何单片机系统,用户都可以按部就班的进行设计、开发、编程。论文介绍了基于此类目的开发的单片机软件架构,能适用于大多数单片机控制系统。

1 基本设计思想

单片机(如无特殊说明,单片机均指与Intel C51系列单片机兼容的CPU)归根结底就是一款CPU,确切地说是基于冯·诺依曼结构(程序存储执行)的CPU。因此,可以模仿CPU的工作方式来设计的软件架构。

CPU的工作过程可简单的描述如下[1-2]:

(1)CPU按顺序逐条执行程序存储器中的指令。

(2)在两条机器指令之间,CPU执行中断标志的检测。如果检测到中断则跳转到中断服务程序中执行。

(3)中断处理完毕后,CPU跳转到先前被中断的指令处继续执行。

上述过程是CPU最基本的工作过程,略去了有关步骤更深入的细节,因为其对软件架构没有本质影响。

仿照CPU的工作过程,单片机软件框架基本结构应该是这样的(基于C语言描述)[3]。

void main()

{

BYTE data e = 0;∥存储检测到的事件类型;

init(); onEvtRST();∥初始化系统,产生'RST'通知事件;

while ( 1 ) {

if ( getEvt(&e) ){∥检测事件;

processEvt(e); delEvt(e);//处理事件,删除处理完的事件;

}

else{

onIdle();∥无事件需要处理时,执行空闲代码;

}

}

}

其中变量e用于存储getEvt()函数所获取的当前产生的事件类型。这里的“事件”就相当于CPU处理过程中的“中断”。该框架最多支持8类事件,即变量e的每一个二进制位代表了一类事件。为了保证所有产生的事件都被处理而不发生事件丢失现象,getEvt()函数以及事件处理函数processEvt()并不删除任何事件,因此,在事件处理完后要调用delEvt()函数将事件删除。否则相同的事件就会不断地被处理。当没有事件产生时,系统运行一个空闲代码onIdle()去执行一些实时性要求不高的动作。

processEvt()函数用于处理e中记录的事件,且每次仅获取一个事件(如果有的话),即每次检测,变量e中只会有一位被置为1。onEvtRST()是一个“软事件”,相当于CPU处理过程中的“软中断”,其中可以放置一些通知代码,以通知上位机单片机产生了一次复位动作。

总体上,框架用“函数调用”代替了CPU的“机器指令”,用“事件”代替了CPU的“中断”,以完全模仿CPU工作过程的方式构建整个单片机软件执行架构。

2 事件的记录与检测

框架使用全局变量g_evt记录系统产生的全部事件,与代码 1中变量e类型相同,但可以同时记录8个事件。它位于全局存储区,便于各事件产生代码(如中断服务程序)并记录各自产生的事件类型。需要注意的是,同一类型的事件在被处理之前只能被记录一次。如果一类事件从产生到被处理之前又产生了该类事件,将会发生事件丢失现象。出现这种情况说明单片机的处理速度不够,即事件产生的频率过快,应提高单片机的主频。与事件记录(存储)及检测有关的代码如下:

volatile BYTE data g_evt = 0;∥全局变量;

#define MAX_EVT 8

#define isEvtOn(e) (0 != (g_evt&(e)) )

#define addEvt(e) (g_evt |= (e) )

#define delEvt(e) (g_evt &= (~(e)) )

#define clrEvt() (g_evt = 0 )

BOOL getEvt(BYTE *p)

{

BYTE data i;

for (*p =1, i= 0; i< MAX_EVT;++i, (*p) <<= 1){

if ( isEvtOn(*p) ){

return TRUE;

}

}

return FALSE;

}

3 事件的类型及产生方式

单片机系统的事件主要包含以下几种:

(1)命令事件,即收到的上位机命令,由串口中断服务程序产生的事件。该事件需串口中断服务程序应接收到完整的命令后才能产生,因此应设置全局命令缓冲区用于存储接收到的单个字符,同时设置缓冲区指针以指示当前接收到的字符应存放的缓冲区位置。命令缓冲区还用于事件处理函数中判断当前事件是哪个具体的命令产生的。因此,串口中断服务程序中要首先判断程序当前是否正在处理该类事件,即缓冲区当前是否空闲,才能决定是否将收到的字符放入缓冲区中,否则将干扰函数对事件的处理。

(2)外部中断触发事件,由单片机配置的外设硬件触发,由外部中断服务程序注册,由0号定时器中断产生。该类事件不直接在中断服务程序中产生,主要是由于该类事件的产生具有很大的随机性,可能在极短的时间内产生很多个,如果直接在中断服务程序中产生并处理,可能导致单片机无法处理其他事件。同时,该类事件还可能是外设的误动作如按键的抖动等。因此,让定时器以某一固定的时间间隔来检测该类事件比较合适(这有点类似于多任务系统的时间片概念),这样可以抑制该类事件产生的频度,还能达到去抖的目的。

(3)自定义事件,即“软事件”,是由具体应用定义的事件。例如当检测到某一端口电平状态(开关量)时,或当检测到某一模拟量输入时(比如代码 1中的“RST”事件),自定义事件直接由软件在一定条件下通过某种算法产生。

与事件类型及产生有关的代码如下:

enum{//事件类型;

EVT_CMD= 0x01,∥00000001,命令事件;

EVT_EX0= 0x02,∥00000010,外部硬件中断0事件;

EVT_EX1= 0x04,∥00000100,外部硬件中断1事件;

/*

...∥自定义类型事件。

*/

};

volatile BYTE data g_int = 0;∥全局变量;

#define isIntOn(e) (0 != (g_int&(e)) )

#define addInt(e) (g_int |= (e) )

#define delInt(e) (g_int &= (~(e)) )

#define clrInt() (g_int = 0 )

#define chkInt() ( (g_evt |= g_int), clrInt() )

全局变量g_int用于存储当前产生的中断类型,含义与g_evt类似。在外部硬件中断服务程序中调用addInt()向g_int中添加(注册)中断,在0号定时器中断服务程序中调用chkInt()检测产生的中断并同时产生相应的事件,最后清除注册的中断(调用clrInt())。

各类事件均有其特定的产生机制,一般与具体应用有关。命令事件是指上位机发送给下位机的命令。大多数情况下单片机通过串口(UART)与上位机进行通讯,命令事件在串口中断服务程序中产生。这类事件实时性要求较高且不存在误触发及“抖动”问题,可直接在中断服务程序中产生。在此仅给出较有代表性的命令事件的产生过程以供参考,具体代码如下:

#define INT_COM0 4 /*串口中断的中断号*/

#define CMD_SIZE 32 /*命令的最大长度*/

char data g_cmd[CMD_SIZE] = {0};∥命令缓冲区,全局变量;

void isrCOM0 ()interrupt INT_COM0

{

if ( RI0 ){∥处理“读”中断;

static int data pos = 0;∥命令缓冲区指针;

const char data ch = SBUF0;∥读串口;

if ( !isEvtOn(EVT_CMD) ){∥确保程序当前未在处理该类事件;

if ( (pos >= CMD_SIZE)||('?' == ch)||('=' == ch) ){

pos = 0;

}

g_cmd[pos++]= ch;∥将字符存入命令缓冲区;

if ( ';' == ch ){∥';'表示接收到一个有效的命令;

g_cmd[pos]= '/0';∥构造C格式的字符串;

pos = 0;∥复位缓冲区指针;

addEvt(EVT_CMD);∥产生事件;

}

}

RI0 = 0;∥清除硬件中断标志;

}

else{∥处理“写”中断;

TI0 = 0;∥清除硬件中断标志;

}

}

该事件中命令使用ASCII字符进行编码,所有命令均以“?”或“=”开头,以“;”结尾。因此,中断服务程序中,每次检测到“;”字符即可确定当前收到了一个完整的命令,从而产生命令事件。在命令事件处理程序(onEvtCMD())中通过对全局命令缓冲区g_cmd中的内容进行字符串比对即可判断具体的命令类型。

4 事件处理过程

事件处理函数的定价代码如下:

void processEvt(BYTE e)

{

switch ( e ){

case EVT_CMD:onEvtCMD();break;∥命令事件;

case EVT_EX0:onEvtEX0();break;∥外部硬件中断0事件;

case EVT_EX1:onEvtEX1();break;∥外部硬件中断1事件;

/*

…∥自定义类型事件。

*/

default: break;

}

}

其中以“onEvt”开头的函数为对应某一特定事件的处理函数,代码与具体应用有关。

5 定时器中断服务程序

单片机程序应充分利用0号定时器中断将CPU时间进行“分片”,以控制程序的执行步调,避免发生“阻塞”现象,如前面提到的“外部中断事件”的处理频度等问题。

选择0号定时器中断的理由有两个:①几乎所有的C51单片机硬件都默认配置有该定时器硬件;②0号定时器中断的优先级较高,一般不会被其他中断干扰。针对某一特定单片机应用系统,应将定时器中断配置成某一最小定时周期(称其为系统“滴答”周期),例如1微秒或1毫秒等,然后通过在定时器中断内部对中断次数进行计数的方式达到任意定时时长的目的。

对外部中断类事件进行定时检测的定时器中断服务程序某一实例代码如下:

#define INT_T0 1/*0号定时器中断号*/

#define TN_EVENT ((WORD)(0.025*TF) )//25ms

void isrT0 ()interrupt INT_T0

{

static WORD data iEvent= 0;

if ((++iEvent) >= TN_EVENT){

chkInt();

iEvent = 0;

}

}

其TF为定时器中断的产生频率,即每秒中发生中断的次数,即系统“滴答”的频率。对于具体的应用,TF应视实际情况在系统初始化时对定时器进行配置。

6 应用实例

应用该框架,设计并开发了一款数据采集系统,该系统的原理见图1[4]。

图1 某款数据采集系统原理框图

该系统是一个相对复杂的数据采集应用系统,涉及较多的外部信号采集、处理,包括模拟量输入和输出、数字量(开关量,脉冲计数等)输入和输出、硬件触发中断输入、数字通讯等诸多信号输入、输出处理[5],如果不对单片机软件系统进行仔细的设计以选择合理的软件架构,将很难应付错综复杂的程序流程。

7 结 论

基于灵活、通用的软件开发准则的设计该软件架构,使单片机应用系统的开发过程规范化、结构化、流程化,降低开发的复杂程度,使开发人员可以将主要精力集中于系统功能设计方面而不必在软件实现方面花费过多的精力。该架构可在保证功能实现的前提下,大大缩短单片机应用系统的开发周期,系统的稳定性及可靠性也得到了很大的提高。随着工业自动化进程的不断深化,该软件架构将在单片机系统开发领域具有广阔的应用前景。

[1] 王克义,鲁守智,蔡建新.微机原理与接口技术教程[M].北京:北京大学出版社,2004.

[2] Lan McLoughlin.计算机体系结构:嵌入式方法[M].王 沁,齐 悦译.北京:机械工业出版社,2012.

[3] 徐爱钧,徐 阳.Keil C51单片机高级语言应用编程与实践[M].北京:电子工业出版社,2013.

[4] 程国钢,陈跃琴,崔荔蒙.51单片机典型模块开发查询手册[M].北京:电子工业出版社,2012.

[5] 胡晓军.数据采集与分析技术[M].西安:西安电子科技大学出版社,2010.

2015-11-23)

*国家重大科学仪器设备开发专项(2012YQ240121)。

杨振龙(1976—),男,工程师,118000 辽宁省丹东市振兴区滨江中路136号。

猜你喜欢

缓冲区中断命令
只听主人的命令
基于FPGA的中断控制器设计*
Linux中断线程化分析及中断延时测试
基于ARC的闪存数据库缓冲区算法①
移防命令下达后
跟踪导练(二)(5)
千里移防,卫勤保障不中断
一类装配支线缓冲区配置的两阶段求解方法研究
这是人民的命令
初涉缓冲区