一、实验目的
1. 深入了解STM32定时器结构和工作原理;
2. 掌握定时器PWM功能的配置方法;
3. 掌握定时器常用的固件函数和使用方法;
4. 掌握PWM应用程序的编写方法。
二、实验内容
使用库函数开发模版编写编写PWM应用程序,使用TIM13的CH1通道输出PWM控制LED灯D1的明暗程度或蜂鸣器声音的大小。
三、实验设备仪器和材料
硬件:STM32开发板, PC 机;
软件:MDK5集成开发环境,Windows 操作系统;
四、实验原理和接线
1. PWM简介
STM32F4除了基本定时器TIM6和TIM7,其他定时器都可以产生PWM输出。其中高级定时器TIM1 和TIM8 可以同时产生多达7路的PWM输出。而通用定时器也能同时产生多达4路的PWM 输出(TIM9-TIM14最多能产生2路)。
PWM的输出其实就是对外输出脉宽可调(即占空比调节)的方波信号,信号频率是由自动重装寄存器ARR的值决定,占空比由比较寄存器CCR的值决定。
PWM常见有两种输出模式:PWM1和PWM2,这两种模式的区别是输出电平的极性不同。
模式 | 计数器CNT计数方式 | 说明 |
---|---|---|
PWM1 | 递增 | CNT<CCR,通道CH输出高电平 |
PWM1 | 递减 | CNT>=CCR,通道CH输出低电平 |
PWM2 | 递增 | CNT<CCR,通道CH输出低电平 |
PWM2 | 递减 | CNT>=CCR,通道CH输出高电平 |
2. PWM—边沿对齐模式
当TIMx_CR1 寄存器中的DIR位为低时执行递增计数,计数器CNT 从0计数到自动重载值(TIMx_ARR寄存器的内容),然后重新从0开始计数并生成计数器上溢事件。
以PWM模式1为例。只要TIMx_CNT < TIMx_CCRx,PWM参考信号OCxREF便为高电平,否则为低电平。如果TIMx_CCRx中的比较值大于自动重载值(TIMx_ARR中),则OCxREF保持为“1”。如果比较值为0,则OCxREF保持为“0”。
当TIMx_CR1寄存器中的DIR位为高时执行递减计数,计数器CNT从自动重载值(TIMx_ARR寄存器的内容)递减计数到0,然后重新从TIMx_ARR值开始计数并生成计数器下溢事件。
以PWM模式1为例。只要TIMx_CNT >TIMx_CCRx,PWM参考信号OCxREF便为低电平,否则为高电平。如果TIMx_CCRx中的比较值大于自动重载值(TIMx_ARR 中),则OCxREF保持为“1”。此模式下不能产生0%的PWM波形。
3. PWM—中心对齐模式
在中心对齐模式下,计数器CNT是工作做递增/递减模式下。开始的时候,计数器CNT从О开始计数到自动重载值减1(ARR-1),生成计数器上溢事件;然后从自动重载值开始向下计数到1并生成计数器下溢事件。之后从0开始重新计数。
以ARR=8,CCRx=4为例。第一阶段计数器CNT工作在递增计数方式,从0开始计数,当TIMx_CNT< TIMx_CCRx 时,PWM参考信号OCxREF为高电平,当TIMx_CNT >= TIMx_CCRx 时,PWM参考信号OCxREF为低电平。第二阶段计数器CNT工作在递减计数方式,从ARR开始递减计数,当TIMx_CNT >TIMx_CCRx时,PWM参考信号OCxREF为低电平,当TIMx_CNT <= TIMx_CCRx 时,PWM参考信号OCxREF为高电平。
中心对齐模式又分为中心对齐模式1/2/3三种,具体由寄存器CR1位CMS[1:0]配置。具体的区别就是比较中断标志位CCxIF在何时置1:中心模式1在CNT递减计数的时候置1,中心对齐模式2在CNT递增计数时置1,中心模式3在CNT递增和递减计数时都置1。
五、实验操作步骤
1. 编写led.c文件
#include "led.h"
void LED_Init()
{
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量,该语句的作用是将GPIO_InitTypeDef结构体命名为GPIO_InitStructure
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE); //使能端口F时钟,
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;//设置输出模式
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10;//管脚设置为F9和F10
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//IO口速度为100M
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOF,&GPIO_InitStructure); //初始化结构体,初始化PF口
GPIO_SetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10);//输出高电平
}
2. 编写beep.c文件
beep.c文件用于进行蜂鸣器的初始化
#include "beep.h"
void BEEP_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE); //使能端口F时钟
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式
GPIO_InitStructure.GPIO_Pin=BEEP_Pin;//管脚设置F8
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉
GPIO_Init(BEEP_Port,&GPIO_InitStructure); //初始化结构体
GPIO_SetBits(BEEP_Port,BEEP_Pin); //关闭蜂鸣器
}
3. 编写pwm.c文件
操作步骤和思路:
(1)使能定时器及端口时钟,并设置引脚复用映射
使用TIM13的通道CH1输出PWM信号,所以使能TIM13时钟,将引脚设置为复用模式,调用库函数:RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM13,ENABLE) GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF
(2)初始化定时器参数,包含自动重装值,分频系数,计数方式
(3)初始化PWM输出参数,包括PWM模式、输出极性、使能
配置TIM13的CH1为PWM1模式,输出极性为低电平,并且使能PWM输出
(4)开启定时器,调用TIM_Cmd(TIM13,ENABLE)函数
#include "pwm.h"
void TIM13_CH1_PWM_Init(u16 per,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM13,ENABLE);//使能TIM13时钟
GPIO_PinAFConfig(GPIOF,GPIO_PinSource8,GPIO_AF_TIM13);//管脚复用
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //复用输出模式
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;//管脚设置
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOF,&GPIO_InitStructure); //初始化结构体
TIM_TimeBaseInitStructure.TIM_Period=per; //自动装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
TIM_TimeBaseInit(TIM13,&TIM_TimeBaseInitStructure);
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OC1Init(TIM13,&TIM_OCInitStructure); //输出比较通道1初始化
TIM_OC1PreloadConfig(TIM13,TIM_OCPreload_Enable); //使能TIMx在CCR1上的预装载寄存器
TIM_ARRPreloadConfig(TIM13,ENABLE);//使能预装载寄存器
TIM_Cmd(TIM13,ENABLE); //使能定时器
}
4. 编写main.c文件
操作步骤和思路:
(1)首先初始化对应的硬件端口始终和IO口
(2)调用TIM13_CH1_PWM_Init函数,设定定时器自动重装载值为500-1,预分频系数为84-1,定时周期为500us,即频率1KHz
(3)通过变量fx控制i的方向,如果fx=0,i值累加,否则递减,将这个变化的i值传递给改变占空比TIM_SetComparel函数,因此可以控制蜂鸣器声音的强弱。
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "beep.h"
#include "pwm.h"
int main()
{
u16 i;
u8 fx=0;
SysTick_Init(168);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组
//LED_Init();
BEEP_Init();
TIM13_CH1_PWM_Init(500-1,84-1); //频率是2kh
while(1)
{
if(fx==0)
{
i++;
if(i==300)
{
fx=1;
}
}
else
{
i--;
if(i==0)
{
fx=0;
}
}
TIM_SetCompare1(TIM13,i); //i值最大可以取499,因为ARR最大值是499
delay_ms(10);
}
}
六、实验结果
本次实验使用库函数开发模板编写PWM应用程序,使用TIM13的CH1通道输出PWM控制蜂鸣器声音的大小,可以听到蜂鸣器声音由小变大再逐渐变小,循环发声。
总结:
PWM的基本原理就是对逆变电路开关器件的通断进行控制,使输出端得到一系列幅值相等的脉冲,用这些脉冲来代替正弦波或所需要的波形,也就是在输出波形的半个周期中产生多个脉冲,使各脉冲的等值电压为正弦波形,所获得的输出平滑且低次谐波少,按一定的规则对各脉冲的宽度进行调制,既可改变逆变电路输出电压的大小,也可改变输出频率。通过使用TIM13的CH1通道控制蜂鸣器的PWM输出,可以得到逐渐递增再递减的声音,实现渐变过程。