(藍牙、AS608指紋、RFID刷卡PN532、鍵盤、LCD、界面友好)單片機嵌入式開發(fā)(項目開源)
程序鏈接:智能鎖-作者:STM時 PCB和小工具鏈接:智能鎖-PCB和工具-PCB制作者:STM時 PN532的資料:PN532的資料(資料比較大,不一定用到) 提取碼:1234? --來自百度網(wǎng)盤超級會員V5的分享
B站視頻:基于STM32的智能鎖(藍牙、指紋、RFID刷卡磁卡、LCD顯示)
前言
- 本次設(shè)計是基于STM32F103C8T6(以下C8T6等同)開發(fā)的智能鎖,支持多種方式對系統(tǒng)進行操作:藍牙、指紋、RFID刷卡、4x4鍵盤輸入,擁有友好的藍牙收發(fā)界面和LCD交互界面。
- 藍牙:作為總系統(tǒng)的管理員,有主管理和次管理,主管理只能有一個,副管理員可以有多個。主管理員擁有全部權(quán)限(包括修改管理員數(shù)據(jù));而副管理員不能修改管理員數(shù)據(jù),但可以修改指紋、RFID刷卡、鍵盤密碼的數(shù)據(jù)。藍牙交互界面提供了多種選項,同時兼顧ID密碼登數(shù)據(jù)發(fā)送和指令發(fā)送,功能齊全,藍牙界面通過管理員賬號登錄。
- 指紋:在鎖屏界面下可以通過驗證指紋來解鎖智能鎖,可以通過主/副管理員來添加指紋和刪除指紋。
- RFID刷卡:在鎖屏界面下可以通過驗證ID/IC卡來進行智能鎖解鎖,可以通過主/副管理員來添加ID/IC卡和刪除ID/IC卡。
- 4x4鍵盤:4x4鍵盤既可以作為系統(tǒng)的選項按鈕,也可以作為ID和密碼輸入的按鈕,在鎖屏界面可以選擇進入鍵盤輸入功能,進行鍵盤用戶ID和密碼認證,認證通過后開啟智能鎖。
- LCD:LCD提供了友好的交互界面,可以通過4x4鍵盤來進行功能選擇。
- 收發(fā)協(xié)議:藍牙、指紋、RFID刷卡使用USART(剛好用完C8T6的三個USART串口),LCD使用SPI(如果你用的是STM32F4或其他的系列,那么你需要對LCD的代碼驅(qū)動進行修改,因為F1和F4的SPI代碼程序不一樣),4x4鍵盤使用推挽輸出和上拉輸入(4x4掃描,必是一邊輸出、一邊輸入)。
?模塊介紹
序號 |
模塊 |
型號規(guī)格 |
數(shù)量 |
1 |
微控制器 |
STM32F103C8T6 |
1 |
2 |
指紋 |
AS608 |
1 |
3 |
RFID射頻讀卡模塊 |
PN532 NFC RFID V3 |
1 |
4 |
藍牙 |
匯承HC-08 |
1 |
5 |
LCD顯示 |
TFT-ST7735S |
1 |
6 |
電機驅(qū)動 |
兩路直流雙H橋L298N |
1 |
7 |
按鍵 |
6*6*4.3輕觸按鍵 |
16 |
8 |
下載器 |
ST-LINK V2 |
1 |
9 |
電源 |
DC12-3.3/5/7V |
1 |
10 |
電池 |
DC12-2800mAh |
1 |
STM32F103C8T6
提醒:我們經(jīng)常使用的STM32F103C8T6,有一些是用兼容芯片做的,雖然99%的功能都差不多,但是這次開發(fā)我遇到了那1%,我試了幾個不同店鋪的STM32F103C8T6,發(fā)現(xiàn)很多都不能正常使用AS608指紋模塊(個人猜測可能是因為AS608識別不到指令...),因為在USART串口發(fā)送時,總是會有那么一點錯誤,我用藍牙模塊對串口進行了測試,發(fā)現(xiàn)第一次發(fā)送數(shù)據(jù)總是會帶有一小點亂碼。
我買的店鋪是touglesy,不是說其他的店鋪不好(我買東西一般不會拘泥于一家店鋪,其他模塊也會換換家買,畢竟每個店鋪都有自己的干貨),這次是無奈了,而是我又不知道哪些能用,撞了很多次腳才發(fā)現(xiàn)問題所在,然后AS608要求的串口穩(wěn)定性也太高(如果是大板子,那么不用擔(dān)心這個,我用STM32103ZET6和STM32F407ZGT6大板子都可以驅(qū)動AS608),希望建議有幫助。
(甚至有可能是AS608的問題,僅供參考)
藍牙?
藍牙我買的是匯承的HC-08,主從一體,比較方便,使用的時候拿官方的藍牙測試架設(shè)置為從機就行了,官方網(wǎng)站可以下載藍牙模塊使用手冊、上位機調(diào)試、手機藍牙助手APP。(當然我也會打包到分享資料中)
AS608
我買的是光學(xué)AS608,支持USB D- D+、USART傳輸模式,我這里走的是USART,沒什么好說的,直接上圖。
RFID射頻讀卡模塊
RFID射頻刷卡模塊有很多種型號,我這里買的是PN532 NFC RFID V3,支持多種類型的卡(根據(jù)自身需求,這個可以自己去商家哪里查,買其他的比如522也可以的)。支持I2C、SPI、高速USART多種傳輸模式,我這里走的是USART。配套的應(yīng)該會送兩張卡,試過用校園卡也能刷,沒什么好說的,直接上圖。
LCD顯示
LCD屏幕我買的1.8寸?TFT-ST7735S,正面管腳順序G,V,SCL,SDA,RST,DC,CS,BLK(具體買什么型號看需求吧)
電源
電源我買的是12V轉(zhuǎn)3.3V、5V、12V,實際只需要3.3V和5V的并沒有使用,實際看個人需求。
電池
電池我用的是12V,2800mAh,DC公母頭鋰電池,實際看個人需求。(圖片來自淘寶商家,侵權(quán)刪)
其他模塊
按鍵:按鍵買什么都行,看個人需求。
電機驅(qū)動和電機:這個都行,我用的是兩路直流雙H橋L298N,加一個減速電機。(視頻沒有演示電機部分,程序里寫有電機驅(qū)動,本次設(shè)計只介紹系統(tǒng)設(shè)計而不介紹電機)
下載器(下載方式):我用的是ST LINK V2下載器,閃存flash燒錄,實際看個人習(xí)慣。
程序設(shè)計部分
ID、密碼和卡號
本次設(shè)計中,如果僅用程序模擬數(shù)據(jù)的方式,則機器掉電后將會使數(shù)據(jù)丟失。
所以我的設(shè)計思路是,將藍牙管理員、鍵盤使用者、指紋ID、卡號全部保存近閃存中。在驗證身份時,調(diào)用閃存中的數(shù)據(jù)進行認證。
?結(jié)構(gòu)體
?定義結(jié)構(gòu)體,方便管理ID、密碼和卡號:
struct CODE_STU//自由ID
{
int ID;
char CODE[CODE_LEN];
};
extern struct CODE_STU USER_CODE[CN];//用戶密碼,用于按鍵
extern struct CODE_STU MASTER_CODE[CN];//管理員密碼,用于藍牙
struct RFID_STU//自動分配ID號
{
int ID;
uint8_t CODE[RFID_LEN];
};
extern u16 FR_ID[300];//指紋ID,指紋只需要ID,就不定義結(jié)構(gòu)體了
extern struct RFID_STU USER_RFID[CN];//卡號
閃存的讀寫?
?編寫程序,用來閃存讀寫:
void flash_write(uint32_t address, void *data, uint32_t size)//閃存寫
{
uint32_t *flash_ptr = (uint32_t *)data;
FLASH_Status flash_status = FLASH_COMPLETE;
FLASH_Unlock(); // 解鎖Flash
// 擦除扇區(qū)
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); // 清除Flash標志位
flash_status = FLASH_ErasePage(address);
if (flash_status != FLASH_COMPLETE)
{
// 擦除失敗處理
}
// 寫入數(shù)據(jù)
for (uint32_t i = 0; i < size / 4; i++)
{
flash_status = FLASH_ProgramWord(address, *flash_ptr);
if (flash_status != FLASH_COMPLETE)
{
// 寫入失敗處理
}
address += 4;
flash_ptr++;
}
FLASH_Lock(); // 鎖定Flash
}
void flash_read(uint32_t address, void *data, uint32_t size)//閃存讀
{
uint32_t *flash_ptr = (uint32_t *)data;
for (uint32_t i = 0; i < size / 4; i++)
{
*flash_ptr = *(__IO uint32_t*)address;
address += 4;
flash_ptr++;
}
}
定義閃存地址,用來分配藍牙管理員、鍵盤使用者、指紋ID、卡號的閃存地址:
#define VAR_FLASH_ADDR ((uint32_t)0x08014000) // 第一管理員ID,用來記錄主管理員的ID號
#define MASTER_FLASH_ADDR ((uint32_t)0x08015000) // 管理員數(shù)據(jù)存儲地址
#define USER_FLASH_ADDR ((uint32_t)0x08017000) // 用戶數(shù)據(jù)存儲地址C
#define FR_FLASHID_ADDR ((uint32_t)0x08018000) // 指紋ID
#define RFID_FLASHID_ADDR ((uint32_t)0x08019000) // 刷卡ID索引
#define RFID_FLASH_ADDR ((uint32_t)0x0801B000) // 卡號
函數(shù)的用法:
//以藍牙管理員和鍵盤使用者為例:
//要尋找時
flash_read(VAR_FLASH_ADDR, &first_masterID, sizeof(first_masterID));//第一管理員ID
flash_read(USER_FLASH_ADDR, USER_CODE, sizeof(USER_CODE));//使用者
flash_read(MASTER_FLASH_ADDR, MASTER_CODE, sizeof(MASTER_CODE));//管理員
/*
一系列查找結(jié)構(gòu)體成員的程序
*/
//要更新結(jié)構(gòu)體時
/*
一系列對結(jié)構(gòu)體修改的程序
*/
flash_write(VAR_FLASH_ADDR, &first_masterID, sizeof(first_masterID));//第一管理員ID
flash_write(USER_FLASH_ADDR, USER_CODE, sizeof(USER_CODE));//使用者
flash_write(MASTER_FLASH_ADDR, MASTER_CODE, sizeof(MASTER_CODE));//管理員
LCD程序設(shè)計
程序所需文件:
Lcd_Driver.c、Lcd_Driver.h、LCD_Config.h、GUI.c、GUI.h 、Font.h
Lcd_Driver.c初始化驅(qū)動,Lcd_Driver.h管腳宏定義,LCD_Config.h最大分辨率,GUI.c顯示函數(shù),GUI.h顯示函數(shù)定義,F(xiàn)ont.h字符模編碼
LCD的程序直接用商家提供的就行了,不過商家提供的不能直接顯示數(shù)字,需要用C函數(shù)轉(zhuǎn)換為字符類型。(或者自己設(shè)計也行)
int i=0;
char LCD_id[4];
sprintf(LCD_id,"%d",i);//i轉(zhuǎn)換為LCD_id字符串
然后講一下LCD顯示函數(shù)的使用,如下所示,Gui_DrawFont_GBK16和24為商家提供,32是我自己魔改出來的,也能使用。*s必須是u8[ ]類型、字符串char[ ]類型或者直接使用 "鎖屏" 。
Gui_DrawFont_GBK16(u16 x, u16 y, u16 fc, u16 bc, u8 *s);
Gui_DrawFont_GBK24(u16 x, u16 y, u16 fc, u16 bc, u8 *s);
Gui_DrawFont_GBK32(u16 x, u16 y, u16 fc, u16 bc, u8 *s);
//Gui_DrawFont_GBK16后面的數(shù)字表示16x16顯示
//x表示行分辨率,y表示列分辨率,fc表示顏色,bc表示背光灰度
//*s能使用的類型:char CODE[100] 、uint8_t CODE[100]和"鎖屏界面"都可以用
//例如:Gui_DrawFont_GBK16(28,0,BLUE,GRAY0,"鎖屏界面");
//表示在28,0的地方開始顯示“鎖屏界面”,字體顏色為藍色,背景灰度為白色,若GRAY1則顏色偏灰
/*又例如:
int i=15;
char LCD_id[4];
sprintf(LCD_id,"%d",i);//i轉(zhuǎn)換為LCD_id字符串
Gui_DrawFont_GBK16(28,0,BLUE,GRAY0,LCD_id);
這樣就可以顯示15
*/
/*
#define RED 0xf800 //紅色
#define GREEN 0x07e0 //綠色
#define BLUE 0x001f //藍色
#define WHITE 0xffff //白色
#define BLACK 0x0000 //黑色
#define PINK 0xFFC011 //粉色
#define YELLOW 0xFFE0 //黃色
#define GRAY0 0xEF7D //灰色0 3165 00110 001011 00101
#define GRAY1 0x8410 //灰色1 00000 000000 00000
#define GRAY2 0x4208 //灰色2 1111111111011111
*/
特別說明:該函數(shù)不能直接使用中文,若要使用中文,則需要使用LCD商家提供的文字取模工具導(dǎo)出中文編碼(配套我會全部放到資料中),代碼示例如下(中文編碼在front.h中)。
這是16x16的編碼存放結(jié)構(gòu)體,hz16_num代表文字數(shù)量,若超出200,則需要修改,其他數(shù)值不用動。
如果是24x24,則需要找另一個結(jié)構(gòu)體,也在front.h中。
中文的編碼存放方式如下,如果要增加新的中文字符,則使用文字取模工具取碼。
文字取模示例:實際用法放在資料包里,下面放一張圖
LCD模塊特別說明:
如果是STM32F103,則不需要修改程序,如果是STM32F4系列,則需要進行細微的修改,F(xiàn)4和F1的SPI傳輸方式不一樣,F(xiàn)4需要修改SPI發(fā)送函數(shù),當然F4使用LCD的程序我也放在了資料包里。
藍牙程序設(shè)計
程序所需文件:
usart2_bluetooth.c藍牙初始化+藍牙程序設(shè)計usart2_bluetooth.h藍牙收發(fā)緩沖定義和函數(shù)定義
藍牙測試
藍牙首先需要自己用官方的工具藍牙測試架進行測試和參數(shù)調(diào)整,我這里是波特率115200,從機模式,名稱也可以通過藍牙測試架修改。
注:在測試藍牙串口時,同樣需要測試MCU單片機的串口(使用TTL轉(zhuǎn)USB就行了),測試單片機的方法不多講,教程很多了。
藍牙程序
測試好MCU的串口USART和藍牙的串口USART之后,就可以讓MCU和藍牙模塊進行通信了。
手機給藍牙發(fā)送數(shù)據(jù)之后,數(shù)據(jù)會通過串口直接發(fā)給MCU,然后程序?qū)ζ溥M行處理。
藍牙模塊各函數(shù)的意義:
//以下函數(shù)存于usart2_bluetooth.c文件
void usart2_init(u32 bound2);//串口2初始化
/*
用法:
usart2_init(115200);//115200設(shè)置波特率
*/
u8 bluetooth(void);
/*
用法:
藍牙功能界面,直接進入就行。bluetooth();
*/
void u2_printf(char* fmt, ...);//發(fā)送數(shù)據(jù)用的函數(shù)
/*
用法:
藍牙發(fā)送函數(shù),發(fā)送數(shù)據(jù)類型與上面說的LCD類似
一、
u2_printf("%s","藍牙界面\n");
二、
int i=15;
char LCD_id[4];
sprintf(LCD_id,"%d",i);//i轉(zhuǎn)換為LCD_id字符串
u2_printf("%s",LCD_id);//發(fā)送15
*/
u8 add_blue_code(struct CODE_STU* code);//藍牙添加管理員/鍵盤用戶函數(shù)
u8 delete_blue_code(struct CODE_STU* code);//藍牙刪除管理員/鍵盤用戶函數(shù)(也可轉(zhuǎn)讓主管理員)
u8 errror_blue_code(struct CODE_STU* code);//藍牙驗證ID密碼函數(shù)
/*
用法:
add_blue_code(MASTER_CODE);//MASTER_CODE為管理員的結(jié)構(gòu)體
add_blue_code(USER_CODE);//USER_CODE為鍵盤密碼的結(jié)構(gòu)體
三個函數(shù)都是這么調(diào)用
關(guān)于結(jié)構(gòu)體,后面會介紹
*/
void USART2_SendData(USART_TypeDef* USARTx, uint16_t Data);
void send2HexData(uint8_t data[], uint16_t length);
/*
用法:
這兩句是十六進制串口發(fā)送函數(shù),藍牙模塊暫時用不到
uint8_t data[] = {0x11, 0xAB, 0xFE, 0x42};
send2HexData(data, sizeof(data)/sizeof(data[0]));
*/
int isUART2Idle(void);
/*
用法:
判斷串口是否為空閑狀態(tài)
配合RX2K來判斷數(shù)據(jù)是否接收完畢
if(RX2K == 1 && isUART2Idle())//判斷是否收到數(shù)據(jù),是否接收完畢
{
//程序.....
//末尾必須放這三句清空狀態(tài)
RX2K=0;
rxs2_index=0;
memset(RX2DATA, 0, sizeof(RX2DATA));
}
*/
void USART2_IRQHandler(void)
/*
用法:
中斷函數(shù),根據(jù)中斷線觸發(fā),不需要調(diào)用
藍牙接收中斷,收到數(shù)據(jù)自動將數(shù)據(jù)保存到緩存USART2_RX_BUF和RX2DATA中
USART2_RX_BUF為總緩存,RX2DATA為單次緩存
每次接收數(shù)據(jù),處理完這批數(shù)據(jù)之后,都需要運行下面三句代碼刪除數(shù)據(jù)
不然下次收到數(shù)據(jù)會保留有上一次的數(shù)據(jù)
RX2K=0;
rxs2_index=0;
memset(RX2DATA, 0, sizeof(RX2DATA));
*/
藍牙界面開發(fā)
首先,藍牙模塊只能是收或者發(fā),并沒有界面一說(喜歡折騰的小伙伴可以自行開發(fā)一個APP),我這里是基于手機藍牙助手的收發(fā)界面來做個人定制。
既然沒有界面,那就用收發(fā)來做界面。
界面:藍牙給手機發(fā)數(shù)據(jù)來當做類似界面的東西,如下圖(或者視頻演示)
功能鍵和ID密碼輸入:手機給藍牙發(fā)數(shù)據(jù)來當做功能鍵或者ID密碼
使用APP自帶的自定義按鈕定義%A到%F作為功能鍵(這些功能鍵的功能與LCD+鍵盤交互界面一致,也可以通過鍵盤來選擇功能)
藍牙界面開發(fā)代碼程序框架:
實際程序設(shè)計看我的程序資源包或者自行定制
//這里舉例一個簡單的框架
//LCD界面
Gui_DrawFont_GBK16(0,20,RED,GRAY0,"A:功能一");
Gui_DrawFont_GBK16(0,40,RED,GRAY0,"B:功能二");
Gui_DrawFont_GBK16(0,60,RED,GRAY0,"C:功能三");
//藍牙界面
u2_printf("%s","%A功能一\n");
delay_ms(100);
u2_printf("%s","%B功能二\n");
delay_ms(100);
u2_printf("%s","%C功能三\n");
delay_ms(100);
while (1)
{
key4_4_Scan();//鍵盤值讀取
/功能選擇行///
//一級標題
if (keyv == 4 || memcmp("%A",RX2DATA,4)==0)//鍵盤A或者藍牙%A
{ //功能一
RX2K = 0;
rxs2_index = 0;
memset(RX2DATA, 0, sizeof(RX2DATA));
}
//一級標題
else if (keyv == 8 | memcmp("%B",RX2DATA,4)==0)//鍵盤B或者藍牙%B
{ //功能二
RX2K = 0;
rxs2_index = 0;
memset(RX2DATA, 0, sizeof(RX2DATA));
}
//一級標題
else if(keyv == 12 || memcmp("%C",RX2DATA,4)==0)//鍵盤C或者藍牙%C
{ //功能三
RX2K = 0;
rxs2_index = 0;
memset(RX2DATA, 0, sizeof(RX2DATA));
}
//其他更多功能.........
//....................
/數(shù)據(jù)收發(fā)行
//一級標題
else if(RX2K == 1 && isUART2Idle())//既判斷已經(jīng)發(fā)送,又判斷發(fā)送完成
{
RX2K = 0;
//二級標題
if (IDorMI == 0)
{
//對藍牙發(fā)送的ID號進行臨時保存
//ID號一定是臨時保存,不能直接用RX2DATA
//因為每次進入if都需要清除RX2DATA(前面說的那三句代碼)
//memset(RX2DATA, 0, sizeof(RX2DATA));
//這樣避免數(shù)據(jù)沖突
}
else if (IDorMI == 1)
{
//對藍牙發(fā)送的密碼進行臨時保存
//密碼一定是臨時保存,不能直接用RX2DATA
//因為每次進入if都需要清除RX2DATA(前面說的那三句代碼)
//memset(RX2DATA, 0, sizeof(RX2DATA));
//這樣避免數(shù)據(jù)沖突
}
rxs2_index = 0;
memset(RX2DATA, 0, sizeof(RX2DATA));//清除RX2DATA
}
//一級標題
else if(RX2K == 1 && isUART2Idle())//發(fā)送無關(guān)的數(shù)據(jù)則不進行處理
{
RX2K=0;
rxs2_index=0;
memset(RX2DATA, 0, sizeof(RX2DATA));
}
}
}
4x4鍵盤程序設(shè)計
注意:4x4鍵盤使用鍵盤掃描的方式,一邊用上拉輸入,一邊用推挽輸出,但不是所有的管腳都有上拉輸入和推挽輸出的功能,有些管腳無法上拉輸入,有些管腳無法推挽輸出。
無法上拉的情況表現(xiàn)為:無論你管腳輸入啥,管腳狀態(tài)都讀取到0
無法推挽的情況表現(xiàn)為:管腳輸出狀態(tài)單一,可能只能輸出1或者只能輸出0特別說明:
上拉輸入為,MCU單片機自己設(shè)置了一個上拉電阻,在沒有任何輸入的情況下管腳狀態(tài)為1,當管腳輸入0(接地)時,管腳狀態(tài)讀取到0,實現(xiàn)掃描讀取按鍵的目的。
推挽輸出為,MCU單片機可以根據(jù)程序來決定管腳輸出0還是輸出1。
這里說下我用的管腳:
X1? ? ?X2? ? ?X3? ? ?X4
PA11 PA12 PA15 PB3
Y1? ?Y2? ? Y3? ?Y4PA0 PB5 PB6 PB7
??? ?//X為上拉輸入,Y為推挽輸出(管腳定義)
?? ?/*
?? ?X1 X2 X3 X4? ? -------------------------
? ??↑? ? ↑? ? ↑? ??↑? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
?? ?------------------? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
?? ?1? ? 2? ?3? ? A? |?←?Y1? ? ? ? ? ? ? ? ? ? ?? |
?? ?4? ? 5? ?6? ? B? | ←?Y2? -----------MCU單片機
?? ?7? ? 8? ?9? ? C? |?←?Y3
? ???*? ??0?? #? ? D??|?←?Y4
?? ?*/
4x4鍵盤掃描原理,首先我們的按鍵是有兩頭的,以下稱為左邊和右邊。
方便理解:
單個按鍵的掃描方式是,MCU<----按鍵-----GND
左邊接MCU,右邊接一個地,當按鍵按下,就相當于MCU上拉輸入端接GND,該管腳狀態(tài)變?yōu)?
然后鍵盤掃描的方式是單個按鍵掃描的改良版
每個按鍵的左邊接X,右邊接Y,根據(jù)按鍵的排/列號來確定接的是X幾/Y幾,原理圖如下。
Y端從MCU循環(huán)輸出0來模擬單個按鍵的右邊GND狀態(tài)。
X端給MCU給MCU讀取狀態(tài),按下哪個X就是哪個X輸入0。
例如,Y1輸出0,X1按下,則為按鍵1
Y輸出循環(huán):
Y1? ?Y2? ? Y3? ?Y4
0? ? ? 1? ? ? 1? ? ?1? ? ?row=0?
1? ? ? 0? ? ? 1? ? ?1? ? ?row=1
1? ? ? 1? ? ? 0? ? ?1? ? ?row=2
1? ? ? 1? ? ? 1? ? ?0? ? ?row=3
使用for循環(huán)for (row = 0; row < 4; row++)來定位Y的輸出位置。
使用管腳狀態(tài)查詢來獲取X的位置,當某個按鍵按下,GPIO_ReadInputDataBit(X_KEYα_PORT,X_KEYα)?α為1、2、3、4
X1? ?X2? ? X3? ?X4
0? ? ? 1? ? ? 1? ? ?1? ? ?col=1?
1? ? ? 0? ? ? 1? ? ?1? ? ?col=2
1? ? ? 1? ? ? 0? ? ?1? ? ?col=3
1? ? ? 1? ? ? 1? ? ?0? ? ?col=4
讀取得到按鍵的值keyv=(row * 4 + col)(1到16)
程序使用方法:
鍵盤交互界面程序
void key4_4_Init(void);//4x4鍵盤初始化程序
void key4_4_Scan(void);
//在while循環(huán)里使用key4_4_Scan();就可以更新鍵盤狀態(tài)
//鍵盤值keyv持續(xù)更新
//例:
//下面這段程序可以用于界面開發(fā),功能選項
/*
key4_4_Init();
Gui_DrawFont_GBK16(0,20,RED,GRAY0,"A:功能一");
Gui_DrawFont_GBK16(0,40,RED,GRAY0,"B:功能二");
Gui_DrawFont_GBK16(0,60,RED,GRAY0,"C:功能三");
Gui_DrawFont_GBK16(0,80,RED,GRAY0,"D:功能四");
while(1)
{
key4_4_Scan();
if(keyv==4)//A鍵
{
//程序 }
if(keyv==8)//B鍵
{
//程序 }
if(keyv==12)//C鍵
{
//程序 }
if(keyv==16)//D鍵
{
//程序 }
}
*/
指紋程序設(shè)計
程序所需文件:
as608.c,as608.h,usart1_fr.c,usart1_fr.h
測試指紋模塊
準備一個TTL轉(zhuǎn)USB(用于串口USART轉(zhuǎn)成USB,然后用電腦上位機進行串口測試指紋模塊),使用配套資料里的指紋上位機進行指紋模塊功能測試。
注:在測試指紋串口時,同樣需要測試MCU單片機的串口(使用TTL轉(zhuǎn)USB就行了),測試單片機的方法不多講,教程很多了。
上位機程序:
上位機連接:
指紋錄入測試:
指紋對比測試:
測試完指紋模塊沒問題就可以進行程序設(shè)計了
程序說明部分
指紋程序設(shè)計可以直接參考ALIENTEK給出的函數(shù)(僅供學(xué)習(xí),請勿用于其他用途)
ALIENTEK的程序存放在as608.c和as608.h中
或者可以自己查找AS608指紋模塊的數(shù)據(jù)手冊,里面有指令,根據(jù)指令,可以自行完成指紋模塊功能函數(shù)的編寫。
//ALIENTEK給出的函數(shù)
void PS_StaGPIO_Init(void);//初始化PA6讀狀態(tài)引腳
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);//寫系統(tǒng)寄存器
u8 PS_ReadSysPara(SysPara *p); //讀系統(tǒng)基本參數(shù)
u8 PS_SetAddr(u32 addr); //設(shè)置模塊地址
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);//讀有效模板個數(shù)
u8 PS_HandShake(u32 *PS_Addr); //與AS608模塊握手
有了ALIENTEK的函數(shù),我們就可以自行定制AS608指紋模塊的功能了,比如指紋錄入、刷指紋對比、指紋刪除等操作。
但只有as608.c和as608.h我們是不能直接調(diào)用的,我們還得使MCU單片機和as608模塊建立通信,以便MCU單片機通過USART或USB將指令傳輸給as608。(類似的操作同樣可以在ALIENTEK的教程里面找),我們可以根據(jù)需求進行修改,定制出適合自己方案的功能。
我這里是根據(jù)需求定義了三個函數(shù),添加指紋、刷指紋、刪除指紋(操作見于視頻)
程序具體實現(xiàn)自行下載我的程序資源包,在usart1_fr.c和usart1_fr.h里面
有串口初始化、添加指紋、刷指紋、刪除指紋的函數(shù)
滿足這幾個功能,需要的ALIENTEK函數(shù)有:
u8 PS_ValidTempleteNum(u16 *ValidN);//讀有效模板個數(shù),三個函數(shù)都用到?
//添加指紋函數(shù)void Add_FR(void);
u8 PS_GetImage(void); //錄入圖像?
u8 PS_GenChar(u8 BufferID);//生成特征?
u8 PS_Match(void);//精確比對兩枚指紋特征
u8 PS_RegModel(void);//合并特征(生成模板)
u8 PS_StoreChar(u8 BufferID,u16 PageID);//儲存模板?
//刷指紋void press_FR(void);
u8 PS_GetImage(void); //錄入圖像?
u8 PS_GenChar(u8 BufferID);//生成特征
u8 PS_HighSpeedSearch(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p);//高速搜索
//刪除指紋void Del_FR(void);
u8 PS_DeletChar(u16 PageID,u16 N);//刪除單個模板?
u8 PS_Empty(void);//清空指紋庫
這里我使用c語言對每個添加進來的新指紋進行ID分配,ID保存到u16 FR_ID[300];中,指紋添加時,自動分配到空的ID上,比如現(xiàn)有ID:1,3,4,則新指紋自動分配ID:2
u16 FR_ID[300];掉電后數(shù)據(jù)不會丟失。
每次添加新指紋自動更新u16 FR_ID[300];到STM32的閃存中。
RFID刷卡程序設(shè)計
程序所需文件:
usart3_rfid.c和usart3_rfid.h
測試PN532刷卡模塊
與指紋模塊的測試類似,拿一個TTL轉(zhuǎn)USB就能使用電腦進行測試了,不過這里使用的上位機與指紋的上位機不一樣,這里要使用串口助手sscom進行測試
串口連接上電腦后,使用PN532的指令代碼對PN532模塊進行測試
具體的指令可以查PN532的數(shù)據(jù)手冊,也可以跳轉(zhuǎn)下面這篇文章,講得比較好。
NFC芯片--PN532的使用
上位機測試:
PN532程序設(shè)計思路
本次設(shè)計我只使用了PN532激活指令和尋卡指令
激活指令是必須要發(fā)送的,尋卡指令我用于開啟尋卡狀態(tài)并獲取讀取到的卡號
本次智能鎖設(shè)計僅需要卡號就行了,不需要進入卡認證讀寫,ID號和卡號的保存和藍牙、鍵盤用戶一致,使用結(jié)構(gòu)體保存。
使用結(jié)構(gòu)體保存卡號主要是為了方便設(shè)計和數(shù)據(jù)管理,將藍牙管理員、鍵盤使用者、卡號都使用結(jié)構(gòu)體保存,有利于統(tǒng)一管理數(shù)據(jù)。
結(jié)構(gòu)體有ID和卡號
struct RFID_STU
{
? ? int ID;? //ID自動分配到空閑的ID中
? ? uint8_t CODE[RFID_LEN]; //卡號通過刷卡獲取
};
添加刷卡時,尋卡后將卡號保存到結(jié)構(gòu),同時寫入閃存。
對比刷卡時,從閃存中讀取出結(jié)構(gòu)體,尋卡后獲得卡號對比結(jié)構(gòu)體中卡號,完成開鎖。
刪除刷卡時,從閃存中讀取出結(jié)構(gòu)體,可以直接通過藍牙管理員發(fā)送ID號進行刪除,也可以通過刷卡對比卡號來刪除。然后更新結(jié)構(gòu)體到閃存。
函數(shù)功能:
void usart3_init(u32 bound3); //串口3初始化
u8 add_rfid(void);//加卡
u8 press_rfid(void);//刷卡
u8 del_rfid(void);//刪卡
void USART3_SendData(USART_TypeDef* USARTx, uint16_t Data);
void send3HexData(uint8_t data[], uint16_t length);
//用來發(fā)送十六進制數(shù),PN532只能接收十六進制的指令
/*
刷卡流程:
uint8_t a1[40] =//喚醒
{0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0xFD, 0xD4, 0x14, 0x01, 0x17, 0x00};
uint8_t a2[40]=//尋卡
{0x00, 0x00, 0xFF, 0x04, 0xFC, 0xD4, 0x4A, 0x01, 0x00, 0xE1, 0x00};
a1和a2必須是全局變量
send3HexData(a1, sizeof(a1) / sizeof(a1[0]));//喚醒
rxs3_index=0;
memset(RX3DATA, 0, sizeof(RX3DATA));//清一次以免數(shù)據(jù)沖突
delay_ms(100);
send3HexData(a2, sizeof(a2) / sizeof(a2[0]));//尋卡
delay_ms(100);
RX3K=0;
rxs3_index=0;
memset(RX3DATA, 0, sizeof(RX3DATA));//清一次以免數(shù)據(jù)沖突
//.......等待尋卡,當有卡刷到PN532時,卡號將通過串口發(fā)送給RX3DATA
//然后就可以對接收到的RX3DATA進行處理
*/
以上是簡單的函數(shù)使用和尋卡流程,根據(jù)這個尋卡流程,就可以自定義各種刷卡操作類的函數(shù)了
我這里是定義了三個函數(shù):
u8 add_rfid(void);//加卡
u8 press_rfid(void);//刷卡
u8 del_rfid(void);//刪卡
具體的,請看我分享的程序資源或者自行定制。
程序鏈接:智能鎖-作者:STM時
PCB和小工具鏈接:智能鎖-PCB和工具-PCB制作者:STM時
PN532的資料:PN532的資料(資料比較大,不一定用到)
提取碼:1234?
--來自百度網(wǎng)盤超級會員V5的分享文章來源:http://www.zghlxwxcb.cn/news/detail-715882.html
B站實物演示視頻鏈接:基于STM32的智能鎖(藍牙、指紋、RFID刷卡磁卡、LCD顯示)文章來源地址http://www.zghlxwxcb.cn/news/detail-715882.html
到了這里,關(guān)于基于STM32的智能門鎖/智能門禁多功能系統(tǒng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!