超子物联网HAL库笔记:定时器[外部模式]篇

超子物联网 HAL库学习 汇总入口:

超子物联网HAL库笔记:[汇总]

写作不易,如果您觉得写的不错,欢迎给博主来一波点赞、收藏~让博主更有动力吧!

一、资源介绍:STM32F103C8T6定时器资源介绍

高级定时器(TIM1)

  • 时基单元包含:
    • 计数器寄存器(TIMx_CNT)
    • 预分频器寄存器(TIMx_PSC)
    • 自动装载寄存器(TIMx_ARR)
    • 重复次数寄存器(TIMx_RCR)

通用定时器(TIM2、TIM3、TIM4)

  • 时基单元包含:
    • 计数器寄存器(TIMx_CNT)
    • 预分频器寄存器(TIMx_PSC)
    • 自动装载寄存器(TIMx_ARR)

定时器1 外部通道

  • 通道 1:PA8,DMA1_Channel2
  • 通道 2:PA9,DMA1_Channel3
  • 通道 ETR:PA12

定时器2 外部通道

  • 通道 1:PA0(重映射 PA15),DMA1_Channel5(如果重映射,需要内部上拉)
  • 通道 2:PA1(重映射 PB3),DMA1_Channel7
  • 通道 ETR:PA0(重映射 PA15)

定时器3 外部通道

  • 通道 1:PA6(重映射 PB4),DMA1_Channel6(如果重映射,需要内部上拉)
  • 通道 2:PA7(重映射 PB5)
  • 通道 ETR:无

定时器4 外部通道

  • 通道 1:PB6,DMA1_Channel1
  • 通道 2:PB7,DMA1_Channel4
  • 通道 ETR:无

来自江协的定时器基本结构图

二、HAL库:TIM1 外部时钟模式1 轮询方式 按键计数

1. 功能说明

  • 按下按键,定时器计数

2. 注意事项*

  1. 引脚冲突问题

    外部时钟模式1,定时器1:

    通道1 PA8 DMA1_Channel2

    通道2 PA9 DMA1_Channel3

    而串口1的Tx也为PA9

    所以要善用重映射功能(会重映射到PB6),避免引脚冲突

    并且在切换不同的通道的时候,注意GPIO口的初始化与上下拉配置

  2. ED双边沿检测,不过滤波器

  3. 外部时钟模式1 通往TRGI, TRGI会产生一个触发事件 会置位TIF为1,也就是HAL库的TIM_FLAG_TRIGGER标志位会置1,我们可以通过判断标志位来进行判断单次的触发事件。

  4. 通道1 、2 上的滤波器解释

3. 相关函数

  • 重映射串口1

    • __HAL_RCC_AFIO_CLK_ENABLE();
    • __HAL_AFIO_REMAP_USART1_ENABLE();
  • TIM_ClockConfigTypeDef 时钟配置总控结构体

  • 基础的定时器配置初始化(定时器1通道 2举例)

        tim1.Instance = TIM1;                                        // 实例tim1.Init.Period = arr;                                      // 重装载值tim1.Init.Prescaler = psc;                                   // 分频系数tim1.Init.CounterMode = TIM_COUNTERMODE_UP;                  // 计数模式tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;            // 分频因子tim1.Init.RepetitionCounter = rep;                           // 重复计数值tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)HAL_TIM_Base_Init(&tim1);                       //初始化定时器__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   //手动 清除 定时器 更新事件/* 通道1边沿检测  ED *///tim1_clock.ClockSource = TIM_CLOCKSOURCE_TI1ED; //边沿检测另外仨(时钟过滤, 有效极性, 外部触发 预分频ETR)不用配置//HAL_TIM_ConfigClockSource(&tim1, &tim1_clock);  //初始化定时器时钟配置/* 通道2上升沿/下降沿检测 (Both不生效F103 ,只对下降沿生效)  */tim1_clock.ClockSource = TIM_CLOCKSOURCE_TI2; //通道2//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_RISING;    //上升沿检测//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_FALLING;   //下降沿检测tim1_clock.ClockFilter = 0x03;                          //滤波(注意是外部时钟的波)HAL_TIM_ConfigClockSource(&tim1, &tim1_clock);  //初始化定时器时钟配置HAL_TIM_Base_Start(&tim1);   //打开定时器(轮询方式)
    
  • 初始化硬件配置回调函数

    if(htim->Instance == TIM1){__HAL_RCC_TIM1_CLK_ENABLE();                //使能时钟__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitType;GPIO_InitType.Pin = GPIO_PIN_9;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //上拉GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;HAL_GPIO_Init(GPIOA,&GPIO_InitType);
    

4. 程序

time.c

#include "stm32f1xx_hal.h"
#include "time.h"TIM_HandleTypeDef tim1; //(高级)定时器1总控结构体
TIM_HandleTypeDef tim2; 
TIM_HandleTypeDef tim3; 
TIM_HandleTypeDef tim4; DMA_HandleTypeDef tim1_dmaup;
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;TIM_ClockConfigTypeDef tim1_clock;  //时钟配置结构体uint16_t tim1_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim2_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim3_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim4_dmaBuff[4] = {20000, 30000, 40000, 50000};//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{tim1.Instance = TIM1;                                        // 实例tim1.Init.Period = arr;                                      // 重装载值tim1.Init.Prescaler = psc;                                   // 分频系数tim1.Init.CounterMode = TIM_COUNTERMODE_UP;                  // 计数模式tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;            // 分频因子tim1.Init.RepetitionCounter = rep;                           // 重复计数值tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)HAL_TIM_Base_Init(&tim1);                       //初始化定时器__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   //手动 清除 定时器 更新事件/* 通道1边沿检测  ED *///tim1_clock.ClockSource = TIM_CLOCKSOURCE_TI1ED; //边沿检测另外仨(时钟过滤, 有效极性, 外部触发 预分频ETR)不用配置//HAL_TIM_ConfigClockSource(&tim1, &tim1_clock);  //初始化定时器时钟配置/* 通道2上升沿/下降沿检测 (Both不生效F103 ,只对下降沿生效)  */tim1_clock.ClockSource = TIM_CLOCKSOURCE_TI2; //通道2//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_RISING;    //上升沿检测//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_FALLING;   //下降沿检测tim1_clock.ClockFilter = 0x03;                          //滤波(注意是外部时钟的波)HAL_TIM_ConfigClockSource(&tim1, &tim1_clock);  //初始化定时器时钟配置HAL_TIM_Base_Start(&tim1);   //打开定时器(轮询方式)
}//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{tim2.Instance = TIM2;tim2.Init.Period = arr; tim2.Init.Prescaler = psc;tim2.Init.CounterMode = TIM_COUNTERMODE_UP;tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim2);__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);__HAL_TIM_ENABLE_IT(&tim2, TIM1_UP_IRQn);HAL_TIM_Base_Start_DMA(&tim2, (uint32_t*)tim2_dmaBuff, 4);
}//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{tim3.Instance = TIM3;tim3.Init.Period = arr;tim3.Init.Prescaler = psc;tim3.Init.CounterMode = TIM_COUNTERMODE_UP;tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim3); __HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);__HAL_TIM_ENABLE_IT(&tim3, TIM1_UP_IRQn);HAL_TIM_Base_Start_DMA(&tim3, (uint32_t*)tim3_dmaBuff, 4);
}//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{tim4.Instance = TIM4;tim4.Init.Period = arr;tim4.Init.Prescaler = psc;tim4.Init.CounterMode = TIM_COUNTERMODE_UP;tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim4);__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);__HAL_TIM_ENABLE_IT(&tim4, TIM1_UP_IRQn);HAL_TIM_Base_Start_DMA(&tim4, (uint32_t*)tim4_dmaBuff, 4);
}//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){__HAL_RCC_TIM1_CLK_ENABLE();                //使能时钟__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitType;GPIO_InitType.Pin = GPIO_PIN_9;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //上拉GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;HAL_GPIO_Init(GPIOA,&GPIO_InitType);//        __HAL_RCC_DMA1_CLK_ENABLE();
//        
//        HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0);   //配置、打开 更新中断
//        HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
//        
//        /* DMA配置 */
//        tim1_dmaup.Instance = DMA1_Channel5;    
//        tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;   //存储区到外设
//        tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE;           //存储区递增
//        tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;       //外设不递增
//        tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //半字 2字节
//        tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
//        tim1_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式
//        tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; 
//        __HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
//        HAL_DMA_Init(&tim1_dmaup);
//        
//        HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0);   //配置、打开 通道5的中断
//        HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
//        }else if(htim->Instance == TIM2){__HAL_RCC_TIM2_CLK_ENABLE();__HAL_RCC_DMA1_CLK_ENABLE();HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM2_IRQn);/* DMA配置 */tim2_dmaup.Instance = DMA1_Channel2;    tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;tim2_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; __HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);HAL_DMA_Init(&tim2_dmaup);HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0);   //配置、打开 通道5的中断HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);}else if(htim->Instance == TIM3){__HAL_RCC_TIM3_CLK_ENABLE();__HAL_RCC_DMA1_CLK_ENABLE();HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM3_IRQn);/* DMA配置 */tim3_dmaup.Instance = DMA1_Channel3;    tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;tim3_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; __HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);HAL_DMA_Init(&tim3_dmaup);HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0);   //配置、打开 通道5的中断HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);}else if(htim->Instance == TIM4){__HAL_RCC_TIM4_CLK_ENABLE();__HAL_RCC_DMA1_CLK_ENABLE();HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM4_IRQn);/* DMA配置 */tim4_dmaup.Instance = DMA1_Channel7;    tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;tim4_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; __HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);HAL_DMA_Init(&tim4_dmaup);HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0);   //配置、打开 通道5的中断HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);}
}//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){__HAL_RCC_TIM1_CLK_DISABLE();}else if(htim->Instance == TIM2){__HAL_RCC_TIM2_CLK_DISABLE();}else if(htim->Instance == TIM3){__HAL_RCC_TIM3_CLK_DISABLE();}else if(htim->Instance == TIM4){__HAL_RCC_TIM4_CLK_DISABLE();}    
}//更新中断  回调函数(同时也是DMA完成的回调函数)uint16_t time1 = 1;uint16_t time2 = 1; uint16_t time3 = 1;uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{    if(htim->Instance == TIM1){/* 判断TIM是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 */if(htim->State  == HAL_DMA_STATE_READY){U1_Printf("DMA1 完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else{U1_Printf("定时器 1 定时时间:%d\\r\\n",time1++);}}else if(htim->Instance == TIM2){if(htim->State  == HAL_DMA_STATE_READY){U1_Printf("DMA2 完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else{U1_Printf("定时器 2 定时时间:%d\\r\\n",time2++);}}else if(htim->Instance == TIM3){if(htim->State  == HAL_DMA_STATE_READY){U1_Printf("DMA3 完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else{U1_Printf("定时器 3 定时时间:%d\\r\\n",time3++);}}else if(htim->Instance == TIM4){if(htim->State  == HAL_DMA_STATE_READY){U1_Printf("DMA4 完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else{U1_Printf("定时器 4 定时时间:%d\\r\\n",time4++);}}
}//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){U1_Printf("定时器 1 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else if(htim->Instance == TIM2){U1_Printf("定时器 2 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else if(htim->Instance == TIM3){U1_Printf("定时器 3 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else if(htim->Instance == TIM4){U1_Printf("定时器 4 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}}

time.h

#ifndef __TIME_H
#define __TIME_H#include "uart.h"/* 对外声明总控结构体 */
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;/* 初始化函数 */
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);#endif

main.c

 while(1){/* 获取更新标志位 */if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   ///清除标志位U1_Printf("定时器 1 更新事件\\r\\n");}if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_TRIGGER)){__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER);   ///清除标志位U1_Printf("定时器 1 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(&tim1));  //输出当前计数值}}

三、HAL库:TIM1 外部模式1 ETR通道 轮询方式 按键计数

1. 注意事项*

  1. ETR的通道有专门的预分频器,需要按需配置预分频器TIM_CLOCKPRESCALER_DIV1/2/4/8

  2. 特别注意:当设置ETR的预分频器为2、4、8分频时,如果ETR的有效电平(取决于是否ETR反向)与IO的引脚默认电平不匹配,那么复位后首次按下会直接产生一次触发事件,后续正常。

    • **解决办法:**匹配IO与ETR的有效电平 (例如IO下拉,ETR有效电平为低电平,也就是ETR反转。那么就能匹配默认电平与ETR,就不会出现上述错误)
  3. 特别注意:如果通道的 分频因子 加大(同时加大分频因子),会使得检测变慢,也就是频率和带宽就变低了,变得更严格。会导致复位之后立刻产生一次触发事件。

    • 解决办法:在启动定时器之前,

      先进行一段时间的延时操作,再清除TIm的Counter和TRIG触发事件标志位

      这样就能保证在启动时不会有任何触发事件产生(添加延时的原因是因为程序运行太快了,得等段时间反映。)

2. 相关函数

  • TIM_ClockConfigTypeDef 时钟配置总控结构体

  • 基础的定时器配置初始化(定时器1通道 2举例)

    //定时器 1
    void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
    {tim1.Instance = TIM1;                                        // 实例tim1.Init.Period = arr;                                      // 重装载值tim1.Init.Prescaler = psc;                                   // 分频系数tim1.Init.CounterMode = TIM_COUNTERMODE_UP;                  // 计数模式tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;            // 分频因子tim1.Init.RepetitionCounter = rep;                           // 重复计数值tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)HAL_TIM_Base_Init(&tim1);                       //初始化定时器__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   //手动 清除 定时器 更新事件/* 外部模式1 ETR通道  */tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETRtim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED;    //ETR反向 (低电平或下降沿有效)  为了匹配IO和ETR,防止复位后按一下就产生触发事件//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED;    //ETR不反向 (高电平或上升沿有效)tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV4;      //ETR的预分频器配置tim1_clock.ClockFilter = 0x03;                          //滤波(注意是外部时钟的波)HAL_TIM_ConfigClockSource(&tim1, &tim1_clock);  //初始化定时器时钟配置/* 防止加大分频因子或滤波强度而导致的 复位后产生触发事件 */HAL_Delay(50);__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER);   ///清除触发事件标志位__HAL_TIM_SET_COUNTER(&tim1, 0);                 // 清除计数值HAL_TIM_Base_Start(&tim1);   //打开定时器(轮询方式)
    }
    
  • 初始化硬件配置回调函数

    if(htim->Instance == TIM1){__HAL_RCC_TIM1_CLK_ENABLE();                //使能时钟__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitType;GPIO_InitType.Pin = GPIO_PIN_9;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //上拉GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;HAL_GPIO_Init(GPIOA,&GPIO_InitType);
    

3. 程序

time.c

#include "stm32f1xx_hal.h"
#include "time.h"TIM_HandleTypeDef tim1; //(高级)定时器1总控结构体
TIM_HandleTypeDef tim2; 
TIM_HandleTypeDef tim3; 
TIM_HandleTypeDef tim4; DMA_HandleTypeDef tim1_dmaup;
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;TIM_ClockConfigTypeDef tim1_clock;  //时钟配置结构体uint16_t tim1_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim2_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim3_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim4_dmaBuff[4] = {20000, 30000, 40000, 50000};//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{tim1.Instance = TIM1;                                        // 实例tim1.Init.Period = arr;                                      // 重装载值tim1.Init.Prescaler = psc;                                   // 分频系数tim1.Init.CounterMode = TIM_COUNTERMODE_UP;                  // 计数模式tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;            // 分频因子tim1.Init.RepetitionCounter = rep;                           // 重复计数值tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)HAL_TIM_Base_Init(&tim1);                       //初始化定时器__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   //手动 清除 定时器 更新事件/* 外部模式1 ETR通道  */tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETRtim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED;    //ETR反向 (低电平或下降沿有效)  为了匹配IO和ETR,防止复位后按一下就产生触发事件//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED;    //ETR不反向 (高电平或上升沿有效)tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV4;      //ETR的预分频器配置tim1_clock.ClockFilter = 0x03;                          //滤波(注意是外部时钟的波)HAL_TIM_ConfigClockSource(&tim1, &tim1_clock);  //初始化定时器时钟配置/* 防止加大分频因子或滤波强度而导致的 复位后产生触发事件 */HAL_Delay(50);__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER);   ///清除触发事件标志位__HAL_TIM_SET_COUNTER(&tim1, 0);                 // 清除计数值HAL_TIM_Base_Start(&tim1);   //打开定时器(轮询方式)
}//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{tim2.Instance = TIM2;tim2.Init.Period = arr; tim2.Init.Prescaler = psc;tim2.Init.CounterMode = TIM_COUNTERMODE_UP;tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim2);__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);__HAL_TIM_ENABLE_IT(&tim2, TIM1_UP_IRQn);HAL_TIM_Base_Start_DMA(&tim2, (uint32_t*)tim2_dmaBuff, 4);
}//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{tim3.Instance = TIM3;tim3.Init.Period = arr;tim3.Init.Prescaler = psc;tim3.Init.CounterMode = TIM_COUNTERMODE_UP;tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim3); __HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);__HAL_TIM_ENABLE_IT(&tim3, TIM1_UP_IRQn);HAL_TIM_Base_Start_DMA(&tim3, (uint32_t*)tim3_dmaBuff, 4);
}//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{tim4.Instance = TIM4;tim4.Init.Period = arr;tim4.Init.Prescaler = psc;tim4.Init.CounterMode = TIM_COUNTERMODE_UP;tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim4);__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);__HAL_TIM_ENABLE_IT(&tim4, TIM1_UP_IRQn);HAL_TIM_Base_Start_DMA(&tim4, (uint32_t*)tim4_dmaBuff, 4);
}//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){__HAL_RCC_TIM1_CLK_ENABLE();                //使能时钟__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitType;GPIO_InitType.Pin = GPIO_PIN_12;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //低电平按下,上拉GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;HAL_GPIO_Init(GPIOA,&GPIO_InitType);//        __HAL_RCC_DMA1_CLK_ENABLE();
//        
//        HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0);   //配置、打开 更新中断
//        HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
//        
//        /* DMA配置 */
//        tim1_dmaup.Instance = DMA1_Channel5;    
//        tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;   //存储区到外设
//        tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE;           //存储区递增
//        tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;       //外设不递增
//        tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //半字 2字节
//        tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
//        tim1_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式
//        tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; 
//        __HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
//        HAL_DMA_Init(&tim1_dmaup);
//        
//        HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0);   //配置、打开 通道5的中断
//        HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
//        }else if(htim->Instance == TIM2){__HAL_RCC_TIM2_CLK_ENABLE();__HAL_RCC_DMA1_CLK_ENABLE();HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM2_IRQn);/* DMA配置 */tim2_dmaup.Instance = DMA1_Channel2;    tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;tim2_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; __HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);HAL_DMA_Init(&tim2_dmaup);HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0);   //配置、打开 通道5的中断HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);}else if(htim->Instance == TIM3){__HAL_RCC_TIM3_CLK_ENABLE();__HAL_RCC_DMA1_CLK_ENABLE();HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM3_IRQn);/* DMA配置 */tim3_dmaup.Instance = DMA1_Channel3;    tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;tim3_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; __HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);HAL_DMA_Init(&tim3_dmaup);HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0);   //配置、打开 通道5的中断HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);}else if(htim->Instance == TIM4){__HAL_RCC_TIM4_CLK_ENABLE();__HAL_RCC_DMA1_CLK_ENABLE();HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM4_IRQn);/* DMA配置 */tim4_dmaup.Instance = DMA1_Channel7;    tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;tim4_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; __HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);HAL_DMA_Init(&tim4_dmaup);HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0);   //配置、打开 通道5的中断HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);}
}//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){__HAL_RCC_TIM1_CLK_DISABLE();}else if(htim->Instance == TIM2){__HAL_RCC_TIM2_CLK_DISABLE();}else if(htim->Instance == TIM3){__HAL_RCC_TIM3_CLK_DISABLE();}else if(htim->Instance == TIM4){__HAL_RCC_TIM4_CLK_DISABLE();}    
}//更新中断  回调函数(同时也是DMA完成的回调函数)uint16_t time1 = 1;uint16_t time2 = 1; uint16_t time3 = 1;uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{    if(htim->Instance == TIM1){/* 判断TIM是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 */if(htim->State  == HAL_DMA_STATE_READY){U1_Printf("DMA1 完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else{U1_Printf("定时器 1 定时时间:%d\\r\\n",time1++);}}else if(htim->Instance == TIM2){if(htim->State  == HAL_DMA_STATE_READY){U1_Printf("DMA2 完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else{U1_Printf("定时器 2 定时时间:%d\\r\\n",time2++);}}else if(htim->Instance == TIM3){if(htim->State  == HAL_DMA_STATE_READY){U1_Printf("DMA3 完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else{U1_Printf("定时器 3 定时时间:%d\\r\\n",time3++);}}else if(htim->Instance == TIM4){if(htim->State  == HAL_DMA_STATE_READY){U1_Printf("DMA4 完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else{U1_Printf("定时器 4 定时时间:%d\\r\\n",time4++);}}
}//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){U1_Printf("定时器 1 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else if(htim->Instance == TIM2){U1_Printf("定时器 2 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else if(htim->Instance == TIM3){U1_Printf("定时器 3 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else if(htim->Instance == TIM4){U1_Printf("定时器 4 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}}

time.h

#ifndef __TIME_H
#define __TIME_H#include "uart.h"/* 对外声明总控结构体 */
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;/* 初始化函数 */
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);#endif

main.c

 while(1){/* 获取更新标志位 */if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   ///清除标志位U1_Printf("定时器 1 更新事件\\r\\n");}if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_TRIGGER)){__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER);   ///清除标志位U1_Printf("定时器 1 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(&tim1));  //输出当前计数值}}

四、HAL库:TIM234 外部模式1 通道1 2 轮询方式 重映射通道 边沿检测 按键计数

1. 注意事项*

  1. 引脚冲突问题

    要善用重映射功能,避免引脚冲突

    并且在切换不同的通道的时候,注意GPIO口的初始化与上下拉配置

  2. 还是引脚冲突问题

    单片机在默认状态佳,SW+JTAG仿真都是开启状态的。

    当定时器2 的通道1 重映射会映射到 PA15,会与JTAG的引脚冲突。注意一下需要

  3. 如果映射TIM2时, 一旦设计仿真接口切换为普通接口,需要在初始化时保持一致

2. 程序

time.c

#include "stm32f1xx_hal.h"
#include "time.h"TIM_HandleTypeDef tim1; //定时器结构体
TIM_HandleTypeDef tim2; 
TIM_HandleTypeDef tim3; 
TIM_HandleTypeDef tim4; DMA_HandleTypeDef tim1_dmaup;   //DMA通道配置结构体
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;TIM_ClockConfigTypeDef tim1_clock;  //时钟配置结构体
TIM_ClockConfigTypeDef tim2_clock;
TIM_ClockConfigTypeDef tim3_clock;
TIM_ClockConfigTypeDef tim4_clock;uint16_t tim1_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim2_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim3_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim4_dmaBuff[4] = {20000, 30000, 40000, 50000};//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{tim1.Instance = TIM1;                                        // 实例tim1.Init.Period = arr;                                      // 重装载值tim1.Init.Prescaler = psc;                                   // 分频系数tim1.Init.CounterMode = TIM_COUNTERMODE_UP;                  // 计数模式tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;            // 分频因子tim1.Init.RepetitionCounter = rep;                           // 重复计数值tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)HAL_TIM_Base_Init(&tim1);                       //初始化定时器__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   //手动 清除 定时器 更新事件/* 外部模式1 ETR通道  */tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETRtim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED;      //ETR反向 (低电平或下降沿有效)//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED;    //ETR不反向 (高电平或上升沿有效)tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1;      //ETR的预分频器配置tim1_clock.ClockFilter = 0x03;                          //滤波(注意是外部时钟的波)HAL_TIM_ConfigClockSource(&tim1, &tim1_clock);  //初始化定时器时钟配置HAL_TIM_Base_Start(&tim1);   //打开定时器(轮询方式)
}//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{tim2.Instance = TIM2;tim2.Init.Period = arr; tim2.Init.Prescaler = psc;tim2.Init.CounterMode = TIM_COUNTERMODE_UP;tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim2);__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);/* 外部模式1 通道1 双边沿检测  重映射*/tim2_clock.ClockSource = TIM_CLOCKSOURCE_TI1ED; //通道1 边沿检测HAL_TIM_ConfigClockSource(&tim2, &tim2_clock);  //初始化定时器时钟配置HAL_TIM_Base_Start(&tim2);   //打开定时器(轮询方式)
}//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{tim3.Instance = TIM3;tim3.Init.Period = arr;tim3.Init.Prescaler = psc;tim3.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; //中央对齐模式tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim3); __HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);/* 外部模式1 通道1 */tim3_clock.ClockSource = TIM_CLOCKSOURCE_TI1;             // 通道1tim3_clock.ClockPolarity = TIM_CLOCKPOLARITY_RISING;      // 上升沿tim3_clock.ClockFilter = 0x03;                            // 滤波HAL_TIM_ConfigClockSource(&tim3, &tim3_clock);  //初始化定时器时钟配置HAL_TIM_Base_Start(&tim3);   //打开定时器(轮询方式)
}//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{tim4.Instance = TIM4;tim4.Init.Period = arr;tim4.Init.Prescaler = psc;tim4.Init.CounterMode = TIM_COUNTERMODE_UP;tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim4); __HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);/* 外部模式1 通道2 */tim4_clock.ClockSource = TIM_CLOCKSOURCE_TI2;             // 通道2tim4_clock.ClockPolarity = TIM_CLOCKPOLARITY_FALLING;     // 下降沿tim4_clock.ClockFilter = 0x03;                            // 滤波HAL_TIM_ConfigClockSource(&tim4, &tim4_clock);  //初始化定时器时钟配置HAL_TIM_Base_Start(&tim4);   //打开定时器(轮询方式)
}//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{GPIO_InitTypeDef GPIO_InitType;if(htim->Instance == TIM1){__HAL_RCC_TIM1_CLK_ENABLE();                //使能时钟/* 定时器1 外部模式1 ETR通道IO */__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitType.Pin = GPIO_PIN_12;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //低电平按下,上拉HAL_GPIO_Init(GPIOA,&GPIO_InitType);//        __HAL_RCC_DMA1_CLK_ENABLE();
//        
//        HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0);   //配置、打开 更新中断
//        HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
//        
//        /* DMA配置 */
//        tim1_dmaup.Instance = DMA1_Channel5;    
//        tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;   //存储区到外设
//        tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE;           //存储区递增
//        tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;       //外设不递增
//        tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //半字 2字节
//        tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
//        tim1_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式
//        tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;  
//        __HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
//        HAL_DMA_Init(&tim1_dmaup);
//        
//        HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0);   //配置、打开 通道5的中断
//        HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
//        }else if(htim->Instance == TIM2){__HAL_RCC_TIM2_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_AFIO_CLK_ENABLE();__HAL_AFIO_REMAP_TIM2_ENABLE();//__HAL_AFIO_REMAP_TIM2_PARTIAL_1(); //(同样的功能)__HAL_AFIO_REMAP_SWJ_NOJTAG();/* 定时器2 外部模式1 通道1 重映射*///GPIO_InitType.Pin = GPIO_PIN_0;GPIO_InitType.Pin = GPIO_PIN_15;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //低电平按下,上拉HAL_GPIO_Init(GPIOA,&GPIO_InitType);//        __HAL_RCC_DMA1_CLK_ENABLE();//        HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);
//        HAL_NVIC_EnableIRQ(TIM2_IRQn);
//        
//        /* DMA配置 */
//        tim2_dmaup.Instance = DMA1_Channel2;    
//        tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
//        tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;
//        tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
//        tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
//        tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
//        tim2_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式
//        tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; 
//        __HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);
//        HAL_DMA_Init(&tim2_dmaup);
//        
//        HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0);   //配置、打开 通道5的中断
//        HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);}else if(htim->Instance == TIM3){__HAL_RCC_TIM3_CLK_ENABLE();//__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_AFIO_CLK_ENABLE();__HAL_AFIO_REMAP_TIM3_PARTIAL();    //部分映射__HAL_AFIO_REMAP_SWJ_NONJTRST();    //完全SW+JATG 但没有NJTRST/* 定时器3 外部模式1 通道1 重映射*///GPIO_InitType.Pin = GPIO_PIN_6;GPIO_InitType.Pin = GPIO_PIN_4;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //低电平按下,上拉HAL_GPIO_Init(GPIOB,&GPIO_InitType);//        __HAL_RCC_DMA1_CLK_ENABLE();//        HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);
//        HAL_NVIC_EnableIRQ(TIM3_IRQn);
//        
//        /* DMA配置 */
//        tim3_dmaup.Instance = DMA1_Channel3;    
//        tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
//        tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;
//        tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
//        tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
//        tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
//        tim3_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式
//        tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; 
//        __HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);
//        HAL_DMA_Init(&tim3_dmaup);
//        
//        HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0);   //配置、打开 通道5的中断
//        HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);}else if(htim->Instance == TIM4){__HAL_RCC_TIM4_CLK_ENABLE();/* 定时器4 外部模式1 通道2 */__HAL_RCC_GPIOB_CLK_ENABLE();GPIO_InitType.Pin = GPIO_PIN_7;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //低电平按下,上拉HAL_GPIO_Init(GPIOB, &GPIO_InitType);//        __HAL_RCC_DMA1_CLK_ENABLE();//        HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);
//        HAL_NVIC_EnableIRQ(TIM4_IRQn);
//        
//        /* DMA配置 */
//        tim4_dmaup.Instance = DMA1_Channel7;    
//        tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
//        tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;
//        tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
//        tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
//        tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
//        tim4_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式
//        tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; 
//        __HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);
//        HAL_DMA_Init(&tim4_dmaup);
//        
//        HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0);   //配置、打开 通道5的中断
//        HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);}
}//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){__HAL_RCC_TIM1_CLK_DISABLE();}else if(htim->Instance == TIM2){__HAL_RCC_TIM2_CLK_DISABLE();}else if(htim->Instance == TIM3){__HAL_RCC_TIM3_CLK_DISABLE();}else if(htim->Instance == TIM4){__HAL_RCC_TIM4_CLK_DISABLE();}    
}//更新中断  回调函数(同时也是DMA完成的回调函数)uint16_t time1 = 1;uint16_t time2 = 1; uint16_t time3 = 1;uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{    if(htim->Instance == TIM1){/* 判断TIM是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 */if(htim->State  == HAL_DMA_STATE_READY){U1_Printf("DMA1 完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else{U1_Printf("定时器 1 定时时间:%d\\r\\n",time1++);}}else if(htim->Instance == TIM2){if(htim->State  == HAL_DMA_STATE_READY){U1_Printf("DMA2 完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else{U1_Printf("定时器 2 定时时间:%d\\r\\n",time2++);}}else if(htim->Instance == TIM3){if(htim->State  == HAL_DMA_STATE_READY){U1_Printf("DMA3 完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else{U1_Printf("定时器 3 定时时间:%d\\r\\n",time3++);}}else if(htim->Instance == TIM4){if(htim->State  == HAL_DMA_STATE_READY){U1_Printf("DMA4 完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else{U1_Printf("定时器 4 定时时间:%d\\r\\n",time4++);}}
}//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){U1_Printf("定时器 1 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else if(htim->Instance == TIM2){U1_Printf("定时器 2 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else if(htim->Instance == TIM3){U1_Printf("定时器 3 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else if(htim->Instance == TIM4){U1_Printf("定时器 4 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}}

time.h

#ifndef __TIME_H
#define __TIME_H#include "uart.h"/* 对外声明总控结构体 */
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;/* 初始化函数 */
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);#endif

main.c

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
#include "time.h"int main(void){HAL_Init();RccClock_Init();U1_Init(921600);Timer1_Init(5 - 1, 0, 1 - 1);         //5次有效边沿Timer2_Init(5 - 1, 0);   // 5次Timer3_Init(5 - 1, 0);   // 5次Timer4_Init(5 - 1, 0);   // 5次//    uint16_t time1 = 0;
//    uint16_t time2 = 0;
//    uint16_t time3 = 0;
//    uint16_t time4 = 0;while(1){/* 获取更新标志位 *//* TIM1 */if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   ///清除标志位U1_Printf("定时器 1 更新事件\\r\\n");}if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_TRIGGER)){__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER);   ///清除标志位U1_Printf("定时器 1 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(&tim1));  //输出当前计数值}/* TIM2 */if(__HAL_TIM_GET_FLAG(&tim2, TIM_FLAG_UPDATE)){__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);U1_Printf("定时器 2 更新事件\\r\\n");}if(__HAL_TIM_GET_FLAG(&tim2, TIM_FLAG_TRIGGER)){__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_TRIGGER);U1_Printf("定时器 2 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(&tim2));}/* TIM3 */if(__HAL_TIM_GET_FLAG(&tim3, TIM_FLAG_UPDATE)){__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);U1_Printf("定时器 3 更新事件\\r\\n");}if(__HAL_TIM_GET_FLAG(&tim3, TIM_FLAG_TRIGGER)){__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_TRIGGER);U1_Printf("定时器 3 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(&tim3));}/* TIM4 */if(__HAL_TIM_GET_FLAG(&tim4, TIM_FLAG_UPDATE)){__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);U1_Printf("定时器 4 更新事件\\r\\n");}if(__HAL_TIM_GET_FLAG(&tim4, TIM_FLAG_TRIGGER)){__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_TRIGGER);U1_Printf("定时器 4 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(&tim4));}//        
//        if(__HAL_TIM_GET_FLAG(&tim2, TIM_FLAG_UPDATE)){
//            __HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
//            U1_Printf("定时器 2 定时时间:%d\\r\\n",time2++);
//        }
//        
//        if(__HAL_TIM_GET_FLAG(&tim3, TIM_FLAG_UPDATE)){
//            __HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
//            U1_Printf("定时器 3 定时时间:%d\\r\\n",time3++);
//        }
//        
//        if(__HAL_TIM_GET_FLAG(&tim4, TIM_FLAG_UPDATE)){
//            __HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
//            U1_Printf("定时器 4 定时时间:%d\\r\\n",time4++);
//        }}
}

五、HAL库:TIM1234 外部模式1 中断方式 按键计数

1. 注意事项*

  1. HAL库只会打开Up中断,触发中断需要手动打开
  2. 注意定时器与别的外设 引脚冲突

2. 相关函数

  • __HAL_TIM_ENABLE_IT(&tim3, TIM_IT_TRIGGER); 手动打开触发中断
  • HAL_TIM_Base_Start_IT(&tim4); 打开定时器(中断方式)

3. 程序

time.c

#include "stm32f1xx_hal.h"
#include "time.h"TIM_HandleTypeDef tim1; //定时器结构体
TIM_HandleTypeDef tim2; 
TIM_HandleTypeDef tim3; 
TIM_HandleTypeDef tim4; DMA_HandleTypeDef tim1_dmaup;   //DMA通道配置结构体
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;TIM_ClockConfigTypeDef tim1_clock;  //时钟配置结构体
TIM_ClockConfigTypeDef tim2_clock;
TIM_ClockConfigTypeDef tim3_clock;
TIM_ClockConfigTypeDef tim4_clock;uint16_t tim1_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim2_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim3_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim4_dmaBuff[4] = {20000, 30000, 40000, 50000};//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{tim1.Instance = TIM1;                                        // 实例tim1.Init.Period = arr;                                      // 重装载值tim1.Init.Prescaler = psc;                                   // 分频系数tim1.Init.CounterMode = TIM_COUNTERMODE_UP;                  // 计数模式tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;            // 分频因子tim1.Init.RepetitionCounter = rep;                           // 重复计数值tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)HAL_TIM_Base_Init(&tim1);                       //初始化定时器__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   //手动 清除 定时器 更新事件/* 外部模式1 ETR通道  */  //PA12 下降沿 按下计数 上拉tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETRtim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED;      //ETR反向 (低电平或下降沿有效)//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED;    //ETR不反向 (高电平或上升沿有效)tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1;      //ETR的预分频器配置tim1_clock.ClockFilter = 0x03;                          //滤波(注意是外部时钟的波)HAL_TIM_ConfigClockSource(&tim1, &tim1_clock);  //初始化定时器时钟配置__HAL_TIM_ENABLE_IT(&tim1, TIM_IT_TRIGGER); //手动打开触发中断HAL_TIM_Base_Start_IT(&tim1);   //打开定时器(中断方式)
}//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{tim2.Instance = TIM2;tim2.Init.Period = arr; tim2.Init.Prescaler = psc;tim2.Init.CounterMode = TIM_COUNTERMODE_UP;tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim2);__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);/* 外部模式1 通道1 双边沿检测  重映射*/   //PA15 双边边沿 上拉tim2_clock.ClockSource = TIM_CLOCKSOURCE_TI1ED; //通道1 边沿检测HAL_TIM_ConfigClockSource(&tim2, &tim2_clock);  //初始化定时器时钟配置__HAL_TIM_ENABLE_IT(&tim2, TIM_IT_TRIGGER); //手动打开触发中断HAL_TIM_Base_Start_IT(&tim2);   //打开定时器(中断方式)
}//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{tim3.Instance = TIM3;tim3.Init.Period = arr;tim3.Init.Prescaler = psc;tim3.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; //中央对齐模式tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim3); __HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);/* 外部模式1 通道1 */ //PB4 上升沿 上拉 抬起计数tim3_clock.ClockSource = TIM_CLOCKSOURCE_TI1;             // 通道1tim3_clock.ClockPolarity = TIM_CLOCKPOLARITY_RISING;      // 上升沿tim3_clock.ClockFilter = 0x03;                            // 滤波HAL_TIM_ConfigClockSource(&tim3, &tim3_clock);  //初始化定时器时钟配置__HAL_TIM_ENABLE_IT(&tim3, TIM_IT_TRIGGER); //手动打开触发中断HAL_TIM_Base_Start_IT(&tim3);   //打开定时器(中断方式)
}//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{tim4.Instance = TIM4;tim4.Init.Period = arr;tim4.Init.Prescaler = psc;tim4.Init.CounterMode = TIM_COUNTERMODE_UP;tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim4); __HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);/* 外部模式1 通道2 */ //PB7 下降沿 上拉 按下计数tim4_clock.ClockSource = TIM_CLOCKSOURCE_TI2;             // 通道2tim4_clock.ClockPolarity = TIM_CLOCKPOLARITY_FALLING;     // 下降沿tim4_clock.ClockFilter = 0x03;                            // 滤波HAL_TIM_ConfigClockSource(&tim4, &tim4_clock);  //初始化定时器时钟配置__HAL_TIM_ENABLE_IT(&tim4, TIM_IT_TRIGGER); //手动打开触发中断HAL_TIM_Base_Start_IT(&tim4);   //打开定时器(中断方式)
}//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{GPIO_InitTypeDef GPIO_InitType;if(htim->Instance == TIM1){__HAL_RCC_TIM1_CLK_ENABLE();                //使能时钟/* 定时器1 外部模式1 ETR通道IO */__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitType.Pin = GPIO_PIN_12;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //低电平按下,上拉HAL_GPIO_Init(GPIOA,&GPIO_InitType);//        __HAL_RCC_DMA1_CLK_ENABLE();
//        HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0);   //配置、打开 更新中断HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);HAL_NVIC_SetPriority(TIM1_TRG_COM_IRQn, 3, 0);   //配置、打开 触发中断HAL_NVIC_EnableIRQ(TIM1_TRG_COM_IRQn);
//        
//        /* DMA配置 */
//        tim1_dmaup.Instance = DMA1_Channel5;    
//        tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;   //存储区到外设
//        tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE;           //存储区递增
//        tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;       //外设不递增
//        tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //半字 2字节
//        tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
//        tim1_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式
//        tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;  
//        __HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
//        HAL_DMA_Init(&tim1_dmaup);
//        
//        HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0);   //配置、打开 通道5的中断
//        HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
//        }else if(htim->Instance == TIM2){__HAL_RCC_TIM2_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_AFIO_CLK_ENABLE();__HAL_AFIO_REMAP_TIM2_ENABLE();//__HAL_AFIO_REMAP_TIM2_PARTIAL_1(); //(同样的功能)__HAL_AFIO_REMAP_SWJ_NOJTAG();/* 定时器2 外部模式1 通道1 重映射*///GPIO_InitType.Pin = GPIO_PIN_0;GPIO_InitType.Pin = GPIO_PIN_15;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //低电平按下,上拉HAL_GPIO_Init(GPIOA,&GPIO_InitType);//        __HAL_RCC_DMA1_CLK_ENABLE();HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM2_IRQn);
//        
//        /* DMA配置 */
//        tim2_dmaup.Instance = DMA1_Channel2;    
//        tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
//        tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;
//        tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
//        tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
//        tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
//        tim2_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式
//        tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; 
//        __HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);
//        HAL_DMA_Init(&tim2_dmaup);
//        
//        HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0);   //配置、打开 通道5的中断
//        HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);}else if(htim->Instance == TIM3){__HAL_RCC_TIM3_CLK_ENABLE();//__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_AFIO_CLK_ENABLE();__HAL_AFIO_REMAP_TIM3_PARTIAL();    //部分映射__HAL_AFIO_REMAP_SWJ_NONJTRST();    //完全SW+JATG 但没有NJTRST/* 定时器3 外部模式1 通道1 重映射*///GPIO_InitType.Pin = GPIO_PIN_6;GPIO_InitType.Pin = GPIO_PIN_4;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //低电平按下,上拉HAL_GPIO_Init(GPIOB,&GPIO_InitType);//        __HAL_RCC_DMA1_CLK_ENABLE();HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM3_IRQn);
//        
//        /* DMA配置 */
//        tim3_dmaup.Instance = DMA1_Channel3;    
//        tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
//        tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;
//        tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
//        tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
//        tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
//        tim3_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式
//        tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; 
//        __HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);
//        HAL_DMA_Init(&tim3_dmaup);
//        
//        HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0);   //配置、打开 通道5的中断
//        HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);}else if(htim->Instance == TIM4){__HAL_RCC_TIM4_CLK_ENABLE();/* 定时器4 外部模式1 通道2 */__HAL_RCC_GPIOB_CLK_ENABLE();GPIO_InitType.Pin = GPIO_PIN_7;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //低电平按下,上拉HAL_GPIO_Init(GPIOB, &GPIO_InitType);//        __HAL_RCC_DMA1_CLK_ENABLE();HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM4_IRQn);
//        
//        /* DMA配置 */
//        tim4_dmaup.Instance = DMA1_Channel7;    
//        tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
//        tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;
//        tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
//        tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
//        tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
//        tim4_dmaup.Init.Mode = DMA_CIRCULAR;  //循环模式
//        tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; 
//        __HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);
//        HAL_DMA_Init(&tim4_dmaup);
//        
//        HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0);   //配置、打开 通道5的中断
//        HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);}
}//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){__HAL_RCC_TIM1_CLK_DISABLE();}else if(htim->Instance == TIM2){__HAL_RCC_TIM2_CLK_DISABLE();}else if(htim->Instance == TIM3){__HAL_RCC_TIM3_CLK_DISABLE();}else if(htim->Instance == TIM4){__HAL_RCC_TIM4_CLK_DISABLE();}    
}//更新中断  回调函数(同时也是DMA完成的回调函数)uint16_t time1 = 1;uint16_t time2 = 1; uint16_t time3 = 1;uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{    if(htim->Instance == TIM1){
//        /* 判断TIM是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 */
//        if(htim->State  == HAL_DMA_STATE_READY){
//            U1_Printf("DMA1 完成中断\\r\\n");
//            htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态
//        }else{
//            U1_Printf("定时器 1 定时时间:%d\\r\\n",time1++);
//        }U1_Printf("定时器 1 更新事件\\r\\n");}else if(htim->Instance == TIM2){
//        if(htim->State  == HAL_DMA_STATE_READY){
//            U1_Printf("DMA2 完成中断\\r\\n");
//            htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态
//        }else{
//            U1_Printf("定时器 2 定时时间:%d\\r\\n",time2++);
//        }U1_Printf("定时器 2 更新事件\\r\\n");}else if(htim->Instance == TIM3){
//         if(htim->State  == HAL_DMA_STATE_READY){
//            U1_Printf("DMA3 完成中断\\r\\n");
//            htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态
//        }else{
//            U1_Printf("定时器 3 定时时间:%d\\r\\n",time3++);
//        }U1_Printf("定时器 3 更新事件\\r\\n");}else if(htim->Instance == TIM4){
//         if(htim->State  == HAL_DMA_STATE_READY){
//            U1_Printf("DMA4 完成中断\\r\\n");
//            htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态
//        }else{
//            U1_Printf("定时器 4 定时时间:%d\\r\\n",time4++);
//        }U1_Printf("定时器 4 更新事件\\r\\n");}
}//触发中断 回调函数
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){U1_Printf("定时器 1 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim));  //输出当前计数值}else if(htim->Instance == TIM2){U1_Printf("定时器 2 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim));  //输出当前计数值}else if(htim->Instance == TIM3){U1_Printf("定时器 3 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim));  //输出当前计数值}else if(htim->Instance == TIM4){U1_Printf("定时器 4 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim));  //输出当前计数值}}//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){U1_Printf("定时器 1 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else if(htim->Instance == TIM2){U1_Printf("定时器 2 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else if(htim->Instance == TIM3){U1_Printf("定时器 3 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}else if(htim->Instance == TIM4){U1_Printf("定时器 4 DMA半完成中断\\r\\n");htim->State = HAL_TIM_STATE_BUSY;           //设置定时器 BUSY状态}
}

time.h

#ifndef __TIME_H
#define __TIME_H#include "uart.h"/* 对外声明总控结构体 */
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;/* 初始化函数 */
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);#endif

main.c

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
#include "time.h"int main(void){HAL_Init();RccClock_Init();U1_Init(921600);Timer1_Init(5 - 1, 0, 1 - 1);         //5次有效边沿Timer2_Init(5 - 1, 0);   // 5次Timer3_Init(5 - 1, 0);   // 5次Timer4_Init(5 - 1, 0);   // 5次U1_Printf("初始化完成\\r\\n");while(1){}
}

stm32f1xx_it.c

/*-------------------------------------------------*/
/*                                                 */
/*          实现各种中断服务函数的源文件           */
/*                                                 */
/*-------------------------------------------------*/#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h"
#include "uart.h"
#include "time.h"void EXTI15_10_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
void EXTI0_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void USART1_IRQHandler(void)
{HAL_UART_IRQHandler(&uart1.uart);if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){__HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);uart1.RxCounter += (U1_RX_MAX - __HAL_DMA_GET_COUNTER(&uart1.dmarx));HAL_UART_AbortReceive_IT(&uart1.uart);}
}
void USART2_IRQHandler(void)
{HAL_UART_IRQHandler(&uart2.uart);if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){__HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));HAL_UART_AbortReceive_IT(&uart2.uart);}
}
void USART3_IRQHandler(void)
{HAL_UART_IRQHandler(&uart3.uart);if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){__HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));HAL_UART_AbortReceive_IT(&uart3.uart);}
}
void DMA1_Channel4_IRQHandler(void)
{HAL_DMA_IRQHandler(&uart1.dmatx);
}
//void DMA1_Channel5_IRQHandler(void)
//{
//    HAL_DMA_IRQHandler(&uart1.dmarx);
//}
//void DMA1_Channel7_IRQHandler(void)
//{
//    HAL_DMA_IRQHandler(&uart2.dmatx);
//}
void DMA1_Channel6_IRQHandler(void)
{HAL_DMA_IRQHandler(&uart2.dmarx);
}
//void DMA1_Channel2_IRQHandler(void)
//{
//    HAL_DMA_IRQHandler(&uart3.dmatx);
//}
//void DMA1_Channel3_IRQHandler(void)
//{
//    HAL_DMA_IRQHandler(&uart3.dmarx);
//}
void DMA1_Channel5_IRQHandler(void)
{HAL_DMA_IRQHandler(&tim1_dmaup);
}
void DMA1_Channel2_IRQHandler(void)
{HAL_DMA_IRQHandler(&tim2_dmaup);
}
void DMA1_Channel3_IRQHandler(void)
{HAL_DMA_IRQHandler(&tim3_dmaup);
}
void DMA1_Channel7_IRQHandler(void)
{HAL_DMA_IRQHandler(&tim4_dmaup);
}void TIM1_UP_IRQHandler(void)
{HAL_TIM_IRQHandler(&tim1);
}void TIM1_TRG_COM_IRQHandler(void)
{HAL_TIM_IRQHandler(&tim1);
}void TIM2_IRQHandler(void)
{HAL_TIM_IRQHandler(&tim2);
}void TIM3_IRQHandler(void)
{HAL_TIM_IRQHandler(&tim3);
}void TIM4_IRQHandler(void)
{HAL_TIM_IRQHandler(&tim4);
}/*-------------------------------------------------*/
/*函数名:不可屏蔽中断处理函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void NMI_Handler(void)
{}/*-------------------------------------------------*/
/*函数名:硬件出错后进入的中断处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void HardFault_Handler(void)
{}
/*-------------------------------------------------*/
/*函数名:软中断,SWI 指令调用的处理函数           */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SVC_Handler(void)
{}
/*-------------------------------------------------*/
/*函数名:可挂起的系统服务处理函数                 */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void PendSV_Handler(void)
{}
/*-------------------------------------------------*/
/*函数名:SysTic系统嘀嗒定时器处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SysTick_Handler(void)
{  HAL_IncTick();	
}

六、HAL库:TIM1234 外部模式1 DMA单次/循环模式 中断方式 按键计数

1. 注意事项*

  1. DMA方式,HAL库不会开启任何中断,需要自己开启更新和触发中断
  2. 注意定时器与别的外设 引脚冲突
  3. 普通的更新中断与DMA完成中断共用一个回调函数

2. 简单介绍

DMA方式,会在每次更新时,传递新的值到ARR重载值,我们初始 化的时候设置ARR为5,然后启动DMA 4次传输分别传输6,7,8,9。

对于单次DMA向上计数,第一次5+1个有效边沿,第二次6+1个有效 边沿,第三次7+1个有效边沿,第四次8+1个有效边沿,第五次9+1 个有效边沿,之后一直都是9+1个有效边沿。

对于循环DMA向上计数,第一次5+1个有效边沿,第二次6+1个有效 边沿,第三次7+1个有效边沿,第四次8+1个有效边沿,第五次9+1 个有效边沿,第六次6+1个有效边沿,第七次7+1个有效边沿,第八 次8+1个有效边沿,第九次9+1个有效边沿,第十次6+1个有效边 沿.......往复循环

2. 相关函数

  • __HAL_TIM_ENABLE_IT(&tim3, TIM_IT_TRIGGER); 手动打开中断
  • HAL_TIM_Base_Start_DMA(&tim4); 打开定时器(DMA方式)

3. 程序

time.c

#include "stm32f1xx_hal.h"
#include "time.h"TIM_HandleTypeDef tim1; //定时器结构体
TIM_HandleTypeDef tim2; 
TIM_HandleTypeDef tim3; 
TIM_HandleTypeDef tim4; DMA_HandleTypeDef tim1_dmaup;   //DMA通道配置结构体
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;TIM_ClockConfigTypeDef tim1_clock;  //时钟配置结构体
TIM_ClockConfigTypeDef tim2_clock;
TIM_ClockConfigTypeDef tim3_clock;
TIM_ClockConfigTypeDef tim4_clock;uint16_t tim1_dmaBuff[4] = {6, 7, 8, 9};
uint16_t tim2_dmaBuff[4] = {6, 7, 8, 9};
uint16_t tim3_dmaBuff[4] = {6, 7, 8, 9};
uint16_t tim4_dmaBuff[4] = {6, 7, 8, 9};//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{tim1.Instance = TIM1;                                        // 实例tim1.Init.Period = arr;                                      // 重装载值tim1.Init.Prescaler = psc;                                   // 分频系数tim1.Init.CounterMode = TIM_COUNTERMODE_UP;                  // 计数模式tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;            // 分频因子tim1.Init.RepetitionCounter = rep;                           // 重复计数值tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)HAL_TIM_Base_Init(&tim1);                       //初始化定时器__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   //手动 清除 定时器 更新事件/* 外部模式1 ETR通道  */  //PA12 下降沿 按下计数 上拉tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETRtim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED;      //ETR反向 (低电平或下降沿有效)//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED;    //ETR不反向 (高电平或上升沿有效)tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1;      //ETR的预分频器配置tim1_clock.ClockFilter = 0x03;                          //滤波(注意是外部时钟的波)HAL_TIM_ConfigClockSource(&tim1, &tim1_clock);  //初始化定时器时钟配置__HAL_TIM_ENABLE_IT(&tim1, TIM_IT_TRIGGER | TIM_IT_UPDATE); //手动打开触发中断、更新中断HAL_TIM_Base_Start_DMA(&tim1, (uint32_t* )tim1_dmaBuff, 4);   //打开定时器(DMA方式)
}//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{tim2.Instance = TIM2;tim2.Init.Period = arr; tim2.Init.Prescaler = psc;tim2.Init.CounterMode = TIM_COUNTERMODE_UP;tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim2);__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);/* 外部模式1 通道1 双边沿检测  重映射*/   //PA15 双边边沿 上拉tim2_clock.ClockSource = TIM_CLOCKSOURCE_TI1ED; //通道1 边沿检测HAL_TIM_ConfigClockSource(&tim2, &tim2_clock);  //初始化定时器时钟配置__HAL_TIM_ENABLE_IT(&tim2, TIM_IT_TRIGGER | TIM_IT_UPDATE); //手动打开触发中断、更新中断HAL_TIM_Base_Start_DMA(&tim2, (uint32_t* )tim2_dmaBuff, 4);   //打开定时器(DMA方式)
}//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{tim3.Instance = TIM3;tim3.Init.Period = arr;tim3.Init.Prescaler = psc;tim3.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; //中央对齐模式tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim3); __HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);/* 外部模式1 通道1 */ //PB4 上升沿 上拉 抬起计数tim3_clock.ClockSource = TIM_CLOCKSOURCE_TI1;             // 通道1tim3_clock.ClockPolarity = TIM_CLOCKPOLARITY_RISING;      // 上升沿tim3_clock.ClockFilter = 0x03;                            // 滤波HAL_TIM_ConfigClockSource(&tim3, &tim3_clock);  //初始化定时器时钟配置__HAL_TIM_ENABLE_IT(&tim3, TIM_IT_TRIGGER | TIM_IT_UPDATE); //手动打开触发中断、更新中断HAL_TIM_Base_Start_DMA(&tim3, (uint32_t* )tim3_dmaBuff, 4);   //打开定时器(DMA方式)
}//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{tim4.Instance = TIM4;tim4.Init.Period = arr;tim4.Init.Prescaler = psc;tim4.Init.CounterMode = TIM_COUNTERMODE_UP;tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim4); __HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);/* 外部模式1 通道2 */ //PB7 下降沿 上拉 按下计数tim4_clock.ClockSource = TIM_CLOCKSOURCE_TI2;             // 通道2tim4_clock.ClockPolarity = TIM_CLOCKPOLARITY_FALLING;     // 下降沿tim4_clock.ClockFilter = 0x03;                            // 滤波HAL_TIM_ConfigClockSource(&tim4, &tim4_clock);  //初始化定时器时钟配置__HAL_TIM_ENABLE_IT(&tim4, TIM_IT_TRIGGER | TIM_IT_UPDATE); //手动打开触发中断、更新中断HAL_TIM_Base_Start_DMA(&tim4, (uint32_t* )tim4_dmaBuff, 4);   //打开定时器(DMA方式)
}//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{GPIO_InitTypeDef GPIO_InitType;if(htim->Instance == TIM1){__HAL_RCC_TIM1_CLK_ENABLE();                //使能时钟/* 定时器1 外部模式1 ETR通道IO */__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitType.Pin = GPIO_PIN_12;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //低电平按下,上拉HAL_GPIO_Init(GPIOA,&GPIO_InitType);HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0);   //配置、打开 更新中断HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);HAL_NVIC_SetPriority(TIM1_TRG_COM_IRQn, 3, 0);   //配置、打开 触发中断HAL_NVIC_EnableIRQ(TIM1_TRG_COM_IRQn);/* DMA配置 */__HAL_RCC_DMA1_CLK_ENABLE();tim1_dmaup.Instance = DMA1_Channel5;    tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;   //存储区到外设tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE;           //存储区递增tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;       //外设不递增tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //半字 2字节tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;tim1_dmaup.Init.Mode = DMA_NORMAL;      //单次模式//tim2_dmaup.Init.Mode = DMA_CIRCULAR;    //循环模式tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;  __HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);HAL_DMA_Init(&tim1_dmaup);HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0);   //配置、打开 通道5的中断HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);}else if(htim->Instance == TIM2){__HAL_RCC_TIM2_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_AFIO_CLK_ENABLE();__HAL_AFIO_REMAP_TIM2_ENABLE();//__HAL_AFIO_REMAP_TIM2_PARTIAL_1(); //(同样的功能)__HAL_AFIO_REMAP_SWJ_NOJTAG();/* 定时器2 外部模式1 通道1 重映射*///GPIO_InitType.Pin = GPIO_PIN_0;GPIO_InitType.Pin = GPIO_PIN_15;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //低电平按下,上拉HAL_GPIO_Init(GPIOA,&GPIO_InitType);HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM2_IRQn);/* DMA配置 */__HAL_RCC_DMA1_CLK_ENABLE();tim2_dmaup.Instance = DMA1_Channel2;    tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;tim1_dmaup.Init.Mode = DMA_NORMAL;      //单次模式//tim2_dmaup.Init.Mode = DMA_CIRCULAR;    //循环模式tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; __HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);HAL_DMA_Init(&tim2_dmaup);HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0);   //配置、打开 通道5的中断HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);}else if(htim->Instance == TIM3){__HAL_RCC_TIM3_CLK_ENABLE();//__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_AFIO_CLK_ENABLE();__HAL_AFIO_REMAP_TIM3_PARTIAL();    //部分映射__HAL_AFIO_REMAP_SWJ_NONJTRST();    //完全SW+JATG 但没有NJTRST/* 定时器3 外部模式1 通道1 重映射*///GPIO_InitType.Pin = GPIO_PIN_6;GPIO_InitType.Pin = GPIO_PIN_4;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //低电平按下,上拉HAL_GPIO_Init(GPIOB,&GPIO_InitType);HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM3_IRQn);/* DMA配置 */__HAL_RCC_DMA1_CLK_ENABLE();tim3_dmaup.Instance = DMA1_Channel3;    tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;tim1_dmaup.Init.Mode = DMA_NORMAL;      //单次模式//tim2_dmaup.Init.Mode = DMA_CIRCULAR;    //循环模式tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; __HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);HAL_DMA_Init(&tim3_dmaup);HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0);   //配置、打开 通道5的中断HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);}else if(htim->Instance == TIM4){__HAL_RCC_TIM4_CLK_ENABLE();/* 定时器4 外部模式1 通道2 */__HAL_RCC_GPIOB_CLK_ENABLE();GPIO_InitType.Pin = GPIO_PIN_7;GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;GPIO_InitType.Pull = GPIO_PULLUP;           //低电平按下,上拉HAL_GPIO_Init(GPIOB, &GPIO_InitType);HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM4_IRQn);/* DMA配置 */__HAL_RCC_DMA1_CLK_ENABLE();tim4_dmaup.Instance = DMA1_Channel7;    tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;tim1_dmaup.Init.Mode = DMA_NORMAL;      //单次模式//tim2_dmaup.Init.Mode = DMA_CIRCULAR;    //循环模式tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM; __HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);HAL_DMA_Init(&tim4_dmaup);HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0);   //配置、打开 通道5的中断HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);}
}//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){__HAL_RCC_TIM1_CLK_DISABLE();}else if(htim->Instance == TIM2){__HAL_RCC_TIM2_CLK_DISABLE();}else if(htim->Instance == TIM3){__HAL_RCC_TIM3_CLK_DISABLE();}else if(htim->Instance == TIM4){__HAL_RCC_TIM4_CLK_DISABLE();}    
}//更新中断  回调函数(同时也是DMA完成的回调函数)uint16_t time1 = 1; uint16_t time2 = 1; uint16_t time3 = 1;uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{    if(htim->Instance == TIM1){/* 判断DMA的状态是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 */if(htim->hdma[TIM_DMA_ID_UPDATE]->State  == HAL_DMA_STATE_READY){U1_Printf("DMA1 完成中断\\r\\n");HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]);           //关闭DMA}else{U1_Printf("定时器 1 更新事件\\r\\n");}}else if(htim->Instance == TIM2){if(htim->hdma[TIM_DMA_ID_UPDATE]->State  == HAL_DMA_STATE_READY){U1_Printf("DMA2 完成中断\\r\\n");HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]);           //关闭DMA}else{U1_Printf("定时器 2 更新事件\\r\\n");}}else if(htim->Instance == TIM3){if(htim->hdma[TIM_DMA_ID_UPDATE]->State  == HAL_DMA_STATE_READY){U1_Printf("DMA3 完成中断\\r\\n");HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]);           //关闭DMA}else{U1_Printf("定时器 3 更新事件\\r\\n");}}else if(htim->Instance == TIM4){if(htim->hdma[TIM_DMA_ID_UPDATE]->State  == HAL_DMA_STATE_READY){U1_Printf("DMA4 完成中断\\r\\n");HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]);           //关闭DMA}else{U1_Printf("定时器 4 更新事件\\r\\n");}}
}//触发中断 回调函数
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){U1_Printf("定时器 1 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim));  //输出当前计数值}else if(htim->Instance == TIM2){U1_Printf("定时器 2 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim));  //输出当前计数值}else if(htim->Instance == TIM3){U1_Printf("定时器 3 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim));  //输出当前计数值}else if(htim->Instance == TIM4){U1_Printf("定时器 4 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim));  //输出当前计数值}}//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){U1_Printf("定时器 1 DMA半完成中断\\r\\n");}else if(htim->Instance == TIM2){U1_Printf("定时器 2 DMA半完成中断\\r\\n");}else if(htim->Instance == TIM3){U1_Printf("定时器 3 DMA半完成中断\\r\\n");}else if(htim->Instance == TIM4){U1_Printf("定时器 4 DMA半完成中断\\r\\n");}
}

time.h

#ifndef __TIME_H
#define __TIME_H#include "uart.h"/* 对外声明总控结构体 */
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;/* 初始化函数 */
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);#endif

main.c

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
#include "time.h"int main(void){HAL_Init();RccClock_Init();U1_Init(921600);Timer1_Init(5 - 1, 0, 1 - 1);         //5次有效边沿Timer2_Init(5 - 1, 0);   // 5次Timer3_Init(5 - 1, 0);   // 5次Timer4_Init(5 - 1, 0);   // 5次U1_Printf("初始化完成\\r\\n");while(1){}
}

stm32f1xx_it.c

/*-------------------------------------------------*/
/*                                                 */
/*          实现各种中断服务函数的源文件           */
/*                                                 */
/*-------------------------------------------------*/#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h"
#include "uart.h"
#include "time.h"void EXTI15_10_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
void EXTI0_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void USART1_IRQHandler(void)
{HAL_UART_IRQHandler(&uart1.uart);if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){__HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);uart1.RxCounter += (U1_RX_MAX - __HAL_DMA_GET_COUNTER(&uart1.dmarx));HAL_UART_AbortReceive_IT(&uart1.uart);}
}
void USART2_IRQHandler(void)
{HAL_UART_IRQHandler(&uart2.uart);if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){__HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));HAL_UART_AbortReceive_IT(&uart2.uart);}
}
void USART3_IRQHandler(void)
{HAL_UART_IRQHandler(&uart3.uart);if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){__HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));HAL_UART_AbortReceive_IT(&uart3.uart);}
}
void DMA1_Channel4_IRQHandler(void)
{HAL_DMA_IRQHandler(&uart1.dmatx);
}
//void DMA1_Channel5_IRQHandler(void)
//{
//    HAL_DMA_IRQHandler(&uart1.dmarx);
//}
//void DMA1_Channel7_IRQHandler(void)
//{
//    HAL_DMA_IRQHandler(&uart2.dmatx);
//}
void DMA1_Channel6_IRQHandler(void)
{HAL_DMA_IRQHandler(&uart2.dmarx);
}
//void DMA1_Channel2_IRQHandler(void)
//{
//    HAL_DMA_IRQHandler(&uart3.dmatx);
//}
//void DMA1_Channel3_IRQHandler(void)
//{
//    HAL_DMA_IRQHandler(&uart3.dmarx);
//}void TIM1_UP_IRQHandler(void)
{HAL_TIM_IRQHandler(&tim1);
}
void TIM1_TRG_COM_IRQHandler(void)
{HAL_TIM_IRQHandler(&tim1);
}
void DMA1_Channel5_IRQHandler(void)
{HAL_DMA_IRQHandler(&tim1_dmaup);
}void TIM2_IRQHandler(void)
{HAL_TIM_IRQHandler(&tim2);
}
void DMA1_Channel2_IRQHandler(void)
{HAL_DMA_IRQHandler(&tim2_dmaup);
}void TIM3_IRQHandler(void)
{HAL_TIM_IRQHandler(&tim3);
}
void DMA1_Channel3_IRQHandler(void)
{HAL_DMA_IRQHandler(&tim3_dmaup);
}void TIM4_IRQHandler(void)
{HAL_TIM_IRQHandler(&tim4);
}
void DMA1_Channel7_IRQHandler(void)
{HAL_DMA_IRQHandler(&tim4_dmaup);
}/*-------------------------------------------------*/
/*函数名:不可屏蔽中断处理函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void NMI_Handler(void)
{}/*-------------------------------------------------*/
/*函数名:硬件出错后进入的中断处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void HardFault_Handler(void)
{}
/*-------------------------------------------------*/
/*函数名:软中断,SWI 指令调用的处理函数           */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SVC_Handler(void)
{}
/*-------------------------------------------------*/
/*函数名:可挂起的系统服务处理函数                 */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void PendSV_Handler(void)
{}
/*-------------------------------------------------*/
/*函数名:SysTic系统嘀嗒定时器处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SysTick_Handler(void)
{  HAL_IncTick();	
}

七、HAL库:TIM12 外部模式2 循环 中断 DMA方式 按键计数

具体方式与外模1类似,但是需要注意一下 两 点:

  1. 外部模式2并没有触发中断

    可以看到外部模式1 有TIF触发事件的产生

    但是外部模式2并没有

  2. 外部模式2仅支持ETR通道

    • STMF103C8T6只有TIM 1 2 有ERT通道

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

谷歌浏览器的自动翻译功能如何开启

在当今全球化的网络环境中,能够流畅地浏览不同语言的网页是至关重要的。谷歌浏览器(Google Chrome)提供了一项强大的自动翻译功能,可以帮助用户轻松跨越语言障碍。本文将详细介绍如何开启和使用谷歌浏览器的自动翻译功能&#xff…

【大数据技术基础 | 实验十】Hive实验:部署Hive

文章目录 一、实验目的二、实验要求三、实验原理四、实验环境五、实验内容和步骤(一)安装部署(二)配置HDFS(三)启动Hive 六、实验结果(一)启动结果(二)Hive基…

使用 Vue 配合豆包MarsCode 实现“小恐龙酷跑“小游戏

作者:BLACK595 “小恐龙酷跑”,它是一款有趣的离线游戏,是Google给Chrome浏览器加的一个有趣的彩蛋。当我们浏览器断网时一只像素小恐龙便会出来提示断网。许多人认为这只是一个可爱的小图标, 但当我们按下空格后,小恐…

案例精选 | 河北省某检察院安全运营中异构日志数据融合的实践探索

河北省某检察院是当地重要的法律监督机构,肩负着维护法律尊严和社会公平正义的重要职责。该机构依法独立行使检察权,负责对犯罪行为提起公诉,并监督整个诉讼过程,同时积极参与社会治理,保护公民权益,推动法…

7天用Go从零实现分布式缓存GeeCache(学习)(3)

目录结构 ├── geecache │ ├── byteview.go │ ├── cache.go │ ├── consistenthash │ │ ├── consistenthash.go │ │ └── consistenthash_test.go │ ├── geecache.go │ ├── go.mod │ ├── http.go │ ├── lru │ …

力扣 LeetCode 142. 环形链表II(Day2:链表)

解题思路&#xff1a; 使用set判断是否重复添加&#xff0c;如果set加入不进去证明之前到达过该节点&#xff0c;有环 public class Solution {public ListNode detectCycle(ListNode head) {Set<ListNode> set new HashSet<>();ListNode cur head;while (cur …

CLion配置QT开发环境

一、将qmake工程转为cmake工程&#xff08;方法一&#xff1a;用工具转换并做适当修改&#xff09; 1、工具链接&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1grW2QY3sW8X2JaHWM_ePPw 提取码&#xff1a;7at4 工具源码:https://github.com/milahu/qmake2cmake 2、执行…

《AI 使生活更美好》

《AI 使生活更美好》 当我们步入科技腾飞的时代&#xff0c;人工智能&#xff08;AI&#xff09;如同一颗璀璨的新星&#xff0c;照亮了我们生活的每一个角落。它以惊人的速度改变着我们的世界&#xff0c;从医疗到教育&#xff0c;从交通到娱乐&#xff0c;AI 正以前所未有的力…

项目模块十七:HttpServer模块

一、项目模块设计思路 目的&#xff1a;实现HTTP服务器搭建 思想&#xff1a;设计请求路由表&#xff0c;记录请求方法与对应业务的处理函数映射关系。用户实现请求方法和处理函数添加到路由表&#xff0c;服务器只接受请求并调用用户的处理函数即可。 处理流程&#xff1a; …

ODOO学习笔记(1):ODOO的SWOT分析和技术优势是什么?

ODOO是一款开源的企业管理软件套件&#xff0c;广泛应用于企业管理中。它由比利时的Odoo S.A.公司开发&#xff0c;最初名为OpenERP&#xff0c;现在已经成为全球流行的ERP解决方案之一。ODOO集成了ERP、CRM、电子商务和CMS等多种功能模块&#xff0c;适用于各种规模的企业应用…

出海攻略,如何一键保存Facebook视频素材

提词宝&#xff1a;快速保存Facebook视频教程 目标人群与痛点 目标人群&#xff1a;经常在Facebook上浏览视频但不知道如何保存的用户&#xff0c;包括学生、内容创作者、营销从业者&#xff0c;以及需要保存重要视频素材的人。 痛点与场景&#xff1a; 看到喜欢的视频&…

【Playwright + Python】系列(十)利用 Playwright 完美处理 Dialogs 对话框

哈喽&#xff0c;大家好&#xff0c;我是六哥&#xff01;今天我来给大家分享一下如何使用playwight处理Dialogs对话框&#xff0c;面向对象为功能测试及零基础小白&#xff0c;这里我尽量用大白话的方式举例讲解&#xff0c;力求所有人都能看懂&#xff0c;建议大家先收藏&…

LLM - 使用 LLaMA-Factory 微调大模型 Qwen2-VL SFT(LoRA) 图像数据集 教程 (2)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/143725947 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 LLaMA-…

自动驾驶3D目标检测综述(一)

文章地址&#xff1a;[2206.09474] 3D Object Detection for Autonomous Driving: A Comprehensive Survey (arxiv.org) 这篇综述简单易懂&#xff0c;非常合适对自动驾驶和3D目标检测感兴趣的小白阅读&#xff0c;对相关算法进行初步理解。 目录 一、摘要 &#xff08;一&a…

回归分析学习

学习视频链接&#xff1a; 【回归分析,一套搞定】&#xff01;全网最通俗易懂的回归分析教程&#xff0c;我终于学明白了&#xff01;_哔哩哔哩_bilibili 相关分析&#xff1a;2个或两个以上的变量之间的相关程度及大小的统计方法&#xff1b; 回归分析&#xff1a;存在相关关…

LabVIEW 实现 find_nearest_neighbors 功能(二维平面上的最近邻查找)

1. 背景介绍 在数据分析和图像处理领域&#xff0c;经常需要查找给定点的最近邻居点。在LabVIEW中&#xff0c;计算二维平面上多个点之间的欧氏距离&#xff0c;并返回距离最近的几个点是一种常见操作。find_nearest_neighbors 函数用于实现这个功能。 2. 欧氏距离计算 在二维…

后端:Aop 面向切面编程

文章目录 1. Aop 初步学习面向切面编程&#xff0c;EnableAspectJAutoProxy2. AOP的核心概念3. 前置通知&#xff08;Before&#xff09;4. 后置通知&#xff08;After&#xff09;5. 返回通知&#xff08;AfterReturning&#xff09;6. 异常通知&#xff08;AfterThrowing&…

无插件H5播放器EasyPlayer.js网页web无插件播放器vue和react详细介绍

EasyPlayer.js H5播放器&#xff0c;是一款能够同时支持HTTP、HTTP-FLV、HLS&#xff08;m3u8&#xff09;、WS、WEBRTC、FMP4视频直播与视频点播等多种协议&#xff0c;支持H.264、H.265、AAC、G711A、Mp3等多种音视频编码格式&#xff0c;支持MSE、WASM、WebCodec等多种解码方…

管家婆财贸ERP BB045.销售批量收款

最低适用版本: 财贸系列 22.8 插件简要功能说明: 销售类单据支持批量收款,简化收款做单流程更多细节描述见下方详细文档插件操作视频: 进销存类定制插件--销售批量收款 插件详细功能文档: 1. 应用中心增加菜单【销售批量收款】 a. 参考23.0应用中心-移动管理-物联宝-【…

基于MATLAB+opencv人脸疲劳检测

我们可以通过多种方式从现实世界中获取数字图像&#xff0c;比如&#xff1a;数码相机、扫描仪、计算机扫描和磁共振成像等等。在这些情况中&#xff0c;虽然我们肉眼看到的是图像&#xff0c;但是当需要将图像在数字设备中变换传输时&#xff0c;图像的每个像素则对应一个数值…