STC15单片机可设置倒计时(0~9999)报警器+Proteus仿真

STC15单片机可设置倒计时(0~9999)报警器+Proteus仿真


  • 📺Proteus仿真
    在这里插入图片描述

  • ✨2023-3-3 内容更新:

    1. 修复原程序bug,新增按键,引脚定义在P34,在设定倒计时的时候,可以减少数值。
    1. 仿真中添加了继电器,在倒计时时开启,倒计时结束关闭。
      在这里插入图片描述

📝程序代码

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
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316

/\*------------------------------------------------------------------\*/
/\* --- STC MCU International Limited -------------------------------\*/
/\* --- STC 1T Series MCU RC Demo -----------------------------------\*/
/\* --- Mobile: (86)13922805190 -------------------------------------\*/
/\* --- Fax: 86-0513-55012956,55012947,55012969 ---------------------\*/
/\* --- Tel: 86-0513-55012928,55012929,55012966 ---------------------\*/
/\* --- Web: www.GXWMCU.com -----------------------------------------\*/
/\* --- QQ: 800003751 ----------------------------------------------\*/
/\* If you want to use the program or the program referenced in the \*/
/\* article, please specify in which data and procedures from STC \*/
/\*------------------------------------------------------------------\*/


#include "config.h"
#include "GPIO.h"
#include "delay.h"

/\*\*\*\*\*\*\*\*\*\*\*\*\* 功能说明 \*\*\*\*\*\*\*\*\*\*\*\*\*\*

本程序演示跑马灯。
程序使用P2口来演示,输出低驱动。用户可以修改为别的口。

\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/

/\*\*\*\*\*\*\*\*\*\*\*\*\* 本地常量声明 \*\*\*\*\*\*\*\*\*\*\*\*\*\*/
#define u8 unsigned char
#define u16 unsigned int
#define u32 unsigned long
#define s8 signed char
#define s16 signed int
#define s32 signed long
#define KEY\_TIME 25 //按键消抖时间 (毫秒)
#define reset() IAP\_CONTR |= 0x20 //芯片复位
#define feed\_dog() WDT\_CONTR |= 0x10 //看门狗喂狗
u8 code nbr[16] = { //共阴数码管段码16进制
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
};
u8 show[4]; //4位数码管当前显示的段码 更改数码管显示的段码 只需更改此数组
u8 wink; //闪烁的数码管段码 0x01: 第一位闪烁 0x02:第二位闪烁 0x04: 第三位闪烁 0x0F:全闪烁 0x00:全不闪烁

sbit P3_0 = P3 ^ 0; //按键S1 (I/O口定义的按键未经消抖,请勿在中断外直接使用)
sbit P3_1 = P3 ^ 1; //按键S2
sbit P3_2 = P3 ^ 2; //有源蜂鸣器 低电平鸣叫
sbit P3_3 = P3 ^ 3; //继电器或MOS管 低电平吸合(导通)
u16 S1_ms, S2_ms; //按键0、按键1连续按下的时间 定时器中断计数此变量 最长65535毫秒 松开清零

u16 delayms; //定时器中断延时 (毫秒)
u16 time; //定时时间 (秒)
u16 beep_ms; //蜂鸣器鸣叫时间 (毫秒)

u16 bdata Bit16 = 0; //定义16位可位寻址变量
sbit delay = Bit16 ^ 0; //定时器中断延时毫秒开关 中断外置1 延时完中断内清0
sbit test = Bit16 ^ 1; //此值为1数码管全亮 蜂鸣器响 所有按键无效 否则正常
sbit S1 = Bit16 ^ 2; //按键0 连续按下N毫秒清0, 松开置1(定时器0中断消抖)
sbit S2 = Bit16 ^ 3; //按键1 (处理方式与按键0相同)
sbit hz10 = Bit16 ^ 4; //10Hz信号源 (定时器0中断产生,用于控制数码管闪烁)
sbit bak = Bit16 ^ 5; //按键长按识别处理用
sbit Beep = Bit16 ^ 6; //有源蜂鸣器 低电平响
sbit start = Bit16 ^ 7; //倒计时开关 置1倒计时开始 清0则结束
sbit pause = Bit16 ^ 8; //1暂停倒计时 0正常
sbit relay = Bit16 ^ 9; //继电器或MOS管 低电平吸合(导通) 1秒只能吸合或释放1次

/\*\*\*\*\*\*\*\*\*\*\*\*\* 本地变量声明 \*\*\*\*\*\*\*\*\*\*\*\*\*\*/


/\*\*\*\*\*\*\*\*\*\*\*\*\* 本地函数声明 \*\*\*\*\*\*\*\*\*\*\*\*\*\*/



/\*\*\*\*\*\*\*\*\*\*\*\*\* 外部函数和变量声明 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
void InitTimer0() { //初始化定时器0中断
TMOD = 0x01;
TH0 = 0xFC;
TL0 = 0x18;
EA = 1;
ET0 = 1;
TR0 = 1;
}

void beep(u16 ms) { //蜂鸣器鸣叫 参数:鸣叫毫秒
beep_ms = ms;
Beep = 0;
}

u16 set\_time() { //设定定时时间
u8 n = 0; //0:编辑千位 1:百位 2:十位 3:个位
u8 o[4];
o[0] = 0; o[1] = 0; o[2] = 0; o[3] = 0;
while (1) {
feed\_dog();
wink = 8 >> n;
show[0] = nbr[o[0]];
show[1] = nbr[o[1]];
show[2] = nbr[o[2]];
show[3] = nbr[o[3]];
if (S2 == 0) { //S2按下 短按加1
beep(50);
if (o[n]++ >= 9) o[n] = 0;
show[n] = nbr[o[n]];
delayms = 500; delay = 1;
while (delay && S2 == 0); //长按延时等待
while (S2_ms >= 500) { //按键长按,开始连加
feed\_dog();
delayms = 125; delay = 1; //0.125秒连加一次
while (delay && S2 == 0);
beep(50);
if (o[n]++ >= 9) o[n] = 0;
show[n] = nbr[o[n]];
}
delay = 0;
delayms = 0;
}

if (S1 == 0) { //S1按下
beep(50);
n++; //输入下一位
while (S1 == 0) {
feed\_dog();
if (S1_ms >= 1000 && !bak) { //长按退回编辑
beep(50);
n = 0;
wink = 8 >> n;
show[0] = nbr[o[0]];
show[1] = nbr[o[1]];
show[2] = nbr[o[2]];
show[3] = nbr[o[3]];
bak = 1;
}
}

if (bak) {
bak = 0;
continue;
}

if (n >= 4) { //个位输入完成
wink = 0;
return o[0] \* 1000 + o[1] \* 100 + o[2] \* 10 + o[3];

}
}
}
// return 0;
}


/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* IO配置函数 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
void GPIO\_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //结构定义
GPIO_InitStructure.Pin = GPIO_Pin_All; //指定要初始化的IO, GPIO\_Pin\_0 ~ GPIO\_Pin\_7, 或操作
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO\_PullUp,GPIO\_HighZ,GPIO\_OUT\_OD,GPIO\_OUT\_PP
GPIO\_Inilize(GPIO_P2,&GPIO_InitStructure); //初始化
}



/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 主函数 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
void main(void)
{
u8 i = 0;
Beep = 1;
WDT_CONTR = 0x27; //初始化看门狗
P1M0 = 0x0F; P1M1 = 0x00; //P1.0~P1.3强推挽
P2M0 = 0xFF; P2M1 = 0x00; //P2.0~P2.7强推挽
//上电1秒数码管全亮 蜂鸣器响
test = 1;
GPIO\_config();
InitTimer0();
delayms = 1000; delay = 1;
while (delay);
test = 0;

show[0] = nbr[0];
show[1] = nbr[0];
show[2] = nbr[0];
show[3] = nbr[0];
while(1)
{
relay = 1;
pause = 0;
do { //时间设定
time = set\_time();
} while (!time);
time -= 1;
start = 1;
relay = 0;
while (start) {
feed\_dog();
if (S1 == 0) { //S1按下蜂鸣器响1下
beep(50);
while (S1 == 0) {
feed\_dog();
}
}

if (S2 == 0) { //S2按下暂停倒计时
beep(50);
pause = !pause;
relay = pause;
while (S2 == 0) {
feed\_dog();
if (pause && S2_ms >= 3000) { //长按3秒复位
\_nop\_(); \_nop\_(); \_nop\_(); \_nop\_();
reset();
\_nop\_(); \_nop\_(); \_nop\_(); \_nop\_();
}
}
}

}
//倒计时结束
show[0] = 0x79; //E
show[1] = 0x54; //n
show[2] = 0x5E; //d
show[3] = 0x00;
for (i = 0; i < 6; i++) { //蜂鸣器响6下
delayms = 500; delay = 1; while (delay);
beep(500);
while (!Beep);
feed\_dog();
}

while (1) {
feed\_dog();
if (S1 == 0 || S2 == 0) {
beep(50);
while (S1 == 0 || S2 == 0) {
feed\_dog();
}
break;
}
}
}
}

void Timer0Interrupt() interrupt 1{ //12Mhz 1mS定时器中断
static u8 seg = 0; //当前正在扫描的数码管段码 4位数码管 范围:0~3
static u8 ms1 = 0;
static u16 ms = 0, ms2 = 0;
TH0 = 0xFC;
TL0 = 0x18;
if (delay && !--delayms) { //延时任意毫秒
delay = 0;
}
//数码管动态扫描处理
P1 |= 0xF; //消影
P2 = test ? 0xFF : (wink & (1 << (3 ^ seg)) && !hz10 ? 0 : show[seg]); //段码
P1 &= ~(1 << seg); //位码
if (++seg >= 4) seg = 0;

if (test) { //测试模式
S1 = 1; S2 = 1;
P3_2 = 0;
return;
}

//蜂鸣器处理
P3_2 = Beep;
if (!Beep && !--beep_ms) {
Beep = 1;
}
if (++ms1 >= 50) {
ms1 = 0;
hz10 = !hz10;
}

//按键处理
if (P3_0 == 0) {
if (S1_ms != 0xFFFF) S1_ms++;
}
else {
S1_ms = 0;
}

if (P3_1 == 0) {
if (S2_ms != 0xFFFF) S2_ms++;
}
else {
S2_ms = 0;
}

S1 = !(S1_ms >= KEY_TIME);
S2 = !(S2_ms >= KEY_TIME);
//继电器处理
if (++ms2 >= 1000) { //继电器1秒只能进行1次吸合或释放,防止频繁开关导致设备损坏
ms2 = 0;
P3_3 = relay;
}
//时间倒计时处理
if (start) {
if (pause) {
wink = 0xF;
}
else {
wink = 0;
if (++ms >= 1000) {
ms = 0;
show[0] = nbr[time / 1000 % 10];
show[1] = nbr[time / 100 % 10];
show[2] = nbr[time / 10 % 10];
show[3] = nbr[time % 10];

if (!time--) { //倒计时结束
start = 0;
relay = 1;
}
}
}
}
}




📚程序源码和仿真资源

1
2
3
链接:https://pan.baidu.com/s/1DjhHyl\_yG3VP1gXn8rU5iQ 
提取码:07fx

  • ✅资源更新(2023-3-3)
1
2
3
4

链接: https://pan.baidu.com/s/1xaQZnQ3xNZuZpbiDwixsjg
提取码: 8nr4