单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 782|回复: 3
打印 上一主题 下一主题
收起左侧

基于STM32+GPRS的智能家居控制系统程序源码+设计论文分享

[复制链接]
跳转到指定楼层
楼主
基于STM32的智能家居系统设计

摘要
本文设计介绍一种以stm32 单片机为核心,设计了一套基于GPRS无线网络的智能家居控制系统。该系统以GPRS通信为基础、能通过无线通信技术实时监控家居的温湿度状态,并能自由控制家居的电器的开关操作。同时集成光强采集电路,能自动开关窗帘的功能。

本设计硬件电路结构简单,分为控制器模块,GPRS模块,继电器控制模块,步进电机控制模块等五大电路模块,其中控制器选用基于cotex-m3内核的32位微控制器STM32F103R8T6。GPRS模块选用SIM900模块,人机交互模块选用OLED12864模块显示数据,独立键盘作为输入设备,继电器控制输出控制家电电路开关。最终通过系统的测试,本设计实现的功能包括:窗帘电机检测当前光照强度或者湿度情况实现自动开闭以及本地按键控制开闭、GSM短信远程控制继电器的开闭、室内温度异常时的GSM短信通知。

Design of Intelligent Home System Based on STM32
Abstract:This paper introduces a kind of intelligent home control system based on GPRS wireless network with stm32 single chip as the core. The system based on GPRS communication, wireless communication technology can be real-time monitoring of home temperature and humidity status, and can freely control the home electrical switch operation, the use of stm32 internal calendar to achieve effective time management of household appliances, while integrated light Acquisition circuit, can automatically switch the function of the window.
The design of the hardware circuit is simple, divided into controller module, GPRS module, relay control module, stepper motor control module and other five circuit modules, including controller based on cotex-m3 core 32-bit microcontroller STM32F103R8T6. GPRS module selection SIM900 module, human-computer interaction module selection OLED12864 module display data, independent keyboard as input device, relay control output control home appliance circuit switch. Finally, through the system test, the design of the realization of the functions include: the curtain motor to detect the current light intensity or humidity to achieve automatic opening and closing and local key control open and close, GSM SMS remote control relay opening and closing, indoor temperature abnormal GSM SMS notification

目录
第1章  前言
1.1 课题研究的背景和实际意义
1.1.1课题背景
1.1.2实际意义
1.2国内外发展现状、存在问题以及前景
1.2.1发展现状
1.2.2存在问题
1.2.3发展前景
1.3 主要工作、内容安排及预期成果
1.3.1主要研究工作
1.3.2预期成果
第2章 总体设计方案
2.1 系统总体方案设计
2.2 系统方案选择
2.2.1 无线通讯方案选择
2.2.2              显示器方案选择
第3章 系统硬件设计
3.1 控制单元模块
3.2 人机交互模块
3.3 GPRS电路设计
3.4 温湿度传感器电路设计
3.5 光强检测电路设计
3.6 窗帘控制电路设计
3.6.1 步进电机的选用
3.6.2 步进电机28BYJ-48介绍
3.6.3 步进电机驱动
3.7 继电器驱动电路设计
3.8 电源电路设计
第4章 系统软件设计
4.1 软件开发环境介绍
4.2 软件总体设计
4.2.1 程序结构分析
4.2.2 主程序设计
4.2.3 OLED驱动程序分析
4.2.4 SIM900通信程序设计
第5章  系统调试与结果分析
5.1 程序仿真设计
5.2 实物调试
结论
致谢
参考文献

第1章 前 言
1.1 课题研究的背景和实际意义

1.1.1 课题背景

智能家居是在以原有传统住宅为基础,添加了网络通信、智控家电、大规模传感网络等模块设施的新型居住环境。这种新型家居环境的特点是集服务、系统控制、设施为一体,优点是舒适便捷、安全环保。系统既包含分布家居各个部位和设备上的传感器网络系统,还包括中央控制系统、计算机网络系统和网络通信系统。用户通过手机、电脑等终端设备以及网络通信系统实现对室内家电进行本地或远程控制。智能家居系统通常可以实现监控功能:室内烟雾、煤气检测及门窗监控等;远程控制功能:开闭家电、远程收水电费等。智能家居具有可定制性,即可根据不同客户的家居需求、预算及住房条件来设计不同的设计方案。
在20世纪80年代初,在美国业内就提出了Smart Home的概念,即智能家居的原型。然而在很长一段时间内没有具体的建筑案例问世。直到1984年,在建设美国康涅狄格州(Connecticut)哈特佛市(Hartford)的CityPlaceBuilding时,美国联合科技公司(United Technologies Building System)把建筑设备信息化、智控化应用于这项工程,才出现了第一项的“智能化建筑”工程,由此将智能家居行业的发展和需求推到了全世界面前。
1.1.2 实际意义

经济的飞速发展使人们对家居环境的要求日趋上涨与当前智能家居所产生的发展瓶颈形成尖锐的矛盾,将迫切地驱使智能家居技术有进一步的飞跃。本课题的实际意义就在于通过对智能家居控制系统的了解及基础应用,有助于读者的智能家居概念启蒙和深入理解,激发读者对智能家居控制系统的研究兴趣。其次,从工程意义上讲,本文所介绍的基于stm32控制器的和GPRS网络通信控制的家居环境监测及家居电器开关控制系统是在一定程度可用于实践的,以此来满足人们生活的多样化需要,提升人们的生活质量。
1.2 国内外发展现状、存在问题以及前景

1.2.1 发展现状

国际市场上看,由于发展开始较早且大量的研发资源投入,美国以及一些欧洲国家在智能家居研发技术和市场比例一直走在世界前列。而发展近期,欧美一些顶尖研发公司投入到智能家居市场中来,极大地推动了智能家居的发展进程,同时也上线了一些可规模生产的实用项目。如“梦幻之家”、“居所之门”、“家庭主任”等。除此之外,亚太地区日、韩、新等国的相关前沿企业也正为智能家居研发作大规模投入。
而国内,信息化的春风走进了千家万户为中国智能家居的发展能追上国际发展脚步提供了可能。进年来,国家也越来越注重国内智能家居的发展。但由于我国智能家居发展起步较晚,还尚未形成合理统一的国家标准,所以还需克服很多标准上技术上的难关。目前,国内智能家居市场也开发出了以海尔企业的e家庭和清华同方企业的e-home为代表的智能家居产品。
1.2.2 存在问题

目前存在的智能家居系统产品自身性能与消费者的要求相去甚远,这样的矛盾在很大程度阻碍了智能家居的发展。具体情况如下:
①人们对于智能家居的期望过大导致智能家居功能过于理想化。而广告商对智能家居不切实际的宣传加剧了这一现象。在技术落后的发展现状面前,这就形成了一个形式大于实际效果的尖锐矛盾。
②智能家居行业还没有建立起统一的标准和协议。智能家居的各个研发行业均开发了属于自己产品的协议标准,这样导致各产品整合、关联时出现不兼容的现象。所以,要综合各研发行业的成果来进一步推进智能家居的发展必须建立统一的标准协议。
③作为新颖的研发行业,智能家居的发展是建立在大量科研前沿的技术和成果上的,所以要大规模发展智能家居必然导致巨额的推广和普及成本。要想使智能家居大规模普及实用,价格问题不同忽视。
1.2.3 发展前景

曾几何时,智能家居仅仅是一个寄托了人们对未来生活想象的抽象概念。而时至今日,在科技发展的推动下,人们生活品质在一波又一波的智能浪潮中获得提升。如今,智能家居行业已经处于快速发展轨道且效用日益在人们生活中扩大化,但前文中提到的当下出现的问题决定了智能家居行业还有很长的路要走,并且这条路会越走越宽,前景大好。
放眼于国内,自从引入智能家居以来,由于诸多原因,国内智能家居行业发展一直不愠不火。目前国内行业正进入了一个发展期的临界点,领头企业所推出的相关智能产品一直处于争议状态,而市场消费观念还尚未形成。但在未来发展中,消费者认知的提高和观念的转变以及相关政策的鼓励一定会大大地推进智能家居的发展。除此之外,现代网络技术、电子信息科学技术及物联网技术的发展与成熟,也将给传统智能家居提供源源不断的发展动力,为其指明发展变革的道路。
1.3 主要工作、内容安排及预期成果

1.3.1 主要研究工作

消费者们对于智能家居呈现出一种多样化的迫切性需求,一方面是居住环境的安全性,体现在门窗安全、煤气泄漏及火灾隐患自动报警等要求;另一方面是居住环境的舒适便捷性,体现在无线通信的控制方式、室内灯光以及直观性人机交互操作等方面。
在了解到消费者对智能家居实质性需求的基础上,结合本人自身的开发能力,本课题最终确定研究的简易智能家居控制系统涵盖了如下几个模块:传感器模块、控制器模块,GPRS通讯模块,继电器输出控制模块,显示器模块等五大电路模块。本系统主要是侧重点是在远程报警(室内温度异常时,通过GPRS通讯模块向手机发送报警短信)和远程控制(需要时,远程终端通过GPRS通讯模块向本地控制器发送控制指令,控制继电器开闭)方面。除此之外,还有窗帘根据光照强度自动开闭以及本地按键执行中断控制(应用于特殊情况,如自动控制出错时)。
1.3.2预期成果

通过本系统设计各个模块的搭建,预计能够实现如下功能:
1、本地温度湿度报警器实时监测室内情况,当温度异常时发送室内实时数据到设定手机上;测量范围为湿度:20~90%RH;温度:0~50℃。所以本设计使用范围广泛,既可用于气候干燥的北方,也可用于较为湿润的南方;既可适用于工地环境,也可用于婴儿房环境;
2、窗帘的自动控制和按键控制(本设计中用电机正反转表示窗帘的开闭),这个功能解决了用户频繁手动打开窗帘的麻烦。日常生活中,当遇到有强光的晴天,本设计的窗帘则能自动关闭,减少用户亲自打开窗帘的麻烦,遇到相反情况则相反处理。此外设计的按键控制窗帘,也可减少用户手拨窗帘的不便;
3、手机发送控制指令的短信到GPRS通讯模块,实现继电器的开闭。本设计用两个发光二极管代替所控制的家电,实际应用中,可通过继电器控制空调、电饭煲等家用电器。例如炎炎夏季,空调制冷需要一定时间,用户在回家前提前远程控制空调打开,回家即可享受到冰爽的体验。

第2章 总体设计方案2.1 系统总体方案设计
本设计硬件电路结构包含6个部分,分别是STM32控制器、输入部分、输出部分、电源模块、环境探测、SIM900无线通讯。其中控制器选用32位微控制器STM32F103R8T6OLED显示器;输入部分包含按键输入、SMS指令输入;输出部分包含0.96寸12864 OLED显示器、继电器输出、窗帘控制输出;环境探测包含一体化温湿度检测模块DHT11、光强检测4线制光敏传感器模块。结构框图如下图1.1所示。
光强检测选用的是光感电阻传感器模块,可输出模拟量(电压)至STM32控制器处理后由OLED显示器显示出当前光照强度,同时输出经比较器LM393比较后输出的开关量(0或1)至STM32来控制窗帘的开关从而控制家居的通光率。在系统接通电源开始运行后,控制器通过串口访问SIM900通讯模块,不断判断是否收到绑定手机发送的短信指令,若接受到有效命令则解析指令控制继电器的开闭,从而达到控制家电开闭的目的。在系统工作过程中,温湿度传感器DHT11不断采集环境的实时温湿度并通过串口送入控制器。设置阈值来判别正常和异常情况,当发现异常时触发SIM900模块向设定手机号发送状态信息。此外,系统通过按键扫描的方式实现人机交互,控制器响应按键输入同时控制OLED显示各类相关数据信息。
2.2 系统方案选择2.2.1 远程通信方案选择
方案一、以太网。现如今,光纤和宽带的大规模建设和普及使无线网络几乎已经覆盖了城市绝大部分区域。所以使用智能终端直接通过wifi网络通信实现远程控制家居电器不得不算是一种可行的方法。
方案二、GPRS网络。利用已建立的GPRS通信网络,通过收发短信讯息和指令来完成远程的人机交互。
相较之下,互联网络明显的弊端是是节点的生产成本高;其次,单一wifi网络覆盖十分有限,且网络稳定性并不确定,会给系统带来不稳定因素;再者,由于互联网涉及的控制环节较多,实现的技术要求更高、难度更大。相较于互联网络,支持手机通讯的GPRS网络有着更为广泛的覆盖率。根据中国移动公司公示的统计数据,中国的GPRS网络覆盖率已经达到98%以上。所以,借由GPRS为载体网络的家居控制更具可行性和可推广性。而且GPRS成本更低,技术水平要求更低。因此本设计选择以GPRS网络的方式实现无线通信。
2.2.2 显示器方案选择
方案一:七段数码管显示;
方案二:OLED液晶屏显示。
相较之下,LED的优点是硬件设计简单,成本相对较低,但缺点是只能显示数字而不能显示字符,不能实现更为复杂多样的功能。当显示大数据时,需要使用另外的编码器进行设计,占用了大量的软件资源。而OLED的优点是节省电能、显示功能广泛、携带方便易封装、可视角度大。最大支持64个字符显示,4行显示,每行16字符。自带字体库,并且支持所有ASCII码。一般采用SPI数据通讯方式,可将主控器的I/O端直接接入OLED的端口即可实现数据显示,并保存当前显示状态。因此综合考虑到本设计的实用性,选用OLED作为显示器。

第3章 系统硬件设计
本设计的硬件部分包括控制单元模块、人机交互模块、无线通信模块(GPRS)、执行模块(步进电机)、传感器模块(温湿度检测、光照检测)
本章主要内容是将各个模块进行拆分阐述和基本介绍。
3.1 控制单元模块
本设计采用的控制器是一款基于arm核和cotex-m3架构技术的32位控制器。支持传统Thumb和新型Thumb-2指令的译码器,采用三级流水线指令作业方式,内部PLL技术,最高运行频率达72MHZ。并且内部资源丰富,内置有128K的flash,多达20K的运行RAM,集成多路定时器,12位的AD转换器,多达9个通信接口和USB2.0接口,内嵌经出厂调教的8MHz的RC振荡器。支持串行单线调试(SWD)和JTAG接口技术,支持睡眠、停机和待机模式,其采用ECOPACK封装。被告广泛应用于便携式穿戴设备上。
主控制器及其电路是整个电路的核心,负责着整个系统的资源调度和计算控制。如图3-1所示为主控制器模块电路图,其中主控制器型号为STM32F103R8T6,按键S1为复位按键,Y1为晶振。
本设计的晶振选用8MHz无源外部晶振,选用22P的C11,C13为起振电筒。整个外部时钟电路为控制器提供一个8MHz的稳定的时钟源。再经内部配置PLL,使控制器运行在72MHZ工作频率。为了方便起振,起振电容选用22pF。图中Y2为万年历时钟电路,BT1为万年历备用电池,当主机电源关闭时,自动切换到电池供电,以保证万年历数据不丢失。虽然本设计使用控制器的万年历,但硬件上留有设置口,为日常升级使用。R18为0欧电阻,可以适应吸取一些微小信号。滤除低频噪声使用10uF的大电容C15,滤除高频噪声使用104的小电容C16,电容C15,C16构成退耦滤波电路,减小电路的波动从而提高电路稳定性。BOOT0,和BOOT1引脚均通过下拉电阻至地,使主控制器工作在用户闪存启动模式。复位电路由104的小电容C10和10k电阻R11构成:上电后,电容充电,STM32的RESET复位引脚高电平;充电结束,复位端RESET低电平,充电过程在STM32复位端形成下降沿脉冲实现复位。当按键S1按下后,电容端的电压对释放,RESET端重新出现高电平,松开后,C10电容重新被充电,因此RESET再次出现一低电平脉冲,使得MCU复位
3.2 人机交互模块
显示原理图如下图2-2所示。
人机交互模块有按键和显示分别作为输入输出。由于需要设定万年历时间,温湿度异常报警,主机手机号等参数,系统设定三个按键完成人机输出。R20,R21,R22为上拉电阻,当按键弹开为,输入至MCU引脚为高电平,当按键按下,由于S2另一端接地,输入至MCU引脚变低电平。控制器通过采集输入引脚PB8,PB9,PB10可以获知按键输入状态。
OLED显示器是本次设计输出器的重要部分,采用四行显示,显示内容包括实时光照强度、年月时间、实时温湿度指数、短信接受号码、继电器开关状态。
OLED显示器采用SPI数据通讯方式一共有7个引脚,1,2脚为供电引脚,3号脚为SDI脚接到MCU,PB15脚(亦为SPI2_MOSI脚),4号脚为SCL脚接至MCU的P14脚(亦为SPI2_MISO脚),5号脚为SCK接至MCU的P12脚(亦为SPI2_SCK脚),6号脚为RESET脚,由于复位电平方式与主控制器兼容,直接接至主控制器RESET端。7号脚为A0脚为数据/命令选择口脚接至MCU的PB11脚。
3.3 GPRS电路设计
作为整个设计的无线通信模块,GSM模块的完备对是否能实现远程控制功能有着至关重要的影响。本设计选用集成化的GSM模块,型号是SIM900。采用标准的AT指令操作接受和发送短信指令,模块解码后发送至STM32主控制器执行控制操作。本设计中最为核心的功能即是短信指令控制继电器的开关,继而达到远程操控家电的目的。(本设计硬件电路中用发光二级管的开闭代替家电的开关)。
GSM使用短信指令实现控制,操作便捷,发送短信仅需要3条指令。GSM通信应用广泛,目前应用短信控制开关、气象数据监测、全球远距离无线通讯。本模块支持900~1800频段,包括中国移动与中国联通。SIM900模块与STM32控制器采用串口直连的方式,方便美观。SIM900模块包含六个引脚:GND(电源负极)、RX(模块接收端:对应STM32的TX 端口)、TX(模块发射端)、KEY(启动引脚:接地释放启动和一直接地实现上电自启)、VCC(模块供电端:电压范围3.7~4.2V)。SIM900模块连接图见图3-3。
3.4 温湿度传感器电路设计
温湿度采集是主要的输入信号之一,通过设定阈值来触发GSM模块向设定手机发送报警短信。本设计默认设定温度阈值为40℃,默认湿度阈值为60RH。此外,可根据具体情况,通过电路板上的设置按键设定所需温湿度阈值。
查阅DHT11官方数据手册可知此检测模块封装形式采用4针单排直插;测量范围是:湿度(20-90%)、温度(0-50℃);湿度检测精度可到到±5%RH,温度检测精度可达±2℃;分辨力位1。
传感器包含4个引脚,分别是电源引脚、串行数据总线、悬空引脚、接地引脚,其电路图如下图3-4所示。温湿度传感器供电电压范围为3.3V~5.5V。由于是单总线数据传输方式,并且通过判断高电平时间来区分高低电平,所以此检测模块的优点是数据传输距离长,现场温湿度监控有良好的应用效果。采用数字输出接口经上拉电阻R22后接入STM32的PB5引脚。上拉电阻的大小是由信号线的长度来决定的,两者呈反比关系,即信号线越长时,电阻越小;信号线越短,电阻越大。
3.5 光强检测电路设计
光强检测电路是实现窗帘自动开闭重要的前端电路,本次设计采用光敏电阻式模块化传感器,原理图见下图3-5。
集成化模块-输出可以直接与主控制器或者A/D连接。光照强度较低时(低于预设值),传感器的D0端输出高电平;光照强度较高(高于预设值),传感器的D1端输出低电平。本设计将可采集到的光照强度划分成20个光强等级,采集范围从0 Lux开始,1000Lux为一个跨度,超过20000Lux只显示等级20。本设计默认设定光强阈值为16个光强等级单位。
3.6 窗帘控制电路设计3.6.1 步进电机的选用
对步进电机和直流电机简单比较有如下结论:
①当步进电机锁定位置时,电机不再耗电;
②步进电机体积小、寿命长;
③步进电机成本低廉、驱动简单;
④步进电机定位控制精确,直流电机定位控制误差较大;
⑤驱动方式不同:步进电机驱动方法的分类主要有恒电压驱动方式,直流电机驱动方法是有刷驱动和无刷驱动;
⑥控制方式不同:步进电机开环操作、直接控制,直流电机加反馈间接控制;
综合分析直流电机和交流电机的优缺点以及本设计的高精度要求,选用步进电机。且确定型号为28BYJ-48。
3.6.2 步进电机28BYJ-48介绍
首先了解型号中各位数字字母包含的具体含义:28——步进电机的有效最大外径是 28 毫米;B——表示是步进电机;Y——表示是永磁式;J——表示是减速型;48——表示四相八拍。参数见表3-1。

表格3-1 步进电机参数

电机型号
电压V
相数
相电阻Ω
±10%
步距角度
减速比
起动转矩
100P.P.S
g.cm
起动频率P.P.S
定位转矩g.cm
摩擦转矩g.cm
噪声dB
绝缘介电强度
28BYJ-48
5
4
300
5.625/64
1:64
≥300
≥550
≥300
≤35
600VAC1S

3.6.3 步进电机驱动
本设计采用小型步进电机进行模拟。考虑到窗帘需要打开和关闭。其执行电机必须实现正反转控制。因此采用步进电机构成的开环控制系统实现。采用5V供电的四相步进电机作为执行机构。采用ULN2004作为驱动器件,组成窗帘控制电路。步进电机驱动方法如下表3-2,驱动原理如下图3-6。

表格3-2 步进电机的驱动方法

导线颜色
1
2
3
4
5
6
7
8
6红
4橙






3黄





2粉





1蓝






3.7 继电器驱动电路设计
继电器作为本设计的输出控制模块,接收STM主控制器传输来的高低电平信号来控制家电。设计用L1和L3的亮灭表示继电器的开闭。驱动电路如图3-7所示。
由于继电器的功率较大,本设计中采用8050和8550组成达林顿管方式来驱动,它的最大集电极电流可以达到1A。继电器线圈从通电到断开电感电流不能突变,所以需要一个电流泄放回路。二极管Q1,Q3采用二极管IN4007对继电器的线圈进行续流。R13,R17为限流电阻,使三极管工作在放大区。R9,L2,R14,L3构成继电器工作指示电路。
3.8 电源电路设计
电源模块的主要作用是为整个系统供电,保证系统工作稳定。本系统需要两种电压:SIM900模块工作的3.7V~4.2V、MCU的3.3V工作电压。因此系统直接采用12V电压输入,由LM2596-ADJ芯片构成的固定频率开关降压稳压电路后,得到4.2V直流电压,为SIM900模块提供工作电压. 电路中通过调节R2电阻,可调节输出电压。主机电源模块电路如图3-8所示。
线性低压差三端稳压器LM1117的作用是将4.2V电压转换成3.3V电压,继而给STM32控制器、各部分传感模块、OLED显示模块等供电。大电容C5、C6的作用是滤除低频电源纹波,小电容C7、C8的作用是滤除高频噪声,外加0欧电阻,使得电源抗干扰能力更强。BT1为电池,为另一种系统供电方式。电阻R8和二极管D2构成电源指示电路。


第4章 系统软件设计
4.1 软件开发环境介绍
本设计中选用KEIL公司推出名为MDK的编译器。其主要指向是arm核控制器开发的集成开发环境作为主机程序设计。Keil MDK软件为基于Cortex-M、Cortex-R4、ARM7、ARM9处理器的设备创造了完整的开发环境。
MDK的功能特点:
●支持的器件库丰富,包括Cortex-M、Cortex-R4、ARM7等系列;
●可使用C/C++语言编程,使用受众广泛易于上手;
●小封装实时操作系统;
●μVision4 IDE集成开发环境,调试器和仿真环境;
●TCP/IP网络套件提供多种的协议和各种应用;
●提供带标准驱动类的USB 设备和USB 主机栈;
●完善的GUI库支持;
●符合CMSIS (Cortex微控制器软件接口标准)。
4.2 软件总体设计4.2.1 程序结构分析
软件设计的主要任务有:
1)从SIM900 GPRS模块读取短信,并进行判断,从而对家用电器进行开关控制;
2)采集光照强度,实现家居光照率自动控制;
3)采集温湿度值,判断发生异常时,触发短息报警通知主机;
4)读取主控器万年历时钟,对家用电器进行时间段开关管理;
5)按键扫描,将实时的数据信息和操作消息显示在OLED屏上。
4.2.2 主程序设计
为了使温湿度以及光照采集新的信息能实时地进行传输和处理,本设计的程序通过循环扫描对光敏电阻传感模块和DHT11传感模块进行数据采集。主程序功能实现系统的初始化,之后再进行功能模块的运行。因而主程序需要完成的设置任务是系统各部分初始化、进行人机交互。主程序流程图如图4-1所示。
系统开始运行后,首先进行系统的初始化,包括相关系统参数的初始化、OLED模块的初始化、I/O串口的配置和初始化、RTC及ADC的初始化。完成初始化后,程序开始循环扫描,首先读取DHT11传感器采集处理的温湿度数据,STM32控制器进行数据分析后逻辑判断温湿度情况是否正常。若判断出异常,控制器置异常标志位,控制SIM900模块周期性向设定手机发送提醒短信。程序不断访问SIM900模块,随时准备接受短信并解码,解码到有效指令则控制相关模块输出。若对指令不予处理,程序开始进行扫描响应按键。程序中设置有五个按键输入,其中两个执行中断操作,实现中断控制窗帘的开闭,其余三个按键输入用于参数、模式的设置,包括温湿度阈值设置、光照强度阈值设置。接着程序获取万年历时间,若到达设定开机时间或者关机时间,则控制继电器输出变化。最后程序指令STM32控制器根据采集的信息控制显示器显示实时温湿度值、预设定手机号码、继电器状态、万年历时间及GSM模块工作状态。
4.2.3 OLED驱动分析
OLED采用SPI数据通讯协议。驱动程序关键在于OLED读写时序。本设计功能中,程序只需要实现实时写入数据,用于OLED显示,达到人机交互的目的。OLED的时序图如图4-2所示,对时序图详细分析后再模拟时序编程就能驱动显示器了。
4.2.4 SIM900通信程序设计
SIM900模块支持AT串口指令集,对SIM900进行访问相当于对STM32 I/O口的访问。所以通过AT指令,即可以实现控制SIM900的短信发送和读取。下面介绍与短信发送和读取的AT命令:AT+CMGF=?——选择模式;AT+CMGS——发送一条SMS;AT+CMGR——读取一条SMS;AT+CMGD ——删除一条SMS;
在本设计中,SIM900串口通讯协议为9600波特率,8位数据位,无校验,1位停止位。系统启动后先初始化SIM900 模块,内容包括设置短信模式、接收短信模式方式等。运行过程中,程序不断扫描串口,当串口接收到由于接收到含有“+CMTI”字符的短信后,程序则会进入读取短信的过程。这是由于当模块接收到短信后,SIM900会经过串口向主控制器传送“+CMTI: "SM",1”的命令,通过接收指令即可判断是否接收到短信。读取短信时,SIM900又会发送字符为“AT+CMGR=1”的指令,将信息读出并根据信息内容判断对继电器的开闭操作,以此实现远程家电的控制功能。

第5章  系统调试与结果分析
通过实际测试,本次设计出的基于stm32的智能家居系统能接收短息,并响应有效的命令,对继电器进行控制,实现家用电器的开关控制,并且能够根据光照强度,实现窗帘的自动开关,并切确地对时间响应,在设定时间段打开继电器。
5.1 程序仿真设计
1、系统仿真采用仿真软件Proteus7.0。仿真开始测试图(lcd屏显示初始,温湿度感测值,状态值)如图5-1所示。
2、调整湿度值,湿度过高,电机反转关窗测试图,见下图5-2。
5.2 实物调试
实物图通电后,等待各个模块启动,在OLED显示器上显示当前室内环境的实时数据。
1、报警调试:用打火机提高检测环境温度,超过预设阈值(35℃),STM32控制GPRS模块向设定手机(184****5651)发送报警短信,见下图5-3。
2、窗帘控制调试:打开闪光灯增强光照传感器探测环境光强,电机正转表示窗帘关闭,OLED显示器显示窗帘关闭,见图5-4。

3、家电开光调试:用设定手机(184****5651)向GPRS通讯模块的手机号(155****3582)发送指令短信“2 Open”,打开继电器2的发光二极管,见图5-5所示。
结论

本次设计完成了一个基于STM32控制芯片的简易智能家居系统,其核心功能主要是实现实时的环境监测并显示,当环境温度或者湿度超过设定值时判定为异常情况并向设定手机发送报警信息,其次实现光控窗帘的自动控制和按键控制功能,再次实现设定手机向GSM模块发送控制指令打开继电器。由于设计中所用到的核心主控制器STM32芯片以及GSM模块都是本科期间未学习的课程,所以是本次设计工作需要大量重零学习的过程,也遇到了很多的困难。

通过本次设计, 本人不仅将以前学习的理论知识应用于实际,还对自己的动手能力有较大提升。除此之外,本人还深深意识到查阅其他相关论文文献对于丰富自身知识和建立设计思路的重要性。所以,检索文献资料对于我们也是相当重要的技能。而经过这次毕业设计,也学会了利用网络和图书馆等资源来帮助自己完成作品。


致谢

时间如白驹过隙,悄无声息地从指缝中溜走。在四年大学生活的末尾,我完成了能够证明四年青春的毕业设计和论文。至此,衷心地感谢一如既往支持我学习的家人、陪伴我成长的同学们以及孜孜不倦地指导我学习的老师们。

其次,特别感谢高雪菲老师。从选定课题开始到毕业论文定稿,高老师的严格要求和监督都激励我不断学习和进步。在做毕业设计过程中,遇到了很多的问题,甚至曾好几次因理解不了器件的使用方法我都萌生放弃的念头,这时高雪菲老师不仅提供给我专业知识的帮助和设计方面的建议,还不断鼓励我克服困难,把遇到的困难最后转化成工程设计的经验。

接着,是学校和学院给提供了毕业设计这样一个平台来让大家有机会综合整理自己大学四年所学的知识并用于实践中,所以在此也要向学校表达我的感谢。在同学们即将步入社会之际,这样一个过程能够提高我们的学习能力和适应工程设计开发的能力。

最后,还要感谢那些共同为毕业设计挑灯奋战的同学们,你们不单单是在毕业设计中给我提供了很多宝贵意见和实质帮助。更多的是在我沮丧的时候给予的鼓励。没有大家,我很难独立完成这次设计,在此真诚的感谢你们。


单片机程序源码如下:


  1. //头文件调用
  2. #include "usually.h"
  3. #include "usart.h"
  4. #include "oled.h"
  5. #include "dht11.h"
  6. #include "rtc.h"
  7. #include "delay.h"
  8. #include "stm32f10x_adc.h"
  9. #include <string.h>
  10. #include "BSP_Config.h"
  11. #include "gpio.h"
  12. #include "gsm.h"


  13. //宏定义
  14. #define ADC_CH0  0 //通道0
  15. #define ADC_CH1  1 //通道1
  16. #define ADC_CH2  2 //通道2
  17. #define ADC_CH3  3 //通道3        


  18. #define SEC 0
  19. #define MIN 1
  20. #define HOUR 2
  21. #define DATE 3
  22. #define MON 4
  23. #define YEAR 6

  24. #define MODE_NORMAL 0
  25. #define MODE_SET_HOUR 1
  26. #define MODE_SET_MIN 2
  27. #define MODE_SET_SEC 3
  28. #define MODE_SET_YEAR 4
  29. #define MODE_SET_MON 5
  30. #define MODE_SET_DATE 6
  31. #define MODE_SET_HUMI_HIGH 8
  32. #define MODE_SET_TEMP_HIGH 7
  33. #define MODE_SET_LIGHT 9


  34. #define KEY_MENU_IN PBin(0)
  35. #define KEY_ADD_IN PBin(1)
  36. #define KEY_SUB_IN PBin(2)

  37. //步进控制 A-AB-B-BC-C-CD-D-DA
  38. #define Motor1_A_run  { GPIO_SetBits(GPIOB,GPIO_Pin_8);  GPIO_ResetBits(GPIOB,GPIO_Pin_9);GPIO_ResetBits(GPIOB,GPIO_Pin_10);GPIO_ResetBits(GPIOB,GPIO_Pin_11);}
  39. #define Motor1_AB_run { GPIO_SetBits(GPIOB,GPIO_Pin_8);  GPIO_SetBits(GPIOB,GPIO_Pin_9);  GPIO_ResetBits(GPIOB,GPIO_Pin_10);GPIO_ResetBits(GPIOB,GPIO_Pin_11);}
  40. #define Motor1_B_run  { GPIO_ResetBits(GPIOB,GPIO_Pin_8);GPIO_SetBits(GPIOB,GPIO_Pin_9);  GPIO_ResetBits(GPIOB,GPIO_Pin_10);GPIO_ResetBits(GPIOB,GPIO_Pin_11);}
  41. #define Motor1_BC_run { GPIO_ResetBits(GPIOB,GPIO_Pin_8);GPIO_SetBits(GPIOB,GPIO_Pin_9);  GPIO_SetBits(GPIOB,GPIO_Pin_10);  GPIO_ResetBits(GPIOB,GPIO_Pin_11);}
  42. #define Motor1_C_run  { GPIO_ResetBits(GPIOB,GPIO_Pin_8);GPIO_ResetBits(GPIOB,GPIO_Pin_9);GPIO_SetBits(GPIOB,GPIO_Pin_10);  GPIO_ResetBits(GPIOB,GPIO_Pin_11);}
  43. #define Motor1_CD_run { GPIO_ResetBits(GPIOB,GPIO_Pin_8);GPIO_ResetBits(GPIOB,GPIO_Pin_9);GPIO_SetBits(GPIOB,GPIO_Pin_10);  GPIO_SetBits(GPIOB,GPIO_Pin_11);}
  44. #define Motor1_D_run  { GPIO_ResetBits(GPIOB,GPIO_Pin_8);GPIO_ResetBits(GPIOB,GPIO_Pin_9);GPIO_ResetBits(GPIOB,GPIO_Pin_10);GPIO_SetBits(GPIOB,GPIO_Pin_11);}
  45. #define Motor1_DA_run { GPIO_SetBits(GPIOB,GPIO_Pin_8);  GPIO_ResetBits(GPIOB,GPIO_Pin_9);GPIO_ResetBits(GPIOB,GPIO_Pin_10);GPIO_SetBits(GPIOB,GPIO_Pin_11);}
  46. #define Motor1_STOP_run { GPIO_ResetBits(GPIOB,GPIO_Pin_8);  GPIO_ResetBits(GPIOB,GPIO_Pin_9);GPIO_ResetBits(GPIOB,GPIO_Pin_10);GPIO_ResetBits(GPIOB,GPIO_Pin_11);}


  47. #define motorSpdDelayUs  1100
  48. //声明变量
  49. extern struct Data_Time  timer;
  50. unsigned char *pUart1_Rxd;//接收数据指针
  51. unsigned int  uart1_RxNum=0;//串口1接收字数
  52. unsigned char Num_TXD=0;//串口1发送缓冲区的字节数
  53. unsigned char Uart1_TxBuf[256]={0,2,3,};//串口1发送缓冲区
  54. unsigned char Uart1_RxBuf[256]; //串口1接收缓冲区

  55. unsigned char *pUart2_Rxd;                        //串口2接收数据指针
  56. unsigned int  uart2_RxNum=0;         //串口2接收字数
  57. unsigned char uart2_TxNum=0;         //串口2发送缓冲区的字节数
  58. unsigned char Uart2_TxBuf[256]={0,2,3,};//串口2发送缓冲区
  59. unsigned char Uart2_RxBuf[256]; //串口2接收缓冲区

  60. //变量声明
  61. //extern struct tm  timer;
  62. char line1str[17]="Welcome to use!";
  63. char line2str[17]="Wating gsm... ";
  64. char line3str[17]="              ";
  65. char line4str[17]="              ";
  66. uint8_t dht11_buf[5];
  67. uint8_t nowtemp,nowhumi;//当前温湿度值
  68. uint8_t thalmflg;  //温湿度过高报警
  69. uint16_t adtemp[12]={0};  //连续采集12点算平均值
  70. uint16_t light_adc,set_lit_high,lit_high;
  71. uint8_t almtmp_high,almhumi_high;
  72. uint8_t mode_status; //模式
  73. uint8_t flashflg; //模式
  74. uint8_t settimeflg;        //时间被设置标志位
  75. uint8_t solid1flg,solid2flg,winflg;
  76. unsigned char settime[8]={0x00,30,12,0x6,10,0x01,15};//??sec,min,hour,date,month,week,year
  77. char recephonenum[12]="13538510586";
  78. char phonenum_flash;
  79. uint8_t adci=0;
  80. char strLs[32];
  81. //按键输入初始化
  82. void Key_init(void){
  83.         
  84.   GPIO_InitTypeDef  GPIO_InitStructure;
  85.         
  86.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);         //使能PB端口时钟
  87.         //Configure pin Pb1 as output
  88.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;                //PA13,PA14,PA15按键输入
  89.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  90.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;         //上拉输入        
  91.         GPIO_Init(GPIOB,&GPIO_InitStructure);        
  92.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  93.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  94.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;         //上拉输入
  95.         GPIO_Init(GPIOB,&GPIO_InitStructure);        
  96.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  97.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  98.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;         //上拉输入
  99.         GPIO_Init(GPIOB,&GPIO_InitStructure);        

  100. }

  101. //继电器输出IO初始化
  102. void Solid_Init(){
  103.         
  104.   GPIO_InitTypeDef  GPIO_InitStructure;
  105.         //Configure pin Pb0 as output
  106.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  107.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  108.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
  109.         GPIO_Init(GPIOB,&GPIO_InitStructure);

  110.         //Configure pin Pb1 as output
  111.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  112.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  113.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
  114.         GPIO_Init(GPIOB,&GPIO_InitStructure);
  115. /*        GPIO_SetBits(GPIOB,GPIO_Pin_5);
  116.         GPIO_SetBits(GPIOB,GPIO_Pin_6);        
  117.         GPIO_ResetBits(GPIOB,GPIO_Pin_5);
  118.         GPIO_ResetBits(GPIOB,GPIO_Pin_6);        */
  119. }

  120. //步进输出IO初始化
  121. void Motor_Init(){
  122.         
  123.   GPIO_InitTypeDef  GPIO_InitStructure;
  124.         //Configure pin Pb0 as output
  125.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  126.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  127.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
  128.         GPIO_Init(GPIOB,&GPIO_InitStructure);

  129.         //Configure pin Pb1 as output
  130.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  131.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  132.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
  133.         GPIO_Init(GPIOB,&GPIO_InitStructure);
  134.                 //Configure pin Pb0 as output
  135.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  136.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  137.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
  138.         GPIO_Init(GPIOB,&GPIO_InitStructure);

  139.         //Configure pin Pb1 as output
  140.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  141.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  142.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
  143.         GPIO_Init(GPIOB,&GPIO_InitStructure);
  144.         
  145.         
  146. /*        GPIO_SetBits(GPIOB,GPIO_Pin_5);
  147.         GPIO_SetBits(GPIOB,GPIO_Pin_6);        
  148.         GPIO_ResetBits(GPIOB,GPIO_Pin_5);
  149.         GPIO_ResetBits(GPIOB,GPIO_Pin_6);        */
  150. }

  151. //初始化ADC
  152. //这里我们仅以规则通道为例
  153. //我们默认将开启通道0~3                                                                                                                                          
  154. void  Adc_Init(void)
  155. {   
  156.         //先初始化IO口
  157.          RCC->APB2ENR|=1<<2;    //使能PORTA口时钟
  158.         GPIOA->CRL&=0XFFFF0000;//PA0 1 2 3 anolog输入
  159.         //通道10/11设置                        
  160.         RCC->APB2ENR|=1<<9;    //ADC1时钟使能         
  161.         RCC->APB2RSTR|=1<<9;   //ADC1复位
  162.         RCC->APB2RSTR&=~(1<<9);//复位结束            
  163.         RCC->CFGR&=~(3<<14);   //分频因子清零        
  164.         //SYSCLK/DIV2=12M ADC时钟设置为12M,ADC最大时钟不能超过14M!
  165.         //否则将导致ADC准确度下降!
  166.         RCC->CFGR|=2<<14;               

  167.         ADC1->CR1&=0XF0FFFF;   //工作模式清零
  168.         ADC1->CR1|=0<<16;      //独立工作模式  
  169.         ADC1->CR1&=~(1<<8);    //非扫描模式         
  170.         ADC1->CR2&=~(1<<1);    //单次转换模式
  171.         ADC1->CR2&=~(7<<17);           
  172.         ADC1->CR2|=7<<17;           //软件控制转换  
  173.         ADC1->CR2|=1<<20;      //使用用外部触发(SWSTART)!!!        必须使用一个事件来触发
  174.         ADC1->CR2&=~(1<<11);   //右对齐         
  175.         ADC1->SQR1&=~(0XF<<20);
  176.         ADC1->SQR1&=0<<20;     //1个转换在规则序列中 也就是只转换规则序列1                           
  177.         //设置通道0~3的采样时间
  178.         ADC1->SMPR2&=0XFFFFF000;//通道0,1,2,3采样时间清空         
  179.         ADC1->SMPR2|=7<<9;      //通道3  239.5周期,提高采样时间可以提高精确度         
  180.         ADC1->SMPR2|=7<<6;      //通道2  239.5周期,提高采样时间可以提高精确度         
  181.         ADC1->SMPR2|=7<<3;      //通道1  239.5周期,提高采样时间可以提高精确度         
  182.         ADC1->SMPR2|=7<<0;      //通道0  239.5周期,提高采样时间可以提高精确度         

  183.         ADC1->CR2|=1<<0;            //开启AD转换器         
  184.         ADC1->CR2|=1<<3;        //使能复位校准  
  185.         while(ADC1->CR2&1<<3);  //等待校准结束                          
  186.     //该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。                  
  187.         ADC1->CR2|=1<<2;        //开启AD校准           
  188.         while(ADC1->CR2&1<<2);  //等待校准结束
  189.         //该位由软件设置以开始校准,并在校准结束时由硬件清除  
  190. }                                 
  191. //获得ADC值
  192. //ch:通道值 0~3
  193. u16 Get_Adc(u8 ch)   
  194. {
  195.         //设置转换序列                           
  196.         ADC1->SQR3&=0XFFFFFFE0;//规则序列1 通道ch
  197.         ADC1->SQR3|=ch;                                             
  198.         ADC1->CR2|=1<<22;       //启动规则转换通道
  199.         while(!(ADC1->SR&1<<1));//等待转换结束                    
  200.         return ADC1->DR;                //返回adc值        
  201. }


  202. //
  203. uint16_t adc_avg(void)
  204. {
  205.   uint8_t i;
  206.         uint32_t sum=0;
  207.         uint16_t ret=0;
  208.         for(i=0;i<12;i++)  sum+=adtemp[i];
  209.         ret= sum/12;
  210.         
  211.         return ret;  
  212. }
  213. //马达正转开窗帘
  214. void motor_Foreward(void)
  215. {
  216.     Motor1_A_run;
  217.     delay_us(motorSpdDelayUs);
  218.     Motor1_AB_run;
  219.     delay_us(motorSpdDelayUs);
  220.     Motor1_B_run;
  221.     delay_us(motorSpdDelayUs);
  222.     Motor1_BC_run;
  223.     delay_us(motorSpdDelayUs);
  224.     Motor1_C_run;
  225.     delay_us(motorSpdDelayUs);
  226.     Motor1_CD_run;
  227.     delay_us(motorSpdDelayUs);
  228.     Motor1_D_run;
  229.     delay_us(motorSpdDelayUs);
  230.     Motor1_DA_run;
  231.     delay_us(motorSpdDelayUs);
  232. }


  233. //马达反转关窗帘
  234. void motor_Backward(void)
  235. {
  236.     Motor1_DA_run;
  237.     delay_us(motorSpdDelayUs);   
  238.     Motor1_D_run;
  239.     delay_us(motorSpdDelayUs);
  240.     Motor1_CD_run;
  241.     delay_us(motorSpdDelayUs);
  242.     Motor1_C_run;
  243.     delay_us(motorSpdDelayUs);
  244.     Motor1_BC_run;
  245.     delay_us(motorSpdDelayUs);
  246.     Motor1_B_run;
  247.     delay_us(motorSpdDelayUs);
  248.     Motor1_AB_run;
  249.     delay_us(motorSpdDelayUs);
  250.     Motor1_A_run;
  251.     delay_us(motorSpdDelayUs);   
  252. }



  253. //显示设置页面
  254. void Show_Normal(void){
  255.         //显示温湿度
  256.         strncpy(line1str,"tmp:99C/hm:99%RH",16);
  257.         line1str[4]=0x30+nowtemp/10;
  258.         line1str[5]=0x30+nowtemp%10;
  259.         line1str[11]=0x30+nowhumi/10;
  260.         line1str[12]=0x30+nowhumi%10;
  261.         OLED_8x16Str(0,0,line1str);        
  262.         //显示光照强度及窗帘状态
  263.         if(winflg){
  264.           strncpy(line2str,"lit:99 /wn:open ",16);
  265.         }else{
  266.                 strncpy(line2str,"lit:99 /wn:close",16);
  267.   }
  268.         line2str[4]=0x30+light_adc/41/10; //100%显示
  269.         line2str[5]=0x30+light_adc/41%10;
  270.         OLED_8x16Str(0,2,line2str);        
  271.         
  272.         //显示继电器输出状态
  273.         strncpy(line3str, "s1:open s2:open ",16);
  274.         if(solid1flg) {
  275.           line3str[3]='o';line3str[4]='p';line3str[5]='e';line3str[6]='n';line3str[7]=' ';
  276.   }else{
  277.           line3str[3]='c';line3str[4]='l';line3str[5]='o';line3str[6]='s';line3str[7]='e';
  278.   }
  279.         if(solid2flg) {
  280.           line3str[11]='o';line3str[12]='p';line3str[13]='e';line3str[14]='n';line3str[15]=' ';
  281.   }else{
  282.           line3str[11]='c';line3str[12]='l';line3str[13]='o';line3str[14]='s';line3str[15]='e';
  283.   }        
  284.         
  285.         OLED_8x16Str(0,4,line3str);
  286.         
  287.         //显示时间
  288.         //line4str[0]= 0x30+ timer.w_year%1000%100/10;        
  289.         line4str[0]= 0x30+ timer.w_year%1000%100%10;        
  290.         line4str[1]= '/';
  291.         line4str[2]= 0x30+timer.w_month/10;        
  292.         line4str[3]= 0x30+ timer.w_month%10;        
  293.         line4str[4]= '/';        
  294.         line4str[5]= 0x30+timer.w_date/10;        
  295.         line4str[6]= 0x30+ timer.w_date%10;        
  296.         line4str[7]= ' ';               
  297.         line4str[8]= 0x30+ timer.hour/10;        
  298.         line4str[9]= 0x30+ timer.hour%10;        
  299.         line4str[10]= ':';
  300.         line4str[11]= 0x30+timer.min/10;        
  301.         line4str[12]= 0x30+ timer.min%10;        
  302.         line4str[13]= ':';        
  303.         line4str[14]= 0x30+timer.sec/10;        
  304.         line4str[15]= 0x30+timer.sec%10;        
  305.         OLED_8x16Str(0,6,line4str);

  306. }
  307. /*
  308.    显示设置页面

  309. */
  310. void Show_SetPage(void){
  311.         uint8_t i;
  312.         //显示温湿度
  313.         strncpy(line1str,"tH:99C/hH:99%RH ",16);
  314.         
  315.         if(MODE_SET_TEMP_HIGH== mode_status && flashflg){
  316.                 line1str[3]=' ';
  317.                 line1str[4]=' ';
  318.         }else{
  319.                 line1str[3]=0x30+almtmp_high/10;
  320.                 line1str[4]=0x30+almtmp_high%10;
  321.   }
  322.         if(MODE_SET_HUMI_HIGH== mode_status && flashflg){
  323.                 line1str[10]=' ';
  324.                 line1str[11]=' ';
  325.   }else{
  326.                 line1str[10]=0x30+almhumi_high/10;
  327.                 line1str[11]=0x30+almhumi_high%10;
  328.         }
  329.         OLED_8x16Str(0,0,line1str);        
  330.         
  331.         //设置光强度
  332.         strncpy(line2str,"litH:99 15/04/25",16);
  333.         
  334.         if(MODE_SET_LIGHT== mode_status && flashflg){
  335.           line2str[5]=' '; //100%显示
  336.           line2str[6]=' ';

  337.   }else{
  338.           line2str[5]=0x30+set_lit_high/10; //100%显示
  339.           line2str[6]=0x30+set_lit_high%10;
  340.         }
  341.         if(MODE_SET_YEAR== mode_status && flashflg){
  342.           line2str[8]=' '; //100%显示
  343.           line2str[9]=' ';

  344.   }else{
  345.           line2str[8]=0x30+settime[YEAR]/10; //100%显示
  346.           line2str[9]=0x30+settime[YEAR]%10;
  347.         }        
  348.         
  349.         if(MODE_SET_MON== mode_status && flashflg){
  350.           line2str[11]=' '; //100%显示
  351.           line2str[12]=' ';

  352.   }else{
  353.           line2str[11]=0x30+settime[MON]/10; //100%显示
  354.           line2str[12]=0x30+settime[MON]%10;
  355.         }               
  356.         
  357.         if(MODE_SET_DATE== mode_status && flashflg){
  358.           line2str[14]=' '; //100%显示
  359.           line2str[15]=' ';

  360.   }else{
  361.           line2str[14]=0x30+settime[DATE]/10; //100%显示
  362.           line2str[15]=0x30+settime[DATE]%10;
  363.         }        
  364.         OLED_8x16Str(0,2,line2str);        
  365.         

  366.         //设置时间
  367.         strncpy(line3str," 10/59/00       ",16);
  368.         
  369.         if(MODE_SET_HOUR== mode_status && flashflg){
  370.           line3str[1]=' '; //100%显示
  371.           line3str[2]=' ';

  372.   }else{
  373.           line3str[1]=0x30+settime[HOUR]/10; //100%显示
  374.           line3str[2]=0x30+settime[HOUR]%10;
  375.         }
  376.         if(MODE_SET_MIN== mode_status && flashflg){
  377.           line3str[4]=' '; //100%显示
  378.           line3str[5]=' ';

  379.   }else{
  380.           line3str[4]=0x30+settime[MIN]/10; //100%显示
  381.           line3str[5]=0x30+settime[MIN]%10;
  382.         }        
  383.         
  384.         if(MODE_SET_SEC== mode_status && flashflg){
  385.           line3str[7]=' '; //100%显示
  386.           line3str[8]=' ';

  387.   }else{
  388.           line3str[7]=0x30+settime[SEC]/10; //100%显示
  389.           line3str[8]=0x30+settime[SEC]%10;
  390.         }               
  391.         OLED_8x16Str(0,4,line3str);
  392.         
  393.         //显示手机
  394.         strncpy(line4str,"NO:13538510586   ",16);
  395.         for(i=3;i<14;i++){
  396.     line4str[i]=  recephonenum[i-3];
  397.   }
  398.         OLED_8x16Str(0,6,line4str);
  399. }



  400. /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  401. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
  402. int main(void)
  403. {
  404.         uint8_t check,flashi,t,posi;
  405.         uint16_t adcx,motori,tt;
  406.         u32 i=0,xx;
  407.         SystemInit();                                        //系统时钟配置
  408.         OLED_Init();                                          //初始化OLED  
  409.   NVIC_Configuration();                //初始化中断向量
  410.         Init_RTC();                                                        //内部RTC初始化
  411.         Adc_Init();                                                        //adc 初始化
  412.         Usart1_Configuration(9600);        //串口配置 设置波特率9600
  413.         USART2_Config(9600);
  414.         Key_init();                                                        //按键初始化输入
  415.   OLED_8x16Str(0,0,line1str);
  416.         OLED_8x16Str(0,2,line2str);
  417.   OLED_8x16Str(0,4,line3str);
  418.         OLED_8x16Str(0,6,line4str);        

  419.         Motor_Init();                                                //马达控制IO初始化
  420.         
  421.         Uart1_ClrBuf();
  422.   while(0==Sim_Send_AT())   delay_ms(1000);                //??SIM ???? ,SIM900?????
  423.   Sim_Set_MODE(1);
  424.   delay_ms(800);
  425.   Sim_ReSms_Config();
  426.   delay_ms(800);
  427.   Sim_Sms_Config_Cscs();
  428.         Solid_Init();                                         //继电器IO配置输出
  429.         Uart2_ClrBuf();
  430.         Uart1_ClrBuf();

  431.         set_lit_high=85;
  432.   almtmp_high=40;
  433.   almhumi_high=60;
  434.         
  435.         mode_status=0;
  436.         //RTC_Set(2015,4,25,20,35,00);
  437.         adci=0;
  438.         while(1)                                                                                                        
  439.         {
  440.           if(KEY_MENU_IN==0){        
  441.                                 delay_ms(5);
  442.                           if(KEY_MENU_IN==0){
  443.           mode_status++; //
  444.                       if(mode_status>9) mode_status=0;               
  445.                                         if( settimeflg){
  446.                                                 settimeflg=0;
  447.                                                 Time_Update(settime[YEAR]+2000,settime[MON],settime[DATE],settime[HOUR],settime[MIN],settime[SEC]);
  448.                                         }
  449.                                 }
  450.         while(KEY_MENU_IN==0) ;                        //等待放键
  451.           }        
  452.           if(KEY_ADD_IN==0){    //加键
  453.                         delay_ms(5);
  454.                         if(KEY_ADD_IN==0){
  455.                           switch(mode_status ){ //
  456.          case MODE_SET_HOUR:   
  457.                                          if(settime[HOUR]<24)  settime[HOUR]++;
  458.                                          else                                                        settime[HOUR]=0;
  459.                                          settimeflg=1;
  460.                                  break;
  461.          case MODE_SET_MIN:   
  462.                                          if(settime[MIN]<60)  settime[MIN]++;
  463.                                          else                                                        settime[MIN]=0;
  464.                                          settimeflg=1;
  465.                                  break;                                 
  466.          case MODE_SET_SEC:   
  467.                                          if(settime[MIN]<60)  settime[SEC]++;
  468.                                          else                                                        settime[SEC]=0;
  469.                                          settimeflg=1;
  470.                                  break;               
  471.          case MODE_SET_YEAR:   
  472.                                          if(settime[YEAR]<99)  settime[YEAR]++;
  473.                                          else                                                        settime[YEAR]=0;
  474.                                          settimeflg=1;
  475.                                  break;               
  476.          case MODE_SET_MON:   
  477.                                          if(settime[MON]<12)  settime[MON]++;
  478.                                          else                                                        settime[MON]=0;
  479.                                          settimeflg=1;
  480.                                  break;               
  481.          case MODE_SET_DATE:   
  482.                                          if(settime[DATE]<31)  settime[DATE]++;
  483.                                          else                                                        settime[DATE]=0;
  484.                                          settimeflg=1;
  485.                                  break;
  486.          case MODE_SET_TEMP_HIGH:   
  487.                                          if(almtmp_high<99)  almtmp_high++;
  488.                                          else                                                        almtmp_high=0;
  489.                                  break;
  490.          case MODE_SET_HUMI_HIGH :   
  491.                                          if(almhumi_high<99)  almhumi_high++;
  492.                                          else                                                        almhumi_high=0;
  493.                                  break;        
  494.          case MODE_SET_LIGHT :   
  495.                                          if(set_lit_high<99)  set_lit_high++;
  496.                                          else                                                        set_lit_high=0;
  497.                                  break;                                         
  498.                           }
  499.                         }                                
  500.       while(KEY_ADD_IN==0) ;                        
  501.         }
  502.         if(KEY_SUB_IN==0){   
  503.       delay_ms(5);  
  504.                         if(KEY_SUB_IN==0){        
  505.                           switch(mode_status ){ //
  506.          case MODE_SET_HOUR:   
  507.                                          if(settime[HOUR]>0)  settime[HOUR]--;
  508.                                          else                                                        settime[HOUR]=0;
  509.                                          settimeflg=1;
  510.                                  break;
  511.          case MODE_SET_MIN:   
  512.                                          if(settime[MIN]>0)  settime[MIN]--;
  513.                                          else                                                        settime[MIN]=0;
  514.                                          settimeflg=1;
  515.                                  break;                                 
  516.          case MODE_SET_SEC:   
  517.                                          if(settime[MIN]>0)  settime[SEC]--;
  518.                                          else                                                        settime[SEC]=0;
  519.                                          settimeflg=1;
  520.                                  break;               
  521.          case MODE_SET_YEAR:   
  522.                                          if(settime[YEAR]>0)  settime[YEAR]--;
  523.                                          else                                 settime[YEAR]=0;
  524.                                          settimeflg=1;
  525.                                  break;               
  526.          case MODE_SET_MON:   
  527.                                          if(settime[MON]>0)  settime[MON]--;
  528.                                          else                                                        settime[MON]=0;
  529.                                          settimeflg=1;
  530.                                  break;               
  531.          case MODE_SET_DATE:   
  532.                                          if(settime[DATE]>0)  settime[DATE]--;
  533.                                          else                                                        settime[DATE]=0;
  534.                                          settimeflg=1;
  535.                                  break;
  536.          case MODE_SET_TEMP_HIGH:   
  537.                                          if(almtmp_high>0)  almtmp_high--;
  538.                                          else                                                        almtmp_high=0;
  539.                                  break;
  540.          case MODE_SET_HUMI_HIGH :   
  541.                                          if(almhumi_high>0)  almhumi_high--;
  542.                                          else                                                        almhumi_high=0;
  543.                                  break;                                 
  544.          case MODE_SET_LIGHT :   
  545.                                          if(set_lit_high>0)  set_lit_high--;
  546.                                          else                                                        set_lit_high=0;
  547.                                  break;                                                
  548.                          }         
  549.                  }                                
  550.      while(KEY_SUB_IN==0) ;                        
  551. }        


  552. switch(mode_status){  ///不同状态显示不同页面
  553.          
  554.                         case MODE_NORMAL:                                
  555.                
  556.                         dht11_readdata(dht11_buf);
  557.                         check= dht11_buf[0]+ dht11_buf[1]+ dht11_buf[2]+ dht11_buf[3];
  558.                         if(dht11_buf[4]==check){

  559.                                 nowhumi = dht11_buf[0];
  560.                                 nowtemp = dht11_buf[2];
  561.                                 thalmflg =0;
  562.                                 if(nowtemp> almtmp_high) thalmflg=1;
  563.                                 if(nowhumi> almhumi_high) thalmflg=1;
  564.                         
  565.                                 if (thalmflg){  //触发短息发送
  566.                                                 tt++;
  567.                                           if(tt>300){
  568.                                                         strncpy(strLs,"Alarm Temp:99 oC, Humi:99 %RH",29);
  569.                                             strLs[11]=0x30+nowtemp/10;
  570.                                                         strLs[12]=0x30+nowtemp%10;
  571.                                                         strLs[23]=0x30+nowhumi/10;
  572.                                                         strLs[24]=0x30+nowhumi%10;
  573.                                                         OLED_8x16Str(0,2,"Sending msg.... ");        
  574.                                                         delay_ms(1000);
  575.                                                         Sim_Send_Text(recephonenum,strLs);
  576.                                                         tt=0;
  577.                                                 }
  578.                                        
  579.                                 }               
  580.                         }        
  581.                         
  582.                                 adtemp[adci]=Get_Adc(ADC_CH0);
  583.                                 adci++;               
  584.                                 if(        adci>11) {
  585.                                         adci=0;
  586.                                         light_adc = adc_avg();
  587.                                         if(light_adc >  set_lit_high*41) {//光照充足关闭窗帘
  588.             if(winflg==1){
  589.                                                           motori=800;
  590.                 while(motori--) { motor_Backward();}
  591.                                                                 Motor1_STOP_run;
  592.                                                 }
  593.                                                 winflg=0;}        
  594.                                   else        {
  595.                                                 if(winflg==0){
  596.                                                           motori=800;
  597.                 while(motori--) { motor_Foreward();}
  598.                                                                 Motor1_STOP_run;
  599.                                                 }
  600.                                                 winflg=1;   //打开窗帘
  601.                                         }
  602.                                 }        

  603.                                 if(t!=timer.sec)
  604.                                 {
  605.                                         t=timer.sec;
  606.                                         //printf("%d年%d月%d日%d点%d分%d秒\r\n",timer.w_year,timer.w_month,timer.w_date,timer.hour,timer.min,timer.sec);               
  607.                                 }        
  608.                                 Show_Normal();
  609.                                 memset(strLs,0,sizeof(strLs));
  610.                                 strLs[0]=0x3a;
  611.                                 strLs[1]=nowtemp/10+0x30;
  612.                                 strLs[2]=nowtemp%10+0x30;                                
  613.                                 strLs[3]=nowhumi/10+0x30;
  614.                                 strLs[4]=nowtemp%10+0x30;                                
  615.                                 strLs[5]=0x30+light_adc/41/10;        
  616.                                 strLs[6]=0x30+light_adc/41%10;               
  617.                                 strLs[7]=timer.w_year%1000%100/10+0x30;
  618.                                 strLs[8]=timer.w_year%1000%100%10+0x30;
  619.                                 strLs[9]=timer.w_month/10+0x30;                        
  620.                                 strLs[10]=timer.w_month%10+0x30;               
  621.                                 strLs[11]=timer.w_date/10+0x30;                        
  622.                                 strLs[12]=timer.w_date%10+0x30;                        
  623.                                 if(solid1flg) strLs[14]=1+0x30;                        
  624.                                 else                                        strLs[14]=0+0x30;               
  625.                                 if(solid2flg) strLs[15]=1+0x30;                        
  626.                                 else                                        strLs[15]=0+0x30;        
  627.                                 if(winflg)                 strLs[16]=1+0x30;                        
  628.                                 else                                        strLs[16]=0+0x30;                        
  629.                                 
  630.                                 for(i=0;i<17;i++) USART2_Senddata(strLs[i]);
  631.                    break;

  632.             case MODE_SET_HOUR:
  633.                         case MODE_SET_MIN:
  634.                         case MODE_SET_SEC:
  635.                   case MODE_SET_YEAR:
  636.                         case MODE_SET_MON:
  637.                         case MODE_SET_DATE:        
  638.                         case MODE_SET_HUMI_HIGH:
  639.                         case MODE_SET_TEMP_HIGH:               
  640.                         case MODE_SET_LIGHT:               
  641.                                 flashi++;
  642.                                 if(flashi>2){
  643.                                         flashflg=~flashflg;
  644.                                         flashi=0;
  645.                                 }                        
  646.                                 Show_SetPage();

  647.                          break;
  648.                          default:
  649.                                         break;

  650.                 }        
  651.                  
  652.                
  653.                 if(mystrstr(Uart1_RxBuf,"+CMTI:")!= NULL ){  //接收到手机短息
  654.                         delay_ms(300);
  655.                         OLED_8x16Str(0,2,"Receing msg.... ");        
  656.                   Uart1_ClrBuf();
  657.                         delay_ms(1000);               
  658.             USART1_SendString("AT+CMGR=1\r\n"); //??????
  659.                
  660.                         while(Uart1_RxBuf[0]==0);                                        //等级待接收
  661.                         delay_ms(1000);                                //set 1lu:
  662.                         delay_ms(1000);                                //set 1lu:
  663.                         delay_ms(1000);                                //set 1lu:
  664.                         if( mystrstr(Uart1_RxBuf,"1 Close")!= NULL ){
  665.                                 GPIO_ResetBits(GPIOB,GPIO_Pin_5);  //关闭1路继电器输出
  666.                                 solid1flg=0;
  667.                         }
  668.                         if( mystrstr(Uart1_RxBuf,"1 Open")!= NULL ){
  669.                                 GPIO_SetBits(GPIOB,GPIO_Pin_5);  //关闭1路继电器输出
  670.                                 solid1flg=1;
  671.                         }
  672.                         if( mystrstr(Uart1_RxBuf,"2 Close")!= NULL ){
  673.                                 GPIO_ResetBits(GPIOB,GPIO_Pin_6);  //关闭2路继电器输出
  674.                                 solid2flg=0;
  675.                         }
  676.                         if( mystrstr(Uart1_RxBuf,"2 Open")!= NULL ){
  677.                                 GPIO_SetBits(GPIOB,GPIO_Pin_6);  //打开2路继电器输出
  678.                                 solid2flg=1;
  679.                         }
  680.                         Sim_delt_Sms();                //删除短信
  681. …………
  682. …………
  683. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码



所有资料51hei提供下载:

基于STM32的智能家居控制系统.rar (1.73 MB, 下载次数: 63)




评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 转播转播 分享分享 分享淘帖 顶1 踩
回复

使用道具 举报

沙发
niexiaohui 发表于 2018-12-24 20:54 | 只看该作者
学习了,谢谢版主!!
回复

使用道具 举报

无效楼层,该帖已经被删除
地板
niexiaohui 发表于 2018-12-24 21:26 | 只看该作者
所有资料51hei提供下载:
回复

使用道具 举报

5#
linqiming222 发表于 2019-1-11 15:04 | 只看该作者
最近准备学习一下单片机
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|单片机论坛 |51黑电子论坛单片机.

Powered by 单片机教程网

快速回复 返回顶部 返回列表