文档章节

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

小汉憨憨
 小汉憨憨
发布于 2014/05/07 18:09
字数 776
阅读 1818
收藏 7

下面为大家介绍一个曾见过的在裸机系统中,非阻塞延时的巧妙设计,当时它是被用在一导航影音娱乐系统的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;
}

 

 


© 著作权归作者所有

小汉憨憨
粉丝 4
博文 12
码字总数 14052
作品 0
武汉
程序员
私信 提问
加载中

评论(3)

G
G_lk
1 确实存在2楼说的问题, 需要在进入SysTimer _Process()后关闭中断响应;
2 在SysTimer _Process()中,也可以移位操作, gTimer.Status.byte>>=4, 应该比if判断更快一些.
yurenchen
yurenchen
没理解 巧妙之处, 反而感觉
如果在执行
gTimer.Status.byte &= 0x0F;
时 跳进 SysTick_Handler 恐怕 flg 写操作 会发生 竞争
Jr小王子
Jr小王子
353535 非常好 谢谢
STM32系统滴答_及不可不知的延时技巧 - (上)

我想每个单片机爱好者及工程开发设计人员都有过点灯的经历。流水灯是个好东西,尤其是在调试资源有限的环境中,有时会帮上大忙。 然在最初入门时,如何让这些小灯们按照我们的想法欢快地跑起...

小汉憨憨
2014/04/29
9.1K
0
STM32之SysTick定时器

SysTick-------操作系统的心跳 SysTick是系统滴答定时器,可以说是操作系统的的“心跳”,它被绑在NVIC中,用于产生SysTick异常(异常号:15)。一旦产生SysTick异常,就会产生滴答中断,这个...

panrenqiu
2018/04/14
0
0
SysTick的优先级是高还是低

SysTick系统嘀嗒定时器并非STM32独有的,它是Cortex内核的部分,CM3为它专门开出一个异常类型,并且在中断向量表中占有一席之地(异常号15)。这样它可以很方便的移植到不同厂商出CM3内核...

OceanStack
2015/01/24
5.8K
0
STM32读取MPU6050问题总结 (可读ID无数据; PWR_MGMT_1休眠位无法清零; 寄存器读写正常无数据;初始化前加延时无法解决问题)

因为网上关于STM32读取6050的例程并不少但是总会有古怪的问题存在,在尝试读取的过程中在网上逛论坛发现很多问题到最后没结果不了了之,不知那些前辈们是否已经自己查出了问题,我想尽自己微...

qq_26039737
2018/01/31
0
0
进程调度与切换简单总结

一、Linux时钟系统 1.时钟硬件 绝大多数的PC都有两个时钟源,RTC(实时时钟)和OS(系统时钟)。RTC也叫做CMOS时钟,它是PC主机板上的一块芯片。OS时钟产生于PC主板上的定时/计数芯片,由操作...

8yi少女的夢
2017/10/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

java通过ServerSocket与Socket实现通信

首先说一下ServerSocket与Socket. 1.ServerSocket ServerSocket是用来监听客户端Socket连接的类,如果没有连接会一直处于等待状态. ServetSocket有三个构造方法: (1) ServerSocket(int port);...

Blueeeeeee
今天
6
0
用 Sphinx 搭建博客时,如何自定义插件?

之前有不少同学看过我的个人博客(http://python-online.cn),也根据我写的教程完成了自己个人站点的搭建。 点此:使用 Python 30分钟 教你快速搭建一个博客 为防有的同学不清楚 Sphinx ,这...

王炳明
昨天
5
0
黑客之道-40本书籍助你快速入门黑客技术免费下载

场景 黑客是一个中文词语,皆源自英文hacker,随着灰鸽子的出现,灰鸽子成为了很多假借黑客名义控制他人电脑的黑客技术,于是出现了“骇客”与"黑客"分家。2012年电影频道节目中心出品的电影...

badaoliumang
昨天
15
0
很遗憾,没有一篇文章能讲清楚线程的生命周期!

(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本。 简介 大家都知道线程是有生命周期,但是彤哥可以认真负责地告诉你网上几乎没有一篇文章讲得是完全正确的。 ...

彤哥读源码
昨天
15
0
jquery--DOM操作基础

本文转载于:专业的前端网站➭jquery--DOM操作基础 元素的访问 元素属性操作 获取:attr(name);$("#my").attr("src"); 设置:attr(name,value);$("#myImg").attr("src","images/1.jpg"); ......

前端老手
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部