STM32---通用定时器(二)相关实验

写在前面:前面我们学习了基本定时器、通用定时器的相关理论部分,了解到通用定时器的结构框图,总共包含六大模块:时钟源、控制器、时基单元、输入捕获、公共部分以及输出捕获。对相关模块的使用也做详细的讲解。本节我们主要是对上节的理论部分进行实验的操作,力争对理论部分有更好的掌握。

本节主要操作三个实验:

1、通用定时器中断实验;2通用定时器输出PWM波形;3、通用定时器输入捕获;

基本定时器回顾:STM32---基本定时器(含源码)小白可入_stm32简易定时器-CSDN博客

通用定时器基础回顾:STM32---通用定时器(一)理论基础-CSDN博客

一、通用定时器中断实验

1.1实验描述

        通过STM32的通用定时器完成计数,在中断中点亮LED灯;

        在主函数进行LED1进行亮灭翻转,在利用通用定时器进行中断,在中断中实现LED0的亮灭翻转。

1.2相关寄存器

        使用通用定时器之前,我们需要根据定时器的结构框图,确定以下的一些问题:

1、使用定时器的哪个时钟源?

2、是否使用通用定时器的输入捕获部分?

3、是否使用通用定时器的输出比较部分?

4、是否使用通用定时溢出后的中断?

        在这里我们确定,使用定时器的内部时钟源,不使用输入捕获,也不使用输出捕获,但是需要使用定时器溢出后的中断,因为在中断中我们需要进行点灯。

1.控制寄存器(TIMx_CR1)

(APRE)自动重载寄存器允许位:如果 ARPE 位置 1,ARR 起缓冲作用,即只有在更新事件发生时才会把 ARR的值写入其影子寄存器里;如果 ARPE 位置 0,那么修改自动重载寄存器的值时,该值会马上被写入其影子寄存器中,从而立即生效。

CMS[1:0]选择中央对齐模式:分为边沿对齐(即递增或递减技术模式)、中央对齐模式;

DIR :用于控制定时器的计数方向,递增计数或递减计数;

CEN 位:用于使能计数器的工作,必须要设置该位为 1,计数器才会开始计数。

2、从模式控制寄存器(TIMx_SMCR)

主要用于选择计数器输入的时钟来源; 

  SMS[2:0]位:我们设置 SMS[2:0]=000,禁止从模式,这样 PSC 预分频器的时钟就直接来自内部时钟(CK_INT),按照我们例程 sys_stm32_clock_init 函数的配置,频率为 72Mhz(APB1总线时钟频率的 2 倍)

3、DMA/中断使能寄存器(TIMx_DIER)

 该寄存器用于使能/失能触发 DMA 请求、捕获/比较中断以及更新中断。

4、状态寄存器(TIMx_SR) 

        在通用定时器中断实验我们用到更新中断标志位,当定时器更新中断到来后,位 0(UIF)会由硬件置 1,我们需要在中断服务函数里面把该位清零。

5、计数寄存器(TIMx_CNT) 

        TIM2/TIM3/TIM4/TIM5 的计数寄存器都是 16 位有效的,计数模式可以是递增计数模式、
递减计数模式和中心对齐计数模式,计数值范围 0~65535。可以直接写该寄存器设置计数的初
始值,也可以读取该寄存器获取计数器值 。

6、预分频寄存器(TIMx_PSC)

        定时器的预分频寄存器都是 16 位的,即写入该寄存器的数值范围是 0 到 65535,表示 1 到
65536 分频。

7、自动重载寄存器(TIMx_ARR) 

        自动重载寄存器是低 16 位有效。该寄存器可以由 APRE 位设置是否进行缓冲。计数器的
值会和自动重装寄存器影子寄存器进行比较,当两者相等,定时器就会溢出,从而发生更新事
件,如果打开了更新中断,还会发生更新中断。 

1.3 程序设计

程序源码

链接:https://pan.baidu.com/s/1cYrbkah9Awvf4TZ_-NrN0A 
提取码:1022

timer.c

#include "./BSP/TIMER/timer.h"
#include "./BSP/LED/led.h"
/**
* @brief通用定时器定时中断初始化函数
* @note
*通用定时器的时钟来自 APB1,当 PPRE1 ≥ 2 分频的时候
*通用定时器的时钟为 APB1 时钟的 2 倍, 而 APB1 为 36M, 所以定时器时钟 = 72Mhz
*定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
*              Ft=定时器工作频率,单位:Mhz
* @param       arr: 自动重装值。
* @param       prc: 时钟预分频数
* @retval无
*/
TIM_HandleTypeDef timer_handle;/* 定义句柄 */
void timer_init(uint16_t prc,uint16_t arr)/* 定义变量:1、arr自动重装值2、prc预分频系数*/
{
    timer_handle.Instance=TIM5;         /* 定时器TIM5基地址 */
    timer_handle.Init.Prescaler=prc;    /* 预分频系数 */
    timer_handle.Init.Period=arr;       /* 自动重装载值 */
    timer_handle.Init.CounterMode=TIM_COUNTERMODE_DOWN; /* 递减计数模式 */
     HAL_TIM_Base_Init(&timer_handle);     
     HAL_TIM_Base_Start_IT(&timer_handle);  /* 使能定时器以及使能定时器更新中断 */
    
}
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance==TIM5)/* 判断是否为TIM5 */
    {
        __HAL_RCC_TIM5_CLK_ENABLE();    /* 使能定时器时钟 */
        HAL_NVIC_EnableIRQ(TIM5_IRQn);  /* 使能定时器TIM5中断 */
        HAL_NVIC_SetPriority(TIM5_IRQn,2,2);/* 设置中断优先级 */
    }
}
/**
* @brief定时器中断服务函数
* @param无
* @retval无
*/
void TIM5_IRQHandler (void)
{
    HAL_TIM_IRQHandler(&timer_handle);  /* 定时器公共处理函数,会自动清除定时器溢出中断标志位 */

}
/**
* @brief定时器溢出中断回调函数
* @param句柄
* @retval无
*/
 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)    
 {
        if(htim->Instance==TIM5)
    {
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
    }
 }

led.c

#include "./BSP/LED/led.h"
void LED_init()//LED初始化
{
      __HAL_RCC_GPIOB_CLK_ENABLE();
    GPIO_InitTypeDef gpio_init_struct;
    gpio_init_struct.Mode=GPIO_MODE_OUTPUT_PP;
    gpio_init_struct.Pin=GPIO_PIN_5;
    gpio_init_struct.Speed=GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &gpio_init_struct);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
    
       __HAL_RCC_GPIOE_CLK_ENABLE();
    gpio_init_struct.Mode=GPIO_MODE_OUTPUT_PP;
    gpio_init_struct.Pin=GPIO_PIN_5;
    gpio_init_struct.Speed=GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOE, &gpio_init_struct);
    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_SET);

}

main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/timer.h"

int main(void)
{
    HAL_Init();                              /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);      /* 设置时钟, 72Mhz */
    delay_init(72);                          /* 延时初始化 */
     LED_init();
    timer_init(7200-1,5000-1);              /* 设置预分频器系数,以及重装在寄存器的值 */
    while(1)
    { 
      delay_ms(500);
      HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_5);
        
    }
}

1.4实验现象

通用定时器点灯

二、通用定时器输出PWM波形

2.1 实验描述

        使用通用定时器实现PWM波形的输出;PWM:脉冲宽度调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。

        在此实验中,我们需要输出电平信号,所以我们需要用到输出比较,通过计数器的值同捕获/比较寄存器的值进行比较,输出信号,再通过控制输出比较部分的工作模式,有效电平,达到PWM波形的输出。

        上图为PWM波形产生的原理,确定一个自动重载寄存器的值,设定一个比较值,让计数器的值不断增加(递增模式),与比较值进行比较,当大于比较值时,输出一种电平信号,当小于比较值时,输出另一种电平信号(具体输出那种信号,由输出模式控制)。

        由此可见,影响PWM波形的周期参数为:自动重装载寄存器ARR的值,

                        影响PWM波形的占空比的参数为:捕获/比较寄存器CRR的值。

        定时器产生 PWM 的方式有许多种,下面我们以边沿对齐模式(即递增计数模式/递减计数
模式)为例,PWM 模式 1 或者 PWM 模式 2 产生 PWM 的示意图。

         使用 TIM3 通道 2(由 PB5 复用)输出 PWM, PB5 引脚连接了 LED0,从而实现 PWM 输
出控制 LED0 亮度,达到呼吸灯的效果。

2.2 相关寄存器

1.捕获/比较模式寄存器 1/2(TIMx_CCMR1/2)

        TIMx _CCMR1 和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和 CH2,而 TIMx_CCMR2 控制CH3 和 CH4。

        OC2M[2:0]就是对应着通道 2 的模式设置,此部分由 3 位组成。总共可以配置成 8 种
模式,我们使用的是 PWM 模式,所以这 3 位必须设置为 110 或者 111,分别对应 PWM 模式 1
和 PWM 模式 2。两种 PWM 模式的区别就是输出有效电平的极性相反。

       OC2PE 控制输出比较通道 2 的预装载使能,实际就是控制 CCR2 寄存器是否进行缓冲。因为 CCR2 寄存器也是有影子寄存器的,影子寄存器才是真正起作用的寄存器。

        CC2S[1:0]用于设置通道 2 的方向(输入/输出)默认设置为 0,就是设置通道作为输出使用。

2.捕获/比较使能寄存器(TIMx_CCER)

该寄存器控制着各个输入输出通道的开关和极性。

         要让 TIM3 的 CH2 输出 PWM 波,这里我们要使能 CC2E 位,该位是通道 2 输入/输出使能位,要想 PWM 从 IO 口输出,这个位必须设置为 1。CC2P 位是设置通道2 的输出极性。

3.捕获/比较寄存器 1/2/3/4(TIMx_CCR1/2/3/4)  

        在输出模式下,捕获/比较寄存器影子寄存器的值与 CNT 的值比较,根据比较结果产生相
应动作,利用这点,我们通过修改这个寄存器的值,就可以控制 PWM 的占空比了。 

2.3程序设计

程序源码

链接:https://pan.baidu.com/s/1lsbm3VWhuhO4I5BEoQHNZQ 
提取码:1022

 pwm.c

#include "./BSP/PWM/pwm.h"
 
TIM_HandleTypeDef btim_pwm_handle; /* 定义句柄 */ 


/*** @brief通用定时器 TIM3 通道2 PWM 输出初始化函数(使用 PWM 模式 1)
* @note*通用定时器的时钟来自 APB1,当 D2PPRE1≥2 分频的时候
*通用定时器的时钟为 APB1 时钟的 2 倍, 而 APB1 为 36M, 所以定时器时钟 = 72Mhz
*定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
*              Ft=定时器工作频率,单位:Mhz
* @param       arr: 自动重装值。
* @param       psc: 时钟预分频数
* @retval
*/
 void btim_pwm_init(uint16_t arr,uint16_t psc)
 {  
   btim_pwm_handle.Instance=TIM3;   /* 定时器TIM3基地址 */
   btim_pwm_handle.Init.Period=arr; /* 自动重装载值 */
   btim_pwm_handle.Init.Prescaler=psc;/* 预分频系数 */
   btim_pwm_handle.Init.CounterMode=TIM_COUNTERMODE_UP;  /* 递增计数模式 */
    HAL_TIM_PWM_Init(&btim_pwm_handle); /* 初始化PWM */
     
   TIM_OC_InitTypeDef timx_oc_pwm_struct={0};/* 定义结构体,并赋初值为0,这一点是很重要的 */
   timx_oc_pwm_struct.OCMode=TIM_OCMODE_PWM1;/* 设置输出PWM模式,此处采用模式1 */
   timx_oc_pwm_struct.Pulse=arr/2;/* 设置捕获/比较寄存器的值,此处设置为自动重装载值的一半,则输出的PWM波形的占空比为50% */
   timx_oc_pwm_struct.OCPolarity=TIM_OCPOLARITY_LOW;/* 输出比较极性为低 */
    HAL_TIM_PWM_ConfigChannel(&btim_pwm_handle,&timx_oc_pwm_struct,TIM_CHANNEL_2);/* 定时器的 PWM 通道设置初始化函数 */
    HAL_TIM_PWM_Start(&btim_pwm_handle, TIM_CHANNEL_2);/* 定时器的 PWM 输出启动函数,参数1为句柄,参数2为通道数 */
 }
 
/**
* @brief定时器底层驱动,时钟使能,引脚配置此函数会被 HAL_TIM_PWM_Init()调用
* @param       htim:定时器句柄
* @retval无
*/ 
 void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
 {
     if(htim->Instance==TIM3)/* 判断是否为定时器3 */
     {
      __HAL_RCC_TIM3_CLK_ENABLE();/* 使能定时器时钟 */
      __HAL_RCC_GPIOB_CLK_ENABLE();/* 使能输出IO的时钟 */
         
        GPIO_InitTypeDef gpio_init_struct;
        gpio_init_struct.Mode=GPIO_MODE_AF_PP;
        gpio_init_struct.Pull = GPIO_PULLUP;
        gpio_init_struct.Pin=GPIO_PIN_5;
        gpio_init_struct.Speed=GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GPIOB, &gpio_init_struct);
         __HAL_RCC_AFIO_CLK_ENABLE();/* 使能重映射时钟 */
         __HAL_AFIO_REMAP_TIM3_PARTIAL(); /* IO 口 REMAP 设置,设置重映射 */
     }
 }

main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/PWM/pwm.h"
uint8_t dir=1;
uint16_t ccr=0;
int main(void)
{
    HAL_Init();                              /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);      /* 设置时钟, 72Mhz */
    delay_init(72);                          /* 延时初始化 */
    led_init();                              /* LED初始化 */
    btim_pwm_init(500-1,72-1);/* 72M/72=1M 的计数频率,自动重装载为 500,那么 PWM 频率为 1M/500=2kHZ */
    while(1)
    { 
        delay_ms(10);
        if(dir) ccr++;
        else  ccr--;
        
        if(ccr>400)   dir=0;
        if(ccr==0) dir=1;
        
       __HAL_TIM_SET_COMPARE(&btim_pwm_handle,TIM_CHANNEL_2,ccr); /* 修改比较值控制占空比,达到呼吸灯的效果 */

    }
}

2.4实验现象

PWM呼吸灯

示波器测量PWM波形

三、通用定时器输入捕获实验

3.1 实验描述

        输入捕获模式可以用来测量脉冲宽度或者测量频率,我们用来测量脉冲的宽度,即给通用定时器的输入捕获端一个高电平,测量出高电平的时间(低电平相同)。

        使用 TIM5_CH1 来做输入捕获,捕获 PA0 上的高电平脉宽,并将脉宽时间通过串口打
印出来,然后通过按 WK_UP 按键,模拟输入高电平。

输入捕获脉宽测量原理:

t1 到 t2 的时间段,就是我们需要测量的高电平时间测量方法为:

        假设定时器的计数器工作在递增模式,设置输入通道为上升沿触发,则在t1时刻,由于上升沿的到来,就会发生捕获事件,在捕获事件中(中断),我们将计数器的值清零,并将触发方式改为下降沿触发。        

        这样在t2时刻,由于下降沿触发,就会再次发生捕获事件。捕获事件发生时,计数器的值会被所存放捕获/比较寄存器中。

        这样我们将捕获/比较寄存器中的值再加上一系列的溢出次数(溢出次数可以通过更新中断统计),就能算出高电平脉冲的时间。

计数个数=N*(ARR+1)+ CCRx2。N溢出次数,ARR自动重装载值,CCRx2时间t2点,捕获/比较寄存器的值.

高电平时间=计数个数*计数3.2器计1个数的时间;

3.2相关寄存器

TIMx_ARR、TIMx_PSC、TIMx_CCMR1、TIMx_CCER、TIMx_DIER、TIMx_CR1、TIMx_CCR1 这些寄存器在前面的章节都有提到。

1.捕获/比较模式寄存器 1/2(TIMx_CCMR1/2)

        该寄存器在输入模式和输出模式下,功能是不一样的,TIMx_CCMR1 寄存器对应于通道 1 和通道 2 的设置,CCMR2 寄存器对应通道 3和通道 4。

        CC1S[1:0],这两个位用于 CCR1 的通道配置,这里我们设置 IC1S[1:0]=01,也就是配
置 IC1 映射在 TI1 上。

        输入捕获 1 预分频器 IC1PSC[1:0],这个比较好理解。我们是 1 次边沿就触发 1 次捕获,所
以选择 00 就行了。

        输入捕获 1 滤波器 IC1F[3:0],这个用来设置输入采样频率和数字滤波器长度。一般不需要进行滤波

  2.捕获/比较使能寄存器(TIMx_CCER)

        使能输入捕获,必须设置 CC1E=1,而 CC1P 则根据自己的需要来配置。我们这里是保留默认设置值 0,即高电平触发捕获。 

此外我们需要开启DMA/中断使能寄存器:用于计数溢出次数。

3.3程序设计

链接:https://pan.baidu.com/s/1ZinCNBBShkMFLSA-bZlo6w 
提取码:1022

程序文件

timer.c

#include "./BSP/TIMER/timer.h"
#include "./BSP/LED/led.h"

TIM_HandleTypeDef tim_ic_handled;/* 定义句柄*/
/*** @brief通用定时器 TIM5通道1输入捕获初始化函数
* @note
*通用定时器的时钟来自 APB1,当 PPRE1 ≥ 2 分频的时候
*通用定时器的时钟为 APB1 时钟的 2 倍, 而 APB1 为 36M, 所以定时器时钟 = 72Mhz
*定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
*              Ft=定时器工作频率,单位:Mhz
*
* @param       arr: 自动重装值
* @param       psc: 时钟预分频数
* @retval
无
*/
void tim_ic_init(uint16_t arr,uint16_t psc)
{
   tim_ic_handled.Instance=TIM5;                         /* 定时器基地址:定时器 5 */
   tim_ic_handled.Init.Period=arr;                       /* 自动重装载值:arr */  
   tim_ic_handled.Init.Prescaler=psc;                    /* 预分频系数:psc */  
   tim_ic_handled.Init.CounterMode=TIM_COUNTERMODE_UP;   /* 计数模式:向上计数 */        
   HAL_TIM_IC_Init(&tim_ic_handled); 
    
   TIM_IC_InitTypeDef tim_ic_cap_csh_struct={0};
   tim_ic_cap_csh_struct.ICFilter=0;                            /* 通道配置滤波器:不滤波 */
   tim_ic_cap_csh_struct.ICPolarity=TIM_ICPOLARITY_RISING;      /* 通道捕获方式:上升沿捕获 */
   tim_ic_cap_csh_struct.ICPrescaler=TIM_ICPSC_DIV1;            /* 通道输入分频:不分频 */
   tim_ic_cap_csh_struct.ICSelection=TIM_ICSELECTION_DIRECTTI;  /* 通道映射 */  
   HAL_TIM_IC_ConfigChannel(&tim_ic_handled, &tim_ic_cap_csh_struct, TIM_CHANNEL_1);
   
    __HAL_TIM_ENABLE_IT(&tim_ic_handled, TIM_IT_UPDATE);    /* 使能更新中断 ,单独使能定时器中断*/ 
     HAL_TIM_IC_Start_IT(&tim_ic_handled, TIM_CHANNEL_1);  /* 使能通道输入以及使能捕获中断 */
 
}
/**
* @brief通用定时器输入捕获初始化接口HAL 库调用的接口,用于配置不同的输入捕获
* @param       htim:定时器句柄
* @note
此函数会被 HAL_TIM_IC_Init()调用
* @retval
无
*/
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{    
   
    if(htim->Instance==TIM5)
    {
   __HAL_RCC_TIM5_CLK_ENABLE();                     /* 使能定时器5的时钟 */
   __HAL_RCC_GPIOA_CLK_ENABLE();                    /* 使能捕获IO的时钟 */
   GPIO_InitTypeDef gpio_init_struct; 
   gpio_init_struct.Mode=GPIO_MODE_AF_PP;           /* IO的工作模式:复用推挽输出 */
   gpio_init_struct.Pin=GPIO_PIN_0;                 /* IO的引脚:PA0 */
   gpio_init_struct.Pull=GPIO_PULLDOWN;             /* IO上下拉电阻:下拉电阻 */
   gpio_init_struct.Speed=GPIO_SPEED_FREQ_HIGH;      /* IO输出速度:高速 */
   HAL_GPIO_Init(GPIOA, &gpio_init_struct);
    
    HAL_NVIC_SetPriority(TIM5_IRQn, 2, 2);           /* 设置中断优先级 */
    HAL_NVIC_EnableIRQ(TIM5_IRQn);                    /* 开启定时器5中断 */
    }
    
  }
uint8_t g_tim5csh_cap_sta =0;    /* 设置输入捕获状态 */
uint16_t g_tim5csh_cap_val=0;    /* 设置捕获值 */
  
  
 void TIM5_IRQHandler(void)
 {
    HAL_TIM_IRQHandler(&tim_ic_handled);/*定时器公共处理函数 */
 }
  /**
* @brief定时器输入捕获中断处理回调函数
* @param       htim:定时器句柄指针
* @note该函数在 HAL_TIM_IRQHandler 中会被调用
* @retval无
*/
  void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
  {
    if(htim->Instance==TIM5)
    {
      if((g_tim5csh_cap_sta & 0x80)==0)         /* 还没能成功捕获 */
      {
            if((g_tim5csh_cap_sta & 0x40))    /* 捕获到一个下降沿 */
            {  
                 g_tim5csh_cap_sta |=0x80;      /* 标记捕获到一个下降沿 ,成功捕获到一个高电平脉冲 */
                 g_tim5csh_cap_val = HAL_TIM_ReadCapturedValue(&tim_ic_handled,TIM_CHANNEL_1);  /* 获取捕获值 */
                 TIM_RESET_CAPTUREPOLARITY(&tim_ic_handled,TIM_CHANNEL_1); /*清除之前的下降沿触发模式 */ 
                 TIM_SET_CAPTUREPOLARITY(&tim_ic_handled,TIM_CHANNEL_1, TIM_ICPOLARITY_RISING );/*设置新的触发方式:上升沿触发模式 */
            }
                
            else        /* 捕获到一个上升沿降沿 */
          {    
            g_tim5csh_cap_sta =0;    
            g_tim5csh_cap_val=0;
            g_tim5csh_cap_sta |=0x40;   /* 标记捕获到一个上升沿 */
            __HAL_TIM_DISABLE(&tim_ic_handled); /* 失能定时器5 */ 
            __HAL_TIM_SET_COUNTER(&tim_ic_handled,0);/*计数器值清零 */ 
            TIM_RESET_CAPTUREPOLARITY(&tim_ic_handled,TIM_CHANNEL_1); /*清除之前的上升沿触发模式 */ 
            TIM_SET_CAPTUREPOLARITY(&tim_ic_handled,TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING );/*设置新的触发方式:下降沿触发模式 */
            __HAL_TIM_ENABLE(&tim_ic_handled);/* 使能定时器5 */ 
           
         }     
      }
    }      
  }
/**
* @brief定时器输入捕获中断处理回调函数
* @param       htim:定时器句柄指针
* @note该函数在 HAL_TIM_IRQHandler 中会被调用
* @retval无
*/
  void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  {
        if(htim->Instance==TIM5)
        {
        
            if((g_tim5csh_cap_sta & 0x80)==0)
            {
                if((g_tim5csh_cap_sta & 0x40))//非0和等于1是两码事
                {
                    if((g_tim5csh_cap_sta & 0x3f)==0x3f)
                    {
                        TIM_RESET_CAPTUREPOLARITY(&tim_ic_handled,TIM_CHANNEL_1); /*清除之前的下降沿触发模式 */ 
                        TIM_SET_CAPTUREPOLARITY(&tim_ic_handled,TIM_CHANNEL_1, TIM_ICPOLARITY_RISING );/*设置新的触发方式:上升沿触发模式 */                
                       g_tim5csh_cap_sta |=0x80;
                       g_tim5csh_cap_val=0xffff; 
                    }
                    else
                    {g_tim5csh_cap_sta++;}                
                }           
            }                   
        } 
  }

  

led.c

#include "./BSP/LED/led.h"
void led_init()
{
    
     GPIO_InitTypeDef gpio_init_struct;
    __HAL_RCC_GPIOE_CLK_ENABLE();
    gpio_init_struct.Mode=GPIO_MODE_OUTPUT_OD;
    gpio_init_struct.Pin=GPIO_PIN_5;
    gpio_init_struct.Speed=GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOE, &gpio_init_struct);
    __HAL_RCC_GPIOB_CLK_ENABLE();
    gpio_init_struct.Mode=GPIO_MODE_OUTPUT_OD;
    gpio_init_struct.Pin=GPIO_PIN_5;
    gpio_init_struct.Speed=GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &gpio_init_struct);

}

main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/timer.h"
uint32_t temp=0;
int main(void)
{
    HAL_Init();                              /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);      /* 设置时钟, 72Mhz */
    delay_init(72);                          /* 延时初始化 */
    led_init();                              /* LED初始化 */
    usart_init(115200);
    tim_ic_init(0xffff ,72-1);
    
    while(1)
    { 
      
      if(g_tim5csh_cap_sta &0x80) /* 是否完成一次按键按下 */
      {
          
        temp=g_tim5csh_cap_sta &0x3f;
        temp*=65536;
        temp += g_tim5csh_cap_val;
        printf("HIGH:%d us\r\n", temp);
            g_tim5csh_cap_sta=0;
      }          
        
       HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);
       delay_ms(1000);
    }
}

3.4实验现象

20240309_175827

总结:本节我们结合上节的通用定时器的基础理论,分别实现了:通用定时器中断实验、通用定时器输出PWM实验、通用定时器输入捕获实验;进行代码书写以及实验测试。大家学习的时候,多多动手定有收获。

创作不易,还请大家多多点赞支持,有问题欢迎评论区讨论!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/444551.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【NR 定位】3GPP NR Positioning 5G定位标准解读(八)- OTDOA定位

前言 3GPP NR Positioning 5G定位标准:3GPP TS 38.305 V18 3GPP 标准网址:Directory Listing /ftp/ 【NR 定位】3GPP NR Positioning 5G定位标准解读(一)-CSDN博客 【NR 定位】3GPP NR Positioning 5G定位标准解读(…

少儿编程 蓝桥杯青少组科技素养题 信息素养真题及解析第25套

少儿编程 科技素养 信息素养真题第25套 1、旅行结束之后,回到家的小蓝决定将照片备份在云端的网盘上。备份照片主要占用的是小蓝家的( )带宽 A、下行 B、上行 C、文件 D、数据 答案:B 考点分析:主要考查网络相关知识,要将照…

多种方法求解数组排序

𝙉𝙞𝙘𝙚!!👏🏻‧✧̣̥̇‧✦👏🏻‧✧̣̥̇‧✦ 👏🏻‧✧̣̥̇:Solitary_walk ⸝⋆ ━━━┓ - 个性标签 - :来于“云”的“羽球人”。…

基于GAN对抗网进行图像修复

一、简介 使用PyTorch实现的生成对抗网络(GAN)模型,包括编码器(Encoder)、解码器(Decoder)、生成器(ResnetGenerator)和判别器(Discriminator)。…

CSS中有哪些方式可以隐藏页面元素(区别详解)

文章目录 一、前言二、实现方式display:nonevisibility:hiddenopacity:0设置height、width属性为0position:absoluteclip-path小结 三、区别参考文献 一、前言 在平常的样式排版中,我们经常遇到将某个模块隐藏的场景 通过css隐藏元素的方法有很多种,它…

HttpURLConnection详解及使用

HttpURLConnection 请求响应流程 设置连接参数的方法 setAllowUserInteractionsetDoInputsetDoOutputsetIfModifiedSincesetUseCachessetDefaultAllowUserInteractionsetDefaultUseCaches 发送URL请求 建立实际连接之后,就是发送请求,把请求参数传到…

探讨系统测试的最佳实践与思维模式!

这是测试活动过程详解系列的最后一篇文章。之前的想法,是对测试过程各重要环节进行拆解,然后介绍这个环节重点要做的事情,为什么要做这些事,以及注意事项。 前面几篇文章分别介绍了单元测试、集成测试、回归测试阶段要解决的问题…

初识C语言—初识C语言

前言 C语言全面了解,全貌认识 细致的学习,细枝末节 什么是C语言 维基百科 C 语言是一种通用的高级语言,最初是由丹尼斯里奇在贝尔实验室为开发 UNIX 操作系统而设计的。C 语言最开始是于 1972 年在 DEC PDP-11 计算机上被首次实现。 在 1978 …

【QT+QGIS跨平台编译】之七十六:【QGIS_Native+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、QGIS_Native介绍二、QGIS下载三、文件分析四、pro文件五、编译实践一、QGIS_Native介绍 QGIS_Native模块是QGIS软件的核心部分,提供了许多基本功能和核心组件,主要用于处理与底层操作系统的关系。 二、QGIS下载 QGIS网址: QGIS Source Download 三、文件分析…

苹果cms模板保护设置,防止被扒

苹果cms模板保护设置,防止被扒 如今互联网时代,网站模板前端被扒是常有的事,如何防止模板数据被扒? 保护设置方法: 登录宝塔 找到安装模板的网站 设置禁止访问文件 方法参考截图后缀填:php|html 目录填&a…

抽象的java发送邮箱2.0版本

优化了更多细节 SpringBoot3&#xff1a;前置框架 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jdbc</artifactId></dependency><dependency><groupId>org.springframewo…

Linux系统架构----nginx上构建虚拟主机

Linux系统架构----nginx上构建虚拟主机 一、构建虚拟主机概述 利用虚拟主机&#xff0c;不用为每个运行的网站提供一台单独的Nginx服务器或单独运行一组Nginx进程&#xff0c;虚拟主机提供了在同一台服务器、同一组Nginx进程上运行的多个网站的功能与Apache相同&#xff0c;N…

【OpenCV】如何在Linux操作系统下正确安装 OpenCV

前言 我是在虚拟机上跑的 Linux 5.8.0-44-generic。 配置如下&#xff1a; 目录 第一步&#xff1a;下载依赖文件 第二步&#xff1a;下载 opencv 和 opencv_contrib 源码 第三步&#xff1a;解压缩包 第四步&#xff1a;移动文件 第五步&#xff1a;生成 makefile 文件 …

深入理解 Webpack 热更新原理:提升开发效率的关键

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

攻击技术:命令和控制服务器(C2)是什么意思

在攻击者使用的众多策略中&#xff0c;最阴险的策略之一是命令和控制服务器&#xff08;C2&#xff09;。通过这篇文章&#xff0c;我们想准确地解释它是什么。 这些服务器充当计算机黑客行动的大脑&#xff0c;协调受感染设备的操作并允许攻击者随意操纵它们。 在网络安全领…

智慧公厕系统的组成部分有什么?

智慧公厕系统是现代城市管理中一项重要的创新&#xff0c;利用物联网、互联网、大数据、云计算、自动化控制等先进的技术手段&#xff0c;提供高效便捷的公厕服务。从信息系统的角度来看&#xff0c;智慧公厕系统主要由硬件、软件和网络组成&#xff0c;硬件、软件和网络三大部…

首屏性能优化:提升用户体验的秘籍

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Python图像处理:1.插值、频域变换与对比度增强

一、几何变换 7.图像的插值 (1)原理介绍 下面对比三种插值方法&#xff0c;分别是最近邻插值法、双线性插值法、卷积插值法&#xff0c;三种方法的前提和特点、优缺点、适用场景如下&#xff1a; 最近邻插值&#xff08;Nearest Neighbor Interpolation&#xff09;&#xf…

flask-sqlalchemy库

彩笔激流勇退。 1. 简介 ORM&#xff0c;对象关系映射。简单来说&#xff0c;ORM将数据库中的表与面向对象中的类建立了一种对应关系。这样&#xff0c;我们要操作数据库&#xff0c;表&#xff0c;记录就可以直接通过操作类或者类实例来完成。 SQLAlchemy 是目前python中最…

UDP与TCP:了解这两种网络协议的不同之处

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…