STM32系统滴答_及不可不知的延时技巧 - (下)

本文转载自https://my.oschina.net/czzhu/blog/261802;作者: 小汉憨憨
摘要: 单片机非阻塞延时巧妙的软件设计。

下面为大家介绍一个曾见过的在裸机系统中,非阻塞延时的巧妙设计,当时它是被用在一导航影音娱乐系统的MCU驱动软件中,在此我对其作了一定的改动。

此章节涉及到STM32内容不多,以软件为主。

此延时软件的设计可以直接进行1050100ms1s的查询定时,并且当若需其它时间要求的定时或延时可以很方便的自己编写软件很简单方便设定。

 

首先需要设置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.bit7

typedef 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;
}
 


原创文章 24 获赞 45 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weilixin88/article/details/74011145