1、 Esp8266之 搭建开发环境,开始一个“hellow world”串口打印。
2、 Esp8266之 利用GPIO开始使用按钮点亮你的“第一盏灯”。
3、 Esp8266之 利用 "软件定时器 " 定时0.5秒闪烁点亮一盏LED。
4 、Esp8266之 了解PWM,更为深入地用PWM控制一盏LED的亮度变化。
5 、Esp8266之 原生乐鑫SDK高级使用之封装Post与Get请求云端,拿到“天气预报信息”。
6 、Esp8266之 了解 SmartConfig与Airkiss一键配网,给8266配网上云端。无需把wifi名字密码写在固件里。
7 、Esp8266之 了解 softAP热点配网模式原理,仿“机智云”定义自己的热点配网模式协议。
8、 Esp8266之 你要找的8266作为UDP、TCP客户端或服务端的角色通讯,都在这了。
9、 Esp8266进阶之路第1篇: [小实战上篇]Windows系统搭建8266的本地Mqtt服务器,局域网点亮一盏LED灯。
10、 Esp8266进阶之路第2篇: [小实战下篇]Windows系统搭建8266的本地Mqtt服务器,局域网点亮一盏LED灯。
11、 Esp8266进阶之路第3篇: 8266接入阿里智能,点亮一盏LED灯,期待天猫精灵语音控制的不约而至!
12、 Esp8266进阶之路第4篇: 图文并茂学习阿里云主机搭建8266MQTT服务器,实现移动网络远程控制一盏LED。
13、 Esp8266进阶之路第5篇: 动手做个8266毕设小案例,smartConfig + MQTT协议轻松实现远程控制一盏LED。
14、 Esp8266进阶之路第6篇: esp8266的 FreeRtos系统学习的正确姿势 ------ 环境搭建、烧录。
15、 Esp8266进阶之路第7篇: esp8266的 物联网又一股清流,8266接入阿里云平台非阿里智能的SDS服务,点亮一盏LED灯。
16、 Esp8266进阶之路第8篇: esp8266的 基于Nonos移植红外线H1838,实现红外遥控器配网,远程控制一盏灯。
17、 Esp8266进阶之路第9篇: esp8266自研的快速上电开关五次 (开-关为一次) ,无需按键触发则8266进去一键配网模式。
18、 Esp8266进阶之路第10篇: esp8266 基于NONOS 实现 OTA 远程升级,实现无线“ 热修复 ”升级固件程序。
19、 Esp8266进阶之路第11篇: esp8266驱动 ds18b20、dht11 温湿度传感器,采集温湿度传感器到服务器。
20、 Esp8266进阶之路第12篇: 深入学习esp8266的esp now模式,仿机智云做一个小网关,实现无需网络下轻松彼此连接通讯交互数据。
21、 Esp8266进阶之路第13篇: 浅谈 esp8266 如何在本地局域网网络情况下实现最大效率地和前端实现数据交互。
22、 Esp8266进阶之路第14篇: esp8266的工程如何添加第三方静态库文件以及如何自定义文件夹,聊聊那些makeFile的事。。
23、 Esp8266进阶之路第15篇: 再来一波 esp8266 基于 freeRtos系统连接自己私有的服务器实现OTA远程升级,接触下 lwip的基本知识。。
24、 Esp8266进阶之路第16篇: 渗透学习回顾下esp8266的外置spi芯片25q系列,熟悉8266代码块在其的分布,得心应手放置图片或其他资料。
25、 Esp8266进阶之路第17篇: 深聊下esp8266的串口 Uart 通讯中断编程,为您准备好了 NONOS 版本 和 RTOS 系统的串口驱动文件。
26、 Esp8266进阶之路第18篇: RTOS分析 MQTT 实现过程,实现移植 MQTT协议在 esp8266 rtos实时系统,可断线重连。
27、 Esp8266进阶之路第19篇: 跟紧脚步,用VisualStudio Code开发 esp8266 rtos SDK v3.0版本,全新的 idf 框架,节省内存模块化开发。
28、 Esp8266进阶之路第20篇: 教你轻松自如使用cJson在乐鑫 esp8266 如何解析一段json数据以及如何生成一段json数据。
29、 Esp8266进阶之路第21篇: 百万条消息免费之乐鑫esp8266使用TCP直连模式MQTT协议接入阿里云物联网平台,支持私家服务器对接支持阿里云规则引擎。
30、 Esp8266进阶之路第22篇: 乐鑫esp8266 SDK编程使用 IIC总线驱动 0.96寸的OLED显示屏,显示天气预报信息。
31、 Esp8266进阶之路第23篇: 当esp8266遇到 Html,该怎么内置网页控制设备,理清内置网页的实现过程,实现无需路由器手机也可以控制esp8266。
32、 Esp8266进阶之路第24篇: 细聊HmacMD5的加密方法带来的安全性,并实践在esp8266上,最大保障传输的过程的信息的安全性。
33、 Esp8266进阶之路第25篇: 如何优雅地像乐鑫原厂封装esp8266底层寄存器的逻辑思维,做成自己的静态库库文件,让第三方人使用?
34、 Esp8266进阶之路第26篇: 乐鑫esp8266 NONOS SDK 3.0编程使用 SPI 驱动基于Max7219芯片的八位数码管,显示日期信息。
35、 Esp8266进阶之路第27篇: 乐鑫esp8266芯片借助机智云平台做一个商业化的七彩RGB灯泡可调整体方案项目,炫彩夺目高大尚。
36、 Esp8266学习rtos3.0笔记第1篇: 认识esp8266 Rtos 3.0 sdk 工程结构,esp8266如何向esp-idf工程靠近的,如何自定义头文件编译?
37、 Esp8266学习rtos3.0笔记第2篇: 你要找的基本外设功能都在这里了,包括Gpio、Pwm 和 Uart 接口使用。
38、 Esp8266学习rtos3.0笔记第3篇: 一篇文章带你搞掂存储技术 NVS 的认识和使用,如何利用NVS保存整型、字符串、数组以及结构体。
39、 Esp8266学习rtos3.0笔记第4篇: 带你捋一捋市面上的微信公众号配网智能设备 esp8266 并绑定设备的过程,移植并成功实现在 esp8266 rtos3.1 sdk。
40、 Esp8266学习rtos3.0笔记第5篇: 基于乐鑫idf框架,研究出超稳定、掉线重连、解决内存泄露问题的Mqtt框架!支持esp8266和esp32!
MQTT
代码工程存在些不足,本博文已根据部分修正部分代码。具体的刨坑链接:https://github.com/espressif/ESP8266_RTOS_SDK/issues/285 ,修订时间:2018/8/27
esp8266
的实时系统rtos
是后面才出来支持的,其最后的调用也是调用乐鑫提供的API
接口,所以,如果你已经玩转了NONOS
下的编程,那么移植rtos
代码是非常迅捷的,因为你已经对其的API
接口非常熟悉,当然了,熟透一款芯片开发,当然不是一天半天的事情,需要长时间的积累。
那么本博文是基于rtos
的MQTT
协议的实现,优化了官方的代码示范,而且带你走一走MQTT
协议的世界。
MQTT
的常识;众所周知,
MQTT
是一种轻捷快速的协议,基于TCP
之上,所以为长连接
的一种协议,非常适合那些短小消息发送的数据交互的用途,比如APP
的推送新闻用途,最常见的用在我们现在物联网领域;毕竟是小且快;
TCP/TLS
连接。所以基本的通讯如下:topic
主题来识别,这个是服务器的事情了;下面列下一些常见的专用名词:①:
ClientID
客户端唯一标识,服务端用于关联一个Session。
只能包含这些 大写字母,小写字母 和 数字(0-9a-zA-Z),23个字符以内,同一时间内 Server 和同一个 ClientID 只能保持一个 TCP 连接,再次连接会踢掉前一个连接的客户端。
②:
Keep Alive
顾名思义,目的是保持长连接的可靠性,以及双方对彼此是否在线的确认。
客户端在Connect的时候设置 Keep Alive 时长。如果服务端在 1.5 * KeepAlive 时间内没有收到客户端的报文,它必须断开客户端的网络连接。
③:
Will
遗嘱,遗愿;遗嘱消息(Will Message)存储在服务端,当网络连接关闭时,服务端必须发布这个遗嘱消息,所以被形象地称之为遗嘱,可用于通知异常断线。
④:
retain
0: 服务端不能存储这个消息,也不能移除或替换任何 现存的保留消息 。
1: 服务端必须存储这个应用消息和它的QoS等级,以便它可以被分发给未来的订阅者,所以如果后面未来有客户端订阅了这个主题,那么这个客户端一上线就会收到此消息。
⑤:
qos
0: 【最多一次】 没有回复,不需要存储。有可能丢失(网络异常断开,业务层繁忙或者错误) 。
1: 【至少一次】确保消息到达,但消息重复可能会发生。
2: 【只有一次】确保消息到达一次;
⑥:
poyload
用来传输用户的数据,最大允许 256MB ,发布的消息的
Payload
允许为空。在很多场合下,代表将持久消息(或者遗嘱消息)清空;格式为UTF-8
编码;
rtos
移植了eclipse
的标准的paho mqtt
,在官方的GitHub
已经看到了源码:点我查看,这个库非常出名,很多嵌入式的芯片都是移植这个库。
#define MQTT_CLIENT_THREAD_NAME "mqtt_client_thread"
#define MQTT_CLIENT_THREAD_STACK_WORDS 2048
#define MQTT_CLIENT_THREAD_PRIO 8
LOCAL xTaskHandle mqttc_client_handle;
static void messageArrived(MessageData* data)
{
printf("Message arrived: %s\n", data->message->payload);
}
static void mqtt_client_thread(void* pvParameters)
{
printf("mqtt client thread starts\n");
MQTTClient client;
Network network;
//指定缓存区的大小
unsigned char sendbuf[80], readbuf[80] = {0};
int rc = 0, count = 1;
MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer;
pvParameters = 0;
//初始化TCP连接
NetworkInit(&network);
//初始化客户端,注意后面都是发送和接收数据的缓存区,一定要加大这个缓存区的大小;否则后面发送不成功!
MQTTClientInit(&client, &network, 30000, sendbuf, sizeof(sendbuf), readbuf, sizeof(readbuf));
char* address = MQTT_BROKER;
//底层的TCP开始连接
if ((rc = NetworkConnect(&network, address, MQTT_PORT)) != 0) {
printf("Return code from network connect is %d\n", rc);
}
//后天任务:如果这个不成功执行,就不会自动进去回调方法:messageArrived;
#if defined(MQTT_TASK)
if ((rc = MQTTStartTask(&client)) != pdPASS) {
printf("Return code from start tasks is %d\n", rc);
} else {
printf("Use MQTTStartTask\n");
}
#endif
//定义mqtt版本: 3 = 3.1 , 4 = 3.1.1
connectData.MQTTVersion = 3;
//定义客户端ID(必须唯一): 大伙们可以定义mac地址作为ID
connectData.clientID.cstring = "ESP8266_sample";
//定义连接的账户名,这个根据服务器的选型来弄;【可有可无】
connectData.username.cstring= "admin";
//定义连接的账户名密码,这个根据服务器的选型来弄;【可有可无】
connectData.password.cstring="admin123456";
//定义连接心跳;
connectData.keepAliveInterval = 40;
//清楚会话
connectData.cleansession = true;
//连接MQTT服务器
if ((rc = MQTTConnect(&client, &connectData)) != 0) {
printf("Return code from MQTT connect is %d\n", rc);
} else {
printf("MQTT Connected\n");
}
//订阅主题 MQTTSubscribe --->【ESP8266/sample/pub】
if ((rc = MQTTSubscribe(&client, "ESP8266/sample/pub", 2, messageArrived)) != 0) {
printf("Return code from MQTT subscribe is %d\n", rc);
} else {
printf("fuck MQTT subscribe to topic \"ESP8266/sample/pub\"\n");
}
//死循环,时隔一秒发送一则消息
while (count++) {
//初始化一则消息结构体
MQTTMessage message;
char payload[80];
message.qos = QOS2;
message.retained = 0;
message.payload = payload;
sprintf(payload,
"{\"uuid\":\"dsaasdad22\",\"token\":\"saddsa412\",\"ver\":1.0,\"statusCode\":0,\"skill\":%d}",
count);
message.payloadlen = strlen(payload);
printf("MQTT publish to payloadlen :%s\n", message.payload);
if ((rc = MQTTPublish(&client, "ESP8266/sample/pub", &message)) != 0) {
printf("Return code from MQTT publish is %d\n", rc);
} else {
printf(
"MQTT publish topic \"ESP8266/sample/pub\", message number is %d\n",
count);
}
vTaskDelay(1000 / portTICK_RATE_MS); //send every 1 seconds
}
printf("mqtt_client_thread going to be deleted\n");
vTaskDelete(NULL);
return;
}
NONOS
代码不一样,这个是不会自动重连服务器的,假如你的路由器突然没了外网,导致这个连接不成功,那么就会永远发布不了消息;所以优化如下,代码略多,主要原理:1、通过判断是否发布消息成功的标志,是否重新连接服务器和订阅主题;
2、 如果把发布消息的任务独立开来,就相当于开启了新的线程,我看了一些高质量的代码,都是创建一则消息队列,处于阻塞等待,直到有消息要发布,则在此死循环内发布,如果不发布,那么重新连接则发布;
3、连接和订阅主题的代码都是在死循环内的,但是初始化客户端的代码千万别在死循环内,因为这个初始化相当于开辟了内存,会占据内存,多次了连接了 ,就相当于开辟多个内存了!
static void Task_MqttClient_Connect(void* pvParameters) {
bool isNeedQueue = true;
Network network;
unsigned char sendbuf[2048], readbuf[2048] = { 0 };
int rc = 0, count = 0;
MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer;
pvParameters = 0;
NetworkInit(&network);
MQTTClientInit(&client, &network, 30000, sendbuf, sizeof(sendbuf), readbuf,
sizeof(readbuf));
//!!!!!不要把初始化放在里面
for (;;) {
//判断是否已经获取了路由器分配的IP
while (wifi_station_get_connect_status() != STATION_GOT_IP) {
vTaskDelay(1000 / portTICK_RATE_MS);
}
char* address = MQTT_SERVICE;
connectData.MQTTVersion = 3;
connectData.clientID.cstring = checkTopic;
connectData.username.cstring = MQTT_USER_NAME;
connectData.password.cstring = MQTT_USER_PAW;
connectData.keepAliveInterval = 40;
connectData.cleansession = true;
if ((rc = NetworkConnect(&network, address, MQTT_PORT)) != 0) {
printf("MClouds NetworkConnect connect is %d\n", rc);
}
if ((rc = MQTTStartTask(&client)) != pdPASS) {
printf("Return code from start tasks is %d\n", rc);
} else {
printf("Use MQTTStartTask\n");
}
if ((rc = MQTTConnect(&client, &connectData)) != 0) {
printf("[SY] MClouds connect is %d\n", rc);
network.disconnect(&network);
vTaskDelay(1000 / portTICK_RATE_MS);
}
if ((rc = MQTTSubscribe(&client, subTopic, QOS0, MessageArrived))
!= 0) {
printf("[SY] MClouds sub fail is %d\n", rc);
network.disconnect(&network);
vTaskDelay(1000 / portTICK_RATE_MS);
}
printf("MQTT subscribe to topic -> %s\n", subTopic);
xQueueReset(MqttMessageQueueHandler);
while (1) {
char payload[2048];
struct esp_mqtt_msg_type *pMsg;
printf("MqttMessageQueueHandler waitting ..\n");
//阻塞等待
xQueueReceive(MqttMessageQueueHandler, &pMsg, portMAX_DELAY);
sprintf(payload, "%s", pMsg->allData);
//printf("MQTT publish payload: %s\n", payload);
os_printf(" [SY] 1 MQTT get freeHeap: %d\n",system_get_free_heap_size());
MQTTMessage message;
message.qos = QOS0;
message.retained = false;
message.payload = (void*) payload;
message.payloadlen = strlen(payload) + 1;
if ((rc = MQTTPublish(&client, pubTopic, &message)) != 0) {
printf("Return code from MQTT publish is %d\n", rc);
} else {
printf("MQTT publish succeed ..\n");
}
if (rc != 0) {
break;
}
}
network.disconnect(&network);
}
printf("mqtt_client_thread going to be deleted\n");
vTaskDelete(NULL);
return;
}
(注意要填写服务器地址,还要熟悉
rtos
的消息队列。)
1.一定要用最新版的SDK
包的工程,而且要看博文前面的刨坑的连接里面的库文件是否更新到您的工程。
2. 由于下面的硬件代码链接不可以修改了,大家下载之后,修改下静态库文件和上面的Task_MqttClient_Connect
方法即可。之后通过不断轮询服务器是否断开,如果是则发送消息重连即可。
3.目前2018.8.27
为止,v2.0.0的SDK的MQTT还是蛮稳定的。断开连接的可能性较低。
esp8266
源代码学习汇总:https://github.com/xuhongv/StudyInEsp8266esp32
源代码学习汇总:https://github.com/xuhongv/StudyInEsp32QQ付费交流群,众多大神带您飞:
434878850