玩轉(zhuǎn) ESP32 + Arduino (三) GPIO和串口

我用的 ESP32 DEVKIT V1
引腳圖



原理圖


【騰訊文檔】ESP32引腳功能篩選器https://docs.qq.com/sheet/DWXpUWVFMZWlQZGl4

一、GPIO

1、初始化GPIO

pinMode(pin, mode)

作用:設(shè)置一個(gè)引腳(pin)作為GPIO時(shí)的I/O模式。

參數(shù):

pin:引腳編號(hào)

mode:GPIO的I/O模式,取值有3種

INPUT :作為數(shù)字輸入

OUTPUT :作為數(shù)字輸出

INPUT_PULLUP:作為數(shù)字輸入,且使能引腳的內(nèi)部上拉電阻

注意:

a、引腳作為PWM輸出時(shí),無(wú)需先前使用pinMode配置其模式,因?yàn)镻WM本身就代表了輸出的意思。且官方庫(kù)源代碼中可以發(fā)現(xiàn),它已經(jīng)幫我們配置為輸出了。

b、模擬引腳也可以作為數(shù)字引腳使用,完全OK。這在數(shù)字引腳不夠用的情況下非常有用。

2、GPIO數(shù)字輸出

digitalWrite(pin,value)

作用:設(shè)置一個(gè)數(shù)字輸出引腳的輸出電平值,HIGH或者LOW。

參數(shù):

pin:引腳編號(hào)。此引腳必須在之前使用pinMode設(shè)置為OUTPUT模式。

value:2個(gè)值

LOW:輸出低電平

HIGH:輸出高電平

3、GPIO數(shù)字輸入

int digitalRead(pin)

作用:讀取一個(gè)數(shù)字輸入引腳的電平值。

返回:HIGH(高電平)或者LOW(低電平)。

參數(shù):

pin:引腳編號(hào)。

示例 : 按鍵控制燈亮滅

void setup()
{
  pinMode(2,OUTPUT);
  pinMode(0,INPUT_PULLUP);
}

void loop()
{
  if(digitalRead(0))
  {
    while(digitalRead(0));
    digitalWrite(2,!digitalRead(2));
  }
}

4、GPIO模擬輸入:analogRead(pin)

注意 : 模擬輸入是通過(guò)PWM實(shí)現(xiàn)的, 所以不需要初始化PIN

analogRead(4)

5. 模擬信號(hào)輸入分辨率: analogSetWidth(bit);

bit的值 范圍
9 0~511
10 0~1023
11 0~2047
12(默認(rèn)) 0~4095

6. 模擬信號(hào)輸出 (基于LEDC)

LEDC是基于PWM調(diào)制實(shí)現(xiàn)模擬輸出的.
與arduino uno主板不同, ESP32的PWM模擬是一個(gè)個(gè)通道 共16個(gè), 通道可以映射到引腳上. 引腳就可以輸出PWM信號(hào)了.

6.1 設(shè)置通道 ledcSetup(channel,freq,bit_num)

參數(shù):

  • channel : LEDC的PWM通道參數(shù),可選0~15
  • freq : 10Hz到40MHz , 但較高的頻率精確度低
  • bit_num: 占空比分辨率(可選1~16), 比如bit_num=8 則范圍 0~2的8次方 , 也就是0~255

推薦的配置:

頻率 位深 過(guò)渡的可用步驟
1220赫茲 16 65536
2441赫茲 15 32768
4882赫茲 14 16384
9765Hz 13 8192
19531赫茲 12 4096
ledcSetup(1,1200,16);
6.2 通道與引腳映射 ledcAttachPin(pin,channel)
  ledcAttachPin(5,1);

注意: 一個(gè)通道可以同時(shí)映射多個(gè)引腳

6.3 取消引腳的PWM映射 ledcDetachPin(pin)
ledcDetachPin(5);
6.4 向指定通道寫(xiě)入占空比 ledcWrite(channel,duty)

例: 呼吸燈

bool add_status = true;
void setup()
{
  pinMode(2,OUTPUT);
  ledcSetup(2,1200,8);
  ledcAttachPin(2,2);
}

void loop()
{
   for(int i = 0 ; i<256; i++)
   {
    if(add_status)
    {
      ledcWrite(2,i);
    }
    else
    {
      ledcWrite(2,256-i);
    }
    delay(5);
  }
  add_status = !add_status;
}
例子, 全彩呼吸燈
#include <Arduino.h>

#define LED_R 27
#define LED_G 33
#define LED_B 32

void setup()
{
  Serial.begin(115200);
  ledcSetup(1, 1200, 8);
  ledcSetup(2, 1200, 8);
  ledcSetup(3, 1200, 8);

  ledcAttachPin(LED_R, 1);
  ledcAttachPin(LED_G, 2);
  ledcAttachPin(LED_B, 3);

  ledcWrite(1, 255);
  ledcWrite(2, 255);
  ledcWrite(3, 255);
}

void loop()
{
  for (int i = 0; i < 510; i++)
  {
    if (i >= 0 && i < 255)
      ledcWrite(1, 255 - i);
    if (i >= 255 && i < 510)
      ledcWrite(1, i - 255);

    if (i >= 0 && i < 170)
      ledcWrite(2, 85 + i);
    if (i >= 170 && i < 425)
      ledcWrite(2, 425 - i);
    if (i >= 425 && i < 510)
      ledcWrite(2, i - 425);

    if (i >= 0 && i < 85)
      ledcWrite(3, 85 - i);
    if (i >= 85 && i < 340)
      ledcWrite(3, i - 85);
    if (i >= 340 && i < 510)
      ledcWrite(3, 595 - i);
    delay(10);
  }
}
6.5 向指定通道輸出指定頻率的音符信號(hào) ledcWriteTone(channel, freq)
6.6 向指定通道輸出指定的音符和音階 ledcWriteNote(channel,note,octava)

參數(shù)

  • note : 音符 可選(NOTE_C, NOTE_Cs, NOTE_D, NOTE_Eb, NOTE_C......)
  • octava : 音階 , 可選0~7

7. 模擬信號(hào)輸出函數(shù) (基于DAC)

ESP32提供了兩個(gè)DAC通道, 對(duì)應(yīng)引腳25 , 26. 精度為8位.

dacWrite(pin,value);

  • value取值: 0~255
void setup()
{

}

void loop()
{
   for(int i = 0 ; i<256; i++)
   {
    dacWrite(25,i);
    delay(10);
  }
}

二、串口打印 UART

ESP32共有3個(gè)UART端口, 其中UART1用于Flash讀/寫(xiě).

串口名 Arduino名 TX RX
UART0 Serial pin1 pin3
UART1 Serial1 pin10 pin9
UART2 Serial2 pin17 pin16

1、串口初始化

Serial.begin(speed, config)

  • 參數(shù):
    • speed:波特率,一般取值9600,115200等。
    • config:設(shè)置數(shù)據(jù)位、校驗(yàn)位和停止位。默認(rèn)SERIAL_8N1表示8個(gè)數(shù)據(jù)位,無(wú)校驗(yàn)位,1個(gè)停止位。
  • 返回值:無(wú)。

2、關(guān)閉串口

Serial.end()

  • 描述:禁止串口傳輸。此時(shí)串口Rx和Tx可以作為數(shù)字IO引腳使用。
  • 原型:Serial.end()
  • 參數(shù):無(wú)。
  • 返回值:無(wú)。

3、串口打印

Serial.print()

  • 描述:串口輸出數(shù)據(jù),寫(xiě)入字符數(shù)據(jù)到串口。
  • 原型:
    • Serial.print(val)
    • Serial.print(val, format)
  • 參數(shù):
    • val:打印的值,任意數(shù)據(jù)類(lèi)型。
    • config:輸出的數(shù)據(jù)格式。BIN(二進(jìn)制)、OCT(八進(jìn)制)、DEC(十進(jìn)制)、HEX(十六進(jìn)制)。對(duì)于浮點(diǎn)數(shù),此參數(shù)指定要使用的小數(shù)位數(shù)。

4、串口輸出數(shù)據(jù)并換行 println() 和 printf()

Serial.println()
Serial.printf()

  • 描述:串口輸出數(shù)據(jù)并換行。
  • 原型:
    • Serial.println(val)
    • Serial.println(val, format)
  • 參數(shù):
    • val:打印的值,任意數(shù)據(jù)類(lèi)型。
    • config:輸出的數(shù)據(jù)格式。
  • 返回值:返回寫(xiě)入的字節(jié)數(shù)。
附: 常用格式字符及轉(zhuǎn)義字符
字符 說(shuō)明
%o 八進(jìn)制整數(shù)輸出
%d 十進(jìn)制整數(shù)輸出
%x 十六進(jìn)制整數(shù)輸出
%f 浮點(diǎn)輸出,默認(rèn)6位小數(shù)
%c 單字符輸出
%s 字符串輸出
\n 換行
\r 回車(chē)
\t Tab制表符

5、將二進(jìn)制數(shù)寫(xiě)入串口

Serial.write()

描述
將二進(jìn)制數(shù)據(jù)寫(xiě)入串行端口。該數(shù)據(jù)以字節(jié)或一系列字節(jié)的形式發(fā)送;要發(fā)送代表數(shù)字?jǐn)?shù)字的字符,請(qǐng)改用print()函數(shù)。
句法
*Serial*.write(val)
*Serial*.write(str)
*Serial*.write(buf, len)
參量
*Serial*:串行端口對(duì)象。請(qǐng)參閱“ 串行”主頁(yè)上每個(gè)板的可用串行端口列表。
val:要作為單個(gè)字節(jié)發(fā)送的值。
str:作為一系列字節(jié)發(fā)送的字符串。
buf:要作為一系列字節(jié)發(fā)送的數(shù)組。
len:要從數(shù)組發(fā)送的字節(jié)數(shù)。
退貨
write()將返回寫(xiě)入的字節(jié)數(shù),盡管讀取該數(shù)字是可選的。資料類(lèi)型:size_t。

6、判斷串口緩沖區(qū)的狀態(tài)

Serial.available()

  • 描述:判斷串口緩沖區(qū)的狀態(tài),返回從串口緩沖區(qū)讀取的字節(jié)數(shù)。
  • 原型:Serial.available()
  • 參數(shù):無(wú)。
  • 返回值:可讀取的字節(jié)數(shù)。

7、讀取串口數(shù)據(jù)

Serial.read()
描述:讀取串口數(shù)據(jù),一次讀一個(gè)字符,讀完后刪除已讀數(shù)據(jù)。

  • 原型:Serial.read()
  • 參數(shù):無(wú)。
  • 返回值:返回串口緩存中第一個(gè)可讀字節(jié),當(dāng)沒(méi)有可讀數(shù)據(jù)時(shí)返回-1,整數(shù)類(lèi)型。
#include <Arduino.h>
char rev;
void setup() {
  Serial.begin(115200);
}

void loop() {
  if(Serial.available())
  {
    rev=Serial.read();
    Serial.print("rev=");
    Serial.println(rev);
    }
}

Serial.readBytes()

  • 描述:從串口讀取指定長(zhǎng)度的字符到緩存數(shù)組。
  • 原型:Serial.readBytes(buffer, length)
  • 參數(shù):
    • buffer:緩存變量。
    • length:設(shè)定的讀取長(zhǎng)度。

返回值:返回存入緩存的字符數(shù)。

Serial.readString()

描述

Serial.readString()從串行緩沖區(qū)讀取字符到字符串。如果超時(shí),該函數(shù)將終止。

Serial.readString()Stream實(shí)用程序類(lèi)繼承。

句法

*Serial*.readString()

參量

*Serial*:串行端口對(duì)象。請(qǐng)參閱“ 串行”主頁(yè)上每個(gè)板的可用串行端口列表。

返回值

一個(gè)String從串行讀緩沖器

Serial.readStringUntil()

描述
readStringUntil()從串行緩沖區(qū)讀取字符到字符串。如果超時(shí),該函數(shù)將終止(請(qǐng)參見(jiàn)setTimeout())。
Serial.readStringUntil()Stream實(shí)用程序類(lèi)繼承。
句法
*Serial*.readStringUntil(terminator)
參量
*Serial*:串行端口對(duì)象。請(qǐng)參閱“ 串行”主頁(yè)上每個(gè)板的可用串行端口列表。
terminator:要搜索的字符。允許的數(shù)據(jù)類(lèi)型:char。
返回值
String從串行緩沖區(qū)的整個(gè)讀取,直到終止符

注意和警告
終止符將從串行緩沖區(qū)中丟棄。

Serial.find()

描述
Serial.find()從串行緩沖區(qū)讀取數(shù)據(jù),直到找到目標(biāo)為止。true如果找到目標(biāo),函數(shù)將返回false超時(shí)。
Serial.find()實(shí)用程序類(lèi)繼承。
句法
*Serial*.find(target)
*Serial*.find(target, length)
參量
*Serial*:串行端口對(duì)象。請(qǐng)參閱“ 串行”主頁(yè)上每個(gè)板的可用串行端口列表。
target:要搜索的字符串。允許的數(shù)據(jù)類(lèi)型:char。
length:目標(biāo)的長(zhǎng)度。允許的數(shù)據(jù)類(lèi)型:size_t。
返回值
資料類(lèi)型:bool

Serial.findUntil()

描述
Serial.findUntil() 從串行緩沖區(qū)讀取數(shù)據(jù),直到找到給定長(zhǎng)度的目標(biāo)字符串或終止符字符串。
如果找到目標(biāo)字符串,則該函數(shù)返回true;如果超時(shí),則返回false。
Serial.findUntil()Stream實(shí)用程序類(lèi)繼承。
句法
*Serial*.findUntil(target, terminal)
參量
*Serial*:串行端口對(duì)象。請(qǐng)參閱“ 串行”主頁(yè)上每個(gè)板的可用串行端口列表。
target:要搜索的字符串。允許的數(shù)據(jù)類(lèi)型:char。
terminal:搜索中的終端字符串。允許的數(shù)據(jù)類(lèi)型:char。
返回值
資料類(lèi)型:bool

Serial.parseFloat()

描述
Serial.parseFloat()從串行緩沖區(qū)返回第一個(gè)有效的浮點(diǎn)數(shù)。parseFloat()以不是浮點(diǎn)數(shù)的第一個(gè)字符終止。如果超時(shí),該函數(shù)將終止(請(qǐng)參見(jiàn)Serial.setTimeout())。
Serial.parseFloat()Stream實(shí)用程序類(lèi)繼承。
句法
*Serial*.parseFloat()
*Serial*.parseFloat(lookahead)
*Serial*.parseFloat(lookahead, ignore)
參量
*Serial*:串行端口對(duì)象。請(qǐng)參閱“ 串行”主頁(yè)上每個(gè)板的可用串行端口列表。
lookahead:用于在流中向前查詢(xún)浮點(diǎn)數(shù)的模式。允許的數(shù)據(jù)類(lèi)型:LookaheadMode。允許lookahead值:

  • SKIP_ALL:掃描流中的浮點(diǎn)數(shù)時(shí),除負(fù)號(hào),小數(shù)點(diǎn)或數(shù)字以外的所有字符都將被忽略。這是默認(rèn)模式。
  • SKIP_NONE:任何內(nèi)容都不會(huì)被跳過(guò),除非第一個(gè)等待的字符有效,否則流不會(huì)被觸摸。
  • SKIP_WHITESPACE:僅跳過(guò)制表符,空格,換行符和回車(chē)符。
    ignore:用于跳過(guò)搜索中指示的字符。例如,用于跳過(guò)數(shù)千個(gè)分頻器。允許的數(shù)據(jù)類(lèi)型:char
    返回值:
    類(lèi)型:float。

Serial.parseInt()

描述
在輸入的序列中查找下一個(gè)有效整數(shù)。如果超時(shí),該函數(shù)將終止(請(qǐng)參見(jiàn)Serial.setTimeout())。
Serial.parseInt()Stream實(shí)用程序類(lèi)繼承。
尤其是:

  • 如果沒(méi)有讀取到可配置的超時(shí)值的字符,或者讀取了非數(shù)字,則分析停止。
  • 如果在發(fā)生超時(shí)(請(qǐng)參見(jiàn)Serial.setTimeout())時(shí)未讀取到有效數(shù)字,則返回0;否則返回0。

句法
*Serial*.parseInt()
*Serial*.parseInt(lookahead)
*Serial*.parseInt(lookahead, ignore)
參量
*Serial*:串行端口對(duì)象。請(qǐng)參閱“ 串行”主頁(yè)上每個(gè)板的可用串行端口列表。
lookahead:用于在流中向前搜索整數(shù)的模式。允許的數(shù)據(jù)類(lèi)型:LookaheadMode。允許lookahead值:

  • SKIP_ALL:掃描流中的整數(shù)時(shí),將忽略數(shù)字或減號(hào)以外的所有字符。這是默認(rèn)模式。
  • SKIP_NONE:任何內(nèi)容都不會(huì)被跳過(guò),除非第一個(gè)等待的字符有效,否則流不會(huì)被觸摸。
  • SKIP_WHITESPACE:僅跳過(guò)制表符,空格,換行符和回車(chē)符。

ignore:用于跳過(guò)搜索中指示的字符。例如,用于跳過(guò)數(shù)千個(gè)分頻器。允許的數(shù)據(jù)類(lèi)型:char
返回值
下一個(gè)有效整數(shù)。資料類(lèi)型:long

8.判斷串口是否就緒** Serial

描述

指示指定的串行端口是否已就緒。

在具有本地USB的板上if (Serial)(或if(SerialUSB)在Due上)指示USB CDC串行連接是否打開(kāi)。對(duì)于所有其他板卡和非USB CDC端口,這將始終返回true。

這是在Arduino IDE 1.0.1中引入的。

句法

if (Serial) while (!Serial) 等等

參量

沒(méi)有

返回值

如果指定的串行端口可用,則返回true。如果在準(zhǔn)備就緒之前查詢(xún)Leonardo的USB CDC串行連接,則僅返回false。類(lèi)型:bool。

9、設(shè)置串口超時(shí)**

Serial.setTimeout()

描述
Serial.setTimeout()設(shè)置等待串行數(shù)據(jù)的最大毫秒數(shù)。默認(rèn)值為1000毫秒。
Serial.setTimeout()Stream實(shí)用程序類(lèi)繼承。
句法
*Serial*.setTimeout(time)
參量
*Serial*:串行端口對(duì)象。請(qǐng)參閱“ 串行”主頁(yè)上每個(gè)板的可用串行端口列表。
time:超時(shí)時(shí)間(以毫秒為單位)。允許的數(shù)據(jù)類(lèi)型:long。
退貨
沒(méi)有

注意和警告
使用通過(guò)*Serial*.setTimeout()以下方式設(shè)置的超時(shí)值的串行函數(shù):

  • *Serial*.find()
  • *Serial*.findUntil()
  • *Serial*.parseInt()
  • *Serial*.parseFloat()
  • *Serial*.readBytes()
  • *Serial*.readBytesUntil()
  • *Serial*.readString()
  • *Serial*.readStringUntil()

也可以看看

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB
  }
}

void loop() {
  //proceed normally
}
/*
   Serial
   串口通訊實(shí)驗(yàn)
*/
int incomedate = 0;
void setup() {

  Serial.begin(9600); //設(shè)置串口波特率9600

  Serial.println(78, BIN);// "1001110"
  Serial.println(78, OCT);// "116"
  Serial.println(78, DEC);// "78"
  Serial.println(78, HEX);// "4E"
  Serial.println(1.23456, 0);// "1"
  Serial.println(1.23456, 2);// "1.23"
  Serial.println(1.23456, 4);// "1.2346"
  Serial.println('N');// "N"
  Serial.println("Hello world.");// "Hello world."
}
void loop() {

  if (Serial.available() > 0)//串口接收到數(shù)據(jù)
  {
    incomedate = Serial.read();//獲取串口接收到的數(shù)據(jù)
    if (incomedate == 'H')
    {
      Serial.println("Good Job!");
    }
  }
  delay(1000);
}

使用的串口Serial其實(shí)是HardwareSerial類(lèi)的實(shí)例化,實(shí)例化過(guò)程中傳入了串口號(hào),實(shí)現(xiàn)過(guò)程如下:

三. Serial1 和 Serial2 的使用

ESP32有三個(gè)串口,串口0,串口1,串口2.

名稱(chēng) 標(biāo)號(hào) 引腳 可用否
串口0 Serial TX 是 GPIO1, RX 是 GPIO 3 可用,很多開(kāi)發(fā)板默認(rèn)用此連接USB/串口換芯片
串口1 Serial1 TX 是 GPIO10, RX 是 GPIO 9 不可用,默認(rèn)被Flash占用
串口2 Serial2 TX 是 GPIO17, RX 是 GPIO 16 可用

arduino-esp32 中定義了 Serial,Serial1,Serial2 三個(gè)對(duì)象, Serial1 是無(wú)法拿來(lái)直接使用, Serial 和 Serial2 可以正常使用,所有除了Serial之外, Serial2 直接使用即可, 引腳接17 ,16
下面, 我們將上面的例子改為Serial2發(fā)送, Serial接受并打印

#include <Arduino.h>
String rev;
void setup() {
  Serial.begin(115200);
  Serial2.begin(115200);
}

void loop() {
  if(Serial2.available())
  {
    rev=Serial2.readString();
    Serial.println("This is ESP32 (serial0)");
    Serial.print("rev from serial2: ");
    Serial.println(rev);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容