一、問(wèn)題/目標(biāo)
前面我們學(xué)習(xí)了 Python語(yǔ)言, 開(kāi)發(fā)無(wú)線電軌智能車模使用的是 MicroPython 語(yǔ)言,如何從 Python 語(yǔ)言編程, 轉(zhuǎn)向 MicroPython 語(yǔ)言編程,下面讓我們來(lái)談?wù)勔韵氯齻(gè)問(wèn)題: (1)他們之間的區(qū)別;(2) MicroPython中特殊的硬件開(kāi)發(fā)軟件包;(3)在 MicroPython 開(kāi)發(fā)單片機(jī)中嵌入式程序的三個(gè)需要注意到的特點(diǎn),Setup-Loop 整體框架結(jié)構(gòu);硬件相關(guān)軟件結(jié)構(gòu);硬件中斷的使用。下面讓我們逐一討論一下。

二、基本原理
1、與Python之間的差異
- Introduction to MicroPython – Python for Microcontrollers
MicroPython 語(yǔ)言是集成了 Python 語(yǔ)言的一個(gè)分支, 實(shí)現(xiàn)了 Python 3.4 版本語(yǔ)言標(biāo)準(zhǔn)。它是專門為在單片機(jī)這類嵌入式微控制器上, 實(shí)現(xiàn)的一款簡(jiǎn)潔穩(wěn)定的Python語(yǔ)言解釋器由于它屬于高級(jí)解釋型語(yǔ)言, 使得單片機(jī)的開(kāi)發(fā)變得容易起來(lái)現(xiàn)在已經(jīng)有眾多的單片機(jī)平臺(tái)都支持 MicroPython 進(jìn)行應(yīng)用軟件的開(kāi)發(fā)。對(duì)于初學(xué)者來(lái)講, 在語(yǔ)法層面, MicroPython 與 Python 語(yǔ)言的差別基本上不易被覺(jué)察。 這里就不做展開(kāi), 大家如果感興趣,可以在 MicroPython 官網(wǎng)進(jìn)行查看。 最后需要說(shuō)明一點(diǎn)的是, 為了便于軟件開(kāi)發(fā), 在MicroPython中有一種交互式程序開(kāi)發(fā)模式, REPL, 也就是 Read Evaluate Print Loop。MicroPython 在此模式下, 不斷讀取從串口輸入的 MicroPython 指令, 執(zhí)行后, 進(jìn)行結(jié)果輸出。這個(gè)過(guò)程不斷循環(huán), 形成一個(gè)交互式開(kāi)發(fā)模式。

比如在Thonny 環(huán)境中,利用上面程序編輯窗口進(jìn)行軟件開(kāi)發(fā)屬于正常程序開(kāi)發(fā),在Shell中就可以使用 REPL 機(jī)制進(jìn)行交互式開(kāi)發(fā),比如下面演示在 Shell 中 命令提示符后面輸入不同命令, 回車后, MicroPython 執(zhí)行結(jié)果的演示。手工輸入, 或者拷貝前面的命令, 都可以進(jìn)行執(zhí)行。
2、硬件軟件包
為了應(yīng)用到單片機(jī)平臺(tái)中的硬件模塊,在 MicroPython 中還集成了很多特殊的軟件包。應(yīng)用這些軟件包可以定義一些與硬件相關(guān)的對(duì)象, 以及相關(guān)的硬件函數(shù)接口。
這里以無(wú)線電軌智能車重核心控制板 ESP32為例, 在它的MicroPython 中就集成了很多的硬件軟件包包括有管腳、異步串口、PWM、ADC 以及外部的 I2C, SPI 串行接口等。通過(guò)這些特殊的硬件驅(qū)動(dòng)軟件包, 我們就可以在Python 語(yǔ)言中訪問(wèn)利用這些硬件資源, 來(lái)控制車模的運(yùn)行, 感知外部環(huán)境等。比如這里是 I2C總線軟件包, 通過(guò)它可以連接單片機(jī)外部很多資源,為了應(yīng)用這個(gè)端口,可以 import machine 軟件包中的 Pin, I2C 模塊,通過(guò)定義相應(yīng)的對(duì)象, 設(shè)置 I2C 總線端口的屬性,并與外部設(shè)備通信。

通過(guò)實(shí)驗(yàn) 掌握更多單片機(jī)的這些硬件資源的特點(diǎn)和使用方法是應(yīng)用單片機(jī)解決車模控制問(wèn)題的管腳所在。
3、嵌入式程序開(kāi)發(fā)
最后, 我們討論一下 MicroPython 開(kāi)發(fā)嵌入式程序的特點(diǎn)。對(duì)于初學(xué)者需要注意三個(gè)方面的內(nèi)容。第一個(gè)就是程序主題大體上呈現(xiàn)設(shè)置與循環(huán)兩部分。在設(shè)置部分,往往需要 import 所需要的軟件包、 對(duì)程序軟件變量和硬件模塊進(jìn)行初始化等然后程序進(jìn)入一個(gè)由 for 或者 while 語(yǔ)句構(gòu)成的無(wú)限循環(huán)結(jié)構(gòu), 在這個(gè)結(jié)構(gòu)中周期的執(zhí)行一系列的指令, 完成控制的主要任務(wù)。第二部分就是需要理解程序中包含有一些與硬件相關(guān)的變量、對(duì)象等。它們需要不停的進(jìn)行循環(huán)刷新和幅值,這些實(shí)時(shí)變量的值反映了單片機(jī)外部端口的電壓信號(hào), 或者通訊數(shù)據(jù)等, 通過(guò)前面的循環(huán)結(jié)構(gòu)進(jìn)行周期的讀取或者賦值。 最終形成對(duì)外部電路的控制。

最后講一下在車模控制中會(huì)碰到的另外一個(gè)特殊編程技術(shù), 那就是中斷。中斷是在 單片機(jī)內(nèi)部硬件在滿足某些條件下執(zhí)行的程序片段, 比如當(dāng)定時(shí)器硬件出現(xiàn)溢出是會(huì)產(chǎn)生周期的定時(shí)器中斷; 在外部端口出現(xiàn)電壓變化時(shí)會(huì)出現(xiàn) IO 信號(hào)中斷;在串口接收到數(shù)據(jù)的時(shí)候會(huì)出現(xiàn)串口通訊中斷等。靈活的應(yīng)用中斷是單片機(jī)嵌入式開(kāi)發(fā)的重要技巧。 通常情況下, 前面的 Loop 循環(huán) 以及中斷程序, 在嵌入式軟件開(kāi)發(fā)中往往被稱為嵌入式程序的 后臺(tái) 任務(wù)和 前臺(tái) 任務(wù)。

三、應(yīng)用舉例
這里以無(wú)線電軌智能車綜合測(cè)試程序?yàn)槔? 來(lái)說(shuō)明一下 MicroPython 程序的特點(diǎn)。對(duì)于初學(xué)者來(lái)看, 這個(gè)程序顯得有點(diǎn)復(fù)雜,但在整體上, 大家看到, 它分為前后兩部分。 前面部分屬于 Setup 初始化部分, 做了很多的硬件初始化, 也定義了一些函數(shù)。后面一部分,就是有 while 形成的 循環(huán)控制部分, 這些屬于軟件的后臺(tái)任務(wù)部分。在每一次循環(huán)中依次執(zhí)行 OLED 屏幕的刷新,按鍵的檢測(cè)處理,以及控制板上 LED 的閃爍, 用于顯示程序運(yùn)行狀態(tài)。此時(shí)估計(jì)大家會(huì)有一個(gè)疑問(wèn), 車模運(yùn)動(dòng)中舵機(jī)和電機(jī)控制代碼在哪里執(zhí)行呢?

為了解決這個(gè)疑問(wèn), 大家看這個(gè)綜合演示程序的中間部分,在這里定義了 ESP32 硬件定時(shí)器對(duì)象, timer0,接下來(lái)定義了一個(gè)函數(shù), 用于定時(shí)器中斷函數(shù)后面是對(duì)定時(shí)器進(jìn)行初始化,設(shè)置定時(shí)器工作模式為周期中斷模式,中斷周期為 10毫秒, 也就是100Hz 的重復(fù)頻率,第三個(gè)參數(shù)設(shè)置中斷服務(wù)程序。這個(gè)程序就是前面定義的 timer0 irq 函數(shù)。因此這個(gè)中斷程序就會(huì)在 Timer0 的中斷驅(qū)動(dòng)下, 每隔精確的 10毫秒, 就被執(zhí)行一次。 中斷程序?qū)儆谇度胧杰浖那芭_(tái)任務(wù)。 中斷程序定義了中斷任務(wù)這些是需要用到的全局變量, 和程序中其它函數(shù)進(jìn)行信息傳遞。讀取電磁場(chǎng)傳感器的交流電壓值判斷賽道的屬性計(jì)算舵機(jī)偏移量對(duì)舵機(jī)偏移量進(jìn)行限幅下面就是設(shè)置電機(jī)運(yùn)行速度和舵機(jī)偏移量。中間部分是用于控制電機(jī)是否運(yùn)行的邏輯。之所以利用中斷周期進(jìn)行車模控制, 主要是為了保證控制時(shí)間的精確和周期的穩(wěn)定。 這要比在 while 循環(huán)中執(zhí)行控制命令更加可靠。

大家感興趣還可以研究一下這個(gè)程序前面的初始化過(guò)程,對(duì)于一些和硬件相關(guān)的模塊的使用,可以配合后面相關(guān)的實(shí)驗(yàn)介紹進(jìn)行聯(lián)系。通過(guò)這個(gè)程序, 大家能夠熟悉 MicroPython 編寫嵌入式軟件的一些特點(diǎn)。
