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