AVR单片机TCB定时器详解:输入捕获、单脉冲与PWM模式实战指南

AVR单片机TCB定时器详解:输入捕获、单脉冲与PWM模式实战指南
1. 项目概述为什么你需要深入了解AVR的TCB定时器如果你正在用AVR单片机做项目无论是控制一个电机、测量一个脉冲宽度还是实现一个精准的延时你大概率绕不开定时器。而当你翻开ATmega4809、ATtiny1617这些新系列AVR单片机的数据手册会发现除了我们熟悉的TCATimer/Counter Type A还多了一个叫TCBTimer/Counter Type B的家伙。很多朋友第一次接触TCB时会有点懵它和TCA有什么区别什么时候该用它数据手册里那些“输入捕获”、“单脉冲输出”、“PWM模式”又该怎么玩我最初用TCB是为了给一个传感器做高精度的脉冲宽度测量传统用TCA加外部中断的方式代码繁琐且容易受中断延迟影响。折腾了一番TCB的输入捕获模式后发现它简直就是为这类任务量身定做的硬件外设配置好后几乎不占用CPU。后来在需要生成精确单脉冲驱动步进电机以及输出简单但需同步的PWM信号时TCB也屡建奇功。它不像TCA那样功能庞杂但它在几个特定任务上做得极其专注和高效。简单来说TCB是一个16位的定时器/计数器它的核心设计理念是“单一任务硬件完成”。它不像TCA那样可以多路PWM输出但它在输入捕获的精度、单脉冲生成的灵活性以及8位PWM的简易性上表现突出。对于资源受限又想实现精准定时功能的项目TCB是一个被严重低估的利器。本文将结合具体寄存器操作和代码片段带你彻底搞懂TCB的这三种核心工作模式让你在下次项目选型时能自信地判断“嗯这个功能用TCB来做更合适。”2. TCB与TCA的核心差异定位决定用法在深入TCB的具体模式之前我们必须先理清它和家族中另一位明星TCA的根本区别。这决定了你项目的架构选择。你可以把TCA想象成一个“瑞士军刀”功能全面而TCB则更像一把“专用手术刀”在特定场景下极其锋利。TCA (Timer/Counter Type A) 的特点多通道输出这是TCA最强大的特性。一个TCA模块通常支持3到6路独立的PWM输出通道例如ATmega4809的TCA0有6路每路都可以独立设置占空比。这对于驱动多个舵机、RGB LED调光、三相电机驱动等需要多路同步PWM的场景是必不可少的。波形生成能力强支持单斜率、双斜率中心对齐PWM模式频率和占空比调节非常灵活。通常用作主PWM发生器在大多数应用中如果需要生成多路PWMTCA是首选。TCB (Timer/Counter Type B) 的特点单一通道任务专注一个TCB模块通常只专注于一件事。它有三种主模式输入捕获、单脉冲输出、8位PWM输出。在同一时刻它只能工作在一种模式下。输入捕获是王牌TCB的输入捕获功能是其设计亮点。它拥有一个专用的输入捕获引脚和寄存器捕获事件可以触发中断或直接写入捕获寄存器精度高达一个系统时钟周期非常适合测量频率、脉冲宽度如超声波测距、编码器读数。单脉冲模式可以硬件生成一个精确宽度和延迟的脉冲响应外部事件事件输入或软件命令。这在需要精确触发一个动作如相机快门、激光发射时非常有用CPU只需发起命令无需忙等待。8位PWM模式这是一个“轻量级”PWM模式。它只能生成固定频率由计数器TOP值决定、占空比可调的PWM波。虽然功能不如TCA强大但它配置简单且可以与TCA的PWM输出同步通过使用相同的时钟源或事件系统适合作为补充输出。如何选择一个简单的决策流需求是多路独立PWM- 毫不犹豫选TCA。需求是高精度测量脉冲宽度或频率- 优先考虑TCB的输入捕获模式。需求是响应某个事件如按键按下、传感器触发后经过一段精确延时再输出一个固定宽度的脉冲- TCB的单脉冲模式是不二之选。只需要一路简单的PWM且希望配置尽可能简单- TCB的8位PWM模式可以胜任。理解了定位我们接下来就拆解TCB的三种模式。我会以Microchip ATmega4809为例因其外设丰富文档易得但原理通用於所有具备TCB的新一代AVR单片机。3. 模式一输入捕获模式——高精度测量的利器输入捕获模式是TCB的“杀手锏”。它的原理很简单当指定的输入引脚通常是芯片引脚上的TCBn功能发生预设的边沿事件上升沿、下降沿或两者时硬件会自动将当前TCB计数器TCBn.CNT的值锁存到捕获寄存器TCBn.CCMP中并可以产生中断。通过记录连续两次捕获的计数器值我们就能计算出脉冲的宽度或周期。3.1 核心寄存器配置与工作流程要让TCB工作在输入捕获模式你需要配置以下几个关键寄存器TCBn.CTRLB (控制寄存器B)将TCBn.CTRLB寄存器中的CNTMODE位域设置为0x1这代表“周期性中断”模式。是的输入捕获模式在寄存器配置上叫“周期性中断”模式这是历史命名原因我们关注的是它具备捕获功能。TCBn.EVCTRL (事件控制寄存器)这是配置的关键你需要使能输入捕获事件。CAPTEI(Capture Event Input Enable)置1使能事件输入作为捕获触发源。EDGE选择捕获边沿。0为下降沿1为上升沿。你也可以通过软件在中断中切换这个位来实现双边沿捕获。TCBn.INTCTRL (中断控制寄存器)使能捕获中断CAPT。这样每次捕获发生时都会进入中断服务程序ISR。TCBn.CTRLA (控制寄存器A)选择时钟源CLKSEL例如系统时钟/2然后使能定时器ENABLE位。一个典型的工作流程如下初始化TCB为输入捕获模式使能上升沿捕获和中断。第一个上升沿到来当前计数器值CNT被锁存到CCMPINTFLAGS.CAPT标志置位进入中断。在中断服务程序中读取CCMP的值存入变量timestamp_prev并清除CAPT标志位。第二个上升沿到来再次触发中断读取新的CCMP值到timestamp_now。脉冲周期 (timestamp_now - timestamp_prev) * 时钟周期。如果时钟是4MHz计数器差值1000则周期为250微秒频率为4kHz。3.2 实战代码测量PWM信号占空比假设我们需要测量从PA3引脚输入的PWM信号的频率和占空比。我们使用TCB0并利用双边沿捕获来实现。#include avr/io.h #include avr/interrupt.h volatile uint16_t rising_edge_time 0; volatile uint16_t falling_edge_time 0; volatile uint16_t period 0; volatile uint16_t pulse_width 0; volatile uint8_t measurement_ready 0; void TCB0_init_input_capture(void) { // 1. 配置引脚PA3为输入启用上拉可选 PORTA.PIN3CTRL PORT_PULLUPEN_bm; // 将PA3复用为TCB0的输入捕获引脚WO0默认但输入捕获是另一个复用功能具体见数据手册 // 对于ATmega4809TCB0的输入捕获在PF4这里仅为示例流程。实际需查表。 // 2. 配置TCB0为输入捕获模式 TCB0.CTRLB TCB_CNTMODE_INT_gc; // 周期性中断/输入捕获模式 TCB0.EVCTRL TCB_CAPTEI_bm // 使能事件输入捕获 | TCB_EDGE_bm; // 初始设置为上升沿捕获 TCB0.INTCTRL TCB_CAPT_bm; // 使能捕获中断 // 3. 配置时钟和启动定时器 TCB0.CTRLA TCB_CLKSEL_CLKDIV2_gc // 使用系统时钟/2 | TCB_ENABLE_bm; // 使能定时器 // 4. 全局中断使能 sei(); } // TCB0捕获中断服务程序 ISR(TCB0_INT_vect) { uint16_t capture_value TCB0.CCMP; // 读取捕获到的时刻 static uint8_t edge_state 0; // 0:等待上升沿1:已捕获上升沿 if (edge_state 0) { // 捕获到的是上升沿 rising_edge_time capture_value; // 切换为下降沿捕获 TCB0.EVCTRL ~TCB_EDGE_bm; edge_state 1; } else { // 捕获到的是下降沿 falling_edge_time capture_value; // 计算脉冲宽度下降沿时间 - 上升沿时间 // 注意处理计数器溢出这里假设两次捕获间隔远小于65535个时钟。 pulse_width falling_edge_time - rising_edge_time; // 切换回上升沿捕获为下一个周期做准备 TCB0.EVCTRL | TCB_EDGE_bm; edge_state 0; // 此时我们可以计算周期需要记录上一个上升沿时间 static uint16_t last_rising_edge 0; period capture_value - last_rising_edge; // 当前上升沿即capture_value与上一次的差值 last_rising_edge capture_value; measurement_ready 1; // 设置标志主循环可以读取计算结果 } TCB0.INTFLAGS TCB_CAPT_bm; // 必须清除中断标志 } int main(void) { TCB0_init_input_capture(); while (1) { if (measurement_ready) { measurement_ready 0; // 假设系统时钟为4MHzTCB时钟为2MHzCLKDIV2每个计数0.5us // uint32_t period_us (uint32_t)period * 2; // 乘以2因为每个计数是0.5us // uint32_t pulse_width_us (uint32_t)pulse_width * 2; // 计算占空比 (pulse_width_us * 100) / period_us; // ... 进行你的处理 ... } // 主循环其他任务 } }注意上述代码中关于引脚复用的部分需要根据具体单片机型号的数据手册进行修改。ATmega4809的TCB0输入捕获可能在PF4引脚你需要配置PORTF.PIN4CTRL并将复用功能切换到TCB0。3.3 避坑指南与高级技巧计数器溢出处理上面的示例代码忽略了计数器溢出。如果被测脉冲周期很长计数器可能从65535翻转到0。正确的处理方法是使用一个溢出中断TCBn.INTCTRL中的OVF中断或一个更高位的软件计数器。在捕获中断中结合溢出次数来计算绝对时间。噪声与毛刺输入信号可能有毛刺导致误触发。可以在硬件上添加RC低通滤波或者在软件上采用“多次采样取稳定值”的算法。使用事件系统Event System新一代AVR的强大功能。你可以将TCB的捕获事件通过事件系统路由给其他外设如另一个TCB来生成同步脉冲完全无需CPU干预实现极低功耗的联动操作。输入频率范围TCB的计数器时钟频率决定了可测量的最大频率理论上不超过时钟频率的1/2。同时过低的频率可能导致计数器溢出。需要根据应用场景合理选择时钟分频。4. 模式二单脉冲输出模式——精准的硬件“一击”单脉冲模式允许TCB在收到一个触发信号软件命令或外部事件后在经过一段可编程的“延迟”后输出一个宽度可编程的“脉冲”。整个过程由硬件完成CPU只需发起一次触发之后就可以去处理其他任务非常适合需要精确定时控制的场景。4.1 工作原理与寄存器配置单脉冲模式的核心是CCMP寄存器被拆分为两个比较值CCMPL低字节和CCMPH高字节。在单脉冲模式下CCMPH用于设置脉冲的宽度Pulse Width。CCMPL用于设置脉冲开始的延迟Delay。工作流程定时器被使能但计数器CNT保持为0等待触发。触发到来软件写CTRLB的CMD位或外部事件输入。计数器开始从0向上计数。当CNT CCMPL时输出引脚电平翻转例如从低变高脉冲开始。当CNT CCMPH时输出引脚电平再次翻转例如从高变低脉冲结束。计数器停止等待下一次触发。关键寄存器配置TCBn.CTRLB将CNTMODE设置为0x3单脉冲模式。ASYNC位通常保持为0使用系统时钟。TCBn.CCMPCCMPH定义脉冲宽度CCMPL定义延迟。例如CCMP 0x00FF0030表示延迟为0x0030个时钟周期脉冲宽度为(0x00FF - 0x0030)个时钟周期。TCBn.EVCTRL如果你希望用外部事件如另一个定时器的溢出、引脚变化来触发单脉冲需要使能事件输入EVACT位域设置为相应模式如0x1代表事件触发。TCBn.CTRLA选择时钟源并ENABLE定时器。引脚配置将对应的单片机引脚如WO输出引脚配置为输出模式并复用为TCB波形输出功能。4.2 实战代码响应按键生成精确脉冲驱动蜂鸣器假设我们想实现一个功能按下按键PA2下降沿后延迟50ms然后让蜂鸣器PB2响100ms。我们用TCB1的单脉冲模式来实现。#include avr/io.h #include avr/interrupt.h #define F_CPU 4000000UL // 假设系统时钟4MHz #define TCB_CLK_DIV 2 // TCB时钟预分频 #define TCB_CLK (F_CPU / TCB_CLK_DIV) // TCB实际时钟2MHz void TCB1_init_single_shot(void) { // 1. 配置蜂鸣器引脚PB2为输出并复用为TCB1的WO输出 PORTB.DIRSET PIN2_bm; // 根据数据手册将PB2的复用功能设置为TCB WO。对于ATmega4809可能是PORTMUX.TCBROUTEA | PORTMUX_TCB1_bm;及引脚控制。 // 此处简化实际需查表配置复用。 // 2. 配置TCB1为单脉冲模式 TCB1.CTRLB TCB_CNTMODE_SINGLE_gc; // 单脉冲模式 // 默认输出极性为高电平有效即脉冲期间输出高。可通过CCMPCTRL寄存器调整。 // 3. 计算并设置延迟和脉冲宽度 // 延迟 50ms 0.05s // 脉冲宽度 100ms 0.1s // TCB计数周期 1 / TCB_CLK 0.5us uint32_t delay_ticks (uint32_t)(0.05 * TCB_CLK); // 0.05s * 2,000,000 Hz 100,000 ticks uint32_t pulse_end_ticks delay_ticks (uint32_t)(0.1 * TCB_CLK); // 100,000 200,000 300,000 ticks // 注意TCB是16位定时器最大计数65535。300,000远超此值 // 因此我们必须降低时钟频率或使用更短的延时。这里我们调整设计使用预分频更大的时钟。 // 重新配置使用CLKDIV8 (500kHz), 延迟50ms需要25,000 ticks脉冲结束需要75,000 ticks仍然超出。 // 使用CLKDIV64 (62.5kHz)延迟50ms需要3,125 ticks脉冲结束需要9,375 ticks。这个可行。 TCB1.CTRLA TCB_CLKSEL_CLKDIV64_gc; // 62.5kHz时钟 uint32_t tcb_freq F_CPU / 64; // 62.5kHz delay_ticks (uint32_t)(0.05 * tcb_freq); // 3125 pulse_end_ticks delay_ticks (uint32_t)(0.1 * tcb_freq); // 3125 6250 9375 // 设置CCMP寄存器高字节为脉冲结束点低字节为延迟开始点 TCB1.CCMP (pulse_end_ticks 16) | (delay_ticks 0xFFFF); // 4. 配置事件系统用外部中断按键触发此处简化实际使用事件系统需配置EVSYS // 更简单的方式在按键中断中软件触发。 // 先使能TCB1 TCB1.CTRLA | TCB_ENABLE_bm; } // 假设PA2按键已配置为下降沿外部中断 ISR(PORTA_PORT_vect) { if (PORTA.INTFLAGS PIN2_bm) { // 判断是否是PA2的中断 PORTA.INTFLAGS PIN2_bm; // 清除中断标志 // 软件触发TCB1开始单脉冲序列 TCB1.CTRLB | TCB_CMD_RESTART_gc; // 写入任意值到CMD位域即可触发 } } int main(void) { // 初始化按键中断略 TCB1_init_single_shot(); sei(); while(1) { // 主循环空闲等待中断 sleep_mode(); // 进入休眠以省电 } }提示单脉冲模式对时钟精度要求高。如果对脉冲时间精度要求极高应使用未分频的系统时钟或外部晶振。同时注意16位计数器的溢出限制合理选择时钟分频和脉冲时间参数。4.3 避坑指南与高级技巧16位计数器限制这是最大的限制。延迟脉冲宽度的总时间对应的计数值不能超过65535。对于长延时必须使用大的时钟分频但这会降低时间分辨率。折衷方案是结合软件计数器或使用TCA等具有更长计数范围的定时器。软件触发与事件触发CTRLB.CMD位是软件触发。写入任何值都会启动一次单脉冲序列。如果配置了事件触发EVCTRL.EVACT则相应的事件如另一个定时器溢出、引脚变化会自动触发无需软件干预响应更及时且节能。输出极性通过CTRLC或CCMPCTRL寄存器型号不同可以配置输出极性决定脉冲是高电平有效还是低电平有效。与输入捕获模式联动一个非常强大的应用是用TCB0做输入捕获测量到一个脉冲宽度然后通过事件系统触发TCB1生成一个与测量值成比例的单脉冲。整个过程无需CPU参与实现了纯硬件的信号处理链。5. 模式三8位PWM模式——简单够用的补充输出当你的项目只需要一路PWM且对频率和分辨率要求不是特别高时TCB的8位PWM模式提供了一个极其简洁的解决方案。它配置简单占用代码空间小。5.1 工作原理与寄存器配置在此模式下TCB作为一个8位PWM发生器工作。CCMP寄存器的CCMPH字节被用作PWM的周期TOP值而CCMPL字节被用作比较值决定占空比。计数器CNT从0向上计数到CCMPH然后清零重启。当0 CNT CCMPL时输出为有效电平通常为高。当CCMPL CNT CCMPH时输出为无效电平通常为低。因此占空比 CCMPL / (CCMPH 1)。关键寄存器配置TCBn.CTRLB将CNTMODE设置为0x28位PWM模式。TCBn.CCMPCCMPH设置PWM的周期值TOP。PWM频率 TCB_CLK / (CCMPH 1)。CCMPL设置PWM的占空比比较值。占空比 (CCMPL 1) / (CCMPH 1)这里有个细节根据数据手册在8位PWM模式下输出在CNT CCMPL时为高CNT CCMPL时为低。所以当CCMPL0时输出始终为低占空比0%当CCMPL CCMPH时输出始终为高占空比100%。通常我们设置CCMPL在0到CCMPH之间来调节占空比。TCBn.CTRLA选择时钟源并ENABLE定时器。引脚配置同样需要将对应引脚配置为输出并复用为TCB的WO功能。5.2 实战代码生成一个1kHz50%占空比的PWM假设系统时钟4MHz我们希望用TCB2生成一个1kHz的PWM波初始占空比50%。#include avr/io.h void TCB2_init_pwm(void) { // 1. 配置PWM输出引脚例如PC0复用为TCB2 WO PORTC.DIRSET PIN0_bm; // 根据数据手册配置引脚复用例如PORTMUX.TCBROUTEA // 2. 配置TCB2为8位PWM模式 TCB2.CTRLB TCB_CNTMODE_PWM8_gc; // 3. 计算并设置周期(CCMPH)和占空比(CCMPL) // 期望频率 1kHz 1000 Hz // TCB时钟我们选择系统时钟/4 1MHz TCB2.CTRLA TCB_CLKSEL_CLKDIV4_gc; // 1MHz时钟 uint32_t tcb_clk 1000000UL; // 1MHz // 周期值 TOP (tcb_clk / desired_freq) - 1 uint16_t top_value (tcb_clk / 1000) - 1; // 1000 - 1 999 // 但CCMPH是8位寄存器高字节最大值2551MHz时钟下1kHz频率要求TOP999远超255。 // 因此我们必须降低TCB时钟频率或接受更低的PWM频率。 // 方案使用更低的时钟分频得到更低的PWM频率。 // 重新计算使用CLKDIV64 (62.5kHz) TCB2.CTRLA TCB_CLKSEL_CLKDIV64_gc; // 62.5kHz时钟 tcb_clk F_CPU / 64; // 62.5kHz top_value (tcb_clk / 1000) - 1; // 62.5 - 1 ≈ 61.5取整61 // 此时实际频率 62.5kHz / (611) ≈ 1008Hz接近1kHz。 uint8_t duty_cycle_50 top_value / 2; // 占空比50%比较值设为周期值的一半 // 设置CCMP寄存器高字节为TOP低字节为比较值 TCB2.CCMP (top_value 8) | duty_cycle_50; // 4. 使能定时器 TCB2.CTRLA | TCB_ENABLE_bm; } int main(void) { TCB2_init_pwm(); while(1) { // 主循环中我们可以动态修改占空比 // 例如通过ADC读取电位器值映射到0-top_value然后更新CCMPL // uint8_t adc_value read_adc(); // uint8_t new_duty (adc_value * top_value) / 255; // TCB2.CCMP (TCB2.CCMP 0xFF00) | new_duty; // 只更新低字节 } }5.3 避坑指南与高级技巧频率与分辨率限制这是8位PWM模式的主要局限。由于CCMPH是8位最大255因此PWM频率受到时钟和TOP值的双重限制。PWM频率 TCB_CLK / (TOP 1)。在给定系统时钟下更高的频率意味着更小的TOP值从而导致分辨率降低可调节的占空比等级变少。你需要根据应用在频率和分辨率之间权衡。动态更新占空比如示例代码所示可以通过只更新CCMP寄存器的低字节CCMPL来动态改变占空比。为了避免在PWM周期中间更新产生毛刺最好在计数器为0时即周期开始时更新。可以启用溢出中断OVF在中断中更新CCMPL。与TCA同步你可以将TCB的时钟源设置为与TCA相同例如都使用CLK_PER并将TCB配置为在TCA的某个事件如溢出时复位或启动从而实现多路PWM的严格同步。这对于需要多路协调控制的应用如RGB调色很有用。输出极性同样可以配置以适应不同驱动电路的需求如共阳极 vs 共阴极LED。6. 模式进阶与综合应用事件系统联动的威力单独使用TCB的三种模式已经很强大了但新一代AVR如megaAVR 0-series tinyAVR 0/1/2-series的事件系统Event System能将TCB的能力提升到一个新高度。事件系统允许外设之间直接通信无需CPU介入。一个综合案例超声波测距与自动响应假设我们用TCB0的输入捕获模式测量超声波模块回波的脉冲宽度即距离。我们希望当测量距离小于某个阈值时自动触发TCB1的单脉冲模式驱动一个蜂鸣器发出短促警报。传统CPU干预方式TCB0捕获完成产生中断。CPU进入中断读取捕获值计算距离。CPU判断距离是否小于阈值。如果小于CPU软件触发TCB1。 这个过程有中断延迟和软件处理时间。使用事件系统的纯硬件方式配置TCB0输入捕获使其捕获事件CAPT作为一个事件生成器Event Generator。配置事件系统通道将TCB0的捕获事件路由到某个事件通道EVENTn。配置TCB1单脉冲将其触发源EVCTRL.EVACT设置为该事件通道。同时将TCB1的计数初始值或比较值设置为与TCB0的捕获值即距离相关联。这可能需要借助其他外设如CCL可配置定制逻辑或DMA但思路是硬件直接联动。结果当超声波回波被捕获时硬件瞬间触发蜂鸣器脉冲延迟极短且CPU可以全程休眠极大节省功耗。虽然完整实现此案例需要深入配置事件系统EVSYS和可能的CCL但它展示了TCB在低功耗、高实时性系统中的潜力。在实际项目中即使只使用部分联动也能显著简化软件逻辑提高系统可靠性。7. 调试心得与常见问题排查在实际使用TCB时我踩过不少坑这里分享几个最常见的模式不生效计数器不计数检查CTRLA.ENABLE位这是最容易被忽略的即使配置了模式也必须使能定时器ENABLE1它才会开始计数。检查时钟源CLKSEL如果选择了外部时钟或事件计数模式但没有外部信号计数器自然不动。调试时先从内部系统时钟开始。检查单脉冲模式的触发在单脉冲模式下计数器需要触发软件CMD或外部事件才会开始。你是不是忘了触发它输入捕获无反应确认引脚复用这是最大的坑单片机引脚可能有多个复用功能。你必须正确配置PORTx.PINnCTRL寄存器中的ISC输入感应设置并且通过PORTMUX或EVSYS等寄存器将引脚路由到TCB的输入捕获功能。务必仔细查阅数据手册的“I/O Multiplexing”章节。检查EVCTRL.CAPTEI输入捕获事件使能位必须置1。检查边沿选择EVCTRL.EDGE确保设置的边沿与你输入的信号变化一致。使用逻辑分析仪或示波器直接观察输入引脚是否有信号以及信号边沿是否干净。PWM无输出或频率不对引脚方向和复用再次强调必须将引脚设置为输出DIRSET并且复用为TCB的波形输出WO功能。计算TOP值CCMPHPWM频率不对八成是CCMPH算错了。记住公式频率 TCB_CLK / (CCMPH 1)。TCB_CLK是你的时钟源经过预分频后的实际频率。占空比反了检查输出极性配置。如果你以为设置CCMPL0是满占空比结果输出一直是低那可能就是极性反了。中断进不去全局中断使能sei()忘了开总中断开关。中断向量名写错不同编译器、不同型号单片机的中断向量名可能不同。查看编译器提供的头文件如iotn4809.h或查看数据手册的“Interrupt Vector”表格。中断标志未清除在中断服务程序ISR中必须清除对应的中断标志如TCB0.INTFLAGS TCB_CAPT_bm;否则退出后会立即再次进入中断。功耗过高如果不需要TCB工作一定要将其禁用CTRLA.ENABLE0。即使计数器暂停外设模块本身可能仍在耗电。在睡眠模式下如果希望TCB继续工作以唤醒MCU需要根据数据手册选择在相应睡眠模式下仍能运行的时钟源如外部32.768kHz晶振。TCB定时器是一个设计精巧的工具它用有限的资源在特定任务上做到了极致。理解它的三种模式及其最佳应用场景能让你在AVR单片机项目设计中多一份从容和选择。下次当你需要测量时间、生成精准脉冲或添加一路简单的PWM时不妨先问问自己“用TCB是不是更优雅”