esp8266_esp8266教程 - CSDN
精华内容
参与话题
  • ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明

    万次阅读 多人点赞 2020-01-17 19:49:13
        笔者本书的主题是基于Arduino平台来开发ESP8266。那么从另外一个角度来看待这句话,可以理解为:把ESP8266当作一款类似于Arduino UNO型号(为什么不是Mega2560呢?可以从硬件资源方向考虑)的Arduino开发板...

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力。希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石。。。

    共同学习成长QQ群 622368884,不喜勿加,里面有一大群志同道合的探路人

    快速导航
    单片机菜鸟的博客快速索引(快速找到你要的)

    如果觉得有用,麻烦点赞收藏,您的支持是博主创作的动力。

        笔者本书的主题是基于Arduino平台来开发ESP8266。那么从另外一个角度来看待这句话,可以理解为:把ESP8266当作一款类似于Arduino UNO型号(为什么不是Mega2560呢?可以从硬件资源方向考虑)的Arduino开发板,用Arduino平台的开发方式来开发项目,只不过ESP8266是在Arduino UNO的基础上加了网络功能
        本章将介绍ESP8266作为Arduino UNO开发板的一些重要开发知识点。
        主要分为8个部分:
        1.ESP8266 Arduino程序结构
        2.计时和延时(Timing and delays)
        3.NodeMcu 端口映射
        4.数字IO(Digital IO)
        5.中断功能
        6.模拟输入(ADC)
        7.模拟输出(PWM)
        8.串口通信(Serial)

    1. Arduino程序结构

        在第2章中,笔者提供了一个测试用例,让我们来回顾一下,代码如下:

    /**
     * Demo:
     *    测试ESP8266 demo
     *    打印ESP8266模块信息
     *    1.打印Arduino Core For ESP8266 版本,笔者是2.4.2版本
     *    2.打印Flash的唯一性芯片id(读者可以思考一下是否可以用来做点什么唯一性参考)
     *    3.打印Flash实际大小
     *    4.打印IDE配置的使用Flash大小
     *    5.打印IDE配置的Flash连接通信的频率
     *    6.打印Flash连接模式:QIO QOUT DIO DOUT,可以理解为Flash传输速率
     * @author 单片机菜鸟
     * @date 2018/10/22
     */
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(115200);
      //使能软件看门狗的触发间隔
      ESP.wdtEnable(5000);
    }
    
    void loop() {
      //喂狗
      ESP.wdtFeed();
      FlashMode_t ideMode = ESP.getFlashChipMode();
      String coreVersion = ESP.getCoreVersion();
      Serial.print(F("Arduino Core For ESP8266 Version: "));
      Serial.println(coreVersion);
      Serial.printf("Flash real id(唯一标识符):   %08X\n", ESP.getFlashChipId());
      Serial.printf("Flash 实际大小: %u KBytes\n", ESP.getFlashChipRealSize()/1024);
      Serial.printf("IDE配置Flash大小: %u KBytes,往往小于实际大小\n", ESP.getFlashChipSize()/1024);
      Serial.printf("IDE配置Flash频率 : %u MHz\n", ESP.getFlashChipSpeed()/1000000);
      Serial.printf("Flash ide mode:  %s\n\n", (ideMode == FM_QIO ? "QIO" : ideMode == FM_QOUT ? "QOUT" : ideMode == FM_DIO ? "DIO" : ideMode == FM_DOUT ? "DOUT" : "UNKNOWN"));
      
      delay(1000);
    }
    

        去掉代码细节,会得到类似于Arduino编程的代码结构:

    /**
     * ESP8266 Arduino程序结构
     * @author 单片机菜鸟
     * @date 2018/10/24
     */
    void setup() {
      // 这里开始写初始化代码,只会执行一次
      
    }
    
    void loop() {
      //这里写运行代码,重复执行
    }
    

        对于习惯c语言编程的读者,以上代码又可以抽象成以下伪代码结构:

    /**
     * ESP8266 Arduino程序伪代码结构
     * @author 单片机菜鸟
     * @date 2018/10/24
     */
    void main(){
      watchdogEnable();//启动看门狗
      setup();//初始化函数
      while(1){
        loop();//业务代码函数
      }
    }
    

    代码解析

    1.在ESP8266 Arduino编程中,默认会开启看门狗功能,也就是对应伪代码的watchdogEnable(),意味着我们需要适当喂狗,不然会触发看门狗复位;
    2.setup()方法:初始化函数,只会运行一次,所以一般情况下,我们都会在这里配置好初始化参数,比如IO口模式、串口波特率设置等等;
    3.loop()方法:不断重复执行,这里编写我们的业务代码,同时要注意执行喂狗操作。

    2. 计时和延时(Timing and delays)

        时间控制,基本上可以说存在于每一个项目代码中。目前在Arduino中跟时间控制有关的方法包括以下几个:
        delay(ms)
        暂停一个给定的毫秒数的时间间隔。
        delayMicroseconds(us)
        暂停一个给定的微秒数的时间间隔。
        millis()
        返回重启(reset)后所经过的毫秒数。
        micros()
        返回重启(reset)后所经过的微秒数

    温馨提示

        通常,我们控制LED灯闪烁都会加上一个delay延时来达到切换亮灭时间长度。但是delay有个缺点就是:在给定的时间间隔内是不能做其他操作,这样对于一些需要响应按键操作的场景就不适用了。那么有没有什么办法既能延时又能不影响其他操作呢?当然,这就是millis()的妙用,通过获取两个时间点的毫秒数,然后计算它们的差值,差值时间间隔内是可以执行其他操作的。代码片段如下:

    long debouncdDelay = 60;//延时间隔
    long lastDebounceTime = 0; //最近记录的一次时间
    
    // 判断时间间隔是否大于设定的时间间隔。
    if(millis()-lastDebounceTime>debouncdDelay){
        lastDebounceTime = millis();
    }
    

    3. NodeMcu 端口映射

        在前面,笔者有说到,本书的实验案例是基于NodeMcu这块ESP8266开发板来进行的,其中NodeMcu的核心芯片是ESP8266-12F。要想知道ESP8266-12F给我们提供了什么功能模块,首先了解一下它有什么引脚端口以及NodeMcu与它之间的引脚端口映射关系。

    3.1 ESP8266-12F

        首先,认识一下ESP8266-12F的引脚定义,通常会隐藏pin6-pin11,如下图:
    image
        当然,笔者也会提供完整的引脚图以便对比,如下图:
    image
        分析引脚图,可以得出几个结论:
        1.ESP8266-12F总共有22个引脚,对应了第1章选型表的SMD-22封装工艺,同时有GPIO0-GPIO16共17个通用IO口,但是得注意有些IO口还可以完成其他功能(也叫做引脚复用),诸如Serial、I2C、SPI,由相应的函数库完成;
        2.ESP8266具有一个可用的单通道ADC;
        3.GPIO6-GPIO11(复用引脚CS、MISO、MOSI、SCK)用于连接外部flash,对用户不可用,试图使用这些引脚作为IO将会导致程序奔溃;
        4.支持SPI总线通信,对应引脚为GPIO12-GPIO15;
        5.支持I2C总线,对应引脚为GPIO4-GPIO5;
        6.支持串口通信Serial、Serial1,默认对应引脚GPIO1-GPIO3;

    3.2 NodeMcu

        接下来,先了解一下NoodeMcu的实物图,如下图:

    image

        同时,读者也需要知道ESP8266-12F与NodeMcu的端口映射关系,如下图:
    image

        可以看出:
        1.中间的DEVKIT部分,就是NodeMcu提供给外界的端口,对应实物图上标注的端口名称;
        2.除开中间部分,其他部分基本上对应ESP8266引脚,以不同颜色块来区分不同功能;

    温馨提示

        NodeMcu上的CLK、SD0、CMD、SD1、SD2引脚,是用于连接外接flash芯片,不应该用于连接其他模块,悬空即可,以防程序奔溃。

        或许笔者会觉得看图有点复杂,所以笔者总结了下面的GPIO引脚映射表,以供参考:

    NodeMCU的引脚名称 ESP8266内部GPIO引脚号 可复用功能 备注
    D0 GPIO16 可用,只能用作GPIO读/写,不支持特殊功能
    D1 GPIO5 I2C总线的SCL 可用
    D2 GPIO4 I2C总线的SDA 可用
    D3 GPIO0 不可用,烧录固件或者运行模式控制端口
    D4 GPIO2 Serial1的TX Serial1没有RX
    D5 GPIO14 SPI总线的SCLK 可用
    D6 GPIO12 SPI总线的MISO 可用
    D7 GPIO13 SPI总线的MOSI、Serial的RX 可用
    D8 GPIO15 SPI总线的CS、Serial的TX 可用
    D9 GPIO3 Serial的RX 可用
    D10 GPIO1 Serial的TX 可用
    SD2 GPIO9 尽量不用
    SD3 GPIO10 尽量不用

        从上面表格可以看出,我们大约11个GPIO引脚可用。而11个中的2个引脚通常被保留用于RX和TX,以便进行串口通信。因此最后,只剩下8个通用I / O引脚,即D0到D8(除开D3特殊用途)。

    温馨提示

        请注意,D0 / GPIO16引脚只能用作GPIO读/写,不支持特殊功能。

    4. 数字IO(Digital IO)

        上面说到,ESP8266-12F(也可以大胆说ESP8266-12系列)最终只剩下8个通用的I/O引脚以供我们使用,即是NodeMcu上的D0-D8(除D3之外)。
        Arduino中的引脚号直接与ESP8266 GPIO的引脚号对应通信。pinMode/digitalRead/digitalWrite函数不变,所以要读取GPIO2,可调用digitalRead(2)。除了D0可以设置为INPUT(输入)、OUTPUT(输出)或者INPUT_PULLDOWN(输入,默认下拉,也就是低电平),剩余的数字IO引脚可以设置为INPUT(输入)、OUTPUT(输出)或者INPUT_PULLUP(输入,默认上拉,也就是高电平)。
        下面,将在NodeMcu的D1引脚上写一个LED Blink的Arduino草图:

    /**
     * LED灯闪烁实验
     */
    void setup() {
        pinMode(D1, OUTPUT);   // 初始化D1引脚为输出引脚
    }
     
    void loop() {
        digitalWrite(D1, LOW); // 亮灯
        delay(1000); // 延时1s
        digitalWrite(D1, HIGH);// 灭灯
        delay(1000); // 延时1s
    }
    

    注意

        某些开发板和模块,仍将使用第9和第11引脚(如果闪存芯片工作于DIO模式,与默认的QIO模式相反),它们可用于IO。

    5. 中断功能

        中断可以理解为在正常的运行流程中突然插入的操作,这就像你在忙于工作的时候,领导突然叫你去买个下午茶,然后你就去把下午茶买回来,再继续工作。基于ESP8266的NodeMcu的数字IO的中断功能是通过attachInterruptdetachInterrupt函数所支持的。除了D0/GPIO16,中断可以绑定到任意GPIO的引脚上。所支持的标准中断类型有:CHANGE(改变沿,电平从低到高或者从高到低)、RISING(上升沿,电平从低到高)、FALLING(下降沿,电平从高到低)。
        首先,我们来看看Arduino IDE中用于中断的函数。
        1.attachInterrupt()
        该功能用于在将指定引脚设置为响应中断。
        函数: attachInterrupt(pin, function, mode);
        参数:
            pin:要设置中断编号,注意,这里不是引脚编号。
            function:中断发生时运行的函数, 这个函数不带任何参数,不返回任何内容。
            Interrupt type/mode:它定义中断被触发的条件方式。
                CHANGE:改变沿,引脚电平从低变为高或者从高变为低时触发中断。
                RISING:上升沿,引脚电平从低变为高时触发中断。
                FALLING:下降沿,引脚电平从高变为低时触发中断。
        返回值: 无;

        2.detachInterrupt()
        该功能用于禁用指定GPIO引脚上的中断。
        函数: detachInterrupt(pin)
        参数:
            pin:要禁用的中断的GPIO引脚。
        返回值: 无;

        3.digitalPinToInterrupt()
        该功能用于获取指定GPIO引脚的中断号。
        函数: digitalPinToInterrupt(pin)
        参数:
            pin:要获取中断号的GPIO引脚。

    例子
        将NodeMcu的D2引脚设置为上升沿中断。在D2上外接一个按键,按键通过电阻下拉到地。当发生中断的时候,我们在串口监视器上打印“Hello ESP8266”。

    image

    例子代码

    /**
     * 功能描述:ESP8266中断演示
     */ 
    void setup() {
     Serial.begin(115200);//设置串口波特率
     attachInterrupt(digitalPinToInterrupt(D2), InterruptFunc, RISING);//设置中断号、响应函数、触发方式
    }
     
    void loop() {
    }
    
    /**
     * 中断响应函数
     */ 
    ICACHE_RAM_ATTR void InterruptFunc(){
     Serial.println("Hello ESP8266");
    }
    

    6. 模拟输入(ADC)

        学过模拟电路或者数字电路的人都会听过ADC,它又叫做模数转换器,用于将模拟信号转换成可视化的数字形式。ESP8266具有内置的10位ADC,只有一个ADC通道,即只有一个ADC输入引脚可读取来自外部器件的模拟电压。
        ESP8266上的ADC通道和芯片供电电压复用,也就是说我们可以将其设置为测量系统电压或者外部电压。

    6.1 测量外部电压

        相关方法
            analogRead(A0),用于读取施加在模块的ADC引脚上的外部电压;
        输入电压范围
            0 - 1.0V之间;
        测量精度
            由于ADC具有10位分辨率,因此会给出0-1023的值范围;
        注意点
            为了支持外部电压范围(0-3.3v),NodeMcu做了一个电阻分压器,如图所示:

    image

        例程
        编写一个读取NodeMcu的ADC引脚上的模拟电压。我们这里使用电位器在ADC引脚上提供0-3.3V的可变电压。如下图连接线:
    image
        代码如下:

    /**
     * 功能描述:ESP8266 ADC 读取外部电压
     * 在串口调试器查看效果
     */
    void setup() {
      Serial.begin(115200);//配置波特率
    }
     
    void loop() {
      Serial.print("ADC Value: ");
      Serial.println(analogRead(A0));//输出0-1023 对应 外部输入电压 0-1.0v
      //延时1s
      delay(1000);
    }
    

    6.2 测量系统电压

        相关方法
            ESP.getVcc(),读取NodeMCU模块的VCC电压,单位是mV;
        注意点
            ADC引脚必须保持悬空;在读取VCC电源电压之前,应更改ADC模式以读取系统电压。
    要ADC_MODE(mode)在#include行后面改变ADC模式。
    模式是ADC_TOUT(对于外部电压),ADC_VCC(对于系统电压)。默认情况下,它读取外部电压。
        例程
        编写ESP8266读取系统电压,代码如下:

    /**
     * 功能描述:ESP8266 ADC 读取系统电压
     * 在串口调试器查看效果
     */
    ADC_MODE(ADC_VCC);//设置ADC模式为读取系统电压
     
    void setup() {
      Serial.begin(115200);
    }
     
    void loop() {
      Serial.print("ESP8266当前系统电压(mV): ");
      Serial.println(ESP.getVcc());
      delay(1000);
    }
    

    7. 模拟输出(PWM)

        PWM(Pulse Width Modulation,脉宽调制),是在保持波的频率不变的同时改变脉宽的技术。当我们需要连续控制电压变化,实现呼吸灯或者电机转速的时候,就要用到PWM,如下图。
    image
        首先,我们来理解一下占空比。一个脉冲周期由一个ON周期(VCCC)和一个OFF周期(GND)组成。一段时间内ON周期占据脉冲周期的比例就叫做占空比。

    DutyCycle(percentage)=Ton/TotalPeriodX100

        例如,一个10ms的脉冲保持ON 2ms,那么根据公式,占空比是20%。

    注意点

        脉冲频率一般都是固定的,跟占空比没有关系。

    NodeMcu PWM引脚

        如下图,标注PWM引脚。

    image

        基本上数字IO都可以作为PWM复用引脚,除了D0。不过需要注意的是,D3尽量不用,它内部连接ESP8266 GPIO0。

    NodeMcu PWM有关Arduino函数

        1.analogWrite()
        该功能用于在指定的引脚上启用软件PWM。
        函数: analogWrite(pin,val)
        参数:
            pin:要启用软件PWM的GPIO引脚。
            val:数值,一般在0到PWMRANGE范围,默认PWMRANGE是1023。
        返回值: 无;
        注意点:
            analogWrite(pin, 0)用于禁用指定引脚上的PWM。
        2.analogWriteRange()
        该功能用于改变PWMRANGE数值。
        函数: analogWriteRange(new_range)
        参数:
            new_range:新的PWMRANGE数值。
        返回值: 无;
        注意点:
            可以理解为PWM精度范围。同样的PWM频率下,默认占空数值0-123。如果你改变PWMRANGE为2047,那么占空数值就变成0-2047。精度高了一倍。
        3.analogWriteFreq()
        该功能用于改变PWM频率。
        函数: analogWriteFreq(new_frequency)
        参数:
            new_frequency:新PWM频率,默认是1kHZ。
        返回值: 无;
        注意点:
            百度上很多资料都说PWM频率范围为1-1KHz。但是通过查看源码,如下:

    static uint16_t analogFreq = 1000;
    
    extern void __analogWriteFreq(uint32_t freq) {
      if (freq < 100) {
        analogFreq = 100;
      } else if (freq > 40000) {
        analogFreq = 40000;
      } else {
        analogFreq = freq;
      }
    }
    

        可以看出,Arduino For ESP8266的PWM频率范围应该是100Hz-40KHz

    PWM例程

        呼吸灯,LED灯明暗连续变化。代码如下:

    /**
     * 功能描述:ESP8266 PWM演示例程
     * @author 单片机菜鸟
     * @date 2018/10/25
     */
     
    #define PIN_LED D6
     
    void setup() {
      // 这里开始写初始化代码,只会执行一次
      pinMode(PIN_LED,OUTPUT);
      analogWrite(PIN_LED,0);
    }
    
    void loop() {
      //这里写运行代码,重复执行
      for(int val=0;val<1024;val++){
         //占空比不断增大  亮度渐亮
    	 analogWrite(PIN_LED,val);
    	 delay(2);
      }
      
      for(int val=1023;val>=0;val--){
         //占空比不断变小  亮度渐暗
    	 analogWrite(PIN_LED,1023);
    	 delay(2);
      }
    }
    

    8. 串口通信(Serial)

        ESP8266的串口通信与传统的Arduino设备完全一样。除了硬件FIFO(128字节用于TX和RX)之外,硬件串口还有额外的256字节的TX和RX缓存。发送和接收全都由中断驱动。当FIFO/缓存满时,write函数会阻塞工程代码的执行,等待空闲空间。当FIFO/缓存空时,read函数也会阻塞工程代码的执行,等待串口数据进来。
        NodeMcu上有两组串口,Serial和Serial1。
        Serial使用UART0,默认对应引脚是GPIO1(TX)和GPIO3(RX)。在Serial.begin执行之后,调用Serial.swap()可以将Serial重新映射到GPIO15(TX)和GPIO13(RX)。再次调用Serial.swap()将Serial重新映射回GPIO1和GPIO3。不过,一般情况下,默认就好。

    串口映射例程

    /**
     * 功能描述:ESP8266 Serial映射例程
     * @author 单片机菜鸟
     * @date 2018/10/25
     */
     
    void setup() {
      // 这里开始写初始化代码,只会执行一次
      Serial.begin(115200);
      Serial.println("GPIO1(TX),GPIO3(RX)");
      //调用映射方法
      Serial.swap();
      Serial.println("GPIO15(TX),GPIO13(RX)");
      //重新映射回来
      Serial.swap();
      Serial.println("GPIO1(TX),GPIO3(RX)");
    }
    
    void loop() {
      //这里写运行代码,重复执行
    }
    

        Serial1使用UART1,默认对应引脚是GPIO2(TX)。Serial1不能用于接收数据,因为它的RX引脚被用于flash芯片连接。要使用Serial1,请调用Serial.begin(baudrate)。代码如下:

    /**
     * 功能描述:ESP8266 串口例程
     * @author 单片机菜鸟
     * @date 2018/10/25
     */
     
    void setup() {
      // 这里开始写初始化代码,只会执行一次
      Serial.begin(115200);
      Serial.println("Hello Serial");
      Serial1.begin(115200);
      Serial1.println("Hello Serial1");
    }
    
    void loop() {
      //这里写运行代码,重复执行
    }
    

        如果不使用Serial1并且不映射串口,可以将UART0的TX映射到GPIO2,具体操作是:在Serial.begin()之后调用Serial.set_tx(2)或者直接调用Serial.begin(baud,config,mode,2)。
        默认情况下,当调用Serial.begin后,将禁用WiFi库的诊断输出。要想再次启动调试输出,请调用Serial.setDebugOutput(true)。要将调试输出映射到Serial1时,需要调用Serial1.setDebugOutput(true)。
        调用Serial.setRxBufferSize(size_t size)允许定义接收缓冲区的大小,默认值是256(缓冲区也是使用内存,意味着不能一味地去增大这个值)。
        Serial和Serial1对象都支持5,6,7,8个数据位,奇数(O)、偶数(E)和无(N)奇偶校验,以及1或者2个停止位。要设置所需的模式,请调用Serial.begin(baudrate, SERIAL_8N1), Serial.begin(baudrate, SERIAL_6E2)等。
        Serial和Serial1都实现了一种新方法用来获取当前的波特率设置。要获取当前的波特率,请调用Serial.baudRate(),Serial1.baudRate()。代码如下:

    /**
     * 功能描述:ESP8266 串口波特率例程
     * @author 单片机菜鸟
     * @date 2018/10/25
     */
     
    void setup() {
      // 这里开始写初始化代码,只会执行一次
      // 设置当前波特率为57600
      Serial.begin(57600);
      // 获取当前波特率
      int br = Serial.baudRate();
      // 将打印 "Serial is 57600 bps"
      Serial.printf("Serial is %d bps", br);
    }
    
    void loop() {
      //这里写运行代码,重复执行
    }
    

        Serial和Serial1都属于硬件串口(HardwareSerial)的实例,如果读者需要使用ESP8266 软件串口的功能,请参考以下库:https://github.com/plerup/espsoftwareserial。
        为了检测进入Serial的未知波特率的数据,可以调用Serial.detectBaudrate(time_t timeoutMillis)。这个方法尝试在timeoutMillis ms的时间内检测波特率,检测成功返回波特率,检测失败返回0。detectBaudrate()方法在Serial.begin()被调用之前调用(因为它不需要用到接收缓冲区或者串口配置),并且它不能检测数据位位数或者停止位。这个检测过程不会去改变数据的波特率,所以可以在检测成功之后,调用Serial.begin(detectedBaudrate)。

    串口用处

        一般来说,串口通信用在两个方面:
        1.与外围串口设备传输数据,比如蓝牙模块、Arduino等等;
        2.开发过程中用来调试代码,通过串口输出Debug信息了解程序运行信息。例程如下:

    /**
     * Demo1:
     *    statin模式下,创建一个连接到可接入点(wifi热点),并且打印IP地址
     * @author 单片机菜鸟
     * @date 2019/09/02
     */
    #include <ESP8266WiFi.h>
     
    #define AP_SSID "xxxxx" //这里改成你的wifi名字
    #define AP_PSW  "xxxxx"//这里改成你的wifi密码
    //以下三个定义为调试定义
    #define DebugBegin(baud_rate)    Serial.begin(baud_rate)
    #define DebugPrintln(message)    Serial.println(message)
    #define DebugPrint(message)    Serial.print(message)
     
    void setup(){
      //设置串口波特率,以便打印信息
      DebugBegin(115200);
      //延时2s 为了演示效果
      delay(2000);
      DebugPrintln("Setup start");
      //启动STA模式,并连接到wifi网络
      WiFi.begin(AP_SSID, AP_PSW);
     
      DebugPrint(String("Connecting to ")+AP_SSID);
      //判断网络状态是否连接上,没连接上就延时500ms,并且打出一个点,模拟连接过程
      //笔者扩展:加入网络一直都连不上 是否可以做个判断,由你们自己实现
      while (WiFi.status() != WL_CONNECTED){
        delay(500);
        DebugPrint(".");
      }
      DebugPrintln("");
     
      DebugPrint("Connected, IP address: ");
      //输出station IP地址,这里的IP地址由DHCP分配
      DebugPrintln(WiFi.localIP());
      DebugPrintln("Setup End");
    }
     
    void loop() {
    }
    

    9. 总结

        总体上讲,本章基础内容比较多,笔者介绍ESP8266在Arduino平台上的一些基础知识点,包括程序结构、NodeMcu端口映射、ESP8266 数字IO、PWM、ADC、串口通信等等。
    本章目的很简单,就是为了告诉读者,ESP8266到底给我们提供了什么可利用硬件资源,以方便我们项目开发。

    展开全文
  • ESP8266 WIFI串口通信模块应该是使用最广泛的一种WIFI模块之一了。为什么呢? 因为ESP8266模块是一款高性能的WIFI串口模块,可以不用知道太多WIFI相关知识就可以很好的上手。说白了,只是个WIFI转串口的设备,你...

    物联网,万物互联。这里涉及到的最基本的东西就是如何将所有的物联网设备连接在一起。最简单、最广泛使用的就是互联网。

    ESP8266 WIFI串口通信模块应该是使用最广泛的一种WIFI模块之一了。为什么呢?

    因为ESP8266模块是一款高性能的WIFI串口模块,可以不用知道太多WIFI相关知识就可以很好的上手。说白了,只是个WIFI转串口的设备,你只要知道串口怎么编程使用,就可以了,实现了所谓的透明传输。

    但是就是这么一个很常见的模块,网上很多的博客写的都是错的,或者都是很不详细的。

     

    模块名称:ESP8266 WIFI串口通信模块

    参考资料:ESP8266 WIFI串口通信模块官方资源ATK-ESP8266资源包(提取码: nhsh)

    知识储备:【STM32】串口通信基本原理(超基础、详细版)

    其他模块:USB转TTL模块

    项目下载链接:见本文文末

     

    WIFI模块的调试

    准备工作

    USB转TTL模块与ESP8266 WIFI模块的接线:

    现在市面上使用比较的ESP8266有两个版本,分别是官方的ESP8266(两排8引脚)、ATK-ESP8266(一排6引脚)。其实并没有太大的区别,只是将其中的一些引脚进行额外布局而已。

    如果是官方的ESP8266模块,接线方式如下:

    如果是ATK-ESP8266(正点原子)模块,接线方式如下:

    这六个引脚只需要4个就行了:RXD、TXD、GND、VCC,分别和USB转TTL模块的TXD、RXD、GND、VCC相连接就行了。

    需要注意两点:

    1、ESP8266的RXD(数据的接收端)需要连接USB转TTL模块的TXD,TXD(数据的发送端)需要连接USB转TTL模块的RXD,这是基本的;

    2、关于VCC的选取,在USB转TTL模块上有3.3V和5V两个引脚可以作为VCC,但是一般选取5V作为VCC。如果选取3.3V,可能会因为供电不足而引起不断的重启,从而不停的复位。

    AT指令

    在使用USB转TTL模块与电脑连接之后,就可以使用串口调试助手进行WIFI模块的调试了。首先有一点,AT指令不区分大小写,均以回车、换行结尾。下面介绍常用的AT指令:

    常用AT指令
    指令名 响应 含义
    AT OK 测试指令
    AT+CWMODE=<mode> OK 设置应用模式(需重启生效)
    AT+CWMODE? +CWMODE:<mode> 获得当前应用模式
    AT+CWLAP +CWLAP:<ecn>,<ssid>,<rssi> 返回目前的AP列表
    AT+CWJAP=<ssid>,<pwd> OK 加入某一AP
    AT+CWJAP? +CWJAP:<ssid> 返回当前加入的AP
    AT+CWQAP OK 退出当前加入的AP
    AT+CIPSTART=<type>,<addr>,<port> OK 建立TCP/UDP连接
    AT+CIPMUX=<mode> OK 是否启用多连接
    AT+CIPSEND=<param> OK 发送数据
    AT+CIPMODE=<mode> OK 是否进入透传模式

    需要补充几点:

    1、ESP8266的应用模式:ESP266支撑单AP模式、单STA模式和混合模式。简单的来说就是:

    • AP:可以将ESP8266作为热点,可以让其他的设备连接上它;
    • STA:可以连接上当前环境下的WIFI热点。

    2、什么是透传模式?

    透传就是指不需要关心wifi协议是如何实现的。所需要做的就是A通过串口发数据,B通过串口收数据,整个过程中A串口和B串口就像是用导线直接连接起来了一样。则对于开发人员来看,就是完全透明的。

    更简单地理解就是:

    如果不开启透传模式,我们怎么发送数据呢?在每次发送数据前都必须先发送指令AT+CIPSEND=<param>,例如:

    AT+CIPSEND=4
    
    OK
    >                //在 > 后面输入要上传的数据

    但是一旦开启了透传模式,我们就不需要在每次发送数据前都发送指令AT+CIPSEND=<param>了,只需要发送一次AT+CIPSEND,之后发送的所有内容全部当成是数据了!

    但是这也存在一个问题,要是我后来又想发送命令了,但是却也当成是数据发送过去了。这可怎么办?

    这就要退出透传模式了。怎么退出,发送数据"+++"就可以了。注意:此时“+++”后面,不接“发送新行”!

     

    WIFI模块的使用

    ESP8266的一般使用顺序

    这里的“一般”指的是:ESP8266连接当前环境的热点,与服务器建立TCP连接,传输数据。

    1. AT+CWMODE=1:设置工作模式(STA模式)
    2. AT+RST:模块重启(生效工作模式)
    3. AT+CWJAP="111","11111111":连接当前环境的WIFI热点(热点名,密码)
    4. AT+CIPMUX=0:设置单路连接模式
    5. AT+CIPSTART="TCP","xxx.xxx.xxx.xxx",xxxx:建立TCP连接
    6. AT+CIPMODE=1:开启透传模式
    7. AT+CIPSEND:透传模式下,传输数据
    8. +++:退出透传模式

    ESP8266的封装代码

    关于与单片机的引脚连接:ESP8266与USART3(引脚PB10、PB11)连接。

    首先是USART的配置:

    #include "delay.h"
    #include "usart3.h"
    #include "stdarg.h"	 	 
    #include "stdio.h"	 	 
    #include "string.h"	 
    #include "timer.h" 
    
    //串口接收缓存区 	
    u8 USART3_RX_BUF[USART3_MAX_RECV_LEN]; 				//接收缓冲,最大USART3_MAX_RECV_LEN个字节.
    u8  USART3_TX_BUF[USART3_MAX_SEND_LEN]; 			//发送缓冲,最大USART3_MAX_SEND_LEN字节
    
    //通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据.
    //如果2个字符接收间隔超过10ms,则认为不是1次连续数据.也就是超过10ms没有接收到
    //任何数据,则表示此次接收完毕.
    //接收到的数据状态
    //[15]:0,没有接收到数据;1,接收到了一批数据.
    //[14:0]:接收到的数据长度
    vu16 USART3_RX_STA=0;   	
    
    
    void USART3_IRQHandler(void)
    {
    	u8 res;	      
    	if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)//接收到数据
    	{	 
    		res =USART_ReceiveData(USART3);		 
    		if((USART3_RX_STA&(1<<15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据
    		{ 
    			if(USART3_RX_STA<USART3_MAX_RECV_LEN)	//还可以接收数据
    			{
    				TIM_SetCounter(TIM7,0);//计数器清空          				//计数器清空
    				if(USART3_RX_STA==0) 				//使能定时器7的中断 
    				{
    					TIM_Cmd(TIM7,ENABLE);//使能定时器7
    				}
    				USART3_RX_BUF[USART3_RX_STA++]=res;	//记录接收到的值	 
    			}else 
    			{
    				USART3_RX_STA|=1<<15;				//强制标记接收完成
    			} 
    		}
    	}  				 											 
    }   
    
    
    //初始化IO 串口3
    //pclk1:PCLK1时钟频率(Mhz)
    //bound:波特率	  
    void usart3_init(u32 bound)
    {  
    
    	NVIC_InitTypeDef NVIC_InitStructure;
    	GPIO_InitTypeDef GPIO_InitStructure;
    	USART_InitTypeDef USART_InitStructure;
    
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	// GPIOB时钟
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口3时钟使能
    
     	USART_DeInit(USART3);  //复位串口3
    		 //USART3_TX   PB10
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
      GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB10
       
        //USART3_RX	  PB11
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
      GPIO_Init(GPIOB, &GPIO_InitStructure);  //初始化PB11
    	
    	USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;
    	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
      
    	USART_Init(USART3, &USART_InitStructure); //初始化串口	3
      
    
    	USART_Cmd(USART3, ENABLE);                    //使能串口 
    	
    	//使能接收中断
      USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断   
    	
    	//设置中断优先级
    	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
    	
    	
    	TIM7_Int_Init(1000-1,7200-1);		//10ms中断
    	USART3_RX_STA=0;		//清零
    	TIM_Cmd(TIM7,DISABLE);			//关闭定时器7
    
    }
    
    //串口3,printf 函数
    //确保一次发送数据不超过USART3_MAX_SEND_LEN字节
    void u3_printf(char* fmt,...)  
    {  
    	u16 i,j; 
    	va_list ap; 
    	va_start(ap,fmt);
    	vsprintf((char*)USART3_TX_BUF,fmt,ap);
    	va_end(ap);
    	i=strlen((const char*)USART3_TX_BUF);		//此次发送数据的长度
    	for(j=0;j<i;j++)							//循环发送数据
    	{
    	  while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕   
    		USART_SendData(USART3,USART3_TX_BUF[j]); 
    	} 
    }

    由于在USART3中是通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据,而10ms怎么定呢?通过定时器来的,所以我们需要开启定时器:

    #include "timer.h"
    
    extern vu16 USART3_RX_STA;
    
    //定时器7中断服务程序		    
    void TIM7_IRQHandler(void)
    { 	
    	if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET)//是更新中断
    	{	 			   
    		USART3_RX_STA|=1<<15;	//标记接收完成
    		TIM_ClearITPendingBit(TIM7, TIM_IT_Update  );  //清除TIM7更新中断标志    
    		TIM_Cmd(TIM7, DISABLE);  //关闭TIM7 
    	}	    
    }
     
    //通用定时器7中断初始化,这里时钟选择为APB1的2倍
    //arr:自动重装值 psc:时钟预分频数
    //定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
    //Ft=定时器工作频率,单位:Mhz 
    //通用定时器中断初始化 
    void TIM7_Int_Init(u16 arr,u16 psc)
    {	
    	NVIC_InitTypeDef NVIC_InitStructure;
    	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);//TIM7时钟使能    
    	
    	//定时器TIM7初始化
    	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
    	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    	TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
     
    	TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE ); //使能指定的TIM7中断,允许更新中断
    	
    	TIM_Cmd(TIM7,ENABLE);//开启定时器7
    	
    	NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		//子优先级2
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
    	
    }

    这两个都完成了之后,就可以向ESP8266传输数据了:

    #include "esp8266.h"
    #include "string.h"
    #include "usart.h"
    #include "usart3.h"
    #include "stm32f10x.h"
    #include "sys.h" 
    #include "delay.h"
    
    //ESP8266模块和PC进入透传模式
    void esp8266_start_trans(void)
    {
    	//设置工作模式 1:station模式   2:AP模式  3:兼容 AP+station模式
    	esp8266_send_cmd("AT+CWMODE=1","OK",50);
    	
    	//让Wifi模块重启的命令
    	esp8266_send_cmd("AT+RST","ready",20);
    	
    	delay_ms(1000);         //延时3S等待重启成功
    	delay_ms(1000);
    	delay_ms(1000);
    	delay_ms(1000);
    	
    	//让模块连接上自己的路由
    	while(esp8266_send_cmd("AT+CWJAP=\"111\",\"11111111\"","WIFI GOT IP",600));
    	
    	//=0:单路连接模式     =1:多路连接模式
    	esp8266_send_cmd("AT+CIPMUX=0","OK",20);
    	
    	//建立TCP连接  这四项分别代表了 要连接的ID号0~4   连接类型  远程服务器IP地址   远程服务器端口号
    	while(esp8266_send_cmd("AT+CIPSTART=\"TCP\",\"xxx.xxx.xxx.xxx\",xxxx","CONNECT",200));
    	
    	//是否开启透传模式  0:表示关闭 1:表示开启透传
    	esp8266_send_cmd("AT+CIPMODE=1","OK",200);
    	
    	//透传模式下 开始发送数据的指令 这个指令之后就可以直接发数据了
    	esp8266_send_cmd("AT+CIPSEND","OK",50);
    }
    
    //ESP8266退出透传模式   返回值:0,退出成功;1,退出失败
    //配置wifi模块,通过想wifi模块连续发送3个+(每个+号之间 超过10ms,这样认为是连续三次发送+)
    u8 esp8266_quit_trans(void)
    {
    	u8 result=1;
    	u3_printf("+++");
    	delay_ms(1000);					//等待500ms太少 要1000ms才可以退出
    	result=esp8266_send_cmd("AT","OK",20);//退出透传判断.
    	if(result)
    		printf("quit_trans failed!");
    	else
    		printf("quit_trans success!");
    	return result;
    }
    
    
    //向ESP8266发送命令
    //cmd:发送的命令字符串;ack:期待的应答结果,如果为空,则表示不需要等待应答;waittime:等待时间(单位:10ms)
    //返回值:0,发送成功(得到了期待的应答结果);1,发送失败
    u8 esp8266_send_cmd(u8 *cmd,u8 *ack,u16 waittime)
    {
    	u8 res=0; 
    	USART3_RX_STA=0;
    	u3_printf("%s\r\n",cmd);	//发送命令
    	if(ack&&waittime)		//需要等待应答
    	{
    		while(--waittime)	//等待倒计时
    		{
    			delay_ms(10);
    			if(USART3_RX_STA&0X8000)//接收到期待的应答结果
    			{
    				if(esp8266_check_cmd(ack))
    				{
    					printf("ack:%s\r\n",(u8*)ack);
    					break;//得到有效数据 
    				}
    					USART3_RX_STA=0;
    			} 
    		}
    		if(waittime==0)res=1; 
    	}
    	return res;
    } 
    
    
    //ESP8266发送命令后,检测接收到的应答
    //str:期待的应答结果
    //返回值:0,没有得到期待的应答结果;其他,期待应答结果的位置(str的位置)
    u8* esp8266_check_cmd(u8 *str)
    {
    	char *strx=0;
    	if(USART3_RX_STA&0X8000)		//接收到一次数据了
    	{ 
    		USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
    		strx=strstr((const char*)USART3_RX_BUF,(const char*)str);
    	} 
    	return (u8*)strx;
    }
    
    //向ESP8266发送数据
    //cmd:发送的命令字符串;waittime:等待时间(单位:10ms)
    //返回值:发送数据后,服务器的返回验证码
    u8* esp8266_send_data(u8 *cmd,u16 waittime)
    {
    	char temp[5];
    	char *ack=temp;
    	USART3_RX_STA=0;
    	u3_printf("%s",cmd);	//发送命令
    	if(waittime)		//需要等待应答
    	{
    		while(--waittime)	//等待倒计时
    		{
    			delay_ms(10);
    			if(USART3_RX_STA&0X8000)//接收到期待的应答结果
    			{
    				USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
    				ack=(char*)USART3_RX_BUF;
    				printf("ack:%s\r\n",(u8*)ack);
    				USART3_RX_STA=0;
    				break;//得到有效数据 
    			} 
    		}
    	}
    	return (u8*)ack;
    } 

    最后是主程序:

    #include "delay.h"
    #include "sys.h"
    #include "usart.h"
    #include "usart3.h"
    #include "esp8266.h"
    #include "string.h"
    #include "timer.h"
     
    /*
    项目的主要内容:STM32配合ESP8266模块与服务器数据交互
    
    ESP8266的连接:USART3(PB10、PB11)
    
    如何判断数据接收完全?
    1、出现了换行符;
    2、如果超过10ms了都没有下一条数据(TIM7来进行10ms的定时)。
    */
    
    
     int main(void)
     {		
    	delay_init();	    	 			//延时函数初始化	  
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 			//设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    	uart_init(115200);	 				//串口初始化为115200
    	usart3_init(115200);	 				//串口初始化为115200
    
    	esp8266_start_trans();							//esp8266进行初始化
    	 
    	esp8266_send_data("12",50);
    	 
    	esp8266_quit_trans();
    
     	while(1)
    	{
    		
    	}
     }

    完整项目链接:

    百度云盘链接: https://pan.baidu.com/s/1LKjJL06fHyt1O5p9Jxmbig 提取码: p8yn 

    展开全文
  • 智能家居简单实现---使用ESP8266简单实现和APP通讯

    万次阅读 多人点赞 2019-01-09 19:59:28
    前段时间,公司利用 ESP8266 这个WiFi模块,做了好多小产品。从手机 APP 直连这个 ESP8266 进行通讯,再到实现远程控制。中间实现过程磕磕碰碰,虽然这方面已经做得非常成熟,但是网上的资料少之又少。现在把实现...

    前段时间,公司利用 ESP8266 这个WiFi模块,做了好多小产品。从手机 APP 直连这个 ESP8266 进行通讯,再到实现远程控制。中间实现过程磕磕碰碰,虽然这方面已经做得非常成熟,但是网上的资料少之又少。现在把实现方式展示出来,同时也算是做一个笔记。

    首先这里要实现的是Android端的APP直连ESP8266进行双向通讯。

    如果想了解Android端的APP远程连接与ESP8266进行双向通信的,实现真正的智能家居,可以参与这场Chat:智能家居远程控制,实现APP与ESP8266远程通信

    首先我们来说一下这个ESP8266,这个在淘宝上非常便宜,10块左右,安信可的产品。这个WiFi模块已经做得非常的成熟,下面介绍一下它的基本使用,首先这个模块有三种模式:
    1:STA 模式:ESP8266模块通过路由器连接互联网,手机或电脑通过互联网实现对设备的远程控制。
    2:AP 模式:ESP8266模块作为热点,实现手机或电脑直接与模块通信,实现局域网无线控制。
    3:STA+AP 模式:两种模式的共存模式,即可以通过互联网控制可实现无缝切换,方便操作。

    今天的实现用AP模式就够了,指令有下面这几个就够了:
    1、设置wifi模式:AT+CWMODE=2
    2、重启生效:AT+RST
    3、启动多连接:AT+CIPMUX=1
    4、建立server:AT+CIPSERVER=1

    另外还有非常多的指令可以修改这个模块的参数,甚至还可以修改里面的程序重新烧录,更多的详情就参考安信可的官网。这个就需要电子比较厉害的人才会适合了,我是Android开发的,所以这方面不太了解,还望海涵。

    这是设备:

     

    接下来通过串口发送指令开启ESP8266的WiFi:


     

    发送完这四个指令之后,打开手机就可以看到相应的WiFi开启了(这个WiFi名给我改过):

     

    好了,硬件准备完毕,接下来我们准备APP软件,针对Android端的。新建一个Android项目,项目结构:

    添加一个异步处理类:

     

    /**
     * Created by Layne_Yao on 2017/5/12.
     * CSDN:http://blog.csdn.net/Jsagacity
     */
    
    public class SendAsyncTask extends AsyncTask<String, Void, Void> {
    	
    	//这里是连接ESP8266的IP和端口号,IP是通过指令在单片机开发板查询到,而端口号可以自行设置,也可以使用默认的,333就是默认的
    	private static final String IP = "192.168.4.1";
    	private static final int PORT = 333;
    
    
    
    	private Socket client = null;
    	private PrintStream out = null;
    
    
    	@Override
    	protected Void doInBackground(String... params) {
    		String str = params[0];
    		try {
    			client = new Socket(IP, PORT);
    			client.setSoTimeout(5000);
    			// 获取Socket的输出流,用来发送数据到服务端
    			out = new PrintStream(client.getOutputStream());
    			out.print(str);
    			out.flush();
    
    			if (client == null) {
    				return null;
    			} else {
    				out.close();
    				client.close();
    			}
    
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    
    		return null;
    	}
    	
    }


    在手机端建立一个作为接受ESP8266发送的消息的服务器:

     

    public class MobileServer implements Runnable {
    	private ServerSocket server;
    	private DataInputStream in;
    	private byte[] receice;
    
    	private Handler handler = new Handler();
    
    	public MobileServer() {
    	}
    
    	public void setHandler(Handler handler) {
    		this.handler = handler;
    	}
    
    	@Override
    	public void run() {
    
    		try {
    			//5000是手机端开启的服务器的端口号,ESP8266进行TCP连接时使用的端口,而IP也是通过指令查询的联入设备的IP
    			server = new ServerSocket(5000);
    			while (true) {
    				Socket client = server.accept();
    				in = new DataInputStream(client.getInputStream());
    				receice = new byte[50];
    				in.read(receice);
    				in.close();
    				
    				Message message = new Message();
    				message.what = 1;
    				message.obj = new String(receice);
    				handler.sendMessage(message);
    			}
    
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		try {
    			server.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }


    布局文件:

     

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.itman.connectesp8266.MainActivity" >
    
        <TextView
            android:id="@+id/tv_content"
            android:layout_width="match_parent"
            android:layout_height="25dp"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="10dp"
            android:background="#fe9920"
            android:gravity="center"
            android:text="接收的内容" />
    
        <Button
            android:id="@+id/bt_send"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/tv_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="40dp"
            android:text="发送" />
    
        <TextView
            android:id="@+id/tv_send_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/bt_send"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="33dp"
            android:text="发送的内容" />
    
    </RelativeLayout>


    最后是MainActivity:

    public class MainActivity extends ActionBarActivity implements OnClickListener {
    	private TextView tv_content, tv_send_text;
    	private Button bt_send;
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    
    		InitView();
    
    		//开启服务器
    		MobileServer mobileServer = new MobileServer();
    		mobileServer.setHandler(handler);
    		new Thread(mobileServer).start();
    
    	}
    
    	private void InitView() {
    		tv_content = (TextView) findViewById(R.id.tv_content);
    		tv_send_text = (TextView) findViewById(R.id.tv_send_text);
    		bt_send = (Button) findViewById(R.id.bt_send);
    
    		bt_send.setOnClickListener(this);
    
    	}
    
    	@Override
    	public void onClick(View v) {
    		switch (v.getId()) {
    		case R.id.bt_send:
    			String str = "Sent to the ESP8266";
    			new SendAsyncTask().execute(str);
    			tv_send_text.setText(str);
    			break;
    		}
    
    	}
    
    	Handler handler = new Handler() {
    		@Override
    		public void handleMessage(Message msg) {
    			switch (msg.what) {
    			case 1:
    				tv_content.setText("WiFi模块发送的:" + msg.obj);
    				Toast.makeText(MainActivity.this, "接收到信息", Toast.LENGTH_LONG)
    						.show();
    			}
    		}
    	};
    
    }


    最后不要忘了添加网路权限:

    <uses-permission android:name="android.permission.INTERNET"/>


    运行到真机,确保手机连接上ESP8266的WiFi,就可以进行手机发送信息到ESP8266了。手机APP发送过去的:

     

     

    ESP8266接收到的:

     

     

    接下来是ESP8266发送数据到APP。首先ESP要使用到的指令有:

    1、建立TCP连接:AT+CIPSTART=0,"TCP","192.168.4.2",5000
    2、确定发送数据的长度:AT+CIPSEND=0,19
    3、发送信息:Sent to the Android

    操作指令:

     

    APP端接受到的信息:

     

    以上是简单的实现APP和ESP8266直连通讯的实现。

     

    如果想要实现远程控制,过程是比较繁杂的,但是并不复杂。

    这里只简单的说明一下大致的实现方式:

    1、要实现远程控制就必须得租用一个服务器,当然自己电脑也可以作为服务器,就是需要配置。最简单的方式是租用云服务器,比如阿里云的ECS,如果是学生,还有学生价。

    2、接下来是最麻烦的步骤:

    1)手机发数据到云服务器,这个不用多说了,使用json数据的网络通信;

    2)接着就是云服务器继续把手机发送过来的转发的ESP8266,而云服务器和ESP8266之间的通讯是需要使用TCP长连接的。因为ESP8266这边的IP是会变化的所以只能使用长连接;

    3)ESP8266发数据到云服务器就不用再多说了,就第2点中的长连接。但是云服务器怎么推送数据到APP呢?答案也是长连接的,这里可以使用别人集成好的框架mina。

    以上就是远程控制的大致过程要点,想要实现就各自去完成了。当初我还是在别的平台问人问到的实现方案,网上根本没有相应的资料,或者是方案。以上的实现方案虽然有点繁杂,但是并不复杂,慢慢实现是没有很大难度的。

    如果想直接学习并实现的,可以参与这场Chat:智能家居远程控制,实现APP与ESP8266远程通信

    如果是想学习Android开发基础的,可以看一下这篇文章:简单的入门Android开发基础

                                                                    

    关注个人公众号「技术人的日常」,关注后回复:安卓基础,即可获取Android基础入门学习资料。

    展开全文
  • ESP8266系列WIFI模块的使用·

    万次阅读 多人点赞 2018-06-07 21:10:43
    一、概述ESP8266是由乐鑫公司出品的一款物联网芯片,因为价格较低,性能稳定等收到很大关注。该芯片可工作于三种种模式下,分别是:AP模式,station模式以及混合模式,通过常用的AT指令进行控制。自芯片面世以来发行...

    一、概述

    ESP8266是由乐鑫公司出品的一款物联网芯片,因为价格较低,性能稳定等收到很大关注。该芯片可工作于三种种模式下,分别是:AP模式,station模式以及混合模式,通过常用的AT指令进行控制。自芯片面世以来发行过多种型号。单单我用过的就有ESP8266-01,ESP8266-12F,ESP8266-12E这三种。当然,我没接触到过的型号还有很多。在使用这三种芯片时均是使其工作在AP模式下。所以,就拿这三个型号说一下ESP8266在AP模式下的配置吧(AP模式下通信协议为TCP,也就是说AP模式下的ESP8266相当于一个TCP服务器)。

    二、ESP8266-01

    因为ESP8266-01是比较早的型号,所以也存在诸多不完善的地方。一开始用的时候也走过很多弯路,例如:ESP8266-01型号不支持1200及2400的波特率(网上的资料说是支持的),就因为这个原因就玩坏了三块芯片,将近100人民币就打水漂了(幸亏指导老师还安慰我,学习的过程就是消耗的过程),一开始不知道什么原因,后来才发现是波特率的问题。因为一开始的测试用的普中V3.0的学习版,该板搭载的是12.0Mhz的晶振,而且身边也没有可以换的11.0592Mhz的晶振,没办法才选择了2400的波特率,最终导致三块ESP8266-01坏掉。而且坏掉后上电就出现乱码,这些乱码用“格西烽火串口助手”中的所有波特率都读不出来所以一旦出问题无法修复。另外,该芯片对电压要求出奇的高,标准3.3V,一点小的电压波动都会引起模块工作异常。网上曾有一种说法,“十个不能正常工作的芯片中就有八个是电压问题引起的”。(ESP8266-01的接线图如下)


    三、ESP8266-12F

    ESP8266-12F相比于ESP8266-01有很多改进。首先12F的flash闪存比较大,另外12F支持机智云的MCU运行。当然,与增加的功能相适应,12F增加了很多IO口,一般是16个。但工作在AP模式下,二者并没有本质区别。但是12F有一个缺点就是需要自己搭建一些简单的外围电路。(接线图如下)

    四、ESP8266-01与ESP8266-12F工作在AP模式下的配置命令。

    1.基本配置命令:

    AT+CIOBAUD=******//修改波特率为********(模块初始波特率默认为115200,该命令通过串口助手发送,重新上电后有效)

    AT+CWMODE=2//设置模块为AP模式

    AT+CWSAP="111","222",11,0//设置wifi名字为111,密码是222,通道号是11,加密方式是OPEN(可以修改)

    AT+CIPMUX=1//启动多路连接方式(可以修改)

    AT+CIPSERVER=1,5000//开启server,端口号为5000(可以修改)

    AT+CIPSEND=0,5//向id为0的链接发送5字节数据(可以修改)

    2.单片机控制程序:单片机型号为STC89C52RC,晶振11.0592MHz,波特率为9600(控制程序均为自己编写且测试有效)

    #include<reg51.h>


    void Serial_Inti();//初始化程序(必须使用,否则无法收发)

    void Uart_Sends(unsigned char *str);//发送char型字符串

    //void Delay1ms(unsigned int t);//1ms延时函数

    unsigned char Uart_Receive();//接收字符子函数

    void Uart_Dat(unsigned char dat);//数据发送子函数

    void Wifi_Init();//wifi模块初始化

    void Uart_Byte(char byte);//字节发送子函数

    void Delay1ms(unsigned int t);//t ms延时子函数


    /*串口初始化子函数*/

    void Serial_Inti()//串口初始化,一定注意不要启动T1的串口中断

    {

        TMOD = 0x20;

        SCON = 0x50;

        TH1 = 0xFD;

        TL1 = TH1;

        PCON = 0x00;

    ES=0;//关闭串口中断

        TR1 = 1;

    }



    /*字符串发送子函数(用于配置)*/

    void Uart_Sends(unsigned char *str)

    {

    while(*str!='\0')

    {

    SBUF=*str;

    while(!TI);//等待发送完成信号(TI=1)出现

    TI=0;//清除发送中断标志位以继续发送

    str++;

    }

    }



    /*WIFI模块初始化*/

    void Wifi_Init()

    {

    Delay1ms(3000);

    Serial_Inti();

    Uart_Sends("AT+CWMODE=2\r\n");

    Delay1ms(2000);

    Uart_Sends("AT+CWSAP=\"******\",\"*****\",11,0\r\n");//wifi名称及密码设置

    Delay1ms(2000);

    Uart_Sends("AT+CIPMUX=1\r\n");

    Delay1ms(2000);

    Uart_Sends("AT+CIPSERVER=1,5000\r\n");

    }



    /*字节发送子函数*/

    void Uart_Byte(char byte)

    {

    SBUF=byte;

    while(!TI);

    TI=0;

    }



    /*数据发送子函数*/

    void Uart_Dat(unsigned char dat)

    {

    Uart_Sends("AT+CIPSEND=0,1\r\n");

    Delay1ms(1000);

    Uart_Byte(dat);

    Uart_Byte('\r');

    Uart_Byte('\n');

    Delay1ms(100);//延时100ms防止出现循环发送现象

    }



    /*指令接收子函数*/

    unsigned char Uart_Receive()

    {

    unsigned char order;

    RI=0;//先将接收表示位置0,防止wifi'配置使的返回信息将其置1

    while(!RI);//等待接收到信息后跳出循环

    order=SBUF;//当RI==1时接收到数据

    RI=0;//清除接收中断标志位以继续接收

    return order;

    }

    void Delay1ms(unsigned int t)   //误差 0us

    {

        unsigned char a,b,c;

    for(t;t>0;t--)

        for(c=1;c>0;c--)

            for(b=142;b>0;b--)

                for(a=2;a>0;a--);

    }


    五、ESP8266-12E CP2102

    刚开始使用ESP8266-12E CP2102时很蒙,因为焊接在CP2102板上之后原来的操作方式就不再适用。经过摸索发现了一个比较合适的而且好用的固件ESP8266_Doit_ser2net(v2.4).bin。所以方向很明确,要给12E刷新固件。首先ESP8266-12E CP2102长这样:

    用USB线连接PC,下载工具为flash_download_tool_v1.2_150512.exe,选择ESP8266_Doit_ser2net(v2.4).bin,下载地址为0x00000,按住Falsh键不放,然后按Reset键,使芯片进入下载模式,点击软件上的START开始下载,下载完成后重新上电。(如下图)

    下载成功重新上电后就会发现这个固件的好处。连接wifi访问192.168.4.1就会出现以下界面

    在该界面可以直接设置芯片的波特率以及AP模式下的配置,省去了麻烦的AT命令。所以,ESP8266-12E CP2102是我目前为止用到的最好用的ESP8266系列模块。

    当然,我所涉及到的只是ESP8266的冰山一角,期待以后更加深入的学习!


    左肩理想,右肩担当。君子不怨永远不会停下脚步!



    展开全文
  • 史上最简单的开发ESP8266物联网小项目的方法

    万次阅读 多人点赞 2019-01-10 18:30:06
     自己学习ESP8266好久了,从AT指令集到SDK到lua开发也都学习了很多方法。想要切实的完成一个物联网作品大致需要几部分:MCU控制程序+ESP8266开发+服务器选择搭建+app程序设计  对于和我一样的小白而言,可能只对...
  • ESP8266:NodeMCU WiFi OLED:1.3’ 控制芯片:SH1106 软件准备 Arduino IDE U8g2lib 连线 GND - 地 VCC - 3.3v OLED SCK - GPIO 14 (NodeMCU D5) OLED MOSI - GPIO 13(NodeMCU D7) OLED CS - GPIO 15 (NodeMCU ...
  • AT+CUSTOTA=total_len,current_packet_len,offset,checksum OK MCU 收到 > 之后发送 data,当前数据写入到 FLASH 之后,打印 RECV OK,当接收到 total_len 所有数据之后,如果校验成功会打印 CUSTOTA OK,否则...
  • 1、 Esp8266之 搭建开发环境,开始一个“hellow world”串口打印。 2、 Esp8266之 利用GPIO开始使用按钮点亮你的“第一盏灯”。 3、 Esp8266之 利用 “软件定时器 ” 定时0.5秒闪烁点亮一盏LED。 4 、Es...
  • ESP HTTPS OTA用法

    2019-04-28 16:01:55
    esp_https_ota 提供简易的API通过HTTPS对固件进行升级。...esp_err_t do_firmware_upgrade() { esp_http_client_config_t config = { .url = CONFIG_FIRMWARE_UPGRADE_URL, .cert_pem = (char ...
  • 1、 Esp8266之 搭建开发环境,开始一个“hellow world”串口打印。 2、 Esp8266之 利用GPIO开始使用按钮点亮你的“第一盏灯”。 3、 Esp8266之 利用 “软件定时器 ” 定时0.5秒闪烁点亮一盏LED。 4 、Esp8266之 ...
  • ESP8266简介:三种编程方式

    万次阅读 多人点赞 2019-04-22 15:21:25
    想要玩转智能家居,就离不开互联网,今天给大家介绍一款模块——ESP8266。小编将手把手教大家利用8266实现家电的控制。 ESP8266 可以用来做串口透传,PWM 调控,远程控制开关:控制插座、开关、电器等。该模块有三种...
  • 1、 Esp8266之 搭建开发环境,开始一个“hellow world”串口打印。 2、 Esp8266之 利用GPIO开始使用按钮点亮你的“第一盏灯”。 3、 Esp8266之 利用 “软件定时器 ” 定时0.5秒闪烁点亮一盏LED。 4 、Esp8266之 ...
  • 硬件:51单片机开发板、ESP8266无线模块(ESP8266-01)、TTL-USB串口、杜邦线、数据线; 软件:keil uv4单片机软件、STC-ISP烧录软件、串口调试助手:SSCOM或ATK-XCOM、TCP/UDP调试助手:SocketTool或网络调试助手...
  • ESP8266系列原理图和封装

    万次阅读 2018-04-19 09:48:30
    ESP8266系列原理图和封装
  • ESP8266(一)---引脚定义&接线说明

    万次阅读 2018-11-07 17:48:38
    一、引脚定义: Function Description URXD UART_RXD,接收 UTXD UART_TXD,发送 RST 外部Reset信号,低电平复位,高电平工作(默认高) GND GND ...下拉:UARTDownload,...
  • ESP8266 AT指令设置及51单片机的控制

    万次阅读 多人点赞 2020-09-09 08:39:23
    ESP8266 AT指令设置及51单片机的控制 (献给正在学习路上的兄弟姐妹们) 对于ESP8266模块好多刚接触的朋友们第一感觉就是价格的确很便宜,然而初次接触它时你也许会对它束手无策,因为关于怎样使用它,官方给出的...
  • ESP8266开发之旅 基础篇① 走进ESP8266的世界

    万次阅读 多人点赞 2020-10-16 13:57:32
        欢迎大家来到ESP8266的世界,从现在开始,笔者将带领大家慢慢揭开ESP8266神秘的面纱。 1. 简介     从笔者的角度来说,ESP8266这个词可以理解为ESP8266EX芯片(当然,后面也有可能出现了其他芯片,...
  • ESP8266 PIN与GPIO引脚对应关系

    万次阅读 2018-10-29 02:22:07
    例如:lua程序中的pin5对应D5,D5对应GPIO14 pin2对应D2,D2对应GPIO4
  • ESP8266烧录固件

    千次阅读 2019-01-10 18:32:45
    ESP 烧录固件 1、下载工具 https://wiki.ai-thinker.com/esp_download 2、硬件连接 出现上面信息就说明模块正常。...D:\ESP8266\workspace\sample\ESP8266_NONOS_SDK-2.2.0_tcpclient\bi...
  • 打开arduino 打开file ->... 将这个链接http://arduino.esp8266.com/stable/package_esp8266com_index.json填入’Additional Boards Manager URls’中 打开tool->board->boards manage,在其...
1 2 3 4 5 ... 20
收藏数 11,683
精华内容 4,673
关键字:

esp8266