基于STM32无线智能门锁

一、介绍系统

1.功能介绍

本系统由指纹模块、RC522模块、矩阵键盘、LCD1602显示屏、ESP8266模块几个部分构成。该系统功能可以通过指纹、刷卡、输入密码和APP远程解锁这四种解锁开门的方式,并且APP将会记录门锁状态和各个模块解锁的次数。

2.系统软件框架图

二、模块程序

1.矩阵键盘初始化配置程序
//KEY初始化
void KEY_GPIO_Init(void)
{
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO |RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB , ENABLE); 
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);  //关闭JTAG模式 使A15,PB3,PB4变成普通IO口
}


//A15,B3,B4,B5为输出,B6,B7,B8,B9为输入
 void PA15_AND_PB3_5OUT_AND_PB6_9IN(void)
{
 
 GPIO_InitTypeDef  GPIO_InitStructure;
 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);	 //使能PA,PB端口时钟
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;				 // 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOA, &GPIO_InitStructure);					 //根据设定参数初始化GPIOC 
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;				 // 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOC 
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;				 //端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; 		 //下拉输入
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB

}


//A15,B3,B4,B5为输入,B6,B7,B8,B9为输出
 void PA15_AND_PB3_5IN_AND_PB6_9OUT(void)
{
 
 GPIO_InitTypeDef  GPIO_InitStructure;
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);	
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;				 // 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOA, &GPIO_InitStructure);					 //根据设定参数初始化GPIOC 
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;				 // 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOC 
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;				 //端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //下拉输入
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB

}


//消抖
void KEY_DELAY(void)
{
    u16 i = 10000;
	  while(i--);
}
2.矩阵键盘判断是否按下程序
//矩阵键盘初始化
u8 KEYSCAN(void)    
{ 
	   u8 temp = 0,num = 99;
	   PA15_AND_PB3_5OUT_AND_PB6_9IN(); //A15,B3,B4,B5为输出,B6,B7,B8,B9为输入
     GPIO_WriteBit(GPIOA,GPIO_Pin_15,1);	//A15输出高电平
	   GPIO_Write(GPIOB,(GPIO_ReadOutputData(GPIOB)|0X0038));     // B3,B4,B5输出高电平 
		 KEY_DELAY();//去抖动 
		 if((GPIO_ReadInputData(GPIOB) & 0X03C0 )!= 0) // B6,B7,B8,B9检测到高电平,说明有按键按下      
		 {                                                                                            
			  temp = (u8)((GPIO_ReadInputData(GPIOB) & 0X03C0) >> 2);  //   temp: XXXX 0000  temp: 0010 0000
			  PA15_AND_PB3_5IN_AND_PB6_9OUT(); //A15,B3,B4,B5为输入,B6,B7,B8,B9为输出
			  GPIO_Write(GPIOB,(GPIO_ReadOutputData(GPIOB)|0X03C0));//B6,B7,B8,B9输出高电平  
			  KEY_DELAY();//去抖动 
			  if((GPIO_ReadInputData(GPIOB) & 0X0038) != 0 || GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15))//A15,B3,B4,B5检测到高电平,说明有按键按下 
		    {
					 temp += (u8)((GPIO_ReadInputData(GPIOB) & 0X0038) >> 2) + GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15);// temp: XXXX XXXX  
					 //return temp;                                                                                    //  temp: 0000 0001  
					                                                                                                     
					 while((GPIO_ReadInputData(GPIOB) & 0X0038) != 0 || GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15));
					 
					 switch(temp)// temp数据对应引脚:B9,B8,B7,B6,B5,B4,B3,A15
					 {
						  case 33: num = 15; break;
						  case 36: num = 6; break;
						  case 65: num = 0; break;
						  case 66: num = 2; break;
						  case 68: num = 5; break;
						  case 24: num = 10; break;
						  case 20: num = 11; break;
						  case 132: num = 4; break;
						  case 130: num = 1; break;
						  case 18: num = 12; break;
						  case 34: num = 3; break;
						  case 17: num = 13; break;     
						  case 40: num = 9; break;
						  case 72: num = 8; break;
						  case 136: num = 7; break;    
						  case 129: num = 14; break;
						  default : break;
           }
					
				}	
           				
     }
		 
		   return num;	
}
3.LCD1602模块程序
u8 Dao_xu(u8 data)//倒叙函数
{
    u8 i = 0 ,temp = 0;;
	  
	  for(i = 0; i < 8; i++)
	 {
	   temp += (((data >> i) & 0x01) << (7 - i));
	 }
	 return temp;
}


/*------------------------------------------------
              写入命令函数
------------------------------------------------*/
 void LCD_Write_Com(unsigned char com) 
{                              
  LCD1602_RS=0;	 //命令
	delay_us(1);
  LCD1602_RW=0;
  delay_us(1);
  LCD1602_EN=1;                  
	delay_us(1);
  GPIO_Write(GPIOA,(GPIO_ReadOutputData(GPIOA)&0XFF00)+Dao_xu(com)); //在不影响A8-A15引脚的前提下,把数据写到A0-A7引脚     
	delay_us(100);
  LCD1602_EN=0;
}

/*------------------------------------------------
              写入数据函数
------------------------------------------------*/
 void LCD_Write_Data(unsigned char Data) 
{                                  
  LCD1602_RS=1;   //数据              
	delay_us(1);
  LCD1602_RW=0;
  delay_us(1);	
  LCD1602_EN=1;                  
	delay_us(1);
  GPIO_Write(GPIOA,(GPIO_ReadOutputData(GPIOA)&0XFF00)+Dao_xu(Data)); //在不影响A8-A15引脚的前提下,把数据写到A0-A7引脚   
	delay_us(100);
  LCD1602_EN=0;
}
/*------------------------------------------------
              写入字符串函数
------------------------------------------------*/
 void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s) 
 {     
 if (y == 0) 
 	{     
	 LCD_Write_Com(0x80 + x);  //第一行   
 	}
 else 
 	{     
 	LCD_Write_Com(0xC0 + x);  //第二行   
 	}        
	while (*s) //判断是否检测到结尾符 
 	{     
		 LCD_Write_Data( *s);//显示字符     
		 s ++;  //指针加1   
 	}
 }
/*------------------------------------------------
              写入字符函数
------------------------------------------------*/
 void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data) 
 {     
 if (y == 0) 
 	{     
 	LCD_Write_Com(0x80 + x);    //第一行    
 	}    
 else 
 	{     
 	LCD_Write_Com(0xC0 + x);  //第二行     
 	}        
 LCD_Write_Data( Data); //显示字符      
 }
 

 /*------------------------------------------------
                清屏函数
------------------------------------------------*/
 void LCD_Clear(void) 
 { 
 LCD_Write_Com(0x01); 
 delay_ms(5);
 }

/*------------------------------------------------*/
 void LCD_Init(void) 
{
	  GPIO_InitTypeDef GPIO_InitStructure;
	  
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE);  //开启GPIOA GPIOB GPIOC时钟
	  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 |
    GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出速度50MHZ
    GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA
	
	
	  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1;  // LCD1602 RS-RW-EN
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //输出速度50MHZ
    GPIO_Init(GPIOB, &GPIO_InitStructure);   //GPIOB
	
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;  // LCD1602 RS-RW-EN
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //输出速度50MHZ
    GPIO_Init(GPIOC, &GPIO_InitStructure);   //GPIOB
	
   LCD_Write_Com(0x38);
   delay_ms(5);  
	 LCD_Write_Com(0x38);
   delay_ms(5);  
	 LCD_Write_Com(0x38);
   delay_ms(5);  
   LCD_Write_Com(0x08);    /*显示关闭*/
   delay_ms(5); 	
   LCD_Write_Com(0x01);    /*显示清屏*/
   delay_ms(5); 	
   LCD_Write_Com(0x06);    /*显示光标移动设置*/ 
	 delay_ms(5); 
   LCD_Write_Com(0x0C);    /*显示开及光标设置*/
	 delay_ms(5); 
}
4.RC522初始化程序
void RC522_Init ( void )
{
	RC522_SPI_Config ();
	
	macRC522_Reset_Disable();
	
	macRC522_CS_Disable();

}

static void RC522_SPI_Config ( void )
{
  /* SPI_InitTypeDef  SPI_InitStructure */
  GPIO_InitTypeDef GPIO_InitStructure;
  

	/*!< Configure SPI_RC522_SPI pins: CS */
	macRC522_GPIO_CS_CLK_FUN ( macRC522_GPIO_CS_CLK, ENABLE );
  GPIO_InitStructure.GPIO_Pin = macRC522_GPIO_CS_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = macRC522_GPIO_CS_Mode;
  GPIO_Init(macRC522_GPIO_CS_PORT, &GPIO_InitStructure);
	
  /*!< Configure SPI_RC522_SPI pins: SCK */
	macRC522_GPIO_SCK_CLK_FUN ( macRC522_GPIO_SCK_CLK, ENABLE );
  GPIO_InitStructure.GPIO_Pin = macRC522_GPIO_SCK_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = macRC522_GPIO_SCK_Mode;
  GPIO_Init(macRC522_GPIO_SCK_PORT, &GPIO_InitStructure);
	
  /*!< Configure SPI_RC522_SPI pins: MOSI */
	macRC522_GPIO_MOSI_CLK_FUN ( macRC522_GPIO_MOSI_CLK, ENABLE );
  GPIO_InitStructure.GPIO_Pin = macRC522_GPIO_MOSI_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = macRC522_GPIO_MOSI_Mode;
  GPIO_Init(macRC522_GPIO_MOSI_PORT, &GPIO_InitStructure);

  /*!< Configure SPI_RC522_SPI pins: MISO */
	macRC522_GPIO_MISO_CLK_FUN ( macRC522_GPIO_MISO_CLK, ENABLE );
  GPIO_InitStructure.GPIO_Pin = macRC522_GPIO_MISO_PIN;
  GPIO_InitStructure.GPIO_Mode = macRC522_GPIO_MISO_Mode;
  GPIO_Init(macRC522_GPIO_MISO_PORT, &GPIO_InitStructure);	
	
	
  /*!< Configure SPI_RC522_SPI pins: RST */
	macRC522_GPIO_RST_CLK_FUN ( macRC522_GPIO_RST_CLK, ENABLE );
  GPIO_InitStructure.GPIO_Pin = macRC522_GPIO_RST_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = macRC522_GPIO_RST_Mode;
  GPIO_Init(macRC522_GPIO_RST_PORT, &GPIO_InitStructure);
	
}

5.指纹模块AS608程序

#define STM32_RX1_BUF       Usart1RecBuf 
#define STM32_Rx1Counter    RxCounter
#define STM32_RX1BUFF_SIZE  USART1_RXBUFF_SIZE

 unsigned char AS608_RECEICE_BUFFER[24];//指纹数据存储数组

//FINGERPRINT通信协议定义
 unsigned char AS608_Pack_Head[6] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF};  //协议包头
 unsigned char AS608_Get_Img[6] = {0x01,0x00,0x03,0x01,0x0,0x05};    //获得指纹图像
 unsigned char FP_Search[11]= {0x01,0x0,0x08,0x04,0x01,0x0,0x0,0x03,0xA1,0x0,0xB2}; //搜索指纹搜索范围0 - 929
 unsigned char FP_Img_To_Buffer1[7]= {0x01,0x0,0x04,0x02,0x01,0x0,0x08}; //将图像放入到BUFFER1
 unsigned char FP_Img_To_Buffer2[7]= {0x01,0x0,0x04,0x02,0x02,0x0,0x09}; //将图像放入到BUFFER2
 unsigned char FP_Reg_Model[6]= {0x01,0x0,0x03,0x05,0x0,0x09}; //将BUFFER1跟BUFFER2合成特征模版
 unsigned char FP_Delet_All_Model[6]= {0x01,0x0,0x03,0x0d,0x00,0x11}; //删除指纹模块里所有的模版
 unsigned char  FP_Save_Finger[9]= {0x01,0x00,0x06,0x06,0x01,0x00,0x0B,0x00,0x19}; //将BUFFER1中的特征码存放到指定的位置
 unsigned char  FP_Delete_Model[10]= {0x01,0x00,0x07,0x0C,0x0,0x0,0x0,0x1,0x0,0x0}; //删除指定的模版

	    
//读出感应状态(有指纹按下时,输出高电平)
void PS_StaGPIO_Init(void)
{   
		GPIO_InitTypeDef  GPIO_InitStructure;
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//时钟开启

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//下拉输入
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
		GPIO_Init(GPIOC, &GPIO_InitStructure);
} 

unsigned char uart_recv(unsigned char *bufs, unsigned short timeout)//接收数据
{
    unsigned char i;
		unsigned short	RX_TimeOut;

    RX_TimeOut = timeout;
		
    do
    {
        delay_ms(1);
        if(RX_TimeOut > 0)		//超时计数
        {
            if(--RX_TimeOut == 0)//等待时间到
            {
                unsigned char ret;

                ret = STM32_Rx1Counter;//获取字节数
                if(STM32_Rx1Counter > 0)
                {
                    for(i=0; i<STM32_Rx1Counter; i++)
                    {
                        *bufs = STM32_RX1_BUF[i];
                        bufs ++;
                    }
                }
                STM32_Rx1Counter = 0;
                return ret;//返回字节数,并跳出while
            }
        }
    }
    while(1);
}
 
/*------------------ FINGERPRINT命令字 --------------------------*/
//接收反馈数据缓冲
unsigned char  AS608_Receive_Data(void)
{
	  memset(AS608_RECEICE_BUFFER,0,24);//清空数据
    return uart_recv(AS608_RECEICE_BUFFER,1000);
}

void AS608_Cmd_Send_Pack_Head(void) //发送包头
{
    uart1_send(AS608_Pack_Head,6);
}

//FINGERPRINT_获得指纹图像命令判断接收到的确认码,等于0指纹获取成功
unsigned char AS608_Cmd_Get_Img(void)
{
    AS608_Cmd_Send_Pack_Head(); //发送通信协议包头
    uart1_send(AS608_Get_Img,6);
    if (AS608_Receive_Data() > 0)
    {
        return AS608_RECEICE_BUFFER[9];
    }
    else
    {
        return 0xFE;
    }
}

//讲图像转换成特征码存放在Buffer1中
unsigned char  FINGERPRINT_Cmd_Img_To_Buffer1(void)
{
    AS608_Cmd_Send_Pack_Head(); //发送通信协议包头
    uart1_send(FP_Img_To_Buffer1,7);//发送命令 将图像转换成 特征码 存放在 CHAR_buffer1
    if (AS608_Receive_Data() > 0)
    {
        return AS608_RECEICE_BUFFER[9];
    }
    else
    {
        return 0xFE;
    }
}

//将图像转换成特征码存放在Buffer2中
unsigned char  FINGERPRINT_Cmd_Img_To_Buffer2(void)
{
    AS608_Cmd_Send_Pack_Head(); //发送通信协议包头
    uart1_send(FP_Img_To_Buffer2,7);
    if (AS608_Receive_Data() > 0)
    {
        return AS608_RECEICE_BUFFER[9];
    }
    else
    {
        return 0xFE;
    }
}

//将BUFFER1 跟 BUFFER2 中的特征码合并成指纹模版
unsigned char FINGERPRINT_Cmd_Reg_Model(void)
{
    AS608_Cmd_Send_Pack_Head(); //发送通信协议包头
    uart1_send(FP_Reg_Model,6);
    if (AS608_Receive_Data() > 0)
    {
        return AS608_RECEICE_BUFFER[9];
    }
    else
    {
        return 0xFE;
    }
}

//删除指纹模块里的所有指纹模版
unsigned char FINGERPRINT_Cmd_Delete_All_Model(void)
{
    AS608_Cmd_Send_Pack_Head(); //发送通信协议包头
    uart1_send(FP_Delet_All_Model,6);
    if (AS608_Receive_Data() > 0)
    {
        return AS608_RECEICE_BUFFER[9];
    }
    else
    {
        return 0xFE;
    }
}

//删除指纹模块里的指定指纹模版
void FINGERPRINT_Cmd_Delete_Model(unsigned short uiID_temp)
{
    unsigned short uiSum_temp = 0;
    unsigned char i;

    FP_Delete_Model[4]=(uiID_temp&0xFF00)>>8;
    FP_Delete_Model[5]=(uiID_temp&0x00FF);

    for(i=0; i<8; i++)
        uiSum_temp = uiSum_temp + FP_Delete_Model[i];

    FP_Delete_Model[8]=(uiSum_temp&0xFF00)>>8;
    FP_Delete_Model[9]=uiSum_temp&0xFF;


    AS608_Cmd_Send_Pack_Head(); //发送通信协议包头
    uart1_send(FP_Delete_Model,10);
}

//搜索全部用户999枚
unsigned short FINGERPRINT_Cmd_Search_Finger(void)
{
    AS608_Cmd_Send_Pack_Head(); //发送通信协议包头
    uart1_send(FP_Search,11);
    if (AS608_Receive_Data() > 0 && AS608_RECEICE_BUFFER[9] == 0)
    {
        return (AS608_RECEICE_BUFFER[10]*256 + AS608_RECEICE_BUFFER[11]);
    }
    else
    {
        return 0xFFFE;
    }
}

unsigned char FINGERPRINT_Cmd_Save_Finger(unsigned short storeID)
{
    unsigned short temp = 0;
    unsigned char i;

    FP_Save_Finger[5] =(storeID&0xFF00)>>8;
    FP_Save_Finger[6] = (storeID&0x00FF);

    for(i=0; i<7; i++) //计算校验和
        temp = temp + FP_Save_Finger[i];

    FP_Save_Finger[7]=(temp & 0xFF00) >> 8; //存放校验数据
    FP_Save_Finger[8]= temp & 0xFF;

    AS608_Cmd_Send_Pack_Head(); //发送通信协议包头

    uart1_send(FP_Save_Finger,9);
    if (AS608_Receive_Data() > 0)
    {
        return AS608_RECEICE_BUFFER[9];
    }
    else
    {
        return 0xFE;
    }
}

//返回指纹ID 0xFFFE错误
unsigned short AS608_Find_Fingerprint(void)
{
    if(AS608_Cmd_Get_Img() == 0)
    {
        delay_ms(100);
        if (FINGERPRINT_Cmd_Img_To_Buffer1() == 0)
        {
            return FINGERPRINT_Cmd_Search_Finger();
        }
    }
    return 0xFFFE;
}

//指纹添加新用户
unsigned short AS608_Add_Fingerprint(unsigned short ID)
{
    if(AS608_Cmd_Get_Img() == 0)
    {
        //delay_ms(100);
        if (FINGERPRINT_Cmd_Img_To_Buffer1() == 0)
        {
            if(AS608_Cmd_Get_Img() == 0)
            {
                //delay_ms(100);
                if (FINGERPRINT_Cmd_Img_To_Buffer2() == 0)
                {
                    if (FINGERPRINT_Cmd_Reg_Model() == 0)
                    {
                        return FINGERPRINT_Cmd_Save_Finger(ID) ;
                    }
                }
            }
        }
    }
    return 0xFFFE;
}
5.往STM32内部FLASH写入数据
void WRITE_IC_NUM_TO_FLASH(u8* ID_Buffer,u8 space)//IC卡号写入STM32内部FLASH
{
		  STMFLASH_Write(FLASH_SAVE_ADDR + 0x10 * space,(u16*)ID_Buffer,SIZE); 
      delay_ms(100);                             //内部FLASH寿命不长,防止误操作反复擦鞋
}

void READ_IC_NUM_FOR_FLASH(u8* ID_TEMP_Buffer ,u8 space)//从STM32内部FLASH读出IC卡号
{
		 STMFLASH_Read(FLASH_SAVE_ADDR + 0x10 * space,(u16*)ID_TEMP_Buffer,SIZE);
}
 
void WRITE_DATA_TO_FLASH(u8* ID_Buffer,u8 LEN)//密码写入STM32内部FLASH
{
		STMFLASH_Write(FLASH_SAVE_ADDR + 0x10*MAX_PEOPLE*2,(u16*)ID_Buffer,LEN); 
    delay_ms(100);                             //内部FLASH寿命不长,防止误操作反复擦写
}

void READ_DATA_FOR_FLASH(u8* ID_TEMP_Buffer ,u8 LEN)//从STM32内部FLASH读出密码
{
		STMFLASH_Read(FLASH_SAVE_ADDR + 0x10*MAX_PEOPLE*2,(u16*)ID_TEMP_Buffer,LEN);
}

void CHECK_NEW_MCU(void)  // 检查是否是新的单片机,是的话清空存储区,否则保留
{
	  u8 comper_str[6],i=0;
    u8 clear_str[10] = {0};
		memset(clear_str,'0',sizeof(clear_str));//把clear_str这个数组全部清 ‘0’
	  STMFLASH_Read(FLASH_SAVE_ADDR,(u16*)comper_str,5); //从0X0801F010这个地址读出数据 
	  comper_str[5] = '\0';
	  if(strstr((char*)comper_str,"FDYDZ") == NULL)  //新的单片机
		{
			 WRITE_DATA_TO_FLASH(initpassword,6); //单片机第一次使用时,密码为6个0
			 for(i = 0; i < MAX_PEOPLE; i++)//把存卡内部缓存全部清零
			 {
					WRITE_IC_NUM_TO_FLASH(clear_str,i);//存IC的地址内容全部清零
			 }
			 STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)"FDYDZ",5); //写入“FDYDZ”,方便下次校验
	  }
		READ_DATA_FOR_FLASH(CurrentPassword,6); 					//从STM32内部FLASH里读出存储密码
}
6.ESP8266初始化程序
//==========================================================
//	函数名称:	ESP8266_Init
//
//	函数功能:	初始化ESP8266
//
//	入口参数:	无
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void ESP8266_Init(void)
{
	
	ESP8266_Clear();
	
	while(ESP8266_SendCmd("AT\r\n", "OK"))
		 delay_ms(500);

	ESP8266_SendCmd("AT+RST\r\n", "");
		delay_ms(500);
	ESP8266_SendCmd("AT+CIPCLOSE\r\n", "");
		delay_ms(500);
	
	while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))
		delay_ms(500);

	while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK"))
		delay_ms(500);

	while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))
		delay_ms(500);

	while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "CONNECT"))
		delay_ms(500);

}
7.继电器和蜂鸣器初始化程序
#define BEEP  PCout(13)	
#define RELAY PBout(12)	


void BEEP_AND_RELAY_GPIO_Init(void)
{

		GPIO_InitTypeDef  GPIO_InitStructure;
 	
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE);	 //使能PB端口时钟

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;				 // 端口配置
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; 		 //推挽输出
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
		GPIO_Init(GPIOB, &GPIO_InitStructure);			
		GPIO_ResetBits(GPIOB,GPIO_Pin_12);	//输出低电平
	
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;				 // 端口配置
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
		GPIO_Init(GPIOC, &GPIO_InitStructure);			
		GPIO_ResetBits(GPIOC,GPIO_Pin_13);	//输出低电平
}

三、核心执行程序

1.矩阵按键核心程序
//==========================确认键,并通过相应标志位执行相应功能===============================
void Ensure(void)
{
	  if(PressNum == 6)//必须输入6位数密码才有效
		{
			  if((InputData[0]==0)&&(InputData[1]==3)&&(InputData[2]==1)&&(InputData[3]==4)&&(InputData[4]==0)&&(InputData[5]==6))//031406密码初始化为000000
				{
						WRITE_DATA_TO_FLASH(initpassword,6);  				// 强制将初始密码写入STM32内部存储
					  delay_ms(100);
					  READ_DATA_FOR_FLASH(CurrentPassword,6); 			//从STM32内部FLASH里读出存储密码
					  LCD_Write_String(0,1,"Init password...");
					  BEEP = 1;
					  delay_ms(1000);
					  BEEP = 0;
						LCD_Write_String(0,1,"password:       ");
						LCD_Write_Com(0x80+0x40+9);
						LCD_Write_Com(0x0F);//光标闪烁
				}
				else if((InputData[0]==0)&&(InputData[1]==3)&&(InputData[2]==1)&&(InputData[3]==4)&&(InputData[4]==0)&&(InputData[5]==7))//031407注册指纹、注册卡、删除卡
				{
								LCD_Write_String(0,1,"                ");
								LCD_Write_String(0,2,"    manager     ");
								BuzzerRingsNum(2);				//提示音,响两声
								zc=1;
				}
				
				else if((InputData[0]==0)&&(InputData[1]==3)&&(InputData[2]==1)&&(InputData[3]==4)&&(InputData[4]==0)&&(InputData[5]==8))//031408指纹清空
				{
					  if (FINGERPRINT_Cmd_Delete_All_Model() == 0)
						{
								LCD_Write_String(0,1," clear finger ok");
								BuzzerRingsNum(2);				//提示音,响两声
						}
						user_id = 0;
						delay_ms(1000);
						InitDisplay = 1;
				}
				
				else
				{
						if((InputData[0]==CurrentPassword[0])&&(InputData[1]==CurrentPassword[1])&&(InputData[2]==CurrentPassword[2])&&  
							 (InputData[3]==CurrentPassword[3])&&(InputData[4]==CurrentPassword[4])&&(InputData[5]==CurrentPassword[5]))  //密码匹配正确
						{ 
							  CorrectCont++;
							
/*==========================按键解锁成功==========================*/
							
							  if(CorrectCont==1)		//正确输入计数,当只有一次正确输入时,开锁,
								{
										LCD_Write_String(0,1,"      open      ");  //显示开锁
									
										Sample_Upload_Fun(3);
									
										RELAY = 1; 					//继电器开启
										RELAY_TIME = 15; 		//继电器开启15秒
										pass = 1;						//密码正确标志
										BuzzerRingsNum(2);				//提示音,响两声
								}
								else              	//当两次正确输入时,开启重置密码功能
								{
										LCD_Write_String(0,1,"SetNewWordEnable");
									  BuzzerRingsNum(2);				//提示音,响两声
									  ReInputEn=1;									//允许重置密码输入
										CorrectCont=0;									//正确计数器清零
								}
						}
						else
						{
							  ErrorCont++;
							  LCD_Write_String(0,1,"      error     "); //显示错误
							  if(ErrorCont==3)//错误输入计数达三次时,报警
								{
									   do
										{
											  LCD_Write_String(0,1,"Keyboard Locked!");
											  RELAY=0;					//关闭锁
												BEEP = !BEEP;
												delay_ms(55);
										}while(1);
								}
								else
								{
									  /密码输错一次,蜂鸣器长响一声
									  BEEP=1;
										delay_ms(1000);
									  BEEP=0;
										LCD_Write_String(0,1,"password:       ");
										LCD_Write_Com(0x80+0x40+9);
										LCD_Write_Com(0x0F);//光标闪烁
								}
						}
				}
				DataInit();  //将输入数据计数器清零,为下一次输入作准备
		}
}
2.指纹模块核心程序
void  finger_ctrl(void)
{
    u8 ret;
    if(PS_Sta == 1)//感应到有手指按上去
		{
				if (RegFingerprint == 1)//指纹录入
				{
						ret = AS608_Add_Fingerprint(user_id);//指纹添加新用户
						if (ret== 0)
						{
								user_id ++;
								if (user_id > 9)//最多录9个指纹
										user_id = 0;

								display_user_id();//显示
								BuzzerRingsNum(1);//蜂鸣器响
						}
				}
				if (RegFingerprint ==0)
				{
						unsigned short ret_userid = 0;

						ret_userid = AS608_Find_Fingerprint();//扫描指纹
					
/*==========================指纹解锁成功==========================*/
					
						if (ret_userid != 0xFFFE)//说明识别到指纹
						{
								LCD_Write_String(0,1,"      open      ");  //显示开锁
							
								Sample_Upload_Fun(1);
							
								RELAY = 1; 					//继电器开启
								RELAY_TIME = 15; 		//继电器开启15秒
								pass = 1;						//密码正确标志
								BuzzerRingsNum(2);				//提示音,响两声
						}
						else 
						{
							ErrorCont++;
							LCD_Write_String(0,1,"      error     "); //显示错误
							if(ErrorCont==3)//错误输入计数达三次时,报警
							{
									 do
									{
											LCD_Write_String(0,1,"Keyboard Locked!");
											RELAY=0;					//关闭锁
											BEEP = !BEEP;
											delay_ms(55);
									}while(1);
							}
							else
							{
									/密码输错一次,蜂鸣器长响一声
									BEEP=1;
									delay_ms(1000);
									BEEP=0;
									LCD_Write_String(0,1,"password:       ");
									LCD_Write_Com(0x80+0x40+9);
									LCD_Write_Com(0x0F);//光标闪烁
							}	
						}
				}
		}
}
3.RC522核心程序
//正常待机刷卡函数
void COMPER_ID_MODE(void)
{
		 if(RC522_SCAN(ID_BUF)) //检测到有卡刷入
		 {  
			 u8 i = 0;
			 ICpass = 0;
			 LCD_Write_Com(0x0C);//关闭光标
			 LCD_Write_String(0,1," IC:             ");
			 LCD_Write_String(4,1,ID_BUF);//显示卡号
			 BEEP = 1; //蜂鸣器响
			 delay_ms(500);
			 BEEP = 0;
       			 
			 for(i = 0; i < MAX_PEOPLE; i++)//从5张IC卡中扫描
			 {
					READ_IC_NUM_FOR_FLASH(ID_TEMP_Buffer,i);//读取STM32内部FLASH存储的卡号
				 
/*==========================FRID解锁成功==========================*/
					if(strstr((char*)ID_TEMP_Buffer,(char*)ID_BUF) != NULL ) //查找匹配正确
					{
						 LCD_Write_String(0,1,"      open      ");  //显示开锁
						
						 Sample_Upload_Fun(2);
						
						 RELAY = 1; 					//继电器开启
						 RELAY_TIME = 15; 		//继电器开启15秒
						 ICpass = 1;						//IC正确标志	
						 ErrorCont=0;						
						 break;  
					}
					
					else
					{
						ICpass = 0;
					}
			 }
			 if(ICpass == 0)
			 {
					ErrorCont++;
					LCD_Write_String(0,1,"      error     "); //显示错误
					if(ErrorCont==3)//错误输入计数达三次时,报警
					{
							 do
							{
									LCD_Write_String(0,1,"Keyboard Locked!");
									RELAY=0;					//关闭锁
									BEEP = !BEEP;
									delay_ms(55);
							}while(1);
					}
					else
					{
							/密码输错一次,蜂鸣器长响一声
							BEEP=1;
							delay_ms(1000);
							BEEP=0;
							LCD_Write_String(0,1,"password:       ");
							LCD_Write_Com(0x80+0x40+9);
							LCD_Write_Com(0x0F);//光标闪烁
					}	
					//break;			
				  InitDisplay = 1;
			 }
		 }
}

4.APP远程开门函数

void OneNet_RevPro(unsigned char *cmd)
{
	
	MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};								//协议包
	
	char *req_payload = NULL;
	char *cmdid_topic = NULL;
	
	unsigned short topic_len = 0;
	unsigned short req_len = 0;
	
	unsigned char type = 0;
	unsigned char qos = 0;
	static unsigned short pkt_id = 0;
	
	short result = 0;

	char *dataPtr = NULL;
	char numBuf[10];
	int num = 0;
	
	type = MQTT_UnPacketRecv(cmd);
	switch(type)
	{
		case MQTT_PKT_CMD:															//命令下发
			
			result = MQTT_UnPacketCmd(cmd, &cmdid_topic, &req_payload, &req_len);	//解出topic和消息体
			if(result == 0)
			{
//				UsartPrintf(USART_DEBUG, "cmdid: %s, req: %s, req_len: %d\r\n", cmdid_topic, req_payload, req_len);
				
				if(MQTT_PacketCmdResp(cmdid_topic, req_payload, &mqttPacket) == 0)	//命令回复组包
				{
//					UsartPrintf(USART_DEBUG, "Tips:	Send CmdResp\r\n");
					
					ESP8266_SendData(mqttPacket._data, mqttPacket._len);			//回复命令
					MQTT_DeleteBuffer(&mqttPacket);									//删包
				}
			}
		
		break;
			
		case MQTT_PKT_PUBLISH:														//接收的Publish消息
		
			result = MQTT_UnPacketPublish(cmd, &cmdid_topic, &topic_len, &req_payload, &req_len, &qos, &pkt_id);
			if(result == 0)
			{
//				UsartPrintf(USART_DEBUG, "topic: %s, topic_len: %d, payload: %s, payload_len: %d\r\n",
//																	cmdid_topic, topic_len, req_payload, req_len);
				
				switch(qos)
				{
					case 1:															//收到publish的qos为1,设备需要回复Ack
					
						if(MQTT_PacketPublishAck(pkt_id, &mqttPacket) == 0)
						{
//							UsartPrintf(USART_DEBUG, "Tips:	Send PublishAck\r\n");
							ESP8266_SendData(mqttPacket._data, mqttPacket._len);
							MQTT_DeleteBuffer(&mqttPacket);
						}
					
					break;
					
					case 2:															//收到publish的qos为2,设备先回复Rec
																					//平台回复Rel,设备再回复Comp
						if(MQTT_PacketPublishRec(pkt_id, &mqttPacket) == 0)
						{
//							UsartPrintf(USART_DEBUG, "Tips:	Send PublishRec\r\n");
							ESP8266_SendData(mqttPacket._data, mqttPacket._len);
							MQTT_DeleteBuffer(&mqttPacket);
						}
					
					break;
					
					default:
						break;
				}
			}
		
		break;
			
		case MQTT_PKT_PUBACK:														//发送Publish消息,平台回复的Ack
		
			if(MQTT_UnPacketPublishAck(cmd) == 0)
//				UsartPrintf(USART_DEBUG, "Tips:	MQTT Publish Send OK\r\n");
			
		break;
			
		case MQTT_PKT_PUBREC:														//发送Publish消息,平台回复的Rec,设备需回复Rel消息
		
			if(MQTT_UnPacketPublishRec(cmd) == 0)
			{
//				UsartPrintf(USART_DEBUG, "Tips:	Rev PublishRec\r\n");
				if(MQTT_PacketPublishRel(MQTT_PUBLISH_ID, &mqttPacket) == 0)
				{
//					UsartPrintf(USART_DEBUG, "Tips:	Send PublishRel\r\n");
					ESP8266_SendData(mqttPacket._data, mqttPacket._len);
					MQTT_DeleteBuffer(&mqttPacket);
				}
			}
		
		break;
			
		case MQTT_PKT_PUBREL:														//收到Publish消息,设备回复Rec后,平台回复的Rel,设备需再回复Comp
			
			if(MQTT_UnPacketPublishRel(cmd, pkt_id) == 0)
			{
//				UsartPrintf(USART_DEBUG, "Tips:	Rev PublishRel\r\n");
				if(MQTT_PacketPublishComp(MQTT_PUBLISH_ID, &mqttPacket) == 0)
				{
//					UsartPrintf(USART_DEBUG, "Tips:	Send PublishComp\r\n");
					ESP8266_SendData(mqttPacket._data, mqttPacket._len);
					MQTT_DeleteBuffer(&mqttPacket);
				}
			}
		
		break;
		
		case MQTT_PKT_PUBCOMP:														//发送Publish消息,平台返回Rec,设备回复Rel,平台再返回的Comp
		
			if(MQTT_UnPacketPublishComp(cmd) == 0)
			{
//				UsartPrintf(USART_DEBUG, "Tips:	Rev PublishComp\r\n");
			}
		
		break;
			
		case MQTT_PKT_SUBACK:														//发送Subscribe消息的Ack
		
			if(MQTT_UnPacketSubscribe(cmd) == 0);
//				UsartPrintf(USART_DEBUG, "Tips:	MQTT Subscribe OK\r\n");
			else;
//				UsartPrintf(USART_DEBUG, "Tips:	MQTT Subscribe Err\r\n");
		
		break;
			
		case MQTT_PKT_UNSUBACK:														//发送UnSubscribe消息的Ack
		
			if(MQTT_UnPacketUnSubscribe(cmd) == 0);
//				UsartPrintf(USART_DEBUG, "Tips:	MQTT UnSubscribe OK\r\n");
			else;
//				UsartPrintf(USART_DEBUG, "Tips:	MQTT UnSubscribe Err\r\n");
		
		break;
		
		default:
			result = -1;
		break;
	}
	
	ESP8266_Clear();									//清空缓存
	
	if(result == -1)
		return;
	
	dataPtr = strchr(req_payload, '}');					//搜索'}'

	if(dataPtr != NULL && result != -1)					//如果找到了
	{
		dataPtr++;
		
		while(*dataPtr >= '0' && *dataPtr <= '9')		//判断是否是下发的命令控制数据
		{
			numBuf[num++] = *dataPtr++;
		}
		
		num = atoi((const char *)numBuf);				//转为数值形式
		
	}
	
	
	//判断下滑指令
	if(strstr((char *)req_payload, "flag:1"))  //开锁
	{
		LCD_Write_String(0,1,"      open      ");  //显示开锁
		RELAY = 1; 					
		pass = 1;						
		BuzzerRingsNum(2);			
	}
	else if(strstr((char *)req_payload, "flag:0"))  //关锁
	{
		Cancel();
	}
	
	

	if(type == MQTT_PKT_CMD || type == MQTT_PKT_PUBLISH)
	{
		MQTT_FreeBuffer(cmdid_topic);
		MQTT_FreeBuffer(req_payload);
	}

}

四、Android studio程序

这里只展示远程开门锁和接收各个模块开门锁的程序,连接OneNET程序这些前几个文章有说明,这里就不在说明了。

1.远程开门锁
    private void publishDataToMQTT() {
        String topic = "cmd/water";
        String payload = "flag:"+count;
        int qos = 1;

        try {
            MqttMessage message = new MqttMessage(payload.getBytes());
            message.setQos(qos);

            mqttClient.publish(topic, message);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }



Lock_open.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textView3.setText("开");
                if(count != 1) count=1;
                count_app++;
                View_App.setText("  "+count_app+"  次");
                publishDataToMQTT();
            }
        });

        //close-----0
        Lock_close.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textView3.setText("关");
                if(count != 0) count=0;
                publishDataToMQTT();
            }
        });
2.接收各个模块开门锁以及次数
public void messageArrived(String topic, MqttMessage message) throws Exception {
                    // 处理收到的消息
                    String data = new String(message.getPayload());

                    if(data.indexOf("fing")!=-1)
                    {
                        count_fing++;
                        count_open=1;
                    }

                    else if(data.indexOf("FRID")!=-1)
                    {
                        count_FRID++;
                        count_open=1;
                    }

                    else if(data.indexOf("Key")!=-1)
                    {
                        count_Key++;
                        count_open=1;
                    }
                    else if(data.indexOf("close")!=-1)
                    {
                        count_open=0;
                    }

                    if(count_open==0) textView3.setText("关");
                    else if(count_open==1) textView3.setText("开");
                    View_fingerprint.setText("  "+count_fing+"  次");
                    View_FRID.setText("  "+count_FRID+"  次");
                    View_Key.setText("  "+count_Key+"  次");

                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {
                    // 处理消息发送完成的情况
                }
            });
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }
3.APP界面展示

五、实验效果

  • 10
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值