89c51——led闪烁,中断
1.led闪烁
/*
使led小灯以每秒一次的频率进行闪烁
*/
#include<reg52.h>
#define uint unsigned int;
sbit led1 = P1^0; //sbit:subsitutite代替的意思
uint i,j;
void main()
{
while(1) //一直循环
{
led1=0; //灯灭
for(i=1000;i>0;i--) //这个循环要走110000次,即1000*110
for(j=110;j>0;j--);
led1=1;
for(i=1000;i>0;i--)
for(j=110;j>0;j--);
}
}
2.带中断的led闪烁
//外接中断
#include <reg52.h>
#define uchar unsigned char //使用宏定义定义了uchar,uint
#define uint unsigned int
void delay_ms(uint ms) //定义了一个延时函数
{
uchar i;
while(ms--)
for(i=0;i<123;i++); //在12MHZ时,循环123次为1ms
}
void main()
{ //前三个开关打开,使得中断允许
EA=1; //EA:全局控制位(总闸)
EX0=1; //EX0,EX1分别为外部中断0中断允许位,外部中断1中断允许位
IT0=1; //IT0,IT1分别为外部中断0(或1)触发方式选择位,1位下降沿触发,0为低电平触发
while(1) //如果外部中断没有开启,则p1所有端口为1
P1=0xff; //效果为:不按时8个led全亮,按一次则4~7灭,0~3亮,然后全灭,然后全亮
}
void int0(void) interrupt 0 using 0 //中断函数特殊的格式
{
P1=0x0f; //p1=00001111
delay_ms(800);
P1=0x00; //p1=00000000
delay_ms(800);
}
3.中断
(1)格式
//中断函数的格式
void 函数名 () interrupt 中断号 using 工作组
{
中断服务程序;
}
//例子如下
void int0() interrupt 0 using 0 //中断函数特殊的格式
{
P1=0x0f; //p1=00001111
delay_ms(800);
P1=0x00; //p1=00000000
delay_ms(800);
}
//关于中断号
/*
中断号是取决于中断源的,不同的中断源有不同的优先级。
优先级:外部中断0 > 计数器0 > 外部中断1 > 计数器1 > 串口中断
中断号分别为:0 1 2 3 4
*/
(2)中断源
89c51的中断源:5个
2个外部中断源,2个计时器,1个串行口中断
(3)中断嵌套
中断嵌套中断嵌套其实就是对中断优先级的相应处理。
设想一下,你正在津津有味地看书,忽然电话铃响了,你刚要去接电话又有人敲门,那么这两件事应该先做哪件呢?如果你正在等一个很重要的电话,通常是先接电话,然后再看是谁敲门;反之,如果你正在等一个很重要的客人,就会先看看是谁在敲门,然后再处理未接电话;当然,如果你既没有等人,也没有等电话,那就按自己的习惯去处理。总之,在这件事例中存在一个优先级的问题。
在单片机的世界里同样如此,也有优先级的问题。**优先级的问题不仅发生在两个中断同时产生的情况下,也发生在一个中断已产生但未处理完,又有另一个中断产生的情况下。**比如,你正在接电话,又有人敲门;或者你正开门接收快递,电话又响了。如果这样的事情发生了,你一般会怎么做呢?这就用到了前面谈到的IP寄存器的功能。
(4)中断的嵌套与处理
中断的响应与处理当有中断事件发生时,在处理中断事件之前我们通常会做些工作。仍以你正在看书为例,有中断发生时(有人敲门、电话响),你会先想办法记住现在看到了第几页(拿支笔或书签放在当前页的位置),然后去处理相应的事情(如果是有人敲门,你会走到门口;如果是电话铃响,你会走到电话机旁。也就是说,对于不同的中断事件,你会在不同的地点处理,而且这个地点通常还是固定的—―这就是中断号的概念。
单片机中采用的也是这种方法,有中断发生时,处理器会先保存下一条要执行指令的地址,然后根据中断源的不同,到一个固定的地址去找处理这个中断的程序,处理完后再读取刚才保存的指令地址,回到原来程序运行的地方继续执行。