在第一章部落格中,我們講了Arduino對Esp32的一個環境設定,以及瞭解到了常用的一個匯流排通訊協定,其中有SPI,IIC,UART等,今天我為大家帶來UART串列埠通訊和c#串列埠進行通訊的一個案例,以及什麼是中斷,中斷的作用和實踐,話不多說,讓我們正式開始。
在第一篇部落格中,我們講了UART是需要一個接收一個傳送的引腳,總共兩個,分別是TXD(傳送引腳),RXD(接收引腳),不管是什麼型別的微控制器串列埠引腳都是這兩個,可能有的是少了最後面的那個D,但是都是一樣的東西,在ESP32的開發板上,是有三對UART的引腳的,也就是說板子上有三個串列埠可以供我們使用,如下圖,Serial0對應的引腳為1和3,Serial1對應的引腳為9和10,Serial2對應的引腳為16和17,但是在我們燒錄的時候,1和3是不能使用的,因為我們通過USB將微控制器連線到電腦上,使用的串列埠引腳就是1和3,所以我們可使用串列埠只有兩個,而Arduino IDE上面,對應的Serial也有四個靜態類,分別是Serial,Serial1和Serial2以及Serial3。雖然他的數量和我們ESP32的串列埠數量是一樣,但是隻有第一個可以使用,後面兩個我們是無法使用的,因為後面兩個對應的引腳和我們ESP32的引腳是不相同的,我們可以從下面第二個圖看到,Serial1,Serial2的 PINS是和我們ESP32的引腳是對不上的,所以我們在串列埠開發的時候是不使用這兩個,對於第一個Serial我們是可以使用的。
我們如果需要使用ESP32的串列埠開發,在ESP的開發包裡,官方給我們提供了一個HardwareSerial的一個串列埠庫,裡面我們可以使用開發板上面的串列埠,同時將引腳指定為我們引腳圖上面的引腳。這個庫的位置為我們Arduino IDE目錄下的hardware/espressif/esp32/cores/esp32可以找到這個庫,這個資料夾下包含了一些ESP32的官方庫;使用這個HardwareSerial.h檔案我們可以實現使用ESP32開發板上面的串列埠進行開發,接下來我們在程式碼中去了解他如何使用。
在下面的程式碼中,我們開始了一個簡單的一個串列埠通訊,在程式碼第一行,是和c語言一樣引入我們需要的庫檔案,然後在第二行,定義了HardwareSerial這個類的一個MySerial1物件,裡面的建構函式的值是1代表著,我們將使用第一個串列埠,在下面的setup裡面,我們開始啟動了MySerial1這個串列埠物件,啟動的波特率是9600,資料長度是8,校驗位是NONE,停止位是1,以及串列埠的rx的引腳是16,tx的引腳為17。在下一行程式碼,我們傳入了一個我們下方定義的receiveEvent的一個方法,這個方法用來接收串列埠接收資料的一個回撥,將我們這個方法指標傳入進去,在串列埠接收到資料之後,會進入到我們這個方法中。
最後一行程式碼,我們是啟用了第0個串列埠,波特率是9600。
可能上面的程式碼有朋友就有疑惑了,明明16和17在引腳圖中定義的串列埠是2,為什麼這裡定義的是1呢,實際上這個我們可以自己修改這個串列埠的定義和引腳,這個建構函式傳入的引數取值範圍為0,1,2,對應的是我們開發板上的三個UART串列埠,在begin哪裡傳入的引腳和這個0,1,2是沒有任何關係的,但是這個傳入的引腳必須是開發板上三個UART串列埠之一,所以我們也可以定義為MySerial2.begin(9600,SERIAL_8N1,10,9);這裡的0,1,2僅對應有三對串列埠,不指定對應的引腳,在begin方法我們指定對應的串列埠的引腳。
在下面的接收到串列埠訊息的回撥中,我們第一行程式碼呼叫了available這個方法,這個方法返回的是一個int引數,當然了我們這塊也可以寫available()>0,也是可以的,這個方法是從串列埠快取中讀取我們接收到的資料長度,這個條件成立,說明我們是有接收到資料,然後在裡面我們開始去讀取資料。
在所有的Serial都是及程式Arduino的一個Stream的一個基礎類,這個類提供了一些我們對資料處理的一個方法,所以在下面的程式碼中,我們將讀取的資料轉為字串,然後將程式碼延遲暫停了一秒,隨後,我們使用我們的串列埠物件,將接收到的資料寫入緩衝區,緩衝區會把我們寫入的資料,在傳送出去,即將println裡面傳入的引數傳送到我們的串列埠傳送方,誰發的資料,誰就會收到"i am receive!!"+str。
#include <HardwareSerial.h>
HardwareSerial MySerial1(1);
void setup() {
// put your setup code here, to run once:
MySerial1.begin(9600,SERIAL_8N1,16,17);
MySerial1.onReceive(receiveEvent);
Serial.begin(9600);
}
void loop() {
}
void receiveEvent()
{
if(MySerial1.available())
{
String str= MySerial1.readString();
delay(1000);
MySerial1.println("i am receive!!"+str);
}
delay(1000);
}
Stream包括了以下方法,其中繼承Stream的分別為串列埠,IIC通訊的Wire,SD卡的一個類,以及用於網路連線的Ethernet類,都可以使用這些方法用來對資料進行操作。
C#方面的程式碼則簡單很多,介面一個開啟串列埠的按鈕,一個傳送資料的按鈕和文字方塊,以及用來接收資料顯示的文字方塊。
在程式碼中我們開啟了串列埠,指定了開啟的是哪一個串列埠,一些屬性是需要和ESP32那邊設定一樣的,在上面我們設定波特率為9600,資料為是8,停止位是1,校驗位是NONE,所以在c#這邊我們也需要這樣設定,不過校驗位預設是NONE的,所以此處我們沒有設定,然後開啟串列埠,註冊了一個接收到資料的一個回撥,然後定義一個1024的位元組陣列,從串列埠讀取資料,返回讀取的資料長度,然後在對剛才定義的1024位元組陣列進行擷取,然後通過UTF-8的格式轉為字串,然後顯示到介面上的富文字方塊中,在傳送按鈕事件中,我們從輸入框讀取資料轉為位元組陣列,然後將資料寫入到串列埠中去即可。
public partial class Form1 : Form
{
private SerialPort serialPort = new SerialPort("COM6");
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
serialPort.BaudRate = 9600;
serialPort.StopBits = StopBits.One;
serialPort.DataBits = 8;
serialPort.Open();
serialPort.DataReceived += (a, b) => {
var serial = a as SerialPort;
var data = new byte[1024];
var res=serial.Read(data,0, data.Length);
data = data[..res];
string st = Encoding.UTF8
.GetString(data);
BeginInvoke(() => { richTextBox1.Text += st; });
};
}
private void button2_Click(object sender, EventArgs e)
{
var str = Encoding.UTF8.GetBytes(textBox1.Text);
serialPort.Write(str, 0, str.Length);
}
}
在此處的範例,我們需要準備一個USB轉TTL的模組,四根母對母的杜邦線,在程式燒錄之後,我們需要將使用杜邦線讓USB轉TTL模組和微控制器進行連線,VCC或者5V接微控制器的5V引腳,USB轉TTL的GND和微控制器的GND相接,然後USB轉TTL的rxd引腳和微控制器17引腳相接,txd引腳和微控制器的16引腳相接,如下圖所示接線,5v不可和gnd接反,否則可能會燒壞模組,確認接線無誤後,將USB轉TTL模組插入電腦中,然後程式碼中執行c#程式,電機開啟串列埠,隨後傳送資料,可以接收到微控制器的反饋。
串列埠通訊是物聯網中,必不可少的一種通訊方式,通常情況下都是RX接TX,TX接RX,除非是模組廠商的規定,否則都是這樣接線,在後面的課程中,我會依次對IIC,以及PWM,還有SPI,以及中斷單獨做一個講解,歡迎大家關注,學習和探討,我會將我所知道的都會分享,同時,後面也會有STM32系列的教學。如果有感興趣的朋友,可以加QQ群一起來討論822084696。