自学内容网 自学内容网

stm32入门-----TIM定时器(输入捕获模式——下)

 目录

前言

一、C语言编程初始化步骤

1.开启时钟

2.配置GPIO口

 3.配置时基单元

4.配置输入捕获单元(主模式)

 5.配置触发源于从模式

6.开启定时器

二、项目实操(测周法)

1.定时器测量方波

2.定时器测量方波的占空比


前言

        接着上一期的内容(上一期链接:stm32入门-----TIM定时器(输入捕获模式——上)-CSDN博客),本期主要是实践和编程,分为两个部分,分别是定时器测量方波的频率,定时器测量方波的占空比,测量方法是测周法。(视频:[6-6] 输入捕获模式测频率&PWMI模式测频率占空比_哔哩哔哩_bilibili

一、C语言编程初始化步骤

 根据下图,我们只需要把定时器输入捕获模式的相关功能通路打开即可。

本期主要讲解如何用定时器捕获输入信号,项目实验是需要定时器输出波形的,然后再捕获,如果不知道怎么输出PWM波形的可以看看我前面发过的文章:stm32入门-----TIM定时器(PWM输出比较——下)-CSDN博客

1.开启时钟

这里我是选择通用定时器的定时器3,因为定时器2是作为输出PWM的定时器已经使用了。

//1.开启时钟
//开启定时器时钟,TIM3总线是为APB1的
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//开启GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
TIM_InternalClockConfig(TIM3);  //给TIM3选择时钟 为内部时钟,定时器默认是使用内部的时钟,不写这一行也行的

2.配置GPIO口

 //2.配置GPIO口, PA6 为输入口
GPIO_InitTypeDef GPIO_initstruct; 
GPIO_initstruct.GPIO_Mode=GPIO_Mode_IPU; //使用上拉输入
GPIO_initstruct.GPIO_Pin=GPIO_Pin_6;  
GPIO_initstruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_initstruct); 
 

 3.配置时基单元

//3.配置时基单元
    TIM_TimeBaseInitTypeDef TIM_timebasestruct;
    //下面两个是运行控制操作值
    TIM_timebasestruct.TIM_ClockDivision=TIM_CKD_DIV1;//对输入信号进行初步分频,内部时钟72Mhz信号
    TIM_timebasestruct.TIM_CounterMode=TIM_CounterMode_Up;//计数方式选择向上计数
    //以下三个是时基单元里面的实际参数值
    /* 计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)
       = CK_PSC / (PSC + 1) / (ARR + 1) */
TIM_timebasestruct.TIM_Period=65536-1;  //计数器的重装值,这里我设置为最大65535,这里是表示计数的最大范围换句话说就是最大可以测量的频率,
//并不是计数到65535才去执行其他操作,执行操作的要去看输入捕获单元  ARR
    TIM_timebasestruct.TIM_Prescaler=72-1; //预分频器的值          PSC
    TIM_timebasestruct.TIM_RepetitionCounter=0;//重复计数功能,这个是高级计数器才有的,当前选择的是通用计数器,设置0即可
TIM_TimeBaseInit(TIM3,&TIM_timebasestruct);

4.配置输入捕获单元(主模式)

配置输入捕获单元是用结构体去配置的,这里我们都已经很熟悉了。

   //4.配置输入捕获单元(主模式)
    TIM_ICInitTypeDef TIM_icinitstruct;
    TIM_icinitstruct.TIM_Channel=TIM_Channel_1; //选择定时器的通道(CH1~CH4),这里定时器3选择通道1
    TIM_icinitstruct.TIM_ICFilter=0xF; //选择滤波,消除噪音
    TIM_icinitstruct.TIM_ICPolarity=TIM_ICPolarity_Rising; //触发方式,选择上升沿还是下降沿触发
    TIM_icinitstruct.TIM_ICPrescaler=TIM_ICPSC_DIV1; //选择对输入信号的分频值,我们是测量波形,所以不分频
    TIM_icinitstruct.TIM_ICSelection=TIM_ICSelection_DirectTI;//选择通道,这里选择直连通道
    TIM_ICInit(TIM3,&TIM_icinitstruct);

 5.配置触发源于从模式

 上面我们已经配置好了主模式的捕获单元通道,那么下面就要给TRGO信号进行选择触发源以及从模式。

 下面是触发源选择:

下面是从模式的选择: 

    //配置主模式的触发源选择,TRGO选择TI1FP1
    TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);

    //配置从模式
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);

6.开启定时器

 配置完了之后就可以开启定时器使能了。

    //启动定时器3,使能
    TIM_Cmd(TIM3,ENABLE);

整体初始化代码如下:

void IC_init(){
    //1.开启时钟
//开启定时器时钟,TIM3总线是为APB1的
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//开启GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
TIM_InternalClockConfig(TIM3);  //给TIM3选择时钟 为内部时钟,定时器默认是使用内部的时钟,不写这一行也行的

    //2.配置GPIO口, PA6 为输入口
GPIO_InitTypeDef GPIO_initstruct; 
GPIO_initstruct.GPIO_Mode=GPIO_Mode_IPU; //使用上拉输入
GPIO_initstruct.GPIO_Pin=GPIO_Pin_6;  
GPIO_initstruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_initstruct); 
 
    //3.配置时基单元
    TIM_TimeBaseInitTypeDef TIM_timebasestruct;
    //下面两个是运行控制操作值
    TIM_timebasestruct.TIM_ClockDivision=TIM_CKD_DIV1;//对输入信号进行初步分频,内部时钟72Mhz信号
    TIM_timebasestruct.TIM_CounterMode=TIM_CounterMode_Up;//计数方式选择向上计数
    //以下三个是时基单元里面的实际参数值
    /* 计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)
       = CK_PSC / (PSC + 1) / (ARR + 1) */
TIM_timebasestruct.TIM_Period=65536-1;  //计数器的重装值,这里我设置为最大65535  ARR
    TIM_timebasestruct.TIM_Prescaler=72-1; //预分频器的值          PSC
    TIM_timebasestruct.TIM_RepetitionCounter=0;//重复计数功能,这个是高级计数器才有的,当前选择的是通用计数器,设置0即可
TIM_TimeBaseInit(TIM3,&TIM_timebasestruct);

    //4.配置输入捕获单元(主模式)
    TIM_ICInitTypeDef TIM_icinitstruct;
    TIM_icinitstruct.TIM_Channel=TIM_Channel_1; //选择定时器的通道(CH1~CH4),这里定时器3选择通道1
    TIM_icinitstruct.TIM_ICFilter=0xF; //选择滤波,消除噪音
    TIM_icinitstruct.TIM_ICPolarity=TIM_ICPolarity_Rising; //触发方式,选择上升沿还是下降沿触发
    TIM_icinitstruct.TIM_ICPrescaler=TIM_ICPSC_DIV1; //选择对输入信号的分频值,我们是测量波形,所以不分频
    TIM_icinitstruct.TIM_ICSelection=TIM_ICSelection_DirectTI;//选择通道,这里选择直连通道
    TIM_ICInit(TIM3,&TIM_icinitstruct);

    //配置主模式的触发源选择,TRGO选择TI1FP1
    TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);

    //配置从模式
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);

    //启动定时器3,使能
    TIM_Cmd(TIM3,ENABLE);

}

二、项目实操(测周法)

本期全部完整代码可在百度网盘自行下载

链接:https://pan.baidu.com/s/1FJ7GYt-Ltzj77oyAh4t6hA?pwd=0721 
提取码:0721

1.定时器测量方波

实验现象:

电路连接图:

这里我们就自己输出波形,然后自己测量波形结果。从PA0输出波形,PA6捕获波形。

工程主要文件如下,这里需要PWM去输出波形,IC是用于读取和计算波形的文件。 

IC.c文件代码:

#include "stm32f10x.h"                  // Device header

void IC_init(){
    //1.开启时钟
//开启定时器时钟,TIM3总线是为APB1的
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//开启GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
TIM_InternalClockConfig(TIM3);  //给TIM3选择时钟 为内部时钟,定时器默认是使用内部的时钟,不写这一行也行的

    //2.配置GPIO口, PA6 为输入口
GPIO_InitTypeDef GPIO_initstruct; 
GPIO_initstruct.GPIO_Mode=GPIO_Mode_IPU; //使用上拉输入
GPIO_initstruct.GPIO_Pin=GPIO_Pin_6;  
GPIO_initstruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_initstruct); 
 
    //3.配置时基单元
    TIM_TimeBaseInitTypeDef TIM_timebasestruct;
    //下面两个是运行控制操作值
    TIM_timebasestruct.TIM_ClockDivision=TIM_CKD_DIV1;//对输入信号进行初步分频,内部时钟72Mhz信号
    TIM_timebasestruct.TIM_CounterMode=TIM_CounterMode_Up;//计数方式选择向上计数
    //以下三个是时基单元里面的实际参数值
    /* 计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)
       = CK_PSC / (PSC + 1) / (ARR + 1) */
TIM_timebasestruct.TIM_Period=65536-1;  //计数器的重装值,这里我设置为最大65535,这里是表示计数的最大范围换句话说就是最大可以测量的频率,
//并不是计数到65535才去执行其他操作,执行操作的要去看输入捕获单元  ARR
    TIM_timebasestruct.TIM_Prescaler=72-1; //预分频器的值          PSC
    TIM_timebasestruct.TIM_RepetitionCounter=0;//重复计数功能,这个是高级计数器才有的,当前选择的是通用计数器,设置0即可
TIM_TimeBaseInit(TIM3,&TIM_timebasestruct);

    //4.配置输入捕获单元(主模式)
    TIM_ICInitTypeDef TIM_icinitstruct;
    TIM_icinitstruct.TIM_Channel=TIM_Channel_1; //选择定时器的通道(CH1~CH4),这里定时器3选择通道1
    TIM_icinitstruct.TIM_ICFilter=0xF; //选择滤波,消除噪音
    TIM_icinitstruct.TIM_ICPolarity=TIM_ICPolarity_Rising; //触发方式,选择上升沿还是下降沿触发
    TIM_icinitstruct.TIM_ICPrescaler=TIM_ICPSC_DIV1; //选择对输入信号的分频值,我们是测量波形,所以不分频
    TIM_icinitstruct.TIM_ICSelection=TIM_ICSelection_DirectTI;//选择通道,这里选择直连通道
    TIM_ICInit(TIM3,&TIM_icinitstruct);

    //配置主模式的触发源选择,TRGO选择TI1FP1
    TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);

    //配置从模式
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);

    //启动定时器3,使能
    TIM_Cmd(TIM3,ENABLE);

}

//计算频率Hz
uint32_t IC_Getfreq(){
// 初始化的预装分频器值为72,那么频率为72MHz / 72 = 1MHz
//然后根据公式计算出f= 1MHz / CCR
    return 1000000 / (1+TIM_GetCapture1(TIM3)); //CNT是从0开始加的,所以CCR这里要加上1
}

 IC.h文件代码:

#ifndef __IC_H
#define __IC_H
void IC_init();
uint32_t IC_Getfreq();

#endif // !__IC_H

main.c代码:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
int main(void){

OLED_Init();
PWM_init();
IC_init();
OLED_ShowString(1,1,"Freq:00000Hz");
PWM_Setperscaler(720-1);  //频率 f=72M / (psc+1) / 100              (ARR+1)
PWM_Setcompare1(50);  //占空比 D= CCR / 100
while(1){
OLED_ShowNum(1,6,IC_Getfreq(),5);
}
}


2.定时器测量方波的占空比

实验现象:

 电路连接图(都是一样的):

主要工程文件同上:

这里涉及到测量占空比,所以需要用到PWMI模式的功能,也就是一个输入信号可以有两个通道去进行分析计算。

这里我们可以去直接使用这个PWMI封装好的函数去初始化捕获单元 ,这个是stm32库里面就有的,直接把TIM_ICInit(TIM3,&TIM_icinitstruct); 这个换为下面这个即可。

 IC.c代码如下:

#include "stm32f10x.h"                  // Device header

void IC_init(){
       //1.开启定时器时钟,TIM2总线是为APB1的
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
TIM_InternalClockConfig(TIM3);  //给TIM2选择时钟 为内部时钟,定时器默认是使用内部的时钟,不写这一行也行的

    //2.配置GPIO口, PA0 为输出口
GPIO_InitTypeDef GPIO_initstruct; 
GPIO_initstruct.GPIO_Mode=GPIO_Mode_IPU; //使用复用推挽输出,因为这里不是输出寄存器控制的,是片上外设定时器操作的,所以要用到复用推挽输出
GPIO_initstruct.GPIO_Pin=GPIO_Pin_6;  //重新映射到15口 GPIO_initstruct.GPIO_Pin=GPIO_Pin_15;
GPIO_initstruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_initstruct); 
 
    //3.配置时基单元
    TIM_TimeBaseInitTypeDef TIM_timebasestruct;
    //下面两个是运行控制操作值
    TIM_timebasestruct.TIM_ClockDivision=TIM_CKD_DIV1;//对输入信号进行初步分频,内部时钟72Mhz信号
    TIM_timebasestruct.TIM_CounterMode=TIM_CounterMode_Up;//计数方式选择向上计数
    //以下三个是时基单元里面的实际参数值
    /* 计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)
       = CK_PSC / (PSC + 1) / (ARR + 1) */
    TIM_timebasestruct.TIM_Period=65536-1;  //计数器的重装值,目标值  ARR
    TIM_timebasestruct.TIM_Prescaler=72-1; //预分频器的值          PSC
    TIM_timebasestruct.TIM_RepetitionCounter=0;//重复计数功能,这个是高级计数器才有的,当前选择的是通用计数器,设置0即可
TIM_TimeBaseInit(TIM3,&TIM_timebasestruct);

    //配置输入捕获单元(主模式)
    TIM_ICInitTypeDef TIM_icinitstruct;
    //通道1
    TIM_icinitstruct.TIM_Channel=TIM_Channel_1; //选择定时器的通道(CH1~CH4),这里定时器3选择通道1
    TIM_icinitstruct.TIM_ICFilter=0xF; //选择滤波,消除噪音
    TIM_icinitstruct.TIM_ICPolarity=TIM_ICPolarity_Rising; //触发方式,选择上升沿还是下降沿触发
    TIM_icinitstruct.TIM_ICPrescaler=TIM_ICPSC_DIV1; //选择对输入信号的分频值,我们是测量波形,所以不分频
    TIM_icinitstruct.TIM_ICSelection=TIM_ICSelection_DirectTI;//选择通道,这里选择直连通道

    TIM_PWMIConfig(TIM3,&TIM_icinitstruct); //这个初始化是直接使用PWMI模式,直接帮你配置好两个通道,仅仅支持通道1和通道2

    //如果传入的是通道1直连上升沿,那就配置通道2交叉下降沿;如果通道2为直连上升沿,那么就配置通道1交叉下降沿

    //TIM_ICInit(TIM3,&TIM_icinitstruct);
    //通道2

    // TIM_icinitstruct.TIM_Channel=TIM_Channel_2; //选择定时器的通道(CH1~CH4),这里定时器3选择通道1
    // TIM_icinitstruct.TIM_ICFilter=0xF; //选择滤波,消除噪音
    // TIM_icinitstruct.TIM_ICPolarity=TIM_ICPolarity_Falling; //触发方式,选择上升沿还是下降沿触发
    // TIM_icinitstruct.TIM_ICPrescaler=TIM_ICPSC_DIV1; //选择对输入信号的分频值,我们是测量波形,所以不分频
    // TIM_icinitstruct.TIM_ICSelection=TIM_ICSelection_IndirectTI;//选择通道,这里选择直连通道
    // TIM_ICInit(TIM3,&TIM_icinitstruct);

    //配置主模式的触发源选择,TRGO选择TI1FP1
    TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);

    //配置从陌生
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);

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

}

//计算频率Hz
uint32_t IC_Getfreq(){
    return 1000000 / (1+TIM_GetCapture1(TIM3));
}
//获取占空比
uint32_t IC_Getduty(){
    return (TIM_GetCapture2(TIM3)+1)*100 / (TIM_GetCapture1(TIM3)+1);
}

IC.h代码:

#ifndef __IC_H
#define __IC_H
void IC_init();
uint32_t IC_Getfreq();
uint32_t IC_Getduty();
#endif // !__IC_H

main.c代码:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
int main(void){

OLED_Init();
PWM_init();
IC_init();
OLED_ShowString(1,1,"Freq:00000Hz");
OLED_ShowString(2,1,"Duty:00%");
PWM_Setperscaler(720-1);  // f=72M / (psc+1) / 100              (ARR+1)
PWM_Setcompare1(20);  // D= CCR / 100
while(1){
OLED_ShowNum(1,6,IC_Getfreq(),5);
OLED_ShowNum(2,6,IC_Getduty(),2);
}
}


以上就是本期的全部内容了,我们下次见!

今日壁纸:


原文地址:https://blog.csdn.net/m0_73633088/article/details/140632563

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