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