精华内容
下载资源
问答
  • stm32定时器产生pwm波
    千次阅读
    2022-03-24 17:33:09

    对于STM32定时器输出PWM波需要了解定时器的基本使用方法和pwm的基本原理。这里使用STM32定时器3输出PWM波。

    1.什么是PWM波

    1.我们都知道单片机的引脚可以输出高低两种电平,高电平称之为1,而低电平称之为0;而所谓的PWM波指的是在一定周期内不同比例的高低电平,如下图所示,输出不同比例的方波,在一定时间内高电平的比例分别达到10%,50%,90%。

    2.PWM的作用,我们都知道对于一个发光二极管,在一定电压范围内,输入端的电压越高,二极管的亮度也就越大。我们可以用单片机控制二极管的亮灭,我们会发现单片机引脚只能输出两种电压,即1与0;但是我们想控制二极管亮度。这是我们可以用PWM波控制,通过输出不同比例的高低电平,等效于一定的电压值,此时,就可以对二极管亮度调节了。

    2.用定时器输出PWM

    1.如下通过STM32的定时器3编写的pwm输出程序代码。

    //TIM3 PWM部分初始化 
    //PWM输出初始化
    //arr:自动重装值
    //psc:时钟预分频数
    void TIM3_PWM_Init(u16 arr,u16 psc)
    {  
    	GPIO_InitTypeDef GPIO_InitStructure;
    	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    	TIM_OCInitTypeDef  TIM_OCInitStructure;
    	
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器3时钟
     	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟
    	
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_6; //TIM_CH2
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
     
       //初始化TIM3
    	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 
    	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    	
    	//初始化TIM3 Channel2 PWM模式	 
    	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2
     	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
    	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
    	
    	TIM_OC1Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC1
    	TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2	
      TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR1上的预装载寄存器
    	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器
     
    	TIM_Cmd(TIM3, ENABLE);  //使能TIM3	
    }

    这里使用的是定时器的通道1与通道2,对应着A6,A7两个引脚。具体详细配置请看上述注释。

    其中:

    1.定时器中断一次的时间为Tout(溢出时间)=(ARR+1)(PSC+1)/Tclk,tclk为时钟频率,一般为72000000,arr:自动重装值  psc:时钟预分频数

    2.

     

     2.主程序中的相关配置

    对于主程序先对TIM3_PWM_Init(u16 arr,u16 psc)进行初始化,并配置好arr与psc,以确定周期频率。然后再调用  void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare2);与void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);即可配置PWM值。

    更多相关内容
  • STM32F103ZET6STM32定时器产生PWM波控制电机(寄存器版)
  • STM32学习入门
  • STM32定时器2PWM输出

    2019-08-12 11:56:51
    pwm输出实验 经过验证 TIM2定时器输出 输出4通道 通道1 PA0 通道2 PA1 通道3 PA2 通道4 PA3 可通过TIM_SetCompare1(TIM1, PWM);对PA1进行输出PWM 谢谢
  • STM32定时器PWM脉冲数量.rar
  • 高级定时器PWM波介绍及配置

    本人纯小白一枚,如有错误,还请大佬指出

    目录

    1.定时器引脚图

    2.总体框架

    2.1时基模块

    2.2比较寄存器

    2.3死区发生器

    2.4输出控制

    3.结构体

    4.编程

    5.说明


    1.定时器引脚图

    2.总体框架

    注:高级定时器除了通用定时器所具有的输入捕获和输出比较功能外,另外还添加了可编程死区互补输出、重复计 数器、带刹车 (断路) 功能,本文章只截取了其中的输出比较框图。

    我将高级定时器的框架分为4个部分:时基模块、比较寄存器、死区发生器、输出控制。

    2.1时基模块

    高级定时器时钟源有4个,这里仅介绍内部时钟源

     时基单元框架如图

    将此分为4部分:1.预分频器PSC,可实现1-65536的分频。2.计数器 CNT:三种计数模式,递增计数模式、递减计数模式和递增/递减 (中 心对齐) 计数模式。3.自动重载寄存器 ARR及4.重复计数器 RCR

    这里与基本定时器不一样的就是三种计数模式及重复计数器。

    通俗来讲就是,循环从0(或最大值)往上(或往下数),当数到最大值(或0),可以发生中断或者事件,而当使用了重复计数器后,数特定的遍数会产生中断1或者事件。其中往上或者往下计数则取决于计数模式。

    而本次输出PWM波,不需要采用中断,只需其计数功能即可。

    2.2比较寄存器

    当计数器 CNT 的值跟比较寄存器 CCR 的值相等的时候,输出参考信号 OCxREF 的信号的极性 就会改变,其中 OCxREF=1(高电平)称之为有效电平,OCxREF=0(低电平)称之为无效电平。

    此处输出的信号为OCxREF.

    在进入死区发生器之前,可以设置输出比较模式,对于输出PWM波而言,有两个模式可供选择,分别为PWM1,PWM2

    2.3死区发生器

    在经过死区发生器之后会产生两路带死区的互补 信号 OCx_DT 和 OCxN_DT。如果没有加入死区控制,那么进入输出控制电 路的信号就直接是 OCxREF。

    单纯的PWM波,此处不做详细介绍。

    2.4输出控制

    由死区发生器输出的信号会被分成两路,一路是原始信号,一路是被反向的信号,具体的由寄存器 CCER 的位 CCxP 和 CCxNP 控制。经过极性选择的信号是否由 OCx 引脚输出到外部引脚 CHx/CHxN (即是否使能),则由寄存器 CCER 的位 CxE/CxNE 配置。

    3.结构体

    typedef struct
    {
      uint16_t TIM_Prescaler;        //时钟预分频,对应PSC
                                     
      uint16_t TIM_CounterMode;      //时钟计数模式,对应3中计数方法
                                     
      uint16_t TIM_Period;           //定时器周期,对应ARR寄存器
                                                                 
      uint16_t TIM_ClockDivision;    //时钟分频,设置定时器时钟 CK_INT 频率与死区发生器以及数字滤 
                                     //波器,采样时钟频率分频比。可以选择 1、2、4 分频。
    
      uint8_t TIM_RepetitionCounter; //重复计数器,对应RAR
                                                                     
    } TIM_TimeBaseInitTypeDef;       
    
    
    typedef struct
    {
      uint16_t TIM_OCMode;          //输出模式,PWM1及PWM2,对应寄存器CCMR1->OCxM
                                 
      uint16_t TIM_OutputState;     //比较输出使能,对应CCER->CCxE
                                 
      uint16_t TIM_OutputNState;    //比较互补输出使能,对应CCER->CCxNE
                                  
      uint16_t TIM_Pulse;           //脉冲宽度,即比较寄存器的值,对应CCR1
                                 
      uint16_t TIM_OCPolarity;      //输出极性,对应CCER->CCxP
    
      uint16_t TIM_OCNPolarity;     //互补输出极性,对应CCER->CCxP
    
      uint16_t TIM_OCIdleState;     //空闲状态比较输出状态,对应CR2->OIS1
    
      uint16_t TIM_OCNIdleState;    //空闲状态下比较互补输出状态,对应CR2->OIS1N
                                   
    } TIM_OCInitTypeDef;
    
    

     配置pwm的结构体主要用到两个,一个是时基初始化的结构体,一个是输出比较的结构体,时基初始化的结构体

    其中输出比较的结构体对应图中的寄存器如下图

     但是我们除了要配备这两个结构体之外,还有一个寄存器要使能 

    对应BDER->MOE寄存器,官方介绍如下图

     就是使能输出引脚

    4.编程

    总结一下,编程的目标:

    1.对通道的GPIO引脚进行配置

    2.对两个结构体进行配置

    3.使能时钟源,使能输出通道

    以下程序配置的为1Khz,占空比为40%的PWM波

    void advance_tim1_gpio_config(void)
    {
    	//1.结构体
    	GPIO_InitTypeDef GPIO_InitStructure;
    	
    	//2.开时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    	//3.配置
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    		
    	//4.初始化
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	
    	//5.使能(无)	
    }
    
    void advance_tim1_mode_config()
    {
    	//1.结构体,时基结构体及输出比较结构体
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    	TIM_OCInitTypeDef TIM_OCInitStructure;
    	
    	//2.开时钟,TIM1的时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
    	
    	//3.配置及初始化
    	/*--------------------时基结构体初始化-------------------------*/
    	// PWM 信号的频率 F = TIM_CLK/{(ARR+1)*(PSC+1)}
    	
    	TIM_TimeBaseStructure.TIM_Period = 9;	                      //ARR寄存器的值
    	TIM_TimeBaseStructure.TIM_Prescaler = 7199;	                  //PSC分频的值
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   //向上计数
    	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;                //重复计数器为0
    	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
    	
    	/*--------------------输出比较结构体初始化-------------------*/
    	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;             //输出模式:PWM1
    	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
    	TIM_OCInitStructure.TIM_Pulse = 4;			                  //设置占空比
    	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;     //有效电平
    	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;  //空闲时比较输出状态
    	TIM_OC1Init(TIM1, &TIM_OCInitStructure);
    
    	//4.使能,此处使能为将内部时钟作为TIM1时钟源的使能
    	TIM_Cmd(TIM1, ENABLE);									      //使能计数器
    	TIM_CtrlPWMOutputs(TIM1, ENABLE);				              //使能输出通道
    }
    

    说明:ARR寄存器与PSC寄存器都是从0开始计数,所以值要减一。

    PWM波频率=TIM_CLK/{(ARR+1)*(PSC+1)}

    其中TIM_CLK一般是APB2的频率,因为TIM1挂载在APB2中,APB2一般为72Mhz

    占空比=TIM_OCInitStructure.TIM_Pulse/(ARR+1)

    个人配置PWM波,一般如以下步骤

    1.确认PWM波的频率

    2.确认PWM波的精度(对应ARR寄存器)

    3.确认占空比,TIM_OCInitStructure.TIM_Pulse

    另外,有一个函数专门修改占空比(即修改TIM_OCInitStructure.TIM_Pulse的值),我之前不知道,还自己写了一个(大家避坑)

    void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);

    5.说明

    除了本文章说明的寄存器,还有一些预装载函数,如TIM_OC1PreloadConfi();

    等,此函数对应CCMR->OC1PE,但是我暂时并不需要此功能,所以不做详细介绍。 

    官方说明如下:此外,对于时基单元,个别寄存器下有阴影,对应影子寄存器,也不作详细介绍。

    后续会出一篇PWM波控制电调的文章。

    参考文献有《STM32F10x-中文参考手册》《STM32库开发实战指南——基于野火指南者开发板》

    展开全文
  • 本工程代码在STM32F407ZET6开发板上测试通过,其中使用TIM14产生一个PWM脉冲信号来控制一个LED灯,使之成为一个呼吸灯。本压缩包中也包含了STM32F4xx的中文用户手册,以及本人使用的开发板的原理图。欢迎大家下载...
  • 使用CubeMX配置生成,底层采用HAL库,可以使用易于上手
  • STM32中应用定时器产生PWM波定时器的配置,PWM波占空比的设置等的简单模拟。
  • STM32定时器PWM 输出

    千次阅读 2021-06-28 10:30:35
    26.1 关于 PWM 26.1.1 PWM 介绍 PWM(Pulse Width Modulation,脉冲宽度调制)。是一种利用微处理器的数字输出来对模拟电路进行控制的技术,广泛应用在测量、通信、功率控制等诸多领域。 举个最常见的例子,利用PWM...

    26.1 关于 PWM

    26.1.1 PWM 介绍

    PWM(Pulse Width Modulation,脉冲宽度调制)。是一种利用微处理器的数字输出来对模拟电路进行控制的技术,广泛应用在测量、通信、功率控制等诸多领域。

    举个最常见的例子,利用PWM控制显示屏亮度。屏幕背光可以看作是一个大灯,这个大灯只有亮、灭两种状态。如果把灯亮看作100%,灯灭看作0%,要实现50%的亮度,可以在某个单位时间里亮灯50%时间、灭灯50%时间,只要这个单位时间够小,由于人眼具有视觉暂留效应,就会从宏观的感觉整个灯是一直亮着,且亮度只要原来的一半。

    PWM实质就是GPIO不断翻转输出高、低电平,这个效果可以写代码控制GPIO产生,但这样就会占用CPU,CPU就不方便做其它事情。此时可以利用定时器,设置好翻转时间,让其自动控制GPIO翻转,无需CPU再参与。

    在一个周期内,高电平占整个信号周期的百分比,称之为占空比(Duty Cycle),如图 26.1.1 所示,占空比分别为30%、50%、70%。
    在这里插入图片描述

    26.1.2 STM32 的 PWM

    PWM是定时器输出比较的典型应用。除STM32的基本定时器(TIM6、TIM7)外,其它定时器都支持PWM输出,每个通用定时器(TIM2、TIM3、TIM4、TIM5)可以同时产生4路PWM,每个高级定时器(TIM1、 TIM8)可以同时产生多达7路PWM。

    以通用定时器为例,如上图 25.1.2 所示,每个定时器有四路输出通道:TIMx_CH1、TIMx_CH2、TIMx_CH2、TIMx_CH4,每个通道都对应一个捕获/比较寄存器:TIMx_CCR1\TIMx_CCR2、TIMx_CCR3、 TIMx_CCR4。将计数器CNT的值,与捕获/比较寄存器相比较,由比较结果决定输出电平高低,从而实现PWM输出。

    举个例子,若当前设置计数器为向上计数,定时器重载值为TIMx_ARR,通道1的捕获/比较寄存器值为TIMx_CCR1。如图 26.1.2 所示,首先定时器从0开始计数,在0t1时间段,TIMx_CNT<TIMx_CCR1,输出低电平;在t1t2时间段,TIMx_CNT>TIMx_CCR1,输出高电平;t2时,TIMx_CNT=TIMx_ARR计数器溢出,重新从0开始,如此循环。

    由此可以看出,TIMx_ARR决定PWM的周期,TIMx_CCR1决定PWM的占空比,此时占空比计算公式为:
    在这里插入图片描述

    在这里插入图片描述
    每个定时器的输出比较模式共同8种(通过配置寄存器CCMRx的位OCxM [2:0]选择),其中有两种是最常用的PWM输出模式:PWM模式1和PWM模式2。两种模式区别在于,计数器CNT与TIMx_CCRx比较的结果,输出的电平不同,如表 26.1.1 所示。
    在这里插入图片描述

    26.2 硬件设计

    本实验通过三色LED灯的显示效果来展示PWM输出,原理图如图 26.2.1 所示,结合《数据手册.pdf》的引脚描述章节,可知:LED红色所接的PB0为TIM3的通道3;LED绿色所接的PB1为TIM3的通道4;LED蓝色所接的PB5重映射后为TIM3的通道2。

    此外,当引脚为低电平时LED灯亮,因此PWM的占空比越高,LED越暗,PWM的占空比越低,LED灯越亮。
    在这里插入图片描述

    26.3 软件设计

    26.3.1 软件设计思路

    实验目的:本实验通过使用定时器的PWM输出功能,实现三色LED灯的红、绿、蓝组合,显示任意色,让读者理解PWM输出的设置方法。

    1. 初始化定时器相关参数:配置时钟、工作方式、PWM模式等;
    2. 初始化定时器涉及的硬件相关参数:初始化涉及的时钟、引脚、中断;
    3. 在定时器中断函数里,修改占空比;
    4. 在按键中断函数里,切换LED模式和修改R G B值;
    5. 主函数编写控制逻辑:实现随机模式和用户模式。随机模式即间隔1s,随机生成R G B值显示;用户模式即用户按键修改R G B值,显示自己需要的颜色。

    本实验配套代码位于“5_程序源码\18_定时器—PWM输出\”。

    26.3.2 软件设计讲解

    1. GPIO选择与接口定义
      宏定义涉及的定时器、周期、引脚等,如代码段 26.3.1 所示。

    代码段 26.3.1 相关宏定义(driver_timer.h)

    typedef struct
    {
    uint8_t rgb_red;
    uint8_t rgb_green;
    uint8_t rgb_blue;
    }RGB;
    #define TIMx TIM3
    #define TIMx_IRQn TIM3_IRQn
    #define TIMx_IRQHandler TIM3_IRQHandler
    #define TIM_PRESCALER ((36*10)-1) // 频率 200kHz
    #define TIM_PERIOD (2000-1) // 周期 2000/f_tim = 10ms
    #define RGB_RED (0) // 占空比
    #define RGB_GREEN (0) // 占空比
    #define RGB_BLUE (0) // 占空比
    #define TIM_RLED_PIN GPIO_PIN_0
    #define TIM_RLED_PORT GPIOB
    #define TIM_RLED_CHANNEL TIM_CHANNEL_3
    #define TIM_GLED_PIN GPIO_PIN_1
    #define TIM_GLED_PORT GPIOB
    #define TIM_GLED_CHANNEL TIM_CHANNEL_4
    #define TIM_BLED_PIN GPIO_PIN_5
    #define TIM_BLED_PORT GPIOB
    #define TIM_BLED_CHANNEL TIM_CHANNEL_2
    #define TIM_PWM_CLK_EN() __HAL_RCC_TIM3_CLK_ENABLE()
    #define TIM_PWM_GPIO_CLK_EN() __HAL_RCC_GPIOB_CLK_ENABLE()
    

    首先初始化定时器PWM相关参数,如代码段 26.3.2 所示。
    代码段 26.3.2 定时器 PWM 初始化(driver_timer.c)

    /*
    * 函数名:void TimerPWMInit(void)
    * 输入参数:无
    * 输出参数:无
    * 返回值:无
    * 函数作用:初始化定时器,输出频率 1Hz,占空比 50%的 PWMN 波
    */
    void TimerPWMInit(void) {
    TIM_ClockConfigTypeDef sClockSourceConfig;
    TIM_OC_InitTypeDef sConfig;
    // 定时器基本功能配置
    hpwm.Instance = TIMx; // 指定定时器 TIM3
    hpwm.Init.Prescaler = TIM_PRESCALER; // 预分频系数 PSC=360-1
    hpwm.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数
    hpwm.Init.Period = TIM_PERIOD; // 自动装载器 ARR 的值,ARR=2000-1
    // 72MHz 经过 360 分频后,定时器时钟为 200KHz,即计数器每间隔 5us 计数一次,从 0 计数到 ARR,经历 10ms
    hpwm.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 定时器时钟不从 HCLK 分频
    //hpwm.Init.RepetitionCounter = 0; // 重复计数器值,仅存在于高级定时器
    hpwm.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 不自动重新装载
    // 将 TIM3 按 PWM 模式初始化
    if (HAL_TIM_PWM_Init(&hpwm) != HAL_OK)
    {
    Error_Handler(); }
    // 定时器时钟源选择
    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; // 选用内部时钟作为定时器时钟源
    HAL_TIM_ConfigClockSource(&hpwm, &sClockSourceConfig);
    // 配置 PWM 的输出通道参数
    sConfig.OCMode = TIM_OCMODE_PWM1; // PWM 输出的两种模式:PWM1 当极性为低,CCR<CNT,输出低电平,反之高电平
    sConfig.OCPolarity = TIM_OCPOLARITY_LOW; // 设置极性为低(硬件上低电平亮灯)
    sConfig.OCFastMode = TIM_OCFAST_DISABLE; // 输出比较快速使能禁止(仅在 PWM1 和 PWM2 可设置)
    sConfig.Pulse = RGB_RED; // 在 PWM1 模式下,通道 3(RLED)占空比
    if (HAL_TIM_PWM_ConfigChannel(&hpwm, &sConfig, TIM_RLED_CHANNEL) != HAL_OK)
    {
    Error_Handler(); }
    sConfig.Pulse = RGB_GREEN; // 在 PWM1 模式下,通道 4(GLED)占空比
    if (HAL_TIM_PWM_ConfigChannel(&hpwm, &sConfig, TIM_GLED_CHANNEL) != HAL_OK)
    {
    Error_Handler(); }
    sConfig.Pulse = RGB_BLUE; // 在 PWM1 模式下,通道 2(BLED)占空比
    if (HAL_TIM_PWM_ConfigChannel(&hpwm, &sConfig, TIM_BLED_CHANNEL) != HAL_OK)
    {
    Error_Handler(); } }
    
    • 14行:选择配置哪一个定时器;
    • 15行:设置定时器时钟预分频系数PSC,这里设置为360-1,则72MHz经过360分频后,定时器时钟为200KHz,
      即定时器计数1次的时间为5us;
    • 16行:设置定时器计数方式,这里为向上计数:
    • 17行:设置自动装载器ARR的值,这里设置为2000-1,则计数器从0开始计数到2000,周期为10ms;
    • 20行:设置时钟分频,用于计数器工作时滤除高频干扰,本实验不涉及,任意即可;
    • 21行:设置重复计数器值,仅存在于高级定时器,这里使用的TIM2为通用定时器,不涉及;
    • 22行:设置是否定时器自动重新装载,本实验不需要自动装载;
    • 25~28行:将定时器按PWM功能初始化,同时该函数会调用“HAL_TIM_PWM_MspInit()”进行硬件相关初始化;
    • 31~32行:设置内部时钟作为定时器时钟源;
    • 35~36行:设置PWM的模式和极性。这里设置PWM1模式,极性为低,与LED灯低电平亮灯对应;此时,在周期和ARR确定的情况下,计数器CNT从0到CCR,输出低电平,LED灯亮,计数器CNT从CCR到ARR,输出高电平,LED灯灭。即,CCR值越小,占空比越大,灯越暗,CCR值越大,占空比越小,灯越亮,ARR值与亮度成正比;
    • 37行:输出比较快速模式,可减少输出延时,可以不使用禁止;
    • 38~54行:分别设置三色灯所对应的三个通道的占空比和前面的输出通道参数;当前占空比为0,后面代码再修改占空比值;

    然后覆写定时器PWM硬件相关初始化,如代码段 26.3.3 所示。因为蓝色LED灯PB5,需要重映射才能是TIM3_CH2功能,这里需要使能重映射相关的AFIO(Alternate function I/O)时钟,然后使用HAL函数“__HAL_AFIO_REMAP_TIM3_PARTIAL()”启动TIM3重映射,同时将PB5设置为复用功能,此时PB5才能作为TIM3_CH2功能。

    代码段 26.3.3 定时器 PWM 硬件相关初始化(driver_timer.c)

    /*
    * 函数名:void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
    * 输入参数:htim-TIM 句柄
    * 输出参数:无
    * 返回值:无
    * 函数作用:HAL_TIM_PWM_Init 回调硬件初始化
    */
    void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
    {
    GPIO_InitTypeDef GPIO_InitStruct;
    TIM_PWM_CLK_EN(); // PWM 所涉及的 TIM3 时钟使能
    TIM_PWM_GPIO_CLK_EN(); // PWM 所涉及的 GPIOB 时钟使能
    __HAL_RCC_AFIO_CLK_ENABLE(); // 重映射涉及时钟使能
    __HAL_AFIO_REMAP_TIM3_PARTIAL(); // 启用 TIM3 重映射
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输出
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Pin = TIM_RLED_PIN;
    HAL_GPIO_Init(TIM_RLED_PORT, &GPIO_InitStruct); // 初始化红灯引脚
    GPIO_InitStruct.Pin = TIM_GLED_PIN;
    HAL_GPIO_Init(TIM_GLED_PORT, &GPIO_InitStruct); // 初始化绿灯引脚
    GPIO_InitStruct.Pin = TIM_BLED_PIN;
    HAL_GPIO_Init(TIM_BLED_PORT, &GPIO_InitStruct); // 初始化蓝灯引脚
    HAL_NVIC_SetPriority(TIMx_IRQn, 0, 0); // 配置定时器中断优先级
    HAL_NVIC_EnableIRQ(TIMx_IRQn); // 使能 TIM3 中断
    }
    
    1. TIM中断处理函数
      当定时器TIM3计数溢出时,会进入中断处理“TIM3_IRQHandler()”,在中断函数里,根据RGB值,设置比较寄存器CCR的值,也就实现了修改占空比,如代码段 26.3.4 所示。
      代码段 26.3.4 TIM3 中断处理函数(driver_timer.c)
    /*
    * 函数名:void TIM3_IRQHandler(void)
    * 输入参数:无
    * 输出参数:无
    * 返回值:无
    * 函数作用:TIM3 中断的中断处理函数
    */
    void TIM3_IRQHandler(void) {
    HAL_TIM_IRQHandler(&hpwm); }
    /*
    * 函数名:void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
    * 输入参数:htim-TIM 句柄
    * 输出参数:无
    * 返回值:无
    * 函数作用:TIM 中断回调周期更新函数
    */
    void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
    {
    if(htim->Instance == TIMx) {
    // 根据 R G B 值,修改对应通道的比较寄存器 CCR 的值(占空比)
    __HAL_TIM_SET_COMPARE(&hpwm, TIM_RLED_CHANNEL, rgb.rgb_red *2000/255);
    __HAL_TIM_SET_COMPARE(&hpwm, TIM_GLED_CHANNEL, rgb.rgb_green*2000/255);
    __HAL_TIM_SET_COMPARE(&hpwm, TIM_BLED_CHANNEL, rgb.rgb_blue *2000/255); }
    }
    

    这里简单补充下一些色彩理论知识,常见的色彩定义标准有四种:
    ①HSB:基于人眼视觉的颜色模式;
    ②RGB:基于光色的颜色模式,是加色模式,两者组合变亮;
    ③CMYK:基于印刷颜料的颜色模式,是减色模式,两者组合变暗;
    ④Lab:基于人对颜色的感觉,与设备无关,色域宽阔;
    在这里插入图片描述
    LED灯属于发光色,RGB三个颜色通道的变化,以及它们相互之间的叠加来得到各式各样的颜色的,几乎包括了人类视力所能感知的所有颜色,RGB色彩定义:

    • R(Red):0~255阶,一共256阶色;
    • G(Green):0~255阶,一共256阶色;
    • B(Blue):0~255阶,一共256阶色;
      因此,这里把每个颜色的LED灯最暗用0表示,LED灯最亮用255表示,而整个计数周期为2000,因此传入的比较寄存器值为:
      在这里插入图片描述

    最后使用“__HAL_TIM_SET_COMPARE()”,根据颜色色阶,设置每个通道的比较寄存器值。

    1. 按键功能
      根据需求,这里使用按键进行模式切换和RGB颜色调整。初始化按键后,在按键中断处理函数中添加每个按键的功能,如代码段 26.3.5 所示

    代码段 26.3.5 按键中断处理回调函数(driver_key.c)

    /*
    * 函数名:void HAL_GPIO_EXTI_Callback(void)
    * 输入参数:无
    * 输出参数:无
    * 返回值:无
    * 函数作用:外部中断处理函数的回调函数,用以处理不同引脚触发的中断服务最终函数
    */
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
    if(GPIO_Pin == KEY_UP_GPIO_PIN) // 按键 Up(KEY1)切换模式
    {
    step = !step;
    rgb.rgb_red = 0; // 模式切换后,先关闭所有灯
    rgb.rgb_green = 0;
    rgb.rgb_blue = 0; }
    if(GPIO_Pin == KEY_LEFT_GPIO_PIN) // 按键 Left(KEY3)调整红色 R {
    if (rgb.rgb_red > 255)
    rgb.rgb_red = 0;
    rgb.rgb_red = rgb.rgb_red + 10; }
    if(GPIO_Pin == KEY_DOWN_GPIO_PIN) // 按键 Down(KEY2)调整绿色 G {
    if (rgb.rgb_green > 255)
    rgb.rgb_green = 0;
    rgb.rgb_green = rgb.rgb_green + 10; }
    if(GPIO_Pin == KEY_RIGHT_GPIO_PIN) // 按键 Right(KEY4)调整蓝色 B {
    if (rgb.rgb_blue > 255)
    rgb.rgb_blue = 0;
    rgb.rgb_blue = rgb.rgb_blue + 10; } }
    
    • 10~17行:当按键KEY1_UP按下后,修改模式标志位setp,同时清除RGB的初始值;
    • 19~24行:当按键KEY3_LEFT按下后,增加红色LED灯亮度(占空比);
    • 26~31行:当按键KEY2_DOWN按下后,增加绿色LED灯亮度(占空比);
    • 19~24行:当按键KEY3_RIGH按下后,增加蓝色LED灯亮度(占空比);
    1. 主函数控制逻辑
      在主函数里依次初始化时钟、串口、按键,定时器PWM等,便可以启动PWM输出了,如代码段 26.3.6所示。

    代码段 26.3.6 主函数控制逻辑(main.c)

    // 初始化定时器 2 输出 PWM
    TimerPWMInit();
    if (HAL_TIM_PWM_Start_IT(&hpwm, TIM_RLED_CHANNEL) != HAL_OK) // 启动红色 LED 所在通道定时器 PWM
    {
    Error_Handler(); }
    if (HAL_TIM_PWM_Start_IT(&hpwm, TIM_GLED_CHANNEL) != HAL_OK) // 启动绿色 LED 所在通道定时器 PWM
    {
    Error_Handler(); }
    if (HAL_TIM_PWM_Start_IT(&hpwm, TIM_BLED_CHANNEL) != HAL_OK) // 启动蓝色 LED 所在通道定时器 PWM
    {
    Error_Handler(); }
    while(1) {
    if(step==0) // 随机模式:三色灯随机变换颜色(默认模式) {
    rgb.rgb_red = rand()%256;
    rgb.rgb_green = rand()%256;
    rgb.rgb_blue = rand()%256;
    HAL_Delay(1000); }
    else // 用户模式:用户使用按键控制 RGB 颜色
    {
    // 在按键中断中修改 R G B 值
    // 在 TIM 中断中修改占空比
    rgb.rgb_red = rgb.rgb_red%256;
    rgb.rgb_green = rgb.rgb_green%256;
    rgb.rgb_blue = rgb.rgb_blue%256; } }
    
    • 2行:初始化定时器PWM;
    • 4~7行:使用带中断的方式启动定时器PWM,传入红色LED所在通道;
    • 8~11行:使用带中断的方式启动定时器PWM,传入绿色LED所在通道;
    • 12~15行:使用带中断的方式启动定时器PWM,传入蓝色LED所在通道;
    • 17行~34行:主循环
    • 19-25行:如果KEY1_UP按下,则中断会修改step为1,进入该判断中;使用C库的“rand()”函数产生一个随机数,然后使用“%”取余,得到一个1~255之间的随机数,该随机数作为颜色色阶,定时器PWM中断产生后,便以此值作为占空比,实现LED亮度的修改;
    • 26~33行:用户模式下,无需任何操作,在按键中断中修改RGB值,在TIM中断中修改占空比,实现用户分别控制RGB亮度;

    26.4 实验效果

    本实验对应配套资料的“5_程序源码\18_定时器—PWM输出\”。打开工程后,编译,下载,串口提示如图 26.4.1 所示。
    在这里插入图片描述

    此时可以看到三色LED灯显示随机颜色(注意不要长时间直视三色灯,可使用薄纸巾盖住观察),按下KEY1_UP键后,三色LED不再随机变化,分别按下KEY3_LEFT、KEY2_DOWN、KEY4_RIGH可分别控制红色、绿色、蓝色的亮度。


    百问网技术论坛:
    http://bbs.100ask.net/

    百问网嵌入式视频官网:
    https://www.100ask.net/index

    百问网开发板:
    淘宝:https://100ask.taobao.com/
    天猫:https://weidongshan.tmall.com/

    技术交流群2(鸿蒙开发/Linux/嵌入式/驱动/资料下载)
    QQ群:752871361

    单片机-嵌入式Linux交流群:
    QQ群:536785813

    韦东山嵌入式培训班交流群③
    QQ群:717041375

    展开全文
  • STM32使用定时器输出pwm到指定io口
  • 基于STM32定时器产生PWM的研究.doc
  • stm32定时器输出PWM波仿真频率不正确

    千次阅读 2020-08-04 16:26:11
    1.用stm32写了个简单的pwm波输出程序,仿真发现输出的频率为设置的一半,查看了设置的值没问题 TIM2_PWM_Init(7199,0); 频率=72000000/((psc+1)*(arr+1)) 结果波形为: 周期为20ms,即频率为5000Hz,差了一半 2....

    QUESTION1.用stm32写了个简单的pwm波输出程序,仿真发现输出的频率为设置的一半,查看了设置的值没问题

    TIM2_PWM_Init(7199,0);
    

    频率=72000000/((psc+1)*(arr+1))
    结果波形为:
    在这里插入图片描述
    周期为0.2ms,即频率为5000Hz,差了一半

    **解决方法:**后面无意间去翻SystemInit();文件,发现我用的之前别人的工程模板,里面的默认频率设置为36MHz
    在这里插入图片描述
    注释掉36MHz那一行,把72MHz那一行取消注释,再输出波形正常了,周期为10ms,即频率10KHZ
    在这里插入图片描述
    结果:
    在这里插入图片描述

    QUESTION2:设定的定时器3输出50HZ方波,但是用keil仿真出的方波频率是74HZ左右的;

    Motor_PWM_Init(19999,71);   //初始化定时器输出方波频率50HZ
    while(1)
    	{
    		TIM_SetCompare1(TIM3,3000);  //输出通道1波形
    		TIM_SetCompare2(TIM3,3000);
    		TIM_SetCompare3(TIM3,3000);
    		TIM_SetCompare4(TIM3,3000);		
    	}
    

    仿真图形如下,频率为74HZ左右:
    在这里插入图片描述
    查看SystemInit()里面的配置也是正确的;
    解决方法:查看MDK软件里面的外部晶振频率设置是否正确?
    在这里插入图片描述
    看了看我的stm32外部晶振是8MHz的,将其改为8MHz再次仿真:
    结果正确:
    在这里插入图片描述

    展开全文
  • 基于-STM32定时器产生PWM的研究.doc
  • 基于STM32定时器产生PWM的研究报告.doc
  • 1.PWM的工作原理 2.PWM的内部运作机制 3.PWM的模式 ...5.定时器输出PWM结构体讲解 ...6.定时器输出PWM库函数讲解 ...#include "stm32f10x.h" // Device header #include "motor.h" void motor_co..
  • stm32除了TIM6~TIM7(基本定时器)之外,其他都可以产生PWM波输出、 ②通用寄存器:TIM2~TIM5,每个定时器都有四个独立通道可以作为:输入捕获、输出比较、PWM输出、单脉冲模式输出 ③高级定时器TIM1、TIM8可以...
  • STM32定时器学习-PWM输出

    千次阅读 2022-03-03 10:57:10
    基本定时器 最基础功能定时,两个基础定时器TM6和TM7,基本定时器时钟源只来自内部时钟。 如果我们想要一个1s的定时,那么我们应该怎么设置定时器呢?... uint32_t Period; // 定时器周期 uint16_t ClockDi
  • 使用的开发环境为kei5.采用定时器的方式,同时输出4路pwm波形,芯片型号,和芯片引脚根据自己的设备修改
  • 通过stm32单片机定时器产生PWM波,实现LED灯的调光
  • STM32F4的定时器4输出4 路PWM波(寄存器版)
  • 最近在做电机控制 ,看到一篇好总结!! 比较输出模式 这个模式的特点是4个通道的输出周期频率是一样的.....PWM模式下,CCRx控制的是高电平的计数周期.初相位不可调,脉宽可调 ————————————
  • 最小值和最大值之间存在一个自定的值,当计数器的值小于自定值时,I/O输出低电平,大于自定值则产生高电平。通过设置不同的最大值和自定值,可以控制I/O口输出不同时间宽度的高低电平。 定义GPIO结构体 RCC_AHB1...
  • PWM输出 脉冲宽度调制模式可以生成一个信号,该信号频率由TIMx_ARR自动重载寄存器值决定,其占空比则由TIMx_CCRx捕获比较寄存器值决定。 通过向TIMx_CCMRx寄存器中的OCxM位写入110(PWM模式1)或111(PWM模式2)...
  • 基于STM32定时器PWM实验教学.pdf
  • STM32 定时器捕获PWM波 以及占空比
  • 1.初始化 1.定义相关变量 GPIO_InitTypeDef GPIO_InitStructure;...2.打开定时器和GPIO时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,
  • stm32定时器功能十分强大,这是stm32定时器高级用法之一:pwminput模式。在学习过程中我们经常使用输入捕获模式来捕获pwm信号,这种方法适合捕获低频和占空比区中的波形,在捕获相对高频和占空比1%或者说99%这些...
  • stm32使用定时器输出PWM

    千次阅读 2021-06-25 15:34:23
    而通用定时器也能同时产生多达 4路的 PWM 输出,这样,STM32 最多可以同时产生 30 路 PWM 输出!这里我们仅利用 TIM3的 CH2 产生一路 PWM 输出。 1:定时器产生PWM原理 在PWM输出模式下,除了CNT(计数器当前值)...
  • 函数功能:定时器1通道1 4产生PWM波 函数参数:无 函数返回值:无 函数描述:无 */ void Dingshiqi1_PWM_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; //时间基 结构体变量 GPIO_InitTypeDef ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,349
精华内容 4,139
关键字:

stm32定时器产生pwm波