使用Arduino开发ESP32(11):IO口与相关外设说明与记录

时间:2024-11-07 16:31:20

文章目录

  • 目的
  • 数字IO口
    • 基本使用
    • 外部中断
    • 使用示例
    • 参考链接
  • LEDC(PWM)
    • 常用方法
    • 使用示例
    • 参考链接
  • SigmaDelta
    • 参考链接
  • ADC
    • 常用方法
    • 使用示例
    • 参考链接
    • 存在的问题
  • DAC
    • 常用方法
    • 使用示例
    • 参考链接
  • Serial port
  • I2C
    • 参考链接
  • I2S
    • 参考链接
  • SPI
    • 参考链接
  • CAN
    • 参考链接
  • 触摸功能
    • 参考链接
  • HallSensor
    • 参考链接
  • 题外话(全局中断关闭与开启)
  • 总结

目的

Arduino core for the ESP32中IO口和外设的使用和一般的Arduino产不多,这里做个说明与记录。
先上一张ESP32模块的管脚图(点击看大图):
在这里插入图片描述
更完整管脚说明需要去参考的乐鑫官方《ESP32 技术规格书》。

数字IO口

基本使用

IO口基本使用方式如下:

  • 使用pinMode(pin, mode)来设置GPIO口工作模式,mode可选比较多INPUTOUTPUTINPUT_PULLUPINPUT_PULLDOWN模式(输入、输出、上拉输入、下拉输入,另外还有开漏等模式),具体是否能设置对应模式还得参考技术规格书(一般的GPIO0 ~ 33可以设置为输出,基本上都可以设置为输入,GPIO6 ~ 11一般不推荐使用,因为这几个口接了存储程序用的Flash,不当使用可能引起程序崩溃);
  • 使用digitalWrite(pin, value)来设置输出状态,value可选值为HIGHLOW,即1和0;
  • 使用digitalRead(pin)来读取GPIO口电平,返回值为HIGHLOW,即1和0;

题外话:请注意ESP32的IO12,这个IO口上上电时的电平会决定外部flash(存放程序的那颗)的工作电压,上电时该脚为高则认为flash工作于1.8V,为低则认为flash工作于3.3V。常用的像是Wroom-32系列模块该脚内部已下拉,即flash是工作于3.3V的,若外部电路接强上拉则可能导致模块工作异常。

外部中断

外部中断使用方式如下:

  • 使用attachInterrupt(uint8_t pin, void (*)(void), int mode)attachInterruptArg(uint8_t pin, void (*)(void*), void * arg, int mode)来设置外部中断,输入参数有gpio号、中断触发时的回调函数、回调函数输入参数、外部中断触发模式(RISINGFALLINGCHANGE……上升沿、下降沿、改变时、低电平、高电平等);
  • 使用detachInterrupt(uint8_t pin)来关闭外部中断;

使用示例

使用下面代码进行测试:

// IO14 输出
// IO12 下拉输入模式 电平改变触发中断
// 使用导线连接 IO14 和 IO12

void callBack(void)
{
  int lv = digitalRead(12); //读取加载到IO12上的电平
  Serial.printf("触发了中断,当前电平是: %d\n", lv);
}

void setup()
{
  Serial.begin(115200);
  Serial.println();

  pinMode(14, OUTPUT);
  digitalWrite(14, LOW);

  pinMode(12, INPUT_PULLDOWN);
  attachInterrupt(12, callBack, CHANGE); //使能中断

  for (int i = 0; i < 5; i++)
  {
    delay(1000);
    digitalWrite(14, 1 ^ digitalRead(14)); //翻转 IO14 输出电平
  }

  detachInterrupt(12); //失能中断
}

void loop()
{
  delay(1000);
  digitalWrite(14, 1 ^ digitalRead(14));
}

在这里插入图片描述

参考链接

/espressif/arduino-esp32/blob/master/cores/esp32/
/espressif/arduino-esp32/blob/master/cores/esp32/
/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/GPIO

LEDC(PWM)

Arduino core for the ESP32并没有一般Arduino中用来输出PWM的analogWrite(pin, value)方法,取而代之的ESP32有一个LEDC,设计是用来控制LED,像是实现呼吸灯或是控制全彩LED之类,简单的输出PWM当然不在话下。
ESP32的LEDC总共有16个路通道(0 ~ 15),分为高低速两组,高速通道(0 ~ 7)由80MHz时钟驱动,低速通道(8 ~ 15)由1MHz时钟驱动。

常用方法

  • double ledcSetup(uint8_t channel, double freq, uint8_t resolution_bits)
    设置LEDC通道对应的频率和计数位数(占空比分辨率),各项说明如下:
    channel为通道号,取值0 ~ 15
    freq期望设置频率;
    resolution_bits计数位数,取值0 ~ 20(该值决定后面ledcWrite方法中占空比可写值,比如该值写10,则占空比最大可写1023 即 (1<<resolution_bits)-1 );
    通道最终频率 = 时钟 / ( 分频系数 * ( 1 << 计数位数 ) );(分频系数最大为1024)
    该方法返回最终频率;

  • void ledcWrite(uint8_t channel, uint32_t duty)
    指定通道输出一定占空比波形;

  • double ledcWriteTone(uint8_t channel, double freq)
    类似于arduino的tone,当外接无源蜂鸣器的时候可以发出某个声音(根据频率不同而不同);

  • double ledcWriteNote(uint8_t channel, note_t note, uint8_t octave)
    该方法是上面方法的进一步封装,可以直接输出指定调式和音阶声音的信号,参数如下:
    note:调式,相当于do、re、mi、fa……这些,取值为NOTE_C, NOTE_Cs, NOTE_D, NOTE_Eb, NOTE_E, NOTE_F, NOTE_Fs, NOTE_G, NOTE_Gs, NOTE_A, NOTE_Bb, NOTE_B
    octave音阶,取值0~7;
    乐理相关内容可以参考下面文章:
    http:///content/17/1231/01/47685146_717797647.shtml
    /sns/?s=/news/index/detail/id/

  • uint32_t ledcRead(uint8_t channel)
    返回指定通道占空比的值;

  • double ledcReadFreq(uint8_t channel)
    返回指定通道当前频率(如果当前占空比为0 则该方法返回0);

  • void ledcAttachPin(uint8_t pin, uint8_t channel)
    将LEDC通道绑定到指定IO口上以实现输出;

  • void ledcDetachPin(uint8_t pin)
    解除IO口的LEDC功能;

使用示例

使用下面代码进行测试:

// IO14 输出PWM
// IO12 读取IO14输出的信号

void setup()
{
  Serial.begin(115200);
  Serial.println();

  ledcSetup(8, 1, 10);  //设置LEDC通道8频率为1,分辨率为10位,即占空比可选0~1023
  ledcAttachPin(14, 8); //设置LEDC通道8在IO14上输出

  pinMode(12, INPUT_PULLDOWN);

  for (int i = 0; i < 5; i++)
  {
    ledcWrite(8, 250 * i); //设置输出PWM
    for (int j = 0; j < 100; j++)
    {
      delay(10);
      Serial.println(digitalRead(12));
    }
  }
}

void loop()
{
}

在这里插入图片描述

参考链接

/espressif/arduino-esp32/blob/master/cores/esp32/
/espressif/arduino-esp32/blob/master/cores/esp32/
/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/AnalogOut/LEDCSoftwareFade
/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/AnalogOut/ledcWrite_RGB

SigmaDelta

SigmaDelta一般用在红外遥控器上,常见的家电的遥控器都是使用这类信号的,这里仅做下记录。

参考链接

/espressif/arduino-esp32/blob/master/cores/esp32/
/espressif/arduino-esp32/blob/master/cores/esp32/
/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/AnalogOut/SigmaDelta

ADC

ADC是比较常用的功能,使用起来也比较简单。ESP32有两个ADC,每个ADC有多个通道,同一时间每个ADC只能采集一个通道。

常用方法

  • uint16_t analogRead(uint8_t pin)
    获取指定IO口的模拟电压数据(该方法将阻塞直到采集完成);

  • void analogReadResolution(uint8_t bits)
    设置模拟数据读取分辨率,取值1~16,默认为12;

  • void analogSetWidth(uint8_t bits)
    设置ADC采样分辨率,取值9~12,默认为12;

  • void analogSetCycles(uint8_t cycles)
    设置单次采样的周期,取值1~255,默认为8;

  • void analogSetSamples(uint8_t samples)
    设置单次采样的实际采样次数,取值1~255,默认为1;
    该项的设置相当于提高了ADC的灵敏度,比如该值为2,则采样获得数据就是真实数据的2倍;

  • void analogSetClockDiv(uint8_t clockDiv)
    设置ADC时钟分频系数,取值1~255,默认为1;

  • void analogSetAttenuation(adc_attenuation_t attenuation)
    设置ADC全局输入衰减,取值ADC_0db, ADC_2_5db, ADC_6db, ADC_11db,默认为11db;
    当 VDD_A 为 3.3V 时:
    0dB 下量程最大为 1.1V
    2.5dB 下量程最大为 1.5V
    6dB 下量程最大为 2.2V
    11dB 下量程最大为 3.9V(最大可以采集到3.3V电压)

  • void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation)
    设置单独某个IO口的输入衰减;

  • int hallRead()
    Get value for HALL sensor (without LNA) connected to pins 36(SVP) and 39(SVN);
    (关联下文霍尔传感器)

========= 以下为非阻塞采样 =========

  • bool adcAttachPin(uint8_t pin)
    将IO口连接到ADC;

  • bool adcStart(uint8_t pin)
    开启采样与转换;

  • bool adcBusy(uint8_t pin)
    检查采样与转换是否完成;

  • uint16_t adcEnd(uint8_t pin)
    读取采集到的数据(如果未完成将阻塞至完成);

使用示例

见下文DAC部分使用示例;

参考链接

/espressif/arduino-esp32/blob/master/cores/esp32/
/espressif/arduino-esp32/blob/master/cores/esp32/

存在的问题

  • 当使用WiFi的时候无法使用ADC2;
  • ESP32的ADC线性度挺差,比如输入衰减为11dB时只能保证在150–2450mV间测量较准确(详见ESP32技术规格书);

DAC

相对于ADC来说DAC用的稍微少些,不过用起来也不复杂。

常用方法

  • void dacWrite(uint8_t pin, uint8_t value)
    DAC输出;
    pin取值为25、26;
    value取值为0~255;
    DAC输出电压由VDD3P3_RTC引脚输入电压和value决定,使用常用的模块时VDD3P3_RTC上电压为3.3V;
    DAC_OUT = VDD3P3_RTC * value / 256 ;

使用示例

使用下面代码进行测试:

void setup()
{
  Serial.begin(115200);
  Serial.println();

  dacWrite(26, 100); //IO26 DAC输出 100*3.3V/255≈1.294V

  int vtmp = analogRead(27); //IO27 ADC获取电压

  Serial.printf("采样值为:%d\n", vtmp);
  Serial.printf("电压为:%.3fV\n", vtmp * 3.9 / 4095);
}

void loop()
{
}

在这里插入图片描述

参考链接

/espressif/arduino-esp32/blob/master/cores/esp32/
/espressif/arduino-esp32/blob/master/cores/esp32/

Serial port

Serial port使用见之前文章:
《使用Arduino开发ESP32(02):串口(Serial port)使用说明》

I2C

I2C是一种常用的接口,这里先做下记录。

参考链接

/espressif/arduino-esp32/tree/master/libraries/Wire
/espressif/arduino-esp32/blob/master/cores/esp32/
/espressif/arduino-esp32/blob/master/cores/esp32/

I2S

I2S相对来说用的不多,这里仅做下记录。

参考链接

/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/I2S
/espressif/arduino-esp32/blob/master/tools/sdk/include/driver/driver/

SPI

SPI是一种常用的接口,这里先做下记录。

参考链接

/espressif/arduino-esp32/tree/master/libraries/SPI
/espressif/arduino-esp32/blob/master/cores/esp32/
/espressif/arduino-esp32/blob/master/cores/esp32/

CAN

CAN是一种常用的现场总线,这里仅做下记录。

参考链接

/espressif/arduino-esp32/blob/master/tools/sdk/include/driver/driver/

触摸功能

触摸功能主要用于触摸传感器,像是按键、滑块等。这里先做下记录。
《ESP32 触摸传感器应用方案简介》
《ESP32 触摸功能开发套件》

参考链接

/espressif/arduino-esp32/blob/master/cores/esp32/
/espressif/arduino-esp32/blob/master/cores/esp32/
/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/Touch

HallSensor

霍尔传感器相对来说用的不多,这里仅做下记录。(ESP32的霍尔传感器读取其实就是靠ADC的,可以参考ADC部分)

参考链接

/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/HallSensor

题外话(全局中断关闭与开启)

使用IO口时很多操作对时序要求比较高,如果系统频繁进入中断可能会使操作失败,这时候就需要暂时关闭中断等操作完成后再开启中断,可以使用下面方法进行中断的开启和关闭:

  • noInterrupts()
    cli()
    关闭中断;
  • interrupts()
    sei()
    开启中断;

注意:关闭中断完成需要的操作后一定要记得开启中断!

总结

事实上对于单片机来说IO口与相关外设的使用才是大头的内容,一篇文章难以介绍详尽,这是只是做个记录。不过相应的各种类别的单片机IO口与相关外设使用起来大同小异,网上教程资源比较充分,如果对某块功能不了解的话可以参考别的更加详细的教程。