单片机学习整理----定时器/计数器
本来打算从LED开始写起的,仔细一想,没有必要。不妨博客当笔记把单片机重要的部分记下来。以后忘记了还可以看一看。
声明:1、我用是STC89C52系列单片机
2、内有两个16位的定时器和计数器 T0 T1
3、时钟频率是11.0592
关于定时器定时原理: 因为是16位计数寄存器。每经过一个机器周期,它内部就自动加1 直到溢出。
(1111 1111 1111 1111)B = 65535
那么如果工作方式为 TL0 TH0 (两个装初值的寄存器)都用到了
那定时模式时间最多为 65535 * 1.085us = 时间 71105.475us
1.085怎么得来的:11.0592MHZ 1 / 11.0592 * 12 = 1.085us
比如我要定时 50ms的定时器 工作模式为16位定时器 TH0 TL0 该赋什么初值?
50ms = 50000us 用最大时间 减去 50ms 为 max-50ms = 21105.475us
除以 1.058 ≈ 19452.05069 转化为二进制 0100 1011 1111 1101
所以给TL0 = 0x4b TH0 = 0XFD
计数器工作原理: 当工作在计数器模式时,T0(P3.4引脚)T1(P3.5)引脚 每来一个脉冲,计数寄存器就加1。
用定时器/计数器的流程可以分为3 步: ① 启动定时器/计数器 (TCON控制)
② 设置定时器/计数器工作模式(TMOD控制)
③ 判断定时器/计数器是否溢出 (TCON内的TF位)
查阅单片机手册 看所需要配置寄存器(看手册是个很枯燥的事情)
看到这张图,找重点嘛 (可位寻址)
1、我要用哪个定时器/或计数器,T0 T1 开启单位分别是 TR1 TR0
TR?是由软件置位和清零
2、 溢出标志判断 TF? 由硬件清0 时间是否到就查询它受否溢出。
TMOD的手册
1、不可位寻址
2、C/T 管理是用于定时器还是计数器
如果用于计数器:需要从T0 (P3.4) T1(P3.5) 口输入脉冲信号。
3、 M0 M1 用于管理哪种模式 怎么用TH0 和TL0 存初值。
上面已经讲过一次了。
下面开始写定时器0程序:
1 #include <reg52.h> //引入51头文件 2 #include <intrins.h> //引入循环库 3 4 #define uchar unsigned char 5 #define uint unsigned int 6 7 sbit DU = P2^6; //数码管段选 8 sbit WE = P2^7; //数码管位选 9 /*共阴极数码管的段选表 code存放到rom区*/ 10 uchar code table [] = {0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F}; //0123456789 的16进制 11 12 void delay(uint z); 13 void display(uchar i); 14 void timer0Init(); 15 16 void main() 17 { 18 uchar msec,sec; //毫秒和秒存储变量 19 timer0Init(); 20 while(1) 21 { 22 if(TF0 == 1) //判断标志位是否溢出,定时器是否到时间 23 { 24 TF0 = 0; //软件清0 25 msec++; //50毫秒到 26 if(msec == 20) 27 { 28 msec = 0; 29 sec++; //一秒时间到 \' 30 if(sec > 10) sec = 0; //如果大于10秒 秒清零 31 } 32 } 33 display(sec); 34 } 35 36 } 37 /*ms级延迟函数*/ 38 void delay(uint z) 39 { 40 uint x,y; 41 for(x = z; x>0; x--) 42 for(y = 144; y>0 ; y--); 43 } 44 /*数码管显示*/ 45 void display(uchar i) 46 { 47 uchar bai,shi,ge; //代表百十个 48 bai = i/100; 49 shi = i % 100 / 10; 50 ge = i % 10; 51 /*第一位数码管*/ 52 P0 =0XFF; //清除段码 53 WE = 1; //打开位选锁存器 54 P0 = 0XFE; // 1111 1110 55 WE = 0; //锁存数据 56 57 DU = 1; //打开段选锁存器 58 P0 = table[bai]; 59 DU = 0; // 锁存数据 60 delay(5); //延迟 5 毫秒 61 /*第二位数码管*/ 62 P0 = 0XFF; 63 WE = 1; //打开位选锁存器 64 P0 = 0XFD; // 1111 1101 65 WE = 0; //锁存数据 66 67 DU = 1; //打开段选锁存器 68 P0 = table[shi]; 69 DU = 0; // 锁存数据 70 delay(5); 71 /*第三位数码管*/ 72 P0 = 0XFF; 73 WE = 1; //打开位选锁存器 74 P0 = 0XFB; //1111 1011 75 WE = 0; //锁存数据 76 77 DU = 1; //打开段选锁存器 78 P0 = table[ge]; 79 DU = 0; // 锁存数据 80 delay(5); 81 } 82 /*定时器0初始化函数*/ 83 void timer0Init() 84 { 85 TR0 = 1; //定时器启动 86 TMOD = 0X01; //设置模式为定时器 0000 0001 为16位定时器 87 TH0 = 0x4b; //初始值的高8位 设置定时为50ms 88 TL0 = 0xfd; //初始值的低8位 89 90 }
计数器代码:用T1的定时器来计时 每50ms发送一次脉冲 (通过P1^0口实现
/* 方法:用杜邦线从 P1^0接到 P3^4 原理:用定时器来控制led灯的闪烁来产生脉冲波形 使计数器计数,并且用数码管显示低8位 */ #include <reg52.h> //引入51头文件 #include <intrins.h> //引入循环库 #define uchar unsigned char #define uint unsigned int sbit DU = P2^6; //数码管段选 sbit WE = P2^7; //数码管位选 sbit led1 = P1^0; // 第一个led1用它的闪烁来表示方波; /*共阴极数码管的段选表 code存放到rom区*/ uchar code table [] = {0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F}; //0123456789 的16进制 void delay(uint z); void display(uchar i); void number0Init(); void timer1Init(); void main() { uchar msec; //毫秒和秒的存储变量 timer1Init(); //定时器1初始化函数 调用 number0Init(); //定时器0变计数器函数调用 while(1) { if(TF1 == 1) //判断标志位是否溢出(定时器是否到时间) { TF1 = 0; //软件清0 TH1 = 0X4B; TL1 = 0XFD; //再次定时50ms msec++; //50毫秒到了自增 if(msec == 10) //定时500ms到了 { msec = 0; led1 = !led1; //产生一个方波 } } display(TL0); //显示低8位的值 } } void delay(uint z) { uint x,y; for(x = z; x>0; x--) for(y = 144; y>0 ; y--); } void display(uchar i) { uchar bai,shi,ge; //代表百十个 bai = i/100; shi = i % 100 / 10; ge = i % 10; /*第一位数码管*/ P0 =0XFF; //清除段码 WE = 1; //打开位选锁存器 P0 = 0XFE; // 1111 1110 WE = 0; //锁存数据 DU = 1; //打开段选锁存器 P0 = table[bai]; DU = 0; // 锁存数据 delay(5); //延迟 5 毫秒 /*第二位数码管*/ P0 = 0XFF; WE = 1; //打开位选锁存器 P0 = 0XFD; // 1111 1101 WE = 0; //锁存数据 DU = 1; //打开段选锁存器 P0 = table[shi]; DU = 0; // 锁存数据 delay(5); /*第三位数码管*/ P0 = 0XFF; WE = 1; //打开位选锁存器 P0 = 0XFB; //1111 1011 WE = 0; //锁存数据 DU = 1; //打开段选锁存器 P0 = table[ge]; DU = 0; // 锁存数据 delay(5); } /*定时器0初始化为计数器函数*/ void number0Init() { TR0 = 1; //定时器启动 TMOD |= 0X05; //设置模式为计数器 0000 0101 为16位计数器 TH0 = 0; //初始值的高8位 TL0 = 0; //初始值的低8位 } /*定时器1初始化函数*/ void timer1Init() { TR1 = 1; //定时器启动 TMOD |= 0X10; //设置模式为计数器 0000 0101 为16位计数器 TH1 = 0x4b; //初始值的高8位 定时50ms TL1 = 0xfd; //初始值的低8位 }