目录
前言
一、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);
}
}
以上就是本期的全部内容了,我们下次见!
今日壁纸: