51单片机——定时器0+动态数码管显示

实验内容

基于上一次的动态数码管显示(51单片机——动态数码管)icon-default.png?t=O83Ahttps://blog.csdn.net/li_han_han/article/details/142371983这次我们改用定时器中断来执行数码管的动态扫描。

电路部分

电路与上一篇动态数码管中的一样,就不再进行赘述了。

keil代码

再讲解代码前,我们应该先了解一下什么是定时器,以及定时器中断。

在51单片机(也称为8051单片机)中,定时器是一种内置的功能模块,用于实现定时或计数功能。51单片机通常包含两个可编程的16位定时器/计数器(Timer/Counter),即定时器0(T0)和定时器1(T1)。这些定时器/计数器可以在不同的模式下工作,以满足不同的应用需求。

定时器的基本功能

  1. 定时功能:通过设置定时器的初值,并启动定时器,当定时器从初值计数到全零(0xFFFF)时,可以产生一个定时中断(或称为溢出中断)。通过计算计数周期和单片机的时钟频率,可以精确计算出定时时间。

  2. 计数功能:定时器也可以配置为外部事件计数器,对外部引脚上的脉冲信号进行计数。这在需要测量外部事件频率或脉冲数量的应用中非常有用。

定时器的工作模式

51单片机的定时器/计数器通常具有以下几种工作模式:

  1. 模式0:13位定时器/计数器模式。在这种模式下,定时器/计数器使用THx(高8位)和TLx(低5位)寄存器,共13位。

  2. 模式1:16位定时器/计数器模式。这是最常用的模式,定时器/计数器使用THx和TLx寄存器,共16位。

  3. 模式2:8位自动重装载模式。在这种模式下,TLx寄存器用作8位定时器/计数器,而THx寄存器的内容在TLx溢出时自动重装载到TLx。

  4. 模式3:两个8位定时器/计数器模式。在这种模式下,THx和TLx各自独立作为8位定时器/计数器工作。

定时器的应用

定时器在51单片机中的应用非常广泛,包括但不限于:

  • 产生精确的延时:通过配置定时器的初值和时钟源,可以实现微秒级到毫秒级的精确延时。
  • 测量时间间隔:利用定时器的计数功能,可以测量两个事件之间的时间间隔。
  • 产生定时中断:定时器溢出时可以产生中断,用于实现多任务处理或周期性任务。
  • PWM(脉宽调制)输出:通过控制定时器的输出和占空比,可以生成PWM信号,用于电机控制等应用。

定时器的配置和使用

在使用定时器之前,通常需要进行以下配置:

  1. 选择工作模式:通过设置定时器控制寄存器(如TMOD)来选择定时器的工作模式。
  2. 设置初值:将定时器的初值加载到THx和TLx寄存器中。
  3. 启动定时器:通过设置定时器控制寄存器(如TCON)中的相关位来启动定时器。
  4. 配置中断(如果需要):如果需要定时器溢出时产生中断,需要配置中断允许寄存器(如IE)和中断优先级寄存器(如IP)。

通过合理配置和使用定时器,51单片机可以实现各种复杂的定时和计数功能,满足不同的应用需求。

那什么是定时器中断呢?

其实简单点来说(灵感来源于其他博主,但是我忘记是谁的了),原本的main函数中,程序都是一条一条的执行,就像大家去上公共厕所,一共就那么几个坑位,上一个拉完了,下一个才可以进去,但是呢定时器中断就像是串稀快呼之欲出的人,它有特权,它可以直接打开厕所门把正在拉的人抓出去(先不让他啦,让他夹住^_^),然后拉稀的先进去,因为定时器中断都是执行快的、简单的、不那么复杂的程序,跟串稀的一样,一旦释放几下就结束战斗了,所以定时器中断结束后,又回到刚刚被打断的程序继续执行,即让那个夹住的人继续(QaQ).

本次实验代码

在编写的过程中,我出现了两个错误

1、我觉得本次不需要在main中执行其他程序就将while循环删掉,main中的while循环也要写,不写就破坏了单片机的时序,因为数码管是通过定时器中断来更新的, 那么while(1){}循环的存在确保了定时器中断可以被持续处理,每次定时器溢出时,中断服务程序都会被调用,更新数码管的显示.
 *如果没有while(1) {}循环,程序将在初始化后立即结束,定时器中断将不会被处理,因此数码管将不会显示任何内容

2、在上次动态数码管显示中,我使用的是for循环来调用每个数码管的段选和位选。本次实验开始前,我想当然以为把for循环显示的内容移动到定时器中断中即可。但是事实不是这样的,因为之前的for循环是一直在main的while中循环,没有什么影响,但是在定时器中断中就不一样了,定时器中断是每隔一个时间段(取决于你定时器的长短),进去一次,进入后for就一直执行,直到for满足条件才停止跳出定时器(数码管的值停在了第八位),所以在protues中显示的效果就是只显示了第八位。

#include<reg52.h> 
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int 	
uint i=0;                                                //uchar code pos[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};	//8位数码管的位选
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66, //共阴型段码表0~9
									 0x6d,0x7d,0x07,0x7f,0x6f};
uchar xuehao[8]={1,2,0,1,2,1, 1,0};	//学号后8位比如为:12012110
uint CTRL_bit=0;
/******************数码管位选段选****************************************/
void ShowSMG_Bit(unsigned char value, unsigned int pos)
{
	//共阴数码管,位选接P3为低,段选接P0为高
  //数码管位选
  P3 = ~(0X01 << pos);//通过移位选位
  //数码管段选
  P0 = table[xuehao[value]];
}

/*******定时器*****************************************/
void InitTimer0()//定时器初始化函数
{
   TMOD = 0x01; // 设置定时器0为模式1(16位定时器)  
   TH0 = (65535 - 5000) /256;  // 7100以下都可以正常显示数码管,不会闪烁
   TL0 = (65535 - 5000) %256;  // 加载定时器初值(5000=5ms)  
   
	
    ET0 = 1;     // 使能定时器0中断  
    EA = 1;      // 使能全局中断  
    TR0 = 1;     // 启动定时器0  
}
/*******定时器中断*****************************************/
void Timer0() interrupt 1
{
	
	TH0 = (65535 - 5000) /256;
  TL0 = (65535 - 5000) %256;  // 重载定时器初值(也可选择自动重载模式就不需要手动重载) 
	/*
			for(i=0;i<8;i++)
			{
				ShowSMG_Bit(i,i);
			}	
		此处不可用for代替switch,虽说逻辑相似,但是大有不同
		switch是进一次中断刷新一下,for是进一次中断就将8位都显示一遍
		最后离开中断数码管停在第八位显示第八位的数
	*/

	switch(CTRL_bit)
	{
		case 0 :ShowSMG_Bit(0,0);break;
		case 1 :ShowSMG_Bit(1,1);break;
		case 2 :ShowSMG_Bit(2,2);break;
		case 3 :ShowSMG_Bit(3,3);break;
		case 4 :ShowSMG_Bit(4,4);break;
		case 5 :ShowSMG_Bit(5,5);break;
		case 6 :ShowSMG_Bit(6,6);break;
		case 7 :ShowSMG_Bit(7,7);break;
	}                      
	CTRL_bit=(CTRL_bit+1)%8;

}

/*****************主函数******************************************/
void main()
{
//	TMOD = 0x01; // 设置定时器0为模式1(16位定时器)  
//   TH0 = (65535 - 5000) /256;
//   TL0 = (65535 - 5000) %256;  // 加载定时器初值(10ms)  
//   
//	
//    ET0 = 1;     // 使能定时器0中断  
//    EA = 1;      // 使能全局中断  
//    TR0 = 1;     // 启动定时器0  
	InitTimer0();
	while(1)
	{
		/*
			空的while(1)循环必须要写,因为数码管是通过定时器中断来更新的
			那么while(1){}循环的存在确保了定时器中断可以被持续处理
			每次定时器溢出时,中断服务程序都会被调用,更新数码管的显示
		 *如果没有while(1) {}循环,程序将在初始化后立即结束,定时器中断将不会被处理,因此数码管将不会显示任何内容
		*/
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值