1、中断小案例(演示通过外部中断按钮触发LED)
#include<reg51.h>
#define uchar unsigned char
//定义LED的控制引脚P2^0,用来控制灯光的打开和关闭;
sbit led = P2^0;
//定义按钮的中断触发控制位,来触发执行中断函数;
sbit button=P3^2;
//延时函数抖动
void delayms(uchar ms){
uchar i;
while(ms--){
for(i=0;i<123;i++){
;
}
}
}
//定义中断函数,指定中断号码为0,INT0,外部中断,低电平下降沿触发;
void int0_action(void) interrupt 0
{
//中断打开灯光
delayms(1);
led=1;
delayms(1000);
}
//初始化中断配置项目
void int0_init(){
//1、开中断是否允许接受中断(一级控制)
EA=1; //IE中断中断寄存器:CPU的总中断允许控制位, EA=1,CPU开放中断,EA=0,CPU屏蔽所有的中断申请。
//2、选择寄存器
IT0=1;//TCON标志控制寄存器:外部中断IT0,控制引脚P3^2,IT0=1设置低电平下降沿触发
//3、设置所需寄存器的允许位(二级控制)
EX0=1;//IE中断允许寄存器: 外部中断0中断允许位。EX0=1,允许中断;EX0=0禁止中断
/*********************************
也可以将上边的寄存器合起来写,上边嘚瑟属于寄存器的位赋值方式;
下边的合起来的属于寄存器的整体赋值;
TCON=0X01; //TCON包含 IT0=1;
IE=0X81; //IE包含EA=1; EX0=1;
**********************************/
}
void main(){
int0_init();
while(1){
led=0;
}
}
2、定时器测试案例(演示通过定时器控制LED)
/******************************
定时器(内部)/ 计数器(外部):
包括时间源(北京时间)、时间长度(定时多久)、定时任务(到时间后触发什么动作)
时钟源:属于单片机内部时钟源,由单片机的晶振提供。计数器是外部;
计时长度:一个定时器对应两个8为寄存器,TH\TL,总共2^16=65536;
中断触发函数:执行中断任务;
触发定时器需要进行以下步骤:
1、设置定时器模式:
通过TMOD寄存器来设置定时器的工作模式。
例如,如果我们想将定时器0设置为模式1(16位定时/计数器模式),我们可以写入TMOD = 0x01;。
2、加载定时初值:
定时初值决定了定时器中断的触发频率。我们可以通过TH0和TL0寄存器来设置定时器0的初值。
例如,我们可以写入TH0 = 0xFC; TL0 = 0x18;来设置定时初值,他就会以这个数开始–。
在51单片机的定时器中,TH0是高8位,TL0是低8位。这两个寄存器共同组成了一个16位的定时/计数器。
当我们说"设置定时器的初值"时,通常是指同时设置这两个寄存器的值。
3、开启定时器中断:
通过IE寄存器来开启定时器的中断。例如,我们可以写入ET0 = 1; EA = 1;来开启定时器0的中断。
4、动定时器:
通过TR0位来启动定时器0。例如,我们可以写入TR0 = 1;来启动定时器。
在带有XX0中,0就是定时器编号,也可以写1,因为有两个定时器
******************************/
#include<reg52.h>
// 标志位,统计时间溢出次数
int flag=0;
// 驱动LED引脚
sbit LED = P2^0;
/*
外部中断0(INT0) 中断号0 入口地址0003H
定时/计数器0(T0) 中断号1 入口地址000BH
外部中断1(INT1) 中断号2 入口地址0013H
定时/计数器1(T1) 中断号3 入口地址001BH
串行口中(RI/TI) 中断号4 入口地址0023H
*/
void timer1(void) interrupt 3 //设置使用的是定时器1(模式1),所以需要选择与定时器1对应的终端号3
{
/*
8051系列单片机又在这个基础上进行细分,将一个机器周期划分为6个状态周期,也就是S1-S6,
每个状态周期又由两个节拍组成,P1和P2,而P1=P2=时钟周期。这也就是经常说的8051系列单片机的的时钟频率是晶振频率的12分频,或者是1/12,
如果依照f=12MHz晶振计算,每次时钟周期=1/f;
因为单片机时钟频率是晶振频率的1/12,所以单片机时钟周期是T=1/(f/12)=(1/f)*12 = 1/12000000=1微妙,那么单片机定时器16位计时范围2^16=65535
50000次就是0.05秒,乘以20次,就是1秒钟
*/
TH1=(65536-50000)/256; //依照12MHz晶振计算,每次机器周期1/f = 1/12000000=1微妙,初始话定时器的处值,定时器从初值开始统计寄存器溢出次数
TL1=(65536-50000)%256;
flag++; //每溢出一次,标志位加1, 每次溢出需要50毫秒
if (flag==20) //达到1s
{
flag =0; //累计一秒后重置0
LED=~LED; //一秒间隔闪烁取反
}
}
void timer_init(){
/************设置特殊功能寄存器TMOD:选择定时器、以及定时器工作模式*********************/
/*
符号位 GATE C/T M1 M0 GATE C/T M1 M0
●GATE=1时,“与门”的输出信号K由INTx输入电平和TRx位的状态一起决定(即此时K=TRx·INTx),当且仅当TRx=1,INTx=1(高电平)时,计数启动;否则,计数停止。
当INT0引脚为高电平时且TR0置位,TR0=1;启动定时器T0;
当INT1引脚为高电平时且TR1置位,TR1=1;启动定时器T1。
●GATE=0时,“或门”输出恒为1,“与门”的输出信号K由TRx决定(即此时K=TRx),定时器不受INTx输入电平的影响,由TRx直接控制定时器的启动和停止。
当TR0=1,启动定时器T0。
当TR1=1,启动定时器T1。
●C/T=0时为定时功能: 加1计数器对脉冲f进行计数,每来一个脉冲,计数器加1,直到计时器TFx满溢出;
●C/T=1时为计数功能: 加1计数器对来自输入引脚T0(P3.4)和T1(P3.5)的外信号脉冲进行计数,每来一个脉冲,计数器加1,直到计时器TFx满溢出;
●M1 0/1
●M0 0/1
//0 0 方式0 13位计数器 TMOD=0x00
//0 1 方式1 16位计数器 TMOD=0x01
//1 0 方式2 自动重装8位计数器 TMOD=0x02
//1 1 方式3 T0分为2个8位独立计数器,T1为无中断重装8位计数器 TMOD=0x03
*/
TMOD=0x10; //0x10 = 0000 0001,高四位是定时器1、第四位是定时器0,
/******************定时器赋初始值****************************/
//1)假设我使用的单片机的晶振为12MHZ,其机器周期是1us,即每1us产生一次计数;
//2)1s需要1*10^6个机器周期,但定时器T0只能对机器周期能进行最大65536次计数,很明显已经超过了,并不能直接采用T0的默认值;
//3)取个65535之内的整数值,经过简单倍数关系即可转换为1s。很明显,50ms符合要求。即一次中断5 * 10^4次,中断20次即为1s
//4)但根据中断原理,T0中断器溢出时计数1次,但5 * 10^4<65536,根本不会发生溢出。
// 如果我给T0定时器附上初始值,使其从初试值开始计数,最终读数为65536发生溢出,中断一次。这个初始值就是65536和5 * 104的差值
//5)T0中断器由两个8位构成,低8位,即2^8,满打满算也只能计数256个机械周期,当大于256个机械周期就必须采用高8位了。换而言之,高8位每增加1,低八位就装满一次。
//6)故用初始值除以256取整,存入高8位。取余,即小于256次数,放入低8位。
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
/*****************配置中断允许控制寄存器************************/
/*
位符号 EX0 ET0 EX1 ET1 ES -- -- EA
EX0:外部中断0允许位。EX0=1,允许外部中断0中断;EX0=0,禁止外部中断0中断。当EX0=1( SETB EX0 )时,同时单片机P3.2引脚上出现中断信号时,单片机中断主程序的执行而“飞”往中断服务子程序,执行完后通过中断返回指令RET 动返回主程序。当EX0=0( CLR EX0)时,即使单片机P3.2引脚上出现中断信程序也不会从主程序“飞” 出去执行,因为此时单片机的CPU相当于被“堵上了耳朵”,根本接收不到P3.2引脚上的中断信号,但是这并不表示这个信号不存在。如果单片机的CPU有空查一下TCON中的IE0位,若为1就说明有中断信号出现过。 [3]
ET0:T0溢出中断允许位。ET0=1,允许T0中断;ET0=0,禁止T0中断。
EX1:外部中断1允许位。EX1=1,允许外部中断1中断;EX1=0,禁止外部中断1中断。当EX1=1( SETB EX1)时,并且外部P3.3引脚上出现中断信号时,单片机CPU会中断主程序而去执行相应的中断服务子程序;当EX1=0( CLR EX1)时使外部P3.3引脚上即使出现中断信号,单片机的CPU也不能中断主程序转而去行中断服务子程序。 [3]因此,可以这样认为,EX0和EX1是决定CPU能否感觉到外部引脚P3.2P3.3上的中断信号的控制位。
ET1:T1溢出中断允许位。ET1=1,允许T1中断;ET1=0,禁止T1中断。
ES:串行中断允许位。ES=1,允许串行口中断;ES=0,禁止串行口中断。
EA:中断总允许位。EA=1,CPU开放中断;EA=0,CPU禁止所有的中断请求。总允许EA好比一个总开关。EA就相当于每家水管的总闸,如果总闸不开,各个龙头即