项目有些久远,前年的机器人上需要的功能,当时是需要将STM32上的数据上传到服务器,比如机器人的速度,行驶距离,是否在拍照等等。便于管理者在PC或者手机上了解机器人的工作状态,同时可以远程下发指令给机器人,控制其完成相应动作。$ p- K* ]. }' D
因为所有的逻辑判断和控制都在服务器或者STM32上面,作为中间的无线模块仅仅需要上传STM32的数据并接收服务器下发的指令即可,所以这里对WiFi模块的要求不高,仅仅需要它作为透传功能即可。当时在选型的时候试过好几款WiFi模块,最终敲定了安信可的ESP8266,价格便宜,开发简单,但是搭建环境是真的不容易,深受其害。7 I2 a/ F3 Y' Z( N
选择好模块就该考虑使用AT指令还是使用SDK开发,AT指令固然简单,但是局限性非常大。如果使用AT指令,我那开发控制端的同事估计就要跳脚了,代码里需要写一大堆的AT指令,如果功能改变,指令代码就需要重写,烦不胜烦。
/ V8 e) b2 \% r# f8 X. A; a" W如果使用SDK开发,控制端只需发送简单的数据就行,完全不用考虑其他任何东西,ESP8266完全当做一个中转站,相对应的我的工作就会繁重,但是,我屈服了,选择使用SDK。0 A0 K) p V' B4 q) A! A9 w, l
于是就有了下面基于NONOS 2.0的ESP8266串口透传。主要有以下几个功能:* |& @5 c: w: g3 q
/ B% o5 I. s( M5 g L
- 纯串口透传,接收MCU串口数据,直接通过MQTT上传到服务器,接收服务器数据下发给MCU。
- smartconfig+airkiss配网,随意使用,场景丰富。
- 最多储存5个WIFI账号和密码,自动寻找网络连接。
- 按键配网,长按重新配网,前一次WiFi自动储存,添加配网指示灯。
- OTA空中升级(待验证)! z$ {! b' V/ I& `$ _
3 L3 c; D( K+ y ( R7 I4 J: x" `& t
从程序的入口开始:- ( K7 w4 L3 }% |5 H9 R! p6 H& M$ w$ f
- //程序入口
% ~, U1 l: }1 P( b - void ICACHE_FLASH_ATTR user_init(void). l5 X& J& p& O6 d% P2 @) u
- { e9 X! e/ Z; D
- uart_init(115200, 115200);4 a& r6 @1 E2 d7 b {0 ?& j
- os_delay_us(60000);
' q6 S! m( h$ s - keyInit();
- K+ J9 F; U- e3 E - set_uart_cb(uart_cb);* I( `* R4 M% X0 d
- 5 c" l* w' u2 x
- PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12); //GPIO12初始化
- n) U4 Y/ _2 b4 u; i0 _2 i7 l5 ^ - GPIO_OUTPUT_SET(GPIO_ID_PIN(12), 0);//低电平
; v# t4 q8 @2 D) d. h
- q' m+ {0 { g- get_mac();//获取MAC地址
" Z/ d+ N, ^) J - 7 z' d+ J: T: A2 Z
- wifi_set_opmode(STATION_MODE);
/ c% V/ s2 b& Z2 R, L - //设置wifi信息存储数量,最大为5个
" [+ Q7 b* |) F6 P7 d4 ? - wifi_station_ap_number_set(2);* }( M8 o0 f5 R0 D
- . ^* M3 C' ^! j8 f0 v/ C1 Q) T, R
- mqtt_init();! B1 {, K) e" G- e6 q8 Z9 {7 i
- * ~) E) ~8 o& _2 f& q" x1 Q* l
- set_wifistate_cb(wifi_connect_cb, wifi_disconnect_cb);2 u% c1 o% ?! i2 @- I, }9 b
- }
复制代码 $ \& E" e, p7 j) E* P% e: |1 L$ I
程序的入口先进行串口初始化和按键的初始化,以及LED的初始化。串口要初始化波特率,按键初始化配网按键,用于短按配网,长按重新配网,LED只要用于判断模块是否进入配网模式以及是否配网完成。3 o9 A ]8 K4 }
初始化完成后会首先读取MAC地址,该地址是唯一的,每个模块都不一样,用于填充进主题中,便于服务器区分不同设备,用于多台量产设备的使用,在连接MQTT服务器时会自动填充。6 p& Z) |2 s8 ~6 I3 W3 w
4 _) T; Z! z7 D5 e8 ]% x# H' Z每连接一次WiFi都会将WiFi信息保存在模块内部,每次上电都会自动扫描暴露的WiFi,直接连接,就像手机的WIFI连接,目前最大支持五个WiFi信息的保存,超过5个会剔除最早的WiFi信息,通过短按D5(GPIO14)可进入配网模式。% W! w1 @. a1 i) L, E( `) ]
5 m# L* o. Z. I7 o' y, v, ?- /**
G- p1 i1 e0 {+ k, N+ F - * 按键短按回调% r" }. d$ @6 C
- */
+ R w' M5 b# K& J a7 r - LOCAL void ICACHE_FLASH_ATTR key1ShortPress(void) {4 N, F' F" C# ~5 I
* G/ y4 J! `+ H% c" I' ?- start_smartconfig(smartconfig_cd);
5 F$ l$ r0 r" H0 G( n - INFO("start_smartconfig\n");1 C k6 R0 s" n8 F
- }* U3 h7 a9 Q! b; [) s
- /**
9 b& h* s$ a! R - * 按键长按回调7 j) n+ f7 ?3 S
- */' D' B$ F7 W9 F3 _ ~4 s' {
- LOCAL void ICACHE_FLASH_ATTR key1LongPress(void) {5 z9 ], a. G! y7 m& U
- 0 m5 t1 e" F- s- N1 h5 K
- start_smartconfig(smartconfig_cd);+ u6 P6 `. D; o2 q, B
- INFO("start_smartconfig\n");
# m2 S& G! \3 Q0 y5 K$ w - }: q1 R/ u2 ?( ?; C' k# M/ U2 }
- /** [. R: f8 `8 z6 b( T
- * 按键初始化2 X7 v; [4 q( y5 U" m3 A
- */( L5 |+ o. s/ H8 j
- LOCAL void ICACHE_FLASH_ATTR keyInit(void) {
: e% E2 v8 K- r1 L
6 l. {, y6 v3 c7 n- //设置按键数量( u& w2 J0 e ]4 a) I+ i0 j
- set_key_num(1);3 s* b& r6 I. V
- //长按、短按的按键回调
, R1 e/ d3 a4 [ ] - key_add(D5, NULL, key1ShortPress);
/ F: m* f9 q" A9 x5 Y4 f - key_add(D5, NULL, key1LongPress);
. _1 ~8 e8 t/ v9 B7 I i - 0 n# [0 Y( Y3 n$ w& E. O; S; P
- }
复制代码 ! K R" D; @: v/ n. P$ H/ [! F
) e0 G U% }! _7 [* U/ g0 e( A
由于找不到最新的代码。这里的长按我没做处理,应该是断开WiFi重新进入配网模式, 或者软复位模块,再进入start_smartconfig()函数:) [6 e; q/ Z8 ]$ B# ?2 x
5 z* m6 ^% N' M0 Q; j- /**
; t5 H0 M2 q3 A - * 开始Smartconfig配置 + K+ |1 l: }* Z
- * @param cd: Smartconfig状态回调: U9 j5 J; l. d
- * @retval None
1 h1 [; o' c+ x; A& s - */
' O- v! ?$ ~& O2 Y5 ] - void ICACHE_FLASH_ATTR start_smartconfig(smartconfig_cd_t cd) {# d7 E' w" e# S z: J) ?
- smartconfig_flag = 1;- g: \% A, E7 v/ q3 V2 Y# u* B
- smartconfig_set_type(SC_TYPE_ESPTOUCH_AIRKISS); //SC_TYPE_ESPTOUCH,SC_TYPE_AIRKISS,SC_TYPE_ESPTOUCH_AIRKISS" z8 s5 y9 P: o5 n1 h. h
- wifi_station_disconnect();! X, t: y# ?2 T+ _
- wifi_set_opmode(STATION_MODE);$ ?( L" O2 }1 `+ Z
- finish_cd = cd;
! z+ {! h& I& |: h, S' ]" l - smartconfig_start(smartconfig_done);. U3 Z* l0 C: U4 n; F
- os_timer_disarm(&OS_Timer_Wifichange); // 关闭定时器! T1 @. o9 x* a( y# L0 L, w) c9 d( N
( S% F7 R2 [6 r6 j- if(connect_flag == 1){5 l* T. p1 ]5 }: c
- w_disconnect();
) v. y+ s9 O7 R4 J' t5 G |3 ?! e - connect_flag = 0;
+ \9 U! p7 d$ a - }7 W. h; I1 h7 x% k
# C- t$ m1 B+ w r4 C- os_timer_disarm(&OS_Timer_SM); // 关闭定时器
; t6 `/ D! x: v* G1 N6 E2 p& f. H - os_timer_setfn(&OS_Timer_SM, (os_timer_func_t *) sm_wait_time, NULL);// 设置定时器( o3 V% }. r; `! p# }& ?
- os_timer_arm(&OS_Timer_SM, 1000, 1); // 使能定时器" v5 C3 a+ R$ o. r+ B A
- }
复制代码 $ b1 H, i' l: V2 ?' J
3 ^, B3 ~- o) l, W( r* x, R% _4 U ( o0 v! h3 H2 k3 `6 X4 A
smartconfig_set_type();函数可选3个参数:分别是:SC_TYPE_ESPTOUCH、SC_TYPE_AIRKISS和SC_TYPE_ESPTOUCH_AIRKISS4 l& H0 T* D2 k- t( u: G
第一个是smartconfig配网(手机APP),第二个是airkiss配网(微信公众号),最后一个两者都可以。进入该函数会调用smartconfig_start();,该函数会调用smartconfig_done()函数进行配网,配网成功后会点亮LED灯。- ( k E+ y, e' z4 A1 N' q
- /**
: ]0 D# ^% g( r5 B% a - * Smartconfig 状态处理, ]4 Z: a1 ~# [# \7 m" o
- * @param status: 状态
$ T3 o* o8 m9 F" M - * @param *pdata: AP数据
- Z1 q3 v5 X! Y - * @retval None! U% ^& ]4 F7 D5 G2 B
- */' A; O7 I$ t& P' a! e( M
- void ICACHE_FLASH_ATTR
( c2 F% J4 L& u - smartconfig_done(sc_status status, void *pdata) {
3 Q3 Q% K1 R$ w' L - switch (status) {
" ]2 n' ~) D& H; ~ - case SC_STATUS_WAIT:
7 P% A, M( O+ x1 v7 y! H) C/ _ - INFO("SC_STATUS_WAIT\n");* D# Y; r) Y- v0 l2 b$ [
- break;- |' l6 }6 v# i9 y& \+ o5 k
- case SC_STATUS_FIND_CHANNEL:; L. w( X' d' y
- INFO("SC_STATUS_FIND_CHANNEL\n");
! g8 ^& {% y5 Z3 K% s - break;
R9 ~: M3 q, F$ g - case SC_STATUS_GETTING_SSID_PSWD:
! q* _' `+ ?- l0 m4 s/ t - INFO("SC_STATUS_GETTING_SSID_PSWD\n");
% R! P1 m& G! P% x8 a% G, J - sc_type *type = pdata;, b8 C$ b; H0 C# c0 G2 C
- if (*type == SC_TYPE_ESPTOUCH) {2 W+ @6 a c- }' M# f8 ^; N
- INFO("SC_TYPE:SC_TYPE_ESPTOUCH\n");
6 K; ]1 l7 J5 R$ g* Q - } else {
5 @% k$ n1 L6 k/ K- b* |# v5 ^; l - INFO("SC_TYPE:SC_TYPE_AIRKISS\n");! n7 u4 G- M6 G# f) x+ }1 e
- }
; s+ H: C( Q$ \7 h - break;
6 g- i* U# v+ {$ K: m9 ] - case SC_STATUS_LINK:
$ {) C$ m9 J0 q: v- B+ \* x - INFO("SC_STATUS_LINK\n");+ Z. N& V) u. g+ G% m' b. |
- sm_comfig_status = SM_STATUS_GETINFO;
0 P2 A8 X! E3 R j - struct station_config *sta_conf = pdata;
9 ~& _; x: `' { - wifi_station_set_config(sta_conf);
! o' K% ^. I9 r - wifi_station_disconnect();
; B- f9 }% H: v$ V* ?( r+ d6 Z - wifi_station_connect();7 @5 Z' _3 q% a# L! x d
- break;
! b0 i' J( }& {- F" A/ U3 L - case SC_STATUS_LINK_OVER:
* L v. T7 G9 k# X) Z% q1 m% S - sm_comfig_status = SM_STATUS_FINISH;
7 t# {( W$ n. ?8 V6 d& u - INFO("SC_STATUS_LINK_OVER\n");. c7 d. V2 ]: r& \: R' M
- if (pdata != NULL) {
' I. U8 m# ^3 ?+ B+ O1 D7 x- D - //SC_TYPE_ESPTOUCH M: s' }! L( ?$ S. K9 W1 m
- uint8 phone_ip[4] = { 0 };) Q& u# S& `% `% u% ^" z4 V8 z
- os_memcpy(phone_ip, (uint8*) pdata, 4);
% A+ s1 Y" Q! t V8 F1 l% I - INFO("Phone ip: %d.%d.%d.%d\n", phone_ip[0], phone_ip[1],
6 [1 f/ g" J& b; ~* C- ` - phone_ip[2], phone_ip[3]);
0 b2 s. n& X$ s0 V/ \) F - } else {
, j4 ]1 j: @/ { - //SC_TYPE_AIRKISS - support airkiss v2.0
; e1 k& K3 D# H9 q9 l1 K. m0 C' y - airkiss_start_discover();
6 b" G" e/ g+ L1 B6 B, o - }, l, @; }- ]& n8 n
- smartconfig_stop();
. G9 Y6 }# @4 Y - smartconfig_flag = 0;9 ]5 M" g" |* F; c4 ~" N0 g- ^; j
- connect_flag = 0;
, Q2 ]8 u' e, N5 l& j, K& `4 b7 W - os_timer_disarm(&OS_Timer_SM); // 关闭定时器
8 t" ~7 I9 M4 @$ ^ - finish_cd(sm_comfig_status);, a0 S5 [! T0 S' |
- os_timer_arm(&OS_Timer_Wifichange, 3000, 1); // 使能定时器
" E$ y/ X) W/ l$ q& d. c) h# f - break;
5 V1 S! `) v' i - }
6 n l9 T( i0 M5 k
1 @9 x7 y( b% x( m* R- }# D9 H$ z% ` L) e- `
- : q$ r$ t! L. c/ f0 f: e/ v
- /**
4 a: h/ d2 v! T - * WIFI连接回调
8 X* K& ^5 o, f4 e* K- [4 ~' R - */ @3 B$ e8 _& Y5 ^ o
- void wifi_connect_cb(void){: U1 b' [" i5 x3 L
- 6 a1 u' Z+ |1 V! d* h" O+ p8 ?' T
- INFO("wifi connect!\r\n");
: W+ M( L# ?" u& i, ~1 p - os_printf("----- WiFi连接成功,打开绿灯---\r\n");
: a3 q9 _8 x- A$ V# P& T - GPIO_OUTPUT_SET(GPIO_ID_PIN(12), 1);
0 @6 s; o# s' N, u - MQTT_Connect(&mqttClient);
- W# A9 y( m9 s: b( M( [: d - }
: F C* B+ g2 p( p( c% j
! ?7 J! x( \ M- e- X- f6 a- /**
# S* J; x/ y6 v8 b% k- k4 o$ h; ? L - * WIFI断开回调" r% w4 y9 `3 y1 z9 h
- */
; K% v* Y* j- V, z; J7 B$ \ - void wifi_disconnect_cb(void){
! d' K7 i B3 G! ?3 }0 M& e - INFO("wifi disconnect!\r\n");* F& Y/ J3 R, l( @1 V0 y
- os_printf("----- WiFi断开,关闭绿灯---\r\n");
; k6 @# f6 i/ }) ~$ I# I - GPIO_OUTPUT_SET(GPIO_ID_PIN(12), 0);
l. D1 p3 O9 T6 \- @ - MQTT_Disconnect(&mqttClient);0 s/ Z+ _8 h! p+ t; ~) n! ?
- }
复制代码
0 G) {' [( y# V# o- o: x* K1 o( Y* H1 l1 D2 R/ F9 _2 \& i
连接MQTT服务器:! w6 a I4 A! _1 ]: X5 h. C
$ d" u& l, `* Q/ x( p2 H8 r3 u6 l
网络连接成功以后可以开始MQTT的初始化,初始化包涵一系列的连接初始化回调,连接成功或不成功回调,主题订阅发布回调等等。
% }6 @, |: {$ v9 d- /**
9 x( |, M! Z# R' ~+ M. N6 H6 H - * MQTT初始化
5 c8 `9 ^ s& J' L - */
9 \) A& ~+ p+ s2 h. M$ m" ?) { - void ICACHE_FLASH_ATTR mqtt_init(void) {
( q' H/ ^) }" K& F- Y6 _/ u
/ P Z% h) Q& e" K' J- MQTT_InitConnection(&mqttClient, MQTT_HOST, MQTT_PORT, DEFAULT_SECURITY);9 C$ {, ?9 t8 c! d
- MQTT_InitClient(&mqttClient, mac_str, MQTT_USER,MQTT_PASS, MQTT_KEEPALIVE, 1);
8 \3 Y7 N# Z5 }8 W6 F% h. u* m - MQTT_InitLWT(&mqttClient, lwt_topic, LWT_MESSAGE, 0, 0);
' k7 k* ~2 V. q! b8 Q3 V- Z - MQTT_OnConnected(&mqttClient, mqttConnectedCb);7 ^$ q, [- k# E
- MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);
7 N; v% ^ m' H' d/ z! c! u8 B( D - MQTT_OnPublished(&mqttClient, mqttPublishedCb);
2 T+ x3 s8 W0 _3 i; H. y2 b% G! g, Y - MQTT_OnData(&mqttClient, mqttDataCb);( {- h0 |+ }% B3 @
- }
. e6 Y5 h3 a! c; x3 ~0 `
6 W5 E. e2 J, `0 S9 y/ |0 o$ ?; h$ p- void ICACHE_FLASH_ATTR3 z9 y0 y. N/ }+ u) ~* X! I
- MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32_t port, uint8_t security)
1 b, a9 W |8 N7 _" Q5 M - {
6 U( F8 D! {, ^( m5 S - uint32_t temp;+ z K1 Q/ H8 T, o% m7 ]$ j! m
- INFO("MQTT_InitConnection\r\n"); F" ^7 S1 d4 S% J
- os_memset(mqttClient, 0, sizeof(MQTT_Client));* R w9 y0 n1 H6 V. n8 P& s5 _
- temp = os_strlen(host);
- _: S ]* \0 n( j, w T - mqttClient->host = (uint8_t*)os_zalloc(temp + 1);: Z+ F/ x* |& i8 n; f/ M8 E* U, `
- os_strcpy(mqttClient->host, host);
: `, ]2 m3 P$ W' n - mqttClient->host[temp] = 0;
8 [) I# o5 x$ q) L: @. h( K: i- ^( z ] - mqttClient->port = port;
" y6 U6 ]( \! O8 [0 V - mqttClient->security = security;8 n# S- g5 A0 f
- - L( i! m' T4 U3 v
- }
( D6 V( e7 L5 \! K( m - ; W, m3 s% r# J' g% m
- void ICACHE_FLASH_ATTR5 T$ {6 F( i% r8 p( v3 m2 Z4 E6 N2 H
- MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession)& f- |- @9 N) H4 h; Q X
- {
0 i! [% `4 W' d- D - uint32_t temp;1 E) J7 i# g8 ?1 S
- INFO("MQTT_InitClient\r\n");7 h$ [ Z. B4 j
- os_printf("CD MQTT_InitClient++++++++++++++++++++++\n");7 M0 _4 Z6 a1 p1 b! @; s0 \9 k# N
- os_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t));
# c/ ?- \, A5 G% k, d - & b4 B$ f F3 V( H+ }4 W7 }( Z9 f
- temp = os_strlen(client_id);
5 R9 W. ?$ F: s, G/ p - mqttClient->connect_info.client_id = (uint8_t*)os_zalloc(temp + 1);
6 F! n! |( T) x) I7 ^ - os_strcpy(mqttClient->connect_info.client_id, client_id);
2 Y" A7 o( v D! C6 p2 L i* b& f3 F - mqttClient->connect_info.client_id[temp] = 0;
/ M: Q2 E& C }4 e, j0 ?/ O+ \
( O2 l! v% D" x' ~- Z9 K9 `' C- if (client_user)
O7 U1 }- @* v/ }& E - {
, R# `1 [4 A! J7 F+ w - temp = os_strlen(client_user);
; }6 x' A' C! [6 U/ h$ j4 S - mqttClient->connect_info.username = (uint8_t*)os_zalloc(temp + 1);, w" P3 Z; P- U8 }5 L
- os_strcpy(mqttClient->connect_info.username, client_user);
9 U+ [- Z+ q# z - mqttClient->connect_info.username[temp] = 0;
. N4 w4 M: R- x& P- K! r: n - }% H8 e4 p. y! `4 F( P% b& y# o
- ) q2 M- }5 O: _$ j# O* N7 w
- if (client_pass) Y. E; h, `0 `8 y j
- {
' m" @2 t+ z# H+ [4 C6 L S* b - temp = os_strlen(client_pass); N o% D- e8 t5 j
- mqttClient->connect_info.password = (uint8_t*)os_zalloc(temp + 1);% R1 u- N* c4 U/ F" [
- os_strcpy(mqttClient->connect_info.password, client_pass);9 [# U1 C6 o& ]9 K Q. r' H1 B
- mqttClient->connect_info.password[temp] = 0;4 i, M9 P/ {7 D% Z* m
- }% e O+ v7 t( T# {2 c$ H3 L
- ; d* S" ]; r2 }0 i
/ p. Z3 g/ X( t' D5 h- mqttClient->connect_info.keepalive = keepAliveTime;
0 b; I4 q# b0 i - mqttClient->connect_info.clean_session = cleanSession;
* S5 P5 z8 ^' g- `4 [ - 8 ]& W ?# z( a0 u! P
- mqttClient->mqtt_state.in_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE);
, K* I; m3 Q8 e! O - mqttClient->mqtt_state.in_buffer_length = MQTT_BUF_SIZE;
: g/ P% q" ]/ a) q( Y X - mqttClient->mqtt_state.out_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE);8 U' z- n3 v( o: v4 @; \
- mqttClient->mqtt_state.out_buffer_length = MQTT_BUF_SIZE;
. g& u! p3 j4 ~- q. V' T. p+ z% N - mqttClient->mqtt_state.connect_info = &mqttClient->connect_info;
- _+ v: T% ?0 R4 ^9 m4 F3 l' Q - * z |3 V1 h& c3 K: I+ m* R
- mqtt_msg_init(&mqttClient->mqtt_state.mqtt_connection, mqttClient->mqtt_state.out_buffer, mqttClient->mqtt_state.out_buffer_length);$ R# h) m, n/ c* A; g
- 0 O/ v1 C" g4 j# H8 M# g4 Y
- QUEUE_Init(&mqttClient->msgQueue, QUEUE_BUFFER_SIZE);8 Q6 t* x) z( U4 k. r- q" d4 \
- ! u0 w0 y4 `8 A
- system_os_task(MQTT_Task, MQTT_TASK_PRIO, mqtt_procTaskQueue, MQTT_TASK_QUEUE_SIZE);
; U3 W7 y& b# b# c0 Y8 C" B* c - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient);
3 {0 J2 c% F* u* ]4 j - }
复制代码
& i6 p" \% X- v$ X
" W8 n9 d/ g9 K, I- B [ WiFi连接成功和失败会触发不同的回调函数:- 5 Z1 t6 G+ B1 o# B! E& W- S* n/ \" R
- /**. Q5 n& z4 ^+ [: O2 N
- * MQTT连接回调
) _; ]# S1 u4 ?6 D- o - */
6 ~6 ?* t o6 y' \9 X, I3 F - void mqttConnectedCb(uint32_t *args) {
' J5 D, x n. A/ } k' } - MQTT_Client* client = (MQTT_Client*) args;8 Q& C. s- J8 b: F: R# V7 h
- 3 }2 z5 w/ D& S
- INFO("MQTT: Connected\r\n");3 @1 S9 y. a1 G: u
- MQTT_Publish(client, birth_topic, BIRTH_MESSAGE, os_strlen(BIRTH_MESSAGE), 0,0);
* ~2 M# j. _0 r6 b8 M# a0 v - MQTT_Subscribe(client,ota_topic, 0);# C$ o; K( h& z1 ~- ]
- if(updata_status_check()){
/ k' I/ X0 o) Q$ G0 A - MQTT_Publish(client, ota_topic, "updata_finish", os_strlen("updata_finish"), 0,0);
% K, r& w* g' `7 ?. c6 Z) R - }8 ?/ W5 r$ A, ]5 x/ [/ w" Q
- }
: e( G+ l& a6 u. ~2 o - /**
9 _3 R7 F' D" [$ X! P; y - 6 p! s8 I7 Z% l, E' d3 Z
- * MQTT断开连接回调
/ M/ k& |! ]8 T; e6 M1 a - */
Q4 P( V5 }, M7 d - void mqttDisconnectedCb(uint32_t *args) {
' Q! J5 ~: i0 f - MQTT_Client* client = (MQTT_Client*) args;
: @) V" U% n! U3 o( M; ` - INFO("MQTT: Disconnected\r\n");
, s" o+ V/ k- y - }
; A' j3 {; Q* r$ t$ z9 X8 g" a
2 Y0 q0 [# n3 |- /**
9 E' A4 A, i2 R& K* L1 e) E9 G; d - * MQTT发布消息回调* \0 y) J6 R9 [$ {3 t8 U4 J
- */% s4 R) J& J+ b( V9 |
- void mqttPublishedCb(uint32_t *args) {
$ |! `! r$ Q& D4 c& T: U c1 D5 Q - MQTT_Client* client = (MQTT_Client*) args;
$ }, G, Z* t6 w3 N) u- O) g \$ _ - INFO("MQTT: Published\r\n");- @$ i. l0 a8 Y O' f/ C. R0 o
- }
复制代码 9 n' R# L) x( j9 L- l2 O# z4 p
串口透传:5 h- S9 N+ i; k0 _
当模块的WiFi和MQTT服务器都连接上之后,模块就开始监听串口和服务器的数据,如果串口有数据过来便转发到服务器或者进行OTA升级,如果服务器有指令下发就转发给串口。
3 V+ {- M6 {9 R; M8 l- /**
0 Q1 ]* p ?4 `: k7 h - * MQTT接收数据回调(用于OTA升级和串口透传)/ A, e1 T# A s* _2 O- F2 x
- */- z0 H6 P# k! { |+ `5 g
- void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len,
* g" b* E! N& P3 P - const char *data, uint32_t data_len) {) g3 L6 R% ~8 }7 V2 u' O' c/ v. Z, ^5 d
- char *topicBuf = (char*) os_zalloc(topic_len + 1), *dataBuf =% |0 ?- c$ s2 j8 p& A
- (char*) os_zalloc(data_len + 1);
% e9 a P Q! Z - ! A) Z8 h# S1 Z, b. x! U
- uint8 *pdata = (uint8*)data;2 ?! o9 H3 I/ i; t- ]& f. U, o" V
- uint16 len = data_len;# N. z% ?5 S0 N" ?$ N
- uart0_tx_buffer(pdata, len);//串口输出
8 `- x$ O1 C) z' _; f - - | @2 a( y" O) \
- MQTT_Client* client = (MQTT_Client*) args;% X! c8 K! x& b% S3 ^( p6 f
- % G) F" X& m9 J5 i; i( Z+ c
- os_memcpy(topicBuf, topic, topic_len);
+ c# w/ h8 j- P" ]7 a - topicBuf[topic_len] = 0;1 ]5 s) S/ Y9 t* C
; g% g7 l6 ^8 I' v/ h0 I. Q- os_memcpy(dataBuf, data, data_len);
8 e0 j% b0 r6 _9 p, h3 a' K- m - dataBuf[data_len] = 0;! p' \* B4 ^. H" R
- 0 t7 Z; U }8 ]: M" }' L
- // INFO("Receive topic: %s, data: %s \r\n", topicBuf, dataBuf);
1 U) D& o1 K% l1 G; ] - # u: S8 C. c X: p# [% `/ @9 X
- //data = {"url"="http://yourdomain.com:9001/ota/"}
$ Y; V* H+ Y- ^( z7 G" s - if (os_strcmp(topicBuf, ota_topic) == 0) {# A9 c: P. z( |0 f! V
- char url_data[200];0 s3 o5 J5 S- K( R! I
- if(get_josn_str(dataBuf,"url",url_data)){
+ m6 E9 K4 R/ z4 U! o/ C; n - // INFO("ota_start\n");* N" i# O( d8 ]+ v6 |
- ota_upgrade(url_data,ota_finished_callback);
" W% ]- ]% u; K - }
* ?" K2 ~( T1 U% a1 I! @ - }
! a0 O8 r: A4 _2 S5 |9 G; v7 y
; [; T2 {% f2 B1 N) X1 V! T2 v- os_free(topicBuf);
, K1 z2 R0 `9 a/ v7 z8 y3 ` - os_free(dataBuf);/ o0 R7 }. t* ^' l& ]
- h- }7 Q* h! S \- / O, v. ~% N% Z. C
- 3 Q# A6 X$ [# w( c% m; b
- }
+ ]1 R& N7 P4 g) G6 v P* a: E - ' U* I$ v! u6 ^8 |
- /**
$ G5 O5 Q# D4 `) [' q - * ota升级回调/ O0 m o, D( y) n1 _* o
- */
$ d4 R& V9 ?0 H( L( X; k) K - void ICACHE_FLASH_ATTR ota_finished_callback(void * arg) {6 [0 d7 E' [& R& K5 Y
- struct upgrade_server_info *update = arg;
9 ~3 a2 S- z! N0 e- C, i8 x" Y; R - if (update->upgrade_flag == true) {: e; }5 [ U& L+ v( V
- INFO("OTA Success ! rebooting!\n");( I! r# t4 a! Q, z6 z
- system_upgrade_reboot();
' I! H) ?5 r% U/ O - } else {
& ]) Q8 a9 {$ \" G# H - INFO("OTA Failed!\n");6 q0 P4 \$ C2 Q A$ F$ Y
- }
/ E$ V9 _$ e6 p% B, m9 q) v9 n( X) C - }
复制代码
! N! b1 i/ b: H% H8 ~9 T3 R其他问题:3 }5 K" Q2 D# M! V) G
连接的服务器地址,端口号等信息需要写在代码里烧录进模块,这些信息在在mqtt_config.h文件中定义。
! v) U3 Y8 _& n7 B& F& V. E8 O9 o7 s D
: }: O, z# U: b, M# r$ p, v
上电后可以在串口助手看到打印的MAC地址:( a" H/ J1 O1 L. I# O7 c
+ Y% _2 U8 @0 [: U3 C/ ]
+ [4 G( Q( m1 j1 f! H% ]2 k' W
按下配网按键(GPIO14接地),进入配网模式,使用APP或者微信公众号将信息发给模块便可联网,联网后自动连接MQTT服务器。
8 F7 f* O% G. F* I7 A
/ Q1 J% _/ V6 v! _至此连接完成,后续只需要串口发数据给模块,便可在服务器收到信息,服务器下发指令,单片机串口也可以接收到数据。但是要记得订阅主题哦。该透传代码烧录完成可搭配任意MCU的串口使用。非常便捷。由于项目期较远,可能介绍的不是很详细,需要的大大们可以点击阅读原文回帖获取源码。自行查看。
8 h( s3 N$ Y5 n3 x& P) K1 P
8 [* m% ]' c Z. }6 X0 c |