超子物联网HAL库笔记:定时器[基础定时]篇

devtools/2024/11/12 21:08:37/

超子物联网 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
  • **通道 3:**PA10、 DMA1_Channel6
  • **通道 4:**PA11、 DMA1_Channel4
  • **通道 ETR:**PA12

  • 刹车: PB12、PA6(重映射)
  • 通道 1 互补:PB13、PA7(重映射)
  • 通道 2 互补:PB14、PB0(重映射)
  • 通道 3 互补:PB15、PB1(重映射)

定时器 2 通道

  • 通道 1:PA0(重映射 PA15)、PA1(重映射 PB3)
  • 通道 2:PA2(重映射 PB10)
  • 通道 3:DMA1_Channel5、DMA1_Channel7、DMA1_Channel1、DMA1_Channel7
  • 通道 4:PA3(重映射 PB11)
  • 通道 ETR:PA0(重映射 PA15)

定时器 3 通道

  • 通道 1:PA6(重映射 PB4)、DMA1_Channel6、DMA1_Channel2、DMA1_Channel3
  • 通道 2:PA7(重映射 PB5)
  • 通道 3:PB0
  • 通道 4:PB1
  • 通道 ETR:无

定时器 4 通道

  • 通道1:PB6 DMA1 Channel1
  • 通道2:PB7 DMA1 Channel4
  • 通道3:PB8 DMA1 Channel5
  • 通道4:PB9
  • 通道ETR:无

二、HAL库:TIM1234轮询方式 基础定时

1. 相关函数

  • TIM_HandleTypeDef 定时器总控结构体

  • HAL_TIM_Base_Init(&tim3); 轮询 初始化定时器

  • __HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE); 清除更新标志位

  • HAL_TIM_Base_Start(&tim3); 开启定时器

  • void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim) 定时器DeInit回调函数

  • 基础的初始化

  • void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim) 定时器Init回调函数

  • 基础的初始化

    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);   //手动清除更新事件HAL_TIM_Base_Start(&tim1);                      //打开定时器(轮询方式)
    }
    
  • 主循环while判断

    if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   ///清除标志位U1_Printf("定时器 1 定时时间:%d\\r\\n",time1++);}
    

2. 程序

time.c

#include "stm32f1xx_hal.h"
#include "time.h"TIM_HandleTypeDef tim1; //(高级)定时器1总控结构体
TIM_HandleTypeDef tim2; 
TIM_HandleTypeDef tim3; 
TIM_HandleTypeDef tim4; //定时器 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);   //手动清除更新事件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_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_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_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);HAL_TIM_Base_Start(&tim4);
}//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){__HAL_RCC_TIM1_CLK_ENABLE();}else if(htim->Instance == TIM2){__HAL_RCC_TIM2_CLK_ENABLE();}else if(htim->Instance == TIM3){__HAL_RCC_TIM3_CLK_ENABLE();}else if(htim->Instance == TIM4){__HAL_RCC_TIM4_CLK_ENABLE();}
}//定时器 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_TIM1_CLK_DISABLE();}else if(htim->Instance == TIM3){__HAL_RCC_TIM1_CLK_DISABLE();}else if(htim->Instance == TIM4){__HAL_RCC_TIM1_CLK_DISABLE();}
}

time.h

#ifndef __TIME_H
#define __TIME_H/* 对外声明总控结构体 */
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;/* 初始化函数 */
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(20000 - 1, 3600 - 1, 4 - 1);   // 72000000/3600/20000 = 1   *   4  =  4sTimer2_Init(30000 - 1, 7200 - 1);   // 3sTimer3_Init(20000 - 1, 7200 - 1);   // 2sTimer4_Init(10000 - 1, 7200 - 1);   // 1suint16_t time1 = 1;uint16_t time2 = 1;uint16_t time3 = 1;uint16_t time4 = 1;while(1){/* 获取更新标志位 */if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   ///清除标志位U1_Printf("定时器 1 定时时间:%d\\r\\n",time1++);if(time1 > 5){U1_Printf("定时器 1 关闭\\r\\n"); HAL_TIM_Base_Stop(&tim1);       //停止定时器HAL_TIM_Base_DeInit(&tim1);     //释放}}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_TIM_Base_Init(&tim1); 初始化定时器基础配置函数中 TIM_Base_SetConfig 函数中的最后一行: TIMx->EGR = TIM_EGR_UG; 这里HAL库人为的 更新了一下EGR寄存器的Ug位,也就是事件产生寄存器为1。

为什么要在初始化的时候更新一下事件:

原因是因为 定时器中的 PSC 和重复计数器Rep(这个是高级定时器才有)

只有在一次更新事件之后才会彻底写入(影子寄存器)

ARR虽然也有影子寄存器。但是他不管是在关闭还是开启的状态下,只要设置就能直接转正(写入)。

如何避免复位后直接产生更新事件?

在Start之前,手动清除UIF位

四、HAL库:TIM1234中断方式 基础定时

在轮询基础上,配置和开启了中断。

这里需要大概知道 需要定义 定时器的更新回调函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

注意开启定时器使用挂it方式的就ok ..

然后在对应的中断函数中处理就ok

2. 程序

time.c

#include "stm32f1xx_hal.h"
#include "time.h"TIM_HandleTypeDef tim1; //(高级)定时器1总控结构体
TIM_HandleTypeDef tim2; 
TIM_HandleTypeDef tim3; 
TIM_HandleTypeDef tim4; //定时器 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);   //手动清除更新事件HAL_TIM_Base_Start_IT(&tim1);                   //打开定时器(IT方式)
}//定时器 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_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_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_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);HAL_TIM_Base_Start_IT(&tim4);
}//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){__HAL_RCC_TIM1_CLK_ENABLE();                //使能时钟HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0);   //配置、打开 更新中断HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);}else if(htim->Instance == TIM2){__HAL_RCC_TIM2_CLK_ENABLE();HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM2_IRQn);}else if(htim->Instance == TIM3){__HAL_RCC_TIM3_CLK_ENABLE();HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM3_IRQn);}else if(htim->Instance == TIM4){__HAL_RCC_TIM4_CLK_ENABLE();HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);HAL_NVIC_EnableIRQ(TIM4_IRQn);}
}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){U1_Printf("定时器 1 定时时间:%d\\r\\n",time1++);}else if(htim->Instance == TIM2){U1_Printf("定时器 2 定时时间:%d\\r\\n",time2++);}else if(htim->Instance == TIM3){U1_Printf("定时器 3 定时时间:%d\\r\\n",time3++);}else if(htim->Instance == TIM4){U1_Printf("定时器 4 定时时间:%d\\r\\n",time4++);}
}//定时器 硬件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();}    }

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;/* 初始化函数 */
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

stm32f1xx_it.c

/*-------------------------------------------------*/
/*                                                 */
/*          实现各种中断服务函数的源文件           */
/*                                                 */
/*-------------------------------------------------*/#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h"
#include "uart.h"
#include "time.h"//定时器相关
void TIM1_UP_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 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 NMI_Handler(void)
{}/*-------------------------------------------------*/
/*函数名:硬件出错后进入的中断处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void HardFault_Handler(void)
{}
/*-------------------------------------------------*/
/*函数名:软中断,SWI 指令调用的处理函数           */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SVC_Handler(void)
{}
/*-------------------------------------------------*/
/*函数名:可挂起的系统服务处理函数                 */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void PendSV_Handler(void)
{}
/*-------------------------------------------------*/
/*函数名:SysTic系统嘀嗒定时器处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SysTick_Handler(void)
{  HAL_IncTick();	
}

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(20000 - 1, 3600 - 1, 4 - 1);   // 72000000/3600/20000 = 1   *   4  =  4sTimer2_Init(30000 - 1, 7200 - 1);   // 3sTimer3_Init(20000 - 1, 7200 - 1);   // 2sTimer4_Init(10000 - 1, 7200 - 1);   // 1s//    uint16_t time1 = 0;
//    uint16_t time2 = 0;
//    uint16_t time3 = 0;
//    uint16_t time4 = 0;while(1){/* 获取更新标志位 */
//        if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){
//            __HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   ///清除标志位//            U1_Printf("定时器 1 定时时间:%d\\r\\n",time1++);
//        }
//        
//        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 DMA单次方式 改变定时时间

1. 如何做到改变定时时间

更新DMA事件可以改变ARR重载值,从而改变基础定时时间

2. 实验现象

DMA单次方式,传输4次数据,改变定时时间:第一次定时1s,第二次定时2s,第三次定时3s,第四次定时4s第五次定时5s,然后以后一直都是5s

3. 注意

  1. DMA有半完成回调 和 完成回调

    • 其中完成回调,和定时器更新回调的函数是一个函数
    • 所以,如果要使用更新中断和DMA完成中断,则需要判断一下。
      • 方法:通过判断DMA的状态,如果为Busy,则说明是更新中断进入的 定时器更新回调函数
  2. DMA方式的定时器并不会开启更新中断,所以要手动打开更新中断

  3. DMA使用数 要注意通道的重复使用。避免重复。

  4. LinkDMA时,第二个参数的 外设句柄内的一个DMA句柄指针(可以理解为通道绑定),可以在这里直接看到他的所有成员。在用时,可以这样用

    • __HAL_LINKDMA(&tim1, **hdma[TIM_DMA_ID_UPDATE]**, &tim1_dmaup);
    • /* 判断DMA是否为Ready状态,如果是则是DMA完成中断进入的回调函数 */ if(htim->hdma[TIM_DMA_ID_UPDATE]->State == HAL_DMA_STATE_READY){
  5. DMA在Link TIM和DMA的某通道之后,可以直接在TIM中找到通道的配置总控结构体

4. 相关函数

  • TIM_HandleTypeDef 定时器总控结构体
  • DMA_HandleTypeDef DMA总控结构体
  • __HAL_TIM_CLEAR_FLAG ****清除标志位
  • __HAL_TIM_ENABLE_IT 使能中断
  • HAL_TIM_Base_Start_DMA DMA方式启动定时器
  • __HAL_LINKDMA DMA LINK

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;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);   //手动 清除 定时器 更新事件__HAL_TIM_ENABLE_IT(&tim1, TIM1_UP_IRQn);       //手动 使能 定时器 更新中断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);__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_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_NORMAL;  //单次模式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;     //半字 2字节tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;tim2_dmaup.Init.Mode = DMA_NORMAL;  //单次模式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;     //半字 2字节tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;tim3_dmaup.Init.Mode = DMA_NORMAL;  //单次模式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;     //半字 2字节tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;tim4_dmaup.Init.Mode = DMA_NORMAL;  //单次模式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 定时时间:%d\\r\\n",time1++);if(time1 >= 6){             //大于等于6 则关闭U1_Printf("定时器1 关闭\\r\\n");HAL_TIM_Base_Stop_DMA(htim);HAL_TIM_Base_DeInit(htim);}}}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 定时时间:%d\\r\\n",time2++);if(time2 >= 6){             //大于等于6 则关闭U1_Printf("定时器2 关闭\\r\\n");HAL_TIM_Base_Stop_DMA(htim);HAL_TIM_Base_DeInit(htim);}}}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 定时时间:%d\\r\\n",time3++);if(time3 >= 6){             //大于等于6 则关闭U1_Printf("定时器3 关闭\\r\\n");HAL_TIM_Base_Stop_DMA(htim);HAL_TIM_Base_DeInit(htim);}}}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 定时时间:%d\\r\\n",time4++);if(time4 >= 6){             //大于等于6 则关闭U1_Printf("定时器4 关闭\\r\\n");HAL_TIM_Base_Stop_DMA(htim);HAL_TIM_Base_DeInit(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

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 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();	
}

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(10000 - 1, 7200 - 1, 1 - 1);   // 72000000/7200/10000  =  1sTimer2_Init(10000 - 1, 7200 - 1);   // 1sTimer3_Init(10000 - 1, 7200 - 1);   // 1sTimer4_Init(10000 - 1, 7200 - 1);   // 1s//    uint16_t time1 = 0;
//    uint16_t time2 = 0;
//    uint16_t time3 = 0;
//    uint16_t time4 = 0;while(1){/* 获取更新标志位 */
//        if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){
//            __HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   ///清除标志位//            U1_Printf("定时器 1 定时时间:%d\\r\\n",time1++);
//        }
//        
//        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 DMA单次方式 改变定时时间

1. 实验现象

DMA循环方式,传输4次*n数据,改变定时时间:第一次定时1s(初始化),第二次定时2s,第三次定时3s,第四次定时4s第五次定时5s,然后第六次 2s,第七次3s,第八次4s,第、九次5s,第十次2s

2. 如何判断DMA中断还是更新中断*

  1. 上一小节所说:DMA有半完成回调 和 完成回调

    • 其中完成回调,和定时器更新回调的函数是一个函数
    • 所以,如果要使用更新中断和DMA完成中断,则需要判断一下。
      • 方法:通过判断DMA的状态,如果为Busy,则说明是更新中断进入的 定时器更新回调函数
  2. 那么在这一节是行不通的,**因为DMA一直在循环模式,一直处于BUSY状态,所以不能判断了。**但是 DMA的半完成中断和完成中断,在进入回调函数之前 就会把定时器设置成Ready状态,定时器更新中断 并不会设置定时器的状态为Ready。

    • 所以,着急需要判断定时器的更新中断,就可以判断这次中断是更新中断还是 DMA的中断。
    • 并且,判断过后,需要把定时器状态重新赋值为 BUSY, 这样是为了防止更新中断在进入时,仍然进入DMA完成的分支

    代码节选

    //更新中断  回调函数(同时也是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++);}}
    }
    

4. 相关函数

  • TIM_HandleTypeDef 定时器总控结构体
  • DMA_HandleTypeDef DMA总控结构体
  • __HAL_TIM_CLEAR_FLAG ****清除标志位
  • __HAL_TIM_ENABLE_IT 使能中断
  • HAL_TIM_Base_Start_DMA DMA方式启动定时器
  • __HAL_LINKDMA DMA LINK
/* 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);

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;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);   //手动 清除 定时器 更新事件__HAL_TIM_ENABLE_IT(&tim1, TIM1_UP_IRQn);       //手动 使能 定时器 更新中断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);__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_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

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 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();	
}

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(10000 - 1, 7200 - 1, 1 - 1);   // 72000000/7200/10000  =  1sTimer2_Init(10000 - 1, 7200 - 1);   // 1sTimer3_Init(10000 - 1, 7200 - 1);   // 1sTimer4_Init(10000 - 1, 7200 - 1);   // 1s//    uint16_t time1 = 0;
//    uint16_t time2 = 0;
//    uint16_t time3 = 0;
//    uint16_t time4 = 0;while(1){/* 获取更新标志位 */
//        if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){
//            __HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE);   ///清除标志位//            U1_Printf("定时器 1 定时时间:%d\\r\\n",time1++);
//        }
//        
//        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++);
//        }}
}


http://www.ppmy.cn/devtools/133053.html

相关文章

CSRF详解

CSRF,全称是Cross-Site Request Forgery,即跨站请求伪造,也被称为“one click attack”或者session riding,是一种网络攻击方式。它允许攻击者诱导用户在已登录的Web应用程序上执行非预期的操作。 工作原理CSRF攻击通常涉及三个主…

Spring Security @PreAuthorize @PostAuthorize 权限控制

PreAuthorize : 在方法执行之前进行权限验证 PostAuthorize : 在方法执行之后进行权限验证 注解参数: hasRole,对应 public final boolean hasRole(String role) 方法,含义为必须含有某角色(非ROLE_开头),如有多个的…

vue,uniapp,微信小程序解决字符串中出现数字则修改数字样式,以及获取字符串中的数字

简单记录一下,最近遇到的一个新需求:后端返回的是非富文本,只是一串字符串,其中包含了文字和数字,前端需要将出现数字的地方将其加粗或者修改颜色等需求 设计思路:(简单做个记录方便以后理解&a…

mac-泛洪

泛洪攻击的类型 TCP SYN Flood: 攻击者向目标服务器发送大量的 TCP SYN 请求,但不完成握手过程。服务器为每个请求分配资源,最终可能耗尽其连接表,导致无法处理正常请求。 UDP Flood: 攻击者向目标发送大量的 UDP 数据…

spring AOP详解

文章目录 AOP1 环境准备1.1 工程及接口创建1.2 工程存在的问题1.2.1 问题1.2.2 解决思路 2 AOP面向切面编程2.1 AOP概述2.2 AOP原理分析 3 基于注解的AOP3.1 入门示例3.2 使用流程3.3 切入点表达式3.4 练习3.5 通知类型 AOP ​ AOP(Aspect Orient Programming&…

gitlab无法创建合并请求是所有分支都不显示

点击Merge Requests ------> New merge request 创建新的合并请求时,在Source branch和Target branch中一个分支都不显示 排查思路: 1.怀疑是权限问题。 发现只有我的一个账号出现,检查了账号的权限,尝试了master、develop角色…

图像手动标注-labelme+yolo格式导出

conda环境 运行以下命令来激活你的虚拟环境: conda activate labelme如果你没有创建 labelme 环境,首先需要创建一个环境并安装 labelme: conda create -n labelme python3.8 conda activate labelme conda install -c conda-forge labelm…

React Native的生命周期

React Native 组件的生命周期分为三个阶段:Mounting(挂载)、Updating(更新) 和 Unmounting(卸载)。每个阶段都会触发不同的生命周期方法。 下面是详细的生命周期解释,并通过一个项目…