前面的章節中,我們已經了解了如何使用一些常見的硬件,但隨著構建的項目越來越多,你可能想要擴展到使用各種不同的傳感器和顯示器。要如何與這些設備通信?
有時,你可能會發現有一個 MicroPython 庫可以使用,其中有人已經將低級函數轉換為易于使用的接口。然而,情況并不總是這樣。幸運的是,有一些連接低級數字設備的標準方法在 MicroPython 中通過 I2C 和 串行外設接口(SPI)得以實現。
I2C 和 SPI 在許多方面非常相似,因為它們都定義了一種將兩個設備之間的雙向接口連接的方式。事實上,許多部件都有這兩種版本接口,這樣你就可以選擇一個適合你的項目的接口。在這兩種情況下,都需要一個主控設備來控制通信(樹莓派 Pico)和一個或多個設備等待來自主控設備的指令。然而,也有一些不同之處。我們會時不時地對比這兩種協議幫助你從中作出合適的選擇
I2C
I2C 的通信在兩條線上進行:一個時鐘(通常標記為 SCL)和一個數據通道(通常標記為SDA)。
這兩個引腳都必須連接到 Pico 的特定引腳上。Pico 上有兩個 I2C 總線(I2C0 和 I2C1),你可以使用其中一種。在我們的示例中,我們將使用 I2C0—GP0 用于 SDA,GP1 用于 SCL。
為了演示這些協議,我們將使用 SparkFun 的 SerLCD 模塊。這樣做的優點是它同時擁有 I2C 和 SPI 接口,因此我們可以看到在相同的硬件下這兩種方法之間的區別。如果只使用 I2C 接口,也可以使用帶 I2C 接口的 LCD1602 液晶屏模塊替代。
這個液晶顯示器可以顯示兩行,每一行最多 16 個字符。它是一種有用的設備,可以輸出關于我們系統的信息。讓我們看看如何使用它。
將 Pico 上的 SDA 引腳與 LCD 上的 SDA 引腳連接,SCL 引腳與 LCD 上的 SCL 引腳連接。由于 I2C 處理通信的方式,還需要一個電阻連接 SDA 到 3.3V 和 SCL 到 3.3V。通常是 4.7kΩ。然而,我們的設備已經包含了這些電阻,所以我們不需要添加任何額外的電阻。
圖為 I2C 連接一個串行 LCD 模塊,編程讓它顯示信息非常簡單:
import machine sda=machine.Pin(0) scl=machine.Pin(1) i2c=machine.I2C(0,sda=sda, scl=scl, freq=400000) i2c.writeto(114, 'x7C') i2c.writeto(114, 'x2D') i2c.writeto(114, "hello world")
這段代碼并沒有做很多事情。它連接到 I2C 設備并發送一些數據。然而,也有一些看起來有點不尋常。writeto() 行中的 114 指的是 I2C 設備的地址。你可以將許多設備連接到 I2C 總線,每次要發送或接收數據時,都需要指定要與之通信的設備的地址。這個地址是硬連接到設備上的。
你應該在設備的文檔中找到設備的地址,你也可以掃描 I2C 總線來查看當前使用的地址。設置好 I2C 總線后,可以運行 scan 方法輸出當前使用的地址:
import machine sda=machine.Pin(0) scl=machine.Pin(1) i2c=machine.I2C(0,sda=sda, scl=scl, freq=400000) print(i2c.scan())
下一個看起來有點奇怪的位是寫入的 x7C 和 x2D 命令。每一個 I2C 設備需要以特定格式發送數據。這方面沒有標準,所以你必須參考設備的文檔了解你正在設置的 I2C 設備。每一個開頭的 x 告訴 MicroPython,我們正在發送一個十六進制字符串,這是一種常見的方式,以確保你正在發送你想要的確切數據。對于我們的液晶顯示器,7C 進入命令模式,2D 清空液晶顯示器,并將光標設置到開始。接下來,我們可以發送數據顯示到屏幕上:
file.close()
當然,在屏幕上只顯示 Hello World 并沒有多大用處,所以讓我們看看如何把它變成一個更有用的東西——溫度計。在之前的系列教程中,我們學習了如何使用 Pico 的內部溫度傳感器使用 ADC 讀取溫度。現在,我們可以在此代碼的基礎上構建一個獨立的溫度計,它不需要計算機讀取輸出。在你的 LCD 仍然像之前一樣連接,運行以下代碼:
import machine import utime sda=machine.Pin(0) scl=machine.Pin(1) i2c=machine.I2C(0,sda=sda, scl=scl, freq=400000) adc = machine.ADC(4) conversion_factor = 3.3 / (65535) while True: reading = adc.read_u16() * conversion_factor temperature = 25 - (reading - 0.706)/0.001721 i2c.writeto(114, 'x7C') i2c.writeto(114, 'x2D') out_string = "Temp: " + str(temperature) i2c.writeto(114, out_string) utime.sleep(2)
這看起來應該很熟悉。對之前的溫度代碼的唯一細微變化是,在輸出計算結果之前,LCD 需要顯示字符,因此我們使用 str 函數將數字轉換為字符串。然后,我們可以將它與 “Temp:” 組合起來,將其構建為一個信息更豐富的輸出。
如你所見,I2C 是一種將其他硬件鏈接到 Pico 的簡單方法。你需要確保你有任何你想要連接的設備的設備文檔,讓你知道什么命令做什么,但只要你知道這一點,你可以很容易地添加各種各樣的比特和鮑勃到你的 Pico 和創建令人印象深刻的構建。
串行外圍接口
我們已經了解了 I2C 的工作原理,現在讓我們來看看 SPI。我們將使用完全相同的 LCD,因此命令和其他一切都是相同的,只是我們發送數據的協議不同 SPI 有四個連接:SCLK、MOSI、MISO 和 CS(有時標記為SS)。SCLK 是時鐘,MOSI 是將數據從你的 Pico 到外圍設備。MISO 將數據從外圍設備發送到 Pico。CS 代表芯片選擇用于將多個設備連接到單個 SPI 總線。你可以把 CS 到 GPIO 引腳并切換這個開關來啟用和禁用顯示,但由于我們只有一個設備,我們可以簡單地將它連接到 GND,以保持它的啟用。因此,SerLCD 的電源線連接到 VBUS 和 GND,我們只需要連接 itsSDO 到 Pico 的 MISO (GP4/SPI0 RX),SDI 接到 MOSI (GP3/SPI0 TX),SCK 接到 SCLK(GP2/SPI0 TX),SCK 和 CS 接到 GND。
SPI 需要四個連接:一個從主服務器獲取數據設備到從設備,另一個在相反的方向上獲取數據,加上電源和 GND。兩根數據線意味著數據可以同時在兩個方向上旅行。這些通常被稱為 Master Out Slave In (MOSI) 和 Master In Slave Out (MISO)。然而,你會見到不同的叫法。如果你看一下 Raspberry Pi Pico 引腳圖,它們被稱為 SPI TX(發送)和 SPI RX(接收)。這是因為 Pico 可以是兩者之一主設備或從設備,所以無論這些連接是 MOSI 還是 MISO,取決于 Pico 的當前功能。在我們使用的液晶顯示器上,它們被標記為 SDI(串行數據輸入)和 SDO(串行數據輸出)SPI 中沒有地址,所以我們可以直接寫代碼:
import machine spi_sck=machine.Pin(2) spi_tx=machine.Pin(3) spi_rx=machine.Pin(4) spi=machine.SPI(0,baudrate=100000,sck=spi_sck, mosi=spi_tx, miso=spi_rx) spi.write('x7C') spi.write('x2D') spi.write("hello world")
在這種情況下,我們使用的是 SPI0,一組可用的引腳是 GP2、GP3 和 GP4。大多數類型的串行通信有一個速度或波特率,這基本上是多少每秒可以通過信道傳輸的數據位。很多事情都會影響這個,比如連接的兩個設備的能力和它們之間的連接(多長時間)如果有其他設備的干擾。如果你發現數據錯誤或丟失問題,那么你可能需要減少它。對于我們的小屏幕,我們只發送一個字節的數據字符,因此我們發送它的速度并不重要,但是對于其他一些SPI設備,微調波特率可能很重要。
讓我們看看下面我們的使用的溫度計代碼:
import machine import utime spi_sck=machine.Pin(2) spi_tx=machine.Pin(3) spi_rx=machine.Pin(4) spi=machine.SPI(0,baudrate=100000,sck=spi_sck, mosi=spi_tx, miso=spi_rx) adc = machine.ADC(4) conversion_factor = 3.3 / (65535) while True: reading = adc.read_u16() * conversion_factor temperature = 25 - (reading - 0.706)/0.001721 spi.write('x7C') spi.write('x2D') out_string = "Temp: " + str(temperature) spi.write(out_string) utime.sleep(2)
正如你所看到的,I2C 和 SPI 之間的代碼實際上差別很小。一旦你完成了電路和代碼,唯一的真正改變是與 I2C 你指定的地址發送數據。
那么,既然它們如此相似,在構建項目時你應該選擇哪種協議呢?有需要考慮的幾個因素。第一個是你想要附加的東西的可用性。有時,一個傳感器只能支持 I2C 或 SPI,所以你必須使用它。但是,如果你有選擇的話對于硬件來說,當你使用多個額外的設備時,影響最大。通過 I2C 你可以在一個 I2C 總線上連接多達 128 個設備;然而,它們都需要有一個單獨的地址。這些地址是硬連接的。如果你想要更多相同類型的傳感器,你可能會受到傳感器的 I2C 地址數量的限制。在本例中,SPI 也許是更好的選擇。
另外,SPI 可以有無限數量的設備連接;然而,每一個都必須有自己的 CS 引腳。在 Pico 上,有 26 個 GPIO 引腳。所以這意味著有 23 哥可用的 CS 引腳。這是假設你不需要任何其他東西。如果可用的 GPIO 非常緊缺,那么你可能需要考慮 I2C。
實際上,對于許多項目,你都可以隨意地使用其中任何一種協議,你可能會發現這選擇使用哪一個更多的是與你在零件箱里找到的零件有關,而不是兩者在技術上的區別。
審核編輯:劉清
-
通信協議
+關注
關注
28文章
1033瀏覽量
41151 -
樹莓派
+關注
關注
121文章
2001瀏覽量
107421
原文標題:樹莓派 Pico 的數字通信協議:I2C 和 SPI
文章出處:【微信號:趣無盡,微信公眾號:趣無盡】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
數字通信協議中,什么是I2C和SPI總線協議?

spi與i2c總線協議的對比分析
I2C通信協議應該如何學習

linux移植MPU6050的I2C驅動

i2c和spi通信協議的概念與區別 I2C/SPI總線通信協議你搞懂沒有
I2C通信協議:了解I2C Primer、 PMBus和SMBus

評論