用的是野火的例程
main函数:
#define CLI() __set_PRIMASK(1)
#define SEI() __set_PRIMASK(0)
int main(void)
{
CLI();
SEI();
TIM34_PWM_Init();
while (1)
{
}
}
bsp_pwm_output.c用户文件
void TIM3_PWM_Init(void)
{
TIM34_GPIO_Config();
TIM34_Mode_Config();
}
static void TIM34_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3|RCC_APB1Periph_TIM4|RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
其中,引脚PA6和PA7的复用功能就是TIM3的CH1通道,和CH2通道。所以要开启复用时钟。同时要注意,定时器的时钟不是直接来自APB1或APB2,而是来自于输入为APB1或APB2的一个倍频器。使用任何一个外设都必须打开相应的时钟。这样的好处就是,如果不使用一个外设的时候,就把它的时钟关掉,从而可以降低系统的功耗,达到节能,实现低功耗的效果。具体见http://blog.csdn.net/yx_l128125/article/details/7879506,这里TIM3,4为APB1的2倍频后,时钟为72MHZ。
static void TIM34_Mode_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
NVIC_Configuration();
TIM_TimeBaseStructure.TIM_Period = 7199;//产生的spwm波的周期为T=1*7200/72M=100us(10KHz)
TIM_TimeBaseStructure.TIM_Prescaler = 0;//设置预分频:不预分频,即为72MHz
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//设置时钟分频系数:不分频(这里用不到)
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;//不懂什么意思
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);//初始化定时器3的基础数据
TIM_DeInit(TIM4); //复位TIM4定时器,使之进入初始状态 其功能为复位外设PPP的所有寄存器至缺省值
TIM_TimeBaseStructure.TIM_Period=1; //自动装载寄存器的值
TIM_TimeBaseStructure.TIM_Prescaler= 3599; //时钟预分频数 使TIM4_CLK=20KHz
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;//采样分频:TIM4每次定时的时间T=2*3600/72M=100us
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);//初始化定时器4的基础数据
TIM_ClearFlag(TIM4, TIM_FLAG_Update); //清除中断位
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); //允许TIM4中断
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//配置为PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;// 开启oc*输出到对应引脚
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;//互补输出使能
TIM_OCInitStructure.TIM_Pulse =50* 7200 / 100;//占空比为50%
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//当定时器计数值小于CCR1_Val时为高电平(极性为正)
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //使能TIM3的通道1和通道2
TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
TIM_BDTRInitStructure.TIM_DeadTime = 12;
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
TIM_BDTRConfig(TIM3, &TIM_BDTRInitStructure);
TIM_CtrlPWMOutputs(TIM3, ENABLE); //开启定时器3的PWM模式
TIM_Cmd(TIM3, ENABLE); //使能定时器3
TIM_Cmd(TIM4, ENABLE); //使能定时器3
}
中断的初始化函数
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
stm32f10x_it.c 中断路径处理
void TIM4_IRQHandler(void)·
{
static vu16 sign = 0;
static vu16 Counter_sine=0;
static vu16 Duty_Cycle_sinewavetable[128]={
0x0,0x83,0x105,0x187,0x209,
0x28A,0x30A,0x38A,0x409,0x486,
0x502,0x57D,0x5F7,0x66F,0x6E5,
0x75A,0x7CC,0x83D,0x8AB,0x917,
0x981,0x9E8,0xA4D,0xAAF,0xB0E,
0xB6B,0xBC4,0xC1B,0xC6E,0xCBE,
0xD0B,0xD54,0xD9A,0xDDD,0xE1C,
0xE57,0xE8F,0xEC3,0xEF3,0xF1F,
0xF48,0xF6C,0xF8D,0xFA9,0xFC2,
0xFD6,0xFE6,0xFF3,0xFFB,0xFFF,
0xFFF,0xFFB,0xFF3,0xFE6,0xFD6,
0xFC2,0xFA9,0xF8D,0xF6C,0xF48,
0xF1F,0xEF3,0xEC3,0xE8F,0xE57,
0xE1C,0xDDD,0xD9A,0xD54,0xD0B,
0xCBE,0xC6E,0xC1B,0xBC4,0xB6B,
0xB0E,0xAAF,0xA4D,0x9E8,0x981,
0x917,0x8AB,0x83D,0x7CC,0x75A,
0x6E5,0x66F,0x5F7,0x57D,0x502,
0x486,0x409,0x38A,0x30A,0x28A,
0x209,0x187,0x105,0x83,0x0};
if ( TIM_GetITStatus(TIM4 , TIM_IT_Update) == SET)
{
if(sign == 0)
{
TIM_SetCompare1(TIM3,Duty_Cycle_sinewavetable[Counter_sine]);
TIM_SetCompare2(TIM3,0);
Counter_sine++;
if(Counter_sine==100) //
{
Counter_sine=0;
sign = 1;
}
}else{
TIM_SetCompare1(TIM3,0);
TIM_SetCompare2(TIM3,Duty_Cycle_sinewavetable[Counter_sine]);
Counter_sine++;
if(Counter_sine==100)
{
Counter_sine=0;
sign = 0;
}
}
}
TIM_ClearITPendingBit(TIM4 , TIM_FLAG_Update);
}
spwm波产生的原理就是,按正弦规律改变pwm的波的占空比,滤出的基波的频率是改变占空比的频率。
TIM4计时溢出中断,每中断一次,在中断函数中,改变TIM3的比较寄存器的值,即修改占空比。
TIM4_CLK的中断频率是10Khz,又半个周期采样100个点,即半个周期要改100次占空比,也即1个周期改200次占空比,所以改变占空比的频率是10KHZ/200=50hz。基波频率为50hz。注意这个表示只有半个周期的。
还有就是,为什么表里有128个点,但是半个周期采样100个,当然这样周期是可以保证50hz,但如果我把100改为127,周期是按照预想的所变化了,即(10KHZ/256=39.0HZ)但是波形确无法完美互补。。如图:
接下来上双极性的spwm:
中断函数修改了其中的数组
void TIM4_IRQHandler(void)
{
static vu16 sign = 0;
static vu16 Counter_sine=0;
static vu16 Duty_Cycle_sinewavetable[128]={
3783,3952,4150,4320,4489,4658,4828,4997,5138,5308,
5449,5618,5760,5901,6014,6155,6268,6381,6494,6607,
6691,6776,6861,6917,7002,7058,7087,7143,7171,7171,
7200,7200,7200,7171,7171,7143,7087,7058,7002,6917,
6861,6776,6691,6607,6494,6381,6268,6155,6014,5901,
5760,5618,5449,5308,5138,4997,4828,4658,4489,4320,
4150,3952,3783,3614,3444,3275,3077,2908,2738,2569,
2400,2230,2089,1920,1778,1609,1468,1327,1214,1072,
960,847,734,621,536,451,367,310,225,169,141,84,56,56,
28,28,28,56,56,84,141,169,225,310,367,451,536,621,734,
847,960,1072,1214,1327,1468,1609,1778,1920,2089,2230,
2400,2569,2738,2908,3077,3275,3444,3614
};
if ( TIM_GetITStatus(TIM4 , TIM_IT_Update) == SET)
{
TIM_SetCompare1(TIM3,Duty_Cycle_sinewavetable[Counter_sine]);
Counter_sine++;
if(Counter_sine==128) //?????100??
{
Counter_sine=0;
}
}
TIM_ClearITPendingBit(TIM4 , TIM_FLAG_Update);
}
注意这个数组是完整的正弦波了;关于数字的取得也想分享一下,作为菜鸟表示研究了好久。
因为自动装载值是7200,所以要以7200作为参考,如3600就是占空比为50%,然后用excel做表。大家不要笑话我哈,网上有正弦波生成表,用于单片机产生正弦波的,一般以256为最大比列,然后我就把生成的值除以256乘以7200得到上述数组。
注意,想要得到50hz的正弦波,就要使中断频率为50Hz*128=6400hz,根据公式反推 TIM_TimeBaseStructure.TIM_Period,TIM_TimeBaseStructure.TIM_Prescaler的值,也就是72M/(TIM_Period+1)*(TIM_Prescaler+1)=6400,
我就取
TIM_TimeBaseStructure.TIM_Period=4;
TIM_TimeBaseStructure.TIM_Prescaler= 2249;