STM32实现呼吸灯:嵌入式系统开发13

本文主要介绍在STM32F103C8T6上,利用定时器输出PWM波形,进而驱动LED实现呼吸灯。

目录

  • 一、任务要求
  • 二、PWM简介
  • 1、什么是PWM
  • 2、相关概念
  • 3、PWM的产生
  • 4、PWM的通道
  • 5、PWM工作过程
  • 6、PWM输出高低电平
  • 7、PWM的计数模式
  • 8、PWM相关寄存器
  • 三、创建工程
  • 四、代码编写
  • 五、编译
  • 六、烧录
  • 1、硬件连接
  • 2、烧录
  • 3、运行效果
  • 七、总结
  • 一、任务要求

    使用TIM3和TIM4,分别输出一个PWM波形,PWM的占空比随时间变化,去驱动你外接的一个LED以及最小开发板上已焊接的LED(固定接在 PC13 GPIO端口),实现2个 LED呼吸灯的效果。

    二、PWM简介

    1、什么是PWM

    脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。

    通俗讲,PWM是一种 对模拟信号电平进行数字编码 的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码

    PWM信号仍然是数字的 ,因为在给定的任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被断开的时候。只要带宽足够,任何模拟值都可以使用PWM进行编码。

    2、相关概念

  • pwm的频率:
    是指1秒钟内信号从高电平到低电平再回到高电平的次数(一个周期);也就是说一秒钟PWM有多少个周期
    单位: Hz
    表示方式: 50Hz 100Hz

  • pwm的周期:
    周期: 一个脉冲信号的时间
    1s内测周期次数等于频率:T=1/f
    如:50Hz = 20ms 一个周期,频率为50Hz ,也就是说一个周期是20ms 那么一秒钟就有 50次PWM周期

  • 占空比:
    是一个脉冲周期内,高电平的时间与整个周期时间的比例
    单位: % (0%-100%)
    表示方式:20%

  • 脉宽时间: 高电平时间
    脉宽时间占总周期时间的比例,就是占空比

  • 3、PWM的产生

    通过STM32控制板,有两种方式能产生PWM,第一是利用 普通IO口 输出PWM,第二种是利用 定时器的PWM的IO口复用IO口

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

    (2)普通IO口
    一般能够输出PWM的端口都会在主要功能那一栏出现CHx的标志,而普通定时器没有出现这种标志。如图所示,上面的红框就是普通的定时器,不是专用的PWM端口。

    STM32F103C8T6的PWM口
    由于本人的实验环境是在stm32最小系统上实现的,因此在此给出 STM32F103C8T6 的PWM口配置。不是所有的芯片都有重映像功能的STM32F103C8T6 的四个定时器就不需要重映像。

    TIM1_CH1->PA8;
    TIM1_CH2->PA9;
    TIM1_CH3->PA10;
    TIM1_CH4->PA11;

    TIM2_CH1->PA0;
    TIM2_CH2->PA1;
    TIM2_CH3->PA2;
    TIM2_CH4->PA3;

    TIM3_CH1->PA6;
    TIM3_CH2->PA7;
    TIM3_CH3->PB0;
    TIM3_CH4->PB1;

    TIM4_CH1->PB6;
    TIM4_CH1->PB7;
    TIM4_CH1->PB8;
    TIM4_CH1->PB9;

    普通IO口产生PWM
    普通IO口产生一个pwm其实就是通过一个高低电平周期性的变化。确定频率就可以确定周期(T=1/f)也就是在一个周期内产生pwm的时间。
    改变占空比: 确定了时间,高电平的时间不就是想要的占空比么,比如要产生一个频率1khz,占空比为70%的pwm,根据频率我们知道了周期为1ms,产生一个占空比为70%的不就是0.7ms的时间给高电平么。我们用定时器中断的方式,使0.1ms产生一次中断,计数中断次数,中断处理函数前七次中断都给高电平就可以产生对应的波形了。

    区别
    1)一般而言,尽量选用PWM口进行PWM输出,因为普通IO口模拟PWM的输出频率越高,进入定时器中断的次数就越快,中断间隔的时间越短,如果再有其他类型的中断也要处理时,会因为中断的优先级嵌套等待响应,影响控制精度,PWM输出误差增大,也会影响其他如ADC等中断处理,甚至会较出现单片机逻辑出错,死机或者跑飞的情况。

    2)普通IO也可以输出PWM,只是产生PWM一般用转用芯片(开关电源上用的较多)或者单片机的PWM内置模块如定时器,很小直接用MCU的IO口线直接输出因为那样太耗MCU资源了。

    4、PWM的通道

    每一个捕获/比较通道都是围绕着一个捕获/比较寄存器(包含影子寄存器),包括捕获的输入部分(数字滤波、多路复用和预分频器),和输出部分(比较器和输出控制)

    捕获/比较模块由一个预装载寄存器和一个影子寄存器组成。读写过程仅操作预装载寄存器

    在捕获模式下,捕获发生在影子寄存器上,然后再复制到预装载寄存器中

    在比较模式下,预装载寄存器的内容被复制到影子寄存器中,然后影子寄存器的内容和计数器进行比较

    5、PWM工作过程


    每个定时器有四个通道,每一个通道都有一个捕获比较寄存器,将寄存器值和计数器值比较,通过比较结果输出高低电平,实现输出PWM信号

    如图为向上计数:
    定时器重装载值为ARR,比较值CCRx
    t时刻对计数器值和比较值进行比较
    如果计数器值小于CCRx值,输出低电平
    如果计数器值大于CCRx值,输出高电平

    PWM的一个周期
    定时器从0开始向上计数
    当0-t1段,定时器计数器TIMx_CNT值小于CCRx值,输出低电平
    t1-t2段,定时器计数器TIMx_CNT值大于CCRx值,输出高电平
    当TIMx_CNT值达到ARR时,定时器溢出,重新向上计数…循环此过程
    至此一个PWM周期完成

    影响因素
    ARR : 决定PWM周期(在时钟频率一定的情况下,当前为默认内部时钟CK_INT)
    CCRx : 决定PWM占空比(高低电平所占整个周期比例)

    PWM工作过程(以通道1为例)

  • TIMx_CCMR1 寄存器的 OC1M[2:0] 位,设置输出模式控制器
    110: PWM模式1
    111: PWM模式2

  • 计数器值 TIMx_CNT 与通道1捕获比较寄存器 CCR1 进行比较,通过比较结果输出有效电平和无效电平
    OC1REF =0 无效电平
    OC1REF =1 无效电平

  • 通过输出模式控制器产生的信号
    TIMx_CCER 寄存器的 CC1P 位,设置输入/捕获通道1输出极性
    0: 高电平有效
    1: 低电平有效

  • TIMx_CCER:CC1E 位控制输出使能电路,信号由此输出到对应引脚
    0: 关闭
    1: 开启

  • 6、PWM输出高低电平

    计数器值 TIMx_CNT 与捕获比较寄存器值 CCRx 比较后,最终输出高电平还是低电平, 由TIMx_CCMR1:OC1M 位和 TIMx_CCER:CC1P 位共同决定

    (1)TIMx_CCMR1 寄存器的 OC1M[2:0] 位,设置PWM 模式1模式2

    通过设置模式1或模式2,决定了比较结果输出有效或无效电平

    (2)TIMx_CCER 寄存器的 CC1P 位,设置输入/捕获通道1输出极性

    通过设置输出极性,确定有效或无效电平为最终输出的高电平或低电平

    总结:
    模式1:
    CNT<CCR 为有效电平 //(OC1REF = 1)
    CNT>CCR 为无效电平 //(OC1REF = 0)
    模式2:
    CNT<CCR 为无效电平 //(OC1REF = 0)
    CNT>CCR 为有效电平 //(OC1REF = 1)
    CC1P:
    0:高电平有效
    1:低电平有效

    目录

  • 一、任务要求
  • 二、PWM简介
  • 1、什么是PWM
  • 2、相关概念
  • 3、PWM的产生
  • 4、PWM的通道
  • 5、PWM工作过程
  • 6、PWM输出高低电平
  • 7、PWM的计数模式
  • 8、PWM相关寄存器
  • 三、创建工程
  • 四、代码编写
  • 五、编译
  • 六、烧录
  • 1、硬件连接
  • 2、烧录
  • 3、运行效果
  • 七、总结
  • 7、PWM的计数模式

    向上计数模式:
    下面是一个PWM模式1的例子。当 TIMx_CNT<TIMx_CCRx 时PWM信号参考 OCxREF 为高,否则为低。如果 TIMx_CCRx 中的比较值大于自动重装载值 (TIMx_ARR) ,则 OCxREF 保持为’1’。如果比较值为0,则 OCxREF 保持为’0’:

    向下计数模式:
    在PWM模式1,当 TIMx_CNT>TIMx_CCRx 时参考信号 OCxREF 为低,否则为高。如果 TIMx_CCRx 中的比较值大于 TIMx_ARR 中的自动重装载值,则 OCxREF 保持为’1’。该模式下不能产生0%的PWM波形

    中央对齐模式:
    TIMx_CR1 寄存器中的 CMS 位不为’00’时,为中央对齐模式(所有其他的配置对 OCxREF/OCx 信号都有相同的作用)。根据不同的 CMS 位设置,比较标志可以在计数器向上计数时被置’1’、在计数器向下计数时被置’1’、或在计数器向上和向下计数时被置’1’。TIMx_CR1 寄存器中的计数方向位(DIR)由硬件更新,不要用软件修改它。

    8、PWM相关寄存器

    包含三个寄存器: 捕获/比较模式寄存器(TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、捕获/比较寄存器(TIMx_CCR1~4) 。设置 TIMx_CCMRx 寄存器 OCxPE 位以使能相应的预装载寄存器,最后还要设置 TIMx_CR1 寄存器的 ARPE 位,(在向上计数或中心对称模式中)使能自动重装载的预装载寄存器。其中模式设置位 OCxM 位,此位由3位组成,一共可以配置成7种模式,我们使用的是PWM模式,所以 这三位必须为110/111

    捕获/比较模式寄存器总共2个,TIMx_CCMR1TIMx_CCMR2TIMx_CCMR1 控制CH1和CH2,TIMx_CCMR2 控制CH3和CH4。

    下面来简单介绍一下这三种寄存器:

  • 捕获/比较模式寄存器(TIMx_CCMR1)
    作用:在PWM输出模式下,确定PWM的模式、使能相应的预装载寄存器等操作:

  • 捕获/比较使能寄存器(TIMx_CCER)
    作用:在PWM输出模式下,确定PWM的输出极性和输出使能:

  • 捕获/比较寄存器(TIMx_CCR1)
    作用:在PWM输出模式下,确定比较的值:

  • 三、创建工程

    (1)打开 STM32CubeMX,点击 ACCEE TO MCU SELECTOR

    (2)在搜索框输入 STM32F103C8,双击选择 STM32F103C8Tx

    (3)选择调试接口,点击 System Core,选择 SYS,在右侧弹出的菜单栏中选 Serial Wire

    (4)打开外部时钟,点击 System Core,选择 RCC,在右侧弹出的菜单栏中选择Crystal/Ceramic Resonator

    (5)配置 TIM3,勾选 Internal Clock(内部时钟);将 Channel1 设置为 PWM Generation CH1(PWM输出通道1);
    Prtscaler (定时器分频系数) 设置为71,即72分频——1MHz;Counter Mode(计数模式)设置为Up(向上计数模式);Counter Period(自动重装载值) 设置为50000,计数器从0向上计数(递增)到自动装载值,然后再次回到0开始计数,并产生一个计数溢出事件,即0.05s;CKD(时钟分频因子) 设置为No Division (不分频 )

    (6)将 TIM4 设置的和 TIM3 一样

    (7)配置时钟,将 HCLK 设置为 72MHz

    (8)设置项目的名称、位置和编译环境,生成项目

    (9)打开项目,准备代码编辑

    四、代码编写

    主要利用下面两个函数来控制定时器实现PWM输出

    //开启 TIMx 的通道x,输出PWM
    void HAL_TIM_PWM_Start(&htimx, TIM_CHANNEL_x);
    /*
     * @Descript	PWM占空比更改
     * @param		htimx			相关定时器指针	
     * @param		TIM_CHANNEL_x	相关PWM通道
     * @param		Pulse			Duty_cycle = Pulse / Counter Period 
     * @return		void
    */
    
    //修改TIMx的通道x的PWM波形的占空比
    void __HAL_TIM_SET_COMPARE(&htimx, TIM_CHANNEL_x, Pulse);
    /*
     * @Descript	PWM频率更改
     * @param		htimx			相关定时器指针	
     * @param		Counter_Period	PWM_fre = TIM_frq / ( Prescaler + 1 ) / ( Counter Period + 1 )
     * @return		void
    */
    

    (1)在 main.c 文件中定义一个变量来记录 pwm 波形的占空比

    uint16_t pwm=0;   //占空比
    

    (2)打开定时器 TIM3TIM4PWM 通道1

    	HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1); 
    	HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_1); 
    

    (3)在主函数 while 循环里加入如下代码

    	while (pwm< 500)                                       //在0.5s的时间内逐渐增大输出PWM的占空比,即让LED慢慢变亮
    	{
    		pwm++;
    		__HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_1, pwm);    //修改TIM3的占空比
    		__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_1, pwm);  	//修改TIM4的占空比		
    		HAL_Delay(1);
    	}
    	while (pwm>=0)                                        //在0.5s的时间内逐渐减小输出PWM的占空比,即让LED慢慢变暗
    	{
    		pwm--;
    		__HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_1, pwm);   //修改TIM3的占空比 
    		__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_1, pwm);    //修改TIM4的占空比
    		HAL_Delay(1);
    	}
    	HAL_Delay(100);                                         //延时0.1s
    

    五、编译

    (1)点击 Options for Target…,在 Output 下勾选 Create HEX File

    (2)在 Debug 下勾选 Use Simulator,将 Dialog DLL下的输入框改为 DARMSTM.DLL,Parameter 输入框改为 -pSTM32F103C8

    (3)在 Target 选择使用 V5编译器

    (4)点击 Rebuild进行编译

    六、烧录

    1、硬件连接

    USB转TTL STM32F103C8T6
    GND G
    3V3 3V3
    RXD PA9
    TXD PA10

    注意将核心板上的BOOT0设置为1,BOOT1设置为0


    LED模块连接方法:

    输出端口 目的端口
    3.3V LED阳极
    PA6 LED阴极
    PB6 PC13

    其中的PB6->PC13是为了将TIM4_CH1的输出PWM波形接到PC13上,PC13连接着板子上的LED,从而驱动板子上的LED实现呼吸灯

    2、烧录

    打开 FlyMcu 烧录助手,选择刚刚生成的 HEX文件,点击 开始编程 进行烧录

    3、运行效果

    PWM呼吸灯

    七、总结

    本文主要介绍PWM相关理论知识,在学习理论知识的基础上,实现在STM32F103C8T6上,利用定时器TIM3和TIM4输出PWM波形,PWM的占空比随时间变化,去驱动你外接的一个LED以及最小开发板上已焊接的LED(固定接在 PC13 GPIO端口),实现2个 LED呼吸灯的效果。通过本次的练习,让我更加深入的理解了STM32的定时器功能以及PWM的相关知识。

    学习要把理论和实践结合起来。只有在实践过程中一步一步的试错,在“发现问题——分析问题——解决问题”的过程中,逐步加深自己对理论和知识的理解。就比如在本次实践过程中,如果仅仅只阅读一些理论知识,那么对定时器和PWM的理解就会大打折扣。并且在实现呼吸灯的过程中,我也遇到了不少问题,如果没有进行实践,那将很难发现这些问题,也将不会知道如何实现PWM输出和定时器的操作。

    最后就是当我们碰到解决不了的问题时,要多查阅资料,多参考他人的成功方法。这里不是指去抄别人的代码,而是去理解大佬们解决问题的思路,学习大佬们分析问题的方法以及严谨的思维方式,在理解思路的过程中提升自我。

    感谢大家的阅读,欢迎大家指出本文存在的问题!


    参考列表:
    1.STM32CUBEMX_基于PWM的呼吸灯
    2.stm32f103呼吸灯(PWM脉冲宽度调制)
    3.使用STM32输出PWM波形
    4.STM32 PWM基本知识及配置过程

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32实现呼吸灯:嵌入式系统开发13

    发表评论