软中断在51单片机中的实现及其应用_第1页
软中断在51单片机中的实现及其应用_第2页
软中断在51单片机中的实现及其应用_第3页
软中断在51单片机中的实现及其应用_第4页
软中断在51单片机中的实现及其应用_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、软中断在51单片机中的实现及其应用彭树林摘要本文讨论软中断在51单片机(兼容)中的实现方法以及软中断在51单片机(兼容)系统中的应用。详细说明了在51单片机实现软中断的方法,并就软中断的应用作了简明扼要的阐述。关键词软中断单片机51单片机实时操作系统1、序言现代的单片机应用中,某些单片机为了方便操作系统编程,会保留一些特权指令给RTOSM乍系统,以便实时控制整个机器;软件中的一些原子操作不允许中断破坏,也需要一些特权指令。软中断指令表面上类似于函数调用,主要是使单片机进入特权运行状态,并在这个状态下,操作一些用户状态下不能使用的功能。51兼容单片机没有特权功能,也不存在软中断指令。但是我们的一

2、些应用确实需要软中断特权指令来完成一些特殊的操作。本文所讨论软中断在51兼容单片机中的实现方法以及软中断在51兼容单片机系统中的应用。2、软中断与硬中断软中断,最早出现在Intel8086处理器中,该处理器的指令系统中,可使用INT指令来申请中断服务。在DOSM乍系统下,利用INT21这条指令,应用软件可以申请多达84个DOS(统服务。在Linux、WindowsSOLAIRS等操作系统中,都有软中断在为系统提供服务。软中断和硬中断区别不大,软中断是程序中用软件代码人为地产生中断,让CPUS执行相应的中断服务程序。硬中断由硬件产生并触发中断,让CPlfe执行相应的中断服务程序以响应该事件。可以

3、这样理解,软中断以软件中断指令所携带的参数作为工作的依据,而硬中断是以计算机系统中硬件所发生的事件为工作依据。可见软件中断的灵活性非常强,可根据程序的运行状态、硬件状态以及任务之间的消息作为触发条件,中请相应的软中断功能服务。软中断最大的用途在于RTOSS供系统级服务,提高系统的实时性。在没有RTOS勺情况下,我们也可利用软中断服务对敏感代码和敏感数据进行保护。比如互斥访问共享硬件以及互斥访问共享数据等。3、51单片机(兼容)中断系统的秘密51单片机(兼容)的中断系统中,各个中断标志的置位条件和如何清除,者B在公开的技术资料中进行了详细的描述。然而,公开的技术细节实际上并没有将中断系统的工作原

4、理讲述清楚。大家使用的51兼容单片机,其中断系统的工作细节以及工作的结果与公开的技术资料有些小小的差异。比如关于外部中断标志IE0的置位,附1是五个公司对IE0的描述。各个公司开发的51单片机(兼容),其中断系统也兼容,仅仅是中断源的多少,中断优先级的级数以及中断向量的多少的不同,附2列举了六家公司51单片机(兼容)的中断系统资料。中断系统的秘密在于:中断标志完全可以通过一定的方式实现软件置位和软件清除。可否通过软件置位和清除中断标志,是在51单片机中实现软中断的关键,如果不能用软件申请中断,软中断的实现就无从谈起。硬件置位中断申请标志只是方法之一而不是唯一的方法,CPUI全可以设置这些标志位

5、为“0”或者“1”。这是理解本文的基础,对于有丰富经验的51单片机开发者,只要知道这个道理就好,基本没有必要再阅读后面的部分。本文接下来的部分具体描述如何在51单片机中实现软中断,主要针对51单片机开发经验还不是十分丰富的读者。IE0和IE1的秘密在于,如果将中断检测的方式(IT0、IT1)设置为边沿检测,就可以用软件来设置或清除IE0和IE1(消除也可以让中断系统在响应中断时自动完成)。TFRTF1、TF2TI以及RI是已知的可以软件操控的中断申请标志。对于各个公司的51单片机(兼容)增强部分的中断,可以根据实际应用,在关闭模块功能的情况下一般都可以自由使用其中断资源。具体应用时,应编写一个

6、测试软件,测试具体型号的51单片机各个中断资源是否能够被利用,避免走弯路。读者应当注意到,有些单片机的某些中断申请标志,其清除方法是通过对该标志位写“1”来完成的,这种中断源就不适合用于软中断,比如STC12C5AxxS2单片机的SPI中断。如果要使用STC12C5AxxS单片机的SPI中断作为软中断,就必须放弃该模块占用的IO弓唧,以实现软中断。例如在40脚DIP封装的STC12C5AxxS单片机中,将SPI影射到P4口不会占用外部的引脚,将SPI设置为MASTE模式,就可以通过对SPDATW入0xFF数据来是SPI工作,SPI工作完成后会自动设置中断申请标志,从而完成软中断的申请。而在44

7、或48脚封装的STC12C5AxxS单片机,用SPI中断源实现软中断就必须考虑放弃SPI占用的引脚(P1口或P4口)。大部分51单片机(兼容)增强部分,在系统的应用中不能全部同时使用,因为它们可能共享了IO端口上的引脚。因此,总是能在一个51单片机中找到空闲资源实现软中断。4、软中断实现的方法只要是代码兼容的51单片机,就可以利用空闲不用的中断来实现软中断。对于没有空闲中断的应用系统,也可以通过本文描述的方法来实现共享硬件中断和软中断。在51单片机应用系统中,实现软中断的基本原理是用软件置位硬件中断的中请标志位,迫使系统承认一个“硬件中断”发生进而去响应这个“硬件中断事件”这样,就实现了用软件

8、申请实现中断服务。具体在一个应用系统中实现时,可能还需要作如下的安排:1)将应用系统中已经使用的全部硬件中断设置为高优先级;2)让软中断使用的中断源的优先级为最低优先级,以确保软中断中可以响应硬件中断,实现中断嵌套。4.1 使用外部中断使用外部中断0和1作为软中断时,应当使中断的触发方式设置为边沿触发,并且对应的引脚只能进行输出,不能为输入,若设计为输入时系统不能分辨硬件触发和软件触发。即使是对外输出,也需要限制为软中断的服务来提供输出,就能避免输出的变化错误地触发中断。经过上述的设置后,就可以利用软件来控制中断标志IE0或IE1的置位和清除,由于51单片机(兼容)中断系统能够在中断返回时自动

9、清除外部中段标志IE0或IE1,因此在结束软中断服务时可以不清除中断标志。例如,使用外部中断0来实现软中断。首先,开放外部中断0,使EX0=1其次,设置外部中断0为沿触发,使IT0=1;接下来用“IE0=1”来置位IE0申请软中断服务,而使用“IE0=0”来清除IE0结束软中断服务(可以不使用“IE0=0”而由中断系统在中断服务中自动清除)。参见例2所示例程。4.2 使用定时器中断使用定时器0、定时器1和定时器2中断,需要考虑的是关闭定时器,以避免定时器溢出产生中断申请。这时软件就能完全控制中断标志TFRTF1或TF2的置位以及清除,以申请软中断和结束软中断服务。应当注意,51单片机(兼容)的

10、中断系统在中断返回时不会自动消除TFRTF1和TF2,因此,在结束软中断服务时,一定要清除相应得中断标志TFRTF1或TF2。对于具有定时计数器2的单片机,如果将其应用于串口的波特率发生器,就是最好的软中断资源。因为定时器而一旦被应用于串口产生发送时钟或者接收时钟,定时器的溢出就不会设置TF2(TF2willnotbesetwheneitherRCLK=1orTCLK=1.)。例如,使用定时器0来实现软中断。首先,关闭定时器0,使TR0=Q其次,开放定时器0的中断,使ET0=1;接下来用“TF0=1”来置位TF0申请软中断服务,而使用“TF0=0”来清除TF0结束软中断服务。参见例2所示例程。

11、4.3 使用其它中断资源其他的中断资源,只要没有和引脚有关联,就可以在关闭模块功能的条件下直接,用软件来设置或清除相应模块的中断申请标志,以申请软中断服务或结束软中断服务。例如,在51单片机(兼容)应用系统中没有使用用口(对于多用口单片机,是串口0)通讯,就可以使用串口的RI中断标志来实现软中断。首先,禁止接收(复位状态就是禁止的),使REN=0其次,开放用口中断,使ES=1;接下来,利用“RI=1”来置位RI申请软中断服务,而使用“RI=0”来清除RI结束软中断服务。参见例2所示例程。再例如,在STC12C5AxxS2用系统中,不使用ADCB块,就可以使用ADO块的ADC_FLA序断标志来实

12、现软中断。首先,禁止ADCS块(复位状态就是禁止的),使ADC_POWER翔闭ADC®块的电源;其次,开放ADC中断,使EADC=1接下来用“ADC_CONTTOx10”来置位ADC_FLA由请软中断服务,而使用“ADC_CONTR=0x00”来清除ADC_FLA鳍束软中断服务。参见例2所示例程。4.3定义软中断为了使软件具有很好的移植性,可以使用宏定义来实现具体应用系统的软中断。在这个宏定义中,应当完成参数的传递以及软中断的申请。例1定义了一个可以携带3个参数的宏,第一个参数是申请的功能号,第二个参数是输入数据的地址,第三个参数是结果输出的地址。利用这三个参数,就可以处理任意类型的

13、数据(参考例2所示的例程)。对于简单的系统,如果软中断提供的服务没有其他的数据需要输入输出,就可只使用一个参数:服务功能号。例1:软中断的宏定义#defineSWI(a,b,c)FunctionNum=a;InputParameter=(unsignedchar*)&b;OutputParameter=(unsignedchar*)&c;SWI_IRQ();_nop_();在例1所示的宏中,SWI_IRQ()也是一个宏,用来在宏中自动地选择中断源,而不需要修改代码。参照例2,一个SWI_IRQ()定义的例子:/定义软件中断使用的中断号defineSWI_NUM1使用外部中断0作

14、软中断ifSWI_NUM=0defineSWI_IRQ()IE0=1defineCLEAR_SWI()/IE0=0/使用T0中断祚软件中断elifSWI_NUM=1defineSWI_IRQ()TF0=1defineCLEAR_SWI()TF0=0对于复杂的系统,可以动态指定软中断服务的具体函数以及数据输入输出的入口地址。参照例3,定义软中断携带两个参数:一个是功能号,一个是函数入口地址,就可在软中断服务中执行动态的代码Func_CallBack,以完成不同类型的任务。#defineSWI(a,b)FunctionNum=a;Func_CallBack=(void*)b;SWI_IRQ();_

15、nop_();voidSWI_ISR(void)interruptSWI_NUM/测试抬入的参数CLEAR_SWI();/清除可能需要清除的标志Func_CallBack();/执行指定的功能函数FunctionNum=0;清除申请功能号5、软中断和硬件中断共享一个中断源的实现的方法前面所描述的软中断实现方法,是利用系统中不使用的中断源,将其分配给软中断来使用,在大多数情况下这都是适的方法。然而有的应用系统确实已经使用的全部的中断资源,还想要软中断功能,这该怎么办?下面就来讨论这个题目:如何共享硬件中断和软中断。解决这个问题的关键在于正确区分硬件触发与软件触发的中断,既要保证没有多余的触发,又

16、要保证不漏掉任何一个触发。由于中断标志只有一个,若软中断触发时硬中断也触发,就不能分辨了。仅仅加软件标志通常不能解决这个问题,这时需要寻求其他的实现方法。必要时需要附加硬件来帮助实现软中断功能。选择共享中断源的依据是能够准确区分硬件中断和软中断。比较容易成功的方法是通过附加硬件措施来改造两个外部中断中的一个。对于用低电平触发的外部中断申请,如果中断的撤销是由CPU来完成的,则CPU在中断服务程序中就能通过查询外部中断线的电平状态来判断是否同时发生了硬件中断的申请,这时软中断的申请标志和硬中断的申请电平就是两个相互独立的标志,也就能够准确区分硬件中断和软中断了。具有一般性的做法是将外部中断0或外

17、部中断1的中断申请改为利用一个D触发器来进行电平方式的中断申请,并将中断申请的撤销交给CPU来控制,以便系统能够准确识别每一个中断申请。图1是将边沿触发中断改为电平触发的一种实现方式。图2是将主动撤销信号电平申请改为由CPU空制信号撤销电平申请的一种实现方式。对于其他的应用于系统之间通讯的通讯端口,不推荐用于共享方式实现软中断。这是因为通讯的数据流可能很大,在没有FIFO缓冲的51兼容单片机中,很有可能造成接收溢出。在51兼容单片机中,用口UAR1W使在不使用发送中断的情况下,也不推荐应用于软中断服务,因为每一个数据发送完成都会自动置位TI标志,会干扰软中断的执行。图1边沿触发中断申请改为低电

18、平触发中断申请图2低电平触发中断申请改为CPLB销信号的低电平触发中断申请6、软中断在实时操作系统环境下的应用在基于51单片机的嵌入式系统中,数据采集处理、程序控制和数据通讯是三个主要的应用方面,以下三小节分别描述数据采集处理任务、程序控制任务和数据通讯任务中软中断的使用,以帮助读者加深对软中断的理解。软中断服务在数据采集处理任务中的应用实时操作系统下,中断处理占用的时间越短,系统的实时性越好。在一些应用中,数据处理的实时性要求很高,系统的响应时间在0.5毫秒以内。如果数据处理的时间在最坏情况下超过0.3毫秒,系统的软件设计就受到挑战。如果将数据处理全部放入中断中进行处理,系统中其它任务的实时

19、性会受到严重影响。解决的办法通常是以下两种:1)不使用51单片机,改用其它处理速度更快的处理器(如ARMM理器);2)不使用操作系统。这两种解决办法要受到产品成本和开发效率的约束。软中断的应用可以成为上述问题的第3种解决方法,并且是最优的解决方法。使用一个最低优先级的中断源来实现软中断,将数据处理放入软中断中完成。这样,软中断就可以随时剥夺任何一个正在运行的任务而优先执行,执行完成后可以回到正在执行的任务,也可以切换到已就绪的更高优先级的任务。如此,系统的实时性就提高了,同时,软件开发效率也提高了。具体的办法是,在数据采集中断中,只完成数据的获取,将数据存放到队列中,然后申请软中断服务后退出中

20、断服务程序。只要系统中没有其它中断事务等待处理,软中断就可以开始处理,并且在软中断处理过程中可以响应其它的硬件中断,从而保证系统的实时性由于软中断总是优先于任务执行,所以能够保证数据处理的实时性。当队列中没有数据时,软中断退出,执行其它任务。在这样的机制下,没有频繁的上下文切换,因此CPU勺使用效率得到提高,以保证整个系统的实时性。以下代码片断是一种车辆检测器的代码,使用了软中断来处理数据。可以看出,找外部中断0中将数据放入队列,然后申请软中断。在软中断中,只要队列中还有数据,就循环处理直到队列为空才退出软中断。voidint0_int(void)interruptIE0_VECTOR/外部G

21、断0TR0=0;/读计数器NewNode=QMalloc();申请分配内存if(NewNode<Q_MAX_LEN)/内存分配成功LoopQNewNode.LoopChannel=LoopCounter;/TH2,TH1,TH0,TL7,TL6,TL5,TL4,TL3,TL2,TL1,TL0,P27P2.6,P2.5,P24P2.3/读取21位计数值拼成2字节,组成16位计数值LoopQNewNode.LoopNv=(TH0&0x03)*8192)+(TL0*32)+(P2>>3)&0x1F);LoopQNewNode.TimeStamp=0;/没有测速,不需

22、血时间戳AddLoopNode(NewNode);SWI_IRQ();/申请软件中断,以便处理数据LoopSet();/计算并设置下一个通道LoopProcTimer=0;,/软中断服务函数voidSWI_ISR(void)interruptSWI_NUM/while(1)ProcNode=GetLoopNode();/从队列中取待处理的数据if(ProcNode=0xFF)break;/队列中没有数据,退出lopcout=LoopQProcNode.LoopChannel;/取通道号nvlopcout=LoopQProcNode.LoopNv;/取测量数据QFree(ProcNode);/释

23、放内存以便宿环使用LoopProc();/通道计算CLEAR_SWI();/清除可能需要清除的标志软中断在程序控制任务中的应用在操作系统中的程序控制任务,具运行受系统内核支配。如果程序控制任务在逻辑上有严格的时间安排,很可能被高优先级任务剥夺运行而导致逻辑失败。这种任务如果全部安排在中断中完成处理,会影响系统中其它任务的实时性。这时比较好的方法就是利用软中断来处理时间要求很严格部分。通过软中断,中请在指定时刻执行指定的代码。以下的代码是程序控制任务计算出来的控制序列,通过申请软中断服务,将待执行的程序控制交给系统,系统在定时器的严格同步下,将非常准确地完成控制过程。代码中,35毫秒后,功能1和

24、功能4将“同时”启动执行,实际上功能1先于功能4执行,时间上相差大约10uS左右。SWI_REQ(20,func1,data1);/SWI_REQ(25,func2,data2);/SWI_REQ(26,func3,data3);/SWI_REQ(35,func1,data4);/SWI_REQ(35,func4,data5);/SWI_REQ(36,func3,data6);/申请20ms后执行功能1,其所需的参数在data1申请25ms后执行功能2,其所需的参数在data2申请26ms后执行功能3,其所需的参数在data3申请35ms后执行功能1,其所需的参数在data4申请35ms后执行

25、功能4,其所需的参数在data5申请36ms后执行功能3,其所需的参数在data6软中断在数据通讯任务中的应用在数据通讯中,有些通讯协议对系统的响应时间有严格的要求,两个数据包之间的空闲时间有严格的限制,超过一定时间就认为超时。这种情况下,数据通讯任务如果全部安排在中断中完成处理,则会影响系统其它任务的实时性,如果放在任务中运行,运行的时间又不可控制。当然可以在任务中关闭中断来处理实时性要求较强的代码,可是这样做会影响其他部分的实时性。比较好的方法,就是利用软中断,将需要提供的实时服务通过软中断申请将目标代码和数据在不影响系统实时性的条件下优先执行。首先,在系统中建立一个软中断函数执行的链表,

26、将等待执行代码入口地址和数据入口地址放在这个链表中。一旦内核运行完毕,就自动来检测这个链表中是否存在待执行的软中断代码。如果有软中断代码,立即按照优先顺序执行。当所有的软中断代码执行完成后,就检查是否有高优先级的任务已经就绪等待执行,若有,进行任务调度。当然,申请软中断服务本身就可能引发任务调度。这得看软中断服务完成后,是否有更高优先级任务进入就绪态。比如,有一个任务在发送完成一个数据包后,有严格的时间要求在20ms后准确启动第二个数据包的发送。如果利用OSWait()或OSTimeDly()的方式,则完全不可能在20ms后准确开始。如果关闭中断等待20ms,系统的效率将十分低下。用软中断的方

27、法是,向系统申请一个软中断服务,将服务要求的启动时刻、提供服务函数入口地址以及数据的存储地址提供给系统,就可以在指定的时刻运行这段代码,完成数据的发送工作。即使当前任务在申请完软中断服务后被剥夺,也能保证指定的数据在20ms后发送出去。软中断函数执行链表的结构typedefstructSwi_List_MALLOC_MEM_*SwiNode;typedefstructSwi_ListunsignedintTimeDelay;/延迟多少时间开始执行,等于0表示立即执行void(*Func)(unsignedchar*pInOut);/执行的函数入口地址unsignedchar*pInOut;/执

28、行函数的数据输入输出地址SwiNodeNextNode;/下一个节点的地址;这样的伪代码就是:,/准备第一个数据包Send(Packet1);/发送第一个数据包/准备第二个数据包SWI_REQ(20,Send,Pachet2);申请20ms后发送第二个数据包7、无操作系统环境下软中断的应用在没有操作系统软件环境中,如果要执行的事务比较简单也比较少,用轮询的方法调度各个模块就基本可以满足。然而当事务比较多或事务比较复杂时,实时性的协调就很难。在这种情况下,就可以利用软中断来简化各个模块之间的时间协调,可大大提高系统的实时性和可协调性。在一个没有操作系统的51单片机应用系统中开发软件,软中断不仅可

29、以用来帮助对临界段的管理,以实现硬件资源的互斥访问以及共享数据的互斥访问,还可以实现无阻塞等待。还举6.3节的例子,一个模块在发送完成一个数据包后,有严格的时间要求在20ms后准确启动第二个数据包的发送。用软中断在系统中申请一个20ms的延时定时器,定时器到时执行回调函数Send(),完成第二个数据包的发送。这样的伪代码就是:unsignedcharPacket_Send(void)If(CanSend=0)return1;/发送忙,返回1If(IsPendInTimer(Send)return2;/Send函数被挂起在定时器的服务列表中,第二个数据包还没有启动发送,返回2/准备第一个数据包S

30、end(Packet1,len1);/发送第一个数据包/准备第二个数据包SWI_REQ(20,Send,Pachet2,len2);/申请20ms后发送第二个数据包return0;/发送完成,返回0卜面一个例子,揭示软中断如何实现硬件资源的互斥访问大家都使用过I2C总线器件,比如实时时钟、温度传感器、EEPRO除等。不论单片机自带的硬件I2C控制器还是用软件模拟的I2C控制器,我们都必须保证对I2C总线操作的完整性,避免多个模块之间同时争用I2C总线。在实时操作系统环境下,这个很容易实现,但在没有实时操作系统来管理时,就需要设置信号量来帮助各个模块之间协调使用。我们都知道,I2C总线是低速总线

31、,软件模拟中线控制器时将耗费很多CPU时间,并且一个模块必须完成访问后才能释放访问权限。在没有实时操作系统的软件环境中,CPUt不得不等待。为了提高CPU勺利用率,在12c总线的驱动程序中使用软中断,能够很好地协调各模块之间使用12c总线访问不同的器件。软中断服务执行指定的发送或接收函数,并将结果复制到指定的内存地址中,然后还可以执行指定的回调函数(如果有的话)。由于软中断优于任何模块获得CPU运行,故模块之间提交的软中断独立于模块代码而完整运行(硬件中断不妨碍其正确执行)。由于收发的硬件操作仅在软中断中执行,自然实现了硬件资源的互斥访问。同时,软中断中对共享的变量操作也具有了原子性。参阅例程

32、4所示代码片断。/模块1:VoidM1()(SWI(1,&MySwiNode1);/申请软中断/退出该模块,软件中断执行完成后,实时时钟的数据自动保存在clock口中/模块2:VoidM2()(省略)SWI(1,&MySwiNode2);/申请软中断/退出该模块,软件中断执行完成后,温度数据自动保存在temp口中voidmain(void)(,/运行模块1M1();/运行模块2M2();,8、结语在51单片机中,利用硬件中断的中断向量,实现软中断是完全可行的,并且使用软中断能够优化应用软件的执行效率。例2:一个SWI演示例程(STC12C5AxxS2片机)#include<

33、;STC_NEW_8051.h>#include<intrins.h>sbitLED=P1A0;定义软件中断使用的中断号,可选09#defineSWI_NUM1/使用外部吊断0作软中断ifSWI_NUM=0defineSWI_IRQ()IE0=1defineCLEAR_SWI()/IE0=0/使用T0中断存软件中断elifSWI_NUM=1defineSWI_IRQ()TF0=1defineCLEAR_SWI()TF0=0/使用外部中断1作软中断elifSWI_NUM=2defineSWI_IRQ()IE1=1defineCLEAR_SWI()/IE1=0/使用T1中断存软件

34、中断elifSWI_NUM=3defineSWI_IRQ()TF1=1defineCLEAR_SWI()TF1=0/使用UART中嬴乍软件中断elifSWI_NUM=4defineSWI_IRQ()RI=1defineCLEAR_SWI()RI=0/使用ADC断作软件中断elifSWI_NUM=5defineSWI_IRQ()ADC_CONTR=0x10defineCLEAR_SWI()ADC_CONTR=0x00/使用LVD中断作软件中断elifSWI_NUM=6defineSWI_IRQ()PCON|=0x20defineCLEAR_SWI()PCON&=0xDF/使用PCA中麻作

35、软件中断elifSWI_NUM=7defineSWI_IRQ()CF=1defineCLEAR_SWI()CF=0/使用UART巾断作软件中断elifSWI_NUM=8defineSWI_IRQ()S2CON|=0x01defineCLEAR_SWI()S2CON&=0xFE/使用SPI中断作软件中断elifSWI_NUM=9defineSWI_IRQ()SPDAT=0xFFdefineCLEAR_SWI()SPSTAT=0xC0#endif#ifdefSWI_NUMunsignedcharFunctionNum;/unsignedchar*InputParameter;unsigne

36、dchar*OutputParameter;#defineSWI(a,b,c)FunctionNum=a;InputParameter=(unsignedchar*)&bOutputParameter=(unsignedchar*)&c;SWI_IRQ();_nop_();#endifvoidSwiFunction_Init(void)一/将硬件中断源置于高优先级,IP=0xFF;IP2=0xFF;IPH=0x00;IPH2=0x00;/将软中断所使用的中断源置于低优先级ifSWI_NUM<8IP&=(0x01<<SWI_NUM);elifSWI_NU

37、M<10IP2&=(0x01<<(SWI_NUM-8);#endif/使用外部中断0作软中断ifSWI_NUM=0IT0=1;/边沿触发EX0=1;/使用T0中断作软件中断elifSWI_NUM=1ET0=1;/使用外部中断1作软中断elifSWI_NUM=2IT1=1;/边沿触发EX1=1;/使用T1中断作软件中断elifSWI_NUM=3ET1=1;/使用UAR伸断作软件中断elifSWI_NUM=4ES=1;/使用ADC断作软件中断elifSWI_NUM=5EADC=1;/使用LVD中断作软件中断elifSWI_NUM=6ELVD=1;/使用PCA中断作软件中断

38、elifSWI_NUM=7CMOD|=0x01;/ECF=1/使用UART珅断作软件中断#elifSWI_NUM=8IE2|=0x01;/ES2=1/使用SPI中断作软件中断#elifSWI_NUM=9AUXR1|=0x20;/SPI切换到P4口SPCTL=0xD0;/MASTE秋式IE2|=0x02;/ESPI=1#endifEA=1;voidmain(void)unsignedcharSwiFun_Num;intDataIn,result,i;P0=0xFF;P1=0xFF;P2=0xFF;P3=0xFF;SwiFunction_Init();/初始化软中断功能DataIn=0;resul

39、t=0;SwiFun_Num=0;while(1)SwiFun_Num+;DataIn+;SWI(SwiFun_Num,DataIn,result);申请软中断服务if(result!=(DataIn+SwiFun_Num)for(;)_nop_();/错,停在这里for(i=0;i<32767;i+)_nop_();#ifdefSWI_NUMvoidSWI_ISR(void)interruptSWI_NUM/软中所服务函数提供的功能是输出=输入+申请功能号LEDA=1;/便于观察是否进入软中断服务CLEAR_SWI();/清除可能需要清除的标志*(int*)OutputParamete

40、r=*(int*)InputParameter+FunctionNum;FunctionNum=0;/清除申请功能号#endif例3:一个具有动态代码执行能力的SWI演示例程(STC12C5AxxS单片机)#include<STC_NEW_8051.h>#include<intrins.h>voidSet_LED0(void);voidSet_LED1(void);省略,同例2sbitLED=P1A0;/定义软件中断使用的中断号:#ifdefSWI_NUMunsignedcharFunctionNum;void(*Func_CallBack)(void);#define

41、SWI(a,b)FunctionNum=a;Func_CallBack=(void*)b;SWI_IRQ();_nop_();省略,代码同例2#endifvoidSwiFunction_Init(void)/voidSet_LED0(void)LED=0;voidSet_LED1(void)LED=1;voidmain(void)unsignedcharSwiFun_Num;inti;P0=0xFF;P1=0xFF;P2=0xFF;P3=0xFF;SwiFunction_Init();/初始化软中断功能SwiFun_Num=0;while(1)SwiFun_Num+;/申请欣中断服务if(LE

42、D=1)SWI(SwiFun_Num,Set_LED0);ElseSWI(SwiFun_Num,Set_LED1);for(i=0;i<32767;i+)_nop_();#ifdefSWI_NUMvoidSWI_ISR(void)interruptSWI_NUM/软中而服务函数,提供的服务是执行指定的功能函数CLEAR_SWI();/清除可能需要清除的标志Func_CallBack();/执行指定的功能函数FunctionNum=0;/清除申请功能号#endif例程4:一个SWI演示例程,互斥访问I2C总线(STC12C5AxxS单片机)typedefstructSwi_List*Swi

43、Node;typedefstructSwi_ListunsignedintTimeDelay;/延迟多少时间开始执行,等于0表示立即执行void(*Func)(unsignedchar*pInOut);/执行的函数入口地址unsignedchar*pInOut;/执行函数的数据输入输出地址SwiNodeNextNode;/下一个节点的地址;SwiNodeSWI_Head_Node;/原统内核使用的指针变量#ifdefSWI_NUMunsignedcharFunctionNum;SwiNodeSwiIRQNode;#defineSWI(a,b)FunctionNum=a;SwiIRQNode=b

44、;SWI_IRQ();_nop_();#endifuint8IICRead(uint8*Ret,uint8Addr,uint8NByte)/硬件上操作总线,完成读取功能(省略)uint8IICWrite(uint8Addr,uint8*Data,uint8NByte)/硬件上操作总线,完成写入功能(省略)voidPCF8563Read(uint8*Data)uint8NByte;NByte=*Data+;IICWrite(PCF8563Addr,Data,1);IICRead(Data-1,PCF8563Addr,NByte);voidPCF8563Write(uint8*Data)uint8

45、NByte;NByte=*Data+;NByte+;IICWrite(PCF8563Addr,Data,NByte);voidGet_Temperature(int*RegTemperature)/读传忌器的温度,力感器的地址本*RegTemperature指定uint8SensorAddr;uint8TempReg2;SensorAddr=(uint8*)RegTemperature;/访问的传感器地址TempReg0=SENSOR_REG_TEMPERATUREW感器的温度值寄存器IICWrite(WRITE_SENSOR_ADDR0+(SensorAddr&0x07)*2,Tem

46、pReg,1);/写一个字节IICRead(Temp,READ_SENSOR_ADDR0+(SensorAddr&0x07)*2,2);/读两个字节*RegTemperature=(Temp0<<8)+Temp1;voidSWI_ISR(void)interruptSWI_NUM/软中所服务函数提供的服务是执行链表中的函数if(FunctionNum=1)/功能1:增加软中断服务,将软中断申请放到队列中等待执行if(SWI_Head_Node=0)/申请内存SWI_Head_Node=(SwiNode)malloc(sizeof(Swi_List_Struct);if(SW

47、I_Head_Node!=0)SWI_Head_Node->TimeDelay=SwiIRQNode->TimeDelay;SWI_Head_Node->Func=SwiIRQNode->Func;SWI_Head_Node->pInOut=SwiIRQNode->pInOut;SWI_Head_Node->NextNode=0;)一一)else(省略)/寻找是否有就绪的软中断任务需要执行pNode=SWI_Head_Node;pRightNode=SWI_Head_Node;for(;)if(pNode!=0)if(pNode->TimeDel

48、ay)=0)/发现一个等待执行的软中断if(pNode=SWI_Head_Node)/是第一个节及一if(pNode->NextNode)!=0)/还有下一个节点/撤销节点SWI_Head_Node=pNode->NextNode;pRightNode=SWI_Head_Node;/执行函数pNode->Func(pNode->pInOut);/释放内存free(pNode);pNode=pRightNode;/指向下一个节点)else/没有下一个节点(省略)else/不是第一个节点(省略)else/移动指针pRightNode=pNode;pNode=pNode-&g

49、t;NextNode;)elsebreak;)FunctionNum=0;/清除申请功能号CLEAR_SWI();/清除可能需要清除的标志)/模块1:VoidM1()Swi_List_StructMySwiNode1;/用于读写PCF856裳时时钟staticuint8clock8=0,0,0,0,0,0,0,0;/根据温度执行相应的操作(省略)/读取PCF8563勺时间数据MySwiNode1.Func=PCF8563Read;/胞行的函数是PCF8563ReadMySwiNode1.pInOut=clock;/输入输出的参数clock8clock0=7;/读7个字节clock1=2;/从PCF寄存器2开始读MySwiNodel.TimeDelay=0;/执行功能的延迟时间为0,要求立即开始执行SWI(1,&MySwiNode1);/申请软中断/退出该模块,软件中断执行完成后,实时时钟的数据自动保存在clock口中/模块2:VoidM2()Swi_List_StructMySwiNode2;/staticuint8temp2=0,0;/用于读写AD741魏度传感器int*T;T=(int*)temp;/指向存储温度的内存/根据温度执行相应的操作(省略),/读取AD7416勺温度数据MySwiNode2.Func=Get_

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论