目標
制作一個ESP8266串口和MQTT相互透傳的小WIFI,可用手機修改其連接的路由器,由此該模塊可以任意加載到各種串口傳輸的單片機上,完成硬件到雲端的傳輸。
1 實物圖

2 MQTT網頁測試客戶端
鏈接:https://pan.baidu.com/s/1th4U0_nC3FOnvusPokYSGQ
提取碼:j7fm

3 ESP8266硬件程序燒錄代碼


//----------------------------------------------------------------------------------------//
//-----------------------------------程序功能-----------------------------------------//
/*
總功能: 制作一個MQTT服務器和ESP8266串口互相傳輸消息的模塊
如何使用:
1修改每個芯片的信息
1-1 修改每一個產品的ID
1-2 修改對應MQTT服務器配置信息
1-3 修改默認登陸WIFI的消息
2使用步驟
2-1 連接WIFI
上電前5S內
如果檢測到超過2S的按鍵長按,進入配網模式,LED慢閃。配網成功后,自動記錄WIFI的賬號和密碼。
如果沒有檢測到超過2S的按鍵動作,5s后自動進入連接WIFi模式,,LED快閃,連接上次記錄的WIFI。
2-2 連接MQTT服務器
連接不成功,5S后重連。
連接成功,等待服務器發送過來消息,或者將自己的串口收到的消息發送給MQTT服務器
2-3 按鍵功能預留
按下按鍵,led亮
離開按鍵,led滅
*/
//----------------------------------------------------------------------------------------//
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <math.h>
#include <EEPROM.h>
WiFiClient espClient;
PubSubClient client(espClient);
//----------------------------------------------------------------------------------------//
//-----------------------------------配置信息開始-----------------------------------------//
//----------------------------------------------------------------------------------------//
// 產品唯一ID 微信分配
#define PRODUCT_ID "gh_e93c1b3098b9_cc8c4f4cd693972f"
// 默認連接WIFI賬號密碼
#define DEFAULT_STASSID "dongdong"//默認連接的路由器的名字 HUAWEI-H3VBKZ
#define DEFAULT_STAPSW "dongdong"//默認連接的路由器的名字 13991320168
//通信服務器消息
#define MQTT_SEVER "www.dongvdong.top"
#define MQTT_PORT 1883
#define MQTT_USER "dongdong"
#define MQTT_PASS "dongdong"
#define MQTT_ID PRODUCT_ID // 使用產品ID充當服務器識別ID
#define MQTT_PUB_TOPIC PRODUCT_ID"/s" // 發布話題 產品ID+/s
#define MQTT_REC_TOPIC PRODUCT_ID"/r" // 接受話題 產品ID+/r
// led狀態反轉
bool ledState=0;
// 配網
#define Smart_KEY D2 //配網按鍵
#define Smart_LED D4 //配網LED指示燈
//led控制按鍵中斷
#define Use_LED D4 //控制LED
#define Use_KEY D2 //控制LED的按鍵
//-----------------------------------配置信息結束-----------------------------------------//
#define MAGIC_NUMBER 0xAA
struct config_type
{
char stassid[32];
char stapsw[64];
uint8_t magic;
};
config_type config;
char sendmsg[100];// 發送話題
/***************************(1.1)按鍵LED函數()*****************************/
// LED管腳口初始化
void LED_begin(){
pinMode(Use_LED,OUTPUT);
digitalWrite(Use_LED, LOW);
pinMode(Use_KEY, INPUT);
detachInterrupt(Use_KEY);
attachInterrupt(Use_KEY, highInterrupt, RISING);
}
// 高電平觸發
void highInterrupt(){
digitalWrite(Use_LED, LOW);
detachInterrupt(Use_KEY);
attachInterrupt(Use_KEY, lowInterrupt,FALLING);
}
// 低電平觸發
void lowInterrupt(){
digitalWrite(Use_LED, HIGH);
detachInterrupt(Use_KEY);
attachInterrupt(Use_KEY, highInterrupt, RISING);
}
/**************************************************************/
/*************************(2) WIFI連接設置 *************************************/
/* 1連接WIFI 自動連WIFI接入網絡*/
void setup_wifi() {
WiFi.begin(config.stassid, config.stapsw);
while (WiFi.status() != WL_CONNECTED) {
ESP.wdtFeed();
delay(200);
ledState = !ledState;
digitalWrite(Smart_LED, ledState);
Serial.print("...");
}
Serial.println("\r\n--------------WIFi CONNECT!-------------\r\n");
Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
}
/**************************************************************************/
/*************************(3) 服務器連接設置 *************************************/
/* 2連接服務器 等待,直到連接上服務器*/
void reconnect() {//等待,直到連接上服務器
while (!client.connected()) {//如果沒有連接上
Serial.println("Connect lost!");//連接失敗
if (client.connect(MQTT_ID+random(999999999),MQTT_USER,MQTT_PASS)) {//接入時的用戶名,盡量取一個很不常用的用戶名
client.subscribe(MQTT_REC_TOPIC);//接收外來的數據時的intopic
client.publish(MQTT_PUB_TOPIC,"hello world ");
Serial.println("Connect sever succes!");//連接失敗
} else {
Serial.println("failed, rc=");//連接失敗
Serial.print(client.state());//重新連接
Serial.println(" try again in 5 seconds");//延時5秒后重新連接
delay(5000);
}
}
}
void callback(char* topic, byte* payload, unsigned int length) {//用於接收數據
char recmsg[length+1];
for (int i = length-1; i >=0; i--) {
recmsg[i]=(char)payload[i];
}
recmsg[length]='\0';
Serial.println(recmsg);
// String str(recmsg); // char 轉換String
}
/**************************************************************************/
/*************************(4) smartConfig配置 *************************************/
void smartConfig()
{
Serial.println("Start smartConfig module");
pinMode(Smart_LED, OUTPUT);
digitalWrite(Smart_LED, 0);
WiFi.mode(WIFI_STA);
Serial.println("\r\nWait for Smartconfig");
WiFi.stopSmartConfig();
WiFi.beginSmartConfig();
while (1)
{
Serial.print(".");
digitalWrite(Smart_LED, 0);
delay(500);
digitalWrite(Smart_LED, 1);
delay(500);
if (WiFi.smartConfigDone())
{
Serial.println("SmartConfig Success");
strcpy(config.stassid, WiFi.SSID().c_str());
strcpy(config.stapsw, WiFi.psk().c_str());
Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
saveConfig();
break;
}
}
}
/**************************************************************************/
/*******************************5 保存信息**************************************/
/*
* 保存參數到EEPROM
*/
void saveConfig()
{
Serial.println("Save config!");
Serial.print("stassid:");
Serial.println(config.stassid);
Serial.print("stapsw:");
Serial.println(config.stapsw);
EEPROM.begin(1024);
uint8_t *p = (uint8_t*)(&config);
for (int i = 0; i < sizeof(config); i++)
{
EEPROM.write(i, *(p + i));
}
EEPROM.commit();
}
/*
* 從EEPROM加載參數
*/
void loadConfig()
{
EEPROM.begin(1024);
uint8_t *p = (uint8_t*)(&config);
for (int i = 0; i < sizeof(config); i++)
{
*(p + i) = EEPROM.read(i);
}
EEPROM.commit();
//出廠自帶
if (config.magic != MAGIC_NUMBER)
{
strcpy(config.stassid, DEFAULT_STASSID);
strcpy(config.stapsw, DEFAULT_STAPSW);
config.magic = MAGIC_NUMBER;
saveConfig();
Serial.println("Restore config!");
}
Serial.println(" ");
Serial.println("-----Read config-----");
Serial.print("stassid:");
Serial.println(config.stassid);
Serial.print("stapsw:");
Serial.println(config.stapsw);
Serial.println("-------------------");
}
void waitKey()
{
pinMode (Smart_LED, OUTPUT);
pinMode (Smart_KEY, INPUT);
digitalWrite(Smart_LED, 0);
Serial.println(" press key 2s: smartconfig mode! \r\n press key <2s: connect wifi!");
char keyCnt = 0;
unsigned long preTick = millis();
unsigned long preTick2 = millis();
int num = 0;
while (1)
{
ESP.wdtFeed();
if (millis() - preTick < 10 ) continue;//等待10ms
preTick = millis();
num++;
if (num % 20 == 0) //50*10=500ms=0.5s 反轉一次
{
ledState = !ledState;
digitalWrite(Smart_LED, ledState);
// delay(1);
Serial.print(".");
}
if (keyCnt >= 200 && digitalRead(Smart_KEY) == 1)
{ //按2S 進入一鍵配置
keyCnt = 0;
Serial.println("\r\n try to begin smartConfig! \r\n");
smartConfig();// 手機靈活設置WIFI
break;
}
// 不按按鍵,自動連接上傳WIFI
if (millis() - preTick2 > 5 * 1000) {
Serial.println("\r\n try to connect wifi! \r\n");
setup_wifi();
break;
}
if (digitalRead(Smart_KEY) == 1){ keyCnt++;}
else{keyCnt = 0;}
}
digitalWrite(Smart_LED, 0);
pinMode (Smart_KEY, OUTPUT);
}
/**************************************************************************/
void serial_mqtt_sendmsg(){
//-------------------Begin----------------------//
//功能: 通過串口給MQTT服務器發送數據
if(Serial.available()>0){
delay(100);
String comdata = Serial.readString();
Serial.print("Serial.readString:");
//從串口緩存區中讀取的整個字符串,直至檢測到終止字符。
// char terminator = ',';
// String comdata =Serial.readStringUntil(terminator);
// Serial.print("Serial.readStringUntil: ");
Serial.println(comdata);
while(Serial.read()>= 0){}
char charBuf[100];
comdata.toCharArray(charBuf, 100) ;
client.publish(MQTT_PUB_TOPIC,charBuf);
comdata = "";
}
//-------------------End----------------------//
}
//初始化函數
void setup() {//初始化程序,只運行一遍
Serial.begin(9600);//設置串口波特率(與燒寫用波特率不是一個概念)
loadConfig();// 讀取信息
waitKey();
delay(5000);
client.setServer(MQTT_SEVER, MQTT_PORT);//端口號
client.setCallback(callback); //用於接收服務器接收的數據
LED_begin();//設置LED模式
}
// 循環主函數
void loop() {//主循環
if(WiFi.status() == WL_CONNECTED){
// 初始化連接
reconnect();//確保連上服務器,否則一直等待。
// 訂閱話題等待
client.loop();//MUC接收數據的主循環函數。
// 將串口數據發送給服務器
serial_mqtt_sendmsg();
}
else
{
Serial.println("wifi fail!");
setup_wifi() ;
}
}
