"比较器输出PWM"这个标题乍一看有点反直觉。PWM不都是定时器或者专用PWM模块产生的吗?拿比较器去"输出PWM",算哪门子做法?我第一次在选型表上看到这个功能也没太当回事,直到真在项目里用上,才意识到这是一个把模拟检测和数字输出直接焊死在一起的能力,用好了能省掉不少麻烦,也让系统在关键场景下反应速度快上几个量级。
这里说的"比较器输出PWM",并不是让比较器去替代硬件PWM发生器,而是把模拟比较器的翻转结果作为PWM模块的控制信号、保护输入或者调制源。比如过流、过压、超温这类模拟量瞬间越过阈值,比较器在微秒级翻转,直接联动PWM输出强制动作,根本不用等CPU中断再去改寄存器。松瀚SN8F5703这颗8位MCU上,比较器、PWM这些外设都是片内集成的,做消费电子、小家电、电源控制和电机类应用很常见。把"比较器到PWM"这趟信号路径理解清楚,很多反馈和保护类的功能都能做得更干净。
这篇文章我从硬件架构、电路参数、寄存器配置和调试排障几个维度展开,适合正在用SN8F5703做项目的新手,也适合想了解低成本模拟保护方案怎么落到实际电路里的开发者。
1. 为什么会有"比较器输出PWM"这种玩法
1.1 先看懂比较器在MCU里的角色
MCU里集成的模拟比较器,功能就是比较两个输入端电压。正向输入电压大于反向输入端时,输出高电平;反之输出低电平。听起来简单,但它的价值在于纯硬件比较,不经过CPU、不跑指令、不排队等中断,翻转速度通常在纳秒到微秒级别。SN8F5703的比较器还可以选择输入来源,比如外部引脚和内部基准分压,输出端除了落到标志位和中断请求,还能往PWM模块送。
有意识地使用比较器而不是"ADC加软件判断",是因为有些场景CPU根本来不及。一颗主频几MHz到十几MHz的8位MCU,执行一轮ADC读取、比较、再输出的代码路径,轻轻松松超过几十微秒;而比较器本身从信号变化到输出翻转,可能只有几个微秒甚至更快。我见过不少项目把过流保护做在ADC中断里,结果MOS管都烧了中断还没排上队,这就是典型的保护路径选错工具。
1.2 三个典型玩法:保护、调制、联动
先说过流保护刹车。把采样电阻上的电压送到比较器正向输入,负向输入接基准阈值。电流一旦超过设定值,比较器翻转,输出直接控制PWM输出引脚关断或强制跳变,整个过程是纯硬件路径。MCU的主循环还在跑别的任务,这边保护已经完成了。这是"比较器输出PWM"最常出现的场景。
再说简易PWM调制器。让比较器正端输入一个控制电压,负端输入一个三角波或锯齿波,比较器输出自然就是占空比随控制电压变化的PWM方波。某些没有硬件PWM模块的型号,或者想用模拟反馈直接做闭环控制的场合,这种接法很实用。
第三种是阈值状态联动。比较器翻转信号作为PWM模块的工作使能或触发信号,温度超限才让PWM运行,没超限就保持关闭。比如温控风扇,温度没到阈值风扇不转,到了阈值直接给一个预设的PWM占空比,省掉CPU轮询。
1.3 硬件路径的价值:省中断、省功耗、响应快
软件处理存在判断窗口,如果采样时刻恰好错过毛刺或窄脉冲,可能漏报。比较器是持续的模拟比较,只要出现过阈值就会翻转并触发联动,不存在"采样间隔"这个概念。从鲁棒性角度看,这是硬件保护路径无法被替代的理由。
另外一个容易被忽略的好处是省功耗。MCU不需要频繁醒来读ADC、做比较、改PWM寄存器,比较器独立工作,CPU可以跑更低的主频或者进入睡眠模式,只有比较器翻转才唤醒。对于电池供电的设备,这个差异是实打实的续航优势。
2. SN8F5703里比较器和PWM是怎么配合的
2.1 片上的比较器和PWM外设
SN8F5703这类芯片通常包含一个或多个模拟比较器。输入侧可以选择外部引脚或者内部基准,有些比较器输入引脚和ADC通道、GPIO是复用关系,所以先看数据手册确认功能切换。芯片的PWM模块则有独立的周期寄存器、占空比寄存器和时钟分频,支持多路输出,有些还带互补输出和死区时间控制。
我在实际配置里习惯先把外设框图研究透。数据手册里一般会有一张"比较器与PWM互连框图",上面画着比较器输出到PWM模块的连线、可选的多路开关、极性控制位。这张图是整个功能的总钥匙,寄存器配置顺序和信号极性都从这张图来。
2.2 从比较器到PWM的三条互联路径
片上比较器的输出至少有三个去向:一个是寄存器标志位,软件查询翻转状态;一个是中断源,可配置上升沿或下降沿触发;还有一个是内部功能互连,送到PWM模块的特定控制逻辑。第三种正是本文的主题。
连接到PWM侧之后,按功能可以分成三类:
- 使能控制:比较器输出决定PWM是否运行。高电平运行、低电平关闭,或反过来由极性位决定。
- 刹车保护:比较器翻转后强制PWM输出到安全状态,比如全低电平或者高阻态。这是过流过压保护最常用的方式。
- 调制通路:把比较器输出直接接到PWM输出引脚的通路上,用比较器输出的方波作为最终PWM波形,典型场景就是配合外部三角波做模拟调制。
这三类连接方式对应完全不同的应用意图,配置寄存器的侧重点也不一样。保护场景关心安全状态和响应速度;调制场景关心比较器翻转频率和占空比线性度;使能场景关心的是比较器和PWM上电时序。
2.3 一个关键认知:比较器不是"生成"PWM,而是"控制"或"调制"PWM
这个概念要特别拎出来讲,因为太多人在这里绕弯子。硬件PWM模块负责产生固定频率、可调占空比的PWM,这叫"生成"。比较器做的是给PWM模块施加外部影响:保护模式下,比较器改变PWM的输出状态;调制模式下,比较器输出本身就构成了PWM波形。
SN8F5703的PWM模块有自己完整的波形产生能力,比较器只是在PWM的生死开关或者调制度上插了一手。如果脑子里没有这个区分,调试时会经常问出"为什么比较器配置对了但PWM波形不对"这种问题——大概率是PWM本身就没配置对。
3. 实战电路设计与参数计算
3.1 一个过流保护案例的完整搭法
假设需求很具体:直流电机驱动,正常工作电流200mA,设定保护电流500mA,电流超过保护值后立即关闭PWM输出,响应越快越好。
电路搭法如下。低侧采样电阻Rshunt = 0.1Ω串联在电机回路里,采样电压送入比较器正向输入,负向输入接基准分压设定翻转阈值,比较器输出通过内部互联控制PWM关断。
先算阈值电压。保护电流500mA流经0.1Ω采样电阻产生的压降:
Vth = Ith × Rshunt = 0.5A × 0.1Ω = 0.05V = 50mV
然后设计基准分压。如果直接用VDD分压,5V供电下想得到50mV,分压比是1:100。取上臂电阻R1=99kΩ、下臂电阻R2=1kΩ,那么:
Vref = VDD × R2 / (R1 + R2) = 5V × 1kΩ / (99kΩ + 1kΩ) = 50mV
电阻精度直接影响保护点精度。默认5%贴片电阻的误差算下来,最坏情况保护电流可能偏到450mA甚至更低,所以我建议这里直接用1%精度电阻,成本差异几分钱,保护点稳定很多。
3.2 滞回设计与正反馈计算
比较器没有滞回时,在阈值附近会抖动。电机电流纹波、采样电阻上的噪声都会造成比较器在阈值附近反复翻转,表现出来就是PWM一会儿关断一会儿恢复,严重时驱动端会发出滋滋的啸叫。
解决方式是加滞回。常见的做法是从比较器输出端接一个正反馈电阻Rfb到正向输入端。比较器翻转后,输出电平变化量通过Rfb反馈到正输入,把阈值往反方向推一点,形成一个"翻转后阈值偏移"的效果。
实际推导不复杂。假设输出高电平接近VDD,输出低电平接近GND,滞回电压大约等于VDD乘以后级反馈分压系数。工程上我更推荐的经验做法是:先估算一个数量级,然后上示波器实测调电阻。以这个案例,Rfb取100kΩ到470kΩ之间,滞回大概能调到10mV到50mV。我通常在过流保护里把滞回控制在20mV上下,也就是保护点500mA、恢复点约300mA,既不会抖动,故障移除后又能自动恢复。
注意:滞回不能给太大。滞回大了,恢复阈值会变得很低,故障电流明明已经降下来了,PWM还是关着,容易造成系统长时间停摆。滞回的本质是给比较器一个"容错区间",不是让保护锁死。
3.3 输入滤波、阻抗和引脚保护
比较器正输入直接接采样电阻时,采样点会有毛刺,电机换向或PWM开关瞬间尤其明显。所以通常要加一个RC低通滤掉高频噪声。RC截止频率按实际故障信号带宽来选,我习惯取1kHz到10kHz之间。但要注意一个矛盾:RC时间常数太大,故障信号本身也会被滤掉,保护速度大打折扣。我的经验是快速保护路径上RC截止频率不低于PWM频率的5到10倍,留足够的边沿余量,同时又能衰减开关纹波。
比较器输入的阻抗问题也容易踩坑。外部分压网络总阻抗如果太高,和比较器输入偏置电流一叠加,会形成额外误差。一般建议外部分压网络总阻抗控制在几十kΩ以内,具体数值要对数据手册里的输入漏电流参数。分压电阻越精密,保护点越稳,但也别把阻抗压太低,否则静态功耗变大,电池供电时划不来。
比较器输入电压还要注意不能超过芯片允许的输入范围。采样电阻电压虽然只有几十毫伏,但电机端出现感性反冲时,地弹和振铃可能让输入引脚瞬间过压。稳妥的做法是在比较器输入端并联一个钳位二极管或者小电容到地,配合RC滤波吸收毛刺。
4. 寄存器配置和固件实现
4.1 比较器部分怎么配置
写代码之前先确定一件事:比较器输出走的是中断、标志位,还是直接互联到PWM。如果只是为了保护,我通常不使能中断,让比较器纯粹作为硬件联动源,这样CPU完全不用参与,代码也简单。
SN8F5703的寄存器命名按这个思路去理解:比较器控制寄存器里会有使能位、输入选择位、输出极性位、输出使能位。具体位号以芯片数据手册为准,但配置流程是一致的。
配置步骤:
- 使能比较器模块,必要时先打开对应的外设时钟。
- 正向输入选择外部引脚,也就是连接采样电阻的通道。
- 负向输入选择内部基准分压档位,或者选择外部基准引脚。
- 设置输出极性。这里一定要想清楚:过流时采样电压升高,比较器输出是高还是低取决于你的接法,而PWM刹车逻辑要哪个极性又有一套定义。极性配反是最常见的低级错误。
- 把比较器输出使能到内部互联路径,并确认没有误接成普通GPIO输出。
4.2 PWM部分怎么配置
PWM侧的配置要点是周期、占空比和联动方式。
先选时钟源和预分频,再设周期寄存器和占空比寄存器。比如系统时钟16MHz,预分频1,周期寄存器设1000,那么PWM频率就是16kHz。这个频率对多数电机驱动和电源控制都够用,噪音也不明显。
联动配置里最关键的是选择"比较器输出作为PWM关断信号"的模式。对应数据手册里可能叫刹车输入、保护输入或关断控制。选中之后还要配置关断后的输出电平:大部分保护场景要求关断到安全电平,比如PWM输出低电平或者高阻,避免MOS管误导通。
PWM配置顺序有讲究。我建议先完成PWM所有配置,但输出保持禁止状态;然后配置比较器并让它稳定下来;最后再开PWM输出。这样避免上电瞬间比较器输入还没稳定,输出乱翻,把PWM误关了。初始化代码注释里我会把这个顺序写清楚,防止同事接手后改坏。
4.3 初始化和联动代码示例
下面这个代码骨架不绑定具体寄存器地址,按寄存器功能位示意,实际移植时对照数据手册改名即可。
void bsp_cmp_init(void) { // 比较器控制寄存器:使能比较器 CMP_CON = 0x00; CMP_CON |= CMP_EN; // 使能比较器模块 CMP_CON |= CMP_PSEL_EXTPIN; // 正向输入选择外部引脚(采样电压) CMP_CON |= CMP_NSEL_INTREF; // 负向输入选择内部基准 CMP_CON |= CMP_POL_NORMAL; // 输出极性:正向输入高时输出高 CMP_CON |= CMP_OUT_ENABLE; // 比较器输出送往内部互联 CMP_CON &= ~CMP_INT_EN; // 不使用中断,纯硬件联动 } void bsp_pwm_init(void) { PWM_CTL = 0x00; PWM_CTL |= PWM_CLK_SYS; // PWM时钟选择系统时钟 PWM_CTL |= PWM_PRESC_1; // 预分频1 PWM_PERIOD = 1000; // 周期寄存器,决定PWM频率 PWM_DUTY = 500; // 初始占空比50% PWM_CTL |= PWM_BRAKE_EN; // 使能比较器刹车联动 PWM_CTL |= PWM_ACTIVE_LOW; // 刹车时PWM输出到安全低电平 PWM_CTL &= ~PWM_OUT_EN; // 先禁止PWM输出,等待初始化完成 } void bsp_protection_enable(void) { bsp_cmp_init(); // 先配置并稳定比较器 bsp_pwm_init(); // 再配置PWM参数 PWM_CTL |= PWM_OUT_EN; // 最后开放PWM输出 }这段代码里,比较器初始化在PWM输出使能之前完成,就是为了避开上电毛刺导致的误触发。如果你的产品对安全要求更高,还可以把PWM输出使能延后几十毫秒,让电源电压和内部基准充分稳定后再开。
void fault_clear_and_restart(void) { // 故障源消除后,由软件清除比较器事件标志 // 重新恢复PWM输出 CMP_CON &= ~CMP_IF; // 清比较器中断/事件标志 PWM_CTL |= PWM_OUT_EN; // 重新允许PWM输出 }恢复逻辑看产品定义。有些设备要求故障锁定,只能断电重启;有些设备希望自动恢复。我遇到过客户要求两秒钟内自动重启三次,三次后锁死,这个逻辑放到主循环里用状态机做很简单,而真正的硬件保护路径始终是随时待命的。
4.4 中断的取舍和故障记录
比较器联动PWM的硬件保护路径是不需要中断的,但我还是会顺手使能比较器中断,目的不是参与保护,而是给故障留下痕迹。比较器翻转触发中断,中断服务程序里记录故障时间、清标志位、累计故障次数,方便生产调试和售后分析。中断里的代码越短越好,只做记录,不要做恢复动作,恢复动作留给主循环或者独立状态机。
5. 调试与问题排查实录
5.1 常见问题速查表
我把实际调试中遇到的八类典型问题整理成一张表,方便对照排查。
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 比较器完全不翻转 | 输入极性接反、基准未配置、引脚没切到模拟功能 | 万用表量两个输入电压,读寄存器标志位确认比较器是否翻转 |
| 阈值附近抖动 | 没有滞回或滞回太小 | 增加正反馈电阻,实测滞回电压 |
| 保护点到不了设定值 | 分压电阻精度不够、基准档位不对 | 用精密电阻,校准实际翻转电压 |
| PWM关不掉 | 比较器极性配反、PWM刹车有效电平选错 | 强制把比较器输出拉高/拉低,看PWM是否联动 |
| 上电瞬间误动作 | 比较器输入悬空、基准建立慢 | 先配置比较器再开PWM输出,输入接确定电平 |
| 保护点随温度漂移 | 电阻温漂、内部基准温漂 | 选低温漂电阻,优先用内部带隙基准 |
| 触发后无法恢复 | 滞回太大、恢复阈值太低 | 减小滞回,测试恢复点 |
| 信号线上有振铃毛刺 | RC滤波不足、PCB布局地线过长 | 补RC滤波,缩短采样回路走线 |
最值得提的一句:调试这类保护功能时,千万不要用"把代码改一下试试"的方式排查硬件问题。先用示波器量比较器两个输入端电压,再量输出端,从前往后逐级确认,十分钟就能定位问题,比盲改代码快得多。
5.2 示波器测量和保护响应时间验证
示波器测比较器输出时,探头地线要尽量短,最好用弹簧接地夹,否则探头地线上感应到的噪声会被当成比较器翻转信号,造成假象。测PWM输出端时,量靠近芯片引脚的位置,别在线束末端量,线束上的阻抗和分布电容会把波形拖变形。
验证保护响应速度,可以用信号发生器给比较器输入一个阶跃电压,从低于阈值瞬间跳到高于阈值,同时示波器双通道看输入和PWM输出,测量两者之间的延时。这个延时包括比较器传播延时、内部互联延时和PWM模块刹车响应时间。SN8F5703这类芯片整体响应时间大概率在微秒量级,具体以数据手册参数为准。
5.3 芯片供电和基准稳定性的细节
SN8F5703是8位MCU,典型工作电压范围比较宽,但比较器模拟部分的精度受VDD影响。如果VDD本身就是开关电源输出的,纹波大,分压电阻取出来的基准也会跟着抖,保护点就变得不可靠。
所以,基准方案优先考虑内部带隙基准,或者从LDO后面取电再分压。我在一个项目里刚开始直接拿VDD分压当基准,结果电源纹波20mV,保护点就跟着漂了差不多20mV,最后换成内部基准档位,整个保护点稳定得多了。
还有引脚规划。比较器输入引脚如果和ADC采样引脚复用,配置ADC时不能同时占用。设计阶段就要把引脚分配表理清楚:哪些脚是采样电压、哪些脚是基准分压、哪些脚是PWM输出,别等画完板子才改,那会非常痛苦。
5.4 一个真实排查案例的流程
有次调试遇到PWM随机关断,刚开始怀疑代码逻辑,后来在示波器上看到比较器正向输入偶尔会有一个尖峰,幅度已经超过阈值。尖峰来源是采样电阻上的开关电流毛刺,不是真正过流。加了一个1kΩ串联电阻加4.7nF电容到地的低通滤波,时间常数约4.7微秒,毛刺被压下去,保护功能恢复正常。
这个案例里最关键的教训是:保护电路也要防误报。一个响应极快的保护系统,如果输入端不做滤波,会把正常噪声当成故障,三天两头误关设备,比不保护还闹心。"快速保护"和"噪声抗扰"要平衡,RC滤波的值要纯粹靠示波器实测来定,不要拍脑袋。
最后说点实在的。我在实际使用这类比较器联动PWM的功能时,最大的感受是"别把这功能想得太神秘"。它本质上就是一条模拟信号到硬件数字输出的快车道。设计时先把互连框图看懂,然后严格确认信号极性和安全电平,剩下的就是调滞回和滤波。踩过几次坑之后,我认为最值得记住的经验是:给比较器留一点滞回,给PWM保护路径确认好安全电平,给输入信号留一点滤波余量,这套设计就基本稳了。