0
点赞
收藏
分享

微信扫一扫

【STM32学习笔记-02】(外部中断+定时器基本定时)捕获按键按下时长

一、定时器

        通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。 它适用于多种场合,包括测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)。 

1.1 主要特性

通用TIMx (TIM2、TIM3、TIM4和TIM5)定时器功能包括:

  • 16位向上、向下、向上/向下自动装载计数器
  • 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意数值
  • 4个独立通道:
  • 输入捕获
  • 输出比较
  • PWM生成(边缘或中间对齐模式)
  • 单脉冲模式输出

1.2 结构框图

【STM32学习笔记-02】(外部中断+定时器基本定时)捕获按键按下时长_stm32

        如上是定时器基本定时功能的结构框图。从上图不难看出,要实现基本定时功能需要涉及到3个器件;这三个也是定时器实现定时的根本:预分频器(PSC)、自动重装载寄存器(ARR)、计数器(CNT)。

        计数器按照定时器本身的工作频率进行计数实现了计时功能;如果想要实现最终的定时功能就需要我们的自动重装载寄存器了;它的功能简而言之就是可以给计数器设定一个目标值,CNT每次计数之后都会和ARR里的值进行比较,当CNT的值等于ARR的值时会出发溢出事件。至此就实现了定时功能;既然计数器+自动重装载寄存器这两个器件就已经实现了定时功能,那预分频器就毫无意义了吗?很显然不是的。预分频器的主要功能是降低CNT的计数频率,从而使我们可以计更长的时间;分频值越大,会导致CNT计数的耗时增加,整体的计时时长也会相应增加。

        实际使用过程中,为方便使用,我们常用的分频值如下表分布:


工作主频



分频值



CNT计数频率



单次计数耗时



最长溢出时间



72MHz



1



72MHz



1/72us



65535 * 1/72us ≈ 910us



72



1MHz



1us



65535 * 1us = 65535us ≈ 65.54ms



7200



10KHz



0.1ms



65535 * 0.1ms = 6553.5ms ≈ 6.55s



36000



2KHz



0.5ms



65535 * 0.5ms = 32767.5ms ≈ 32.77s


1.3 相关寄存器

【STM32学习笔记-02】(外部中断+定时器基本定时)捕获按键按下时长_外部中断_02

【STM32学习笔记-02】(外部中断+定时器基本定时)捕获按键按下时长_单片机_03

【STM32学习笔记-02】(外部中断+定时器基本定时)捕获按键按下时长_单片机_04

1.4 相关配置代码

/******************************************************************************\
函数功能:TIM1基本定时功能初始化配置
形参说明:
返 回 值:
\******************************************************************************/
void TIM1_Init(u16 psc, u16 arr)
{
//1,打开外设时钟
RCC->APB2ENR |= 1<<11; //TIM1外设时钟使能
RCC->APB2RSTR |= 1<<11; //开启TIM1复位
RCC->APB2RSTR &= ~(1<<11);//关闭TIM1复位

//2,配置核心寄存器
TIM1->CNT = 0;
TIM1->PSC = psc - 1; //填写分频值
TIM1->ARR = arr - 1; //重装载值

//3,中断配置
TIM1->DIER |= 1<<0; //允许更新中断
CM3_NVIC_SetPriority(TIM1_UP_IRQn, 2, 2); //设置中断优先级

TIM1->CR1 &= ~(1<<0); //计数器失能
}

//TIM1中断服务函数
u8 OverFlowCnt; //记录定时器溢出次数
void TIM1_UP_IRQHandler(void)
{
if(TIM1->SR & 1<<0)
{
OverFlowCnt++;
TIM1->SR &= ~(1<<0); //清除溢出标志位
}
}

二、外部中断

        对于互联型产品,外部中断/事件控制器由20个产生事件/中断请求的边沿检测器组成,对于其它产品,则有19个能产生事件/中断请求的边沿检测器。每个输入线可以独立地配置输入类型(脉冲或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以独立地被屏蔽。挂起寄存器保持着状态线的中断请求。

2.1 主要特性

EXTI控制器的主要特性如下:

  • 每个中断/事件都有独立的触发和屏蔽
  • 每个中断线都有专用的状态位
  • 支持多达20个软件的中断/事件请求
  • 检测脉冲宽度低于APB2时钟宽度的外部信号。参见数据手册中电气特性部分的相关参数。

2.2 结构框图

【STM32学习笔记-02】(外部中断+定时器基本定时)捕获按键按下时长_外部中断_05

2.3 相关代码配置

/******************************************************************************\
函数功能:外部中断线0初始化配置---以KEY1(PA0)为例
形参说明:
返 回 值:
\******************************************************************************/
void EXTI0_Init(void)
{
//1,开放来自线0上的中断请求
EXTI->IMR |= 1<<0;

//2,设置需要监测边沿(上升沿、下降沿、上升沿和下降沿)
EXTI->RTSR |= 1<<0; //允许输入线0上的上升沿触发
EXTI->FTSR |= 1<<0; //允许输入线0上的下降沿触发

//3,选择EXTI0的信号源
//3.1 打开AFIO的时钟
RCC->APB2ENR |= 1<<0;
//3.2 选择PA0作为EXTI0的信号源
AFIO->EXTICR[0] &= ~(0xF<<0);

//4,设置中断优先级
CM3_NVIC_SetPriority(EXTI0_IRQn, 2, 2);
}

//EXTI0的中断服务函数
extern u8 OverFlowCnt; //定时器溢出次数
void EXTI0_IRQHandler(void)
{
u32 total;
if(EXTI->PR & 1<<0) //PR的第0位的状态
{
//判断到底是触发了什么边沿
if(KEY1) //上升沿
{
TIM1->CNT = 0;
TIM1->CR1 |= 1<<0; //启动计数器
}
else //下降沿
{
TIM1->CR1 &= ~(1<<0); //关闭计数器
total = OverFlowCnt * 65000 + TIM1->CNT; //计算总时长
printf("捕获时长:%dus, %.2fms, %.2fs\n", total, total/1000.0, total/1000000.0);
OverFlowCnt = 0;
}
EXTI->PR |= 1<<0; //清除标志位
}
}

2.4 小结

        在使用外部中断时,有一步是要选择外部中断线的信号源;这一步设置的寄存器比较特殊,位于AFIO寄存器中。通过AFIO_EXTICRx配置GPIO线上的外部中断/事件,必须先使能AFIO时钟。

【STM32学习笔记-02】(外部中断+定时器基本定时)捕获按键按下时长_stm32_06

三、效果展示

【STM32学习笔记-02】(外部中断+定时器基本定时)捕获按键按下时长_单片机_07

        至此,基本实现了对按键按下时长的捕获,当然实际的测试结果还是会存在一定的误差;实际上,这次实现的功能约等于定时器自带的输入捕获功能。


举报

相关推荐

0 条评论