1、51 单片机中断系统程序实例 (STC89C52RC)51 单片机有了中断,在程序设计中就可以做到,在做某件事的过程中,停下来先去响应中断,做别的事情,做好别的事情再继续原来的事情。中断优先级是可以给要做的事情排序。单片机的学习不难,只要掌握学习方法,学起来并不难。什么是好的学习方法呢,一定要掌握二个要点:1. 要知道寄存器的英文全拼,比如 IE = interrupt 中断不知道全拼,要去猜,去查。这样就可以理解为什么是这个名称,理解了以后就不用记忆了。2. 每个知识点要有形像的出处比如看到 TF0,脑子里马上要形像地定位到 TCON 寄存器的某位看到 ET0, 马上要形像地定位到 IE 寄
2、存器的第 2 位http:/ 形像是记忆的最大技巧。当人眼看到某个图时,是把视觉信号转化成电信号,再转化成人能理解的形像。当我们回忆形像时,就是在重新检索原先那个视觉信号,并放大。在学习过程中,不断练习检索、放大信号,我们的学习能力就会越来越强。写程序代码时,也要把尽量把每行代码形像化。51 单片机内中断源8051 有五个中断源,有两个优先级。与中断系统有关的特殊功能寄存器有IE(中断允许寄存器)、IP(中断优先级控制寄存器)、中断源控制寄存器(如 TCON、SCON 的有关位)。51 单片机的中断系统结构如下图(注意,IF0 应为 TF0):8052 有 6 个中断源,它比 8051 多一个
3、定时器/计数器 T2 中断源。8051 五个中断源分别是:(1)51 单片机外部中断源8051 有两个外部中断源,分别是 INT0 和 INT1,分别从 P3.2 和 P3.3 两个引脚引入中断请求信号,两个中断源的中断触发允许由 TCON 的低 4 位控制,TCON的高 4 位控制运行和溢出标志。INT0 也就是 Interrupt 0。在这里应该看一下你的 51 单片机开发板的电路原理图。离开形像的记忆是没有意义的。读到上面这句,你应该回忆起原理图上的连接。任何记忆都转化为形像,这是学习的根本原理,我们通过学习单片机要学会这种学习方法,会让你一辈子受益无穷。TCON 的结构如下图:(a)定
4、时器 T0 的运行控制位 TR0TR0 由软件置位或者清 0。当门控位 GATE=0 时,TO 计数器仅由 TR0 控制,TR0=1 启动计数,TR0=0 时停止。当门控位 GATE=1 时,T0 计数器由 INT0 和 TR0共同控制,当 INT0=1 且 TR0=1 时启动 T0 计数器。(b)定时器 T0 溢出标志位 TF0当 T0 溢出时 TF0=1,并向 CPU 申请中断,CPU 响应中断后由硬件将 TF0 清 0,也可以由软件查询方式将 TF0 清 0。c)定时器 T1 的运行控制位 TR1功能同 TR0。(d)定时器 T1 溢出标志为 TF1功能同 TF1。(e)外部中断源 1(
5、INT1、P3.3)中断请求标志 IE1IE1=1 时外部中断源 1 正在向 CPU 请求中断,当 CPU 响应该中断时由硬件将 IE1清 0(下降沿触发方式)。(f)外部中断源 1 触发方式选择位 IT1IT1=0 时外部中断源 1 选择电平触发方式,当输入低电平时置位 IE1;IT1=1 时外部中断源 1 选择下降沿触发方式,当中断源由高电平变低电平时置位 IE1,向 CPU 请求中断。(g)外部中断源 0(INT0、P3.2)中断请求标志 IE0功能类同 IE1。(h)外部中断源 0 触发方式选择位 IT0功能类同 IT1。CPU 在每个机器周期采样 INT0 和 INT1 引脚的输入电
6、平。i、电平触发方式当 CPU 采样到低电平时,置位 IE0 和 IE1,采样到高电平时,将 IE0 和 IE1 清零。在电平触发方式下,外部中断源必须一直保持低电平(至少保持 1 个以上的机器周期)直到 CPU 响应中断请求,否则中断请求将丢失,同时在中断处理程序结束之前必须,外部中断源必须变为高电平,否则将产生另一次中断。ii、下降沿触发方式CPU 每个机器周期采样中断输入引脚,如果相续的两次采样,第一次是高电平,第二次是低电平,则置位相应的 IE,响应中断后,硬件自动将 IE 清 0。采样下降沿触发方式,中断源的高、低电平都必须保持 12 个振荡周期(即 1 个机器周期)以上,这样 CP
7、U 才能有效检测到下降沿,并引发 CPU 中断。(2)51 单片机内部中断源8051 有 3 个内部中断源,分别是定时器 T0、T1 和串行口中断。8052 增加了一个 T2 定时器中断。2、51 单片机中断使能控制中断的允许和禁止由中断使能控制寄存器 IE 控制,其字节地址为 0A8H,可以位寻址,其结构如下图所示:EX0:外部中断 0 中断允许位;ET0:定时器/计数器 T0 中断允许位;EX1:外部中断 1 中断允许位;ET1:定时器/计数器 T1 中断允许位;ES:串行口中断允许位;ET2:定时器/计数器 T2 中断允许位;(只要 8052 具有)EA:CPU 中断总允许位,EA=1
8、时所有的中断开放,EA=0 时禁止所有的中断。3、51 单片机中断优先级51 有两个优先级:高、低。通过 IP(中断优先级寄存器)来设置优先级,其字节地址为 0B8H,可位寻址,其结构如下图:IP 中各位值为 0 时表示低优先级中断,为 1 时表示高优先级中断。CPU 复位后IP=0。高优先级中断可以中断低优先级中断,同优先级中断不能相互中断。当 CPU 同时接到同优先级的几个中断请求时,CPU 按照如下硬件顺序进行中断响应:4、51 单片机中断请求的撤除CPU 响应中断请求,执行中断服务程序,但在中断返回指令(RETI)之前必须撤除中断信号,否则将可能再次引起中断而发生错误。中断请求撤销的方
9、法有三种:a、单片机内部硬件自动复位:对于定时器/计数器 T0、T1 及采用边沿触发方式的外部中断请求,CPU 在响应中断后,由内部硬件自动撤销中断请求;b、应用软件清除响应标志:对串口发送/接收中断请求及定时器 T2 的溢出和捕获中断请求,CPU 响应中断后,内部无硬件自动复位 RI、TI、TF2 及 EXF2,必须在中断服务程序中清除这些标志,才能撤除中断;c、既无软件清除也无硬件撤除:对于采用电平方式的外部中断请求,CPU 对引脚上的中断请求信号既无控制能力,也无应答信号,为保障 CPU 响应中断请求中断后,执行返回指令前撤除中断请求,必须考虑另外的措施。5、51 单片机中断响应过程51
10、 单片机在每个机器周期的 S5P2 状态顺序检查每个中断源的中断请求标志,若有中断源发送中断请求,CPU 在下个机器周期的 S5P2 状态按优先级顺序查询各中断标志,并且取高优先级的中断进行响应。响应中断后置位相应的中断优先级状态触发器,标明当前中断服务的优先级别,执行硬件调用程序,将程序计数器 PC 的内容压入堆栈进行保护。对于中断源的中断入口地址装入程序计数器 PC,使程序转入该中断入口处执行中断服务程序,直到遇到 RETI 指令。执行 RETI 指令,撤销中断优先级触发器,弹出断点地址至程序计数器 PC,继续源程序的执行过程。在接收中断申请时,如遇到下列情况之一,硬件调用子程序将被封锁:
11、a、正在执行同级或高一级的中断服务程序;b、当前指令周期不是该指令的最后一个周期(或一条指令未执行完);c、当前正在执行的指令是 RETI 或对 IE、IP 的读写操作。6、中断入口地址各中断源的中断入口地址为:STC86C52RC 51 单片机中断示例程序#include typedef unsigned char uint8;typedef unsigned int uint16;typedef unsigned long uint32;sbit enableG1 = P13; sbit enableG2 = P14;sbit selectC = P12; sbit selectB = P
12、11; sbit selectA = P10;code uint16 num1616 = 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E ;/共阳数码管真极表uint8 num66 = 0;/储存秒,0-5 对应于个位.10 万位上各位上的值void enable138(void); /启用 138 译码器切换 IO 口void refresh_led(void);void thtl_init(void);void timer1_init(void);vo
13、id et1_init(void);/ by http:/ main(void) enable138();timer1_init();et1_init();while(1);void interrupt_timer1(void) interrupt 3static uint16 counter = 0;static uint32 sec = 0;counter+;thtl_init();if(counter = 1000)counter = 0;sec+;num60 = sec % 10;num61 = sec/10%10;num62 = sec/100%10;num63 = sec/1000
14、%10;num64 = sec/10000%10;num65 = sec/100000%10; refresh_led();/更新 num6 数组后再刷新数码管void enable138(void) enableG1 = 1; enableG2 = 0; /刷新数码管,只显示有效值void refresh_led(void)static uint8 i = 0;switch(i)case 0: selectC = 0; selectB = 0; selectA = 0; P0 = num16 num60 ; break;case 1: selectC = 0; selectB = 0; se
15、lectA = 1; P0 = num65 = 0 break;case 2: selectC = 0; selectB = 1; selectA = 0; P0 = num65 = 0 break;case 3: selectC = 0; selectB = 1; selectA = 1; P0 = num65 = 0 break;case 4: selectC = 1; selectB = 0; selectA = 0; P0 = num65 = 0 break;case 5: selectC = 1; selectB = 0; selectA = 1; P0 = num65 = 0 ? 0xFF : num16 num65 ; break; default: break;i = +i % 6;/设置计数器初数值,重用的内容都应该写成独立函数出来方便维护void thtl_init(void)TH1 = (65536 - 922) / 256;TL1 = (65536 - 922) % 256;void timer1_init(void)TMOD |= 0X10;TMOD thtl_init();TR1 = 1;void et1_init(void) ET1 = 1; EA = 1;