这里主要讲测周法计算输入源的频率,代码总结自江科大,加上自己的一些理解。
方法概述:
•
测周法:两个上升沿内,以标准频率
f
c
计次,得到
N
,则频率等于:
𝑓𝑥 = 𝑓𝑐 / 𝑁
简单理解就是:在一个周期内,用CNT计数器来数这个待测周期需要用时多少个标准周期,而标准
周期是由定时器的预分频器PSC来决定的,即 72MHZ/(PSC+1),假设PSC+1=72,那么CNT+1代表时间过了1us。
假如一个输入源的两个上升沿之间(即一个周期)计数CNT共1000次,边沿检测器发送信号使得从模式触发,这时CNT的值装入CCR捕获/比较寄存器,CNT清0,CCR的值N=1000 * 标准周期1us即为待测周期,取倒数则为待测频率。
其他说明:
- 内部时钟会一直运行计数,而每次遇到上升沿(下降沿)则会置零,CCR的值会一直被更新。如果频率稳定某个值,单片机高速运行下会在现象上保持输出一个值。
- CNT最大值为ARR的值 = 65535,如果标准周期设置得太小,会导致CNT计数太大溢出这个值,这时需要考虑增大PSC的值,增大一次计数所代表的时间。
- 该方法适合频率低,即周期长的波形,因为周期太短,则N就会很小,测出来的值就不准确,这时候更适合测频法,即在1秒内统计上升沿的次数。
代码部分:
先是一些固定的初始化流程
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//开启TIM3时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开GPIO的时钟
GPIO_InitTypeDef GPIO_Initstructure;
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入,也可以是其他输入方式
GPIO_Initstructure.GPIO_Pin = GPIO_Pin_6;//初始化Pin口
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 = 65535-1; //ARR 自动重装载
TIM_TimeBaseInitStructure.TIM_Prescaler = 72-1; //PSC预分频器,可以调节精度
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
//初始化IC输入捕获
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;//选择TIm3的通道
TIM_ICInitStruct.TIM_ICFilter = 0xF; //配置滤波器参数
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//选择哪个边沿触发
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;//分频器,1就是每次触发都有效,2就是两次触发一次有效
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;//数据选择器 直连or交叉
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//选择从模式触发源
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//设置从模式执行的操作
TIM_Cmd(TIM3,ENABLE);//将TIM3使能
最后,待测周期为
T =(72000000/TIM_GetPrescaler(TIM3)) /TIM_GetCapture1(TIM3); //即f/N