STM32频率的测量:高频适合使用的方法是测频法,低频适合使用的是测周法,(其中使用测频法测量频率比较稳定,使用测周法测量频率的方式没有这么稳定,因为测周法只会通过一次的测量就能得出结果所以测试出来的频率波动相对较大)
在测量频率的过程中会存在误差,所以当N的值越大的时候误差是越小的
输入捕获通道一的详细图解
输入捕获接接线图
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct); // 使用结构体配置输入捕获单元
// 初始化输入捕获单元,可以配置两个通道
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
// 给输入捕获结构体赋一个初始值
void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);
// 选择输入触发源TRGI
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
// 选择输出触发源TRGO
void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);
// 选择从模式
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);
// 分别单独配置通道 1 2 3 4 分频器
void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC2Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC3Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
// 分别读取4个通道的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);
/*
** 输出比较模式下:CCR是只写的,要使用SetCompare写入
输入捕获模式下:CCR是只读的,要使用GetCapture读出**
*/
PWM.C
`#include "stm32f10x.h" // Device headervoid PWM_Init(void){// 开启时钟,这里TIM2是通用寄存器RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);// GPIO初始化代码/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟// GPIO引脚重映射,表示重映射和引脚之间的关系RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;// 使用复用开漏推挽输出模式GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA1和PA2引脚初始化为推挽输出// 选择时基单元的时钟,选择内部时钟的模式,定时器默认使用的是内部单元的时钟TIM_InternalClockConfig(TIM2);/*PWM频率的公式:== 更新频率 = 72M/(PSC+1)/(ARR+1)*/// 配置时基单元,初始化结构体TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;// 将结构体成员都引用出来放置在这个位置TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 配置参数是否分屏TIM_TimeBaseInitStructure.TIM_CounterMode =TIM_CounterMode_Up; // 选择计数的模式选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 100 -1; // 表示ARR自动重装器的值,这两个参数的取值都要在0-65535之间TIM_TimeBaseInitStructure.TIM_Prescaler = 720-1; // PSC预分频器的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; // 重复计数器的值// 初始化结构体并将结构体的地址放置在init函数中TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);// 初始化输出比较单元TIM_OCInitTypeDef TIM_OCInitStructure;// 给结构体赋初始值TIM_OCStructInit(&TIM_OCInitStructure);// 设置输出比较的模式TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;// 设置输出比较的极性,选择高极性TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;// 设置输出使能,输出状态TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable ;//设置CCR,设置ccr寄存器的值TIM_OCInitStructure.TIM_Pulse = 0; // CCRTIM_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的函数:第一个参数表示使用的定时器,第二个参数是需要写入PSC的值,第三个参数重装模式TIM_PrescalerConfig(TIM2, Prescaler,TIM_PSCReloadMode_Immediate);}`
PWM.hIC.C
`#include "stm32f10x.h" // 初始化的步骤 1: RCC开启时钟将GPIO和TIM的时钟开启// GPIO初始化将GPIO初始化为输入模式一般为上拉输入或者是浮空输入// 第三步:配置时基单元让CNT计数器在内部时钟的驱动下进行自增// 第四步:配置输入捕获单元包括输入,极性,直连通道还是交叉通道,分频参数等// 第五步:选择从模式的触发源触发源选择为TI1FP1,使用调用库函数的方式给一个参数// 第六步:选择触发之后执行的操作执行reset操作,使用库函数的方式实现// 第七步:调用TIM_CMD函数开启定时器void IC_Init(void){// 开启时钟,这里TIM2是通用寄存器RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/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); //将PA1和PA2引脚初始化为推挽输出// 选择时基单元的时钟,选择内部时钟的模式,定时器默认使用的是内部单元的时钟TIM_InternalClockConfig(TIM3);/*PWM频率的公式:== 更新频率 = 72M/(PSC+1)/(ARR+1)*/// 配置时基单元,初始化结构体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自动重装器的值,这两个参数的取值都要在0-65535之间TIM_TimeBaseInitStructure.TIM_Prescaler = 72-1; // PSC预分频器的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; // 重复计数器的值// 初始化结构体并将结构体的地址放置在init函数中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);}`
IC.H
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"int main(void)
{// 初始化oledOLED_Init();PWM_Init();IC_Init();OLED_ShowString(1, 1, "Freq:00000Hz");PWM_SetPrescaler(720-1);// 计算频率的公式,Freq = 72M / (PSC + 1) / (ARR + 1)/100PWM_SetCompare1(50); // 计算占空比的公式 Duty = CCR / 100 // 输入捕获代码while (1){OLED_ShowNum(1,6,IC_GetFreq(),5);}
}