本篇博客重点在于标准库函数的理解与使用,搭建一个框架便于快速开发
目录
前言
输入捕获简介
输入捕获配置
初始化IO口
输入捕获初始化
选择触发源及从模式
测量频率方法
输入捕获代码
IC.h
IC.c
输入捕获测占空比
前言
建议先阅读这篇博客,理解时基单元的配置
【STM32】通用定时器TIM(时钟源选择与更新中断)-CSDN博客
输入捕获简介
IC(Input Capture)输入捕获
输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
STM32F10xxx通用定时器为TIM2、TIM3、TIM4和TIM5,每个通用定时器和高级定时器都拥有4个输出比较通道和4个输入捕获通道
可配置为PWMI模式,同时测量频率和占空比
可配合主从触发模式,实现硬件全自动测量
输入捕获框图
输入捕获配置
初始化IO口
GPIO的其它参数的理解可以阅读下方博客,这里不再赘述。
【STM32】GPIO和AFIO标准库使用框架_gpio afio-CSDN博客
查找引脚定义表,将通用定时器3的输入捕获通道1(PA6)配置为上拉输入,由GPIO输入至定时器捕获单元
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
输入捕获初始化
输入捕获基本结构
/*输入捕获初始化*/
TIM_ICInitTypeDef TIM_ICInitStructure; //定义结构体变量
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择配置定时器通道1
TIM_ICInitStructure.TIM_ICFilter = 0xF; //输入滤波器参数,可以过滤信号抖动
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //极性,选择为上升沿触发捕获
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕获预分频,选择不分频,每次信号都触发捕获
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //输入信号交叉,选择直通,不交叉
TIM_ICInit(TIM3, &TIM_ICInitStructure); //将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
参数TIM_ICFilter :
参数TIM_ICSelection :
选择触发源及从模式
TI1FP1为触发源
TI1FP1全称为Timer Input 1 Filtered Input 1,捕获到设置的边沿,TI1FP1可触发定时器的CNT计数器清0。本篇博客将TI1FP1选择为上升沿捕获,捕获到上升沿将计数器清0.
/*选择触发源及从模式*/
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); //触发源选择TI1FP1
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); //从模式选择复位
//即TI1产生上升沿时,会触发CNT归零
触发源选择:
从模式选择:
主模式本博客代码没有用到,这里只是顺便介绍一下
主模式
定时器的TRGO(Trigger Output )信号至其他定时器和DAC/ADC
TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Update); //选择TRGO触发源为计时器更新时间
OutputTrigger:
标准库函数中有This paramter can be one of the following values,意思是不能配置多个信号外部外部
应用案例
ADC采样间隔问题+TRGO作为ADC的触发源头 - dadide - 博客园 (cnblogs.com)
测量频率方法
测频法适合测量高频率,测周法适合测量低频率
在周期的数字信号中,一个指定边沿(上升沿或下降沿,本篇博客选上升沿)代表一个周期的开始,也表示上一个周期的结束
测频法是在固定的时间内,检测待测信号周期次数,频率=(固定的时间/待测信号周期次数)的倒数。
固定的时间/待测信号周期次数,其实就是固定时间内多少个待测信号周期,测量信号的第一个和最后一个待测信号周期可能不完整,会出现待测信号周期次数偏多或偏少的情况,需要需要较多的待测信号周期个数减小误差,较多的待测信号周期个数意味着待测信号频率高
测周法是在一个待测周期内,以固定的频率采样,频率=1/(固定的周期时间*计数次数)=固定的频率/计数次数
固定的频率的倒数其实就是固定的周期时间,测周法其实就是测待测信号的一个周期时间内能检测到固定周期多少次。在一个待测信号的周期时间内,固定周期的第一个和最后一个周期可能不完整,会出现固定周期次数偏多或偏少的情况,需要较多的固定周期个数减小误差减小误差。较多的固定周期个数意味着待测信号频率低。
本篇选择测周法 ,固定频率 = CK_PSC/(PSC + 1)=72MHz/72=1MHz,CNT计数器以这个固定频率计数。输入捕获单元捕获到指定边沿(本篇指定上升沿),CNT计数器的值会复制到捕获寄存器CCR1。
uint32_t IC_GetFreq(void)
{
return 1000000 / (TIM_GetCapture1(TIM3) + 1); //测周法得到频率fx = fc / N
}
输入捕获代码
输入捕获测频率代码
IC.h
#ifndef __IC_H
#define __IC_H
void IC_Init(void);
uint32_t IC_GetFreq(void);
//uint32_t IC_GetDuty(void);//测占空比解除注释
#endif
IC.c
#include "stm32f10x.h" // Device header
void IC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARR,尽量要大,防止待测信号频率过大导致CNT计数器溢出
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3, &TIM_ICInitStructure);
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
TIM_Cmd(TIM3, ENABLE);
}
/**
* 函 数:获取输入捕获的频率
* 参 数:无
* 返 回 值:捕获得到的频率
*/
uint32_t IC_GetFreq(void)
{
return 1000000 / (TIM_GetCapture1(TIM3) + 1); //测周法得到频率fx = fc / N,这里不执行+1的操作也可
}
频率测完了怎么测占空比呢?
输入捕获测占空比
测量占空比就需要获取一个PWM周期内高电平时间与一个周期时间比值,显然要在测频率的基础上再用一个输入捕获通道
在周期的数字信号中,一个指定边沿(上升沿或下降沿,本篇博客选上升沿)代表一个周期的开始也是上一个周期的结束,另一个指定边沿(本篇博客选下降沿)代表一个周期内的信号边沿变化。
占空比=高电平时间/一个待测信号周期时间=捕获下降沿的值/捕获上升沿的值
PWMI基本结构
PWMI框图
TIM_PWMIConfig函数
实现PWMI模式,此函数会把另一个通道配置为边沿相反,不直连。该函数其实就是注释的代码的封装函数。
完整代码需在输入捕获测频率的基础上更改
//放在测频率输入捕获初始化代码后
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure); //将结构体变量交给TIM_PWMIConfig,配置TIM3的输入捕获通道
/**
* 函 数:获取输入捕获的占空比
* 参 数:无
* 返 回 值:捕获得到的占空比
*/
uint32_t IC_GetDuty(void)
{
return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1); //占空比Duty = CCR2 / CCR1 * 100,这里不执行+1的操作也可
}