基于STM32的智能门锁系统设计

本文最后更新于:2022年5月29日 上午

一、项目介绍

本系统由STM32F103C8T6单片机主控芯片、电源供电稳压模块、LCD显示屏模块、薄膜矩阵键盘模块、指纹识别模块、RFID射频模块、蜂鸣器模块以及舵机模块组成。实现以下功能:

  1. 支持指纹、NFC、密码及感应卡四种开锁方式;

  2. 具有分级管理权限,管理员才可增删信息,在管理员模式,可以进行更改开锁密码和管理员密码,以及增删指纹/感应卡信息。

  3. 密码断电也不会丢失,具有断电存储功能,设定指纹录入、感应卡信息等,掉电均会存储;

  4. 支持虚伪密码,在正确密码前后可随意输入数字保护真实密码;

  5. 当密码/指纹开锁失败,系统会有错误提示信息,当多次开锁失败后,系统便会劫持开锁;

  6. 系统具备管理员密码,即使忘记密码,管理员密码也可以打开门锁。

先放一张实物图,一个小玩意,做得比较粗糙,见笑了。

YhTmWR.jpg

二、系统构成

为了实现上述需求,需要对各个传感器电路进行设计搭建,系统整体框架如下图所示。

YhTeY9.png

三、程序设计图

YhT4mT.png

四、程序模块化设计

1,AS608指纹识别模块

ATK-AS608生物指纹识别模块是ALIENTEK公司推出的一种高性能光学指纹识别模块。AS608指纹识别模块采用了中国著名的指纹识别芯片公司杭州晟元芯片技术有限公司的AS608指纹识别芯片。该芯片具有很高的效率去获取图像并进行数据特征的提取和处理。该模块有串行通信端口和USB通信接口。用户使用该模块,不需要理会内部的繁杂操作,比如图像处理和指纹识别算法,只需要通过串口发送指令来进行控制即可。该模块可应用的场景有许多种,例如指纹锁,保险箱,指纹门禁系统,考勤机等。详细资料查看下面链接下载:

链接: https://pan.baidu.com/s/1iyRFzPl_aPtjznfkL0ImSA
提取码:t6dr

Yh7j8s.png

(1)as608.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
#ifndef __AS608_H
#define __AS608_H

#include "stm32f10x.h"
#include "usart.h"
#include "string.h"
#include "systick.h"

//Pin definition
/*************************************************************************/
#define AS608_GPIO_PORT GPIOA
#define AS608_GPIO_CLK RCC_APB2Periph_GPIOA
#define AS608_TOUCH_PIN GPIO_Pin_1

/*************************************************************************/

#define PS_Sta GPIO_ReadInputDataBit(AS608_GPIO_PORT,AS608_TOUCH_PIN) //读指纹模块状态引脚
#define CharBuffer1 0x01
#define CharBuffer2 0x02

extern u32 AS608Addr; //模块地址

typedef struct
{
u16 pageID; //指纹ID
u16 mathscore; //匹配得分
}SearchResult;

typedef struct
{
u16 PS_max; //指纹最大容量
u8 PS_level; //安全等级
u32 PS_addr;
u8 PS_size; //通讯数据包大小
u8 PS_N; //波特率基数N
}SysPara;

void PS_StaGPIO_Init(void); //初始化PA6读状态引脚

u8 PS_GetImage(void); //录入图像
u8 PS_GenChar(u8 BufferID); //生成特征
u8 PS_Match(void); //精确比对两枚指纹特征
u8 PS_Search(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p);//搜索指纹
u8 PS_RegModel(void); //合并特征(生成模板)
u8 PS_StoreChar(u8 BufferID,u16 PageID); //储存模板
u8 PS_DeletChar(u16 PageID,u16 N); //删除模板
u8 PS_Empty(void); //清空指纹库
u8 PS_WriteReg(u8 RegNum,u8 DATA); //写系统寄存器
u8 PS_ReadSysPara(SysPara *p); //读系统基本参数
u8 PS_SetAddr(u32 addr); //设置模块地址
u8 PS_WriteNotepad(u8 NotePageNum,u8 *content); //写记事本
u8 PS_ReadNotepad(u8 NotePageNum,u8 *note); //读记事
u8 PS_HighSpeedSearch(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p);//高速搜索
u8 PS_ValidTempleteNum(u16 *ValidN); //读有效模板个数
u8 PS_HandShake(u32 *PS_Addr); //与AS608模块握手
const char *EnsureMessage(u8 ensure); //确认码错误信息解析
#endif /* __AS608_H */

(2)as608.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
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
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
/**
******************************************************************************
* @file as608.c
* @author Soso
* @date 2019-12-17
* @brief AS608 fingerprint recognition module driver code.
******************************************************************************
*/
#include "as608.h"

u32 AS608Addr = 0XFFFFFFFF; //默认

//初始化PA6为下拉输入
//读摸出感应状态(触摸感应时输出高电平信号)
void PS_StaGPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(AS608_GPIO_CLK, ENABLE);//使能GPIOA时钟
//初始化读状态引脚GPIOA
GPIO_InitStructure.GPIO_Pin = AS608_TOUCH_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//输入下拉模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
GPIO_Init(AS608_GPIO_PORT, &GPIO_InitStructure);//初始化GPIO


}

//发送包头
static void SendHead(void)
{
Usart_SendByte(AS608_USART,0xEF);
Usart_SendByte(AS608_USART,0x01);
}
//发送地址
static void SendAddr(void)
{
Usart_SendByte(AS608_USART,AS608Addr>>24);
Usart_SendByte(AS608_USART,AS608Addr>>16);
Usart_SendByte(AS608_USART,AS608Addr>>8);
Usart_SendByte(AS608_USART,AS608Addr);
}
//发送包标识,
static void SendFlag(u8 flag)
{
Usart_SendByte(AS608_USART,flag);
}
//发送包长度
static void SendLength(int length)
{
Usart_SendByte(AS608_USART,length>>8);
Usart_SendByte(AS608_USART,length);
}
//发送指令码
static void Sendcmd(u8 cmd)
{
Usart_SendByte(AS608_USART,cmd);
}
//发送校验和
static void SendCheck(u16 check)
{
Usart_SendByte(AS608_USART,check>>8);
Usart_SendByte(AS608_USART,check);
}
//判断中断接收的数组有没有应答包
//waittime为等待中断接收数据的时间(单位1ms)
//返回值:数据包首地址
static u8 *JudgeStr(u16 waittime)
{
char *data;
u8 str[8];
str[0]=0xef;
str[1]=0x01;
str[2]=AS608Addr>>24;
str[3]=AS608Addr>>16;
str[4]=AS608Addr>>8;
str[5]=AS608Addr;
str[6]=0x07;
str[7]='\0';
AS608_RX_STA=0;
while(--waittime)
{
delay_ms(1);
if(AS608_RX_STA&0X8000)//接收到一次数据
{
AS608_RX_STA=0;
data=strstr((const char*)AS608_RX_BUF,(const char*)str);
if(data)
return (u8*)data;
}
}
return 0;
}

//录入图像 PS_GetImage
//功能:探测手指,探测到后录入指纹图像存于ImageBuffer。
//模块返回确认字
u8 PS_GetImage(void)
{
u16 temp;
u8 ensure;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(0x03);
Sendcmd(0x01);
temp = 0x01+0x03+0x01;
SendCheck(temp);
data = JudgeStr(2000);
if(data)
ensure = data[9];
else
ensure = 0xff;
return ensure;
}

//生成特征 PS_GenChar
//功能:将ImageBuffer中的原始图像生成指纹特征文件存于CharBuffer1或CharBuffer2
//参数:BufferID --> charBuffer1:0x01 charBuffer1:0x02
//模块返回确认字
u8 PS_GenChar(u8 BufferID)
{
u16 temp;
u8 ensure;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(0x04);
Sendcmd(0x02);
Usart_SendByte(AS608_USART,BufferID);
temp = 0x01+0x04+0x02+BufferID;
SendCheck(temp);
data = JudgeStr(2000);
if(data)
ensure = data[9];
else
ensure = 0xff;
return ensure;
}

//精确比对两枚指纹特征 PS_Match
//功能:精确比对CharBuffer1 与CharBuffer2 中的特征文件
//模块返回确认字
u8 PS_Match(void)
{
u16 temp;
u8 ensure;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(0x03);
Sendcmd(0x03);
temp = 0x01+0x03+0x03;
SendCheck(temp);
data = JudgeStr(2000);
if(data)
ensure = data[9];
else
ensure = 0xff;
return ensure;
}

//搜索指纹 PS_Search
//功能:以CharBuffer1或CharBuffer2中的特征文件搜索整个或部分指纹库.若搜索到,则返回页码。
//参数: BufferID @ref CharBuffer1 CharBuffer2
//说明: 模块返回确认字,页码(相配指纹模板)
u8 PS_Search(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p)
{
u16 temp;
u8 ensure;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(0x08);
Sendcmd(0x04);
Usart_SendByte(AS608_USART,BufferID);
Usart_SendByte(AS608_USART,StartPage>>8);
Usart_SendByte(AS608_USART,StartPage);
Usart_SendByte(AS608_USART,PageNum>>8);
Usart_SendByte(AS608_USART,PageNum);
temp = 0x01+0x08+0x04+BufferID+(StartPage>>8)+(u8)StartPage+(PageNum>>8)+(u8)PageNum;
SendCheck(temp);
data = JudgeStr(2000);
if(data)
{
ensure = data[9];
p->pageID = (data[10]<<8)+data[11];
p->mathscore = (data[12]<<8)+data[13];
}
else
ensure = 0xff;
return ensure;
}

//合并特征(生成模板)PS_RegModel
//功能:将CharBuffer1与CharBuffer2中的特征文件合并生成 模板,结果存于CharBuffer1与CharBuffer2
//说明: 模块返回确认字
u8 PS_RegModel(void)
{
u16 temp;
u8 ensure;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(0x03);
Sendcmd(0x05);
temp = 0x01+0x03+0x05;
SendCheck(temp);
data = JudgeStr(2000);
if(data)
ensure = data[9];
else
ensure = 0xff;
return ensure;
}

//储存模板 PS_StoreChar
//功能:将 CharBuffer1 或 CharBuffer2 中的模板文件存到 PageID 号flash数据库位置。
//参数: BufferID @ref charBuffer1:0x01 charBuffer1:0x02
// PageID(指纹库位置号)
//说明: 模块返回确认字
u8 PS_StoreChar(u8 BufferID,u16 PageID)
{
u16 temp;
u8 ensure;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(0x06);
Sendcmd(0x06);
Usart_SendByte(AS608_USART,BufferID);
Usart_SendByte(AS608_USART,PageID>>8);
Usart_SendByte(AS608_USART,PageID);
temp = 0x01+0x06+0x06+BufferID+(PageID>>8)+(u8)PageID;
SendCheck(temp);
data = JudgeStr(2000);
if(data)
ensure = data[9];
else
ensure = 0xff;
return ensure;
}

//删除模板 PS_DeletChar
//功能: 删除flash数据库中指定ID号开始的N个指纹模板
//参数: PageID(指纹库模板号),N删除的模板个数。
//说明: 模块返回确认字
u8 PS_DeletChar(u16 PageID,u16 N)
{
u16 temp;
u8 ensure;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(0x07);
Sendcmd(0x0C);
Usart_SendByte(AS608_USART,PageID>>8);
Usart_SendByte(AS608_USART,PageID);
Usart_SendByte(AS608_USART,N>>8);
Usart_SendByte(AS608_USART,N);
temp = 0x01+0x07+0x0C+(PageID>>8)+(u8)PageID+(N>>8)+(u8)N;
SendCheck(temp);
data = JudgeStr(2000);
if(data)
ensure = data[9];
else
ensure = 0xff;
return ensure;
}

//清空指纹库 PS_Empty
//功能: 删除flash数据库中所有指纹模板
//参数: 无
//说明: 模块返回确认字
u8 PS_Empty(void)
{
u16 temp;
u8 ensure;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(0x03);
Sendcmd(0x0D);
temp = 0x01+0x03+0x0D;
SendCheck(temp);
data = JudgeStr(2000);
if(data)
ensure = data[9];
else
ensure = 0xff;
return ensure;
}
//写系统寄存器 PS_WriteReg
//功能: 写模块寄存器
//参数: 寄存器序号RegNum:4\5\6
//说明: 模块返回确认字
u8 PS_WriteReg(u8 RegNum,u8 DATA)
{
u16 temp;
u8 ensure;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(0x05);
Sendcmd(0x0E);
Usart_SendByte(AS608_USART,RegNum);
Usart_SendByte(AS608_USART,DATA);
temp = RegNum+DATA+0x01+0x05+0x0E;
SendCheck(temp);
data = JudgeStr(2000);
if(data)
ensure = data[9];
else
ensure = 0xff;
// if(ensure==0)
// printf("\r\n设置参数成功!");
// else
// printf("\r\n%s",EnsureMessage(ensure));
return ensure;
}

//读系统基本参数 PS_ReadSysPara
//功能: 读取模块的基本参数(波特率,包大小等)
//参数: 无
//说明: 模块返回确认字 + 基本参数(16bytes)
u8 PS_ReadSysPara(SysPara *p)
{
u16 temp;
u8 ensure;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(0x03);
Sendcmd(0x0F);
temp = 0x01+0x03+0x0F;
SendCheck(temp);
data = JudgeStr(1000);
if(data)
{
ensure = data[9];
p->PS_max = (data[14]<<8)+data[15];
p->PS_level = data[17];
p->PS_addr = (data[18]<<24)+(data[19]<<16)+(data[20]<<8)+data[21];
p->PS_size = data[23];
p->PS_N = data[25];
}
else
ensure=0xff;
// if(ensure==0x00)
// {
// printf("\r\n模块最大指纹容量=%d",p->PS_max);
// printf("\r\n对比等级=%d",p->PS_level);
// printf("\r\n地址=%x",p->PS_addr);
// printf("\r\n波特率=%d",p->PS_N*9600);
// }
// else
// printf("\r\n%s",EnsureMessage(ensure));
return ensure;
}

//设置模块地址 PS_SetAddr
//功能: 设置模块地址
//参数: PS_addr
//说明: 模块返回确认字
u8 PS_SetAddr(u32 PS_addr)
{
u16 temp;
u8 ensure;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(0x07);
Sendcmd(0x15);
Usart_SendByte(AS608_USART,PS_addr>>24);
Usart_SendByte(AS608_USART,PS_addr>>16);
Usart_SendByte(AS608_USART,PS_addr>>8);
Usart_SendByte(AS608_USART,PS_addr);
temp = 0x01+0x07+0x15+(u8)(PS_addr>>24)+(u8)(PS_addr>>16)+(u8)(PS_addr>>8) +(u8)PS_addr;
SendCheck(temp);
AS608Addr = PS_addr;//发送完指令,更换地址
data = JudgeStr(2000);
if(data)
ensure = data[9];
else
ensure = 0xff;
// if(ensure==0x00)
// printf("\r\n设置地址成功!");
// else
// printf("\r\n%s",EnsureMessage(ensure));
return ensure;
}

//功能: 模块内部为用户开辟了256bytes的FLASH空间用于存用户记事本,
// 该记事本逻辑上被分成 16 个页。
//参数: NotePageNum(0~15),Byte32(要写入内容,32个字节)
//说明: 模块返回确认字
u8 PS_WriteNotepad(u8 NotePageNum,u8 *Byte32)
{
u16 temp;
u8 ensure,i;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(36);
Sendcmd(0x18);
Usart_SendByte(AS608_USART,NotePageNum);
for(i=0;i<32;i++)
{
Usart_SendByte(AS608_USART,Byte32[i]);
temp += Byte32[i];
}
temp = 0x01+36+0x18+NotePageNum+temp;
SendCheck(temp);
data = JudgeStr(2000);
if(data)
ensure = data[9];
else
ensure = 0xff;
return ensure;
}

//读记事PS_ReadNotepad
//功能: 读取FLASH用户区的128bytes数据
//参数: NotePageNum(0~15)
//说明: 模块返回确认字+用户信息
u8 PS_ReadNotepad(u8 NotePageNum,u8 *Byte32)
{
u16 temp;
u8 ensure,i;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(0x04);
Sendcmd(0x19);
Usart_SendByte(AS608_USART,NotePageNum);
temp = 0x01+0x04+0x19+NotePageNum;
SendCheck(temp);
data = JudgeStr(2000);
if(data)
{
ensure = data[9];
for(i=0;i<32;i++)
{
Byte32[i] = data[10+i];
}
}
else
ensure = 0xff;
return ensure;
}

//高速搜索PS_HighSpeedSearch
//功能:以 CharBuffer1或CharBuffer2中的特征文件高速搜索整个或部分指纹库。
// 若搜索到,则返回页码,该指令对于的确存在于指纹库中 ,且登录时质量
// 很好的指纹,会很快给出搜索结果。
//参数: BufferID, StartPage(起始页),PageNum(页数)
//说明: 模块返回确认字+页码(相配指纹模板)
u8 PS_HighSpeedSearch(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p)
{
u16 temp;
u8 ensure;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(0x08);
Sendcmd(0x1b);
Usart_SendByte(AS608_USART,BufferID);
Usart_SendByte(AS608_USART,StartPage>>8);
Usart_SendByte(AS608_USART,StartPage);
Usart_SendByte(AS608_USART,PageNum>>8);
Usart_SendByte(AS608_USART,PageNum);
temp = 0x01+0x08+0x1b+BufferID+(StartPage>>8)+(u8)StartPage+(PageNum>>8)+(u8)PageNum;
SendCheck(temp);
data = JudgeStr(2000);
if(data)
{
ensure = data[9];
p->pageID = (data[10]<<8) +data[11];
p->mathscore = (data[12]<<8) +data[13];
}
else
ensure=0xff;
return ensure;
}

//读有效模板个数 PS_ValidTempleteNum
//功能:读有效模板个数
//参数: 无
//说明: 模块返回确认字+有效模板个数ValidN
u8 PS_ValidTempleteNum(u16 *ValidN)
{
u16 temp;
u8 ensure;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01); //命令包标识
SendLength(0x03);
Sendcmd(0x1d);
temp = 0x01+0x03+0x1d;
SendCheck(temp);
data=JudgeStr(2000);
if(data)
{
ensure=data[9];
*ValidN = (data[10]<<8) +data[11];
}
else
ensure=0xff;

// if(ensure==0x00)
// {
// printf("\r\n有效指纹个数=%d",(data[10]<<8)+data[11]);
// }
// else
// printf("\r\n%s",EnsureMessage(ensure));
return ensure;
}

//与AS608握手 PS_HandShake
//参数: PS_Addr地址指针
//说明: 模块返新地址(正确地址)
u8 PS_HandShake(u32 *PS_Addr)
{
SendHead();
SendAddr();
Usart_SendByte(AS608_USART,0X01);
Usart_SendByte(AS608_USART,0X00);
Usart_SendByte(AS608_USART,0X00);
delay_ms(200);
if(AS608_RX_STA&0X8000)//接收到数据
{
//判断是不是模块返回的应答包
if( AS608_RX_BUF[0]==0XEF&&AS608_RX_BUF[1]==0X01&&AS608_RX_BUF[6]==0X07)
{
*PS_Addr=(AS608_RX_BUF[2]<<24) + (AS608_RX_BUF[3]<<16)
+(AS608_RX_BUF[4]<<8) + (AS608_RX_BUF[5]);
AS608_RX_STA = 0;
return 0;
}
AS608_RX_STA=0;
}
return 1;
}

//模块应答包确认码信息解析
//功能:解析确认码错误信息返回信息
//参数: ensure
const char *EnsureMessage(u8 ensure)
{
const char *p;
switch(ensure)
{
case 0x00:
p="OK";break;
case 0x01:
p="数据包接收错误";break;
case 0x02:
p="传感器上没有手指";break;
case 0x03:
p="录入指纹图像失败";break;
case 0x04:
p="指纹图像太干、太淡而生不成特征";break;
case 0x05:
p="指纹图像太湿、太糊而生不成特征";break;
case 0x06:
p="指纹图像太乱而生不成特征";break;
case 0x07:
p="指纹图像正常,但特征点太少";break;
case 0x08:
p="指纹不匹配";break;
case 0x09:
p="没搜索到指纹";break;
case 0x0a:
p="特征合并失败";break;
case 0x0b:
p="访问指纹库地址序号超出指纹库范围";break;
case 0x10:
p="删除模板失败";break;
case 0x11:
p="清空指纹库失败";break;
case 0x15:
p="缓冲区内没有有效原始图";break;
case 0x18:
p="读写 FLASH 出错";break;
case 0x19:
p="未定义错误";break;
case 0x1a:
p="无效寄存器号";break;
case 0x1b:
p="寄存器设定内容错误";break;
case 0x1c:
p="记事本页码指定错误";break;
case 0x1f:
p="指纹库满";break;
case 0x20:
p="地址错误";break;
default :
p="模块返回确认码有误";break;
}
return p;
}

2,RFID-RC522读卡模块

RFID-RC522读卡模块集成MFRC522芯片电路,具有低电压、低成本、小体积和非接触式读取的特点。该模块使用方便,成本低廉,采用3.3v电压供电,使用SPI接口进行通信,它与主机间通信采用SPI模式,有利于减少连线,缩小PCB板体积,降低成本,可以保证模块稳定可靠的工作、读卡距离远。该模块实物图如下图所示。

Qvlif1.png

(1)rc522.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
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
#ifndef __RC522_H
#define __RC522_H

#include "stm32f10x.h"
#include "systick.h"


/////////////////////////////////////////////////////////////////////
//MF522命令字
/////////////////////////////////////////////////////////////////////
#define PCD_IDLE 0x00 //取消当前命令
#define PCD_AUTHENT 0x0E //验证密钥
#define PCD_RECEIVE 0x08 //接收数据
#define PCD_TRANSMIT 0x04 //发送数据
#define PCD_TRANSCEIVE 0x0C //发送并接收数据
#define PCD_RESETPHASE 0x0F //复位
#define PCD_CALCCRC 0x03 //CRC计算

/////////////////////////////////////////////////////////////////////
//Mifare_One卡片命令字
/////////////////////////////////////////////////////////////////////
#define PICC_REQIDL 0x26 //寻天线区内未进入休眠状态
#define PICC_REQALL 0x52 //寻天线区内全部卡
#define PICC_ANTICOLL1 0x93 //防冲撞
#define PICC_ANTICOLL2 0x95 //防冲撞
#define PICC_AUTHENT1A 0x60 //验证A密钥
#define PICC_AUTHENT1B 0x61 //验证B密钥
#define PICC_READ 0x30 //读块
#define PICC_WRITE 0xA0 //写块
#define PICC_DECREMENT 0xC0 //扣款
#define PICC_INCREMENT 0xC1 //充值
#define PICC_RESTORE 0xC2 //调块数据到缓冲区
#define PICC_TRANSFER 0xB0 //保存缓冲区中数据
#define PICC_HALT 0x50 //休眠

/////////////////////////////////////////////////////////////////////
//MF522 FIFO长度定义
/////////////////////////////////////////////////////////////////////
#define DEF_FIFO_LENGTH 64 //FIFO size=64byte
#define MAXRLEN 18

/////////////////////////////////////////////////////////////////////
//MF522寄存器定义
/////////////////////////////////////////////////////////////////////
// PAGE 0
#define RFU00 0x00
#define CommandReg 0x01
#define ComIEnReg 0x02
#define DivlEnReg 0x03
#define ComIrqReg 0x04
#define DivIrqReg 0x05
#define ErrorReg 0x06
#define Status1Reg 0x07
#define Status2Reg 0x08
#define FIFODataReg 0x09
#define FIFOLevelReg 0x0A
#define WaterLevelReg 0x0B
#define ControlReg 0x0C
#define BitFramingReg 0x0D
#define CollReg 0x0E
#define RFU0F 0x0F
// PAGE 1
#define RFU10 0x10
#define ModeReg 0x11
#define TxModeReg 0x12
#define RxModeReg 0x13
#define TxControlReg 0x14
#define TxAutoReg 0x15
#define TxSelReg 0x16
#define RxSelReg 0x17
#define RxThresholdReg 0x18
#define DemodReg 0x19
#define RFU1A 0x1A
#define RFU1B 0x1B
#define MifareReg 0x1C
#define RFU1D 0x1D
#define RFU1E 0x1E
#define SerialSpeedReg 0x1F
// PAGE 2
#define RFU20 0x20
#define CRCResultRegM 0x21
#define CRCResultRegL 0x22
#define RFU23 0x23
#define ModWidthReg 0x24
#define RFU25 0x25
#define RFCfgReg 0x26
#define GsNReg 0x27
#define CWGsCfgReg 0x28
#define ModGsCfgReg 0x29
#define TModeReg 0x2A
#define TPrescalerReg 0x2B
#define TReloadRegH 0x2C
#define TReloadRegL 0x2D
#define TCounterValueRegH 0x2E
#define TCounterValueRegL 0x2F
// PAGE 3
#define RFU30 0x30
#define TestSel1Reg 0x31
#define TestSel2Reg 0x32
#define TestPinEnReg 0x33
#define TestPinValueReg 0x34
#define TestBusReg 0x35
#define AutoTestReg 0x36
#define VersionReg 0x37
#define AnalogTestReg 0x38
#define TestDAC1Reg 0x39
#define TestDAC2Reg 0x3A
#define TestADCReg 0x3B
#define RFU3C 0x3C
#define RFU3D 0x3D
#define RFU3E 0x3E
#define RFU3F 0x3F

/////////////////////////////////////////////////////////////////////
//和MF522通讯时返回的错误代码
/////////////////////////////////////////////////////////////////////
#define MI_OK 0x26
#define MI_NOTAGERR 0xcc
#define MI_ERR 0xbb



/*********************************** RC522 引脚定义 *********************************************/
#define RC522_GPIO_CS_CLK_FUN RCC_APB2PeriphClockCmd
#define RC522_GPIO_CS_CLK RCC_APB2Periph_GPIOA
#define RC522_GPIO_CS_PORT GPIOA
#define RC522_GPIO_CS_PIN GPIO_Pin_4
#define RC522_GPIO_CS_Mode GPIO_Mode_Out_PP

#define RC522_GPIO_SCK_CLK_FUN RCC_APB2PeriphClockCmd
#define RC522_GPIO_SCK_CLK RCC_APB2Periph_GPIOA
#define RC522_GPIO_SCK_PORT GPIOA
#define RC522_GPIO_SCK_PIN GPIO_Pin_5
#define RC522_GPIO_SCK_Mode GPIO_Mode_Out_PP

#define RC522_GPIO_MOSI_CLK_FUN RCC_APB2PeriphClockCmd
#define RC522_GPIO_MOSI_CLK RCC_APB2Periph_GPIOA
#define RC522_GPIO_MOSI_PORT GPIOA
#define RC522_GPIO_MOSI_PIN GPIO_Pin_7
#define RC522_GPIO_MOSI_Mode GPIO_Mode_Out_PP

#define RC522_GPIO_MISO_CLK_FUN RCC_APB2PeriphClockCmd
#define RC522_GPIO_MISO_CLK RCC_APB2Periph_GPIOA
#define RC522_GPIO_MISO_PORT GPIOA
#define RC522_GPIO_MISO_PIN GPIO_Pin_6
#define RC522_GPIO_MISO_Mode GPIO_Mode_IN_FLOATING

#define RC522_GPIO_RST_CLK_FUN RCC_APB2PeriphClockCmd
#define RC522_GPIO_RST_CLK RCC_APB2Periph_GPIOB
#define RC522_GPIO_RST_PORT GPIOB
#define RC522_GPIO_RST_PIN GPIO_Pin_0
#define RC522_GPIO_RST_Mode GPIO_Mode_Out_PP



/*********************************** RC522 函数宏定义*********************************************/
#define RC522_CS_Enable() GPIO_ResetBits ( RC522_GPIO_CS_PORT, RC522_GPIO_CS_PIN )
#define RC522_CS_Disable() GPIO_SetBits ( RC522_GPIO_CS_PORT, RC522_GPIO_CS_PIN )

#define RC522_Reset_Enable() GPIO_ResetBits( RC522_GPIO_RST_PORT, RC522_GPIO_RST_PIN )
#define RC522_Reset_Disable() GPIO_SetBits ( RC522_GPIO_RST_PORT, RC522_GPIO_RST_PIN )

#define RC522_SCK_0() GPIO_ResetBits( RC522_GPIO_SCK_PORT, RC522_GPIO_SCK_PIN )
#define RC522_SCK_1() GPIO_SetBits ( RC522_GPIO_SCK_PORT, RC522_GPIO_SCK_PIN )

#define RC522_MOSI_0() GPIO_ResetBits( RC522_GPIO_MOSI_PORT, RC522_GPIO_MOSI_PIN )
#define RC522_MOSI_1() GPIO_SetBits ( RC522_GPIO_MOSI_PORT, RC522_GPIO_MOSI_PIN )

#define RC522_MISO_GET() GPIO_ReadInputDataBit ( RC522_GPIO_MISO_PORT, RC522_GPIO_MISO_PIN )


/*********************************** 函数 *********************************************/
void RC522_Init( void ); // 初始化
void PcdReset( void ); // 复位
void M500PcdConfigISOType( u8 type ); // 工作方式
char PcdRequest( u8 req_code, u8 * pTagType ); // 寻卡
char PcdAnticoll( u8 * pSnr); // 读卡号


#endif /* __RC522_H */

(1)rc522.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
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
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
/**
******************************************************************************
* @file rc522.c
* @author Soso
* @date 2019-12-17
* @brief RC522 module driver code.
******************************************************************************
*/

#include "rc522.h"

#define RC522_DELAY() delay_us(200)


static void RC522_SPI_Config ( void )
{
/* SPI_InitTypeDef SPI_InitStructure */
GPIO_InitTypeDef GPIO_InitStructure;

/*!< Configure SPI_RC522_SPI pins: CS */
RC522_GPIO_CS_CLK_FUN ( RC522_GPIO_CS_CLK, ENABLE );
GPIO_InitStructure.GPIO_Pin = RC522_GPIO_CS_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = RC522_GPIO_CS_Mode;
GPIO_Init(RC522_GPIO_CS_PORT, &GPIO_InitStructure);

/*!< Configure SPI_RC522_SPI pins: SCK */
RC522_GPIO_SCK_CLK_FUN ( RC522_GPIO_SCK_CLK, ENABLE );
GPIO_InitStructure.GPIO_Pin = RC522_GPIO_SCK_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = RC522_GPIO_SCK_Mode;
GPIO_Init(RC522_GPIO_SCK_PORT, &GPIO_InitStructure);

/*!< Configure SPI_RC522_SPI pins: MOSI */
RC522_GPIO_MOSI_CLK_FUN ( RC522_GPIO_MOSI_CLK, ENABLE );
GPIO_InitStructure.GPIO_Pin = RC522_GPIO_MOSI_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = RC522_GPIO_MOSI_Mode;
GPIO_Init(RC522_GPIO_MOSI_PORT, &GPIO_InitStructure);

/*!< Configure SPI_RC522_SPI pins: MISO */
RC522_GPIO_MISO_CLK_FUN ( RC522_GPIO_MISO_CLK, ENABLE );
GPIO_InitStructure.GPIO_Pin = RC522_GPIO_MISO_PIN;
GPIO_InitStructure.GPIO_Mode = RC522_GPIO_MISO_Mode;
GPIO_Init(RC522_GPIO_MISO_PORT, &GPIO_InitStructure);


/*!< Configure SPI_RC522_SPI pins: RST */
RC522_GPIO_RST_CLK_FUN ( RC522_GPIO_RST_CLK, ENABLE );
GPIO_InitStructure.GPIO_Pin = RC522_GPIO_RST_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = RC522_GPIO_RST_Mode;
GPIO_Init(RC522_GPIO_RST_PORT, &GPIO_InitStructure);

}

void RC522_Init( void )
{
RC522_SPI_Config();
RC522_Reset_Disable();
RC522_CS_Disable();
PcdReset(); // 复位
M500PcdConfigISOType('A'); //设置工作方式
}


/*
* 函数名:SPI_RC522_SendByte
* 描述 :向RC522发送1 Byte 数据
* 输入 :byte,要发送的数据
* 返回 : RC522返回的数据
* 调用 :内部调用
*/
void SPI_RC522_SendByte ( u8 byte )
{
u8 counter;


for(counter=0;counter<8;counter++)
{
if ( byte & 0x80 )
RC522_MOSI_1 ();
else
RC522_MOSI_0 ();

RC522_DELAY();
RC522_SCK_0 ();
RC522_DELAY();
RC522_SCK_1();
RC522_DELAY();

byte <<= 1;
}

}

/*
* 函数名:SPI_RC522_ReadByte
* 描述 :从RC522发送1 Byte 数据
* 输入 :无
* 返回 : RC522返回的数据
* 调用 :内部调用
*/
u8 SPI_RC522_ReadByte ( void )
{
u8 counter;
u8 SPI_Data;

for(counter=0;counter<8;counter++)
{
SPI_Data <<= 1;

RC522_SCK_0 ();
RC522_DELAY();

if(RC522_MISO_GET() == 1)
SPI_Data |= 0x01;

RC522_DELAY();
RC522_SCK_1 ();
RC522_DELAY();
}

return SPI_Data;
}


/*
* 函数名:ReadRawRC
* 描述 :读RC522寄存器
* 输入 :ucAddress,寄存器地址
* 返回 : 寄存器的当前值
* 调用 :内部调用
*/
u8 ReadRawRC ( u8 ucAddress )
{
u8 ucAddr, ucReturn;


ucAddr = ( ( ucAddress << 1 ) & 0x7E ) | 0x80;

RC522_CS_Enable();

SPI_RC522_SendByte ( ucAddr );

ucReturn = SPI_RC522_ReadByte ();

RC522_CS_Disable();


return ucReturn;
}


/*
* 函数名:WriteRawRC
* 描述 :写RC522寄存器
* 输入 :ucAddress,寄存器地址
* ucValue,写入寄存器的值
* 返回 : 无
* 调用 :内部调用
*/
void WriteRawRC ( u8 ucAddress, u8 ucValue )
{
u8 ucAddr;


ucAddr = ( ucAddress << 1 ) & 0x7E;

RC522_CS_Enable();

SPI_RC522_SendByte ( ucAddr );

SPI_RC522_SendByte ( ucValue );

RC522_CS_Disable();
}


/*
* 函数名:SetBitMask
* 描述 :对RC522寄存器置位
* 输入 :ucReg,寄存器地址
* ucMask,置位值
* 返回 : 无
* 调用 :内部调用
*/
void SetBitMask ( u8 ucReg, u8 ucMask )
{
u8 ucTemp;

ucTemp = ReadRawRC ( ucReg );
WriteRawRC ( ucReg, ucTemp | ucMask ); // set bit mask
}


/*
* 函数名:ClearBitMask
* 描述 :对RC522寄存器清位
* 输入 :ucReg,寄存器地址
* ucMask,清位值
* 返回 : 无
* 调用 :内部调用
*/
void ClearBitMask ( u8 ucReg, u8 ucMask )
{
u8 ucTemp;

ucTemp = ReadRawRC ( ucReg );
WriteRawRC ( ucReg, ucTemp & ( ~ ucMask) ); // clear bit mask
}


/*
* 函数名:PcdAntennaOn
* 描述 :开启天线
* 输入 :无
* 返回 : 无
* 调用 :内部调用
*/
void PcdAntennaOn ( void )
{
u8 uc;

uc = ReadRawRC ( TxControlReg );
if ( ! ( uc & 0x03 ) )
SetBitMask(TxControlReg, 0x03);
}


/*
* 函数名:PcdAntennaOff
* 描述 :开启天线
* 输入 :无
* 返回 : 无
* 调用 :内部调用
*/
void PcdAntennaOff ( void )
{
ClearBitMask ( TxControlReg, 0x03 );
}


/*
* 函数名:PcdRese
* 描述 :复位RC522
* 输入 :无
* 返回 : 无
* 调用 :外部调用
*/
void PcdReset ( void )
{
RC522_Reset_Disable();

delay_us ( 1 );

RC522_Reset_Enable();

delay_us ( 1 );

RC522_Reset_Disable();

delay_us ( 1 );

WriteRawRC ( CommandReg, 0x0f );

while ( ReadRawRC ( CommandReg ) & 0x10 );

delay_us ( 1 );

WriteRawRC ( ModeReg, 0x3D ); //定义发送和接收常用模式 和Mifare卡通讯,CRC初始值0x6363

WriteRawRC ( TReloadRegL, 30 ); //16位定时器低位
WriteRawRC ( TReloadRegH, 0 ); //16位定时器高位

WriteRawRC ( TModeReg, 0x8D ); //定义内部定时器的设置

WriteRawRC ( TPrescalerReg, 0x3E ); //设置定时器分频系数

WriteRawRC ( TxAutoReg, 0x40 ); //调制发送信号为100%ASK
}


/*
* 函数名:M500PcdConfigISOType
* 描述 :设置RC522的工作方式
* 输入 :ucType,工作方式
* 返回 : 无
* 调用 :外部调用
*/
void M500PcdConfigISOType ( u8 ucType )
{
if(ucType == 'A') //ISO14443_A
{
ClearBitMask ( Status2Reg, 0x08 );

WriteRawRC ( ModeReg, 0x3D ); //3F

WriteRawRC ( RxSelReg, 0x86 ); //84

WriteRawRC( RFCfgReg, 0x7F ); //4F

WriteRawRC( TReloadRegL, 30 ); // TReloadVal = 'h6a =tmoLength(dec)

WriteRawRC ( TReloadRegH, 0 );

WriteRawRC ( TModeReg, 0x8D );

WriteRawRC ( TPrescalerReg, 0x3E );

delay_us ( 2 );

PcdAntennaOn ();//开天线
}
}


/*
* 函数名:PcdComMF522
* 描述 :通过RC522和ISO14443卡通讯
* 输入 :ucCommand,RC522命令字
* pInData,通过RC522发送到卡片的数据
* ucInLenByte,发送数据的字节长度
* pOutData,接收到的卡片返回数据
* pOutLenBit,返回数据的位长度
* 返回 : 状态值
* = MI_OK,成功
* 调用 :内部调用
*/
char PcdComMF522 ( u8 ucCommand, u8 * pInData, u8 ucInLenByte, u8 * pOutData, u32 * pOutLenBit )
{
char cStatus = MI_ERR;
u8 ucIrqEn = 0x00;
u8 ucWaitFor = 0x00;
u8 ucLastBits;
u8 ucN;
u32 ul;

switch ( ucCommand )
{
case PCD_AUTHENT: //Mifare认证
ucIrqEn = 0x12; //允许错误中断请求ErrIEn 允许空闲中断IdleIEn
ucWaitFor = 0x10; //认证寻卡等待时候 查询空闲中断标志位
break;

case PCD_TRANSCEIVE: //接收发送 发送接收
ucIrqEn = 0x77; //允许TxIEn RxIEn IdleIEn LoAlertIEn ErrIEn TimerIEn
ucWaitFor = 0x30; //寻卡等待时候 查询接收中断标志位与 空闲中断标志位
break;

default:
break;

}

WriteRawRC ( ComIEnReg, ucIrqEn | 0x80 ); //IRqInv置位管脚IRQ与Status1Reg的IRq位的值相反
ClearBitMask ( ComIrqReg, 0x80 ); //Set1该位清零时,CommIRqReg的屏蔽位清零
WriteRawRC ( CommandReg, PCD_IDLE ); //写空闲命令
SetBitMask ( FIFOLevelReg, 0x80 ); //置位FlushBuffer清除内部FIFO的读和写指针以及ErrReg的BufferOvfl标志位被清除

for ( ul = 0; ul < ucInLenByte; ul ++ )
WriteRawRC ( FIFODataReg, pInData [ ul ] ); //写数据进FIFOdata

WriteRawRC ( CommandReg, ucCommand ); //写命令


if ( ucCommand == PCD_TRANSCEIVE )
SetBitMask(BitFramingReg,0x80); //StartSend置位启动数据发送 该位与收发命令使用时才有效

ul = 1000; //根据时钟频率调整,操作M1卡最大等待时间25ms

do //认证 与寻卡等待时间
{
ucN = ReadRawRC ( ComIrqReg ); //查询事件中断
ul --;
}while(( ul != 0 ) && (!(ucN & 0x01)) && (!(ucN & ucWaitFor))); //退出条件i=0,定时器中断,与写空闲命令

ClearBitMask ( BitFramingReg, 0x80 ); //清理允许StartSend位

if ( ul != 0 )
{
if ( ! ( ReadRawRC ( ErrorReg ) & 0x1B ) ) //读错误标志寄存器BufferOfI CollErr ParityErr ProtocolErr
{
cStatus = MI_OK;

if ( ucN & ucIrqEn & 0x01 ) //是否发生定时器中断
cStatus = MI_NOTAGERR;

if ( ucCommand == PCD_TRANSCEIVE )
{
ucN = ReadRawRC ( FIFOLevelReg ); //读FIFO中保存的字节数

ucLastBits = ReadRawRC ( ControlReg ) & 0x07; //最后接收到得字节的有效位数

if ( ucLastBits )
* pOutLenBit = ( ucN - 1 ) * 8 + ucLastBits; //N个字节数减去1(最后一个字节)+最后一位的位数 读取到的数据总位数
else
* pOutLenBit = ucN * 8; //最后接收到的字节整个字节有效

if ( ucN == 0 )
ucN = 1;

if ( ucN > MAXRLEN )
ucN = MAXRLEN;

for ( ul = 0; ul < ucN; ul ++ )
pOutData [ ul ] = ReadRawRC ( FIFODataReg );
}
}
else
cStatus = MI_ERR;
}

SetBitMask ( ControlReg, 0x80 ); // stop timer now
WriteRawRC ( CommandReg, PCD_IDLE );

return cStatus;
}


/*
* 函数名:PcdRequest
* 描述 :寻卡
* 输入 :ucReq_code,寻卡方式
* = 0x52,寻感应区内所有符合14443A标准的卡
* = 0x26,寻未进入休眠状态的卡
* pTagType,卡片类型代码
* = 0x4400,Mifare_UltraLight
* = 0x0400,Mifare_One(S50)
* = 0x0200,Mifare_One(S70)
* = 0x0800,Mifare_Pro(X))
* = 0x4403,Mifare_DESFire
* 返回 : 状态值
* = MI_OK,成功
* 调用 :外部调用
*/
char PcdRequest ( u8 ucReq_code, u8 * pTagType )
{
char cStatus;
u8 ucComMF522Buf [ MAXRLEN ];
u32 ulLen;

ClearBitMask ( Status2Reg, 0x08 ); //清理指示MIFARECyptol单元接通以及所有卡的数据通信被加密的情况
WriteRawRC ( BitFramingReg, 0x07 ); // 发送的最后一个字节的 七位
SetBitMask ( TxControlReg, 0x03 ); //TX1,TX2管脚的输出信号传递经发送调制的13.56的能量载波信号

ucComMF522Buf [ 0 ] = ucReq_code; //存入 卡片命令字

cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 1, ucComMF522Buf, & ulLen ); //寻卡

if((cStatus == MI_OK) && (ulLen == 0x10)) //寻卡成功返回卡类型
{
*pTagType = ucComMF522Buf[0];
*(pTagType + 1) = ucComMF522Buf[1];
}
else
cStatus = MI_ERR;

return cStatus;
}


/*
* 函数名:PcdAnticoll
* 描述 :防冲撞
* 输入 :pSnr,卡片序列号,4字节
* 返回 : 状态值
* = MI_OK,成功
* 调用 :外部调用
*/
char PcdAnticoll ( u8 * pSnr )
{
char cStatus;
u8 uc, ucSnr_check = 0;
u8 ucComMF522Buf [ MAXRLEN ];
u32 ulLen;

ClearBitMask ( Status2Reg, 0x08 ); //清MFCryptol On位 只有成功执行MFAuthent命令后,该位才能置位
WriteRawRC ( BitFramingReg, 0x00); //清理寄存器 停止收发
ClearBitMask ( CollReg, 0x80 ); //清ValuesAfterColl所有接收的位在冲突后被清除

ucComMF522Buf [ 0 ] = 0x93; //卡片防冲突命令
ucComMF522Buf [ 1 ] = 0x20;

cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 2, ucComMF522Buf, & ulLen);//与卡片通信

if ( cStatus == MI_OK) //通信成功
{
for ( uc = 0; uc < 4; uc ++ )
{
* ( pSnr + uc ) = ucComMF522Buf [ uc ]; //读出UID
ucSnr_check ^= ucComMF522Buf [ uc ];
}

if ( ucSnr_check != ucComMF522Buf [ uc ] )
cStatus = MI_ERR;
}

SetBitMask ( CollReg, 0x80 );

return cStatus;
}


/*
* 函数名:CalulateCRC
* 描述 :用RC522计算CRC16
* 输入 :pIndata,计算CRC16的数组
* ucLen,计算CRC16的数组字节长度
* pOutData,存放计算结果存放的首地址
* 返回 : 无
* 调用 :内部调用
*/
void CalulateCRC ( u8 * pIndata, u8 ucLen, u8 * pOutData )
{
u8 uc, ucN;

ClearBitMask(DivIrqReg,0x04);
WriteRawRC(CommandReg,PCD_IDLE);
SetBitMask(FIFOLevelReg,0x80);

for ( uc = 0; uc < ucLen; uc ++)
WriteRawRC ( FIFODataReg, * ( pIndata + uc ) );

WriteRawRC ( CommandReg, PCD_CALCCRC );

uc = 0xFF;

do
{
ucN = ReadRawRC ( DivIrqReg );
uc --;
} while ( ( uc != 0 ) && ! ( ucN & 0x04 ) );

pOutData [ 0 ] = ReadRawRC ( CRCResultRegL );
pOutData [ 1 ] = ReadRawRC ( CRCResultRegM );
}


/*
* 函数名:PcdSelect
* 描述 :选定卡片
* 输入 :pSnr,卡片序列号,4字节
* 返回 : 状态值
* = MI_OK,成功
* 调用 :外部调用
*/
char PcdSelect ( u8 * pSnr )
{
char ucN;
u8 uc;
u8 ucComMF522Buf [ MAXRLEN ];
u32 ulLen;

ucComMF522Buf [ 0 ] = PICC_ANTICOLL1;
ucComMF522Buf [ 1 ] = 0x70;
ucComMF522Buf [ 6 ] = 0;

for ( uc = 0; uc < 4; uc ++ )
{
ucComMF522Buf [ uc + 2 ] = * ( pSnr + uc );
ucComMF522Buf [ 6 ] ^= * ( pSnr + uc );
}

CalulateCRC ( ucComMF522Buf, 7, & ucComMF522Buf [ 7 ] );

ClearBitMask ( Status2Reg, 0x08 );

ucN = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 9, ucComMF522Buf, & ulLen );

if ( ( ucN == MI_OK ) && ( ulLen == 0x18 ) )
ucN = MI_OK;
else
ucN = MI_ERR;

return ucN;
}


/*
* 函数名:PcdAuthState
* 描述 :验证卡片密码
* 输入 :ucAuth_mode,密码验证模式
* = 0x60,验证A密钥
* = 0x61,验证B密钥
* u8 ucAddr,块地址
* pKey,密码
* pSnr,卡片序列号,4字节
* 返回 : 状态值
* = MI_OK,成功
* 调用 :外部调用
*/
char PcdAuthState ( u8 ucAuth_mode, u8 ucAddr, u8 * pKey, u8 * pSnr )
{
char cStatus;
u8 uc, ucComMF522Buf [ MAXRLEN ];
u32 ulLen;


ucComMF522Buf [ 0 ] = ucAuth_mode;
ucComMF522Buf [ 1 ] = ucAddr;

for ( uc = 0; uc < 6; uc ++ )
ucComMF522Buf [ uc + 2 ] = * ( pKey + uc );

for ( uc = 0; uc < 6; uc ++ )
ucComMF522Buf [ uc + 8 ] = * ( pSnr + uc );

cStatus = PcdComMF522 ( PCD_AUTHENT, ucComMF522Buf, 12, ucComMF522Buf, & ulLen );

if ( ( cStatus != MI_OK ) || ( ! ( ReadRawRC ( Status2Reg ) & 0x08 ) ) )
cStatus = MI_ERR;

return cStatus;
}


/*
* 函数名:PcdWrite
* 描述 :写数据到M1卡一块
* 输入 :u8 ucAddr,块地址
* pData,写入的数据,16字节
* 返回 : 状态值
* = MI_OK,成功
* 调用 :外部调用
*/
char PcdWrite ( u8 ucAddr, u8 * pData )
{
char cStatus;
u8 uc, ucComMF522Buf [ MAXRLEN ];
u32 ulLen;

ucComMF522Buf [ 0 ] = PICC_WRITE;
ucComMF522Buf [ 1 ] = ucAddr;

CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );

cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );

if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )
cStatus = MI_ERR;

if ( cStatus == MI_OK )
{
//memcpy(ucComMF522Buf, pData, 16);
for ( uc = 0; uc < 16; uc ++ )
ucComMF522Buf [ uc ] = * ( pData + uc );

CalulateCRC ( ucComMF522Buf, 16, & ucComMF522Buf [ 16 ] );

cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 18, ucComMF522Buf, & ulLen );

if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )
cStatus = MI_ERR;
}

return cStatus;
}


/*
* 函数名:PcdRead
* 描述 :读取M1卡一块数据
* 输入 :u8 ucAddr,块地址
* pData,读出的数据,16字节
* 返回 : 状态值
* = MI_OK,成功
* 调用 :外部调用
*/
char PcdRead ( u8 ucAddr, u8 * pData )
{
char cStatus;
u8 uc, ucComMF522Buf [ MAXRLEN ];
u32 ulLen;

ucComMF522Buf [ 0 ] = PICC_READ;
ucComMF522Buf [ 1 ] = ucAddr;

CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );

cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );

if ( ( cStatus == MI_OK ) && ( ulLen == 0x90 ) )
{
for ( uc = 0; uc < 16; uc ++ )
*( pData + uc ) = ucComMF522Buf [ uc ];
}
else
cStatus = MI_ERR;


return cStatus;
}


/*
* 函数名:PcdHalt
* 描述 :命令卡片进入休眠状态
* 输入 :无
* 返回 : 状态值
* = MI_OK,成功
* 调用 :外部调用
*/
char PcdHalt( void )
{
u8 ucComMF522Buf [ MAXRLEN ];
u32 ulLen;

ucComMF522Buf [ 0 ] = PICC_HALT;
ucComMF522Buf [ 1 ] = 0;

CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );

return MI_OK;
}


void IC_CMT ( u8 * UID, u8 * KEY, u8 RW, u8 * Dat )
{
u8 ucArray_ID [ 4 ] = { 0 };//先后存放IC卡的类型和UID(IC卡序列号)

PcdRequest ( 0x52, ucArray_ID );//寻卡
PcdAnticoll ( ucArray_ID );//防冲撞
PcdSelect ( UID );//选定卡
PcdAuthState ( 0x60, 0x10, KEY, UID );//校验

if ( RW )//读写选择,1是读,0是写
PcdRead ( 0x10, Dat );
else
PcdWrite ( 0x10, Dat );

PcdHalt ();
}

/*********************************************END OF FILE*********************************************/

3,LCD12864液晶显示屏

液晶作为一种显示装置,广泛应用于仪器仪表和电子设备等低功耗产品,在数字电路中,所有的数据都用0和1来保存,通过对LCD控制器进行不同的数据操作,可以得到不同的结果。该模块自带中文字库,可以直接进行中文输入显示。模块实物图如下所示。

YhHXdO.png

(1)lcd12864.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
#ifndef __LCD12864_H
#define __LCD12864_H

#include "stm32f10x.h"
#include "systick.h"

#define WRITE_CMD 0xF8 // 写命令
#define WRITE_DAT 0xFA // 写数据


//Pin definition
/*******************************************************/
#define LCD_GPIO_PORT GPIOB
#define LCD_GPIO_CLK RCC_APB2Periph_GPIOB

#define CS_PIN GPIO_Pin_7
#define SID_PIN GPIO_Pin_8
#define SCLK_PIN GPIO_Pin_9

#define CS_H GPIO_SetBits(LCD_GPIO_PORT,CS_PIN)
#define CS_L GPIO_ResetBits(LCD_GPIO_PORT,CS_PIN)

#define SID_H GPIO_SetBits(LCD_GPIO_PORT,SID_PIN)
#define SID_L GPIO_ResetBits(LCD_GPIO_PORT,SID_PIN)

#define SCLK_H GPIO_SetBits(LCD_GPIO_PORT,SCLK_PIN)
#define SCLK_L GPIO_ResetBits(LCD_GPIO_PORT,SCLK_PIN)
/************************************************************/

void LCD_Init(void);
void LCD12864_GPIO_Init(void);

void Send_Byte(u8 zdata);
u8 Receive_Byte(void);
void Check_Busy(void);
u8 Read_Data(void);
void Write_LCD_Command(u8 cmdcode);
void Write_LCD_Data(u8 Dispdata);
void LCD_Clear_Scr( void );
void Set_Display_Pos(u8 x,u8 y);
void Display_LCD_String(const char *s);
void LCD_Display_Words(uint8_t x,uint8_t y,char *str);


#endif /* __LCD12864_H */

(2)lcd12864.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
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
/**
******************************************************************************
* @file lcd12864.c
* @author Soso
* @date 2019-08-02
* @brief LCD 12864 configuration,with font, serial mode.
******************************************************************************
*/

#include "lcd12864.h"


void LCD12864_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Enable GPIO port clock */
RCC_APB2PeriphClockCmd(LCD_GPIO_CLK, ENABLE);

GPIO_InitStructure.GPIO_Pin = CS_PIN|SID_PIN|SCLK_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(LCD_GPIO_PORT, &GPIO_InitStructure);
}


void LCD_Init(void)
{
LCD12864_GPIO_Init();

delay_ms(50); // 等待液晶自检(延时>40ms)
Write_LCD_Command(0x30); // 功能设定:选择基本指令集,8bit数据流
Write_LCD_Command(0x0c); // 显示器开,光标关闭
Write_LCD_Command(0x01); // 清屏,并且设定地址指针为00H
Write_LCD_Command(0x06); // 进入设定点,初始化完成
}


/*********************************************************
函数名:Send_Byte()
返回值:无
功 能: 写数据到LCD
*********************************************************/
void Send_Byte(u8 zdata)
{
u8 i;
for(i=0; i<8; i++)
{
if((zdata << i) & 0x80)
SID_H;
else
SID_L;
SCLK_H;
SCLK_L;
}
}


/*********************************************************
函数名:Receive_Byte()
返回值:temp1+temp2
功 能: 读LCD数据
*********************************************************/
u8 Receive_Byte(void)
{
u8 i,temp1,temp2,value;
temp1=0;
temp2=0;
for(i=0;i<8;i++)
{
temp1=temp1<<1;
SCLK_L;
SCLK_H;
SCLK_L;
if(GPIO_ReadOutputDataBit(LCD_GPIO_PORT,SID_PIN)==1)
{
temp1++;
}
}
for(i=0;i<8;i++)
{
temp2=temp2<<1;
SCLK_L;
SCLK_H;
SCLK_L;
if(GPIO_ReadOutputDataBit(LCD_GPIO_PORT,SID_PIN)==1)
{
temp2++;
}
}
temp1=0xf0&temp1;
temp2=0x0f&temp2;
value=temp1+temp2;
return value;
}


/*********************************************************
函数名:Check_Busy()
返回值:无
功 能: LCD忙检查
*********************************************************/
void Check_Busy(void)
{
do
Send_Byte(0xfc); //11111,RW(1),RS(0),0
while(0x80&Receive_Byte());
}


/*********************************************************
函数名: Read_LCD_Data()
返回值:LCD收到的数据
功 能: 读取LCD显示内容
*********************************************************/
u8 Read_Data(void)
{
Check_Busy();
Send_Byte(0xfe); //11111,RW(1),RS(1),0 LCD->MCU
return Receive_Byte();
}


/*********************************************************
函数名: Write_LCD_Command()
返回值:无
功 能: 写命令到LCD
*********************************************************/
void Write_LCD_Command(u8 cmdcode)
{
CS_H;
Check_Busy();
Send_Byte(WRITE_CMD);
Send_Byte(cmdcode & 0xf0);
Send_Byte((cmdcode << 4) & 0xf0);
delay_ms(2);
CS_L;
}
/*********************************************************
函数名: Write_LCD_Data()
返回值:无
功 能: 写显示内容到LCD
*********************************************************/
void Write_LCD_Data(u8 Dispdata)
{
CS_H;
Check_Busy();
Send_Byte(WRITE_DAT); //11111,RW(0),RS(1),0
Send_Byte(Dispdata & 0xf0);
Send_Byte((Dispdata << 4) & 0xf0);
delay_ms(2);
CS_L;
}


/*********************************************************
函数名: LCD_Clear_Scr
返回值:无
功 能: LCD清屏
*********************************************************/
void LCD_Clear_Scr( void )
{
Write_LCD_Command(0x01);
delay_ms(2);
}

/*********************************************************
函数名: Set_Display_Pos
参数:X为行,Y为列
返回值:无
功 能:设置显示位置
*********************************************************/
void Set_Display_Pos(u8 x,u8 y)
{
u8 pos;
switch(x)
{
case 0: x=0x80;break;
case 1: x=0x90;break;
case 2: x=0x88;break;
case 3: x=0x98;break;
}
pos=x+y;
Write_LCD_Command(pos);
}

/*********************************************************
函数名:Display_LCD_String()
返回值:无
功 能:显示字符串
*********************************************************/
void Display_LCD_String(const char *s)
{
while(*s != '\0')
{
Write_LCD_Data(*s);
s++;
delay_ms(2); //控制每一个字符之间显示的时间 间隔
}
}


/*!
* @brief 显示字符或汉字
* @param x: row(0~3)
* @param y: line(0~7)
* @param str: 要显示的字符
*/
void LCD_Display_Words(uint8_t x,uint8_t y,char *str)
{
Set_Display_Pos(x,y); //写初始光标位置
while(*str>0)
{
Write_LCD_Data(*str); //写数据
str++;
}
}
/*********************************************END OF FILE*********************************************/

4,薄膜矩阵键盘模块

键盘的矩阵结构比单个按键一对一直接连接引脚的方法复杂,相应的读取识别也更复杂。本设计选用的是薄膜矩阵键盘,它的引脚采用标准的7芯杜邦头,间距2.54mm,可以直接插在排针上连接到电路;键盘背面白色贴纸可以揭去,牢固粘贴在物体表面,方便放置。其电路原理图如下图所示。

QHy3ZV.png

(1)keyboard.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
#ifndef __KEYBOARD_H
#define __KEYBOARD_H

#include "stm32f10x.h"
#include "systick.h"
#include "buzzer.h"

extern uint8_t key_flag;

//Pin definition
/*******************************************************************/
#define ROW_KEY_GPIO_PORT GPIOA
#define ROW_KEY_GPIO_CLK RCC_APB2Periph_GPIOA
#define R1_PIN GPIO_Pin_8
#define R2_PIN GPIO_Pin_9
#define R3_PIN GPIO_Pin_10
#define R4_PIN GPIO_Pin_11


#define COLUMN_KEY_GPIO_PORT GPIOB
#define COLUMN_KEY_GPIO_CLK RCC_APB2Periph_GPIOB
#define C1_PIN GPIO_Pin_15
#define C2_PIN GPIO_Pin_14
#define C3_PIN GPIO_Pin_13
/************************************************************************/

void KeyBoard_Init(void);
uint16_t Key_scan(void);
void Key_Buzzer(void);

#endif /* __KEYBOARD_H */

(2)keyboard.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
/**
******************************************************************************
* @file keyboard.c
* @author Soso
* @date 2019-08-02
* @brief Matrix keyboard driver configuration.
******************************************************************************
*/

#include "keyboard.h"


uint8_t key_flag;

void KeyBoard_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;

/* Enable KeyGPIO port clock */
RCC_APB2PeriphClockCmd(COLUMN_KEY_GPIO_CLK|ROW_KEY_GPIO_CLK,ENABLE);

/* Column Key GPIO Configuration */
GPIO_InitStruct.GPIO_Pin = C1_PIN|C2_PIN|C3_PIN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(COLUMN_KEY_GPIO_PORT,&GPIO_InitStruct);

/* Row Key GPIO Configuration */
GPIO_InitStruct.GPIO_Pin = R1_PIN|R2_PIN|R3_PIN|R4_PIN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(ROW_KEY_GPIO_PORT,&GPIO_InitStruct);

GPIO_ResetBits(COLUMN_KEY_GPIO_PORT,C1_PIN|C2_PIN|C3_PIN);
GPIO_ResetBits(ROW_KEY_GPIO_PORT,R1_PIN|R2_PIN|R3_PIN|R4_PIN);
}


uint16_t Key_scan(void)
{
uint16_t temp = 0;
char Key_val = 0;

/*************************** Column 1 ***************************/
GPIO_SetBits(COLUMN_KEY_GPIO_PORT,C1_PIN);
GPIO_ResetBits(COLUMN_KEY_GPIO_PORT,C2_PIN|C3_PIN);

temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0x0F00;

if(temp != 0x0000)
{
delay_ms(5);
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0x0F00;
if(temp != 0x0000)
{
key_flag = 1;
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0x0F00;
switch(temp)
{
case 0x0100: Key_val = '*';break;
case 0x0200: Key_val = '7';break;
case 0x0400: Key_val = '4';break;
case 0x0800: Key_val = '1';break;
}
Key_Buzzer();
}
while(temp != 0x0000)
{
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0x0F00;
}
}

/*************************** Column 2 ***************************/
GPIO_SetBits(COLUMN_KEY_GPIO_PORT,C2_PIN);
GPIO_ResetBits(COLUMN_KEY_GPIO_PORT,C1_PIN|C3_PIN);

temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0x0F00;

if(temp != 0x0000)
{
delay_ms(5);
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0x0F00;
if(temp != 0x0000)
{
key_flag = 1;
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0x0F00;
switch(temp)
{
case 0x0100: Key_val = '0';break;
case 0x0200: Key_val = '8';break;
case 0x0400: Key_val = '5';break;
case 0x0800: Key_val = '2';break;
}
Key_Buzzer();
}
while(temp != 0x0000)
{
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0x0F00;
}
}

/*************************** Column 3 ***************************/
GPIO_SetBits(COLUMN_KEY_GPIO_PORT,C3_PIN);
GPIO_ResetBits(COLUMN_KEY_GPIO_PORT,C1_PIN|C2_PIN);

temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0x0F00;

if(temp != 0x0000)
{
delay_ms(5);
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0x0F00;
if(temp != 0x0000)
{
key_flag = 1;
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0x0F00;
switch(temp)
{
case 0x0100: Key_val = '#';break;
case 0x0200: Key_val = '9';break;
case 0x0400: Key_val = '6';break;
case 0x0800: Key_val = '3';break;
}
Key_Buzzer();
}
while(temp != 0x0000)
{
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0x0F00;
}
}

return Key_val;
}

void Key_Buzzer(void)
{
OPEN_BUZZER();
delay_ms(100);
CLOSE_BUZZER();
}
/*********************************************END OF FILE*********************************************/

5,flash读写模块

对STM32内部flash进行读写操作完成信息存储,实现掉电存储功能。STM32F103C8T6内部flash内存分布如下图所示。

QhGWB8.png

(1)stm_flash.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
#ifndef __STM_FLASH_H
#define __STM_FLASH_H

#include "stm32f10x.h"

/*************************************************************************************/
// Set according to your needs
#define STM32_FLASH_SIZE 64 // FLASH capacity of the selected MCU (unit is K)
#define STM32_FLASH_WREN 1 // Enable FLASH write (0, disable; 1, enable)

// FLASH start address
#define STM32_FLASH_BASE 0x08000000 // STM32 FLASH start address

#if FLASH_SIZE<256
#define SECTOR_SIZE 1024 // byte
#else
#define SECTOR_SIZE 2048 // byte
#endif
/*************************************************************************************/

void STMFLASH_Write_NoCheck(uint32_t WriteAddr,uint16_t *pBuffer,uint16_t NumToWrite);
void STMFLASH_Write(uint32_t WriteAddr,uint16_t *pBuffer,uint16_t NumToWrite);
void STMFLASH_Read(uint32_t ReadAddr,uint16_t *pBuffer,uint16_t NumToRead) ;

#endif /* __STM_FLASH_H */



(2)stm_flash.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
/**
******************************************************************************
* @file stm_flash.c
* @author Soso
* @date 2019-12-15
* @brief STM32 FLASH driver code.
******************************************************************************
*/
#include "stm_flash.h"


/**
* @brief Read the half word (16-bit data) of the specified address.
* @param faddr: read address (this address must be a multiple of 2 !!).
* @retval Corresponding data.
*/
static uint16_t STMFLASH_ReadHalfWord(uint32_t faddr)
{
return *(vu16*)faddr;
}


#if STM32_FLASH_WREN // If enable flash write
/**
* @brief Do not check writes.
* @param WriteAddr: starting address.
* @param pBuffer: data pointer.
* @param NumToWrite: half-word (16-bit) number.
* @retval None.
*/
void STMFLASH_Write_NoCheck(uint32_t WriteAddr,uint16_t *pBuffer,uint16_t NumToWrite)
{
uint16_t i;
for(i=0;i<NumToWrite;i++)
{
FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
WriteAddr+=2; // Address increased by 2
}
}

// A sector size is (SECTOR_SIZE) bytes,
// A uint16_t type data is 2 bytes,
// So a sector can hold a maximum of (SECTOR_SIZE/2) uint16_t type data.
uint16_t STMFLASH_BUF[SECTOR_SIZE/2];

/**
* @brief Write data of specified length from the specified address.
* @param WriteAddr: Start address(this address must be a multiple of 2 !!).
* @param pBuffer: data pointer.
* @param NumToWrite: Halfword (16-bit) number.
* @retval None.
*/
void STMFLASH_Write(uint32_t WriteAddr,uint16_t *pBuffer,uint16_t NumToWrite)
{
uint16_t i;
uint32_t secpos; // Sector address
uint16_t secoff; // Intra-sector offset address (16-bit word calculation)
uint16_t secremain; // Remaining address in the sector (16-bit word calculation)
uint32_t offaddr; // Remove the address after 0X08000000

if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))
return; // Illegal address

FLASH_Unlock(); // Unlock flash
offaddr = WriteAddr-STM32_FLASH_BASE; // Actual offset address.
secpos = offaddr/SECTOR_SIZE; // Sector address 0 ~ 63 for STM32F103C8T6
secoff = (offaddr%SECTOR_SIZE)/2; // Offset within the sector (2 bytes as the basic unit)
secremain = SECTOR_SIZE/2-secoff; // Sector remaining space
if(NumToWrite <= secremain) // Not greater than the sector range
secremain = NumToWrite;

while(1)
{
STMFLASH_Read(secpos*SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,SECTOR_SIZE/2);//Read the entire sector
for(i=0;i<secremain;i++) // Check data
{
if(STMFLASH_BUF[secoff+i] != 0XFFFF)
break; // Need to erase
}

if(i < secremain) // Need to erase
{
FLASH_ErasePage(secpos*SECTOR_SIZE+STM32_FLASH_BASE); // Erase this sector
for(i=0;i<secremain;i++) // Copy data
{
STMFLASH_BUF[i+secoff] = pBuffer[i];
}
// Write entire sector
STMFLASH_Write_NoCheck(secpos*SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,SECTOR_SIZE/2);
}
else // If it has been erased, it is directly written into the remaining sector.
STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);

if(NumToWrite == secremain) // Writing is complete
break;
else // Writing is not complete
{
secpos++; // Sector address increased by 1
secoff = 0; // Offset position is 0
pBuffer += secremain; // Pointer offset
WriteAddr += secremain; // Write address offset
NumToWrite -= secremain;// Decrement the number of bytes (16 bits)
if(NumToWrite > (SECTOR_SIZE/2))// Data cannot be written in the next sector
secremain = SECTOR_SIZE/2;
else // Data can be written in the next sector
secremain = NumToWrite;
}
};
FLASH_Lock(); // Lock flash
}
#endif


/**
* @brief Read data of specified length from specified address.
* @param ReadAddr: Start address(this address must be a multiple of 2 !!).
* @param pBuffer: data pointer.
* @param NumToWrite: Halfword (16-bit) number.
* @retval None.
*/
void STMFLASH_Read(uint32_t ReadAddr,uint16_t *pBuffer,uint16_t NumToRead)
{
uint16_t i;
for(i=0;i<NumToRead;i++)
{
pBuffer[i] = STMFLASH_ReadHalfWord(ReadAddr); // Read 2 bytes.
ReadAddr += 2; // Offset 2 bytes.
}
}

6,有源蜂鸣器模块

有源蜂鸣器采用多晶片集成电路(SOT塑封装),此集成电路采用金丝球焊接,生产工艺复杂,使用寿命长,性能稳定,产品合格率高。有源蜂鸣器内部带震荡源,所以只要通电就会发出声响。有源蜂鸣器模块的高度为0.9cm,半径0.55cm,电路板用黑胶封闭,具有两个引脚,长引脚为‘+’,短引脚为‘-’。

YhLV2j.jpg

(1)buzzer.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
#ifndef __BUZZER_H
#define __BUZZER_H

#include "stm32f10x.h"
#include "systick.h"


/********************************Pin definition********************************/

#define BUZZER_GPIO_PORT GPIOB
#define BUZZER_GPIO_CLK RCC_APB2Periph_GPIOB
#define BUZZER_GPIO_PIN GPIO_Pin_0

/******************************************************************************/

#define OPEN_BUZZER() GPIO_SetBits(BUZZER_GPIO_PORT,BUZZER_GPIO_PIN);
#define CLOSE_BUZZER() GPIO_ResetBits(BUZZER_GPIO_PORT,BUZZER_GPIO_PIN)


/************************************Funtion************************************/

void Buzzer_GPIO_Config(void);


#endif /* __BUZZER_H */

(2)buzzer.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
/**
******************************************************************************
* @file buzzer.c
* @author Soso
* @date 2019-09-27
* @brief buzzer applicatiom function interface.
******************************************************************************
*/

#include "buzzer.h"

void Buzzer_GPIO_Config(void)
{
// Enable GPIO port clock
RCC_APB2PeriphClockCmd(BUZZER_GPIO_CLK,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;

// GPIO configuration
GPIO_InitStructure.GPIO_Pin = BUZZER_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;

GPIO_Init(BUZZER_GPIO_PORT,&GPIO_InitStructure);

// Close buzzer
GPIO_ResetBits(BUZZER_GPIO_PORT,BUZZER_GPIO_PIN);
}

/*********************************************END OF FILE*********************************************/

7,舵机模块

舵机一般都是使用PWM进行控制,配置好相应的频率即可。

(1)rds3115.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
#ifndef __RDS3115_H
#define __RDS3115_H

#include "stm32f10x.h"


// Pin definition
/************************************************************/
#define RDS3115_OCPWM_GPIO_CLK RCC_APB2Periph_GPIOB
#define RDS3115_OCPWM_GPIO_AF RCC_APB2Periph_AFIO

#define RDS3115_OC1PWM_GPIO_PORT GPIOB
#define RDS3115_OC1PWM_PIN GPIO_Pin_6
#define RDS3115_OC1PWM_PINSOURCE GPIO_PinSource6


#define RDS3115_TIM TIM4
#define RDS3115_TIM_CLK RCC_APB1Periph_TIM4

/************************************************************/

void RDS3115_Init(void);

#endif /* __RDS3115_H */

(2)rds3115.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
/**
******************************************************************************
* @file rds3115.c
* @author Soso
* @date 2018-10-20
* @brief General purpose timer multi-channel PWM output configuration.
* Steering gear pin GPIO mode configuration.
******************************************************************************
*/

#include "rds3115.h"


/**
* @brief Configure the I/O used when the TIM multiplexes the output PWM.
* @param None
* @retval None
*/
static void TIM4_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Enable the relevant GPIO peripheral clock */
RCC_APB2PeriphClockCmd(RDS3115_OCPWM_GPIO_CLK|RDS3115_OCPWM_GPIO_AF, ENABLE);

/* Timer channel pin configuration */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

/* Channel 1 initialization */
GPIO_InitStructure.GPIO_Pin = RDS3115_OC1PWM_PIN;
GPIO_Init(RDS3115_OC1PWM_GPIO_PORT, &GPIO_InitStructure);
}


/**
* @brief Timer PWM output mode configuartion.
* @param None
* @retval None
*/
static void TIM4_PWM_Config_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;

/* Enable TIMx_CLK */
RCC_APB1PeriphClockCmd(RDS3115_TIM_CLK, ENABLE);

/* 1, PSC(prescaler) = 7200-1,
timer frequency = 72M/(PSC + 1) = 10KHZ,
calculate the time of one pulse = 1 / 10,000 s
2, ARR (automatic reload register) = 200-1, counted from 0 to 199, then counted 200 times.
3, Time=200/10,000=0.02s=20ms */
TIM_TimeBaseStructure.TIM_Period = 200-1; // 20ms
TIM_TimeBaseStructure.TIM_Prescaler = 7200-1;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
// Initialization TIMx
TIM_TimeBaseInit(RDS3115_TIM, &TIM_TimeBaseStructure);

/* PWM mode configuration */
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // Configured as PWM mode 1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 1-1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // High level when the timer count value is less than CCR1_Val

/* Enable channel 1 */
TIM_OC1Init(RDS3115_TIM, &TIM_OCInitStructure);


TIM_CtrlPWMOutputs(RDS3115_TIM,ENABLE);

/* Enable channel 1 overload */
TIM_OC1PreloadConfig(RDS3115_TIM, TIM_OCPreload_Enable);


/* Enable timer */
TIM_Cmd(RDS3115_TIM, ENABLE);
}


void RDS3115_Init(void)
{
TIM4_GPIO_Config();
TIM4_PWM_Config_Init();
}
/*********************************************END OF FILE*********************************************/

8,定时器计时模块

(1)tim.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef __TIME_H
#define __TIME_H

#include "stm32f10x.h"
#include "usart.h"

#define COUNTER_TIM TIM2
#define COUNTER_TIM_CLK RCC_APB1Periph_TIM2

#define COUNTER_TIM_IRQn TIM2_IRQn
#define COUNTER_TIM_IRQHandler TIM2_IRQHandler

void COUNTER_TIM_Init(uint16_t arr,uint16_t psc);

#endif /* __TIME_H */

(2)tim.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
/**
******************************************************************************
* @file time.c
* @author Soso
* @date 2019-12-17
* @brief General timer driver code.
*
******************************************************************************
*/

#include "time.h"

extern vu16 AS608_RX_STA;

//定时器4中断服务程序
void COUNTER_TIM_IRQHandler(void)
{
if (TIM_GetITStatus(COUNTER_TIM, TIM_IT_Update) != RESET)//是更新中断
{
AS608_RX_STA|=1<<15; //标记接收完成
TIM_ClearITPendingBit(COUNTER_TIM, TIM_IT_Update); //清除TIM2更新中断标志
TIM_Cmd(COUNTER_TIM, DISABLE); //关闭TIM2
}
}

// Configuring nested vectored interrupt controller(NVIC)
static void TIMx_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure NVIC as a priority group 1 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

/* Configure interrupt source*/
NVIC_InitStructure.NVIC_IRQChannel = COUNTER_TIM_IRQn;
/* Configuration preemption priority: 1 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* Configure sub-priority: 1 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* Enable interrupt channel */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}


void COUNTER_TIM_Init(uint16_t arr,uint16_t psc)
{
SystemInit();
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// Enable TIM2_CLK
RCC_APB1PeriphClockCmd(COUNTER_TIM_CLK,ENABLE);

/* eg:arr=1000,psc=720
1, PSC(prescaler) = 720-1
timer frequency = 72M/(PSC + 1) = 100KHZ
calculate the time of one pulse = 1/100,000 s
2, ARR (automatic reload register) = 1000-1, counted from 0 to 999, then counted 1000 times.
3, Time = 1000/100,000 = 0.01s = 10ms */
TIM_TimeBaseStructure.TIM_Period = arr-1;
TIM_TimeBaseStructure.TIM_Prescaler = psc-1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(COUNTER_TIM,&TIM_TimeBaseStructure);

// Clear timer update interrupt flag
TIM_ClearITPendingBit(COUNTER_TIM,TIM_IT_Update);
// Enable timer update interrupt
TIM_ITConfig(COUNTER_TIM,TIM_IT_Update,ENABLE);
// Initialization disable timer
TIM_Cmd(COUNTER_TIM,DISABLE);

TIMx_NVIC_Config();
}





/*********************************************END OF FILE*********************************************/

9,串口调试模块

(1)usart.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
#ifndef __USART_H
#define __USART_H

#include "stm32f10x.h"
#include "stdio.h"
#include "time.h"

#define AS608_MAX_RECV_LEN 400 //最大接收缓存字节数
#define AS608_MAX_SEND_LEN 400 //最大发送缓存字节数
#define AS608_RX_EN 1 //0,不接收;1,接收.

extern uint8_t AS608_RX_BUF[AS608_MAX_RECV_LEN]; //接收缓冲,最大USART2_MAX_RECV_LEN字节
extern uint8_t AS608_TX_BUF[AS608_MAX_SEND_LEN]; //发送缓冲,最大USART2_MAX_SEND_LEN字节
extern vu16 AS608_RX_STA; //接收数据状态

//Pin definition
/*************************************************************************/
#define DEBUG_USART USART3
#define DEBUG_USART_CLK RCC_APB1Periph_USART3
#define DEBUG_USART_AF RCC_APB2Periph_AFIO
#define DEBUG_USART_GPIO_CLK RCC_APB2Periph_GPIOB
#define DEBUG_USART_BAUDRATE 115200

#define DEBUG_USART_RX_GPIO_PORT GPIOB
#define DEBUG_USART_RX_PIN GPIO_Pin_11

#define DEBUG_USART_TX_GPIO_PORT GPIOB
#define DEBUG_USART_TX_PIN GPIO_Pin_10

#define DEBUG_USART_IRQ USART3_IRQn
#define DEBUG_USART_IRQHandler USART3_IRQHandler


#define AS608_USART USART2
#define AS608_USART_CLK RCC_APB1Periph_USART2
#define AS608_USART_AF RCC_APB2Periph_AFIO
#define AS608_USART_GPIO_CLK RCC_APB2Periph_GPIOA
#define AS608_USART_BAUDRATE 115200

#define AS608_USART_RX_GPIO_PORT GPIOA
#define AS608_USART_RX_PIN GPIO_Pin_3

#define AS608_USART_TX_GPIO_PORT GPIOA
#define AS608_USART_TX_PIN GPIO_Pin_2

#define AS608_USART_IRQ USART2_IRQn
#define AS608_USART_IRQHandler USART2_IRQHandler
/******************************************************************************/

void USART_Config(void);
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch);
int fputc(int ch, FILE *f);
int fgetc(FILE *f);

#endif /* __USART_H */

(2)usart.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
194
195
196
197
198
199
/**
******************************************************************************
* @file uasrt.c
* @author Soso
* @date 2019-12-17
* @brief USART1(AS608_USART) and USART3(DEBUG_USART) driver configuration code.
Redirect c library printf function to USART3 port.
******************************************************************************
*/

#include "usart.h"

//串口接收缓存区
uint8_t AS608_RX_BUF[AS608_MAX_RECV_LEN]; //接收缓冲,最大AS608_MAX_RECV_LEN个字节.
uint8_t AS608_TX_BUF[AS608_MAX_SEND_LEN]; //发送缓冲,最大AS608_MAX_SEND_LEN字节

//通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据.
//如果2个字符接收间隔超过10ms,则认为不是1次连续数据.也就是超过10ms没有接收到
//任何数据,则表示此次接收完毕.
//接收到的数据状态
//[15]:0,没有接收到数据;1,接收到了一批数据.
//[14:0]:接收到的数据长度
vu16 AS608_RX_STA = 0;

void AS608_USART_IRQHandler(void)
{
uint8_t res;
if(USART_GetITStatus(AS608_USART, USART_IT_RXNE) != RESET)//接收到数据
{
res = USART_ReceiveData(AS608_USART);
if((AS608_RX_STA&(1<<15))==0) //接收完的一批数据,还没有被处理,则不再接收其他数据
{
if(AS608_RX_STA<AS608_MAX_RECV_LEN) //还可以接收数据
{
TIM_SetCounter(COUNTER_TIM,0); //计数器清空 //计数器清空
if(AS608_RX_STA == 0) //使能定时器2的中断
{
TIM_Cmd(COUNTER_TIM,ENABLE);//使能定时器2
}
AS608_RX_BUF[AS608_RX_STA++]=res; //记录接收到的值
}else
{
AS608_RX_STA |= 1<<15; //强制标记接收完成
}
}
}
}


/* Configuring nested vectored interrupt controller NVIC */
static void USART_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;

/* Nested vector interrupt controller group selection */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

/* Preemptio Priority is 1 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* Sub Priority is 1 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* Enable interrupt */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

/* Configure USART as the interrupt source */
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
/* Initialize configuration NVIC */
NVIC_Init(&NVIC_InitStructure);
/* Configure USART as the interrupt source */
NVIC_InitStructure.NVIC_IRQChannel = AS608_USART_IRQ;
/* Initialize configuration NVIC */
NVIC_Init(&NVIC_InitStructure);
}

void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;

/* Enable port alternate function and enable USART GPIO clock */
RCC_APB2PeriphClockCmd(DEBUG_USART_AF|DEBUG_USART_GPIO_CLK,ENABLE);
RCC_APB2PeriphClockCmd(AS608_USART_AF|AS608_USART_GPIO_CLK,ENABLE);
/* Enable USART Clock */
RCC_APB1PeriphClockCmd(DEBUG_USART_CLK,ENABLE);
RCC_APB1PeriphClockCmd(AS608_USART_CLK,ENABLE);

/* Configure the Tx pin for alternate function */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = AS608_USART_TX_PIN;
GPIO_Init(AS608_USART_RX_GPIO_PORT, &GPIO_InitStructure);

/* Configure the Rx pin for the alternate function */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = AS608_USART_RX_PIN;
GPIO_Init(AS608_USART_RX_GPIO_PORT, &GPIO_InitStructure);

/* Configuration USART mode */
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
/* USART mode control: simultaneous enable send and receive */
USART_InitStructure.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;

USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
USART_Init(DEBUG_USART, &USART_InitStructure);
USART_InitStructure.USART_BaudRate = AS608_USART_BAUDRATE;
USART_Init(AS608_USART, &USART_InitStructure);

/* Enable serial port receive interrupt */
USART_ITConfig(AS608_USART, USART_IT_RXNE, ENABLE);

/* Enable serial */
USART_Cmd(DEBUG_USART, ENABLE);
USART_Cmd(AS608_USART, ENABLE);

USART_NVIC_Config();
}


/***************** Send a character **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
/* Send a byte of data to the USART */
USART_SendData(pUSARTx,ch);

/* Waiting for the transmit data register to be empty */
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}

/***************** Send string **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k=0;
do
{
Usart_SendByte( pUSARTx, *(str + k) );
k++;
}while(*(str + k)!='\0');

/* Waiting for transmission to complete */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}

/***************** Send a 16-digit number **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
uint8_t temp_h, temp_l;

/* Take out the high eight */
temp_h = (ch&0XFF00)>>8;
/* Take the lower eight */
temp_l = ch&0XFF;

/* Send high eight */
USART_SendData(pUSARTx,temp_h);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);

/* Send the lower eight digits */
USART_SendData(pUSARTx,temp_l);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}

/* Redirect the c library function printf to the serial port,
use the printf function after redirection. */
int fputc(int ch, FILE *f)
{
/* Send a byte of data to the serial port */
USART_SendData(DEBUG_USART, (uint8_t) ch);

/* Waiting to send */
while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET);

return (ch);
}

/* Redirect the c library function scanf to the serial port,
rewrite backwards can use scanf, getchar and other functions. */
int fgetc(FILE *f)
{
uint8_t ch;
/* Waiting for serial input data */
while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_RXNE) == RESET);

ch = USART_ReceiveData(DEBUG_USART);
USART_SendData(DEBUG_USART, (uint8_t)ch); // 串口回显

return (int)ch;
}
/*********************************************END OF FILE*********************************************/

10,延时函数配置模块

(1)systick.h
1
2
3
4
5
6
7
8
9
10
11
#ifndef __SYSTICK_H
#define __SYSTICK_H

#include"stm32f10x.h"

void delay_us(u32 i);
void delay_ms(u32 i);


#endif /* __SYSTICK_DELAY_H */

(2)systick.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
#include "systick.h"

void delay_us(u32 i)
{
u32 temp;
SysTick->LOAD=9*i; //Set the reload value, at 72MHZ
SysTick->CTRL=0X01; //Enable, reduce to zero is no action, use external clock source
SysTick->VAL=0; //Clear counter
do
{
temp=SysTick->CTRL; //Read current countdown value
}
while((temp&0x01)&&(!(temp&(1<<16)))); //Waiting time to arrive
SysTick->CTRL=0; //Close counter
SysTick->VAL=0; //Empty counter
}
void delay_ms(u32 i)
{
u32 temp;
SysTick->LOAD=9000*i; //Set the reload value, at 72MHZ
SysTick->CTRL=0X01; //Enable, reduce to zero is no action, use external clock source
SysTick->VAL=0; //Clear counter
do
{
temp=SysTick->CTRL; //Read current countdown value
}
while((temp&0x01)&&(!(temp&(1<<16)))); //Waiting time to arrive
SysTick->CTRL=0; //Close counter
SysTick->VAL=0; //Empty counter
}

11,main.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
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
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
/**
******************************************************************************
* @file main.c
* @author Soso
* @date 2019-12-19
* @brief STM32f103 fingerprint identification Smart door lock system.
*
******************************************************************************
*/

#include "stm32f10x.h"
#include "time.h"
#include "as608.h"
#include "usart.h"
#include "systick.h"
#include "keyboard.h"
#include "lcd12864.h"
#include "stm_flash.h"
#include "rc522.h"
#include "rds3115.h"
#include "buzzer.h"


#define PASSWORD_SIZE 6 // 密码长度
#define ICCARD_NUM 20 // 限制IC卡数量(一个IC卡序列号长度为4,该值最大为(1023/4))

/* 设置FLASH 保存地址 */
#define ICCARD_FLASH_SAVE_ADDR 0x0800F400 // 倒数第3页(Page61)
#define UNLOCK_FLASH_SAVE_ADDR 0x0800F800 // 倒数第2页(Page62)
#define MANAGE_FLASH_SAVE_ADDR 0x0800FC00 // 倒数第1页(Page63)

void ShowErrMessage(uint8_t ensure);
void Show_ModifPW_MenuFirst(void);
void Show_ModifPW_MenuSecond(void);
void Show_DelFR_Menu(void);
void Show_AddFR_Menu(void);
void Show_AddIcCard_Menu(void);
void Show_DelIcCard_Menu(void);

void SystemInitDisplay(void);
void UserMenu(void);
void BackSta_ManageMenu(void);
void FR_ManageMenu(void);
void PW_ManageMenu(void);
void IcCardManage_Menu(void);

void UserMenu_Ctrl(uint8_t *proceIndex);
void BackSta_ManageMenuCtrl(uint8_t *proceIndex);
void FR_ManageMenuCtrl(uint8_t *proceIndex);
void PW_ManageMenuCtrl(uint8_t *proceIndex);
void ModifUnlockPw_Ctrl(uint8_t *proceIndex);
void ModifManagePw_Ctrl(uint8_t *proceIndex);
void AddFR_Ctrl(uint8_t *proceIndex); // Add figerprint
void DelFR_Ctrl(uint8_t *proceIndex); // Delete fingerprint
uint8_t Press_FR(void); // Press fingerprint
void IcCard_ManageMenuCtrl(uint8_t *proceIndex);
void AddIcCard_Ctrl(uint8_t *proceIndex);
void DelIcCard_Ctrl(uint8_t *proceIndex);
u8 Card_Detected(void);
void SteeringGear_Unlock(void);

SysPara AS608Para; // 指纹模块AS608参数
uint16_t ValidN = 0; // 模块内有效模板个数
uint16_t IcCardNum = 0; // 当前IC卡数量
uint16_t ErrUnlock = 0,AllowErrUnlock = 5;
uint16_t PWbuff[PASSWORD_SIZE] = {0},ManagBuff[PASSWORD_SIZE] = {0},ICBuff[ICCARD_NUM][4] = {0};


int main(void)
{
uint8_t proceIndex = 0;
// uint16_t Data_Buffer1[6] = {'3','3','3','3','3','3'};
// uint16_t Data_Buffer2[6] = {'1','1','1','1','1','1'};
uint16_t ICText_Buff[ICCARD_NUM*4] = {0};
uint16_t Text_Buffer1[6] = {0},Text_Buffer2[6] = {0};

LCD_Init();
RC522_Init();
KeyBoard_Init();
COUNTER_TIM_Init(1000,720); // 10ms
USART_Config();
PS_StaGPIO_Init(); // Initial read FR status pin
Buzzer_GPIO_Config();
RDS3115_Init();

SystemInitDisplay();
// STMFLASH_Write(UNLOCK_FLASH_SAVE_ADDR,Data_Buffer1,PASSWORD_SIZE);
// STMFLASH_Write(MANAGE_FLASH_SAVE_ADDR,Data_Buffer2,PASSWORD_SIZE);
// STMFLASH_Write(ICCARD_FLASH_SAVE_ADDR,ICText_Buff,ICCARD_NUM*4);

STMFLASH_Read(UNLOCK_FLASH_SAVE_ADDR,Text_Buffer1,PASSWORD_SIZE);
STMFLASH_Read(MANAGE_FLASH_SAVE_ADDR,Text_Buffer2,PASSWORD_SIZE);
STMFLASH_Read(ICCARD_FLASH_SAVE_ADDR,ICText_Buff,ICCARD_NUM*4);
for(u8 i=0;i<PASSWORD_SIZE;i++)
{
PWbuff[i] = Text_Buffer1[i];
ManagBuff[i] = Text_Buffer2[i];
}
if(ICText_Buff[0] != 0)
{
IcCardNum = ICText_Buff[0];
for(u8 i=0;i<=IcCardNum;i++)
for(u8 j=0;j<4;j++)
ICBuff[i][j] = ICText_Buff[i*4+j];
}

while(1)
{
if(proceIndex == 0) // 运行界面
{
UserMenu_Ctrl(&proceIndex);
}
else if(proceIndex == 1) // 后台管理界面
{
BackSta_ManageMenuCtrl(&proceIndex);
}
else if(proceIndex == 2) // 指纹管理界面
{
FR_ManageMenuCtrl(&proceIndex);
}
else if(proceIndex == 3) // 密码管理界面
{
PW_ManageMenuCtrl(&proceIndex);
}
else if(proceIndex == 4) // 修改开锁密码
{
ModifUnlockPw_Ctrl(&proceIndex);
}
else if(proceIndex == 5) // 修改管理员密码
{
ModifManagePw_Ctrl(&proceIndex);
}
else if(proceIndex == 6) // 添加指纹
{
AddFR_Ctrl(&proceIndex);
}
else if(proceIndex == 7) // 删除指纹
{
DelFR_Ctrl(&proceIndex);
}
else if(proceIndex == 8) // IC卡管理界面
{
IcCard_ManageMenuCtrl(&proceIndex);
}
else if(proceIndex == 9) // 添加IC卡
{
AddIcCard_Ctrl(&proceIndex);
}
else if(proceIndex == 10) // 删除IC卡
{
DelIcCard_Ctrl(&proceIndex);
}
}
}

/**************************************************************************************/

// 系统初始化显示界面
void SystemInitDisplay(void)
{
uint8_t waitCnt = 3;

LCD_Clear_Scr();
LCD_Display_Words(0,1,"智能门锁系统");
LCD_Display_Words(1,0,"系统初始化中,");
LCD_Display_Words(2,0,"请稍后");
LCD_Display_Words(3,4,"BY-Soso");
delay_ms(1500);
while(PS_HandShake(&AS608Addr)) // Shake hands with AS608 module
{
LCD_Display_Words(2,waitCnt,".");
waitCnt++;
if(waitCnt > 7)
{
LCD_Display_Words(2,3," ");
LCD_Display_Words(2,4," ");
LCD_Display_Words(2,5," ");
LCD_Display_Words(2,6," ");
LCD_Display_Words(2,7," ");
waitCnt = 3;
}
delay_ms(1000);
}
}

// 运行界面
void UserMenu_Ctrl(uint8_t *proceIndex)
{
uint16_t inputComparSta = 0,tempIndex = 0,i = 0;
uint16_t key_value = 0,tempBuff[50] = {0};
char IntToChar[10]={'0','1','2','3','4','5','6','7','8','9'},temp;
UserMenu();

while(1)
{
if(Card_Detected()) // 检测IC卡
break;
if(PS_Sta) //检测PS_Sta状态,如果有手指按下
{
if(Press_FR()) //刷指纹
break;
}
key_value = Key_scan();
if(key_flag == 1)
{
key_flag = 0;
if(key_value == '#')
{
u8 a = 0,b = 0;
for(i=0;i<tempIndex;i++)
{
if(tempBuff[i] == ManagBuff[a]) // 比较输入的是否是管理员密码
a++;
else
a = 0;
if(tempBuff[i] == PWbuff[b]) // 比较输入的是否是开锁密码
b++;
else
b = 0;

if(a == 6)
{
inputComparSta = 1;
break;
}
else if(b == 6)
{
inputComparSta = 2;
break;
}
}

if(inputComparSta == 1)
{
*proceIndex = 1; // 转到后台管理界面
break;
}
else if(inputComparSta == 2 && ErrUnlock < AllowErrUnlock)
{
ErrUnlock = 0;
LCD_Clear_Scr();
LCD_Display_Words(1,2,"欢迎回家!");
LCD_Display_Words(2,3,"^o^");
/* 开锁 */
SteeringGear_Unlock();
break;
}
else
{
ErrUnlock++;
if(ErrUnlock >= AllowErrUnlock)
{
LCD_Clear_Scr();
LCD_Display_Words(1,1,"门锁已锁死!!");
OPEN_BUZZER();
delay_ms(1500);
CLOSE_BUZZER();
}
else
{
temp = IntToChar[AllowErrUnlock-ErrUnlock];
LCD_Clear_Scr();
LCD_Display_Words(0,2,"**提示**");
LCD_Display_Words(1,0,"密码错误!");
LCD_Display_Words(2,0,"再输入错误");
LCD_Display_Words(2,5,&temp);
LCD_Display_Words(2,6,"次");
LCD_Display_Words(3,0,"门锁将锁死!!");
OPEN_BUZZER();
delay_ms(1500);
CLOSE_BUZZER();
}
break;
}
}
else
{
if(tempIndex < 8)
LCD_Display_Words(2,tempIndex,"*");
else
{
LCD_Display_Words(2,7," ");
delay_ms(50);
LCD_Display_Words(2,7,"*");
}
tempBuff[tempIndex] = key_value;
tempIndex++;
}
}
}
}

// 后台管理界面
void BackSta_ManageMenuCtrl(uint8_t *proceIndex)
{
char temp = 0;
uint16_t key_value = 0;
BackSta_ManageMenu();

if(ErrUnlock >= AllowErrUnlock)
{
ErrUnlock = 0;
SteeringGear_Unlock();
}
while(1)
{
key_value = Key_scan();
if(key_flag == 1)
{
key_flag = 0;
if(key_value == '1' || key_value == '2' || key_value == '3')
{
LCD_Display_Words(1,6," ");
LCD_Display_Words(2,6," ");
LCD_Display_Words(3,6," ");
LCD_Display_Words(key_value-'0',6,"★");
temp = key_value;
}
else if(key_value == '*')
{
*proceIndex = 0; // 转到运行界面
break;
}
else if(key_value == '#')
{
if(temp == '1')
{
*proceIndex = 2; // 转到指纹管理界面
break;
}
else if(temp == '2')
{
*proceIndex = 3; // 转到密码管理界面
break;
}
else if(temp == '3')
{
*proceIndex = 8; // 转到IC卡管理界面
break;
}
}
}
}
}

// 指纹管理界面
void FR_ManageMenuCtrl(uint8_t *proceIndex)
{
uint16_t key_value = 0,temp = 0;
FR_ManageMenu();

while(1)
{
key_value = Key_scan();
if(key_flag == 1)
{
key_flag = 0;
if(key_value == '1' || key_value == '2')
{
LCD_Display_Words(1,6," ");
LCD_Display_Words(2,6," ");
LCD_Display_Words(key_value-'0',6,"★");
temp = key_value;
}
else if(key_value == '*')
{
*proceIndex = 1; // 转到后台管理界面
break;
}
else if(key_value == '#')
{
if(temp == '1')
{
*proceIndex = 6; // 转到添加指纹界面
break;
}
else if(temp == '2')
{
*proceIndex = 7; // 转到删除指纹界面
break;
}
}
}
}
}

// 密码管理界面
void PW_ManageMenuCtrl(uint8_t *proceIndex)
{
uint16_t key_value = 0,temp = 0;
PW_ManageMenu();

while(1)
{
key_value = Key_scan();
if(key_flag == 1)
{
key_flag = 0;
if(key_value == '1' || key_value == '2')
{
LCD_Display_Words(1,7," ");
LCD_Display_Words(2,7," ");
LCD_Display_Words(key_value-'0',7,"★");
temp = key_value;
}
else if(key_value == '*')
{
*proceIndex = 1; // 转到后台管理界面
break;
}
else if(key_value == '#')
{
if(temp == '1')
{
*proceIndex = 4; // 转到修改开锁密码界面
break;
}
else if(temp == '2')
{
*proceIndex = 5; // 转到修改管理员密码界面
break;
}
}
}
}
}

// IC卡管理界面
void IcCard_ManageMenuCtrl(uint8_t *proceIndex)
{
uint16_t key_value = 0,temp = 0;
IcCardManage_Menu();

while(1)
{
key_value = Key_scan();
if(key_flag == 1)
{
key_flag = 0;
if(key_value == '1' || key_value == '2')
{
LCD_Display_Words(1,6," ");
LCD_Display_Words(2,6," ");
LCD_Display_Words(key_value-'0',6,"★");
temp = key_value;
}
else if(key_value == '*')
{
*proceIndex = 1; // 转到后台管理界面
break;
}
else if(key_value == '#')
{
if(temp == '1')
{
*proceIndex = 9; // 转到添加IC卡界面
break;
}
else if(temp == '2')
{
*proceIndex = 10; // 转到删除IC卡界面
break;
}
}
}
}
}

// 修改开锁密码界面
void ModifUnlockPw_Ctrl(uint8_t *proceIndex)
{
uint16_t key_value = 0,buff1[6] = {0},buff2[6] = {0};
uint8_t i = 0,modifIndex = 0,twoInputCompa = 0;
uint8_t tempCnt = 0;
char keytemp = 0;

Show_ModifPW_MenuFirst();

while(1)
{
key_value = Key_scan();
if(key_flag == 1)
{
key_flag = 0;

if(key_value == '*')
{
*proceIndex = 3; // 转到密码管理界面
break;
}
else if(key_value == '#' && tempCnt == 6)
{
if(modifIndex == 0)
{
Show_ModifPW_MenuSecond();
modifIndex = 1;
tempCnt = 0;
}
else
{
for(i=0;i<tempCnt;i++)
{
if(buff1[i] != buff2[i])
{
twoInputCompa = 1;
break;
}
if(buff1[i] == ManagBuff[i])
twoInputCompa = 2;
}
if(twoInputCompa == 1)
{
LCD_Clear_Scr();
LCD_Display_Words(0,2,"**提示**");
LCD_Display_Words(1,0,"两次密码不匹配!");
LCD_Display_Words(2,0,"请重新输入。");
delay_ms(1500);
break;
}
else if(twoInputCompa == 2)
{
LCD_Clear_Scr();
LCD_Display_Words(0,2,"**提示**");
LCD_Display_Words(1,0,"开锁密码不能与管");
LCD_Display_Words(2,0,"理员密码相同!");
LCD_Display_Words(3,0,"请重新输入。");
delay_ms(1500);
delay_ms(1000);
break;
}
else
{
for(i=0;i<tempCnt;i++)
PWbuff[i] = buff2[i];
LCD_Clear_Scr();
LCD_Display_Words(1,0,"密码修改成功!");
STMFLASH_Write(UNLOCK_FLASH_SAVE_ADDR,PWbuff,PASSWORD_SIZE);
delay_ms(1500);
*proceIndex = 3;
break;
}
}
}
else if(tempCnt<6)
{
if(modifIndex == 0)
buff1[tempCnt] = key_value;
else
buff2[tempCnt] = key_value;
keytemp = key_value;
LCD_Display_Words(2,tempCnt,&keytemp);
tempCnt++;
}
}
}
}

// 修改管理员密码界面
void ModifManagePw_Ctrl(uint8_t *proceIndex)
{
uint16_t key_value = 0,buff1[6] = {0},buff2[6] = {0};
uint8_t i = 0,modifIndex = 0,twoInputCompa = 0;
uint8_t tempCnt = 0;
char keytemp = 0;
Show_ModifPW_MenuFirst();

while(1)
{
key_value = Key_scan();
if(key_flag == 1)
{
key_flag = 0;

if(key_value == '*')
{
*proceIndex = 3; // 转到密码管理界面
break;
}
else if(key_value == '#' && tempCnt == 6)
{
if(modifIndex == 0)
{
Show_ModifPW_MenuSecond();
modifIndex = 1;
tempCnt = 0;
}
else
{
for(i=0;i<tempCnt;i++)
{
if(buff1[i] != buff2[i])
{
twoInputCompa = 1;
break;
}
if(buff1[i] == PWbuff[i])
twoInputCompa = 2;
}

if(twoInputCompa == 1)
{
LCD_Clear_Scr();
LCD_Display_Words(0,2,"**提示**");
LCD_Display_Words(1,0,"两次密码不匹配!");
LCD_Display_Words(2,0,"请重新输入。");
delay_ms(1500);
break;
}
else if(twoInputCompa == 2)
{
LCD_Clear_Scr();
LCD_Display_Words(0,2,"**提示**");
LCD_Display_Words(1,0,"理员密码不能与开");
LCD_Display_Words(2,0,"锁密码相同!");
LCD_Display_Words(3,0,"请重新输入。");
delay_ms(1500);
delay_ms(1000);
break;
}
else
{
for(i=0;i<tempCnt;i++)
ManagBuff[i] = buff2[i];
LCD_Clear_Scr();
LCD_Display_Words(1,0,"密码修改成功!");
STMFLASH_Write(MANAGE_FLASH_SAVE_ADDR,ManagBuff,PASSWORD_SIZE);
delay_ms(1500);
*proceIndex = 3;
break;
}
}
}
else if(tempCnt<6)
{
if(modifIndex == 0)
buff1[tempCnt] = key_value;
else
buff2[tempCnt] = key_value;
keytemp = key_value;
LCD_Display_Words(2,tempCnt,&keytemp);
tempCnt++;
}
}
}
}

//录指纹
void AddFR_Ctrl(uint8_t *proceIndex)
{
uint8_t i=0,ensure,processnum=0;
uint16_t ID;
uint16_t key_value = 0,tempBuff[3]={0};
uint8_t tempCnt = 0;
char keytemp = 0;

Show_AddFR_Menu();

while(1)
{
key_value = Key_scan();
if(key_flag == 1)
{
key_flag = 0;
if(key_value == '*')
{
*proceIndex = 2; // 转到指纹管理界面
break;
}
else if(key_value == '#' && tempCnt > 0)
{
if(tempCnt == 1)
ID = tempBuff[0]-'0';
else if(tempCnt == 2)
ID = (tempBuff[0]-'0')*10 + tempBuff[1]-'0';
else
ID = (tempBuff[0]-'0')*100 + (tempBuff[1]-'0')*10 + tempBuff[2]-'0';
break;

}
else if(tempCnt < 3)
{
tempBuff[tempCnt] = key_value;
keytemp = key_value;
LCD_Display_Words(1,tempCnt+5,&keytemp);
tempCnt++;
}
}
}
if(*proceIndex == 2)
return;
while(1)
{
switch(processnum)
{
case 0:
i++;
LCD_Clear_Scr();
LCD_Display_Words(1,0,"请按下你的手指"); //请按手指
while(!PS_Sta); //等待手指按下
ensure=PS_GetImage();
if(ensure==0x00)
{
ensure=PS_GenChar(CharBuffer1);//生成特征
if(ensure==0x00)
{
LCD_Display_Words(2,0,"指纹正确");//指纹正确
i=0;
processnum=1;//跳到第二步
}else ShowErrMessage(ensure);
}else ShowErrMessage(ensure);
delay_ms(1500);
break;

case 1:
i++;
LCD_Clear_Scr();
LCD_Display_Words(1,0,"请再按一次手指");//再按一次手指
while(!PS_Sta);//等待手指按下
ensure=PS_GetImage();
if(ensure==0x00)
{
ensure=PS_GenChar(CharBuffer2);//生成特征
if(ensure==0x00)
{
LCD_Display_Words(2,0,"指纹正确");//指纹正确
i=0;
processnum=2;//跳到第三步
}else ShowErrMessage(ensure);
}else ShowErrMessage(ensure);
delay_ms(1500);
break;

case 2:
LCD_Clear_Scr();
LCD_Display_Words(1,0,"对比两次指纹");//对比两次指纹
delay_ms(1000);
ensure=PS_Match();
if(ensure==0x00)
{
LCD_Display_Words(2,0,"两次指纹是一样的");//两次指纹是一样的
processnum=3;//跳到第四步
}
else
{
LCD_Clear_Scr();
LCD_Display_Words(1,0,"对比失败!");
LCD_Display_Words(2,0,"请重新按手指。");
ShowErrMessage(ensure);
i=0;
processnum=0;//跳回第一步
}
delay_ms(1000);
break;

case 3:
LCD_Clear_Scr();
LCD_Display_Words(1,0,"正在生成指纹模板");//产生一个指纹模板
delay_ms(1000);
ensure=PS_RegModel();
if(ensure==0x00)
{
LCD_Display_Words(2,0,"生成指纹模板成功");//生成指纹模板成功
processnum=4;//跳到第五步
}
else
{
processnum=0;
ShowErrMessage(ensure);
}
delay_ms(1000);
break;

case 4:
ensure=PS_StoreChar(CharBuffer2,ID);//储存模板
if(ensure==0x00)
{
LCD_Clear_Scr();
LCD_Display_Words(1,0,"添加指纹成功");//添加指纹成功
delay_ms(1500);
*proceIndex = 2; // 转到指纹管理界面
return ;
}
else
{
processnum=0;
ShowErrMessage(ensure);
}
break;
}
if(i==5) //超过5次没有按手指则退出
{
LCD_Clear_Scr();
LCD_Display_Words(0,3,"警告");
LCD_Display_Words(2,3,"没有手指按下");
delay_ms(1500);
*proceIndex = 2; // 转到指纹管理界面
break;
}
}
}

//删除指纹
void DelFR_Ctrl(uint8_t *proceIndex)
{
uint8_t ensure,tempCnt = 0;
uint16_t num = 0;
uint16_t key_value = 0,tempBuff[3] = {0};
char keytemp = 0;

Show_DelFR_Menu(); // 显示删除指纹界面
while(1)
{
key_value = Key_scan();
if(key_flag == 1)
{
key_flag = 0;
if(key_value == '*')
{
*proceIndex = 2; // 转到指纹管理界面
break;
}
else if(key_value == '#' && tempCnt > 0)
{
if(tempCnt == 1)
num = tempBuff[0]-'0';
else if(tempCnt == 2)
num = (tempBuff[0]-'0')*10 + tempBuff[1]-'0';
else
num = (tempBuff[0]-'0')*100 + (tempBuff[1]-'0')*10 + tempBuff[2]-'0';
break;

}
else if(tempCnt < 3)
{
tempBuff[tempCnt] = key_value;
keytemp = key_value;
LCD_Display_Words(1,tempCnt+5,&keytemp);
tempCnt++;
}
}
}

if(*proceIndex != 2)
{
if(num == 333)
ensure = PS_Empty();// 清空指纹库
else
ensure = PS_DeletChar(num,1);// 删除单个指纹
if(ensure == 0)
{
LCD_Clear_Scr();
if(num == 333)
LCD_Display_Words(1,0,"清空指纹库成功!"); //删除指纹成功
else
LCD_Display_Words(1,0,"删除指纹成功!"); //删除指纹成功
*proceIndex = 2; // 转到指纹管理界面
}
else
ShowErrMessage(ensure);
delay_ms(1500);
}

}

//刷指纹
uint8_t Press_FR(void)
{
SearchResult seach;
uint8_t ensure;
char IntToChar[10]={'0','1','2','3','4','5','6','7','8','9'},temp = 0;

while(!PS_Sta);//等待手指按下
ensure=PS_GetImage();
if(ensure==0x00)//获取图像成功
{
ensure=PS_GenChar(CharBuffer1);
if(ensure==0x00) //生成特征成功
{
ensure=PS_HighSpeedSearch(CharBuffer1,0,300,&seach);
if(ensure==0x00 && ErrUnlock < AllowErrUnlock) //搜索成功
{
ErrUnlock = 0;
LCD_Clear_Scr();
LCD_Display_Words(1,2,"欢迎回家!");
LCD_Display_Words(2,3,"^o^");
/* 开锁 */
SteeringGear_Unlock();
}
else
{
ErrUnlock++;
if(ErrUnlock >= AllowErrUnlock)
{
LCD_Clear_Scr();
LCD_Display_Words(1,1,"门锁已锁死!!");
OPEN_BUZZER();
delay_ms(1500);
CLOSE_BUZZER();
}
else
{
temp = IntToChar[AllowErrUnlock-ErrUnlock];
LCD_Clear_Scr();
LCD_Display_Words(0,2,"**提示**");
LCD_Display_Words(1,0,"指纹错误!");
LCD_Display_Words(2,0,"再输入错误");
LCD_Display_Words(2,5,&temp);
LCD_Display_Words(2,6,"次");
LCD_Display_Words(3,0,"门锁将锁死!!");
OPEN_BUZZER();
delay_ms(1500);
CLOSE_BUZZER();
}
}
}
return 1;
}
return 0;
}

// 添加IC卡
void AddIcCard_Ctrl(uint8_t *proceIndex)
{
u8 ucArray_ID[4]; //先后存放IC卡的类型和UID(IC卡序列号)
u8 ucStatusReturn; //返回状态
uint16_t key_value = 0,flag = 0;
char IntToChar[10]={'0','1','2','3','4','5','6','7','8','9'},temp = 0;

Show_AddIcCard_Menu(); // 显示添加IC卡界面
while(1)
{
key_value = Key_scan();
if(key_flag == 1)
{
key_flag = 0;
if(key_value == '*')
{
*proceIndex = 8; // 转到IC卡管理界面
break;
}
}

ucStatusReturn = PcdRequest(PICC_REQALL, ucArray_ID); //寻卡
if(ucStatusReturn == MI_OK)
{
if(PcdAnticoll (ucArray_ID) == MI_OK) //防冲撞(当有多张卡进入读写器操作范围时,防冲突机制会从其中选择一张进行操作)
{
for(u8 i=1;i<=IcCardNum;i++)
{
for(u8 j=0;j<4;j++)
{
if(ICBuff[i][j] == ucArray_ID[j])
{
flag++;
if(flag == 4)
break;
}
else
{
flag = 0;
break;
}
}
if(flag == 4)
break;
}
if(flag == 4)
{
LCD_Clear_Scr();
LCD_Display_Words(0,0,"******错误******");
LCD_Display_Words(2,1,"此IC卡已存在");
delay_ms(1000);
}
else
{
IcCardNum++;
for(u8 i=0;i<4;i++)
ICBuff[IcCardNum][i] = ucArray_ID[i];
temp = IntToChar[IcCardNum];
ICBuff[0][0] = IcCardNum;
STMFLASH_Write(ICCARD_FLASH_SAVE_ADDR,(uint16_t *)ICBuff,(IcCardNum+1)*4); // 保存内容到FLASH
LCD_Clear_Scr();
LCD_Display_Words(1,0,"读取完成");
delay_ms(800);
LCD_Display_Words(2,0,"添加卡");
LCD_Display_Words(2,3,&temp);
LCD_Display_Words(2,4,"成功");
delay_ms(1500);
}
*proceIndex = 9; // 转到添加IC卡界面
break;
}
}
}
}

// 删除IC卡
void DelIcCard_Ctrl(uint8_t *proceIndex)
{
if(IcCardNum == 0)
{
LCD_Clear_Scr();
LCD_Display_Words(0,0,"******提示******");
LCD_Display_Words(2,1,"IC卡已清空");
*proceIndex = 8; // 转到IC卡管理界面
delay_ms(1000);
delay_ms(1000);
return;
}
u8 ucArray_ID[4]; //先后存放IC卡的类型和UID(IC卡序列号)
u8 ucStatusReturn; //返回状态
uint16_t tempBuff[2] = {0},tempCnt = 0,key_value = 0,num = 0;
u8 flag = 0,detectFlag = 0;
char keytemp = 0,temp = 0;
char IntToChar[10]={'0','1','2','3','4','5','6','7','8','9'};

Show_DelIcCard_Menu(); // 显示添加IC卡界面
while(1)
{
key_value = Key_scan();
if(key_flag == 1)
{
key_flag = 0;
if(key_value == '*')
{
*proceIndex = 8; // 转到IC卡管理界面
break;
}
else if(key_value == '#' && tempCnt > 0)
{
if(tempCnt == 1)
num = tempBuff[0]-'0';
else if(tempCnt == 2)
num = (tempBuff[0]-'0')*10 + tempBuff[1]-'0';
flag = 1;
break;
}
else if(tempCnt < 2)
{
tempBuff[tempCnt] = key_value;
keytemp = key_value;
LCD_Display_Words(2,tempCnt+4,&keytemp);
tempCnt++;
}
}

ucStatusReturn = PcdRequest(PICC_REQALL, ucArray_ID); //寻卡
if(ucStatusReturn == MI_OK)
{
if(PcdAnticoll (ucArray_ID) == MI_OK) //防冲撞(当有多张卡进入读写器操作范围时,防冲突机制会从其中选择一张进行操作)
{
detectFlag = 1;
for(u8 i=1;i<=IcCardNum;i++)
{
for(u8 j=0;j<4;j++)
{
if(ICBuff[i][j] == ucArray_ID[j])
{
flag++;
if(flag == 4)
break;
}
else
{
flag = 0;
break;
}
}
if(flag == 4)
{
num = i;
break;
}
}
}

}
if(flag == 4 || detectFlag == 1)
break;
}
if(*proceIndex != 8)
{
if(num == 33) // 删除所有IC卡
{
for(u16 i=0;i<ICCARD_NUM;i++)
for(u16 j=0;j<4;j++)
ICBuff[i][j] = 0;
uint16_t buff[ICCARD_NUM] = {0};
STMFLASH_Write(ICCARD_FLASH_SAVE_ADDR,buff,(IcCardNum+1)*4); // 保存内容到FLASH
IcCardNum = 0;
}
else if(flag == 0 || num > IcCardNum || num == 0)
{
LCD_Clear_Scr();
LCD_Display_Words(0,0,"******错误******");
LCD_Display_Words(2,1,"此IC卡不存在");
delay_ms(1000);
}
else
{
// 删除相应的IC卡
for(u8 i=0;i<4;i++)
ICBuff[num][i] = 0;
temp = IntToChar[num];
IcCardNum--;
ICBuff[0][0] = IcCardNum;
STMFLASH_Write(ICCARD_FLASH_SAVE_ADDR,(uint16_t *)ICBuff,(IcCardNum+1)*4); // 保存内容到FLASH
LCD_Clear_Scr();
LCD_Display_Words(1,0,"删除卡");
LCD_Display_Words(1,3,&temp);
LCD_Display_Words(1,4,"成功");
delay_ms(1500);
}
*proceIndex = 10; // 转到删除IC卡界面
}
}

// 检测IC卡
u8 Card_Detected(void)
{
u8 ucArray_ID[4]; //先后存放IC卡的类型和UID(IC卡序列号)
u8 ucStatusReturn; //返回状态
u8 flag = 0;

ucStatusReturn = PcdRequest(PICC_REQALL, ucArray_ID); //若失败再次寻卡
if(ucStatusReturn == MI_OK)
{
if(PcdAnticoll (ucArray_ID) == MI_OK) //防冲撞(当有多张卡进入读写器操作范围时,防冲突机制会从其中选择一张进行操作)
{
for(u8 i=1;i<=IcCardNum;i++)
{
for(u8 j=0;j<4;j++)
{
if(ICBuff[i][j] == ucArray_ID[j])
{
flag++;
if(flag == 4)
break;
}
else
{
flag = 0;
break;
}
}
if(flag == 4 && ErrUnlock < AllowErrUnlock)
{
ErrUnlock = 0;
LCD_Clear_Scr();
LCD_Display_Words(1,2,"欢迎回家!");
LCD_Display_Words(2,3,"^o^");
/* 开锁 */
SteeringGear_Unlock();

return 1;
}
}
}
}
return 0;
}
// 显示确认码错误信息
void ShowErrMessage(uint8_t ensure)
{
LCD_Clear_Scr();
Display_LCD_String(EnsureMessage(ensure));
}

// 显示使用界面
void UserMenu(void)
{
LCD_Clear_Scr();
LCD_Display_Words(0,2,"智能门锁");
LCD_Display_Words(1,0,"输入密码:");
LCD_Display_Words(3,4,"确认(#)");
}

// 显示后台管理界面
void BackSta_ManageMenu(void)
{
LCD_Clear_Scr();
LCD_Display_Words(0,0,"----");
LCD_Display_Words(0,6,"----");
LCD_Display_Words(0,2,"后台管理");
LCD_Display_Words(1,1,"1.指纹管理");
LCD_Display_Words(2,1,"2.密码管理");
LCD_Display_Words(3,1,"3.IC卡管理");
}

// 显示指纹管理界面
void FR_ManageMenu(void)
{
LCD_Clear_Scr();
LCD_Display_Words(0,0,"----");
LCD_Display_Words(0,6,"----");
LCD_Display_Words(0,2,"指纹管理");
LCD_Display_Words(1,1,"1.添加指纹");
LCD_Display_Words(2,1,"2.删除指纹");
LCD_Display_Words(3,0,"后退");
LCD_Display_Words(3,6,"确认");
}

// 显示密码管理界面
void PW_ManageMenu(void)
{
LCD_Clear_Scr();
LCD_Display_Words(0,0,"----");
LCD_Display_Words(0,6,"----");
LCD_Display_Words(0,2,"密码管理");
LCD_Display_Words(1,0,"1.修改开锁密码");
LCD_Display_Words(2,0,"2.修改管理密码");
LCD_Display_Words(3,0,"后退");
LCD_Display_Words(3,6,"确认");
}

// 显示IC卡管理界面
void IcCardManage_Menu(void)
{
LCD_Clear_Scr();
LCD_Display_Words(0,0,"----");
LCD_Display_Words(0,6,"----");
LCD_Display_Words(0,2,"IC卡管理");
LCD_Display_Words(1,1,"1.添加IC卡");
LCD_Display_Words(2,1,"2.删除IC卡");
LCD_Display_Words(3,0,"后退");
LCD_Display_Words(3,6,"确认");
}

// 显示修改开锁密码界面
void Show_ModifPW_MenuFirst(void)
{
LCD_Clear_Scr();
LCD_Display_Words(0,0,"----");
LCD_Display_Words(0,6,"----");
LCD_Display_Words(0,2,"修改密码");
LCD_Display_Words(1,0,"请输入新密码:");
LCD_Display_Words(3,0,"取消");
LCD_Display_Words(3,6,"确认");
}

// 显示修改开锁密码界面
void Show_ModifPW_MenuSecond(void)
{
LCD_Clear_Scr();
LCD_Display_Words(0,0,"----");
LCD_Display_Words(0,6,"----");
LCD_Display_Words(0,2,"修改密码");
LCD_Display_Words(1,0,"请确认新密码:");
LCD_Display_Words(3,0,"取消");
LCD_Display_Words(3,6,"确认");
}

// 显示添加指纹界面
void Show_AddFR_Menu(void)
{
LCD_Clear_Scr();
LCD_Display_Words(0,0,"----");
LCD_Display_Words(0,6,"----");
LCD_Display_Words(0,2,"添加指纹");
LCD_Display_Words(1,0,"请输入ID:");
LCD_Display_Words(3,0,"后退");
LCD_Display_Words(3,6,"确认");
}

// 显示删除指纹界面
void Show_DelFR_Menu(void)
{
LCD_Clear_Scr();
LCD_Display_Words(0,0,"----");
LCD_Display_Words(0,6,"----");
LCD_Display_Words(0,2,"删除指纹");
LCD_Display_Words(1,0,"请输入ID:");
LCD_Display_Words(3,0,"后退");
LCD_Display_Words(3,6,"确认");
}

// 显示添加IC卡界面
void Show_AddIcCard_Menu(void)
{
LCD_Clear_Scr();
LCD_Display_Words(0,0,"----");
LCD_Display_Words(0,6,"----");
LCD_Display_Words(0,2,"添加IC卡");
LCD_Display_Words(1,0,"请把新IC卡放置到");
LCD_Display_Words(2,0,"感应区域。");
LCD_Display_Words(3,0,"取消");
}

// 显示删除IC卡界面
void Show_DelIcCard_Menu(void)
{
LCD_Clear_Scr();
LCD_Display_Words(0,0,"----");
LCD_Display_Words(0,6,"----");
LCD_Display_Words(0,2,"删除IC卡");
LCD_Display_Words(1,0,"请直接刷卡,或者");
LCD_Display_Words(2,0,"输入ID:");
LCD_Display_Words(3,0,"取消");
LCD_Display_Words(3,6,"确认");
}

void SteeringGear_Unlock(void)
{
TIM_SetCompare1(RDS3115_TIM,5);
delay_ms(1500);
TIM_SetCompare1(RDS3115_TIM,9);
delay_ms(100);
TIM_SetCompare1(RDS3115_TIM,13);
}
/*********************************************END OF FILE*********************************************/

六、元器件接线说明

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
【 !】 引脚分配

STM32 LCD12864
+3.3v <---> Vcc
GND <---> GND
PB7 <---> CS(RS)
PB8 <---> SID(R/W)
PB9 <---> SCLK(E)
GND <---> PSB
+3.3v <---> RST
+3.3v <---> BLA
GND <---> BLK

STM32 矩阵键盘
PB12 <---> C4
PB13 <---> C3
PB14 <---> C2
PB15 <---> C1
PA8 <---> R4
PA9 <---> R3
PA10 <---> R2
PA11 <---> R1

STM32 ATK-AS608
+3.3V <---> Vi
PA3(Rx) <---> Tx
PA2(Tx) <---> Rx
GND <---> GND
PA1 <---> WAK
+3.3V <---> Vt
波特率:115200

STM32 RC522
PA4 <---> SDA
PA5 <---> SCK
PA7 <---> MOSI
PA6 <---> MISO
GND <---> GND
PA0 <---> RST
+3.3V <---> +3.3V

STM32 Buzzer
PB0 <---> +
GND <---> GND

STM32 Steering gear
PB6 <---> signal
GND <---> GND
+3.3V <---> +3.3V

STM32 串口模块
PB11(Rx) <---> Tx
PB10(Tx) <---> Rx
+3.3V <---> +3.3V
GND <---> GND
波特率:115200


基于STM32的智能门锁系统设计
https://kevinloongc.github.io/posts/6304ed30.html
作者
Kevin Loongc
发布于
2019年12月28日
许可协议