输入捕获:当TIMx_CHx通道引脚出现指定电平跳变时,当前时基单元的CNT值会被所存到CCR寄存器中,这样可以用于测量PWM波形的频率,占空比,脉冲间隔,电平持续时间等参数;
PWM测量:
1个TIMx-CHx引脚经过输入滤波器(输入引脚抖动滤波)和边沿检测器(指定上升、下降沿)处理后,可以产生两个输出,TIxFP1和TIxFP2(两路信号的滤波和边沿检测可以单独设定);同时送给两个捕获寄存器(可做预分频);这样可以实现一个通道上测量PWM信号,上升沿电平触发,将CNT值转运到CCR1,下降沿电平触发,将CNT值转运到CCR2;就可以实现占空比和频率的测量;
主从模式:
输入捕获下,每次当TIMX-CHX在有信号(如上图TI1FP1)变化导致CNT值向CCR转运时,同时会触发从模式控制;完成CNT的清零;
主模式:将定时器内部的信号,映射到TRGO,用于触发别的外设(其他外设包括其他定时器);
从模式:接受其他外设或者自身外设的信号,用于控制自身定时器的运行;
同时转运也会在触发一个捕获事件,同时在状态寄存器中置标志位,可以产生中断,利用中断去处理某些任务;
GPIO初始化:参考GPIO操作,模式选择上拉输入,高阻可能导致信号抖动误触发;
1、使能GPIO时钟;
2、创建GPIO_InitTypeDef类型的结构体并赋值;
3、调用GPIO_Init()函数初始化GPIO
输入捕获单元设置:
1、创建TIM_OCInitTypeDef类型的结构体并赋值,涉及
typedef struct
{
uint16_t TIM_Channel; /*定时器输入捕获通道1~4*/
uint16_t TIM_ICPolarity; /*边沿选择,上升沿?下降沿?*/
uint16_t TIM_ICSelection; /*输入极性(直接输入,1对1,2对2,;还是交叉输入,1通道触发2的CCR,2通道触发1的CCR) */
uint16_t TIM_ICPrescaler; /*分频器设置,1/2/4/8分频 */
uint16_t TIM_ICFilter; /*以系统时钟72M进行滤波,0x0 and 0xF可设定 */
} TIM_ICInitTypeDef;
2、捕获单元初始化void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
时基单元设置:
1、开启定时器时钟使能;
2、选择内部时钟:TIM_InternalClockConfig(TIMx);
3、创建TIM_TimeBaseInitTypeDef类型的结构体并赋值,涉及
typedef struct
{
uint16_t TIM_Prescaler; /*PSC预分频值 */
uint16_t TIM_CounterMode; /*上升沿下降沿模式*/
uint16_t TIM_Period; /*自动重装值 */
uint16_t TIM_ClockDivision; /*外部时钟的分频系数,使用内部时钟无效 */
uint8_t TIM_RepetitionCounter; /*重复计数,高级定时器有效 */
} TIM_TimeBaseInitTypeDef;
4、初始化时基单元TIM_TimeBaseInit();
从模式触发源选择:
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
/*从模式的触发源选择,TRGI的前级信号选择*/
触发源:3/4通道没有作为触发源,不能自动触发从模式,如要清零CNT,就需要进中断手动处理
* @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
上述配置完成后,在有外部边沿触发信号过来时,在经过滤波极性等操作后,送到分频器以为,同时还会有TI1FP1信号被触发送出,此时若从模式触发源原则为TI1FP1,则会进入从模式进行响应操作;
从模式操作命令
从模式下有8种动作,4种为编码器相关,另外介绍,剩下4种,测量PWM频率,需要将时基单元的CNT清零,故选择RESET
* @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.
函数调用TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
使能计数器:TIM_Cmd(TIM3, ENABLE);
如此计数器自动计数,在GPIO有边沿触发后将CNT值转移到CCR寄存器中同时清零CNT值;
最后调用TIM_GetCapture1(TIMx)函数返回值,即两个上升沿/下降沿之间的CNT,换算为频率;
代码如下:
#include "stm32f10x.h" // Device header
void IC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
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 TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
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);
}
PWMI模式:
在PWM基础上,1个GPIO触发时,设置两组触发信号分别送到两个CCR中,一个为上升沿触发,一个为下降沿触发,上升沿触发转运CNT值转运到CCR1并通过TI1FP1触发从模式清零CNT;下降沿触发CNT值转运到CCR2;CCR1可以计算PWM频率,CCR2可以计算占空比;
GPIO初始化:参考GPIO操作,模式选择上拉输入,高阻可能导致信号抖动误触发;
1、使能GPIO时钟;
2、创建GPIO_InitTypeDef类型的结构体并赋值;
3、调用GPIO_Init()函数初始化GPIO
输入捕获单元设置:
1、创建TIM_OCInitTypeDef类型的结构体并赋值,涉及
typedef struct
{
uint16_t TIM_Channel; /*定时器输入捕获通道1~4*/
uint16_t TIM_ICPolarity; /*边沿选择,上升沿?下降沿?*/
uint16_t TIM_ICSelection; /*输入极性(直接输入,1对1,2对2,;还是交叉输入,1通道触发2的CCR,2通道触发1的CCR) */
uint16_t TIM_ICPrescaler; /*分频器设置,1/2/4/8分频 */
uint16_t TIM_ICFilter; /*以系统时钟72M进行滤波,0x0 and 0xF可设定 */
} TIM_ICInitTypeDef;
2、捕获单元初始化
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);/*设定捕获通道设置*/
TIM_PWMIConfig(TIMx, &TIM_ICInitStructure);/*极性选择交叉输入,若结构体原设定通道1,则此设置触发2通道的CCR,若原通道2,则触发CCR1,同时,通道选择根据原设定对换2或者1,同时将上面结构体中的边沿检测取反,用来触发反向通道的CCR*/
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);
}
}
时基单元设置:
1、开启定时器时钟使能;
2、选择内部时钟:TIM_InternalClockConfig(TIMx);
3、创建TIM_TimeBaseInitTypeDef类型的结构体并赋值,涉及
typedef struct
{
uint16_t TIM_Prescaler; /*PSC预分频值 */
uint16_t TIM_CounterMode; /*上升沿下降沿模式*/
uint16_t TIM_Period; /*自动重装值 */
uint16_t TIM_ClockDivision; /*外部时钟的分频系数,使用内部时钟无效 */
uint8_t TIM_RepetitionCounter; /*重复计数,高级定时器有效 */
} TIM_TimeBaseInitTypeDef;
4、初始化时基单元TIM_TimeBaseInit();
从模式触发源选择:
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
/*从模式的触发源选择,TRGI的前级信号选择*/
上述配置完成后,在有外部边沿触发信号过来时,在经过滤波极性等操作后,送到分频器以为,同时还会有TI1FP1信号被触发送出,此时若从模式触发源原则为TI1FP1,则会进入从模式进行响应操作;
从模式操作命令
从模式下有8种动作,4种为编码器相关,另外介绍,剩下4种,测量PWM频率,需要将时基单元的CNT清零,故选择RESET
* @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.
函数调用TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
使能计数器:TIM_Cmd(TIM3, ENABLE);
如此计数器自动计数,在GPIO有边沿触发后将CNT值转移到CCR寄存器中同时清零CNT值;
最后调用TIM_GetCapture1(TIM1)的函数返回值,即两个上升沿/下降沿之间的CNT,换算为频率;调用TIM_GetCapture1(TIM2)的函数返回值,即高电平的CNT累加书,换算为占空比;
代码如下:
#include "stm32f10x.h" // Device header
void IC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
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 TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
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_PWMIConfig(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);
}
uint32_t IC_GetDuty(void)
{
return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);
}