
Jellyfish从89C51到AI8051学习贴第十七天!
今天继续学习《8051U深度入门到32位51大型实战教学视频》第十五集 定时器用作计数器。
0x01 学习重点
-
练习1:CT计数器

-
配置各种寄存器
0x02 学习心得
-
定时器4有隐藏寄存器
定时器 4 有两个隐藏的寄存器 RL_T4H 和 RL_T4L。RL_T4H 与 T4H 共有同一个地址,RL_T4L 与 T4L共有同一个地址。当 T4R=0 即定时器/计数器 4 被禁止工作时,对 T4L 写入的内容会同时写入 RL_T4L,对T4H 写入的内容也会同时写入 RL_T4H。当 T4R=1 即定时器/计数器 4 被允许工作时,对 T4L 写入内容,实际上不是写入当前寄存器 T4L 中,而是写入隐藏的寄存器 RL_T4L 中,对 T4H 写入内容,实际上也不是写入当前寄存器 T4H 中,而是写入隐藏的寄存器 RL_T4H,这样可以巧妙地实现 16 位重装载定时器。当读 T4H和 T4L 的内容时,所读的内容就是 T4H 和 T4L 的内容,而不是 RL_T4H 和 RL_T4L 的内容。
想要实现初始起点赋值,需要先T4R=0,然后对T4H、T4L进行赋值。
-
通过双缓存逻辑: times 和 interval 作为 static 变量来缓存旧值,只有当数据变化时才重新计算 Disp_Buf。“变更触发”。极大减轻了 CPU 负担,避免了每 100ms 都在重复执行耗时的除法运算。
-
32位AI8051U十分强大16位除法比减法还要快!
测试结果:
除法 10次 消耗 T3 计数值: 72
减法 10次 消耗 T3 计数值: 135
// 1. 准备:初始化 T3 为 16 位定时器模式,不分频,不中断
T3R = 0; T3_CT = 0;
T3H = 0; T3L = 0;
T3R = 1; // 开始数数
void Test_Performance(){
u16 start_count, end_count, i;
volatile u16 test_val = 12345; // 使用 volatile 防止被编译器优化掉
u8 cnt;
// --- 测试 A:除法逻辑 ---
start_count = (T3H << 8) | T3L;
for (i = 0; i < 10; i++) { // 跑 1000 次足够看出差异
Disp_Buf[7] = (u8)(test_val % 10);
Disp_Buf[6] = (u8)((test_val / 10) % 10);
Disp_Buf[5] = (u8)((test_val / 100) % 10);
Disp_Buf[4] = (u8)((test_val / 1000) % 10);
}
end_count = (T3H << 8) | T3L;
printf_usb("除法 10次 消耗 T3 计数值: %u\r\n", end_count - start_count);
// 2. 重置计数器
T3H = 0; T3L = 0;
// --- 测试 B:循环减法逻辑 ---
start_count = (T3H << 8) | T3L;
for (i = 0; i < 10; i++) {
u16 temp = test_val;
cnt = 0; while(temp >= 1000) { temp -= 1000; cnt++; } Disp_Buf[4] = cnt;
cnt = 0; while(temp >= 100) { temp -= 100; cnt++; } Disp_Buf[5] = cnt;
cnt = 0; while(temp >= 10) { temp -= 10; cnt++; } Disp_Buf[6] = cnt;
Disp_Buf[7] = (u8)temp;
}
end_count = (T3H << 8) | T3L;
printf_usb("减法 10次 消耗 T3 计数值: %u\r\n", end_count - start_count);
}
-
配置启用定时器4用作计数器
P00=0; //矩阵键盘配置P00为低电平,这样可以给P06提供下降沿
T4_CT=1; //配置定时器3为计数器模式
T4L=0xff; //配置底八位
T4H=0xff; //配置高八位 默认16位自动重载
T4R=1; //配置定时器3开始计数
ET4=1; //开启定时器3中断
T4IF=0; //清除中断请求标志位
EA=1; //开启总中断
//中断函数
void Timer4_Isr(void) interrupt 20
{
PulseTotal++;
PulseInterval_Show=PulseInterval_100ms;
PulseInterval_100ms=0;
}
//定时器调度结构体
TASK_COMPONENTS Task_Comps[]=
{
//状态 计数 周期 函数
{0, 1, 1, Seg_Task},
{0, 100, 100, ClacTimes},
};
//字段定义
u16 PulseTotal=0; //累计按下
u16 PulseInterval_100ms=0; //间隔数量(单位100ms)
u16 PulseInterval_Show=0; //显示的间隔数量
// --- 计算当前数量 100ms 调度任务逻辑 ---
void ClacTimes(){
static u16 interval=0xffff,times=0xffff;
u16 val=0;
//每100ms给计数器加一;
PulseInterval_100ms++;
// printf_usb("PulseInterval_Show=%d",PulseInterval_Show);
if (times!=PulseTotal)
{
times=PulseTotal;
Disp_Buf[3] = (u8)(times%10);
Disp_Buf[2] = (u8)((times/10)%10);
Disp_Buf[1] = (u8)((times/100)%10);
Disp_Buf[0] = (u8)((times/1000)%10);
}
if (interval != PulseInterval_Show)
{
interval=PulseInterval_Show;
for ()
printf_usb("开始PulseInterval_Show=%d",PulseInterval_Show);
Disp_Buf[7] = (u8)(interval%10);
Disp_Buf[6] = (u8)((interval/10)%10);
Disp_Buf[5] = (u8)((interval/100)%10);
Disp_Buf[4] = (u8)((interval/1000)%10);
}
}