?
一、環(huán)境介紹
程序開發(fā)IDE: keil5
STM32程序風(fēng)格: 采用寄存器方式開發(fā),注釋齊全,執(zhí)行效率高,方便移植
手機(jī)APP: 采用QT設(shè)計,程序支持跨平臺編譯運(yùn)行(Android、IOS、Windows、Linux都可以編譯運(yùn)行,對應(yīng)平臺上QT的環(huán)境搭建,之前博客已經(jīng)發(fā)了文章講解)
硬件包含:SRM32F103C8T6最小系統(tǒng)板、紅外熱釋電人體感應(yīng)模塊、DHT11溫濕度傳感器、0.96寸單色OLED顯示屏、ESP8266、繼電器、RGB大功率白燈.

?


?



?

?

二、功能介紹
這是基于STM32設(shè)計的智能插座+人體感應(yīng)燈。
硬件包含:
1. SRM32F103C8T6最小系統(tǒng)板: 基礎(chǔ)的系統(tǒng)板,引出了所有IO口
2. 紅外熱釋電人體感應(yīng)模塊: 用來檢測人體
3. DHT11溫濕度傳感器: 檢測環(huán)境的溫度、濕度
4. 0.96寸單色OLED顯示屏 : 顯示狀態(tài)信息。比如: WIFI狀態(tài)、RTC時鐘、插座狀態(tài)、溫濕度值
5. ESP8266: 用來與手機(jī)APP之間通信
6. 繼電器: 模擬插座開關(guān)
7. RGB大功率白燈: 模擬正常的燈泡
支持的功能如下:
1. 使用熱釋電人體感應(yīng)模塊檢測人體,檢測到人體自動開燈,30秒(時間可以根據(jù)要求調(diào)整)沒有檢測到人體就自動關(guān)燈。
2. 檢測環(huán)境溫濕度,使用OLED顯示屏在界面上實(shí)時顯示出來。 如果環(huán)境溫度高于閥值,強(qiáng)制關(guān)閉插座、如果濕度高于閥值,也會強(qiáng)制關(guān)閉插座;防止火災(zāi)隱患。 溫度最高閥值設(shè)置為: 30°,濕度閥值為80%, 這些都可以根據(jù)設(shè)計要求調(diào)整。
并且RGB燈也會根據(jù)不同的溫度閥值亮不同顏色的燈。 比如: 溫度高于30°亮紅色、溫度20°黃色 、溫度10°青色
3. 設(shè)置ESP8266WIFI模塊為AP模式(路由器模式),手機(jī)或者電腦可以連接到ESP8266.搭建局域網(wǎng)。
4. 設(shè)計手機(jī)APP和電腦客戶端軟件,可以實(shí)時顯示收到的溫濕度數(shù)據(jù)(3秒上傳一次).可以顯示歷史. 點(diǎn)擊手機(jī)APP上的按鈕,可以用來控制插座開關(guān)。
5. OLED一共有4個頁面。 RTC實(shí)時時鐘顯示頁面、溫濕度顯示頁面、智能插座開關(guān)狀態(tài)頁面、WIFI熱點(diǎn)信息頁面
6. OLED顯示屏的第一頁是實(shí)時時鐘頁面,時間可以通過手機(jī)APP來校準(zhǔn)。 在手機(jī)APP上有一個RTC校準(zhǔn)按鈕,點(diǎn)擊一下就可以校準(zhǔn)設(shè)備上的時間。
三、使用的相關(guān)硬件介紹
3.1DTH11 溫濕度傳感器

?

DHT11數(shù)字溫濕度傳感器是一款含有已校準(zhǔn)數(shù)字信號輸出的溫濕度復(fù)合傳感器,它應(yīng)用專用的數(shù)字模塊采集技術(shù)和溫濕度傳感技術(shù),確保產(chǎn)品具有極高的可靠性和卓越的長期穩(wěn)定性。傳感器包括一個電阻式感濕元件和一個NTC測溫元件,并與一個高性能8位單片機(jī)相連接。因此該產(chǎn)品具有品質(zhì)卓越、超快響應(yīng)、抗干擾能力強(qiáng)、性價比極高等優(yōu)點(diǎn)。每個DHT11傳感器都在極為精確的濕度校驗(yàn)室中進(jìn)行校準(zhǔn)。校準(zhǔn)系數(shù)以程序的形式存在OTP內(nèi)存中,傳感器內(nèi)部在檢測信號的處理過程中要調(diào)用這些校準(zhǔn)系數(shù)。單線制串行接口,使系統(tǒng)集成變得簡易快捷。超小的體積、極低的功耗,使其成為該類應(yīng)用中,在苛刻應(yīng)用場合的最佳選擇。產(chǎn)品為4針單排引腳封裝,連接方便。
3.2熱釋電傳感器

?


?

熱釋電紅外傳感器在結(jié)構(gòu)上引入場效應(yīng)管,其目的在于完成阻抗變換。由于熱釋電元輸出的是電荷信號,并不能直接使用,因而需要用電阻將其轉(zhuǎn)換為電壓形式。故引入的N溝道結(jié)型場效應(yīng)管應(yīng)接成共漏形式來完成阻抗變換。熱釋電紅外傳感器由傳感探測元、干涉濾光片和場效應(yīng)管匹配器三部分組成。設(shè)計時應(yīng)將高熱電材料制成一定厚度的薄片,并在它的兩面鍍上金屬電極,然后加電對其進(jìn)行極化,這樣便制成了熱釋電探測元。
熱釋電紅外傳感器的外形如上圖所示。其可以檢測人體發(fā)出的紅外線信號,并將其轉(zhuǎn)換成電信號輸出。傳感器頂部的長方形窗口加有濾光片,可以使人體發(fā)出的9~10μm波長的紅外線通過,而其它波長的紅外線被濾除,這樣便提高了抗干擾能。熱釋電紅外傳感器由濾光片、熱釋電探測元和前置放大器組成,補(bǔ)償型熱釋電傳感器還帶有溫度補(bǔ)償元件,圖所示為熱釋電傳感器的內(nèi)部結(jié)構(gòu)。為防止外部環(huán)境對傳感器輸出信號的干擾,上述元件被真空封裝在一個金屬營內(nèi)。熱釋電傳感器的濾光片為帶通濾光片,它封裝在傳感器殼體的頂端,使特定波長的紅外輻射選擇性地通過,到達(dá)熱釋電探測元+在其截止范圍外的紅外輻射則不能通過。
熱釋電探測元是熱釋電傳感器的核心元件,它是在熱釋電晶體的兩面鍍上金屬電極后,加電極化制成,相當(dāng)于一個以熱釋電晶體為電介質(zhì)的平板電容器。當(dāng)它受到非恒定強(qiáng)度的紅外光照射時,產(chǎn)生的溫度變化導(dǎo)致其表面電極的電荷密度發(fā)生改變,從而產(chǎn)生熱釋電電流。
前置放大器由一個高內(nèi)阻的場效應(yīng)管源極跟隨器構(gòu)成,通過阻抗變換,將熱釋電探測元微弱的電流信號轉(zhuǎn)換為有用的電壓信號輸出。
3.3ESP8266串口WIFI模塊

?

ESP8266系列無線模塊是高性價比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 時鐘速度最?可達(dá) 160 MHz,?持實(shí)時操作系統(tǒng) (RTOS) 和 Wi-Fi 協(xié)議棧,可將?達(dá) 80% 的處理能?應(yīng)用于編程和開發(fā)。
高度集成
ESP8266 芯片高度集成天線開關(guān)、射頻巴倫、功率放大器、低噪聲接收放大器、濾波器等射頻模塊。模組尺寸小巧,尤其適用于空間受限的產(chǎn)品設(shè)計。
認(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 模組既可以通過 ESP-AT 指令固件,為外部主機(jī) MCU 提供 Wi-Fi 連接功能;也可以作為獨(dú)立 Wi-Fi MCU 運(yùn)行,用戶通過基于 RTOS 的 SDK 開發(fā)帶 Wi-Fi 連接功能的產(chǎn)品。用戶可以輕松實(shí)現(xiàn)開箱即用的云連接、低功耗運(yùn)行模式,以及包括 WPA3 在內(nèi)的 Wi-Fi 安全支持等功能。
3.4OLED顯示屏

?

OLED顯示屏是利用有機(jī)電自發(fā)光二極管制成的顯示屏。由于同時具備自發(fā)光有機(jī)電激發(fā)光二極管,不需背光源、對比度高、厚度薄、視角廣、反應(yīng)速度快、可用于撓曲性面板、使用溫度范圍廣、構(gòu)造及制程較簡單等優(yōu)異之特性,被認(rèn)為是下一代的平面顯示器新興應(yīng)用技術(shù)。
有機(jī)發(fā)光二極管 (OLED)顯示器越來越普遍,在手機(jī)、媒體播放器及小型入門級電視等產(chǎn)品中最為顯著。不同于標(biāo)準(zhǔn)的液晶顯示器,OLED 像素是由電流源所驅(qū)動。若要了解 OLED 電源供應(yīng)如何及為何會影響顯示器畫質(zhì),必須先了解 OLED 顯示器技術(shù)及電源供應(yīng)需求。本文將說明最新的 OLED 顯示器技術(shù),并探討主要的電源供應(yīng)需求及解決方案,另外也介紹專為 OLED 電源供應(yīng)需求而提出的創(chuàng)新性電源供應(yīng)架構(gòu)。
背板技術(shù)造就軟性顯示器 高分辨率彩色主動式矩陣有機(jī)發(fā)光二極管 (AMOLED) 顯示器需要采用主動式矩陣背板,此背板使用主動式開關(guān)進(jìn)行各像素的開關(guān)。液晶 (LC) 顯示器非晶硅制程已臻成熟,可供應(yīng)低成本的主動式矩陣背板,并且可用于 OLED。許多公司正針對軟性顯示器開發(fā)有機(jī)薄膜晶體管 (OTFT) 背板制程,此一制程也可用于 OLED 顯示器,以實(shí)現(xiàn)全彩軟性顯示器的推出。不論是標(biāo)準(zhǔn)或軟性 OLED,都需要運(yùn)用相同的電源供應(yīng)及驅(qū)動技術(shù)。若要了解 OLED 技術(shù)、功能及其與電源供應(yīng)之間的互動,必須深入剖析這項(xiàng)技術(shù)本身。OLED 顯示器是一種自體發(fā)光顯示器技術(shù),完全不需要任何背光。OLED 采用的材質(zhì)屬于化學(xué)結(jié)構(gòu)適用的有機(jī)材質(zhì)。 OLED 技術(shù)需要電流控制驅(qū)動方法 OLED 具有與標(biāo)準(zhǔn)發(fā)光二極管 (LED) 相當(dāng)類似的電氣特性,亮度均取決于 LED 電流。若要開啟和關(guān)閉 OLED 并控制 OLED 電流,需要使用薄膜晶體管 (TFT)的控制電路。
OLED為自發(fā)光材料,不需用到背光板,同時視角廣、畫質(zhì)均勻、反應(yīng)速度快、較易彩色化、用簡單驅(qū)動電路即可達(dá)到發(fā)光、制程簡單、可制作成撓曲式面板,符合輕薄短小的原則,應(yīng)用范圍屬于中小尺寸面板。
顯示方面:主動發(fā)光、視角范圍大;響應(yīng)速度快,圖像穩(wěn)定;亮度高、色彩豐富、分辨率高。
工作條件:驅(qū)動電壓低、能耗低,可與太陽能電池、集成電路等相匹配。
適應(yīng)性廣:采用玻璃襯底可實(shí)現(xiàn)大面積平板顯示;如用柔性材料做襯底,能制成可折疊的顯示器。由于OLED是全固態(tài)、非真空器件,具有抗震蕩、耐低溫(-40℃)等特性,在軍事方面也有十分重要的應(yīng)用,如用作坦克、飛機(jī)等現(xiàn)代化武器的顯示終端。
3.5LED大功率燈模塊

?

LED燈是一塊電致發(fā)光的半導(dǎo)體材料芯片,用銀膠或白膠固化到支架上,然后用銀線或金線連接芯片和電路板,四周用環(huán)氧樹脂密封,起到保護(hù)內(nèi)部芯線的作用,最后安裝外殼,所以 LED 燈的抗震性能好。
LED(Light Emitting Diode),發(fā)光二極管,是一種能夠?qū)㈦娔苻D(zhuǎn)化為可見光的固態(tài)的半導(dǎo)體器件,它可以直接把電轉(zhuǎn)化為光。LED的心臟是一個半導(dǎo)體的晶片,晶片的一端附在一個支架上,一端是負(fù)極,另一端連接電源的正極,使整個晶片被環(huán)氧樹脂封裝起來。
半導(dǎo)體晶片由兩部分組成,一部分是P型半導(dǎo)體,在它里面空穴占主導(dǎo)地位,另一端是N型半導(dǎo)體,在這邊主要是電子。但這兩種半導(dǎo)體連接起來的時候,它們之間就形成一個P-N結(jié)。當(dāng)電流通過導(dǎo)線作用于這個晶片的時候,電子就會被推向P區(qū),在P區(qū)里電子跟空穴復(fù)合,然后就會以光子的形式發(fā)出能量,這就是LED燈發(fā)光的原理。而光的波長也就是光的顏色,是由形成P-N結(jié)的材料決定的。
LED可以直接發(fā)出紅、黃、藍(lán)、綠、青、橙、紫、白色的光。
3.6STM32F103C8T6最小系統(tǒng)板

?

STM32F系列屬于中低端的32位ARM微控制器,該系列芯片是意法半導(dǎo)體(ST)公司出品,其內(nèi)核是Cortex-M3。
該系列芯片按片內(nèi)Flash的大小可分為三大類:小容量(16K和32K)、中容量(64K和128K)、大容量(256K、384K和512K)。
芯片集成定時器Timer,CAN,ADC,SPI,I2C,USB,UART等多種外設(shè)功能。
內(nèi)核
--ARM 32位的Cortex-M3
--最高72MHz工作頻率,在存儲器的0等待周期訪問時可達(dá)1.25DMips/MHZ(DhrystONe2.1)
--單周期乘法和硬件除法
存儲器
--從16K到512K字節(jié)的閃存程序存儲器(STM32F103XXXX中的第二個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)測器(PVD)
--4-16MHZ晶振
--內(nèi)嵌經(jīng)出廠調(diào)校的8MHz的RC振蕩器
--內(nèi)嵌帶校準(zhǔn)的40KHz的RC振蕩器
--產(chǎn)生CPU時鐘的PLL
--帶校準(zhǔn)的32KHz的RC振蕩器
低功耗
--睡眠、停機(jī)和待機(jī)模式
--Vbat為RTC和后備寄存器供電
模數(shù)轉(zhuǎn)換器
--2個12位模數(shù)轉(zhuǎn)換器,1us轉(zhuǎn)換時間(多達(dá)16個輸入通道)
--轉(zhuǎn)換范圍:0至3.6V
--雙采樣和保持功能
--溫度傳感器
DMA
--2個DMA控制器,共12個DMA通道:DMA1有7個通道,DMA2有5個通道
--支持的外設(shè):定時器、ADC、SPI、USB、IIC和UART
--多達(dá)112個快速I/O端口(僅Z系列有超過100個引腳)
--26/37/51/80/112個I/O口,所有I/O口一塊映像到16個外部中斷;幾乎所有的端口均可容忍5V信號
調(diào)試模式
--串行單線調(diào)試(SWD)和JTAG接口
--多達(dá)8個定時器
--3個16位定時器,每個定時器有多達(dá)4個用于輸入捕獲/輸出比較/PWM或脈沖計數(shù)的通道和增量編碼器輸入
--1個16位帶死區(qū)控制和緊急剎車,用于電機(jī)控制的PWM高級控制定時器
--2個看門狗定時器(獨(dú)立的和窗口型的)
--系統(tǒng)時間定時器:24位自減型計數(shù)器
--多達(dá)9個通信接口:
2個I2C接口(支持SMBus/PMBus)
3個USART接口(支持ISO7816接口,LIN,IrDA接口和調(diào)制解調(diào)控制)
2個SPI接口(18M位/秒)
CAN接口(2.0B主動)
USB 2.0全速接口
計算單元
CRC計算單元,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ù)功能: 繪制時鐘表盤框架
*/
void DrawTimeFrame(void)
{
u8 i;
OLED_Circle(32,32,31);//畫外圓
OLED_Circle(32,32,1); //畫中心圓
//畫刻度
for(i=0;i<60;i++)
{
if(i%5==0)OLED_DrawAngleLine(32,32,6*i,31,3,1);
}
OLED_RefreshGRAM(); //刷新數(shù)據(jù)到OLED屏幕
}
/*
函數(shù)功能: 更新時間框架顯示,在RTC中斷里調(diào)用
*/
char TimeBuff[20];
void Update_FrameShow(void)
{
/*1. 繪制秒針、分針、時針*/
OLED_DrawAngleLine2(32,32,rtc_clock.sec*6-6-90,27,0);//清除之前的秒針
OLED_DrawAngleLine2(32,32,rtc_clock.sec*6-90,27,1); //畫秒針
OLED_DrawAngleLine2(32,32,rtc_clock.min*6-6-90,24,0);
OLED_DrawAngleLine2(32,32,rtc_clock.min*6-90,24,1);
OLED_DrawAngleLine2(32,32,rtc_clock.hour*30-6-90,21,0);
OLED_DrawAngleLine2(32,32,rtc_clock.hour*30-90,21,1);
//繪制電子鐘時間
sprintf(TimeBuff,"%d",rtc_clock.year);
OLED_ShowString(65,16*0,16,TimeBuff); //年份字符串
OLED_ShowChineseFont(66+32,16*0,16,4); //顯示年
sprintf(TimeBuff,"%d/%d",rtc_clock.mon,rtc_clock.day);
OLED_ShowString(75,16*1,16,TimeBuff); //月
if(rtc_clock.sec==0)OLED_ShowString(65,16*2,16," "); //清除多余的數(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所有顯示頁面信息初始化
*/
u8 ESP8266_Stat=0; //存放ESP8266狀態(tài) 1 OK ,0 error
u8 ESP8266_WIFI_AP_SSID[10]; //存放WIFI的名稱
#define STM32_96BIT_UID (0x1FFFF7E8) //STM32內(nèi)部96位唯一芯片標(biāo)識符寄存器地址
/*
函數(shù)功能: ESP8266 WIFI 顯示頁面
*/
char ESP8266_PwdShow[20];
char ESP8266_IP_PortAddr[30]; //存放ESP8266 IP地址與端口號地址
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..."); //顯示頁面提示信息
/*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 延時3S等待重啟成功*/
DelayMs(1000);
DelayMs(1000);
DelayMs(1000);
//得到WIFI的名稱
uid=(u8*)STM32_96BIT_UID; //轉(zhuǎn)為指針為1個字節(jié)
for(i=0;i<96;i++)
{
stm32_uid+=*uid++; //計算校驗(yàn)和,得到WIFI數(shù)字編號
}
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("請用設(shè)備連接WIFI熱點(diǎn):%s,%s,%s\r\n",(u8*)ESP8266_WIFI_AP_SSID,(u8*)wifiap_encryption,(u8*)wifiap_password);
/*1.4 配置模塊AP模式無線參數(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ù)器模式必須開啟)*/
ESP8266_SendCmd("AT+CIPMUX=1\r\n","OK",20);
/*1.6 開啟Server模式(0,關(guān)閉;1,打開),端口號為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"); //顯示頁面提示信息
}
/*
函數(shù)功能: 顯示開關(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; //開燈
// }
// 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; //顯示的頁面
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(); //畫時鐘框架
USART3_RX_STA=0; //清空串口的接收標(biāo)志位
USART3_RX_CNT=0; //清空計數(shù)器
printf("初始化DHT11...\r\n");
DHT11_Init(); //初始化DHT11
printf("熱釋電模塊初始化...\r\n");
HumanDetection_Init(); //熱釋電模塊初始化
//OLED_Clear(0);
printf("開始進(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);
//時鐘頁面
if(page_cnt==0)
{
DrawTimeFrame(); //畫時鐘框架
RTC->CRH|=1<<0; //開啟秒中斷
}
//溫濕度頁面
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(); //畫時鐘框架
RTC->CRH|=1<<0; //開啟秒中斷
page_cnt=0;
}
}
//時間記錄
DelayMs(10);
TimeCnt++;
wifi_TimeCnt++;
if(TimeCnt>=100) //1000毫秒一次
{
TimeCnt=0;
//讀取溫濕度數(shù)據(jù)
DHT11_Read_Data(&temp,&humi);
//濕度大于90就關(guān)閉開關(guān)
if(humi>90)
{
socket_state=0;
if(page_cnt==3)
{
Show_Switch(socket_state);
}
}
//溫濕度頁面
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ù)長度
ESP8266_SendData(Save_ESP8266_SendData,(u8*)"OK",100); //WIFI發(fā)送數(shù)據(jù)
}
//熱釋電狀態(tài) 為真表示有人
if(HumanState)
{
LED1=0; //開燈
}
else //為假
{
LED1=1; //關(guān)燈
}
/*輪詢掃描數(shù)據(jù)*/
if(USART3_RX_STA) //WIFI 接收到一次數(shù)據(jù)了
{
rlen=USART3_RX_CNT; //得到本次接收到的數(shù)據(jù)長度
USART3_RX_BUF[rlen]='\0'; //添加結(jié)束符
// printf("接收的數(shù)據(jù): %s\r\n",USART3_RX_BUF); //發(fā)送到串口
{
/*判斷是否收到客戶端發(fā)來的數(shù)據(jù) */
p=strstr((char*)USART3_RX_BUF,"+IPD");
if(p!=NULL) //正常數(shù)據(jù)格式: +IPD,0,7:LED1_ON +IPD,0表示第0個客戶端 7:LED1_ON表示數(shù)據(jù)長度與數(shù)據(jù)
{
/*解析上位機(jī)發(fā)來的數(shù)據(jù)*/
p=strstr((char*)USART3_RX_BUF,":");
if(p!=NULL)
{
p+=1; //向后偏移1個字節(jié)
if(*p=='*') //設(shè)置RTC時間
{
p+=1; //向后偏移,指向正確的時間
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();//畫時鐘框架
}
}
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)
{
//檢查是不是第一次配置時鐘
u8 temp=0;
if(BKP->DR1!=0X5051)//之前使用的不是LSE
{
RCC->APB1ENR|=1<<28; //使能電源時鐘
RCC->APB1ENR|=1<<27; //使能備份時鐘
PWR->CR|=1<<8; //取消備份區(qū)寫保護(hù)
RCC->BDCR|=1<<16; //備份區(qū)域軟復(fù)位
RCC->BDCR&=~(1<<16); //備份區(qū)域軟復(fù)位結(jié)束
RCC->BDCR|=1<<0; //開啟外部低速振蕩器
while((!(RCC->BDCR&0X02))&&temp<250)//等待外部時鐘就緒
{
temp++;
DelayMs(10);
};
if(temp>=250) //return 1;//初始化時鐘失敗,晶振有問題
{
RCC->CSR|=1<<0; //開啟外部低速振蕩器
while(!(RCC->CSR&(1<<1)));//外部低速振蕩器
RCC->BDCR|=2<<8; //LSI作為RTC時鐘
BKP->DR1=0X5050; //標(biāo)記使用LSI作為RTC時鐘
}
else
{
RCC->BDCR|=1<<8; //LSE作為RTC時鐘
BKP->DR1=0X5051; //標(biāo)記使用LSE作為RTC時鐘
}
RCC->BDCR|=1<<15;//RTC時鐘使能
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è)置(有待觀察,看是否跑慢了?)理論值:32767
RTC_SetTime(2021,4,25,20,36,20); //設(shè)置時間
RTC->CRL&=~(1<<4); //配置更新
while(!(RTC->CRL&(1<<5))); //等待RTC寄存器操作完成
printf("FIRST TIME\n");
}else//系統(tǒng)繼續(xù)計時
{
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)先級
}
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)時間
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("鬧鐘時間到達(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ù)形參:
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)過去的年份*/
for(i=2017;iAPB1ENR|=1<<28;//使能電源時鐘
RCC->APB1ENR|=1<<27;//使能備份時鐘
PWR->CR|=1<<8; //取消備份區(qū)寫保護(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ù): u32 sec 秒單位時間
*/
void RTC_GetTime(u32 sec)
{
u32 i;
rtc_clock.year=2017; //基準(zhǔn)年份
/*1. 計算當(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. 計算當(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. 計算當(dāng)前的天數(shù)*/
rtc_clock.day=1;
while(1)
{
if(sec>=24*60*60)
{
sec-=24*60*60;
rtc_clock.day++;
}
else break;
}
/*4. 計算當(dāng)前的小時*/
rtc_clock.hour=0;
while(1)
{
if(sec>=60*60)
{
sec-=60*60;
rtc_clock.hour++;
}
else break;
}
/*5. 計算當(dāng)前的分鐘*/
rtc_clock.min=0;
while(1)
{
if(sec>=60)
{
sec-=60;
rtc_clock.min++;
}
else break;
}
/*6. 計算當(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); //將秒單位時間轉(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:等待時間(單位: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) //等待倒計時
{
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ā)送命令后,檢測接收到的應(yīng)答
函數(shù)參數(shù):str:期待的應(yīng)答結(jié)果
返 回 值:0,沒有得到期待的應(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ù)(不需要添加回車)
ack:期待的應(yīng)答結(jié)果,如果為空,則表示不需要等待應(yīng)答
waittime:等待時間(單位: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) //等待倒計時
{
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退出透傳模式
返 回 值:0,退出成功;
1,退出失敗
*/
u8 ESP8266_QuitTrans(void)
{
while((USART3->SR&0X40)==0); //等待發(fā)送空
USART3->DR='+';
DelayMs(15); //大于串口組幀時間(10ms)
while((USART3->SR&0X40)==0); //等待發(fā)送空
USART3->DR='+';
DelayMs(15); //大于串口組幀時間(10ms)
while((USART3->SR&0X40)==0); //等待發(fā)送空
USART3->DR='+';
DelayMs(500); //等待500ms
return ESP8266_SendCmd("AT\r\n","OK",20);//退出透傳判斷.
}
/*
函數(shù)功能:獲取ESP8266模塊的連接狀態(tài)
返 回 值:0,未連接;1,連接成功.
*/
u8 ESP8266_ConstaCheck(void)
{
u8 *p;
u8 res;
if(ESP8266_QuitTrans())return 0; //退出透傳
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ī)代碼: Android手機(jī)APP+Windows系統(tǒng)上位機(jī)


?


-
Linux
+關(guān)注
關(guān)注
87文章
11496瀏覽量
213225 -
STM32
+關(guān)注
關(guān)注
2291文章
11022瀏覽量
363417 -
智能家居
+關(guān)注
關(guān)注
1934文章
9777瀏覽量
190119 -
人體感應(yīng)
+關(guān)注
關(guān)注
3文章
66瀏覽量
17265 -
智能插座
+關(guān)注
關(guān)注
5文章
196瀏覽量
28092
發(fā)布評論請先 登錄
STM32F103x8 STM32F103xB單片機(jī)數(shù)據(jù)手冊
STM32F103C8T6開發(fā)板最小系統(tǒng)原理圖
stm32f103c8t6編碼器模式在keil的debug調(diào)試時遇到的問題求解
STM32F103C8T6使用CubeIDE燒錄運(yùn)行報硬件錯誤,相同代碼MDK燒錄卻可以正常運(yùn)行,為什么?
STM32F103C8T6 PA2無PWM輸出怎么解決?
基于STM32F103V8T6的智能水處理系統(tǒng)設(shè)計與實(shí)現(xiàn)

基于STM32F103C8T6 ADXL345 加速度傳感器的計步器設(shè)計指南和代碼
基于STM32+Rd-03D做個智能人體跟隨旋轉(zhuǎn)臺

19.3-星曈科技 openmv Hopenmv發(fā)送五個uchar Openmv+STM32F103C8T6視覺巡線小車 STM32循跡小車系列教程

19.4-STM32接收數(shù)據(jù)-狀態(tài)顯示在屏幕 openMV尋跡與小車控制 Openmv+STM32F103C8T6視覺巡線小車

評論