单片机学习笔记 13. 定时/计数器_计数
更多单片机学习笔记:
单片机学习笔记 1. 点亮一个LED灯
单片机学习笔记 2. LED灯闪烁
单片机学习笔记 3. LED灯流水灯
单片机学习笔记 4. 蜂鸣器滴~滴~滴~
单片机学习笔记 5. 数码管静态显示
单片机学习笔记 6. 数码管动态显示
单片机学习笔记 7. 独立键盘
单片机学习笔记 8. 矩阵键盘按键检测
单片机学习笔记 9. 8×8LED点阵屏
单片机学习笔记 10. 中断系统(理论)
单片机学习笔记 11. 外部中断
单片机学习笔记 12. 定时/计数器_定时
目录
0、实现的功能
1、Keil工程
2、代码实现
0、实现的功能
用T0定时器定时50ms的,T1做计数器,过了1秒就LED1闪烁/熄灭,同时数码管+1。可做时钟
1、Keil工程
工作在计数模式下,每接收到一个高低电平,P3.4就会加1
TMOD的2位 置1即可,即TMOD=0x05。
初始值TH0和TL0都为0
2、代码实现
将P34和P10相连,每次P10电平变化一次(产生方波),T0(TH0和TL0)就加1(数码管就显示加1)
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit WE = P2^7;
sbit DU = P2^6;
sbit LED1 = P1^0;//定义LED1
uchar code table[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f} ;
//延时模块
void delay(uint z)
{
uint x;
uint y;
for(x = z; x > 0; x--)
for(y = 114; y > 0; y--);
}
void display(uint i)
{
uchar bai, shi , ge;
bai = i / 100;
shi = i % 100 /10;
ge = i % 10;
//第一个数码管
P0 = 0xff;
WE = 1;
P0 = 0xfe;
WE = 0;
DU = 1;
P0 = table[bai];
DU = 0;
delay(5);
//第二个数码管
P0 = 0xff; //清除断码,让位锁存器哪个都不选
WE = 1;//位选锁存打开
P0 = 0xfd;//选第二个管
WE = 0; //关上位选锁存器,进入锁存
DU = 1;//段选锁存打开
P0 = table[shi]; //亮shi
DU = 0;//进入锁存
delay(5); //延时5ms
//第三个数码管
P0 = 0xff; //清除断码,让位锁存器哪个都不选
WE = 1;//位选锁存打开
P0 = 0xfb;//选第三个管
WE = 0; //关上位选锁存器,进入锁存
DU = 1;//段选锁存打开
P0 = table[ge]; //亮ge
DU = 0;//进入锁存
delay(5); //延时5ms
}
//计数器0初始化,初值为0
void timer0Init()
{
TR0 = 1; //启动计数器0
TMOD = 0x05;//启动计数器0的工作模式1:16位计数
TH0 = 0;
TL0 = 0;
}
void main()
{
timer0Init();//计数器0初始化
while(1)
{
delay(500);//延时500ms后P10取反,也就是产生500ms为半个周期的方波
LED1 = ~LED1;//P10取反,将P10状态给P34,产生高低电平,进行计数
display(TL0);//从低位开始计时
}
}
实物展示:发现不是一直显示前两位,因为在延时500ms的时候,CPU只是一直在做延时的处理,就是在不停的加加减减浪费时间,没有精力去管数码管的动态显示了;这时再加上个中断就可以了,中断可以停止当前的事去干中断响应处理
或者用定时+计数的方式去做,反正只要不用Delay就行
代码实现:
这里定时器和计数器的初始化可以不用或等于 |=, 直接TMOD = 0x15也行
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit WE = P2^7;
sbit DU = P2^6;
sbit LED1 = P1^0;//定义LED1
uchar code table[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f} ;
//延时模块
void delay(uint z)
{
uint x;
uint y;
for(x = z; x > 0; x--)
for(y = 114; y > 0; y--);
}
void display(uint i)
{
uchar bai, shi , ge;
bai = i / 100;
shi = i % 100 /10;
ge = i % 10;
//第一个数码管
P0 = 0xff;
WE = 1;
P0 = 0xfe;
WE = 0;
DU = 1;
P0 = table[bai];
DU = 0;
delay(5);
//第二个数码管
P0 = 0xff; //清除断码,让位锁存器哪个都不选
WE = 1;//位选锁存打开
P0 = 0xfd;//选第二个管
WE = 0; //关上位选锁存器,进入锁存
DU = 1;//段选锁存打开
P0 = table[shi]; //亮shi
DU = 0;//进入锁存
delay(5); //延时5ms
//第三个数码管
P0 = 0xff; //清除断码,让位锁存器哪个都不选
WE = 1;//位选锁存打开
P0 = 0xfb;//选第三个管
WE = 0; //关上位选锁存器,进入锁存
DU = 1;//段选锁存打开
P0 = table[ge]; //亮ge
DU = 0;//进入锁存
delay(5); //延时5ms
}
//计数器0初始化,初值为0
void timer0Init()
{
TR0 = 1; //启动计数器0
TMOD |= 0x05;//启动计数器0的工作模式1:16位计数。或等是为了不影响定时器1的定义
TH0 = 0;
TL0 = 0;
}
//定时器1初始化,初值为50ms
void timer1Init()
{
TR1 = 1; //启动定时器1
TMOD |= 0x10;//启动计数器1的工作模式1:16位定时
TH1 = 0x4b;
TL1 = 0xfd;//初始值50ms
}
void main()
{
uchar mSec;//毫秒的存储变量
timer0Init();//计数器0初始化
timer1Init();//定时器1初始化
while(1)
{
if(TF1 == 1)//定时溢出时已过50ms
{
TF1 = 0;//软件清零溢出标志位
TH1 = 0x4b;
TL1 = 0xfd;//重新定时50ms
mSec++;//已过了50ms
if(mSec == 10)//如果已经过了10个50ms 也就是500ms
{
mSec = 0;//mSec清零
LED1 = ~LED1;//P10取反,将P10状态给P34,产生方波,进行计数
}
}
display(TL0);//从低位开始计时
}
}
实物展示: