GD32F30x系列Systick系统滴答定时器
- 【0】Qt 项目效果展示
- 【1】SysTick 简介
- 【2】SysTick 寄存器
- 【3】代码配置和初始化说明
- 【3.1】core_cm4.h头文件
- 【3.2】systick.h
- 【3.3】mainwindow.h
- 【3.4】systick.cpp
- 【3.5】mainwindow.cpp [主流程]
 
本次Systick系统滴答定时器,只是在Qt平台模拟,重在学会用法
【0】Qt 项目效果展示

 
 
【1】SysTick 简介
SysTick—系统定时器是属于 CM3 或CM4内核中的一个外设,内嵌在 NVIC 中。
 系统定时器是一个 24bit 的向下递减的计数器,计数器每计数一次的时间为 1/SYSCLK,一般我们设置系统时钟 SYSCLK 等于 72MHz。
 当重装载数值寄存器的值递减到 0 的时候,系统定时器就产生一次中断,以此循环往复。
 因为 SysTick 是属于 CM3 或CM4 内核的外设,所以所有基于 CM3 或CM4内核的单片机都具有这个系统定时器, 使得软件在 CM3 单片机中可以很容易的移植。
 系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。
应用说明:
1、因systick是一个24位的定时器,故重装值最大值为2的24次方=16 777 215,要注意不要超出这个值。
2、systick是cortex_m3/4的标配,不是外设。故不需要在RCC寄存器组打开他的时钟。
3、每次systick溢出后会置位计数标志位和中断标志位,计数标志位在计数器重装载后被清除,而中断标志位也会随着中断服务程序的响应被清除,所以这两个标志位都不需要手动清除。
4、采用使用库函数的方法,只能采用中断的方法响应定时器计时时间到,如要采用查询的方法,那只能采用设置systick的寄存器的方法,具体操作以后再做分析。
【2】SysTick 寄存器


 
【3】代码配置和初始化说明
1.第一个内敛函数,修饰简短的函数 可加快编译时间 节省系统资源
2.后面两个关键字请看这篇
#define STATIC_INLINE  static __inline
#define IO    volatile
#define I     volatile const
这就是Systick系统滴答定时器基地址宏定义处
基地址:可以这么理解,如同数组的第一个元素的起始地址,偏移地址如同数组下标递增或递减,偏移到不同位置,获取不同的值,就有不同的功能,这就是寄存器的强大之处,寄存器地址的偏移,一般改变某一位,要保证其他位不变,所以离不开这些运算符(&,~,|)等
/* 内存 映射 的 Cortex-M4 硬件 */
#define SCS_BASE            (0xE000E000UL)                            /*!<系统控制空间基底地址*/
#define SysTick_BASE        (SCS_BASE +  0x0010UL)                    /*!<systick基址*/
#define NVIC_BASE           (SCS_BASE +  0x0100UL)                    /*!<NVIC 基址*/
#define SCB_BASE            (SCS_BASE +  0x0D00UL)                    /*!<系统控制块的基本地址*/
#define SCB                 ((SCB_Type       *)     SCB_BASE      )   /*!<SCB 配置结构         */
#define SysTick             ((SysTick_Type   *)     SysTick_BASE  )   /*!<SysTick configuration struct       */
#define NVIC                ((NVIC_Type      *)     NVIC_BASE     )   /*!<NVIC configuration struct          */
【3.1】core_cm4.h头文件
本次只是使用了本头文件的变量,函数没有调用,这两个函数忽略
#ifndef CORE_CM4_H
#define CORE_CM4_H
#include "systick.h"
//================================================仅供参考 本次项目未使用=============================================
#define GD32F30X_HD					1			//GD32F303ZET6属于HD,勿动
/*定义中断编号 */
typedef enum IRQn
{
    /* Cortex-M4 处理器异常编号 */
    SysTick_IRQn                 = -1,     /*!< 15 Cortex-M4 system tick interrupt                       */
    /* interruput numbers */
    WWDGT_IRQn                   = 0,      /*!< window watchDog timer interrupt                          */
    LVD_IRQn                     = 1,      /*!< LVD through EXTI line detect interrupt                   */
    TAMPER_IRQn                  = 2,      /*!< tamper through EXTI line detect                          */
    RTC_IRQn                     = 3,      /*!< RTC through EXTI line interrupt                          */
    FMC_IRQn                     = 4,      /*!< FMC interrupt                                            */
    RCU_CTC_IRQn                 = 5,      /*!< RCU_BASE and CTC interrupt                                    */
    EXTI0_IRQn                   = 6,      /*!< EXTI line 0 interrupt                                    */
    EXTI1_IRQn                   = 7,      /*!< EXTI line 1 interrupt                                    */
    EXTI2_IRQn                   = 8,      /*!< EXTI line 2 interrupt                                    */
    EXTI3_IRQn                   = 9,      /*!< EXTI line 3 interrupt                                    */
    EXTI4_IRQn                   = 10,     /*!< EXTI line 4 interrupt                                    */
    DMA0_Channel0_IRQn           = 11,     /*!< DMA0 channel0 interrupt                                  */
    DMA0_Channel1_IRQn           = 12,     /*!< DMA0 channel1 interrupt                                  */
    DMA0_Channel2_IRQn           = 13,     /*!< DMA0 channel2 interrupt                                  */
    DMA0_Channel3_IRQn           = 14,     /*!< DMA0 channel3 interrupt                                  */
    DMA0_Channel4_IRQn           = 15,     /*!< DMA0 channel4 interrupt                                  */
    DMA0_Channel5_IRQn           = 16,     /*!< DMA0 channel5 interrupt                                  */
    DMA0_Channel6_IRQn           = 17,     /*!< DMA0 channel6 interrupt                                  */
    ADC0_1_IRQn                  = 18,     /*!< ADC0 and ADC1 interrupt                                  */
#ifdef GD32F30X_HD
    USBD_HP_CAN0_TX_IRQn         = 19,     /*!< CAN0 TX interrupts                                       */
    USBD_LP_CAN0_RX0_IRQn        = 20,     /*!< CAN0 RX0 interrupts                                      */
    CAN0_RX1_IRQn                = 21,     /*!< CAN0 RX1 interrupt                                       */
    CAN0_EWMC_IRQn               = 22,     /*!< CAN0 EWMC interrupt                                      */
    EXTI5_9_IRQn                 = 23,     /*!< EXTI[9:5] interrupts                                     */
    TIMER0_BRK_IRQn              = 24,     /*!< TIMER0 break interrupt                                   */
    TIMER0_UP_IRQn               = 25,     /*!< TIMER0 update interrupt                                  */
    TIMER0_TRG_CMT_IRQn          = 26,     /*!< TIMER0 trigger and commutation interrupt                 */
    TIMER0_Channel_IRQn          = 27,     /*!< TIMER0 channel capture compare interrupt                 */
    TIMER1_IRQn                  = 28,     /*!< TIMER1 interrupt                                         */
    TIMER2_IRQn                  = 29,     /*!< TIMER2 interrupt                                         */
    TIMER3_IRQn                  = 30,     /*!< TIMER3 interrupt                                         */
    I2C0_EV_IRQn                 = 31,     /*!< I2C0 event interrupt                                     */
    I2C0_ER_IRQn                 = 32,     /*!< I2C0 error interrupt                                     */
    I2C1_EV_IRQn                 = 33,     /*!< I2C1 event interrupt                                     */
    I2C1_ER_IRQn                 = 34,     /*!< I2C1 error interrupt                                     */
    SPI0_IRQn                    = 35,     /*!< SPI0 interrupt                                           */
    SPI1_IRQn                    = 36,     /*!< SPI1 interrupt                                           */
    USART0_IRQn                  = 37,     /*!< USART0 interrupt                                         */
    USART1_IRQn                  = 38,     /*!< USART1 interrupt                                         */
    USART2_IRQn                  = 39,     /*!< USART2 interrupt                                         */
    EXTI10_15_IRQn               = 40,     /*!< EXTI[15:10] interrupts                                   */
    RTC_Alarm_IRQn               = 41,     /*!< RTC alarm interrupt                                      */
    USBD_WKUP_IRQn               = 42,     /*!< USBD Wakeup interrupt                                    */
    TIMER7_BRK_IRQn              = 43,     /*!< TIMER7 break interrupt                                   */
    TIMER7_UP_IRQn               = 44,     /*!< TIMER7 update interrupt                                  */
    TIMER7_TRG_CMT_IRQn          = 45,     /*!< TIMER7 trigger and commutation interrupt                 */
    TIMER7_Channel_IRQn          = 46,     /*!< TIMER7 channel capture compare interrupt                 */
    ADC2_IRQn                    = 47,     /*!< ADC2 global interrupt                                    */
    EXMC_IRQn                    = 48,     /*!< EXMC global interrupt                                    */
    SDIO_IRQn                    = 49,     /*!< SDIO global interrupt                                    */
    TIMER4_IRQn                  = 50,     /*!< TIMER4 global interrupt                                  */
    SPI2_IRQn                    = 51,     /*!< SPI2 global interrupt                                    */
    UART3_IRQn                   = 52,     /*!< UART3 global interrupt                                   */
    UART4_IRQn                   = 53,     /*!< UART4 global interrupt                                   */
    TIMER5_IRQn                  = 54,     /*!< TIMER5 global interrupt                                  */
    TIMER6_IRQn                  = 55,     /*!< TIMER6 global interrupt                                  */
    DMA1_Channel0_IRQn           = 56,     /*!< DMA1 channel0 global interrupt                           */
    DMA1_Channel1_IRQn           = 57,     /*!< DMA1 channel1 global interrupt                           */
    DMA1_Channel2_IRQn           = 58,     /*!< DMA1 channel2 global interrupt                           */
    DMA1_Channel3_Channel4_IRQn  = 59,     /*!< DMA1 channel3 and channel4 global Interrupt              */
#endif /* GD32F30X_HD */
} IRQn_Type;
#define STATIC_INLINE  static __inline
#define NVIC_PRIO_BITS          4        /*!<GD32F30x 优先级用4位  */
/* 内存 映射 的 Cortex-M4 硬件 */
#define SCS_BASE            (0xE000E000UL)                            /*!<系统控制空间基底地址*/
#define SysTick_BASE        (SCS_BASE +  0x0010UL)                    /*!<systick基址*/
#define NVIC_BASE           (SCS_BASE +  0x0100UL)                    /*!<NVIC 基址*/
#define SCB_BASE            (SCS_BASE +  0x0D00UL)                    /*!<系统控制块的基本地址*/
#define SCB                 ((SCB_Type       *)     SCB_BASE      )   /*!<SCB 配置结构         */
#define SysTick             ((SysTick_Type   *)     SysTick_BASE  )   /*!<SysTick configuration struct       */
#define NVIC                ((NVIC_Type      *)     NVIC_BASE     )   /*!<NVIC configuration struct          */
typedef struct
{
  IO uint32_t ISER[8];                 /*!< Offset: 0x000 (R/W)  Interrupt Set Enable Register           */
       uint32_t RESERVED0[24];
  IO uint32_t ICER[8];                 /*!< Offset: 0x080 (R/W)  Interrupt Clear Enable Register         */
       uint32_t RSERVED1[24];
  IO uint32_t ISPR[8];                 /*!< Offset: 0x100 (R/W)  Interrupt Set Pending Register          */
       uint32_t RESERVED2[24];
  IO uint32_t ICPR[8];                 /*!< Offset: 0x180 (R/W)  Interrupt Clear Pending Register        */
       uint32_t RESERVED3[24];
  IO uint32_t IABR[8];                 /*!< Offset: 0x200 (R/W)  Interrupt Active bit Register           */
       uint32_t RESERVED4[56];
  IO uint8_t  IP[240];                 /*!< Offset: 0x300 (R/W)  Interrupt Priority Register (8Bit wide) */
       uint32_t RESERVED5[644];
  IO  uint32_t STIR;                    /*!< Offset: 0xE00 ( /W)  Software Trigger Interrupt Register     */
}  NVIC_Type;
typedef struct
{
  I  uint32_t CPUID;                   /*!< Offset: 0x000 (R/ )  CPUID Base Register                                   */
  IO uint32_t ICSR;                    /*!< Offset: 0x004 (R/W)  Interrupt Control and State Register                  */
  IO uint32_t VTOR;                    /*!< Offset: 0x008 (R/W)  Vector Table Offset Register                          */
  IO uint32_t AIRCR;                   /*!< Offset: 0x00C (R/W)  Application Interrupt and Reset Control Register      */
  IO uint32_t SCR;                     /*!< Offset: 0x010 (R/W)  System Control Register                               */
  IO uint32_t CCR;                     /*!< Offset: 0x014 (R/W)  Configuration Control Register                        */
  IO uint8_t  SHP[12];                 /*!<Offset: 0x018 (R/W)  系统处理程序的优先级寄存器 (4-7, 8-11, 12-15) */
  IO uint32_t SHCSR;                   /*!< Offset: 0x024 (R/W)  System Handler Control and State Register             */
  IO uint32_t CFSR;                    /*!< Offset: 0x028 (R/W)  Configurable Fault Status Register                    */
  IO uint32_t HFSR;                    /*!< Offset: 0x02C (R/W)  HardFault Status Register                             */
  IO uint32_t DFSR;                    /*!< Offset: 0x030 (R/W)  Debug Fault Status Register                           */
  IO uint32_t MMFAR;                   /*!< Offset: 0x034 (R/W)  MemManage Fault Address Register                      */
  IO uint32_t BFAR;                    /*!< Offset: 0x038 (R/W)  BusFault Address Register                             */
  IO uint32_t AFSR;                    /*!< Offset: 0x03C (R/W)  Auxiliary Fault Status Register                       */
  I  uint32_t PFR[2];                  /*!< Offset: 0x040 (R/ )  Processor Feature Register                            */
  I  uint32_t DFR;                     /*!< Offset: 0x048 (R/ )  Debug Feature Register                                */
  I  uint32_t ADR;                     /*!< Offset: 0x04C (R/ )  Auxiliary Feature Register                            */
  I  uint32_t MMFR[4];                 /*!< Offset: 0x050 (R/ )  Memory Model Feature Register                         */
  I  uint32_t ISAR[5];                 /*!< Offset: 0x060 (R/ )  Instruction Set Attributes Register                   */
     uint32_t RESERVED0[5];
  IO uint32_t CPACR;                   /*!< Offset: 0x088 (R/W)  Coprocessor Access Control Register                   */
} SCB_Type;
#define __NVIC_PRIO_BITS          4        /*!<GD32F30x 优先级用4位*/
//SysTick_IRQn 设置中断优先级 参数:枚举值  优先级数     -1      4
STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
  if(IRQn < 0) {
      //4294967295&0xF=F-4=11 等效=4294967295%16=15-4=11 目的:值<=15  //(4<<(8-4))&0xff=64   4<<4=64%256=64  目的:值<=255
      //0x0-0xF=
    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* 设置优先级 Cortex-M  系统中断 */
  else {
    NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */
}
//SysTick配置
STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
   //判断tick的值是否大于2……24次方,如果大于,则不符合规则。
  if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk)  return (1);      /* 重新加载值不可能 */
  SysTick->LOAD  = ticks - 1;                                /* 设置重新加载寄存器 */
  NVIC_SetPriority (SysTick_IRQn, (1<<NVIC_PRIO_BITS) - 1);  /* 设置系统控制器中断的优先级 */
  SysTick->VAL   = 0;                                        /* 加载系统计数器值 */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                    /* 使能 SysTick IRQ 和 SysTick 定时器 */
  return (0);                                                  /* 函数成功返回0 */
}
#endif // CORE_CM4_H
【3.2】systick.h
这个头文件是本次项目的重点,因为我只当学习,所以本次使用Qt模拟这个过程,目的是学会怎么用,而不是真的用,懂我意思吗?老表
#ifndef SYSTICK_H
#define SYSTICK_H
extern "C"  //使用C语言编译器规则编译
{
#include <stdint.h>
#include <stdio.h>
#define IO    volatile
#define I     volatile const
#if 1
#define TIMER_STOP 				0   //停止时间
#define TIMER_PAUSE				1   //暂停时间
#define TIMER_RUNNING 			2   //时间运行
typedef struct{
    uint8_t MonitorFlagUNIONBitNeedRstIntoBoot;
    double _sys_tick_count;
}Boot;
extern Boot boot;
#define TIMER_1MS				1                       //1ms
#define TIMER_1S				((uint32_t)1000)        //1s
#define TIMER_1MIN				(((uint32_t)1000)*60)   //1min
typedef enum
{
    TIMER_BALANCE_PRESS_WAIT,//平衡气压等待   0
    TIMER_CHECK_PRESS_WAIT,//检查压力等待     1
    TIMER_MIN_200MMHG_CHECK,//检查200mmHg    2
    TIMER_CHECK_PRESS_WAIT2,//检查压力等待2   3
    TIMER_HD_BALANCE_CHECK,//平衡气压HD       4
    TIMER_FLOW_CHECK,//检查流量 5
    TIMER_TEMP_CHECK,//检查温度 6
    TIMER_TEMP_CHECK2,//检查温度2 7
    TIMER_DIALYSIS_WAIT,//透析等待 8
    TIMER_CONCENTRATION_CHECK1,//浓度检查1 9
    TIMER_CONCENTRATION_CHECK2,//浓度检查2  10
    TIMER_BLOOD_LEAK_CHECK,//漏血检查   11
    TIMER_BLOOD_LEAK_CHECK2,//漏血检查2 12
    TIMER_VEN_CLAMP_OFF_CHECK,//静脉夹关    13
    TIMER_VEN_CLAMP_CHECK1,//静脉夹检查      14
    TIMER_VEN_5s_CHECK,//静脉压5s检查        15
    TIMER_VEN_30s_CHECK,//静脉压30s检查      16
    TIMER_VEN_10s_CHECK,//静脉压10s检查      17
    TIMER_INFP_CORRECT_10S,//肝素泵校正10s   18
    TIMER_HD_CLOSED_BALANCE_CHECK,//平衡性检查关闭 HD模式    19
    TIMER_GP02_ON_5s,//GP02开    20
    TIMER_TEST,		//测试用   21
    TIMER_NONE,		//必须为最后一个 22
}Timer_Num;
enum
{
  FALSE,
  TRUE
};
typedef struct
{
    uint32_t Timer_Cnt;    //时间计数
    uint32_t Timer_Status; //时间状态
}Timer_Struct;
extern Timer_Struct Soft_Timer[TIMER_NONE + 1];//结构体数组  22+1=23刚好保存枚举中每种状态时间
typedef struct
{
  IO uint32_t CTRL;                    /*!<Offset: 0x000 (R/W)  系统控制和状态寄存器*/
  IO uint32_t LOAD;                    /*!<Offset: 0x004 (R/W)  systick重载值寄存器*/
  IO uint32_t VAL;                     /*!<Offset: 0x008 (R/W)  SysTick当前值寄存器*/
  I  uint32_t CALIB;                   /*!<Offset: 0x00C (R/ )  SysTick 校准寄存器*/
} SysTick_Type;
/* 系统控制/状态寄存器定义 */
#define SysTick_CTRL_COUNTFLAG_Pos         16                                             /*!<SysTick CTRL: 计数器位置*/
//0x10000
#define SysTick_CTRL_COUNTFLAG_Msk         (1UL << SysTick_CTRL_COUNTFLAG_Pos)            /*!<SysTick CTRL: 计数器掩码 */
#define SysTick_CTRL_CLKSOURCE_Pos          2                                             /*!<SysTick CTRL: 时钟源位置 */
//0x4
#define SysTick_CTRL_CLKSOURCE_Msk         (1UL << SysTick_CTRL_CLKSOURCE_Pos)            /*!<SysTick CTRL: 时钟源掩码*/
#define SysTick_CTRL_TICKINT_Pos            1                                             /*!<SysTick CTRL: 定时中断位置 */
//0x2
#define SysTick_CTRL_TICKINT_Msk           (1UL << SysTick_CTRL_TICKINT_Pos)              /*!<SysTick CTRL: 定时中断掩码0x2*/
#define SysTick_CTRL_ENABLE_Pos             0                                             /*!<SysTick CTRL: 启动位置 */
//0x1
#define SysTick_CTRL_ENABLE_Msk            (1UL << SysTick_CTRL_ENABLE_Pos)               /*!<SysTick CTRL: 启用掩码0x1 */
/* SysTick 重加载寄存器定义 */
#define SysTick_LOAD_RELOAD_Pos             0                                             /*!<SysTick LOAD: 重加载位置 */
//0xFFFFFF
#define SysTick_LOAD_RELOAD_Msk            (0xFFFFFFUL << SysTick_LOAD_RELOAD_Pos)        /*!<SysTick LOAD: 重加载掩码 */
/* SysTick 当前寄存器定义 */
#define SysTick_VAL_CURRENT_Pos             0                                             /*!<SysTick VAL:当前寄存器位置*/
//0xFFFFFF
#define SysTick_VAL_CURRENT_Msk            (0xFFFFFFUL << SysTick_VAL_CURRENT_Pos)        /*!<SysTick VAL:当前寄存器掩码*/
/* SysTick 校准寄存器定义 */
#define SysTick_CALIB_NOREF_Pos            31                                             /*!<SysTick CALIB: 校准寄存器位置 */
//0x80000000
#define SysTick_CALIB_NOREF_Msk            (1UL << SysTick_CALIB_NOREF_Pos)               /*!<SysTick CALIB:校准寄存器掩码*/
#define SysTick_CALIB_SKEW_Pos             30                                             /*!<SysTick CALIB: SKEW Position */
//0x40000000
#define SysTick_CALIB_SKEW_Msk             (1UL << SysTick_CALIB_SKEW_Pos)                /*!<SysTick CALIB: SKEW Mask */
#define SysTick_CALIB_TENMS_Pos             0                                             /*!<SysTick CALIB: TENMS Position */
//0xFFFFFF
#define SysTick_CALIB_TENMS_Msk            (0xFFFFFFUL << SysTick_VAL_CURRENT_Pos)        /*!<SysTick CALIB: TENMS Mask */
#define SCS_BASE            (0xE000E000UL)             /*!<系统控制空间基底地址*/
#define SysTick_BASE        (SCS_BASE +  0x0010UL)     /*!<SysTick基地址*/
#define SysTick  ((SysTick_Type   *) SysTick_BASE  )   /*!<systick结构*/
void Soft_Timer_Set_New_Status(uint32_t Timer_Num,uint8_t NewSatatus);
void Soft_Timer_Set(uint32_t Timer_Num,uint32_t time);
int8_t Soft_Timer_Get_Status(uint32_t Timer_Num);
static void SoftTimer(void);
void SoftTimer_Init(void);
#endif
void SysTick_Handler();//RB-A
void SysTickInit(void);
void SysTickDeInit(void);
void RunBoot(void);
uint32_t GetTickCount(void);
void SetUserTimer(uint32_t *Timer,uint32_t T);
void ResetUserTimer(uint32_t *Timer);
uint32_t ReadUserTimer(uint32_t *Timer);
void Delayms(uint32_t ms);
};
#endif // SYSTICK_H
【3.3】mainwindow.h
使用Qt界面的方式模拟时钟,使用两个定时器,第一个用于模拟单片机的中断服务函数,第二个不必理会,只是测试一下变量最大范围
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "systick.h"
#include <QDebug>
#include <QTimer>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void MainID();
private slots:
    void on_pushButton_clicked();
    void on_pushButton_2_clicked();
    void ProssSystick();
    void on_pushButton_5_clicked();
    void on_pushButton_6_clicked();
    void on_pushButton_7_clicked();
    void on_pushButton_8_clicked();
    void on_pushButton_9_clicked();
    void testuint32_tsize();
    void on_checkBox_clicked();
private:
    Ui::MainWindow *ui;
    QTimer ISystick;//定时器1
    QTimer testtime;//定时器2
};
#endif // MAINWINDOW_H
【3.4】systick.cpp
非常重要,只要使用了这个Systick系统滴答定时器的,这个模板可以直接套用
#include "systick.h"
#include <QDebug>
static uint32_t _sys_tick_count = 4294967295;//定时数 定义  值等于多少都不影响计数 超过最大值会自动=0
#if 1
Timer_Struct Soft_Timer[TIMER_NONE + 1];//结构体数组定义
Boot boot;
/********************************************************************************
  * @brief  设置定时器的新状态   例如:Soft_Timer_Set_New_Status(18,1);
  * 用户可调用这个函数 给枚举里面的某个步骤设置是: 停止(时间=0) ,暂停(时间!=0) ,运行((时间!=0))
********************************************************************************/
void Soft_Timer_Set_New_Status(uint32_t Timer_Num,uint8_t NewSatatus)
{
    if (Timer_Num > TIMER_NONE)//22
        return;
    switch(NewSatatus)
    {
        case TIMER_STOP:
            Soft_Timer[Timer_Num].Timer_Cnt = 0;
            Soft_Timer[Timer_Num].Timer_Status = TIMER_STOP;
            break;
        case TIMER_RUNNING:
            Soft_Timer[Timer_Num].Timer_Status = TIMER_RUNNING;
            break;
        case TIMER_PAUSE:
            Soft_Timer[Timer_Num].Timer_Status = TIMER_PAUSE;
            break;
        default:
            break;
    }
}
//开启一个软定时器  记录他的时间 这里设置后 中断服务函数会将time_ms--,一直等于0,此时Soft_Timer[Timer_Num].Timer_Status = TIMER_STOP;
//此时通过Soft_Timer_Get_Status函数,获取Timer_Num的状态=TIMER_STOP,就代表延时结束
void Soft_Timer_Set(uint32_t Timer_Num,uint32_t time_ms)
{
    if (Timer_Num > TIMER_NONE)
        return;
    Soft_Timer[Timer_Num].Timer_Cnt = time_ms;
    Soft_Timer[Timer_Num].Timer_Status = TIMER_RUNNING;
}
//获取这个枚举定时器变量的状态 例如:Timer_Status=0停止 Timer_Status=1暂停 Timer_Status=2运行,计数中
int8_t Soft_Timer_Get_Status(uint32_t Timer_Num)
{
    if (Timer_Num > TIMER_NONE)
        return -1;
    return Soft_Timer[Timer_Num].Timer_Status;
}
/*****************************************************************************
**函数名称:	 	SysTick_Handler
**函数功能:	 	1ms产生一次中断,_sys_tick_count加1  SysTick时钟外设:中断服务函数
******************************************************************************/
void SysTick_Handler()
{
    do
    {
         qDebug()<<"SysTick_Handler->_sys_tick_count="<<_sys_tick_count;
        _sys_tick_count++;  //静态变量,一直加,达到最大值,由从0,继续加
        boot._sys_tick_count=_sys_tick_count;
    }while (0 == _sys_tick_count);
    /*用户自定添加的延时函数,采用向下递减计数方式,可以同时开启多个延时*/
    SoftTimer();
}
//静态函数  只在本函数实现    其他.不可访问      计数方式是向下计数
static void SoftTimer()
{
    uint8_t Timer_Num = 0;
    for (Timer_Num = 0; Timer_Num <= TIMER_NONE; Timer_Num++)	//扫描所有软定时器
    {
        if (Soft_Timer[Timer_Num].Timer_Status == TIMER_RUNNING)//如果已启动该软定时器
        {
            qDebug()<<"====================SoftTimer 中断服务函数 向下计数================";
            if (Soft_Timer[Timer_Num].Timer_Cnt)				//如果计数未到0
            {
                Soft_Timer[Timer_Num].Timer_Cnt--;              //例如:5000-- 5s定时
                qDebug()<<"Soft_Timer[Timer_Num].Timer_Cnt="<<Soft_Timer[Timer_Num].Timer_Cnt<<endl;
            }
            if (!Soft_Timer[Timer_Num].Timer_Cnt)				//倒计时到0 例如:5000--=0
            {
                Soft_Timer[Timer_Num].Timer_Status = TIMER_STOP;//标记该定时器为停止
            }
        }
    }
}
//【1】初始化结构体数组的定时状态=0
void SoftTimer_Init(void)
{
    uint8_t Timer_Num = 0;
    for (Timer_Num = 0; Timer_Num <= TIMER_NONE; Timer_Num++)//扫描所有软定时器
    {
        Soft_Timer[Timer_Num].Timer_Status = TIMER_STOP;	//标记该定时器为停止
    }
}
#endif
/*****************************************************************************
**函数名称:	 	ReadUserTimer
******************************************************************************/
uint32_t ReadUserTimer(uint32_t *Timer)
{
    return (_sys_tick_count - *Timer);//4000-4000
}
/*****************************************************************************
**函数名称:	 	ResetUserTimer  Timer:复位用户时间=系统时间
******************************************************************************/
void ResetUserTimer(uint32_t *Timer)
{
    qDebug()<<"===============ResetUserTimer=======*Timer ="<<*Timer;
    *Timer = _sys_tick_count;//4000
}
/*****************************************************************************
**函数名称:	 	SetUserTimer    设置用户时间 Timer=系统时间+用户要设置的时间
******************************************************************************/
void SetUserTimer(uint32_t *Timer,uint32_t T)
{
    qDebug()<<"=============SetUserTimer==============";
    *Timer = _sys_tick_count + T;
}
/*****************************************************************************
**函数名称:	 	GetTickCount
**函数功能:     实时返回系统计数时间 单位由中断服务函数决定  例如:1ms
******************************************************************************/
uint32_t GetTickCount(void)
{
    qDebug()<<"==============GetTickCount=====================";
    return _sys_tick_count;
}
/*****************************************************************************
**函数名称:	 	Delayms
**函数功能:
**入口参数:
**返回参数:
******************************************************************************/
void Delayms(uint32_t Time)
{
    uint32_t t;
    //滴答定时器注销后不能再使用该延时函数,否则会陷入死循环
    if( !(SysTick->CTRL&0x01) )  //获取滴答定时器使能位,1:使能,0:失能
    {
        printf("\r\n ######## Error: SysTick Disable --> Can't use Delayms function! ########");
        return;
    }
    ResetUserTimer(&t);
    while(ReadUserTimer(&t) < Time)
    {
        //FeedWdt();        看门狗喂狗函数 这里不说明  关闭中断 设置
//        void FeedWdt()
//        {
//            DisableInterrupts;
//            WDOG0->CNT = 0x02A602A6; //WDOG_CNT 寄存器,offset: 0x8
//            WDOG0->CNT = 0x80B480B4;
//            EnableInterrupts;        //开启中断
//        }
    }
}
/*****************************************************************************
**函数名称:	 	SYSTICK_InternalInit
**函数功能:	 	实现1ms定时
** SysTick校准值设为15000,SysTick时钟频率配置为HCLK/8,此时若HCLK时钟被配置为
120MHz,则SysTick中断会1ms响应一次。
SysTick 15 可编程设置 0x0000_003C 系统节拍定时器
******************************************************************************/
void SysTickInit(void)
{
    qDebug("\r\n################  SysTick Init  ##############");
    boot.MonitorFlagUNIONBitNeedRstIntoBoot=0;
    return;
    //1ms
    uint32_t ticks = (12000000/1000)*1; //12000   1s计数12000000次  1ms=(12000000/1000)*1=12000次 【保持这个值不变】
    SysTick->LOAD = ticks - 1;  		//自动重载值 【12000--】【向下计数  每次-1 =0时 触发中断服务函数】【反反复复执行】
    SysTick->VAL = 0x00;				//当前数值寄存器 清空计数器
    SysTick->CTRL  = SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;  //使能定时器中断|使能定时器011
    SysTick->CTRL &= ~SysTick_CTRL_CLKSOURCE_Msk;   //时钟源控制位置0;时钟是由系统时钟8分频后提供;96M/8=12M,AHB=96M
                                                    //1us 的时间内会计数 12 次,共计数1200次,可实现定时1ms
}
/*****************************************************************************
**函数名称:	 	SysTickDeInit
** 不使能定时器中断-不使能定时器 ->>关闭外设时钟定时器 一般进行某些特殊情况才调用,否则整个项目都不调用
******************************************************************************/
void SysTickDeInit(void)
{
    qDebug("\r\n################  SysTickDeInit  ##############");
    return;
    SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;
    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
//切换到boot进行升级
void RunBoot()
{
     SysTickDeInit();
}
【3.5】mainwindow.cpp [主流程]
具体多看代码吧
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    qDebug()<<"uint32_t(-1)="<<uint32_t(-1);
    connect(&ISystick,SIGNAL(timeout()),this,SLOT(ProssSystick()));
    connect(&testtime,SIGNAL(timeout()),this,SLOT(testuint32_tsize()));
    ui->textEdit->setFontPointSize(15);
    ui->textEdit->setAlignment(Qt::AlignCenter | Qt::AlignVCenter);
}
MainWindow::~MainWindow()
{
    delete ui;
}
//Systick init 可忽略
void MainWindow::on_pushButton_clicked()
{
    SysTickInit();
    ui->textEdit->append("==========SysTickInit()==========");
}
//不使能定时器中断-不使能定时器 可忽略
void MainWindow::on_pushButton_2_clicked()
{
    qDebug("\r\n=====================切换到boot进行升级==================\r\n");
    ui->textEdit->append("======切换到boot进行升级==========");
}
//把这个函数看成中断服务函数  1ms调用一次  也相当于 main()函数
//1ms产生一次中断,_sys_tick_count加1  实际效果如何还是实践一下更好
void MainWindow::ProssSystick()
{
    static uint8_t x1=0;
    if(x1==0)
    {
        ui->textEdit->append("==========while(1) start==========");
        ui->textEdit->append("==========SysTickInit==========");
        SysTickInit();
        ui->textEdit->append("==========SoftTimer_Init=======");
        SoftTimer_Init();
        x1=2;
    }
    if(x1==2)
    {
        ui->textEdit->append("==========SysTick_Handler==========");
        x1=3;
    }
     SysTick_Handler(); //中断服务函数:【1】系统时间++,用户时间设置--  一起在中断服务函数中使用
     ui->lineEdit->setText(QString("%1").arg(boot._sys_tick_count));
     static uint32_t Timer2 = 0;
     qDebug(" ReadUserTimer = %d ",ReadUserTimer(&Timer2));
     static uint t=0;
    if (ReadUserTimer(&Timer2) == 1000 && t==0)
    {
         ui->textEdit->append("1s 结束 开始液体填充");
         ui->textEdit->append("系统时间="+ui->lineEdit->text());
         ResetUserTimer(&Timer2);
         qDebug(" Timer2 = %d ",Timer2);
         t=1;
         ISystick.stop();
    }
    static uint32_t PressCorrectionTimer = 0;
    if(t==1)
    {
        SetUserTimer(&PressCorrectionTimer, 1000*4);		//4s=4000
        ui->textEdit->append("4s 定时 开始");
        t=2;
    }
    qDebug(" PressCorrectionTimer = %d ",PressCorrectionTimer);
    if (GetTickCount() >= PressCorrectionTimer && t==2)
    {
        qDebug(" GetTickCount()  = %d ",GetTickCount() );
        //SetUserTimer(&PressCorrectionTimer, 1000*4);	//4s							//过去4s的血泵流量稳定
        qDebug("\r\n #################### DialyPressCorrection() Step  = DPC1 - 1 血泵流量稳定 ###################");
        ui->textEdit->append("4s 定时 结束 血泵流量稳定");
        ui->textEdit->append("系统时间="+ui->lineEdit->text());
        Soft_Timer_Set(TIMER_INFP_CORRECT_10S, TIMER_1S * 4);
        ui->textEdit->append(QString("TIMER_INFP_CORRECT_10S=%1").arg(Soft_Timer[TIMER_INFP_CORRECT_10S].Timer_Status));
        t=3;
        ISystick.stop();
    }
    if(Soft_Timer_Get_Status(TIMER_INFP_CORRECT_10S)==TIMER_STOP && t==3)
    {
        qDebug()<<"=============10s计数结束===========";
        ui->textEdit->append("系统时间="+ui->lineEdit->text());
        ui->textEdit->append(QString("TIMER_INFP_CORRECT_10S 10s计数 = %1").arg(Soft_Timer[TIMER_INFP_CORRECT_10S].Timer_Cnt));
        ISystick.stop();
        t=4;
    }
    //需要重启boot
    static uint32_t into_boot_timer=0;
    if (boot.MonitorFlagUNIONBitNeedRstIntoBoot == 1)
    {
        if (ReadUserTimer(&into_boot_timer) == 2000)//新系统时间-当前系统时间=2000  也既是新系统时间=当前系统时间+2000
        {
            ui->textEdit->append("==========切换到boot进行升级 RunBoot() 2s==========");
            ui->textEdit->append("==========SysTickDeInit==========");
            ui->textEdit->append(QString("_sys_tick_count - *Timer =%1").arg(boot._sys_tick_count));
            RunBoot();
            boot.MonitorFlagUNIONBitNeedRstIntoBoot=0;
            ISystick.stop();
            t=0;
            ResetUserTimer(&Timer2); //从头开始
        }
    }
    else
    {
        ResetUserTimer(&into_boot_timer);//into_boot_timer=当前系统时间
    }
}
void MainWindow::MainID()
{
}
//1ms stop
void MainWindow::on_pushButton_5_clicked()
{
    ISystick.stop();
}
//软定时设置新的状态
void MainWindow::on_pushButton_6_clicked()
{
    qDebug()<<"==============Soft_Timer_Set_New_Status==================";
    Soft_Timer_Set_New_Status(TIMER_INFP_CORRECT_10S,TIMER_PAUSE);//18 1
    qDebug("Timer_Cnt=%d ",Soft_Timer[TIMER_INFP_CORRECT_10S].Timer_Cnt);
    if(Soft_Timer_Get_Status(TIMER_INFP_CORRECT_10S) == TIMER_PAUSE)
    {
        qDebug("Timer_Status=%d ",Soft_Timer[TIMER_INFP_CORRECT_10S].Timer_Status);
    }
}
//SoftTimer_Init
void MainWindow::on_pushButton_7_clicked()
{
    qDebug()<<"==============SoftTimer_Init==================";
    SoftTimer_Init();
    for (int i = 0; i <= TIMER_NONE; i++)//扫描所有软定时器
    {
        qDebug("i= %d \t Timer_Status=%d ",i,Soft_Timer[i].Timer_Status);
    }
}
//开启Systick中断 1ms
void MainWindow::on_pushButton_8_clicked()
{
    //开启中断
    qDebug()<<"======start Interrupt================";
    ISystick.start(1);//1ms
}
//RunBoot 模拟当这个标志位=1  代表机器重启 当成机器上的某个按键
void MainWindow::on_pushButton_9_clicked()
{
    ui->textEdit->append(QString("MonitorFlagUNIONBitNeedRstIntoBoot=%1").arg(boot.MonitorFlagUNIONBitNeedRstIntoBoot));
    boot.MonitorFlagUNIONBitNeedRstIntoBoot=1;
    ui->textEdit->append(QString("MonitorFlagUNIONBitNeedRstIntoBoot=%1").arg(boot.MonitorFlagUNIONBitNeedRstIntoBoot));
}
//测试uint32_t 大小
void MainWindow::on_checkBox_clicked()
{
    testtime.start(1);
}
//测试uint32_t 大小
void MainWindow::testuint32_tsize()
{
    static uint32_t t=4294967295; //网查最大范围值 超过这个值自动=0  又开始自增 反反复复
    ui->lineEdit_2->setText(QString("%1").arg(t++));
    if(t==0)
        ui->textEdit->append("uint32_t 最大后 自动=0");
}



![[附源码]Python计算机毕业设计Django勤工助学管理系统](https://img-blog.csdnimg.cn/c97fd8a05acc45379379f8121d844c1a.png)















