如图回顾一下上面的测量案件按下时间原理图
当检测到下降沿时, 定时器中断 计数器清零 统计在低电平期间 溢出arr的次数 根据下面公式 将psc设置为72 这样就可设置一次计数的时间为0.000001s 只需统计计数个数即可 当检测到上升沿时 记录当前ccr的值 就可统计出来
在此回调函数中 HAL_TIM_IC_CaptureCallback() 一定要注意设置succeed_flag标志位 这样当一次捕获下降沿 一次捕获上升沿后 succeed_flag 置1 激发另一个if条件语句即pressed_time_get 函数 从而计算按键按下时间 结束后一定要用memset(&capture_status, 0, sizeof(capture_status)); 来清除结构体当中的值 从而为下一次再次捕获做准备
HAL_TIM_PeriodElapsedCallback() 用此函数来计算中断溢出次数 这个也是回调函数 时内部自己运行的 即中断溢出函数
代码如下
#include "ic.h"
#include "stdint.h"
#include "stdio.h"
#include "string.h"
struct
{
uint8_t succeed_flag; //检测是否成功捕获到上升or下降沿标志位
uint8_t rising_flag; //上升沿标致位
uint8_t falling_flag; //下降沿标志位
uint8_t timout_cnt; //溢出的次数标致位
}capture_status ={0};
uint16_t lastccr=0;
TIM_HandleTypeDef ic_handle={0};
void ic_init(uint16_t arr,uint16_t psc)
{
TIM_IC_InitTypeDef ic_config ={0};
ic_handle.Instance = TIM2;
ic_handle.Init.Period = arr;
ic_handle.Init.CounterMode =TIM_COUNTERMODE_UP;
ic_handle.Init.Prescaler = psc;
HAL_TIM_IC_Init(&ic_handle); //时基工作参数配置
ic_config.ICPolarity = TIM_ICPOLARITY_FALLING; //选择极性 刚开始捕获的是下降沿 故选择下降沿的模式
ic_config.ICSelection = TIM_ICSELECTION_DIRECTTI; //定时器2被直接连接到相应的输入捕获通道
ic_config.ICPrescaler = TIM_ICPSC_DIV1; //默认不分频
ic_config.ICFilter =0; //滤不滤波 不滤波设置为0
HAL_TIM_IC_ConfigChannel(&ic_handle,&ic_config,TIM_CHANNEL_2); //输入通道的配置 捕获的边沿 映射 分频 滤波
__HAL_TIM_ENABLE_IT(&ic_handle,TIM_IT_UPDATE); //更新中断使能 第二个参数为更新中断的模式
HAL_TIM_IC_Start_IT(&ic_handle,TIM_CHANNEL_2); //使能捕获 捕获中断及计数器
}
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2)
{
//①定义初始化结构体
GPIO_InitTypeDef gpio_initstruct;
//打开时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //打开GPIO的时钟
__HAL_RCC_TIM2_CLK_ENABLE(); //打开定时器的时钟
//调用GPIO初始化函数
gpio_initstruct.Pin = GPIO_PIN_1 ; //LED1、LED2对应的引脚
gpio_initstruct.Pull = GPIO_PULLUP; //上拉
gpio_initstruct.Mode =GPIO_MODE_INPUT; //推挽复用输出
gpio_initstruct.Speed =GPIO_SPEED_FREQ_HIGH; //高速
HAL_GPIO_Init(GPIOA,&gpio_initstruct);
HAL_NVIC_SetPriority(TIM2_IRQn, 2,2); //设置NVIC
HAL_NVIC_EnableIRQ(TIM2_IRQn); //设置NVIC
}
}
void TIM2_IRQHandler(void)
{
HAL_TIM_IRQHandler(&ic_handle);
}
//下面代码冗余
/*
void HAL_TIM_IC_CaptureCallback (TIM_HandleTypeDef *htim)
{
//printf("捕获到下降沿\r\n");
if(htim->Instance == TIM2) //回调函数中也有很多定时器 因此要确是否是定时器2
{
if(capture_status.succeed_flag == 0)
{
if(capture_status.falling_flag == 1)
{
printf("捕获到上升沿\r\n");
capture_status.succeed_flag =1;
TIM_RESET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2); //清除通道设置 传入两个参数 一个是距离 另外一个是渠道
TIM_SET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2,TIM_ICPOLARITY_FALLING); //设置为下降沿检测等待检测下降沿 变成初始检测状态
memset(&capture_status,0,sizeof(capture_status)); //让结构体中的所有都置0
}
else
{
printf("捕获到下降沿\r\n");
memset(&capture_status,0,sizeof(capture_status)); //让结构体中的所有都置0
capture_status.falling_flag = 1;
TIM_RESET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2); //清除通道设置 传入两个参数 一个是距离 另外一个是渠道
TIM_SET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2,TIM_ICPOLARITY_RISING); //设置为上升沿检测等待检测上升沿 因为初始检测的是下降沿
}
}
}
}
*/
void HAL_TIM_IC_CaptureCallback (TIM_HandleTypeDef *htim)
{
//printf("捕获到下降沿\r\n");
if(htim->Instance == TIM2) //回调函数中也有很多定时器 因此要确是否是定时器2
{
if(capture_status.succeed_flag == 0)
{
if(capture_status.falling_flag == 1)
{
printf("捕获到上升沿\r\n");
capture_status.succeed_flag=1; //检测是否捕获到一次完整的上升沿和下降沿
lastccr=HAL_TIM_ReadCapturedValue(&ic_handle,TIM_CHANNEL_2); //记录上升沿时 只需记录当前ccr的值
TIM_RESET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2); //清除通道设置 传入两个参数 一个是距离 另外一个是渠道
TIM_SET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2,TIM_ICPOLARITY_FALLING); //设置为下降沿检测等待检测下降沿 变成初始检测状态
//memset(&capture_status,0,sizeof(capture_status)); //让结构体中的所有都置0
}
else
{
printf("捕获到下降沿\r\n");
capture_status.falling_flag = 1;
__HAL_TIM_DISABLE(&ic_handle); //关闭定时器
__HAL_TIM_SET_COUNTER(&ic_handle,0); //计数器清零 第二个参数为计数器的值置几
TIM_RESET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2); //清除通道设置 主要用于清空下降沿捕获的命令 传入两个参数 一个是距离 另外一个是渠道
TIM_SET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2,TIM_ICPOLARITY_RISING); //设置为上升沿检测等待检测上升沿 因为初始检测的是下降沿
__HAL_TIM_ENABLE(&ic_handle); //开启定时器
}
}
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef * htim) //专门用于计数溢出中断的回调函数
{
if(htim->Instance == TIM2)
{
if(capture_status.falling_flag == 1)
{
capture_status.timout_cnt++; //每次中断溢出后都会自增1
}
}
}
void pressed_time_get(void)
{
if(capture_status.succeed_flag == 1)
{
printf("按下时间: %d us\r\n",capture_status.timout_cnt *65536+lastccr );
memset(&capture_status,0,sizeof(capture_status));
}
}
主函数如下
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "ic.h"
int main(void) {
HAL_Init();
stm32_clock_init(RCC_PLL_MUL9); // 设置时钟,72MHz
led_init();
uart1_init(115200); // 初始化 UART
printf("hello world!\r\n"); // 通过 UART 输出 "hello world"
ic_init(65536-1,72-1); //可理解为总共需要计数65536个 一次计数需要72/72M的时间
while(1) {
pressed_time_get();
delay_ms(10);
// led1_on();
// led2_off();
// delay_ms(500);
// led1_toggle();
// led2_toggle();
// delay_ms(500);
}
}