1、在proteus软件上绘制原理图
- 这里的选用的是共阴数码管 ,段选信号高电平亮。
- RP1是上下拉排阻,当其1脚接电源时为上拉排阻,接地时为下拉排阻。
- RN1为限流排阻,可通过修改其名字来更改排阻的阻值
- 74HC240是双线八路反相缓冲器/线路驱动器,具有三态输出。该三态输出由输出使能端
控制。
接高电平将使输出端呈现高阻态。
- 两个按键必须分别接在P3.2和P3.3引脚,本次实验通过按键触发外部中断实现加减计数。
2、在keil5上编写代码
#include <AT89X51.H>
unsigned char SEGTAB[] =
{
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
};
unsigned char DIGTAB[] =
{
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
};
unsigned char LEDBuffer[4];
unsigned char LEDPointer;
void Delay1mS(void)
{
unsigned char i,j;
for(i=2;i>0;i--)
for(j=248;j>0;j--);
}
char KeyCnt = 0;
void main(void)
{
IT0 = 1; //设置外部中断0的触发方式为下降沿触发
IT1 = 1; //设置外部中断1的触发方式为下降沿触发
EX0 = 1; //启用外部中断0
EX1 = 1; //启用外部中断1
EA = 1; //打开总中断
while(1)
{
P0 = SEGTAB[LEDBuffer[LEDPointer]];//段选
P2 = DIGTAB[LEDPointer];//位选
if(++LEDPointer == sizeof(LEDBuffer)) LEDPointer = 0;
Delay1mS();
P2 = 0;
}
}
//外部中断0的中断服务函数
void INT0_ISR(void) interrupt 0
{
EX0 = 0;
Delay1mS();
if(0 ==P3_2)
{
if(++KeyCnt == 100) KeyCnt = 0;
LEDBuffer[0] = KeyCnt%10;
LEDBuffer[1] = KeyCnt/10;
}
IE0 = 0;
EX0 = 1;
}
//外部中断1的中断服务函数
void INT1_ISR(void) interrupt 2
{
EX1 = 0;
Delay1mS();
if(0 ==P3_3)
{
if(--KeyCnt < 0) KeyCnt = 99;
LEDBuffer[0] = KeyCnt%10;
LEDBuffer[1] = KeyCnt/10;
}
IE1 = 0;
EX1 = 1;
}
-
引用51的头文件。#include <AT89X51.H>
-
定义段选译码表,及需要显示0~f对应输出的段选信号(控制a,b,c,d,e,f,g,h八段LED)。unsigned char SEGTAB[] = { 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71, };
-
unsigned char DIGTAB[] = { 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80, };
定义位选译码器,位选时只选中一位数码管,则8bit中只有一位是高电平,输出经过74hc240反转电平,在连接到数码管的公共极,在本次实验中只用到四位数码管,且原理图的P2组引脚未用于连接其他外设,所以这里可以不考虑高位的值。
-
unsigned char LEDBuffer[4];
定义一个长度为4的数组,用于存放四位数码管的要显示的数据。
-
unsigned char LEDPointer;
定义一个索引变量,用于指定当前显示的数码管
-
void Delay1mS(void) { unsigned char i,j; for(i=2;i>0;i--) for(j=248;j>0;j--); }
定义1ms的延时函数,在单片机的晶振为12Mhz的情况下
-
char KeyCnt = 0;
定义计数值,其中定义为char类型是为了可判断计数器为负数时,将赋最大值给计数器。
-
IT0 = 1; //设置外部中断0的触发方式为下降沿触发 IT1 = 1; //设置外部中断1的触发方式为下降沿触发
配置外部中断的IT寄存器,T89C51单片机的外部中断0和外部中断1支持两种触发方式:低电平触发方式和下降沿触发方式。通过设置TCON寄存器的IT0和IT1来实现。这里置1寄存器,设置为下降沿触发。
-
EX0 = 1; //启用外部中断0 EX1 = 1; //启用外部中断1 EA = 1; //打开总中断
置1EX寄存器,允许外部中断产生中断;置1EA寄存器,使CPU让出中断权(及打开总中断)
-
P0 = SEGTAB[LEDBuffer[LEDPointer]];//段选 P2 = DIGTAB[LEDPointer];//位选 if(++LEDPointer == sizeof(LEDBuffer)) LEDPointer = 0; Delay1mS(); P2 = 0;
数码管动态扫描程序,通过LEDPointer索引指定LEDBuffer的元素位到SEGTAB表查找对应的数码管段选值给P0口输出;通过LEDPointer索引找到DIGTAB表中对应的位选值给P2口输出;++LEDPointer使每位数码管进行轮流显示;这里延时1ms说明1s中每位数码管显示了1s/(4*1ms)=250帧,足以使人眼看到动态的显示结果;显示完一位后一定要关闭P2,再对P0口赋值,防止出现鬼影。(及不能在位选打开的情况下,段选更改为下一位位选的值)。
-
//外部中断0的中断服务函数 void INT0_ISR(void) interrupt 0 { EX0 = 0; Delay1mS(); if(0 ==P3_2) { if(++KeyCnt == 100) KeyCnt = 0; LEDBuffer[0] = KeyCnt%10; LEDBuffer[1] = KeyCnt/10 } IE0 = 0; EX0 = 1; }
外部中断0的中断服务函数
在上表中找到外部中断0对应的外部中断号“0”,在中断服务函数中,防止多次触发中断首先失能外部中断0,及EX0置0,手动清零外部中断0的中断标志位IE0 = 0;由于本次实验比较简单,所以我们直接在中断服务函数中进行软件延时对按键进行消抖,在复杂的工程中,不建议在中断中进行软件延时。消抖后再判断按键是否按下,确定按下后再对计数值增加,最后分别取计数值的十位和个位赋值到LEDBuffer中。当完成中断的一系列操作后要使能外部中断0。外部中断1的逻辑类似,这里就不在赘述了。