经过了几天的摸索,下午电机终于转起来了。
从论坛里面找到很多有用的资源和建议,程序也是摸索着写的。
但是论坛里面没有相关的程序,偶尔有几个帖子是相关的,楼主也是发完贴就失踪了
在此,把我的程序和大家分享一下,欢迎提建议。
首先说几点:
1、我是做DTC控制的,做这个旋转磁场只是为了验证一下硬件平台能不能用,所以程序里面没有写SPWM闭环控制算法,是一个纯开环的,但是大家可以在这个基础上写各种闭环算法。
2、我用的是stm32f103的timer1,因为是rct6型号,好像就这一个高级计时器,说一个基本知识,就是只有高级计时器才能产生互补通道,在三相控制驱动电机的时候,每个桥臂的上下桥臂不会同时打开
3、我的IPM模块是IPM100RLA060,是低电平导通的,我之前没做过强电,第一次做,默认是高电平导通,炸了有7、8个保险丝之后才发现了这个问题,等于每次上电都是310v直接短路,那段时间一上电就觉得有东西要炸,好在最后发现了这个问题,之后就一直顺利,我说这个的原因是,因为是低电平导通,所以程序里面的死区我必须用高电平,但是据我的摸索,死区要设置高电平,只能
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCNPolarity=TIM_OCNPolarity_Low;
这样的话,在每次给CCR赋值的时候就不能直接赋sin表里面的值,就需要赋值周期值减去sin表。
具体的困惑写在了这个帖子里,有盆友发现了解决方案的可以留言告诉我,非常感谢
http://www.openedv.com/posts/list/0/51941.htm?privmsg=26154&&sysid=4#296170
因为没有做低通滤波电路,所以,没图,就是直接在逻辑分析仪上看的,看完直接驱动电机很稳定,忘了截逻辑分析仪的图,
但是确实验证过了。
[mw_shl_code=c,true]/*********************************************************************************
*Copyright(C)
*FileName: PWM.c
*Author: 陶涛
*Version: v1.1
*Date: 2015/01/16
*Description: 本程序为stm32的高级计时器timer1生成PWM的API,rct6型号上测试过
*Version:
*Function List:
*History:
<Author> <Date> <Version> <Description>
taotao 2015/05/08 1.0 大部分函数改自原子大哥
taotao 2015/05/09 1.1 添加了SPWM的API,以定时器3作为中断,加载新的CCR,占空比值
*Others:
只有高级计时器可以输出互补波
TIM1模块是增强型的定时器模块,可以产生3组6路PWM,同时每组2路PWM为互补,并可以带有死区,可以用来驱动H桥。
硬件上的引脚连接:
PA8---TIM1_CH1 PB13---TIM1_CH1N
PA9---TIM1_CH2 PB14---TIM1_CH2N
PA10--TIM1_CH3 PB15---TIM1_CH3N
**********************************************************************************/
#include <
WM.h>
#include "GPIO.h " //测试用led灯
//主函数初始化中,需要做delay_init(72);和TIM1_PWM_Init(3600-1,0); //预分频数为0 PWM频率=72000/(3600-1+1)=20Khz 周期3600
//这几个占空比更改参数,需要配合TIM1_PWM_Init中的arr使用
u16 CCR1_Val=1800; //设置TIM1通道1输出占空比50%
u16 CCR2_Val=900; //设置TIM1通道1输出占空比25%
u16 CCR3_Val=450; //设置TIM1通道1输出占空比12.5%
void TIM1_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
//第一步:配置时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); //使能定时器3时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE); //使能GPIO和服用功能时钟
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //引脚重映射要开这个时钟
//第二步,配置gpio口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10; //PWM输出在PA8,9,10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; //PWM输出在PA7
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化GPIO
//第三步,定时器基本配置
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_TimeBaseStructure.TIM_RepetitionCounter=0; //重复寄存器,用于自动更新pwm占空比
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
//第四步pwm输出配置,TIM_OCInitStructure共七项配置
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM2; //设置为pwm1输出模式
/*:PWM模式1-
在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;
在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),
否则为有效电平(OC1REF=1)。
PWM模式2-
在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平;
在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。*/
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low; //设置输出极性//输出极性和互补极性的有效电平为低
//Polarity_Low实际上是往极性控制位写1,所以会输出高电平
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable; //使能该通道输出//比较输出使能
//下面几个参数(除了pulse)是高级定时器才会用到,通用定时器不用配置
TIM_OCInitStructure.TIM_OCNPolarity=TIM_OCNPolarity_Low; //设置互补端输出极性//输出极性和互补极性的有效电平为低
TIM_OCInitStructure.TIM_OutputNState=TIM_OutputNState_Enable; //使能互补端输出
TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Reset; //死区后输出状态
TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCNIdleState_Set; //死区后互补端输出状态
//设置通道1捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_Pulse=CCR1_Val;
TIM_OC1Init(TIM1,&TIM_OCInitStructure); //设置通道1
//设置通道2捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_Pulse=CCR2_Val;
TIM_OC2Init(TIM1,&TIM_OCInitStructure);
//设置通道3捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_Pulse=CCR3_Val;
TIM_OC3Init(TIM1,&TIM_OCInitStructure);
//第五步,死区和刹车功能配置,高级定时器才有的,通用定时器不用配置TIM_BDTRInitStructure,共七项配置
TIM_BDTRInitStructure.TIM_OSSRState=TIM_OSSRState_Disable; //运行模式下输出选择//运行模式下“关闭状态”使能
TIM_BDTRInitStructure.TIM_OSSIState=TIM_OSSIState_Disable; //空闲模式下输出选择//关闭模式下“关闭状态”使能
TIM_BDTRInitStructure.TIM_LOCKLevel=TIM_LOCKLevel_OFF; //锁定设置
TIM_BDTRInitStructure.TIM_DeadTime=0xA0; //死区时间设置
TIM_BDTRInitStructure.TIM_Break=TIM_Break_Disable; //刹车功能不使能
TIM_BDTRInitStructure.TIM_BreakPolarity=TIM_BreakPolarity_High; //刹车输入极性 //刹车输入高电平有效
TIM_BDTRInitStructure.TIM_AutomaticOutput=TIM_AutomaticOutput_Enable; //自动输出使能
TIM_BDTRConfig(TIM1,&TIM_BDTRInitStructure);
//第六步,使能端的打开
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); //使能TIMx在CCR1上的预装载寄存器,这句的功能是让改变CCR之后马上有效 ,立刻改变占空比
TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable); //使能TIMx在CCR2上的预装载寄存器
TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable); //使能TIMx在CCR3上的预装载寄存器,这句的功能是让改变CCR之后马上有效 ,立刻改变占空比
TIM_ARRPreloadConfig(TIM1,ENABLE); //使能TIMx在ARR上的预装载寄存器?//立刻改变频率
TIM_Cmd(TIM1,ENABLE); //打开TIM1
//下面这句是高级定时器才有的,输出pwm必须打开
TIM_CtrlPWMOutputs(TIM1,ENABLE); //pwm输出使能,一定要记得打开
}
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIMx
}
#define Sample_NUM 33 //采样点
unsigned int SinTab[Sample_NUM]={0x0400,0x04C2,0x057C,0x0629,0x06C2,0x0741,0x07A3,0x07E2,0x07FE,0x07F5,
0x07C7,0x0776,0x0705,0x0678,0x05D5,0x0520,0x0461,0x039F,0x02E0,0x022B,
0x0188,0x00FB,0x008A,0x0039,0x000B,0x0002,0x001E,0x005D,0x00BF,0x013E,
0x01D7,0x0284,0x033E};
unsigned char SinTab_i = 0;
//定时器3中断服务程序
void TIM3_IRQHandler(void) //TIM3中断
{
unsigned int SinTab_j,SinTab_k;
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{ TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除TIMx更新中断标志
SinTab_j=SinTab_i+Sample_NUM/3; //200/3 相差120°
SinTab_k=SinTab_i+Sample_NUM*2/3; //400/3 相差240°
SinTab_i++;
if(SinTab_i == Sample_NUM){SinTab_i = 0;}
if(SinTab_j >= Sample_NUM){SinTab_j = SinTab_j-Sample_NUM;}
if(SinTab_k >= Sample_NUM){SinTab_k = SinTab_k-Sample_NUM;}
TIM1->CCR1 = 7200-SinTab[SinTab_i]*2; //配合主函数的 TIM1_PWM_Init(7200-1,6-1); 使用
TIM1->CCR2 = 7200-SinTab[SinTab_j]*2;
TIM1->CCR3 = 7200-SinTab[SinTab_k]*2;
}
}
[/mw_shl_code]
主函数里面只要写
TIM1_PWM_Init(7200-1,6-1);
TIM3_Int_Init(39,719);
初始化就行了,再开中断
程序写的不好,请大家多多指教!共同学习!
sin表的数据是用论坛里面下的一个软件生成的,也可以自己算。
为了方便大家,我把这个软件再传一下,原帖我一下找不到了,在这里也感谢原作者
---------------------------------
恩,不用的,可以相当于初始化一下,其实是之前调试用的
---------------------------------
具体计算我忘了,有个公式
死区就是上下桥臂同时关断啊,是给0还是给1,看你的IPM模块的要求了
你也是要做这个的吗 我有改好的程序 可否与你交流下
一周热门 更多>