?
一、環(huán)境介紹
程序開(kāi)發(fā)IDE: keil5
STM32程序風(fēng)格: 采用寄存器方式開(kāi)發(fā),注釋齊全,執(zhí)行效率高,方便移植
手機(jī)APP: 采用QT設(shè)計(jì),程序支持跨平臺(tái)編譯運(yùn)行(Android、IOS、Windows、Linux都可以編譯運(yùn)行,對(duì)應(yīng)平臺(tái)上QT的環(huán)境搭建,之前博客已經(jīng)發(fā)了文章講解)
硬件包含:SRM32F103C8T6最小系統(tǒng)板、紅外熱釋電人體感應(yīng)模塊、DHT11溫濕度傳感器、0.96寸單色OLED顯示屏、ESP8266、繼電器、RGB大功率白燈.
?
?
?
?
二、功能介紹
這是基于STM32設(shè)計(jì)的智能插座+人體感應(yīng)燈。
硬件包含:
1. SRM32F103C8T6最小系統(tǒng)板: 基礎(chǔ)的系統(tǒng)板,引出了所有IO口
2. 紅外熱釋電人體感應(yīng)模塊: 用來(lái)檢測(cè)人體
3. DHT11溫濕度傳感器: 檢測(cè)環(huán)境的溫度、濕度
4. 0.96寸單色OLED顯示屏 : 顯示狀態(tài)信息。比如: WIFI狀態(tài)、RTC時(shí)鐘、插座狀態(tài)、溫濕度值
5. ESP8266: 用來(lái)與手機(jī)APP之間通信
6. 繼電器: 模擬插座開(kāi)關(guān)
7. RGB大功率白燈: 模擬正常的燈泡
支持的功能如下:
1. 使用熱釋電人體感應(yīng)模塊檢測(cè)人體,檢測(cè)到人體自動(dòng)開(kāi)燈,30秒(時(shí)間可以根據(jù)要求調(diào)整)沒(méi)有檢測(cè)到人體就自動(dòng)關(guān)燈。
2. 檢測(cè)環(huán)境溫濕度,使用OLED顯示屏在界面上實(shí)時(shí)顯示出來(lái)。 如果環(huán)境溫度高于閥值,強(qiáng)制關(guān)閉插座、如果濕度高于閥值,也會(huì)強(qiáng)制關(guān)閉插座;防止火災(zāi)隱患。 溫度最高閥值設(shè)置為: 30°,濕度閥值為80%, 這些都可以根據(jù)設(shè)計(jì)要求調(diào)整。
并且RGB燈也會(huì)根據(jù)不同的溫度閥值亮不同顏色的燈。 比如: 溫度高于30°亮紅色、溫度20°黃色 、溫度10°青色
3. 設(shè)置ESP8266WIFI模塊為AP模式(路由器模式),手機(jī)或者電腦可以連接到ESP8266.搭建局域網(wǎng)。
4. 設(shè)計(jì)手機(jī)APP和電腦客戶端軟件,可以實(shí)時(shí)顯示收到的溫濕度數(shù)據(jù)(3秒上傳一次).可以顯示歷史. 點(diǎn)擊手機(jī)APP上的按鈕,可以用來(lái)控制插座開(kāi)關(guān)。
5. OLED一共有4個(gè)頁(yè)面。 RTC實(shí)時(shí)時(shí)鐘顯示頁(yè)面、溫濕度顯示頁(yè)面、智能插座開(kāi)關(guān)狀態(tài)頁(yè)面、WIFI熱點(diǎn)信息頁(yè)面
6. OLED顯示屏的第一頁(yè)是實(shí)時(shí)時(shí)鐘頁(yè)面,時(shí)間可以通過(guò)手機(jī)APP來(lái)校準(zhǔn)。 在手機(jī)APP上有一個(gè)RTC校準(zhǔn)按鈕,點(diǎn)擊一下就可以校準(zhǔn)設(shè)備上的時(shí)間。
三、使用的相關(guān)硬件介紹
3.1DTH11 溫濕度傳感器
?
DHT11數(shù)字溫濕度傳感器是一款含有已校準(zhǔn)數(shù)字信號(hào)輸出的溫濕度復(fù)合傳感器,它應(yīng)用專(zhuān)用的數(shù)字模塊采集技術(shù)和溫濕度傳感技術(shù),確保產(chǎn)品具有極高的可靠性和卓越的長(zhǎng)期穩(wěn)定性。傳感器包括一個(gè)電阻式感濕元件和一個(gè)NTC測(cè)溫元件,并與一個(gè)高性能8位單片機(jī)相連接。因此該產(chǎn)品具有品質(zhì)卓越、超快響應(yīng)、抗干擾能力強(qiáng)、性價(jià)比極高等優(yōu)點(diǎn)。每個(gè)DHT11傳感器都在極為精確的濕度校驗(yàn)室中進(jìn)行校準(zhǔn)。校準(zhǔn)系數(shù)以程序的形式存在OTP內(nèi)存中,傳感器內(nèi)部在檢測(cè)信號(hào)的處理過(guò)程中要調(diào)用這些校準(zhǔn)系數(shù)。單線制串行接口,使系統(tǒng)集成變得簡(jiǎn)易快捷。超小的體積、極低的功耗,使其成為該類(lèi)應(yīng)用中,在苛刻應(yīng)用場(chǎng)合的最佳選擇。產(chǎn)品為4針單排引腳封裝,連接方便。
3.2熱釋電傳感器
?
?
熱釋電紅外傳感器在結(jié)構(gòu)上引入場(chǎng)效應(yīng)管,其目的在于完成阻抗變換。由于熱釋電元輸出的是電荷信號(hào),并不能直接使用,因而需要用電阻將其轉(zhuǎn)換為電壓形式。故引入的N溝道結(jié)型場(chǎng)效應(yīng)管應(yīng)接成共漏形式來(lái)完成阻抗變換。熱釋電紅外傳感器由傳感探測(cè)元、干涉濾光片和場(chǎng)效應(yīng)管匹配器三部分組成。設(shè)計(jì)時(shí)應(yīng)將高熱電材料制成一定厚度的薄片,并在它的兩面鍍上金屬電極,然后加電對(duì)其進(jìn)行極化,這樣便制成了熱釋電探測(cè)元。
熱釋電紅外傳感器的外形如上圖所示。其可以檢測(cè)人體發(fā)出的紅外線信號(hào),并將其轉(zhuǎn)換成電信號(hào)輸出。傳感器頂部的長(zhǎng)方形窗口加有濾光片,可以使人體發(fā)出的9~10μm波長(zhǎng)的紅外線通過(guò),而其它波長(zhǎng)的紅外線被濾除,這樣便提高了抗干擾能。熱釋電紅外傳感器由濾光片、熱釋電探測(cè)元和前置放大器組成,補(bǔ)償型熱釋電傳感器還帶有溫度補(bǔ)償元件,圖所示為熱釋電傳感器的內(nèi)部結(jié)構(gòu)。為防止外部環(huán)境對(duì)傳感器輸出信號(hào)的干擾,上述元件被真空封裝在一個(gè)金屬營(yíng)內(nèi)。熱釋電傳感器的濾光片為帶通濾光片,它封裝在傳感器殼體的頂端,使特定波長(zhǎng)的紅外輻射選擇性地通過(guò),到達(dá)熱釋電探測(cè)元+在其截止范圍外的紅外輻射則不能通過(guò)。
熱釋電探測(cè)元是熱釋電傳感器的核心元件,它是在熱釋電晶體的兩面鍍上金屬電極后,加電極化制成,相當(dāng)于一個(gè)以熱釋電晶體為電介質(zhì)的平板電容器。當(dāng)它受到非恒定強(qiáng)度的紅外光照射時(shí),產(chǎn)生的溫度變化導(dǎo)致其表面電極的電荷密度發(fā)生改變,從而產(chǎn)生熱釋電電流。
前置放大器由一個(gè)高內(nèi)阻的場(chǎng)效應(yīng)管源極跟隨器構(gòu)成,通過(guò)阻抗變換,將熱釋電探測(cè)元微弱的電流信號(hào)轉(zhuǎn)換為有用的電壓信號(hào)輸出。
3.3ESP8266串口WIFI模塊
?
ESP8266系列無(wú)線模塊是高性價(jià)比WIFI SOC模組,該系列模塊支持標(biāo)準(zhǔn)的IEEE802.11b/g/n協(xié)議,內(nèi)置完整的TCP/IP協(xié)議棧。用戶可以使用該系列模塊為現(xiàn)有的設(shè)備添加聯(lián)網(wǎng)功能,也可以構(gòu)建獨(dú)立的網(wǎng)絡(luò)控制器。
能卓越
ESP8266EX 芯片內(nèi)置超低功耗 Tensilica L106 32 位 RISC 處理器,CPU 時(shí)鐘速度最?可達(dá) 160 MHz,?持實(shí)時(shí)操作系統(tǒng) (RTOS) 和 Wi-Fi 協(xié)議棧,可將?達(dá) 80% 的處理能?應(yīng)用于編程和開(kāi)發(fā)。
高度集成
ESP8266 芯片高度集成天線開(kāi)關(guān)、射頻巴倫、功率放大器、低噪聲接收放大器、濾波器等射頻模塊。模組尺寸小巧,尤其適用于空間受限的產(chǎn)品設(shè)計(jì)。
認(rèn)證齊全
RF 認(rèn)證:SRRC、FCC、CE-RED、KCC、TELEC/MIC、IC 和 NCC 認(rèn)證;
環(huán)保認(rèn)證:RoHS、REACH;
可靠性認(rèn)證:HTOL、HTSL、μHAST、TCT、ESD。
豐富的產(chǎn)品應(yīng)用
ESP8266 模組既可以通過(guò) ESP-AT 指令固件,為外部主機(jī) MCU 提供 Wi-Fi 連接功能;也可以作為獨(dú)立 Wi-Fi MCU 運(yùn)行,用戶通過(guò)基于 RTOS 的 SDK 開(kāi)發(fā)帶 Wi-Fi 連接功能的產(chǎn)品。用戶可以輕松實(shí)現(xiàn)開(kāi)箱即用的云連接、低功耗運(yùn)行模式,以及包括 WPA3 在內(nèi)的 Wi-Fi 安全支持等功能。
3.4OLED顯示屏
?
OLED顯示屏是利用有機(jī)電自發(fā)光二極管制成的顯示屏。由于同時(shí)具備自發(fā)光有機(jī)電激發(fā)光二極管,不需背光源、對(duì)比度高、厚度薄、視角廣、反應(yīng)速度快、可用于撓曲性面板、使用溫度范圍廣、構(gòu)造及制程較簡(jiǎn)單等優(yōu)異之特性,被認(rèn)為是下一代的平面顯示器新興應(yīng)用技術(shù)。
有機(jī)發(fā)光二極管 (OLED)顯示器越來(lái)越普遍,在手機(jī)、媒體播放器及小型入門(mén)級(jí)電視等產(chǎn)品中最為顯著。不同于標(biāo)準(zhǔn)的液晶顯示器,OLED 像素是由電流源所驅(qū)動(dòng)。若要了解 OLED 電源供應(yīng)如何及為何會(huì)影響顯示器畫(huà)質(zhì),必須先了解 OLED 顯示器技術(shù)及電源供應(yīng)需求。本文將說(shuō)明最新的 OLED 顯示器技術(shù),并探討主要的電源供應(yīng)需求及解決方案,另外也介紹專(zhuān)為 OLED 電源供應(yīng)需求而提出的創(chuàng)新性電源供應(yīng)架構(gòu)。
背板技術(shù)造就軟性顯示器 高分辨率彩色主動(dòng)式矩陣有機(jī)發(fā)光二極管 (AMOLED) 顯示器需要采用主動(dòng)式矩陣背板,此背板使用主動(dòng)式開(kāi)關(guān)進(jìn)行各像素的開(kāi)關(guān)。液晶 (LC) 顯示器非晶硅制程已臻成熟,可供應(yīng)低成本的主動(dòng)式矩陣背板,并且可用于 OLED。許多公司正針對(duì)軟性顯示器開(kāi)發(fā)有機(jī)薄膜晶體管 (OTFT) 背板制程,此一制程也可用于 OLED 顯示器,以實(shí)現(xiàn)全彩軟性顯示器的推出。不論是標(biāo)準(zhǔn)或軟性 OLED,都需要運(yùn)用相同的電源供應(yīng)及驅(qū)動(dòng)技術(shù)。若要了解 OLED 技術(shù)、功能及其與電源供應(yīng)之間的互動(dòng),必須深入剖析這項(xiàng)技術(shù)本身。OLED 顯示器是一種自體發(fā)光顯示器技術(shù),完全不需要任何背光。OLED 采用的材質(zhì)屬于化學(xué)結(jié)構(gòu)適用的有機(jī)材質(zhì)。 OLED 技術(shù)需要電流控制驅(qū)動(dòng)方法 OLED 具有與標(biāo)準(zhǔn)發(fā)光二極管 (LED) 相當(dāng)類(lèi)似的電氣特性,亮度均取決于 LED 電流。若要開(kāi)啟和關(guān)閉 OLED 并控制 OLED 電流,需要使用薄膜晶體管 (TFT)的控制電路。
OLED為自發(fā)光材料,不需用到背光板,同時(shí)視角廣、畫(huà)質(zhì)均勻、反應(yīng)速度快、較易彩色化、用簡(jiǎn)單驅(qū)動(dòng)電路即可達(dá)到發(fā)光、制程簡(jiǎn)單、可制作成撓曲式面板,符合輕薄短小的原則,應(yīng)用范圍屬于中小尺寸面板。
顯示方面:主動(dòng)發(fā)光、視角范圍大;響應(yīng)速度快,圖像穩(wěn)定;亮度高、色彩豐富、分辨率高。
工作條件:驅(qū)動(dòng)電壓低、能耗低,可與太陽(yáng)能電池、集成電路等相匹配。
適應(yīng)性廣:采用玻璃襯底可實(shí)現(xiàn)大面積平板顯示;如用柔性材料做襯底,能制成可折疊的顯示器。由于OLED是全固態(tài)、非真空器件,具有抗震蕩、耐低溫(-40℃)等特性,在軍事方面也有十分重要的應(yīng)用,如用作坦克、飛機(jī)等現(xiàn)代化武器的顯示終端。
3.5LED大功率燈模塊
?
LED燈是一塊電致發(fā)光的半導(dǎo)體材料芯片,用銀膠或白膠固化到支架上,然后用銀線或金線連接芯片和電路板,四周用環(huán)氧樹(shù)脂密封,起到保護(hù)內(nèi)部芯線的作用,最后安裝外殼,所以 LED 燈的抗震性能好。
LED(Light Emitting Diode),發(fā)光二極管,是一種能夠?qū)㈦娔苻D(zhuǎn)化為可見(jiàn)光的固態(tài)的半導(dǎo)體器件,它可以直接把電轉(zhuǎn)化為光。LED的心臟是一個(gè)半導(dǎo)體的晶片,晶片的一端附在一個(gè)支架上,一端是負(fù)極,另一端連接電源的正極,使整個(gè)晶片被環(huán)氧樹(shù)脂封裝起來(lái)。
半導(dǎo)體晶片由兩部分組成,一部分是P型半導(dǎo)體,在它里面空穴占主導(dǎo)地位,另一端是N型半導(dǎo)體,在這邊主要是電子。但這兩種半導(dǎo)體連接起來(lái)的時(shí)候,它們之間就形成一個(gè)P-N結(jié)。當(dāng)電流通過(guò)導(dǎo)線作用于這個(gè)晶片的時(shí)候,電子就會(huì)被推向P區(qū),在P區(qū)里電子跟空穴復(fù)合,然后就會(huì)以光子的形式發(fā)出能量,這就是LED燈發(fā)光的原理。而光的波長(zhǎng)也就是光的顏色,是由形成P-N結(jié)的材料決定的。
LED可以直接發(fā)出紅、黃、藍(lán)、綠、青、橙、紫、白色的光。
3.6STM32F103C8T6最小系統(tǒng)板
?
STM32F系列屬于中低端的32位ARM微控制器,該系列芯片是意法半導(dǎo)體(ST)公司出品,其內(nèi)核是Cortex-M3。
該系列芯片按片內(nèi)Flash的大小可分為三大類(lèi):小容量(16K和32K)、中容量(64K和128K)、大容量(256K、384K和512K)。
芯片集成定時(shí)器Timer,CAN,ADC,SPI,I2C,USB,UART等多種外設(shè)功能。
內(nèi)核
--ARM 32位的Cortex-M3
--最高72MHz工作頻率,在存儲(chǔ)器的0等待周期訪問(wèn)時(shí)可達(dá)1.25DMips/MHZ(DhrystONe2.1)
--單周期乘法和硬件除法
存儲(chǔ)器
--從16K到512K字節(jié)的閃存程序存儲(chǔ)器(STM32F103XXXX中的第二個(gè)X表示FLASH容量,其中:“4”=16K,“6”=32K,“8”=64K,B=128K,C=256K,D=384K,E=512K)
--最大64K字節(jié)的SRAM
電源管理
--2.0-3.6V供電和I/O引腳
--上電/斷電復(fù)位(POR/PDR)、可編程電壓監(jiān)測(cè)器(PVD)
--4-16MHZ晶振
--內(nèi)嵌經(jīng)出廠調(diào)校的8MHz的RC振蕩器
--內(nèi)嵌帶校準(zhǔn)的40KHz的RC振蕩器
--產(chǎn)生CPU時(shí)鐘的PLL
--帶校準(zhǔn)的32KHz的RC振蕩器
低功耗
--睡眠、停機(jī)和待機(jī)模式
--Vbat為RTC和后備寄存器供電
模數(shù)轉(zhuǎn)換器
--2個(gè)12位模數(shù)轉(zhuǎn)換器,1us轉(zhuǎn)換時(shí)間(多達(dá)16個(gè)輸入通道)
--轉(zhuǎn)換范圍:0至3.6V
--雙采樣和保持功能
--溫度傳感器
DMA
--2個(gè)DMA控制器,共12個(gè)DMA通道:DMA1有7個(gè)通道,DMA2有5個(gè)通道
--支持的外設(shè):定時(shí)器、ADC、SPI、USB、IIC和UART
--多達(dá)112個(gè)快速I(mǎi)/O端口(僅Z系列有超過(guò)100個(gè)引腳)
--26/37/51/80/112個(gè)I/O口,所有I/O口一塊映像到16個(gè)外部中斷;幾乎所有的端口均可容忍5V信號(hào)
調(diào)試模式
--串行單線調(diào)試(SWD)和JTAG接口
--多達(dá)8個(gè)定時(shí)器
--3個(gè)16位定時(shí)器,每個(gè)定時(shí)器有多達(dá)4個(gè)用于輸入捕獲/輸出比較/PWM或脈沖計(jì)數(shù)的通道和增量編碼器輸入
--1個(gè)16位帶死區(qū)控制和緊急剎車(chē),用于電機(jī)控制的PWM高級(jí)控制定時(shí)器
--2個(gè)看門(mén)狗定時(shí)器(獨(dú)立的和窗口型的)
--系統(tǒng)時(shí)間定時(shí)器:24位自減型計(jì)數(shù)器
--多達(dá)9個(gè)通信接口:
2個(gè)I2C接口(支持SMBus/PMBus)
3個(gè)USART接口(支持ISO7816接口,LIN,IrDA接口和調(diào)制解調(diào)控制)
2個(gè)SPI接口(18M位/秒)
CAN接口(2.0B主動(dòng))
USB 2.0全速接口
計(jì)算單元
CRC計(jì)算單元,96位的新批唯一代碼
封裝
ECOPACK封裝
3.7杜邦線
?
3.8 繼電器
?
?
四、STM32核心代碼
?
4.1 STM32: main.c
#include "stm32f10x.h"
#include "beep.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include
#include
#include "exti.h"
#include "timer.h"
#include "rtc.h"
#include "wdg.h"
#include "oled.h"
#include "fontdata.h"
#include "adc.h"
#include "FunctionConfig.h"
#include "dht11.h"
#include "HumanDetection.h"
#include "esp8266.h"
/*
函數(shù)功能: 繪制時(shí)鐘表盤(pán)框架
*/
void DrawTimeFrame(void)
{
u8 i;
OLED_Circle(32,32,31);//畫(huà)外圓
OLED_Circle(32,32,1); //畫(huà)中心圓
//畫(huà)刻度
for(i=0;i<60;i++)
{
if(i%5==0)OLED_DrawAngleLine(32,32,6*i,31,3,1);
}
OLED_RefreshGRAM(); //刷新數(shù)據(jù)到OLED屏幕
}
/*
函數(shù)功能: 更新時(shí)間框架顯示,在RTC中斷里調(diào)用
*/
char TimeBuff[20];
void Update_FrameShow(void)
{
/*1. 繪制秒針、分針、時(shí)針*/
OLED_DrawAngleLine2(32,32,rtc_clock.sec*6-6-90,27,0);//清除之前的秒針
OLED_DrawAngleLine2(32,32,rtc_clock.sec*6-90,27,1); //畫(huà)秒針
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);
//繪制電子鐘時(shí)間
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," "); //清除多余的數(shù)據(jù)
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); //具體的值
}
/*
函數(shù)功能: 溫濕度顯示
*/
void ShowTemperatureAndHumidity(u8 temp,u8 humi)
{
sprintf(TimeBuff,"T: %d",temp);
OLED_ShowString(40,16*1,16,TimeBuff);
sprintf(TimeBuff,"H: %d%%",humi);
OLED_ShowString(40,16*2,16,TimeBuff);
}
/*
函數(shù)功能: OLED所有顯示頁(yè)面信息初始化
*/
u8 ESP8266_Stat=0; //存放ESP8266狀態(tài) 1 OK ,0 error
u8 ESP8266_WIFI_AP_SSID[10]; //存放WIFI的名稱(chēng)
#define STM32_96BIT_UID (0x1FFFF7E8) //STM32內(nèi)部96位唯一芯片標(biāo)識(shí)符寄存器地址
/*
函數(shù)功能: ESP8266 WIFI 顯示頁(yè)面
*/
char ESP8266_PwdShow[20];
char ESP8266_IP_PortAddr[30]; //存放ESP8266 IP地址與端口號(hào)地址
u8 Save_ESP8266_SendCmd[30]; //保存WIFI發(fā)送的命令
u8 Save_ESP8266_SendData[50]; //保存WIFI發(fā)送的數(shù)據(jù)
void ESP8266_ShowPageTable(void)
{
if(ESP8266_Stat)OLED_ShowString(0,16*0,16,"WIFI STAT:ERROR");
else OLED_ShowString(0,16*0,16,"WIFI STAT:OK");
//顯示字符串
//OLED_ShowString(0,2,(u8*)" "); //清除一行的顯示
memset((u8*)ESP8266_PwdShow,0,20); //清空內(nèi)存
sprintf((char*)ESP8266_PwdShow,"WIFI:%s",ESP8266_WIFI_AP_SSID);
ESP8266_PwdShow[15]='\0';
OLED_ShowString(0,16*1,16,ESP8266_PwdShow);
memset((u8*)ESP8266_PwdShow,0,20); //清空內(nèi)存
sprintf((char*)ESP8266_PwdShow,"PWD:%s",wifiap_password);
OLED_ShowString(0,16*2,16,ESP8266_PwdShow);
OLED_ShowString(0,16*3,16,"192.168.4.1:8089");
}
void OledShowPageTableInit(void)
{
u8 data[100],i;
u32 stm32_uid=0;
u8 *uid;
/*1. ESP8266 WIFI相關(guān)信息初始化*/
OLED_ShowString(0,2,16," "); //清空一行的顯示
OLED_ShowString(0,2,16,"WifiInit..."); //顯示頁(yè)面提示信息
/*1.1 設(shè)置WIFI AP模式 */
if(ESP8266_SendCmd("AT+CWMODE=2\r\n","OK",50))
{
ESP8266_Stat=1; //OK
}
else
{
ESP8266_Stat=0; //ERROR
}
/*1.2 重啟模塊 */
ESP8266_SendCmd("AT+RST\r\n","OK",20);
/*1.3 延時(shí)3S等待重啟成功*/
DelayMs(1000);
DelayMs(1000);
DelayMs(1000);
//得到WIFI的名稱(chēng)
uid=(u8*)STM32_96BIT_UID; //轉(zhuǎn)為指針為1個(gè)字節(jié)
for(i=0;i<96;i++)
{
stm32_uid+=*uid++; //計(jì)算校驗(yàn)和,得到WIFI數(shù)字編號(hào)
}
printf("stm32_uid=%d\r\n",stm32_uid);
sprintf((char*)data,"%d",stm32_uid);
strcpy((char*)ESP8266_WIFI_AP_SSID,"wbyq_");
strcat((char*)ESP8266_WIFI_AP_SSID,(char*)data);
printf("請(qǐng)用設(shè)備連接WIFI熱點(diǎn):%s,%s,%s\r\n",(u8*)ESP8266_WIFI_AP_SSID,(u8*)wifiap_encryption,(u8*)wifiap_password);
/*1.4 配置模塊AP模式無(wú)線參數(shù)*/
memset(data,0,100); //清空數(shù)組
sprintf((char*)data,"AT+CWSAP=\"%s\",\"%s\",1,4\r\n",ESP8266_WIFI_AP_SSID,wifiap_password);
ESP8266_SendCmd(data,"OK",1000);
/*1.5 設(shè)置多連接模式:0單連接,1多連接(服務(wù)器模式必須開(kāi)啟)*/
ESP8266_SendCmd("AT+CIPMUX=1\r\n","OK",20);
/*1.6 開(kāi)啟Server模式(0,關(guān)閉;1,打開(kāi)),端口號(hào)為portnum */
memset(data,0,100); //清空數(shù)組
sprintf((char*)data,"AT+CIPSERVER=1,%s\r\n",(u8*)portnum);
ESP8266_SendCmd(data,"OK",50);
/*1.7 獲取當(dāng)前模塊的IP*/
ESP8266_GetWanip((u8*)ESP8266_IP_PortAddr);
strcat(ESP8266_IP_PortAddr,":");
strcat(ESP8266_IP_PortAddr,portnum);
printf("IP地址:%s\r\n",ESP8266_IP_PortAddr);
OLED_ShowString(0,2,16," "); //清空一行的顯示
OLED_ShowString(0,2,16,"WifiInitOk"); //顯示頁(yè)面提示信息
}
/*
函數(shù)功能: 顯示開(kāi)關(guān)狀態(tài)
*/
void Show_Switch(int state)
{
//清屏
OLED_Clear(0);
if(state)
{
sprintf(TimeBuff,"Socket:ON");
OLED_ShowString(20,16*2,16,TimeBuff);
}
else
{
sprintf(TimeBuff,"Socket:OFF");
OLED_ShowString(20,16*2,16,TimeBuff);
}
}
//int main1(void)
//{
// HumanDetection_Init(); //熱釋電模塊初始化
// UsartInit(USART1,72,115200);//串口1的初始化
// LED_Init(); //初始化LED
// while(1)
// {
// //熱釋電狀態(tài) 為真表示有人
// if(HumanState)
// {
// LED1=0; //開(kāi)燈
// }
// else //為假
// {
// LED1=1; //關(guān)燈
// }
// printf("%d\n",HumanState);
// }
//}
int main(void)
{
u8 rlen;
char *p;
u8 temp; //溫度
u8 humi; //濕度
u8 stat;
u8 key_val;
u32 TimeCnt=0;
u32 wifi_TimeCnt=0;
u16 temp_data; //溫度數(shù)據(jù)
u8 page_cnt=0; //顯示的頁(yè)面
char *time;
u8 socket_state=0;
UsartInit(USART1,72,115200);//串口1的初始化
BEEP_Init(); //初始化蜂鳴器
LED_Init(); //初始化LED
KEY_Init(); //按鍵初始化
printf("正在初始化OLED...\r\n");
OLED_Init(0xc8,0xa1); //OLED顯示屏初始化--正常顯示
//OLED_Init(0xc0,0xa0); //OLED顯示屏初始化--翻轉(zhuǎn)顯示
OLED_Clear(0x00); //清屏
UsartInit(USART3,36,115200); //WIFI的波特率為115200
Timer2Init(72,10000); //10ms中斷一次,輔助串口3接收數(shù)據(jù)--WIFI數(shù)據(jù)
printf("正在初始化ESP8266..\r\n");
//ESP8266初始化
OledShowPageTableInit();
//清屏
OLED_Clear(0);
printf("正在初始化RTC...\r\n");
RTC_Init(); //RTC初始化
DrawTimeFrame(); //畫(huà)時(shí)鐘框架
USART3_RX_STA=0; //清空串口的接收標(biāo)志位
USART3_RX_CNT=0; //清空計(jì)數(shù)器
printf("初始化DHT11...\r\n");
DHT11_Init(); //初始化DHT11
printf("熱釋電模塊初始化...\r\n");
HumanDetection_Init(); //熱釋電模塊初始化
//OLED_Clear(0);
printf("開(kāi)始進(jìn)入while(1)\r\n");
while(1)
{
key_val=KEY_GetValue();
if(key_val)
{
page_cnt++;
printf("page_cnt:%d\r\n",page_cnt);
//清屏
OLED_Clear(0);
//時(shí)鐘頁(yè)面
if(page_cnt==0)
{
DrawTimeFrame(); //畫(huà)時(shí)鐘框架
RTC->CRH|=1<<0; //開(kāi)啟秒中斷
}
//溫濕度頁(yè)面
else if(page_cnt==1)
{
RTC->CRH&=~(1<<0); //關(guān)閉秒中斷
//溫濕度
ShowTemperatureAndHumidity(temp,humi);
}
//ESP8266顯示
else if(page_cnt==2)
{
ESP8266_ShowPageTable();
}
else if(page_cnt==3)
{
Show_Switch(socket_state);
}
else
{
DrawTimeFrame(); //畫(huà)時(shí)鐘框架
RTC->CRH|=1<<0; //開(kāi)啟秒中斷
page_cnt=0;
}
}
//時(shí)間記錄
DelayMs(10);
TimeCnt++;
wifi_TimeCnt++;
if(TimeCnt>=100) //1000毫秒一次
{
TimeCnt=0;
//讀取溫濕度數(shù)據(jù)
DHT11_Read_Data(&temp,&humi);
//濕度大于90就關(guān)閉開(kāi)關(guān)
if(humi>90)
{
socket_state=0;
if(page_cnt==3)
{
Show_Switch(socket_state);
}
}
//溫濕度頁(yè)面
if(page_cnt==1)
{
//溫濕度
ShowTemperatureAndHumidity(temp,humi);
}
}
if(wifi_TimeCnt>=300) //3000毫秒一次
{
wifi_TimeCnt=0;
//溫濕度1秒上傳一次
sprintf((char*)Save_ESP8266_SendData,"#%d,%d",temp,humi); //拼接數(shù)據(jù)
sprintf((char*)Save_ESP8266_SendCmd,"AT+CIPSEND=0,%d\r\n",strlen((char*)Save_ESP8266_SendData));
ESP8266_SendCmd(Save_ESP8266_SendCmd,(u8*)"OK",200); //WIFI設(shè)置發(fā)送數(shù)據(jù)長(zhǎng)度
ESP8266_SendData(Save_ESP8266_SendData,(u8*)"OK",100); //WIFI發(fā)送數(shù)據(jù)
}
//熱釋電狀態(tài) 為真表示有人
if(HumanState)
{
LED1=0; //開(kāi)燈
}
else //為假
{
LED1=1; //關(guān)燈
}
/*輪詢掃描數(shù)據(jù)*/
if(USART3_RX_STA) //WIFI 接收到一次數(shù)據(jù)了
{
rlen=USART3_RX_CNT; //得到本次接收到的數(shù)據(jù)長(zhǎng)度
USART3_RX_BUF[rlen]='\0'; //添加結(jié)束符
// printf("接收的數(shù)據(jù): %s\r\n",USART3_RX_BUF); //發(fā)送到串口
{
/*判斷是否收到客戶端發(fā)來(lái)的數(shù)據(jù) */
p=strstr((char*)USART3_RX_BUF,"+IPD");
if(p!=NULL) //正常數(shù)據(jù)格式: +IPD,0,7:LED1_ON +IPD,0表示第0個(gè)客戶端 7:LED1_ON表示數(shù)據(jù)長(zhǎng)度與數(shù)據(jù)
{
/*解析上位機(jī)發(fā)來(lái)的數(shù)據(jù)*/
p=strstr((char*)USART3_RX_BUF,":");
if(p!=NULL)
{
p+=1; //向后偏移1個(gè)字節(jié)
if(*p=='*') //設(shè)置RTC時(shí)間
{
p+=1; //向后偏移,指向正確的時(shí)間
time=p;
rtc_clock.year=(time[0]-48)*1000+(time[1]-48)*100+(time[2]-48)*10+(time[3]-48)*1;
rtc_clock.mon=(time[4]-48)*10+(time[5]-48)*1;
rtc_clock.day=(time[6]-48)*10+(time[7]-48)*1;
rtc_clock.hour=(time[8]-48)*10+(time[9]-48)*1;
rtc_clock.min=(time[10]-48)*10+(time[11]-48)*1;
rtc_clock.sec=(time[12]-48)*10+(time[13]-48)*1;
RTC_SetTime(rtc_clock.year,rtc_clock.mon,rtc_clock.day,rtc_clock.hour,rtc_clock.min,rtc_clock.sec);
if(page_cnt==0)
{
OLED_Clear(0); //OLED清屏
DrawTimeFrame();//畫(huà)時(shí)鐘框架
}
}
else if(strcmp(p,"LED1_ON")==0)
{
socket_state=1;
}
else if(strcmp(p,"LED1_OFF")==0)
{
socket_state=0;
}
if(page_cnt==3)
{
Show_Switch(socket_state);
}
}
}
}
USART3_RX_STA=0;
USART3_RX_CNT=0;
}
}
}
4.2 STM32: rtc.c
#include "rtc.h"
//定義RTC標(biāo)準(zhǔn)結(jié)構(gòu)體
struct RTC_CLOCK rtc_clock;
/*
函數(shù)功能: RTC初始化函數(shù)
*/
void RTC_Init(void)
{
//檢查是不是第一次配置時(shí)鐘
u8 temp=0;
if(BKP->DR1!=0X5051)//之前使用的不是LSE
{
RCC->APB1ENR|=1<<28; //使能電源時(shí)鐘
RCC->APB1ENR|=1<<27; //使能備份時(shí)鐘
PWR->CR|=1<<8; //取消備份區(qū)寫(xiě)保護(hù)
RCC->BDCR|=1<<16; //備份區(qū)域軟復(fù)位
RCC->BDCR&=~(1<<16); //備份區(qū)域軟復(fù)位結(jié)束
RCC->BDCR|=1<<0; //開(kāi)啟外部低速振蕩器
while((!(RCC->BDCR&0X02))&&temp<250)//等待外部時(shí)鐘就緒
{
temp++;
DelayMs(10);
};
if(temp>=250) //return 1;//初始化時(shí)鐘失敗,晶振有問(wèn)題
{
RCC->CSR|=1<<0; //開(kāi)啟外部低速振蕩器
while(!(RCC->CSR&(1<<1)));//外部低速振蕩器
RCC->BDCR|=2<<8; //LSI作為RTC時(shí)鐘
BKP->DR1=0X5050; //標(biāo)記使用LSI作為RTC時(shí)鐘
}
else
{
RCC->BDCR|=1<<8; //LSE作為RTC時(shí)鐘
BKP->DR1=0X5051; //標(biāo)記使用LSE作為RTC時(shí)鐘
}
RCC->BDCR|=1<<15;//RTC時(shí)鐘使能
while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成
while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步
RTC->CRH|=0X01; //允許秒中斷
while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成
RTC->CRL|=1<<4; //允許配置
RTC->PRLH=0X0000;
RTC->PRLL=32767; //時(shí)鐘周期設(shè)置(有待觀察,看是否跑慢了?)理論值:32767
RTC_SetTime(2021,4,25,20,36,20); //設(shè)置時(shí)間
RTC->CRL&=~(1<<4); //配置更新
while(!(RTC->CRL&(1<<5))); //等待RTC寄存器操作完成
printf("FIRST TIME\n");
}else//系統(tǒng)繼續(xù)計(jì)時(shí)
{
while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步
RTC->CRH|=0X01; //允許秒中斷
while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成
printf("OK\n");
}
STM32_NVIC_SetPriority(RTC_IRQn,2,2); //優(yōu)先級(jí)
}
extern void Update_FrameShow(void);
/*
函數(shù)功能: RTC鬧鐘中斷服務(wù)函數(shù)
*/
void RTC_IRQHandler(void)
{
u32 SecCnt;
if(RTC->CRL&1<<0)
{
SecCnt=RTC->CNTH<<16;//獲取高位
SecCnt|=RTC->CNTL; //獲取低位
RTC_GetTime(SecCnt); //轉(zhuǎn)換標(biāo)準(zhǔn)時(shí)間
RTC_GetWeek(SecCnt);
// printf("%d-%d-%d %d:%d:%d week:%d\n",rtc_clock.year,rtc_clock.mon,rtc_clock.day,rtc_clock.hour,rtc_clock.min,rtc_clock.sec,rtc_clock.week);
Update_FrameShow(); //更新顯示
RTC->CRL&=~(1<<0); //清除秒中斷標(biāo)志位
}
if(RTC->CRL&1<<1)
{
// printf("鬧鐘時(shí)間到達(dá)!....\n");
// BEEP=1;
// DelayMs(500);
// BEEP=0;
RTC->CRL&=~(1<<1); //清除鬧鐘中斷標(biāo)志位
}
}
//閏年的月份
static int mon_r[12]={31,29,31,30,31,30,31,31,30,31,30,31};
//平年的月份
static int mon_p[12]={31,28,31,30,31,30,31,31,30,31,30,31};
/*
函數(shù)功能: 設(shè)置RTC時(shí)間
函數(shù)形參:
u32 year; 2018
u32 mon; 8
u32 day;
u32 hour;
u32 min;
u32 sec;
*/
void RTC_SetTime(u32 year,u32 mon,u32 day,u32 hour,u32 min,u32 sec)
{
u32 i;
u32 SecCnt=0; //總秒數(shù)
/*1. 累加已經(jīng)過(guò)去的年份*/
for(i=2017;iAPB1ENR|=1<<28;//使能電源時(shí)鐘
RCC->APB1ENR|=1<<27;//使能備份時(shí)鐘
PWR->CR|=1<<8; //取消備份區(qū)寫(xiě)保護(hù)
//上面三步是必須的!
RTC->CRL|=1<<4; //允許配置
RTC->CNTL=SecCnt&0xffff;
RTC->CNTH=SecCnt>>16;
RTC->CRL&=~(1<<4);//配置更新
while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成
}
/*
函數(shù)功能: 獲取RTC時(shí)間
函數(shù)參數(shù): u32 sec 秒單位時(shí)間
*/
void RTC_GetTime(u32 sec)
{
u32 i;
rtc_clock.year=2017; //基準(zhǔn)年份
/*1. 計(jì)算當(dāng)前的年份*/
while(1)
{
if(RTC_GetYearState(rtc_clock.year))
{
if(sec>=366*24*60*60) //夠一年
{
sec-=366*24*60*60;
rtc_clock.year++;
}
else break;
}
else
{
if(sec>=365*24*60*60) //夠一年
{
sec-=365*24*60*60;
rtc_clock.year++;
}
else break;
}
}
/*2. 計(jì)算當(dāng)前的月份*/
rtc_clock.mon=1;
for(i=0;i<12;i++)
{
if(RTC_GetYearState(rtc_clock.year))
{
if(sec>=mon_r[i]*24*60*60)
{
sec-=mon_r[i]*24*60*60;
rtc_clock.mon++;
}
else break;
}
else
{
if(sec>=mon_p[i]*24*60*60)
{
sec-=mon_p[i]*24*60*60;
rtc_clock.mon++;
}
else break;
}
}
/*3. 計(jì)算當(dāng)前的天數(shù)*/
rtc_clock.day=1;
while(1)
{
if(sec>=24*60*60)
{
sec-=24*60*60;
rtc_clock.day++;
}
else break;
}
/*4. 計(jì)算當(dāng)前的小時(shí)*/
rtc_clock.hour=0;
while(1)
{
if(sec>=60*60)
{
sec-=60*60;
rtc_clock.hour++;
}
else break;
}
/*5. 計(jì)算當(dāng)前的分鐘*/
rtc_clock.min=0;
while(1)
{
if(sec>=60)
{
sec-=60;
rtc_clock.min++;
}
else break;
}
/*6. 計(jì)算當(dāng)前的秒*/
rtc_clock.sec=sec;
}
/*
函數(shù)功能: 判斷年份是否是平年、閏年
返回值 : 0表示平年 1表示閏年
*/
u8 RTC_GetYearState(u32 year)
{
if((year%4==0&&year%100!=0)||year%400==0)
{
return 1;
}
return 0;
}
/*
函數(shù)功能: 獲取星期
*/
void RTC_GetWeek(u32 sec)
{
u32 day1=sec/(60*60*24); //將秒單位時(shí)間轉(zhuǎn)為天數(shù)
switch(day1%7)
{
case 0:
rtc_clock.week=0;
break;
case 1:
rtc_clock.week=1;
break;
case 2:
rtc_clock.week=2;
break;
case 3:
rtc_clock.week=3;
break;
case 4:
rtc_clock.week=4;
break;
case 5:
rtc_clock.week=5;
break;
case 6:
rtc_clock.week=6;
break;
}
}
;i++)>
4.3 ESP8266.c
#include "esp8266.h"
/*
函數(shù)功能:向ESP82668266發(fā)送命令
函數(shù)參數(shù):
cmd:發(fā)送的命令字符串
ack:期待的應(yīng)答結(jié)果,如果為空,則表示不需要等待應(yīng)答
waittime:等待時(shí)間(單位:10ms)
返 回 值:
0,發(fā)送成功(得到了期待的應(yīng)答結(jié)果)
1,發(fā)送失敗
*/
u8 ESP8266_SendCmd(u8 *cmd,u8 *ack,u16 waittime)
{
u8 res=0;
USART3_RX_STA=0;
USART3_RX_CNT=0;
UsartStringSend(USART3,cmd);//發(fā)送命令
if(ack&&waittime) //需要等待應(yīng)答
{
while(--waittime) //等待倒計(jì)時(shí)
{
DelayMs(10);
if(USART3_RX_STA)//接收到期待的應(yīng)答結(jié)果
{
if(ESP8266_CheckCmd(ack))
{
res=0;
//printf("cmd->ack:%s,%s\r\n",cmd,(u8*)ack);
break;//得到有效數(shù)據(jù)
}
USART3_RX_STA=0;
USART3_RX_CNT=0;
}
}
if(waittime==0)res=1;
}
return res;
}
/*
函數(shù)功能:ESP8266發(fā)送命令后,檢測(cè)接收到的應(yīng)答
函數(shù)參數(shù):str:期待的應(yīng)答結(jié)果
返 回 值:0,沒(méi)有得到期待的應(yīng)答結(jié)果
其他,期待應(yīng)答結(jié)果的位置(str的位置)
*/
u8* ESP8266_CheckCmd(u8 *str)
{
char *strx=0;
if(USART3_RX_STA) //接收到一次數(shù)據(jù)了
{
USART3_RX_BUF[USART3_RX_CNT]=0;//添加結(jié)束符
strx=strstr((const char*)USART3_RX_BUF,(const char*)str); //查找是否應(yīng)答成功
//printf("RX=%s",USART3_RX_BUF);
}
return (u8*)strx;
}
/*
函數(shù)功能:向ESP8266發(fā)送指定數(shù)據(jù)
函數(shù)參數(shù):
data:發(fā)送的數(shù)據(jù)(不需要添加回車(chē))
ack:期待的應(yīng)答結(jié)果,如果為空,則表示不需要等待應(yīng)答
waittime:等待時(shí)間(單位:10ms)
返 回 值:0,發(fā)送成功(得到了期待的應(yīng)答結(jié)果)luojian
*/
u8 ESP8266_SendData(u8 *data,u8 *ack,u16 waittime)
{
u8 res=0;
USART3_RX_STA=0;
UsartStringSend(USART3,data);//發(fā)送數(shù)據(jù)
if(ack&&waittime) //需要等待應(yīng)答
{
while(--waittime) //等待倒計(jì)時(shí)
{
DelayMs(10);
if(USART3_RX_STA)//接收到期待的應(yīng)答結(jié)果
{
if(ESP8266_CheckCmd(ack))break;//得到有效數(shù)據(jù)
USART3_RX_STA=0;
USART3_RX_CNT=0;
}
}
if(waittime==0)res=1;
}
return res;
}
/*
函數(shù)功能:ESP8266退出透?jìng)髂J?返 回 值:0,退出成功;
1,退出失敗
*/
u8 ESP8266_QuitTrans(void)
{
while((USART3->SR&0X40)==0); //等待發(fā)送空
USART3->DR='+';
DelayMs(15); //大于串口組幀時(shí)間(10ms)
while((USART3->SR&0X40)==0); //等待發(fā)送空
USART3->DR='+';
DelayMs(15); //大于串口組幀時(shí)間(10ms)
while((USART3->SR&0X40)==0); //等待發(fā)送空
USART3->DR='+';
DelayMs(500); //等待500ms
return ESP8266_SendCmd("AT\r\n","OK",20);//退出透?jìng)髋袛?
}
/*
函數(shù)功能:獲取ESP8266模塊的連接狀態(tài)
返 回 值:0,未連接;1,連接成功.
*/
u8 ESP8266_ConstaCheck(void)
{
u8 *p;
u8 res;
if(ESP8266_QuitTrans())return 0; //退出透?jìng)?
ESP8266_SendCmd("AT+CIPSTATUS\r\n",":",50); //發(fā)送AT+CIPSTATUS指令,查詢連接狀態(tài)
p=ESP8266_CheckCmd("+CIPSTATUS\r\n:");
res=*p; //得到連接狀態(tài)
return res;
}
/*
函數(shù)功能:獲取ip地址
函數(shù)參數(shù):ipbuf:ip地址輸出緩存區(qū)
*/
void ESP8266_GetWanip(u8* ipbuf)
{
u8 *p,*p1;
if(ESP8266_SendCmd("AT+CIFSR\r\n","OK",50))//獲取WAN IP地址失敗
{
ipbuf[0]=0;
return;
}
p=ESP8266_CheckCmd(""");
p1=(u8*)strstr((const char*)(p+1),""");
*p1=0;
sprintf((char*)ipbuf,"%s",p+1);
}
五、QT設(shè)計(jì)的上位機(jī)代碼: Android手機(jī)APP+Windows系統(tǒng)上位機(jī)
?
-
Linux
+關(guān)注
關(guān)注
87文章
11329瀏覽量
209977 -
STM32
+關(guān)注
關(guān)注
2270文章
10915瀏覽量
356787 -
智能家居
+關(guān)注
關(guān)注
1928文章
9592瀏覽量
185814 -
人體感應(yīng)
+關(guān)注
關(guān)注
3文章
64瀏覽量
17018 -
智能插座
+關(guān)注
關(guān)注
5文章
194瀏覽量
27762
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論