当前位置:   article > 正文

STM32智能家居系统设计(门禁、人体感应、GSM远程控制)_stm32门禁

stm32门禁

这是小编在学校时期做的一个课题,其功能包括门禁功能、人体感应灯功能、GSM远程短信控制家电功能。整个系统的设计是建立在STM32F407开发板上的,并运用了开发板上的触摸屏进行系统显示。其中门禁功能包括了密码开门和指纹开门两个功能,可以修改系统中的密码和指纹。指纹部分采用的是AS608指纹识别模块,使用了官方提供的函数能实现指纹的录入存储,验证,删除。最后的人体感应灯和GSM远程控制部分则是随便做的。该设计的报告现贴出供有需要的人学习参考,不喜勿喷。

智能家居系统设计

  

第一章 绪论

1.1 选题背景及意义

1.2 国内外研究现状 

     1.2.1 国外研究现状 

      1.2.2 国内研究现状 

1.3 本文研究内容 

1.4 实际应用价值 

第二章 门禁功能 

2.1 密码部分 

      2.1.1 密码输入 

      2.1.2 密码主程序设计 

      2.1.3 密码修改 

      2.1.4 密码的存储 

2.2 指纹部分 

      2.2.1 模块简介 

      2.2.2 硬件连接 

      2.2.3 软件实现 

      2.2.4 录入指纹 

      2.2.5 删除指纹 

第三章 人体感应灯光 

3.1 模块简介 

3.2 硬件连接 

3.3 软件实现 

3.4 开关与延时功能 

第四章 GSM远程控制 

4.1 模块简介 

4.2 硬件连接 

4.3 软件实现 

系统显示 

章 总结与展望 

第一章 绪论

1.1选题背景及意义

智能家居系统概念起源于20世纪 70年代的美国科技公司。随后欧洲、日本等国家均应用了此概念,快速发展出了自己的智能家居系统,例如德国的 EIB 系统、新加坡的8X系统等。韩国、日本也借力于自家的家电制造行业以及移动互联网技术构建了宏大的智能家电网络。进入 20 世纪以来,随着互联网技术、物联网技术以及智能终端不断创新、成熟和普及,实现安全可靠的智能家居系统已不再是梦想。我们可以预测到在不久以后的将来,智能家居将成为家居行业的主流。为了顺应时代的发展,更为了满足人们对美好生活的向往,我们理应顺应这个方向,发展出符合我国国情的智能家居控制系统。

为了满足人们对快捷、方便、舒适、智能化的家居生活有越来越多的需求,我们针对这些需求进行智能家居控制系统的设计、改善。首先是门禁部分,提高门禁系统的安全性、便携性。其次是家庭灯光等设备,提高设备控制的便捷性,多样性。最终为人们提供一个舒适、安全、便捷的居住环境。而通过对智能家居系统的研究,在理论上推动智能化技术在家居领域深入的发展,并为各类智能化家具新产品的设计与开发提供一定的理论依据,产生巨大的经济效益和社会效益。所以,对该课题的研究具有非常重要的意义。

1.2国内外研究现状

1.2.1国外研究现状

智能家居的概念最先出自国外,始于20世纪70年代。世界上第一幢智能建筑在1984年的美国出现此后其他国家也先后效仿,加拿大、澳大利亚以及其他东南亚等经济技术比较发达的国家,先后也提出了各种智能家居的解决方案。例如德国的EIB系统、新加坡的8X系统等。韩国、日本也借力于自家的家电制造行业以及移动互联网技术构建了宏大的智能家电网络。进入21世纪后,通信技术和物联网技术快速发展,给智能家居的发展提供了很好的平台。例如 GPRS、4G、WiFi、蓝牙以及ZigBee等通讯技术的出现,使得智能家居更加人性化、智能化和便捷化。通信技术的不断进步为智能家居提供了更加广泛的前景。但到目前,市面上的智能家居行业都还没有形成统一的行业标准,而且产品的种类繁多,很多技术上的问题也都有待进一步解决,这也使现在人们迫切追求一种完善的符合人性的智能家居系统,来满足人们的生活需求。

1.2.2国内研究现状

智能家居在国内相比国外起步较晚,但发展得却非常迅速。一开始由于技术不够成熟以及研究经费太高,所以需要向国外购买设备及技术,成本较高,难以实现大规模推广使用。而且人们的接受意愿也不高,使得产品的整体销量并不好,也没有多少企业加入研发。而随着近几年技术的发展,我国开始对物联网技术自主研究,在吸收、借鉴国外先进技术的基础上,我国物联网技术以及传感器技术得到了快速发展,智能家居产品逐渐增加。此外,人们的生活水平也逐年提高,逐渐接受了智能家居给生活带来的便利和乐趣,越来越多的人用上了智能家居,使得该行业在这几年有了飞速增长。这让越来越多的企业看到了其中巨大的经济利益,纷纷加入到该领域中来,使得发展智能化家居成了历史发展的必然趋势。来,我们的智能家居系统也将全面升级,实现全屋智能化,向更高的性能、更高的控制精确度、向更低的功耗、向更加实惠的价格发展,在未来的日子里大放光彩。

1.3本文研究内容

本次智能家居系统主要以stm32F407系列单片机作为主控芯片,实现功能有:家居系统中的门禁功能来保证用户安全(如密码输入、指纹输入);通过传感器模块实现家居环境中人体自动识别,并用来控制灯光部分的开、关以及延时功能;通过手机远程向GSM模块发送短信,并识别短信的内容,根据器内容实现对家庭电器、窗帘、照明的本地或远程控制。

1.4实际应用价值

门锁部分在我看来是每一个家庭实现家居智能化的第一步,也是最重要的一环,涉及家居生活的安全性。传统的机械门锁出门都需要带上一条小小的钥匙,极其容易遗失,钥匙多了又很沉重。反观智能门锁不需要携带钥匙,并且有多种解锁方式,相比机械门锁更安全、更智能、更人性化

灯光部分在一个家庭生活中起着非常重要的作用。老式灯光只能通过上的固定开关控制,极其不方便,灯的功能单一的同时开关也容易按坏,给人的体验极其不佳。现代的智能灯光系统则能摈弃这些缺点,它常常带有人体感应功能、远程控制功能、灯光效果设置灯功能既没有了老式灯的烦恼,又给人的家居生活提供温馨的生活氛围,是一种非常不错生活体验。

智能家居系统同时也离不开远程控制功能。传统的家居控制方式不足之处在于其应用范围只能在家庭内部控制家电设备,而远程控制系统则扩展了其的应用范围,并且具有可靠性高、安全性强、响应快速等先天性优势,真正让家居的控制实现走出家门。智能家居系统以无线的方式,通过手机等通讯设备,人们可以随心所欲地控制家电设备,以及监视家里的情况,极大的便捷了我们的生活。在实现家居操控的问题上,无线远程操控已成为必然的发展趋势。客观地说,正是因为有了远程控制系统,才让智能家居真正变得方便、自由、舒适。

第二章 门禁功能

2.1密码部分

2.1.1密码输入

该密码部分采用4x4密码按键模块输入。硬件电路如图所示:

4x4矩阵按键原理图:

4x4矩阵按键模块共有8个引脚,自上向下排列,上面四个为列分别为列4、列3、列2、列1,分别连接PF7、PF6、PF5、PF4,下面四个分别为行1、行2、行3、行4,分别连接PF0、PF1、PF2、PF3。将每列都设置成上拉输入模式,每行都设置成推挽输出模式,并且一开始行输出都为低电平。

将第一行变为低电平,其余行为高电平。然后读取列的电平变化,判断某一列是否按下。第一列被按下则PF4被拉低,返回数值1;第二列被按下则PF5被拉低,返回数值2;第三列被按下则PF6被拉低,返回数值3;第四列被按下则PF7被拉低,返回数值4。若没有检测到按下则执行检测下一行的程序。

同理,检测第二行,第三行第四行。当所有程序都执行一遍若还没有检测到按键继续执行下一遍按键扫描。这样就能准确的知道哪个按键被按下,然后根据返回的数值来设置具体按键实现的功能。

密码按键界面设计:

1

2

3

4

5

6

7

8

9

0

显示

删除

清除

确定

2.1.2密码主程序设计

该密码系统设计为有两个6位数字密码,可以进入系统后选择修改密码。首先,系统会不断扫描是否有按键输入。当检测到密码输入时,会将输入的数值保存在一个字符串中,并显示“*”来防止偷窥,可以通过“显示”按键来显示或隐藏密码。密码最多输入6位,输入完成后按确认键,系统就会将字符串的密码一位位地和系统保存的密码进行比较,当存在不同时,系统会显示“密码错误”并清空输入的密码。输入密码正确则跳转进入系统的主界面。

流程图如图所示:

程序实现:

int password(void)

{

int  key_num=0,i=0,satus=0;

u16 num=0,num1=0,num2=0;

u8 pwd[7]="       ";

u8 hidepwd[7]="       ";

while(1)

{

key_num=Button4_4_Scan();

if(key_num)

{

if(key_num>=1 && key_num<10 && i>=0 && i<6){  //按键0-9

pwd[i]=key_num+0x30;

hidepwd[i]='*';

i++;

}

if(key_num==10 && i>=0 && i<6){ //按键“0”

pwd[i]=0x30;

hidepwd[i]='*';

i++;

}

if(key_num==12){//显示

satus=!satus;

}

if(key_num==13 && i>0){//删除

pwd[--i]=' ';  

hidepwd[i]=' ';

}

if(key_num==14){//清空

while(i--){

pwd[i]=' ';

hidepwd[i]=' ';  

}

i=0;

}

if(key_num==15){//返回

return -1;

}

if(key_num==16)break;  //确定

}

if(satus==0)  LCD_ShowString(95,95,100,16,16,hidepwd);

else LCD_ShowString(95,95,100,16,16,pwd);

}

for(i=0; i<10; i++)

{   

if(pwd[i]==Pwd[num])

 { num++; }

else{ num=0;break; }

if(num==6)

{ break; }

}

for(i=0; i<10; i++)

{   

if(pwd[i]==Pwd1[num1])

 { num1++; }

else{ num1=0;break; }

if(num1==6)

{ break; }

}

for(i=0; i<10; i++)

{   

if(pwd[i]==Pwd2[num2])

{ num2++;}

else { num2=0; break; }

if(num2==6)

{ break;}

}

if(num==6 | num1==6 | num2==6){

Show_Str(88,225,100,16,"密码正确",16,0);

vTaskDelay(1500);

LCD_Fill(95,95,195,111,WHITE);

    LCD_Fill(88,225,188,241,WHITE);

return 0;

}

else {

Show_Str(88,225,100,16,"密码错误",16,0);

vTaskDelay(1500);

LCD_Fill(95,95,195,111,WHITE);

LCD_Fill(88,225,188,241,WHITE);

return -1;

}

}

2.1.3密码修改

该系统具备了密码修改功能。密码正确后跳转进入界面,可以选择修改密码按钮对系统存储的密码进行修改。与密码输入同理,采用4x4矩阵按键输入。输入密码后,按确认,系统就会将输入的密码写入内部的flash中,同时读取一次刷新系统密码(这样就不需要重启系统刷新密码,直接使用)。该功能还具备了密码切换的按钮,给用户切换修改密码1或者密码2(该系统给用户提供了2个6位数字密码)。

按键界面设计

1

2

3

4

5

6

7

8

9

0

切换

显示

删除

清除

退出

确定

修改密程序设计:

void SetPassworld(void)

{

int pwd_ch=0;//密码选择

int  key_num=0,i=0,satus=0;

u8 pwd[6]="      ";

u8 hidepwd[6]="      ";

u8 buf[10];

LCD_Clear(WHITE);//清屏

//显示密码键盘

Show_Str(50,90,180,16," 1    2    3     4  ",16,0);

Show_Str(50,120,180,16," 5    6    7     8  ",16,0);

Show_Str(50,150,180,16," 9    0   切换  显示  ",16,0);

Show_Str(50,180,180,16,"删除 清空 退出  确定  ",16,0);

while(1)

{

//提示密码信息

sprintf((char*)buf,"新密码%d:",pwd_ch+1);

Show_Str(60,50,70,16,buf,16,0);//显示密码

key_num=Button4_4_Scan();

if(key_num)

{

     if(key_num>=1 && key_num<10 && i>=0 && i<6){  //0-9键

pwd[i]=key_num+0x30;

hidepwd[i]='*';

i++;

}

if(key_num==10 && i>=0 && i<6){       //0键

pwd[i]=0x30;

hidepwd[i]='*';

i++;

}

if(key_num==11){//密码选择

pwd_ch=!pwd_ch;

}

if(key_num==12){//显示

satus=!satus;

}

if(key_num==13 && i>0){

pwd[--i]=' ';  //删除键

hidepwd[i]=' ';

}

if(key_num==14){

while(i--){

pwd[i]=' ';  //清空键

hidepwd[i]=' ';  

}

i=0;

}

if(key_num==15){//返回键

return ;

}

if(key_num==16)break;  //确定键

}

//密码显示与隐藏

if(satus==0)  LCD_ShowString(130,50,100,16,16,hidepwd);

  else LCD_ShowString(130,50,100,16,16,pwd);

}

if(pwd_ch==0)

{

STMFLASH_Write(0X08020004,(u32*)pwd,2);//写入flash

STMFLASH_Read(0X08020004,(u32*)Pwd1,2); //读取密码1

}

else

{

STMFLASH_Write(0X08090004,(u32*)pwd,2);

STMFLASH_Read(0X08090004,(u32*)Pwd2,2); //读取密码2

}

Show_Str(70,220,128,16,"密码修改成功 !",16,0);

vTaskDelay(1000);

}

2.1.4密码的存储

在我们的日常开发中,经常会遇到有一些程序的运行参数需要保存,来防止掉电丢失数据。如一些系数,它们数量少而且不需要有经常修改,但又不能定义为常量,因为每台设备可能不一样,在以后也还有修改的可能。所以需要将这类数据存在指定的位置,需要用时就直接读取,需要修改时就直接修改存储位置的数值。如果使用专门的存储单元既不经济,也没有必要,而STM32F4内部的Flash容量较大,而且库函数中也提供了基本的Flash操作函数,所以将数据存储进flash中实现起来也比较方便。我们用STMFLASH_Write函数就能将密码存储进stm32flash的指定地址中,需要用时直接用STMFLASH_Read函数就能读取出密码了。

STM32F40xx/41xx 的闪存模块组织如图所示:

 扇区擦除步骤如下:

(1)检查FLASH_CR的LOCK是否解锁,如果没有则先解锁;

(2)检查FLASH_SR寄存器中的BSY位,确保当前未执行任何FLASH操作;

(3)在FLASH_CR寄存器中,将SER位置1,并从主存储块的12个扇区中选择要擦除的扇区(SNB);

(4)将FLASH_CR寄存器中的STRT位置1,触发擦除操作;

(5)等待BSY位清零

读FLASH操作:

STM23F4的FLASH读取是很简单的。我们要从地址addr,读取一个字(字节为8位,半字为16位,字为32位),可以通过如下的语句读取:data=(vu32)addr;将addr强制转换为vu32指针,然后取该指针所指向的地址的值,即得到了addr地址的值。

详情请参考正点原子实验34 FLASH模拟EEPROM实验例程。

2.2指纹部分

2.2.1模块简介

 ATK-AS608指纹识别模块是ALIENTEK推出的一款高性能的光学指纹识别模块。AS608 模块采用了AS608指纹识别芯片,芯片内置DSP运算单元,集成了指纹识别算法,能高效快速采集图像并识别指纹特征。指纹的采集利用光的折射和反射原理,光从底部射向三棱镜,并经棱镜射出,射出的光线在手指表面指纹凹凸不平的线纹上折射的角度及反射回去的光线明暗就会不一样。CMOS或者CCD的光学器件就会收集到不同明暗程度的图片信息,就完成指纹的采集。

系统内设有一个72K字节的图像缓冲区与二个512bytes 大小的特征文件缓冲区,名字 分别称为:ImageBuffer,CharBuffer1和CharBuffer2。用户可以通过指令读写任意一个缓冲区。CharBuffer1或CharBuffer2既可以用于存放普通特征文件也可以用于存放模板特征文件。模块配备了串口、USB 通讯接口,用户无需研究复杂的图像处理及指纹识别算法,只需通过简单的串口、USB 按照通讯协议便可控制模块。

模块引脚描述:

序号

名称

说明

1

Vi

模块电源正输入端。

2

Tx

串行数据输出。 TTL 逻辑电平

3

Rx

串行数据输入。 TTL 逻辑电平

4

GND

信号地。内部与电源地连接

5

WAK

感应信号输出,默认高电平有效

6

Vt

触摸感应电源输入端,3.3v 供电

7

U+

USB D+

8

U-

USB D-

2.2.2硬件连接

硬件连接图:

 Vi和Vt连接到到电源3.3V,GND接地,Rx连接到PA2(RX),Tx连接到PA3(TX),WAK连接到PA6引脚,将PA(6)设置成下拉输入模式,不断检测是否有指纹输入。

2.2.3软件实现

    开机首先实现与指纹模块握手,握手成功后,才进入系统界面;握手失败则提示连接失败,请检查连接并重启。

//与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;

}

指纹识别步骤:

第一,录入图像。当你的手指放在光学指纹窗口的时候执行这个指令,就可以把指纹的图像拍下来。

第二,生成特征。当你的指纹图像拍下来之后,调用这个指令就可以把图像中的指纹特征记录下来。AS608里面有2个缓存区可以存这个特征。

第三,搜索指纹。调用这个指令就会将已经存在Flash里面的指纹模板和缓存区的指纹特征一一比对,如果有搜索到,会进入系统主界面。要注意的是,调用的时候需要指明比对的特征是缓存区1还是缓存区2,即你要选择第二步生成的特征所存储的缓存区。

刷指纹流程图:

 软件实现:

int press_FR(void)

{

SearchResult seach;

u8 ensure;

char *str;

ensure=PS_GetImage();

if(ensure==0x00)//获取图像成功

{

ensure=PS_GenChar(CharBuffer1);

if(ensure==0x00) //生成特征成功

{

ensure=PS_HighSpeedSearch(CharBuffer1,0,AS608Para.PS_max,&seach);

if(ensure==0x00)//搜索成功

{

              LCD_Fill(0,220,lcddev.width,160,WHITE);

Show_Str_Mid(0,230,"刷指纹成功",16,240);

str=mymalloc(SRAMIN,2000);//查找内存地址

myfree(SRAMIN,str);//释放内存

delay_ms(1000);

return 0;

}

else

{

ShowErrMessage(ensure);

     delay_ms(500);

return -1;

     }

 }

else

 ShowErrMessage(ensure);

 delay_ms(500);

 LCD_Fill(0,220,lcddev.width,160,WHITE);

return -1;

 }

return -1;

 }

将错误信息显示在屏幕上。

//显示指纹模块返回信息

void ShowErrMessage(u8 ensure)

{

Show_Str_Mid(0,265,(u8*)EnsureMessage(ensure),16,240);//EnsureMessage为错误信息集合

vTaskDelay(1000);

LCD_Fill(0,265,lcddev.width,310,WHITE);

}

2.2.4录入指纹

录入指纹步骤:

第一,录入图像。把指纹的图像拍下来。

第二,生成特征。把图像中的指纹特征记录下来。AS608里面有2个缓存区可以存这个特征,我们这里先用第1个存。

第三,再次录入图像。把同一个手指放在光学指纹窗口,然后执行这个指令,再拍一个指纹图像。

第四,再次生成特征。把第二次录入的图像的指纹特征存到第2个缓存区。

第五.精确比对两枚指纹特征。对录入的两个指纹特征进行比对,如果一致就说明是同一个人的同一个指纹。

第六,合并特征,生成模板。当录入了两个指纹特征,并且两个特征是一致的时候,就可以把两个特征合并成一个指纹模板。这个指纹模板就是我们最终要录入的指纹。

第七,储存模板。当生成一个模板的时候,我们可以把这个模板存到AS608内部的Flash里面,存储的时候需要输入一个指纹ID号,这个ID其实是Flash的地址,不同的ID号,存储的位置不同。

录入指纹流程图:

软件实现:

void Add_FR(void)

{

u8 i=0,ensure ,processnum=0;

u16 ID;

while(1)

{

switch (processnum)

{

case 0:

i++;

   LCD_Clear(WHITE);

Show_Str_Mid(0,100,"请按指纹",16,240);

ensure=PS_GetImage();

if(ensure==0x00) //获取图像成功

{

ensure=PS_GenChar(CharBuffer1);//生成特征

if(ensure==0x00)//生成特征成功

{

LCD_Fill(0,130,lcddev.width,160,WHITE);

Show_Str_Mid(0,130,"指纹正常",16,240);

i=0;

processnum=1;//跳到第2步

}else ShowErrMessage(ensure);

}else ShowErrMessage(ensure);

break;

case 1:

i++;

LCD_Fill(0,100,lcddev.width,160,WHITE);

Show_Str_Mid(0,100,"请再按一次指纹",16,240);

ensure=PS_GetImage();

if(ensure==0x00)

{

ensure=PS_GenChar(CharBuffer2);//生成特征

if(ensure==0x00)

{

Show_Str_Mid(0,130,"指纹正常",16,240);

i=0;

processnum=2;//跳到第3步

}else ShowErrMessage(ensure);

}else ShowErrMessage(ensure);

break;

case 2:

LCD_Fill(0,100,lcddev.width,160,WHITE);

Show_Str_Mid(0,100,"对比两次指纹",16,240);

ensure=PS_Match();

  vTaskDelay(500);

if(ensure==0x00)

{

Show_Str_Mid(0,130,"对比成功,两次指纹一样",16,240);

processnum=3;//跳到第4步

}

else

{

Show_Str_Mid(0,130,"对比失败,请重新录入指纹",16,240);

ShowErrMessage(ensure);

i=0;

processnum=0;//跳回第一步

}

vTaskDelay(1200);

break;

case 3:

LCD_Fill(0,100,lcddev.width,160,WHITE);

Show_Str_Mid(0,100,"生成指纹模板",16,240);

ensure=PS_RegModel();

if(ensure==0x00)

{

Show_Str_Mid(0,130,"生成指纹模板成功",16,240);

processnum=4;//跳到第5步

}else {processnum=0;ShowErrMessage(ensure);}

vTaskDelay(1200);

break;

case 4:

LCD_Fill(0,100,lcddev.width,160,WHITE);

Show_Str_Mid(0,40,"请输入存储ID",16,240);

Show_Str_Mid(0,70,"0 =< ID <= 299",16,240);

   Show_Str(50,110,180,16," 1    2    3     4  ",16,0);

          Show_Str(50,140,180,16," 5    6    7     8  ",16,0);

          Show_Str(50,170,180,16," 9    0               ",16,0);

          Show_Str(50,200,180,16,"删除 清空       确定  ",16,0);

do

ID=GET_NUM();//获取指纹ID

while(!(ID<AS608Para.PS_max));//输入ID必须小于模块容量 ensure=PS_StoreChar(CharBuffer2,ID);//存储模板

if(ensure==0x00)

{

Show_Str_Mid(0,220,"录入指纹成功",24,240);

Show_Str(60,250,200,16,"剩余指纹容量",16,0);

PS_ValidTempleteNum(&ValidN);//读库指纹个数

          LCD_ShowNum(160,250,AS608Para.PS_max-ValidN,3,16);//显示剩余指纹容量

vTaskDelay(1500);

return ;

}else {processnum=0;ShowErrMessage(ensure);}

break;

}

if(i==5) break;//超过5次没有按手指则退出

}

}

    对于指纹ID的获取,我们选用上面密码输入的4x4矩阵按键进行输入,由于指纹ID最高为300所以限制输入3位有效数字。

u16 GET_NUM(void)

{

u8  key_num=0;

u16 num=0;

while(1)

{

key_num=Button4_4_Scan();

if(key_num)

{

if(key_num==14)return 0xFFFF;//返回键

if(key_num==15)return 0xFF00;//

if(key_num>=1&&key_num<10&&num<99)//1-9键(限制输入3位数)

num =num*10+key_num;

if(key_num==13)num =num/10;//删除键

if(key_num==10&&num<99)num =num*10;//0键

if(key_num==16)return num;  //确认键

}

LCD_ShowNum(105,90,num,3,16);

}

}

2.2.5删除指纹

进入主界面后,可以选择删除指纹进入删除指纹界面,然后输入要删除的指纹ID,点击确定,即可删除指纹。删除指纹可以选择删除个别指纹或者删除所有指纹。删除一个:调用“删除模板”指令,输入要删除的ID号,就会把Flash里面ID号对应位置的数据清除掉。删除所有:调用“清空指纹库”指令即可。对于指纹ID的输入,也采用4x4矩阵按键输入。

软件实现:

//删除指纹

void Del_FR(void)

{

u8  ensure;

u16 num;

LCD_Clear(WHITE);

Show_Str_Mid(0,30,"删除指纹",16,240);

Show_Str_Mid(0,60,"0 =< ID <= 299",16,240);

Show_Str(50,110,180,16," 1    2    3     4  ",16,0);

Show_Str(50,140,180,16," 5    6    7     8  ",16,0);

Show_Str(50,170,180,16," 9    0               ",16,0);

Show_Str(50,200,180,16,"删除 全清 退出 确定  ",16,0);

PS_ValidTempleteNum(&ValidN);//读库指纹个数

Show_Str(60,280,100,16,"剩余指纹容量",16,0);

LCD_ShowNum(160,280,AS608Para.PS_max-ValidN,3,16);//显示剩余指纹个数

vTaskDelay(50);

while(1)

{

num=GET_NUM();//获取返回的数值

if(num==0xFF00) break ; //返回主页面

else if(num==0xFFFF)

ensure=PS_Empty();//清空指纹库

else

ensure=PS_DeletChar(num,1);//删除单个指纹

if(ensure==0)

{ Show_Str_Mid(0,240,"删除指纹成功",16,240);

vTaskDelay(1200);

LCD_Fill(0,240,240,256,WHITE);//将字体清除}

  else

ShowErrMessage(ensure);

PS_ValidTempleteNum(&ValidN);//读库指纹个数

LCD_Fill(160,280,240,296,WHITE);//将字体清除

LCD_ShowNum(160,280,AS608Para.PS_max-ValidN,3,16);

  }

}

第三章 人体感应灯光

3.1模块简介

人体红外检测模块HC-SR501只有个管脚(VCC,GND,DATA),电源VCC和地GND,数据输出管脚DATA,当检测到有人体活动时DATA输出高电平平常没有检测到有人体活动时输出为低电平。

HCSR501模块采用了热释电红外传感器该传感器是一种能检测人或动物发射的红外线而输出电信号的传感器。热释电效应同压电效应类似,是指由于温度的变化而引起晶体表面荷电的现象。热释电传感器是对温度敏感的传感器。它由陶瓷氧化物或压电晶体元件组成,在元件两个表面做成电极,在传感器监测范围内温度有ΔT的变化时,热释电效应会在两个电极上会产生电荷ΔQ,即在两电极之间产生一微弱的电压ΔV。由于它的输出阻抗极高,在传感器中有一个场效应管进行阻抗变换。热释电效应所产生的电荷ΔQ会被空气中的离子所结合而消失,即当环境温度稳定不变时,ΔT=0,则传感器无输出。当人体进入检测区,因人体温度与环境温度有差别,产生ΔT,则有ΔT输出;若人体进入检测区后不动,则温度没有变化,传感器也没有输出了。

触发方式的选择

 L为不可重复,H为可重复。可跳线选择,默认为H。

(1)不可重复触发方式:即感应输出高电平后,延时一结束,输出将自动从高电平变为低电平。

(2)可重复触发方式: 即感应输出高电平后,在延时时间内,如果有人体在其感应范围内活动,其输出将一直保持高电平,直到人离开后才延时将高电平变为低电平,即以最后一次活动的时间为延时时间的起始点,检测到人体的每一次活动后会自动顺延一个延时时间。

延时调节灵敏度调节:

 延时调节:顺时针旋转,输出延时加长;逆时针旋转,输出延时减短。

灵敏度调节:顺时针旋转,器件灵敏度提高;逆时针旋转,器件灵敏度降低。

3.2硬件连接

 VCC接电源+5V,GND接地,OUT接PF14,IO口设置为输入模式,PF10接灯设置为输出模式。当HC-SR501检测到有人体热源时,OUT就会输出高电平。STM32检测到高电平,就会控制PF10输出高电平,从而灯实现点亮。

3.3软件实现

HCSR501模块不断对周围环境进行检测,当检测到人体时就会输出高电平到控制器stm32。stm32会先读取flash中保存的延时时间,然后对PF10管脚进行精准的定时输出,PF10连接的灯就能根据系统设置的延时时间实现精准的延时控制。

流程图如图所示:

 代码实现:

void HCSR_task(void *pvParameters)

{

int n0=0,n1=0,n2=0,n3=0;

while(1)

{

   STMFLASH_Read(0X080E0004,(u32*)time,1);//读取flash延时时间

       n0=time[0]-0x30;

   n1=time[1]-0x30;

       n2=time[2]-0x30;

   n3=n0*100+n1*10+n2;

if(HCSR501_in==1){

                 GPIO_ResetBits(GPIOF,GPIO_Pin_10);

                 vTaskDelay(n3);  }//当检测到信号输入,控制灯亮,延时规定时间

else {

   GPIO_SetBits(GPIOF,GPIO_Pin_10);

 vTaskDelay(10); }//没有信号输入,控制灯灭,执行其他程序

}

}

3.4开关与延时功能

延时的设置采用4*4矩阵按键模块输入,确认输入后系统会将延时时间存储进入stm32的flash中。在每次检测到人体信号时都会读取一次存储的延时时间。

开关控制部分通过定义一个全局变量实现。全局变量为0时,说明人体感应灯是开着的,当开关按钮按下,全局变量置1,灯关闭;全局变量为1时,说明人体感应灯是关闭的,当开关按钮按下,全局变量置0,灯功能开启。

软件实现:

void LED_set(void)

{

int  key_num=0,i=0;

u8 pwd[3]="   ";

LCD_Clear(WHITE);

Show_Str(90,40,200,16,"延时设置",16,0);

Show_Str(125,70,200,16," S",16,0);

Show_Str(50,100,180,16," 1    2    3     4  ",16,0);

Show_Str(50,130,180,16," 5    6    7     8  ",16,0);

Show_Str(50,160,180,16," 9    0               ",16,0);

Show_Str(50,190,180,16,"删除 开关 退出 确定   ",16,0);

while(1)

{

key_num=Button4_4_Scan();

if(key_num)

{

   if(key_num>=1 && key_num<10 && i>=0 && i<3){  //输入3位1-9

pwd[i]=key_num+0x30;

   i++;

}

if(key_num==10 && i>=0 && i<3){       //输入0

pwd[i]=0x30;

     i++;

}

if(key_num==13 && i>0){

pwd[--i]=' ';  //删除键

  }

if(key_num==14){

if(on_off==0)

              {

GPIO_SetBits(GPIOF,GPIO_Pin_10);;

vTaskSuspend(HCSRTask_Handler);

    Show_Str_Mid(0,220,"已关闭",16,240);

            vTaskDelay(1000);

            LCD_Fill(0,220,240,236,WHITE);

     on_off=1;

    break;

     }

   if(on_off==1)

   {

vTaskResume(HCSRTask_Handler);

        Show_Str_Mid(0,220,"已开启",16,240);

            vTaskDelay(1000);

            LCD_Fill(0,220,240,236,WHITE);

    on_off=0;

    break;

                }

}

if(key_num==15){//返回

return ;

}

if(key_num==16)//确定

{

STMFLASH_Write(0X080E0004,(u32*)pwd,1);//将延时时间写入flash

if(on_off==1) vTaskResume(HCSRTask_Handler);

            Show_Str(85,220,128,16,"修改成功",16,0);

vTaskDelay(1000);

        LCD_Fill(0,220,240,240,WHITE);

    break;

}

}

 LCD_ShowString(100,70,100,16,16,pwd);

}

}

第四章 GSM远程控制

4.1模块简介

 SIM800C 模块是一款高性能工业GSM/GPRS模块。SIM800C是一款四频GSM/GPRS模块:SIM800C,工作频段四频:850/900/1800/1900MHz,可以低功耗实现语音、SMS(短信)、MMS(彩信)、蓝牙数据信息的传输。SIM800C模块支持RS232串口和LVTTL串口(即支持3.3V/5V系统),并带硬件流控制,支持5V~24V的超宽工作范围。采用串口(UART)通信,使用标准的 AT 指令对SIM800C模块进行控制,实现打电话发短信等功能。所以,使用单片机连接到SIM900A模块的TTL接口,硬件连接完毕后,就可以通过串口来发送AT指令来实现相应的功能了。

4.2硬件连接

 模块SRXD——单片机 TXD

模块STXD——单片机 RXD

模块GND——单片机 GND

模块VCC——单片机DC5V

模块VCC_MCU——单片机DC5V

4.3软件实现

系统不断检测是否有短信输入,当接收到信息时,屏幕提示信息输入,并读取短信内容,如果短信中有“on”则开灯,有“off”则关灯,如果都没有则退出。该开灯关灯都会关闭人体感应功能。

流程图如图所示:

 程序设计如下:

void Letter_task(void *pvParameters)

{

u8 res;

  while(1)

  {

   if(Flag_Rec_Message==1)

    {

Show_Str(80,5,200,12,"接收到信息",12,0);

vTaskDelay(1000);

LCD_Fill(80,5,240,17,WHITE);

  Flag_Rec_Message=0;

  res=SIM_HANDLE_MESSAGE_CMD();

   if(res)

   {

   if(res==1){

vTaskSuspend(HCSRTask_Handler);

GPIO_ResetBits(GPIOF,GPIO_Pin_10);

on_off=0;

  }

    else if(res==2){

                        vTaskSuspend(HCSRTask_Handler);

GPIO_SetBits(GPIOF,GPIO_Pin_10);

on_off=1;

        }

     }

 }

else vTaskDelay(10);

}

}

u8 SIM_HANDLE_MESSAGE_CMD(void)//信息判断

{

if(strstr((char*)USART3_RX_BUF,"on")!=NULL)

{ return 1;  }

else if(strstr((char*)USART3_RX_BUF,"off")!=NULL) return 2;

return 0;

}

系统开机时,首先需要单片机与sim800c模块建立连接,检测模块连接通讯是否正常。正常则进入设置模块的短信模式然后进入系统,否则需要提示错误信息。

用到指令有以下:

AT

测试串口通讯是否正常

AT+CPIN?

查询 SIM 卡的状态,如果该指令返回:+CPIN:READY,则表明SIM卡状态正常,返回其他值,则有可能是没有 SIM 卡。

AT+CREG

查询模块是否注册网络,若查询返回+CREG: 0,5,则表示SIM卡处于漫游状态。

AT+CSQ

检测模块信号质量

具体代码实现如下:

//连接sim800c模块

Show_Str(55,160,200,16,"正在连接GSM模块....",16,0);

u8 res=1;

while(res){ res=sim900a_work_test(); }

res=1;

while(res){   res=sim900a_send_enmessage();  }

Show_Str(80,190,200,16,"连接成功!!!",16,0);

delay_ms(2000);

LCD_Clear(WHITE);

设置短信模式,用到的指令如下:

AT+CMGF=1

选择短消息格式,设置为文本模式。

AT+CSCS="GSM"

编码设置,设置为缺省字符集即可

AT+CSCA?

模块会根据SIM卡自动设置短消息中心号码,只做查询即可。

AT+CSMP=17,167,0,241

设置短消息文本模式参数,TEXT(GSM)模式下发送英文短消息,短消息储存至SIM卡中

AT+CNMI=2,2

新消息指示设置,短信自动读取

u8 sim900a_work_test(void)

{

if(sim900a_send_cmd((u8 *)"AT",(u8 *)"OK",100)) //测试串口通讯是否正常

  {

   if(sim900a_send_cmd((u8 *)"AT+CPIN?",(u8 *)"READY",400))//查询是否检测到SIM卡

{

   if(sim900a_send_cmd((u8 *)"AT+CREG?",(u8 *)"0,1",400)) //查询模块是否注册网络      

{

           if(strstr((const char*)USART3_RX_BUF,"0,5")==NULL) //若查询返回+CREG:0,5,表示sim卡处于没有漫游状态

            {

             if(!sim900a_send_cmd((u8 *)"AT+CSQ",(u8 *)"OK",200)) //查询信号质量

              {

            memcpy(SIM900_CSQ,USART3_RX_BUF+15,2);

                return SIM_CREG_FAIL; //等待附着到网络

               }

            else { return SIM_OK; }

            }

         }

}  

   else{

     return SIM_CPIN_ERR; //有sim卡

     }

  }

else {

     return SIM_COMMUNTION_ERR; //通讯不上

   }

}

u8 sim900a_send_enmessage(void)

{ //设置短信模式

if(sim900a_send_cmd((u8 *)"AT+CMGF=1",(u8 *)"OK",100))

{  //设置为英文

  if(sim900a_send_cmd((u8 *)"AT+CSCS=\"GSM\"",(u8 *)"OK",100))

{

    if(sim900a_send_cmd((u8 *)"AT+CSCA?",(u8 *)"OK",100))

{//设置短信模式

        if(sim900a_send_cmd((u8 *)"AT+CSMP=17,167,0,241",(u8 *)"OK",100))

{//设置新消息提示

                 if(sim900a_send_cmd((u8 *)"AT+CNMI=2,2",(u8 *)"OK",200)) return SIM_OK;//设置短信自动上报

    else return SIM_CNMI_ERR;

}

else return SIM_CSMP_ERR;

  }

else return SIM_CSCA_ERR;

}

else return SIM_CSCS_ERR;

}

else return SIM_CMGF_ERR;

}

系统设置为短信模式自动上报,单片机接收玩短信数据后,我们在中断服务程序中添加一个标志,用于系统检测判断是否有短信输入,有短信输入则Flag_Rec_Message=1。然后直接对短信内容进行判断。

//定时器3中端服务程序     

void TIM3_IRQHandler(void)

{

if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)//是更新中断

{      

USART3_RX_STA|=1<<15; //标记接收完成

TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIM3更新中断标志   

TIM_Cmd(TIM3, DISABLE);  //关闭TIM3 

if(!USART3_RX_REC_ATCOMMAD)

{

USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符

USART3_RX_STA=0;

if(strstr((char*)USART3_RX_BUF,"CMT:")!=0) Flag_Rec_Message=1;//检测是否来短信

}

}     

}

第五章 汉字显示

汉字在液晶上的显示其实就是一些点的显示与不显示。所以要显示汉字,我们首先要知道汉字的点阵数据,这些数据可以由专门的软件来生成。只要知道了一个汉字点阵的生成方法,那么我们在程序里面就可以把这个点阵数据解析成一个汉字。STM32F4的汉字显示原理就是读取存在FLASH里面的字库,然后将汉字显示在LCD上面

汉字在各种文件里面的存储不是以点阵数据的形式存储的,而是以内码的形式存储的,就是GB2312/GBK/BIG5等这几种的一种,每个汉字对应着一个内码,在知道了内码之后再去字库里面查找这个汉字的点阵数据,然后在液晶上显示出来。单片机需要做的就是根据字内码去查找点阵库然后解析最后显示汉字

那么我们要解决的问题就是制作一个与汉字内码对得上号的汉字点阵库而且要方便单片机的查找。每个GBK码由2个字节组成,第一个字节为0X81~0XFE,第二个字节分为两部分,一是0X40~0X7E,二是0X80~0XFE。我们的点阵库按照这个编码规则,从0X8140开始逐一建立,每个区的点阵大小为每个汉字所用的字节数*190。这样,我们就可以得到在这个字库里面定位汉字的方法:

 当GBKL<0X7F时:Hp=((GBKH-0x81)*190+GBKL-0X40)*(size*2);

  当GBKL>0X80时:Hp=((GBKH-0x81)*190+GBKL-0X41)*(size*2);

其中GBKH、GBKL分别代表GBK的第一个字节和第二个字节(也就是高位和低位),size代表汉字字体的大小(比如16字体,12字体等),Hp则为对应汉字点阵数据在字库里面的起始地址(假设是从0开始存放)。这样我们只要得到了汉字的GBK码,从而实现汉字在液晶上的显示。字库的生成,我们要用到一款软件,由易木雨软件工作室设计的点阵字库生成器V3.8。该软件可以在WINDOWS系统下生成任意点阵大小的ASCII,GB2312(简体中文)、GBK(简体中文)等,具体操作可以上网查询这里不在叙述。需要注意的是,电脑端的字体大小与我们生成点阵大小的关系为:fsize=dsize*6/8其中,fsize是电脑端字体大小,dsize是点阵大小(12、16、24等)。所以16*16点阵大小对应的是12字体生成完以后,我们把文件名和后缀改成:GBK16.FON。同样的方法,生成12*12的点阵库(GBK12.FON)和24*24的点阵库(GBK24.FON),总共制作3个字库。做完字库后我们添加到我们的工程中就可以。具体可以参考正点原子STM32F4的汉字显示实验。

系统开机时我们还要对字库进行检测,防止字库丢失造成汉字显示失败。代码实现如下:

while(font_init()) 

{

UPD:   LCD_Clear(WHITE);     

  POINT_COLOR=RED;        

LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");

while(SD_Init()) 

{ LCD_ShowString(30,70,200,16,16,"SD Card Failed!");

     delay_ms(200);

     LCD_Fill(30,70,200+30,70+16,WHITE);

     delay_ms(200); }

LCD_ShowString(30,70,200,16,16,"SD Card OK");

LCD_ShowString(30,90,200,16,16,"Font Updating...");

key=update_font(20,110,16,"0:");

while(key)

{ LCD_ShowString(30,110,200,16,16,"Font Update Failed!");

delay_ms(200);

LCD_Fill(20,110,200+20,110+16,WHITE);

delay_ms(200); }   

LCD_ShowString(30,110,200,16,16,"Font Update Success!   ");

delay_ms(1500);

LCD_Clear(WHITE);    

}


第六章 总结与展望

本次作品以实用价值为目的开展的设计,满足智能家居控制系统的基本应用的同时,制作了具有良好的人机交互界面,操作更加人性化,方便用户的输入控制。经过此次设计,使我对嵌入式开发的基本流程有了更深的了解,强化了自己对代码的编写能力。在编写程序的过程中,经常会遇到自己没了解过的知识领域,为了实现其功能往往需要通过查阅大量的文献还有查看网上的例程,才能一步步地去解决所遇到的困难。这让我认识到完成一个作品的不容易。这不仅锻炼我的毅力还增加实操的能力,在这个过程中也学到了的很多知识,为将来投入相关工作积累了经验。未来如果想要从事该相关行业的开发工作,还需要不断地学习,增长自己的见识和能力。

视频展示:

https://www.bilibili.com/video/BV1Cd4y1K74d?spm_id_from=333.999.list.card_archive.click&vd_source=ce938dcfefa882fd4e0688c4edbc195ez

资料包:

https://download.csdn.net/download/m0_54185043/86268384

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/424215
推荐阅读
相关标签
  

闽ICP备14008679号