變頻電風扇調速,我們總是想要由低至高,分段來表示速度,我們可以利用一個 7-節 顯示器 (7-segment LED display),參考以下影片:How to use a 7-segment LED display with the Raspberry Pi Pico
雖然這個例子使用了 Raspberry Pi Pico 開發板,我相信您應該很容易的改在 ESP32-S3 開發板上執行。從這個例子中,我們發現要使用這樣可以顯示 0-9 數字的 display, 我們必須在開發板中相對的對每一個 LED (代表着一個線段, segment),連接到不同的 GPIO 接腳,這樣,我們需要佔用 7 個 GPIO,若是要顯示兩個位數的 00-99 數字,我們需要 14 接腳,若是要推動 4 個位數,那就要 28 個接腳,那實在是太多了!
另外一種做法是用掃描的方式,利用人們的視覺暫留現象,例如用 4 個 GPIO,來啓動相對應位數的七節顯示器,這樣我們就可以用 4 + 7 ,共 11 個 GPIO 就可以來顯示 4 位數的 7 節顯示器。
但是相對的掃描更新方式,在程式中難免會動用到很多的迴圈來實作,我們也發現,當掃描快的時候,顯示器會亮一些,掃描慢一些,亮度變暗,甚至太慢了,變成了閃爍,看不清數字! 而且還要準備字形,在影片中準備了 0 - 9 數字的字形,字形中的節點(segment)要顯示暗(LED off) 的爲 0 , 要顯示亮 (LED on) 的爲 1.
這樣在軟體或者硬體的設計上其實都很麻煩,這還是 7-segment LED display 而已,若是像 8x8 的點矩陣顯示器,一個位數就需要 8 + 8 個 GPIO, 若是四位數就需要 4 + 8 + 8 個 GPIO,在軟體上的複雜程度可以想像變成很高!
您若是瞭解了這種顯示原理,就會同時理解:從這些低解析度的 7-segment LED display, 到高解析度的 LED 顯示螢幕或是液晶電視,其掃描的原理大致相同。
因爲像這種多位數的七節 LED 顯示器非常常見,用途也很廣,因此有很多廠商已經將這些功能整合到 IC 當中了,這樣大大的降低使用這些元器件的軟硬體複雜度。常見的有 I2C 與 SPI 這類的串口界面,當然,有 內建 IC 的模組,售價相對的比較高一點。我們今天以 I2C 界面來說明。
有關 I2C 的詳細說明可以查閱 wiki I2C ,或是上 google 找資料。同樣地,若您有看不懂的地方,歡迎留言提問。
我們今天以下面這個顯示器模組,來說明如何在 Micropython 中使用 I2C 界面:
這個模組使用了 IC TM1367 來驅動一個 4 位數的 7 節顯示器,我們可以從 google 查到 TM1367 的 datasheet
接下來將模組的四個接腳接到開發板上:
GND --> 開發板 GND
VCC --> 開發板 3V3
DIO --> 開發板 GPIO 15 (SDA)
CLK --> 開發板 GPIO 16 (SCL)
依序執行下面的程式
>>> from machine import Pin, SoftI2C
>>> i2c = SoftI2C(scl=Pin(16), sda=Pin(15), freq=100000)
>>> i2c.scan()
[8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119]
>>>
這代表着 TM1637 顯示模組已經接上了,但是有個問題要特別注意:這種 I2C 週邊 IC 其實並沒有完整實現 I2C 的標準。
正常的情況下,一個 I2C 裝置會有一個 I2C 地址,有 7-bit 與 10-bit 地址,不過目前 Micropython 只支援 7-bit 地址。但我們用 scan() 函數去掃描 I2C BUS 時,被詢問到的裝置會回應 ACK 信號。由於 TM1637 並沒有正式指定到 I2C 地址,但是程式需要收到 ACK 才會認爲裝置有接上 BUS,因此對於每一個 I2C 地址的詢問,TM1637 全都回應了! 這代表著會有什麼後果,您可以思考一下,不過在此並不影響使用!
至於 Micropython 的驅動已經有大神寫好了,您可以參考:https://github.com/mcauser/micropython-tm1637
程式庫模組的安裝可以使用 mpremote:
$ mpremote mip install github:mcauser/micropython-tm1637
基本的使用:
import tm1637
from machine import Pin
tm = tm1637.TM1637(clk=Pin(16), dio=Pin(15))
# all LEDS on "88:88"
tm.write([127, 255, 127, 127])
# all LEDS off
tm.write([0, 0, 0, 0])
# show "0123"
tm.write([63, 6, 91, 79])
# show "COOL"
tm.write([0b00111001, 0b00111111, 0b00111111, 0b00111000])
# show "HELP"
tm.show('help')
# display "dEAd", "bEEF"
tm.hex(0xdead)
tm.hex(0xbeef)
# show "12:59"
tm.numbers(12, 59)
# show "-123"
tm.number(-123)
# show temperature '24*C'
tm.temperature(24)
要注意的是,mcauser 的 TM1637 display 驅動,並不是利用 Micropython I2C 程式庫模組,而是自造出了 I2C 的時序信號出來,程式相當簡潔,值得研究!
接下來,您是否可以挑戰用 I2C 的方式自己寫一個驅動呢?