如何移除索引逻辑,基于Amp*sin(w*t)公式修改正弦波频率
解决方案
要实现基于经典正弦公式Amp*sin(2πft)的SPWM输出并灵活修改频率,核心是用相位累加替代索引查表,直接在中断中计算当前时刻的正弦值,无需依赖固定长度的查表数组。以下是具体实现步骤和修改后的代码:
关键思路
- 移除查表依赖:不再需要维护
sineWave和sineWave180数组,直接在中断中实时计算当前占空比。 - 相位累加替代索引:用浮点型相位变量累计每次中断的相位增量,替代原来的
sineIndex。相位增量由目标频率和中断周期共同决定:delta_theta = 2π * target_freq * T_int,其中T_int是定时器3的中断周期(需根据硬件配置计算)。 - 频率修改方式:只需调整
target_freq变量的值,就能直接改变输出正弦波的频率,无需修改其他逻辑。
修改后的代码
#include <math.h> // 定时器中断周期(需根据你的硬件配置计算,示例为1微秒) #define T_INT 1e-6f // 目标正弦波频率(可随时修改此值调整输出频率) volatile float target_freq = 50.0f; // 振幅系数(范围0~1,控制正弦波幅度) volatile float Amp_coef = 1.0f; // 相位累加器,记录当前正弦波相位 volatile float theta = 0.0f; void __attribute__((__interrupt__, no_auto_psv)) _T3Interrupt(void) { IFS0bits.T3IF = 0; // 清除定时器3中断标志 // 计算本次中断的相位增量,并累加 float delta_theta = 2 * M_PI * target_freq * T_INT; theta += delta_theta; // 保持相位在0~2π范围内,避免浮点数精度衰减 if (theta >= 2 * M_PI) { theta -= 2 * M_PI; } // 计算当前正弦值(范围:-Amp_coef ~ Amp_coef) float sine = Amp_coef * sin(theta); // 映射正弦值到占空比范围(0 ~ P1TPER),再转换为16位占空比寄存器值 int duty1 = (int)((P1TPER / 2) * sine + P1TPER / 2); int duty2 = (int)((P1TPER / 2) * (-sine) + P1TPER / 2); P1DC1 = duty1 * 2; // 周期寄存器15位,占空比16位,故乘以2 P1DC2 = duty2 * 2; }
关键细节说明
- 中断周期
T_INT计算:需根据你的定时器3配置(预分频值、PR3寄存器值、系统时钟)计算,公式为:T_INT = (PR3 + 1) * 指令周期 * 预分频系数。例如,若系统时钟为40MHz,指令周期为100ns,预分频为1:1,PR3=9,则T_INT = 10 * 100ns * 1 = 1us。 - 相位重置:当相位累加超过
2π时减去2π,避免浮点数因累计过大导致精度下降。 - 振幅控制:
Amp_coef设为0~1之间的值,确保占空比不会超出0~P1TPER的范围,避免输出异常。 - 频率修改:只需修改
target_freq的值(比如从50Hz改为60Hz),输出正弦波的频率就会同步变化,无需调整中断周期或其他逻辑。
内容的提问来源于stack exchange,提问作者Nobody Else
相关产品推荐
相关产品推荐

