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


    本次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
    
    • 1
    • 2
    • 3

    这就是Systick系统滴答定时器基地址宏定义处

    基地址:可以这么理解,如同数组的第一个元素的起始地址,偏移地址如同数组下标递增或递减,偏移到不同位置,获取不同的值,就有不同的功能,这就是寄存器的强大之处,寄存器地址的偏移,一般改变某一位,要保证其他位不变,所以离不开这些运算符(&,~,|)等

    /* 内存 映射 的 Cortex-M4 硬件 */
    #define SCS_BASE            (0xE000E000UL)                            /*!<系统控制空间基底地址*/
    #define SysTick_BASE        (SCS_BASE +  0x0010UL)                    /*!
    #define NVIC_BASE           (SCS_BASE +  0x0100UL)                    /*!
    #define SCB_BASE            (SCS_BASE +  0x0D00UL)                    /*!<系统控制块的基本地址*/
    
    #define SCB                 ((SCB_Type       *)     SCB_BASE      )   /*!
    #define SysTick             ((SysTick_Type   *)     SysTick_BASE  )   /*!
    #define NVIC                ((NVIC_Type      *)     NVIC_BASE     )   /*!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    【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        /*!
    
    /* 内存 映射 的 Cortex-M4 硬件 */
    #define SCS_BASE            (0xE000E000UL)                            /*!<系统控制空间基底地址*/
    #define SysTick_BASE        (SCS_BASE +  0x0010UL)                    /*!
    #define NVIC_BASE           (SCS_BASE +  0x0100UL)                    /*!
    #define SCB_BASE            (SCS_BASE +  0x0D00UL)                    /*!<系统控制块的基本地址*/
    
    #define SCB                 ((SCB_Type       *)     SCB_BASE      )   /*!
    #define SysTick             ((SysTick_Type   *)     SysTick_BASE  )   /*!
    #define NVIC                ((NVIC_Type      *)     NVIC_BASE     )   /*!
    
    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];                 /*!
      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        /*!
    
    
    //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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160

    【3.2】systick.h

    这个头文件是本次项目的重点,因为我只当学习,所以本次使用Qt模拟这个过程,目的是学会怎么用,而不是真的用,懂我意思吗?老表

    #ifndef SYSTICK_H
    #define SYSTICK_H
    
    
    
    extern "C"  //使用C语言编译器规则编译
    {
    #include 
    #include 
    
    #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;                    /*!
      IO uint32_t LOAD;                    /*!
      IO uint32_t VAL;                     /*!
      I  uint32_t CALIB;                   /*!
    } SysTick_Type;
    
    /* 系统控制/状态寄存器定义 */
    #define SysTick_CTRL_COUNTFLAG_Pos         16                                             /*!
    //0x10000
    #define SysTick_CTRL_COUNTFLAG_Msk         (1UL << SysTick_CTRL_COUNTFLAG_Pos)            /*!
    
    #define SysTick_CTRL_CLKSOURCE_Pos          2                                             /*!
    //0x4
    #define SysTick_CTRL_CLKSOURCE_Msk         (1UL << SysTick_CTRL_CLKSOURCE_Pos)            /*!
    
    #define SysTick_CTRL_TICKINT_Pos            1                                             /*!
    //0x2
    #define SysTick_CTRL_TICKINT_Msk           (1UL << SysTick_CTRL_TICKINT_Pos)              /*!
    
    #define SysTick_CTRL_ENABLE_Pos             0                                             /*!
    //0x1
    #define SysTick_CTRL_ENABLE_Msk            (1UL << SysTick_CTRL_ENABLE_Pos)               /*!
    
    /* SysTick 重加载寄存器定义 */
    #define SysTick_LOAD_RELOAD_Pos             0                                             /*!
    //0xFFFFFF
    #define SysTick_LOAD_RELOAD_Msk            (0xFFFFFFUL << SysTick_LOAD_RELOAD_Pos)        /*!
    
    /* SysTick 当前寄存器定义 */
    #define SysTick_VAL_CURRENT_Pos             0                                             /*!
    //0xFFFFFF
    #define SysTick_VAL_CURRENT_Msk            (0xFFFFFFUL << SysTick_VAL_CURRENT_Pos)        /*!
    
    /* SysTick 校准寄存器定义 */
    #define SysTick_CALIB_NOREF_Pos            31                                             /*!
    //0x80000000
    #define SysTick_CALIB_NOREF_Msk            (1UL << SysTick_CALIB_NOREF_Pos)               /*!
    
    #define SysTick_CALIB_SKEW_Pos             30                                             /*!
    //0x40000000
    #define SysTick_CALIB_SKEW_Msk             (1UL << SysTick_CALIB_SKEW_Pos)                /*!
    
    #define SysTick_CALIB_TENMS_Pos             0                                             /*!
    //0xFFFFFF
    #define SysTick_CALIB_TENMS_Msk            (0xFFFFFFUL << SysTick_VAL_CURRENT_Pos)        /*!
    
    #define SCS_BASE            (0xE000E000UL)             /*!<系统控制空间基底地址*/
    #define SysTick_BASE        (SCS_BASE +  0x0010UL)     /*!
    #define SysTick  ((SysTick_Type   *) SysTick_BASE  )   /*!
    
    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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154

    【3.3】mainwindow.h

    使用Qt界面的方式模拟时钟,使用两个定时器,第一个用于模拟单片机的中断服务函数,第二个不必理会,只是测试一下变量最大范围

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include 
    #include "systick.h"
    #include 
    #include 
    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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    【3.4】systick.cpp

    非常重要,只要使用了这个Systick系统滴答定时器的,这个模板可以直接套用

    #include "systick.h"
    #include 
    
    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();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211

    【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");
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183

  • 相关阅读:
    linux免密
    QT 样式插件示例
    Hadoop
    .NET快速对接极光消息推送
    Wireshark 提示和技巧 | 如何匿名化数据包
    福利又来了,mongo还不会快来练起来!操作汇总
    @Configuration和@Component注解的区别
    一篇文章就能学会的 Redis 的事务
    手写一个摸鱼神器:使用python手写一个看小说的脚本,在ide中输出小说内容,同事直呼“还得是你”
    leetcode905-Sort Array By Parity
  • 原文地址:https://blog.csdn.net/m0_45463480/article/details/128187427