51中断用法
51单片机外部中断详解
一.外部中断相关寄存器1.定时器/计数器控制寄存器控制寄存器(TCON)IT0:外部中断0触发方式控制位当IT0=0时,为电平触发方式(低电平有效)当IT0=1时,为边沿触发方式(下降沿有效)IT1:外部中断1触发方式控制位当IT1=0时,为电平触发方式(低电平有效)当IT1=1时,为边沿触发方式(下降沿有效)2.中断允许控制寄存器(IE)EX0:外部中断0允许位;EX1:外部中断1允许位;EA :CPU中断允许(总允许)位。
二.外部中断的处理过程1、设置中断触发方式,即IT0=1或0,IT1=1或02、开对应的外部中断,即EX0=1或EX1=1;3、开总中断,即EA=1;4、等待外部设备产生中断请求,即通过P3.2,P.3.3口连接外部设备产生中断5、中断响应,执行中断服务函数三.程序编写要求:通过两位按键连接外部中断0和1,设定外部中断0为下降沿触发方式,外部中断1为低电平触发方式,按键产生中断使数字加减,用一位共阳极数码管来显示数值。
目的:感受外部中断对程序的影响,体会低电平触发和下降沿触发的区别。
#include<reg51.h>#define uint unsigned int #define uchar unsigned char uchar code dat[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; uint num;void main(){EA=1; //开总中断IT0=1; //下降沿触发IT1=0; //低电平触发EX0=1; //外部中断0允许EX1=1; //外部中断1允许while(1){P0=dat[num%10];}}void plus() interrupt 0//外部中断0 {EX0=0;num++;EX0=1;}void minus() interrupt 2//外部中断1 {EX1=0;num--; EX1=1; }。
51单片机中断实施的步骤
51单片机中断实施的步骤介绍中断是指在程序运行的过程中,当发生特定条件的时候,中断会打断程序的正常执行,转而执行中断服务程序。
51单片机中断实施的步骤可以帮助开发者合理地利用中断的功能,提高程序的灵活性和效率。
本文将详细介绍51单片机中断实施的步骤。
步骤一:设置中断向量表中断向量表是存放中断服务程序入口地址的一组地址。
首先,需要用特定的指令将中断服务程序的入口地址存入中断向量表的相应位置。
51单片机具有8个中断源,对应的中断向量表从0x0003~0x001B,每个中断源有两个地址,分别为中断入口地址和重定向入口地址。
步骤二:开放中断在51单片机中,中断允许位和中断优先级相互影响,因此在开放中断之前,需要设置好相关的中断优先级和中断允许位。
设置中断优先级的方法有两种,一种是通过设置中断允许位的方式,另一种是通过设置寄存器中的优先级位的方式。
步骤三:编写中断服务程序中断服务程序是在中断发生时执行的一段特定的代码。
在编写中断服务程序时,需要注意以下几点: - 中断服务程序必须使用org指令指定入口地址,保证程序正确执行; - 中断服务程序中不应该包含太长的延时和大量的计算; - 中断服务程序中可以操作的寄存器有限,需要仔细查看相关的资料。
步骤四:设置中断允许位为了使中断能够正常工作,需要在中断实施前设置相关的中断允许位。
在51单片机中,P33为总中断允许位,P34为定时器0中断允许位,P3^5为定时器1中断允许位,以此类推。
设置中断允许位的代码如下:EA=1; // 总中断允许位ET0=1; // 定时器0中断允许位ET1=1; // 定时器1中断允许位...步骤五:配置中断源在实施中断之前,需要配置好中断源。
在51单片机中,中断源可以是外部中断、定时器中断、串口中断等等。
配置中断源的代码如下:IT0=1; // 外部中断0下降沿触发IT1=0; // 外部中断1低电平触发...步骤六:启动中断通过设置中断允许位和配置中断源后,即可启动中断。
51单片机中断程序例子
51单片机中断程序例子
1. 外部中断:当外部信号引脚检测到高电平时,单片机会触发外部中断服务程序。
可以利用外部中断实现按键扫描功能,当按键按下时,触发中断程序对按键进行处理。
2. 定时器中断:利用定时器中断可以实现精确的时间控制。
例如,我们可以设置定时器中断为1秒,当定时器溢出时,触发中断程序,实现1秒钟执行一次的任务。
3. 串口中断:当接收到串口数据时,单片机会触发串口中断服务程序,可以利用串口中断实现串口通信功能。
4. ADC中断:当模数转换器完成一次转换时,单片机会触发ADC中断服务程序,可以利用ADC中断实现模拟信号的采集和处理。
5. 看门狗中断:看门狗定时器溢出时,单片机会触发看门狗中断服务程序,可以利用看门狗中断实现系统复位或其他相关功能。
6. 外部中断优先级:当多个外部中断同时触发时,可以通过设置外部中断的优先级来确定触发的顺序和优先级。
7. 定时器中断优先级:当多个定时器中断同时触发时,可以通过设置定时器中断的优先级来确定触发的顺序和优先级。
8. 中断嵌套:单片机支持中断嵌套,即在一个中断服务程序中触发
另一个中断服务程序,可以通过中断嵌套实现复杂的任务处理。
9. 中断屏蔽:单片机支持对中断的屏蔽,即可以通过设置中断屏蔽标志位来屏蔽某些中断,使其暂时不被触发。
10. 中断标志位:单片机提供中断标志位,用于标识中断是否被触发。
在中断服务程序中,可以通过读取和清除中断标志位来判断中断是否发生。
以上是根据51单片机中断程序的例子进行的描述,这些例子涵盖了常见的中断类型和相关功能。
通过学习和理解这些例子,可以更好地掌握51单片机中断编程的原理和方法。
51单片机中断代码
51单片机中断代码51单片机中断代码是在使用51单片机时经常会遇到的一个概念,它可以帮助我们实现一些特定的功能。
本文将介绍51单片机中断代码的基本原理和用法。
一、简介51单片机是一种广泛使用的单片机型号,它具有低成本、易学易用等特点,因此在嵌入式系统开发中得到了广泛应用。
中断是51单片机中的一个重要功能,通过中断,我们可以在程序运行的过程中,根据外部事件的发生来立即打断当前的程序流程执行特定的代码。
二、中断的原理在详细介绍51单片机中断代码之前,我们首先需要了解中断的原理。
中断是由外部事件触发的,当外部事件发生时,中断请求会被送到单片机的中断控制器,然后中断控制器会暂停当前正在执行的程序,并执行特定的中断服务程序。
中断服务程序会在中断处理完成后,恢复之前被暂停的程序继续执行。
三、中断的使用在51单片机中,我们可以通过设置相关的中断向量和中断服务程序来实现中断的功能。
下面是一个简单的例子,展示了如何在51单片机中使用中断代码。
首先,我们需要引入头文件,头文件中包含了51单片机的寄存器定义和中断相关的宏定义。
```c#include <reg51.h>```接下来,我们需要定义中断服务程序。
中断服务程序是一个函数,具有特定的命名规则和参数。
下面是一个简单的中断服务程序的例子,该例子演示了当外部中断触发时,LED灯会闪烁。
```cvoid interrupt_INT0() interrupt 0{P1 = 0xFF; // 将P1口设置为高电平delay(500); // 延时500毫秒P1 = 0x00; // 将P1口设置为低电平delay(500); // 延时500毫秒}```在上面的中断服务程序中,`interrupt_INT0()`是中断的名称,`interrupt 0`表示该中断是外部中断0。
我们可以根据需求设置外部中断的触发条件和中断优先级。
最后,我们需要在主函数中启用中断,并设置相应的中断向量。
51单片机interrupt用法
51单片机interrupt用法1. 什么是51单片机interrupt?51单片机是一种常用的嵌入式微控制器,被广泛应用于各种电子设备中。
中断是一种特殊的处理机制,它允许单片机在执行某个任务的过程中,临时暂停当前的任务,去处理其他紧急事件。
这些紧急事件可以是来自外部设备的信号、计时器溢出等。
2. 为什么要使用interrupt?使用interrupt的好处是可以及时响应外部事件,提高系统的实时性和可靠性。
不使用interrupt的话,单片机只能按照预定的程序执行,无法即时响应外部事件,造成系统的延迟和不稳定。
3. 如何使用interrupt?首先,我们需要了解51单片机的interrupt架构。
51单片机有两个interrupt源,分别是外部中断和定时器/计数器中断。
外部中断:单片机的P3口(即引脚INT0和INT1)可以接收外部中断信号。
当INT0引脚检测到高电平脉冲时(可以通过软件设置为下降沿触发或低电平触发),单片机就会执行外部中断的相关程序。
INT1引脚类似。
定时器/计数器中断:单片机的定时器/计数器模块可以设置定时中断。
定时器可以根据一定的时钟源进行计数,当计数值达到预设值时,就会触发中断。
通过设置计数器的工作模式和计数初值,可以灵活控制定时中断的触发时间和频率。
对于外部中断,我们可以通过设置相应的中断控制寄存器来选择触发方式(下降沿触发、低电平触发等)。
然后,在主程序中需要响应外部中断的地方,我们可以编写一个中断服务程序(ISR),用来处理中断事件。
中断服务程序需要使用关键字”interrupt”进行声明,同时需要保存现场(将寄存器的值及其他关键状态保存在堆栈中),以便中断结束后能够正确恢复。
对于定时器/计数器中断,我们首先需要对定时器进行初始化设置,选择时钟源和工作模式。
然后,我们可以设置计数初值和中断触发时间。
当计数器达到预设值时,中断程序会被执行。
下面我们就来介绍一个常见应用案例:使用外部中断实现按键控制LED的亮灭。
51单片机中断总结
51单片机中断总结:1. 查询优先级为固定的(外部中断0>定时器0>外部中断1>定时器1>串行中断)。
2. 执行优先级可以通过IP寄存器进行设置(高/低)。
3. CPU同时收到多个中断请求时,首先响应优先级较高者,然后相应优先级较低者;如果优先级相同,则按照查询优先级顺序依次响应。
4. 正在执行的中断服务,不能被同级或更低级的中断请求打断,但会被更高级的中断请求打断。
推论(1)高优先级的中断不能被任何其它中断所打断(2)低优先级的中断只能在没有任何中断服务运行时得到响应。
5. 对于定时器和外部中断,在进入中断服务后,其中断标志位会自动清零;对于串行中断,由于有两个中断源,需要手动查询并清零RI或/和TI。
if (RI) {// processingRI = 0;}if (TI) {// processingTI = 0;}6. 如果是使用汇编写中断服务,需要保护累加器、状态寄存器、寄存器组等8051 Tutorial: Interrupts/tutint.phpAs the name implies, an interrupt is some event which interrupts normal program execution.As stated earlier, program flow is always sequential, being altered only by those instructions which expressly cause program flow to deviate in some way. However, interrupts give us a mechanism to "put on hold" the normal program flow, execute a subroutine, and then resume normal program flow as if we had never left it. This subroutine, called an interrupt handler, is only executed when a certain event (interrupt) occurs. The event may be one of the timers "overflowing," receiving a character via the serial port, transmitting a character via the serialport, or one of two "external events." The 8051 may be configured so that when any of these events occur the main program is temporarily suspended and control passed to a special section of code which presumably would execute some function related to the event that occured. Once complete, control would be returned to the original program. The main program never even knows it was interrupted.The ability to interrupt normal program execution when certain events occur makes it much easier and much more efficient to handle certain conditions. If it were not for interrupts we would have to manually check in our main program whether the timers had overflown, whether we had received another character via the serial port, or if some external event had occured. Besides making the main program ugly and hard to read, such a situation would make our program inefficient since wed be burning precious "instruction cycles" checking for events that usually dont happen.For example, lets say we have a large 16k program executing many subroutines performing many tasks. Lets also suppose that we want our program to automatically toggle the P3.0 port every time timer 0 overflows. The code to do this isnt too difficult:JNB TF0,SKIP_TOGGLECPL P3.0CLR TF0SKIP_TOGGLE: ...Since the TF0 flag is set whenever timer 0 overflows, the above code will toggle P3.0 every time timer 0 overflows. This accomplishes what we want, but is inefficient. The JNB instruction consumes 2 instruction cycles to determine that the flag is not set and jump over the unnecessary code. In the event that timer 0 overflows, the CPL and CLR instruction require 2 instruction cycles to execute. To make the math easy, lets say the rest of the code in the program requires 98 instruction cycles. Thus, in total, our code consumes 100 instruction cycles (98 instruction cycles plus the 2 that are executed every iteration to determine whether or not timer 0 has overflowed). If were in 16-bit timer mode, timer 0 will overflow every 65,536 machine cycles. In that time we would have performed 655 JNB tests for a total of 1310 instruction cycles, plus another 2 instruction cycles to perform the code. So to achieve our goal weve spent 1312 instruction cycles. So 2.002% of our time is being spent just checking when to toggle P3.0. And our code is ugly because we have to make that check every iteration of our main program loop.Luckily, this isnt necessary. Interrupts let us forget about checking for the condition. The microcontroller itself will check for the condition automatically and when the condition is met will jump to a subroutine (called an interrupt handler), execute the code, then return. In this case, our subroutine would be nothing more than:CPL P3.0RETIFirst, youll notice the CLR TF0 command has disappeared. Thats because when the 8051 executes our "timer 0 interrupt routine," it automatically clears the TF0 flag. Youll also notice that instead of a normal RET instruction we have a RETI instruction. The RETI instruction does the same thing as a RET instruction, but tells the 8051 that an interrupt routine has finished. You must always end your interrupt handlers with RETI.Thus, every 65536 instruction cycles we execute the CPL instruction and the RETI instruction. Those two instructions together require 3 instruction cycles, and weve accomplished the same goal as the first example that required 1312 instruction cycles. As far as the toggling of P3.0 goes, our code is 437 times more efficient! Not to mention its much easier to read and understand because we dont have to remember to always check for the timer 0 flag in our main program. We just setup the interrupt and forget about it, secure in the knowledge that the 8051 will execute our code whenever its necessary.The same idea applies to receiving data via the serial port. One way to do it is to continuously check the status of the RI flag in an endless loop. Or we could check the RI flag as part of a larger program loop. However, in the latter case we run the risk of missing characters--what happens if a character is received right after we do the check, the rest of our program executes, and before we even check RI a second character has come in. We will lose the first character. With interrupts, the 8051 will put the main program "on hold" and call our special routine to handle the reception of a character. Thus, we neither have to put an ugly check in our main code nor will we lose characters.What Events Can Trigger Interrupts, and where do they go?We can configure the 8051 so that any of the following events will cause an interrupt:Timer 0 Overflow.Timer 1 Overflow.Reception/Transmission of Serial Character.External Event 0.External Event 1.In other words, we can configure the 8051 so that when Timer 0 Overflows or when a character is sent/received, the appropriate interrupt handler routines are called.Obviously we need to be able to distinguish between various interrupts and executing different code depending on what interrupt was triggered. This is accomplished by jumping to a fixed address when a given interrupt occurs.Interrupt Flag Interrupt Handler AddressExternal 0 IE0 0003hTimer 0 TF0 000BhExternal 1 IE1 0013hTimer 1 TF1 001BhSerial RI/TI 0023hBy consulting the above chart we see that whenever Timer 0 overflows (i.e., the TF0 bit is set), the main program will be temporarily suspended and control will jump to 000BH. It is assumed that we have code at address 000BH that handles the situation of Timer 0 overflowing.Setting Up InterruptsBy default at powerup, all interrupts are disabled. This means that even if, for example, the TF0 bit is set, the 8051 will not execute the interrupt. Your program must specifically tell the 8051 that it wishes to enable interrupts and specifically which interrupts it wishes to enable.Your program may enable and disable interrupts by modifying the IE SFR (A8h):Bit Name Bit Address Explanation of Function7 EA AFh Global Interrupt Enable/Disable6 - AEh Undefined5 - ADh Undefined4 ES ACh Enable Serial Interrupt3 ET1 ABh Enable Timer 1 Interrupt2 EX1 AAh Enable External 1 Interrupt1 ET0 A9h Enable Timer 0 Interrupt0 EX0 A8h Enable External 0 InterruptAs you can see, each of the 8051s interrupts has its own bit in the IE SFR. You enable a given interrupt by setting the corresponding bit. For example, if you wish to enable Timer 1 Interrupt, you would execute either:MOV IE,#08horSETB ET1Both of the above instructions set bit 3 of IE, thus enabling Timer 1 Interrupt. Once Timer 1 Interrupt is enabled, whenever the TF1 bit is set, the 8051 will automatically put "on hold" the main program and execute the Timer 1 Interrupt Handler at address 001Bh.However, before Timer 1 Interrupt (or any other interrupt) is truly enabled, you must also set bit 7 of IE. Bit 7, the Global Interupt Enable/Disable, enables or disables all interrupts simultaneously. That is to say, if bit 7 is cleared then no interrupts will occur, even if all the other bits of IE are set. Setting bit 7 will enable all the interrupts that have been selected by setting other bits in IE. This is useful in program execution if you have time-critical code that needs to execute. In this case, you may need the code to execute from start to finish without any interrupt getting in the way. To accomplish this you can simply clear bit 7 of IE (CLR EA) and then set it after your time-criticial code is done.So, to sum up what has been stated in this section, to enable the Timer 1 Interrupt the most common approach is to execute the following two instructions:SETB ET1SETB EAThereafter, the Timer 1 Interrupt Handler at 01Bh will automatically be called whenever the TF1 bit is set (upon Timer 1 overflow).Polling SequenceThe 8051 automatically evaluates whether an interrupt should occur after every instruction. When checking for interrupt conditions, it checks them in the following order:External 0 InterruptTimer 0 InterruptExternal 1 InterruptTimer 1 InterruptSerial InterruptThis means that if a Serial Interrupt occurs at the exact same instant that an External 0 Interrupt occurs, the External 0 Interrupt will be executed first and the Serial Interrupt will be executed once the External 0 Interrupt has completed.Interrupt PrioritiesThe 8051 offers two levels of interrupt priority: high and low. By using interrupt priorities you may assign higher priority to certain interrupt conditions.For example, you may have enabled Timer 1 Interrupt which is automatically called every time Timer 1 overflows. Additionally, you may have enabled the Serial Interrupt which is called every time a character is received via the serial port. However, you may consider that receiving a character is much more important than the timer interrupt. In this case, if Timer 1 Interrupt is already executing you may wish that the serial interrupt itself interrupts the Timer 1 Interrupt. When the serial interrupt is complete, control passes back to Timer 1 Interrupt and finally back to the main program. You may accomplish this by assigning a high priority to the Serial Interrupt and a low priority to the Timer 1 Interrupt.Interrupt priorities are controlled by the IP SFR (B8h). The IP SFR has the following format:Bit Name Bit Address Explanation of Function7 - - Undefined6 - - Undefined5 - - Undefined4 PS BCh Serial Interrupt Priority3 PT1 BBh Timer 1 Interrupt Priority2 PX1 BAh External 1 Interrupt Priority1 PT0 B9h Timer 0 Interrupt Priority0 PX0 B8h External 0 Interrupt PriorityWhen considering interrupt priorities, the following rules apply:Nothing can interrupt a high-priority interrupt--not even another high priority interrupt.A high-priority interrupt may interrupt a low-priority interrupt.A low-priority interrupt may only occur if no other interrupt is already executing.If two interrupts occur at the same time, the interrupt with higher priority will execute first. If both interrupts are of the same priority the interrupt which is serviced first by polling sequence will be executed first.What Happens When an Interrupt Occurs?When an interrupt is triggered, the following actions are taken automatically by the microcontroller:The current Program Counter is saved on the stack, low-byte first.Interrupts of the same and lower priority are blocked.In the case of Timer and External interrupts, the corresponding interrupt flag is cleared.Program execution transfers to the corresponding interrupt handler vector address.The Interrupt Handler Routine executes.Take special note of the third step: If the interrupt being handled is a Timer or External interrupt, the microcontroller automatically clears the interrupt flag before passing control to your interrupt handler routine. This means it is not necessary that you clear the bit in your code.What Happens When an Interrupt Ends?An interrupt ends when your program executes the RETI (Return from Interrupt) instruction. When the RETI instruction is executed the following actions are taken by the microcontroller:Two bytes are popped off the stack into the Program Counter to restore normal program execution.Interrupt status is restored to its pre-interrupt status.Serial InterruptsSerial Interrupts are slightly different than the rest of the interrupts. This is due to the fact that there are two interrupt flags: RI and TI. If either flag is set, a serial interrupt is triggered. As you will recall from the section on the serial port, the RI bit is set when a byte is received by the serial port and the TI bit is set when a byte has been sent.This means that when your serial interrupt is executed, it may have been triggered because the RI flag was set or because the TI flag was set--or because both flags were set. Thus, your routine must check the status of these flags to determine what action is appropriate. Also, since the 8051 does not automatically clear the RI and TI flags you must clear these bits in your interrupt handler.A brief code example is in order:INT_SERIAL: JNB RI,CHECK_TI ;If the RI flag is not set, we jump to check TIMOV A,SBUF ;If we got to this line, its because the RI bit *was* setCLR RI ;Clear the RI bit after weve processed itCHECK_TI: JNB TI,EXIT_INT ;If the TI flag is not set, we jump to the exit pointCLR TI ;Clear the TI bit before we send another characterMOV SBUF,#A ;Send another character to the serial portEXIT_INT: RETIAs you can see, our code checks the status of both interrupts flags. If both flags were set, both sections of code will be executed. Also note that each section of code clears its corresponding interrupt flag. If you forget to clear the interrupt bits, the serial interrupt will be executed over and over until you clear the bit. Thus it is very important that you always clear the interrupt flags in a serial interrupt.Important Interrupt Consideration: Register ProtectionOne very important rule applies to all interrupt handlers: Interrupts must leave the processor in the same state as it was in when the interrupt initiated.Remember, the idea behind interrupts is that the main program isnt aware that they are executing in the "background." However, consider the following code:CLR C ;Clear carryMOV A,#25h ;Load the accumulator with 25hADDC A,#10h ;Add 10h, with carryAfter the above three instructions are executed, the accumulator will contain a value of 35h.But what would happen if right after the MOV instruction an interrupt occured. During this interrupt, the carry bit was set and the value of the accumulator was changed to 40h. When the interrupt finished and control was passed back to the main program, the ADDC would add 10h to 40h, and additionally add an additional 1h because the carry bit is set. In this case, the accumulator will contain the value 51h at the end of execution.In this case, the main program has seemingly calculated the wrong answer. How can 25h + 10h yield 51h as a result? It doesnt make sense. A programmer that was unfamiliar with interrupts would be convinced that the microcontroller was damaged in some way, provoking problems with mathematical calculations.What has happened, in reality, is the interrupt did not protect the registers it used. Restated: An interrupt must leave the processor in the same state as it was in when the interrupt initiated.What does this mean? It means if your interrupt uses the accumulator, it must insure that the value of the accumulator is the same at the end of the interrupt as it was at the beginning. This is generally accomplished with a PUSH and POP sequence. For example:PUSH ACCPUSH PSWMOV A,#0FFhADD A,#02hPOP PSWPOP ACCThe guts of the interrupt is the MOV instruction and the ADD instruction. However, these two instructions modify the Accumulator (the MOV instruction) and also modify the value of the carry bit (the ADD instruction will cause the carry bit to be set). Since an interrupt routine must guarantee that the registers remain unchanged by the routine, the routine pushes the original values onto the stack using the PUSH instruction. It is then free to use the registers it protected to its hearts content. Once the interrupt has finished its task, it pops the original values back into the registers. When the interrupt exits, the main program will never know the difference because the registers are exactly the same as they were before the interrupt executed.In general, your interrupt routine must protect the following registers:PSWDPTR (DPH/DPL)PSWACCBRegisters R0-R7Remember that PSW consists of many individual bits that are set by various 8051 instructions. Unless you are absolutely sure of what you are doing and have a complete understanding of what instructions set what bits, it is generally a good idea to always protect PSW by pushing and popping it off the stack at the beginning and end of your interrupts.Note also that most assemblers (in fact, ALL assemblers that I know of) will not allow you to execute the instruction:PUSH R0This is due to the fact that depending on which register bank is selected, R0 may refer to either internal ram address 00h, 08h, 10h, or 18h. R0, in and of itself, is not a valid memory address that the PUSH and POP instructions can use.Thus, if you are using any "R" register in your interrupt routine, you will have to push that registers absolute address onto the stack instead of just saying PUSH R0. For example, instead of PUSH R0 you would execute:PUSH 00hOf course, this only works if youve selected the default register set. If you are using an alternate register set, you must PUSH the address which corresponds to the register you are using.Common Problems with InterruptsInterrupts are a very powerful tool available to the 8051 developer, but when used incorrectly they can be a source of a huge number of debugging hours. Errors in interrupt routines are often very difficult to diagnose and correct.If you are using interrupts and your program is crashing or does not seem to be performing as you would expect, always review the following interrupt-related issues:Register Protection: Make sure you are protecting all your registers, as explained above. If you forget to protect a register that your main program is using, very strange results may occur. In our example above we saw how failure to protect registers caused the main program to apparently calculate that 25h + 10h = 51h. If you witness problems with registers changing values unexpectedly or operations producing "incorrect" values, it is very likely that you've forgotten to protect registers. ALWAYS PROTECT YOUR REGISTERS.Forgetting to restore protected values: Another common error is to push registers onto the stack to protect them, and then forget to pop them off the stack before exiting the interrupt. For example, you may push ACC, B, and PSW onto the stack in order to protect them and subsequently pop only ACC and PSW off the stack before exiting. In this case, since you forgot to restore the value of "B", an extra value remains on the stack. When you execute the RETI instruction the 8051 will use that value as the return address instead of the correct value. In this case, your program will almost certainly crash. ALWAYS MAKE SURE YOU POP THE SAME NUMBER OF VALUES OFF THE STACK AS YOU PUSHED ONTO IT.Using RET instead of RETI: Remember that interrupts are always terminated with the RETI instruction. It is easy to inadvertantly use the RET instruction instead. However, the RETinstruction will not end your interrupt. Usually, using a RET instead of a RETI will cause the illusion of your main program running normally, but your interrupt will only be executed once. If it appears that your interrupt mysteriously stops executing, verify that you are exiting with RETI.11。
51单片机中断程序原理
51单片机中断程序原理中断是51单片机中一个非常重要的概念,它可以使得单片机在执行程序时,突然停下来去处理发生的事件,然后再回到原来被中断的地方继续执行。
这种机制可以使得单片机具有并发执行多个任务的能力,提高系统的响应速度和实时性。
在51单片机中,中断程序原理是这样的:当一个中断事件发生时,单片机会立即停止当前的操作,保存当前的程序现场(包括程序计数器和寄存器等重要信息),然后跳转到中断服务程序(Interrupt Service Routine,ISR)的指定地址开始执行。
为了实现中断程序,需要进行以下几个步骤:1. 配置中断向量表:中断向量表是一个存储中断服务程序地址的表,它将不同的中断事件映射到对应的中断服务程序。
在51单片机中,中断向量表位于片内RAM的0x00-0x1F地址空间,每个中断事件占用一个字节。
用户需要根据自己的需求,在程序中设置相应的中断向量表。
2. 开启中断:单片机有多个中断源,例如外部中断、定时器中断、串口中断等。
用户需要根据自己的需要选择中断源,并在程序中通过设置相关的寄存器,使得中断源为有效状态。
3. 编写中断服务程序:中断服务程序是用户自定义的一段代码,用于处理中断事件。
它负责完成中断事件的相应操作,比如处理接收到的数据、采集传感器数据等。
中断服务程序执行完后,需要使用RET指令返回到中断被触发的地方继续执行。
总之,中断程序原理是通过配置中断向量表、开启中断和编写中断服务程序三个步骤来实现的。
中断可以允许单片机在执行主程序时,及时地响应外部事件,并对其进行处理。
这在实际的应用中非常重要,可以提高系统的可靠性、实时性和响应速度。
51单片机中断函数
51单片机中断函数单片机的中断是指当单片机在正常运行的过程中,突然接收到来自外部设备或者其他源的信号时,能够立即停止正在执行的程序,转而执行一个特定的子程序,完成接收到的信号处理。
单片机中断函数是在中断发生时执行的一段程序代码。
下面将详细介绍51单片机中断函数的原理和使用方法。
首先,需要了解51单片机的中断原理。
51单片机有5个中断源,分别是外部中断0和1(INT0和INT1),定时器/计数器0和1的中断,以及串口中断(RI/TI)。
每个中断源都有自己的中断标志位,当中断源发生时,相应的中断标志位会被设置为1在单片机的中断函数中,需要首先设置中断使能位,使能相应的中断源。
然后,需要编写中断服务子程序(ISR)的函数体,该函数用于处理中断发生时需要完成的任务。
在ISR中,需要首先清除中断标志位,以防止重复中断。
然后,根据需要进行相关的处理,例如读取外部触发的信号或者发送/接收数据等。
以下是一个简单的外部中断0的中断函数示例:```C#include <reg52.h>void ExtInt0_ISR( interrupt 0//处理中断//...//清除中断标志位EX0=0;//使能外部中断0//...EX0=1;void main//设置中断使能位EA=1;//总中断使能位EX0=1;//使能外部中断0//...while (1)//主程序代码//...}```在上述代码中,`ExtInt0_ISR`函数是外部中断0的中断服务子程序,它使用`interrupt 0`关键字来声明,表示该函数用于处理外部中断0。
在`ExtInt0_ISR`函数体中,可以编写处理中断的代码。
在`main`函数中,首先使用`EA=1`来使能总中断,然后使用`EX0=1`使能外部中断0。
在主程序中的循环中,单片机会一直运行,直到外部中断0发生。
当外部中断0发生时,单片机会立即跳转到`ExtInt0_ISR`函数执行相应的任务。
51单片机的串口中断设置
51单片机的串口中断设置首先,你要用软件允许中断,即C语言中EA = 1; 允许总中断ES = 1;//允许串口中断汇编中可用SETB EA ;允许总中断SETB ES ;允许串口中断当单片机接收到一帧数据后,RI会置1,向CPU申请中断,若之前有中断允许,则产生了中断,进入中断服务程序。
当然,单片机发送完一帧数据,TI也会置1,同样会产生中断!一般我们在发送数据时要关中断,因为一般你不用在发送时不用处理数据;接收数据时要开中断,以便你在中断服务程序中将接收到的数据进行存储并处理。
补充:其实,不管你有没有允许中断,上位机(此时即给单片机发送信息的机器)只要给单片机发送数据,单片机就会自动接收数据,并把它放在数据缓冲器SBUF中,如果你之前有允许串行口中断,RI就会置1,向单片机CPU 申请中断,并进入中断服务程序,做完中断函数后就会自动返回断点。
如果你没有允许中断,便不会产生串行中断。
其实,别的中断都是某个I/O口电平变化产生。
这只是外部中断产生条件,不过,你之前也需要用软件允许外部中断。
另外,常见的51系列单片机有5个中断源三种中断5:1、外部中断0和1;2、定时器/计数器溢出中断0和1;3、串行口中断。
另外,STC51系列还有定时器/计数器T2中断,A/D转换中断,PWM中断,串行中断2等等。
你还有什么不懂的可以自己多翻一翻书,学到后面去了你就明白了。
中断服务程序中,那条 RI=0;是不可少的,这是用软件清零RI,准备再次接受一帧数据产生中断,如果你没有这条语句,就会进入死循环,出不来了。
void serial() interrupt 4{ P1=SBUF;RI=0;}。
51单片机中断程序例子
51单片机中断程序例子1. 外部中断程序:外部中断是指由外部设备或外部信号触发的中断。
在51单片机中,通过设置中断允许位和中断优先级来实现对外部中断的响应。
例如,当外部设备发出一个信号时,单片机可以立即停止当前任务,转而执行外部中断程序。
外部中断程序的编写需要根据具体的外部设备和信号进行相应的处理,如读取设备状态、处理数据等。
通过外部中断程序,可以实现单片机与外部设备的互动和数据交换。
2. 定时器中断程序:定时器中断是指通过设置定时器的计数值和中断允许位,使得在指定的时间间隔内触发中断。
在51单片机中,可以通过定时器中断来实现定时任务的执行。
例如,可以设置一个定时器,在每隔一定的时间就触发中断,然后在中断程序中执行相应的任务,如数据采集、数据处理等。
通过定时器中断程序,可以实现定时任务的自动执行,提高系统的实时性和可靠性。
3.串口中断程序:串口中断是指通过串口通信接口接收或发送数据时触发的中断。
在51单片机中,可以通过设置串口中断允许位和中断优先级来实现对串口数据的中断处理。
例如,当接收到一个完整的数据包时,单片机可以立即停止当前任务,转而执行串口中断程序,对接收到的数据进行处理。
通过串口中断程序,可以实现单片机与外部设备的数据交换和通信。
4. ADC中断程序:ADC(模数转换器)中断是指在进行模数转换时触发的中断。
在51单片机中,可以通过设置ADC中断允许位和中断优先级来实现对模数转换结果的中断处理。
例如,当模数转换完成后,单片机可以立即停止当前任务,转而执行ADC中断程序,对转换结果进行处理和分析。
通过ADC中断程序,可以实现对模拟信号的采集和处理,用于实时监测和控制。
5. 外部中断优先级设置:在51单片机中,可以通过设置外部中断的中断优先级来确定中断的响应顺序。
中断优先级越高,优先级越高的中断会先被响应。
通过合理设置中断优先级,可以确保关键任务的及时响应和执行。
例如,当多个外部设备同时发出中断信号时,可以通过设置优先级,确保先响应优先级高的设备,保证系统的正常运行。
c51单片机定时器中断的执行过程
c51单片机定时器中断的执行过程
C51单片机定时器中断的执行过程可以分为以下几个步骤:
1. 初始化定时器:首先需要对定时器进行初始化,设置定时器的计数模式、计数值、溢出方式等参数。
这些参数可以通过编程实现,也可以通过硬件电路进行调整。
2. 启动定时器:初始化完成后,需要启动定时器。
启动定时器后,定时器开始按照预设的参数进行计数。
当计数值达到预设的溢出值时,定时器会产生一个溢出信号。
3. 设置中断服务程序:为了在定时器溢出时执行特定的操作,需要设置一个中断服务程序 ISR)。
中断服务程序是一段特殊的代码,它会在定时器溢出时被自动调用。
4. 开启中断:在中断服务程序设置完成后,需要开启相应的中断。
开启中断后,当定时器溢出时,CPU会自动跳转到中断服务程序执行。
5. 执行中断服务程序:当定时器溢出时,CPU会暂停当前任务,跳转到中断服务程序执行。
在中断服务程序中,可以执行一些特定的操作,如更新显示、读取传感器数据等。
6. 返回主程序:中断服务程序执行完成后,CPU会自动返回到主程序继续执行。
这样,通过定时器中断,可以实现对单片机的周期性控制和数据采集等功能。
51单片机中断
中断一、中断允许寄存器 IEEA-----全局中断允许位EA=0打开全局中断控制。
EA=1关闭全部中断。
ET2----定时器/计数器2中断允许位 ET2=1打开T2中断。
ET2=0关闭T2中断。
ES----串口中断允许位。
ES=1打开串口中断。
ES=0关闭串口中断。
EX1----外部中断1中断允许位; EX1=1打开外部中断1中断。
EX1=0关闭外部中断1中断。
ET0----定时期计数器0中断允许位 ET0=1,打开T0中断。
ET0=0,关闭T 中断。
EX0----外部中断0中断允许位。
位序号 D7 D6 D5 D4 D3 D2 D1 D0 位符号 EA -- ET2 ES ET1 EX1 ET0 EX0 位地址 AFH -- ADH ACH ABH AAH A9H A8HEX0EA PX001ET0PT001EX1PX101ET1PT101ES PS 01≥1RI TISCONTCONIE0TF0IE1TF11101IT0IT1INT0INT1T0T1RX TXIEIP11111111硬件查询自然优先级自然优先级中断入口中断入口高级低级中断源中断源EX0=1打开外部中断0中断。
EX0=0关闭外部中断0中断。
二、中断优先级级寄存器IP位序号D7 D6 D5 D4 D3 D2 D1 D0 位符号-- -- -- PS PT1 PX1 PT0 PX0 位地址-- -- -- BCH BBH BAH B9H B8H 单片机的定时器中断一、定时器/计数器工作方式寄存器TMOD位序号D7 D6 D5 D4 D3 D2 D1 D0 位符号GATE C/T M1 M0 GATE C/T M1 M0 二、定时器/计数器控制寄存器TCON位序号D7 D6 D5 D4 D3 D2 D1 D0位符号TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0 位地址8FH 8EH 8DH 8CH 8BH 8AH 89H 88H。
51单片机interrupt用法
51单片机interrupt用法
Interrupt是指中断,指计算机在执行一段程序时,突然停下来去执行另外一个程序的过程。
在51单片机中,Interrupt也是一种非常重要的编程概念。
它可以让程序在执行的过程中,根据外部的信号来中断当前的执行,去执行一些其他的操作,待操作完成后再回到原来的程序中继续执行。
在51单片机中,Interrupt的使用非常简单。
我们可以通过以下步骤来配置Interrupt:
1.选择使用哪个Interrupt:在51单片机中,有多个Interrupt 可以使用,比如Timer Interrupt、External Interrupt等。
我们需要根据具体的需求来选择需要使用的Interrupt。
2.配置Interrupt的优先级:在多个Interrupt同时发生时,需要按照一定的优先级来执行。
在51单片机中,我们可以通过设置Interrupt的优先级来实现。
3.设置Interrupt的触发方式:在51单片机中,Interrupt可以按照电平触发或者边沿触发来执行。
我们需要根据具体的需求来设置Interrupt的触发方式。
4.编写Interrupt服务程序:在Interrupt被触发时,需要执行一段特定的程序来处理中断。
我们需要编写一个Interrupt服务程序来实现。
5.开启Interrupt:最后,我们需要在程序中开启Interrupt,让它能够正常运行。
总之,Interrupt是51单片机编程中非常重要的一个概念。
掌
握了Interrupt的使用方法,可以为我们的程序提供更加强大的功能。
51单片机串口中断的两种写法
单片机串口通信在嵌入式系统中具有非常重要的作用,而其中串口中断的编写方式更是至关重要。
今天我们来讨论一下51单片机串口中断的两种写法。
1. 外部中断写法在51单片机中,串口通信一般使用串口中断来实现。
外部中断写法是一种常见的串口中断编写方式。
其具体步骤如下:1)需要设置串口工作参数,包括波特率、数据位、停止位和校验位等。
2)在主程序中使能串口中断,并设置中断优先级。
3)在中断服务函数中进行接收数据的处理,可以通过接收缓冲区、中断标志位等来判断接收数据的情况,并进行相应的处理。
2. 定时器中断写法除了外部中断写法,定时器中断也是一种常见的串口中断编写方式。
其具体步骤如下:1)同样需要设置串口工作参数,包括波特率、数据位、停止位和校验位等。
2)在主程序中初始化定时器,并使能定时器中断。
3)在定时器中断服务函数中进行接收数据的处理,同样可以通过接收缓冲区、中断标志位等来判断接收数据的情况,并进行相应的处理。
总结无论是外部中断写法还是定时器中断写法,都是实现51单片机串口通信的常见方式。
在选择具体的编写方式时,需要根据具体的应用场景和需求来进行选择。
在实际应用中,可以根据具体情况来灵活选择合适的串口中断编写方式,以便更好地满足系统的需求。
在实际编写中断服务函数时,需要注意以下几点:1)处理数据时需要考虑数据的完整性和准确性,可以通过校验位等手段来验证数据的正确性。
2)在中断服务函数中应尽量减少对全局变量的访问,以避免出现数据冲突和竞争的情况。
3)合理设置中断优先级,避免产生中断嵌套和冲突。
通过合理的中断编写方式和注意事项,可以更好地实现串口通信功能,提高系统的稳定性和可靠性,为嵌入式系统的应用提供良好的技术支持。
对于外部中断写法和定时器中断写法,两者各有优缺点。
外部中断写法在串口数据到达时能够即刻响应中断、处理数据。
但是,如果数据传输速率较快或需要高精度的数据处理,外部中断写法可能无法满足要求。
在这种情况下,定时器中断写法显得更加合适。
51单片机中断代码解释
51单片机中断代码解释一、引言51单片机是一种广泛使用的微控制器,具有丰富的中断功能。
中断是单片机在执行程序过程中,由于某种原因需要暂停当前的任务,转而处理更为紧急的事件。
处理完该事件后,再返回到之前被中断的程序继续执行。
本文将对51单片机的中断代码进行详细解释,包括中断概念、中断源、中断寄存器和寄存器功能与赋值说明等方面。
二、中断概念中断是一种计算机系统中处理优先级更高任务的方式。
当某个事件发生时,CPU会暂时停止当前任务的执行,转而处理该事件。
处理完该事件后,CPU会返回到之前被中断的程序继续执行。
三、中断源51单片机有多种中断源,包括外部中断0、外部中断1、定时器0、定时器1等。
每个中断源都可以独立地开启或关闭,并且可以设置优先级。
四、中断寄存器51单片机与中断相关的寄存器主要有:1.ICON(中断允许控制寄存器):用于控制中断的开启和关闭。
可以通过设置ICON寄存器的相关位来启用或禁用某个中断。
2.INT0/INT1(外部中断0/1控制寄存器):用于控制外部中断0和外部中断1的触发方式、触发边沿和触发方式等。
3.TMOD(定时器模式控制寄存器):用于设置定时器的模式和工作方式。
4.TH0/TH1(定时器0/1计数器高8位寄存器):用于存储定时器的计数值。
5.TL0/TL1(定时器0/1计数器低8位寄存器):用于存储定时器的计数值。
五、寄存器功能与赋值说明1.ICON寄存器:o EA:全局中断允许位,设置为1时允许所有中断,设置为0时禁止所有中断。
o ET0:定时器0中断允许位,设置为1时允许定时器0中断,设置为0时禁止定时器0中断。
o ET1:定时器1中断允许位,设置为1时允许定时器1中断,设置为0时禁止定时器1中断。
o EX0:外部中断0允许位,设置为1时允许外部中断0,设置为0时禁止外部中断0。
o EX1:外部中断1允许位,设置为1时允许外部中断1,设置为0时禁止外部中断1。
2.INT0/INT1寄存器:o IT0/IT1:外部中断0/1触发方式选择位,设置为0时选择下降沿触发,设置为1时选择低电平触发。
C51单片机教程——中断的应用
C51单片机教程——中断的应用中断是单片机中重要的功能之一,它可以在需要时打断当前程序的执行,转而去执行其他的相关程序,完成以不阻塞常规程序流程的方式处理一些特殊事件。
本文将介绍C51单片机中断的应用。
首先,我们需要了解中断的基本概念。
中断是单片机处理器和外部世界之间的一种通信方式,它通过改变处理器的执行流程来响应外部事件。
单片机处理器在执行中断时会暂停当前任务,转而去执行中断服务程序,中断服务程序执行完毕后,再回到原来被打断的地方继续执行。
通过使用中断,可以提高单片机系统的实时性和响应能力。
在C51单片机中,中断是通过专门的中断向量表和中断控制寄存器实现的。
中断向量表存储了中断服务程序的入口地址,中断控制寄存器用于配置中断的相关参数,如中断源、中断优先级等。
C51单片机支持多个中断源,包括外部中断、定时器中断、串口中断等。
以下是一些中断的常见应用场景。
1.外部中断:外部中断通常用于处理外部触发事件,比如按键、开关等输入信号。
当外部触发事件发生时,单片机会自动跳转到相应的中断服务程序执行。
我们可以在中断服务程序中编写相应的代码来处理触发事件,比如改变状态、计数等。
2.定时器中断:定时器中断常用于定时任务的处理。
通过配置定时器的参数,可以使单片机在设定的时间间隔内产生定时中断。
在定时器中断服务程序中,我们可以编写相应的逻辑代码,比如实现定时器计数、LED闪烁、蜂鸣器发声等功能。
3.串口中断:串口中断用于处理串口通信时的数据传输。
当有数据接收或发送时,单片机会自动触发串口中断,并跳转到中断服务程序中处理数据。
在串口中断服务程序中,我们可以编写相应的代码来处理接收或发送的数据。
例如,我们可以接收串口数据并进行处理或者发送数据到外部设备。
4.ADC中断:ADC中断用于处理模拟信号的采集和转换。
当ADC转换完成后,单片机会自动触发ADC中断,并跳转到中断服务程序中。
在中断服务程序中,我们可以读取ADC的转换结果,进行进一步的处理。
51单片机中断函数
51单片机中断函数51单片机中断函数是一种用于处理外部事件的特殊函数。
当外部事件发生时,中断函数会被调用,以处理这些事件并采取相应的措施。
在51单片机中,中断函数起到了非常重要的作用,它可以让单片机在处理其他任务时及时响应外部事件,提高系统的实时性和可靠性。
中断函数的编写需要遵循一定的规范和流程。
下面将详细介绍51单片机中断函数的编写步骤及其应用。
第一步:中断向量的设置中断向量是用于保存中断函数入口地址的特殊存储单元。
在51单片机中,每个外部中断都对应一个中断向量。
中断向量的地址是固定的,它们的值存放在特定的RAM区域中。
需要根据具体的外部中断需要设置相关的中断向量。
第二步:中断控制寄存器的设置中断控制寄存器用于设置和控制中断的产生和响应。
其中,IE寄存器用于打开和关闭中断,EA寄存器用于全局控制中断的打开和关闭。
需要根据具体的需求设置相关的中断控制寄存器。
第三步:中断服务程序(ISR)的编写中断服务程序是中断函数的实际代码部分。
它需要根据具体的外部事件,实现相应的功能和处理逻辑。
在编写中断服务程序时,需要注意以下几点:1.入栈和出栈操作:中断服务程序在执行之前需要将CPU的现场保护起来,在执行完成后需要将CPU的现场恢复回去。
这就需要进行对应的入栈和出栈操作。
2.中断标志的清除:在中断服务程序执行期间,需要清除中断标志位,以确保不会再次触发中断。
具体的清除方法和寄存器的设置需根据具体的中断控制寄存器标志位来确定。
3.中断事件的处理:根据具体的需求,编写相应的中断处理逻辑。
可以在中断服务程序中实现对IO口的读写、定时器的操作、数据的处理等。
第四步:中断服务程序的调用中断服务程序需要在中断向量中设置的入口地址处调用,以确保在发生中断时能正确地调用中断服务程序。
中断函数的应用非常广泛。
例如,可以使用外部中断来处理按键输入,实现对按键的检测和相应操作;也可以使用定时器中断实现定时功能,如定时采集传感器数据、定时发送数据等;还可以使用串口中断实现数据的接收和发送等。
C51单片机教程——中断的应用
C51单片机教程——中断的应用
一、中断的概念
中断是一种与主程序中断的机制,是CPU在遇到一个特定的事件触发后,立即从主程序中断,跳转到特定的中断服务程序(ISR)中执行。
一
旦中断程序执行完毕,CPU就会回到主程序的执行位置,继续执行主程序。
由于中断会立即响应,它可以用来处理急躁的外部设备事件,把实时性要
求比较高的任务处理正确,这些即使cpu在时间短暂中断,也不会对后续
程序运行产生太大的影响。
二、单片机中断的实现
1、中断类型:单片机的中断有外部中断与定时器中断两种,一般外
部中断处理外设的发出中断请求(如串口发出的数据中断、按键的按下中断),定时器中断用于定时计数(用于产生节拍用,如定时器中断每
10ms产生一个节拍)。
2、中断使能:单片机的中断有相应的中断使能位,当开启相应的中
断使能位时,单片机才会接受这种中断信号。
3、中断服务程序:单片机的中断服务一般由中断服务程序(ISR)实现,当CPU遇到中断时,会跳转到中断服务程序中,具体的由定义的中断
服务程序完成中断处理。
4、中断响应速度:中断响应速度是指单片机接收到中断信号到跳转
到中断服务程序的延时时间,这个速度受单片机芯片结构及设计的影响,
一般1-2微秒可以完成中断响应。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
的使能位 中断号 中断源
--------------------------------
IE.0 0 外部中断0
IE.1 1 定时器0 溢出
IE.2 2 外部中断1
IE.3 3 定时器1 溢出
IE.4 4 串口中断
IE.5 5 定时器2 溢出
8051 系列 MCU 的基本结构包括:32 个 I/O 口(4 组8 bit 端口);两个16 位定时计数器;全双工串行通信;6 个中断源(2 个外部中断、2 个定时/计数器中断、1 个串口输入/输出中断),两字节可寻址数据和代码区。中断发生后,MCU 转到 5 个中断入口处之一,然后执行相应的中断服务
寄存器组使用的原则:
1、8051 的最低32 个字节分成 4 组 8 寄存器。分别为寄存器R0 到R7。寄存器组由PSW 的低两位选择。在 ISR 中,MCU 可以切换到一个不同的寄存器组。对寄存器组的访问不可位寻址,C51 编译器规定使用 using 或 禁止中断的函数(#pragma disable)均不能返回 bit 类型的值。
2、主程序(main函数)使用一组,如 bank 0;低中断优先级的所有中断均使用第二组,如 bank 1;高中断优先级的所有中断均使用再另外一组,如 bank 2。显然,同级别的中断使用同一组寄存器不会有问题,因为不会发生中断嵌套;而高优先级的中断则要使用与低优先级中断不同的一组,因为有可能出现在低优先级中断中发生高优先级中断的情况。编译器会自动判断何时可使用绝对寄存器存取。
举一例子:当需要在中断内和中断外调用同一个函数,假定按照程序的流程控制,不会出现函数的递归调用现象,这样的调用会不会出现问题?若确定不会发生重入情况,则有以下两种情况:
1、如果 ISR 和主程序使用同一寄存器组(主程序缺省使用BANK 0,若 ISR 没有使用 using 为其指定寄存器区,则缺省也使用 BANK 0),则不需其他设置。
1、中断服务函数使用 using 指定与主函数不同的寄存器组(主函数一般使用 Register bank 0)。
2、中断优先级相同的ISR 可用 using 指定相同的寄存器组,但优先级不同的 ISR 必须使用不同的寄存器组,在 ISR 中被调用的函数也要使用 using 指定与中断函数相同的寄存器组。
0 外部中断0
1 定时器0
2 外部中断1
3 定时器1
4 串行中断
其它的根举相应得单片机有自己的含义,实际上c载编译的时候就是把你这个函数的入口地址方到这个对应中断的跳转地址
using y 这个y是说这个中断函数使用的那个寄存器组就是51里面一般有4个 r0 -- r7寄存器,如果你的终端函数和别的程序用的不是同一个寄存器组则进入中断的时候就不会将寄存器组压入堆栈返回时也不会弹出来节省代码和时间
处理程序。中断程序的入口地址被编译器放在中断向量中,中断向量位于程序代码段的最低地址处,注意这里的串口输入/输出中断共用一个中断向量。8051的中断向量表如下:
中断源 中断向量
---------------------------
上电复位 0000H
外部中断0 0003H
定时器0 溢出 000BH
2、如果 ISR 和主程序使用不同的寄存器组(主程序缺省使用BANK 0,ISR 使用 using 指定了其他 BANK),则被调用函数必须放在:
#pragma NOAREGS
#pragma AREGS
控制参数对中,指定编译器不要对该函数使用绝对寄存器寻址方式;或者也可在 Options->C51,选中“Don't use absolute register accesses”,使所有代码均不使用绝对寄存器寻址方式(这样,执行效率将稍有降低)。不论以上的哪一种情况,编译器均会给出重入警告,需手工更改 OVERLAY 参数,做重入说明。
3、还有一种办法:如果被调用函数的代码不是很长,还是将该函数复制一份,用不同的函数名代替,这种情况适合ROM有足够多余的空间。
因此,对using关键字的使用,如果没把握,宁可不用,交给编译系统自己去处理好了。
interrupt xx using y
跟在interrupt 后面的xx 值得是中断号,就是说这个函数对应第几个中断端口,一般在51中
一般只有using 0,1,2,3
单片机中断响应可以分为以下几个步骤:1、停止主程序运行。当前指令执行完后立即终止现行程序的运行。2、保护断点。把程序计数器PC 的当前值压入堆栈,保存终止的地址(即断点地址),以便从中断服务程序返回时能继续执行该程序,3、寻找中断入口。根据5 个不同的中断源所产生的中断,查找5 个不同的入口地址。4、执行中断处理程序。这就不讲了;5、中断返回。执行完中断处理程序后,就从中断处返回到主程序,继续往下执行。
using 关键字用来指定中断服务程序使用的寄存器组。用法是:using 后跟一个0 到3 的数,对应着 4 组工作寄存器。一旦指定工作寄存器组,默认的工作寄存器组就不会被压栈,这将节省 32 个处理周期,因为入栈和出栈都需要 2 个处理周期。这一做法的缺点是所有调用中断的过程都必须使用指定的同一个寄存器组,否则参数传递会发生错误。因此对于using,在使用中需灵活取舍。
既然可以设定人工优先级,那么它又是如何来设置的呢?其实很简单,我们只要把IP 寄存器的对应位置“1”就可以了,看下面的表:
× × × PS PT1 PX1 PT0 PX0
串口 T1 INT1 T0 INT0
开机时,每个中断都处于低优先级,我们可以用指令来对优先级进行设置。例如:现在有如下要求,将T0、INT1 设为高优先级,其它为低优先级,求IP 的值。
外部中断1 0013H
定时器1 溢出 001BH
串行口中断 0023H
定时器2 溢出 002BH
interrupt 和 using 都是 C51 的关键字。C51 中断过程通过使用 interrupt 关键字和中断号(0 到 31)来实现。中断号指明编译器中断程序的入口地址中断序号对应着 8051中断使能寄存器IE 中的使能位,对应关系如下:
IP 的首3 位没用,可任意取值,设为000,后面根据要求写:00000110,即IP=06H,看下面的表。
× × × PS PT1 PX1 PT0 PX0
0 0 0 0 0 1 1 0
void int_0(void) interrupt 0 using 1 {
....
}
在默认状态下,func使用寄存器组0(BANK0),那么当int_0调用func时是否存在当传递参数时会造成参数传递错误?
谢谢!
如果在中断服务函数 ISR 中使用寄存器,那么必须处理好 using 的使用问题:
3、如果不用 using 指定,在 ISR 的入口,C51 默认选择寄存器组0,这相当于中断服务程序的入口首先执行指令:
MOV PSW #0
这点保证了,没使用 using 指定的高优先级中断。可以中断使用不同的寄存器组的低优先级中断。
4、使用 using 关键字给中断指定寄存器组,这样直接切换寄存器组而不必进行大量的 PUSH 和 POP 操作,可以节省RAM空间,加速 MCU 执行时间。寄存器组的切换,总的来说比较容易出错,要对内存的使用情况有比较清晰的认识,其正确性要由你自己来保证。特别在程序中有直接地址访问的时候,一定要小心谨慎!至于“什么时候要用到寄存器组切换”,一种情况是:当你试图让两个(或以上)作业同时运行,而且它们的现场需要一些隔离的时候,就会用上了。在 ISR 或使用实时操作系统RTOS 中,寄存器非常有用。
有了这一声明,编译器不需理会寄存器组参数的使用和对累加器A、状态寄存器、寄存器B、数据指针和默认的寄存器的保护。只要在中断程序中用到,编译器会把它们压栈,在中断程序结束时将他们出栈。C51 支持所有 5 个 8051 标准中断从 0 到 4 和在 8051 系列(增强型)中多达 27 个中断源。
3、在 ISR 中调用其它函数,必须和中断使用相同的寄存器组。当没用 NOAREGS 命令做明确的声明,编译器将使用绝对寄存器寻址方式访问函数选定(即用 using 或 REGISTERBANK 指定)的寄存器组,当函数假定的和实际所选的寄存器组不同时,将产生不可预知的结果,从而可能出现参数传递错误,返回值可能会在错误的寄存器组中。
以上工作是由计算机自动完成的,与编程者无关,在这5 个入口地址处存放有中断处理的程序(这是程序编写时放在那儿的,如果没把中断处理程序放在那儿可就错了,因为中断程序无法被执行到)。有点复杂是吗?没关系,继续往下看。
五个中断源的自然优先级由高到低的排列顺序为外中断0→定时器0→外中断1→定时器1→串口中断。如果我们不对其进行设置,单片机就按照此顺序不断的循环检查各个中断标志(就像我们生活中按照习惯处理事物一样),但有时我们需要人工设置高、低优先级,也就是说由编程者来设定哪些中断是高优先级、哪些中断是低优先级(当然由于只有两级,所以必然只有一些中断处于优先级别,而其他的中断则处于同一级别,处于同一级别的中断顺序就由自然优先级来确定,这一点请大家务必搞清楚了)。
关于using:
您在文中说明“这一做法的缺点是所有调用中断的过程都必须使用指定的同一个寄存器组”是不是这个意思?
举个例子来说:
定义一个函数
void func(unsigned char i) {
...
if(++i==0x12) {
...
}
...
}
有如下一个中断函数