补充前言、固件下载错误进行擦除:
参考:【一起玩esp8266】flash的擦除方法——专治疑难杂症
【ESP8266】安装esptool.py - MicroPython开源版块 - 电子工程世界-论坛
8266烧录固件的ESP FLASH DOWNLOAD TOOL,但是这个工具只能向8266写入固件程序,无法对flash进行擦除操作,因而可能会由于某些原因造成烧录的固件运行不正常。使用esptool.py(一个Python程序,需在Python2环境下运行)。
ESPtool.py是一个python开发的针对ESP8266的小工具,可以实现底层的操作,弥补ESP8266官方工具的不足。flash的小工具,可以弥补ESP8266官方工具的不足。它也是一个开源项目,项目在github上进行托管:https://github.com/themadinventor/esptool
虽然可以直接从github上下载使用,但是更好的方法是通过网络的方式进行安装,这样不会缺少依赖模块,减少运行中的故障。下面就介绍它的安装方法。
因为esptool.py需要使用python2,所以我们先需要安装python2,并将python加入系统路径(path)。
安装python的包管理器pip,通常是使用get-pip.py进行安装。在 https://pip.pypa.io/en/latest/installing/ 可以找到安装的说明和需要下载的文件,按照说明可以很容易安装pip。(如果同时安装了python2和python3,pip可能默认是pip3,需要用pip2来代替下面的pip,在Linux上需要用sudo权限安装)。
用pip安装esptool
pip install esptool
因为esptool需要使用串口,所以还需要安装pyserial。
pip install pyserial
- 安装后,在Linux下,通常就可以直接运行esptool.py,在Windwos下,esptool一般安装在python2\Scripts\目录下,需要输入完整目录才能运行,如:
c:\Python27\Scripts\esptool.py
如果不清楚esptool.py的用法,可以输入-h查看帮助,如
esptool.py -h
甚至可以查看某个用法的帮助:
esptool.py read_flash -h
- 擦除flash。
首先要确认一下8266所连接的串口号,要以串口号作为指令的参数,如我的设备是在COM4,我运行的指令就是esptool.py –port COM4 erase_flash
此处需要注意,执行擦除的指令前,需要像烧录固件一样,让8266进入升级模式,即按住板上的flash键不放,按下rst键,等待两秒,松开rst键,再松开flash键。否则会出现如下的错误提示: 这样flash的擦除工作就完成了,重新再烧录固件之后即可解决固件运行异常的问题。
一、esp8266系列模块基础知识:
ESP8266 系列模组是深圳市安信可科技有限公司开发的一系列基于乐鑫ESP8266EX的低功耗UART-WiFi芯片模组,可以方便地进行二次开发,接入云端服务,实现手机3/4G全球随时随地的控制,加速产品原型设计。
模块核心处理器 ESP8266 在较小尺寸封装中集成了业界领先的 Tensilica L106 超低功耗 32 位微型 MCU,带有 16 位精简模式,主频支持 80 MHz 和 160 MHz,支持 RTOS,集成 Wi-Fi MAC/ BB/RF/PA/LNA,板载天线。支持标准的 IEEE802.11 b/g/n 协议,完整的 TCP/IP 协议栈。用户可以使用该模块为现有的设备添加联网功能,也可以构建独立的网络控制器。
ESP8266 是高性能无线 SoC,以最低成本提供最大实用性,为 Wi-Fi 功能嵌入其他系统提供无限可能。
特点
- 802.11 b/g/n
- 内置Tensilica L106 超低功耗 32 位微型 MCU,主频支持 80 MHz 和160 MHz,支持 RTOS
- 内置10 bit高精度ADC
- 内置TCP/IP协议栈
- 内置TR 开关、balun、LNA、功率放大器和匹配网络
- 内置PLL、稳压器和电源管理组件,802.11b 模式下+18 dBm的输出功率
- A-MPDU 、 A-MSDU 的聚合和 0.4 s的保护间隔
- Wi-Fi @ 2.4 GHz,支持 WPA/WPA2 安全模式
- 支持AT本地升级及云端OTA升级
- 支持 STA/AP/STA+AP 工作模式
- 支持 Smart Config 功能(包括 Android 和 IOS 设备)
- HSPI 、UART、I2C、I2S、IR Remote Control、PWM、GPIO
- 深度睡眠保持电流为 20 uA,关断电流小于 5 uA
- 2 ms 之内唤醒、连接并传递数据包
- 待机状态消耗功率小于1.0 mW (DTIM3)
- 工作温度范围:详情请见具体型号规格书
二、环境准备(Arduino开发):
1、硬件准备:
GPIO0决定板子处于什么模式(下载模式)
①、ESP-01系列:
②、用的最多的12F:
SMD-22封装,GPIO0-GPIO16共17个通用IO口,一个单通道ADC,GPIO6-GPIO11用于连接外部flash,不可用,支持SPI总线通信:GPIO12-GPIO15,支持I2C总线:GPIO4-GPIO5,串口通信:GPIO1-GPIO3。
12F一般D0-D8(除D3口即GPIO0下载用);
D0:INPUT(输入)、OUTPUT(输出)、INPUT_PULLDOWN(输入,默认下拉,低电平);
其余IO口:INPUT(输入)、OTPUT(输出)、INPUT_PULLUP(输入,默认上拉,高电平);
注意:烧录模式GPIO0接地,正常模式GPIO悬空。
③、NodeMcu(ESP-12F开发板):
④、8266-12E:
2、软件准备:
①、Arduino安装+8266包安装:
②、芯片检测程序:
/**
* 测试ESP8266 demo,打印ESP8266模块信息
* 1.打印Arduino Core For ESP8266 版本
* 2.打印Flash的唯一性芯片id
* 3.打印Flash实际大小
* 4.打印IDE配置的使用Flash大小
* 5.打印IDE配置的Flash连接通信的频率
* 6.打印Flash连接模式:QIO QOUT DIO DOUT,可以理解为Flash传输速率
*/
void setup() {
Serial.begin(115200);
//使能软件看门狗的触发间隔
//规定时间(5S)内不喂狗,系统复位
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);
}
三、相关外设使用:
1、计时和延时:
/**
* 计时和延时:
* delay(ms);
* delayMicroseconds(us);延时中不能做其他事
* millis(); //返回重启后所经过的毫秒数
* micros(); //返回重启后所经过的微秒数
**/
long debouncdDelay = 60;//延时间隔
long lastDebounceTime = 0; //最近记录的一次时间
// 判断时间间隔是否大于设定的时间间隔。
if(millis()-lastDebounceTime>debouncdDelay){
lastDebounceTime = millis();
}
2、IO口(Blink):
/**
* LED灯闪烁实验
* 12E模块,LED在GPIO2口,即NodeMCU的D4
*/
void setup() {
pinMode(D4, OUTPUT); // 初始化D1引脚为输出引脚
}
void loop() {
digitalWrite(D4, LOW); // 亮灯
delay(1000); // 延时1s
digitalWrite(D4, HIGH);// 灭灯
delay(1000); // 延时1s
}
3、中断:
(除了DO/GPIO16,中断可以绑到任意GPIO脚)
相关函数:
attachInterrupt(pin,function,mode);
在指定引脚设置为响应中断。pin:要设置的中断号,function:中断时执行的函数,不带任何参数,无返回,Interrupt type/mode:中断触发条件(CHANGE:改变沿;RISING:上升沿;FALLING:下降沿)detachInterrupt(pin);
禁用指定GPIO引脚上的中断。pin:要禁用的中断的GPIO引脚,无返回值。digitalPinToInterrupt(pin);
获取指定GPIO引脚的中断号。
/**
* 功能描述:ESP8266中断演示
* D2口接下拉电阻到地,同时也通过一个按键开关接到VCC
* 当开关按下,D2接到上升沿,开启中断,进入中断函数
*/
void setup() {
Serial.begin(115200);//设置串口波特率
attachInterrupt(digitalPinToInterrupt(D2), InterruptFunc, RISING);//设置中断号、响应函数、触发方式
}
void loop() {
}
/**
* 中断响应函数
*/
ICACHE_RAM_ATTR void InterruptFunc(){
Serial.println("Hello ESP8266");
}
4、模拟输入(ADC):
esp8266只用一个10位ADC通道(和芯片供电电压复用:即可设置为测量系统电压或者外部电压)
①、测量外部电压:
- 方法:
analogRead(A0);
- 0-1.0V
- 测量精度:10位ADC:0~$2^{10}$
- 注意:开发板上做了电阻分压器,使其能够测量0 ~ 3.3V(220K与100K电阻分压)
/**
* 功能描述: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);
}
②、测量系统外部电压:
方法: ESP.getVcc()
单位: mv
ADC引脚要悬空。读取前要更改ADC模式(在#include行后面)
ADC_TOUT
(对外部电压),ADC_VCC
(对系统电压),默认读取外部/** * 功能描述:ESP8266 ADC 读取系统电压 * 在串口调试器查看效果 */ ADC_MODE(ADC_VCC);//设置ADC模式为读取系统电压 void setup() { Serial.begin(115200); } void loop() { Serial.print("ESP8266当前系统电压(mV): "); Serial.println(ESP.getVcc()); delay(1000); }
5、模拟输出(PWM):
方法:
analogWrite(pin,val)
在指定引脚上启用PWM;pin:GPIO; val:一般0 ~ PWMRANGE,默认PWMRANGE=1023;无返回值;analogWrite(pin,0)
相当于禁用指定引脚上的PWM;analogWriteRange(new_range)
改变PWMRANGE数值;new_range:新的PWMRANGE数值;无返回值;(可以调节PWM精度);analogWriteFreq(new_frequency)
改变PWM频率;默认1KHzArduino For ESP8266的PWM频率范围为100Hz ~40KHz:
源码:
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; } }
例程(呼吸灯):
/**
* 功能描述:ESP8266 PWM演示例程
*/
#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);
}
}
6、串口通信:
与传统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)。可来回调用。一般默认/** * 功能描述:ESP8266 Serial映射例程 */ 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.begin(baudrate)
。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.baudRate()
或Serial1.baudRate()
检测进入Serial的未知波特率的数据:
Serial.detectBaudrate(time_t timeoutMillis)
: 尝试在timeoutMillis ms的时间内检测波特率,检测成功返回波特率,失败返回0。detectBaudrate()
方法在Serial.begin()
之前调用。可使用Serial.begin(detectedBaudrate)
示例(WIFI连接):
/**
* statin模式下,创建一个连接到可接入点(wifi热点),并且打印IP地址
*/
#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() {
}