在状态机中管理时间资源

写在前面的话

在嵌入式系统中,经常会使用到延时(Delay)函数,延时有长,有短;500us以下的延时,可以完全用软件来做;较长的延时,可以用硬件Timer或者调用RTOS的时间管理函数。

在简单的MCU中,由于资源限制,无法使用常规的RTOS,这时就需要自己写相应的协调式调度算法,常见的有协程和时间片轮询机制等,万变不离其宗,它们其中的核心是状态机,在状态机中一个核心原则是:函数不能长时间阻塞MCU,否则就会导致整个系统调度失效。也就是说:无法使用纯软件延时

例如,在系统中严禁出现下面代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

void delay_s(uint8_t tick_s)
{

...
}


...


// Code Snippet 1

delay_s(2);

// Code Snippet 2

注:
关于状态机,后面会专门写文章来介绍,这里暂且略过;如果您感兴趣,请自行 百度/google 下面关键字

FSM/HSM/状态机


原理分析

下面讨论下怎么处理这种情况

传统软件延时的核心问题是:没有一个统一的全局时间,所以各个函数只好自己空转来延时;在空转时,也不会释放MCU,
所以导致无法执行其它函数,在OS的环境下,时间资源由RTOS统一接管,调度;无OS的情况下,我们便需要自己来管理时间资源

在APP层,用户使用场景规定如下:

  1. 函数需要延时
  2. 向系统申请时间资源
  3. 任务获取句柄
  4. 任务中,查询定时时间是否到达

实现机制如下:

在系统级别维护一个全局Timer值,该值会不断递增,同时在内部维护一个时间单元数组(链表)
,当用户申请时间资源时,系统查询一个空闲时间单元,将当前时间加上延时值,存储到时间单元结构体中,然后标记单元为占用状态,
返回时间单元ID(即为句柄)

注:当定时时间到达后,原来获取的句柄变会失效,如需重新使用延时服务,请重新申请句柄

代码实现

详细的代码如下:

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

//******************************************************************************************
//!
//! \file SoftTimer.h
//! \brief SoftTimer Interface File
//! This module is used to replace 'delay' function in state machine
//! \author cedar
//! \date 2014-9-17
//! \email xuesong5825718@gmail.com
//! \qq 819280802
//!
//! \license
//!
//! Copyright (c) 2014 Cedar MIT License
//!
//! Permission is hereby granted, free of charge, to any person obtaining a copy
//! of this software and associated documentation files (the "Software"), to deal
//! in the Software without restriction, including without limitation the rights to
//! use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
//! the Software, and to permit persons to whom the Software is furnished to do so,
//! subject to the following conditions:
//!
//! The above copyright notice and this permission notice shall be included in all
//! copies or substantial portions of the Software.
//!
//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//! IN THE SOFTWARE.
///
//******************************************************************************************

#ifndef __SOFT_TIMER_H__
#define __SOFT_TIMER_H__

#ifdef __cplusplus
extern "C"
{
#endif

//******************************************************************************************
//! Portable Configure
//******************************************************************************************

//! If your compiler support stdint.h file, then try to use it, otherwise using folling section
#if 0
typedef unsigned char uint8_t ;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
#endif

#define ENTER_SECURE_SECTION() \
do \
{ \
} while (0)



#define EXIT_SECURE_SECTION() \
do \
{ \
} while (0)




//******************************************************************************************
//! Function Parameters
//******************************************************************************************

#define TIMER_ELEMENT_NUM_MAX 20 //!< Maxium SoftTimer

#define SOFT_TIMER_SUCCESS 0 //!< Operate success
#define SOFT_TIMER_ING 1 //!< Timer Counting
#define SOFT_TIMER_TIMEOUT 2 //!< Timer Timeout
#define SOFT_TIMER_ERR 3 //!< Operate failure, invaild handle


//******************************************************************************************
//! PUBLIC API
//******************************************************************************************

extern uint16_t SoftTimer_Init(void);
extern uint16_t SoftTimer_Req(uint32_t Delay);
extern uint16_t SoftTimer_Check(uint16_t Handle);
extern void TimerISR_Hook(void);

#ifdef __cplusplus
}
#endif

#endif // __SOFT_TIMER_H__
C文件代码
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

//******************************************************************************************
//!
//! \file SoftTimer.c
//! \brief SoftTimer Implement File
//! This module is used to replace 'delay' function in state machine
//! \author cedar
//! \date 2014-9-17
//! \email xuesong5825718@gmail.com
//! \qq 819280802
//!
//! \license
//!
//! Copyright (c) 2014 Cedar MIT License
//!
//! Permission is hereby granted, free of charge, to any person obtaining a copy
//! of this software and associated documentation files (the "Software"), to deal
//! in the Software without restriction, including without limitation the rights to
//! use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
//! the Software, and to permit persons to whom the Software is furnished to do so,
//! subject to the following conditions:
//!
//! The above copyright notice and this permission notice shall be included in all
//! copies or substantial portions of the Software.
//!
//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//! IN THE SOFTWARE.
///
//******************************************************************************************

#include "SoftTimer.h"


//******************************************************************************************
//! Typedef
//******************************************************************************************
typedef struct
{
uint16_t handle; // Timer Resource Handle
uint32_t delay; // Delay Value
uint32_t timestamp; // Timer Stamp
}TimerElem_t;


//******************************************************************************************
//! Private Variable
//******************************************************************************************

static volatile uint32_t TimerCnt = 0;
static volatile uint16_t HandleIndex = 0;
static TimerElem_t SoftTimer[TIMER_ELEMENT_NUM_MAX];


//******************************************************************************************
//! Function Implement
//******************************************************************************************


//******************************************************************************************
//
//! \brief Initialize Timer resource
//!
//! \param None.
//! \retval
//! - SOFT_TIMER_SUCCESS
//!
//! \note
//! - This function must be called first !.
//!
//
//******************************************************************************************
uint16_t SoftTimer_Init(void)
{
uint8_t i = 0;

// Clear All Elements
for(i = 0; i < TIMER_ELEMENT_NUM_MAX; i++)
{
SoftTimer[i].handle = 0;
SoftTimer[i].delay = 0;
SoftTimer[i].timestamp = 0;
}

// Initialize Global Status Variable
TimerCnt = 0;
HandleIndex = 1;

return (SOFT_TIMER_SUCCESS);
}

//******************************************************************************************
//
//! \brief Request Timer resource
//!
//! \param [in] Tick is time eclipse value.
//! \retval
//! - Zero Operate Failure, No Timer Available
//! - Non-Zero Valid Timer Handle
//!
//! \note
//! - Timer handle only can be used once.
//!
//
//******************************************************************************************
uint16_t SoftTimer_Req(uint32_t Tick)
{
uint8_t i = 0;

for (i = 0; i < TIMER_ELEMENT_NUM_MAX; i++)
{
if (SoftTimer[i].handle == 0)
{

ENTER_SECURE_SECTION();

// Timer Handle != 0
if (++HandleIndex == 0)
{
++HandleIndex;
}

SoftTimer[i].handle = HandleIndex;
SoftTimer[i].delay = Tick;
SoftTimer[i].timestamp = Tick + TimerCnt;

EXIT_SECURE_SECTION();

return (HandleIndex);
}
}

return (0);
}

//******************************************************************************************
//
//! \brief Check Timer status
//! You can check register timer status at any time.
//!
//! \param [in] Handle is Timer Handle, which you can get it from \ref SoftTimer_Req.
//! \retval
//! - \ref SOFT_TIMER_ING Timer Counting
//! - \ref SOFT_TIMER_TIMEOUT Timer TimeOut
//! - \ref SOFT_TIMER_ERR Invalid Timer Handle
//!
//! \note
//! - You must call \ref SoftTimer_Req to request an valid timer handle.
//! - Timer handle only can be used once.
//!
//
//******************************************************************************************
uint16_t SoftTimer_Check(uint16_t Handle)
{
uint8_t i = 0;

for(i = 0; i < TIMER_ELEMENT_NUM_MAX; i++)
{
if(SoftTimer[i].handle == Handle)
{
ENTER_SECURE_SECTION();
if(SoftTimer[i].delay + TimerCnt < SoftTimer[i].timestamp)
{
return (SOFT_TIMER_ING);
}
else
{
return (SOFT_TIMER_TIMEOUT);
}
EXIT_SECURE_SECTION();
}
}

return (SOFT_TIMER_ERR);
}


//******************************************************************************************
//
//! \brief SoftTimer Hook Function
//! This callback function must be called interval
//!
//! \note Typical 1ms interval
//
//******************************************************************************************
void TimerISR_Hook(void)
{

TimerCnt++;
}

最新代码,请到https://github.com/cedar-renjun/Codesnippet/tree/master/SoftTimer获取