超子物联网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
  • **通道 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  =  4s
    Timer2_Init(30000 - 1, 7200 - 1);   // 3s
    Timer3_Init(20000 - 1, 7200 - 1);   // 2s
    Timer4_Init(10000 - 1, 7200 - 1);   // 1s

    uint16_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  =  4s
    Timer2_Init(30000 - 1, 7200 - 1);   // 3s
    Timer3_Init(20000 - 1, 7200 - 1);   // 2s
    Timer4_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  =  1s
    Timer2_Init(10000 - 1, 7200 - 1);   // 1s
    Timer3_Init(10000 - 1, 7200 - 1);   // 1s
    Timer4_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  =  1s
    Timer2_Init(10000 - 1, 7200 - 1);   // 1s
    Timer3_Init(10000 - 1, 7200 - 1);   // 1s
    Timer4_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++);
//        }
    }
}
        

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

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

相关文章

ubuntu20.04_从零LOD-3DGS的复现

环境要求 dependencies:- cudatoolkit11.6- plyfile0.8.1- python3.7.13- pip22.3.1- pytorch1.12.1- torchaudio0.12.1- torchvision0.13.1- tqdm1. 安装conda创建环境 conda create -n lod-3dgs python3.7.132. 安装CUDA11.6和相应cuDNN。 2.1 CUDA CUDA安装参考CUDA10.1…

Springboot 启动端口占用如何解决

Springboot 启动端口占用如何解决 1、报错信息如下 *************************** APPLICATION FAILED TO START ***************************Description:Web server failed to start. Port 9010 was already in use.Action:Identify and stop the process thats listening o…

Python注意力机制Attention下CNN-LSTM-ARIMA混合模型预测中国银行股票价格|附数据代码...

全文链接:https://tecdat.cn/?p38195 股票市场在经济发展中占据重要地位。由于股票的高回报特性,股票市场吸引了越来越多机构和投资者的关注。然而,由于股票市场的复杂波动性,有时会给机构或投资者带来巨大损失。考虑到股票市场的…

论文笔记 SuDORMRF:EFFICIENT NETWORKS FOR UNIVERSAL AUDIO SOURCE SEPARATION

SUDORMRF: EFFICIENT NETWORKS FOR UNIVERSAL AUDIO SOURCE SEPARATION 人的精神寄托可以是音乐,可以是书籍,可以是运动,可以是工作,可以是山川湖海,唯独不可以是人。 Depthwise Separable Convolution 深度分离卷积&a…

【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】

在 Kubernetes 中,NodePort 类型的 Service 允许用户通过每个节点的 IP 地址和指定的端口访问应用程序。如果 NodePort 类型的 Service 无法通过节点的 IP 地址和指定端口进行访问,可能会导致用户无法访问应用。本文将详细分析该问题的常见原因及其解决方…

Fiddler安装配置+抓包手机

1.下载安装(汉化版) 链接:https://pan.baidu.com/s/1Xgw66UbV-lVV--BJmwEKOw?pwdybww 提取码:ybww 2. HTTPS设置 3.connection设置 4.使用fiddler对手机进行抓包 前提:先打开fiddler,手机和电脑连接同一…

【专题】计算机网络之网络层

1. 网络层的几个重要概念 1.1 网络层提供的两种服务 (1) 让网络负责可靠交付 计算机网络模仿电信网络,使用面向连接的通信方式。 通信之前先建立虚电路 VC (Virtual Circuit) (即连接),以保证双方通信所需的一切网络资源。 如果再使用可靠传输的网络…

高亚科技签约美妥维志化工,提升业务协同与项目运营效率

近日,中国企业管理软件资深服务商高亚科技与韶关美妥维志化工有限公司(以下简称“美妥维志”)正式签约。基于高亚科技的8Manage PM项目管理软件,美妥维志将实现项目进度、人员审批及问题的统一管理,提升部门间协同效率…

《双城之战》,活成了王者荣耀最羡慕的模样

11月9日,《双城之战》第二季开播,延续了第一季的好口碑,目前该剧集在豆瓣平台荣获9.2分高分,同时在烂番茄平台也收获了100%的好评率,可以说是赢得了国内外观众的一致认可。 与第一季因剧集热度带动游戏市场爆火而略显…

Spring Cloud Eureka 服务注册与发现

Spring Cloud Eureka 服务注册与发现 一、Eureka基础知识概述1.Eureka两个核心组件2.Eureka 服务注册与发现 二、Eureka单机搭建三、Eureka集群搭建四、心跳续约五、Eureka自我保护机制 一、Eureka基础知识概述 1.Eureka两个核心组件 Eureka Server :服务注册中心…

告别系统限制,一键关闭Windows Defender

作为一款专业级系统优化工具,Defender Remover 为追求完全系统控制权的高级用户提供了全方位的安全组件管理解决方案。这款强大的实用工具不仅完美支持从 Windows 8.x 到最新的 Windows 11 全系列操作系统,更提供了精细化的安全组件调整选项。 本工具最…

GitLab 如何降级?

本分分享 GitLab 降级的流程和注意事项。极狐GitLab 为 GitLab 的中文发行版,本文以私有化部署的极狐GitLab 为例来演示整个过程。 【极狐GitLab 推出 GitLab 老旧版本的专业升级服务【https://dl.gitlab.cn/cm33bsfv】,可以让 12.x、13.x、14.x、15.x …

微软日志丢失事件敲响安全警钟

NEWS | 事件回顾 最近,全球最大的软件公司之一——微软,遭遇了一场罕见的日志丢失危机。据报告,从9月2日至9月19日,持续长达两周的时间里,微软的多项核心云服务,包括身份验证平台Microsoft Entra、安全信息…

leetcode268 丢失的数字

class Solution { public:int missingNumber(vector<int>& nums) {sort(nums.begin(),nums.end());int i0;for(;i<nums.size();i){if(i!nums[i]) break;}return i;} }; sort(nums.begin(), nums.end()); 对数组进行排序。虽然排序是一个可行的方法&#xff0c;但是…

HBuilder(uniapp) 配置android模拟器

HBuilder&#xff08;uniapp&#xff09; 配置android模拟器 选择完成之后&#xff0c;点击ok&#xff0c;再次点击Configure—》AVD Manager

Redis高可用-主从复制

这里写目录标题 Redis主从复制主从复制过程环境搭建从节点配置常见问题主从模式缺点 Redis主从复制 虽然 Redis 可以实现单机的数据持久化&#xff0c;但无论是 RDB 也好或者 AOF 也好&#xff0c;都解决不了单点宕机问题&#xff0c;即一旦 redis 服务器本身出现系统故障、硬…

Vue3 -- 项目配置之husky【企业级项目配置保姆级教程4】

引言&#xff1a; eslint&#xff1a;代码规范校验prettier&#xff1a;代码格式化stylelint&#xff1a;CSS代码校验 上述三篇文章集成配置完成代码校验工具&#xff0c;当时需要每次手动的去执行命令才会格式化我们的代码。。如果有人没有格式化就提交了远程仓库&#xff0…

PaddlePaddle 开源产业级文档印章识别PaddleX-Pipeline “seal_recognition”模型 开箱即用篇(一)

AI时代到来&#xff0c;各行各业都在追求细分领域垂直类深度学习模型&#xff0c;今天给大家介绍一个PaddlePaddle旗下&#xff0c;基于PaddleX Pipeline 来完成印章识别的模型“seal_recognition”。 官方地址&#xff1a;https://github.com/PaddlePaddle/PaddleX/blob/relea…

06.VSCODE:备战大项目,CMake专项配置

娇小灵活的简捷配置不过是年轻人谈情说爱的玩具&#xff0c;帝国大厦的构建&#xff0c;终归要交给CMake去母仪天下。一个没有使用 CMake 的 C 项目&#xff0c;就像未来世界里的一台相声表演&#xff0c;有了德纲却无谦&#xff0c;观众笑着遗憾。—— 语出《双城记》作者&…

新高考志愿录取方式变革,如何应对挑战?答案在这里

在教育改革的浪潮中&#xff0c;新高考的实施带来了重大变革&#xff0c;其中志愿录取方式的变化尤为关键。它不仅关系着每一位考生的未来发展&#xff0c;更是对整个教育体系产生着深远影响。今天&#xff0c;我们就来深入探讨新高考的两大志愿录取方式&#xff0c;分析其特点…