[文档下载] 新唐 8051 内核 MCU 定时器配置与应用

[复制链接]
3|0
甜心puppy 发表于 2026-9-18 16:20 | 显示全部楼层 |阅读模式
新唐 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 晶振。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

54

主题

502

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部
0