51单片机练习:用定时器0的方式1实现第一个发光管以200ms间隔闪烁,用定时器1的方式1实现数码管前两位59s循环计时

题目:

用定时器0的方式1实现第一个发光管以200ms间隔闪烁,用定时器1的方式1实现数码管前两位59s循环计时(来自郭天祥老师的51单片机练习)

代码:

初始化函数

//初始化函数
void Init()
{
	TMOD = 0x11;//两个定时器的工作模式
	TH0 = (65536 - 45872) / 256;//T0计时50ms
	TL0 = (65536 - 45872) % 256;
	TH1 = (65536 - 45872) / 256;//T1计时50ms
	TL1 = (65536 - 45872) % 256;
	EA = 1;//使能总中断
	ET0 = 1;//使能T0中断
	ET1 = 1;//使能T1中断
	TR0 = 1;//启动T0
	TR1 = 1;//启动T1
	
	time = 0;//1s加1计时
}

数码管显示函数

//数码管显示函数
void display()
{
	uint ge,shi;
	//计算每秒个位与十位的变化
	if(t1 == 20)
	{
		t1 = 0;
		time++;
		if(time == 60)
		{
			time = 0;
		}
		shi = time / 10;//十位
		ge = time % 10;//个位
	}
	
	//显示十位
	WLE = 1;
	P0 = 0xfe;
	WLE = 0;
	P0 = 0xff;//消影
	DLE = 1;
	P0 = Table[shi];
	DLE = 0;
	delay_1ms(5);//延时短,达到动态扫描的效果
	
	//显示个位
	WLE = 1;
	P0 = 0xfd;
	WLE = 0;
	P0 = 0xff;//消影
	DLE = 1;
	P0 = Table[ge];
	DLE = 0;
	delay_1ms(5);//延时短,达到动态扫描的效果
}

延时1ms函数

//延时1ms函数
void delay_1ms(uint z)
{
	uint x,y;
	for(x = z;x > 0;x--)
	{
		for(y =110;y > 0;y--){}
	}
}

定时器0中断函数

void Timer0() interrupt 1
{
	TH0 = (65536 - 45872) / 256;//T0计时50ms
	TL0 = (65536 - 45872) % 256;
	t0++;
	
	if(t0 == 4)
	{
		t0 = 0;
		led1 = ~led1;	
	}
}

定时器1中断函数

void Timer1() interrupt 3
{
	TH1 = (65536 - 45872) / 256;//T1计时50ms
	TL1 = (65536 - 45872) % 256;
	t1++;
}

整个项目代码

#include 

//【例3.5.2】在 TX-1C 实验板上完成如下功能:用定时器0的方式1实现第一个发光管以200ms间隔闪烁,用定时器1的方式1实现数码管前两位59s循环计时。
//实验板晶振 11.0529MHz

#define uint unsigned int
#define uchar unsigned char
	
sbit led1 = P1^0;//第一个发光管
sbit WLE = P2^7;//位选
sbit DLE = P2^6;//段选
//数码管的编码表
uchar code Table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
uint t0,t1,time;

void Init();
void LED();
void display();
void delay_1ms(uint z);

void main()
{
	Init();
	
	while(1)
	{
		display();
	}
}

//初始化函数
void Init()
{
	TMOD = 0x11;//两个定时器的工作模式
	TH0 = (65536 - 45872) / 256;//T0计时50ms
	TL0 = (65536 - 45872) % 256;
	TH1 = (65536 - 45872) / 256;//T1计时50ms
	TL1 = (65536 - 45872) % 256;
	EA = 1;//使能总中断
	ET0 = 1;//使能T0中断
	ET1 = 1;//使能T1中断
	TR0 = 1;//启动T0
	TR1 = 1;//启动T1
	
	time = 0;//1s加1计时
}

//数码管显示函数
void display()
{
	uint ge,shi;
	//计算每秒个位与十位的变化
	if(t1 == 20)
	{
		t1 = 0;
		time++;
		if(time == 60)
		{
			time = 0;
		}
		shi = time / 10;//十位
		ge = time % 10;//个位
	}
	
	//显示十位
	WLE = 1;
	P0 = 0xfe;
	WLE = 0;
	P0 = 0xff;//消影
	DLE = 1;
	P0 = Table[shi];
	DLE = 0;
	delay_1ms(5);//延时短,达到动态扫描的效果
	
	//显示个位
	WLE = 1;
	P0 = 0xfd;
	WLE = 0;
	P0 = 0xff;//消影
	DLE = 1;
	P0 = Table[ge];
	DLE = 0;
	delay_1ms(5);//延时短,达到动态扫描的效果
}

//延时1ms函数
void delay_1ms(uint z)
{
	uint x,y;
	for(x = z;x > 0;x--)
	{
		for(y =110;y > 0;y--){}
	}
}

void Timer0() interrupt 1
{
	TH0 = (65536 - 45872) / 256;//T0计时50ms
	TL0 = (65536 - 45872) % 256;
	t0++;
	
	if(t0 == 4)
	{
		t0 = 0;
		led1 = ~led1;	
	}
}

void Timer1() interrupt 3
{
	TH1 = (65536 - 45872) / 256;//T1计时50ms
	TL1 = (65536 - 45872) % 256;
	t1++;
}

心得/经验记录:

1.不能将led灯的程序写在主函数中。因为,如果led灯的程序写在主函数中,并且led灯亮灭的间隔时间减短(如20ms),数码管每次显示的时间加长(如50ms),在这种情况下,有可能程序进入到数码管的display函数中执行并延时,但此时led灯的程序也到时间该执行,实际上却无法执行,那么t0变量就会一直加下去,之后led灯也就不会改变状态了。(郭天祥老师经验)

2.在数码管的display函数中,段选与位选的显示语句不能写在if语句中,否则数码管的十位会一直闪,不能正常显示。因为当段选与位选的显示语句写在if语句中时,只有t1=20时,才会显示数码管,对于十位数来说,就是短暂的几毫秒,之后就马上会因为个位数的显示而关闭,因而看到的实验现象是十位数隐隐闪现。当段选与位选的显示语句写在if语句外时,主函数的while语句会一直执行display函数,当t1没到20的时候,数码管就一直显示上一秒的值(数码管动态显示),当他t1=20的时候,说明1秒到达,就改变个位ge和十位shi变量的值,数码管显示数值就会更新,加1秒。

写此文章,仅记录自己学习51单片机过程中的一些思考和心得感悟,方便自己之后查阅,也供学习51单片机的小伙伴学习参考~

你可能感兴趣的:(51单片机学习,51单片机,嵌入式硬件,单片机)