基于巴法云的esp8266实现温湿度、LED、sg90舵机和HC-RS04实现的小程序远程控制
本项目想法已经在我脑海想了很久了,都没有时间去实现它,这次刚刚考完试就用了两天把它做了出来,希望对大家有帮助,有什么需要的可以在下面留言喔。
- 其实这两天遇到的坑还是比较多的,就比如在数据传输的没能想到用cmd9进行获取返回值
- 还有一个便是舵机消抖问题
具体代码.
#include <ESP8266WiFi.h>
#include <SimpleDHT.h>
#include <U8g2lib.h>
#include <Servo.h>
///*********************************************///
//巴法云的定义
#define TCP_SERVER_ADDR "bemfa.com"
#define TCP_SERVER_PORT "8344"
#define DEFAULT_STASSID "123456"
#define DEFAULT_STAPSW "1234567890"
String UID = "xxxxx";
String TOPIC = "temp"; //用于传输温湿度的主题
//主题名字,可在控制台新建
String TOPIC2 = "Light002"; //用于led控制的主题
String TOPIC3 = "distance"; //用于HC-RS04控制的主题
String TOPIC4 = "servo"; //用于电机控制的主题
///*********************************************///
//DHT11引脚值
int pinDHT11 = D4; //连接dht11的引脚
//单片机LED引脚值
int LED_Pin = D2; //假设连接led的引脚
int pin1= D5; //连接HC-RS04的 trig引脚
int pin2= D6; //连接HC-RS04的echo引脚
int servopin = D7; //电机引脚
volatile float item; //物体距离
///*********************************************///
//led 控制函数
void turnOnLed();
void turnOffLed();
//电机控制函数
void turnleft();
void turnright();
//led状态状态
String my_led_status = "off";
//电机状态状态
String my_servo_status = "left";
float cm;
//电机状态之后的 防止状态没变 导致一直运行 防抖
bool my_servo_left =true;
bool my_servo_right =true;
///*********************************************///
//下面的2代表上传间隔是2秒
#define upDataTime 2*1000
SimpleDHT11 dht11(pinDHT11);
Servo myservo;
//最大字节数
#define MAX_PACKETSIZE 512
//tcp客户端相关初始化,默认即可
WiFiClient TCPclient;
String TcpClient_Buff = "";
unsigned int TcpClient_BuffIndex = 0;
unsigned long TcpClient_preTick = 0;
unsigned long preHeartTick = 0;
unsigned long preTCPStartTick = 0;
bool preTCPConnected = false;
///*********************************************///
//相关函数初始化
//连接WIFI
void doWiFiTick();
void startSTA();
//TCP初始化连接
void doTCPClientTick();
void startTCPClient();
void sendtoTCPServer(String p);
///*********************************************///
/*
*发送数据到TCP服务器
*/
void sendtoTCPServer(String p){
if (!TCPclient.connected())
{
Serial.println("Client is not readly");
return;
}
TCPclient.print(p); //将数据发送到巴法云中
Serial.println("刚刚发送到云端的数据为:");
Serial.println(p);
}
///*********************************************///
/*
*初始化和服务器建立连接
*/
void startTCPClient(){
if(TCPclient.connect(TCP_SERVER_ADDR, atoi(TCP_SERVER_PORT))){
Serial.print("\nConnected to server:");
Serial.printf("%s:%d\r\n",TCP_SERVER_ADDR,atoi(TCP_SERVER_PORT));
String tcpTemp="";
tcpTemp = "cmd=1&uid="+UID+"&topic="+TOPIC2+"&msg="+my_led_status+"\r\n"; //这里可以随便写一个主题,主要是测试与服务器的连接状态
sendtoTCPServer(tcpTemp);
preTCPConnected = true;
preHeartTick = millis();
TCPclient.setNoDelay(true);
}
else{
Serial.print("Failed connected to server:");
Serial.println(TCP_SERVER_ADDR);
TCPclient.stop();
preTCPConnected = false;
}
preTCPStartTick = millis();
}
///*********************************************///
/*
*检查数据,发送数据
*/
void doTCPClientTick(){
//检查是否断开,断开后重连
if(WiFi.status() != WL_CONNECTED) return;
if (!TCPclient.connected()) {//断开重连
if(preTCPConnected == true){
preTCPConnected = false;
preTCPStartTick = millis();
Serial.println();
Serial.println("TCP Client disconnected.");
TCPclient.stop();
}
else if(millis() - preTCPStartTick > 1*1000)//重新连接
startTCPClient();
}
else
{
if (TCPclient.available()) {//收数据
char c =TCPclient.read();
TcpClient_Buff +=c;
TcpClient_BuffIndex++;
TcpClient_preTick = millis();
if(TcpClient_BuffIndex>=MAX_PACKETSIZE - 1){
TcpClient_BuffIndex = MAX_PACKETSIZE-2;
TcpClient_preTick = TcpClient_preTick - 200;
}
preHeartTick = millis();
}
if(millis() - preHeartTick >= upDataTime){//上传数据
preHeartTick = millis();
/*****************获取DHT11 温湿度*****************/
// read without samples.
byte temperature = 0;
byte humidity = 0;
int err = SimpleDHTErrSuccess;
if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
Serial.print("Read DHT11 failed, err="); Serial.println(err);delay(1000);
return;
}
/*********************数据上传*******************/
/*
数据用#号包裹,以便app分割出来数据,&msg=#23#80#on#\r\n,即#温度#湿度#按钮状态#,app端会根据#号分割字符串进行取值,以便显示
如果上传的数据不止温湿度,可在#号后面继续添加&msg=#23#80#data1#data2#data3#data4#\r\n,app字符串分割的时候,要根据上传的数据进行分割
*/
String upstr = "";
String upstr1 = "";
String upstr2 = "";
String upstr3 = "";
//发送数据 温湿度及距离用cmd2 发送无需返回值 而需要返回值的 这种情况需要是服务器端操控单片机的话 使用cmd9
upstr = "cmd=2&uid="+UID+"&topic="+TOPIC+"&msg=#"+temperature+"#"+humidity+"#\r\n";
upstr1 = "cmd=9&uid="+UID+"&topic="+TOPIC2+"\r\n";
upstr2 = "cmd=2&uid="+UID+"&topic="+TOPIC3+"&msg="+item+"\r\n";
upstr3 = "cmd=9&uid="+UID+"&topic="+TOPIC4+"\r\n";
sendtoTCPServer(upstr);
sendtoTCPServer(upstr1);
sendtoTCPServer(upstr2);
sendtoTCPServer(upstr3);
upstr = "";
upstr1 = "";
upstr2 = "";
upstr3 = "";
}
}
if((TcpClient_Buff.length() >= 1) && (millis() - TcpClient_preTick>=200))
{//data ready
TCPclient.flush();
Serial.println("Buff");
Serial.println(TcpClient_Buff);
//TcpClient_Buff.indexOf判断返回值中是否有这些字符 本人建议最好加上主题
if((TcpClient_Buff.indexOf("servo&msg=right") > 0)) {
String my_servo1_status = "right";
turnright();
}else if((TcpClient_Buff.indexOf("servo&msg=left") > 0)) {
String my_servo1_status = "left";
turnleft();
}
if((TcpClient_Buff.indexOf("Light002&msg=on") > 0)) {
String my_led1_status = "off";
turnOffLed();
}else if((TcpClient_Buff.indexOf("Light002&msg=off") > 0)) {
String my_led1_status = "on";
turnOnLed();
}
TcpClient_Buff="";
TcpClient_BuffIndex = 0;
}
item = checkdistance_2_3();
}
//打开灯泡
void turnOnLed(){
Serial.println("Turn on");
digitalWrite(LED_Pin,LOW);
my_led_status = "on";
}
//关闭灯泡
void turnOffLed(){
Serial.println("Turn off");
digitalWrite(LED_Pin,HIGH);
my_led_status = "off";
}
//打开电机
void turnleft(){
Serial.println("Turn left");
my_servo_status ="left";
if(my_servo_left==true){ //解决待机问题的消抖
servopulse(180); //引用脉冲函数
delay(1000);
my_servo_left=false;
}else{
my_servo_right=true;
}
}
void turnright(){
Serial.println("Turn right");
my_servo_status ="right";
if(my_servo_right==true){ //解决待机问题的消抖
servopulse(0); //引用脉冲函数
delay(1000);
my_servo_right=false;
}else{
my_servo_left=true;
}
}
void startSTA(){
WiFi.disconnect();
WiFi.mode(WIFI_STA);
WiFi.begin(DEFAULT_STASSID, DEFAULT_STAPSW);
}
//*********************************************************************
void doWiFiTick(){
static bool startSTAFlag = false;
static bool taskStarted = false;
static uint32_t lastWiFiCheckTick = 0;
if (!startSTAFlag) {
startSTAFlag = true;
startSTA();
Serial.printf("Heap size:%d\r\n", ESP.getFreeHeap());
}
//未连接1s重连
if ( WiFi.status() != WL_CONNECTED ) {
if (millis() - lastWiFiCheckTick > 1000) {
lastWiFiCheckTick = millis();
}
}
//连接成功建立
else {
if (taskStarted == false) {
taskStarted = true;
Serial.print("\r\nGet IP Address: ");
Serial.println(WiFi.localIP());
startTCPClient();
}
}
}
//*********************************************************************
float checkdistance_2_3() { //获取物体距离函数
digitalWrite(pin1, LOW);
delayMicroseconds(pin1);
digitalWrite(pin1, HIGH);
delayMicroseconds(10);
digitalWrite(pin1, LOW);
float distance = pulseIn(pin2, HIGH) / 58.00;
delay(10);
return distance;
}
float iif(bool expression, float truePart, float falsePart)
{
return expression ? truePart : falsePart;
}
//*********************************************************************
//消抖
void servopulse(int angle)//定义一个脉冲函数
{
//发送50个脉冲
for (int i = 0; i < 50; i++) {
int pulsewidth = (angle * 11) + 500; //将角度转化为500-2480的脉宽值
digitalWrite(servopin, HIGH); //将舵机接口电平至高
delayMicroseconds(pulsewidth); //延时脉宽值的微秒数
digitalWrite(servopin, LOW); //将舵机接口电平至低
delayMicroseconds(20000 - pulsewidth);
}
// delay(20);
}
// 初始化,相当于main 函数
void setup() {
myservo.attach(servopin);
pinMode(pin1, OUTPUT);
pinMode(pin2, INPUT);
Serial.begin(115200);
//初始化引脚为输出
pinMode(LED_Pin,OUTPUT);
}
//循环
void loop() {
doWiFiTick();
doTCPClientTick();
}