ESP32通过MQTT协议远程控制ESP8266

利用ESP32制作的一个遥杆手柄,通过MQTT协议远程控制ESP8266,里面有方向修正,一键配网,比例调速,开关灯功能,非常棒

注意:这个代码是控制RC车的程序,三线舵机,三线电调那种车,普通车用不了!!!

原理图稍后公布

B站视频:飞宇智控4G远程遥控车 同款遥杆手柄!!!!

下面是ESP32遥杆手柄端代码

//#include <Adafruit_SSD1306.h>
#include <splash.h>

#include <Wire.h>
#include "SSD1306.h"

#include <PubSubClient.h> //MQTT_TEST
#include <Ticker.h>

#include <WiFiManager.h>  // 引用WiFi管理员库
#include <EEPROM.h>     //使用EEPROM保存数据
#include <String.h>
#include "WiFi.h"
#include <ESPmDNS.h>
#include <WebServer.h>    // ESP32网站服务器库
WebServer server(80);           // 建立网站服务器

/********************** 参数设置 *****************/

SSD1306 display(0x3c, 21, 22);

char publishTopic[] = "esp8266-cfeeee" ;
// 设置wifi接入信息(请根据您的WiFi信息进行修改)
const char* mqttServer = "114.132.158.66";

#define ANALOG_PIN_32   32
#define ANALOG_PIN_33   33
#define ANALOG_PIN_34   34
#define ANALOG_PIN_35   35

int analog_value_32 = 0;
int analog_value_33 = 0;
int analog_value_34 = 0;
int analog_value_35 = 0;

byte joy_32_sign = 0;
byte joy_33_sign = 0;
byte joy_34_sign = 0;
byte joy_35_sign = 0;

int joy_32_value = 0;
int joy_33_value = 0;
int joy_34_value = 0;
int joy_35_value = 0;

byte joy_32_value_last = 0;
byte joy_33_value_last = 0;
byte joy_34_value_last = 0;
byte joy_35_value_last = 0;

char joy_32_publish[8]={0};
char joy_33_publish[8]={0};
char joy_34_publish[8]={0};
char joy_35_publish[8]={0};

//char publish_fd[10]={"fd"};
//char publish_bk[10]={"bk"};
//char publish_lf[10]={"lf"};
//char publish_rt[10]={"rt"};
//char publish_qh_bili[20]={"qh"};
//char publish_zy_bili[20]={"zy"};

String  publish_qh = "qh";
String  publish_zy = "zy";

byte i=0;
byte j=0;

bool x=false;
bool y=false;
bool z=false;

bool xx=false;
bool yy=false;
bool zz=false;


Ticker ticker;
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);

int count;    // Ticker计数用变量

#define AP_SSID "智控物联科技社" // 自定义的ESP设备AP名称
#define AP_PWD "12345678" // 自定义的AP密码
#define TRIGGER_PIN 14 // 启用「Wi-Fi设置入口」的按键引脚
unsigned int timeout = 180; // 设置入口的超时秒数
unsigned int startTime = millis(); // 记录设置入口的启动时间
bool portalRunning = false; // 设置入口是否执行中,默认为「否」


WiFiManager wifiManager;  // 建立WiFiManager对象


bool shouldSaveConfig = false;  //是否保存数据的标志位
//回调函数,用于通知我们需要保存配置
void saveConfigCallback () {
  Serial.println("Should save config");
  shouldSaveConfig = true;
}

/********************** 开始编程存储器部分 *****************/
#define EEPROM_SALT 12664   //用于校验读取的数据是否有效
typedef struct
{
  int   salt = EEPROM_SALT;
  char Secret_Key[15]  = "";
}WMSettings;//结构体, 用于保存秘钥数据

WMSettings blynk;   

//EEPROM读取函数
void eeprom_read()
{
  EEPROM.begin(100);
  EEPROM.get(50, blynk);
  EEPROM.end();
  
  Serial.print("从EEPROM读取到的秘钥为:");
  Serial.println(blynk.Secret_Key);
}

//EEPROM存储函数
void eeprom_saveconfig()
{
  EEPROM.begin(100);
  EEPROM.put(50, blynk);
  EEPROM.commit();
  EEPROM.end();
}

unsigned char recharge_BMP[5][16] =
{
{0xFF,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0xFF,0x3C,},      //0%
{0xFF,0x81,0xBD,0xBD,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0xFF,0x3C,},     //25%
{0xFF,0x81,0xBD,0xBD,0x81,0xBD,0xBD,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0xFF,0x3C,},     //50%
{0xFF,0x81,0xBD,0xBD,0x81,0xBD,0xBD,0x81,0xBD,0xBD,0x81,0x81,0x81,0x81,0xFF,0x3C,},     //75%
{0xFF,0x81,0xBD,0xBD,0x81,0xBD,0xBD,0x81,0xBD,0xBD,0x81,0xBD,0xBD,0x81,0xFF,0x3C,}      //100%
};

void Draw_Init_Interface(void) {
    for (size_t i = 0; i < 46; i = i + 3)
    {
        display.clear();
        display.setFont(ArialMT_Plain_10);
        display.drawString(25, 20, "Initialize...");
        display.drawRect(38, 38, 51, 6);//以(38,38)为起点绘制一个长度51宽度为6的矩形
        display.drawLine(40, 40, 40 + i, 40);//循环绘制线条达到显示进度的效果
        display.drawLine(40, 41, 40 + i, 41);
        display.display();
        delay(100);
    }
    display.display();
}

void FORWARD_dispaly(){
     display.clear();
     display.setFont(ArialMT_Plain_16);
     display.drawString(2, 10, "FORWARD");
     display.display();
  }

void BACK_dispaly(){
     display.clear();
     display.drawString(10, 20, "BACKWARD");
     display.display();
  }

void LEFT_dispaly(){
     display.clear();
     display.drawString(10, 20, "TURN LEFT");
     display.display();
  }

void RIGHT_dispaly(){
     display.clear();
     display.drawString(10, 20, "TURN RIGHT");
     display.display();
  }

void STOP_dispaly(){
     display.clear();
     display.drawString(10, 20, "STOP");
     display.display();
  }

void MIDDLE_dispaly(){
     display.clear();
     display.drawString(10, 20, "MIDDLE");
     display.display();
  }

/********************** WIFI管理员参数配置以及重置函数 *****************/
WiFiManagerParameter custom_Secret_Key("KEY", "秘钥", blynk.Secret_Key, 15);

//用于重置WIFI设置以及秘钥
void doWiFiManager() 
{ // 执行WiFi管理员的工作
  if (portalRunning) 
  { // 若「设置入口」执行中…
    wifiManager.process(); // 处理「设置入口」的用户端连接请求
    // 如果「设置入口」已启用超过预设时间(180秒)…
    if ((millis() - startTime) > (timeout * 1000)) 
    {
      Serial.println("「Wi-Fi设置入口」操作超时…");
      portalRunning = false; // 设成「非执行中」
      if(strlen(custom_Secret_Key.getValue()) == 12)//简单判断填写的秘钥是否有效
      {
        strcpy(blynk.Secret_Key, custom_Secret_Key.getValue());
        Serial.print("写入EEPROM的秘钥为:");
        Serial.println(blynk.Secret_Key);
        eeprom_saveconfig();
      }
      wifiManager.stopConfigPortal(); // 停止「设置入口」
      Serial.println("正重启您的设备");
      delay(1000);
      ESP.restart();//重新启动ESP设备
//      Blinker.begin(blynk.Secret_Key, WiFi.SSID().c_str(), WiFi.psk().c_str());
//      Blinker.attachData(dataRead);
//      Button1.attach(button1_callback);
     }
    }
    
    // 若启用「设置入口」的接脚被按一下
     //而且portalRunning的数值不为true…
    if (digitalRead(TRIGGER_PIN) == LOW && (!portalRunning)) 
    {
      Serial.println("按钮被按下了,启动设置入口。");
      wifiManager.setConfigPortalBlocking(false); // 设成「非搁置」模式
      wifiManager.startConfigPortal(AP_SSID, AP_PWD); // 启用Wi-Fi AP
  
      portalRunning = true; // 设成「设置入口」执行中
      startTime = millis(); // 纪录目前的时间
    }
}

void setup() {
    display.init();
    display.flipScreenVertically();
    pinMode(TRIGGER_PIN, INPUT_PULLUP);   //配置触发重置函数的引脚//配置触发重置函数的引脚
    pinMode(ANALOG_PIN_32, INPUT);
    pinMode(ANALOG_PIN_33, INPUT);    
    pinMode(ANALOG_PIN_34, INPUT);
    pinMode(ANALOG_PIN_35, INPUT);  
    Serial.begin(115200);     

    WiFi.mode(WIFI_STA);  //Wi-Fi设置成STA模式;预设模式为STA+AP
    /****************************************************************/
    delay(500);
    eeprom_read();  //读取EEPROM中的秘钥数据
    //判断EEPROM中读取的秘钥数据是否被污染
    if (blynk.salt != EEPROM_SALT)
    {
      Serial.println("读取到 EEPROM 中无效的设置,已尝试使用默认值");
      WMSettings defaults;
      blynk = defaults;
    }
  
    
    wifiManager.addParameter(&custom_Secret_Key); //在WiFi管理员界面添加秘钥参数
    wifiManager.setSaveConfigCallback(saveConfigCallback);
    
    /********************** 只用于测试 *****************/
    //重置设置——进行测试
//    wifiManager.resetSettings();
    //设置信号的最小质量,这样它就忽略了在这个质量下的 AP
    //默认为 8%
//    wifiManager.setMinimumSignalQuality(30);
    //设置连接的超时时间
//    wifiManager.setConnectTimeout(CONNECT_TIMEOUT);
//    wifiManager.setTimeout(AP_TIMEOUT);
  
    //然后进入一个阻塞循环,等待配置
    if (!wifiManager.autoConnect(AP_SSID,AP_PWD)) 
    {
      Serial.println("未能连接或者超时");
      Serial.println("正重启您的设备");
      delay(1000);
      ESP.restart();
    }

    //到这里表示你已经连接上WiFi
    Serial.println("已经连接上WiFi:)");
    
   Draw_Init_Interface();
   delay(2000);
   display.setFont(ArialMT_Plain_16);
   
    //简单判断秘钥是否有效
    if(strlen(custom_Secret_Key.getValue()) == 12)
    {
      strcpy(blynk.Secret_Key, custom_Secret_Key.getValue());
      Serial.print("秘钥为:");
      Serial.println(blynk.Secret_Key);
      eeprom_saveconfig();
    }//至此,结束数据保存

  
    // 自动连接WiFi。以下语句的参数是连接ESP8266时的WiFi名称
//    wifiManager.autoConnect("AutoConnectAP");
    
    // 如果希望该WiFi添加密码,可以使用以下语句:
    // wifiManager.autoConnect("AutoConnectAP", "12345678");
    // 以上语句中的12345678是连接AutoConnectAP的密码
    // WiFi连接成功后将通过串口监视器输出连接成功信息 
    Serial.println(""); 
    Serial.print("ESP8266 Connected to ");
    Serial.println(WiFi.SSID());              // 串口打印当前连接的WIFI名称
    Serial.print("IP address:\t");
    Serial.println(WiFi.localIP());           // 串口打印当前连接的WIFI的IP
    Serial.printf("password: %s\n", WiFi.psk().c_str());// 串口打印当前连接的WIFI密码 

     // 设置MQTT服务器和端口号
    mqttClient.setServer(mqttServer, 1883);

    // 设置MQTT订阅回调函数
    mqttClient.setCallback(receiveCallback);
  
    // 连接MQTT服务器
    connectMQTTServer();
  
    // Ticker定时对象
//    ticker.attach(1, tickerCount); 

}



void loop() {
    doWiFiManager();
    adc_detect();
    if(!portalRunning)
    { if (mqttClient.connected())
  { // 如果开发板成功连接服务器
    // 每隔3秒钟发布一次信息

      pubMQTTmsg();   

    // 保持心跳
    mqttClient.loop();
  } else 
   {                  // 如果开发板未能成功连接服务器
    connectMQTTServer();    // 则尝试连接服务器
   }}

}
//void tickerCount(){
//  count++;
//}

void connectMQTTServer(){
  // 根据ESP8266的MAC地址生成客户端ID(避免与其它ESP8266的客户端ID重名)
  String clientId = "esp8266-" + WiFi.macAddress();

  // 连接MQTT服务器
  if (mqttClient.connect(clientId.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 adc_detect(void){
 analog_value_32 = analogRead(ANALOG_PIN_32);
 delay(5);
 analog_value_33 = analogRead(ANALOG_PIN_33);
 delay(5);
 analog_value_34 = analogRead(ANALOG_PIN_34);
 delay(5);
 analog_value_35 = analogRead(ANALOG_PIN_35);
 delay(5);

//Serial.print("前进摇杆ADC:");
//Serial.print(analog_value_32);
//Serial.println("");
//Serial.print("后退摇杆ADC:");
//Serial.print(analog_value_33);
//Serial.println("");
//Serial.print("转向ADC:");
//Serial.print(analog_value_34);
//Serial.println("");
//Serial.print("调速ADC:");
//Serial.print(analog_value_35);
//Serial.println("");
  }

void qh_bili_publish(void)
{
//    Serial.println("QHBL");
  joy_35_value=analog_value_35+joy_35_value;
  if(i<20){i++;}
  else if(i=20)
  {
  i=0;joy_35_value=joy_35_value/20/46;
  if(((joy_35_value-2)>=joy_35_value_last)||((joy_35_value+2)<=joy_35_value_last)){
  String qh_bili = "qh"+ String(joy_35_value);
  char publishMsg[qh_bili.length() + 1]; 
  strcpy(publishMsg, qh_bili.c_str()); 
  mqttClient.publish(publishTopic, publishMsg);
  Serial.println(publishMsg);
  joy_35_value_last=joy_35_value;

  }
 }
}
//
void jiaozheng_publish(void)
{
//  Serial.println("ZYBL");
  joy_34_value=analog_value_34+joy_34_value;
  if(j<20){j++;}
  else if(j=20)
  {
  j=0;joy_34_value=joy_34_value/20/46;
  if(joy_34_value!=joy_34_value_last){
  if((joy_34_value>43)&&(joy_34_value<46)){mqttClient.publish(publishTopic,"zp00");}
  if(joy_34_value<=43){
  String zp = "zp"+ String(43-joy_34_value);
  char publishMsg1[zp.length() + 1]; 
  strcpy(publishMsg1, zp.c_str()); 
  mqttClient.publish(publishTopic, publishMsg1);
//  Serial.println(publishMsg1);
  }
  else if(joy_34_value>=46){
  String yp = "yp"+ String(joy_34_value-46);
  char publishMsg11[yp.length() + 1]; 
  strcpy(publishMsg11, yp.c_str()); 
  mqttClient.publish(publishTopic, publishMsg11);
//  Serial.println(publishMsg11);
  }
  joy_34_value_last=joy_34_value;

  }
 }
}
//
void qh_publish(void)
{
//    Serial.println("FD");
  if(analog_value_32>3000&&x==false){BACK_dispaly(); mqttClient.publish(publishTopic,"bk");x=true;y=false;z=false;}
  else if(analog_value_32<1000&&y==false){FORWARD_dispaly();mqttClient.publish(publishTopic,"fd");x=false;y=true;z=false;}
  else if(analog_value_32>1000&&analog_value_32<3000&&z==false){STOP_dispaly();mqttClient.publish(publishTopic,"sp");x=false;y=false;z=true;}

}
//
void zy_yaogan(void)
{
  if((joy_33_value_last<analog_value_33/22-2)||(joy_33_value_last>analog_value_33/22+2)&&(analog_value_33<1948||analog_value_33>2148)){
    xx=false;
    joy_33_value_last=analog_value_33/22;
    if(joy_33_value_last<80)
    {joy_33_value=80-joy_33_value_last;
    String z_yg = "rt"+ String(joy_33_value);
    char publishMsg2[z_yg.length() + 1]; 
    strcpy(publishMsg2, z_yg.c_str()); 
    mqttClient.publish(publishTopic, publishMsg2);
    if(yy==false){LEFT_dispaly();}
    yy=true;
//    Serial.println(publishMsg2);
    }
    else if(joy_33_value_last>100)
    {joy_33_value=joy_33_value_last-100;
    String y_yg = "lt"+ String(joy_33_value);
    char publishMsg3[y_yg.length() + 1]; 
    strcpy(publishMsg3, y_yg.c_str()); 
    mqttClient.publish(publishTopic, publishMsg3);
    if(zz==false){RIGHT_dispaly();}
    zz=true;
//    Serial.println(publishMsg3);    
    }
    }
  if(analog_value_33>1760&&analog_value_33<2200&&xx==false){mqttClient.publish(publishTopic,"md");MIDDLE_dispaly();xx=true;yy=false;zz=false;}

}


// 订阅指定主题
void subscribeTopic(){
 
  // 建立订阅主题。主题名称以Taichi-Maker-Sub为前缀,后面添加设备的MAC地址。
  // 这么做是为确保不同设备使用同一个MQTT服务器测试消息订阅时,所订阅的主题名称不同
  String topicString = "POWER_GPS" ;
  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...");
  }  
}

// 收到信息后的回调函数
void receiveCallback(char* topic, byte* payload, unsigned int length) {
  char recode[20]={0};

  Serial.print("Message Received [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
     Serial.println(length);
//    Serial.println((char)payload[i]);
    recode[i] = payload[i];
  }
  clear_power_diaplay();
  if(!strcmp(recode,"POWER:0%")){display.drawFastImage(112, 0, 16, 1, recharge_BMP[0]);}
  if(!strcmp(recode,"POWER:25%")){display.drawFastImage(112, 0, 16, 1, recharge_BMP[1]);}
  if(!strcmp(recode,"POWER:50%")){display.drawFastImage(112, 0, 16, 1, recharge_BMP[2]);}
  if(!strcmp(recode,"POWER:75%")){display.drawFastImage(112, 0, 16, 1, recharge_BMP[3]);}
  if(!strcmp(recode,"POWER:100%")){display.drawFastImage(112, 0, 16, 1, recharge_BMP[4]);}
  display.display();
}

void clear_power_diaplay(){
  for(byte j=112;j<=128;j++){
    for(byte i=0;i<=8;i++){
       display.clearPixel(j,i);
    }
  }
}


  
// 发布信息
void pubMQTTmsg(){
 jiaozheng_publish();
  qh_bili_publish();
  zy_yaogan();
  qh_publish(); 
}

下面是ESP8266遥控车接收端代码

#include "Ticker.h" //引入调度器头文件
#include <SoftwareSerial.h>
#include <PubSubClient.h>
#include <WiFiManager.h>  // 引用WiFi管理员库
#include <EEPROM.h>     //使用EEPROM保存数据
#include <String.h>
#ifdef ESP8266                  // 若晶片类型是ESP8266
#include <ESP8266WiFi.h> 
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>   // ESP8266网站服务器库
ESP8266WebServer server(80);    // 建立网站服务器
#include <Servo.h> //包含伺服电机的库文件

Servo ESC;
Servo ECC; 

int zp = 0;
int yp = 0;
byte zp_flag = 0;
byte yp_flag = 0;
int a = 0;
int b = 0;
byte qh = 0;

//电池部分


Ticker myTicker; //建立一个需要定时调度的对象
float VCC ;


//电池部分

//GPS部分
//SoftwareSerial GPsSerial(13,14); // RX, TX
//
//struct
//{
//  char GPS_Buffer[80];
//  bool isGetData;   //是否获取到GPS数据
//  bool isParseData; //是否解析完成
//  char UTCTime[11];   //UTC时间
//  char latitude[11];    //纬度
//  char N_S[2];    //N/S
//  char longitude[12];   //经度
//  char E_W[2];    //E/W
//  bool isUsefull;   //定位信息是否有效
//} Save_Data;
//
//const unsigned int gpsRxBufferLength = 600;
//char gpsRxBuffer[gpsRxBufferLength];
//unsigned int ii = 0;

//GPS部分

char publishTopic[] = "POWER_GPS" ;

#elif defined(ESP32)            // 若晶片类型是ESP32
#include "WiFi.h"
#include <ESPmDNS.h>
#include <WebServer.h>    // ESP32网站服务器库
WebServer server(80);           // 建立网站服务器
#endif
/********************** 参数设置 *****************/
//const char* mqttServer = "mqtt-cn-i7m2omxjh0b.mqtt.aliyuncs.com";
const char* mqttServer = "114.132.158.66";
#define AP_SSID "智控物联—小车" // 自定义的ESP设备AP名称
#define AP_PWD "12345678" // 自定义的AP密码
#define TRIGGER_PIN 0 // 启用「Wi-Fi设置入口」的按键引脚
unsigned int timeout = 180; // 设置入口的超时秒数
unsigned int startTime = millis(); // 记录设置入口的启动时间
bool portalRunning = false; // 设置入口是否执行中,默认为「否」
// MQTT服务端连接用户名密码
//const char* mqttUserName = "Signature|LTAI5t9XAHpNLn4LUaEKETez|mqtt-cn-i7m2omxjh0b";
//const char* mqttPassword = "0uNk+aVm2W7guPrEfo6iSr6tBow=";
  char st[2]={0};
  char sp[4]={0};

WiFiManager wifiManager;  // 建立WiFiManager对象
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);

bool shouldSaveConfig = false;  //是否保存数据的标志位
//回调函数,用于通知我们需要保存配置
void saveConfigCallback () {
  Serial.println("Should save config");
  shouldSaveConfig = true;
}

/********************** 开始编程存储器部分 *****************/
#define EEPROM_SALT 12664   //用于校验读取的数据是否有效
typedef struct
{
  int   salt = EEPROM_SALT;
  char Secret_Key[15]  = "";
}WMSettings;//结构体, 用于保存秘钥数据

WMSettings blynk;   

//EEPROM读取函数
void eeprom_read()
{
  EEPROM.begin(3000);
  EEPROM.get(2500, blynk);
  EEPROM.end();
  
  Serial.print("从EEPROM读取到的秘钥为:");
  Serial.println(blynk.Secret_Key);
}

//EEPROM存储函数
void eeprom_saveconfig()
{
  EEPROM.begin(3000);
  EEPROM.put(2500, blynk);
  EEPROM.commit();
  EEPROM.end();
}

/********************** 点灯Blinker的配置部分 *****************/

/********************** WIFI管理员参数配置以及重置函数 *****************/
WiFiManagerParameter custom_Secret_Key("KEY", "秘钥", blynk.Secret_Key, 15);

//用于重置WIFI设置以及秘钥
void doWiFiManager() 
{ // 执行WiFi管理员的工作
  if (portalRunning) 
  { // 若「设置入口」执行中…
    wifiManager.process(); // 处理「设置入口」的用户端连接请求
    // 如果「设置入口」已启用超过预设时间(180秒)…
    if ((millis() - startTime) > (timeout * 1000)) 
    {
      Serial.println("「Wi-Fi设置入口」操作超时…");
      portalRunning = false; // 设成「非执行中」
      if(strlen(custom_Secret_Key.getValue()) == 12)//简单判断填写的秘钥是否有效
      {
        strcpy(blynk.Secret_Key, custom_Secret_Key.getValue());
        Serial.print("写入EEPROM的秘钥为:");
        Serial.println(blynk.Secret_Key);
        eeprom_saveconfig();
      }
      wifiManager.stopConfigPortal(); // 停止「设置入口」
      Serial.println("正重启您的设备");
      delay(1000);
      ESP.restart();//重新启动ESP设备
//      Blinker.begin(blynk.Secret_Key, WiFi.SSID().c_str(), WiFi.psk().c_str());
//      Blinker.attachData(dataRead);
//      Button1.attach(button1_callback);
     }
    }
    
    // 若启用「设置入口」的接脚被按一下
    // 而且portalRunning的数值不为true…
    if (digitalRead(TRIGGER_PIN) == LOW && (!portalRunning)) 
    {
      Serial.println("按钮被按下了,启动设置入口。");
      wifiManager.setConfigPortalBlocking(false); // 设成「非搁置」模式
      wifiManager.startConfigPortal(AP_SSID, AP_PWD); // 启用Wi-Fi AP
  
      portalRunning = true; // 设成「设置入口」执行中
      startTime = millis(); // 纪录目前的时间
    }
}

void tickerHandle() //到时间时需要执行的任务
{
  float VCC1 = 0.00;
  if(!portalRunning){if (mqttClient.connected())  { // 如果开发板成功连接服务器
    VCC1 = analogRead(A0);
    VCC = VCC1*13/1024/3;
    if((VCC<=3.45)){mqttClient.publish(publishTopic, "POWER:0%");}
    if((VCC>3.45)&&(VCC<=3.74)){mqttClient.publish(publishTopic, "POWER:25%");}
    if((VCC>3.74)&&(VCC<=3.82)){mqttClient.publish(publishTopic, "POWER:50%");}
    if((VCC>3.82)&&(VCC<=3.92)){mqttClient.publish(publishTopic, "POWER:75%");}
    if((VCC>3.92)&&(VCC<=4.2)){mqttClient.publish(publishTopic, "POWER:100%");}
   }  
 } 
}

void setup() {
 ESC.attach(4,1000,2000); 
 ECC.attach(2,1000,2000); 
 ESC.write(90);    // 发送不同脉宽PWM信号给电调
 ECC.write(90+zp+yp);    // 发送不同脉宽PWM信号给电调  
 
    pinMode(LED_BUILTIN, OUTPUT);     // 设置板上LED引脚为输出模式
    digitalWrite(LED_BUILTIN, HIGH);  // 启动后关闭板上LED
    WiFi.mode(WIFI_STA);  //Wi-Fi设置成STA模式;预设模式为STA+AP
    
//    GPsSerial.begin(9600);
    Serial.begin(115200);  
         
   myTicker.attach(5, tickerHandle); //初始化调度任务,每0.5秒执行一次tickerHandle()
   
  //GPS部分
//  Save_Data.isGetData = false;
//  Save_Data.isParseData = false;
//  Save_Data.isUsefull = false;
  //GPS部分
    
    /****************************************************************/
    delay(500);
    pinMode(TRIGGER_PIN, INPUT_PULLUP);   //配置触发重置函数的引脚
    eeprom_read();  //读取EEPROM中的秘钥数据
    //判断EEPROM中读取的秘钥数据是否被污染
    if (blynk.salt != EEPROM_SALT)
    {
      Serial.println("读取到 EEPROM 中无效的设置,已尝试使用默认值");
      WMSettings defaults;
      blynk = defaults;
    }

  
    
    wifiManager.addParameter(&custom_Secret_Key); //在WiFi管理员界面添加秘钥参数
    wifiManager.setSaveConfigCallback(saveConfigCallback);
    
    /********************** 只用于测试 *****************/
    //重置设置——进行测试
//    wifiManager.resetSettings();
    //设置信号的最小质量,这样它就忽略了在这个质量下的 AP
    //默认为 8%
//    wifiManager.setMinimumSignalQuality(30);
    //设置连接的超时时间
//    wifiManager.setConnectTimeout(CONNECT_TIMEOUT);
//    wifiManager.setTimeout(AP_TIMEOUT);
  
    //然后进入一个阻塞循环,等待配置
    if (!wifiManager.autoConnect(AP_SSID,AP_PWD)) 
    {
      Serial.println("未能连接或者超时");
      Serial.println("正重启您的设备");
      delay(1000);
      ESP.restart();
    }

    //到这里表示你已经连接上WiFi
    Serial.println("已经连接上WiFi:)");

    //简单判断秘钥是否有效
    if(strlen(custom_Secret_Key.getValue()) == 12)
    {
      strcpy(blynk.Secret_Key, custom_Secret_Key.getValue());
      Serial.print("秘钥为:");
      Serial.println(blynk.Secret_Key);
      eeprom_saveconfig();
    }//至此,结束数据保存

  
    // 自动连接WiFi。以下语句的参数是连接ESP8266时的WiFi名称
//    wifiManager.autoConnect("AutoConnectAP");
    
    // 如果希望该WiFi添加密码,可以使用以下语句:
    // wifiManager.autoConnect("AutoConnectAP", "12345678");
    // 以上语句中的12345678是连接AutoConnectAP的密码
    // WiFi连接成功后将通过串口监视器输出连接成功信息 
    Serial.println(""); 
    Serial.print("ESP8266 Connected to ");
    Serial.println(WiFi.SSID());              // 串口打印当前连接的WIFI名称
    Serial.print("IP address:\t");
    Serial.println(WiFi.localIP());           // 串口打印当前连接的WIFI的IP
    Serial.printf("password: %s\n", WiFi.psk().c_str());// 串口打印当前连接的WIFI密码 

      // 设置MQTT服务器和端口号
    mqttClient.setServer(mqttServer, 1883);
      // 设置MQTT订阅回调函数
    mqttClient.setCallback(receiveCallback);
 
    // 连接MQTT服务器
    connectMQTTserver();

}

void loop() {
    doWiFiManager();
    if(!portalRunning){if (mqttClient.connected())  { // 如果开发板成功连接服务器
//    GPS_mqtt();
    mqttClient.loop();          // 处理信息以及心跳
  } else {                      // 如果开发板未能成功连接服务器
    ESC.write(90);
    ECC.write(90);
    connectMQTTserver();        // 则尝试连接服务器
  }}
}





//void GPS_mqtt(){
//  gpsRead();  //获取GPS数据
//  parseGpsBuffer();//解析GPS数据
//  printGpsBuffer();//输出解析后的数据
//  }

GPS部分
//void errorLog(int num)
//{
//  Serial.print("ERROR");
//  Serial.println(num);
  while (1)
  {
    digitalWrite(L, HIGH);
    delay(300);
    digitalWrite(L, LOW);
    delay(300);
  }
//}
//
//void printGpsBuffer()
//{
//  if (Save_Data.isParseData)
//  {
//    Save_Data.isParseData = false;
//    
//    Serial.print("Save_Data.UTCTime = ");
//    Serial.println(Save_Data.UTCTime);
//
//    if(Save_Data.isUsefull)
//    {
//      Save_Data.isUsefull = false;
      Serial.print("Save_Data.latitude = ");
      Serial.println(Save_Data.latitude);
      Serial.print("Save_Data.N_S = ");
      Serial.println(Save_Data.N_S);
      Serial.print("Save_Data.longitude = ");
      Serial.println(Save_Data.longitude);
      Serial.print("Save_Data.E_W = ");
      Serial.println(Save_Data.E_W);
//       String North = String(Save_Data.N_S)+ String(Save_Data.latitude);
//       char publishMsg1[North.length() + 1]; 
//       strcpy(publishMsg1, North.c_str()); 
//       
//       String South = String(Save_Data.E_W)+ String(Save_Data.longitude);
//       char publishMsg2[South.length() + 1]; 
//       strcpy(publishMsg2, South.c_str());       
//        
//      mqttClient.publish(publishTopic, publishMsg1);
//      mqttClient.publish(publishTopic, publishMsg2);
//
//    }
//    else
//    {
//      Serial.println("GPS DATA is not usefull!");
//    }
//    
//  }
//}
//
//void parseGpsBuffer()
//{
//  char *subString;
//  char *subStringNext;
//  if (Save_Data.isGetData)
//  {
//    Save_Data.isGetData = false;
//    Serial.println("**************");
//    Serial.println(Save_Data.GPS_Buffer);
//
//    
//    for (int i = 0 ; i <= 6 ; i++)
//    {
//      if (i == 0)
//      {
//        if ((subString = strstr(Save_Data.GPS_Buffer, ",")) == NULL)
//          errorLog(1);  //解析错误
//      }
//      else
//      {
//        subString++;
//        if ((subStringNext = strstr(subString, ",")) != NULL)
//        {
//          char usefullBuffer[2]; 
//          switch(i)
//          {
//            case 1:memcpy(Save_Data.UTCTime, subString, subStringNext - subString);break; //获取UTC时间
//            case 2:memcpy(usefullBuffer, subString, subStringNext - subString);break; //获取UTC时间
//            case 3:memcpy(Save_Data.latitude, subString, subStringNext - subString);break;  //获取纬度信息
//            case 4:memcpy(Save_Data.N_S, subString, subStringNext - subString);break; //获取N/S
//            case 5:memcpy(Save_Data.longitude, subString, subStringNext - subString);break; //获取纬度信息
//            case 6:memcpy(Save_Data.E_W, subString, subStringNext - subString);break; //获取E/W
//
//            default:break;
//          }
//
//          subString = subStringNext;
//          Save_Data.isParseData = true;
//          if(usefullBuffer[0] == 'A')
//            Save_Data.isUsefull = true;
//          else if(usefullBuffer[0] == 'V')
//            Save_Data.isUsefull = false;
//
//        }
//        else
//        {
//          errorLog(2);  //解析错误
//        }
//      }
//
//
//    }
//  }
//}
//
//
//void gpsRead() {
//  while (GPsSerial.available())
//  {
//    gpsRxBuffer[ii++] = GPsSerial.read();
//    if (ii == gpsRxBufferLength)clrGpsRxBuffer();
//  }
//
//  char* GPS_BufferHead;
//  char* GPS_BufferTail;
//  if ((GPS_BufferHead = strstr(gpsRxBuffer, "$GPRMC,")) != NULL || (GPS_BufferHead = strstr(gpsRxBuffer, "$GNRMC,")) != NULL )
//  {
//    if (((GPS_BufferTail = strstr(GPS_BufferHead, "\r\n")) != NULL) && (GPS_BufferTail > GPS_BufferHead))
//    {
//      memcpy(Save_Data.GPS_Buffer, GPS_BufferHead, GPS_BufferTail - GPS_BufferHead);
//      Save_Data.isGetData = true;
//
//      clrGpsRxBuffer();
//    }
//  }
//}
//
//void clrGpsRxBuffer(void)
//{
//  memset(gpsRxBuffer, 0, gpsRxBufferLength);      //清空
//  ii = 0;
//}
GPS部分

// 连接MQTT服务器并订阅信息
void connectMQTTserver(){
  // 根据ESP8266的MAC地址生成客户端ID(避免与其它ESP8266的客户端ID重名)
  String clientId = "esp8266-" + WiFi.macAddress();
 
  // 连接MQTT服务器
//  if (mqttClient.connect(clientId.c_str(),mqttUserName,mqttPassword)) { 
  if (mqttClient.connect(clientId.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(5000);
  }   
}
 
// 收到信息后的回调函数
void receiveCallback(char* topic, byte* payload, unsigned int length) {
  char recode[20]={0};

  Serial.print("Message Received [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
     Serial.println(length);
//    Serial.println((char)payload[i]);
    recode[i] = payload[i];
  }

st[0]=recode[0];
st[1]=recode[1];
sp[0]=recode[2];
sp[1]=recode[3];

if(!strcmp(st,"sp")){ ESC.write(90);} 

if(!strcmp(st,"qh")){
   qh = atoi(sp);}
   
  if(!strcmp(st,"zp")){
   zp_flag = 1;
   yp_flag = 0;
   zp = atoi(sp);
   ECC.write(90+zp);
                    }
if(!strcmp(st,"yp")){
   zp_flag = 0;
   yp_flag = 1;
   yp = atoi(sp);
   ECC.write(90-yp);
                    }
//   Serial.println(st);
//   Serial.println(*st);
//   Serial.println(sp);
//   Serial.println(sp);
//   Serial.println(recode);
//   Serial.println(*recode);


  if(!strcmp(st,"md")){ 
    if(zp_flag==1){ECC.write(90+zp);}
    else if(yp_flag==1){ECC.write(90-yp);}
    else {ECC.write(90);} } 
  
  if(!strcmp(st,"fd")){
     ESC.write(-qh+90);
//   Serial.println(90+a);
    }
    
  if(!strcmp(st,"bk")){
     ESC.write(qh+90);
//     Serial.println(-a+90);
    }
    
  if(!strcmp(st,"lt")){
      b = atoi(sp);
      ECC.write(b+90); 
//      Serial.println(a+90+zp);
    }
    
   if(!strcmp(st,"rt")){
     b = atoi(sp);
     ECC.write(90-b);
//      Serial.println(a-90-yp); 
    }


}
 
// 订阅指定主题
void subscribeTopic(){
 
  // 建立订阅主题。主题名称以Taichi-Maker-Sub为前缀,后面添加设备的MAC地址。
  // 这么做是为确保不同设备使用同一个MQTT服务器测试消息订阅时,所订阅的主题名称不同
  String topicString = "esp8266-cfeeee" ;
  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...");
  }  
}
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

打工人阿秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值