ndfweb.cn

使用Arduino开发ESP32IO口与相关外设说明与记录


2020-02-27 07:24:22 (6388)


Arduino core for the ESP32中IO口和外设的使用和一般的Arduino产不多,这里做个说明与记录。

先上一张ESP32模块的管脚图(点击看大图):


更完整管脚说明需要去参考的乐鑫官方《ESP32 技术规格书》。


数字IO口


基本使用


IO口基本使用方式如下:


使用pinMode(pin, mode)来设置GPIO口工作模式,mode可选比较多INPUT、OUTPUT、INPUT_PULLUP、INPUT_PULLDOWN模式(输入、输出、上拉输入、下拉输入,另外还有开漏等模式),具体是否能设置对应模式还得参考技术规格书(一般的GPIO0 ~ 33可以设置为输出,基本上都可以设置为输入,GPIO6 ~ 11一般不推荐使用,因为这几个口接了存储程序用的Flash,不当使用可能引起程序崩溃);

使用digitalWrite(pin, value)来设置输出状态,value可选值为HIGH或LOW,即1和0;

使用digitalRead(pin)来读取GPIO口电平,返回值为HIGH或LOW,即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号、中断触发时的回调函数、回调函数输入参数、外部中断触发模式(RISING、FALLING、CHANGE……上升沿、下降沿、改变时、低电平、高电平等);

使用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));

}

参考链接


https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-gpio.h

https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-gpio.c

https://github.com/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://www.360doc.com/content/17/1231/01/47685146_717797647.shtml

https://www.musicbody.net/sns/index.php?s=/news/index/detail/id/406.html


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()

{

}


参考链接


https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-ledc.h

https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-ledc.c

https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/AnalogOut/LEDCSoftwareFade

https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/AnalogOut/ledcWrite_RGB


SigmaDelta


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


参考链接


https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-sigmadelta.h

https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-sigmadelta.c

https://github.com/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部分使用示例;


参考链接


https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-adc.h

https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-adc.c


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()

{

}



参考链接


https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-dac.h

https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-dac.c


Serial port


Serial port使用见之前文章:

《使用Arduino开发ESP32(02):串口(Serial port)使用说明》


I2C


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


参考链接


https://github.com/espressif/arduino-esp32/tree/master/libraries/Wire

https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-i2c.h

https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-i2c.c


I2S


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


参考链接


https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/I2S

https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/driver/driver/i2s.h


SPI


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


参考链接


https://github.com/espressif/arduino-esp32/tree/master/libraries/SPI

https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-spi.h

https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-spi.c


CAN


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


参考链接


https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/driver/driver/can.h


触摸功能


触摸功能主要用于触摸传感器,像是按键、滑块等。这里先做下记录。

《ESP32 触摸传感器应用方案简介》

《ESP32 触摸功能开发套件》


参考链接


https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-touch.h

https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-touch.c

https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/Touch


HallSensor


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


参考链接


https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/HallSensor


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


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


noInterrupts()

cli()

关闭中断;

interrupts()

sei()

开启中断;

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


总结


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


了解更多请访问:http://www.ndfweb.cn/news-784.html
  NDF俱乐部
  国际域名注册
  建站咨询
合作伙伴:万网 | 新网 | 新网互联 NDF网站建设淘宝店 | 实用工具 | 外貿網站建設 | 联系我们
鲁公网安备 37110202000336号 鲁ICP备2021027697号-1 Sitemap - RSSRSS订阅