MC68HC908AT32键盘中断与定时器模块实战:从原理到避坑指南 1. 项目概述与核心价值在嵌入式开发的江湖里MC68HC908AT32这款8位微控制器算得上是“老将”了尤其在汽车电子和一些工业控制领域至今仍有不少存量项目。对于刚接触它的朋友来说其外设模块的配置尤其是键盘中断模块KBD和定时器接口模块TIMA常常是绕不开的“硬骨头”。数据手册虽然详尽但往往过于碎片化缺乏一个从“为什么这么设计”到“怎么用才不踩坑”的连贯视角。今天我就结合自己十多年在8位机上的摸爬滚打把这两个模块掰开揉碎了讲清楚。键盘中断模块本质上是一个高效、低功耗的按键扫描解决方案它能让你用最少的CPU开销实现可靠的按键检测。而定时器接口模块TIMA-6则是一个功能强大的6通道定时器集输入捕获、输出比较和PWM生成于一身是控制时序、测量信号、驱动电机等任务的核心。理解它们不仅是学会配置几个寄存器更是掌握一种“与硬件对话”的思维方式。无论你是正在维护老项目还是想深入理解经典8位MCU的架构设计这篇文章都将提供从原理到实操、从配置到避坑的完整指南。2. 键盘中断模块KBD深度解析与实战键盘中断模块的设计初衷是为了让MCU能够以极低的功耗和CPU占用率响应来自外部引脚通常是连接了矩阵键盘或独立按键的电平变化。它不像软件轮询那样需要CPU不断去“看”引脚状态而是由硬件自动监测一旦有符合条件的边沿或电平出现就主动“打断”CPU让其去处理按键事件。这种事件驱动的模型是嵌入式系统实现实时响应的基石。2.1 核心寄存器与工作机制KBD模块的配置主要围绕两个寄存器展开键盘状态与控制寄存器KBSCR地址$001B和键盘中断使能寄存器KBIER地址$0021。数据手册的图表很清晰但我想用更直白的话来解释每个位的实际作用。KBSCR寄存器是大脑负责决策和状态汇报KEYF位3这是键盘中断标志位。当任何一个被使能的KBI引脚上发生了有效的中断触发事件比如下降沿硬件会自动将此位置1。你可以把它想象成一个“门铃响了”的指示灯。这个位是只读的软件无法直接写1。清除它的唯一方法是向ACKK位位4写入1。这里有个关键细节ACKK位是只写位你读它永远返回0。这个设计防止了误操作也要求我们在编程时必须用“写1清标志”的思维。IMASKK位1键盘中断屏蔽位。这是全局中断开关。当IMASKK1时即使KEYF被置位也不会向CPU核心申请中断。它只影响中断请求的发出不影响KEYF标志位的置位逻辑。在初始化或关键代码段设置此位可以临时屏蔽所有键盘中断。MODEK位0键盘触发灵敏度控制位。这是理解KBD行为模式的关键。MODEK0仅边沿触发。只有当被使能的KBI引脚上检测到下降沿从高电平跳变到低电平时才会置位KEYF。这种模式适用于按键按下时产生明确下降沿的场景能有效避免因按键抖动或电平毛刺导致的多次误触发。MODEK1边沿与电平触发。在下降沿会置位KEYF并且只要该引脚保持低电平KEYF会持续被置位即使你清除了只要引脚还是低很快又会被置位。这个模式有什么用想象一个需要检测“长按”的场景。在边沿触发模式下你只能在按键按下瞬间知道一次。而在电平触发模式下只要按键按着不放中断标志就会反复被置起你可以利用这个特性在中断服务程序ISR中实现计时从而判断长按时间。KBIER寄存器是哨兵名单决定哪些引脚能“上岗”KBIE4-KBIE0位4-0分别对应特定的端口引脚具体对应关系需查芯片数据手册的引脚复用表通常是Port G和Port H的部分引脚。当KBIEx1时对应的引脚被配置为键盘中断输入引脚。这里有一个非常重要的硬件行为一旦某个KBIEx位被置1无论该引脚之前的数据方向寄存器DDR设置是什么它都会被强制设置为输入模式。这意味着如果你想在初始化后还能通过软件读取该引脚的电平例如在非中断模式下查询按键状态你必须确保对应的DDR位是0。如果DDR位是1输出模式即使KBIEx1强制了输入软件读取该端口数据寄存器也将得不到正确的引脚电平。2.2 键盘初始化流程与防误触“坑”手册里给出了两种初始化方法但没细说为什么以及怎么选。我结合实战经验来解读。方法一标准初始化流程推荐用于大多数情况这是最常用、最稳妥的方法核心思想是“先屏蔽后使能再清理”。屏蔽中断设置IMASKK1目的是在配置过程中即使有干扰信号导致KEYF置位也不会立刻触发中断让CPU跳转到可能还未准备好的ISR。使能目标引脚设置KBIEx1此时引脚被强制设为输入内部上拉电阻开始工作。关键点来了内部上拉电阻从无效到稳定建立高电平需要一定时间通常是几个微秒级。在这段“爬升时间”内引脚电平可能处于不确定状态如果恰好被硬件识别为低电平或下降沿就会立即置位KEYF产生一次“虚假中断”。清除虚假中断向ACKK位写1就是为了清除上一步可能产生的虚假标志位。这个操作必须在打开中断屏蔽之前进行。打开中断屏蔽清除IMASKK0至此初始化完成KBD模块进入正常工作状态可以响应真实的外部中断了。方法二通过GPIO输出初始化这个方法更“暴力”一些旨在从根本上避免上拉建立期间的毛刺。先将目标KBI引脚配置为输出模式DDRx1并输出高电平PTx1。这样引脚被MCU内部强行拉高状态绝对稳定。然后再使能键盘中断KBIEx1。由于引脚已经是稳定的高电平使能瞬间就不会产生下降沿或低电平误判。之后你需要记得将DDRx改回0使其恢复为输入模式以便检测外部按键拉低的动作。如何选择如果你的电路板布线良好电源稳定按键上拉可靠无论是内部上拉还是外部上拉方法一简单高效是首选。如果你的系统对噪声非常敏感或者是在极端低功耗模式下唤醒后初始化引脚电平可能浮动那么方法二虽然多几步操作但能提供最高的初始化可靠性。我曾在一些汽车电子唤醒场景中必须使用方法二才能确保第一次按键唤醒的确定性。2.3 低功耗模式下的行为与中断唤醒MC68HC908AT32的WAIT和STOP模式是省电利器而KBD模块在这两种模式下依然保持活动状态。这意味着你可以配置一个按键作为“唤醒源”。操作要点在进入WAIT或STOP模式之前必须确保IMASKK0中断未屏蔽。如果IMASKK1即使按键按下产生了中断事件也无法将MCU从低功耗模式中唤醒。中断服务程序ISR注意事项在KBD的ISR中标准动作是读取按键状态判断哪个引脚触发然后必须向ACKK位写1以清除KEYF标志。如果不清除退出ISR后KEYF依然为1会立刻再次触发中断导致CPU陷入中断死循环。对于电平触发模式MODEK1情况更特殊如果ISR执行完毕后按键仍然保持按下低电平KEYF会再次被置位。因此你的ISR设计必须能处理这种“中断重入”的情况通常采用“首次触发处理持续低电平忽略或做长按判断”的策略。2.4 Break中断下的特殊处理Break模块是HC08系列一个强大的调试功能。在Break中断状态下对寄存器的写操作默认是受保护的以防止调试时误修改关键状态。寄存器BFCR中的BCFE位这个位控制Break状态下标志位的清除使能。如果你想在调试过程中于Break状态下手动清除KEYF标志比如为了单步跟踪需要先将BCFE位设为1然后才能通过写ACKK来清除KEYF。在正常的应用程序运行期间BCFE位通常保持为0默认值这样可以保护KEYF标志不被意外清除增加系统状态的可靠性。3. 定时器接口模块TIMA-6架构与核心功能如果说KBD是灵敏的“哨兵”那么TIMA-6就是精准的“心脏起搏器”兼“秒表”。它是一个6通道、16位的定时器系统其复杂度和灵活性远超简单的延时循环。理解TIMA关键在于理解其双缓冲比较寄存器和丰富的触发模式这是它能高效、精准完成复杂定时任务的核心。3.1 整体架构与时钟源选择TIMA的核心是一个16位向上计数器它可以工作在两种模式下自由运行模式计数器从0x0000开始一直累加到0xFFFF然后翻转到0x0000继续周而复始。模值Modulo模式计数器从0x0000开始累加到TAMODH:TAMODL寄存器设定的模值后在下一个时钟复位到0x0000重新开始。这让你可以精确设定一个周期非常适合生成固定频率的PWM波。计数器的时钟源非常灵活由TIMA状态与控制寄存器TASC的PS[2:0]位选择可以选择7种由内部总线时钟分频而来的预分频时钟。也可以选择外部时钟引脚PTD6/TCLK输入最高频率4MHz。这为外部时钟同步或频率测量提供了可能。初始化第一步通常是停止计数器TSTOP1复位计数器TRST1配置好时钟源和模值最后再启动计数器TSTOP0。TRST位是“瞬时”操作写1后计数器立即清零该位硬件自动清零。3.2 输入捕获Input Capture功能精讲输入捕获功能简单说就是“抓拍”。当指定的引脚如PTE2/TACH0上发生预设的边沿事件上升沿、下降沿或任意沿时硬件会自动将此刻16位计数器TACNT的值“抓拍”下来存入对应的通道寄存器TACHxH:TACHxL并置位通道标志位CHxF可选地产生中断。核心应用与计算测量脉冲宽度假设要测量一个正脉冲的宽度。配置通道为上升沿捕获。脉冲上升沿到来时捕获值Capture1 TACNT。在中断服务程序中重新配置该通道为下降沿捕获或使用另一个通道捕获下降沿。脉冲下降沿到来时捕获值Capture2 TACNT。脉冲宽度(Capture2 - Capture1) * 计数器时钟周期。关键点需要考虑计数器溢出。如果Capture2 Capture1说明在两次捕获之间计数器发生了溢出。此时脉冲宽度(0x10000 Capture2 - Capture1) * 时钟周期。因此在输入捕获的中断服务程序中必须结合**定时器溢出标志TOF**来扩展计算范围到32位或更多。测量信号频率测量两个相邻上升沿或下降沿之间的时间即为信号周期其倒数就是频率。方法与测脉宽类似但捕获的是同一边沿。为外部事件打时间戳这在多事件同步或事件序列分析中非常有用。每个关键外部事件如传感器触发通过输入捕获记录一个时间点后续软件可以分析这些时间点的相对关系。重要提示数据手册提到捕获到的计数器值会比实际事件发生的计数器值大2。这是因为内部同步逻辑需要两个总线时钟的延迟。在进行高精度时间计算时必须减去这个偏移量。例如实际事件发生的计数 读取的捕获值 - 2。忽略这一点会在高时钟频率下引入可观的系统误差。3.3 输出比较Output Compare功能精讲输出比较是输入捕获的“逆过程”。你预先在通道寄存器TACHxH:TACHxL里设置一个目标值。硬件不断将计数器TACNT的值与这个目标值比较当两者相等时就根据配置在对应的引脚上执行一个动作置1、清0或翻转电平同时置位标志CHxF并可产生中断。核心应用生成精确的定时中断不连接外部引脚仅使用其比较匹配产生中断的功能可以替代软件定时器实现非常精准的周期性任务调度。产生单个脉冲或脉冲序列通过计算目标值可以在精确的时间点将引脚拉高或拉低从而生成宽度和间隔都精确可控的脉冲。驱动步进电机或舵机通过输出比较产生精确时序的脉冲是控制这类执行器的常用方法。3.4 脉宽调制PWM生成机制PWM是输出比较功能的一个高级应用模式。TIMA通过结合输出比较和溢出翻转Toggle on Overflow功能来生成PWM。工作原理周期由模值寄存器决定计数器工作在模值模式TAMODH:TAMODL的值决定了PWM的周期。计数器从0计数到模值然后归零此为一个PWM周期。占空比由通道寄存器决定配置通道为输出比较模式并设置TOVx1使能溢出翻转。这意味着当计数器溢出从模值回到0时引脚电平会自动翻转一次。输出比较动作决定脉宽你需要设置输出比较动作。假设我们希望PWM波形开始时为高电平。设置输出比较动作为“清0”Clear on compare。这样当计数器值等于通道寄存器设定值时引脚被拉低。结果就是计数器从0开始引脚为高计数到比较值时引脚被拉低计数到模值溢出时引脚翻转为高开始下一个周期。高电平时间脉宽 比较值 * 时钟周期。低电平时间 (模值 - 比较值) * 时钟周期。占空比 比较值 / (模值 1)。因为计数器从0到模值总计模值1个计数值。缓冲与非缓冲PWM的关键区别 这是TIMA设计的一个精华所在用于解决PWM更新时的“毛刺”问题。非缓冲Unbuffered模式直接向当前正在控制输出的通道寄存器写入新的比较值。如果写入时机不当比如在计数器值已经超过新值但还未超过旧值时写入可能导致当前周期输出异常甚至丢失一个完整的PWM脉冲。手册给出了安全的更新策略减小占空比写更小的值在输出比较中断中更新增大占空比写更大的值在定时器溢出中断中更新。缓冲Buffered模式这是TIMA的亮点功能。通过设置MS0B、MS2B或MS4B可以将通道0/1、2/3、4/5两两配对。例如通道0和1配对后输出仅在PTE2/TACH0引脚。通道0和1的寄存器形成了一个双缓冲器。当通道0寄存器控制当前输出时你可以安全地向通道1寄存器写入下一个周期的比较值。在下一个PWM周期开始时计数器溢出硬件会自动切换让通道1寄存器接管输出控制同时你可以去更新通道0寄存器以备下下个周期使用。如此交替实现了PWM占空比的无毛刺、平滑更新。这对于电机控制、音频合成等需要实时、连续调整PWM的应用至关重要。4. TIMA-6模块的详细配置与编程实践理解了原理我们进入实战环节。配置TIMA就像组装一台精密仪器每一步的顺序和参数都至关重要。4.1 寄存器地图详解与位域操作TIMA的寄存器较多但结构清晰。我们以通道0为例详解其核心控制寄存器TASC0地址$0026位名称功能描述编程要点7CH0F通道0标志位。输入捕获事件或输出比较匹配时由硬件置1。写1清除实际是向一个只写位写1来清除。必须在中断服务程序中清除否则会持续产生中断请求。6CH0IE通道0中断使能位。1允许通道0事件产生CPU中断。在全局中断开启前确保具体通道中断已按需配置。5MS0B模式选择B位。这是启用通道0/1缓冲模式的关键。1通道0与1链接用于缓冲输出比较/PWM。设置此位后通道1的控制寄存器TASC1失效其引脚PTE3/TACH1可作GPIO。4MS0A模式选择A位。与ELS0B、ELS0A共同决定通道模式。详见模式选择表。3ELS0B边沿/电平选择B位。与ELS0A配合选择输入捕获边沿或输出比较动作。2ELS0A边沿/电平选择A位。输入捕获00禁止01上升沿10下降沿11任意沿。输出比较00禁止01比较匹配时翻转10比较匹配时清011比较匹配时置1。1TOV0溢出翻转使能位。1当定时器计数器溢出达到模值时通道0引脚电平自动翻转。生成PWM时必须置1。0CH0MAX通道0最大占空比使能位。这是一个特殊功能。当TOV00且CH0MAX1时引脚强制输出高电平100%占空比。可用于PWM的使能/关闭控制或直接输出固定电平。模式选择MS0A和MS0B的真值表是灵魂MS0BMS0A通道0操作模式00输入捕获01输出比较非缓冲10输出比较/PWM缓冲模式与通道1链接11保留4.2 PWM信号生成完整代码示例C语言风格假设我们需要在PTE2/TACH0引脚上生成一个频率为1kHz占空比为30%的PWM信号使用内部总线时钟8MHz预分频选择/16。第一步计算参数定时器时钟 总线时钟 / 预分频 8MHz / 16 500kHz周期 2μs。PWM周期 1 / 1kHz 1000μs。一个PWM周期需要的计数器 ticks 1000μs / 2μs 500。计数器模值 ticks - 1 499 (因为从0开始计数)。所以TAMODH:TAMODL 0x01F3(499的十六进制)。高电平时间脉宽 1000μs * 30% 300μs。比较值 300μs / 2μs 150。所以TACH0H:TACH0L 0x0096(150的十六进制)。第二步配置代码非缓冲模式// 假设寄存器已通过宏定义映射到内存地址 #define TASC (*(volatile unsigned char*)0x0020) #define TAMODH (*(volatile unsigned char*)0x0024) #define TAMODL (*(volatile unsigned char*)0x0025) #define TASC0 (*(volatile unsigned char*)0x0026) #define TACH0H (*(volatile unsigned char*)0x0027) #define TACH0L (*(volatile unsigned char*)0x0028) void PWM_Init(void) { // 1. 停止并复位定时器 TASC | 0x20; // 设置 TSTOP1停止计数器 TASC | 0x40; // 设置 TRST1复位计数器该位自清零 // 2. 配置预分频和模值 TASC 0xF8; // 清零 PS[2:0] TASC | 0x04; // 设置 PS[2:0]100b即预分频/16 (根据手册具体值调整) TAMODH 0x01; // 写入模值高字节 0x01 TAMODL 0xF3; // 写入模值低字节 0xF3 // 3. 配置通道0比较值占空比 TACH0H 0x00; // 比较值高字节 TACH0L 0x96; // 比较值低字节 0x96 150 // 4. 配置通道0为输出比较使能溢出翻转设置比较匹配时清0输出 // TASC0: CH0F CH0IE MS0B MS0A ELS0B ELS0A TOV0 CH0MAX // 目标: 0 0 0 1 1 0 1 0 // 二进制: 0001 1010 0x1A TASC0 0x1A; // MS0A1 (输出比较), ELS0B:ELS0A10b (清0), TOV01 (溢出翻转) // 5. 启动定时器 TASC ~0x20; // 清除 TSTOP启动计数器 }这段代码运行后PTE2引脚就会输出稳定的1kHz、30%占空比的PWM波。如果需要动态调整占空比只需在安全的时间点如溢出中断中更新TACH0H:TACH0L即可。4.3 输入捕获测量脉冲宽度示例假设使用通道1PTE3/TACH1测量一个正脉冲的宽度。#define TASC1 (*(volatile unsigned char*)0x0029) #define TACH1H (*(volatile unsigned char*)0x002A) #define TACH1L (*(volatile unsigned char*)0x002B) volatile unsigned int capture_start 0, capture_width 0; volatile unsigned char overflow_count 0; // 定时器溢出中断服务程序需配置TASC中的TOIE1 void interrupt Timer_Overflow_ISR(void) { if(TASC 0x80) { // 检查TOF标志 overflow_count; TASC | 0x80; // 写1清除TOF标志ACK操作 } } // 通道1输入捕获中断服务程序 void interrupt TIMA_Ch1_ISR(void) { static unsigned char state 0; // 状态机0-等待上升沿1-等待下降沿 unsigned int capture_temp; if(TASC1 0x80) { // 检查CH1F标志 capture_temp ((unsigned int)TACH1H 8) | TACH1L; switch(state) { case 0: // 捕获到上升沿 capture_start capture_temp; overflow_count 0; // 重置溢出计数器 // 重新配置为下降沿捕获 TASC1 ~0x0C; // 清零ELS1B:ELS1A TASC1 | 0x08; // 设置为下降沿捕获 (10b) state 1; break; case 1: // 捕获到下降沿 // 计算脉宽考虑溢出 if(capture_temp capture_start) { capture_width capture_temp - capture_start (unsigned int)overflow_count * 65536UL; } else { // 发生了一次溢出 capture_width 0x10000UL - capture_start capture_temp (unsigned int)(overflow_count - 1) * 65536UL; } // 补偿内部同步延迟2个计数 if(capture_width 2) { capture_width - 2; } // 重新配置为上升沿捕获准备下一次测量 TASC1 ~0x0C; // 清零ELS1B:ELS1A TASC1 | 0x04; // 设置为上升沿捕获 (01b) state 0; // 此处可以处理capture_width例如转换为时间单位 break; } TASC1 | 0x80; // 写1清除CH1F标志 } } void InputCapture_Init(void) { // 停止定时器可选如果定时器已用于其他目的 // 配置通道1为上升沿输入捕获使能中断 // TASC1: CH1F CH1IE - MS1A ELS1B ELS1A TOV1 CH1MAX // 目标: 0 1 0 0 0 1 0 0 (假设MS1A位在bit4) // 二进制: 0100 0100 0x44 (需根据实际寄存器位域调整) TASC1 0x44; // 使能中断上升沿捕获 // 使能全局中断和定时器溢出中断如果需要 // 启动定时器... }这个示例展示了一个典型的状态机在输入捕获中的应用并妥善处理了计数器溢出和内部延迟补偿。5. 常见问题排查与实战经验分享即使理解了所有寄存器实际调试中还是会遇到各种“妖魔鬼怪”。下面是我总结的几个典型问题及排查思路。5.1 键盘中断无法触发或连续触发现象按键按下程序没反应。检查1电源与上拉首先用万用表或示波器确认按键按下时KBI引脚的电平是否确实能从高接近VDD被拉低到接近0V。如果内部上拉太弱或外部电路有问题可能无法产生干净的低电平。检查2初始化流程是否严格按照“屏蔽-使能-清标志-打开屏蔽”的流程初始化后是否清除了可能存在的虚假KEYF标志检查3中断使能与全局开关KBIEx位使能了吗IMASKK位是0吗CPU的全局中断允许位通常是I位打开了吗中断向量表配置正确吗检查4MODEK模式如果设置为电平触发MODEK1且按键一直按下中断会不断产生。你的ISR设计是否能处理这种情况是否需要在ISR中暂时屏蔽该引脚中断或改变触发模式现象只按一次键中断却触发了很多次。首要怀疑对象按键抖动。机械按键在闭合和断开瞬间会产生毫秒级的毛刺。KBD模块的响应速度是微秒级的会把这些毛刺都当成有效边沿。解决方案硬件消抖在按键两端并联一个0.1μF的电容成本低简单有效。软件消抖在KBD中断服务程序中不立即处理而是设置一个“按键事件”标志。主循环或一个定时器中断中以10-20ms的周期检查这个标志如果标志有效再读取端口状态确认确认后才执行按键处理逻辑。这是最可靠的方法。5.2 TIMA PWM输出异常无输出、占空比不对、毛刺现象引脚没有PWM波形输出。检查1引脚复用PTE2/TACH0这类引脚是复用的。你配置了TIMA功能但数据方向寄存器DDR配置了吗必须将对应引脚的DDR位设置为1输出信号才能输出到引脚上。这是新手最常踩的坑检查2模式配置TASC0寄存器配置对了吗MS0A或MS0B是否设置为输出比较模式ELS0B:ELS0A是否设置为“清0”或“置1”而不是“翻转”或“禁止”TOV0是否设置为1使能溢出翻转检查3定时器运行TSTOP位是0吗时钟源PS[2:0]选对了吗用示波器测一下定时器时钟引脚如果用了外部时钟或计算一下总线时钟和分频是否正确。现象PWM频率或占空比与计算值不符。检查计算重新核对时钟源频率、预分频值、模值、比较值的计算。特别注意计数器是从0计数到模值所以周期ticks 模值 1。检查写入顺序对于16位寄存器如TAMODH:TAMODL,TACH0H:TACH0L写入时先写高字节还是低字节对于HC08系列通常写入缓冲寄存器后需要等到一个特定的“缓冲器传输”时机如下一次溢出才生效。最安全的做法是先写高字节后写低字节。有些模块在写入低字节时会触发一次完整的16位传输。检查缓冲模式如果你使用的是缓冲PWM模式MS0B1你写入的是非活动的缓冲寄存器吗例如当前通道0寄存器控制输出你应该更新通道1寄存器。在下一个溢出后控制权才会切换。现象改变PWM占空比时输出有毛刺或跳动。问题根源在错误的时刻更新了正在使用的比较寄存器。对于非缓冲模式必须遵守手册的更新规则改小在输出比较中断中改大在溢出中断中。终极解决方案启用缓冲PWM模式。这是硬件提供的无毛刺更新机制务必在需要平滑调整PWM的应用中使用。5.3 输入捕获值不准或跳变现象捕获到的数值波动很大每次测量结果都不一样。检查信号质量用示波器观察被测量的信号。是否有过冲、振铃或毛刺这些都会导致边沿检测不准确。可能需要在输入端增加一个小电容滤波如22pF。检查边沿选择ELSxB:ELSxA配置是否正确是上升沿、下降沿还是任意沿补偿延迟你记得在最终计算时减去2个计数值了吗这个偏移是硬件同步引入的必须补偿。现象测量长脉冲时结果完全错误。几乎可以断定是溢出处理问题。你的输入捕获中断服务程序中是否关联了定时器溢出中断TOF是否用一个volatile的全局变量如overflow_count来记录溢出次数在计算脉冲宽度时是否正确地组合了overflow_count、capture_start和capture_end公式必须能处理capture_end capture_start即发生了一次溢出的情况。5.4 低功耗模式下的定时器行为WAIT模式TIMA模块在WAIT模式下默认是继续运行的除非你特意关闭它的时钟。这意味着基于TIMA的PWM输出、输入捕获、周期性中断在WAIT模式下依然工作。这既是优点也是缺点优点是可以用它作为唤醒源比如输出比较中断缺点是它本身会消耗比STOP模式更多的电流。STOP模式在STOP模式下所有时钟都停止了TIMA自然也停止了。因此任何依赖TIMA计时的功能在STOP模式下都会暂停。唤醒后TIMA计数器从停止时的值继续计数。如果你的应用依赖于精确的定时进入STOP模式前需要保存计数器状态唤醒后可能需要重新校准或初始化。调试这类问题逻辑分析仪和示波器是你的左膀右臂。一定要亲眼看到引脚上的波形、中断信号的产生时刻再结合寄存器的值才能快速定位是配置问题、时序问题还是信号完整性问题。对于MC68HC908AT32这种老芯片其设计理念非常经典吃透它对你理解现代MCU的定时器、PWM模块也大有裨益因为很多核心思想是一脉相承的。