目录
1:简历
2:频率测量
3:主从触发模式
4:结构
A:输入捕获功能测频率
1:连接图
2:函数介绍
3:测周法
4 输入捕获模式基本结构
5:步骤
6:代码
B :PWMI模式测频率占空比
1: 连接图
2:PWMI模式的结构
3:函数介绍
4:步骤
5:代码
IC(Input Capture)输入捕获
输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
每个高级定时器和通用定时器都拥有4个输入捕获通道
可配置为PWMI模式,同时测量频率和占空比
可配合主从触发模式,实现硬件全自动测量
对于STM32测频率而言,它也是只能测量数字信号的
频率 : 是单位时间(1s)内周期性过程重复、循环或振动的次数
测频法 : 一般情况下T为1s,符合频率的定义,-----适合测量高频信号
测周法原理 : 先对信号的周期T进行测量,然后根据f=1/T而得到信号的频率。测量2个上升沿的时间, 没有一个精度无穷大的秒表来测量时间,所以使用这个方法来测力量(见 : 3:测周法)-----适合测量高频信号
当N越大时, 正负1的误差对我们的影响就越小
当: 待测频率<中界频率----使用测周法
待测频率>中界频率----使用测频法
主模式 : 可以将定时器内部的信号,映射到TRGO引脚 , 用于触发别的外设,所以这部分叫做主模式
从模式 : 就是接收其他外设或者自身外设的一些信号, 用于控制自身定时器的运行,也就是被别的信号控制
触发源选择 : 就是选择从模式的触发信号源的, 从模式的一部分, 触发源选择,选择指定的一个信号,得到TRGI,TRGI去触发从模式,从模式可以在从模式列表里,选择一项操作来自动执行
输入捕获模式基本结构
PWMI模式的结构
A0:为输出引脚,负责输出PWM波形
A6:为输入引脚复制计算输入的频率
在stm32f10x tim.h文件中的函数-----输入捕获的配置
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
TIM_ICInit :
TIM_ICInitTypeDef TIM_initstruct;
TIM_initstruct.TIM_Channel=TIM_Channel_1; //选择的通道 PA6对应的为通道1
TIM_initstruct.TIM_ICFilter=; //滤波器
TIM_initstruct.TIM_ICPolarity=TIM_ICPolarity_Rising; //极性 我们选择上升沿触发
TIM_initstruct.TIM_ICPrescaler=TIM_ICPSC_DIV1; //分频器 不分频(1)就是每次触发都有效;2分频就是每隔一次有效一次,以此类推
TIM_initstruct.TIM_ICSelection=TIM_ICSelection_DirectTI; //选择触发信号从哪个引脚输入(直连输入)
TIM_ICInit(TIM3,&TIM_initstruct);
在stm32f10x tim.h文件中的函数----触发源选择:配置TRGI的触发源为TI1FP1
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource)
TIM_SelectInputTrigger : 第二个参数选择触发源
在stm32f10x tim.h文件中的函数-----配置从模式--配置从模式为Reseta
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode)
在stm32f10x tim.h文件中的函数-----单独改变PSC的值
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode)
TIM_PrescalerConfig : 可以改变PSC的值的函数
第三个参数(指定定时器预分频器的重装模式): TIM_PSCReloadMode_Update 预分频器在更新事件重装,在更新时间后面生效
TIM_PSCReloadMode_Immediate : 立刻生效
在stm32f10x tim.h文件中的函数---------通道X读取CCR的值
uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx);
PA6对应的为通道1,所以选择 TIM_GetCapture1---选择那个通道取决于引脚的定义
实例使用的是测周法 ; 对于STM32测频率而言,它也是只能测量数字信号的
测周法:两个上升沿内,以标准频率fc计次,得到N ,则频率 fx=fc / N
计数器自增的频率 = 计数标准频率 fc = CK_PSC (72mHZ) / 预分频(PSC)
N : 简单理解就是CCR的值 (详情请看简历第二条)
1 : RCC开启时钟,(TIM外设---RCC_APB1PeriphClockCmd和GPIO外设----RCC_APB2PeriphClockCmd的时钟打开)
2 : 配置GPIO----GPIO_Init (最后写第二步)
3 : 时钟选择----TIM_InternalClockConfig(内部)
4 : 配置时基单元-----TIM_TimeBaseInit()
5 : 配置输入捕获(ic)----TIM_ICInit()
6 : 触发源选择: 配置TRGI的触发源为TI1FP1----------TIM_SelectInputTrigger()
7 : 配置从模式"配置从模式为Reset--------TIM_SelectSlaveMode()
8 : 启动定时器-----TIM_Cmd()
PA0口使用TIM2输出一个PWM波形,PA6口测频率
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
void PWM_init(){
//第一步,RCC开启时钟,把我们要用的TIM外设和GPIO外设的时钟打开
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//第二步,配置GPIO
GPIO_InitTypeDef GPIO_INITStruct;
GPIO_INITStruct.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_INITStruct.GPIO_Pin=GPIO_Pin_0 ;
GPIO_INITStruct.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_INITStruct);
//第三步,时钟源选择(内部时钟)
TIM_InternalClockConfig(TIM2);
//第四步,配置时基单元
TIM_TimeBaseInitTypeDef TIM_INITStruct;
TIM_INITStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_INITStruct.TIM_CounterMode=TIM_CounterMode_Up; 向上计数
TIM_INITStruct.TIM_Period=100-1; //ARR
TIM_INITStruct.TIM_Prescaler=720-1; //PSC
TIM_INITStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2,&TIM_INITStruct);
//第五步,配置输出比较单元
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//给输出比较结构体赋一个默认的值
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择PWM1的模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //有效电频为低电频
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //使能
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
//第六步,启动定时器
TIM_Cmd(TIM2,ENABLE);
}
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);
}
void PWM_SetPrescaler(uint16_t Prescaler)
{
//可以单独改变PSC的值
TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);
}
void IC_init(){
//第一步,RCC开启时钟,把我们要用的TIM外设和GPIO外设的时钟打开
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//第二步,配置GPIO
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);
//第三步,时钟源选择(内部时钟)
TIM_InternalClockConfig(TIM3);
//第四步,配置时基单元
TIM_TimeBaseInitTypeDef TIM_INITStruct;
TIM_INITStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_INITStruct.TIM_CounterMode=TIM_CounterMode_Up; 向上计数
TIM_INITStruct.TIM_Period=65536 - 1; //ARR
TIM_INITStruct.TIM_Prescaler=72-1; //PSC
TIM_INITStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3,&TIM_INITStruct);
//第五步,配置输入捕获(ic)
TIM_ICInitTypeDef TIM_initstruct;
TIM_initstruct.TIM_Channel=TIM_Channel_1; //选择的通道 PA6对应的为通道1
TIM_initstruct.TIM_ICFilter=0xF; //滤波器
TIM_initstruct.TIM_ICPolarity=TIM_ICPolarity_Rising; //极性 我们选择上升沿触发
TIM_initstruct.TIM_ICPrescaler=TIM_ICPSC_DIV1; //分频器 不分频(1)就是每次触发都有效;2分频就是每隔一次有效一次,以此类推
TIM_initstruct.TIM_ICSelection=TIM_ICSelection_DirectTI; //选择触发信号从哪个引脚输入(直连输入)
TIM_ICInit(TIM3,&TIM_initstruct);
//第六步,触发源选择: 配置TRGI的触发源为TI1FP1
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
//第七步,配置从模式-:配置从模式为Reseta
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
//第八步,启动定时器
TIM_Cmd(TIM3,ENABLE);
}
uint32_t IC_GetFreq(void) //Fc=72mHZ/(PSC+1) psc=72-1 FC=1000 000
{ //高电平的计数值存在CCR2里,整个周期的计数值存在CCR1里
return 1000000 / (TIM_GetCapture1(TIM3) + 1); //FX=FC/N N就是读取CCR的值
}
int main(void)
{
OLED_Init();
PWM_init();
IC_init();
OLED_ShowString(1, 1, "Freq:00000Hz");
//pwm文件中ARR定时了为100
PWM_SetPrescaler(720 - 1); //Freq = 72M / (PSC + 1) / 100 改变PA0引脚PSC预分频器的值
PWM_SetCompare1(50); //Duty = CCR / 100 改变PA0引脚CCR的值
while (1)
{
OLED_ShowNum(1, 6, IC_GetFreq(), 5);
}
}
不使用一个定时器? 输出比较使用TMI2(输出pwm), 输入捕获使用TIM3(测频率)
4个输入捕获和输出比较通道(CH),共用4个CCR寄存器, 它们的CH1到CH4,4个通道的引脚,也是共用的. 对于同一个定时器,输入捕获和输出比较只能使用其中一个,不能同时使用
计算输入捕获
输入捕获使用了TIM3通用定时器
高电平的计数值存在CCR2里,整个周期的计数值存在CCR1里
引脚通道
输入捕获
本次使用的是同用定时器TIM3的PA6引脚, 根据引脚的定义我们应该使用通道1
输入捕获的通道选择是在配置IC时选择的(输入捕获的配置): TIM_initstruct.TIM_Channel=TIM_Channel_1; ---通道1
主从触发模式------清零CNT
上升沿用于触发输入捕获,CNT用于计数计时 .每来一个上升沿,取一下CNT的值,自动存在CCR里. CCR捕获到到的值。就是计数值N. CNT的驱动时钟,就是fc
每次捕获之后我们都要把CNT清0一下,下次上升沿再捕获的时候, 取出的CNT的值就是两次上升沿的时间间隔.
在一次捕获后自动将CNT清零的步骤,可以用主从触发模式,自动来完成
硬件电路就可以在捕获之后自动完成CNT的清零工作;
TI1FP1信号和TI1的边沿信号都可以通向从模式控制器, TI1FP1还可以同时触发从模式, 从模式里面,就有电路,可以自动完成CNT的清零
想TI1FP1信号户社知分CNT清零:
1 : 触发源选择-------选中这里的TI1FP1 TIM_SelectInputTrigger
2 : 从模式-------------选执行Reset的操作 TIM_SelectSlaveMode
注意:
这里CNT的值是有上限的,ARR一般设置为最大65535,CNT最大也只能计65535个数
在触发源选择中只有TF1FP1,TF2FP2的信号,没有TF3FP3,TF4FP4的信号; 如果想使用从模式自动清零CNT,就只能用通道1和通道2; 对于通道3和通道4,就只能开启捕获束断。手动清零这样子比较消耗系统资源
和 A:输入捕获功能测频率是一个连接图
在stm32f10x tim.h文件中的函数-----打开PWMI模式
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
只支持通道1和通道2
1 : RCC开启时钟,(TIM外设---RCC_APB1PeriphClockCmd和GPIO外设----RCC_APB2PeriphClockCmd的时钟打开)
2 : 配置GPIO----GPIO_Init (最后写第二步)
3 : 时钟选择----TIM_InternalClockConfig(内部)
4 : 配置时基单元-----TIM_TimeBaseInit()
5 : 配置输入捕获(ic)----TIM_ICInit()
6: 打开PWMI模式-----TIM_PWMIConfig();
7 : 触发源选择: 配置TRGI的触发源为TI1FP1----------TIM_SelectInputTrigger()
8 : 配置从模式"配置从模式为Reset--------TIM_SelectSlaveMode()
9 : 启动定时器-----TIM_Cmd()
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
void PWM_init(){
//第一步,RCC开启时钟,把我们要用的TIM外设和GPIO外设的时钟打开
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//第二步,配置GPIO
GPIO_InitTypeDef GPIO_INITStruct;
GPIO_INITStruct.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_INITStruct.GPIO_Pin=GPIO_Pin_0 ;
GPIO_INITStruct.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_INITStruct);
//第三步,时钟源选择(内部时钟)
TIM_InternalClockConfig(TIM2);
//第四步,配置时基单元
TIM_TimeBaseInitTypeDef TIM_INITStruct;
TIM_INITStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_INITStruct.TIM_CounterMode=TIM_CounterMode_Up; 向上计数
TIM_INITStruct.TIM_Period=100-1; //ARR
TIM_INITStruct.TIM_Prescaler=720-1; //PSC
TIM_INITStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2,&TIM_INITStruct);
//第五步,配置输出比较单元
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//给输出比较结构体赋一个默认的值
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择PWM1的模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //有效电频为低电频
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //使能
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
//第六步,启动定时器
TIM_Cmd(TIM2,ENABLE);
}
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);
}
void PWM_SetPrescaler(uint16_t Prescaler)
{
//可以单独改变PSC的值
TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);
}
void IC_init(){
//第一步,RCC开启时钟,把我们要用的TIM外设和GPIO外设的时钟打开
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//第二步,配置GPIO
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);
//第三步,时钟源选择(内部时钟)
TIM_InternalClockConfig(TIM3);
//第四步,配置时基单元
TIM_TimeBaseInitTypeDef TIM_INITStruct;
TIM_INITStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_INITStruct.TIM_CounterMode=TIM_CounterMode_Up; 向上计数
TIM_INITStruct.TIM_Period=65536 - 1; //ARR
TIM_INITStruct.TIM_Prescaler=72-1; //PSC
TIM_INITStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3,&TIM_INITStruct);
//第五步,配置输入捕获(ic)
TIM_ICInitTypeDef TIM_initstruct;
TIM_initstruct.TIM_Channel=TIM_Channel_1; //选择的通道 PA6对应的为通道1
TIM_initstruct.TIM_ICFilter=0xF; //滤波器
TIM_initstruct.TIM_ICPolarity=TIM_ICPolarity_Rising; //极性 我们选择上升沿触发
TIM_initstruct.TIM_ICPrescaler=TIM_ICPSC_DIV1; //分频器 不分频(1)就是每次触发都有效;2分频就是每隔一次有效一次,以此类推
TIM_initstruct.TIM_ICSelection=TIM_ICSelection_DirectTI; //选择触发信号从哪个引脚输入(直连输入)
TIM_ICInit(TIM3,&TIM_initstruct);
TIM_PWMIConfig(TIM3,&TIM_initstruct);
//第六步,触发源选择: 配置TRGI的触发源为TI1FP1
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
//第七步,配置从模式-:配置从模式为Reseta
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
//第八步,启动定时器
TIM_Cmd(TIM3,ENABLE);
}
uint32_t IC_GetFreq(void) //Fc=72mHZ/(PSC+1) psc=72-1 FC=1000 000
{
return 1000000 / (TIM_GetCapture1(TIM3) + 1); //FX=FC/N N就是读取CCR的值
}
uint32_t IC_duty_cycle(void){
//高电平的计数值存在CCR2里,整个周期的计数值存在CCR1里
return TIM_GetCapture2(TIM3)*100/TIM_GetCapture1(TIM3);
}
int main(void)
{
OLED_Init();
PWM_init();
IC_init();
OLED_ShowString(1, 1, "Freq:00000Hz");
OLED_ShowString(2, 1, "Duty:00%");
//pwm文件中ARR定时了为100
PWM_SetPrescaler(720 - 1); //Freq = 72M / (PSC + 1) / 100 改变PA0引脚PSC预分频器的值
PWM_SetCompare1(50); //Duty = CCR / 100 改变PA0引脚CCR的值
while (1)
{
OLED_ShowNum(1, 6, IC_GetFreq(), 5);
OLED_ShowNum(2, 6, IC_duty_cycle(), 2);
}
}
占空比
uint32_t IC_duty_cycle(void){
//高电平的计数值存在CCR2里,整个周期的计数值存在CCR1里
return TIM_GetCapture2(TIM3)*100/TIM_GetCapture1(TIM3);}
和 A:输入捕获功能测频率的代码相比, 只在配置输入捕获(IC)的时候打开了PWMI通道
TIM_PWMIConfig();