TDxxxV1.0
③处中断程序结束,系统又需要将原来的运行状态还原,然后在④处继续运行主循环程序。一次中断完成。
7.3 中断函数的结构
在了解中断的过程后我们再来看看中断函数应该用一个什么样的结构。由于我们的中断往往涉及我们的计时,同时它还是占用主循环的时间来运行的。那么,要保证主循环的实时性,就要求中断占用的时间越短越好。那么,就要求我们在中断里不能做太多事情!
同时我们可能有几个中断源,我们在系统产生中断的时候就必须去判断是哪个中断源产生的中断。
鉴于以上要求,我们可以对中断程序作这样的安排:
N 是中断1? N Y Y Y 是中断2? N 是中断3? 是中断n? 中断1处理程序 中断2处理程序 中断3处理程序 中断n处理程序 RETI
图7-2 中断处理程序结构图
为了使中断资源不被长时间占用,我们的中断程序内不能运行任何长时间占用系统时间的程序!那么,我们怎么安排中断中的程序呢?其实占用中断资源的任务,我们完全可以安排到中断外去完成!我们只需要告诉主控程序发生了中断以及是哪个中断就可以了!
如:
41
TDxxxV1.0
__interrupt intserv(void) { } if(INTRQ&0x10) { _bCLR(&INTRQ,4); } else if(INTRQ&0x20) { _bCLR(&INTRQ,5); } TC0INT(); T0INT(); void INTround(void) { unsigned int bitValue = 0; if(intStatusWord1.ftc0int) { intStatusWord1.ftc0int = 0; //Add bit which on 10ms interrupt will affect; intStatusWord1.fkeyTimer = 1; intStatusWord1.fflashTimer = 1; } ... Void main(void) { }
…. } … intStatusWord1.ThandDelay = 1; … void TC0INT(void) { } TC0C=0x64; intStatusWord1.ftc0int = 1; INTround(); 图7-3 中断程序与主循环的关联
在上面图中的程序里面,我们看到中断程序只是判断是由哪个中断源引发的中断,然后调用中断处理程序,而中断处理程序只是将中断的状态恢复,然后将相应中断的自定义标志位置1。而主循环设置中断任务安排程序INTround(),由它通过检测相应的中断标志ftc0int去检测中断的发生,并且安排任务,然后在主循环中调用执行它。这样既能及时发现中断产生的请求,并及时处理,又不会过多地占用中断资源。
八、位操作
位是计算机的最基本存储单位,与其相对应的数值表示是二进制。事实上,硬件的所有数据的处理都是通过二进制来处理的,并且SN8系列的单片机的RAM的全部空间都是可位操作的。如此,位操作在我们的单片机程序中的重要性便不言而喻了。
8.1 位的定义
42
TDxxxV1.0
由于对位操作在单片机程序有着举足轻重的地位,所以,有很多类型的单片机C语言提供了bit型变量的定义,如C51。而SN8 C则和ANSI C一样,并没有bit型变量的定义方法。为了更好地标识我们所需要的每一个标志位,方便我们区分并进行操作,增强程序的可读性。我们都会寻求一种办法来对位进行定义,并给我们需要的位赋予一个我们容易理解的名称如keyPress,int10ms等等。
我们在前面已经提到过位域的定义,我们通过struct来定义一个Byte当中的每一个位,如:
Struct bitDefine{
Unsigned bit0:1; Unsigned bit1:1; Unsigned bit2:1; Unsigned bit3:1; Unsigned bit4:1; Unsigned bit5:1; Unsigned bit6:1; Unsigned bit7:1;
};
我们就可以定义一些具体的结构体实例:
Struct bitDefine flag1,flag2,flag3;
然后我们用宏定义的方法将我们需要的位名称赋予相对应的位。如:
#define fkeypress (flag1.bit1) #define fchatfinish (flag1.bit2)
//确认有一个键按下的标志 //按键Debounce完成标志
//有键正在处理的标志
#define fkeyProcessing (flag1.bit3) #define FhandDelay (flag1.bit4) #define FhandDelayRQ (flag1.bit5) #define FreleaseKey (flag1.bit6) #define FfirstAck (flag1.bit7)
//按键释放标志位
//按键第一次确认标志
通过这样的转换,我们就可以在后续的程序中直接用我们自己定义的名称来对每一个定义过的位进行处理了!
上面所说明的处理方法都是对用户自己定义的位进行的操作,其实还有一个重要的存储器部分是系统定义的。这就是芯片的系统寄存器(system register),这也是我们使用最频繁的寄存器。系统已经对需要用到的资源中的寄存器进行了定义,并被赋予了固定的名称,为其编写了固定的操作函数。用户只管拿来用就好了。
8.2 位的运算
对位的操作主要包含以下几种:置位,清除,位与(&),位或(|),位非(~),位异或(^),左移(<<),右移(>>)。
对于自定义的位,对于上面的这些操作举例如下:
Fkeypress = 1;
//置位
43
TDxxxV1.0
Fkeypress = 0;
//清除
而位与(&),位或(|),位异或(^),左移(<<),右移(>>)基本上是基于基本数据类型上的位操作,如:
keyinbuf <<=2;
tempbuf = P0&0x03; keyinbuf |= tempbuf;
keyinbuf = ~keyinbuf;
这些运算目的都是改变或者获得基本数据类型里面的位的值。这就是我们常用的逻辑尺等等东西。这些操作在生成.asm是转换为逻辑运算指令,上面的语句会被转换为:
L209: ;_keyinbuf = _keyinbuf << 2 ;__SelectBANK _keyinbuf
RLCM (_keyinbuf) RLCM (_keyinbuf) MOV A, #0xfc
AND (_keyinbuf), A B0MOV A, 0xd0 AND A, #(0xFF & 3)
__SelectBANK _ee_scale_c_keyscan_LOCAL MOV _ee_scale_c_keyscan_LOCAL+1, A
L210:
L211: ; R3 = _keyinbuf | _ee_scale_c_keyscan_LOCAL+1
__SelectBANK _keyinbuf MOV A, (_keyinbuf+0)
__SelectBANK _ee_scale_c_keyscan_LOCAL OR A, (_ee_scale_c_keyscan_LOCAL+1) B0MOV R3, A
B0MOV A, R3 __SelectBANK _keyinbuf MOV _keyinbuf, A L212:
__SelectBANK (_keyinbuf) MOV A, (_keyinbuf) B0MOV R3, A B0MOV A, R3 XOR A, #0xff B0MOV R3, A B0MOV A, R3
__SelectBANK _keyinbuf MOV _keyinbuf, A
而如果我们操作的对象是系统寄存器中的位,系统给我们提供了专门的位操作函数其原型如下:
44
TDxxxV1.0
void _bSET(unsigned long address, unsigned int bitOffset); void _bCLR(unsigned long address, unsigned int bitOffset); int _bTest0(unsigned long address, unsigned int bitOffset); int _bTest1(unsigned long address, unsigned int bitOffset);
其中传入参数 address 与 bitOffset 必须为常数,不可为变量。 BitOffset 有效值为 0 ~7
address 的高位为 bank number
前面两个是置位和清除函数,专门用于对系统寄存器进行位的置位和清除。 如我们要启动TC0,那么我们就将其TC0ENB(TC0M.bit7)位标志置1:
_bSET(&TC0M,7);
而如果要停止TC0,那么我们就清除其TC0ENB(TC0M.bit7)位标志:
_bCLR(&TC0M,7);
这两个函数也具有很高的转化效率,其转化代码分别为:
PreB0SET 218 7 0 PreB0CLR 218 7 0
后两个是位判断函数,其对给定的位判断为1或者为零,并返回一个int型数值。
8.3 位比较在程序流程控制中的应用
在程序中往往都通过判断一个或几个条件是否成立来控制程序的执行。而条件的成立就会用标志位来标示,这样位的判断比较在程序中就非常重要了!例如下面例子中的判断条件:
if(globalSW.tareRQ) {
//进行零位处理的话,不进行下面的处理
captrueZero(stabledata);
}
上面的判断是对自定义位globalSW.tareRQ进行的判断,若为1则执行函数调用,若为0则跳过函数调用,转而执行下面的语句。产生的汇编码如下:
__SelectBANK _globalSW BTS1 _globalSW.3
JMP L430 L450:
;push arg....
__SelectBANK _stabledata MOV A, _stabledata+1
;Select BANK
__SelectBANK _captrueZero_arg0 MOV (_captrueZero_arg0+1), A __SelectBANK _stabledata MOV A, _stabledata
45
搜索“diyifanwen.net”或“第一范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,第一范文网,提供最新初中教育松翰C语言编程指导C+Program+Guide (9)全文阅读和word下载服务。
相关推荐: