利用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...");
}
}