在开始之前我们要懂得占空比和频率的计算公式是怎样的?即:
频率=(预装载值+1)*(分频系数+1)/72MHZ
占空比= TIMx->CCR/(预装载值为+1)
这个分析完了,我们再把视线拉倒主板上看看其硬件连接pwm是搭载在哪一个GPIO上。在省赛中大多的pwm的配置都是用到PA6和PA7的这两个引脚。在数据手册上。
这里我们知道PA6和PA7用到了定时器3的通道1和通道2。
这些知道了我们就可以开始配置函数了。
首先看看几个重要的函数。
RCC_APB2PeriphClockCmd();//配置时钟
GPIO_Init(); //IO初始化
TIM_TimeBaseInit(); //定时器初始化
TIM_OC1Init(); //定时器通道1
TIM_OC2PreloadConfig(); //使能预装载寄存器
TIM_Cmd(); //使能定时器。
TIM_SetCompare1(); //调节占空比
这里配置两路pwm频率固定,占空比可调。
void pwm_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
TIM_TimeBaseInitStruct.TIM_Period = 999; //预装载值
TIM_TimeBaseInitStruct.TIM_Prescaler =71; //分频系数
TIM_TimeBaseInitStruct.TIM_ClockDivision = 0;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2; //pwm2模式
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//比较输出
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStruct);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2; //pwm2模式
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//比较输出
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM3, &TIM_OCInitStruct);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_Cmd(TIM3, ENABLE);
}
可以看到我们这里配置的预装载值=999,分频系数=71。那么我们的频率为:(999+1)*(71+1)/72000000=1khz
我们在看看如何改变通道的占空比。即:
u16 ch1=100;
u16 ch2=200;
int main(void)
{
pwm_init();
while(1)
{
TIM_SetCompare2(TIM3,ch2);
TIM_SetCompare1(TIM3,ch1);
}
}
这里可以看到初始化的PA6占空比为0.1,PA7占空比为0.2。这里的ch1和ch2可以通过按键进行加减来对占空比的调节。
在来看看如何快速的配置这个模式。快速的配置就要用到比赛时官方给的固件库v3.5。
打开里面的这个路径:6-STM32固件库代码V3.5版\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\TIM\PWM_Output。找到main函数打开
这里两路的PWM配置就完成了。但是里面的有一部分还是要修改的。
●在使用APB2的时钟的时候我们只用到了GPIOA其他没有用到。多余的删除。
●在使用定时器初始化的时候要把预装载的值和分频系数的值修改。
●结构体TIM_Pulse的值可以不用设置。
这种模式与上一种模式的方法配置大致相同。定时器及PWM波的配置程序基本上没什么变化。主要就是使用到了中断服务函数和,输出模式的变化。即:
#include "pwm.h"
u16 CR2_val=10000; //100hz 72MHZ/72/10000=100HZ
u16 CR1_val=5000; //200hz 72MHZ/72/5000=200HZ
float ch1=0.1; //通道1占空比
float ch2=0.1;
u16 cata;
_Bool pa6=0; //标志位
_Bool pa7=0;
void pwm_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
TIM_TimeBaseInitStruct.TIM_ClockDivision=0;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period=65535; //65536-1
TIM_TimeBaseInitStruct.TIM_Prescaler=71;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
NVIC_InitStruct.NVIC_IRQChannel=TIM3_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
NVIC_Init(&NVIC_InitStruct);
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_Toggle; //比较翻转
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_Pulse=CR1_val;
TIM_OC1Init(TIM3,&TIM_OCInitStruct);
TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Disable);
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_Toggle;
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_Pulse=CR2_val;
TIM_OC2Init(TIM3,&TIM_OCInitStruct);
TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Disable);
TIM_Cmd(TIM3,ENABLE);
TIM_ITConfig(TIM3,TIM_IT_CC1|TIM_IT_CC2,ENABLE);
}
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_CC1)!=RESET)
{
TIM_ClearITPendingBit(TIM3,TIM_IT_CC1);
cata=TIM_GetCapture1(TIM3); //获取当前计数器的值
if(pa6==0)
{
TIM_SetCompare1(TIM3,cata+(u16)(CR1_val*ch1));
pa6=1;
}
if(pa6==1)
{
TIM_SetCompare1(TIM3,cata+(u16)(CR1_val*(1-ch1)));
pa6=0;
}
}
if(TIM_GetITStatus(TIM3,TIM_IT_CC2)!=RESET)
{
TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);
cata=TIM_GetCapture2(TIM3);
if(pa7==0)
{
TIM_SetCompare2(TIM3,cata+(u16)(CR2_val*ch2));
pa7=1;
}
if(pa7==1)
{
TIM_SetCompare2(TIM3,cata+(u16)(CR2_val*(1-ch2)));
pa7=0;
}
}
}
在来看看如何快速配置。还是老样子利用到固件库V3.5。
打开路径:STM32固件库代码V3.5版\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\TIM\OCToggle。的main函数
这样就把初始化配置完成了。但是还是有部分要修改的。例如:
时钟的配置、分频系数为71。使用的通道为1、2多余的去掉。
接下来就是服务函数的配置。在相同路径下的stm32f10x_it.c 文件上
这里稍微修改加上标志位进行处理就可以使用了。
在对于频率和占空比的调节。主要也还是
u16 CR2_val=10000; //100hz 72MHZ/72/10000=100HZ
u16 CR1_val=5000; //200hz 72MHZ/72/5000=200HZ
float ch1=0.1; //通道1占空比
float ch2=0.1;
这几个参数的改变来进行控制。
extern float ch,ch;
extern u16 CR2_val,CR1_val;
u16 pinlv1 = 100,pinlv2 =200;//注意pinlv1和pinlv2的值必须分别初始化为72000000/72/CR1_Val和72000000/72/CR2_Val
extern float ch,ch;
extern u16 CR2_val,CR1_val;
u16 pinlv1 = 100,pinlv2 =200;//注意pinlv1和pinlv2的值必须分别初始化为72000000/72/CR1_Val和72000000/72/CR2_Val
unsigned char key_val;
int main(void)
{
pwm_init();
key_init();
while(1)
{
key_val=key_scanf();
if(key_val==1) //第一个按键按下
{
pinlv1 += 100;//pinlv1增加,意味着CR1_Val减小,CCR1_Val减小意味着频率增大,即增加PWM频率,+100表示频率每次增加100Hz
CR1_val = (u16)(72000000/72/pinlv1);
}
if(key_val==2) //第2个按键按下
{
pinlv1 -= 100;//pinlv1减小,意味着CR1_Val增大,CCR1_Val增大意味着频率减小,即减小PWM频率,-100表示频率每次减小100Hz
CR1_val = (u16)(72000000/72/pinlv1);
}
if(key_val==3) //第3个按键按下
{
ch1+=0.1; //通道1占空比+10%
}
if(key_val==4) //第4个按键按下
{
ch1-=0.1; //通道1占空比-10%
}
}
}