下面为大家介绍一个曾见过的在裸机系统中,非阻塞延时的巧妙设计,当时它是被用在一导航影音娱乐系统的MCU驱动软件中,在此我对其作了一定的改动。
此章节涉及到STM32内容不多,以软件为主。
此延时软件的设计可以直接进行10、50、100ms及1s的查询定时,并且当若需其它时间要求的定时或延时可以很方便的自己编写软件很简单方便设定。
首先需要设置SysTick 定时中断为10MS进入一次。然后在定时中断函数中作如下处理
void SysTick_Handler(void){ bTemp10Msec = TIMER_SET; ++gTimer.Tick10Msec; if (0 == (gTimer.Tick10Msec % 5)) { bTemp50Msec = TIMER_SET; } if (0 == (gTimer.Tick10Msec % 10)) { bTemp100Msec = TIMER_SET; } if (100 == gTimer.Tick10Msec) { gTimer.Tick10Msec = 0; bTemp1Sec = TIMER_SET; }}
gTimer是定义的一全局结构体变量,Timer_Struct gTimer;
此软件设计巧妙之处首先在结构体的设计上:
typedef struct{ u8 Tick10Msec; Char_Field Status;} Timer_Struct;
其中Char_Field 为一联合体,设计如下:
typedef union{ unsigned char byte; Timer_Bit field;} Char_Field;
而它内部的Timer_Bit是一个可按位访问的结构体
typedef struct{ unsigned char bit0: 1; unsigned char bit1: 1; unsigned char bit2: 1; unsigned char bit3: 1; unsigned char bit4: 1; unsigned char bit5: 1; unsigned char bit6: 1; unsigned char bit7: 1;} Timer_Bit;
此联合体的这样设计的目的将在后面的代码中体现出来;
定时中断里的bTempXXX及后面定时或延时查询用的bSystemXXX 是宏定义,如下:
#define bSystem10Msec gTimer.Status.field.bit0#define bSystem50Msec gTimer.Status.field.bit1#define bSystem100Msec gTimer.Status.field.bit2#define bSystem1Sec gTimer.Status.field.bit3#define bTemp10Msec gTimer.Status.field.bit4#define bTemp50Msec gTimer.Status.field.bit5#define bTemp100Msec gTimer.Status.field.bit6#define bTemp1Sec gTimer.Status.field.bit7
定时中断里的TIMER_SET 为真(1)可用宏定义,也可如下定义:
typedef enum{ TIMER_RESET = 0, TIMER_SET = 1,} TimerStatus;
以上便是非阻塞延时软件的整体结构设计。
另外还需要在系统运行大的循环中调用设计的控制函数,
void SysTimer _Process(void){ gTimer.Status.byte &= 0xF0; if (bTemp10Msec) { bSystem10Msec = TIMER_SET; } if (bTemp50Msec) { bSystem50Msec = TIMER_SET; } if (bTemp100Msec) { bSystem100Msec = TIMER_SET; } if (bTemp1Sec) { bSystem1Sec = TIMER_SET; } gTimer.Status.byte &= 0x0F;}
此函数开头与结尾两句
gTimer.Status.byte &= 0xF0;gTimer.Status.byte &= 0x0F;
就巧妙的实现了bSystemXXX 和 bTempXXX的消除工作,不用再定时到来后手动把计数值消除。此处便用到了联合体中的变量共用一个起始存储空间的特性。
下面一个简单的应用举例,比如我们想让一LED灯每100MS亮或灭一次,就可以这样设计:
int main(void){ while(1) { SysTimer _Process(); if(TIMER_SET == bSystem100Msec) { LED = !LED; } }}
另 附此软件的整体代码 :
#define bSystem10Msec gTimer.Status.field.bit0#define bSystem50Msec gTimer.Status.field.bit1#define bSystem100Msec gTimer.Status.field.bit2#define bSystem1Sec gTimer.Status.field.bit3#define bTemp10Msec gTimer.Status.field.bit4#define bTemp50Msec gTimer.Status.field.bit5#define bTemp100Msec gTimer.Status.field.bit6#define bTemp1Sec gTimer.Status.field.bit7typedef enum{ TIMER_RESET = 0, TIMER_SET = 1,} TimerStatus;typedef struct{ unsigned char bit0: 1; unsigned char bit1: 1; unsigned char bit2: 1; unsigned char bit3: 1; unsigned char bit4: 1; unsigned char bit5: 1; unsigned char bit6: 1; unsigned char bit7: 1;} Timer_Bit;typedef union{ unsigned char byte; Timer_Bit field;} Char_Field;typedef struct{ u8 Tick10Msec; Char_Field Status;} Timer_Struct;//定义一全局变量Timer_Struct gTimer;void SysTick_Handler(void){ bTemp10Msec = TIMER_SET; ++gTimer.Tick10Msec; if (0 == (gTimer.Tick10Msec % 5)) { bTemp50Msec = TIMER_SET; } if (0 == (gTimer.Tick10Msec % 10)) { bTemp100Msec = TIMER_SET; } if (100 == gTimer.Tick10Msec) { gTimer.Tick10Msec = 0; bTemp1Sec = TIMER_SET; }}void SysTimer _Process(void){ gTimer.Status.byte &= 0xF0; if (bTemp10Msec) { bSystem10Msec = TIMER_SET; } if (bTemp50Msec) { bSystem50Msec = TIMER_SET; } if (bTemp100Msec) { bSystem100Msec = TIMER_SET; } if (bTemp1Sec) { bSystem1Sec = TIMER_SET; } gTimer.Status.byte &= 0x0F;}