STM32输入捕获模式测频率

本文介绍了STM32中如何通过测频法和测周法测量频率,以及如何配置输入捕获通道以实现精确测量。着重讲解了TIMx寄存器的初始化和使用,如TIM_ICInitStruct、TIM_Cmd等函数在频率测量中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述在这里插入图片描述在这里插入图片描述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 header

void 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;    // 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的函数:第一个参数表示使用的定时器,第二个参数是需要写入PSC的值,第三个参数重装模式
  TIM_PrescalerConfig(TIM2, Prescaler,TIM_PSCReloadMode_Immediate);

}

`

PWM.h在这里插入图片描述IC.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)
{
  // 初始化oled
	OLED_Init();
	PWM_Init();
	IC_Init();
	OLED_ShowString(1, 1, "Freq:00000Hz");
	PWM_SetPrescaler(720-1);// 计算频率的公式,Freq = 72M / (PSC + 1) / (ARR + 1)/100
	PWM_SetCompare1(50);    // 计算占空比的公式 Duty = CCR / 100 
	// 输入捕获代码
	while (1)
	{
     OLED_ShowNum(1,6,IC_GetFreq(),5);
	}
}
### STM32 测量信号频率的方法 STM32 是一种功能强大的微控制器,支持多种外设用于信号处理和测量。以下是两种常见的方法来实现频率测量: #### 方法一:基于 ADC 和 FFT 的频率测量 这种方法适合于复杂的信号分析场景,尤其是需要高精度的频谱分析时。 1. **硬件配置** 使用 STM32F103 的 ADC 外设采集输入信号,并通过 DMA 将采样数据传输至内存缓冲区。随后利用快速傅里叶变换 (FFT) 对这些数据进行频域转换,从而提取目标信号的主要频率分量[^1]。 2. **软件流程** - 初始化 ADC、定时器以及 DMA 控制模块。 - 启动连续模式下的 AD 转换操作。 - 收集足够的样本点数后执行 FFT 计算。 - 查找 FFT 输出数组的最大幅值对应的索引位置,该索引映射回实际物理频率值即为目标信号频率。 ```c #include "stm32f1xx_hal.h" void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){ // 当一次完整的AD转换完成后触发此回调函数 } int main(void){ uint16_t adcValue[NUMBER_OF_SAMPLES]; /* 初始化系统 */ MX_DMA_Init(); MX_ADC1_Init(); /* 开始DMA控制的数据获取过程 */ HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adcValue, NUMBER_OF_SAMPLES); while (1){ // 主循环等待DMA完成并调用FFT算法处理数据... } } ``` #### 方法二:使用外部中断 EXTI 或者捕获比较单元 TIM 实现 PWM 波形频 对于周期性的脉冲宽度调制(PWM)类型的方波或者正弦波等简单形式电信号来说,则可以采用更
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值