目标:
1.通过按键1切换pwm频率的切换。
2.通过按键2实现pwm占空比的切换。
3.备注:不附加硬件原理图,但是通过描述简单介绍引脚的连接。
硬件原理描述:
1.通过3个IO口实现16个按键的检测。
2.按键1,按键2不多做描述,通过键盘扫描程序循环检测按键
3.通过TIM2 CHI通道PA0输出波形。
pwm输出配置功能函数:
#include "pwm.h"
static u16 Tim_Prescaler=35; //配置TIM默认时钟分频
static u16 TIMCompare1=200; //配置TIM默认脉冲比较值
void GPIO_cfg() //配置pwm输出相关引脚
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA的时钟
//RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //复用时钟不需要失能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //选择引脚0
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出频率最大50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void TIMER_cfg(void)//配置TIM2
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟
//设置预分频系数
TIM_TimeBaseStructure.TIM_Prescaler =Tim_Prescaler;
//设置计数自动重装值大小
TIM_TimeBaseStructure.TIM_Period = 1000;
//设置计数器模式为向上
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
//设置时钟分割---不分割
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//将配置应用到TIM2中
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
}
void PWM_cfg(void)//配置pwm输出
{
TIM_OCInitTypeDef TimOCInitStructure;
//TIM_OCStructInit(&TimOCInitStructure);
//PWM模式1输出
TimOCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
//设置占空比0.2
TimOCInitStructure.TIM_Pulse = 200;
//TIM输出比较极性高
TimOCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
//使能输出状态
TimOCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
//TIM2的CH1输出
TIM_OC1Init(TIM2, & TimOCInitStructure);
//设置TIM2的PWM输出为使能
//TIM_CtrlPWMOutputs(TIM2,ENABLE); //高级定时器专用,TIM2不需要此函数功能
//使能或者失能TIM2在CCR1上的预装载寄存器 使能:在更新事件发生时才会传送预装载值(从CCR1到影子寄存器);失能:直接传送预装载值
//TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
//使能或者失能 TIMx 自动重装载寄存器·
//TIM_ARRPreloadConfig(TIM2, ENABLE);
}
//pwm输出初始化,默认输出方波频率=2Khz,占空比=0.2
void PWM_Init(void)
{
GPIO_cfg();
TIMER_cfg();
PWM_cfg();
TIM_Cmd(TIM2,ENABLE);
}
void PWM_changefre(void) //频率转换:2Khz 200hz
{
if(Tim_Prescaler==359)
{
Tim_Prescaler=35;
}
else
{
Tim_Prescaler=359;
}
TIM_PrescalerConfig(TIM2, Tim_Prescaler,TIM_PSCReloadMode_Update);//设置 TIM2 预分频,即时或者下次更新作用
}
//更改占空比,默认0.2,0.4,0.6,0.8,0.2依次循环
void PWM_changeduty(void)
{
if(TIMCompare1<800)
{
TIMCompare1+=200;
}
else
TIMCompare1=200;
TIM_SetCompare1(TIM2, TIMCompare1);//设置 TIMx 捕获比较 1 寄存器值
}
主函数:
#include "public.h"
static u8 key=0x10;
int main(void)
{
SystemInit(); //init system rcc HSE 72Mhz
power_init(); //open power sourse
delay_init(72); //system clock frequency 72Mhz
KEY_Init();
PWM_Init();
while(1)
{
key=KEY_Scan();
if(key==0) //修改定时器预分频值,完成pwm频率切换。200HZ--------2KHZ
{
key=0xff;
delay_ms(100);
PWM_changefre();
}
if(key==2) //修改占空比
{
key=0xff;
delay_ms(100);
PWM_changeduty();
}
}
}
总结:
1.配置pwm输出的一般性步骤:
1.配置pwm输出相应的GPIO口。
2.配置pwm输出相应的定时器。
3.配置pwm输出相应的输出通道。
2.几个要点的理解:
1.涉及到IO口重映射问题
2.AFIO时钟问题
对寄存器 AFIO_EVCR、AFIO_MAPR 和 AFIO_EXTICRX 进行读写操作前,应当首先打开 AFIO 的时钟。
上句话是从stm32中文参考手册找到的。
也就是说配置AFIO的事件控制寄存器(AFIO_EVCR)、复用重映射和调试I/O 配置寄存器(AFIO_MAPR)、外部中断配置寄存器 1(AFIO_EXTICR1)等才需要启用AFIO时钟。
并不是说引脚复用时就必须开启AFIO时钟。所以,在上述程序中,不需要开启AFIO 时钟(已经验证OK)。
3.计数器(TIMx_CNT)
这个寄存器是用来计数的,数数用的
4.自动重装载寄存器 和(影子寄存器)--->实际的自动重装载寄存器
a.自动重装载寄存器存储的是TIM计数值的大小,计数器到了这个值就会发生溢出停止计数,但并是用该寄存器直接和计数器比较。
b.真正用来和计数器比较的是影子寄存器(物理存在的),自动重装载寄存器的值送到了这里。
c.这两个寄存器是联通的。
d.什么时候把自动重装载寄存器值送到影子寄存器?
先来看一下下面这个函数:它的作用是使能或者失能 TIMx 在 ARR 上的预装载寄存器(自动重装载寄存器)。
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState Newstate)
失能=0:TIMx_ARR寄存器没有缓冲;
使能=1:TIMx_ARR寄存器被装入缓冲器。
答案:通过配置TIMx_CR1的ARPE位,决定什么时候把自动重装载寄存器值送到影子寄存器。
5.捕获/ 比较寄存器(输出模式下)
该寄存器的值决定pwm输出时的占空比。计数器会根据这个值的大小来判断何时翻转电平。比如:计数值100,,比较值50,则占空比就为50%
同样的,该寄存器也有相应的影子寄存器。功能同上。
6.转换频率:
首先要理解定时器是怎么完成频率输出:
a.系统频率设置为72Mhz 设为X频率
b.初始化定时器时,配置时钟分割X/(时钟分割+1)
c.初始化定时器时,预分频。X/(时钟分割+1)/(预分频系数+1)
d.得到定时器的时钟输入频率。
e.设置自动重装载寄存器(计数值),得到定时器的频率输出 X/(时钟分割+1)/(预分频系数+1)/计数值
其次,判断可更改的变量来改变频率输出。
本次试验选取更改预分频系数,作为控制变量。
7.转换占空比
duty=TIM2_CCR1/TIM2_ARR
本次试验选择改变TIM2_CCR1。
3.心得:
1.参考了网上一些pwm案例,觉得有些案例实现起来,调用了一些不需要的函数,效率下降。
2.本次学习仅仅总结了PWM输出的用法,对定时器的其他功能认知仍存在大量不足。
3.第一次,写这么长的总结,很有成就感。
上一篇:STM32 TIM1输出互补波形
下一篇:STM32 PWM的输出与Keil软件仿真
推荐阅读最新更新时间:2024-03-16 16:07