GD32F30x系列Systick系统滴答定时器 (Qt模拟项目 可套函数模板)

news2024/11/18 18:33:57

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


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu 18.04安装fast-dds

提纲 1、概述 2、foonathan_memory_vendor 3、fast-cdr 4、fast-dds 5、编译HelloWorldExample 6、安装fast-dds-gen&#xff0c;使用IDL文件构建代码 1、概述 fastdds是干什么&#xff0c;就不重复说了。 操作系统是Ubuntu18.04 本次采用源码编译安装&#xff0c;需要使用到…

用二元泊松模型预测2022世界杯8强

用二元泊松模型预测2022世界杯8强 网上有很多文章用双泊松&#xff08;Double Poisson&#xff09;模型来预测世界杯比赛结果。但是双泊松模型有一个严重的缺陷&#xff0c;那就是它假设比赛中两队的比分是条件独立的。而我们都知道&#xff0c;在对抗性比赛中&#xff0c;两…

(十二)笔记MQ学习之优劣介绍

&#xff08;&#xff08;十二&#xff09;笔记MQ学习之优劣介绍一、MQ的优势1.应用解耦2.异步提速3.削峰填谷二、MQ的劣势1.系统可用性降低2.系统复杂度提高3.一致性问题三、MQ的使用条件四、常见的MQ产品一、MQ的优势 1.应用解耦 使用MQ使得应用解耦&#xff0c;提升容错性…

[附源码]Python计算机毕业设计Django勤工助学管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Linux之基于Centos系统安装Redis、MySQL、Nginx

一. Redis的安装 1. 准备 (1). 宿主机&#xff1a;centos 8.0 (2). Redis源码&#xff1a;【压缩包&#xff1a; redis-5.0.0.tar.gz】 需要自行编译。 (PS&#xff1a;这个压缩包可以直接Centos系统中在线下载 或者去Redis官网先下载&#xff0c;然后copy到Centos系统中) …

Java入门教程(4)——JDK环境变量的配置

1 1.path是一个常见的环境变量&#xff0c;它告诉系统除了在当前目录下寻找此程序外&#xff0c;还可以到path指定的目录下寻找。 2.JAVA_HOME (1) 为以后其他软件寻找JDK做准备 classpath不需配置 3.JDK1.5以上版本&#xff0c;JRE会自动搜索当前路径下的类文件及相关jar…

在浏览器中输入url回车后发生了什么

1.dns进行解析&#xff1a;将url地址&#xff08;www.bilibili.com&#xff09;解析成ip地址&#xff08;110.43.34.184&#xff09;&#xff0c;ip地址就是想要访问的服务器的地址 dns就是数据库&#xff0c;这个数据库中记录着url地址和ip地址的对应关系 2.正式发送数据之前…

react 初体验

react笔记 创建一个项目 npm install -g create-react-app // 全局安装脚手架 create-react-app react-01 // 新建一个项目 npm start快捷定义组件 安装组件后&#xff0c;快捷命令 rcc &#xff1a;类式组件 rfc&#xff1a;函数式组件 axios开启代理 在package.json中新…

为什么我推荐你一定要学Python?

很多初学者都听说python很火&#xff0c;可是为啥要学Python&#xff0c;下面谈谈我的感悟 python语言是我目前为止用的最爽的语言&#xff0c;因为它真的很优美.虽然c,c,java也非常的强大和伟大&#xff0c;但是每一种语言伟大的背后都是有一定的时代背景。 说起Python这门编…

VINS学习02——VINS系列代码所有依赖库安装(保姆级)

0.简介 在学习视觉SLAM过程中&#xff0c;先后用了VINS_mono,VINS_Fusion,Omni_swarm,因为是第一次做视觉相关定位&#xff0c;所以大部分库都是第一次装&#xff0c;中间还从虚拟机换到双系统&#xff0c;意识到记录的重要行性&#xff0c;所以在此记录安装相关依赖库的教程。…

python 练习题

for 循环 和 while 循环 判断101-200之间有多少个素数&#xff0c;并输出所有素数。 &#xff08;什么是素数(质数): 除了1和它本身&#xff0c;不能被其他的数整除&#xff09; 方法1&#xff1a; count 0 # 设定素数的初始个数为0 for num in range…

MySql使用MyCat分库分表(四)分片规则

视频学习地址&#xff1a;17-尚硅谷-垂直分库_哔哩哔哩_bilibili 笔记参考地址&#xff1a;MySQL 分库分表 | xustudyxus Blog (frxcat.fun) 分片规则 范围分片 介绍 根据指定的字段及其配置的范围与数据节点的对应情况&#xff0c; 来决定该数据属于哪一个分片。 配置 …

Angular 应用开发里使用 ForRoot 解决 Lazy Loaded Module 里单例行为丢失的问题

笔者在 Angular 实际项目开发中曾经遇到这样一个需求&#xff1a; 我们想创建一个共享模块&#xff0c;它将包含一个配置来设置布尔值&#xff08;作为标志&#xff09;以启用或禁用其他模块的某些功能。 其他模块可以在 Angular 应用程序的引导期间加载&#xff0c;也可以是延…

JVM基本常识

目录 内存区域划分 类加载 何时触发类加载&#xff1f; 双亲委派模型 GC GC回收那部分内存&#xff1f; 怎么回收&#xff1f; 怎么找垃圾(判定某个对象是否是垃圾) 具体怎么回收&#xff1f; 我的GitHub&#xff1a;Powerveil GitHub 我的Gitee&#xff1a;Powercs12…

痞子衡嵌入式:浅析IAR下调试信息输出机制之半主机(Semihosting)

大家好&#xff0c;我是痞子衡&#xff0c;是正经搞技术的痞子。今天痞子衡给大家分享的是IAR下调试信息输出机制之半主机(Semihosting)。 在嵌入式世界里&#xff0c;输出打印信息是一种非常常用的辅助调试手段&#xff0c;借助打印信息&#xff0c;我们可以比较容易地定位和…

由浅到深-模拟实现list

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正。 目录 一 、见见…

Acrel-2000Z电力监控系统在某数据中心的应用-Susie 周

1、概述 随着网络和信息技术的快速发展&#xff0c;人们对“大数据”业务需求不断增长&#xff0c;为了满足日益增长的应用需求&#xff0c;数据的建设规模也在向超大型、园区级数据方向发展。通信、金融、商业等行业&#xff0c;面对未来数据业务的爆发式增长需求&#xff0c…

Go cobra 库学习

cobra既是一个用于创建强大现代CLI应用程序的库&#xff0c;也是一个生成应用程序和命令文件的程序。cobra被用在很多go语言的项目中&#xff0c;比如 Kubernetes、Docker、Istio、ETCD、Hugo、Github CLI等等 其实简单的来说&#xff0c;cobra就是一个自定义命令工具&#xff…

从IPC到分布式软总线的随笔

在Linux 系统中&#xff0c; 客观来说&#xff0c;缺乏相对开发者比较友好的进程间通信框架。谈到Linux上进程间通信&#xff0c;一般都会想起管道&#xff08;匿名、有名&#xff09;、信号/信号灯、共享内存、消息队列和socket。这些都是偏低层的技术&#xff0c;有没有方便开…

HummerRisk 入门3:开发手册

本文是 HummerRisk 的开发手册&#xff0c;介绍项目的结构及如何配置 HummerRisk 的开发环境和开发中的注意事项&#xff0c;快速参与到 HummerRisk 项目的开发中来。 一、项目结构 二、配置开发环境 1、环境准备 后端 HummerRisk 后端使用了 Java 语言的 Spring Boot 框架…