专家
公告
财富商城
电子网
旗下网站
首页
问题库
专栏
标签库
话题
专家
NEW
门户
发布
提问题
发文章
STM32
【ALIENTEK 战舰STM32开发板例程系列连载+教学】第十四章 PWM输出实验
2019-07-21 02:25
发布
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
站内问答
/
STM32/STM8
11216
19
1092
第十四章
PWM
输出实验
上一章,我们介绍了
STM32
的通用定时器
TIM3
,用该定时器的中断来控制
DS1
的闪烁,这一章,我们将向大家介绍如何使用
STM32
的
TIM3
来产生
PWM
输出。在本章中,我们将使用
TIM3
的通道
2
,把通道
2
重映射到
PB5
,产生
PWM
来控制
DS0
的亮度。本章分为如下几个部分:
14.1 PWM
简介
14.2
硬件设计
14.3
软件设计
14.4
下载验证
14.1 PWM
简介
脉冲宽度调制
(PWM)
,是英文
“
Pulse Width Modulation
”
的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。
STM32
的定时器除了
TIM6
和
7
。其他的定时器都可以用来产生
PWM
输出。其中高级定时器
TIM1
和
TIM8
可以同时产生多达
7
路的
PWM
输出。而通用定时器也能同时产生多达
4
路的
PWM
输出,这样,
STM32
最多可以同时产生
30
路
PWM
输出!这里我们仅使用
TIM3
的
CH2
产生一路
PWM
输出。如果要产生多路输出,大家可以根据我们的代码稍作修改即可。
要使
STM32
的通用定时器
TIMx
产生
PWM
输出,除了上一章介绍的寄存器外,我们还会用到
3
个寄存器,来控制
PWM
的。这三个寄存器分别是:捕获
/
比较模式寄存器(
TIMx_CCMR1/2
)、捕获
/
比较使能寄存器(
TIMx_CCER
)、捕获
/
比较寄存器(
TIMx_CCR1~4
)。接下来我们简单介绍一下这三个寄存器。
首先是捕获
/
比较模式寄存器(
TIMx_CCMR1/2
),该寄存器总共有
2
个,
TIMx _CCMR1
和
TIMx _CCMR2
。
TIMx_CCMR1
控制
CH1
和
2
,而
TIMx_CCMR1
控制
CH3
和
4
。该寄存器的各位描述如图
14.1.1
所示:
图
14.1.1 TIMx_CCMR1
寄存器各位描述
该寄存器的有些位在不同模式下,功能不一样,所以在图
14.1.1
中,我们把寄存器分了
2
层,上面一层对应输出而下面的则对应输入。关于该寄存器的详细说明,请参考《
STM32
参考手册》第
288
页,
14.4.7
一节。这里我们需要说明的是模式设置位
OCxM
,此部分由
3
位组成。总共可以配置成
7
种模式,我们使用的是
PWM
模式,所以这
3
位必须设置为
110/111
。这两种
PWM
模式的区别就是输出电平的极性相反。
接下来,我们介绍捕获
/
比较使能寄存器(
TIMx_CCER
),该寄存器控制着各个输入输出通道的开关。该寄存器的各位描述如图
14.1.2
所示:
图
14.1.2 TIMx_ CCER
寄存器各位描述
该寄存器比较简单,我们这里只用到了
CC2E
位,该位是输入
/
捕获
2
输出使能位,要想
PWM
从
IO
口输出,这个位必须设置为
1
,所以我们需要设置该位为
1
。该寄存器更详细的介绍了,请参考《
STM32
参考手册》第
292
页,
14.4.9
这一节。
最后,我们介绍一下捕获
/
比较寄存器(
TIMx_CCR1~4
),该寄存器总共有
4
个,对应
4
个输通道
CH1~4
。因为这
4
个寄存器都差不多,我们仅以
TIMx_CCR1
为例介绍,该寄存器的各位描述如图
14.1.3
所示:
图
14.1.3
寄存器
TIMx_ CCR1
各位描述
在输出模式下,该寄存器的值与
CNT
的值比较,根据比较结果产生相应动作。利用这点,我们通过修改这个寄存器的值,就可以控制
PWM
的输出脉宽了。本章,我们使用的是
TIM3
的通道
2
,所以我们需要修改
TIM3_CCR2
以实现脉宽控制
DS0
的亮度。
我们要使用
TIM3
的
CH2
输出
PWM
来控制
DS0
的亮度,但是
TIM3_CH2
默认是接在
PA7
上面的,而我们的
DS0
接在
PB5
上面,如果普通
MCU
,可能就只能用飞线把
PA7
飞到
PB5
上来实现了,不过,我们用的是
STM32
,它比较高级,可以通过重映射功能,把
TIM3_CH2
映射到
PB5
上。
STM32
的重映射控制是由复用重映射和调试
IO
配置寄存器(
AFIO_MAPR
)控制的,该寄存器的各位描述如图
14.1.4
所示:
图
14.1.4
寄存器
AFIO_MAPR
各位描述
我们这里用到的是
TIM3
的重映射,从上图可以看出,
TIM3_REMAP
是由
[11:10]
这
2
个位控制的。
TIM3_REMAP[1:0]
重映射控制表如表
14.1.1
所示:
表
14.1.1 TIM3_REMAP
重映射控制表
默认条件下,
TIM3_REMAP[1:0]
为
00
,是没有重映射的,所以
TIM3_CH1~TIM3_CH4
分别是接在
PA6
、
PA7
、
PB0
和
PB1
上的,而我们想让
TIM3_CH2
映射到
PB5
上,则需要设置
TIM3_REMAP[1:0]=10
,即部分重映射,这里需要注意,此时
TIM3_CH1
也被映射到
PB4
上了。
至此,我们把本章要用的几个相关寄存器都介绍完了,本章要实现通过重映射
TIM3_CH2
到
PB5
上,由
TIM3_CH2
输出
PWM
来控制
DS0
的亮度。下面我们介绍配置步骤:
1
)开启
TIM3
时钟,配置
PB5
为复用输出。
要使用
TIM3
,我们必须先开启
TIM3
的时钟
(
通过
APB1ENR
设置
)
,这点相信大家看了这么多代码,应该明白了。这里我们还要配置
PB5
为复用输出,这是因为
TIM3_CH2
通道将重映射到
PB5
上,此时,
PB5
属于复用功能输出。
2
)设置
TIM3_CH2
重映射到
PB5
上。
因为
TIM3_CH2
默认是接在
PA7
上的,所以我们需要设置
TIM3_REMAP
为部分重映射(通过
AFIO_MAPR
配置),让
TIM3_CH2
重映射到
PB5
上面。
3
)设置
TIM3
的
ARR
和
PSC
。
在开启了
TIM3
的时钟之后,我们要设置
ARR
和
PSC
两个寄存器的值来控制输出
PWM
的周期。当
PWM
周期太慢(低于
50Hz
)的时候,我们就会明显感觉到闪烁了。因此,
PWM
周期在这里不宜设置的太小。
4
)设置
TIM3_CH2
的
PWM
模式。
接下来,我们要设置
TIM3_CH2
为
PWM
模式(默认是冻结的),因为我们的
DS0
是低电平亮,而我们希望当
CCR2
的值小的时候,
DS0
就暗,
CCR2
值大的时候,
DS0
就亮,所以我们要通过配置
TIM3_CCMR1
的相关位来控制
TIM3_CH2
的模式。
5
)使能
TIM3
的
CH2
输出,使能
TIM3
。
在完成以上设置了之后,我们需要开启
TIM3
的通道
2
输出以及
TIM3
。前者通过
TIM3_CCER1
来设置,是单个通道的开关,而后者则通过
TIM3_CR1
来设置,是整个
TIM3
的总开关。只有设置了这两个寄存器,这样我们才能在
TIM3
的通道
2
上看到
PWM
波输出。
6
)修改
TIM3_CCR2
来控制占空比。
最后,在经过以上设置之后,
PWM
其实已经开始输出了,只是其占空比和频率都是固定的,而我们通过修改
TIM3_CCR2
则可以控制
CH2
的输出占空比。继而控制
DS0
的亮度。
通过以上
6
个步骤,我们就可以控制
TIM3
的
CH2
输出
PWM
波了。这里特别提醒一下大家,高级定时器虽然和通用定时器类似,但是高级定时器要想输出
PWM
,必须还要设置一个
MOE
位
(TIMx_BDTR
的第
15
位
)
,以使能主输出,否则不会输出
PWM!!
14.2
硬件设计
本实验用到的硬件资源有:
1)
指示灯
DS0
2)
定时器
TIM3
这两个前面都有介绍,但是我们这里用到了
TIM3
的部分重映射功能,把
TIM3_CH2
直接映射到了
PB5
上,而通过前面的学习,我们知道
PB5
和
DS0
是直接连接的,所以电路上并没有任何变化。
14.3
软件设计
本章,我们依旧是在前一章的基础上修改代码,先打开之前的工程,然后我们在上一章的基础上,在
timer.c
里面加入如下代码:
//TIM3 PWM
部分初始化
//PWM
输出初始化
//arr
:自动重装值
//psc
:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{
RCC->APB1ENR|=1<<1; //TIM3
时钟使能
RCC->APB2ENR|=1<<3; //
使能
PORTB
时钟
GPIOB->CRL&=0XFF0FFFFF; //PB5
输出
GPIOB->CRL|=0X00B00000; //
复用功能输出
RCC->APB2ENR|=1<<0; //
开启辅助时钟
AFIO->MAPR&=0XFFFFF3FF; //
清除
MAPR
的
[11:10]
AFIO->MAPR|=1<<11; //
部分重映像
,TIM3_CH2->
B5
TIM3->ARR=arr; //
设定计数器自动重装值
TIM3->
SC=psc; //
预分频器不分频
TIM3->CCMR1|=7<<12; //CH2 PWM2
模式
TIM3->CCMR1|=1<<11; //CH2
预装载使能
TIM3->CCER|=1<<4; //OC2
输出使能
TIM3->CR1=0x0080; //ARPE
使能
TIM3->CR1|=0x01; //
使能定时器
3
}
此部分代码包含了上面介绍的
PWM
输出设置的前
5
个步骤。这里我们关于
TIM3
的设置就不再说了,这里提醒下:在配置
AFIO
相关寄存器的时候,必须先开启辅助功能时钟。
接着我们修改
timer.h
如下:
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
//
通过改变
TIM3->CCR2
的值来改变占空比,从而控制
LED0
的亮度
#define LED0_PWM_VAL TIM3->CCR2
void TIM3_Int_Init(u16 arr,u16 psc);
void TIM3_PWM_Init(u16 arr,u16 psc);
#endif
这里头文件与上一章的不同是加入了
TIM3_PWM_Init
的声明以及宏定义了
TIM3
通道
2
的输入
/
捕获寄存器。通过这个宏定义,我们可以在其他文件里面修改
LED0_PWM_VAL
的值,就可以达到控制
LED0
的亮度的目的了。也就是实现了前面介绍的最后一个步骤。
接下来,我们修改主程序里面的
main
函数如下:
int main(void)
{
u16 led0pwmval=0;
u8 dir=1;
Stm32_Clock_Init(9); //
系统时钟设置
uart_init(72,9600); //
串口初始化为
9600
delay_init(72); //
延时初始化
LED_Init(); //
初始化与
LED
连接的硬件接口
BEEP_Init(); //
初始化蜂鸣器端口
KEY_Init(); //
初始化与按键连接的硬件接口
TIM3_PWM_Init(899,0); //
不分频。
PWM
频率
=72000/(899+1)=80Khz
while(1)
{
delay_ms(10);
if(dir)led0pwmval++;
else led0pwmval--;
if(led0pwmval>300)dir=0;
if(led0pwmval==0)dir=1;
LED0_PWM_VAL=led0pwmval;
}
}
这里,我们从死循环函数可以看出,我们控制
LED0_PWM_VAL
的值从
0
变到
300
,然后又从
300
变到
0
,如此循环,因此
DS0
的亮度也会跟着从暗变到亮,然后又从亮变到暗。至于这里的值,我们为什么取
300
,是因为
PWM
的输出占空比达到这个值的时候,我们的
LED
亮度变化就不大了(虽然最大值可以设置到
899
),因此设计过大的值在这里是没必要的。至此,我们的软件设计就完成了。
14.4
下载验证
在完成软件设计之后,将我们将编译好的文件下载到战舰
STM32
开发板上,观看其运行结果是否与我们编写的一致。如果没有错误,我们将看
DS0
不停的由暗变到亮,然后又从亮变到暗。每个过程持续时间大概为
3
秒钟左右。
实际运行结果如下图
14.4.1
所示:
图
14.4.1 PWM
控制
DS0
亮度
友情提示:
此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
19条回答
原@子123
1楼-- · 2019-07-21 04:59
好。。。。。。。。。。。。。。。。。。。
加载中...
小郭
2楼-- · 2019-07-21 08:15
精彩回答 2 元偷偷看……
加载中...
正点原子
3楼-- · 2019-07-21 09:26
回复【3楼】小郭:
---------------------------------
为什么呢?
加载中...
小郭
4楼-- · 2019-07-21 12:38
精彩回答 2 元偷偷看……
加载中...
小郭
5楼-- · 2019-07-21 16:56
回复【4楼】正点原子:
---------------------------------
老大,我理解错误了;常亮是因为暗的时间太短,看不出变化;一开始对定时器的理解错了,导致后面的理解也错了;不过还是有个问题想问下,当我设置CNT<CCR2时,低电平为有效电平;在CNT>=CCR2时,为无效电平,这个无效电平是不是高电平?
加载中...
失心
6楼-- · 2019-07-21 18:01
原子哥,这个延时函数的作用是什么,为什么我修改延时时间实验现象会不一样呢?
(延时1ms亮暗快速变化,延时100ms亮了之后不会变暗)
加载中...
1
2
3
4
下一页
一周热门
更多
>
相关问题
STM32F4上I2C(在PROTEUS中模拟)调试不通的问题
6 个回答
芯片供应紧张,准备换个MCU,MM32L系列替换STM32L系列的怎么样?
7 个回答
STM32同时使用两个串口进行数据收发时数据丢包的问题
5 个回答
STM32F103串口通信死机问题
4 个回答
STM32WLE5CC连接SX1268在LoRa模式下能与 SX1278互通吗?
2 个回答
STM32开发板免费用活动
7 个回答
stm32 处理 DHT11占用太多时间,大家程序是怎么设计的
8 个回答
分享一个STM32单片机做的离线编程器代码
9 个回答
相关文章
ST公司第一款无线低功耗单片机模块有效提高物联网设计生产效率
0个评论
如何实现对单片机寄存器的访问
0个评论
通过USB用STM32片内自带Bootloader下载程序及注意事项
0个评论
欲练此功必先自宫之STM32汇编启动,放慢是为了更好的前行
0个评论
×
关闭
采纳回答
向帮助了您的网友说句感谢的话吧!
非常感谢!
确 认
×
关闭
编辑标签
最多设置5个标签!
STM32
保存
关闭
×
关闭
举报内容
检举类型
检举内容
检举用户
检举原因
广告推广
恶意灌水
回答内容与提问无关
抄袭答案
其他
检举说明(必填)
提交
关闭
×
关闭
您已邀请
15
人回答
查看邀请
擅长该话题的人
回答过该话题的人
我关注的人
---------------------------------
为什么呢?
---------------------------------
老大,我理解错误了;常亮是因为暗的时间太短,看不出变化;一开始对定时器的理解错了,导致后面的理解也错了;不过还是有个问题想问下,当我设置CNT<CCR2时,低电平为有效电平;在CNT>=CCR2时,为无效电平,这个无效电平是不是高电平?
原子哥,这个延时函数的作用是什么,为什么我修改延时时间实验现象会不一样呢?
(延时1ms亮暗快速变化,延时100ms亮了之后不会变暗)
一周热门 更多>