基于EVM_MSPM0L1306的简易PWM发生器
1.任务要求
使用MSPM0L1306的定时器,生成2路重复频率1Hz~1MHz的PWM信号,每一路的重复频率和占空比都可独立调节。
- 其中,PWM重复频率在1Hz~10KHz内连续可调,通过按键切换至100KHz和1MHz。
- PWM重复频率越高,占空比分辨率降低(主时钟32MHz为例)
| 重复频率 | 占空比调节精度 |
|---|---|
| 1MHz | 1/10 |
| 100KHz | 1/100 |
| 10KHz | 1/1,000 |
| 1KHz | 1/10,000 |
| 100Hz | 1/10,000 |
| 1Hz | 1/10,000 |
PWM重复频率在1Hz~10KHz时,占空比的精度不低于1/1000,100Khz和1Mhz的占空比精度按照表格即可。
- 使用按键或拨码开关组合调节输出频率、占空比,并由按键控制每一路PWM信号的输出。
- 能在OLED屏幕上显示基础信息,当前使用引脚示意、引脚相应的PWM参数。
- 将PWM参数(包括两个通道的频率占空比、及通道工作与否)按照1s左右的周期,通过串口发送到上位机。
2.处理思路
1.通过软件SPI驱动我们底版的OLED,实现我们的数据显示。
2.配置我们俩路PWM定时器,实现频率可调和占空比可调的PWM波形。
3.通过配置UART,配置滴答定时器实现1s发送串口,查看我们的频率和占空比和选择通道是否打开。
4.最后通过示波器查看我们的频率和占空比是否正确。
3.程序设计
3.1 程序设计流程图
3.2 代码部分
第一部分:通过SysConfig配置我们的外设
1.PWM
2.串口
3.系统滴答定时器
第二部分:修改定时器频率和占空比
1.修改我们选择对应的定时器通道的频率。
这里我们的频率是通过计数值和分频所决定的,我们需要配置这俩个参数来达到我们的频率。
static void Set_Freq_Timer(int chan, uint8_t cps, uint16_t period) {
//选择通道
GPTIMER_Regs *gptimer = PWM_0_INST;
if (chan == 1) gptimer = PWM_1_INST;
float duty_temp = (float)DL_TimerG_getCaptureCompareValue(gptimer, DL_TIMER_CC_0_INDEX) / (float)DL_TimerG_getLoadValue(gptimer);//计算占空比
DL_TimerG_ClockConfig config = {
.clockSel = DL_TIMER_CLOCK_BUSCLK,
.divideRatio = DL_TIMER_CLOCK_DIVIDE_1,
.prescale = cps};
DL_TimerG_setClockConfig(gptimer, &config);//配置时钟
DL_TimerG_setLoadValue(gptimer, (uint32_t)(period - 1));//配置计数值
DL_TimerG_setCaptureCompareValue(gptimer, (uint32_t)(duty_temp*period), DL_TIMER_CC_0_INDEX);//配置比较值
}
2.修改我们的占空比
我们可以知道占空比的数值是通过:当前计数值-(当前计数值*达到的占空比)、
这里我们是实现通过DL_TimerG_getLoadValue获取当前通道的计数值。
//这里的占空比直接输入0.几就行
void Set_Duty_Timer(int chan,float duty) {
GPTIMER_Regs *gptimer = PWM_0_INST;
if (chan == 1) gptimer = PWM_1_INST;
uint32_t period_duty= 0;
// 获取当前周期值
period_duty = DL_TimerG_getLoadValue(gptimer);
uint32_t compareValue = period_duty - (period_duty * duty);
// 设置新的占空比
DL_TimerG_setCaptureCompareValue(gptimer, compareValue, DL_TIMER_CC_0_INDEX);
}
就可以实现在任意频率下设置我们的占空比,这里需要通过一个函数来获取我们的定时器的计数值,因为我们在修改频率会修改我们的计数值,这里通过函数获取我们准确的数值。
第三部分:OLED显示我们当前的数据
第一行显示我们的占空比
第二行显示我们的频率
第三行显示我们的定时器通道
第四行显示当前定时器是否开启
OLED_ShowString(1,0,"Duty:");
OLED_ShowString(1,2,"Freq:");
OLED_ShowString(1,4,"Data:");
OLED_ShowString(1,6,"Button:");
第四部分:串口显示我们当前数据
我们可以看见串口助手不断打印我们当前的状态。
这是我们串口发送函数
void UART_Send(void)
{
sprintf(txBuf,"Button:PWM0 %d PWM1 %d\r\n",PWM0_Button,PWM1_Button);
SendString(txBuf);
sprintf(txBuf,"Frqe:PWM0 %dHZ PWM1 %dHZ\r\n",Freq_data0,Freq_data1);
SendString(txBuf);
sprintf(txBuf,"Duty:PWM0 %d % PWM1 %d %\r\n",Duty_data0,Duty_data1);
SendString(txBuf);
}
这是我们底层处理函数
void SysTick_Handler(void)
{
SysTick->CTRL &= ~(1 << 16); /*清除滴答定时器中断标志位*/
if(utick++==1000)
{
utick=0;
Uart_data = 1;
}//滴答定时器中断计数
}
void SendString(char *str)
{
while(*str!='\0')
{
DL_UART_Main_transmitDataBlocking(UART_0_INST,*str++);
}
}
第五部分:实物展示
PWM设置我们为10KHZ频率,占空比设置为60.
我们可以看见示波器测量到我们信号为10KHZ,占空比在60%。
总结收获
其中问题遇到很多,一开始的Syscfg配置一直没有更新到ti_msp_dll_config中,后来发现给的底层中有一个remain,查看后发现里面有标注要修改的地址。第二个问题是对板子的库函数很不熟悉,许多想用的函数都找不到,最后通过板子自带的实例教程,通过ti公司的实例,逐渐了解的函数该如何使用,并且也知道如何去查找函数。最后一个点,在配置频率和占空比也很头痛,在摸索发现,在Syscfg配置参数,就可以得到我们想要的频率和占空比,在不断试错和总结经验的过程中完成此次的任务。
最后也感谢电子森林推出此次活动,能让我更好的理解了从0开始学习板子的思路,也在此次中也更进一步让我对PWM调节有了进一步的认识。