arduino analogread_ESP8266开发之旅 基础篇—ESP8266与Arduino的开发说明

1. Arduino程序结构

Arduino编程的代码结构:
/** * ESP8266 Arduino程序结构 * @author SXXZY * @date 2020/11/22 */void setup() {  // 这里开始写初始化代码,只会执行一次  }void loop() {  //这里写运行代码,重复执行}
对于习惯c语言编程的读者,以上代码又可以抽象成以下伪代码结构:
/** * ESP8266 Arduino程序伪代码结构 * @author SXXZY * @date 2020/11/22 */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 端口映射

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

bc4c1432e9a2f8629966b2301ee1b80d.png

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

e36fe44de0e87384d92c12f88ef7227d.png

可以看出:

    1.中间的DEVKIT部分,就是NodeMcu提供给外界的端口,对应实物图上标注的端口名称;

    2.除开中间部分,其他部分基本上对应ESP8266引脚,以不同颜色块来区分不同功能;

温馨提示

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

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

ec8c7fdb2351f3a50d2f309e1b0b6ae3.png

从上面表格可以看出,我们大约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的D4引脚上写一个LED Blink的Arduino草图:

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

5.模拟输入(ADC)

学过模拟电路或者数字电路的人都会听过ADC,它又叫做模数转换器,用于将模拟信号转换成可视化的数字形式。ESP8266具有内置的10位ADC,只有一个ADC通道,即只有一个ADC输入引脚可读取来自外部器件的模拟电压。

    ESP8266上的ADC通道和芯片供电电压复用,也就是说我们可以将其设置为测量系统电压或者外部电压。

5.1 测量外部电压

    相关方法

        analogRead(A0),用于读取施加在模块的ADC引脚上的外部电压;

    输入电压范围

        0 - 1.0V之间;

    测量精度

        由于ADC具有10位分辨率,因此会给出0-1023的值范围;

    注意点

        为了支持外部电压范围(0-3.3v),NodeMcu做了一个电阻分压器,如图所示:

ea9afa974a4954b15c89ba3d357904b5.png

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

c19390856d05b8bbf7705070353543d9.png

代码如下:

/** * 功能描述: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);}

5.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);}

6. 模拟输出(PWM)

PWM(Pulse Width Modulation,脉宽调制),是在保持波的频率不变的同时改变脉宽的技术。当我们需要连续控制电压变化,实现呼吸灯或者电机转速的时候,就要用到PWM,如下图。

4cbfa15fbda245ded899fd18873ccef4.gif

首先,我们来理解一下占空比。一个脉冲周期由一个ON周期(VCCC)和一个OFF周期(GND)组成。一段时间内ON周期占据脉冲周期的比例就叫做占空比。
DutyCycle(percentage)=Ton/TotalPeriodX100
例如,一个10ms的脉冲保持ON 2ms,那么根据公式,占空比是20%。

注意点

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

NodeMcu PWM引脚

    如下图,标注PWM引脚。

2d9490a583b37a7c3e75fff7b413dc77.png

基本上数字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 SXXZY * @date 2020/11/22 */ #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);  }}

7. 串口通信(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 SXXZY * @date 2020/11/22 */ 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 SXXZY * @date 2020/11/22 */ 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 SXXZY * @date 2020/11/22 */ 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 SXXZY * @date 2020/11/22 */#include  #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() {}

8. 总结

总体上讲,基础内容比较多,介绍ESP8266在Arduino平台上的一些基础知识点,包括程序结构、NodeMcu端口映射、ESP8266 数字IO、PWM、ADC、串口通信等等。
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值