自学内容网 自学内容网

STM32 进阶 定时器3 通用定时器 案例2:测量PWM的频率/周期

需求分析

上一个案例我们输出了PWM波,这个案例我们使用输入捕获功能,来测试PWM波的频率/周期。

把测到的结果通过串口发送到电脑,检查测试的结果。

如何测量

1、输入捕获功能主要是:测量输入通道的上升沿和下降沿

2、让第一个上升沿触发,第二个上升沿卡个事件,可以测量到周期

3、然后通过周期反推频率

输入捕获包括三个部分:

共四路,每路都有自己的输入引脚

计数器部分

捕获寄存器部分

过程

通过之前产生的方波信号,然后再配置输入对这个方波信号进行测量,用杜邦线

连接两个引脚,tim4和tim5的引脚,昨天tim5的引脚产生PWM方波,用tim4定时器用于测量。

产生中断会触发中断函数(这个函数将CNT计时器清零),但是触发中断函数之前会产生一个捕获比较事件,这个事件是将CNT的值搬到捕获比较1寄存器中。

上升沿会触发中断,产生搬用事件,并将CNT清零,

然后下一个上升沿会再次产生中断,那么会产生搬用事件将CNT计数器搬到寄存器中,可以抓取这个值,就是这个周期的事件。

设计相关寄存器

每个复用器都需要寄存器进行配置

CCMR1

CC2S:选择输入

IC1F:无滤波,可以抗干扰,一般在硬件就已经抗干扰啦,这里无滤波

CCIS: 输入有三种情况

PSC:预分频 三档2/4/8分频

CCER:

CC1P:上升沿还是下降沿

CC1E: 输入使能

CR2:

TI1S:采用TIMx_CH1的线路

DIER:捕获比较中断

CC1IE:允许中断

tim4.c
#include "tim4.h"

void TIM4_Init(){
    //1.GPIO
    //1.1放时钟
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
    //1.2 PB6 引脚 配置输入模式 浮空输入
    GPIOB->CRL &= ~ (GPIO_CRL_CNF6_1 | GPIO_CRL_MODE6);
    GPIOB->CRL |= GPIO_CRL_CNF6_0;

    //2.TIM4
    //2.0 先放时钟
    RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
    //2.1 控制器 (不管 全部保留默认设72MHz)
    //2.2 时基单元
    //2.2.1 分频  计数频率就是1M 数一个数的时间就是1us
    TIM4->PSC = 72 - 1;
    //2.2.2 尺子越长越好
    TIM4->ARR = 65535;


    //2.3 输入和输出通道
    //2.3.1 通道输入还是输出
    TIM4->CCMR1 |= TIM_CCMR1_CC1S_0;
    TIM4->CCMR1 &= ~TIM_CCMR1_CC1S_1;
    //2.3.2 配置TI1复用器,选择CH1引脚直接过来的信号(默认就是)
    TIM4->CR2 &= ~TIM_CR2_TI1S;
    //2.3.3 配置滤波器(默认就是)
    TIM4->CCMR1 &= ~ TIM_CCMR1_IC1F;
    //2.3.4 配置边沿检测器(默认就是)
    TIM4->CCER &= ~TIM_CCER_CC1P;
    //2.3.5 预分频器(默认就是)
    TIM4->CCMR1 &= ~ TIM_CCMR1_IC1PSC;
    //2.3.6 中断使能
    TIM4->DIER |= TIM_DIER_CC1IE;


    //3 有中断就需要配置NVIC
    //3.1 优先级分组
    NVIC_SetPriorityGrouping(3);
    //3.2 设置本中断的优先级
    NVIC_SetPriority(TIM4_IRQn,6);
    //3.3 对于片上外设 NVIC有一个使能控制
    NVIC_EnableIRQ(TIM4_IRQn);
}


void TIM4_Start(void){
    // 开启通道使能
    TIM4->CCER |= TIM_CCER_CC1E;
    //开启计数器使能
    TIM4->CR1 |= TIM_CR1_CEN;
}

void TIM4_Stop(void){
    // 关闭通道使能
    TIM4->CCER &= ~TIM_CCER_CC1E;
    //关闭计数器使能
    TIM4->CR1 &= ~TIM_CR1_CEN;
}


uint8_t raise_edge_num = 0;

uint16_t cnt = 0;

double TIM4_GetCycleMs(void){
    return cnt/1000.0;
}

double TIM4_GetFreq(void){
    return 1000000.0/cnt;
}


void TIM4_IRQHandler (void){
    //片上外设都有标志位
    //-1 判断什么原因进入中断
    //0 清0 标志位
    if(TIM4->SR & TIM_SR_CC1IF){
        TIM4->SR &= ~TIM_SR_CC1IF;
        //业务逻辑
        //1 .让编号加1
        raise_edge_num ++;
        //2. 分开第一个上升沿和第二个上升沿的逻辑
        if (raise_edge_num == 1)
        {
            //3 如果第一个上升沿到来 我直接从0开始计数
            TIM4->CNT = 0;
        }else if (raise_edge_num == 2)
        {
            //4.如果第二个上升沿到来
            raise_edge_num = 0;
            //5.抄数,把值记录下来
            cnt = TIM4->CCR1;
        }
    }
}
tim4.h
#ifndef __TIM4_H__
#define __TIM4_H__

#include "stm32f10x.h"

void TIM4_Init();


void TIM4_Start(void);

void TIM4_Stop(void);

double TIM4_GetCycleMs(void);

double TIM4_GetFreq(void);

#endif /* __TIM4_H__ */
main.c

我们要设置占空比,因为我们是tim5产生的pwm方波,如果没有占空比,也就没有方波产生,也就产生不了上升沿触发不了中断。

#include "usart1.h"
#include "string.h"
#include <stdio.h>
#include "m24c02.h"
#include "i2c.h"
#include "led.h"
#include "systick.h"
#include "tim6.h"
#include "tim5.h"
#include "tim4.h"

typedef enum {
LIGHT,
DARK
}LED_DIRCT;

extern uint16_t cnt;



int main(void)
{

TIM5_Init();
TIM5_PWMStart();
TIM5_SetDuty(10);

Usart1_Init();
TIM4_Init();
TIM4_Start();
// LED_DIRCT direct = LIGHT;
while (1)
{
Delay_s(2);
printf ("当前的周期时%.2fms,频率是%.2fHz",TIM4_GetCycleMs(),TIM4_GetFreq());
}
}
HAL库

前面有两个__:是宏定义,


原文地址:https://blog.csdn.net/qq_64219867/article/details/144247972

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!