基于MSPM0L1306实现简易PWM发生器
1 项目需求
- 使用MSPM0L1306的定时器,生成2路重复频率1Hz~1MHz的PWM信号,每一路的重复频率和占空比都可独立调节。
- 其中,PWM重复频率在1Hz~10KHz内连续可调,通过按键切换至100KHz和1MHz。
- PWM重复频率越高,占空比分辨率降低。
- PWM重复频率在1Hz~10KHz时,占空比的精度不低于1/1000。
- 使用按键或拨码开关组合调节输出频率、占空比,并由按键控制每一路PWM信号的输出。
- 能在OLED屏幕上显示基础信息,当前使用引脚示意、引脚相应的PWM参数。
- 将PWM参数(包括两个通道的频率占空比、及通道工作与否)按照1s左右的周期,通过串口发送到上位机。
2 完成的功能及达到的性能
(1)两路独立可调频率和占空比PWM信号,范围1Hz~1MHz;
(2)占空比调节精度可达:1MHz 1/10;100KHz 1/100;10KHz 1/1,000;1KHz 1/10,000;100Hz 1/10,000;1Hz 1/10,000;
(3)实用的OLED屏幕显示,可显示输出通道及对应的PWM参数,其中,CH1和CH2分别对应对应PA26和PA21引脚;
(4)串口通信上位机显示PWM相关参数(通道开启与否,占空比及频率)
3 实现思路
初始化:
- 初始化设备、OLED屏幕、计时器及启用中断。
主循环:
- 持续读取按键值。
- 根据按键值计算并更新频率和占空比。
- 更新OLED显示。
按键值计算:
- 处理不同按键值的功能,如数字输入、确认、删除、切换通道、频率/占空比、启用/禁用通道等。
更新频率与占空比:
- 根据按键输入计算新的PWM频率和占空比。
- 设置对应的PWM参数。
OLED显示:
- 更新OLED显示,显示当前通道、频率、占空比及通道启用状态。
中断处理:
- 在TIMER0中断服务程序中,通过串口打印当前频率和占空比。
4 实现过程
4.1 键值计算功能
if (key_value > 0 && key_value <= 16)
{
if (key_num[key_value - 1] >= 0 && key_num[key_value - 1] <= 9)
{
if (temp_num[6] == 0)
{
// 首先检查是否整数部分已经达到了最大可能的长度(8位数字),
// 如果是,则停止处理并返回,避免溢出。
if (temp_num[0] >= 10000000)
{
return;
}
// 如果整数部分未达到最大长度,将当前键值对应的数字添加到整数部分。
// 这里使用乘以10然后加上的方式来构建整数。
temp_num[0] = temp_num[0] * 10 + key_num[key_value - 1];
temp_num[2]++;
// 更新浮点数表示,以保持与整数部分的一致性。
temp_float = temp_num[0];
}
// 如果整数部分已满,开始处理小数部分。
// 初始化浮点数因子为1,这将用于计算小数点后的位数。
else
{
float FloatFactor = 1;
// 增加小数部分的位数计数。
temp_num[2]++;
for (int x = 0; x < temp_num[2]; x++)
{
FloatFactor = FloatFactor * 10; // 计算小数点后需要移动的小数位数。
}
// 根据计算出的小数位数,将当前键值对应的浮点数添加到总和中。
if (temp_num[2] >= 1)
{
temp_float = temp_float + key_float[key_value - 1] / FloatFactor;
}
}
}
此代码段负责根据一系列键值构建一个可能包含整数和小数部分的数值。它首先检查当前键值对应的数字是否在0至9的有效范围内。如果是,则根据当前数值构建状态,将该数字添加到整数或小数部分。如果整数部分尚未开始填充(由temp_num[6]标记),并且整数部分尚未达到8位的最大长度,则将当前键值数字添加到整数部分,并更新整数位数计数器temp_num[2]以及浮点数表示temp_float。一旦整数部分达到最大长度或开始处理小数部分,代码将计算一个小数点后位数的因子(FloatFactor),并使用这个因子将键值对应的小数部分加入到总和中。整个过程确保数值的构建既不会导致整数溢出,又能正确地处理小数点后的精度。
4.2 分频PWM时钟功能
if (PWM_Freq[0] > 500)
{
DL_TimerG_setClockConfig(PWM_0_INST, (DL_TimerG_ClockConfig *)&gPWM_ClockConfigUpdate1);
PWM1_CLK = 32000000;
}
else if (PWM_Freq[0] > 180 && PWM_Freq[0] <= 500)
{
DL_TimerG_setClockConfig(PWM_0_INST, (DL_TimerG_ClockConfig *)&gPWM_ClockConfigUpdate2);
PWM1_CLK = 10666667;
}
else if (PWM_Freq[0] > 65 && PWM_Freq[0] <= 180)
{
DL_TimerG_setClockConfig(PWM_0_INST, (DL_TimerG_ClockConfig *)&gPWM_ClockConfigUpdate3);
PWM1_CLK = 4000000;
}
else if (PWM_Freq[0] > 32 && PWM_Freq[0] <= 65)
{
DL_TimerG_setClockConfig(PWM_0_INST, (DL_TimerG_ClockConfig *)&gPWM_ClockConfigUpdate4);
PWM1_CLK = 1333333;
}
else if (PWM_Freq[0] > 10 && PWM_Freq[0] <= 32)
{
DL_TimerG_setClockConfig(PWM_0_INST, (DL_TimerG_ClockConfig *)&gPWM_ClockConfigUpdate5);
PWM1_CLK = 500000;
}
else if (PWM_Freq[0] > 4 && PWM_Freq[0] <= 10)
{
DL_TimerG_setClockConfig(PWM_0_INST, (DL_TimerG_ClockConfig *)&gPWM_ClockConfigUpdate6);
PWM1_CLK = 250000;
}
else //(PWM_Freq[0]<=3)
{
DL_TimerG_setClockConfig(PWM_0_INST, (DL_TimerG_ClockConfig *)&gPWM_ClockConfigUpdate7);
PWM1_CLK = 62500;
}
// 计算周期和占空比,使用浮点运算以保持精度
period0 = (float)PWM1_CLK / PWM_Freq[0];
dutyCycle0 = period0 * (1 - PWM_Duty[0] / (float)100);
// 将结果转换为整数类型,以便于传递给硬件接口
if (enablechannel[0] == 0)
{
captureCompareValue0 = (uint32_t)period0;
loadValue0 = (uint32_t)dutyCycle0;
// printf("captureCompareValue=%d\n", (unsigned int)captureCompareValue0);
}
函数首先清除OLED屏幕,然后在屏幕上显示两个PWM通道的详细信息,包括频率、占空比和启用状态。同时,它还包含一个菜单区域,指示了当前选定的通道以及调整的参数(频率或占空比)。参数:
PWM1 uint32_t 类型的PWM1频率值。
PWM1_Duty float 类型的PWM1占空比值。
PWM2 uint32_t 类型的PWM2频率值。
PWM2_Duty float 类型的PWM2占空比值。
如果PWM频率为1000000 Hz,显示为"1M"。如果PWM频率为100000 Hz,显示为"100k"。根据temp_num数组中的值更新菜单选项的高亮显示。
5 实际实用
1Mhz
100kHz
10kHz
1kHz
100Hz
10Hz
1Hz
6 实物展示
6.1 屏幕区域指示
①、③:频率状态指示(Freq);
②、④:占空比状态指示(Duty);
⑤、⑥:通道开启状态指示;
⑦:通道选择;
⑧:频率/占空比选择;
⑨:通道启停选择;
⑩:确认。
6.2 按键区域指示
注意:
1、小数点精度仅适用于占空比微调场景;对于频率参数而言,其值需为整数类型,系统在处理时将自动剔除任何小数部分。
2、当用户未选择特定通道时,程序将自动配置 CH1 作为默认操作通道。
3、若用户未指定频率或占空比的调整,系统将遵循以频率设定为首要操作的预置逻辑。
7 总结与展望
本次项目是我我首次系统性地接触TI的MCU。与先前所用的STM32相比,TI的MCU在RAM容量方面通常较小,但这并没有成为本次任务中的瓶颈,因为项目本身对RAM的需求量不大。
在项目编码的过程中,TI提供的SysConfig工具发挥了重要作用,它简化了初始化外部设备的复杂步骤。通过分析SysConfig生成的C语言文件,我能够快速掌握如何编写时钟分频的代码,这极大地提高了工作效率。
我想要特别感谢启是科技和武汉大学的团队,以及电子森林平台。他们不仅为我提供了一个实践的机会,还分享了一系列详实且易懂的示例工程,这对后续的开发工作起到了巨大作用。这次项目套件不仅对电赛有益,同样适用于单片机相关的课程和自学,其价值远远超出了预期。