新唐 8051 系列的定时器和传统 8051 不太一样,以 ML51、MS51 这些 1T 内核为例,定时器的工作方式更接近 32 位 MCU 的设计思路,有自动重载、输入捕捉、PWM 输出这些功能,不再是经典 8051 那种“手动填初值”的**。下面以 ML51 为例拆开讲。
先搞清楚有哪几个定时器
ML51 内部有 4 组 16 位定时器,分别是 Timer0、Timer1、Timer2、Timer3。前两组是通用定时器,后两组功能更丰富一些。所有定时器都支持自动重载模式,配合预分频器,分频系数从 1 到 256 可调。
定时器时钟源来自系统时钟,ML51 的系统时钟可以选 HIRC(内部高速 RC)、LIRC(内部低速 RC)或者外部晶振。做精确定时时用外部晶振,做低功耗定时时用 LIRC 让系统在掉电模式下也能计时。
定时器初始化
以 Timer0 做 1ms 周期中断为例,系统时钟假设跑 24MHz。配置的核心是算出重载值,思路和传统 8051 一致,但寄存器结构不一样。
c
#include "ML51.h"
void Timer0_Init(void)
{
// 使能 Timer0 时钟
TIMER_ClockEnable(TIMER0);
// 配置 Timer0 为模式 0(定时模式),自动重载
TIMER_Open(TIMER0, TIMER_PERIODIC_MODE, 1000); // 1000Hz 即 1ms
// 使能定时器中断
TIMER_EnableInt(TIMER0);
NVIC_EnableIRQ(TMR0_IRQn);
// 启动定时器
TIMER_Start(TIMER0);
}
// 中断服务程序
void TMR0_IRQHandler(void)
{
TIMER_ClearIntFlag(TIMER0);
// 用户代码,每 1ms 执行一次
}
新唐 BSP 把重载值的计算封装在了 TIMER_Open() 里,传入频率参数就行,不用手动算 65536 - (时钟/分频/频率)。这是和传统 8051 写法差别最大的地方。
输入捕捉测频率
Timer2 支持输入捕捉功能,可以用来测量外部信号的频率或脉宽。配置方法是把 Timer2 设为捕捉模式,选择捕捉触发边沿,外部信号从指定引脚输入。
c
void Timer2_Capture_Init(void)
{
TIMER_ClockEnable(TIMER2);
// 配置捕捉模式,上升沿触发
TIMER_Open(TIMER2, TIMER_CAPTURE_MODE, 0);
// 选择捕捉输入引脚
TIMER_SelectCapturePin(TIMER2, TIMER_CAP_PIN_0);
// 使能捕捉中断
TIMER_EnableCaptureInt(TIMER2);
NVIC_EnableIRQ(TMR2_IRQn);
TIMER_Start(TIMER2);
}
捕捉中断触发后,读取 TIMER_GetCaptureData(TIMER2) 拿到当前计数值,两次捕捉值相减再结合时钟频率,就能算出信号周期。做红外解码或转速测量时比较实用。
PWM 输出
Timer3 支持 PWM 模式,可以输出占空比可调的方波。做 LED 调光或电机调速时用得上。
c
void Timer3_PWM_Init(void)
{
TIMER_ClockEnable(TIMER3);
// 配置 PWM 模式,频率 1kHz,占空比 50%
TIMER_Open(TIMER3, TIMER_PWM_MODE, 1000);
TIMER_SetPWMLevel(TIMER3, 500, 500); // 高电平 500,低电平 500
// 选择 PWM 输出引脚
TIMER_SelectPWMOutPin(TIMER3, TIMER_PWM_PIN_0);
TIMER_Start(TIMER3);
}
运行时改占空比调用 TIMER_SetPWMLevel() 就行,不需要停掉定时器重新配置。
低功耗场景下的定时唤醒
电池供电的设备里,定时器经常要承担唤醒任务。ML51 的 Timer0 可以配置成在掉电模式下继续运行,用 LIRC 作为时钟源,定时时间到产生中断把 CPU 唤醒。
c
void Timer0_Wakeup_Init(void)
{
// 时钟源切到 LIRC,10kHz
TIMER_SelectClockSource(TIMER0, TIMER_CLOCK_LIRC);
// 每 2 秒唤醒一次
TIMER_Open(TIMER0, TIMER_PERIODIC_MODE, 1); // 1Hz 即 1 秒
TIMER_EnableInt(TIMER0);
NVIC_EnableIRQ(TMR0_IRQn);
// 进入掉电模式,等待定时器唤醒
CLK_PowerDown();
}
这种用法在无线传感器节点里很常见,MCU 平时睡死,定时器到点醒来采一次数据,发完继续睡。
几个容易踩的坑
中断标志忘了清。 新唐 8051 的定时器中断标志需要软件写 1 清除,不是自动清的。中断服务程序里不调用 TIMER_ClearIntFlag(),程序会反复进中断。
分频系数和重载值搞混。 16 位定时器的重载值最大 65535,如果时钟频率高、定时时间长,得先加分频。24MHz 直接定时 1 秒,重载值超出 16 位范围,必须先分频再算。
低功耗模式下时钟源要选对。 掉电模式里 HIRC 通常会停,定时器如果还在用 HIRC 当时钟源就不会工作。要切到 LIRC 或者外部 32.768kHz 晶振。 |
|