当前位置:   article > 正文

基于stm32f103c8t6及AS608-----指纹锁项目_stm32f103c8t6项目

stm32f103c8t6项目

一、关于本项目:

 

        博主纯小白,本文适合于初学者,大佬还请勿喷,欢迎提出意见,有纰漏之处将及时纠正。在浅学了stmf103c8t6后,想着依据现在所拥有的知识和能力做一个小项目。

eadad54c723549f791d6b8c9d5a259ae.webp

注:工程代码在文章末尾。

二、准备工作:

  1. 掌握C语言基础....这个最基础啦...
  2. 接触过类似单片机,稍微看得懂芯片手册,会烧录啥的...
  3. 画板子,焊接(这个项目里自己给画了一个板子,整体更整洁美观一点,其实也不是必要的,个人选择)..
  4. 需要用到的一些硬件...

三、硬件需要:(大概估计了一下成本在100左右)

1.stm32f103c8t6核心板:某宝上十几元一块吧,如下

2f60e49286664b5c9d9230d836d8aa37.jpeg

 2.AS608指纹模块:(价格的话四十几元左右)

d867b145b3b8418fab75a1d0d2e8b164.jpeg

 3.0.96寸OLED模块:用的IIC,要想用spi的话可以自己改改代码。主要用于菜单选择。

6f8465dd381446e3acca53c0723274b8.png

 4.蜂鸣器:我这直接买的模块,给个低电平就能响,用于判断指纹锁的状态

3a1b0bbb88424705b7807267abdf3ff0.jpeg

 5.薄膜按键:用来对应oled,进行操作的选择。

c8710659c4fb498ea7ebad3f9e739481.jpeg

 6.SG90舵机

1d1e7a74431443ea8813cf3ffb023eca.jpeg

 四、功能介绍及大致流程

      先来个整体图:这是开机通电情况下的,从这个图基本能看到所有的外设。右上角的是总开关。这个开关用的一种金属按钮,这个按钮接线确实需要研究一下,最快的办法就是用万用表测按钮按下和未按下时各个脚的连通情况。左上角的的是一个小型的直流电压表,因为我用的是两节18650输出7.4v电压供电,为了实时监测电池状态,所以加了一个电压表。注:18650电池放电电压低到一定值会对电池造成不可逆的伤害,一般6.3v左右吧。

       中间的oled可以用下面的按键来显示不同功能,无操作时就会显示Main Menu,也就是主菜单的意思。按下2,则进入刷指纹功能,将已经录入过的指纹按在AS608上扫描可以被识别出来,使下面的舵机转动,舵机带动IC进行刷卡动作,(这个透明盒子的下面是留有缺口的的,IC卡能伸出去)宿舍门解锁成功。按下1,会进入录入指纹操作,我这里设置了一个安全防护,也就是说如果需要录入新的指纹,需要先进行一次刷指纹,才能进行录入指纹,也就是说必须要有之前录入过的人去刷一下,然后才能录入新指纹。这里的话安全防护我不是采用输入密码的方式,用指纹解锁替代。3键是返回主菜单键,例如要执行刷指纹操作,按下2后,中途不想继续了,可以按下3直接回到主菜单。4键这里没有用到(其实是当时设计板子的时候没有看这个薄膜按键的实物,如果需要用全四个键,则需要五个接口,而我却以为只需要四个接口ᕙ༼ ͝°益° ༽ᕗ,属实是大意了)。

其实本来想用3D打印做个外壳,但是这价格确实有点高(๑ó﹏ò๑)啊。d49450f85f1544aa82bfb7e8f6902fac.webp

16b16630643e4ea385628f82486914b1.jpeg

46579b541ea24c1e951cfb14b9d2c0ea.jpg

出发点的话比较简单:考虑到宿舍的门锁的类型(我们宿舍门是需要用学生IC卡刷一下解锁才能推进来),所以就想用这个东西来代替人为刷卡。其实说明白点,就是如果没带IC卡,还能通过这一方式来解锁门禁。

五、PCB设计

这个项目的板子是用嘉立创eda画的,毕竟可以免费打板๑乛◡乛๑。项目要求不是很高,随便布的线,如下图

2856b4f2419a48bcb3aa4304d8dbc083.png

0eb83625902c4319884e4a603df8498e.png

具体实物: 

22a46ec3dcde4dd9ba0ed682f1568a7c.jpeg

其实就是几个电源模块,因为输入的是7.4v,用的AMS1117转化为5v或者3.3v供外设使用。 然后引出了一些脚。

40216f109716402c880ad6892920b942.png

 之前在开发板上测试,然后才打的板子。

六、功能代码实现

 (一)本项目AS608使用:

对于这个模块它是有现成的函数去操作它,只需要知道怎么使用即可(可以用资料里的软件测试一下AS608)。下面进行说明:

用到的现成函数
PS_GetImage(void); //录入图像 
PS_GenChar(u8 BufferID);//生成特征 
PS_Match(void);//精确比对两枚指纹特征 
PS_Search(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p);//搜索指纹 
PS_RegModel(void);//合并特征(生成模板)
PS_StoreChar(u8 BufferID,u16 PageID);//储存模板
PS_DeletChar(u16 PageID,u16 N);//删除模板
PS_Empty(void);//清空指纹库
PS_ValidTempleteNum(u16 *ValidN);//读有效模板个数
PS_HandShake(u32 *PS_Addr); //与AS608模块握手

其实大致流程是这样的:

1.用PS_HandShake( )函数与AS608握手,这个握手类似于单片机向AS608发送一些信息,如果AS608能正常工作的话它会返回一些对应东西来回答你。这个函数用于确认AS608能正常运行,开始运行时先执行这个函数。

2.用PS_GetImage( )来获取按在模块上手指的指纹图像,然后执行PS_GenChar( )来获取这个图像里面的特征,将这个特征存在CharBuffer1或CharBuffer2,是AS08中存储的两个区域。这边的两个函数要执行两次,也就是说录入一个指纹的时候需要按两次,然后AS608执行PS_Match( )去对比刚刚采集到的两个特征,如果符合条件,则执行生成模板PS_RegModel( )函数,然后再存储PS_StoreChar( );具体的每个函数需要的变量大家还是参考keil工程里的文件。

 3.PS_DeletChar(u16 PageID,u16 N)这个是用来删除指定位置的指纹,PS_Empty(void);这个函数是清空指纹库。

4.读取内部指纹个数:PS_ValidTempleteNum(u16 *ValidN),可以令一个数等于ValidN,再打印出来即可看见。

5.PS_Search(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p);搜索函数,也就是搜索现在刷的指纹在指纹库库中有没有对应的指纹,如果有的话,可以自定义输出一些提示文字啥的,比如find。

关于AS608:

3f61d1c22d154ba6a193a618b51f950f.png

 引脚接线:一共有八个接口,这里只用到了前六个,一般也不会用到后两个。

  1. Vi 模块电源正输入端,3.3。
  2. Tx 串行数据输出。 TTL 逻辑电平,接c8t6的Rx。
  3. Rx 串行数据输入。 TTL 逻辑电平,接c8t6的Tx。
  4. GND 信号地。内部与电源地连接
  5. WAK 感应信号输出,默认高电平有效(用户可读取状态引脚(WAK)判断有无手指按下,该项目中提供一个中断)
  6. Vt 触摸感应电源输入端,3.3v 供电(没看错,如果需要检测是否有指纹在上面,就需要接入3.3v,总共两个3.3v
  7. U+ USB D+
  8. U- USB D-

 资源分布:

1.缓冲区与指纹库
    系统内设有一个 72K 字节的图像缓冲区与二个 512bytes 大小的特征文件缓冲区,名字分别称为:ImageBuffer,CharBuffer1 和 CharBuffer2。用户可以通过指令读写任意一个缓冲区。
CharBuffer1 或 CharBuffer2 既可以用于存放普通特征文件也可以用于存放模板特征文件。通过 UART 口上传或下载图像时为了加快速度,只用到像素字节的高 4 位,即将两个像素合
成一个字节传送。通过 USB 口则是整 8 位像素。
指纹库容量根据挂接的 FLASH 容量不同而改变,系统会自动判别。指纹模板按照序号存放,序号定义为:0—(N-1)(N 为指纹库容量)。用户只能根据序号访问指纹库内容。
2.用户记事本
    系统在 FLASH 中开辟了一个 512 字节的存储区域作为用户记事本,该记事本逻辑上被分成 16 页,每页 32 字节。上位机可以通过 PS_WriteNotepad 指令和 PS_ReadNotepad 指令
访问任意一页。注意写记事本某一页的时候,该页 32 字节的内容被整体写入,原来的内容被覆盖。
3.随机数产生器
    系统内部集成了硬件 32 位随机数生成器(不需要随机数种子),用户可以通过指令让模块产生一个随机数并上传给上位机。
4.软件开发
模块地址 (大小:4bytes ,属性:读写) )
    模块的默认地址为0xFFFFFFFF,可通过指令修改,数据包的地址域必须与该地址相配,命令包/数据包才被系统接收。 注:与上位机通讯必须是默认地址 0xFFFFFFFF !
   模块口令 (大小:4bytes ,属性:写)
    系统默认口令为 0,可通过指令修改。若默认口令未被修改,则系统不要求验证口令,
上位机和 MCU 与芯片通讯;若口令被修改,则上位机与芯片通讯的第一个指令必须是验证
口令,只有口令验证通过后,芯片才接收其它指令。 注:不建议修改口令!
数据包大小设置(大小:1bytes ,属性:读写)
    发送数据包和接收数据包的长度根据该值设定。
波特率数 系数 N 设置 (大小:1bytes ,属性:读写)
    USART 波特率=N×9600,N=1~12。
安全等级 level 设置(大小:1bytes ,属性:读写)
    系统根据安全等级设定比对阀值,level=1~5。安全等级为 1 时认假率最高,拒认率最低。
安全等级为 5 时认假率最低,拒认率最高。
原文链接:https://blog.csdn.net/qq_44629109/article/details/108582138

此处为as608.c代码:对应功能,代码以注释上。部分函数并没有用到。

  1. #include <string.h>
  2. #include "delay.h"
  3. #include "usart2.h"
  4. #include "as608.h"
  5. #include "stm32f10x.h"
  6. #include "OLED_I2C.h"
  7. #include "sys.h"
  8. #include "BEEP.h"
  9. //extern u16 user_ID;
  10. u32 AS608Addr = 0XFFFFFFFF; //默认
  11. u8 Have; //手指按下标志
  12. extern u16 ValidN;//模块内有效模板个数
  13. extern SysPara AS608Para;//指纹模块AS608参数
  14. //刷指纹
  15. void press_FR(void)
  16. {
  17. SearchResult seach;
  18. u8 ensure;
  19. ensure=PS_GetImage();
  20. if(ensure==0x00)//获取图像成功
  21. {
  22. ensure=PS_GenChar(CharBuffer1);
  23. if(ensure==0x00) //生成特征成功
  24. {
  25. ensure=PS_HighSpeedSearch(CharBuffer1,0,300,&seach);
  26. if(ensure==0x00)//搜索成功
  27. {
  28. OLED_ShowStr(64,3," --INSERT OK--",1);
  29. // printf("\r\n 指纹匹配成功 \r\n");//搜索指纹成功
  30. // open_door_flag=1;
  31. // printf("Match ID:%d Match score:%d",seach.pageID,seach.mathscore);//显示匹配指纹的ID和分数
  32. //user_ID=seach.pageID;
  33. }
  34. else
  35. {
  36. OLED_ShowStr(0,1," --NO finger--",1); //
  37. // BEEP=1;DelayMs(300);BEEP=0;
  38. DelayMs(300);
  39. }
  40. }
  41. else
  42. {
  43. OLED_ShowStr(0,6," --NO finger--",1); //
  44. DelayMs(1000);
  45. printf("\r\n%s",EnsureMessage(ensure));
  46. }
  47. }
  48. }
  49. //初始化PA6为下拉输入
  50. //读摸出感应状态(触摸感应时输出高电平信号)
  51. void PS_StaGPIO_Init(void)
  52. {
  53. EXTI_InitTypeDef EXTI_InitStructure;
  54. NVIC_InitTypeDef NVIC_InitStructure;
  55. GPIO_InitTypeDef GPIO_InitStructure;
  56. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟
  57. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能GPIOA时钟
  58. //打开PA端口时钟,并且打开复用时钟
  59. //初始化读状态引脚GPIOA
  60. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  61. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//输入下拉模式
  62. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
  63. GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
  64. //GPIOA.6 中断线以及中断初始化配置
  65. GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource6);
  66. EXTI_InitStructure.EXTI_Line=EXTI_Line6;
  67. EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  68. EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  69. EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  70. EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
  71. NVIC_InitStructure.NVIC_IRQChannel =EXTI9_5_IRQn; //使能按键所在的外部中断通道
  72. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级2
  73. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级1
  74. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
  75. NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
  76. }
  77. void EXTI9_5_IRQHandler(void)
  78. {
  79. if(EXTI_GetITStatus(EXTI_Line6)!=RESET){
  80. Have=1;
  81. }
  82. EXTI_ClearITPendingBit(EXTI_Line6); //清除LINE5上的中断标志位
  83. }
  84. //串口发送一个字节
  85. static void MYUSART_SendData(u8 data)
  86. {
  87. while((USART2->SR&0X40)==0);
  88. USART2->DR = data;
  89. }
  90. //发送包头
  91. static void SendHead(void)
  92. {
  93. MYUSART_SendData(0xEF);
  94. MYUSART_SendData(0x01);
  95. }
  96. //发送地址
  97. static void SendAddr(void)
  98. {
  99. MYUSART_SendData(AS608Addr>>24);
  100. MYUSART_SendData(AS608Addr>>16);
  101. MYUSART_SendData(AS608Addr>>8);
  102. MYUSART_SendData(AS608Addr);
  103. }
  104. //发送包标识,
  105. static void SendFlag(u8 flag)
  106. {
  107. MYUSART_SendData(flag);
  108. }
  109. //发送包长度
  110. static void SendLength(int length)
  111. {
  112. MYUSART_SendData(length>>8);
  113. MYUSART_SendData(length);
  114. }
  115. //发送指令码
  116. static void Sendcmd(u8 cmd)
  117. {
  118. MYUSART_SendData(cmd);
  119. }
  120. //发送校验和
  121. static void SendCheck(u16 check)
  122. {
  123. MYUSART_SendData(check>>8);
  124. MYUSART_SendData(check);
  125. }
  126. //判断中断接收的数组有没有应答包
  127. //waittime为等待中断接收数据的时间(单位1ms)
  128. //返回值:数据包首地址
  129. static u8 *JudgeStr(u16 waittime)
  130. {
  131. char *data;
  132. u8 str[8];
  133. str[0]=0xef;str[1]=0x01;str[2]=AS608Addr>>24;
  134. str[3]=AS608Addr>>16;str[4]=AS608Addr>>8;
  135. str[5]=AS608Addr;str[6]=0x07;str[7]='\0';
  136. USART2_RX_STA=0;
  137. while(--waittime)
  138. {
  139. DelayMs(1);
  140. if(USART2_RX_STA&0X8000)//接收到一次数据
  141. {
  142. USART2_RX_STA=0;
  143. data=strstr((const char*)USART2_RX_BUF,(const char*)str);
  144. if(data)
  145. return (u8*)data;
  146. }
  147. }
  148. return 0;
  149. }
  150. //上传图像: PS_UPImage
  151. //功能:将图像缓冲区中的数据上传给上位机
  152. //模块返回确认字
  153. u8 PS_UpImage(void)
  154. {
  155. u16 temp;
  156. u8 ensure;
  157. u8 *data;
  158. SendHead();
  159. SendAddr();
  160. SendFlag(0x01);//命令包标识
  161. SendLength(0x03); //数据包长度
  162. Sendcmd(0x0a); //命令包
  163. temp = 0x01+0x03+0x0a;
  164. SendCheck(temp); //校验和
  165. data=JudgeStr(8000);
  166. if(data)
  167. ensure=data[9];
  168. else
  169. ensure=0xff;
  170. return ensure;
  171. }
  172. //录入图像 PS_GetImage
  173. //功能:探测手指,探测到后录入指纹图像存于ImageBuffer。
  174. //模块返回确认字
  175. u8 PS_GetImage(void)
  176. {
  177. u16 temp;
  178. u8 ensure;
  179. u8 *data;
  180. SendHead();
  181. SendAddr();
  182. SendFlag(0x01);//命令包标识
  183. SendLength(0x03);
  184. Sendcmd(0x01);
  185. temp = 0x01+0x03+0x01;
  186. SendCheck(temp);
  187. data=JudgeStr(2000);
  188. if(data)
  189. ensure=data[9];
  190. else
  191. ensure=0xff;
  192. return ensure;
  193. }
  194. //生成特征 PS_GenChar
  195. //功能:将ImageBuffer中的原始图像生成指纹特征文件存于CharBuffer1或CharBuffer2
  196. //参数:BufferID --> charBuffer1:0x01 charBuffer1:0x02
  197. //模块返回确认字
  198. u8 PS_GenChar(u8 BufferID)
  199. {
  200. u16 temp;
  201. u8 ensure;
  202. u8 *data;
  203. SendHead();
  204. SendAddr();
  205. SendFlag(0x01);//命令包标识
  206. SendLength(0x04);
  207. Sendcmd(0x02);
  208. MYUSART_SendData(BufferID);
  209. temp = 0x01+0x04+0x02+BufferID;
  210. SendCheck(temp);
  211. data=JudgeStr(2000);
  212. if(data)
  213. ensure=data[9];
  214. else
  215. ensure=0xff;
  216. return ensure;
  217. }
  218. //精确比对两枚指纹特征 PS_Match
  219. //功能:精确比对CharBuffer1 与CharBuffer2 中的特征文件
  220. //模块返回确认字
  221. u8 PS_Match(void)
  222. {
  223. u16 temp;
  224. u8 ensure;
  225. u8 *data;
  226. SendHead();
  227. SendAddr();
  228. SendFlag(0x01);//命令包标识
  229. SendLength(0x03);
  230. Sendcmd(0x03);
  231. temp = 0x01+0x03+0x03;
  232. SendCheck(temp);
  233. data=JudgeStr(2000);
  234. if(data)
  235. ensure=data[9];
  236. else
  237. ensure=0xff;
  238. return ensure;
  239. }
  240. //搜索指纹 PS_Search
  241. //功能:以CharBuffer1或CharBuffer2中的特征文件搜索整个或部分指纹库.若搜索到,则返回页码。
  242. //参数: BufferID @ref CharBuffer1 CharBuffer2
  243. //说明: 模块返回确认字,页码(相配指纹模板)
  244. u8 PS_Search(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p)
  245. {
  246. u16 temp;
  247. u8 ensure;
  248. u8 *data;
  249. SendHead();
  250. SendAddr();
  251. SendFlag(0x01);//命令包标识
  252. SendLength(0x08);
  253. Sendcmd(0x04);
  254. MYUSART_SendData(BufferID);
  255. MYUSART_SendData(StartPage>>8);
  256. MYUSART_SendData(StartPage);
  257. MYUSART_SendData(PageNum>>8);
  258. MYUSART_SendData(PageNum);
  259. temp = 0x01+0x08+0x04+BufferID
  260. +(StartPage>>8)+(u8)StartPage
  261. +(PageNum>>8)+(u8)PageNum;
  262. SendCheck(temp);
  263. data=JudgeStr(2000);
  264. if(data)
  265. {
  266. ensure = data[9];
  267. p->pageID =(data[10]<<8)+data[11];
  268. p->mathscore=(data[12]<<8)+data[13];
  269. }
  270. else
  271. ensure = 0xff;
  272. return ensure;
  273. }
  274. //合并特征(生成模板)PS_RegModel
  275. //功能:将CharBuffer1与CharBuffer2中的特征文件合并生成 模板,结果存于CharBuffer1与CharBuffer2
  276. //说明: 模块返回确认字
  277. u8 PS_RegModel(void)
  278. {
  279. u16 temp;
  280. u8 ensure;
  281. u8 *data;
  282. SendHead();
  283. SendAddr();
  284. SendFlag(0x01);//命令包标识
  285. SendLength(0x03);
  286. Sendcmd(0x05);
  287. temp = 0x01+0x03+0x05;
  288. SendCheck(temp);
  289. data=JudgeStr(2000);
  290. if(data)
  291. ensure=data[9];
  292. else
  293. ensure=0xff;
  294. return ensure;
  295. }
  296. //储存模板 PS_StoreChar
  297. //功能:将 CharBuffer1 或 CharBuffer2 中的模板文件存到 PageID 号flash数据库位置。
  298. //参数: BufferID @ref charBuffer1:0x01 charBuffer1:0x02
  299. // PageID(指纹库位置号)
  300. //说明: 模块返回确认字
  301. u8 PS_StoreChar(u8 BufferID,u16 PageID)
  302. {
  303. u16 temp;
  304. u8 ensure;
  305. u8 *data;
  306. SendHead();
  307. SendAddr();
  308. SendFlag(0x01);//命令包标识
  309. SendLength(0x06);
  310. Sendcmd(0x06);
  311. MYUSART_SendData(BufferID);
  312. MYUSART_SendData(PageID>>8);
  313. MYUSART_SendData(PageID);
  314. temp = 0x01+0x06+0x06+BufferID
  315. +(PageID>>8)+(u8)PageID;
  316. SendCheck(temp);
  317. data=JudgeStr(2000);
  318. if(data)
  319. ensure=data[9];
  320. else
  321. ensure=0xff;
  322. return ensure;
  323. }
  324. //删除模板 PS_DeletChar
  325. //功能: 删除flash数据库中指定ID号开始的N个指纹模板
  326. //参数: PageID(指纹库模板号),N删除的模板个数。
  327. //说明: 模块返回确认字
  328. u8 PS_DeletChar(u16 PageID,u16 N)
  329. {
  330. u16 temp;
  331. u8 ensure;
  332. u8 *data;
  333. SendHead();
  334. SendAddr();
  335. SendFlag(0x01);//命令包标识
  336. SendLength(0x07);
  337. Sendcmd(0x0C);
  338. MYUSART_SendData(PageID>>8);
  339. MYUSART_SendData(PageID);
  340. MYUSART_SendData(N>>8);
  341. MYUSART_SendData(N);
  342. temp = 0x01+0x07+0x0C
  343. +(PageID>>8)+(u8)PageID
  344. +(N>>8)+(u8)N;
  345. SendCheck(temp);
  346. data=JudgeStr(2000);
  347. if(data)
  348. ensure=data[9];
  349. else
  350. ensure=0xff;
  351. return ensure;
  352. }
  353. //清空指纹库 PS_Empty
  354. //功能: 删除flash数据库中所有指纹模板
  355. //参数: 无
  356. //说明: 模块返回确认字
  357. u8 PS_Empty(void)
  358. {
  359. u16 temp;
  360. u8 ensure;
  361. u8 *data;
  362. SendHead();
  363. SendAddr();
  364. SendFlag(0x01);//命令包标识
  365. SendLength(0x03);
  366. Sendcmd(0x0D);
  367. temp = 0x01+0x03+0x0D;
  368. SendCheck(temp);
  369. data=JudgeStr(2000);
  370. if(data)
  371. ensure=data[9];
  372. else
  373. ensure=0xff;
  374. return ensure;
  375. }
  376. //写系统寄存器 PS_WriteReg
  377. //功能: 写模块寄存器
  378. //参数: 寄存器序号RegNum:4\5\6
  379. //说明: 模块返回确认字
  380. u8 PS_WriteReg(u8 RegNum,u8 DATA)
  381. {
  382. u16 temp;
  383. u8 ensure;
  384. u8 *data;
  385. SendHead();
  386. SendAddr();
  387. SendFlag(0x01);//命令包标识
  388. SendLength(0x05);
  389. Sendcmd(0x0E);
  390. MYUSART_SendData(RegNum);
  391. MYUSART_SendData(DATA);
  392. temp = RegNum+DATA+0x01+0x05+0x0E;
  393. SendCheck(temp);
  394. data=JudgeStr(2000);
  395. if(data)
  396. ensure=data[9];
  397. else
  398. ensure=0xff;
  399. if(ensure==0)
  400. printf("\r\n设置参数成功!");
  401. else
  402. printf("\r\n%s",EnsureMessage(ensure));
  403. return ensure;
  404. }
  405. //读系统基本参数 PS_ReadSysPara
  406. //功能: 读取模块的基本参数(波特率,包大小等)
  407. //参数: 无
  408. //说明: 模块返回确认字 + 基本参数(16bytes)
  409. u8 PS_ReadSysPara(SysPara *p)
  410. {
  411. u16 temp;
  412. u8 ensure;
  413. u8 *data;
  414. SendHead();
  415. SendAddr();
  416. SendFlag(0x01);//命令包标识
  417. SendLength(0x03);
  418. Sendcmd(0x0F);
  419. temp = 0x01+0x03+0x0F;
  420. SendCheck(temp);
  421. data=JudgeStr(1000);
  422. if(data)
  423. {
  424. ensure = data[9];
  425. p->PS_max = (data[14]<<8)+data[15];
  426. p->PS_level = data[17];
  427. p->PS_addr=(data[18]<<24)+(data[19]<<16)+(data[20]<<8)+data[21];
  428. p->PS_size = data[23];
  429. p->PS_N = data[25];
  430. }
  431. else
  432. ensure=0xff;
  433. if(ensure==0x00)
  434. {
  435. printf("\r\n模块最大指纹容量=%d",p->PS_max);
  436. printf("\r\n对比等级=%d",p->PS_level);
  437. printf("\r\n地址=%x",p->PS_addr);
  438. printf("\r\n波特率=%d",p->PS_N*9600);
  439. }
  440. else
  441. printf("\r\n%s",EnsureMessage(ensure));
  442. return ensure;
  443. }
  444. //设置模块地址 PS_SetAddr
  445. //功能: 设置模块地址
  446. //参数: PS_addr
  447. //说明: 模块返回确认字
  448. u8 PS_SetAddr(u32 PS_addr)
  449. {
  450. u16 temp;
  451. u8 ensure;
  452. u8 *data;
  453. SendHead();
  454. SendAddr();
  455. SendFlag(0x01);//命令包标识
  456. SendLength(0x07);
  457. Sendcmd(0x15);
  458. MYUSART_SendData(PS_addr>>24);
  459. MYUSART_SendData(PS_addr>>16);
  460. MYUSART_SendData(PS_addr>>8);
  461. MYUSART_SendData(PS_addr);
  462. temp = 0x01+0x07+0x15
  463. +(u8)(PS_addr>>24)+(u8)(PS_addr>>16)
  464. +(u8)(PS_addr>>8) +(u8)PS_addr;
  465. SendCheck(temp);
  466. AS608Addr=PS_addr;//发送完指令,更换地址
  467. data=JudgeStr(2000);
  468. if(data)
  469. ensure=data[9];
  470. else
  471. ensure=0xff;
  472. AS608Addr = PS_addr;
  473. if(ensure==0x00)
  474. printf("\r\n设置地址成功!");
  475. else
  476. printf("\r\n%s",EnsureMessage(ensure));
  477. return ensure;
  478. }
  479. //功能: 模块内部为用户开辟了256bytes的FLASH空间用于存用户记事本,
  480. // 该记事本逻辑上被分成 16 个页。
  481. //参数: NotePageNum(0~15),Byte32(要写入内容,32个字节)
  482. //说明: 模块返回确认字
  483. u8 PS_WriteNotepad(u8 NotePageNum,u8 *Byte32)
  484. {
  485. u16 temp;
  486. u8 ensure,i;
  487. u8 *data;
  488. SendHead();
  489. SendAddr();
  490. SendFlag(0x01);//命令包标识
  491. SendLength(36);
  492. Sendcmd(0x18);
  493. MYUSART_SendData(NotePageNum);
  494. for(i=0;i<32;i++)
  495. {
  496. MYUSART_SendData(Byte32[i]);
  497. temp += Byte32[i];
  498. }
  499. temp =0x01+36+0x18+NotePageNum+temp;
  500. SendCheck(temp);
  501. data=JudgeStr(2000);
  502. if(data)
  503. ensure=data[9];
  504. else
  505. ensure=0xff;
  506. return ensure;
  507. }
  508. //读记事PS_ReadNotepad
  509. //功能: 读取FLASH用户区的128bytes数据
  510. //参数: NotePageNum(0~15)
  511. //说明: 模块返回确认字+用户信息
  512. u8 PS_ReadNotepad(u8 NotePageNum,u8 *Byte32)
  513. {
  514. u16 temp;
  515. u8 ensure,i;
  516. u8 *data;
  517. SendHead();
  518. SendAddr();
  519. SendFlag(0x01);//命令包标识
  520. SendLength(0x04);
  521. Sendcmd(0x19);
  522. MYUSART_SendData(NotePageNum);
  523. temp = 0x01+0x04+0x19+NotePageNum;
  524. SendCheck(temp);
  525. data=JudgeStr(2000);
  526. if(data)
  527. {
  528. ensure=data[9];
  529. for(i=0;i<32;i++)
  530. {
  531. Byte32[i]=data[10+i];
  532. }
  533. }
  534. else
  535. ensure=0xff;
  536. return ensure;
  537. }
  538. //高速搜索PS_HighSpeedSearch
  539. //功能:以 CharBuffer1或CharBuffer2中的特征文件高速搜索整个或部分指纹库。
  540. // 若搜索到,则返回页码,该指令对于的确存在于指纹库中 ,且登录时质量
  541. // 很好的指纹,会很快给出搜索结果。
  542. //参数: BufferID, StartPage(起始页),PageNum(页数)
  543. //说明: 模块返回确认字+页码(相配指纹模板)
  544. u8 PS_HighSpeedSearch(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p)
  545. {
  546. u16 temp;
  547. u8 ensure;
  548. u8 *data;
  549. SendHead();
  550. SendAddr();
  551. SendFlag(0x01);//命令包标识
  552. SendLength(0x08);
  553. Sendcmd(0x1b);
  554. MYUSART_SendData(BufferID);
  555. MYUSART_SendData(StartPage>>8);
  556. MYUSART_SendData(StartPage);
  557. MYUSART_SendData(PageNum>>8);
  558. MYUSART_SendData(PageNum);
  559. temp = 0x01+0x08+0x1b+BufferID
  560. +(StartPage>>8)+(u8)StartPage
  561. +(PageNum>>8)+(u8)PageNum;
  562. SendCheck(temp);
  563. data=JudgeStr(2000);
  564. if(data)
  565. {
  566. ensure=data[9];
  567. p->pageID =(data[10]<<8) +data[11];
  568. p->mathscore=(data[12]<<8) +data[13];
  569. }
  570. else
  571. ensure=0xff;
  572. return ensure;
  573. }
  574. //读有效模板个数 PS_ValidTempleteNum
  575. //功能:读有效模板个数
  576. //参数: 无
  577. //说明: 模块返回确认字+有效模板个数ValidN
  578. u8 PS_ValidTempleteNum(u16 *ValidN)
  579. {
  580. u16 temp;
  581. u8 ensure;
  582. u8 *data;
  583. SendHead();
  584. SendAddr();
  585. SendFlag(0x01);//命令包标识
  586. SendLength(0x03);
  587. Sendcmd(0x1d);
  588. temp = 0x01+0x03+0x1d;
  589. SendCheck(temp);
  590. data=JudgeStr(2000);
  591. if(data)
  592. {
  593. ensure=data[9];
  594. *ValidN = (data[10]<<8) +data[11];
  595. }
  596. else
  597. ensure=0xff;
  598. if(ensure==0x00)
  599. {
  600. printf("\r\n有效指纹个数=%d",(data[10]<<8)+data[11]);
  601. //user_ID=(data[10]<<8)+data[11];
  602. }
  603. else
  604. printf("\r\n%s",EnsureMessage(ensure));
  605. return ensure;
  606. }
  607. //与AS608握手 PS_HandShake
  608. //参数: PS_Addr地址指针
  609. //说明: 模块返新地址(正确地址)
  610. u8 PS_HandShake(u32 *PS_Addr)
  611. {
  612. SendHead();
  613. SendAddr();
  614. MYUSART_SendData(0X01);
  615. MYUSART_SendData(0X00);
  616. MYUSART_SendData(0X00);
  617. DelayMs(200);
  618. if(USART2_RX_STA&0X8000)//接收到数据
  619. {
  620. if(//判断是不是模块返回的应答包
  621. USART2_RX_BUF[0]==0XEF
  622. &&USART2_RX_BUF[1]==0X01
  623. &&USART2_RX_BUF[6]==0X07
  624. )
  625. {
  626. *PS_Addr=(USART2_RX_BUF[2]<<24) + (USART2_RX_BUF[3]<<16)
  627. +(USART2_RX_BUF[4]<<8) + (USART2_RX_BUF[5]);
  628. USART2_RX_STA=0;
  629. return 0;
  630. }
  631. USART2_RX_STA=0;
  632. }
  633. return 1;
  634. }
  635. //模块应答包确认码信息解析
  636. //功能:解析确认码错误信息返回信息
  637. //参数: ensure
  638. const char *EnsureMessage(u8 ensure)
  639. {
  640. const char *p;
  641. switch(ensure)
  642. {
  643. case 0x00:
  644. p="OK";break;
  645. case 0x01:
  646. p="数据包接收错误";break;
  647. case 0x02:
  648. p="传感器上没有手指";break;
  649. case 0x03:
  650. p="录入指纹图像失败";break;
  651. case 0x04:
  652. p="指纹图像太干、太淡而生不成特征";break;
  653. case 0x05:
  654. p="指纹图像太湿、太糊而生不成特征";break;
  655. case 0x06:
  656. p="指纹图像太乱而生不成特征";break;
  657. case 0x07:
  658. p="指纹图像正常,但特征点太少(或面积太小)而生不成特征";break;
  659. case 0x08:
  660. p="指纹不匹配";break;
  661. case 0x09:
  662. p="没搜索到指纹";break;
  663. case 0x0a:
  664. p="特征合并失败";break;
  665. case 0x0b:
  666. p="访问指纹库时地址序号超出指纹库范围";
  667. case 0x10:
  668. p="删除模板失败";break;
  669. case 0x11:
  670. p="清空指纹库失败";break;
  671. case 0x15:
  672. p="缓冲区内没有有效原始图而生不成图像";break;
  673. case 0x18:
  674. p="读写 FLASH 出错";break;
  675. case 0x19:
  676. p="未定义错误";break;
  677. case 0x1a:
  678. p="无效寄存器号";break;
  679. case 0x1b:
  680. p="寄存器设定内容错误";break;
  681. case 0x1c:
  682. p="记事本页码指定错误";break;
  683. case 0x1f:
  684. p="指纹库满";break;
  685. case 0x20:
  686. p="地址错误";break;
  687. default :
  688. p="模块返回确认码有误";break;
  689. }
  690. return p;
  691. }

(二)按键控制菜单,返回主菜单

其实主函数里就是三种情况,用了几个标志位,Pre_flag是进行刷指纹的标志位,Add_flag是添加指纹功能的标志位,当这两个标志位都为0的话,则OLED显示屏显示Main Menu主菜单界面;如果Pre_flag=1并且Add_flag=0,则开始刷指纹操作;如果Pre_flag=0并且Add_flag=1,此时执行添加指纹模块,在下面的代码中也可看到,添加模式中需要先进行指纹验证才能继续添加新指纹。

不论是那种情况,执行之后都需要将它的标志位清0,循环使用。

  1. while(1){
  2. // for(m=50;m>0;m--){
  3. // OLED_ShowStr(m,3,"Main Menu",2);
  4. // DelayUs(10);
  5. // OLED_CLS();
  6. // }
  7. DelayMs(300);
  8. while((Pre_flag==0)&&(Add_flag==0)){
  9. OLED_ShowStr(23,3,"Main Menu",2);
  10. }
  11. if(m==0){ m=50; }
  12. //---------------刷指纹模式-------------------//
  13. while(Pre_flag==1 && Add_flag==0)
  14. {
  15. OLED_CLS();
  16. DelayMs(100);
  17. press_fr(); //刷指纹
  18. Pre_flag=0; //标志去除
  19. }
  20. //------------------- 添加模式-------------------//
  21. while(Add_flag==1 && Pre_flag==0)
  22. {
  23. OLED_CLS();
  24. DelayMs(100);
  25. OLED_ShowStr(15,3,"verification",2);
  26. DelayMs(300);
  27. mark=0;
  28. OLED_CLS();
  29. while((Continue==0) && (mark1==0)){
  30. Pre_flag=1; //满足刷指纹的条件
  31. Add_flag=0; //如上
  32. press_fr(); //添加之前先按指纹验证
  33. }
  34. mark1==0;
  35. mark=1;
  36. Pre_flag=0; //标志去除
  37. Add_flag=1;
  38. Add_FR();
  39. Add_flag==0; //添加指纹标志去除
  40. }
  41. }
  42. //PS_Empty(); //要清指纹的时候用
  43. }

返回主菜单的功能是用中断实现的,将薄膜按键3对应的IO口中断优先级设为最高,按下3后Pre_flag和Add_flag都会被置为0。可是返回主菜单这个按键一般是在执行某个操作中使用的,那如何实现退出当前的操作?这里我用了一个比较暴力的方式(效率不高),如有好的建议可以在评论区积极提出来呀:例如在刷指纹函数的代码中,隔几行代码就执行一次检查,检查Pre_flag是否还是为1,如果还是为1,则继续执行下去,如果为0,则直接退出。

  1. //----------------按键中断函数----------------//
  2. void EXTI0_IRQHandler(void){
  3. if(EXTI_GetITStatus(EXTI_Line0)!=RESET){ //按一键可以刷指纹
  4. // OLED_CLS();
  5. // OLED_ShowStr(40,3,"PRESS",2);
  6. EXTI_ClearITPendingBit(EXTI_Line0);
  7. Pre_flag=0;
  8. DelayMs(10);
  9. // OLED_CLS();
  10. if(KEY1==0){
  11. Pre_flag=1;
  12. }
  13. }
  14. return;
  15. }
  16. void EXTI1_IRQHandler(void){
  17. if(EXTI_GetITStatus(EXTI_Line1)!=RESET){ //按二键可以加指纹
  18. Add_flag=0;
  19. EXTI_ClearITPendingBit(EXTI_Line1);
  20. DelayMs(10);
  21. // OLED_CLS();
  22. if(KEY2==0){
  23. Add_flag=1; //进行添加标志位
  24. }
  25. }
  26. return;
  27. }
  28. void EXTI4_IRQHandler(void){
  29. if(EXTI_GetITStatus(EXTI_Line4)!=RESET){ //按三键可以加回到主菜单
  30. // OLED_CLS();
  31. // OLED_ShowStr(42,3," ADD ",2);
  32. EXTI_ClearITPendingBit(EXTI_Line4);
  33. DelayMs(10);
  34. if(KEY3==0){
  35. // OLED_CLS();
  36. Add_flag=0; //进行添加标志位
  37. Pre_flag=0;
  38. mark1=1; //打断添加指纹中的刷指纹
  39. }
  40. }
  41. return;
  42. }
  1. void press_fr(void){
  2. SearchResult seach;
  3. u8 ensure;
  4. char *str;
  5. Continue=0;
  6. OLED_CLS();
  7. OLED_ShowStr(15, 3, "Press Finger",2); //提示可以刷指纹了
  8. while(Pre_flag==0){
  9. goto end1; //高频次扫描
  10. }
  11. while(1){ //检测到有指纹按下后继续执行
  12. while(Pre_flag==0){
  13. goto end1;
  14. }
  15. if(Have==1) break;
  16. }
  17. Have=0;
  18. ensure=PS_GetImage();
  19. while(Pre_flag==0){
  20. goto end1;
  21. }

(三)OLED(0.96寸)显示代码等外设使用就不一一在此叙述,详见工程文档。

七、感想

开始做一个小项目之前,要有一个具体的框架,需要实现怎么样的功能?需要用到什么外设?需要用到哪些引脚?需不需要画板子?等等等等都要考虑清楚。最好不要走一步看一步,提前做好规划吧。AS608模块我也是刚接触,确实也有很多不知道的地方,可能以上的说明中会出现部分错误,望谅解。٩( 'ω' )و 。关于引脚的分配等使用都在资料里。

8d8a58644f844ddeb3df81353170e751.jpg

演示视频:http://【大二学牲用stm32做的指纹锁】 https://www.bilibili.com/video/BV1Td4y1w7dK/?share_source=copy_web&vd_source=4d84f07cf9b4e331ed12b31fc1240391

工程资料链接:链接:https://pan.baidu.com/s/1rMt2Nyh3zBiefdZ4V-sBDQ?pwd=1111 
                         提取码:1111 
                          --来自百度网盘超级会员V3的分享

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/480664
推荐阅读
相关标签
  

闽ICP备14008679号