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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
|
| dtimer.h文件
#ifndef _DTIMER_H
#define _DTIMER_H
//软件定时器结构
typedef struct
{
uint32_t SetValue;
uint32_t Target_Ticks;
uint8_t Run_Step;
} Dtimer_Typedef;
//设置软件定时器的延时值函数,这个目的是在其他地方可以修改更新延时值
void dtimer_set(Dtimer_Typedef *dtimer, uint32_t delayvalue);
//设置软件定时器延时值并开始计时函数
void dtimer_en(Dtimer_Typedef *dtimer, uint32_t delayvalue);
//设置软件定时器复位函数
void dtimer_reset(Dtimer_Typedef *dtimer);
//判断软件定时器是否刚到(到定时值时第一次会返回true,第2次返回false,相当于上升沿,只执行一次)
bool dtimer_reaching(Dtimer_Typedef *dtimer);
//判断软件定时器是否已到(已到定时值时,如果没有复位会一直返回true)
bool dtimer_reached(Dtimer_Typedef *dtimer);
#endif
dtimer.c文件
#include "main.h"
#include "dtimer.h"
//设置软件定时器的延时值函数,这个目的是在其他地方可以修改更新延时值
void dtimer_set(Dtimer_Typedef *dtimer, uint32_t delayvalue)
{
if ((*dtimer).Run_Step != 1)
{
(*dtimer).SetValue = delayvalue;
}
}
//设置软件定时器延时值并开始计时函数,定时值到后,必须dtimer_reset后才会再次执行
void dtimer_en(Dtimer_Typedef *dtimer, uint32_t delayvalue)
{
if ((*dtimer).Run_Step == 0)
{
if(delayvalue>0)
{
(*dtimer).SetValue = delayvalue;
}
(*dtimer).Target_Ticks = millis() + (*dtimer).SetValue;
(*dtimer).Run_Step = 1;
}
}
//设置软件定时器复位,复位后,遇到dtimer_en才会启用软件定时器
void dtimer_reset(Dtimer_Typedef *dtimer)
{
if ((*dtimer).Run_Step != 0)
{
(*dtimer).Run_Step = 0;
}
}
//判断软件定时器是否刚到(到定时值时第一次会返回true,第2次返回false,相当于上升沿,只执行一次)
bool dtimer_reaching(Dtimer_Typedef *dtimer)
{
if ((*dtimer).Run_Step == 1)
{
if (millis() > (*dtimer).Target_Ticks)
{
(*dtimer).Run_Step = 2;
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
//判断软件定时器是否已到(已到定时值时,如果没有复位会一直返回true)
bool dtimer_reached(Dtimer_Typedef *dtimer)
{
if (millis() > (*dtimer).Target_Ticks)
{
return true;
}
else
{
return false;
}
}
文件中millis() 为 其他c文件实现的系统毫秒计时返回值,类似于Arduino的中millis()作用,其他单片机可以用定时中断计数累加,如
volatile static uint32_t MILLIS_CNT = 0;
volatile static uint32_t TEMPMS_CNT = 0;
volatile static uint32_t SECOND_CNT = 0;
void SysTick_Handler(void) //定时器1毫秒中断调用
{
MILLIS_CNT++;
TEMPMS_CNT++;
if(TEMPMS_CNT==60)
{
SECOND_CNT++;
TEMPMS_CNT = 0;
}
}
uint32_t seconds(void) //获取系统运行当前秒
{
return SECOND_CNT;
}
uint32_t millis() //获取系统运行当前毫秒
{
return MILLIS_CNT;
}
void delay(uint32_t time) //传统的阻塞式毫秒延时函数
{
uint32_t m_times=millis()+time;
while(millis()<m_times);
}
void delayus(uint32_t time) //传统的阻塞式微秒延时函数
{
uint32_t m_times=micros()+time;
while(micros()<m_times);
}
uint32_t micros(void) //获取系统运行当前微秒
{
uint32_t ms = millis();
uint32_t systick_value = SysTick->VAL;
uint32_t systick_load = SysTick->LOAD + 1;
uint32_t us = ((systick_load - systick_value) * 1000) / systick_load;
return (ms * 1000 + us);
}
使用方法:比如P01 高电平-亮100ms,然后低电平-灭300ms
一般的方法:延时过程,其他代码被阻塞,无法执行
int main(void)
{
while(1)
{
P01=1;
delay(100);
P01=0;
delay(300);
其它代码....
}
}
非阻塞的方法:延时过程,其他代码正常执行,但P01的延时效果跟传统一样
#include "dtimer.h"
static Dtimer_Typedef DT[2]
int main(void)
{
while(1)
{
dtimer_en(&DT[0],100); //软件定时器0启用,计时100毫秒
if(dtimer_reaching(&DT[0])) //软件定时器0延时到,执行一次
{
P01=0; //P01灭
dtimer_reset(&DT[1]); //复位软件定时器1,避免第二次执行时,下面的dtimer_en不起作用
dtimer_en(&DT[1],300); //软件定时器1启用,计时300毫秒
}
else //软件定时器0延时未到
{
P01=1; //P01亮
}
if(dtimer_reaching(&DT[1])) //软件定时器1延时到,执行一次
{
dtimer_reset(&DT[0]); //复位软件定时器0
}
其他代码...
}
}
while的常规代码,遇到fun_1 while时,fun_2就会因为阻塞没有运行到
如:
int i=0;
int main(void)
{
while(1)
{
fun_1();
fun_2();
}
}
void fun_1()
{
代码1
...
while(i<100)
{
代码2
...
i++;
}
代码3
...
}
void fun_2()
{
代码4
...
}
while的非阻塞式转换,fun_1()和传统while一样,i<100时,会不断执行条件里面的代码2.. ,但此时fun_2()并没有被阻塞
int i=0;
static index=0;
int main(void)
{
while(1)
{
fun_1();
fun_2();
}
}
void fun_1()
{
switch(index)
{
case 0:
代码1
...
index=1;
break;
case 1:
if(i<100)
{
代码2
...
i++;
}
else
{
index=2;
}
break;
case 3:
代码3
...
index=0;
break;
}
}
void fun_2()
{
代码4
...
}
|