• 【毕业设计】 stm32单片机的远程WIFI密码锁 - 物联网 嵌入式



    0 前言

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。

    为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天要分享的是

    🚩 基于stm32单片机的远程wifi密码锁

    🥇学长这里给一个题目综合评分(每项满分5分)

    • 难度系数:3分
    • 工作量:3分
    • 创新点:3分

    🧿 选题指导, 项目分享:

    https://gitee.com/dancheng-senior/project-sharing-1/blob/master/%E6%AF%95%E8%AE%BE%E6%8C%87%E5%AF%BC/README.md


    1 简介

    基于STM32单片机设计的一款物联网密码锁,采用MQTT协议连接物联网服务器进行交互,目前版本是本地动态密码锁。采用局域网方式完成网络连接,与门锁进行交互,通信设置,生成密码种子,进行动态密匙比对。

    主要器件

    • STM32单片机为主控制器
    • 触摸矩阵键盘
    • ESP8266无线wifi模块
    • 步进电机

    实现效果

    在这里插入图片描述
    在这里插入图片描述

    手机APP远程开锁

    在这里插入图片描述

    如果需要整个项目工程源码和全部资料可以从这里去下载:
    https://download.csdn.net/download/xiaolong1126626497/85895855

    4 硬件设计

    WIFI模块

    简介

    ESP8266 系列模组是深圳市安信可科技有限公司开发的一系列基于乐鑫ESP8266的低功耗UART-WiFi芯片模组,可以方便地进行二次开发,接入云端服务,实现手机3/4G全球随时随地的控制,加速产品原型设计。

    在这里插入图片描述

    ESP8266的指令介绍

    AT指令可以细分四种类型:
    1.测试指令:AT+=?
    该命令用于查询设置指令的参数以及取值的范围

    2.查询指令:AT+?
    该命令用于返回参数的当前值

    3.设置指令:AT+=<’’’>
    该命令用于设置用户自定义的参数

    4.执行指令:AT+
    该命令用于执行受模块内部程序控制的变参数不可变的功能
    在这里插入图片描述

    ESP8266的指令测试

    可以通过STM开发板转为电平转换的功能连接上ESP8266模块在通过串口显示窗口在PC机上热输入AT指令来进行操作。
    在这里插入图片描述

    ESP8266的AT指令一览

    在这里插入图片描述

    OLED显示屏

    OLED12864屏简介

    OLED 屏幕作为一种新型的显示技术,其自身可以发光,亮度,对比度高,功耗低,在当下备受追捧。而在我们正常的显示调整参数过程中,我们越来越多的使用这种屏幕。我们使用的一般是分辨率为 128x64 ,屏幕尺寸为 0.96 寸。由于其较小的尺寸和比较高的分辨率,让它有着很好的显示效果和便携性。

    基本参数

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    相关原理图

    image-20220408225751486

    硬件接线

    1. 板载ESP8266串口WIFI模块与STM32的串口3相连接。
    PB10--RXD 模块接收脚
    PB11--TXD 模块发送脚
    PB8---CH-PD---悬空
    PB9---RST---悬空
    GND---GND 地
    VCC---VCC 电源(3.3V~5.0V)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2. 触摸按键使用TTP229型号的驱动芯片
    SCL接PC11
    SDA-OUT接PC10
    电源接VCC-3.3
    GND接GND
    
    3. ULN2003控制28BYJ-48步进电机接线:
    
    ULN2003接线:
    IN4: PC9   d
    IN3: PC8   c
    IN2: PC7   b
    IN1: PC6   a
    +  : 5V
    -  : GND
    
    4. OLED显示屏
    D0----SCK-----PB14
    D1----MOSI----PB13
    RES—复位(低电平有效)—PB12
    DC---数据和命令控制管脚—PB1
    CS---片选引脚-----PA7
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    5. 板载按键
    KEY1---PA0 
    KEY2---PC13
    
    • 1
    • 2
    • 3

    6.板载LED灯
    LED1---PB5
    LED2---PB0
    LED3---PB1 
    
    7. 板载蜂鸣器
    BEEP---PA8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    5 软件说明

    开发环境介绍

    上位机软件采用Qt框架设计,Qt是一个跨平台的C++图形用户界面应用程序框架。Qt是一个1991年由Qt
    Company开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。简单来说,QT可以很轻松的帮你做带界面的软件,甚至不需要你投入很大精力。
    image-20220314143105032

    程序下载配置

    image-20220409014444075

    设备初始化打印的信息

    image-20220409014547898

    6 部分核心代码

    #include "stm32f10x.h"
    #include "led.h"
    #include "delay.h"
    #include "key.h"
    #include "usart.h"
    #include 
    #include "timer.h"
    #include "esp8266.h"
    #include "RFID_RC522.h"
    #include "motor.h"
    #include "oled.h"
    #include "rtc.h"
    #include  
    #include 
    
    
    char mqtt_message[200];//上报数据缓存区
    
    char SendBuff[10];
    
    //存放矩阵键盘的值
    char MatrixKey_var[20];
    int MatrixKey_index=0;
    
    //当前显示的页面
    u8 page_show_flag=0; //1时钟页面 
    
    
    /*
    函数功能: 绘制时钟表盘框架
    */
    void DrawTimeFrame(void)
    {
    	u8 i;
    	OLED_Circle(32,32,31);//画外圆
    	OLED_Circle(32,32,1); //画中心圆
    	//画刻度
    	for(i=0;i<60;i++)
    	{
    		if(i%5==0)OLED_DrawAngleLine(32,32,6*i,31,3,1);
    	}
    	OLED_RefreshGRAM();  //刷新数据到OLED屏幕
    }
    
    /*
    函数功能: 更新时间框架显示,在RTC中断里调用
    */
    char TimeBuff[20];
    void Update_FrameShow(void)
    {
        //如果正在显示其他提示文字,就不显示时钟
        if(page_show_flag==1)
        {
            return;
        }
            
    	/*1. 绘制秒针、分针、时针*/
    	OLED_DrawAngleLine2(32,32,rtc_clock.sec*6-6-90,27,0);//清除之前的秒针
    	OLED_DrawAngleLine2(32,32,rtc_clock.sec*6-90,27,1); //画秒针
    	
    	OLED_DrawAngleLine2(32,32,rtc_clock.min*6-6-90,24,0);
    	OLED_DrawAngleLine2(32,32,rtc_clock.min*6-90,24,1);
    	
    	OLED_DrawAngleLine2(32,32,rtc_clock.hour*30-6-90,21,0);
    	OLED_DrawAngleLine2(32,32,rtc_clock.hour*30-90,21,1);
    	
    	//绘制电子钟时间
    	sprintf(TimeBuff,"%d",rtc_clock.year);
    	OLED_ShowString(65,16*0,16,TimeBuff);  //年份字符串
    	OLED_ShowChineseFont(66+32,16*0,16,4); //显示年
    	
    	sprintf(TimeBuff,"%d/%d",rtc_clock.mon,rtc_clock.day);
    	OLED_ShowString(75,16*1,16,TimeBuff); //月
    	
    	if(rtc_clock.sec==0)OLED_ShowString(65,16*2,16,"        ");	//清除多余的数据
    	sprintf(TimeBuff,"%d:%d:%d",rtc_clock.hour,rtc_clock.min,rtc_clock.sec);
    	OLED_ShowString(65,16*2,16,TimeBuff); //秒
    	
    	//显示星期
    	OLED_ShowChineseFont(70,16*3,16,5); //星
    	OLED_ShowChineseFont(70+16,16*3,16,6); //期
    	OLED_ShowChineseFont(70+32,16*3,16,rtc_clock.week+7); //具体的值
    }
    
    
    static unsigned long next=1;//静态全局变量,作为种子
    
    void my_srand(unsigned long seed)//通过传不同的参数更改种子值,一般传time(NULL)
    {
        next=seed;
    }
    
    int my_rand(void)//将srand更改过的种子值通过公式计算出结果作为随机值
    {
        next = next * 1103515245 + 12345;
        return((unsigned)(next/65536) % 32768);
    }
    
    
    //根据时间基准获取6位数随机开锁密码
    char pwdcont[] = "0123456789";
    void GeneratePassword(char *Password,int pwd_size)
    {
    	int i;
    	int random;
    
    	unsigned int sec=TimeToSec(rtc_clock.year,rtc_clock.mon,rtc_clock.day,rtc_clock.hour,rtc_clock.min);
    	//printf("sec=%d\r\n", sec);
    
    	//获取时间种子
    	my_srand(sec);
    
    	for (i = 0; i < pwd_size; i++)
    	{
    		random = my_rand() % (strlen(pwdcont));
    		*(Password + i) = pwdcont[random];
    	}
    	*(Password + i) = '\0';
    }
    
    
    
    
    int main()
    {
        u8 esp8266_state=0;
        u8 key;
        u8 i;
        u32 time_cnt=0;
        u8 MatrixKey=0; //矩阵键盘值
        u32 page_display=0; //页面显示时间刷新
        char Password[10];
        LED_Init();
        KEY_Init();
        USART1_Init(115200);
        RC522_Init();		 //RC522 
        Moto_Init();  //步进电机初始化
        BEEP_Init();
        USART3_Init(115200);//串口-WIFI
        TIMER3_Init(72,20000); //超时时间20ms
        Touch_Configuration(); //触摸按键配置
        
        //OLED初始化
        OLED_Init(0xc8,0xa1); //OLED显示屏初始化--正常显示;
       
    
        USART1_Printf("正在初始化WIFI请稍等.\r\n");
        
        //清屏
        OLED_Clear(0);
        OLED_RefreshGRAM();  //刷新数据到OLED屏幕
        OLED_ShowString(0,0,16,"init esp8266.");
         
        for(i=0;i<5;i++)
        {
            if(ESP8266_Init()==0)
            {
                esp8266_state=1;
                OLED_Clear(0);
                OLED_RefreshGRAM();  //刷新数据到OLED屏幕
                OLED_ShowString(0,0,16,"esp8266 init ok.");
                break;
            }
            else
            {
                esp8266_state=0;
                OLED_Clear(0);
                OLED_RefreshGRAM();  //刷新数据到OLED屏幕
                OLED_ShowString(0,0,16,"esp8266 init error.");
                USART1_Printf("ESP8266硬件检测错误.\n");  
            }
        }
      
         if(esp8266_state)
         {
            printf("ESP8266 WIFI 配置状态:%d\r\n",ESP8266_AP_TCP_Server_Mode("esp8266_xl","12345678",8089));
         }
       
        USART1_Printf("正在初始化RTC实时时钟请稍等.\r\n");
        
        RTC_Init();//RTC初始化,一定要初始化成功 
        OLED_Clear(0x00); 	 //清屏	
        OLED_RefreshGRAM();  //刷新数据到OLED屏幕
        DrawTimeFrame();  	 //画时钟框架
         
    	 while(1)
    	 {
            //按键可以测试开锁和关锁
            key=KEY_Scan();
            if(key==1)
            {
                LED1=0;  //亮灯--表示开锁
                time_cnt=0;
                Motorcw_ring(1,300);   //电机正转1圈
                
                page_show_flag=1;
                page_display=0;
                
                 //清屏
                OLED_Clear(0);
                OLED_ShowString(0,0,16,"open lock.");
            }
            else if(key==2)
            {
                 LED1=1;  //灭灯--表示关锁
                 time_cnt=0;
                 Motorccw_ring(1,300);  //电机反转1圈
    
                page_show_flag=1;
                page_display=0;
                //清屏
                OLED_Clear(0);
                OLED_ShowString(0,0,16,"close lock.");            
            } 
    
            DelayMs(10);
            page_display++;
            time_cnt++;
            if(time_cnt>=50)
            {
                 //获取开锁密码
                GeneratePassword(Password,6);
               // printf("Password = %s\r\n", Password);
                
                time_cnt=0;
                LED2=!LED2;
            }
            
            //判断显示时间是否到达,到达之后恢复正常时钟显示页面
            if(page_show_flag==1 && page_display>200)
            {
                page_show_flag=0;
                OLED_Clear(0x00); 	 //清屏	
                OLED_RefreshGRAM();  //刷新数据到OLED屏幕
                DrawTimeFrame();  	 //画时钟框架
            }
            
            
            //APP开锁方式: 接收WIFI返回的数据
            if(USART3_RX_FLAG)
            {
                USART3_RX_BUFFER[USART3_RX_CNT]='\0';
                
    		    printf("UART3收到数据.....\r\n");
                //向串口打印APP返回的数据
                for(i=0;i<USART3_RX_CNT;i++)
                {
                    USART1_Printf("%c",USART3_RX_BUFFER[i]);
                }
                
                //如果是下发了属性,判断是开锁还是关锁
                if(USART3_RX_CNT>5)
                {
                    //使用字符串查找函数
                    //开锁
                    if(strstr((char*)&USART3_RX_BUFFER[5],"open_lock"))
                    {
                        LED1=0;  //亮灯--表示开锁
                         
                        //开锁
                        //执行开锁代码--电机正转
                         Motorcw_ring(1,300);   //电机正转1圈
                         //清屏
                        OLED_Clear(0);
                        OLED_ShowString(0,0,16,"open lock.");    
                        page_show_flag=1;
                        page_display=0;
                    }
                }
                char *time;
                /*判断是否收到客户端发来的数据  */
                char *p=strstr((char*)USART3_RX_BUFFER,"+IPD");
                if(p!=NULL) //正常数据格式: +IPD,0,7:LED1_ON    +IPD,0表示第0个客户端   7:LED1_ON表示数据长度与数据
                {
                        /*解析上位机发来的数据*/
                        p=strstr((char*)USART3_RX_BUFFER,":");
                        if(p!=NULL)
                        {
                                p+=1; //向后偏移1个字节
                                if(*p=='*')  //设置RTC时间
                                {
                                    p+=1; //向后偏移,指向正确的时间
                                    time=p;
                                    int tm_sec;  //秒
                                    int tm_min;  //分
                                    int tm_hour; //时
                                    int tm_mday; //日
                                    int tm_mon;  //月
                                    int tm_year; //年
                                    tm_year=(time[0]-48)*1000+(time[1]-48)*100+(time[2]-48)*10+(time[3]-48)*1;
                                    tm_mon=(time[4]-48)*10+(time[5]-48)*1;
                                    tm_mday=(time[6]-48)*10+(time[7]-48)*1;
                                    tm_hour=(time[8]-48)*10+(time[9]-48)*1;
                                    tm_min=(time[10]-48)*10+(time[11]-48)*1;
                                    tm_sec=(time[12]-48)*10+(time[13]-48)*1;
                                    RTC_SetTime(tm_year,tm_mon,tm_mday,tm_hour,tm_min,tm_sec);
                                   printf("RTC时间设置成功:%d-%d-%d %d:%d:%d\r\n",tm_year,tm_mon,tm_mday,tm_hour,tm_min,tm_sec);
                                    
                                    OLED_Clear(0x00); 	 //清屏	
                                    OLED_RefreshGRAM();  //刷新数据到OLED屏幕
                                    DrawTimeFrame();  	 //画时钟框架
                                }
                        }
                }
                            
                USART3_RX_CNT=0;
                USART3_RX_FLAG=0;
            }
    				
            
            //输入密码开锁
            MatrixKey=Touch_KeyScan();
            if(MatrixKey!=0)
            {
                //最大密码数限制在10以内。超出自动清理
                if(MatrixKey_index>10)MatrixKey_index=0;
                
                //printf("MatrixKey=%d\r\n",MatrixKey);
                //将按键值存放到数组里.只要数字键
                switch(MatrixKey)
                {
                  case 1: MatrixKey_var[MatrixKey_index++]=1+48;USART1_Printf("输入:1\r\n");break;
                  case 2: MatrixKey_var[MatrixKey_index++]=2+48;USART1_Printf("输入:2\r\n");break;
                  case 3: MatrixKey_var[MatrixKey_index++]=3+48;USART1_Printf("输入:3\r\n");break;
                  case 5: MatrixKey_var[MatrixKey_index++]=4+48;USART1_Printf("输入:4\r\n");break;
                  case 6: MatrixKey_var[MatrixKey_index++]=5+48;USART1_Printf("输入:5\r\n");break;
                  case 7: MatrixKey_var[MatrixKey_index++]=6+48;USART1_Printf("输入:6\r\n");break;
                  case 9: MatrixKey_var[MatrixKey_index++]=7+48;USART1_Printf("输入:7\r\n");break;
                  case 10: MatrixKey_var[MatrixKey_index++]=8+48;USART1_Printf("输入:8\r\n");break;
                  case 11: MatrixKey_var[MatrixKey_index++]=9+48;USART1_Printf("输入:9\r\n");break;
                  case 14: MatrixKey_var[MatrixKey_index++]=0+48;USART1_Printf("输入:0\r\n");break;
                }
                USART1_Printf("正在输入中:%s\r\n",MatrixKey_var);
             
                //按下#号键表示确认输入
                if(MatrixKey==15)
                {
                    MatrixKey_var[MatrixKey_index++]='\0';
                    MatrixKey_index=0;
                  
                    USART1_Printf("输入的密码:%s\r\n",MatrixKey_var);
                  
                    //开锁密码
                    if(strcmp(MatrixKey_var,Password)==0)
                    {
                        USART1_Printf("密码正确,开锁成功.\r\n");
                      
                       LED1=0;  //亮灯--表示开锁
    
                      //执行开锁代码--电机正转
                      Motorcw_ring(1,300);   //电机正转1圈	
    
                      //清屏
                       OLED_Clear(0);
                       OLED_ShowString(0,0,16,"open lock.");   
                        
                        page_show_flag=1;
                        page_display=0;
                    }
                    else
                    {
                        USART1_Printf("密码错误,开锁失败.\r\n");
                        
                        //清屏
                        OLED_Clear(0);
                        OLED_ShowString(0,0,16,"password error.");   
                        
                        page_show_flag=1;
                        page_display=0;
                    }
                }  
                //按下C号键表示清除之前的输入
                else if(MatrixKey==12)
                {
                    MatrixKey_index=0;
                    USART1_Printf("清除之前输入的密码,等待重新输入.\r\n");
                } 
            }
    	 }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380

    7 最后

  • 相关阅读:
    39.JS插件
    《PyTorch深度学习实践》第十一课(卷积神经网络CNN高级版)
    低代码开发项目
    Mongodb实验二——分片集群搭建
    MySQL系列-高级-深入理解Mysql事务隔离级别与锁机制01
    黑马点评-05缓存穿透问题及其解决方案,缓存空字符串或使用布隆过滤器
    DevOps|1024程序员节怎么做?介绍下我的思路
    Nacos+OpenFegin正确调用服务的姿势!
    Springboot错误ASM ClassReader failed
    【微信小程序生成海报保存到相册】
  • 原文地址:https://blog.csdn.net/m0_71572576/article/details/126698763