STM32F103入门 | 12.PWM实现呼吸灯

最新更新时间:2021-11-01来源: eefocus关键字:STM32F103  PWM  呼吸灯 手机看文章 扫描二维码
随时随地手机看文章

12.1. PWM简介


PWM全称为“Pulse Width Modulation”。中文翻译为:脉冲宽度调制。脉冲宽度指的是 脉冲持续的时间,既高电平或低电平保持(持续)的时间。而PWM通俗的说就是人为的(通过微处理器)去控制电平高低保持的时间。这里引出一个新名词,占空比:在一个脉冲的循环中,通电时间相对于总时间所占的比例。


STM32 的定时器除了 TIM6 和 TIM7。其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4 路的 PWM 输出,这样,STM32 最多可以同时产生 30 路 PWM 输出!



12.2. PWM相关寄存器


除了定时器章节介绍的几个寄存器( ARR、PSC、 CR1 等) 外,还会用到 4 个寄存器(通用定时器则只需要 3 个),来控制 PWM 的输出。这四个寄存器分别是:捕获/比较模式寄存器( TIMx_CCMR1/2)、捕获/比较使能寄存器( TIMx_CCER)、捕获/比较寄存器( TIMx_CCR1~4) 以及刹车和死区寄存器( TIMx_BDTR)。


(1)捕获/比较模式寄存器( TIMx_CCMR1/2)


该寄存器总共有 2 个, TIMx _CCMR1 和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和 CH2,而 TIMx_CCMR2 控制 CH3 和 CH4。


寄存器分了 2 层,上面一层对应输出时的设置而下面的则对应输入时的设置。模式设置位 OCxM,此部分由 3 位组成。总共可以配置成 7 种模式,我们使用的是 PWM 模式,这 3 位必须设置为110/111。这两种 PWM 模式的区别就是输出电平的极性相反。 另外 CCxS 用于设置通道的方向(输入/输出)默认设置为 0,就是设置通道作为输出使用。


/**

  * 没有重映射时,TIM3的四个通道CH1, CH2, CH3, CH4分别对应PA6, PA7, PB0, PB1

  * 部分重映射时,TIM3的四个通道CH1, CH2, CH3, CH4分别对应PB4, PB5, PB0, PB1

  * 完全重映射时,TIM3的四个通道CH1, CH2, CH3, CH4分别对应PC6, PC7, PC8, PC9

  * 

  * 110:PWM模式1 - 在向上计数时,一旦TIMx_CNT  * 否则为无效电平;在向下计数时,一旦TIMx_CNT>TIMx_CRRx时,通道x为无效电平,

  * 否则为有效电平。

  *

  * 111:PWM模式2 - 在向上计数时,一旦TIMx_CNT  * 否则为有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CRRx时,通道x为有效电平,

  * 否则为无效电平。

  */

(2)捕获/比较使能寄存器( TIMx_CCER)


这里只用到了 CC1E 位,该位是输入/捕获 1 输出使能位,要想PWM 从 IO 口输出,这个位必须设置为 1。


(3)捕获/比较寄存器( TIMx_CCR1~4)


该寄存器总共有 4 个,对应 4 个输通道 CH1~CH4。在输出模式下,该寄存器的值与 CNT 的值比较,根据比较结果产生相应动作。利用这点,我们通过修改这个寄存器的值,就可以控制 PWM 的输出脉宽了。


(4)刹车和死区寄存器( TIMx_BDTR)


如果是通用定时器,则配置以上三个寄存器就够了,但是如果是高级定时器,则还需要配置:刹车和死区寄存器( TIMx_BDTR)。该寄存器,我们只需要关注最高位: MOE 位,要想高级定时器的 PWM 正常输出,则必须设置 MOE 位为 1,否则不会有输出。注意:通用定时器不需要配置这个。


12.3. PWM波形产生原理


通用定时器可以利用 GPIO 引脚进行脉冲输出,在配置为比较输出、PWM 输出功能时,捕获/比较寄存器 TIMx_CCR 被用作比较功能,下面把它简称为比较寄存器。


这里直接举例说明定时器的PWM输出工作过程:若配置脉冲计数器TIMx_CNT 为向上计数,而重载寄存器 TIMx_ARR 被配置为 N,即 TIMx_CNT 的当前计数值数值X在 TIMxCLK 时钟源的驱动下不断累加,当 TIMx_CNT 的数值X大于 N 时,会重置 TIMx_CNT 数值为 0 重新计数。


而在 TIMxCNT 计数的同时,TIMxCNT 的计数值X会与比较寄存器TIMx_CCR 预先存储了的数值 A 进行比较,当脉冲计数器 TIMx_CNT 的数值X小于比较寄存器 TIMx_CCR 的值A时,输出高电平(或低电平),相反地,当脉冲计数器的数值X大于或等于比较寄存器的值 A 时,输出低电平(或高电平)。


如此循环,得到的输出脉冲周期就为重载寄存器 TIMx_ARR 存储的数值 (N+1) 乘以触发脉冲的时钟周期,其脉冲宽度则为比较寄存器 TIMx_CCR 的值 A 乘以触发脉冲的时钟周期,即输出PWM的占空比为 A/(N+1) 。


12.4 PWM配置步骤


1.开启TIM3时钟、GPIOB时钟和复用功能时钟

2.配置GPIOB5为复用输出

3.设置TIM3_CH2重映射到PB5上

4.初始化TIM3,设置ARR和PSC

5.设置TIM3_CH2的PWM模式

6.使能TIM3的CH2输出

7.使能TIM3

8.在主函数中改变占空比完成呼吸灯


12.5 定时器引脚复用功能映射

根据以上重映像表,我们使用定时器3的通道2作为PWM的输出引脚,所以需要对PB5引脚进行配置。注意:如果使用PB4当做TIM3部分重映射的CH1输出,除了要进行部分重映射配置外,还需要禁用JTAG!并在开启复用时钟后禁用JTAG!


GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);  //禁用JTAG,在开启复用时钟后禁用


1. 新建两个文件,pwm.c 和 pwm.h

2. 在头文件 pwm.h 添加下面代码:


#ifndef _PWM_H

#define _PWM_H

#include "stm32f10x.h"

 

void PWM_Init(u16 arr, u16 psc);

 

#endif;

3. 把 pwm.c 添加到工程中

4. 在 pwm.c 中添加以下代码:


#include "pwm.h"

 

void PWM_Init(u16 arr,u16 psc)

{

    GPIO_InitTypeDef GPIO_InitStructure;              //定义GPIO结构体

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;    //定义TIMx定时器结构体

    TIM_OCInitTypeDef TIM_OCInitStructure;            //定义定时器脉宽调制结构体

    

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);                     //使能TIM3时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);//使能GPIOB时钟和AFIO复用时钟

    

    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);                     //TIM3部分重映射 TIM3_CH2->PB5

    

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                               //TIM_CH2

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                         //复用推挽输出

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;                       //配置输出速率

    GPIO_Init(GPIOB,&GPIO_InitStructure);                                   //初始化GPIOB

    

    TIM_TimeBaseStructure.TIM_Period = arr;                                 //设置自动重装载寄存器周期的值 arr=value-1

    TIM_TimeBaseStructure.TIM_Prescaler = psc;                              //设置预分频值 psc=value-1

    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                            //设置时钟分割:TDTS = Tck_tim

    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;             //TIM向上计数模式

    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);                          //初始化TIMx时间基数

    

    //初始化TIM3 Channel2 PWM模式     

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                       //选择定时器模式:TIM脉冲宽度调制模式1

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;           //使能比较输出

    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;               //输出极性:TIM输出比较极性高

    TIM_OC2Init(TIM3,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM3 OC2

 

    TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);                        //使能TIM3在CCR2上的预装载寄存器

    TIM_Cmd(TIM3, ENABLE);                                                  //使能TIM3

}

 

5. 实现PWM呼吸灯功能


#include "stm32f10x.h"

#include "delay.h"

#include "led.h"

#include "tim.h"

#include "key.h"

#include "pwm.h"

 

int main(void)

{

    u16 pwmValue = 0;

    u8 dir = 0;

 

    delay_init();

    PWM_Init(999, 719);

 

    while(1)

    {

        if(dir) {

            if(pwmValue > 550) TIM_SetCompare2(TIM3, --pwmValue);

            else dir = 0;

        }

        else {

            if(pwmValue < 990) TIM_SetCompare2(TIM3, ++pwmValue);

            else dir = 1;

        }

        delay_ms(3);

    }

}


小提示:如果身边没有LED电阻面包板搭电路,可以用杜邦线连接PB5和PC13,同时PC13设置成开漏输出(GPIO_Mode_Out_OD),这样就能完成呼吸灯实验了(不瞒你说我也是这样干的)。

关键字:STM32F103  PWM  呼吸灯 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic549101.html

上一篇:STM32F103 呼吸灯的实现
下一篇:stm32f103呼吸灯(PWM脉冲宽度调制)

推荐阅读

STM32F103的启动配置
如题,谷歌百度一堆,以及查看数据手册,都知道STM32F103芯片靠BOOT0和BOOT1以及NVIC中断向量表的相关配置,可以做到3种启动模式:从内置用户FLASH启动、从SRAM内存启动、从系统存储器启动。一般地球人都是用FLASH启动,又可以烧进去程序,又可以在线调试。或者用SRAM启动,可以调试小函数。二者的启动方法在数据手册都有很容易的说明,谷歌百度也可以马上查到。我想说的是,如何从系统存储器启动?如果是定义NVIC中断向量表,只能使用:NVIC_SetVectorTable(0x20000000, 0x0);//SRAM启动(芯片内存)NVIC_SetVectorTable(0x08000000, 0x0);//FLAS
发表于 2022-06-01
STM32F103_外部RAM用作运存
概述SRAM的简介折腾过电脑的朋友都知道,当电脑运行比较卡的时候,我们可以通过给电脑加装内存条来改善电脑的性能。那么号称微型计算机的单片机能不能像电脑一样加装内存条呢?装内存条倒是不行,但是我们可以给单片机外加和内存条效果一样的SRAM来提升单片机的性能。下面以STM32F407ZGT6单片机来讲解一下来扩展外部SRAM。原理:给STM32芯片扩展内存与给PC扩展内存的原理是一样的,只是PC上一般以内存条的形式扩展,内存条实质是由多个内存颗粒(即SRAM芯片)组成的通用标准模块,而STM32直接与SRAM芯片连接。SRAM,型号IS62WV51216,管脚图如下:IS62WV51216的管脚总的来说大致分为:电源线、地线、地址线、数
发表于 2022-06-01
<font color='red'>STM32F103</font>_外部RAM用作运存
基于正点原子STM32F103ZET6的ESP8266应用
前言本次测试所使用的是正点原子的ATK-ESP8266 WIFI模块。直接使用官方提供的固件使用AT指令来配置模块并使用。模块默认为AT指令状态,模拟波特率为115200(8bit数据位,1bit停止位)。硬件连接使用USB转TTL方式(电脑需要安装CH340驱动)连接ESP8266,接线图如下:Wifi模块ESP8266简介ESP8266 是串口型WIFI,速度比较低,不能用来传输图像或者视频这些大容量的数据,主要应用于数据量传输比较少的场合,比如温湿度信息,一些传感器的开关量等。ESP8266与单片机串口连接。一方面单片机可以通过串口发送AT命令给ESP8266,ESP8266会返回给单片机一个返回值;另一方面,当手机与ESP8
发表于 2022-05-30
基于正点原子<font color='red'>STM32F103</font>ZET6的ESP8266应用
stm32f10x_it.c 定义的程序列表模板(stm32f103x_it.c中放的是中断的空函数)
1.stm32f103x_it.c中放的是中断的空函数2.STM32是如何进入中断程序的:首先,程序是放在0x80000000-0x8001ffff FLASH所在的代码段内;SRAM从地址0x20000000开始有20K大小 存放变量等。当BOOT0=0时(BOOT0不要悬空啊!),中断向量放在0x80000000开始的地址,这时当ARM启动时程序其实是从0x80000004中存放的“函数地址”开始执行的,要强调函数地址这一点。3.stm32f10x_it.c中点中断服务函数调用其他文件的函数能通过编译但会出现警告:最好把相关的头文件添加进去就可以。使用其他文件的全局变量一定要添加外部变量声明extern,如:在AAA.c中声明u
发表于 2022-05-26
延时函数delay_ms,delay_us会出现进入延时函数出不来的情况
首说明先原子哥的延时函数没有问题。原子哥的延时函数有的是用在STM32F103中的,要看自己的开发板是那个类型。这里给出STM32F103和STM32F030的延时函数。(1)用在STM32F030中:#include "stm32f0xx.h"#include "delay.h"// //本程序只供学习使用,未经作者许可,不得用于其它任何用途//Mini STM32开发板//使用SysTick的普通计数模式对延迟进行管理//包括delay_us,delay_ms//正点原子@ALIENTEK//技术论坛:www.openedv.com//修改日期:2010/5/27//版本:V1.2//版权
发表于 2022-05-25
延时函数delay_ms,delay_us会出现进入延时函数出不来的情况
STM32F103+语音识别模块HBR640
HBR640实物图HBR640框架结构图:串口工具:上位机串口协议:官方给的STM32F4的样例,太过涉及芯片本身特定库函数的调用了,变量和宏定义太多。后面由于工程紧急,且要使用与官方历程不同的芯片实现适应性功能裁剪,没有时间先理解官方繁琐的变量和宏定义变换,再一一对应自己所用芯片就的相同功能修改。所以自己照着不是很复杂的通信协议写了一个模块历程。我曾经在网上搜索这个模块,发现根本没有它的资料,所以我就写了一个命令集齐全的,且对本身芯片型号控制资源依赖少的程序模块出来和大家分享。工程目录:main()函数:void main(){ int num=0; hbr640_init(); while(1) { num=Conti
发表于 2022-05-25
<font color='red'>STM32F103</font>+语音识别模块HBR640

推荐帖子

ADS1248通道与外部接线端子之间的对应关系设置
分享个ADC通道与温控系统之间对应关系混乱的解决方法,不合理之处还望拍砖! 前段时间基于STM32F1、ADS1248实现温控系统的嵌入式编程,在第一板中实现了5通道ADC温控系统,改板后改成了7通道温控系统,并且对应引脚关系大部分都更换了,这几天在对板子进行调试与移植工作, 昨天在调整驱动引脚对应关系时,由于ADS1248的通道转换顺序CH1……CH7与外部接线端子不是一一对应的,于是在程序中添加了两者之间的对应关系表,最初是基于外部接线端子的顺序,ADS1248仍然按CH1……CH7的顺
Tobey TI技术论坛
关于at89s52单片机的看门狗程序问题
我想问一下单片机用的是at89s52看门狗是硬件还是软件?需要另加外围的硬件电路吗?谁能给讲讲?还是看门狗只是一个程序不需要外围器件支持?谢谢我是新手请多多指教谢谢 关于at89s52单片机的看门狗程序问题
rightnow10 嵌入式系统
关于STM32的DFU
最近在搞stm32的dfu,有些状况。在选择了BOOT0--1BOOT1--0之后,连上USB线,主机没有反应。后来发现貌似要先下载一个文件到开发板,STTub30.sys,后缀名是.sys,以前没接触过这个文件,不知道如何下载,下载到哪里,是下载到用户flash还是系统flash。各位大侠,哪位知道,帮个小忙,谢谢啦。关于STM32的DFU
gaokushuai stm32/stm8
无线网状网络的网状拓扑的兼容性设计考量
互连设备通常使用几种网状拓扑之一进行联网,这些拓扑注重网络稳健性、范围覆盖和低功耗。设计人员往往要在这些相互竞争且不兼容的协议中做出选择,然后在选定的硬件平台上实现软件堆栈。这两项工作都具有挑战性,而现在或许都不必去做了。 归功于集成技术的发展,开发人员可以选择现有的低成本、小基底面并支持多种竞争标准的网状网络控制器,包括Thread、Zigbee和低功耗蓝牙(BLE)。这可以带来几种程度不同的灵活性: 允许开发人员继续进行设计,在设计周期的后期阶段再选择协议。
Aguilera 无线连接
模块电源,开关电源软启动电路设计与应用
开关电源,模块电源,军品电源稳压电源 开关电源以其体积小巧、性能卓越、使用方便的显著特点,在通信、网络、工控、铁路、军事等领域日益得到广泛的应用。很多系统设计人员已经意识到,正确合理地设计开关电源,可以省去电源设计、调试方面的麻烦。这样不仅可以提高整体系统的可靠性和设计水平,而且更重要的是缩短了整个产品的研发周期。本文重点阐述如何正确合理设计开关电源的软启动电路,以供广大系统电源设计人员参考。   开关电源的输入电路大都采用整流加电容滤波电路。在输入电路合闸瞬间,由于电容器上的初始电压
mtbf 测试/测量
小白求助大佬推荐高频方波放大电路
电路小白,FPGA需要外接一个高频放大电路,求大佬推荐一下,或者有大佬可以做也可以。基本需求是这样的 输入:0~3.3V,频率为10~40MHz的方波 输出:0~9V,相同频率的方波 希望大佬们推荐一下,提前感谢 小白求助大佬推荐高频方波放大电路
feifan996 模拟电子
小广播
实战 培训 开发板 精华推荐

何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2022 EEWORLD.com.cn, Inc. All rights reserved