第5章 定时器与数码管基础
时钟周期:时钟周期 T 是时序中最小的时间单位。晶振是 11.0592M,则时钟周期=1/11059200 秒。
机器周期:单片机完成一个操作的最短时间。51单片机系列,在其标准架构下一个机器周期是 12 个时钟周期,也就是 12/11059200 秒。对于增强型单片机,一个机器周期可能只需要4个时钟周期。
定时器:作用用来定时。定时器内部有一个寄存器,我们让它开始计数后,这个寄存器的值每经过一个机器周期(标准51单片机也就是12/11059200 秒)就会自动加 1。当计数达到某一值,产生溢出,具体溢出值根据定时器模式不同而不同。
标准的 51 单片机内部有 T0 和 T1 这两个定时器。对应特殊功能寄存器如下:
是定时器控制寄存器 TCON 位分配寄存器各位功能描述:
TMOD寄存器介绍:
模式 1,是 THn 和 TLn 组成了一个 16 位的定时器,计数范围是 0~65535,溢出后,只要不对 THn 和 TLn 重新赋值,则从 0 开始计数。
模式 2,是 8 位自动重装载模式,只有 TLn做加 1 计数,计数范围 0~255,THn 的值并不发生变化,而是保持原值,TLn 溢出后,TFn就直接置 1 了,并且 THn 原先的值直接赋给 TLn,然后 TLn 从新赋值的这个数字开始计数。
使用定时器步骤:
第一步:设置特殊功能寄存器 TMOD,配置好工作模式。
第二步:设置计数寄存器 TH0 和 TL0 的初值。
第三步:设置 TCON,通过 TR0 置 1 来让定时器开始计数。
第四步:判断 TCON 寄存器的 TF0 位,监测定时器溢出情况。
使用定时器计算时间,假如需要定时0.2s,首先需要确定定时器需要多长时间才会使计数器加1,一般是1/11059200s,那么需要计数多少才能达到0.2s?
应该是0.2/(1/11059200);再计算需要给计数器赋初始值多少,才能确保计数0.2/(1/11059200)之后达到溢出状态?对于模式1的16位定时器,其最大计数到65535,那么可以得到需要给定时器赋初值为65536-0.2/(1/11059200)。
使用定时器完成小灯一秒钟的闪烁,代码如下:
#include <reg52.h>
sbit LED = P0^0;
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
void main()
{
unsigned char cnt = 0;
ENLED = 0;
ADDR3 = 1;
ADDR2 = 1;
ADDR1 = 1;
ADDR0 = 0;
TMOD = 0x01; //设置T0为模式1
TH0 = 0xB8; //定时0.2s赋初值,计算得出
TL0 = 0x00;
TR0 = 1; //启动T0
while (1)
{
if (TF0 == 1) //判断T0是否溢出
{
TF0 = 0; //清零中断标志并重新赋初值
TH0 = 0xB8;
TL0 = 0x00;
cnt++;
if (cnt >= 50) //溢出达到50次,累计计时正好1秒钟
{
cnt = 0;
LED = ~LED;
}
}
}
}
数码管
数码管原理图:
数码管共有 a、b、c、d、e、f、g、dp 共8 个段,每段可以当作是一个led小灯。
数码管有共阴极和共阳极两种,其结构示意图如下:
数码管真值表如下 :
数码管原理图:
对应译码器电路图:
数码管静态显示,让数码管DS1显示数字1,代码如下:
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
void main()
{
ENLED = 0; //使能 U3,选择数码管 DS1
ADDR3 = 1;
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 0;
P0 = 0xF9; //点亮数码管段 b 和 c
while (1);
}
实现数码管从0到F依次显示,间隔时间为1秒,代码如下:
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
unsigned char code LedChar[] = {
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
void main()
{
unsigned char cnt = 0; //记录 T0 中断次数
unsigned char sec = 0; //记录经过的秒数
ENLED = 0; //使能 U3,选择数码管 DS1
ADDR3 = 1;
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 0;
TMOD = 0x01; //设置 T0 为模式 1
TH0 = 0xB8; //为 T0 赋初值 0xB800
TL0 = 0x00;
TR0 = 1; //启动 T0
while (1)
{
if (TF0 == 1) //判断 T0 是否溢出
{
TF0 = 0; //T0 溢出后,清零中断标志
TH0 = 0xB8; //并重新赋初值
TL0 = 0x00;
cnt++; //计数值自加 1
if (cnt >= 50) //判断 T0 溢出是否达到 50 次
{
cnt = 0; //达到 50 次后计数值清零
P0 = LedChar[sec]; //当前秒数对应的真值表中的值送到 P0 口
sec++; //秒数记录自加 1
if (sec >= 16) //当秒数超过 0x0F(15)后,重新从 0 开始
{
sec = 0;
}
}
}
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)