#include "timer.h" #include "../App/clock.h" // 外部引用的全局滴答/标志变量 (在 main.c 中定义) extern volatile u16 ms_tick; extern volatile bit alarm_flash_flag; extern volatile u16 key_scan_timer; /* ========================================================================= * Timer0:自由运行硬件时间戳基准 * ========================================================================= */ // Timer0 溢出次数,扩展 16 位硬件计数为 32 位软件时间戳的高位部分 static volatile u16 timer0_ovf_count = 0; void Timer0_Init(void) { TMOD &= 0xF0; // Timer0 模式位清零 -> Mode 0 (STC 上为 16 位不停表计数) TL0 = 0; TH0 = 0; ET0 = 1; // 开启 Timer0 溢出中断允许 TR0 = 1; // 启动 Timer0 计数,此后永不停止 (全局 EA 由 Timer1_Init() 统一开启) } /** * @brief Timer0 溢出中断服务程序 (每约 32.768ms 触发一次) * @details 只做计数扩展,不做任何耗时操作,保持中断尽量短。 */ void Timer0_Isr(void) interrupt 1 { timer0_ovf_count++; } u32 Timer0_GetTimestamp(void) { u16 ovf1, ovf2; u8 h1, h2, l; do { ovf1 = timer0_ovf_count; h1 = TH0; l = TL0; h2 = TH0; ovf2 = timer0_ovf_count; } while (h1 != h2 || ovf1 != ovf2); return ((u32)ovf1 << 16) | ((u16)h1 << 8) | l; } /* ========================================================================= * Timer1:系统 1ms 基准滴答 * ========================================================================= */ // 主循环按键扫描定时标志 (由 1ms 中断置 1,主循环响应清除),定义详见 event.h 的 extern 声明 volatile bit key_scan_flag = 0; void Timer1_Init(void) { AUXR |= 0x40; // 设定定时器 1 为 1T 模式 (无分频,主频直接输入) TMOD &= 0x0F; // 设置定时器 1 模式寄存器,保留低四位 (定时器0配置) { // 按照系统主频 (MAIN_Fosc) 计算 1ms 对应的重装载值 u16 reload = (u16)(65536UL - (MAIN_Fosc / 1000UL)); TL1 = (u8)reload; // 载入低 8 位 TH1 = (u8)(reload >> 8);// 载入高 8 位 } ET1 = 1; // 开启定时器 1 中断允许 TR1 = 1; // 启动定时器 1 计数 EA = 1; // 开启全局中断允许 } /** * @brief 定时器 1 中断服务程序 (每 1ms 触发一次) * @details 承担系统软时钟计算,并每 10ms 置位主循环按键扫描标志,不直接在中断中进行 ADC 多次采样。 */ void Timer1_Isr(void) interrupt 3 { // 1ms 递增全局滴答计数器 (0~999 循环),供各 App 的呼吸灯/闪烁/超时等周期性效果使用 ms_tick++; if (ms_tick >= 1000) { ms_tick = 0; } // 1ms 定时更新软时钟 Clock_IncMS(); // 报警屏幕红边框以 100ms 周期亮灭,进行颜色爆闪指示 alarm_flash_flag = (ms_tick / 100) % 2; /* 物理按键定时计数 (每 10ms 置位一次标志位) */ key_scan_timer++; if (key_scan_timer >= 10) { key_scan_timer = 0; // 重置扫描分频计数器 key_scan_flag = 1; // 仅在中断里置起标志位,留待主循环中执行实际读取与消抖 } }