zoukankan      html  css  js  c++  java
  • STM32 定时器详细篇(基于HAL库)

    l  16位的向上、向下、向上/向下(中心对齐)计数模式,支持自动重装载

    l  16位的预分频器

    l  每个定时器都有多个独立通道,每个通道可用于

    *  输入捕获

    *  输出比较

    *  PWM输出

    *  单脉冲模式

    l  高级定时器还可以产生互补输出

    l  可以产生中断/DMA请求:

    *  更新事件:计数器向上/向下溢出,计数器初始化(通过软或者内部/外部触发)

    *  触发事件:计数器启动,停止,初始化或者有内部/外部触发计数

    *  输入捕获

    *  输出比较

    一、定时器之计数模式

    (一)  计数模式

    向上计数

    计数器从0向上计数(递增)到自动装载值,然后再次回到0开始计数,并产生一个计数溢出事件

    向下计数

    计数器从自动装载值向下计数(递减)到0,然后再次回到自动装载值开始计数,并产生一个计数器向下溢出事件

    中央对齐模式(向上/向下计数)

    计数器从0开始计数到自动装载值-1,并产生一个计数器溢出事件,然后再向下计数到0+1,并产生一个计数溢出事件,然后再向上计数。

    (二)定时器的溢出时间计算

    time=(ARR+1)*(PSC+1)/Tclk

    ARR为自动装载值

    PSC:预分频系数

    Tclk:定时器的APB时钟,通常等于系统时钟

    如:

    tclk为72M

    psc为7199

    arr为4999

    time=(4999+1)*(7199+1)/72 000 000 = 0.5s = 500ms

    (三)CubeMX设置

    这里需要注意的是你所需要使用的定时器是挂载在APB1还是APB2。相应的要调节他们时钟频率

     选择

     选择内部时钟

    基础配置,这里配置的是1秒计数

    l  Prescaler (PSC- 16 bits value),预分频器(PSC- 16位值)

    l  Counter Mode,计数器模式:

    up 向上

    down 向下

    Center Aligned mode 中心对齐模式

    l  Counter Period (AutoReload Register - 16 bits value),重装载值

    l  auto-reload preload,自动重装载开启

    开启更新中断

    中断优先级数字越低越高

    (四)编程记录

    中断开启

    HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)

    溢出事件回调函数

    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
    
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
       if(htim->Instance == TIM1){
             
            HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);//单独输出电平取反
         
         }
    }

    开启中断

    HAL_TIM_Base_Start_IT(&htim1);

    二、 定时器之PWM

    PWM即脉冲宽度调制,是一种模拟控制方式,通常用于LED的亮度调节。其实就是快速的高低电平变化让人感觉不出来。

    (一)了解一下HZ的概念

    1HZ表示1秒变化一个周期

    在家用交流点中:

    50HZ表示电流每秒钟来回变化50次,方向改变100次。

    50HZ是50个周期,所以有50个正玄波形

    这个图表示的是1HZ变化,1个周期,1个正玄波

    50HZ表示每个周期的时间=1S/50=0.02S=20ms

    单片机检测交流电可以200ms内没有检测到高电平,则表示无输入。

    在计算机cpu等使用1khz=1000hz

    在电磁波和机械波等,1Khz=1024hz

    在PWM中

    hz是频率的单位

    1hz 表示PWM的周期是一秒

    1Khz表示一秒钟有一千个周期,也就是周期是1ms

    1KKhz、1Mhz表示一秒钟有100万个周期,也就是周期是1us

    y秒=1/xHZ

    1/1000=0.001S=1ms

    1/1000000=0.000001S=1us

    如果实现周期是100us

    100us=0.0001S=1/0.0001= 10,000HZ

    (二)PWM配置

    ARR为自动装载值

    CCRx 为捕获比较寄存器值

    预分频系数决定了PWM的时钟速度

    ARR的大小决定了PWM的周期

    CRRx决定了输出有效信号的时间

    有效信号:

    高电平

    低电平

    PWM模式:

    模式1,不管是向上还是向下计数,当计数值小于重装载值是输出有效电平。

    模式2,不管是向上还是向下计数,当计数值小于重装载值是输出无效电平。

    PWM周期计算

    Fpwm = 100M / ((arr+1)*(psc+1))(单位:Hz)

    Fpwm = 100M / (arr+1)/(psc+1)(单位:Hz)

    arr 是计数值

    psc 是预分频值

    如:

    3. 主频=100M

    4. arr=100

    5. psc=1000

    100,000,000/100/1000=1000Hz

    (三) CubeMX设置

    设置定时器使用内部时钟

    设置定时器的PWM通道1开启

    STM32F103C8T6对应的PWM通道为PA8

    设置基础参数

    Prescaler,分配系数为36

    Counter Period,重装载值为100

    所以:

    PWM的频率为:72 000 000/35/100=20 000 HZ(20KHZ),周期为 1/20000= 0.00005秒

    PWM脉宽调制的最大值与重装载值一致,其范围为[0,100]

    通道可以设置的值:

    Mode,PWM的模式,可以选择模式1或模式2

    CH Polarity,有效电平,可选高或底

    (四)编程

    初始化

    //开启PWM输出
    HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
    //设置默认的占空比值
    __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,10);

    while循环改变值

    HAL_Delay(30);//延时30ms
    
    //变量修改
    if(i<100) i++;
    else i=0;
    
    //设置占空比值
    __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,i);    

    三、 定时器之输入捕获

    通过检查定时器通道上的边沿信号,在边沿信号跳变(上升沿或者下降沿)的时候,将当前定时器的计数值存储到对应的捕获/比较寄存器里面,完成一次捕获。

    通常用于检测高电平持续时间、低电平持续时间、两次下降沿的持续时间、两次上升沿的持续时间

    滤波器:

    里可以设置以什么频率采集多少次有效电平才说明边沿触发成功,如设置的是上升沿触发,当上升沿发生时,滤波器或以fDTS的频率采集ICF设置的次数,每次检测是否是高电平,这样可以防止误触发所带来的计算干扰。

    边沿检测器:

    设置捕获的触发边沿,可以设置上升沿或下降沿

    通道选择

    通过寄存器可以设置其它通道输入的值到该通道上

    如通道1和通道2都可以映射到IC1,但通常是通道1是IC1,通道2是IC2,每个独立一对一映射,互不干扰。

    分频器:

    每2个事件触发一次捕获,如上升沿捕获时,连续获取到两个上升沿后才会触发计数

    每4个事件触发一次捕获

    每8个事件触发一次捕获

    (一) CubeMX设置

    开启TIM4的通道1作为输入捕获通道,对应是PB6引脚

    Internal Clock表示内部时钟

    input capture direct mode 表示输入捕获

    根据硬件连接,这里设置为上拉

    开启中断

    基础配置

    时钟:72 000 000 /72 = 1 000 000 HZ= 1MHZ,所以计数一次为1us

    最大计数值为65536,约为65ms

    prolarity selection 为触发计数边沿,下降沿

    (二)编程

    测量低电平的持续时间,先下降沿后上升沿,记录计数值,最终输出us单位。

    通用函数

    //变量存储
    typedef struct 
    {   
        uint8_t   flg; //0为未开始,1已经开始,2为结束
        uint16_t  num;//计数值
        uint16_t  num_period;//溢出次数
    }COUNT_TEMP;
    
    COUNT_TEMP count_temp={0};
    
    //捕获中断发送时的回调函数
    void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
    {
          //判断定时器2
            if(TIM2 == htim->Instance){
                if ( count_temp.flg == 0 )
                {   
                    // 清零定时器计数
                    __HAL_TIM_SET_COUNTER(htim,0); 
                    //设置上升沿触发
                    __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING);
                    count_temp .flg = 1;    //设置已经开始    
                    count_temp .num_period = 0;    //溢出计数清零        
                    count_temp .num = 0; //计数清零
                }        
                else
                {
                    // 获取定时器计数值
                    count_temp .num = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_2);
                    //设置下降沿触发
                    __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING);
                    count_temp .flg = 2;
                }
            }
    }    
    
    //定时器溢出回调函数
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
        if(TIM2 == htim->Instance){
        //每次溢出时间为65536us
        if(count_temp.flg==1)//还未成功捕获
        {
                    if(count_temp.num_period==0XFFFF)//电平太长了
                    {
                        count_temp.flg=2;        //标记成功捕获了一次
                        count_temp .num=0XFFFF;
                    }else count_temp .num_period ++;
        }
        }
    }

    初始化

    //开启定时器溢出中断
    HAL_TIM_Base_Start_IT(&htim2);  
    //开启输入捕获中断,设置下降沿触发中断
    __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING); 
    HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);    //启动输入捕获

    while循环

    //等待测量完毕
    if(count_temp.flg == 2 )
    {
        //计数计数值,0xFFFF为最大计数
        uint32_t ulTime = (uint32_t)count_temp .num_period * 0xFFFF + count_temp .num;
        //输出测量的值
        printf ( "低电平时间:%d us
    ",ulTime); 
        count_temp .flg = 0;            
    }

    原文地址:https://www.cnblogs.com/dongxiaodong/p/14351398.html

    找作者:https://space.bilibili.com/162091292


  • 相关阅读:
    shell截取字符串的方法
    安装sql server managerment studio报错"The instance id is required but it is missing"
    windows 80端口被占用的解决方法
    centos如何安装软件
    ORA-00257归档日志写满的解决方法
    VCenter克隆虚拟机报错msg.snapshot.error-QUIESCINGERROR
    如何启动或关闭oracle的归档(ARCHIVELOG)模式
    ubuntu下nagios配置
    vsphere vcenter server下安装ubuntu的vmwaretools
    virtualbox迁移至vcenter/vmware workstation
  • 原文地址:https://www.cnblogs.com/dongxiaodong/p/14351398.html
Copyright © 2011-2022 走看看