STM32入门笔记06_TIM输入捕获+案例: TIM输入测量信号频率 PWMI模式测量信号频率和占空比

TIM输入捕获

输入捕获简介

  • IC(Input Capture) 输入捕获
  • 输入捕获模式下, 当通道输入引脚出现指定电平跳变时, 当前CNT的值将被锁存到CCR中, 可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
  • 每个高级定时器和通用定时器都拥有四个输入捕获通道
  • 可配置为PWMI模式, 同时测量频率和占空比
  • 可配合主从触发模式, 实现硬件全自动测量

频率测量

在这里插入图片描述

  • 测频法: 在闸门时间T内, 对上升沿计次, 得到N, 则频率fx = N / T(适用于测高频信号)

  • 测周法: 两个上升沿内, 以标准频率fc计次, 得到N, 则频率fx = fc / N(适用于测低频信号s)

  • 中界频率: 测频法与测周法误差相等的频率点, fm = sqrt(fc / T)

输入捕获通道

在这里插入图片描述

  • fDTS: 滤波器采样时钟来源
  • TI1F: 滤波后的信号
  • CCMR1寄存器里的ICF位可以控制滤波器的参数
  • 通道2部分电路未画出

主从触发模式

在这里插入图片描述

主模式: 将定时器内部的信号, 映射到TRGO引脚, 用于触发别的外设

从模式: 接受其他外设或者自身外设的信号, 用于控制自身定时器的运行

输入捕获基本结构

在这里插入图片描述

  • 工作流程: 设边沿检测极性为高电平, 信号沿通道GPIO->滤波器->边沿检测, 当检测到高电平后, 发出TI1FP1信号;TI1FP1有两条通道, 第一条通道继续向下到分频器, 最后到CCR捕获/比较寄存器, CCR接受到信号后, 捕获CNT的计次N; 另一条通道, 则通过从模式将CNT置零。
  • 用得到的计次N可得频率 f = fc / N, fc是标准频率, 通过配置时基单元设置, 这里用的是测周法测频率的原理

PWMI基本结构

在这里插入图片描述

  • 与输入捕获结构相似, 但开启了第二条通道, 第二条通道在下降沿(与第一条通道触发方式相反), 触发CCR2寄存器捕获CNT的值得到N1,第一条通道则还是在上升沿捕获CNT的值得到N2
  • 如图所示: 易得占空比 = (N1+1)*100 / (N2+1) %

案例1: TIM输入捕获测量信号频率(对应输入捕获基本机构)

说明

  • 用PA0 的定时器 生成测试信号, PA6的定时器 捕获信号测量频率
  • 由于配置过程类似, 这里仅对IC单元的配置和从模式配置进行详细说明, 其余过程在注释中可以大致了解。

硬件接线

在这里插入图片描述

配置IC单元

	// 配置IC单元
	TIM_ICInitTypeDef TIM_InitStructure;
	TIM_InitStructure.TIM_Channel=TIM_Channel_1;  // 定时器通道
	TIM_InitStructure.TIM_ICFilter=0xF;  // 滤波器
	TIM_InitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;  // 边沿极性选择
	TIM_InitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;  // 分频器
	TIM_InitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;  // 配置选择器模式
	TIM_ICInit(TIM3, &TIM_InitStructure);
TIM_ICInitTypeDef
typedef struct
{

  uint16_t TIM_Channel;      /*!< Specifies the TIM channel.
                                  This parameter can be a value of @ref TIM_Channel */

  uint16_t TIM_ICPolarity;   /*!< Specifies the active edge of the input signal.
                                  This parameter can be a value of @ref TIM_Input_Capture_Polarity */

  uint16_t TIM_ICSelection;  /*!< Specifies the input.
                                  This parameter can be a value of @ref TIM_Input_Capture_Selection */

  uint16_t TIM_ICPrescaler;  /*!< Specifies the Input Capture Prescaler.
                                  This parameter can be a value of @ref TIM_Input_Capture_Prescaler */

  uint16_t TIM_ICFilter;     /*!< Specifies the input capture filter.
                                  This parameter can be a number between 0x0 and 0xF */
} TIM_ICInitTypeDef;
TIM_Channel
#define TIM_Channel_1                      ((uint16_t)0x0000)
#define TIM_Channel_2                      ((uint16_t)0x0004)
#define TIM_Channel_3                      ((uint16_t)0x0008)
#define TIM_Channel_4                      ((uint16_t)0x000C)
TIM_ICPolarity
#define  TIM_ICPolarity_Rising             ((uint16_t)0x0000)
#define  TIM_ICPolarity_Falling            ((uint16_t)0x0002)
#define  TIM_ICPolarity_BothEdge           ((uint16_t)0x000A)
TIM_ICSelection
#define TIM_ICSelection_DirectTI           ((uint16_t)0x0001) /*!< TIM Input 1, 2, 3 or 4 is selected to be 
                                                                   connected to IC1, IC2, IC3 or IC4, respectively */
#define TIM_ICSelection_IndirectTI         ((uint16_t)0x0002) /*!< TIM Input 1, 2, 3 or 4 is selected to be
                                                                   connected to IC2, IC1, IC4 or IC3, respectively. */
#define TIM_ICSelection_TRC                ((uint16_t)0x0003) /*!< TIM Input 1, 2, 3 or 4 is selected to be connected to TRC. */
TIM_ICPrescaler
#define TIM_ICPSC_DIV1                     ((uint16_t)0x0000) /*!< Capture performed each time an edge is detected on the capture input. */
#define TIM_ICPSC_DIV2                     ((uint16_t)0x0004) /*!< Capture performed once every 2 events. */
#define TIM_ICPSC_DIV4                     ((uint16_t)0x0008) /*!< Capture performed once every 4 events. */
#define TIM_ICPSC_DIV8                     ((uint16_t)0x000C) /*!< Capture performed once every 8 events. */

TIM_ICFilter
uint16_t TIM_ICFilter;     /*!< Specifies the input capture filter.
                                  This parameter can be a number between 0x0 and 0xF */

配置从模式

// 配置从模式
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);  // 选择输入触发
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);  // 选择从模式
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource)
/**
  * @brief  Selects the Input Trigger source
  * @param  TIMx: where x can be  1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.
  * @param  TIM_InputTriggerSource: The Input Trigger source.
  *   This parameter can be one of the following values:
  *     @arg TIM_TS_ITR0: Internal Trigger 0
  *     @arg TIM_TS_ITR1: Internal Trigger 1
  *     @arg TIM_TS_ITR2: Internal Trigger 2
  *     @arg TIM_TS_ITR3: Internal Trigger 3
  *     @arg TIM_TS_TI1F_ED: TI1 Edge Detector
  *     @arg TIM_TS_TI1FP1: Filtered Timer Input 1
  *     @arg TIM_TS_TI2FP2: Filtered Timer Input 2
  *     @arg TIM_TS_ETRF: External Trigger input
  * @retval None
  */
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode)
/**
  * @brief  Selects the TIMx Slave Mode.
  * @param  TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.
  * @param  TIM_SlaveMode: specifies the Timer Slave Mode.
  *   This parameter can be one of the following values:
  *     @arg TIM_SlaveMode_Reset: Rising edge of the selected trigger signal (TRGI) re-initializes
  *                               the counter and triggers an update of the registers.
  *     @arg TIM_SlaveMode_Gated:     The counter clock is enabled when the trigger signal (TRGI) is high.
  *     @arg TIM_SlaveMode_Trigger:   The counter starts at a rising edge of the trigger TRGI.
  *     @arg TIM_SlaveMode_External1: Rising edges of the selected trigger (TRGI) clock the counter.
  * @retval None
  */

整体代码

IC.c
#include "stm32f10x.h"

/*
初始化TIM3_IC
*/
void TIM3_IC_Init(void)
{
	// RCC使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	
	// 配置GPIO口 A6 TIM3_CH1
	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 TimeBase_InitStructure;
	TimeBase_InitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TimeBase_InitStructure.TIM_CounterMode=TIM_CounterMode_Up;  // 向上计数
	TimeBase_InitStructure.TIM_Period=65536-1;  // ARR
	TimeBase_InitStructure.TIM_Prescaler=72-1;  // PSC
	TimeBase_InitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM3, &TimeBase_InitStructure);
	
	// 配置IC单元
	TIM_ICInitTypeDef TIM_InitStructure;
	TIM_InitStructure.TIM_Channel=TIM_Channel_1;  // 定时器通道
	TIM_InitStructure.TIM_ICFilter=0xF;  // 滤波器
	TIM_InitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;  // 边沿极性选择
	TIM_InitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;  // 分频器
	TIM_InitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;  // 配置选择器模式
	TIM_ICInit(TIM3, &TIM_InitStructure);
	
	// 配置从模式
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
	// 开启定时器
	TIM_Cmd(TIM3, ENABLE);
}

/*
获取TIM3_CH1 输入波形频率
*/
uint16_t Get_TIM3_CH1_Freq(void)
{
	return 72000000/(TIM_GetPrescaler(TIM3)+1)/ (TIM_GetCapture1(TIM3)+1);
}
PWM.c
#include "stm32f10x.h"

/*
初始化TIM2的PWM模式
*/
void TIM2_PWM_Init(void)
{
	// RCC使能时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 配置GPIO口
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// 配置内部时钟作为TIM的时钟源
	TIM_InternalClockConfig(TIM2);
	
	// 配置时基单元
	TIM_TimeBaseInitTypeDef TimeBase_InitStructure;
	TimeBase_InitStructure.TIM_ClockDivision=TIM_CKD_DIV1 ;
	TimeBase_InitStructure.TIM_CounterMode=TIM_CounterMode_Up;  // 向上计数
	TimeBase_InitStructure.TIM_Period=100-1;  // ARR
	TimeBase_InitStructure.TIM_Prescaler=720-1;  // PSC
	TimeBase_InitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2, &TimeBase_InitStructure);
	
	// 配置OC单元
	TIM_OCInitTypeDef OC1_InitStructure;
	TIM_OCStructInit(&OC1_InitStructure);
	OC1_InitStructure.TIM_OutputState=TIM_OutputState_Enable;
	OC1_InitStructure.TIM_OCMode=TIM_OCMode_PWM1;  // 设置模式
	OC1_InitStructure.TIM_OCPolarity=TIM_OCPolarity_High;  // 设置有效电平
	OC1_InitStructure.TIM_Pulse=50;  // CCR
	TIM_OC1Init(TIM2, &OC1_InitStructure);
	
	// 开启时钟
	TIM_Cmd(TIM2, ENABLE);
}

/*
初始化TIM3的PWM模式
*/
void TIM3_PWM_Init(void)
{
	// RCC使能时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 配置GPIO口
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// 配置内部时钟作为TIM的时钟源
	TIM_InternalClockConfig(TIM3);
	
	// 配置时基单元
	TIM_TimeBaseInitTypeDef TimeBase_InitStructure;
	TimeBase_InitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TimeBase_InitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TimeBase_InitStructure.TIM_Period=100-1; // ARR
	TimeBase_InitStructure.TIM_Prescaler=720-1; // PSC
	TimeBase_InitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM3, &TimeBase_InitStructure);
	
	// 配置OC单元
	TIM_OCInitTypeDef OC1_InitStructure;
	TIM_OCStructInit(&OC1_InitStructure);
	OC1_InitStructure.TIM_OCMode=TIM_OCMode_PWM1;  // 设置模式
	OC1_InitStructure.TIM_OCPolarity=TIM_OCPolarity_High;  // 设置有效电平
	OC1_InitStructure.TIM_OutputState=TIM_OutputState_Enable;  
	OC1_InitStructure.TIM_Pulse=50;  // CCR
	TIM_OC1Init(TIM3, &OC1_InitStructure);
	
	// 开启时钟
	TIM_Cmd(TIM3, ENABLE);
}

/*
设置TIM2的CRR1寄存器
*/
void TIM2_PWM_Set_Compare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);  // 设置OC1 CCR寄存器
}

/*
设置TIM3的CRR1寄存器
*/
void TIM3_PWM_Set_Compare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM3, Compare);
}
main.c
#include "stm32f10x.h" 
#include "OLED.h"
#include "PWM.h"
#include "IC.h"

// TIM输入测频率
// 2023年3月25日11:11:15

int main(void)
{
	TIM2_PWM_Init();
	TIM3_IC_Init();
	OLED_Init();
	OLED_ShowString(1, 1, "Freq:00000Hz");

	while(1)
	{
		
		OLED_ShowNum(1, 6, Get_TIM3_CH1_Freq(), 5);
	}

}

案例2: PWMI模式下测量信号频率和占空比(对应PWMI基本结构)

整体代码

IC.c
#include "stm32f10x.h"

/*
初始化TIM3_IC
*/
void TIM3_IC_Init(void)
{
	// RCC使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	
	// 配置GPIO口 A6 TIM3_CH1
	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 TimeBase_InitStructure;
	TimeBase_InitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TimeBase_InitStructure.TIM_CounterMode=TIM_CounterMode_Up;  // 向上计数
	TimeBase_InitStructure.TIM_Period=65536-1;  // ARR
	TimeBase_InitStructure.TIM_Prescaler=72-1;  // PSC
	TimeBase_InitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM3, &TimeBase_InitStructure);
	
	// 配置IC单元
	TIM_ICInitTypeDef TIM_InitStructure;
	TIM_InitStructure.TIM_Channel=TIM_Channel_1;  // 定时器通道
	TIM_InitStructure.TIM_ICFilter=0xF;  // 滤波器
	TIM_InitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;  // 边沿极性选择
	TIM_InitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;  // 分频器
	TIM_InitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI; // 选择器
	TIM_PWMIConfig(TIM3, &TIM_InitStructure); // 区别在这里
	
	// 配置从模式
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);  // 选择TI1FP1通道
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);  // 选择Reset模式
	// 开启定时器
	TIM_Cmd(TIM3, ENABLE);
}

/*
获取TIM3_CH1 输入波形频率
*/
uint32_t Get_TIM3_CH1_Freq(void)
{
	return 72000000/(TIM_GetPrescaler(TIM3)+1)/ (TIM_GetCapture1(TIM3)+1);
}

/*
获取TIM3_PWMI 模式下占空比
*/

uint32_t Get_TIM3_Duty(void)
{
	return (TIM_GetCapture2(TIM3) + 1)*100 / (TIM_GetCapture1(TIM3) + 1);
}
TIM_PWMIConfig函数原型
/**
  * @brief  Configures the TIM peripheral according to the specified
  *         parameters in the TIM_ICInitStruct to measure an external PWM signal.
  * @param  TIMx: where x can be  1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.
  * @param  TIM_ICInitStruct: pointer to a TIM_ICInitTypeDef structure
  *         that contains the configuration information for the specified TIM peripheral.
  * @retval None
  */
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct)
{
  uint16_t icoppositepolarity = TIM_ICPolarity_Rising;
  uint16_t icoppositeselection = TIM_ICSelection_DirectTI;
  /* Check the parameters */
  assert_param(IS_TIM_LIST6_PERIPH(TIMx));
  /* Select the Opposite Input Polarity */
  if (TIM_ICInitStruct->TIM_ICPolarity == TIM_ICPolarity_Rising)
  {
    icoppositepolarity = TIM_ICPolarity_Falling;
  }
  else
  {
    icoppositepolarity = TIM_ICPolarity_Rising;
  }
  /* Select the Opposite Input */
  if (TIM_ICInitStruct->TIM_ICSelection == TIM_ICSelection_DirectTI)
  {
    icoppositeselection = TIM_ICSelection_IndirectTI;
  }
  else
  {
    icoppositeselection = TIM_ICSelection_DirectTI;
  }
  if (TIM_ICInitStruct->TIM_Channel == TIM_Channel_1)
  {
    /* TI1 Configuration */
    TI1_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, TIM_ICInitStruct->TIM_ICSelection,
               TIM_ICInitStruct->TIM_ICFilter);
    /* Set the Input Capture Prescaler value */
    TIM_SetIC1Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);
    /* TI2 Configuration */
    TI2_Config(TIMx, icoppositepolarity, icoppositeselection, TIM_ICInitStruct->TIM_ICFilter);
    /* Set the Input Capture Prescaler value */
    TIM_SetIC2Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);
  }
  else
  { 
    /* TI2 Configuration */
    TI2_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, TIM_ICInitStruct->TIM_ICSelection,
               TIM_ICInitStruct->TIM_ICFilter);
    /* Set the Input Capture Prescaler value */
    TIM_SetIC2Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);
    /* TI1 Configuration */
    TI1_Config(TIMx, icoppositepolarity, icoppositeselection, TIM_ICInitStruct->TIM_ICFilter);
    /* Set the Input Capture Prescaler value */
    TIM_SetIC1Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);
  }
}
PWM.c
#include "stm32f10x.h"

/*
初始化TIM2的PWM模式
*/
void TIM2_PWM_Init(void)
{
	// RCC使能时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 配置GPIO口
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// 配置内部时钟作为TIM的时钟源
	TIM_InternalClockConfig(TIM2);
	
	// 配置时基单元
	TIM_TimeBaseInitTypeDef TimeBase_InitStructure;
	TimeBase_InitStructure.TIM_ClockDivision=TIM_CKD_DIV1 ;
	TimeBase_InitStructure.TIM_CounterMode=TIM_CounterMode_Up;  // 向上计数
	TimeBase_InitStructure.TIM_Period=100-1;  // ARR
	TimeBase_InitStructure.TIM_Prescaler=720-1;  // PSC
	TimeBase_InitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2, &TimeBase_InitStructure);
	
	// 配置OC单元
	TIM_OCInitTypeDef OC1_InitStructure;
	TIM_OCStructInit(&OC1_InitStructure);
	OC1_InitStructure.TIM_OutputState=TIM_OutputState_Enable;
	OC1_InitStructure.TIM_OCMode=TIM_OCMode_PWM1;  // 设置模式
	OC1_InitStructure.TIM_OCPolarity=TIM_OCPolarity_High;  // 设置有效电平
	OC1_InitStructure.TIM_Pulse=50;  // CCR
	TIM_OC1Init(TIM2, &OC1_InitStructure);
	
	// 开启时钟
	TIM_Cmd(TIM2, ENABLE);
}

/*
初始化TIM3的PWM模式
*/
void TIM3_PWM_Init(void)
{
	// RCC使能时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 配置GPIO口
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// 配置内部时钟作为TIM的时钟源
	TIM_InternalClockConfig(TIM3);
	
	// 配置时基单元
	TIM_TimeBaseInitTypeDef TimeBase_InitStructure;
	TimeBase_InitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TimeBase_InitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TimeBase_InitStructure.TIM_Period=100-1; // ARR
	TimeBase_InitStructure.TIM_Prescaler=720-1; // PSC
	TimeBase_InitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM3, &TimeBase_InitStructure);
	
	// 配置OC单元
	TIM_OCInitTypeDef OC1_InitStructure;
	TIM_OCStructInit(&OC1_InitStructure);
	OC1_InitStructure.TIM_OCMode=TIM_OCMode_PWM1;  // 设置模式
	OC1_InitStructure.TIM_OCPolarity=TIM_OCPolarity_High;  // 设置有效电平
	OC1_InitStructure.TIM_OutputState=TIM_OutputState_Enable;  
	OC1_InitStructure.TIM_Pulse=50;  // CCR
	TIM_OC1Init(TIM3, &OC1_InitStructure);
	
	// 开启时钟
	TIM_Cmd(TIM3, ENABLE);
}

/*
设置TIM2的CRR1寄存器
*/
void TIM2_PWM_Set_Compare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);  // 设置OC1 CCR寄存器
}

/*
设置TIM2的PSC寄存器
*/
void TIM2_PWM_Set_PSC(uint16_t PSC)
{
	TIM_PrescalerConfig(TIM2, PSC, TIM_PSCReloadMode_Update);
}

/*
设置TIM3的CRR1寄存器
*/
void TIM3_PWM_Set_Compare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM3, Compare);
}
main.c
#include "stm32f10x.h" 
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
// PWMI模式下测量信号频率和占空比
// 2023年3月25日11:13:10
int main(void)
{
	TIM2_PWM_Init();
	TIM3_IC_Init();
	OLED_Init();
	OLED_ShowString(1, 1, "Freq:00000Hz");
	OLED_ShowString(2, 1, "Duty:00%");
	
	// 设置占空比
	TIM2_PWM_Set_Compare1(30);  // Duty = CCR / ARR + 1
	// 设置频率  
	TIM2_PWM_Set_PSC(72-1);  	// Freq = 72M / (ARR + 1) / (PSC + 1)
	while(1)
	{
		OLED_ShowNum(1, 6, Get_TIM3_CH1_Freq(), 5);
		OLED_ShowNum(2, 6, Get_TIM3_Duty(), 2);
	}

}

TIM3_PWM_Set_Compare1(uint16_t Compare)
{
TIM_SetCompare1(TIM3, Compare);
}


#### main.c

```C
#include "stm32f10x.h" 
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
// PWMI模式下测量信号频率和占空比
// 2023年3月25日11:13:10
int main(void)
{
	TIM2_PWM_Init();
	TIM3_IC_Init();
	OLED_Init();
	OLED_ShowString(1, 1, "Freq:00000Hz");
	OLED_ShowString(2, 1, "Duty:00%");
	
	// 设置占空比
	TIM2_PWM_Set_Compare1(30);  // Duty = CCR / ARR + 1
	// 设置频率  
	TIM2_PWM_Set_PSC(72-1);  	// Freq = 72M / (ARR + 1) / (PSC + 1)
	while(1)
	{
		OLED_ShowNum(1, 6, Get_TIM3_CH1_Freq(), 5);
		OLED_ShowNum(2, 6, Get_TIM3_Duty(), 2);
	}

}

参考资料

https://www.bilibili.com/video/BV1th411z7sn?p=18&vd_source=722e2c21f78eecf154c5c9d24c2841b3

<think>好的,我现在需要帮助用户解决使用STM32F103C8T6HAL库测量高频信号频率占空比的问题。首先,我应该回顾用户提供的引用资料,看看是否有相关的信息可以利用。 引用[2]提到使用PWM生成高频信号,其中配置定时器分频系数计数模式。用户需要测量高频信号频率占空比,这可能涉及到输入捕获功能。引用[4]正好有一个输入捕获的头文件,里面提到了获取频率占空比的函数,这应该是关键。 接下来,我需要确定如何配置定时器进行输入捕获STM32输入捕获通常使用定时器的捕获/比较通道来测量脉冲的上升沿下降沿的时间差,从而计算频率占空比。根据引用[3],定时器的预分频计数周期设置会影响时间测量的精度。例如,当APB1时钟为72MHz,预分频设置为71,则定时器时钟为1MHz,每个计数周期为1μs。这可能适用于测量较低频率信号,但对于高频信号,可能需要更高的时钟频率或更小的预分频系数。 用户的问题是关于高频信号,所以需要确保定时器的配置足够快。例如,如果输入信号是50kHz(如引用[2]中的PWM频率),定时器的计数周期需要足够短,以避免溢出。引用[2]中将定时器的分频系数设置为0,计数上限为719,这样定时器的频率为50kHz。这可能不适用于输入捕获,但可以参考其配置思路,调整分频系数以提高定时器频率,从而更精确地捕捉高频信号。 接下来,我需要考虑如何用HAL库实现输入捕获。通常需要配置定时器为输入捕获模式,使用两个通道分别捕捉上升沿下降沿,或者使用一个通道交替捕捉。例如,TIMx_CH1用于捕捉上升沿,触发中断后切换到下降沿,并记录两次的时间差来计算占空比周期。 用户可能需要示例代码,所以需要提供一个基本的配置步骤代码框架。首先,在CubeMX中配置定时器,比如TIM2或TIM3,设置合适的预分频计数周期。然后启用输入捕获通道,配置为交替模式或使用两个通道。接着,在代码中初始化输入捕获,编写中断处理函数,计算频率占空比。 需要注意的是,高频信号测量可能要求更高的定时器时钟。例如,如果信号频率为1MHz,定时器的时钟至少需要比这个快,否则可能无法准确捕获。对于STM32F103C8T6,最高定时器时钟是72MHz,因此预分频可以设置为0,这样每个计数周期是1/72MHz ≈13.89ns,可以测量更高频率信号。 同时,要处理定时器溢出的情况,尤其是在测量低频信号时,但用户关注的是高频,所以可能溢出较少,但仍需考虑。此外,DMA可能用于高效读取捕获值,但HAL库的输入捕获通常依赖中断,需要确保中断处理足够快,避免丢失边沿事件。 最后,结合引用[4]中的函数ic_getfreqic_getduty,可以编写类似的函数,基于捕获的时间值计算频率占空比。例如,周期为上升沿之间的时间差,高电平时间为上升沿到下降沿的时间,占空比即为高电平时间除以周期。 总结步骤:配置定时器参数,设置输入捕获通道,编写中断回调函数,计算频率占空比,提供示例代码。同时,需要注意高频下的定时器配置可能的性能限制,比如STM32F103的处理能力,以及代码的效率。</think>### 测量高频信号频率占空比的实现步骤 #### 1. 定时器配置原理 高频信号测量需通过定时器的输入捕获功能实现,关键参数包括: - **定时器时钟频率**:若APB1总线时钟为72MHz,分频系数设置为0,则定时器时钟为$f_{clk}=72\ \text{MHz}$,计时精度为$1/72\ \text{μs} \approx 13.89\ \text{ns}$[^3] - **自动重装载值**:根据信号最高频率选择。例如测量1MHz信号时,周期为1μs,需设置重装载值$ARR \geq 72$(对应$72 \times 13.89\ \text{ns} = 1\ \text{μs}$) - **捕获模式**:使用PWM输入模式(双通道交替捕获)可同时获取周期占空比[^4] #### 2. CubeMX配置步骤 1. 启用TIM2(或其他支持PWM输入模式的定时器) 2. 通道配置: - **TI1**:映射到输入信号引脚,滤波器适当设置 - 触发源选择:TI1FP1 - 从模式选择:复位模式 3. 参数设置: ```c Prescaler = 0 // 无分频 Counter Mode = Up // 向上计数 AutoReload = 65535 // 最大计数范围 ICPolarity = Rising // 初始捕获极性 ``` #### 3. 关键代码实现 ```c // 输入捕获结构体定义 volatile uint32_t IC_Value1 = 0, IC_Value2 = 0; volatile float DutyCycle = 0, Frequency = 0; // 中断回调函数 void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) { if(htim->Instance->CCMR1 & TIM_CCMR1_CC1S_0) // 上升沿捕获 { IC_Value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING); } else // 下降沿捕获 { IC_Value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); DutyCycle = (float)(IC_Value2 - IC_Value1) / htim->Instance->ARR * 100; __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING); } } } // 频率计算函数 float Get_Frequency(TIM_HandleTypeDef *htim) { return (float)(SystemCoreClock / (htim->Instance->PSC + 1)) / (IC_Value1 + 1); } ``` #### 4. 性能优化建议 - **高频信号处理**:当信号频率超过1MHz时,建议: $$ f_{measure} \leq \frac{f_{timer}}{4} $$ 即72MHz时钟下最高可18MHz信号 - **抗干扰设计**:配置输入滤波器,例如设置`ICFilter = 0x0F`时,需满足: $$ t_{filter} \geq \frac{N \times t_{clk}}{f_{DTS}} $$ 其中$N$为采样次数,$f_{DTS}$为数字滤波器时钟[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值