精华内容
下载资源
问答
  • 只需一路定时器的输入捕获即可精确地测量 PWM 频率和占空比,测试精度与定时器的频率有关,测试结果使用串口1打印出来,单位为 us
  • 1.PWM的工作原理 2.PWM的内部运作机制 3.PWM的模式 模块一 边沿对齐模式 模块二 中央对齐模式 4.自动加载的预加载寄存器 5.定时器输出PWM结构体讲解 6.定时器输出PWM库函数讲解 定时器...

    1.PWM的工作原理

    2.PWM的内部运作机制

    3.PWM的模式

    模块一  边沿对齐模式

    模块二 中央对齐模式

    4.自动加载的预加载寄存器

    5.定时器输出PWM结构体讲解

    6.定时器输出PWM库函数讲解

     

    定时器输出PWM+控制舵机

    按步骤去配置

    motor.c
    #include "stm32f10x.h"                  // Device header
    
    #include "motor.h"
    
    void motor_config(void)
    {
    		GPIO_InitTypeDef GPIO_MotorInit;  //1.GPIO结构体
    		TIM_TimeBaseInitTypeDef TIM_MotorInit; //2.配置通用定时器结构体
    		TIM_OCInitTypeDef TIMPWN_MotorInit;    //3.配置定时去输出PWM结构体   +下边的 TIM_OC2Init  TIM_OC2PreloadConfig  TIM_Cmd
    	
    		RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB,  ENABLE); //4.1 打开GPIO时钟
    		RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3,  ENABLE);	//4.2 打开定时器时钟
    		RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO,  ENABLE);	//复用使能时钟
    
    		GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3 , ENABLE );	//4.3 部分重映射时钟
    
    	
    		GPIO_MotorInit.GPIO_Mode  =  GPIO_Mode_AF_PP;//复用推挽输出
    		GPIO_MotorInit.GPIO_Pin   =	 GPIO_Pin_5;
    		GPIO_MotorInit.GPIO_Speed =  GPIO_Speed_50MHz;
    		
    	  GPIO_Init( GPIOB, &GPIO_MotorInit );
    	
    		TIM_MotorInit.TIM_ClockDivision =  TIM_CKD_DIV1;					//设置时钟分割
    		TIM_MotorInit.TIM_CounterMode 	=	 TIM_CounterMode_Up;		//计数模式 TIM向上计数
    		TIM_MotorInit.TIM_Period 				=  200 - 1 ;              //重装载值 设置在下一个更新事件装入活动的重装载值
    		TIM_MotorInit.TIM_Prescaler 		=  7200 - 1 ;							//预分频 TIMx时钟频率预分频值
    
    		TIM_TimeBaseInit( TIM3, &TIM_MotorInit);
    	
    		TIMPWN_MotorInit.TIM_OCIdleState = TIM_OCMode_PWM1;					//选择定时器模式1
    		TIMPWN_MotorInit.TIM_OutputState = TIM_OutputState_Enable;	//比较输出使能
    		TIMPWN_MotorInit.TIM_OCPolarity  = TIM_OCPolarity_Low;			//选择有效输出极性
    	
    		TIM_OC2Init( TIM3,	&TIMPWN_MotorInit ); //选择的是定时器3的通道2 所以用OC2
    		TIM_OC2PreloadConfig( TIM3,  TIM_OCPreload_Enable); //自动加载的预加载寄存器 使能
    		TIM_Cmd( TIM3,  ENABLE);
    
    
    
    }
    motor.h
    #include "stm32f10x.h"                  // Device header
    
    void motor_config(void);
    
    main.c
    #include "stm32f10x.h"                  // Device header
    #include "usart.h"
    #include "led.h"
    #include "tim.h"
    #include "motor.h"
    
    void delay(uint16_t time)
    {
    		uint16_t i = 0;
    		while(time--)
    		{
    			i=12000;
    			while(i--);
    		}
    }
    
    int main(void)
    {
    	uint16_t pwmval = 155;   //  大约3/4  155/200
    	
    	motor_config();
    		
    
    		while(1)
    		{
    			for(pwmval = 195;pwmval >= 175;pwmval-=5)
    			{
    				
    			 TIM_SetCompare2( TIM3,  pwmval);   //5. 配置PWM比较值
    				delay(500);//0.5s
    				
    
    			}
    			
    		}
    }

     

    展开全文
  • STM32CubeMX-定时器产生PWM驱动舵机

    千次阅读 多人点赞 2021-05-03 19:42:18
    STM32CubeMX-使用cube配置定时器产生PWM驱动舵机

    STM32CubeMX笔记-定时器产生PWM驱动舵机

    一、初始准备

    1.硬件平台

    使用正点原子STM32F4探索者

    在这里插入图片描述

    2.软件平台

    STM32CubeMX软件平台

    Keil5软件平台

    STM32CubeProgrammer下载平台
    在这里插入图片描述

    二、操作步骤

    1.CubeMX生成初始化代码

    1.1 建立工程(通用步骤)

    • 芯片选择

    打开cube软件,点击MCU选择
    在这里插入图片描述
    F4探索者的主控为STM32F407ZET6,所以在搜索框找到STM32F407ZE后点击具体芯片,再开始工程
    在这里插入图片描述

    • 配置时钟源

    我们点开SystemCore(系统内核设置),再点击RCC配置HSE和LSE时钟源,这里我都选择使用外部时钟,配置后,我们可以看到右边芯片引脚分配图的两个时钟源引脚点亮,表示配置完成
    在这里插入图片描述

    • 配置时钟树

    我们进入ClockConfiguration配置时钟树,使时钟的输入路径和大小符合我们预期,精英板的晶振和时钟倍频如下

    在这里插入图片描述

    一般配置正确时颜色蓝白为主,配置错误时则会出现紫色,提示我们要修改值

    在这里插入图片描述

    1.2 PWM配置步骤

    • 查看原理图引脚

    我们使用定时器3的通道1,默认映射IO口为PA6
    在这里插入图片描述

    • 配置TIM为PWM

    配置界面找到Timers配置栏,点击TIM3

    在这里插入图片描述
    配置TIM3时钟为内部时钟(internal clock),同时选择通道1为PWM模式(PWM Generation CH1)

    在这里插入图片描述
    配置TIM3的具体参数,主要为分频值和重装载值,修改分频值为720对应一个计数为1/(72M/分频值)=10us,重装载值为2000,使一个PWM的周期为2000*1us=20ms一个周期,符合舵机50hz频率驱动要求

    在这里插入图片描述

    1.3生成代码(通用步骤)

    点击进入Project Manager 配置生成工程的名字,存储路径**(不要有中文)**以及编译器,这里我们选MDK-ARM(Keil被收购后改名)
    在这里插入图片描述
    配置生成选项,主要为下面三大块,第一个我们选择只拷贝必要的库,第二个选择为每个外设生成.c和.h文件,保存之前的用户代码,以及删除之前的生成代码,第三个不选择

    PS:用户代码段是一下注释之间的代码,只有原始的用户代码段注释才有效,用户自己添加的无效

    /* USER CODE BEGIN 1 */
    
    /* USER CODE END 1 */
    

    在这里插入图片描述
    最后点击生成代码
    在这里插入图片描述

    2.编写代码

    打开MDK,在主函数中用户代码段编写如下代码:

    /* USER CODE BEGIN 2 */
      HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
    /* USER CODE END 2 */  
    /* USER CODE BEGIN WHILE */
      while (1)
      {
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
    		__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,100);
    		HAL_Delay(1000);
    		__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,150);
    		HAL_Delay(1000);
    		__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,200);
    		HAL_Delay(1000);
    		__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,150);
    		HAL_Delay(1000);
    		__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,100);
    		HAL_Delay(1000);
      }
      /* USER CODE END 3 */
    

    其中HAL_TIM_PWM_Start用于开启使用到的定时器通道;__HAL_TIM_SET_COMPARE为设置定时器通道比较值的调用函数,传入参数依次为为定时器编号、通道编号、设置的比较值;代码编写完成后,点击编译,编译结果无报错

    在这里插入图片描述

    3.程序下载,观察现象(通用步骤)

    程序下载我一般用两种方式:

    第一种是使用MDK自带的下载环境下载程序,我们给单片机连接ST-Link后配置下载,点击魔术棒,选择debug

    在这里插入图片描述

    选择ST-link后,点击setting

    在这里插入图片描述

    添加对应F4的Flash

    在这里插入图片描述

    keil界面点击下载

    在这里插入图片描述

    第二种是使用Stm32Programmer下载软件,该下载软件下载方式多,下载快,下面我使用st-link下载

    打开软件,点击connect左边选择stlink后再点击connect连接下载器

    在这里插入图片描述

    点击open file,找到工程路径下MDK文件夹下工程生成的hex文件

    在这里插入图片描述

    之后点击downlod下载,下载结果如下

    在这里插入图片描述

    3.实验现象

    舵机循环转动:

    请添加图片描述

    请添加图片描述
    请添加图片描述

    展开全文
  • 通用定时器产生PWM

    2020-01-07 23:16:30
    STM32F1除了基本定时器TIM6和TIM7,其他定时器都可以产生PWM输出:其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出,而通用定时器也能同时产生多达 4路的 PWM 输出。 PWM的输出其实就是对外输出脉宽...

    一、STM32F103 PWM介绍
    STM32F1除了基本定时器TIM6和TIM7,其他定时器都可以产生PWM输出:其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出,而通用定时器也能同时产生多达 4路的 PWM 输出。
    PWM的输出其实就是对外输出脉宽可调(即占空比调节)的方波信号,信号频率是由自动重装寄存器ARR的值决定,占空比由比较寄存器CCR的值决定。
    PWM输出比较模式总共有8种,具体由寄存器 CCMRx 的位 OCxM[2:0]配置。这里只讲解最常用的两种PWM输出模式:PWM1和PWM2。PWM1和PWM2这两种模式用法差不多,区别之处就是输出电平的极性不同。
    在这里插入图片描述
    二、PWM输出配置步骤
    (1)使能定时器及端口时钟,并设置引脚复用器映射

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);	//使能定时器时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//使能引脚复用时钟
    GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);	//TIM3完全重映射
    

    在这里插入图片描述
    (2)初始化相应的GPIO,模式选复用推挽输出
    (3)初始化定时器参数,包含自动重装值,分频系数,计数方式等

    void TIM_TimeBaseInit(TIM_TypeDef*  TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);  //TIMx为对应的定时器,TIM_TimeBaseInitStruct为配置结构体
    

    (4)初始化PWM输出参数,包含PWM模式、输出极性,使能等

    void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);	//TIM_OCInitStruct为配置结构体
    //TIM_OCInitTypeDef的部分成员
    typedef struct{
    	uint16_t TIM_OCMode;        //比较输出模式
    	uint16_t TIM_OutputState;   //比较输出使能
    	uint16_t TIM_OCPolarity;    //输出极性
    }TIM_OCInitTypeDef; 	
    
    TIM_OCMode描述
    TIM_OCMode_PWM1TIM脉宽宽度调制模式1
    TIM_OCMode_PWM2TIM脉宽宽度调制模式2
    TIM_OutputState比较输出使能/失能
    TIM_OutputState_Enable使能
    TIM_OutputState_Disable失能
    TIM_OCCPolarity输出极性
    TIM_OCPlarity_High高电平有效
    TIM_OCPlarity_Low低电平有效

    (5)开启定时器

    TIM_Cmd(TIM3,ENABLE); //开启定时器
    

    (6)使能TIMx在CCRx上的预装载寄存器

    //第一个参数用于选择定时器,第二个参数用于选择使能还是失能输出比较预装载寄存器,可选择为TIM_OCPreload_Enable、TIM_OCPreload_Disable。
    void TIM_OCxPreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
    

    (7)使能 TIMx 在 ARR 上的预装载寄存器允许位

    //第一个参数用于选择定时器,第二个参数用于选择使能还是失能。
    void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
    

    (8)修改TIMx_CCRx的值控制占空比

    //第一个参数用于选择定时器,第二个参数用于控制占空比
    void TIM_SetCompare1(TIM_TypeDef* TIMx, uint32_t Compare1); 
    

    三、总结写法如下

    /******************************
    函数名:void TIM3_PWM_Init(u16 pre,u16 psc);
    参数:pre为周期,psc为预分频
    功能:使用通用定时器TIM3产生四路pwm,因使用完全重映射,故输出引脚分别为PC6、PC7、PC8、PC9
    *******************************/
    void TIM3_PWM_Init(u16 pre,u16 psc){
    	GPIO_InitTypeDef GPIO_initStructure;			//GPIO配置结构体
    	TIM_TimeBaseInitTypeDef TIM_InitStructure;		//定时器配置结构体
    	TIM_OCInitTypeDef TIM_OCInitTypeDefStructure;		//PWM输出参数配置结构体
    	
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);	//使能定时器时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);	//使能GPIOC时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//使能复用功能时钟
    	
    	GPIO_initStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;
    	GPIO_initStructure.GPIO_Mode = GPIO_Mode_AF_PP;		//复用推挽输出
    	GPIO_initStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOC,&GPIO_initStructure);			//初始化GPIO
    	
    	GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);	//复用使能,完全重映射
    	
    	TIM_InitStructure.TIM_Period = pre;			//定时器周期
    	TIM_InitStructure.TIM_Prescaler = psc;			//定时器预分频器
    	TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;	//时钟分频
    	TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//计数模式
    	TIM_TimeBaseInit(TIM3,&TIM_InitStructure);		//初始化TIM3
    	
    	TIM_OCInitTypeDefStructure.TIM_OCMode = TIM_OCMode_PWM1;		//PWM输出模式
    	TIM_OCInitTypeDefStructure.TIM_OCPolarity = TIM_OCPolarity_High;		//输出极性,根据实际需要更改
    	TIM_OCInitTypeDefStructure.TIM_OutputState = TIM_OutputState_Enable;	//使能比较输出
    	
    	TIM_OC1Init(TIM3,&TIM_OCInitTypeDefStructure);		//初始化通道1PWM输出
    	TIM_OC2Init(TIM3,&TIM_OCInitTypeDefStructure);  	//初始化通道2PWM输出
    	TIM_OC3Init(TIM3,&TIM_OCInitTypeDefStructure);  	//初始化通道3PWM输出
    	TIM_OC4Init(TIM3,&TIM_OCInitTypeDefStructure);  	//初始化通道4PWM输出
    	
    	TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);	//使能TIM3在CCR1上的预装载寄存器
    	TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);	//使能TIM3在CCR2上的预装载寄存器
    	TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Enable); 	//使能TIM3在CCR3上的预装载寄存器
    	TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Enable); 	//使能TIM3在CCR4上的预装载寄存器
    	TIM_ARRPreloadConfig(TIM3,ENABLE); 			//使能 TIMx 在 ARR 上的预装载寄存器允许位
    	
    	TIM_Cmd(TIM3,ENABLE);					//开启定时器
    }	
    
    //在main中调用函数修改占空比
    void TIM_SetCompare1(TIM_TypeDef* TIMx, uint32_t Compare1);	//修改通道1占空比
    void TIM_SetCompare2(TIM_TypeDef* TIMx, uint32_t Compare2); 	//修改通道2占空比
    void TIM_SetCompare3(TIM_TypeDef* TIMx, uint32_t Compare3); 	//修改通道3占空比
    void TIM_SetCompare4(TIM_TypeDef* TIMx, uint32_t Compare4); 	//修改通道4占空比
    

    占空比计算: 占空比 = Compare1 / pre * 100%

    展开全文
  • 用STM32CubeMx学习stm32; 使用cube配置,IAR或者Keil编程, 学习STM32定时器中断以及用STM32的定时器产生PWM

    定时器中断及定时器产生PWM


    《用CubeMX学习STM32》

    注释 点击上面蓝字进入完整专栏,这个系列所有文章都会整合到这个专栏

    4、STM32定时器中断以及定时器PWM

    前言: STM32定时器概述
      我演示用的STM32F407ZGt6的核心板有多达14个定时器;  其中包含两个高级定时器(TIM1和TIM8); 十个通用定时器(TIM2~TIM5, TIM9~TIM14); 两个基础定时器(TIM6、TIM7)。

    Tips: 在十个通用定时器里面包含两个看门狗定时器(two watchdog timers)

    下面是datasheet里面官方给出的介绍

    在这里插入图片描述

    Couter resolution—> 计数器位数, 位数越高精度越高;
    Counter type —> 计数类型 即向上计数还是向下计数
    Prescaler factor —> 分频因子, 对时钟的分频, 比如单片机的时钟为84MHz, 预分频系数为4的话, 那定时器的计数器所能用的的就是21MHz了


      本文以用的比较多的通用定时器介绍, 用TIM3;

    (1)主要涉及到的寄存器为
    •    计数器寄存器 (TIMx_CNT)
    •    预分频器寄存器 (TIMx_PSC)
    •    自动重载寄存器 (TIMx_ARR)
      在这里插入图片描述
      太细致的寄存器相关的就不扯了, 看了也是忘, 多用自然会了然于心
    (2)关于计数模式

    以向上计数为例:

    计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。 我们可以在这个溢出事件进入中断, 只要使能中断, 那么溢出事件这个点就会进入中断, 我们只要在中断服务函数中写自己要做的功能, 这就是定时器中断了

    溢出时间计算

    Tout = ((ARR + 1)*(PSC + 1)) / Tclk
    Tout: 溢出时间(us);  Tclk: 定时器的输入时钟频率(MHz);  ARR和PSC的值都在1~65535这个范围

    在这里插入图片描述
    如图中所示, PSC(预分频系数)决定计数周期, ARR(自动重装载值) 确定那个时刻发生溢出

    下面开始Cube配置+IAR编程


    4.1 操作简介

       (1) 定时器中断, 在中断中做点灯操作。使用向上计数模式;  每 200ms LED0翻转一次

       (2) 定时器产生PWM


    4.2 定时器中断

    在主函数的while(1) 里面我们什么都不做, 只在中断里面让LED闪烁。

    Step1 : Cube配置

    • (1) 新建工程
       在新建的工程里面这一次先配置时钟树, 因为我们需要先配置好时钟频率然后计算定时器参数。

      • tips: 配置时钟树之前别忘了先把RCC和SYS勾选好
        在这里插入图片描述
      • 接着配置时钟树
        在这里插入图片描述
    • (2) TIM3配参数置

      • 1、 计算200ms的溢出时间所需要配置的ARR和PSC的值的大小
          通过查阅datatsheet可以知道, TIM3的时钟挂接在APB1总线上, 所以就使用APB1总线时钟频率(84MHz)进行分频
        在这里插入图片描述
        而我们用CubeMx配置的时钟树里面APB1是84MHz, 根据前面的公式:
        Tout = ((ARR + 1)*(PSC + 1)) / Tclk
        已知 Tclk 为 84MHz , 我们需要 Tout 为 200ms 即 200000us , 不妨先让PSC为 839, 带入上述公式可得 ARR = 19999. 这样算出来之后ARR和PSC都在0~65535的范围, 则可以使用这组参数
        *注 :*这个过程最好自己算一下; 还有就是ARR和PSC都是16位的寄存器, 数值一定要在0~65535这个范围
    下面是TIM3的具体配置

    在这里插入图片描述

    因为我们用到TIM3的中断, 所以不要忘记勾选中断使能; 可以在TIM3的NVIC Setting里面使勾选也可以在System Core里面勾选
    在这里插入图片描述

    关于 Priority Group(中断优先级分组)

    在这次的学习中随便设置, 前面的博客也说了, 这个分组主要用于多个定时器中断的时候, 为了各个定时器中断不互相干扰, 而给每个定时器中断排个号, 大家按顺序来;
    按图中的配置解释一下, 2位用于抢占优先级和2位用于子优先级就是抢占优先级可以为0~3, 子优先级也可以为0~3;
    在二进制中, 00就是0, 11就是3, 所以两位数可以表示0~3;

    注 : 优先级大小 0 > 1 > 2 > 3

    中断事件Preemption PrioritySub Priority
    E120
    E221
    E310

      这个表格表示:
        1、 当 E1 和 E2 中断发生时, 若 E3 发生中断, 则可以打断 E1 和 E2 的中断, 因为 E3 的抢占优先级是三者最高的;
        2、 对于抢占优先级相同的E1和E2事件, 若E1 中断正在执行, E2 中断的到来不可以打断 E1 , 等 E1 执行完再去执行 E2 的中断; 反之亦然, 只要抢占优先级一样, 那么谁先发生就先执行谁, 不用比较Sub Priority
        3、 E1 和 E2, 若同时到来, 这个时候才考虑Sub Priority, 先执行E1再执行E2

    • (3) 其他引脚的配置
        我们要在中断里面翻转LED, 所以配置一下LED灯即可
      在这里插入图片描述

    • (4) 工程配置(与前面的类似)
      在这里插入图片描述

    • (5) Generate Code
      在这里插入图片描述


    Step2 : IAR或Keil编程

    • (1) 先看一下tim.c 里面的初始化写了些什么
      在这里插入图片描述
      在这里插入图片描述

    • (2) 写入用户代码

      • 在主函数里面开启定时器中断
      /* USER CODE BEGIN 2 */
      HAL_TIM_Base_Start_IT(&htim3);
      
      /* USER CODE END 2 */
      

      注 : 要使用定时器中断一定要自己在主函数里面用代码打开, cubeMX配置的只是初始化参数, 是否打开取决于用户

      • 写中断服务函数
      在 stm32f4xx_it.h 里面找到 void TIM3_IRQHandler(void); 然后Go To Definition查看定义
      /**
      * @brief This function handles TIM3 global interrupt.
      */
      void TIM3_IRQHandler(void)
      {
          /* USER CODE BEGIN TIM3_IRQn 0 */
      
          /* USER CODE END TIM3_IRQn 0 */
          HAL_TIM_IRQHandler(&htim3);
          /* USER CODE BEGIN TIM3_IRQn 1 */
      
          /* USER CODE END TIM3_IRQn 1 */
      }
      
      再查看 HAL_TIM_IRQHandler() 的定义

    在这里插入图片描述
      可以看到, 对于更新中断事件, 最终是执行的 HAL_TIM_PeriodElapsedCallback() 这个回调函数, 所以我们只需重构这个回调函数, 在里面写入自己的代码
    在这里插入图片描述

    • (3) 重构中断回调函数
        我们把对回调函数的重构写在tim.c 里面, 便于查看也便于以后修改什么的
      在这里插入图片描述
    /* USER CODE BEGIN 1 */
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
        // 如果是定时器3的中断
        if (htim == (&htim3))
        {
            // 翻转LED0的引脚; 下面两句是等价的, main.h 有对应宏定义
            HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
            //HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10);
        }
    }
    
    /* USER CODE END 1 */
    
    • (4) 编译下载
      实际效果如动图所示
      在这里插入图片描述

       验证LED灯是每200ms翻转一次, 需要用示波器查看LED0对应引脚的波形数据
    在这里插入图片描述
    可以看到正频宽是200ms, 负频宽也是200ms, 所以跟我们预期的计算结果是一样的, 完美。


    4.3 定时器产生PWM

    操作简介 : 通过STM32定时器产生的PWM, 让LED灯做出呼吸灯的效果;
    参考正点原子开发指南, 用CubeMX完成其标准库的程序配置
    PWM(Pulse Width Modulation): 即脉冲宽度调制

    在这里插入图片描述
      这个是以向上计数比较的, 当定时器计数器向上计数到CCRx之前, IO口一直输出0, 从到达CCRx开始输出1, 到ARR时溢出,重新计数。
      IO口输出高低电平就用0和1表示。
      显然, 如果改变CCRx值的大小, 就可以变化IO输出的PWM波形的占空比; 改变ARR(自动重装载值), 就可以改变PWM波形的频率。

    在前面配置TIM3的时候我们没有用到那几个Channel, 现在产生PWM就需要用到了。 关掉IAR工程, 回到CubeMX开始配置

    Step1 : Cube配置

    • (1) LED灯的引脚对应的是TIM14的通道1, 所以要配置TIM14来实现效果

    在这里插入图片描述

    注释 :

    CH Polarity即通道输出极性。我们用TIM3向上计数模式, 按照前面PWM原理图解, CH Polarity的极性加上IO逻辑, 才是最终PWM的波形; 举个栗子, 如果CH Polarity为High(1), 那么当向上计数到CCRx之前本该是0(低电平), 但实际上还要加上Ch的输出极性, 所以那一段实际上是输出1(高电平)。 细细品一下脑子就通了
    在这里插入图片描述

    选用PWM模式1, Pulse(脉宽)这个不用设置, 因为我们在程序里面要不断改变占空比去调节LED的亮度
    • (2) 生成代码
    先声明两个变量

    在这里插入图片描述

    /* USER CODE BEGIN 1 */
    uint16_t CCRx_val = 0;	// CCRx的值; 通过不断改变这个值, 并把这个值送入CCRx寄存器, 达到改变占空比的效果
    uint8_t dir = 1;		// 计数方向控制
    
    /* USER CODE END 1 */
    
    启动定时器的PWM

    在这里插入图片描述

    /* USER CODE BEGIN 2 */
    HAL_TIM_PWM_Start(&htim14, TIM_CHANNEL_1);
    
    /* USER CODE END 2 */
    
    while(1)循环内部

    在这里插入图片描述

    /* USER CODE BEGIN 3 */
        HAL_Delay(10);
        if(dir)
            CCRx_val++;
        else
            CCRx_val--;
        if(CCRx_val > 300)
            dir=0;
        if(CCRx_val == 0)
            dir=1;
        // 追踪 HAL_TIM_OC_ConfigChannel   找到  TIM_OC1_SetConfig 再追踪进去
        // TIM14->CCR1 = 任意数值x  即可控制TIM14通道1的脉宽, 占空比为 (x)/(htim14.Init.Period + 1)
        TIM14->CCR1 = CCRx_val;		// 修改占空比  (调节脉宽我们需要调节 sConfigOC.Pulse )
    
    所有用户代码就是这些, 这里用是寄存器操作去修改占空比, 不管使用什么库函数, 标准库或者HAL库亦或者LL库, 他们在程序里的地位都要低于寄存器。 所以当使用CubeMX配置使用HAL库不方便对某些IO操作的时候, 就可以用寄存器来操作
    刚才在cube里面脉宽(Pulse)我们没有配置, 就是在这里通过寄存器操作的, 最终的本质都是寄存器操作; 感兴趣可以按照我的代码注释, 去 Go To Definition 一路追踪到 TIM_OC1_SetConfig() 这个函数, 这里面就是对相应的寄存器操作的。 在 stm32f4xx_hal_tim.c 这个文件里面
    • (3) 编译下载
      • 实际效果如下面动图所示, 看个三到四秒钟就可以看到变化了
        可能看起来不是非常的明显, 自己操作一下可以好好观察现象

    在这里插入图片描述


    人生岂止爱恨, 还有孤独和酒, 更有梦想与生活, 坚持住。 加油 !

    Author : 李光辉
    date : Sun Jan 5 22:18:02 CST 2020
    blog ID: Kevin_8_Lee
    blog site : https://blog.csdn.net/Kevin_8_Lee
    展开全文
  • 这个图中阐述了利用高级定时器产生PWM原理,其中 ARR是自动重装载寄存器(TIMx_ARR)的值 CNT是定时器计数器当前的值 CCRx是捕获/比较寄存器 x(TIMx_CCRx)的值 每经过一次定时器时钟周期就会+1,通过设置定时器的...
  • 定时器产生PWM

    千次阅读 2010-05-08 16:49:00
    1 用两个定时器/计数器产生矩形波这种方法的基本原理就是用T0作为矩形波的周期的定时器,每一周期产生一次中断,用T1作为矩形波的高电平的计时器,每到T0的定时中断,输出矩形波的引脚输出高电平,而到T1中断产生时...
  • 单片机定时器产生pwm

    千次阅读 2012-01-28 10:02:55
    利用定时器产生不同占空比的PWM波形输出. //ICC-AVR application builder : 2006-7-14 16:54:48 // Target : M128 // Crystal: 14.7456Mhz #include  #include  //#define PWM_select ...
  • STM32F4的定时器产生PWM

    千次阅读 2018-03-19 20:48:38
    1、PWM原理简介2、相关寄存器
  • 本工程代码在STM32F407ZET6开发板上测试通过,其中使用TIM14产生一个PWM脉冲信号来控制一个LED灯,使之成为一个呼吸灯。本压缩包中也包含了STM32F4xx的中文用户手册,以及本人使用的开发板的原理图。欢迎大家下载...
  • 本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的通用定时器外设,产生PWM驱动无源蜂鸣器。
  • STM32定时器产生PWM--呼吸灯

    千次阅读 2017-09-27 15:11:06
    说明:本工程代码在STM32F407ZET6上测试通过...(3)电机控制3、分析PWM产生与重点(1)分析PWM产生(看图示PWM) (2)区别PWM1与PWM2模式(STM32F4xx中文参考手册 433页) (2)高低电平极性区别(STM32F4xx中文参
  • 本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的通用定时器外设,产生PWM驱动无源蜂鸣器。 1. 准备工作 硬件准备 开发板 首先需要准备一个开发板,这里我准备的是STM32L4的开发板(BearPi): 蜂鸣器 ...
  • 在控制流水灯中,也可以通过控制占空比来控制流水灯发光时间的长短。而PWM信号是一种具有固定...Timer_A定时器的计数器工作在增计数方式,输出采用模式7(复位/置位模式),则可以利用CCR0控制PWM波形的周期,用某个寄存
  • 【STM32】通用定时器PWM输出(实例:PWM输出)

    万次阅读 多人点赞 2018-04-19 15:22:43
    STM32F1xx官方资料: ...STM32的通用定时器分为TIM2、TIM3、TIM4、TIM5,而每个定时器都有独立的4个通道可以用来作为:输入捕获、输出比较、PWM输出、单脉冲模式输出等。 STM32的定时器除了TIM6和TIM7(基本定时器...
  • 定时器PWM脉冲

    2021-08-09 18:51:15
    其他的定时器都可以用来产生 PWM 输出。 高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。 通用定时器也能同时产生多达 4路的 PWM 输出, PWM 寄存器与功能原理 TIMx_CCR1~4,捕获/比较寄存器 该...
  • stm32定时器输出PWM控制LED灯

    千次阅读 2019-11-05 01:00:38
    本章中,通过查看原理图,我们的LED指示灯配置在PA4管脚上,查表得知PA4的管脚与TIM14的通道1重映射, 通过定时器产生 PWM 来控制指示灯的亮度。 二、本章学习目标 学会查看数据手册 理解stm32端口复用 学会配置...
  • ①stm32除了TIM6~TIM7(基本定时器)之外,其他都可以产生PWM波输出、 ②通用寄存器:TIM2~TIM5,每个定时器都有四个独立通道可以作为:输入捕获、输出比较、PWM输出、单脉冲模式输出 ③高级定时器TIM1、TIM8可以...
  • 使用STM32定时器实现PWM输出

    千次阅读 2019-04-07 09:58:31
    STM32定时器实现PWM原理: 上图就是STM32一个简单的PWM原理示意图。图中,我们假定定时器工作在向上计数PWM模式,且当CNT<CCRx时,输出0,当CNT>=CCRx时输出1。那么就可以得到如上的PWM示意图:当CNT值小于...
  • 上一节介绍了STM32定时器产生PWM波的用法,PWM波有很多种用途,如控制LED的亮度,控制电机的转速等。还有一个常用的功能就是做DAC(数模转换器)用。有时候,项目中可能会需要...
  • 简介:   STM32 的定时器除了 TIM6 和 7。其他的定时器都可以用来...1:定时器产生PWM原理 在PWM输出模式下,除了CNT(计数器当前值)、ARR(自动重装载值)之外,还多了一个值CCRx(捕获/比较寄存器值)。 当CN
  • 通用定时器PWM 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。...其他的定时器都可以用来产生 PWM ...
  • esp8266教程:定时器PWM PWM是什么? PWM即脉冲宽度调制(Pulse width modulation,PWM)技术,在单片机中PWM一般可以用来调节,led的亮度的高低,显示屏的亮度的高低,直流电机速度的快慢。PWM是什么?PWM其实是...
  • 51单片机定时器实现PWM

    千次阅读 2021-05-08 08:33:49
    51单片机是可以实现PWM波输出的,原理其实都是一样的。说白了,PWM波就是让某一个引脚输出周期性连续高低电平变化的信号。 那么如何用51单片机实现周期性的高低电平呢? 答案就是用定时器。首先我们需要配置一下...
  • 怎样用STM32 通用定时器 输出PWM信号

    千次阅读 2018-07-20 10:59:46
    概述 脉宽调制(PWM)是利用微处理器的数字输出来对模拟...STM32 的四个通用定时器TIM2~TIM5均可以同时产生4路PWM输出。 STM32 定时器输出PWM原理 如上图,ARR是STM32中自动重装载寄存器的值,计数器从0开始计...
  • C51使用定时器中断产生PWM方波信号

    千次阅读 2020-05-06 09:29:16
      使用定时器中断产生PWM方波信号,完成50个频率为1KZ的矩形脉冲输出,P20端口接LED闪烁,用于演示。   矩形脉冲频率为1KZ,周期则为1ms, 中断为0.5ms, 所以T0: TH0=(65536-500)/256, TL0=(65536-500)%256。 ...
  • 配置定时器的相关注意事项 心得体会
  • 单片机开发中,电机的控制与定时器有着密不可分的关系,无论是直流电机,步进电机还是舵机,都会用到定时器,比如最常用的有刷直流电机,会使用定时器产生PWM波来调节转速,通过定时器的正交编码器接口来测量转速等...
  • 前面我学习了使用通用定时器产生PWM,对相关库函数进行分析理解后,就产生了想要产生我所期望的PWM的想法,下面是我的对程序的一些更改,若有不对的地方,还请大家批评指正。 原理 Reset_Handler PROC EXPORT Reset...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,631
精华内容 1,052
关键字:

定时器产生pwm原理