SPWM波指的是占空比呈正弦规律变化的PWM波,生成方式是在定时器中断中调整PWM波的占空比。

对于互补的两路SPWM波,一路为低电平 ‘0’ 时,另一路为高电平 ‘1’,即两路是互补的。

对于STM32F7,使用高级定时器TIM1可以方便地生成互补SPWM波。步骤如下:

1、确定载波周期 Tc,也即是每个SPWM波的周期。对于逆变电路,常采用20kHz,也即 Tc =  50us;

2、确定基波周期 Tb,此处取50Hz,即 Tb = 20ms;

3、计算取点数N,Tb / Tc = 20ms/50us = 4000;半个周期内则为  N = 2000点;

4、计算占空比,Di = sin(i*pi / N), i = 1, 2, 3, ..., N;

5、确定最大最小占空比,例如最小占空比 Dmin = 0,最大占空比Dmax = 100%;

6、计算并修改定时器的比较值。将占空比为0%时,定时器的比较值设置为Cmin = 0;将占空比为100%时,定时器的比较值设为Cmax = 5399;则每中断一次,占空比的值设为 Cmax*Di,直接在中断里完成计算。

根据以上计算,可以修改最小占空比和最大占空比,也可以修改基波与载波频率。

以下是具体定时器配置与中断服务函数程序,基于STM32F767IGBT:

//使用高级定时器 1 完成
//Update--2019.6.3
//sin_k = TIM1_ARR / 200.0 * (float)(spwm_max_duty - spwm_min_duty ) ; //正弦波的比例系数,一个简单的数学代换
//sin_b = TIM1_ARR / 200.0 * (float)(spwm_max_duty + spwm_min_duty ) ; //正弦波的截距 #include "timer1.h"
#include "led.h"
#include "math.h" TIM_HandleTypeDef TIM1_Handler; //定时器句柄
TIM_OC_InitTypeDef TIM1_CH1Handler; //定时器3通道4句柄
TIM_BreakDeadTimeConfigTypeDef BreakDeadTime_Config; #define PWM_GPIO GPIOA
#define PWM_PIN1 GPIO_PIN_8      
#define PWM_PIN2 GPIO_PIN_7 #define TIM1_ARR 5399 //SPWM波相关计算
//sin_points -- 一个周期内中断计算的正弦点数,20KHz载波,Tc = 50us,基波周期 Tb = 50us * sin_points
//Tb = 20Hz = 50ms = 50,000us, sin_points = 1000
//Tb = 100Hz = 10ms = 10,000us , sin_points = 200 //(-sin_k + sin_b ) / TIM1_ARR = spwm_min_duty %
//( sin_k + sin_b ) / TIM1_ARR = spwm_max_duty %,反解出 sin_k, sin_b
// sin_k = TIM1_ARR / 200.0 * (float)(spwm_max_duty - spwm_min_duty )
// sin_b = TIM1_ARR / 200.0 * (float)(spwm_max_duty + spwm_min_duty ) uint8_t spwm_min_duty = ; //SPWM波最小占空比
uint8_t spwm_max_duty = ; //SPWM波最大占空比 uint16_t count = ;
uint16_t sin_points = ;
uint16_t cc1_value; //比较寄存器 1的值,修改改变占空比 float sin_k,sin_b; //TIM1 PWM部分初始化
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM1_PWM_Init(u16 arr,u16 psc)
{
//时钟配置
TIM1_Handler.Instance = TIM1; //定时器3
TIM1_Handler.Init.Prescaler = psc; //定时器分频
TIM1_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//向上计数模式
TIM1_Handler.Init.Period=arr; //自动重装载值
TIM1_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
HAL_TIM_PWM_Init(&TIM1_Handler); //初始化PWM,会调用HAL_TIM_PWM_Init(*) //PWM配置
TIM1_CH1Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1
TIM1_CH1Handler.Pulse=arr/; //设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50%
TIM1_CH1Handler.OCPolarity = TIM_OCPOLARITY_HIGH;//输出比较极性为高
TIM1_CH1Handler.OCNPolarity = TIM_OCPOLARITY_HIGH;
TIM1_CH1Handler.OCIdleState = TIM_OCIDLESTATE_SET;
TIM1_CH1Handler.OCNIdleState = TIM_OCIDLESTATE_SET;
HAL_TIM_PWM_ConfigChannel(&TIM1_Handler,&TIM1_CH1Handler,TIM_CHANNEL_1);//配置TIM1通道1 //死区时间配置
//https://blog.csdn.net/DZRYWYBL/article/details/82527889
BreakDeadTime_Config.OffStateRunMode = TIM_OSSR_DISABLE;
BreakDeadTime_Config.OffStateIDLEMode = TIM_OSSI_DISABLE;
BreakDeadTime_Config.LockLevel = TIM_LOCKLEVEL_OFF;
BreakDeadTime_Config.DeadTime = 0X00; //0x00~0xFF,当设置为0xFF时,50us周期,约有4.68us死区时间;0x0F约有100ns死区时间
BreakDeadTime_Config.BreakState = TIM_BREAK_DISABLE;
BreakDeadTime_Config.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
BreakDeadTime_Config.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
HAL_TIMEx_ConfigBreakDeadTime(&TIM1_Handler, &BreakDeadTime_Config); //中断配置
HAL_NVIC_SetPriority(TIM1_CC_IRQn,,); //设置中断优先级,抢占优先级1,子优先级3
HAL_NVIC_EnableIRQ(TIM1_CC_IRQn); //开启ITM3中断
//开启PWM并使能中断
HAL_TIM_PWM_Start_IT(&TIM1_Handler, TIM_CHANNEL_1); //开启PWM输出并使能中断
HAL_TIMEx_PWMN_Start(&TIM1_Handler, TIM_CHANNEL_1); //打开互补通道
} //定时器底层驱动,时钟使能,引脚配置
//此函数会被HAL_TIM_PWM_Init()调用
//htim:定时器句柄
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_TIM1_CLK_ENABLE(); //使能定时器3
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_Initure.Pin=PWM_PIN1 | PWM_PIN2; //PWM Pin
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用推完输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
GPIO_Initure.Alternate=GPIO_AF1_TIM1; //PA8复用为TIM1_CH1
HAL_GPIO_Init(PWM_GPIO,&GPIO_Initure); } //设置TIM通道4的占空比
//compare:比较值
void TIM_SetTIM1Compare1(u32 compare)
{
TIM1->CCR1=compare;
} //定时器1中断服务函数
void TIM1_CC_IRQHandler(void) //注意名称与通用计时器不同,多了 CC
{
HAL_TIM_IRQHandler(&TIM1_Handler);
} //定时器1中断服务函数调用
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==(&TIM1_Handler))
{
count ++;
if(count == sin_points)
count = ; sin_k = TIM1_ARR / 200.0 * (float)(spwm_max_duty - spwm_min_duty ) ; //正弦波的比例系数,一个简单的数学代换//更正为相减
sin_b = TIM1_ARR / 200.0 * (float)(spwm_max_duty + spwm_min_duty ) ; //正弦波的截距//更正为相加
cc1_value = (uint16_t) (sin_k * sin( (double)count * 6.28318 / (double)sin_points) + sin_b); //正弦值计算,得到SPWM波占空比
TIM_SetTIM1Compare1(cc1_value);
}
}

主函数配置为

TIM1_PWM_Init(-,-);     //216M / (5400 * 2 ) = 20K

最新文章

  1. Android中文TTS
  2. Android 自定义View 三板斧之二——组合现有控件
  3. 工作随笔——CentOS6.4支持rz sz操作
  4. 如何查看mysql版本
  5. Android --Android Stuido 导入jar包
  6. Install .NET Framework 4.5.2 on a Cloud Service Role
  7. vsftp搭配iptables的配置
  8. C++ Template之函数模版
  9. Hibernate中的对象状态,及自动更新原因
  10. 交换a和b
  11. hashCode方法和equals方法比较
  12. Linux修改主机名脚本-不重启-支持RedHat、SUSE
  13. uc/os iii移植到STM32F4---IAR开发环境
  14. 为什么分布式一定要有redis?
  15. Linux下的awk文本分析命令实例(二)
  16. jmeter参数化、添加变量、生成随机数和导入csv文件数据
  17. MySQL参数优化案例
  18. 基于bootstrap的内容折叠功能
  19. 把mysql的数据导出成txt
  20. 集群环境ssh免密码登录设置

热门文章

  1. A1136 | 字符串处理、大整数运算
  2. uniapp登录流程详解uni.login
  3. JavaScript 箭头函数
  4. Windows开机自启动快捷操作
  5. Fluent使用UDF遇见Received signal SIGSEGV
  6. python之turtle使用:画一颗美美哒的树
  7. JVM 最多支持多少个线程?
  8. R3300L运行CoreELEC, EmuELEC和Armbian
  9. C#实体类对应SQL数据库的自增长ID怎么设置?
  10. Oracle的“ORA-00937: 不是单组分组函数” 如何解决?