单片机中断系统有外部中断和定时计数器中断
接下来我将为大家介绍中断系统之外部中断的理论和程序部分,以及中断系统之定时计数器理论和程序部分
1:中断系统之外部中断
理论部分
我们通过以下图片来进行讲解
INT0和INT1为单片机的外部中断接下来我将讲解其中的一种另一种类似从INT0开始,当IT0=0时为低电平触发,当IT0=1时为下降沿触发(从高电平转为低电平)这些都在TCOM中设置,IEO=0中断处理后硬件清0无需程序清0,IEO=1外部中断源向CPU请求中断(IEO无需配置),当EX0=1时打开外部中断,当EX0=0时关闭外部中断,EA=1打开总中断,EA=0不打开(EX0,EA在IE中配置)
下面我们来写中断函数的格式
void 函数名()interrupt 中断号 using 寄存器组号
程序部分
#include<reg52.h>
typedef signed char int8; //8位有符号字符型
typedef signed int int16; //16位有符号整型
typedef signed long int32; //32位有符号长整型
typedef unsigned char uint8; //8位无符号字符型
typedef unsigned int uint16; //16位无符号整型
typedef unsigned long uint32; //32位无符号长整型
sbit DATA_A_595 = P1^0; //74HC595 串行数据输入引脚
sbit SHIFT_CLOCK_595 = P1^4; //74HC595 移位寄存器时钟信号输入引脚
sbit LATCH_CLOCK_595 = P2^3; //74HC595 锁存器时钟信号输入引脚
sbit duanxuan = P2^5; //数码管驱动芯片74HC573 段选
sbit weixuan = P2^6; //数码管驱动芯片74HC573 位选
sbit RS_Lcd_1602 = P2^5; //1602液晶屏 RS端口
sbit RW_Lcd_1602 = P2^6; //1602液晶屏 RW端口
sbit E_Lcd_1602 = P2^4; //1602液晶屏 E 端口
#define LCD_1602_IO P0 //1602液晶屏并行总线端口
uint8 *x;
uint32 *x1;
uint8 test=0; //测试外部中断进入次数
void delay(uint16 x_ms); //延迟 x_ms*1 毫秒
void write_byte_74hc595(uint8 dat); //给595芯片写一字节数据函数
void Init_Lcd_1602(); //1602液晶屏初始化函数
void Busy_Lcd_1602(); //1602液晶屏判忙函数
void Write_Order_Lcd_1602(uint8 Order_Dat);//1602液晶屏写指令函数
void Write_Data_Lcd_1602(uint8 Data_Dat); //1602液晶屏写数据函数
void Display_Lcd_1602(uint8 X_1602,uint8 Y_1602,uint8 *P_1602,uint8 Count_1602); //在1602液晶屏,任意行,任意列,写一个任意位数,的字符串
void Display_1602_Lcd_Number(uint8 X_1602,uint8 Y_1602,uint32 Number,uint8 Count_1602);//在1602液晶屏,任意行,任意列,写一个任意位数,的十进制数
/*********************************************************************
*函数名称:main
*函数功能:主函数
*函数调用:
*参数列表:无
*返 回 值:无
*结 果:
*备 注:
*********************************************************************/
void main(void)
{
//*******************************************************************
//外部中断 0 位控制
/*
IT0 = 0; //0 低电平触发 1 下降沿触发
EX0 = 1; //打开外部中断0开关 0关闭 1打开
EA = 1; //打开总中断开关 0关闭 1打开
*/
//*******************************************************************
//外部中断总线控制
// TCON &= 0XFE; // 对IT0 位置 0 0 低电平触发
TCON |= 0X01; // 对IT0 位置 1 1 下降沿触发
IE |=0X01; //EX0 =1 打开外部中断0开关
// IE &=0XFE; //EX0 =0 关闭外部中断0开关
IE |=0X80; //EA =1 打开总中断开关
// IE &=0X7F; //EA =0 关闭总中断开关
//*******************************************************************
/*********************************************************************
//测试1602底层函数
Init_Lcd_1602(); //1602液晶屏初始化函数
Write_Order_Lcd_1602(0X80+0X00);//1602液晶屏写指令函数
Write_Data_Lcd_1602(0X61); //1602液晶屏写数据函数 写 a
Write_Order_Lcd_1602(0X80+0X01);//1602液晶屏写指令函数
Write_Data_Lcd_1602(0X62); //1602液晶屏写数据函数 写 b
Write_Data_Lcd_1602(0X63); //1602液晶屏写数据函数 写 c
Write_Data_Lcd_1602(0X64); //1602液晶屏写数据函数 写 d
Write_Data_Lcd_1602(0X65); //1602液晶屏写数据函数 写 e
**********************************************************************/
/*********************************************************************
//测试字符串显示
Init_Lcd_1602(); //1602液晶屏初始化函数
Display_Lcd_1602(1,1," LCD_1602_TEST ",16); //在1602液晶屏,任意行,任意列,写一个任意位数,的字符串
Display_Lcd_1602(2,1," ",16); //在1602液晶屏,任意行,任意列,写一个任意位数,的字符串
//Display_Lcd_1602(1,1,"0123456789abcdef",16); //在1602液晶屏,任意行,任意列,写一个任意位数,的字符串
//Display_Lcd_1602(2,1,"0123456789abcdef",16); //在1602液晶屏,任意行,任意列,写一个任意位数,的字符串
//Display_Lcd_1602(2,3,"+-AB",4); //在1602液晶屏,任意行,任意列,写一个任意位数,的字符串
**********************************************************************/
/*********************************************************************
Init_Lcd_1602(); //1602液晶屏初始化函数
Display_1602_Lcd_Number(2,1,1234567890,10);//在1602液晶屏,任意行,任意列,写一个任意位数,的十进制数
**********************************************************************/
Init_Lcd_1602(); //1602液晶屏初始化函数
Display_Lcd_1602(1,1," INT0/1 TEST ",16); //在1602液晶屏,任意行,任意列,写一个任意位数,的字符串
Display_Lcd_1602(2,1,"INT0: INT1: ",16); //在1602液晶屏,任意行,任意列,写一个任意位数,的字符串
while(1)
{
Display_1602_Lcd_Number(2,6,test,2);//在1602液晶屏,任意行,任意列,写一个任意位数,的十进制数
Display_1602_Lcd_Number(2,15,00,2);//在1602液晶屏,任意行,任意列,写一个任意位数,的十进制数
}
}
/*********************************************************************
*函数名称:write_byte_74hc595
*函数功能:74HC595芯片数据输入
*函数调用:write_byte_74hc595(uint8 dat);
*参数列表:dat
*返 回 值:无
*结 果:把一个字节数 dat 写到 74HC595芯片的八个输出引脚上
*备 注:dat 数据对应的功能
蜂鸣器 0X04 继电器 0X80
时钟芯片片选 0X10 流水灯 0X40
*********************************************************************/
void write_byte_74hc595(uint8 dat) //给595芯片写一字节数据函数
{
uint8 i;
for(i=0;i<8;i++)
{
DATA_A_595 =(dat<<i)&0x80; //74HC595 串行数据输入引脚
SHIFT_CLOCK_595 = 0; //74HC595 移位寄存器时钟信号输入引脚
SHIFT_CLOCK_595 = 1; //74HC595 移位寄存器时钟信号输入引脚
}
LATCH_CLOCK_595 = 0; //74HC595 锁存器时钟信号输入引脚
LATCH_CLOCK_595 = 1; //74HC595 锁存器时钟信号输入引脚
}
/*********************************************************************
*函数名称:delay
*函数功能:延时函数
*函数调用:delay(uint16 x_ms);
*参数列表:x_ms
*返 回 值:无
*结 果:延迟时间=1* x_ms(毫秒)
*备 注:
*********************************************************************/
void delay(uint16 x_ms) //延迟 x_ms*1 毫秒
{
uint16 i,j;
for(i=x_ms;i>0;i--)
for(j=114;j>0;j--);
}
/*********************************************************************
*函数名称:nit_Lcd_1602
*函数功能:1602液晶屏初始化函数
*函数调用:Init_Lcd_1602();
*参数列表:无
*返 回 值:无
*结 果:
*备 注:
*********************************************************************/
//1602液晶屏初始化函数
void Init_Lcd_1602() //1602液晶屏初始化函数
{
delay(15); //延迟 15ms 延迟 x_ms*1 毫秒
Write_Order_Lcd_1602(0X38); //写指令 38H 显示模式设置
delay(5); //延迟 15ms 延迟 x_ms*1 毫秒
Write_Order_Lcd_1602(0X38);//写指令 38H 显示模式设置
delay(15); //延迟 15ms 延迟 x_ms*1 毫秒
Write_Order_Lcd_1602(0X38);//写指令 38H 显示模式设置
Write_Order_Lcd_1602(0X38);//写指令 38H 显示模式设置
Write_Order_Lcd_1602(0X08);//写指令 08H 显示关闭
Write_Order_Lcd_1602(0X01);//写指令 01H 显示清屏
Write_Order_Lcd_1602(0X06);//写指令 06H 显示光标移动设置 光标坐标自动加1
Write_Order_Lcd_1602(0X0C);//写指令 0CH 显示光标设置
}
/*********************************************************************
*函数名称:Busy_Lcd_1602
*函数功能:1602液晶屏判忙函数
*函数调用:Busy_Lcd_1602();
*参数列表:无
*返 回 值:无
*结 果:
*备 注:
*********************************************************************/
//1602液晶屏判忙函数
void Busy_Lcd_1602()
{
uint8 Busy_Dat=0; //读取1602 总线端口数据 暂存局部变量
LCD_1602_IO = 0XFF; //释放总线
RS_Lcd_1602 = 0; //1602液晶屏 RS端口
RW_Lcd_1602 = 1; //1602液晶屏 RW端口
// E_Lcd_1602 = 1; //1602液晶屏 E 端口
do
{
E_Lcd_1602 = 1; //1602液晶屏 E 端口
Busy_Dat = LCD_1602_IO; //1602液晶屏并行总线端口
E_Lcd_1602 = 0; //1602液晶屏 E 端口
}
while(Busy_Dat & 0X80);
LCD_1602_IO = 0XFF; //释放总线
}
/*********************************************************************
*函数名称:Write_Order_Lcd_1602
*函数功能:1602液晶写指令函数
*函数调用:Write_Order_Lcd_1602(uint8 Order_Dat);
*参数列表:uint8 Order_Dat //被写进去的指令
*返 回 值:无
*结 果:
*备 注:
*********************************************************************/
void Write_Order_Lcd_1602(uint8 Order_Dat) //1602液晶写指令函数
{
Busy_Lcd_1602(); //1602液晶屏判忙函数
E_Lcd_1602 = 0; //1602液晶屏 E 端口
RS_Lcd_1602 = 0; //1602液晶屏 RS端口
RW_Lcd_1602 = 0; //1602液晶屏 RW端口
LCD_1602_IO = Order_Dat ; //释放总线
E_Lcd_1602 = 1; //1602液晶屏 E 端口
E_Lcd_1602 = 0; //1602液晶屏 E 端口
LCD_1602_IO = 0XFF; //释放总线
}
/*********************************************************************
*函数名称:Write_Data_Lcd_1602
*函数功能:1602液晶写数据函数
*函数调用:Write_Data_Lcd_1602(uint8 Data_Dat);
*参数列表:uint8 Data_Dat //被写进去的数据 -数据就是我们写在1602上的字符
*返 回 值:无
*结 果:
*备 注:
*********************************************************************/
void Write_Data_Lcd_1602(uint8 Data_Dat)
{
Busy_Lcd_1602(); //1602液晶屏判忙函数
E_Lcd_1602 = 0; //1602液晶屏 E 端口
RS_Lcd_1602 = 1; //1602液晶屏 RS端口
RW_Lcd_1602 = 0; //1602液晶屏 RW端口
LCD_1602_IO = Data_Dat ; //释放总线
E_Lcd_1602 = 1; //1602液晶屏 E 端口
E_Lcd_1602 = 0; //1602液晶屏 E 端口
LCD_1602_IO = 0XFF; //释放总线
}
/*********************************************************************
*函数名称:Display_Lcd_1602
*函数功能:在1602液晶屏,任意行,任意列,写一个任意位数,的字符串
*函数调用:Display_Lcd_1602(uint8 X_1602,uint8 Y_1602,uint8 *P_1602,uint8 Count_1602);
*参数列表:
X_1602 行坐标 取值范围 1-2
Y_1602 列坐标 取值范围 1-16
*P_1602 字符串指针变量 要求字符串位数,不能超过16位 取值范围 1-16
Count_1602 字符串位数 取值范围 1-16
*返 回 值:无
*结 果:
*备 注:
*********************************************************************/
void Display_Lcd_1602(uint8 X_1602,uint8 Y_1602,uint8 *P_1602,uint8 Count_1602)
{
uint8 i =0;
/*
if(X_1602==1)
Y_1602 = Y_1602 +0X80; //第一行坐标 0X80 +0X00 =0X80
else
Y_1602 = Y_1602 +0XC0; //第二行坐标 0X80+0X40 =0XC0
*/
for(i=0;i<=Count_1602-1;i++)
{
if(X_1602==1)
Y_1602 |= 0X80; //第一行坐标 0X80 +0X00 =0X80 //Y_1602 = Y_1602|0X80; //第一行坐标 0X80 +0X00 =0X80
else
Y_1602 |= 0XC0; //第二行坐标 0X80+0X40 =0XC0 //Y_1602 = Y_1602|0XC0; //第二行坐标 0X80+0X40 =0XC0
Write_Order_Lcd_1602(Y_1602-1);//1602液晶屏写指令函数
Write_Data_Lcd_1602(*P_1602); //1602液晶屏写数据函数
P_1602++;
Y_1602++;
}
}
/*********************************************************************
*函数名称:Display_1602_Lcd_Number
*函数功能:在1602液晶屏,任意行,任意列,写一个任意位数,的十进制数
*函数调用:Display_1602_Lcd_Number(uint8 X_1602,uint8 Y_1602,uint32 Number,uint8 Count_1602);
*参数列表:
X_1602 行坐标 取值范围 1-2
Y_1602 列坐标 取值范围 1-16
Number 任意的10位十进制数
Count_1602 十进制数位数 取值范围 1-10
*返 回 值:无
*结 果:
*备 注:
*********************************************************************/
void Display_1602_Lcd_Number(uint8 X_1602,uint8 Y_1602,uint32 Number,uint8 Count_1602)
{
uint8 numbercode[10];
uint8 i=0;
uint8 Count_1602_Flag=0;
numbercode[0] = Number%10; //个
numbercode[1] = Number%100/10; //十
numbercode[2] = Number%1000/100; //百
numbercode[3] = Number%10000/1000; //千
numbercode[4] = Number%100000/10000; //万
numbercode[5] = Number%1000000/100000; //十万
numbercode[6] = Number%10000000/1000000; //百万
numbercode[7] = Number%100000000/10000000; //千万
numbercode[8] = Number%1000000000/100000000; //亿
numbercode[9] = Number%10000000000/1000000000; //十亿
Count_1602_Flag = Count_1602-1;
for(i=0;i<=Count_1602-1;i++)
{
if(X_1602==1)
Y_1602 |= 0X80; //第一行坐标 0X80 +0X00 =0X80 //Y_1602 = Y_1602|0X80; //第一行坐标 0X80 +0X00 =0X80
else
Y_1602 |= 0XC0; //第二行坐标 0X80+0X40 =0XC0 //Y_1602 = Y_1602|0XC0; //第二行坐标 0X80+0X40 =0XC0
Write_Order_Lcd_1602(Y_1602-1);//1602液晶屏写指令函数
Write_Data_Lcd_1602(0X30+numbercode[Count_1602_Flag]); //1602液晶屏写数据函数
Y_1602++;
Count_1602_Flag--;
}
}
void Int0() interrupt 0 using 1
{
test++;
if(test>=100)
test=0;
delay(10);
}
2:中断系统之定时计数器
定时器内部工作原理分析
定时/计数模式设置(在TMOD寄存器里设置)
1.TMOD=0X01(定时器0 方式1 16位定时/计数器)
2.装初值TL0(低八位)和TH0(高八位)
3.开关定时/计数器TR0=1(打开定时计数器),TR0=0(关闭定时计数器)(在TCON寄存器中设置)
4.打开定时计数器中断允许位(在IE寄存器里设置)ET0=0(不允许),ET0=1(允许)
5.定时计数器中断请求中断标志TF0=1(定时计数器向CPU请求中断)TF0=0(中断处理后由硬件清0)
6.EA=1打开总中断,EA=0不打开(EX0,EA在IE中配置)
程序代码
用定时器0实现原子钟,在1602液晶显示屏上以00:00:00:(时:分:秒)这种格式显示,开始计时
#include<reg52.h>
/*
**********************************************************************
* 本地数据类型/宏定义
**********************************************************************
*/
typedef signed char int8; //8位有符号字符型
typedef signed int int16; //16位有符号整型
typedef signed long int32; //32位有符号长整型
typedef unsigned char uint8; //8位无符号字符型
typedef unsigned int uint16; //16位无符号整型
typedef unsigned long uint32; //32位无符号长整型
/*
**********************************************************************
* 单片机IO口位定义
**********************************************************************
*/
//*******************************************************
//该部分为了关闭数码管和 LED流水灯
sbit DATA_A_595 = P1^0; //74HC595 串行数据输入引脚
sbit SHIFT_CLOCK_595 = P1^4; //74HC595 移位寄存器时钟信号输入引脚
sbit LATCH_CLOCK_595 = P2^3; //74HC595 锁存器时钟信号输入引脚
sbit duanxuan = P2^5; //数码管驱动芯片74HC573 段选
sbit weixuan = P2^6; //数码管驱动芯片74HC573 位选
//*******************************************************
sbit RS_Lcd_1602 = P2^5; //1602液晶屏 RS端口
sbit RW_Lcd_1602 = P2^6; //1602液晶屏 RW端口
sbit E_Lcd_1602 = P2^4; //1602液晶屏 E 端口
#define LCD_1602_IO P0 //1602液晶屏并行总线端口
/*
**********************************************************************
* 本地全局变量/数组定义
**********************************************************************
*/
uint8 time_1s =0; //1s 时间单位
/*
**********************************************************************
* 函数原型声明
**********************************************************************
*/
void delay(uint16 x_ms); //延迟 x_ms*1 毫秒
void write_byte_74hc595(uint8 dat); //给595芯片写一字节数据函数
void Init_Lcd_1602(); //1602液晶屏初始化函数
void Busy_Lcd_1602(); //1602液晶屏判忙函数
void Write_Order_Lcd_1602(uint8 Order_Dat);//1602液晶屏写指令函数
void Write_Data_Lcd_1602(uint8 Data_Dat); //1602液晶屏写数据函数
void Display_Lcd_1602(uint8 X_1602,uint8 Y_1602,uint8 *P_1602,uint8 Count_1602); //在1602液晶屏,任意行,任意列,写一个任意位数,的字符串
void Display_1602_Lcd_Number(uint8 X_1602,uint8 Y_1602,uint32 Number,uint8 Count_1602);//在1602液晶屏,任意行,任意列,写一个任意位数,的十进制数
/*********************************************************************
*函数名称:main
*函数功能:主函数
*函数调用:
*参数列表:无
*返 回 值:无
*结 果:
*备 注:
*********************************************************************/
void main(void)
{
//*******************************************************************
//定时器 0 中断法
// TMOD = 0X01; //总线控制法直接赋值 设置定时器0 方式1
/*
TMOD &=0XF0; //第四位全部置0 设置定时器0 方式1
TMOD |=0X01; //最低位置 1
TH0 = 0X4C; //定时器 0 装初值 定时时间 50ms
TL0 = 0X00;
TR0 = 1; //定时器0 启动计数
ET0 = 1; //打开定时器0 中断允许位
TF0 = 0; //清零定时/计数器中断标志位
EA = 1; //打开总中断开关
*/
//*******************************************************************
//定时器 0 查询法
// TMOD = 0X01; //总线控制法直接赋值 设置定时器0 方式1
TMOD &=0XF0; //第四位全部置0 设置定时器0 方式1
TMOD |=0X01; //最低位置 1
TH0 = 0X4C; //定时器 0 装初值 定时时间 50ms
TL0 = 0X00;
TR0 = 1; //定时器0 启动计数
TF0 = 0; //清零定时/计数器中断标志位
//**********************************************************************
Init_Lcd_1602(); //1602液晶屏初始化函数
Display_Lcd_1602(1,1," Timer0/1 TEST ",16); //在1602液晶屏,任意行,任意列,写一个任意位数,的字符串
Display_Lcd_1602(2,1," 00:00:00 ",16); //在1602液晶屏,任意行,任意列,写一个任意位数,的字符串
write_byte_74hc595(0X00); //给595芯片写一字节数据函数
while(1)
{
//*****************************************************
//定时/计数器0 查询法
if(TF0 == 1) //清零定时/计数器中断标志位
{
static uint8 time=0;
TF0 = 0; //清零定时/计数器中断标志位
TH0 = 0X4C; //定时器 0 装初值 定时时间 50ms
TL0 = 0X00;
time++;
if(time>=20)
{
time_1s++; //1s 时间单位
time=0;
}
}
//*****************************************************
//1s 时间单位
Display_1602_Lcd_Number(2,11,time_1s,2);//在1602液晶屏,任意行,任意列,写一个任意位数,的十进制数
if(time_1s>=60)
time_1s=0;
}
}