• STM32 Timer (3) PWM代码的实现


    理论知识基于上一篇文章 

    STM32 Timer (2) 定时器中断代码框架

    3.1 PWM分频系数和参数的含义

    定时器周期公式T = (arr+1)(psc+1)/f; f = (APB1 *2).

    //
    定时器基本参数: // ARR: 自动重装载值; // ftim: 频率 //PWM参数: // CCRx: 比较值 对于定时器参数更深入的理解 从(APB1 * 2)来的时钟, 经过psc参数进行预分频,会是这样的效果:(假设psc = 108000) (54 *2)MHz/psc = 108Mhz/108000 = 1Khz, 转化为周期T1 = 1/1khz(s) = 1ms, 也就是说,每一个时钟跳动,对于定时器输入来说,都是1ms,当然这是建立在psc = 108000的情况下. 也就是说, psc=108000的时候,定时器每经过1ms,计数器就++ 或 -- 一次. ARR是自动重装载值,也是定时器的设定值, 假设arr = 500; 就代表着当计数器的值到达500的时候, 就触发更新中断,一次定时器的任务就结束. 这两个参数一起使用的时候,就能得到完整的一次定时任务的时间, 每1ms更新一次技术, 更新500次的时候触发中断, 就等于 1ms * 500 = 500ms; 每500ms触发一次定时中断. 在这个理论的基础上,我们来分析pwm的频率是一种什么概念. 假设定时器触发中断的总时间为T, 定时器频率为f1; 计数器设置为500不变, 那么分析psc对定时器的影响. 当psc= 108 时, f1 = 108Mhz /108 = 1Mhz, 1Mhz 是什么概念, T1 = 1/f1(s) = 1us; 也就是定时器每1us更新一次计数器. 这样子触发一个完整的中断T只要 500us;,下面我将数据对比一下
    psc(分频系数) f1(定时器频率) T1(计数器更新时间) arr计数次数 T(定时器完整中断时间)
    108   108Mhz/108 = 1MHz 0.000001s = 1us 500 500us
    1080 108Mhz/1080 = 100KHz 0.00001s = 10us 500 5ms
    10800 108Mhz/10800 = 10KHz 0.0001s = 100us 500 50ms
    108000 108Mhz.108000 = 1Khz 0.001s = 1ms 500 500ms

     

    从图片个表格可以看出来, 预分频系数直接关系着频率, 也就是直观感受上的 快 和 慢.
    当预分频系数越小, 一个定时周期就越短, 因为计数器 咻的一下就把500次心跳更新完了. 
    当预分频系数越大, 一个定时周期就越长, 因为缓慢的心跳让计数器的更新动作也变得缓慢.
    
    重装载值控制控制着计数器的阈值然后影响着 一个完整的定时器中断周期, 在预分频系数一定时,假设每1ms更新一次计数器
    arr = 500 , T = 500ms;
    arr = 1000, T = 1000ms;
    结合CCrx来看是什么效果. 假设CCRx分别是arr值的一半, 
    当arr = 500的时候, 每250ms电平翻转一次;
    当arr = 1000的时候, 每500ms电平翻转一次;
    肉眼看到的led效果就是: 一个快速地flash, 另一个慢慢地闪烁.
    所以呢,在pwm中, 有三个重要的参数,一个是频率,一个是arr重装载值,一个是CCRx比较值
    频率控制着计数器的变化速度,频率越快,计数器变化就越快, 周期就越短,一下子就走到了重装载值的尽头.
    arr重装载值同样起着跟频率一样的作用. 
    
    CCRx比较值呢就是改变占空比的作用. 
    这个放在led上的效果就是,
    占空比越大, led越亮.
    占空比越小, led越暗.
    将两种效果结合起来就是:
    频率越高, led迅速地从暗到亮
    频率越低, led缓慢地从暗到亮
    
    放在蜂鸣器上的效果就是:
    频率改变声音的音调(Hz), 占空比改变声音的响度.

    4.2 代码框架

    //1. 开启TIM时钟和配置PWM输出GPIO,配置GPIO时选择复用功能
    __HAL_RCC_TIM3_CLK_ENABLE(); //使能定时器 3
    __HAL_RCC_GPIOB_CLK_ENABLE(); //开启 GPIOB 时钟
    HAL_GPIO_Init(GPIOB,&GPIO_Initure); //配置GPIO
    
    //2. 初始化 TIM3,设置 TIM3 的 ARR 和 PSC 等参数。
    HAL_TIM_PWM_Init();
    
    //3. 设置 TIM3_CH4 的 PWM 模式,输出比较极性,比较值等参数。
    HAL_TIM_PWM_ConfigChannel();
    
    //4. 能 TIM3,使能 TIM3 的 CH4 输出
    HAL_TIM_PWM_Start();
    
    //5. 修改 TIM3_CCR4 来控制占空比。
    #include <rtthread.h>
    #include <rtdevice.h>
    #include <board.h>
    
    #define THREAD_STACKSIZE    200
    #define THREAD_PRORITY      5
    #define THREAD_TASK         5
    
    
    TIM_HandleTypeDef hpwm;    
    TIM_OC_InitTypeDef TIM3_CH4Handler;
    
    void TIM_SetCompare4(uint32_t compare)
    {
        TIM3->CCR4=compare;
    }
    
    
    void TIM3_PWM_Init(uint16_t arr, uint16_t psc)
    {
       
        hpwm.Instance           = TIM3;        
        hpwm.Init.Prescaler     = psc;    //设置psc预分频系数
        hpwm.Init.CounterMode   = TIM_COUNTERMODE_UP;    //设置计数方式
        hpwm.Init.Period        = arr;                    //设置重装载值
        hpwm.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;    
        HAL_TIM_PWM_Init(&hpwm);    //初始化PWM定时器
        
        
        TIM3_CH4Handler.OCMode = TIM_OCMODE_PWM1;           //设置为小于比较值为有效电平模式
        TIM3_CH4Handler.OCPolarity = TIM_OCPOLARITY_LOW;    //设置有效电平为低电平(LED需要)
        TIM3_CH4Handler.Pulse = arr/2;                      //设置比较值
        HAL_TIM_PWM_ConfigChannel(&hpwm, &TIM3_CH4Handler,TIM_CHANNEL_4);    //配置信道
        
        HAL_TIM_PWM_Start(&hpwm, TIM_CHANNEL_4);    //开启pwm定时器输出
        
    }
    
    static void pwm_timer_entry(void *arg)
    {
        uint8_t dir = 1;
        uint16_t led0pwmval = 0;
        
        //psc = 108 表示每次心跳为1us, 500次更新一次计数器, 共500us一个周期
        //这种效果就等于疯狂刷新定时器, 不停监听占空比的变化
        //总觉得有点丧心病狂
        TIM3_PWM_Init(500-1, 108-1);    
        
        while(1)
        {
            rt_thread_mdelay(10); //每10ms更新一次占空比.
            if(dir)
            {
                led0pwmval ++;    //每次更新的精度为1,越小表示越平滑
            }else
            {
                led0pwmval --;
            }
            if(led0pwmval > 500)    //500 和 arr设置为一样,表示占空比从0到最大
            {
                dir = 0;
                rt_thread_mdelay(10);
            }
            if(led0pwmval == 0)
            {
                dir =1;
                //rt_thread_mdelay(10);
            }
            TIM_SetCompare4(led0pwmval);   //更新占空比的值
        }
    }
        
    
    int pwm_timer()
    {
        rt_thread_t tid;
        tid = rt_thread_create("pwm_timer", pwm_timer_entry, RT_NULL,
                               THREAD_STACKSIZE,
                               THREAD_PRORITY,THREAD_TASK);
        if(tid)
            rt_thread_startup(tid);
        return 0;
    }
    MSH_CMD_EXPORT(pwm_timer, kis_pwm_timer);
    void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* htim_pwm)
    {
    
        if(htim_pwm->Instance==TIM2)
        {
    
            __HAL_RCC_TIM2_CLK_ENABLE();
    
        }else if(htim_pwm->Instance == TIM3)
        {
            GPIO_InitTypeDef GPIO_InitStruck;
            __HAL_RCC_TIM3_CLK_ENABLE();
            __HAL_RCC_GPIOB_CLK_ENABLE();
            
            //gpio
            GPIO_InitStruck.Pin = GPIO_PIN_1;
            GPIO_InitStruck.Mode = GPIO_MODE_AF_PP;
            GPIO_InitStruck.Pull = GPIO_PULLUP;
            GPIO_InitStruck.Speed = GPIO_SPEED_HIGH;
            GPIO_InitStruck.Alternate = GPIO_AF2_TIM3;
            HAL_GPIO_Init(GPIOB,&GPIO_InitStruck);
        }
    
    }
  • 相关阅读:
    201521123076《java程序设计》第四次总结
    201521123076《java程序设计》第三周学习总结
    201521123076《Java程序设计》第2周学习总结
    软件工程网络15个人阅读作业2
    软件工程网络15个人作业1
    java程序设计----学生基本信息管理系统
    201521123070 《JAVA程序设计》第14周学习总结
    201521123070 《JAVA程序设计》第13周学习总结
    201521123070 《JAVA程序设计》第12周学习总结
    201521123070《Java程序设计》 第11周学习总结
  • 原文地址:https://www.cnblogs.com/kmist/p/11669272.html
Copyright © 2020-2023  润新知