完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
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(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 } // 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 //开始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] != ' |