1、可通过指纹模块增删查改家庭成员的指纹信息,增删查改是否成功的相关信息显示在OLED屏幕上
2、在指纹匹配过程中,如果采集的指纹与指纹模块库相匹配,OLED显示匹配成功,并转动步进电机一圈
3、可通过按键设定智能门锁密码,密码可设置为两个(密码六位),如果匹配两个中的一个成功,即可开锁,也可通过按键修改密码,所有的操作过程显示于OLED中
4、实现RFID与手机解锁
三、元件购买地址
1、继电器(锁)
https://item.taobao.com/item.htm?spm=a1z10.3-c-s.w4002-14787471870.9.1a966865lNZF6d&id=577356377112
2、4X4按键
https://item.taobao.com/item.htm?spm=a1z10.3-c-s.w4002-14787471870.9.40f96865MfVG6C&id=563379889617
3、指纹模块
https://item.taobao.com/item.htm?spm=a1z10.3-c-s.w4002-14787471870.9.16d06865bduv8I&id=563705918850
4、OLED(IIC)
https://item.taobao.com/item.htm?spm=a1z10.3-c-s.w4002-14787471870.15.44806865TkULtt&id=575274211818(白色)
5、蓝牙
https://item.taobao.com/item.htm?spm=a1z10.3-c-s.w4002-14787471870.13.471b6865OLuSU6&id=560220493066
四、开发项目
2、项目简介
模块使用:通过获取4x4按键来实现不同功能。本项目使用道IIC协议、SPI协议、RFID读卡模块、蓝牙模块、4x4按键、AS608指纹模块、OLED显示屏模块、STM32F4107开发板。
3、蓝牙模块
①、连接蓝牙
②注意事项
按住蓝牙模块的按键,再将USB转TTL插入电脑,插入电脑后,蓝牙模块的LED灯处于慢闪状态(慢闪状态表示处于AT指令操作模式)快闪处于数据透传模式(透传相当数据无障碍传输)
③、设置为主模块的步骤
①、 PIO11 置高。(根据自己的引脚接线)
②、上电,模块进入 AT 命令响应状态。
③、超级终端或其他串口工具,设置波特率 115200,数据位 8 位,停止位 1 位,无校验位,
无流控制。
④、串口发送字符“AT+ROLE=1rn”,成功返回“OKrn”,其中rn 为回车换行。
⑤、 PIO 置低,重新上电,模块为主模块,自动搜索从模块,建立连接。
⑥、修改蓝牙设备名称:AT+NAME=贵哥rn ——设置模块设备名为:“贵哥”
⑦、模块蓝牙设备地址: 00:02:72:od:22:24,设备名称为: Bluetoothat+rname? 0002, 72, od2224rn
+RNAME:Bluetooth
OK
⑧、手机下载”蓝牙调试器“APP,即可通过手机控制开发板的设备
④、蓝牙代码
/*
PB10 -- TX
PB11 -- RX
*/
/**************************************
通过串口3,接收手机发送的指令,传递给蓝牙模块,蓝牙收到指令
后,做出相应的动作,然后将指令通过串口3传递给开发板,执行指令操作。
************************************/
void Usart3_Init(void)
{
//结构体
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
//使能串口3时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
//使能GPIO B组时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
//PB10引脚映射到串口3
GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_USART3);
//PB11引脚映射到串口3
GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_USART3);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11; //引脚10 11
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //复用模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //输出推挽
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //输出速度
//3、初始化IO口为复用功能输出。
GPIO_Init(GPIOB, &GPIO_InitStruct);
USART_InitStruct.USART_BaudRate = 57600; //一般设置为 9600;
USART_InitStruct.USART_WordLength = USART_WordLength_8b; //字长为 8 位数据格式
USART_InitStruct.USART_StopBits = USART_StopBits_1; //一个停止位
USART_InitStruct.USART_Parity = USART_Parity_No; //无奇偶校验位
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件控制流
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 全双工
//初始化串口
USART_Init(USART3, &USART_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn; //中断通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x01; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x01; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //中断通道使能
//3、启定时器中断,配置NVIC。
NVIC_Init(&NVIC_InitStruct);
//开启中断,接收到数据中断
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
USART_Cmd(USART3, ENABLE);
}
/*
通过触发中断服务函数,来执行蓝牙模块的指令(中断服务函数不需要调用,写好就行)
*/
//串口3中断服务函数
void USART3_IRQHandler(void)
{
char Usart_Data;
//若是非空,则返回值为1,与RESET(0)判断,不相等则判断为真
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
//判断为真后,为下次中断做准备,则需要对中断的标志清零
USART_ClearITPendingBit(USART3,USART_IT_RXNE);
/* DR读取接受到的数据*/
buffer[count++] = USART_ReceiveData(USART3);
if(buffer[count-1] == '.') //接受到一串字符串
{
//将有数据(去掉:)赋值到rx_buffer当中
for(rx_i = 0; rx_i < (count-1); rx_i++)
{
rx_buffer[rx_i] = buffer[rx_i];
}
rx_flag = 1; //接受完毕标志
count = 0; //以便下次字符串从buffer[0]开始存储
memset(buffer, 0, sizeof(buffer));
}
}
}
//手机开门
void Phone_Open_Door(void)
{
// Usart3_Init(); //调用串口3
OLED_ShowStr(20,3,(unsigned char *)"Enter Comment!!",2);//测试8*16字
// USART_Cmd(USART3, ENABLE); //使能串口3
if(rx_flag == 1)
{
printf("rx_buffer = %sn", rx_buffer);
//亮灯
if(strcmp(rx_buffer, "open_door") == 0)//如果手机蓝牙输入的指令也是open_door,则触发中断,实现开门
{
GPIO_ResetBits(GPIOF, GPIO_Pin_10);
OLED_Fill(0x00);//全屏灭
delay_ms(500);
OLED_ShowStr(20,3,(unsigned char *)"Open Success!!!",2);//测试8*16字
delay_ms(500);
}
else
{
GPIO_SetBits(GPIOF, GPIO_Pin_10);
OLED_Fill(0x00);//全屏灭
delay_ms(500);
OLED_ShowStr(20,3,(unsigned char *)"Error !!",2);//测试8*16字
delay_ms(500);
}
memset(rx_buffer, 0, sizeof(rx_buffer));
rx_flag = 0;
}
}
4、RFID
①、在使用之前,需要将弯排针焊接在RFID-RC522模块上,找准RFID的接口与开发板连接。
② 主要指标
. 容量为 8K 位 EEPROM
. 分为 16 个扇区,每个扇区为 4 块,每块 16 个字节,以块为存取单位
. 每个扇区有独立的一组密码及访问控制
. 每张卡有唯一序列号,为 32 位
. 具有防冲突机制,支持多卡操作
. 无电源,自带天线,内含加密控制逻辑和通讯逻辑威廉希尔官方网站
. 数据保存期为 10 年,可改写 10 万次,读无限次
. 工作温度: -20℃ ~50℃ (湿度为 90%)
. 工作频率: 13.56MHZ
. 通信速率: 106 KBPS
. 读写距离: 10 cm 以内(与读写器有关)
③、RFID代码
//.c文件
#include "MFRC522.h"
#include "sys.h"
#include "delay.h"
#include
#include "OLED_I2C.h"
//test
u8 irq_regdata;
u16 wait_count;
u8 error_regdata;
u8 last_bitsdata;
//SPI3初始化
void STM32_SPI3_Init(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
//SPI3 pins: SCK=PD0,
//MFRC522_CS PD14
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_9 | GPIO_Pin_14; //引脚D0 D14
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //速度
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; //上拉
GPIO_Init(GPIOD, &GPIO_InitStruct);
//MFRC522_Reset PE15 , MOSI=PE7
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7| GPIO_Pin_13 | GPIO_Pin_15; //引脚E7 E15
GPIO_Init(GPIOE, &GPIO_InitStruct);
// MISO=PE9,
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; //引脚E9
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; //输入
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; //没有使能上下拉电阻
GPIO_Init(GPIOE, &GPIO_InitStruct);
PDout(9)=1;//VCC
PEout(13)=0;//GND
MFRC522_CS(1); //片选置高电平
}
uint8_t rc522_send_byte(uint8_t byte)
{
u8 i, rx_data=0;
SCK = 0;
//0 1 1 1 1 0 0 0
for(i=0; i<8; i++)
{
/*准备数据*/
//发数据1
if(byte & (1<<(7-i)))
{
MOSI = 1; //引脚输出
}
//发数据0
else
{
MOSI = 0; //引脚输出
}
delay_us(5);
SCK = 1;
delay_us(5);
//接受数据
if(MISO) //引脚为电平为1
{
rx_data |= (1<<(7-i));
}
SCK = 0;
}
return rx_data;
}
void SPI3_Send(u8 val)
{
rc522_send_byte(val);
}
//
u8 SPI3_Receive(void)
{
return rc522_send_byte(0x00);
}
//功能描述向MFRC522的某一寄存器写一个字节数据
//输入参数addr--寄存器地址val--要写入的值
void Write_MFRC522(u8 addr, u8 val)
{
//地址格式0XXXXXX0
MFRC522_CS(0);
SPI3_Send((addr<<1)&0x7E);
SPI3_Send(val);
MFRC522_CS(1);
}
//功能描述从MFRC522的某一寄存器读一个字节数据
//输入参数addr--寄存器地址
//返 回 值返回读取到的一个字节数据
u8 Read_MFRC522(u8 addr)
{
u8 val;
//地址格式1XXXXXX0
MFRC522_CS(0);
SPI3_Send(((addr<<1)&0x7E)|0x80);
val=SPI3_Receive();
MFRC522_CS(1);
//
return val;
}
//下面两个函数只对能读写位有效
//功能描述置RC522寄存器位
//输入参数reg--寄存器地址;mask--置位值
void SetBitMask(u8 reg, u8 mask)
{
u8 tmp=0;
//
tmp=Read_MFRC522(reg);
Write_MFRC522(reg,tmp|mask); // set bit mask
}
//功能描述清RC522寄存器位
//输入参数reg--寄存器地址;mask--清位值
void ClearBitMask(u8 reg, u8 mask)
{
u8 tmp=0;
//
tmp=Read_MFRC522(reg);
Write_MFRC522(reg,tmp&(~mask)); //clear bit mask
}
//功能描述开启天线,每次启动或关闭天线发射之间应至少有1ms的间隔
void AntennaOn(void)
{
u8 temp;
//
temp=Read_MFRC522(TxControlReg);
if ((temp&0x03)==0)
{
SetBitMask(TxControlReg,0x03);
}
}
//功能描述关闭天线,每次启动或关闭天线发射之间应至少有1ms的间隔
void AntennaOff(void)
{
ClearBitMask(TxControlReg,0x03);
}
//功能描述复位MFRC522
void MFRC522_Reset(void)
{
//外复位可以不用
MFRC522_Rst(1);
delay_us(1);
MFRC522_Rst(0);
delay_us(1);
MFRC522_Rst(1);
delay_us(1);
//内复位
Write_MFRC522(CommandReg, PCD_RESETPHASE);
}
//
void MFRC522_Initializtion(void)
{
STM32_SPI3_Init();
MFRC522_Reset();
//Timer: TPrescaler*TreloadVal/6.78MHz = 0xD3E*0x32/6.78=25ms
Write_MFRC522(TModeReg,0x8D); //TAuto=1为自动计数模式,受通信协议影向。低4位为预分频值的高4位
//Write_MFRC522(TModeReg,0x1D); //TAutoRestart=1为自动重载计时,0x0D3E是0.5ms的定时初值//test
Write_MFRC522(TPrescalerReg,0x3E); //预分频值的低8位
Write_MFRC522(TReloadRegL,0x32); //计数器的低8位
Write_MFRC522(TReloadRegH,0x00); //计数器的高8位
Write_MFRC522(TxAutoReg,0x40); //100%ASK
Write_MFRC522(ModeReg,0x3D); //CRC初始值0x6363
Write_MFRC522(CommandReg,0x00); //启动MFRC522
//Write_MFRC522(RFCfgReg, 0x7F); //RxGain = 48dB调节卡感应距离
AntennaOn(); //打开天线
}
//功能描述RC522和ISO14443卡通讯
//输入参数command--MF522命令字
// sendData--通过RC522发送到卡片的数据
// sendLen--发送的数据长度
// BackData--接收到的卡片返回数据
// BackLen--返回数据的位长度
//返 回 值成功返回MI_O
u8 MFRC522_ToCard(u8 command, u8 *sendData, u8 sendLen, u8 *backData, u16 *backLen)
{
u8 status=MI_ERR;
u8 irqEn=0x00;
u8 waitIRq=0x00;
u8 lastBits;
u8 n;
u16 i;
//根据命预设中断参数
switch (command)
{
case PCD_AUTHENT: //认证卡密
irqEn = 0x12; //
waitIRq = 0x10; //
break;
case PCD_TRANSCEIVE: //发送FIFO中数据
irqEn = 0x77; //
waitIRq = 0x30; //
break;
default:
break;
}
//
Write_MFRC522(ComIEnReg, irqEn|0x80); //允许中断请求
ClearBitMask(ComIrqReg, 0x80); //清除所有中断请求位
SetBitMask(FIFOLevelReg, 0x80); //FlushBuffer=1, FIFO初始化
Write_MFRC522(CommandReg, PCD_IDLE); //使MFRC522空闲
//向FIFO中写入数据
for (i=0; i
Write_MFRC522(FIFODataReg, sendData);
//执行命令
Write_MFRC522(CommandReg, command);
//天线发送数据
if (command == PCD_TRANSCEIVE) //如果是卡片通信命令,MFRC522开始向天线发送数据
SetBitMask(BitFramingReg, 0x80); //StartSend=1,transmission of data starts
//等待接收数据完成
i = 10000; //i根据时钟频率调整操作M1卡最大等待时间25ms
do
{
n = Read_MFRC522(ComIrqReg);
//irq_regdata=n; //test
i--;
//wait_count=i; //test
}while ((i!=0) && !(n&0x01) && !(n&waitIRq)); //接收完就退出n=0x64
//停止发送
ClearBitMask(BitFramingReg, 0x80); //StartSend=0
//如果在25ms内读到卡
if (i != 0)
{
if(!(Read_MFRC522(ErrorReg) & 0x1B)) //BufferOvfl Collerr CRCErr ProtecolErr
{
if (n & irqEn & 0x01) //
status = MI_NOTAGERR; //
//
if (command == PCD_TRANSCEIVE)
{
n = Read_MFRC522(FIFOLevelReg); //n=0x02
lastBits = Read_MFRC522(ControlReg) & 0x07; //lastBits=0
if (lastBits!=0)
*backLen = (n-1)*8 + lastBits;
else
*backLen = n*8; //backLen=0x10=16
//
if (n == 0)
n = 1;
if (n > MAX_LEN)
n = MAX_LEN;
//
for (i=0; i
backData = Read_MFRC522(FIFODataReg);
}
//
status = MI_OK;
}
else
status = MI_ERR;
}
//
Write_MFRC522(ControlReg,0x80); //timer stops
Write_MFRC522(CommandReg, PCD_IDLE); //
//
return status;
}
//功能描述寻卡读取卡类型号
//输入参数reqMode--寻卡方式
// TagType--返回卡片类型
// 0x4400 = Mifare_UltraLight
// 0x0400 = Mifare_One(S50)
// 0x0200 = Mifare_One(S70)
// 0x0800 = Mifare_Pro(X)
// 0x4403 = Mifare_DESFire
//返 回 值成功返回MI_OK
u8 MFRC522_Request(u8 reqMode, u8 *TagType)
{
u8 status;
u16 backBits; //接收到的数据位数
//
Write_MFRC522(BitFramingReg, 0x07); //TxLastBists = BitFramingReg[2..0]
TagType[0] = reqMode;
status = MFRC522_ToCard(PCD_TRANSCEIVE, TagType, 1, TagType, &backBits);
//
if ((status != MI_OK) || (backBits != 0x10))
{
status = MI_ERR;
}
//
return status;
}
//功能描述防冲突检测读取选中卡片的卡序列号
//输入参数serNum--返回4字节卡序列号,第5字节为校验字节
//返 回 值成功返回MI_OK
u8 MFRC522_Anticoll(u8 *serNum)
{
u8 status;
u8 i;
u8 serNumCheck=0;
u16 unLen;
//
ClearBitMask(Status2Reg, 0x08); //TempSensclear
ClearBitMask(CollReg,0x80); //ValuesAfterColl
Write_MFRC522(BitFramingReg, 0x00); //TxLastBists = BitFramingReg[2..0]
serNum[0] = PICC_ANTICOLL1;
serNum[1] = 0x20;
status = MFRC522_ToCard(PCD_TRANSCEIVE, serNum, 2, serNum, &unLen);
//
if (status == MI_OK)
{
//校验卡序列号
for(i=0;i<4;i++)
serNumCheck^=serNum;
//
if(serNumCheck!=serNum)
status=MI_ERR;
}
SetBitMask(CollReg,0x80); //ValuesAfterColl=1
//
return status;
}
//功能描述用MF522计算CRC
//输入参数pIndata--要读数CRC的数据len--数据长度pOutData--计算的CRC结果
void CalulateCRC(u8 *pIndata, u8 len, u8 *pOutData)
{
u16 i;
u8 n;
//
ClearBitMask(DivIrqReg, 0x04); //CRCIrq = 0
SetBitMask(FIFOLevelReg, 0x80); //清FIFO指针
Write_MFRC522(CommandReg, PCD_IDLE);
//向FIFO中写入数据
for (i=0; i
Write_MFRC522(FIFODataReg, *(pIndata+i));
//开始RCR计算
Write_MFRC522(CommandReg, PCD_CALCCRC);
//等待CRC计算完成
i = 1000;
do
{
n = Read_MFRC522(DivIrqReg);
i--;
}while ((i!=0) && !(n&0x04)); //CRCIrq = 1
//读取CRC计算结果
pOutData[0] = Read_MFRC522(CRCResultRegL);
pOutData[1] = Read_MFRC522(CRCResultRegH);
Write_MFRC522(CommandReg, PCD_IDLE);
}
//功能描述选卡读取卡存储器容量
//输入参数serNum--传入卡序列号
//返 回 值成功返回卡容量
u8 MFRC522_SelectTag(u8 *serNum)
{
u8 i;
u8 status;
u8 size;
u16 recvBits;
u8 buffer[9];
//
buffer[0] = PICC_ANTICOLL1; //防撞码1
buffer[1] = 0x70;
buffer[6] = 0x00;
for (i=0; i<4; i++)
{
buffer[i+2] = *(serNum+i); //buffer[2]-buffer[5]为卡序列号
buffer[6] ^= *(serNum+i); //卡校验码
}
//
CalulateCRC(buffer, 7, &buffer[7]); //buffer[7]-buffer[8]为RCR校验码
ClearBitMask(Status2Reg,0x08);
status = MFRC522_ToCard(PCD_TRANSCEIVE, buffer, 9, buffer, &recvBits);
//
if ((status == MI_OK) && (recvBits == 0x18))
size = buffer[0];
else
size = 0;
//
return size;
}
//功能描述验证卡片密码
//输入参数authMode--密码验证模式
// 0x60 = 验证A密钥
// 0x61 = 验证B密钥
// BlockAddr--块地址
// Sectorkey--扇区密码
// serNum--卡片序列号4字节
//返 回 值成功返回MI_OK
u8 MFRC522_Auth(u8 authMode, u8 BlockAddr, u8 *Sectorkey, u8 *serNum)
{
u8 status;
u16 recvBits;
u8 i;
u8 buff[12];
//验证模式+块地址+扇区密码+卡序列号
buff[0] = authMode; //验证模式
buff[1] = BlockAddr; //块地址
for (i=0; i<6; i++)
buff[i+2] = *(Sectorkey+i); //扇区密码
//
for (i=0; i<4; i++)
buff[i+8] = *(serNum+i); //卡序列号
//
status = MFRC522_ToCard(PCD_AUTHENT, buff, 12, buff, &recvBits);
//
if ((status != MI_OK) || (!(Read_MFRC522(Status2Reg) & 0x08)))
status = MI_ERR;
//
return status;
}
//功能描述读块数据
//输入参数blockAddr--块地址;recvData--读出的块数据
//返 回 值成功返回MI_OK
u8 MFRC522_Read(u8 blockAddr, u8 *recvData)
{
u8 status;
u16 unLen;
//
recvData[0] = PICC_READ;
recvData[1] = blockAddr;
CalulateCRC(recvData,2, &recvData[2]);
status = MFRC522_ToCard(PCD_TRANSCEIVE, recvData, 4, recvData, &unLen);
//
if ((status != MI_OK) || (unLen != 0x90))
status = MI_ERR;
//
return status;
}
//功能描述写块数据
//输入参数blockAddr--块地址;writeData--向块写16字节数据
//返 回 值成功返回MI_OK
u8 MFRC522_Write(u8 blockAddr, u8 *writeData)
{
u8 status;
u16 recvBits;
u8 i;
u8 buff[18];
//
buff[0] = PICC_WRITE;
buff[1] = blockAddr;
CalulateCRC(buff, 2, &buff[2]);
status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 4, buff, &recvBits);
//
if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A))
status = MI_ERR;
//
if (status == MI_OK)
{
for (i=0; i<16; i++) //向FIFO写16Byte数据
buff = *(writeData+i);
//
CalulateCRC(buff, 16, &buff[16]);
status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 18, buff, &recvBits);
if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A))
status = MI_ERR;
}
return status;
}
//功能描述命令卡片进入休眠状态
void MFRC522_Halt(void)
{
u16 unLen;
u8 buff[4];
//
buff[0] = PICC_HALT;
buff[1] = 0;
CalulateCRC(buff, 2, &buff[2]);
MFRC522_ToCard(PCD_TRANSCEIVE, buff, 4, buff,&unLen);
}
//数字的ASCII码
uc8 numberascii[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
//MFRC522数据区
u8 mfrc552pidbuf[18];
u8 card_pydebuf[2];
u8 card_numberbuf[5];
u8 card_key0Abuf[6]={0xff,0xff,0xff,0xff,0xff,0xff};
u8 card_writebuf[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
u8 card_readbuf[18];
u8 comper_card_ID[5] = {0x59,0x94,0x67,0xb3 ,0x19};
//MFRC522测试函数
u8 MFRC522Test(void)
{
u8 i,j,status,card_size;
//
status=MFRC522_Request(0x52, card_pydebuf); //寻卡 查看读卡器旁边是否有卡
printf("%dn",status);
//
if(status==0) //如果读到卡
{
status=MFRC522_Anticoll(card_numberbuf); //防撞处理 card_numberbuf得到卡号
card_size=MFRC522_SelectTag(card_numberbuf); //选卡
status=MFRC522_Auth(0x60, 4, card_key0Abuf, card_numberbuf); //验卡 匹配密码,这样才能写 第四块
status=MFRC522_Write(4, card_writebuf); //写卡(写卡要小心,特别是各区的块3)
status=MFRC522_Read(4, card_readbuf); //读卡
printf("read card okn");
//卡类型显示
printf("卡类型:0x");
printf("%x%xn",card_pydebuf[0], card_pydebuf[1] );
//卡序列号显,最后一字节为卡的校验码
printf("卡序列号:");
for(i=0;i<5;i++)
{
printf(" %#x ",card_numberbuf);
}
printf("n");
//卡容量显示,单位为Kbits
printf("卡容量 : %dKbitsn",card_size);
//读卡状态显示,正常为0
//读一个块的数据显示
printf("读一个块的数据显示n");
for(i=0;i<18;i++)
printf(" %x",card_readbuf);
printf("n");
if(comper_card_ID[0] == card_numberbuf[0] &&comper_card_ID[1] == card_numberbuf[1]&&comper_card_ID[2] == card_numberbuf[2] &&comper_card_ID[3] == card_numberbuf[3]&&comper_card_ID[4] == card_numberbuf[4])
{
PFout(8)=1;PFout(9)=0;delay_ms(80);
PFout(8)=0;PFout(9)=1;delay_ms(80);
PFout(8)=1;PFout(9)=0;delay_ms(80);
PFout(8)=0;PFout(9)=1;delay_ms(80);
return 1;
}
else
return 0;
}
}
.h文件
//
#ifndef _MFRC522_H_
#define _MFRC522_H_
#include "stm32f4xx.h"
//
//定义MFRC522的CS引脚操作,x=1时CS=1,x=0时CS=0
#define MFRC522_CS(x) x ? GPIO_SetBits(GPIOD,GPIO_Pin_14):GPIO_ResetBits(GPIOD,GPIO_Pin_14)
#define MFRC522_Rst(x) x ? GPIO_SetBits(GPIOE,GPIO_Pin_15):GPIO_ResetBits(GPIOE,GPIO_Pin_15)
/
//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
/
//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 RFU1C 0x1C
#define RFU1D 0x1D
#define RFU1E 0x1E
#define SerialSpeedReg 0x1F
// PAGE 2
#define RFU20 0x20
#define CRCResultRegH 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 0
#define MI_NOTAGERR 1
#define MI_ERR 2
//
#define MAX_LEN 18
//#define F_CS PDout(14)
#define SCK PDout(0)
#define MISO PEin(9)
#define MOSI PEout(7)
//MFRC522 test
u8 MFRC522Test(void);
extern u8 irq_regdata;
extern u16 wait_count;
extern u8 error_regdata;
extern u8 last_bitsdata;
//void MFRC522Test(void);
void Delay1_us(vu16 count);
void STM32_SPI3_Init(void);
void SPI2_Send(u8 val);
u8 SPI2_Receive(void);
void SPI3_Send(u8 val);
u8 SPI3_Receive(void);
void MFRC522_Initializtion(void);
void Write_MFRC522(u8 addr, u8 val);
u8 Read_MFRC522(u8 addr);
void SetBitMask(u8 reg, u8 mask);
void ClearBitMask(u8 reg, u8 mask);
void AntennaOn(void);
void AntennaOff(void);
void MFRC522_Reset(void);
void MFRC522_Init(void);
u8 MFRC522_ToCard(u8 command, u8 *sendData, u8 sendLen, u8 *backData, u16 *backLen);
u8 MFRC522_Request(u8 reqMode, u8 *TagType);
u8 MFRC522_Anticoll(u8 *serNum);
void CalulateCRC(u8 *pIndata, u8 len, u8 *pOutData);
u8 MFRC522_SelectTag(u8 *serNum);
u8 MFRC522_Auth(u8 authMode, u8 BlockAddr, u8 *Sectorkey, u8 *serNum);
u8 MFRC522_Read(u8 blockAddr, u8 *recvData);
u8 MFRC522_Write(u8 blockAddr, u8 *writeData);
void MFRC522_Halt(void);
//
#endif
5、指纹模块
①AS608原理图
②、PCB图
③、 ATK-AS608 指纹识别模块简介
④、引脚介绍
根据自己的开发板,选择引脚的连接
根据自己的开发板,选择引脚的连接
⑤、代码实现
.c文件
#include
#include "delay.h"
#include "usart.h"
#include "finger.h"
u32 AS608Addr = 0XFFFFFFFF; //默认
u8 flag = 0; //用来当作按下手指和未按下的标志位,1表示按下,0表示未按下
//初始化PA6为下拉输入
//读摸出感应状态(触摸感应时输出高电平信号)
void PS_StaGPIO_Init(void)
{
EXTI_InitTypeDef EXTI_InitStruct;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
//初始化读状态引脚GPIOA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入模式
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//下拉模式
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
//3、设置IO口与中断线的映射关系。EXTI0有16个引脚与之对应,这里的映射选择其中一个引脚(PA0)(PE2)(PE3)(PE4)
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource6);
EXTI_InitStruct.EXTI_Line = EXTI_Line6; //中断线6//
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式
EXTI_InitStruct.EXTI_Trigger= EXTI_Trigger_Rising; //上升沿
EXTI_InitStruct.EXTI_LineCmd= ENABLE; //中断线使能
//4、初始化线上中断,设置触发条件等。
EXTI_Init(&EXTI_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn; //中断通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x01; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x01; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //中断通道使能
//5、配置中断分组(NVIC),并使能中断。
NVIC_Init(&NVIC_InitStruct);
}
//6、 编写中断服务函数。满足中断条件后,CPU自动去执行的代码,不需要程序在主函数或者其它函数进行调用。
void EXTI9_5_IRQHandler(void)
{
//判断中断是否为1
if(EXTI_GetITStatus(EXTI_Line6) == SET)
{
delay_ms(10);
if(PS_Sta)
{
flag = 1;//说明按下了手指
}
//7、清除中断标志位,防止一直进入中断
EXTI_ClearITPendingBit(EXTI_Line6);
}
//7、清除中断标志位,防止一直进入中断
EXTI_ClearITPendingBit(EXTI_Line6);
}
//串口发送一个字节
static void MYUSART_SendData(u8 data)
{
while((USART2->SR&0X40)==0);
USART2->DR = data;
}
//发送包头
static void SendHead(void)
{
MYUSART_SendData(0xEF);
MYUSART_SendData(0x01);
}
//发送地址
static void SendAddr(void)
{
MYUSART_SendData(AS608Addr>>24);
MYUSART_SendData(AS608Addr>>16);
MYUSART_SendData(AS608Addr>>8);
MYUSART_SendData(AS608Addr);
}
//发送包标识,
static void SendFlag(u8 flag)
{
MYUSART_SendData(flag);
}
//发送包长度
static void SendLength(int length)
{
MYUSART_SendData(length>>8);
MYUSART_SendData(length);
}
//发送指令码
static void Sendcmd(u8 cmd)
{
MYUSART_SendData(cmd);
}
//发送校验和
static void SendCheck(u16 check)
{
MYUSART_SendData(check>>8);
MYUSART_SendData(check);
}
//判断中断接收的数组有没有应答包
//waittime为等待中断接收数据的时间(单位1ms)
//返回值:数据包首地址
static u8 *JudgeStr(u16 waittime)
{
USART2_RX_STA=0;
while(--waittime)
{
delay_us(500);
}
if(USART2_RX_BUF[9] == 0x00)//确认字为0x00表示正确
{
USART2_RX_STA=0;//下标置零,为了下次重新接受返回过来的数据
return USART2_RX_BUF;//返回存从指纹模块返回过来数据的首地址
}
else
return 0;
}
/*****************************************************************************************
录入指纹:
①、首先要是实现开锁,需要在系统里面录入指纹信息,需要:
②、录入图像->生成特征->快速查找图像->自动注册模板
录入图像 PS_GetImage
功能:探测手指,探测到后录入指纹图像存于ImageBuffer。
模块返回确认字
*****************************************************************************************/
u8 PS_GetImage(void)
{
//printf("111 录入图像 PS_GetImagern");
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;
}
/*****************************************************************************
生成特征指令-> 存入指纹图像,存入单片机给定的缓冲区号BufferID中
生成特征 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);
MYUSART_SendData(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;
}
/*************************************************************************************
快速查找图像生成图像后要验证是否有在Buffer里面
搜索指纹 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);
MYUSART_SendData(BufferID);
MYUSART_SendData(StartPage>>8);
MYUSART_SendData(StartPage);
MYUSART_SendData(PageNum>>8);
MYUSART_SendData(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);
MYUSART_SendData(BufferID);
MYUSART_SendData(PageID>>8);
MYUSART_SendData(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);
MYUSART_SendData(PageID>>8);
MYUSART_SendData(PageID);
MYUSART_SendData(N>>8);
MYUSART_SendData(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:456
//说明: 模块返回确认字
u8 PS_WriteReg(u8 RegNum,u8 DATA)
{
u16 temp;
u8 ensure;
u8 *data;
SendHead();
SendAddr();
SendFlag(0x01);//命令包标识
SendLength(0x05);
Sendcmd(0x0E);
MYUSART_SendData(RegNum);
MYUSART_SendData(DATA);
temp = RegNum+DATA+0x01+0x05+0x0E;
SendCheck(temp);
data=JudgeStr(2000);
if(data)
ensure=data[9];
else
ensure=0xff;
if(ensure==0)
printf("rn设置参数成功!");
else
printf("rn%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("rn模块最大指纹容量=%d",p->PS_max);
printf("rn对比等级=%d",p->PS_level);
printf("rn地址=%x",p->PS_addr);
printf("rn波特率=%d",p->PS_N*9600);
}
else
printf("rn%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);
MYUSART_SendData(PS_addr>>24);
MYUSART_SendData(PS_addr>>16);
MYUSART_SendData(PS_addr>>8);
MYUSART_SendData(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;
AS608Addr = PS_addr;
if(ensure==0x00)
printf("rn设置地址成功!");
else
printf("rn%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);
MYUSART_SendData(NotePageNum);
for(i=0;i<32;i++)
{
MYUSART_SendData(Byte32);
temp += Byte32;
}
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);
MYUSART_SendData(NotePageNum);
temp = 0x01+0x04+0x19+NotePageNum;
SendCheck(temp);
data=JudgeStr(2000);
if(data)
{
ensure=data[9];
for(i=0;i<32;i++)
{
Byte32=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);
MYUSART_SendData(BufferID);
MYUSART_SendData(StartPage>>8);
MYUSART_SendData(StartPage);
MYUSART_SendData(PageNum>>8);
MYUSART_SendData(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("rn有效指纹个数=%d",(data[10]<<8)+data[11]);
}
else
printf("rn%s",EnsureMessage(ensure));
return ensure;
}
//与AS608握手 PS_HandShake
//参数: PS_Addr地址指针
//说明: 模块返新地址(正确地址)
u8 PS_HandShake(u32 *PS_Addr)
{
SendHead();
SendAddr();
MYUSART_SendData(0X01);
MYUSART_SendData(0X00);
MYUSART_SendData(0X00);
delay_ms(200);
if(USART2_RX_STA&0X8000)//接收到数据
{
if(//判断是不是模块返回的应答包
USART2_RX_BUF[0]==0XEF
&&USART2_RX_BUF[1]==0X01
&&USART2_RX_BUF[6]==0X07
)
{
*PS_Addr=(USART2_RX_BUF[2]<<24) + (USART2_RX_BUF[3]<<16)
+(USART2_RX_BUF[4]<<8) + (USART2_RX_BUF[5]);
USART2_RX_STA=0;
return 0;
}
USART2_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="访问指纹库时地址序号超出指纹库范围";
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;
}
//.h文件
#ifndef __AS608_H
#define __AS608_H
#include
#include "stm32f4xx.h"
#include "sys.h"
#define PS_Sta PAin(6)//读指纹模块状态引脚
#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
6、OLED显示屏模块
①接线图
(再次声明,我的开发板是基于STMF4 107系列,要根据自己的开发板来连接)
② OLED 简介:
③、IIC 威廉希尔官方网站
连接
GND: 电源地
VCC: 2.2V~5.5V
SCL: CLK 时钟 (高电平 2.2V~5.5V)
SDA: MOSI 数据 (高电平 2.2V~5.5V)
(注意事项:
OLED 显示屏不同于 LCD,OLED 上电是没有反应的,需要程序驱动才会有显示!)
④、代码实现
//.c文件
//因为我是项目需要,所以会有多个函数,起始都大同小异,还有,需要使用取字模软件,来实现汉字的显示
/************************************************************************************
* Copyright (c), 2014, HelTec Automatic Technology co.,LTD.
* All rights reserved.
*
* Http: www.heltec.cn
* Email: cn.heltec@gmail.com
* WebShop: heltec.taobao.com
*
* File name: OLED_I2C.c
* Project : HelTec.uvprij
* Processor: STM32F103C8T6
* Compiler : MDK fo ARM
*
* Author : 小林
* Version: 1.00
* Date : 2014.4.8
* Email : hello14blog@gmail.com
* Modification: none
*
* Description:128*64点阵的OLED显示屏驱动文件,仅适用于惠特自动化(heltec.taobao.com)的SD1306驱动IIC通信方式显示屏
*
* Others: none;
*
* Function List:
* 1. void I2C_Configuration(void) -- 配置CPU的硬件I2C
* 2. void I2C_WriteByte(uint8_t addr,uint8_t data) -- 向寄存器地址写一个byte的数据
* 3. void WriteCmd(unsigned char I2C_Command) -- 写命令
* 4. void WriteDat(unsigned char I2C_Data) -- 写数据
* 5. void OLED_Init(void) -- OLED屏初始化
* 6. void OLED_SetPos(unsigned char x, unsigned char y) -- 设置起始点坐标
* 7. void OLED_Fill(unsigned char fill_Data) -- 全屏填充
* 8. void OLED_CLS(void) -- 清屏
* 9. void OLED_ON(void) -- 唤醒
* 10. void OLED_OFF(void) -- 睡眠
* 11. void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize) -- 显示字符串(字体大小有6*8和8*16两种)
* 12. void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N) -- 显示中文(中文需要先取模,然后放到codetab.h中)
* 13. void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]) -- BMP图片
*
* History: none;
*
*************************************************************************************/
#include "OLED_I2C.h"
#include "delay.h"
#include "codetab.h"
#include "sys.h"
void I2C_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //结构体
//使能GPIO D E组时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_15; //引脚1 15
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //输出模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //输出推挽
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //输出速度
GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_10; //引脚8 10
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //输出模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //输出推挽
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //输出速度
GPIO_Init(GPIOE, &GPIO_InitStruct);
//电源供电
PDout(1) = 1;
PDout(15) = 0;
//总线空闲
OLED_SCL = 1;
OLED_SDA_OUT = 1;
}
//引脚模式变更
void OLED_Iic_Sda_Mode(GPIOMode_TypeDef mode)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //第10号引脚
GPIO_InitStructure.GPIO_Mode = mode; //输入/输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,增强驱动能力,引脚的输出电流更大
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //引脚的速度最大为100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //没有使用内部上拉电阻
GPIO_Init(GPIOE, &GPIO_InitStructure);
}
//启动信号
void OLED_Iic_Start(void)
{
OLED_Iic_Sda_Mode(GPIO_Mode_OUT);
//总线空闲
OLED_SCL = 1;
OLED_SDA_OUT = 1;
delay_us(5);
//启动信号
OLED_SDA_OUT = 0;
delay_us(5);
OLED_SCL = 0;
}
//停止信号
void OLED_Iic_Stop(void)
{
OLED_Iic_Sda_Mode(GPIO_Mode_OUT);
OLED_SCL = 0;
OLED_SDA_OUT = 0;
delay_us(5);
OLED_SCL = 1;
delay_us(5);
OLED_SDA_OUT = 1;
}
//引脚发送一位数据
void OLED_Iic_Send_Ack(u8 ack)
{
OLED_Iic_Sda_Mode(GPIO_Mode_OUT);
OLED_SCL = 0;
/*准备数据*/
//发数据1
if(ack == 1)
{
OLED_SDA_OUT = 1; //引脚输出
}
//发数据0
if(ack == 0)
{
OLED_SDA_OUT = 0; //引脚输出
}
delay_us(5);
OLED_SCL = 1;
delay_us(5);
OLED_SCL = 0;
}
//引脚发送一个字节数据
void OLED_Iic_Send_Byte(u8 data)
{
u8 i;
OLED_Iic_Sda_Mode(GPIO_Mode_OUT);
OLED_SCL = 0;
//0 1 1 1 1 0 0 0
for(i=0; i<8; i++)
{
/*准备数据*/
//发数据1
if(data & (1<<(7-i)))
{
OLED_SDA_OUT = 1; //引脚输出
}
//发数据0
else
{
OLED_SDA_OUT = 0; //引脚输出
}
delay_us(5);
OLED_SCL = 1;
delay_us(5);
OLED_SCL = 0;
}
}
//接受一位数据
u8 OLED_Iic_Rcv_Ack(void)
{
u8 ack;
OLED_Iic_Sda_Mode(GPIO_Mode_IN);
OLED_SCL = 0;
delay_us(5);
OLED_SCL = 1;
delay_us(5);
if(OLED_SDA_IN == 1) //引脚为电平为1
{
ack = 1;
}
if(OLED_SDA_IN == 0) //引脚为电平为1
{
ack = 0;
}
OLED_SCL = 0;
return ack;
}
//接受一个字节数据
u8 OLED_Iic_Rcv_Byte(void)
{
u8 i, data = 0; //0 0 0 0 0 0 0 0 比如有数据:1 1 0 0 1 0 0 0
OLED_Iic_Sda_Mode(GPIO_Mode_IN);
OLED_SCL = 0;
//0 1 1 1 1 0 0 0
for(i=0; i<8; i++)
{
delay_us(5);
OLED_SCL = 1;
delay_us(5);
//接受数据
if(OLED_SDA_IN == 1) //引脚为电平为1
{
data |= (1<<(7-i));
}
OLED_SCL = 0;
}
return data;
}
void I2C_WriteByte(uint8_t addr,uint8_t data)
{
u8 ack;
// I2C_GenerateSTART(I2C1, ENABLE);//开启I2C1
// while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/
//启动信号
OLED_Iic_Start();
// I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);//器件地址 -- 默认0x78
// while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
OLED_Iic_Send_Byte(OLED_ADDRESS);
ack = OLED_Iic_Rcv_Ack();
if(ack == 1)
{
printf("ack failuren");
return ;
}
// I2C_SendData(I2C1, addr);//寄存器地址
// while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
OLED_Iic_Send_Byte(addr);
ack = OLED_Iic_Rcv_Ack();
if(ack == 1)
{
printf("ack failuren");
return ;
}
// I2C_SendData(I2C1, data);//发送数据
// while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
OLED_Iic_Send_Byte(data);
ack = OLED_Iic_Rcv_Ack();
if(ack == 1)
{
printf("ack failuren");
return ;
}
// I2C_GenerateSTOP(I2C1, ENABLE);//关闭I2C1总线
OLED_Iic_Stop();
}
void WriteCmd(unsigned char I2C_Command)//写命令
{
I2C_WriteByte(0x00, I2C_Command);
}
void WriteDat(unsigned char I2C_Data)//写数据
{
I2C_WriteByte(0x40, I2C_Data);
}
void OLED_Init(void)
{
delay_ms(100); //这里的延时很重要
WriteCmd(0xAE); //display off
WriteCmd(0x20); //Set Memory Addressing Mode
WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
WriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7
WriteCmd(0xc8); //Set COM Output Scan Direction
WriteCmd(0x00); //---set low column address
WriteCmd(0x10); //---set high column address
WriteCmd(0x40); //--set start line address
WriteCmd(0x81); //--set contrast control register
WriteCmd(0xff); //亮度调节 0x00~0xff
WriteCmd(0xa1); //--set segment re-map 0 to 127
WriteCmd(0xa6); //--set normal display
WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
WriteCmd(0x3F); //
WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
WriteCmd(0xd3); //-set display offset
WriteCmd(0x00); //-not offset
WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
WriteCmd(0xf0); //--set divide ratio
WriteCmd(0xd9); //--set pre-charge period
WriteCmd(0x22); //
WriteCmd(0xda); //--set com pins hardware configuration
WriteCmd(0x12);
WriteCmd(0xdb); //--set vcomh
WriteCmd(0x20); //0x20,0.77xVcc
WriteCmd(0x8d); //--set DC-DC enable
WriteCmd(0x14); //
WriteCmd(0xaf); //--turn on oled panel
}
void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标
{
WriteCmd(0xb0+y);
WriteCmd(((x&0xf0)>>4)|0x10);
WriteCmd((x&0x0f)|0x01);
}
void OLED_Fill(unsigned char fill_Data)//全屏填充
{
unsigned char m,n;
for(m=0;m<8;m++)
{
WriteCmd(0xb0+m); //page0-page1
WriteCmd(0x00); //low column start address
WriteCmd(0x10); //high column start address
for(n=0;n<128;n++)
{
WriteDat(fill_Data);
}
}
}
void OLED_CLS(void)//清屏
{
OLED_Fill(0x00);
}
//--------------------------------------------------------------
// Prototype : void OLED_ON(void)
// Calls :
// Parameters : none
// Description : 将OLED从休眠中唤醒
//--------------------------------------------------------------
void OLED_ON(void)
{
WriteCmd(0X8D); //设置电荷泵
WriteCmd(0X14); //开启电荷泵
WriteCmd(0XAF); //OLED唤醒
}
//--------------------------------------------------------------
// Prototype : void OLED_OFF(void)
// Calls :
// Parameters : none
// Description : 让OLED休眠 -- 休眠模式下,OLED功耗不到10uA
//--------------------------------------------------------------
void OLED_OFF(void)
{
WriteCmd(0X8D); //设置电荷泵
WriteCmd(0X10); //关闭电荷泵
WriteCmd(0XAE); //OLED休眠
}
//--------------------------------------------------------------
// Prototype : void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
// Calls :
// Parameters : x,y -- 起始点坐标(x:0~127, y:0~7); ch[] -- 要显示的字符串; TextSize -- 字符大小(1:6*8 ; 2:8*16)
// Description : 显示codetab.h中的ASCII字符,有6*8和8*16可选择
//--------------------------------------------------------------
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
{
unsigned char c = 0,i = 0,j = 0;
switch(TextSize)
{
case 1:
{
while(ch[j] != '