STM32
直播中

的乏味而

13年用户 801经验值
私信 关注
[问答]

如何实现基于stm32智能门锁系统的设计?

如何实现基于STM32智能门锁系统的设计?

回帖(1)

李晟才

2021-12-13 09:48:21
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] != '')
                        {
                                c = ch[j] - 32;
                                if(x > 126)
                                {
                                        x = 0;
                                        y++;
                                }
                                OLED_SetPos(x,y);
                                for(i=0;i<6;i++)
                                        WriteDat(F6x8[c]);
                                x += 6;
                                j++;
                        }
                }break;
                case 2:
                {
                        while(ch[j] != '')
                        {
                                c = ch[j] - 32;
                                if(x > 120)
                                {
                                        x = 0;
                                        y++;
                                }
                                OLED_SetPos(x,y);
                                for(i=0;i<8;i++)
                                        WriteDat(F8X16[c*16+i]);
                                OLED_SetPos(x,y+1);
                                for(i=0;i<8;i++)
                                        WriteDat(F8X16[c*16+i+8]);
                                x += 8;
                                j++;
                        }
                }break;
        }
}


//--------------------------------------------------------------
// Prototype      : void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
// Calls          :
// Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7); N:汉字在codetab.h中的索引
// Description    : 显示codetab.h中的汉字,16*16点阵
//--------------------------------------------------------------
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
        unsigned char wm=0;
        unsigned int  adder=32*N;
        OLED_SetPos(x , y);//       
        for(wm = 0;wm < 16;wm++)
        {
                WriteDat(F16x16[adder]);
                adder += 1;
        }
        OLED_SetPos(x,y + 1);
        for(wm = 0;wm < 16;wm++)
        {
                WriteDat(F16x16[adder]);
                adder += 1;
        }
}




//void OLED_ShowCN1(unsigned char x, unsigned char y, unsigned char N)
//{
//        unsigned char wm=0;
//        unsigned int  adder=32*N;
//        OLED_SetPos(x , y);//       
//        for(wm = 0;wm < 16;wm++)
//        {
//                WriteDat(E16x16[adder]);
//                adder += 1;
//        }
//        OLED_SetPos(x,y + 1);
//        for(wm = 0;wm < 16;wm++)
//        {
//                WriteDat(E16x16[adder]);
//                adder += 1;
//        }
//}
//--------------------------------------------------------------
// Prototype      : void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]);
// Calls          :
// Parameters     : x0,y0 -- 起始点坐标(x0:0~127, y0:0~7); x1,y1 -- 起点对角线(结束点)的坐标(x1:1~128,y1:1~8)
// Description    : 显示BMP位图
//--------------------------------------------------------------
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
{
        unsigned int j=0;
        unsigned char x,y;


  if(y1%8==0)
                y = y1/8;
  else
                y = y1/8 + 1;
        for(y=y0;y         {
                OLED_SetPos(x0,y);
    for(x=x0;x                 {
                        WriteDat(BMP[j++]);
                }
        }
}




显示登陆界面
//void load_shou(void)
//{
//                unsigned char i;
//       
//        Delay_Init();
//        I2C_Configuration();
//        OLED_Init();       
//       
//                OLED_Fill(0xFF);//全屏点亮
//               
//                delay_ms(500);
//                OLED_Fill(0x00);//全屏灭
//                delay_ms(500);       
//                delay_ms(500);
//               
//                for(i=0;i<5;i++)
//                {
//                        OLED_ShowCN1(29+i*16,11,i);//测试显示中文
//                }
//                OLED_OFF();//测试OLED休眠
//                delay_ms(500);
//                delay_ms(500);
//                delay_ms(500);
//                delay_ms(500);
//                OLED_ON();//测试OLED休眠后唤醒
//                delay_ms(500);
//                delay_ms(500);
//                delay_ms(500);
//                delay_ms(500);
//}


//显示主界面
void Show_main(void)
{
                unsigned char i;
       
        Delay_Init();
        I2C_Configuration();
        OLED_Init();       
       
                OLED_Fill(0xFF);//全屏点亮
               
                delay_ms(500);
                OLED_Fill(0x00);//全屏灭
                delay_ms(500);       
                delay_ms(500);
               
                for(i=0;i<5;i++)
                {
                        OLED_ShowCN(29+i*16,11,i);//测试显示中文
                }
                delay_ms(500);
                delay_ms(500);
                delay_ms(500);
                delay_ms(500);
                                OLED_OFF();//测试OLED休眠
                delay_ms(500);
                delay_ms(500);
                delay_ms(500);
                delay_ms(500);
                OLED_ON();//测试OLED休眠后唤醒
                delay_ms(500);
                delay_ms(500);
                delay_ms(500);
                delay_ms(500);
}


//输入密码解锁界面
void show_unlock()
{
        OLED_Fill(0x00);//全屏灭
        delay_ms(500);
       
        OLED_ShowStr(0,3,(unsigned char *)"Please input password",1);//测试8*16字符
}
//密码正确
void show_right()
{
        OLED_Fill(0x00);//全屏灭
        delay_ms(500);
       
        OLED_ShowStr(45,3,(unsigned char *)"Right!",2);//测试8*16字符
}
//刷卡失败
void show_RFID_Failer()
{
        OLED_Fill(0x00);//全屏灭
        delay_ms(500);
       
        OLED_ShowStr(45,3,(unsigned char *)"Error!",2);//测试8*16字符
}


//刷卡成功
void show_RFID_Success()
{
        OLED_Fill(0x00);//全屏灭
        delay_ms(500);
       
        OLED_ShowStr(45,3,(unsigned char *)"Open Door",2);//测试8*16字符
}




//密码错误
void show_error()
{
        OLED_Fill(0x00);//全屏灭
        delay_ms(500);
       
        OLED_ShowStr(45,3,(unsigned char *)"Error!",2);//测试8*16字符
}
//0.返回(显示)
void set_return()
{
        OLED_Fill(0x00);//全屏灭
        delay_ms(500);
       
        //返回(显示)
        for(int i=11; i<15 ;i++)
        {
                OLED_ShowCN(0+(i-11)*16,0,i);//测试显示中文
        }
        OLED_ShowStr(8,0,(unsigned char *)"0",2);//测试8*16字符
}
//1.密码修改(显示)
void set_password()
{
        //密码修改(显示)
        for(int i=15; i<21 ;i++)
        {
                OLED_ShowCN(0+(i-15)*16,2,i);//测试显示中文
        }
        OLED_ShowStr(8,2,(unsigned char *)"1",2);//测试8*16字符
}


//2.添加指纹(显示)
void set_add()
{
        //添加指纹(显示)
        for(int i=21; i<27 ;i++)
        {
                OLED_ShowCN(0+(i-21)*16,4,i);//测试显示中文
        }
        OLED_ShowStr(8,4,(unsigned char *)"2",2);//测试8*16字符
}


//3.删除指纹(显示)
void set_delete()
{       
        //删除指纹(显示)
        for(int i=27; i<33 ;i++)
        {
                OLED_ShowCN(0+(i-27)*16,6,i);//测试显示中文
        }
        OLED_ShowStr(8,6,(unsigned char *)"3",2);//测试8*16字符
}


//展示设置界面
void show_set()
{
        set_return();//返回显示
        set_password();//修改密码显示
        set_add();//添加指纹显示
        set_delete();//删除指纹显示
}


//请按下手指界面
void show_please_press()
{
        OLED_Fill(0x00);//全屏灭
        //delay_ms(500);
       
        OLED_ShowStr(20,4,(unsigned char *)"Please press",2);//测试8*16字符
}


//请再次按下手指界面
void show_press_again()
{
        OLED_Fill(0x00);//全屏灭
        //delay_ms(500);
       
        OLED_ShowStr(20,2,(unsigned char *)"Please press",2);//测试8*16字符
        OLED_ShowStr(30,4,(unsigned char *)"again",2);//测试8*16字符
}

.h文件
#ifndef __OLED_I2C_H
#define        __OLED_I2C_H


#include "stm32f4xx.h"




#define OLED_SCL                  PEout(8)
#define OLED_SDA_IN                PEin(10)
#define OLED_SDA_OUT        PEout(10)






#define OLED_ADDRESS        0x78 //通过调整0R电阻,屏可以0x78和0x7A两个地址 -- 默认0x78


void I2C_Configuration(void);
void I2C_WriteByte(uint8_t addr,uint8_t data);
void WriteCmd(unsigned char I2C_Command);
void WriteDat(unsigned char I2C_Data);
void OLED_Init(void);
void OLED_SetPos(unsigned char x, unsigned char y);
void OLED_Fill(unsigned char fill_Data);
void OLED_CLS(void);
void OLED_ON(void);
void OLED_OFF(void);
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize);
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N);
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]);


#endif
7、 4x4按键

①按键原理图











有4根线控制行、4根线控制列,然后实现16个按键的功能
②、代码实现


//.c文件
#include "key.h"
#include "delay.h"
#include "sys.h"


/*
C4-->PE6
C3-->PB6
C2-->PC9
C1-->PC7


R1-->PC6
R2-->PC8
R3-->PC11
R4-->PE5
*/
extern u8 flag;
void Key_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        //打开GPIOC时钟
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
        //打开GPIOB时钟
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
        //打开GPIOE时钟
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
       
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;//输出模式
        GPIO_InitStructure.GPIO_OType=GPIO_OType_OD;//开漏
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_6|GPIO_Pin_7;//6 7 8 9引脚
        GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉
        GPIO_Init(GPIOC, &GPIO_InitStructure);
        GPIO_SetBits(GPIOC, GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9);//将所有的按键的电平置位
       
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;//6引脚
        GPIO_Init(GPIOB, &GPIO_InitStructure);
        GPIO_SetBits(GPIOB, GPIO_Pin_6);//将所有的按键的电平置位
       
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_6;//5 6引脚
        GPIO_Init(GPIOE, &GPIO_InitStructure);
        GPIO_SetBits(GPIOE, GPIO_Pin_5|GPIO_Pin_6);//将所有的按键的电平置位
       
}


//判断是哪个按键按下函数
u8 Key_Press(void)
{
        while(1)
        {
                //第四列
                C4 = 0;
                //读取各列的值
                if(R1 == 0)//第一行
                {
                        delay_ms(10);//按键消抖
                        if(R1 == 0)
                        {
                                C4 = 1;
                                //第一行第四列按下
                                return 4;
                        }
                }
                if(R2 == 0)//第二行
                {
                        delay_ms(10);//按键消抖
                        if(R2 == 0)
                        {
                                C4 = 1;
                                //第二行第四列按下
                                return 8;
                        }
                }
                if(R3 == 0)//第三行
                {
                        delay_ms(10);//按键消抖
                        if(R3 == 0)
                        {
                                C4 = 1;
                                //第三行第四列按下
                                return 12;
                        }
                }
                if(R4 == 0)//第四行
                {
                        delay_ms(10);//按键消抖
                        if(R4 == 0)
                        {
                                C4 = 1;
                                //第四行第四列按下
                                return 16;
                        }
                }
                C4 = 1;
               
                //第三列
                C3 = 0;
                //读取各列的值
                if(R1 == 0)//第一行
                {
                        delay_ms(10);//按键消抖
                        if(R1 == 0)
                        {
                                C4 = 1;
                                //第一行第三列按下
                                return 3;
                        }
                }
                if(R2 == 0)//第二行
                {
                        delay_ms(10);//按键消抖
                        if(R2 == 0)
                        {
                                C4 = 1;
                                //第二行第三列按下
                                return 7;
                        }
                }
                if(R3 == 0)//第三行
                {
                        delay_ms(10);//按键消抖
                        if(R3 == 0)
                        {
                                C4 = 1;
                                //第三行第三列按下
                                return 11;
                        }
                }
                if(R4 == 0)//第四行
                {
                        delay_ms(10);//按键消抖
                        if(R4 == 0)
                        {
                                C4 = 1;
                                //第四行第三列按下
                                return 15;
                        }
                }
                C3 = 1;
               
               
                //第二列
                C2 = 0;
                //读取各列的值
                if(R1 == 0)//第一行
                {
                        delay_ms(10);//按键消抖
                        if(R1 == 0)
                        {
                                C2 = 1;
                                //第一行第二列按下
                                return 2;
                        }
                }
                if(R2 == 0)//第二行
                {
                        delay_ms(10);//按键消抖
                        if(R2 == 0)
                        {
                                C2 = 1;
                                //第二行第二列按下
                                return 6;
                        }
                }
                if(R3 == 0)//第三行
                {
                        delay_ms(10);//按键消抖
                        if(R3 == 0)
                        {
                                C2 = 1;
                                //第三行第二列按下
                                return 10;
                        }
                }
                if(R4 == 0)//第四行
                {
                        delay_ms(10);//按键消抖
                        if(R4 == 0)
                        {
                                C2 = 1;
                                //第四行第二列按下
                                return 14;
                        }
                }
                C2 = 1;
               
               
                //第一列
                C1 = 0;
                //读取各列的值
                if(R1 == 0)//第一行
                {
                        delay_ms(10);//按键消抖
                        if(R1 == 0)
                        {
                                C1 = 1;
                                //第一行第一列按下
                                return 1;
                        }
                }
                if(R2 == 0)//第二行
                {
                        delay_ms(10);//按键消抖
                        if(R2 == 0)
                        {
                                C1 = 1;
                                //第二行第一列按下
                                return 5;
                        }
                }
                if(R3 == 0)//第三行
                {
                        delay_ms(10);//按键消抖
                        if(R3 == 0)
                        {
                                C1 = 1;
                                //第三行第一列按下
                                return 9;
                        }
                }
                if(R4 == 0)//第四行
                {
                        delay_ms(10);//按键消抖
                        if(R4 == 0)
                        {
                                C1 = 1;
                                //第四行第一列按下
                                return 13;
                        }
                }
                C1 = 1;
        }
}
.h文件
//这里我使用的是位带操作,来实现的引脚配置
#ifndef __KEY_H
#define __KEY_H


#include "stm32f4xx.h"
/*


C4-->PE6               
C3-->PB6
C2-->PC9
C1-->PC7                       


R1-->PC6
R2-->PC8
R3-->PC11
R4-->PE5


*/
#define C4 PEout(6)
#define C3 PBout(6)
#define C2 PCout(9)
#define C1 PCout(7)


#define R1 PCin(6)
#define R2 PCin(8)
#define R3 PCin(11)
#define R4 PEin(5)




void Key_Init(void);
u8 Key_Press(void);




#endif
9、项目总结

通过调用这些函数,就可以实现智能门锁的系统开发,有需要源码的小伙伴,我阔以给你提供。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分