- 純串口透傳,接收MCU串口數(shù)據(jù),直接通過MQTT上傳到服務(wù)器,接收服務(wù)器數(shù)據(jù)下發(fā)給MCU。
- smartconfig+airkiss配網(wǎng),隨意使用,場景豐富。
- 最多儲存5個WIFI賬號和密碼,自動尋找網(wǎng)絡(luò)連接。
- 按鍵配網(wǎng),長按重新配網(wǎng),前一次WiFi自動儲存,添加配網(wǎng)指示燈。
- OTA空中升級(待驗(yàn)證)
程序的入口先進(jìn)行串口初始化和按鍵的初始化,以及LED的初始化。串口要初始化波特率,按鍵初始化配網(wǎng)按鍵,用于短按配網(wǎng),長按重新配網(wǎng),LED只要用于判斷模塊是否進(jìn)入配網(wǎng)模式以及是否配網(wǎng)完成。//程序入口
void ICACHE_FLASH_ATTR user_init(void)
{
uart_init(115200, 115200);
os_delay_us(60000);
keyInit();
set_uart_cb(uart_cb);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12); //GPIO12初始化
GPIO_OUTPUT_SET(GPIO_ID_PIN(12), 0);//低電平
get_mac();//獲取MAC地址
wifi_set_opmode(STATION_MODE);
//設(shè)置wifi信息存儲數(shù)量,最大為5個
wifi_station_ap_number_set(2);
mqtt_init();
set_wifistate_cb(wifi_connect_cb, wifi_disconnect_cb);
}
初始化完成后會首先讀取MAC地址,該地址是唯一的,每個模塊都不一樣,用于填充進(jìn)主題中,便于服務(wù)器區(qū)分不同設(shè)備,用于多臺量產(chǎn)設(shè)備的使用,在連接MQTT服務(wù)器時會自動填充。
每連接一次WiFi都會將WiFi信息保存在模塊內(nèi)部,每次上電都會自動掃描暴露的WiFi,直接連接,就像手機(jī)的WIFI連接,目前最大支持五個WiFi信息的保存,超過5個會剔除最早的WiFi信息,通過短按D5(GPIO14)可進(jìn)入配網(wǎng)模式。
/**
* 按鍵短按回調(diào)
*/
LOCAL void ICACHE_FLASH_ATTR key1ShortPress(void) {
start_smartconfig(smartconfig_cd);
INFO("start_smartconfig ");
}
/**
* 按鍵長按回調(diào)
*/
LOCAL void ICACHE_FLASH_ATTR key1LongPress(void) {
start_smartconfig(smartconfig_cd);
INFO("start_smartconfig ");
}
/**
* 按鍵初始化
*/
LOCAL void ICACHE_FLASH_ATTR keyInit(void) {
//設(shè)置按鍵數(shù)量
set_key_num(1);
//長按、短按的按鍵回調(diào)
key_add(D5, NULL, key1ShortPress);
key_add(D5, NULL, key1LongPress);
}
由于找不到最新的代碼。這里的長按我沒做處理,應(yīng)該是斷開WiFi重新進(jìn)入配網(wǎng)模式, 或者軟復(fù)位模塊,再進(jìn)入start_smartconfig()函數(shù):
/**
* 開始Smartconfig配置
* @param cd: Smartconfig狀態(tài)回調(diào)
* @retval None
*/
void ICACHE_FLASH_ATTR start_smartconfig(smartconfig_cd_t cd) {
smartconfig_flag = 1;
smartconfig_set_type(SC_TYPE_ESPTOUCH_AIRKISS); //SC_TYPE_ESPTOUCH,SC_TYPE_AIRKISS,SC_TYPE_ESPTOUCH_AIRKISS
wifi_station_disconnect();
wifi_set_opmode(STATION_MODE);
finish_cd = cd;
smartconfig_start(smartconfig_done);
os_timer_disarm(&OS_Timer_Wifichange); // 關(guān)閉定時器
if(connect_flag == 1){
w_disconnect();
connect_flag = 0;
}
os_timer_disarm(&OS_Timer_SM); // 關(guān)閉定時器
os_timer_setfn(&OS_Timer_SM, (os_timer_func_t *) sm_wait_time, NULL);// 設(shè)置定時器
os_timer_arm(&OS_Timer_SM, 1000, 1); // 使能定時器
}
第一個是smartconfig配網(wǎng)(手機(jī)APP),第二個是airkiss配網(wǎng)(微信公眾號),最后一個兩者都可以。進(jìn)入該函數(shù)會調(diào)用smartconfig_start();,該函數(shù)會調(diào)用smartconfig_done()函數(shù)進(jìn)行配網(wǎng),配網(wǎng)成功后會點(diǎn)亮LED燈。
/**
* Smartconfig 狀態(tài)處理
* @param status: 狀態(tài)
* @param *pdata: AP數(shù)據(jù)
* @retval None
*/
void ICACHE_FLASH_ATTR
smartconfig_done(sc_status status, void *pdata) {
switch (status) {
case SC_STATUS_WAIT:
INFO("SC_STATUS_WAIT ");
break;
case SC_STATUS_FIND_CHANNEL:
INFO("SC_STATUS_FIND_CHANNEL ");
break;
case SC_STATUS_GETTING_SSID_PSWD:
INFO("SC_STATUS_GETTING_SSID_PSWD ");
sc_type *type = pdata;
if (*type == SC_TYPE_ESPTOUCH) {
INFO("SC_TYPE:SC_TYPE_ESPTOUCH ");
} else {
INFO("SC_TYPE:SC_TYPE_AIRKISS ");
}
break;
case SC_STATUS_LINK:
INFO("SC_STATUS_LINK ");
sm_comfig_status = SM_STATUS_GETINFO;
struct station_config *sta_conf = pdata;
wifi_station_set_config(sta_conf);
wifi_station_disconnect();
wifi_station_connect();
break;
case SC_STATUS_LINK_OVER:
sm_comfig_status = SM_STATUS_FINISH;
INFO("SC_STATUS_LINK_OVER ");
if (pdata != NULL) {
//SC_TYPE_ESPTOUCH
uint8 phone_ip[4] = { 0 };
os_memcpy(phone_ip, (uint8*) pdata, 4);
INFO("Phone ip: %d.%d.%d.%d ", phone_ip[0], phone_ip[1],
phone_ip[2], phone_ip[3]);
} else {
//SC_TYPE_AIRKISS - support airkiss v2.0
airkiss_start_discover();
}
smartconfig_stop();
smartconfig_flag = 0;
connect_flag = 0;
os_timer_disarm(&OS_Timer_SM); // 關(guān)閉定時器
finish_cd(sm_comfig_status);
os_timer_arm(&OS_Timer_Wifichange, 3000, 1); // 使能定時器
break;
}
}
/**
* WIFI連接回調(diào)
*/
void wifi_connect_cb(void){
INFO("wifi connect! ");
os_printf("----- WiFi連接成功,打開綠燈--- ");
GPIO_OUTPUT_SET(GPIO_ID_PIN(12), 1);
MQTT_Connect(&mqttClient);
}
/**
* WIFI斷開回調(diào)
*/
void wifi_disconnect_cb(void){
INFO("wifi disconnect! ");
os_printf("----- WiFi斷開,關(guān)閉綠燈--- ");
GPIO_OUTPUT_SET(GPIO_ID_PIN(12), 0);
MQTT_Disconnect(&mqttClient);
}
連接MQTT服務(wù)器:
網(wǎng)絡(luò)連接成功以后可以開始MQTT的初始化,初始化包涵一系列的連接初始化回調(diào),連接成功或不成功回調(diào),主題訂閱發(fā)布回調(diào)等等。
/**
* MQTT初始化
*/
void ICACHE_FLASH_ATTR mqtt_init(void) {
MQTT_InitConnection(&mqttClient, MQTT_HOST, MQTT_PORT, DEFAULT_SECURITY);
MQTT_InitClient(&mqttClient, mac_str, MQTT_USER,MQTT_PASS, MQTT_KEEPALIVE, 1);
MQTT_InitLWT(&mqttClient, lwt_topic, LWT_MESSAGE, 0, 0);
MQTT_OnConnected(&mqttClient, mqttConnectedCb);
MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);
MQTT_OnPublished(&mqttClient, mqttPublishedCb);
MQTT_OnData(&mqttClient, mqttDataCb);
}
void ICACHE_FLASH_ATTR
MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32_t port, uint8_t security)
{
uint32_t temp;
INFO("MQTT_InitConnection ");
os_memset(mqttClient, 0, sizeof(MQTT_Client));
temp = os_strlen(host);
mqttClient->host = (uint8_t*)os_zalloc(temp + 1);
os_strcpy(mqttClient->host, host);
mqttClient->host[temp] = 0;
mqttClient->port = port;
mqttClient->security = security;
}
void ICACHE_FLASH_ATTR
MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession)
{
uint32_t temp;
INFO("MQTT_InitClient ");
os_printf("CD MQTT_InitClient++++++++++++++++++++++ ");
os_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t));
temp = os_strlen(client_id);
mqttClient->connect_info.client_id = (uint8_t*)os_zalloc(temp + 1);
os_strcpy(mqttClient->connect_info.client_id, client_id);
mqttClient->connect_info.client_id[temp] = 0;
if (client_user)
{
temp = os_strlen(client_user);
mqttClient->connect_info.username = (uint8_t*)os_zalloc(temp + 1);
os_strcpy(mqttClient->connect_info.username, client_user);
mqttClient->connect_info.username[temp] = 0;
}
if (client_pass)
{
temp = os_strlen(client_pass);
mqttClient->connect_info.password = (uint8_t*)os_zalloc(temp + 1);
os_strcpy(mqttClient->connect_info.password, client_pass);
mqttClient->connect_info.password[temp] = 0;
}
mqttClient->connect_info.keepalive = keepAliveTime;
mqttClient->connect_info.clean_session = cleanSession;
mqttClient->mqtt_state.in_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE);
mqttClient->mqtt_state.in_buffer_length = MQTT_BUF_SIZE;
mqttClient->mqtt_state.out_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE);
mqttClient->mqtt_state.out_buffer_length = MQTT_BUF_SIZE;
mqttClient->mqtt_state.connect_info = &mqttClient->connect_info;
mqtt_msg_init(&mqttClient->mqtt_state.mqtt_connection, mqttClient->mqtt_state.out_buffer, mqttClient->mqtt_state.out_buffer_length);
QUEUE_Init(&mqttClient->msgQueue, QUEUE_BUFFER_SIZE);
system_os_task(MQTT_Task, MQTT_TASK_PRIO, mqtt_procTaskQueue, MQTT_TASK_QUEUE_SIZE);
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient);
}
WiFi連接成功和失敗會觸發(fā)不同的回調(diào)函數(shù):
串口透傳:/**
* MQTT連接回調(diào)
*/
void mqttConnectedCb(uint32_t *args) {
MQTT_Client* client = (MQTT_Client*) args;
INFO("MQTT: Connected ");
MQTT_Publish(client, birth_topic, BIRTH_MESSAGE, os_strlen(BIRTH_MESSAGE), 0,0);
MQTT_Subscribe(client,ota_topic, 0);
if(updata_status_check()){
MQTT_Publish(client, ota_topic, "updata_finish", os_strlen("updata_finish"), 0,0);
}
}
/**
* MQTT斷開連接回調(diào)
*/
void mqttDisconnectedCb(uint32_t *args) {
MQTT_Client* client = (MQTT_Client*) args;
INFO("MQTT: Disconnected ");
}
/**
* MQTT發(fā)布消息回調(diào)
*/
void mqttPublishedCb(uint32_t *args) {
MQTT_Client* client = (MQTT_Client*) args;
INFO("MQTT: Published ");
}
當(dāng)模塊的WiFi和MQTT服務(wù)器都連接上之后,模塊就開始監(jiān)聽串口和服務(wù)器的數(shù)據(jù),如果串口有數(shù)據(jù)過來便轉(zhuǎn)發(fā)到服務(wù)器或者進(jìn)行OTA升級,如果服務(wù)器有指令下發(fā)就轉(zhuǎn)發(fā)給串口。
其他問題:連接的服務(wù)器地址,端口號等信息需要寫在代碼里燒錄進(jìn)模塊,這些信息在在mqtt_config.h文件中定義。/**
* MQTT接收數(shù)據(jù)回調(diào)(用于OTA升級和串口透傳)
*/
void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len,
const char *data, uint32_t data_len) {
char *topicBuf = (char*) os_zalloc(topic_len + 1), *dataBuf =
(char*) os_zalloc(data_len + 1);
uint8 *pdata = (uint8*)data;
uint16 len = data_len;
uart0_tx_buffer(pdata, len);//串口輸出
MQTT_Client* client = (MQTT_Client*) args;
os_memcpy(topicBuf, topic, topic_len);
topicBuf[topic_len] = 0;
os_memcpy(dataBuf, data, data_len);
dataBuf[data_len] = 0;
// INFO("Receive topic: %s, data: %s ", topicBuf, dataBuf);
//data = {"url"="http://yourdomain.com:9001/ota/"}
if (os_strcmp(topicBuf, ota_topic) == 0) {
char url_data[200];
if(get_josn_str(dataBuf,"url",url_data)){
// INFO("ota_start ");
ota_upgrade(url_data,ota_finished_callback);
}
}
os_free(topicBuf);
os_free(dataBuf);
}
/**
* ota升級回調(diào)
*/
void ICACHE_FLASH_ATTR ota_finished_callback(void * arg) {
struct upgrade_server_info *update = arg;
if (update->upgrade_flag == true) {
INFO("OTA Success ! rebooting! ");
system_upgrade_reboot();
} else {
INFO("OTA Failed! ");
}
}
上電后可以在串口助手看到打印的MAC地址:
按下配網(wǎng)按鍵(GPIO14接地),進(jìn)入配網(wǎng)模式,使用APP或者微信公眾號將信息發(fā)給模塊便可聯(lián)網(wǎng),聯(lián)網(wǎng)后自動連接MQTT服務(wù)器。
責(zé)任編輯:xj
原文標(biāo)題:什么?單片機(jī)還在裸奔?ESP8266純串口透傳,助力設(shè)備上云端
文章出處:【微信公眾號:嵌入式ARM】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
-
單片機(jī)
+關(guān)注
關(guān)注
6067文章
44992瀏覽量
650497 -
云端
+關(guān)注
關(guān)注
0文章
123瀏覽量
17287 -
ESP8266
+關(guān)注
關(guān)注
51文章
965瀏覽量
47418
原文標(biāo)題:什么?單片機(jī)還在裸奔?ESP8266純串口透傳,助力設(shè)備上云端
文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
ESP32用作經(jīng)典藍(lán)牙串口透傳模塊與手機(jī)進(jìn)行串口通信

ESP8266燒錄與機(jī)智云一鍵配網(wǎng)教程

把esp8266加入到c51單片機(jī)單通道程序怎么寫
DTU終端CATCOM-100云端透傳轉(zhuǎn)發(fā)應(yīng)用

評論