一、PWM(Pulse Width Modulation(脉宽调制))
周期固定,高电平时间可变,通过调节高电平占空比等效调节平均电压,实现电机调速、LED 调光。
不是直接给电机一个变化的电压,而是:
快速地打开、关闭电源,通过控制"打开时间比例"改变平均电压。
1.PWM一个周期
例如:PWM频率:
#define PWM_FREQ 15000
表示:一分钟内没有,是:每秒15000个周期。

2、PWM占空比是什么?
占空比:就是一个周期内:开机时间占多少比例


等效电压原理(直流电机调速核心)
直流电机等效电压 = 电源电压 × 占空比
3、PWM和继电器的分工
**继电器:**控制方向
例如:上升:
24V+
|
电机+
电机-
|
GND
下降:反过来。
**PWM:**控制速度
例如:上升:PWM:
20%
↓
40%
↓
80%
速度:
慢
↓
快
4. ATIM 定时器 PWM1 模式(你代码 ATIM_OCMODE_PWM1)
计数逻辑(向上计数 ATIM_COUNTING_UP)
计数器从 0 → 999 循环:
- 计数值 < 比较值 g_uCurDuty:引脚输出高
- 计数值 ≥ 比较值:引脚输出低
例:Duty=300 0~299 → 高;300~999 → 低
极性 ATIM_OCPOLARITY_NONINVERT 不反转
匹配高电平驱动电机驱动芯片,不需要反向电平。
影子缓存 BufferState=ENABLE
开启预装载,修改占空比不会中途撕裂波形,PWM 边缘平滑无毛刺,电机不抖动。
二、ADC掉电检测
ADC(模数转换器)掉电检测是一种常见的硬件保护机制,用于在系统电源异常跌落时,及时检测并保存关键数据或执行安全关机操作。
1. 基本原理
通过ADC实时监测电源电压(如3.3V、5V等),当检测到电压低于预设阈值时,触发中断或标志,通知MCU进行紧急处理。
2. 电压分压计算
若直接测量高于ADC参考电压的电源(如29V),需使用电阻分压网络。例如:
已知:电源电压 Vsource = 29V,分压电阻 R1 = 100kΩ,R2 = 10kΩ。
则ADC输入电压 VADC = Vsource × R2 / (R1 + R2) = 29V × 10 / (100 + 10) ≈ 2.64V。
3. ADC采样值计算
以CW32系列MCU为例,其ADC为12位,参考电压 VREF = 3.3V。
满量程数字值 = 212 - 1 = 4095。
当 VADC = 2.64V 时,ADC采样值 ≈ (2.64V / 3.3V) × 4095 ≈ 3275。
因此,可设置掉电阈值对应的ADC采样值(如3275),当采样值低于此阈值时,判定为掉电。
cs
#define ADC_FULL 4095.0f
#define ADC_REF 3.3f
#define R_UP 100000.0f
#define R_DOWN 10000.0f
float Power_GetVoltage(uint16_t adc)
{
float vadc;
vadc = adc * ADC_REF / ADC_FULL;
return vadc * (R_UP+R_DOWN) / R_DOWN;
}
掉电判断,假设掉电低于20V
cs
#define POWER_OFF_VOLTAGE 20.0f
void Power_Check(void)
{
float voltage;
voltage = Power_GetVoltage(ADC_Value);
if(voltage < POWER_OFF_VOLTAGE)
{
PowerFail_Handler();
}
}
掉电处理流程:
29V下降→ADC检测→PowerFail_Handler()→关闭电机→关闭PWM→释放继电器→保存高度→等待复位
缓启动 / 缓停止实现思路(适配你的继电器 + PWM 调速架构)
核心原理
- PWM 占空比阶梯式缓慢上升(缓启动),阶梯式缓慢下降(缓停止),避免 29V 母线瞬间大电流冲击,同时配合之前 20V 低压防误判、7A 堵转保护。
- 采用 10ms PID 任务周期,每次步进固定增量
STEP_DUTY,上限最大占空比MAX_DUTY,下限 0 停机。 - 区分 3 种运行状态:加速上升、匀速、减速停机,和堵转 / 低压故障互斥,故障时直接清零 PWM 不缓停。
4. 实现步骤
- 配置ADC通道、采样时间、参考电压等参数。
- 启动ADC连续采样或定时采样。
- 在ADC转换完成中断或主循环中读取采样值。
- 比较采样值与预设阈值,若低于阈值则置位掉电标志。
- 在掉电标志有效时,保存关键数据至非易失存储器(如Flash、EEPROM),或执行安全关机流程。
5. 注意事项
- 分压电阻精度和温漂会影响检测精度。
- 需考虑电源跌落速度与ADC采样/处理速度的匹配。
- 可加入软件滤波(如滑动平均)避免误触发。
- 阈值应留有一定余量,避免临界振荡。
cs
// M1电流计算:扣除空载零点偏移80
float Current_M1_GetAmp(void)
{
uint16_t uRaw = GetFilterAdc(M1_CUR_CH, &g_tM1Current);
// 核心修复:减去空载ADC零点偏移80,解决停机虚电流
int16_t iAdcCorrect = (int16_t)uRaw - CURRENT_OFFSET_ADC;
if(iAdcCorrect < 0)
iAdcCorrect = 0; // 消除负电流
float fAdc = (float)iAdcCorrect;
// 公式完全匹配hw 3.3V基准,电压换算:采样值/4095 * 3.3V基准
float fVol = fAdc / ADC_RESOLUTION * ADC_REF_VOLT;
// 运放21倍放大、0.02Ω采样电阻 计算真实电流
g_tM1Current.fCurAmp = fVol / OP_AMP_GAIN / CURRENT_SHUNT_R;
return g_tM1Current.fCurAmp;
}
// M1独立过流判定,100ms防抖
uint8_t M1_IsBlockProtect(void)
{
// 电流超过7A堵转阈值
float fCurr = Current_M1_GetAmp();
if(fCurr >= BLOCK_CURRENT)
{
uM1OverCnt++;
// 10ms任务周期,累计100次=1秒判定堵转
if(uM1OverCnt >= OVER_CURRENT_TIME)
return 1;// 触发堵转
}
else
uM1OverCnt = 0;// 电流正常计数器清零
return 0;
}
推挽输出(Push-Pull)
GPIO 内部有两个 MOS 管:
- 上管(PMOS):接 VDD (3.3V)
- 下管(NMOS):接 GND
两种工作状态
- 输出高电平 上管导通、下管截止 → 引脚直接拉到 3.3V,驱动能力强,能输出电流(灌电流)
- 输出低电平 下管导通、上管截止 → 引脚直接拉到 GND,吸收外部电流(拉电流)
对比开漏输出(OD)
开漏只有下拉 NMOS,高阻态,只能外部上拉才能输出高; 推挽高低都有驱动能力,电机、继电器、PWM 输出必须用推挽。
适用场景
- PWM 定时器复用输出(PA8/PA9)
- 继电器控制引脚
- LED、电机驱动、普通数字 IO
缺点
两个管子不能同时导通(会电源对地短路),软件不能同时输出高低,你的继电器代码先全断开再延时切换就是规避这个风险。
PWM 高低电平需要强驱动输出,开漏输出无法输出高电平,PWM 波形失效,电机不转。 同时开启PA08_DIGTAL_ENABLE()关闭模拟功能,开启定时器复用外设功能。

