一、输入捕获介绍
1. 概念
输入捕获(Input Capture)是一种用于测量外部信号脉冲宽度或者频率的技术,常用于测量传感器输出、编码器信号、脉冲调制信号等。输入捕获通常通过定时器模块来实现输入捕获功能。
2. STM32F1 资源
STM32F1除了基本定时器TIM6和TIM7,其它定时器都具有输入捕获功能。
3. 捕获原理
捕获原理是指通过定时器模块捕获外部信号的特定事件,例如脉冲的上升沿或下降沿,以便测量脉冲宽度或频率。 输入捕获时,相应的ICx检测到跳变沿,TIMx_CCRx寄存器记录TIMx_CNT计数值;下次跳变时,对TIMx_CNT值进行比较。
图示如下:
注意CNT计数的次数是 N ∗ A R R + C C R ∗ x 2 N*ARR+CCR*x2N∗ARR+CCR∗x2,因为在检测周期里计数可能多次溢出,需要记录溢出次数N。
由计数效数*CNT计数周期,即捕获到信号持续时间。
二、输入捕获配置步骤
1. 使能时钟、设置端口模式
定时器需要的头文件在 stm32f10_tim.h 文件中。
下面示例使用 PA0/TIM5_CH1 引脚。
RCC_APB1PerihpClockCmd(RCC_APB1Periph_TIM5,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
// GPIO 设置为输入拉低
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;
2. 初始化定时器
配置定时器的时钟源、预分频器、计数模式等。
void TIM_TimeBaseInit(TIM_TypeDef *TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
1
3. 设置捕获参数
开启捕获。
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStrcut);
typedef struct{
uint16_t TIM_Channel; // 通道
uint16_t TIM_ICPolarity; // 捕获极性
uint16_t TIM_ICSelection; // 映射
uint16_t TIM_ICPRescaler; // 分频系数
uint16_t TIM_ICFilter; // 滤波器长度
} TIM_ICInitTypeDef;
// 设置通道1
TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Rising);
4. 开启捕获和定时器中断(溢出中断|更新中断)
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
// 捕获通道1
TIM_ITConfig(TIM5, TIM_IT_Update|TIM_IT_CC1,ENABLE);
NVIC_Init()
6. 编写定时器中断服务函数
TIM5_IRQHandler
1
7. 使能定时器
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
1
三、代码实现
1. catch_utils.h
#ifndef __CATCH_UTILS_H__
#define __CATCH_UTILS_H__
#include "stm32f10x.h"
#include "stdio.h"
// 定时器溢出的次数
static u8 TIM5_Overflow = 0;
// 捕获到上升沿
static u8 TIM5_Capture = 0;
void catch_gpio_init(u16 period, u16 prescaler);
void catch_timer_enable(void);
#endif
2. catch_utils.c
#include "catch_utils.h"
#define RISING 0
#define FALLING 1
/**
* @brief 捕获初始化
*/
void catch_gpio_init(u16 period, u16 prescaler)
{
// GPIO 初始化
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 定时器初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = period;
TIM_TimeBaseStructure.TIM_Prescaler = prescaler;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
// 输入捕获初始化
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x00;
TIM_ICInit(TIM5, &TIM_ICInitStructure);
TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Rising);
// 开启捕获和定时器中断
TIM_ITConfig(TIM5, TIM_IT_Update | TIM_IT_CC1, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**
* 中断函数
*/
void TIM5_IRQHandler(void)
{
// 如果捕获到,要翻转一下捕获方向,如果捕获到下降沿,就设置为上升沿,并计算捕获时间并输出
if (TIM_GetITStatus(TIM5, TIM_IT_CC1))
{
if (TIM5_Capture == RISING)
{
printf("catch rising irq, TIM5_Capture= %d \n", TIM5_Capture);
TIM5_Capture = FALLING;
// 关闭定时器
TIM_Cmd(TIM5, DISABLE);
TIM_SetCounter(TIM5, 0);
TIM5_Overflow = 0;
TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Falling);
TIM_Cmd(TIM5, ENABLE);
}
else
{
// 捕获到下降沿
TIM5_Capture = RISING;
// 计算 总时间
u16 time = TIM_GetCapture1(TIM5);
u32 total_time = TIM5_Overflow * 0xffff + time;
printf("catch falling irq, capture time= %d, overflow count = %d \n, total=%dus", time, TIM5_Overflow, total_time);
TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Rising);
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1);
}else if(TIM_GetITStatus(TIM5, TIM_IT_Update)){
TIM5_Overflow++;
TIM_ClearITPendingBit(TIM5, TIM_IT_Update);
}
}
/**
* @brief 使能定时器
*/
void catch_timer_enable(void)
{
TIM_Cmd(TIM5, ENABLE);
}
3. main.c
#include "gpio_utils.h"
#include "rcc_utils.h"
#include "stm32f10x.h"
#include "sys_tick_utils.h"
#include "led_utils.h"
#include "usart_utils.h"
#include "stdio.h"
#include "catch_utils.h"
// 主函数
int main(void)
{
GPIO_Configuration(); // 调用GPIO配置函数
// tick 初始化
sys_tick_init(72);
led_all_off();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
USART3_Init(9600);
printf("starting...");
// led 初始化
custom_led_init();
int i = 0;
// 捕获初始化
catch_gpio_init(0xffff, 72 - 1);
catch_timer_enable();
while (1) // 无限循环
{
delay_ms(990);
led_lightn(i);
i++;
if(i>9){
i=0;
}
}
}
四、触摸按键捕获
我的开发板没有带触摸组件,所以本实验使用外置的触摸按键模块。
这个触摸按键在感应到触摸时,会在SIG引脚输出高电平。 直接把SIG接在 PA0 上即可使用。
但该电路对原KEY_UP按键模块有影响,开发板按键按下的时候,PA0 获取不到足够高的电平。
运行中串口输出示例
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/xundh/article/details/136640793
|
|