STM32调制PWM生成三角波
最近临近期末,课程电力电子大作业老师要求用单片机控制生成信号,经过H桥电路放大之后用RL电路滤波,负载两端的波形要求是三角波。要求不能用da直接输出,所以选用pwm调制的方式。
方案设计
单片机选用stm32f103,用的是正点原子的板子啦。选32的原因就是32有专门的pwm控制器,功能非常的强大,相比51要用定时器自己写波形,方便的多。而且pwm的频率直接影响着生成波形的光滑程度。
程序框图
程序设计中用Time3的一个pwm通道来生成pwm波,然后用Time4来控制占空比的变化。
stm32生成pwm波的原理有很多博客写的很详细了,这里就不赘述了。
程序源码
主函数
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "timer.h"
int i;
float pwmval;
int main(void)
{
u8 dir=1;
pwmval=99;
i=0;
delay_init(); //delay函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位相应优先级
uart_init(115200); //串口初始化115200
LED_Init(); //LED端口初始化
TIM3_PWM_Init(99,71); //TIM3初始化 pwm频率=72000000/(71+1)/(99+1)=10Khz
TIM4_Int_Init(99,71); //TIM4初始化 中断频率=72000000/(71+1)/(99+1) = 10Khz
while(1)
{
TIM_SetCompare2(TIM3,pwmval);
}
}
//定时器4中断函数
void TIM4_IRQHandler(void) //TIM4中断
{
if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //检查TIM中断是否触发
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update ); //清除TIM4的中断待处理位
i++;
if(i<75) //前四分之三周期
pwmval = pwmval-1.32; //占空比递增到百分之一百
else if(i=>75 && i<100) //后四分之三周期
pwmval = pwmval - 3.96; //占空比递减至零
else if(i == 100)
{
pwmval = 99; //重置占空比
LED1=!LED1; //led闪烁,debug用
i = 0; //计数重置
}
}
}
定时器中断函数
#include "timer.h"
#include "led.h"
#include "usart.h"
void TIM4_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //定时器时钟周期的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割TDTS=Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //初始化
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM4中断,允许更新
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //TIM4中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC
TIM_Cmd(TIM4, ENABLE); //使能TIM4外设
}
//TIM3pwm初始化
void TIM3_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外设和AFIO复用功能模块时钟
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //TIM3部分重映射 TIM3_CH2->PB5
//设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形GPIOB.5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
//初始化TIM3
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化
//初始化TIM3 CH2 PWM
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //初始化
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能CCR2上的预装载寄存器
TIM_Cmd(TIM3, ENABLE);
}
程序部分参考了很多正点原子的教学例程,用的是标准库。各种配置确实是有点繁琐,下一个项目可能会用HAL库尝试开发
H桥
生成的PWM波形要变成想要的波形需要经过电感滤波,需要较大的电感和较大的电容,显然单片机的驱动能力的不够的,所以需要一个功率放大。
H桥选用的是L298N电机驱动芯片模块,市面上非常常见。
输出波形
负载的电流波形
负载的电压波形和电流波形对比
放大一点
总结
这次制作的稍微有点匆忙,毕竟是快要考试了,所以就忘了拍具体的硬件电路图
虽然制作之前就经过的仿真和理论学习,但是能够实际看到波形还是对这个理论有了更深刻的理解
STM32还是非常强大的,10k的pwm就可以看到非常漂亮的波形啦,相比51的波形要好看许多
程序比较简单,就写的有点随意了
鉴于本人水平有限,若文章中有错误的地方希望大家能帮我指正。
希望这篇文章对你们有帮助!
谢谢观看
考试了,所以就忘了拍具体的硬件电路图
虽然制作之前就经过的仿真和理论学习,但是能够实际看到波形还是对这个理论有了更深刻的理解
STM32还是非常强大的,10k的pwm就可以看到非常漂亮的波形啦,相比51的波形要好看许多
程序比较简单,就写的有点随意了
鉴于本人水平有限,若文章中有错误的地方希望大家能帮我指正。
希望这篇文章对你们有帮助!
谢谢观看