dsPIC30F 输出比较七步配置:单比较翻转、双比较脉冲与 PWM 三模式一次讲透

阀泵定时靠软件延时抖动大,换输出比较又常被 OCxR、OCxRS 与 PRy 的关系卡住。按 dsPIC30F 参考手册第 14 章拆解八种 OCM 编码、单双比较时序与 PWM 周期精度,给出七步配置与排查表。

2026-11-05
dsPIC30F输出比较单脉冲PWM故障保护寄存器配置

一台包装机用 dsPIC30F 做阀泵时序,原先靠定时器中断里翻转 IO,脉宽在 200 µs 到 5 ms 之间变化,操作工总说同一个配方动作有快有慢。改用输出比较模块后,边沿抖动从几个微秒压到一个指令周期。结论先给:输出比较不是另一种定时器中断,它把比较值直接送到引脚逻辑,匹配后的下一个指令时钟引脚就动作;真正决定脉冲形状的,是 OCxR 与 OCxRS 谁管上升沿、谁管下降沿,以及周期寄存器 PRy 与这两个值的大小关系。

本文按 Microchip《dsPIC30F 系列参考手册》DS70060C_CN 第 14 章整理,寄存器位定义、时序图与算例均取自该章。

一、先划清它和 GPIO 延时、MCPWM 的边界

每个输出比较通道有两个可选时基:OCTSEL(OCxCON<3>)为 0 选 Timer2,为 1 选 Timer3;器件最多 8 个通道,从 OC1 到 OC8,具体数量看型号数据手册。比较匹配发生在时基计数值与 OCxR 相等时,引脚在下一个指令时钟动作,再过 2 个 TCY 才置 OCxIF。这 2 TCY 的滞后只影响中断响应,不改变引脚边沿位置,所以脉宽精度取决于时基分辨率,而不是中断延迟。

两条硬约束常被忽略:一是输出比较不能用 32 位时基,必须把 T32(TxCON<3>)清零;二是切换模式前先把 OCM 清成 000 关掉通道,否则残留状态会让第一次比较就出错。手册在模式说明里专门写了这条建议。

与 MCPWM 的分工也很清楚:MCPWM 面向三相电机,带互补输出、硬件死区和专用故障引脚;输出比较只做到点翻转、到点出脉冲,适合电磁阀、计量泵、蜂鸣器、外部触发这类单路时序。这些活用 MCPWM 来做,通道和死区资源都浪费。

二、OCM 八种编码一张表

模式选择全部压在 OCxCON 的低三位上,先把这张表记住,现场看代码就不用翻手册。

OCM<2:0>模式引脚行为典型用途
000禁止引脚交还 LAT/TRIS 控制切换模式前必须先回到这里
001单比较,置高初始低,匹配后拉高并保持上电使能、单次门控
010单比较,置低初始高,匹配后拉低并保持定时关断
011单比较,翻转每个周期匹配点翻转一次方波、时钟分频输出
100双比较,单脉冲OCxR 定上升沿,OCxRS 定下降沿,只出一次阀动作、超声波发射
101双比较,连续脉冲每个周期出一次脉冲泵 PWM、脉冲串
110PWM,无故障引脚占空比经缓冲寄存器更新加热、调速
111PWM,带故障引脚OCFA/OCFB 为低时输出高阻需要急停的功率级

三、单比较翻转:初始电平得自己定

OCM=011 时,引脚初始为低,之后每来一次匹配就翻转一次。麻烦在于复位后内部输出逻辑固定为 0,而翻转模式又允许软件指定初始状态。手册例 14-1 给的写法是:先写 OCM=001 把引脚钉在低电平,再把 bit1 置起来变成 011;想要初始高电平,就先写 010、再置 bit0。多这一步的意义是让引脚在进入翻转模式前有一个确定状态,否则上电第一拍是高是低要看运气。

中断标志也要按手册的时序理解:引脚动作后 2 个 TCY 才置 OCxIF,ISR 里必须软件清零;如果中断响应慢到跨过下一个匹配点,标志会再次置位,看起来像进了两次中断。用翻转模式测频率时,最好在 ISR 里只做计数,把业务处理放到主循环。

四、双比较:一个周期里放两个边沿

OCM=100 或 101 时,OCxR 与 OCxRS 分别对应脉冲的前沿和后沿,两者比的是同一个递增计数器 TMRy。想让脉冲按预期出现,必须满足 PRy ≥ OCxRS 且 OCxRS > OCxR;一旦越界,手册表 14-1 和表 14-2 列了几种“看似配置成功、实际没波形”的情况。

寄存器关系实际现象处理
OCxR = 0第一个周期不出脉冲,从第二次周期复位后才开始脉冲整体延后一个周期,需要立即出脉冲就把 OCxR 设到 1 以上
OCxR ≥ OCxRS上升沿在本周期,下降沿落到下一个周期,脉宽跨周期保证 OCxRS > OCxR,否则脉宽等于周期减差值
OCxRS > PRy只出现上升沿,没有下降沿;单脉冲模式不置 OCxIF把 PRy 调到不小于 OCxRS
OCxR > PRy不支持,计数器在匹配前已复位,引脚一直是低先核算 TCY 与计数范围,别让比较值超出周期

按 10 MIPS、TCY=100 ns 算一组实际值:PR2 写 0x4000 得 16384 个计数,周期 1.6384 ms;OC1R 写 0x0800 是 204.8 µs 处起脉冲,再加 0x0400 个计数得到 102.4 µs 脉宽,OC1RS 就是 0x0C00。三个数都在 16 位范围内,且满足 0x0C00 小于 0x4000,这时示波器上才能看到干净的单个脉冲。

五、PWM 模式:OCxR 只读,OCxRS 才是缓冲

OCM=110 或 111 进入 PWM 后,OCxR 变成只读的占空比寄存器,用户只能写 OCxRS。周期匹配时硬件才把 OCxRS 装进 OCxR,这就是双缓冲:中途改占空比不会切出半个周期的怪波形。周期公式是(PRy+1)× TCY × 预分频比,占空比按 OCxR 的计数值算,0x0000 是 0%,大于 PRy 是 100%,等于 PRy 时只有一个计数周期为低。

手册例 14-6 用 PR2=0x00BF、OC1RS=0x0060,在 TCY=100 ns 下得到(191+1)×100 ns=19.2 µs,即 52.08 kHz,占空比 96/192 正好一半。这个例子值得抄下来当自检基准:频率对不上先查 TCY 和预分频,占空比不对先查是不是写错了寄存器。

PWM 频率(10 MIPS)周期寄存器可用精度PWM 频率(30 MIPS)可用精度
19 Hz0xFFFF(8 分频)16 位57 Hz16 位
305 Hz0x7FFF15 位916 Hz15 位
9.77 kHz0x03FF10 位29.3 kHz10 位
78.1 kHz0x007F7 位234 kHz7 位

这张表说明频率和分辨率是互相挤占的。10 MIPS 下要 20 kHz,按公式算可用计数约 2000 个,理论分辨率接近 11 位;如果直接抄 78.1 kHz 那档参数,只剩 7 位,占空比调一格就是 0.8%,加热丝上能看到明显台阶。选型阶段就该把目标频率代进公式,而不是写完代码再看波形。

六、故障输入与低功耗的两个坑

OCM=111 才启用故障保护:OCFA 管通道 1 到 4,OCFB 管通道 5 到 8,引脚检测到逻辑 0 后,对应 PWM 输出立即进入高阻,且与器件时钟无关。这里有两个细节:故障引脚必须自己把 TRIS 位置 1 配成输入,使能 PWM 模式并不会替你改方向;OCFLT 是只读位,只有外部故障消失并且重新写 OCM 使能 PWM 时才清零,靠软件写 0 是清不掉的。

低功耗下,休眠时输出比较整体停摆,引脚保持进休眠前的电平;空闲模式则要看 OCSIDL,为 1 时模块停止,为 0 时模块继续工作,但还必须把对应时基的 TxSIDL 也清 0。手册设计技巧里那条“OCSIDL 没置 1,引脚却停了”,答案就在 TxSIDL 上,实际停的是定时器。

七、七步配置:从关通道到启动时基

  1. 选时基:确定用 Timer2 还是 Timer3,把 T32 清 0,按目标周期写 PRy。
  2. 关通道:OCxCON 写 0x0000,确保 OCM=000,避免切换模式时残留状态。
  3. 算计数:用 TCY 和预分频把时间换算成计数,上升沿、脉宽、周期三个值一起核对。
  4. 写比较值:单脉冲/连续脉冲写 OCxR 与 OCxRS;PWM 模式先写 OCxRS,再把同一个初值写进 OCxR。
  5. 配模式:按需置 OCTSEL,再写 OCM 选择 100、101、110 或 111。
  6. 清标志开中断:清 OCxIF,置 OCxIE,设置 IPC 优先级;故障模式还要打开输出比较中断。
  7. 启动时基:置 TON=1,此时引脚才真正开始按比较值动作。
/* dsPIC30F,10 MIPS(TCY = 100 ns),OC1 用 Timer2 出单脉冲 */
void oc1_single_pulse(uint16_t rise, uint16_t width)
{
    OC1CON = 0x0000;          /* OCM=000:切换模式前先关通道 */
    T2CON  = 0x0000;          /* TCKPS=1:1,T32=0,不能用 32 位时基 */
    PR2    = 0x4000;          /* 周期 = 16384 × 100 ns = 1.6384 ms */
    OC1R   = rise;            /* 上升沿计数,如 0x0800 = 204.8 µs */
    OC1RS  = rise + width;    /* 下降沿计数,必须不大于 PR2 */
    IFS0bits.OC1IF = 0;
    IEC0bits.OC1IE = 1;       /* 下降沿后 2 TCY 置标志 */
    OC1CON = 0x0004;          /* OCM=100 单脉冲,OCTSEL=0 选 Timer2 */
    T2CONbits.TON = 1;        /* 启动时基 */
}

如果改成连续脉冲,把 OC1CON 写 0x0005;改成 PWM,写 0x0006 并把 OC1R/OC1RS 都设成占空比计数值。模式切换仍然要先回 0x0000,这一点在中断里动态改模式时尤其重要。

八、六个现场排查

现象根因改法
完全没有波形OCM 还是 000,或 TON 没置 1,或 T32=1按七步顺序核对,T32 必须为 0
只有上升沿没有下降沿OCxRS 大于 PRy把 PRy 调到不小于 OCxRS
脉宽等于一个周期OCxR 大于等于 OCxRS,下降沿跨到下一周期保证 OCxRS 大于 OCxR
第一个脉冲晚一个周期OCxR 写成 0需要立即动作就把 OCxR 设到 1 以上
PWM 占空比改了没反应写的是只读的 OCxR只写 OCxRS,等周期匹配后自动装载
空闲模式下输出停了OCSIDL 或 TxSIDL 为 1两个位都清 0,模块才会在空闲模式继续跑

一句话总结:输出比较的价值在于把边沿交给硬件,软件只算三个数——上升沿、下降沿、周期;OCxR 与 OCxRS 的关系决定脉冲形状,PRy 决定它们能不能落在同一个周期里,先把这三个数的账算平,再谈中断和故障保护。

还想接着看:dsPIC30F2010 电机控制 PWM 死区与故障输入、dsPIC30F QEI 与输入捕捉接口、dsPIC33F 电流环 Q15 定点与饱和。

本文基于 Microchip《dsPIC30F 系列参考手册》DS70060C_CN 技术资料整理优化。

需要定制开发?

沧州艾诺威电子 — 国家高新技术企业,20+项国家专利
嵌入式系统开发 · 物联网方案 · AI智能硬件 · 一站式交付

立即微信咨询

电话:13930711029 | 邮箱:tech@czinv.com | 24小时内响应