proteus仿真51单片机加减计数器

1、在proteus软件上绘制原理图

  • 这里的选用的是共阴数码管 ,段选信号高电平亮。
  • RP1是上下拉排阻,当其1脚接电源时为上拉排阻,接地时为下拉排阻。
  • RN1为限流排阻,可通过修改其名字来更改排阻的阻值
  • 74HC240是双线八路反相缓冲器/线路驱动器,具有三态输出。该三态输出由输出使能端$\overline{OE}$控制。$\overline{OE}$接高电平将使输出端呈现高阻态。
  • 两个按键必须分别接在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;
}
  • #include <AT89X51.H>
    引用51的头文件。
  • unsigned char SEGTAB[] = {
    0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
    };
    定义段选译码表,及需要显示0~f对应输出的段选信号(控制a,b,c,d,e,f,g,h八段LED)。
  • 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的逻辑类似,这里就不在赘述了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值