星期二, 四月 14, 2009

译言——发现、阅读、翻译中文之外的互联网精华

阅微堂的文章链接发现了很好的外文资讯网站, 译言. 它的网站logo如是介绍:
译言——发现、阅读、翻译中文之外的互联网精华其中, 政治、科技、经济、娱乐等等资讯丰富, 来源皆出自各大外文网络或流行纸媒, 值得推荐.
译言还提供难得的全文RSS, 可以很方便的在自己的RSS阅读器(比如Google Reader)中浏览相关文章.
以下是其中的一篇佳作(《十亿消费者》)的节选, 全文请到这里阅读.

标题:
十亿消费者
评语:
译言上最精彩的一部作品。丰富的内容,流畅的翻译,一切都近乎完美。是每个Yeeyaner的必读。
十亿消费者——来自中国商界第一线的经验
作者:James McGregor 翻译:白痴年代
前言
这原本是从北京飞往沿海城市福州的一次常规飞行。航空公司是一家新成立的国有公司,飞机也是新进口的。但乘务组兴奋有余、专业不足,让我觉得这次飞行一点儿也不常规。服务员们在前排嘻笑打闹,急急忙忙地收拢要带回家的大包小包,里面都是多出来的航空餐当中最好的东西。驾驶员舱门在整个飞行期间一直都开着。飞行师会走出来在前排打个小盹。

终于要降落了。脚下郁郁葱葱的绿色大地和星罗密布的农舍和猪圈,离我们越来越近。飞机开始转向,对准正在迅速接近的跑道,两名空乘站在正副飞行员的身后,准备如同冲浪一般把飞机降落到跑道上。突然,当我们距离布满了橡胶轮胎擦痕的跑道不足50英尺的时候,飞行员猛地一把把操纵杆推了上去。引擎尖叫起来,飞机急速爬升。有意思的是,两名空乘都没有载跟头,但她们都踉踉跄跄的回到了座位上,一脸惊恐。飞机升上去,盘旋,再次对准跑道。这次我听到了起落架放下时发出的独特的吱吱声,并感到轮子阻挡气流时的震动。而前一次降落时,我根本没有注意到这些。这就是我们突然掉头的原因了。
当我进入航站楼的时候,我在想选择坐火车的人可太明智了。这时我看到墙上的宣传海报,从那一刻起,那幅海报就深深的印刻在我的脑海中,它是对中国正在经历的变革的最好阐述,海报上写道:努力实现正常飞行。这正是中国一切努力的重点所在:成为一个正常国家,融入到世界经济中,其国民可以尽情享受他们的财富和快乐,而不必再受政治权力斗争之苦。就像我们的新手空乘们一样,中国在过去的25年中,经历了反复的挫折和腾飞,通过不断的尝试和犯错的改革历程,到目前为止,大部分的降落还算顺利。
任何一个西方人都不能忽视中国在全球经济中不断增长的地位。这个国家要养活13亿人口,其消费市场的潜力将超过北美和西欧加在一起的规模。按照购买力平价计算,中国现在的人均GDP为5000美元,而且每年还在不断提高。它已经超过英国成为世界第四大经济实体。中国消耗了全球25%的铁、30%的水泥,还是全球最大的电子用品市场。外国公司纷至沓来,亦卖亦买。每天签订的外国对华投资平均金额为4.2亿美元。
从1978年起,邓小平总理开始了一系列的经济改革,包括利用外国公司和他们的资金、技术和管理能力。今天,中国已经成为制造业大国,它拥有技术复杂的制造工厂,还拥有精力充沛的、聪明的低成本劳动力。但是中国仅允许外国人按照它的条件进来,而这些条件又往往晦涩难懂、相互矛盾、令人困惑。在太多的情况下,法律只有在对中国有利的时候才成为法律。谈判无穷无尽,而最终达成的协议可以立刻就被摈弃。腐败经常成为加快经济车轮的润滑油。在中国,商业往往是在重重帷幕之后、种种密谋之中的交易,至今未变。外国公司自然会担心其中国合作伙伴、客户或供应商会窃取他们的技术、商业机密或直接就从他们口袋里偷钱。共产党领导人和美国以及其它民主国家之间不稳定的关系使得政治成为商业计划中不可分割的一部分。中国于2001年加入世界贸易组织,政府希望将国内公司转变为全球领先企业,每天都有更多的国际化运作方式被引进中国。但是我依然看到,众多的西方管理者充满信心、飘飘然地来到中国,结果却被他们的中国竞争对手、中国政府或中国合作伙伴碾倒,要么就是陷入不切实际的预期、急躁和缺乏常识中去。中国的商界变革越多,它就越保持不变。作为一名记者,我游历了整个国家,能够坐在前排亲眼看到这一历史大剧的上演。作为一名商人,我曾参与多次权力游戏、复杂谈判和政治阴谋,它们都是这个国家商业中的惯例。
本书是想向诸位展示 ——而非阐述——在中国经商是怎么一回事。这里没有简单的公式或魔法咒语。只有通过展示那些异常复杂的细节:交易如何达成或破裂;人们如何看待、对待彼此;政治和偏见如何影响预期和结果,我才能够让你了解那些微妙之处,而正是这些微妙之处才使得中国给外国老板们既带来挫折也带来回报。每一章的开始都有简单的人物和背景介绍。接下来在总体概要部分,我将人物和背景放置到适当的场景中。然后整个故事通过平铺直叙展开。最后一部分标题为“这对你意味着什么”,我将解释这一章中发生的事情将如何影响你在中国的经商之路。最后,我希望通过简洁的语言,模仿毛泽东红宝书的形式来总结我自己的一些心得。
咬文嚼字的人可能会挑书名的毛病:中国现在的人口是13亿。但重要的是“十亿”这个数量级,它代表着广袤而尚未开发的大片市场,无数等待着加入消费洪流的中国人,先行者对赚个盆满钵满的梦想,以及数个世纪以来烙印在外国商人和贸易者脑海中的遍地黄金的宣传和希望。我还希望借此书名向另一位亦是从新闻记者转变成商人的美国同行表示敬意,他就是在上海居住了26年的Carl Crow,Crow在1937年写了《四万万消费者》(400 Million Customers)一书,记叙了关于中国人和在中国作生意的精彩故事和深刻见解,书中的很多内容到今天都是正确的。Crow对中国发自内心深处地尊敬和赞赏,如他所道:“有趣的、恼人的、费解的,以及总是那么可爱的中国人”。我亦有同感。我写本书的目的,也是希望能够和Crow一样,让读者了解那些跨越时间的对在中国做生意的见解和常识,中国人骨子里的思考和行为模式。书中包括了来自学术界的观点、第一手的经验、生动的叙述,以及轻松的幽默,力图将读者真正带入到中国的商业界中去。
祝您旅途愉快。
James McGregor
2005年于北京


阅读全文...

星期日, 四月 12, 2009

《电气传动系统软件设计》之五

4.2.3 中断处理(二)

4.2.3.5 ASM语言编写中断服务程序
用ASM语言编写中断服务程序时, 应确保中断服务程序的标号与中断向量表(或子中断向量表)中的名称对应. 下面以一个具体的汇编语言例子说明中断程序的处理. 本程序完成如下的操作: 当定时器1发生上溢、下溢和比较事件时采用中断方式分别翻转IOPB0、IOPB1和IOPB2引脚的状态.
; file: main.asm
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.include “240xA.h” ;变量和寄存器的定义
.include “vector.h" ;中断向量表的定义

KICK_DOG .macro ;看门狗复位宏
LDP #00E0H
SPLK #05555H,WDKEY
SPLK #0AAAAH,WDKEY
LDP #0
.endm

USE_PVECTOR .set 1 ;中断是否采用外设向量表

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.text ;主程序
_c_int0 LDP #0
SETC INTM ;关总中断
CLRC CNF ;B0配置为数据空间,
SPLK #0000H,IMR ;禁止所有中断
LACC IFR
SACL IFR ;清除所有中断标志
LDP #WDKEY>>7
SPLK #0004H,SCSR1 ;PLL四倍频, 允许EVA时钟
SPLK #006FH,WDCR ;禁止看门狗
KICK_DOG ;清看门狗
MAR *,AR7
LAR AR7,#7FH
LDP #0E1H
SPLK #0000000000000000B,MCRA
SPLK #1111111100000000B,PBDATDIR
;设置IOPB0~2为输出引脚
LDP #GPTCONA>>7
SPLK #0000000000000000B,GPTCONA
SPLK #0000000000000000B,T1CNT
SPLK #0000111101000010B,T1CON
;连续加/减计数, 128分频
;内部时钟, 计数器为0装载CMPR
;允许比较, 采用自己的周期寄存器
SPLK #1111111111111111B,T1PR
SPLK #0111111111111111B,T1CMPR
SPLK #0000011100000000B,EVAIMRA
;允许上溢、下溢和比较中断
SPLK #0000011100000000B,EVAIFRA
;清除外设中断标志
LDP #0
SPLK #0000000000000010B,IMR ;允许INT2中断
CLRC INTM ;允许所有中断
WAIT NOP ;循环等待中断
NOP
B WAIT
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GISR2 ;中断服务程序

MAR *,AR7 ;保护现场
SST #1,*-
SST #0,*-
SACH *-
SACL *
.if USE_PVECTOR ;如果采用外设向量表
LDP #PIVR>>7
LACC PIVR,1
ADD #PVECTORS
BACC
.else ;如果不采用外设向量表
LDP #PIVR>>7
LACL PIVR
XOR #002AH
BCND SISR2A,EQ ;T1上溢
LACL PIVR
XOR #0029H
BCND SISR29,EQ ;T1下溢
LACL PIVR
XOR #0028H
BCND SISR28,EQ ;T1比较
.endif ;结束条件编译
MAR *,AR7 ;恢复现场
LACL *+
ADD *+,16
LST #0,*+
LST #1,*
CLRC INTM
RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SISR2A ;T1上溢中断服务程序
LDP #0E1H
LACC PBDATDIR
XOR #00001H
SACL PBDATDIR ;翻转IOPB0引脚的状态
LDP #GPTCONA>>7
LACC #0400H
SACL EVAIFRA ;清除T1上溢中断标志位
MAR *,AR7 ;恢复现场
LACL *+
ADD *+,16
LST #0,*+
LST #1,*
CLRC INTM ;允许所有中断
RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SISR29 ;T1下溢中断服务程序
LDP #0E1H
LACC PBDATDIR
XOR #00002H
SACL PBDATDIR ;改变IOPB1引脚的状态
LDP #GPTCONA>>7
LACC #0200H
SACL EVAIFRA ;清除T1下溢中断标志位
MAR *,AR7 ;恢复现场
LACL *+
ADD *+,16
LST #0,*+
LST #1,*
CLRC INTM ;允许所有中断
RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SISR28 ;T1比较中断服务程序
LDP #0E1H
LACC PBDATDIR
XOR #00004H
SACL PBDATDIR ;改变IOPB2引脚的状态
LDP #GPTCONA>>7
LACC #0100H
SACL EVAIFRA ;清除T1比较中断标志位
MAR *,AR7 ;恢复现场
LACL *+
ADD *+,16
LST #0,*+
LST #1,*
CLRC INTM ;允许所有中断
RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GISR1 ;未使用的中断直接返回
GISR3
GISR4
GISR5
GISR6
RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PHANTOM ;假中断中清看门狗后返回
KICK_DOG ;复位WD
RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.end
在该程序中T1周期寄存器T1PR设定为0FFFFH, T1比较寄存器T1CMPR设定为7FFFH, T1计数器T1CNT设定为加/减计数. 当T1CNT=7FFFH时产生比较中断, 进入比较中断服务程序SISR28, 在中断服务程序中IOPB2的引脚状态被改变, 从“0”变为“1”或从“1”变为“0”; 当T1CNT=0H时产生下溢中断, 进入下溢中断服务程序SISR29, 在中断服务程序中IOPB1的引脚状态被改变; 当T1CNT=0FFFFH时产生上溢中断, 进入上溢中断服务程序SISR2A, 在中断服务程序中IOPB0的引脚状态被改变.
CPU一旦接收到INT2的中断请求, CPU先在主中断向量表中找到INT2的中断向量入口GISR2. 在GISR2中进入一个特定的中断服务程序SISR, 可采用外设中断向量表, 也可以不采用外设中断向量表. 如果采用外设中断向量表, 外设中断向量表的建立稍显麻烦, 但程序实现比较简单, 只需读取外设向量寄存器PIVR, 加上外设向量表起始地址, 通过查外设向量表就可以转移到一个特定的外设中断服务程序SISR; 如果不采用外设中断向量表, 就不需要建立外设向量表, 在GISR2中通过PIVR的值来判断产生中断请求的外设事件, 从而转移到相应的外设中断服务程序SISR. 程序中通过条件编译伪指令来选择在是否采用外设向量表来实现中断.
在中断服务程序中除了中断事件的处理之外, 还包括中断现场的保护和恢复. 在这里中断现场主要包括累加器和两个状态寄存器, 在实际应用中可根据具体的需要来设定中断现场. 中断现场的保护在GISR中, 每个SISR中都有中断现场的恢复. 这是因为一个完整的中断服务程序是从GISR进入, 然后从其中一个SISR返回. 特别要注意在返回之前一定要清除被响应的外设中断标志位, 并且将INTM清“0”, 否则即使有中断请求, CPU也不会响应该中断请求. CPU的中断标志位IFR不需要中断服务程序处理, 在每次响应中断时, CPU会自动清除该标志位.
在这里, 假中断服务程序PHANTOM只是复位看门狗, 然后返回. 假中断用来保持中断系统的完整性, 以避免中断系统出现故障后程序运行紊乱.
4.1.1.6 C语言编写中断服务程序
用C语言编写中断服务程序时, 也应确保中断服务程序的函数名与中断向量表(或子中断向量表)中的名称对应. 汇编语言中若用到C语言中使用的名称(变量名、函数名等), 需要将该名称增加"_"(下划线)作为前缀, 例如C中有变量x, 汇编中应该使用_x来调用它[11].
TI文档中介绍了如下两种方式对中断服务函数进行定义[11].
1) 采用默认中断函数名c_intd
任何一个函数若名称为c_intd, d代表数字0~9, 它就默认是中断服务程序. 其中c_int0保留为系统重启中断服务程序, 不可作为其它函数使用. 例如:
void c_int1( )
{

}
2) 采用中断关键字interrupt
interrupt void gisr2( )
{

} // interrupt关键字在void之前或之后都是正确的

应注意, 当进入C语言中断服务程序后, 默认是关总中断状态, 即寄存器状态INTM=1. 如果用户希望实现中断嵌套, 应在C语言中断服务程序中重新打开中断, 即执行INTM=0的操作.
应注意, 任何C中断服务程序都必须定义为void无参数型, 并且还应注意编译器设置条件中不能选择"oe"选项, 如图4 2所示, 也就是保持中断指针的编译操作.

图4 2 关于中断的编译优化选项
下面以一个具体的C语言例子说明中断程序的处理, 它完成和上一节中ASM中断服务程序相同的操作.
// file: main.c
/*****************************************************************************/
void main
{
asm(" setc INTM "); //关总中断
asm(" clrc CNF "); //B0被配置为数据存储空间
*IMR = 0x0000; //禁止所有中断
*IFR = 0xffff; //清除所有中断标志
*SCSR1 = 0x0004; //PLL四倍频, 允许EVA时钟
*WDCR = 0x006f; //禁止看门狗
*WDKEY = 0x5555;
*WDKEY = 0xaaaa; //清看门狗

*MCRA = 0x0000;
*PBDATDIR = 0xff00; //设置IOPB0~2为输出引脚

*GPTCONA = 0x0000;
*T1CNT = 0x0000;
*T1CON = 0x0f42; //连续加/减计数,128分频,内部时钟,下溢装载CMPR,允许比较
*T1PR = 0x0ffff;
*T1CMPR = 0xefff;

*EVAIMARA = 0x0700; //允许上溢、下溢和比较中断
*EVAIFARA = 0x0700; //清除外设中断标志
*IMR = 0x0002; //允许INT2中断
asm(" clrc INTM "); //允许所有中断

for(; ;); //循环等待中断
}

// file: intfuns.h
/*****************************************************************************/
#define SISR2A 0x002A //T1上溢中断
#define SISR29 0x0029 //T1下溢中断
#define SISR28 0x0028 //T1比较中断

// file: intfuns.c
/*****************************************************************************/
interrupt void gisr2( ) //中断服务程序
{ //在vector.asm中应该用_gisr2引用该函数
int ipivr;

ipivr = *PIVR;
switch (ipivr ){
case SISR2A: //T1上溢中断
*PBDATDIR ^= 0x0001; //翻转IOPB0引脚的状态
*EVAIFRA = 0x0400; //清除T1上溢中断标志位
break;
case SISR29: //T1下溢中断
*PBDATDIR ^= 0x0002; //翻转IOPB1引脚的状态
*EVAIFRA = 0x0200; //清除T1下溢中断标志位
break;
case SISR28: //T1比较中断
*PBDATDIR ^= 0x0004; //翻转IOPB2引脚的状态
*EVAIFRA = 0x0100; //清除T1比较中断标志位
break;
default:
break;
}
}
interrupt void phantom( ) //假中断服务程序
{ //在vector.asm中应该用_phantom引用该函数
*WDKEY = 0x5555;
*WDKEY = 0xaaaa; //清看门狗
}

阅读全文...

《电气传动系统软件设计》之四

4.3.2 中断处理(一)

4.3.2.1 中断响应机制
DSP中断机制的基本流程可以分为三步, 如下图所示. 一, 中断事件的产生和判断, 当判断为合法的中断事件时会将程序指针PC跳转到中断向量表的相应位置, 这都是由硬件自动完成的; 二, 按照中断向量表定义跳转到中断主服务程序, 实际上中断向量表中就是一条条的跳转(到中断主服务程序的)指令; 三, 执行中断服务程序, 用户将该中断中要处理的任务都放在中断服务程序中完成.


图4‑1 中断机制基本流程

一个外设中断能被CPU响应的话, 从CPU来看, 必须满足三个条件,
◆ 总中断屏蔽位INTM为“0”;
◆ 对应的CPU中断屏蔽位被使能;
◆ 对应的CPU中断标志位为“1”.
CPU中断标志置“1”是由外设扩展模块来处理的, 当外设事件发生时并且该外设事件所对应的中断屏蔽位被使能, 这时就由外设扩展模块将CPU中断标志寄存器中对应位置“1”.

CPU响应外设中断的过程如下: 当外设中断事件发生时, 外设中断标志器中的中断标志位置“1”, 如果外设的中断使能位为“1”, 外设向外设中断扩展模块发出外设中断请求, 外设中断请求位被置“1”, 且向CPU中断发出中断请求. CPU接受中断请求, 相应的中断标志寄存器对应位置“1”, 如果对应的中断屏蔽位被使能, 而且总的中断允许位INTM被清“0”, CPU辨认是哪一个中断并产生中断应答, 此时CPU的中断标志寄存器被清“0”, INTM被置“1”, 即禁止所有中断, 程序计数器指针跳到该所指向的向量地址0000H~0000CH. CPU根据该地址转移到通用中断服务子程序GISR. 在GISR中首先进行现场保护, 然后从外设中断向量寄存器PIVR中读取外设中断向量. 判断外设中断向量是否为假向量, 如果是假向量, 就进入假向量中断服务程序, 如果不是, 就进入外设事件所对应的特定中断服务程序SISR. 在SISR中完成中断服务程序后不要忘记清除外设寄存器中的中断标志位, 清除总的中断允许位, 以及恢复现场.
从中断的响应过程可以看出, 中断服务程序与中断的两级硬件管理结构是对应的, 中断服务程序也分为两级管理: 通用中断服务子程序GISR和特定中断服务程序SISR. GISR除了进行现场保护, 它的主要任务是从外设中断向量寄存器PIVR产生转移到SISR的入口地址. 程序一旦进入中断服务程序, 所有的可屏蔽中断都被屏蔽. 为了防止中断向量寄存器的内容丢失, 必须在中断重新使能之前读取PIVR的内容.


4.3.2.2 假中断
当一个中断被响应, 但没有外设将中断向量地址偏移量装入外设中断向量寄存器PIVR中, 为了保持中断系统的完整性, 0000H被装入PIVR, 这个中断称为假中断. 假中断产生的原因有两个:
◆ CPU执行一个软件中断指令INTR, 使用的参数为1~6;
◆ 外设发出了中断请求, 但其所对应的CPU的标志位在CPU应答之前已被清“0”.
这样CPU不知道装入哪一个外设中断向量地址偏移量到PIVR, 此时假中断向量就装入PIVR.


4.3.2.3 中断寄存器
CPU中断寄存器包括:
◆ 中断标志寄存器IFR;
◆ 中断屏蔽寄存器IMR.
中断标志寄存器用于识别和清除登记的中断. 读取IFR可以识别登记的中断而写IFR则将清除已登记的中断. 清除一个中断请求, 要向相应的IFR位写“1”, 而不是写“0”. IMR包括所有可屏蔽中断(INT1~INT6)的屏蔽位. 为了使能某中断, 应设置相应的IMR位为“1”, 而屏蔽某中断时只需将相应的位设为“0”.
外设中断寄存器包括:
◆ 外设中断向量寄存器PIVR;
◆ 外设中断请求寄存器PIRQR0/ PIRQR1/ PIRQR2;
◆ 外设中断响应寄存器PIACKR0/ PIACKR1/ PIACKR2. PIVR包含了最近一次被响应的外设中断的地址向量;
PIRQR0/ PIRQR1/ PIRQR2和PIACKR0/ PIACKR1/ PIACKR2都属于外设中断用来向CPU产生INT1~INT6中断请求的内部寄存器. 这些寄存器用于测试目的, 而非用户应用目的, 因此在编程中可以忽略.


4.3.2.4 中断程序构成
中断机制的实现应包含如下三个组成部分.
1) 中断数据段分配
由于DSP在响应一个中断事件后, 总会自动跳转到固定的程序存储器单元读取中断服务程序入口地址(如LF2407A的复位中断向量是在0x0000单元), 因此, 要想让DSP正确的找到相应的中断服务程序入口地址, 必须首先完成中断数据段分配的工作. 对于ASM语言工程或是C语言工程, 中断数据段的分配都在CMD文件中完成. 下面的CMD文件代码示例中, 分配了一个名为VECS的存储段(存储首地址为0h, 长度为40h), 并将.vectors代码段连接到该存储段. 其中.vectors代码段即是后面的中断向量表代码将要存放的区域.
MEMORY
{
PAGE0:
VECS: origin=0h, length=40h /*VECTOR*/
PROG: origin=40h, length=0FFC0h /*PROGRAM */
PAGE1:
MMRS: origin=0h, length=60h /*MMRS */
B2: origin=0060h, length=20h /*B2 BLOCK*/
B0: origin=0200h, length=100h /*B0 BLOCK*/
B1: origin=0300h, length=100h /*B1 BLOCK*/
DATA: origin=8000h, length=8000h /*XDM*/
}
SECTIONS
{
.vectors : {}>VECS PAGE0
.text : {}>PROG PAGE0
.cinit : {}>PROG PAGE0
.data : {}>DATA PAGE1
.stack : {}>DATA PAGE1
.bss : {}>DATA PAGE1
}
2) 中断向量表
中断向量表, 顾名思义就是与中断有关的一系列跳转指令(B指令)的列表, 这些跳转指令正如一系列的矢量箭头直指中断服务程序. 正如前面中断响应机制一节所述, 当中断事件发生、中断响应条件满足时, 硬件会自动将程序指针跳转到一段特定的程序空间(可以叫做中断向量空间)中特定的位置, 如果在此已预置了指向中断服务程序的跳转指令, 就可以实现整套中断服务机制.
C24x系列DSP中采用两级中断结构: 对应CPU中断(也称为主中断)的通用中断服务程序(GISR), 和对应外设中断的特定中断服务子程序(SISR). 中断响应后会根据中断向量表进入相应的通用中断服务程序, 然后再根据外设中断向量寄存器PIVR中产生的地址偏移量进入具体的外设中断向量服务程序.
从通用中断服务程序到特定中断服务程序的转移处理有两种方式: ①直接编写外设中断向量(或称子中断向量)表, 根据PIVR中产生的地址偏移值在子中断向量表完成跳转; ②直接判断PIVR中产生的地址偏移值选择进入某一特定中断服务程序.
采用外设中断向量表的中断转移处理程序段如下:
LDP #0E0H
LACC PIVR,1 ;读取某中断事件对应的偏移量地址并左移移位
ADD #PVECTORS ;加上外设矢量表基地址
BACC ;转移到相应的外设中断服务程序
直接判断PIVR的中断转移处理程序段如下:
LDP #0E0H
LACC PIVR ;读取某中断事件对应的偏移量地址
XOR #00NNH ;00NNH为某外设对应的偏移量地址
BCND SISRNN,EQ ;判断是否为该外设对应的偏移量地址,
;如果是就转移到相应的外设中断服务程序
对于C24x系列DSP而言, 无论是ASM语言工程或是C语言工程, 中断向量表都必须使用ASM指令(或者是行内汇编的C语言语句)来实现, 包括自定义段伪指令.sect和一系列的(使用B指令)跳转到中断服务程序的跳转语句. 如果涉及引用文件外部的函数, 还需要引用伪指令.ref. 中断向量表可以写为头文件(如vector.h)形式或汇编源文件(如vector.asm)形式. 下面是一个头文件形式、包含CPU中断合外设中断的中断向量表示例.
; vector.h
;定义主中断向量
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ref _c_int0 ;函数声明
.ref GISR1
.ref GISR2
.ref GISR3
.ref GISR4
.ref GISR5
.ref GISR6
.sect ".vectors" ;定义主向量
RESET B _c_int0 ;地址0000H, 复位, 优先级1
INT1 B GISR1 ;地址0002H, INT1, 优先级4
INT2 B GISR2 ;地址0004H, INT2, 优先级5
INT3 B GISR3 ;地址0006H, INT3, 优先级6
INT4 B GISR4 ;地址0008H, INT4, Capture1,3
INT5 B GISR5 ;地址000AH, INT5, SCIRX,SCITX
INT6 B GISR6 ;地址000CH, INT6, 优先级9
RESERVED B _phantom ;地址000EH, 测试, 优先级10
SW_INT8 B _phantom ;地址0010H, 自定义软中断
SW_INT9 B _phantom ;地址0012H, 自定义软中断
SW_INT10 B _phantom ;地址0014H, 自定义软中断
SW_INT11 B _phantom ;地址0016H, 自定义软中断
SW_INT12 B _phantom ;地址0018H, 自定义软中断
SW_INT13 B _phantom ;地址001AH, 自定义软中断
SW_INT14 B _phantom ;地址001CH, 自定义软中断
SW_INT15 B _phantom ;地址001EH, 自定义软中断
SW_INT16 B _phantom ;地址0020H, 自定义软中断
TRAP B _phantom ;地址0022H, TRAP矢量
NMI B _phantom ;地址0024H, NMI, 优先级3
EMU_TRAP B _phantom ;地址0026H, 仿真Trap, 优先级2
SW_INT20 B _phantom ;地址0028H, 自定义软中断
SW_INT21 B _phantom ;地址002AH, 自定义软中断
SW_INT22 B _phantom ;地址002CH, 自定义软中断
SW_INT23 B _phantom ;地址002EH, 自定义软中断
SW_INT24 B _phantom ;地址0030H, 自定义软中断
SW_INT25 B _phantom ;地址0032H, 自定义软中断
SW_INT26 B _phantom ;地址0034H, 自定义软中断
SW_INT27 B _phantom ;地址0036H, 自定义软中断
SW_INT28 B _phantom ;地址0038H, 自定义软中断
SW_INT29 B _phantom ;地址003AH, 自定义软中断
SW_INT30 B _phantom ;地址003CH, 自定义软中断
SW_INT31 B _phantom ;地址003EH, 自定义软中断

;定义外设中断向量(INT2为例)
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.sect ".pvectors"
PVECTORS B _phantom ;地址0000H, 保留外设向量
B _phantom ;地址0001H, 保留外设向量
B _phantom ;地址0002H, 保留外设向量
B _phantom ;地址0003H, 保留外设向量
B _phantom ;地址0004H, 保留外设向量
B _phantom ;地址0005H, 保留外设向量
B _phantom ;地址0006H, 保留外设向量
B _phantom ;地址0007H, 保留外设向量
B _phantom ;地址0008H, 保留外设向量
B _phantom ;地址0009H, 保留外设向量
B _phantom ;地址000AH, 保留外设向量
B _phantom ;地址000BH, 保留外设向量
B _phantom ;地址000CH, 保留外设向量
B _phantom ;地址000DH, 保留外设向量
B _phantom ;地址000EH, 保留外设向量
B _phantom ;地址000FH, 保留外设向量
B _phantom ;地址0010H, 保留外设向量
B _phantom ;地址0011H, 保留外设向量
B _phantom ;地址0012H, 保留外设向量
B _phantom ;地址0013H, 保留外设向量
B _phantom ;地址0014H, 保留外设向量
B _phantom ;地址0015H, 保留外设向量
B _phantom ;地址0016H, 保留外设向量
B _phantom ;地址0017H, 保留外设向量
B _phantom ;地址0018H, 保留外设向量
B _phantom ;地址0019H, 保留外设向量
B _phantom ;地址001AH, 保留外设向量
B _phantom ;地址001BH, 保留外设向量
B _phantom ;地址001CH, 保留外设向量
B _phantom ;地址001DH, 保留外设向量
B _phantom ;地址001EH, 保留外设向量
B _phantom ;地址001FH, 保留外设向量
B _phantom ;地址0020H, 保留外设向量
B _phantom ;地址0021H, 比较1中断
B _phantom ;地址0022H, 比较2中断
B _phantom ;地址0023H, 比较3中断
B _phantom ;地址0024H, 比较4中断
B _phantom ;地址0025H, 比较5中断
B _phantom ;地址0026H, 比较6中断
B PHANTOM ;地址0027H, 定时器1周期中断
B SISR28 ;地址0028H, 定时器1比较中断
B SISR29 ;地址0029H, 定时器1下溢中断
B SISR2A ;地址002AH, 定时器1上溢中断
B _phantom ;地址002BH, 保留外设向量
B _phantom ;地址002CH, 保留外设向量
B _phantom ;地址002DH, 保留外设向量
B _phantom ;地址002EH, 保留外设向量
B _phantom ;地址002FH, 定时器3周期中断
B _phantom ;地址0030H, 定时器3比较中断
B _phantom ;地址0031H, 定时器3下溢中断
B _phantom ;地址0032H, 定时器3上溢中断
B _phantom ;地址0033H, 保留外设向量
B _phantom ;地址0034H, 保留外设向量
B _phantom ;地址0035H, 保留外设向量
B _phantom ;地址0036H, 保留外设向量
B _phantom ;地址0037H, 保留外设向量
B _phantom ;地址0038H, 保留外设向量
B _phantom ;地址0039H, 保留外设向量
B _phantom ;地址003AH, 保留外设向量
B _phantom ;地址003BH, 保留外设向量
B _phantom ;地址003CH, 保留外设向量
B _phantom ;地址003DH, 保留外设向量
B _phantom ;地址003EH, 保留外设向量
B _phantom ;地址003FH, 保留外设向量
B _phantom ;地址0040H, 保留外设向量
B _phantom ;地址0041H, 高优先级CAN错误中断
3) 中断服务程序中断服务程序完成具体中断事件的处理以及现场的保护和恢复等工作. 中断服务程序可由汇编语言或C语言来编写. 中断服务程序的标号(或函数名)应该与中断向量表(或子中断向量表)中的名称对应.


阅读全文...