前言
本文记录了如何用stm32f103c8t6的高级定时器来生成互补的spwm波且带死区。频率为20khz,经过10uf电容滤波得到50hz正弦波。废话不多说直接上代码。
一、代码
1.1 高级定时器TIM1
PWM.c
#include "stm32f10x.h"
#include "PWM.h"
#include "spwm.h"
void PWM_Init(void)
{
GPIO_InitTypeDef GPIOInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); /*使能GPIOA,GPIOB时钟*/
GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIOInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIOInitStruct.GPIO_Pin = GPIO_Pin_8; /*PA8:CH1*/
GPIO_Init(GPIOA, &GPIOInitStruct);
GPIOInitStruct.GPIO_Pin = GPIO_Pin_13; /*PB13:CH1N*/
GPIO_Init(GPIOB, &GPIOInitStruct);
GPIOInitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIOInitStruct.GPIO_Pin = GPIO_Pin_12; /*PB12:BKIN*/
GPIO_Init(GPIOB, &GPIOInitStruct);
GPIO_SetBits(GPIOB, GPIO_Pin_12); /*设置PB12*/
TIM_TimeBaseInitTypeDef TIMTimeBaseStruct;
TIM_OCInitTypeDef TIMOCInitStruct;
TIM_BDTRInitTypeDef TIMBDTRInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); /*使能TIM1时钟*/
/*时基结构体配置*/
TIMTimeBaseStruct.TIM_Period = MAXNUM - 1; /*从0开始 一个信号周期计数400次*/
TIMTimeBaseStruct.TIM_Prescaler = 9 - 1;
TIMTimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1; /*时钟分频因子 = 1,tDTS=tCKINT*/
TIMTimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up; /*向上计数*/
TIMTimeBaseStruct.TIM_RepetitionCounter = 0; /*禁用重复计数器*/
TIM_TimeBaseInit(TIM1, &TIMTimeBaseStruct);
/*输出比较结构体配置*/
TIMOCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; /*PWM1模式*/
TIMOCInitStruct.TIM_OutputState = TIM_OutputState_Enable; /*输出使能*/
TIMOCInitStruct.TIM_OutputNState = TIM_OutputNState_Enable; /*互补输出使能*/
TIMOCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; /*输出有效电平为高电平*/
TIMOCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High; /*互补输出有效电平为高电平*/
TIMOCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set; /*输出空闲时为高电平*/
TIMOCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Reset; /*互补输出空闲时为低电平*/
/*初始化TIM1的通道1*/
TIMOCInitStruct.TIM_Pulse = 25- 1; /*占空比 = 250 / 1000 = 25%*/
TIM_OC1Init(TIM1,&TIMOCInitStruct);
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); /*开启预装载,在更新时间后才会重新装载数值*/
/*刹车和死区结构体配置*/
TIMBDTRInitStruct.TIM_OSSRState = TIM_OSSRState_Enable; /*运行模式下“关闭模式”选择 = 1*/
TIMBDTRInitStruct.TIM_OSSIState = TIM_OSSIState_Enable; /*空闲模式下“关闭模式”选择 = 1*/
TIMBDTRInitStruct.TIM_LOCKLevel = TIM_LOCKLevel_1; /*锁定级别1,见参考手册*/
TIMBDTRInitStruct.TIM_DeadTime = 0x40; /*死区时间:0x40大概为0.9us*/
TIMBDTRInitStruct.TIM_Break = TIM_Break_Enable; /*开启刹车功能*/
TIMBDTRInitStruct.TIM_BreakPolarity = TIM_BreakPolarity_Low; /*刹车输入低电平有效,如果引脚检测到高电平则会停止PWM的输出,不会产生任何波形*/
TIMBDTRInitStruct.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; /*开启自动输出*/
TIM_BDTRConfig(TIM1, &TIMBDTRInitStruct);
TIM_Cmd(TIM1, ENABLE); /*使能定时器,计数器开始计数*/
TIM_CtrlPWMOutputs(TIM1, ENABLE); /*开启主输出*/
}
void PWM_SetCompare1(uint16_t Compare1)//通道一
{
TIM_SetCompare1(TIM1,Compare1);//0~ARR
}
1.2生成正弦波表格
spwm.c
#include "stm32f10x.h"
#include "spwm.h"
#include "math.h"
uint16_t sinData[400];
float Am=0.85;//调制深度
//point 一个周期内的点数
//maxnum 最大值
void get_sin_tab1( uint16_t point, uint16_t maxnum )
{
uint16_t i = 0, j = 0, k = 0;
float hd = 0.0; //弧度
float fz = 0.0; //峰值
uint16_t tem = 0;
j = point / 2; //水平线位置 单片机没有负电压
hd = PI / j; // π/2 内每一个点对应的弧度值
k = maxnum / 2; //最大值一半
for( i = 0; i < point; i++ )
{
fz = k * sin( hd * i )+200;
tem = ( uint16_t )fz ;
sinData = tem;
}
}
spwm.h
#ifndef _SPWM_H
#define _SPWM_H
#define PI 3.1415926f
#define MAXNUM 400//占空比最大值
extern float Am;
extern uint16_t sinData[400];
void get_sin_tab1(uint16_t point,uint16_t maxnum);
#endif
1.3定时中断
50us一次定时中断
#include "stm32f10x.h" // Device header
void Timer_Init(void)
{
//定时器定时中断和外部时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//第一步使能APB1外设,因为TIM2在APB1
TIM_InternalClockConfig(TIM3);//第二步使用内部时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;//第三步时基单元初始化
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStruct.TIM_Period=100-1;//周期,ARR重装计数器的值,取值0~65535
TIM_TimeBaseInitStruct.TIM_Prescaler=36-1;//PSC预分频器的值,因为预分频器和计数器都有一个数的偏差,所以-1
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//重复计数器的值,高级计数器才有
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
TIM_ClearFlag(TIM3,TIM_FLAG_Update);//手动清除中断标志位,因为库函数会自动更新事件
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//第四步使能中断,TIM_IT_Update更新中断通道
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//第五步配置NVIC//分组
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=TIM3_IRQn;//设置中断通道
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;//配置中断优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStruct);
TIM_Cmd(TIM3,ENABLE);//第六步启动定时器
}
二、主函数部分
#include "stm32f10x.h"
#include "PWM.h"
#include "spwm.h"
#include "Timer.h"
int main(void)
{
PWM_Init();
Timer_Init();
get_sin_tab1(400,MAXNUM);
while(1)
{
}
}
void TIM3_IRQHandler(void)
{
static unsigned int i=0;
uint16_t temp=0;
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)
{
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
i++;
if(i==MAXNUM){i=0;}
temp=Am*sinData+(MAXNUM/2-MAXNUM/2*Am);
PWM_SetCompare1(temp);
}
}
三、波形效果
通过测量得到死区时间为0.9us,图中Xa-Xb为900ns。
四、加电容滤波后的波形
可以看到是相位差180°的两个50hz正弦波。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/m0_68747151/article/details/135140184
|