广西一站网网络技术集团有限公司,网络营销主要干什么,微信管理工具,商业网站设计1、按键按下的时间-思路 我们先检测下降沿信号#xff0c;检测到以后#xff0c;在回调函数里切换成检测上升沿信号#xff0c;当两个信号都检测到的时候#xff0c;这段时间就是按键按下的时间#xff0c;如图所示#xff1a;N*(ARR1)CCRx的值
N是在这段时间内检测到以后在回调函数里切换成检测上升沿信号当两个信号都检测到的时候这段时间就是按键按下的时间如图所示N*(ARR1)CCRx的值
N是在这段时间内可能会发生的N次溢出。CCRx是寄存器中的计数ARR打满65536-1
N个重装载值CCRx的值 2、实验目的
使 用 定 时 器 2 通 道 2 来 捕 获 按 键 2 按 下 时 间 并 通 过 串 口 打 印 。计 一 个 数 的 时 间1 u s P S C 7 1 A R R 6 5 5 3 5下 降 沿 捕 获 、 输 入 通 道 2 映 射 在 TI2 上 、 不 分 频 、 不 滤 波
为什么要使用定时器2通道2来捕获按键2
这个板子只有两个按键。一个是key1一个是key2分别对应A0和A1引脚
原理图 产品手册17页 在这里可以看到KEY1是接的定时器2通道1的ETR引脚通过下图我们可以看出来ETR引脚是作为一个输入源的而我们这里是想要一个通道所以这里使用KEY2
中文参考手册254页 1s 1000 000us
P S C 7 1
PSC172
72/72MHZ
1个时间周期 1/1000 000 1us
这里使用1us来表示记一个数的时也可以更小A R R 6 5 5 3 5直接把ARR拉满 上面是对时基单元配置
下面是对通道的配置
下 降 沿 捕 获 、 输 入 通 道 2 映 射 在 TI2 上 、 不 分 频 、 不 滤 波
滤波器先不要对边沿检测时先对下降沿检测然后迅速在回调函数中对上升沿进行检测。
分频器不分频
3、实现输入捕获功能
复制项目文件19重命名为20-实现捕获功能
打开项目文件
创建文件夹ic 加载文件 编译 编译 编译
代码如下 main.c
#include sys.h
#include delay.h
#include led.h
#include uart1.h
#include ic.hint main(void)
{HAL_Init(); /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */led_init();//初始化led灯uart1_init(115200);//printf(hello word!\r\n);ic_init(72-1,65536-1);while(1){ }
}ic.c
#include ic.h
#include stdio.hTIM_HandleTypeDef ic_handle {0};//初始化输入捕获函数
void ic_init(uint16_t psc,uint16_t arr)
{TIM_IC_InitTypeDef ic_config {0};ic_handle.Instance TIM2;//定时器2ic_handle.Init.Prescaler psc;ic_handle.Init.Period arr;ic_handle.Init.CounterMode TIM_COUNTERMODE_UP;//向上计数模式HAL_TIM_IC_Init(ic_handle);ic_config.ICFilter 0;//过滤器0也就是不要过滤器ic_config.ICPolarity TIM_ICPOLARITY_FALLING;//下降沿捕获ic_config.ICPrescaler TIM_ICPSC_DIV1;//每次在捕获输入上检测到边缘时执行捕获ic_config.ICSelection TIM_ICSELECTION_DIRECTTI;//输入捕获触发信号源直接连接到对应通道的输入捕获引脚这意味着输入捕获触发信号直接作用于定时器的输入捕获电路不需要通过其他中间寄存器或外部电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);}//初始化MSP函数
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{if(htim-Instance TIM2){GPIO_InitTypeDef gpio_initstruct;__HAL_RCC_TIM2_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();gpio_initstruct.Mode GPIO_MODE_INPUT;//复式推挽输出gpio_initstruct.Pin GPIO_PIN_1;//引脚1gpio_initstruct.Pull GPIO_PULLUP;//上拉输出gpio_initstruct.Speed GPIO_SPEED_FREQ_HIGH;//高速HAL_GPIO_Init(GPIOA,gpio_initstruct);HAL_NVIC_SetPriority(TIM2_IRQn,2,2);//外部中断号抢占优先级/响应优先级HAL_NVIC_EnableIRQ(TIM2_IRQn);}}//中断服务函数
void TIM2_IRQHandler(void)
{HAL_TIM_IRQHandler(ic_handle);
}//回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{printf(捕获一个下降沿\r\n);
}
ic.h
#ifndef __IC_H__
#define __IC_H__
#include sys.hvoid ic_init(uint16_t psc,uint16_t arr);#endif 在ic.c函数中
ic_config.ICSelection TIM_ICSELECTION_DIRECTTI;//输入捕获触发信号源直接连接到对应通道的输入捕获引脚这意味着输入捕获触发信号直接作用于定时器的输入捕获电路不需要通过其他中间寄存器或外部电
如果
ic_config.ICSelection TIM_ICSELECTION_INDIRECTTI;//配置输入捕获通道的输入信号选择为间接定时器输入模式。 TIM Input 1 被选择连接到 IC2。 TIM Input 2 被选择连接到 IC1。 TIM Input 3 被选择连接到 IC4。 TIM Input 4 被选择连接到 IC3。 如果这里的ic_config.ICSelection设置成下面这个参数
ic_config.ICSelection TIM_ICSELECTION_INDIRECTTI;
则摁KEY1才会响应按键
这是因为定时器2则连接到通道1中 在串口助手中摁KEY2会显示 4、实现一次完整的按键动作
复制项目文件20-实现捕获功能重命名21-捕获一次完整的按键动作
在上面实现了捕获下降沿在这里将会实现捕获上升沿整合就会实现一次完整的按键动作。
具体流程如下
succeed_flag是否发生了一次完整的按键动作标志位
falling_flag下降沿标志当falling_flag 0时默认情况下代表下降沿捕获成功
当falling_flag 1时默认情况下代表上升沿捕获成功 这里用到两个函数 TIM_RESET_CAPTUREPOLARITY(ic_handle, TIM_CHANNEL_2);//这行代码的作用是重置定时器捕获通道2的触发极性。 TIM_SET_CAPTUREPOLARITY(ic_handle, TIM_CHANNEL_2, TIM_ICPOLARITY_RISING);//这行代码的意思是为ic_handle所指向的定时器的第二个通道配置输入捕获极性为上升沿即输入信号从低电平变为高电平时。 在STM32的HAL库中TIM_RESET_CAPTUREPOLARITY函数用于重置定时器的捕获通道的触发极性。具体来说这个函数会将指定通道的触发极性设置为默认值通常是上升沿或下降沿。
IM_SET_CAPTUREPOLARITY(ic_handle, TIM_CHANNEL_2, TIM_ICPOLARITY_RISING); 这行代码是在使用STM32 HAL库硬件抽象层库进行定时器TIM的输入捕获配置时使用的。
代码流程定义一个结构体用于存放标志位和统计时间在回调函数中当用户按下按键最初赋值是下降沿检测检测到下降沿触发中断响应回调函数在回调函数中初始的相应完整按键的标志位为0执行if初始响应上升沿标志位为0执行else在else中将响应上升沿标志位 置1并且将检测下降沿重置为检测上升沿则在下次进入回调函数时由于检测完整按键的标志位依旧为0进入if检测上升沿标志位为1进入if执行上升沿函数代码段。
代码如下
ic.c
#include ic.h
#include stdio.h
#include string.hstruct
{uint8_t succeed_flag;//完整的按键动作标志位uint8_t rising_flag;//上升标志位uint8_t falling_flag;//下降标志位uint16_t timeout_cnt;//时间统计}capture_status{0};//全部初始化为0TIM_HandleTypeDef ic_handle {0};//初始化输入捕获函数
void ic_init(uint16_t psc,uint16_t arr)
{TIM_IC_InitTypeDef ic_config {0};ic_handle.Instance TIM2;//定时器2ic_handle.Init.Prescaler psc;ic_handle.Init.Period arr;ic_handle.Init.CounterMode TIM_COUNTERMODE_UP;//向上计数模式HAL_TIM_IC_Init(ic_handle);ic_config.ICFilter 0;//过滤器0也就是不要过滤器ic_config.ICPolarity TIM_ICPOLARITY_FALLING;//下降沿捕获ic_config.ICPrescaler TIM_ICPSC_DIV1;//每次在捕获输入上检测到边缘时执行捕获ic_config.ICSelection TIM_ICSELECTION_DIRECTTI;//输入捕获触发信号源直接连接到对应通道的输入捕获引脚这意味着输入捕获触发信号直接作用于定时器的输入捕获电路不需要通过其他中间寄存器或外部电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);}//初始化MSP函数
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{if(htim-Instance TIM2){GPIO_InitTypeDef gpio_initstruct;__HAL_RCC_TIM2_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();gpio_initstruct.Mode GPIO_MODE_INPUT;//复式推挽输出gpio_initstruct.Pin GPIO_PIN_1;//引脚1gpio_initstruct.Pull GPIO_PULLUP;//上拉输出gpio_initstruct.Speed GPIO_SPEED_FREQ_HIGH;//高速HAL_GPIO_Init(GPIOA,gpio_initstruct);HAL_NVIC_SetPriority(TIM2_IRQn,2,2);//外部中断号抢占优先级/响应优先级HAL_NVIC_EnableIRQ(TIM2_IRQn);}}//中断服务函数
void TIM2_IRQHandler(void)
{HAL_TIM_IRQHandler(ic_handle);
}//回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim-Instance TIM2){if(capture_status.succeed_flag 0)//完整按键捕获标志位等于0代表不完整{if(capture_status.rising_flag 1)//上升沿按键捕获标志等于1代表捕获到上升沿{printf(捕获一个上升沿\r\n);memset(capture_status,0,sizeof(capture_status));//对一整个结构体的清零TIM_RESET_CAPTUREPOLARITY(ic_handle,TIM_CHANNEL_2);//重置捕获通道2TIM_SET_CAPTUREPOLARITY(ic_handle,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_FALLING);//配置捕获为下升沿}else{//未捕获到上升沿现在是下降沿printf(捕获一个下降沿\r\n);memset(capture_status,0,sizeof(capture_status));//对一整个结构体的清零capture_status.rising_flag 1;//置位1表示接下来的边沿检测是上升沿的TIM_RESET_CAPTUREPOLARITY(ic_handle,TIM_CHANNEL_2);//重置捕获通道2TIM_SET_CAPTUREPOLARITY(ic_handle,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_RISING);//配置捕获为上升沿}}}
}
打开串口助手
按下按键2串口显示 5、测量按键按下时间
回顾如何测量按键按下的时间计算
在按键按下的瞬间检测到下降沿时立刻把计时器关闭将计数器置0再打开重启一下使其从头开始计数在未检测到上升沿之前计数器中间可能会发生几次溢出当检测到上升沿时关闭计数器查询当前计数器寄存器中的值。 复制项目文件21-捕获一次完整的按键动作重命名为22-测量按键按下时间 __HAL_TIM_DISABLE(ic_handle); 这行代码是在使用STM32 HAL库时用于禁用或停止一个定时器的功能 __HAL_TIM_SET_COUNTER(ic_handle, 0); 这行代码在使用STM32 HAL库时用于设置定时器的计数器值。 __HAL_TIM_ENABLE(ic_handle);//用于打开计数器 HAL_TIM_ReadCapturedValue(ic_handle, TIM_CHANNEL_2); 这行代码在使用STM32 HAL库时用于读取定时器指定通道的捕获值。 代码如下
main.c
#include sys.h
#include delay.h
#include led.h
#include uart1.h
#include ic.hint main(void)
{HAL_Init(); /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */led_init();//初始化led灯uart1_init(115200);//printf(hello word!\r\n);ic_init(72-1,65536-1);while(1){ pressed_time_get();delay_ms(500);}
}ic.c
#include ic.h
#include stdio.h
#include string.hstruct
{uint8_t succeed_flag;//完整的按键动作标志位uint8_t rising_flag;//上升标志位uint8_t falling_flag;//下降标志位uint16_t timeout_cnt;//时间统计}capture_status{0};//全部初始化为0
uint16_t last_cnt 0;TIM_HandleTypeDef ic_handle {0};//初始化输入捕获函数
void ic_init(uint16_t psc,uint16_t arr)
{TIM_IC_InitTypeDef ic_config {0};ic_handle.Instance TIM2;//定时器2ic_handle.Init.Prescaler psc;ic_handle.Init.Period arr;ic_handle.Init.CounterMode TIM_COUNTERMODE_UP;//向上计数模式HAL_TIM_IC_Init(ic_handle);ic_config.ICFilter 0;//过滤器0也就是不要过滤器ic_config.ICPolarity TIM_ICPOLARITY_FALLING;//下降沿捕获ic_config.ICPrescaler TIM_ICPSC_DIV1;//每次在捕获输入上检测到边缘时执行捕获ic_config.ICSelection TIM_ICSELECTION_DIRECTTI;//输入捕获触发信号源直接连接到对应通道的输入捕获引脚这意味着输入捕获触发信号直接作用于定时器的输入捕获电路不需要通过其他中间寄存器或外部电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);}//初始化MSP函数
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{if(htim-Instance TIM2){GPIO_InitTypeDef gpio_initstruct;__HAL_RCC_TIM2_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();gpio_initstruct.Mode GPIO_MODE_INPUT;//复式推挽输出gpio_initstruct.Pin GPIO_PIN_1;//引脚1gpio_initstruct.Pull GPIO_PULLUP;//上拉输出gpio_initstruct.Speed GPIO_SPEED_FREQ_HIGH;//高速HAL_GPIO_Init(GPIOA,gpio_initstruct);HAL_NVIC_SetPriority(TIM2_IRQn,2,2);//外部中断号抢占优先级/响应优先级HAL_NVIC_EnableIRQ(TIM2_IRQn);}}//中断服务函数
void TIM2_IRQHandler(void)
{HAL_TIM_IRQHandler(ic_handle);
}//回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim-Instance TIM2){if(capture_status.succeed_flag 0)//完整按键捕获标志位等于0代表不完整{if(capture_status.rising_flag 1)//上升沿按键捕获标志等于1代表捕获到上升沿{printf(捕获一个上升沿\r\n);capture_status.succeed_flag 1;//检测到一个完整的按键动作TIM_RESET_CAPTUREPOLARITY(ic_handle,TIM_CHANNEL_2);//重置捕获通道2TIM_SET_CAPTUREPOLARITY(ic_handle,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_FALLING);//配置捕获为下升沿last_cnt HAL_TIM_ReadCapturedValue(ic_handle, TIM_CHANNEL_2);//用于读取定时器指定通道的捕获值。}else{//未捕获到上升沿现在是下降沿printf(捕获一个下降沿\r\n);memset(capture_status,0,sizeof(capture_status));//对一整个结构体的清零capture_status.rising_flag 1;//置位1表示接下来的边沿检测是上升沿的__HAL_TIM_DISABLE(ic_handle); //用于禁用或停止一个定时器的功能__HAL_TIM_SET_COUNTER(ic_handle, 0);//用于设置定时器的计数器值。TIM_RESET_CAPTUREPOLARITY(ic_handle,TIM_CHANNEL_2);//重置捕获通道2TIM_SET_CAPTUREPOLARITY(ic_handle,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_RISING);//配置捕获为上升沿__HAL_TIM_ENABLE(ic_handle);//用于打开计数器}}}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//溢出中断回调函数
{if(htim-Instance TIM2){if(capture_status.succeed_flag 0)//在没有产生完整按键时{if(capture_status.rising_flag 1)//边沿检测标志位等于1代表在产生下降沿之后上升沿之前这段时间产生的溢出进行计数{capture_status.timeout_cnt;}}}
}
void pressed_time_get(void)
{if(capture_status.succeed_flag 1)//产生完整按键之后执行下面代码未产生完整按键不执行下面代码{printf(按下时间为%d \r\n,capture_status.timeout_cnt * 65536 last_cnt);memset(capture_status,0,sizeof(capture_status));//对一整个结构体的清零}
}
ic.h
#ifndef __IC_H__
#define __IC_H__
#include sys.hvoid ic_init(uint16_t psc,uint16_t arr);
void pressed_time_get(void);#endif
打开串口助手
按下KEY2
可计算按键按下的时间