基于巴法云的esp8266实现温湿度、LED、sg90舵机和HC-RS04实现的小程序远程控制

该项目通过ESP8266实现温湿度、LED、舵机和超声波传感器的远程控制。使用巴法云作为服务器,通过TCP连接进行数据交互。代码中包含了DHT11传感器读取温湿度、LED开关控制、SG90舵机转动以及HC-SR04超声波测距功能,并解决了舵机消抖问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于巴法云的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();
}

在这里插入图片描述

智能小车的避障功能通常会通过单片机如STC89C52配合传感器执行机构来实现。以下是简要步骤关键代码片段: 1. **硬件连接**: - STC89C52单片机作为主控单元,负责处理信号控制其他部件。 - L298N驱动电路用于控制四个电机,根据指令进行前进、后退、左转、右转等操作。 - SG90舵机用于调整车辆的方向。 - HC-SR04超声波模块用于测量障碍物的距离。 2. **软件设计**: - 使用Keil C51开发环境编写程序,因为这是STC89C52的常用开发工具。 - 主函数中初始化各个模块,设置中断处理程序,特别是超声波模块的数据接收中断。 ```c #include <reg52.h> #include "ultrasonic.h" void main(void) { // 初始化单片机、电机、舵机超声波 init_STC(); init_motors(); init_servo(); init_ultrasonic(); while(1) { int distance = get_distance(); // 调用超声波模块获取距离 if (distance <= min_distance_threshold) { // 遇到障碍 turn_left(); // 向左转,避开障碍 } else { move_forward(); // 无碍,继续直线行驶 } } } ``` 3. **避障算法**: - 当接收到的超声波数据小于预设阈值时,说明有障碍物,这时通过判断转动角度(比如每次左转一定的度数,直到找到无障碍路径),并控制电机改变方向。 4. **相关问题--:** 1. 需要在代码中如何处理超声波数据的读取处理误差? 2. 如何设定合理的`min_distance_threshold`避免误判? 3. 如果需要实时路径规划,应该如何改进这个避障策略?
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

归想

谢谢大家支持

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

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

打赏作者

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

抵扣说明:

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

余额充值