ndfweb.cn

使用Arduino開發ESP32IO口與相關外設說明與記錄


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



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网站建设淘宝店 | ICO图标在线生成 | 外贸网站建设 | 联系我们
©2007-2025 NDF Corporation 鲁ICP备08005967号 Sitemap - RSSRSS订阅