微信小程序+UDP+wifi8266+l293d扩展板+Arduino uno遥控小车

微信小程序+UDP+wifi8266+l293d扩展板+Arduino uno遥控小车

序言

前面突然看到自己已经落灰的Arduino板子,感觉自己必须做点什么。正好手上有个8266的模块、有个焊接接好的小车、有个落灰的Arduino板子,好巧。正好前几天上过一篇8266模块和微信小程序进行UDP通信的博文,一切都正好,那开搞吧。

前置知识需要的不多
至少要去看看微信小程序关于UDP通信的文档,当然你看我上面的文章也行,感觉还挺详细的,有电脑就行(滑稽~),下面的代码我都只贴最核心的代码,基本上都会覆盖到,如果需要所有项目的源码请一键三连留下邮箱,接下来直接正题

主要涉及的一些东西
wifi8266:

	3V3 3.3V供电,避免使用5V供电
	RX	UART_RXD,异步串口接受端
	RST	外部复位引脚,低电平有效,默认高电平
	IO0	GPIO 0引脚;状态:1.悬空:Flash下载模式和工作模式;2.下拉:串口下载模式
	EN	使能端口,高电平工作,低电平模块不工作
	IO2	GPIO2引脚,开机上电时禁止下拉,默认高电平
	UTXD	UART_TXD,异步串口发送端
	GND	GND接地引脚

在这里插入图片描述
烧录工具

广告请忽略,我买的就是这一套,挺方便的

在这里插入图片描述

L293d扩展板

这个没啥好说的,直接插Arduino板子上,下面是太极创客官网的板子介绍,感兴趣可以去看看,别急着吐槽,需要注意的地方我都会在这里说的。比如这里的2号引脚就很重要,没有焊接,这个很关键,esp-01和Arduino串口通信需要用到,板子上的A0-A5也可以作为软串口通信,但是接上esp-01后它无法正常工作(这个可以自己去验证一下,l293d扩展板其实真没什么东西只是为了扩展Arduino的功能,单块l293d最多只能控制两个电机,如果是两轮驱动完全没必要买这个板子,但是转向你需要搞一个舵机,供电建议使用9v电源同时为Arduino和l293d供电,电压不足会导致很多奇怪的行为)

在这里插入图片描述

Arduino uno

这也没啥好说的,感兴趣就自己去太极创客官网看看介绍,主要的硬件差不多就这几个,后面我会贴一个我自己焊接的图,不急

在这里插入图片描述
微信小程序

这个是我自己开发的,因为有的页面空着,发布小程序还被微信驳回了,只能测试玩玩了,不想自己写的话可以扫码体验一把,虽然瑕疵有点多,但是测试还是可以的,后面做新的东西我也会在这个上面继续开发,有需求也可以提,等成熟了可以把代码放github

在这里插入图片描述
小程序wifi功能核心代码以及运行界面

背景是一个video标签,不要在意内容,这里准备接入Esp32-cam摄像头

在这里插入图片描述
代码 html css js


<video class="video-bg" autoplay controls="{{false}}" src="https://vd4.bdstatic.com/mda-kewsvi1w9u7bv42w/v1-cae/mda-kewsvi1w9u7bv42w.mp4?v_from_s=hkapp-haokan-hnb&auth_key=1669192668-0-0-aefa5c11bf88aacc22c048084a76aadb&bcevod_channel=searchbox_feed&pd=1&cd=0&pt=3&logid=0468789483&vid=1260358254659161368&abtest=&klogid=0468789483"></video>
<view class="wificontainer">
  <van-row>
  <van-col span="12">
  <view class="direction" catchtouchmove="move" catchtouchstart="movestart" catchtouchend="moveend" >
    <view class="point" style="left:{{left+'px'}};top:{{top+'px'}}">+</view>
  </view>
  </van-col>
  <van-col span="12">
    <view class="option">
            <view class="btnFore" bindtap="instructions" data-message="accelerate">加速</view>
            <view class="btnBack" bindtap="instructions" data-message="decelerate">减速</view>
            <view class="btnStop" bindtap="instructions" data-message="stop">停止</view>
    </view>
  </van-col>
  </van-row>

</view>
.video-bg{
    width:100vw;
    height:100vh;
    position:absolute;
    z-index:-100;
}
//这里这个style标签只是为了当前显示,在微信小程序中使单个文件
<style>
.wificontainer{
   height: 100vh;
   width:100vw;
   position: relative;
   z-index:100;
   background: transparent;
   position:absolute;
   /* background-position: left top;
   background-repeat: no-repeat;
   background-position: center;
   background-size: cover;
   background-image: url('https://pic.rmb.bdstatic.com/c614c350d47179742c388cf996c3b23d.jpeg'); */
   /* https://pic.rmb.bdstatic.com/c614c350d47179742c388cf996c3b23d.jpeg */
}
.van-row{
    height:100%;
    text-align: center;
    vertical-align: middle;
    /* margin:10px; */
}
.van-col{
        height:100%;
        display: grid;
		grid-template-columns:100%;
        grid-template-rows: 100%;
        justify-items: center;
        align-items: center;
        /* border:1px solid red; */
}
.direction{
    height:140px;
    width:140px;
    line-height:140px;
    border-radius: 50%;
    color:#fff;
    border:1px solid #ccc;
    background-color: rgba(66, 65, 57, 0.2);
    box-shadow: 0 0 14px #fff inset;
    position: relative;
    /* border: 1px solid red; */
}
.point{
     
		width:50px;
        height:50px;
        line-height: 50px;
        display: inline-block;
		background-color: rgba(0,0,0,0.4);
		box-shadow: 0 0 14px #fff inset;
        border-radius: 50%;
        position: relative;
        /* left:00px; */
		/* vertical-align: center; */
		color:#fff;
		/* position: absolute; */
}
/* 操作按钮容器 */
.option{
    height:100%;
    width:100%;
    display: grid;
    align-items: center;
    justify-items: center;
    grid-template-rows: repeat(4,25%);
    grid-template-columns: repeat(4,25%);
    
}
.btnFore{
    /* border:1px solid red; */
    display: inline-block;
    width:60px;
    height:60px;
    line-height:60px;
    grid-row-start: 2;
    grid-row-end:3;
    grid-column-start:3;
    grid-column-end:4;
    color:#fff;
    /* margin:auto; */
    border:1px solid #ccc;
    background-color: rgba(66, 65, 57, 0.2);
    box-shadow: 0 0 14px #fff inset;
    border-radius: 50%;

}
.btnBack{
    display: inline-block;
    width:60px;
    height:60px;
    line-height:60px;
    grid-row-start: 3;
    grid-row-end:4;
    grid-column-start:3;
    grid-column-end:4;
    color:#fff;
    /* margin:auto; */
    border:1px solid #ccc;
    background-color: rgba(66, 65, 57, 0.2);
    box-shadow: 0 0 14px #fff inset;
    border-radius: 50%;
    /* vertical-align: center; */
}
.btnStop{
    display: inline-block;
    width:60px;
    height:60px;
    line-height:60px;
    grid-row-start: 2;
    grid-row-end:3;
    grid-column-start:2;
    grid-column-end:3;
    color:#fff;
    /* margin:auto; */
    border:1px solid #ccc;
    background-color: rgba(192, 17, 66, 0.8);
    box-shadow: 0 0 14px #fff inset;
    border-radius: 50%;
    /* vertical-align: center; */
}
</style>

这里讲一下,因为微信的渲染规则,导致movetouch等方法的触发会有卡顿的情况,所以做了节流处理,有博主说wxs可以解决,可以去试试

// pages/controls/wifi/wifi.js
import Dialog from '@vant/weapp/dialog/dialog';
// import Notify from '@vant/weapp/notify/notify';
Page({

    /**
     * 页面的初始数据
     */
    data: {
        //wifi列表
        equipmentList:[],
        //需要发送的数据
        message:"",
        udpScoket:{},
        //记录起点的相对位置
        originPageX:0,
        originPageY:0,
        left:0,
        top:0,
        operating:true,
        address:'192.168.43.3',
        port:"7788"
    },
    arrayBufferToString(arr){
    
        var dataview=new DataView(arr);
        var ints=new Uint8Array(arr.byteLength);
        for(var i=0;i<ints.length;i++){
          ints[i]=dataview.getUint8(i);
        }
        // console.log(ints)
        arr=ints;
        var str = '',  
            _arr = arr;  
        for(var i = 0; i < _arr.length; i++) {  
            var one = _arr[i].toString(2),  
                v = one.match(/^1+?(?=0)/);  
            if(v && one.length == 8) {  
                var bytesLength = v[0].length;  
                var store = _arr[i].toString(2).slice(7 - bytesLength);  
                for(var st = 1; st < bytesLength; st++) {  
                    store += _arr[st + i].toString(2).slice(2);  
                }  
                str += String.fromCharCode(parseInt(store, 2));  
                i += bytesLength - 1;  
            } else {  
                str += String.fromCharCode(_arr[i]);  
            }  
        }  
        return str; 
    },
    /**
     * 生命周期函数--监听页面加载
     */
    onLoad(options) {
    

        let that=this;
        let is = wx.canIUse('createUDPSocket');
        if(is){
                //开启UDP监听
                this.data.udpScoket =  wx.createUDPSocket();
                this.data.udpScoket.bind(4321) 
                this.data.udpScoket.onListening(function (res) {
                console.log('监听中.....');
                console.log(res);
            })
        
            this.data.udpScoket.onError(function(err) {
            wx.showToast({
                title: err.message,
            })
            
            })
            this.data.udpScoket.onMessage(function(res) {
                console.log(res);
            let mess=that.arrayBufferToString(res.message);
            console.log(mess)
            })
    
        }else{
            this.showToast({
                title:"当前基础库版本不支持createUDPSocket"
            })
        }
       
        
    
        
      
        
      
    },
    /**
     * 生命周期函数--监听页面初次渲染完成
     */
    onReady() {
      
       
        // wx.startLocalServiceDiscovery({
        //     serviceType: '_http._tcp.',
        //     success: (res)=> {
                
        //     console.log(res)
        //     }
        //   })
    
        //   wx.onLocalServiceResolveFail((res)=>{
        //     console.log(res);
        // })
        //   wx.onLocalServiceFound((resp)=>{
        //     console.log(resp);
        // })
    
        
    },
    //向wifi模块发送数据
    instructions(e){
        let message=e.currentTarget.dataset.message;
        console.log(message)
        this.data.udpScoket.send({
            address: this.data.address,
            port: this.data.port,
            message: message,
        })
    },
    /**
     * 生命周期函数--监听页面显示
     */
    onShow() {

    },

    /**
     * 生命周期函数--监听页面隐藏
     */
    onHide() {

    },
    //防抖操作 只执行最后一次
   debounce(fn, delay){
        let timer = null;
        return function(){
            clearTimeout(timer);
            timer = setTimeout(()=> {
                fn.apply(this, arguments);
            }, delay)
        }
    },
    //节流操作 间隔执行
    throttle(fn, delay){
         let that=this;
        return function(){
            if(that.data.operating) {
                that.data.operating = false;
                setTimeout(()=> {
                    fn.apply(this, arguments);
                    that.data.operating = true;
                }, delay)
               
            }
        }
    },
    //计算斜边
    maxBorder(l,t){
        let leftAbs=Math.abs(l);
        let topAbs=Math.abs(t);
        let hypotenuse=Math.pow(leftAbs,2)+Math.pow(topAbs,2)
        // console.log()
        let sqrthy=Math.sqrt(hypotenuse).toFixed()
        return sqrthy;
    },
    //节流方式向wifi模块投递命令
    intervalCall(intervalTime,instruction){
        this.throttle(()=>{
            console.log(instruction)
             this.data.udpScoket.send({
                address:this.data.address,
                port:this.data.port,
                message:instruction
            })
            },intervalTime)(); 
    },
    //记录事件触发
    movestart(e){
        //固定坐标中心点
        // console.log("========开始移动给定相对盒子的位置=======")
        this.setData({
            originPageX:165.30,
            originPageY:187.95,
            left:0,
            top:0
        })
},
    move(e){
        let tempT=e.changedTouches[0].pageY-this.data.originPageY;
        let tempL=e.changedTouches[0].pageX-this.data.originPageX;
        let sqrt=this.maxBorder(tempL,tempT);
        // console.log(sqrt);
        if(sqrt<=70){
               this.setData({
                 left:tempL,
                 top:tempT 
               })
    
        }else{
        // console.log("========移动中的坐标=======")
        let calcLeft= (70*((tempL/sqrt).toFixed(2)));
        let calcTop=(70*((tempT/sqrt).toFixed(2)));
        this.setData({
            left:calcLeft,
            top:calcTop
        })
        // console.log(calcLeft,calcTop)
        if(calcLeft>0&&calcTop>0){
            if(Math.abs(calcLeft)>=Math.abs(calcTop)){
            //节流方式发布方向指令    
                this.intervalCall(50,"right");
            }else{
                this.intervalCall(50,"backward");
            }
        }else if(calcLeft<0&&calcTop>0){
            if(Math.abs(calcLeft)>=Math.abs(calcTop)){
                this.intervalCall(50,"left");
               
            }else{
                this.intervalCall(50,"backward");
            }
        }else if(calcLeft<0&&calcTop<0){
            if(Math.abs(calcLeft)>=Math.abs(calcTop)){
                this.intervalCall(50,"left");
               
            }else{
                this.intervalCall(50,"forward");
              
            } 
        }else if(calcLeft>0&&calcTop<0){
            if(Math.abs(calcLeft)>=Math.abs(calcTop)){
                this.intervalCall(50,"right");
               
            }else{
                this.intervalCall(50,"forward");
              
            }       
        }
        }
       
        
    },
    moveend(e){
        // console.log("========移动终止置位置到起点=======")
        // console.log(Object.defineProperty(this.data,"oprating",{value:false}))
        // console.log(this.data.oprating)
        this.setData({
            originPageX:165.30,
            originPageY:187.95,
            left:0,
            top:0
        })
      
    },
    //udp通信,需要wifi模块与手机接入同一个网段
    UDPComunicate(){
    
        const UDP= wx.createUDPSocket();
        UDP.bind();
        UDP.send({
            address:this.address,
            port:this.part,
            message:this.message
        })

    },
    onUnload() {
      
       if(this.data.udpScoket){
            this.data.udpScoket.close();
           
            
       }
        //  wx.stopLocalServiceDiscovery({
        //     success:(res)=>{
        //         console.log(res);
        //     },
        //     fail:(err)=>{
        //         console.log(err)
        //     }
        // })
       
    },

    /**
     * 页面相关事件处理函数--监听用户下拉动作
     */
    onPullDownRefresh() {

    },

    /**
     * 页面上拉触底事件的处理函数
     */
    onReachBottom() {

    },

    /**
     * 用户点击右上角分享
     */
    onShareAppMessage() {

    }
})

wifi8266代码

因为微信mDNS没有接入成功所以我把wifi和密码写死的,个人手机热点先改成这样吧,用这个小程序的都通用(滑稽~)

 //程序如下:
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ESP8266WiFi.h>
#define ssid      "wifi8266"       //WIFI名字最好别包含特殊符号 不然连接不上
#define password  "987654321"     //WIFI密码
unsigned int localUDPPort = 7788;  //本地监听端口
unsigned int remoteUDPPort = 8877;  //远程监听端口
char incomingPacket[255];  // 保存Udp工具发过来的消息

WiFiUDP UDPInstance;//实例化WiFiUDP


void setup()
{
     Serial.begin(115200);
     delay(10);
     
    Serial.printf("正在连接 %s ", ssid);
    WiFi.begin(ssid, password);//连接到wifi
    
   Serial.println();
  while (WiFi.status() != WL_CONNECTED)//等待连接
  {
    
    delay(600);
    Serial.print(".");
  }
   Serial.println("wifi连接成功");
  

  //启动mdns功能
 if(WiFi.status() == WL_CONNECTED) //wifi连接成功后
  {
     if (UDPInstance.begin(localUDPPort)) { //启动Udp监听服务
      Serial.println("监听成功");
      Serial.printf("现在收听IP:%s, UDP端口:%d\n", WiFi.localIP().toString().c_str(), localUDPPort); //wifi模块的ip地址在这里获取
    } else {
      Serial.println("监听失败");
    }
  }
     
    
 
}
void loop()
{
  if (UDPInstance.parsePacket()) //解析包不为空
  {
    // 读取Udp数据包并存放在incomingPacket
    int len = UDPInstance.read(incomingPacket, 255);//返回数据包字节数
    
    if (len > 0)
    {
      incomingPacket[len] = 0;//清空缓存
      //strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数。
      //基本形式为strcmp(str1,str2),若str1=str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数。
      if (strcmp(incomingPacket, "forward") == 0)
      {
       Serial.println                                                                                                                                                                                                                                    (incomingPacket);
     
       
      }else if(strcmp(incomingPacket, "backward") == 0)
      {
       Serial.printf(incomingPacket);
    
      }else if(strcmp(incomingPacket, "left") == 0)
      {
       Serial.printf(incomingPacket);
      }else if(strcmp(incomingPacket, "right") == 0)
      {
       Serial.printf(incomingPacket);
      }else if(strcmp(incomingPacket, "accelerate") == 0)
      {
       Serial.printf(incomingPacket);
      }else if(strcmp(incomingPacket, "decelerate") == 0)
      {
        Serial.printf(incomingPacket);
      }else if(strcmp(incomingPacket, "stop") == 0)
      {
       Serial.printf(incomingPacket);
      }
      else{
        Serial.printf("无效命令");
      } 
    }
  }
}

//向udp工具发送消息
void sendCallBack(const char *buffer)
{
  UDPInstance.beginPacket(UDPInstance.remoteIP(), remoteUDPPort);//配置远端ip地址和端口
  UDPInstance.write(buffer); //把数据写入发送缓冲区
  UDPInstance.endPacket(); //发送数据
}

L293D代码(叫Arduino代码我感觉更合适)

速度数值可以自己调整,电压推荐9v,6v看起来病秧秧的,模块四个端子默认的频率输出并不相同,介意的可以自己调平

··#include <AFMotor.h>  
#include<SoftwareSerial.h>
SoftwareSerial softSerial(2,3);//软串口,用于接收命令

//常量
#define MAX_SPEED 255 

//变量
String incomingPacket="";
String directionW="fore";
int speedSet = 0;
int currentSpend=120;

 AF_DCMotor motor1(1); // 这4条语句的作用是建立4个直流电机对象,它们的名称分别是:motor1/2/3/4.
 AF_DCMotor motor2(2); 
 AF_DCMotor motor3(3); 
 AF_DCMotor motor4(4); 

void setup() {
     delay(100);
    //读取wifi模块参数作为指令
    softSerial.begin(115200);
    Serial.begin(115200);
    softSerial.listen();
   
    motor1.setSpeed(120); 
    motor2.setSpeed(120);
    motor3.setSpeed(120); 
    motor4.setSpeed(120); 
   
    motor1.run(RELEASE); // 这4条语句的作用是让4个电机在启动时停止转动
    motor2.run(RELEASE); 
    motor3.run(RELEASE); 
    motor4.run(RELEASE); 
}

//执行流程  指令->微信小程序UDP->wifi8266->Arduino->驱动电机动作

void loop() {
 
 //循环接收指令   
  if(softSerial.available()>0){
      incomingPacket=softSerial.readString();
      Serial.println(incomingPacket);
      if (incomingPacket== "forward")
      {
         moveForward();
       
      }else if(incomingPacket== "backward")
      {
        moveBackward();
    
      }else if(incomingPacket=="left")
      {
       turnLeft();
      }else if(incomingPacket=="right")
      {
        turnRight();
      }else if(incomingPacket== "accelerate")
      {
        accelerate();
      }else if(incomingPacket== "decelerate")
      {
        decelerate();
       
      }else if(incomingPacket== "stop")
      {
        moveStop();
      }
      else{
      //        Serial.print("未匹配到该指令"); 
      } 
    }
  

}


//以下为对应操作指令执行的函数
//加速
void accelerate(){
     //这里不修改运动的方向,只做加速
          
    if(currentSpend<=MAX_SPEED-50){
       currentSpend+=50;
        motor1.setSpeed(currentSpend);         
        motor2.setSpeed(currentSpend);         
        motor3.setSpeed(currentSpend);          
        motor4.setSpeed(currentSpend);              
      }else{
        currentSpend=255;
        motor1.setSpeed(currentSpend);         
        motor2.setSpeed(currentSpend);          
        motor3.setSpeed(currentSpend);         
        motor4.setSpeed(currentSpend);          
        }  
         
  }
//减速
void decelerate(){
     if(currentSpend>=50){
      currentSpend-=50;
        motor1.setSpeed(currentSpend);          
        motor2.setSpeed(currentSpend); 
        motor3.setSpeed(currentSpend); 
        motor4.setSpeed(currentSpend); 
    
    }else{
        currentSpend=0;
        motor1.setSpeed(currentSpend);
        motor2.setSpeed(currentSpend);
        motor3.setSpeed(currentSpend);
        motor4.setSpeed(currentSpend);
     
      }
 
    }
//停止    
void moveStop() {
    motor1.run(RELEASE); 
    motor2.run(RELEASE); 
    motor3.run(RELEASE); 
    motor4.run(RELEASE); 
    currentSpend=120;
  } 
//向前
void moveForward() {
    delay(100);
      //防止电压值过低无法工作
      currentSpend=120;
      
      motor1.run(FORWARD);      
      motor2.run(FORWARD);
      motor3.run(FORWARD); 
      motor4.run(FORWARD); 
      
      motor1.setSpeed(currentSpend);          
      motor2.setSpeed(currentSpend);          
      motor3.setSpeed(currentSpend);          
      motor4.setSpeed(currentSpend);          

   //记录当前的方向,用于转向后的方向保持 
    directionW=="fore" ;  
}
//后退
void moveBackward() {
    
     //防止电压值过低无法工作
      currentSpend=120;

      //方向
      motor1.run(BACKWARD);      
      motor2.run(BACKWARD);
      motor3.run(BACKWARD);
      motor4.run(BACKWARD);   

      //速度
      motor1.setSpeed(currentSpend);         
      motor2.setSpeed(currentSpend);         
      motor3.setSpeed(currentSpend);         
      motor4.setSpeed(currentSpend);          

     //记录当前的方向,用于转向后的方向保持
      directionW=="back";
    
}  
//右转
void turnRight() {
      
  if(directionW=="back")
      {
          motor1.run(BACKWARD);
          motor2.run(BACKWARD);
          motor3.run(FORWARD);
          motor4.run(FORWARD);     
          delay(300);
          motor1.run(BACKWARD);      
          motor2.run(BACKWARD);
          motor3.run(BACKWARD);
          motor4.run(BACKWARD); 
        }else if(directionW=="fore"){
          motor1.run(FORWARD);
          motor2.run(FORWARD);
          motor3.run(BACKWARD);
          motor4.run(BACKWARD);     
          delay(300);
          motor1.run(FORWARD);      
          motor2.run(FORWARD);
          motor3.run(FORWARD);
          motor4.run(FORWARD); 
          }else{
            
            }
      motor1.setSpeed(120); 
      motor2.setSpeed(120);
      motor3.setSpeed(120); 
      motor4.setSpeed(120); 
} 
//左转 
void turnLeft() {
     
 if(directionW=="back")
      {
          motor1.run(FORWARD);
          motor2.run(FORWARD);
          motor3.run(BACKWARD);
          motor4.run(BACKWARD);     
          delay(300);
          motor1.run(BACKWARD);      
          motor2.run(BACKWARD);
          motor3.run(BACKWARD);
          motor4.run(BACKWARD); 
        }else if(directionW=="fore"){
          motor1.run(BACKWARD);
          motor2.run(BACKWARD);
          motor3.run(FORWARD);
          motor4.run(FORWARD);     
          delay(300);
          motor1.run(FORWARD);      
          motor2.run(FORWARD);
          motor3.run(FORWARD);
          motor4.run(FORWARD); 
          }else{
            
            }
      motor1.setSpeed(120); 
      motor2.setSpeed(120);
      motor3.setSpeed(120); 
      motor4.setSpeed(120);
}  

核心的东西差不多就这些,讲一下需要注意的一些地方,烧录的时候记得把9v去掉或者把跳线拔掉二选一,否则烧板子,还有就是wifi模块工作电压3.3v,这个是真坑啊,扩展板唯一输出3.3v的就是跳线针脚那里,5v降压或者9v降压不推荐,太费劲,我直接接的5v,工作时会有wifi模块发烫的问题,希望它能坚持一段时间,还有就是接线,wifi模块的TX引脚接l293d上那个空的针脚,也就是2号,作为串口通信使用,3号针脚要是要向wifi模块回送数据也可以接(但是真的难焊,毕竟封死了,滑稽~),关于wifi8266模块(也就是esp-01)烧录相关的问题,可以看我开头说的那篇文章,最后上个整机图,快乐就是这么朴实无华

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值