第十四章 PWM输出实验
[mw_shl_code=c,true]
1.硬件平台:正点原子探索者STM32F407开发板
2.软件平台:MDK5.1
3.固件库版本:V1.4.0
[/mw_shl_code]
上一章,我们介绍了
STM32F4的通用定时器
TIM3,用该定时器的中断来控制
DS1的闪烁,这一章,我们将向大家介绍如何使用
STM32F4的
TIM3来产生
PWM输出。在本章中,我们将使用
TIM14的通道
1来产生
PWM来控制
DS0的亮度。本章分为如下几个部分:
14.1 PWM简介
14.2 硬件设计
14.3 软件设计
14.4 下载验证
14.1 PWM简介
脉冲宽度调制
(PWM),是英文
“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制,
PWM原理如图
14.1.1所示:
图
14.1.1 PWM原理示意图
图
14.1.1就是一个简单的
PWM原理示意图。图中,我们假定定时器工作在向上计数
PWM模式,且当
CNT<CCRx时,输出
0,当
CNT>=CCRx时输出
1。那么就可以得到如上的
PWM示意图:当
CNT值小于
CCRx的时候,
IO输出低电平
(0),当
CNT值大于等于
CCRx的时候,
IO输出高电平
(1),当
CNT达到
ARR值的时候,重新归零,然后重新向上计数,依次循环。改变
CCRx的值,就可以改变
PWM输出的占空比,改变
ARR的值,就可以改变
PWM输出的频率,这就是
PWM输出的原理。
STM32F4的定时器除了
TIM6和
7。其他的定时器都可以用来产生
PWM输出。其中高级定时器
TIM1和
TIM8可以同时产生多达
7路的
PWM输出。而通用定时器也能同时产生多达
4路的
PWM输出!这里我们仅使用
TIM14的
CH1产生一路
PWM输出。
要使
STM32F4的通用定时器
TIMx产生
PWM输出,除了上一章介绍的寄存器外,我们还会用到
3个寄存器,来控制
PWM的。这三个寄存器分别是:捕获
/比较模式寄存器(
TIMx_CCMR1/2)、捕获
/比较使能寄存器(
TIMx_CCER)、捕获
/比较寄存器(
TIMx_CCR1~4)。接下来我们简单介绍一下这三个寄存器。
首先是捕获
/比较模式寄存器(
TIMx_CCMR1/2),该寄存器一般有
2个:
TIMx _CCMR1和
TIMx _CCMR2,不过
TIM14只有一个。
TIMx_CCMR1控制
CH1和
2,而
TIMx_CCMR2控制
CH3和
4。以下我们将以
TIM14为例进行介绍。
TIM14_CCMR1寄存器各位描述如图
14.1.2所示:
图
14.1.2 TIM14_CCMR1寄存器各位描述
该寄存器的有些位在不同模式下,功能不一样,所以在图
14.1.2中,我们把寄存器分了
2层,上面一层对应输出而下面的则对应输入。关于该寄存器的详细说明,请参考《
STM32F4xx中文参考手册》第
476页,
16.6.4节。这里我们需要说明的是模式设置位
OC1M,此部分由
3位组成。总共可以配置成
7种模式,我们使用的是
PWM模式,所以这
3位必须设置为
110/111。这两种
PWM模式的区别就是输出电平的极性相反。另外
CC1S用于设置通道的方向(输入
/输出)默认设置为
0,就是设置通道作为输出使用。注意:这里是因为我们的
TIM14只有
1个通道,所以才只有第八位有效,高八位无效,其他有多个通道的定时器,高八位也是有效的,具体请参考《
STM32F4xx中文参考手册》对应定时器的寄存器描述。
接下来,我们介绍
TIM14的捕获
/比较使能寄存器(
TIM14_CCER),该寄存器控制着各个输入输出通道的开关。该寄存器的各位描述如图
14.1.3所示:
图
14.1.3 TIM14_ CCER寄存器各位描述
该寄存器比较简单,我们这里只用到了
CC1E位,该位是输入
/捕获
1输出使能位,要想
PWM从
IO口输出,这个位必须设置为
1,所以我们需要设置该位为
1。该寄存器更详细的介绍了,请参考《
STM32F4xx中文参考手册》第
478页,
16.6.5这一节。同样,因为
TIM14只有
1个通道,所以才只有低四位有效,如果是其他定时器,该寄存器的其他位也可能有效。
最后,我们介绍一下捕获
/比较寄存器(
TIMx_CCR1~4),该寄存器总共有
4个,对应
4个通道
CH1~4。不过
TIM14只有一个,即:
TIM14_CCR1,该寄存器的各位描述如图
14.1.4所示:
图
14.1.4 寄存器
TIM14_ CCR1各位描述
在输出模式下,该寄存器的值与
CNT的值比较,根据比较结果产生相应动作。利用这点,我们通过修改这个寄存器的值,就可以控制
PWM的输出脉宽了。
如果是通用定时器,则配置以上三个寄存器就够了,但是如果是高级定时器,则还需要配置:刹车和死区寄存器(
TIMx_BDTR),该寄存器各位描述如图
14.1.5所示:
图
14.1.5寄存器
TIMx_ BDTR各位描述
该寄存器,我们只需要关注最高位:
MOE位,要想高级定时器的
PWM正常输出,则必须设置
MOE位为
1,否则不会有输出。注意:通用定时器不需要配置这个。其他位我们这里就不详细介绍了,请参考《
STM32F4xx中文参考手册》第
386页,
14.4.18这一节。
本章,我们使用的是
TIM14的通道
1,所以我们需要修改
TIM14_CCR1以实现脉宽控制
DS0的亮度。至此,我们把本章要用的几个相关寄存器都介绍完了,本章要实现通过
TIM14_CH1输出
PWM来控制
DS0的亮度。下面我们介绍通过库函数来配置该功能的步骤。
首先要提到的是,
PWM实际跟上一章节一样使用的是定时器的功能,所以相关的函数设置同样在库函数文件
stm32f4xx_tim.h和
stm32f4xx_tim.c文件中。
1)开启TIM14和GPIO时钟,配置PF9选择复用功能AF9(TIM14)输出。
要使用
TIM14,我们必须先开启
TIM14的时钟,这点相信大家看了这么多代码,应该明白了。这里我们还要配置
PF9为复用(
AF9)输出,才可以实现
TIM14_CH1的
PWM经过
PF9输出。 库函数使能
TIM14时钟的方法是:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE); //TIM14时钟使能
这在前面章节已经提到过。当然,这里我们还要使能
GPIOF的时钟。然后我们要配置
PF9引脚映射至
AF9,复用为定时器
14,调用的函数为:
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);
//GPIOF9复用为定时器
14
这个方法跟我们串口实验讲解一样,调用的同一个函数,至于函数的使用,在我们的
4.4小节有详细的讲解。最后设置
PF9为复用功能输出这里我们只列出
GPIO初始化为复用功能的一行代码:
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能
这里还需要说明一下,对于定时器通道的引脚关系,大家可以查看
STM32F4对应的数据手册,比如我们
PWM实验,我们使用的是定时器
14的通道
1,对应的引脚
PF9可以从数据手册表中查看:
2)初始化TIM14,设置TIM14的ARR和PSC等参数。
在开启了
TIM14的时钟之后,我们要设置
ARR和
PSC两个寄存器的值来控制输出
PWM的周期。当
PWM周期太慢(低于
50Hz)的时候,我们就会明显感觉到闪烁了。因此,
PWM周期在这里不宜设置的太小。这在库函数是通过
TIM_TimeBaseInit函数实现的,在上一节定时器中断章节我们已经有讲解,这里就不详细讲解,调用的格式为:
TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割
:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode =
TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInit(TIM3,
&TIM_TimeBaseStructure); //根据指定的参数初始化
TIMx的
3)设置TIM14_CH1的PWM模式,使能TIM14的CH1输出。
接下来,我们要设置
TIM14_CH1为
PWM模式(默认是冻结的),因为我们的
DS0是低电平亮,而我们希望当
CCR1的值小的时候,
DS0就暗,
CCR1值大的时候,
DS0就亮,所以我们要通过配置
TIM14_CCMR1的相关位来控制
TIM14_CH1的模式。在库函数中,
PWM通道设置是通过函数
TIM_OC1Init()~TIM_OC4Init()来设置的,不同的通道的设置函数不一样,这里我们使用的是通道
1,所以使用的函数是
TIM_OC1Init()。
void TIM_OC1Init(TIM_TypeDef* TIMx,
TIM_OCInitTypeDef* TIM_OCInitStruct);
这种初始化格式大家学到这里应该也熟悉了,所以我们直接来看看结构体
TIM_OCInitTypeDef的定义:
typedef struct
{
uint16_t
TIM_OCMode;
uint16_t
TIM_OutputState;
uint16_t
TIM_OutputNState; */
uint16_t
TIM_Pulse;
uint16_t
TIM_OCPolarity;
uint16_t
TIM_OCNPolarity;
uint16_t
TIM_OCIdleState;
uint16_t
TIM_OCNIdleState;
} TIM_OCInitTypeDef;
这里我们讲解一下与我们要求相关的几个成员变量:
参数
TIM_OCMode设置模式是
PWM还是输出比较,这里我们是
PWM模式。
参数
TIM_OutputState用来设置比较输出使能,也就是使能
PWM输出到端口。
参数
TIM_OCPolarity用来设置极性是高还是低。
其他的参数
TIM_OutputNState,
TIM_OCNPolarity,
TIM_OCIdleState和
TIM_OCNIdleState是高级定时器才用到的。
要实现我们上面提到的场景,方法是:
TIM_OCInitTypeDef
TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
//选择模式
PWM
TIM_OCInitStructure.TIM_OutputState =
TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity =
TIM_OCPolarity_Low; //输出极性低
TIM_OC1Init(TIM14, &TIM_OCInitStructure); //根据
T指定的参数初始化外设
TIM1 4OC1
4)使能TIM14。
在完成以上设置了之后,我们需要使能
TIM14。使能
TIM14的方法前面已经讲解过:
TIM_Cmd(TIM14, ENABLE); //使能
TIM14
5)修改TIM14_CCR1来控制占空比。
最后,在经过以上设置之后,
PWM其实已经开始输出了,只是其占空比和频率都是固定的,而我们通过修改
TIM14_CCR1则可以控制
CH1的输出占空比。继而控制
DS0的亮度。
在库函数中,修改
TIM14_CCR1占空比的函数是:
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t
Compare2);
理所当然,对于其他通道,分别有一个函数名字,函数格式为
TIM_SetComparex(x=1,2,3,4)。
通过以上
5个步骤,我们就可以控制
TIM14的
CH1输出
PWM波了。这里特别提醒一下大家,高级定时器虽然和通用定时器类似,但是高级定时器要想输出
PWM,必须还要设置一个
MOE位
(TIMx_BDTR的第
15位
),以使能主输出,否则不会输出
PWM。库函数设置的函数为:
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx,
FunctionalState NewState)
14.2 硬件设计
本实验用到的硬件资源有:
1) 指示灯
DS0
2) 定时器
TIM14
这两个我们前面都已经介绍了,因为
TIM14_CH1可以通过
PF9输出
PWM,而
DS0就是直接节在
PF9上面的,所以电路上并没有任何变化。
14.3 软件设计
打开实验
9 PWM输出实验代码可以看到,我们相比上一节,并没有添加其他任何固件库文件,而是添加了我们编写的
PWM配置文件
pwm.c和
pwm.h。
pwm.c源文件代码如下:
//TIM14 PWM部分初始化
//PWM输出初始化
//arr:自动重装值
psc:时钟预分频数
void TIM14_PWM_Init(u32 arr,u32 psc)
{
GPIO_InitTypeDef
GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE); //TIM14时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,
ENABLE); //使能
PORTF时钟
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);
//GF9复用为
TIM14
GPIO_InitStructure.GPIO_Pin
= GPIO_Pin_9; //GPIOF9
GPIO_InitStructure.GPIO_Mode
= GPIO_Mode_AF; //复用功能
GPIO_InitStructure.GPIO_Speed
= GPIO_Speed_100MHz; //速度
50MHz
GPIO_InitStructure.GPIO_OType
= GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd
= GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOF,&GPIO_InitStructure); //初始化
PF9
TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
//向上计数模式
TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM14,&TIM_TimeBaseStructure);//初始化定时器
14
//初始化
TIM14 Channel1 PWM模式
TIM_OCInitStructure.TIM_OCMode
= TIM_OCMode_PWM1; //PWM调制模式
1
TIM_OCInitStructure.TIM_OutputState =
TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity
= TIM_OCPolarity_Low; //输出极性低
TIM_OC1Init(TIM14,
&TIM_OCInitStructure); //初始化外设
TIM1 4OC1
TIM_OC1PreloadConfig(TIM14,
TIM_OCPreload_Enable); //使能预装载寄存器
TIM_ARRPreloadConfig(TIM14,ENABLE);//ARPE使能
TIM_Cmd(TIM14,
ENABLE); //使能
TIM14
}
此部分代码包含了上面介绍的
PWM输出设置的前
5个步骤。这里我们关于
TIM14的设置就不再说了。
接下来,我们看看主程序里面的
main函数如下:
int main(void)
{
u16
led0pwmval=0;
u8
dir=1;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组
2
delay_init(168); //初始化延时函数
uart_init(115200);//初始化串口波特率为
115200
TIM14_PWM_Init(500-1,84-1); //定时器时钟为
84M,分频系数为
84,所以计数频率
//为
84M/84=1Mhz,重装载值
500,所以
PWM频率为
1M/500=2Khz.
while(1)
{
delay_ms(10);
if(dir)led0pwmval++;//dir==1
led0pwmval递增
else
led0pwmval--; //dir==0 led0pwmval递减
if(led0pwmval>300)dir=0;//led0pwmval到达
300后,方向为递减
if(led0pwmval==0)dir=1; //led0pwmval递减到
0后,方向改为递增
TIM_SetCompare1(TIM14,led0pwmval); //修改比较值,修改占空比
}
}
这里,我们从死循环函数可以看出,我们将
led0pwmval这个值设置为
PWM比较值,也就是通过
led0pwmval来控制
PWM的占空比,然后控制
led0pwmval的值从
0变到
300,然后又从
300变到
0,如此循环,因此
DS0的亮度也会跟着信号的占空比变化从暗变到亮,然后又从亮变到暗。至于这里的值,我们为什么取
300,是因为
PWM的输出占空比达到这个值的时候,我们的
LED亮度变化就不大了(虽然最大值可以设置到
499),因此设计过大的值在这里是没必要的。至此,我们的软件设计就完成了。
14.4 下载验证
在完成软件设计之后,将我们将编译好的文件下载到探索者
STM32F4开发板上,观看其运行结果是否与我们编写的一致。如果没有错误,我们将看
DS0不停的由暗变到亮,然后又从亮变到暗。每个过程持续时间大概为
3秒钟左右。
实际运行结果如下图
14.4.1所示:
图
14.4.1 PWM控制
DS0亮度
实验详细手册和源码下载地址:http://www.openedv.com/posts/list/41586.htm
正点原子探索者STM32F407开发板购买地址:http://item.taobao.com/item.htm?id=41855882779
一周热门 更多>