关于ESP8266-NodeMCU和onenet通信传输学习总结(二)

关于ESP8266-NodeMCU和onenet通信传输学习总结(二)

1.更新了一些功能和代码优化和注释

​ 添加了电机的网络控制(后续将用于门锁控制和窗帘控制),过程有点坎坷,本想用一块ESP8266-NodeMCU实现整体功能,结果发现这块板控制电机的同时不能干别的事,多线程也是伪多线程。不好用,便计划用两块开发板,一块负责通信连接和数据传输,另一块用来做下面的硬件控制,结果是可行的,且很容易实现,但不甘于资源的浪费,又想方设法放在一块开发板上实现,最终应该算是成功了,但似乎电机很热发烫,还待优化。ps:arduino官方的电机库放我这就直接跑飞了很奇怪,若有同样问题的博友希望留下经验分享。

这里电机用的是28BYJ-48,这里可能有人吐槽为什么不用42电机,原因在于我只有这个,还是从同学那收破烂来的。。。

说了这么多,不如直接看代码(代码规范有点辣鸡,希望不影响阅读):

/**
 * author: topthemaster
 * time: 2021.1.10
 * 
 */
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include "AccelStepper.h"
#include <Ticker.h>
#include <ArduinoJson.h>
#define PRODUCT_ID    "396066" //产品名
#define API_KEY    "tx6WM==zmW21Z2pt4susBRlHMuY="//产品密钥
#define DEVICE_ID "666259032"//设备名
#define TOPIC     "ceshitopic1"//订阅主题
WiFiClient wifiClient;
Ticker ticker;
Ticker ticker2;
int count=0;//ticker1控制 数据上传下发的间隔时间(s)
int count2=0;//ticker2控制 电机转动的时间(s)
AccelStepper stepper1(4, D0, D2, D1, D3);//电机引脚
String door ="close";//默认检测门关闭
PubSubClient mqttClient(wifiClient);
const char* ssid = "Fishing WiFi ";//wifi名
const char* password = "zheshiyigewifi";//wifi密码
const char* mqttServer = "183.230.40.39";//onenet地址
const uint16_t mqttPort = 6002;//mqtt接口端口
String doorLock="close";//默认门锁指令关闭
char msgJson[75];//存json下发信息数据
char msg_buf[200];//存json上传数据及标识位
//初始化
void setup() {
  stepper1.setMaxSpeed(500);   // 设置电机最大速度为500
  stepper1.setSpeed(0);      // 初始化电机速度为300
  pinMode(LED_BUILTIN, OUTPUT);     // 设置板上LED引脚为输出模式
  digitalWrite(LED_BUILTIN, HIGH);  // 启动后关闭板上LED
  pinMode(D5, OUTPUT);
  pinMode(D6, INPUT_PULLUP);
  digitalWrite(D5, LOW);
  digitalWrite(D6, LOW);
  Serial.begin(9600);
  WiFi.mode(WIFI_STA);
  connectWifi();
  mqttClient.setServer(mqttServer,mqttPort);
  // 设置MQTT订阅回调函数
  mqttClient.setCallback(receiveCallback);
  connectMQTTServer();
  ticker.attach(1, addCount);

}

void loop() {
  if (mqttClient.connected()) { // 如果开发板成功连接服务器
    // 每隔2秒钟发布一次信息  
    // 保持心跳 若电机正在运转,暂时不发信息(由于mcu没有多线程,不能同时运转电机和上传下发数据)
    if(count>=2)
    {  
      if(count2==0)
      { Serial.print("门锁和门状态");
        Serial.print(doorLock);
        Serial.print(door);
        pubMQTTmsg();
        mqttClient.loop();
        count=0;
      }
    }
    
  } else {                  // 如果开发板未能成功连接服务器
    connectMQTTServer();    // 则尝试连接服务器
  }

  //电机控制
  if(doorLock=="close"&&door=="open")
  {
   stepper1.setSpeed(-500);
   Serial.print("1");
   
   ticker2.attach(1, controlDoor);
   
   door="close";
  }
   else if(doorLock=="open"&&door=="close")
   {stepper1.setSpeed(500);
    ticker2.attach(1, controlDoor);
    door="open";
   }
   stepper1.runSpeed();
   
}
//ticker2控制 电机运转时间
void controlDoor(){
  count2++;
  Serial.print("ticker调用");
   if (count2 >= 6) {
    stepper1.setSpeed(0);
    count2=0;
    ticker2.detach();  // 使用detach来停止ticker对象定时调用函数
    Serial.print("ticker.detach()");
  }
}
//连接mqtt服务器
void connectMQTTServer(){
  String clientId = DEVICE_ID;
  String productId=PRODUCT_ID;
  String apiKey=API_KEY;
  // 连接MQTT服务器
  if (mqttClient.connect(clientId.c_str(),productId.c_str(),apiKey.c_str())) { 
    Serial.println("MQTT Server Connected.");
    Serial.println("Server Address: ");
    Serial.println(mqttServer);
    Serial.println("ClientId:");
    Serial.println(clientId);
    subscribeTopic(); // 订阅指定主题
  } else {
    Serial.print("MQTT Server Connect Failed. Client State:");
    Serial.println(mqttClient.state());
    delay(3000);
  }   
}
// 订阅指定主题
void subscribeTopic(){
 
  // 建立订阅主题。主题名称以Taichi-Maker-Sub为前缀,后面添加设备的MAC地址。
  // 这么做是为确保不同设备使用同一个MQTT服务器测试消息订阅时,所订阅的主题名称不同
  String topicString = "temperature";
  char subTopic[topicString.length() + 1];  
  strcpy(subTopic, topicString.c_str());
  
  // 通过串口监视器输出是否成功订阅主题以及订阅的主题名称
  if(mqttClient.subscribe(subTopic)){
    Serial.println("Subscrib Topic:");
    Serial.println(subTopic);
  } else {
    Serial.print("Subscribe Fail...");
  }  
}
  //获取下发指令topic 指定主题 payload 下发信息,以字节存储 length 下发信息长度
void receiveCallback(char* topic, byte* payload, unsigned int length) {
  
  Serial.print("Message Received [");
  Serial.print(topic);
  Serial.print("] ");
  String receivePassage;
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    receivePassage+=(char)payload[i];
  }
  Serial.println("----"+receivePassage+"----");
  Serial.print("Message Length(Bytes) ");
  Serial.println(length);
  ///
  receivePassage="";
  
  //测试下发数据
  if ((char)payload[0] == 'L') {     // 如果收到的信息以“1”为开始
    if((char)payload[1] == '0')
    {
    digitalWrite(BUILTIN_LED, LOW);  // 则点亮LED。
    Serial.println("LED ON");
    }
    else if((char)payload[1] == '1')
    {                           
    digitalWrite(BUILTIN_LED, HIGH); // 否则熄灭LED。
    Serial.println("LED OFF");
    }
  }else if((char)payload[0] == 'D') {     // 如果收到的信息以“1”为开始
    if((char)payload[1] == '1')
    doorLock="open";
    else if((char)payload[1] == '2')
    doorLock="close";
    }
    
   //
    
  
}

//对指定主题上传信息
void pubMQTTmsg(){
  //onenet数据点上传系统主题
  String topicString = "$dp";
  char publishTopic[topicString.length() + 1];  
  strcpy(publishTopic, topicString.c_str());
  //json数据转换为数组
  DynamicJsonDocument doc(64);
  bool pinState = !digitalRead(BUILTIN_LED);
  bool doorState = !digitalRead(D6);
  doc["led"] = pinState;
  doc["door"] = doorState;

  serializeJson(doc, Serial);
  // 建立发布信息。温度
  String jsonCode;  
  serializeJson(doc, jsonCode);
  Serial.print("json Code: ");Serial.println(jsonCode); 
  String messageString = jsonCode; 
  char publishMsg[messageString.length() + 1];   
  strcpy(publishMsg, messageString.c_str());
  int json_len=strlen(publishMsg);
  memset(msg_buf,0,200);
  msg_buf[0]=char(0x03);
  msg_buf[1]=char(json_len>>8);
  msg_buf[2]=char(json_len &0xff);
  memcpy(msg_buf+3,publishMsg,json_len);
  // 实现ESP8266向主题发布信息
  if(mqttClient.publish(publishTopic, (uint8_t*)msg_buf,3+json_len)){
    Serial.println("Publish Topic:");Serial.println(publishTopic);
    String msg_bufTotal;
    for(int i=0;i<sizeof(msg_buf)/sizeof(msg_buf[0]);i++)
    {
      msg_bufTotal+=msg_buf[i];
    }
    Serial.println("Publish message:");Serial.println(msg_bufTotal);    
  } else {
    Serial.println("Message Publish Failed."); 
  }
}
void addCount(){
  count++;
}
void connectWifi(){
 
  WiFi.begin(ssid, password);
 
  //等待WiFi连接,成功连接后输出成功信息
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi Connected!");  
  Serial.println(""); 
}

后续等买的硬件需要的东西到了再更新。

猜你喜欢

转载自blog.csdn.net/TOPthemaster/article/details/112427199