51单片机:01_定时器和数码管的实现

157 阅读7分钟

1.定时器

Pre

1.SFR Special Function Register 特殊功能寄存器

2.T Timer 定时器

3.TCON TimerConfig 定时器控制寄存器

4.TCON的 7个

  • TF1: Timer 1 Overflow Flag
  • TR1: Timer 1 Run Control Bit
  • TF0: Timer 0 Overflow Flag
  • TR0: Timer 0 Run Control Bit
  • IE1: External Interrupt 1 Edge Flag
  • IT1: Interrupt 1 Type Control Bit
  • IE0: External Interrupt 0 Edge Flag
  • IT0: Interrupt 0 Type Control Bit

5.TMOD Timer Mode

6.OSC Oscillator 震荡器

1.1 周期时钟

开发板晶振是 11.0592MHZ,时钟周期=1/11059200秒

1.2.机器周期

单片机完成一个操作的最短时间,汇编中、每条语句占用时间位整数倍、C语言不确定。 不同单片机的 1个机器周期等于时钟周期不同 51单片机的 1个机器周期=12个时钟周期,12/11059200秒

1.3.定时器和计数器

定时器内部的寄存器(T0\T1)在一个机器周期自动+1,即12/11059200秒+1。

定时器溢出:当计数超过寄存器能存的最大数时、定时器溢出到0。如16位寄存器计数到65535后,再+1=0。

T0\T1 寄存器

存储定时器的计数值。分为高8位和低8位 T0 分为TH0、TL0;T1 分为 TH1、TL1

TCON寄存器

定时器控制寄存器

76543210
TF1TR1TF0TR0IE1IT1IE0IT0
符号描述
7TF1定时器1溢出标志。定时器1溢出硬件置1、清零方式:软件置0、定时器中断时硬件清零
6TR1定时器1运行控制位。软件置位 设置1时启动定时器1
5TF0定时器0溢出标志
4TR0定时器0运行控制位
3IE1
2IT1
1IE0
0IT0

TMOD

76543210
GATEC/TM1M0GATEC/TM1M0

T0/T1定时器各占4个

符号描述
7GATE暂时不知道干嘛的
6C/T定时器功能选择、0用作定时器 1用作计数器
M0M1工作模式/描述
00不知道干嘛
01THn和TLn组成16位的定时器
10暂时不知道干嘛的
11禁用定时器1,定时器0变成两个8位定时器

1.4 程序实例:

目标:1秒间隔闪烁LED0灯

main.c

#include <REGX52.H>

sbit LED1=P2^0;
unsigned char count = 1;
void main(){
	
	/*
	* 控制LED灯 1秒闪一次
	* 1.51单片机机器周期是 12、 时钟周期是 11.0592MHZ,一个计数=12/11059200
	* TH+TL =16 位、一共记录 65536个计数
	* 即 12/11059200*65536 ≈ 0.071s
	* 因此 每次计时 最多 0.071s
	* 可以拆成 0.05*20=1s 循环20次 每次0.05秒
	* 12/11059200*x=0.05,得x=46080,
	* 则 计数器从 65535-46080=19455开始计数 即4BFF 每次 TH0=4B TL0=FF开始计算 实际还要加1个数
	* 所以 TH0=4C TL0=00
	*/
	//1.使用T0、工作模式1 0000 0001
	TMOD = 0X01;
	//2.赋初始值
	TH0 =0X00;
	TL0 =0X4C;
	TF0=0;
	TR0 = 1;
	
	while(1){
 //每次溢出重置定时器 计数+1
		if(TF0==1){
			TH0 = 0X00;
			TL0 = 0X4C;
				
			TF0=0;
			count++;
		}
//20次后 更改led0灯状态 计数清0
		if(count>=20){
			LED1 = ~LED1;
			count = 0;
		}
	}
}

2.数码管

分为共阴极(公共端输出0)、共阳极(公共端输出1) 这里选择 LEDn段输出0 LCDn端输出1 共阴级。

LED数码管.png 要解决的问题是:

1.一共有8个数码管、选择哪个数码管显示数字

2.选择了数码管之后、该数码管显示什么数字

问题1解决.选择亮哪个数码管

38译码器.png

如开发板原理图所示,38译码器 P22-P24 选择 LED1-LED8,如:000 选择LED1、001 选择LED2... 这就解决了亮的是哪个数码管。

问题2解决.选择显示哪个数字

数码管.png

数码管全亮的话显示的是数字 8.,即abcdefg+dp 都显示 要显示1时 bc亮 要显示2时 abged亮 ... 那么如何让a、b、c、d...亮呢

数码管2.png

看图得知 a连向了LCD0、而LCD0又连向了P00 因为上面选择的是LEDn输出0、所以LCDn要输出1 由图可知LCD0和P00中间还有一个74HC573 ,那么如何通过P00使得通过74HC573 使得LCD0输出1呢 74HC245.png 由74HC573逻辑图可知 P0n输出几Qn输出几、即LCDn输出几。

这里算出来的1对应bc 需要设置为OB0000 0110=0X06称作段码。 P0=OX06时,并且选择的是LCD0 这时数码管第1位会显示1。

数码管需要不停的输入才能一直显示。 所以数码管数字显示要写在while(){}里,不然会一闪而过。

程序实例

目标:在开发板数码管对应位置显示对应的数字

微信图片_20240910205650.png main.c

#include <REGX52.H>
#include "Delay.h"
//0-9的段码
//0 ABCDEF 	0011 1111 0X3F
//1 BC 		0000 0110 0X06
//2 ABGED 	0110 0011 0X5B
//3 ABGCD   0100 1111 0X4F
//4 FGBC	0110 0110 0X66
//5 AFGCD   0110 1101 0X6D
//6 AFGEDC  0111 1101 0X7D
//7 ABC     0000 0111 0X07
//8 ABCDEFG 0111 1111 0X7F
//9 ABGFCD  0110 1111 0X6F
unsigned char Dig[] = {
	0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F
};
//数码管显示子函数
void Nixie(unsigned char Location,Number)
{
	switch(Location)		//位码输出
	{
		case 1:P2_4=0;P2_3=0;P2_2=0;break;
		case 2:P2_4=0;P2_3=0;P2_2=1;break;
		case 3:P2_4=0;P2_3=1;P2_2=0;break;
		case 4:P2_4=0;P2_3=1;P2_2=1;break;
		case 5:P2_4=1;P2_3=0;P2_2=0;break;
		case 6:P2_4=1;P2_3=0;P2_2=1;break;
		case 7:P2_4=1;P2_3=1;P2_2=0;break;
		case 8:P2_4=1;P2_3=1;P2_2=1;break;
	}
	P0=Dig[Number];	//段码输出
	Delay(1);//显示一段时间
	P0=0x00;//段码清0,消影 
}
void main(){
	// 让数码管 LED1 显示1
 //使用共阴极 所以LEDn输出0 ,LCDn输出1
	//1.选择 LED1
	// P22-P24 = 000
	// 000 0,00 00
 //2.选择数字1
	//要让b、c亮起来 通过看电路图(74HC573)1为亮 0为灭
	//a=LCD0 B=LCD1 C=LCD2 D=LCD3 E=LCD4 F=LCD5 G=LCD6 DP=LCD7
	// 1=BC b = LCD1 C=LCD2,0000 0110 = 0X06
	// 2=ABGED 0101 1011 = 0X5B
	// 1110 0011
	while(1)
	{
		Nixie(1,1);		//在数码管的第1位置显示1
		Nixie(2,2);		//在数码管的第2位置显示2
		Nixie(3,3);		//在数码管的第3位置显示3
		Nixie(4,4);		//在数码管的第4位置显示4
		Nixie(5,5);		//在数码管的第5位置显示5
		Nixie(6,6);		//在数码管的第6位置显示6
		Nixie(7,7);		//在数码管的第7位置显示7
		Nixie(8,8);		//在数码管的第8位置显示8
	}
}