如何基于ESP32和MicroPython構(gòu)建一個(gè)RFID控制的MP3播放器
有一段時(shí)間了,我有一個(gè)圣誕節(jié)抽獎(jiǎng)與射頻識(shí)別標(biāo)簽為ESP32編程。貢獻(xiàn)用語(yǔ)音輸出的測(cè)量結(jié)果回來(lái)。我用手機(jī)記錄下了這些零碎的語(yǔ)言,并將其傳輸?shù)絊D卡上?,F(xiàn)在你當(dāng)然也可以把音樂(lè)保存在SD卡上,并通過(guò)射頻識(shí)別標(biāo)簽調(diào)用——一個(gè)具有擴(kuò)展?jié)摿Φ腗P3播放器已經(jīng)準(zhǔn)備好了。我嘗試了各種編程方法。最初看起來(lái)很有希望和有趣的線程方法,最終不得不放棄,轉(zhuǎn)而支持傳統(tǒng)編程,因?yàn)樾阅懿环衔业南敕?。我現(xiàn)在用這個(gè)系列的新文章向你介紹這個(gè)解決方案
ESP32和ESP8266上的Micropython
今天:
帶RFID的MP3播放器
嚴(yán)格來(lái)說(shuō),我是通過(guò)關(guān)于ESP32/ESP8266 dem Raspberry Pi Pico和那臺(tái)PC上的串行接口的文章產(chǎn)生了這篇文章的想法。我想展示RS232端口上的其他一些應(yīng)用程序。這里使用的DFPlayer Mini是通過(guò)串行接口控制的。由于使用了雙向數(shù)據(jù)交換,因此只需一個(gè)ESP32或Raspberry Pi Pico作為控制器。PC也可以通過(guò)RS232 TTL轉(zhuǎn)換器直接與DFPlayer Mini進(jìn)行對(duì)話,但我將其省略。
兩個(gè)迷你斷路器上的組件通過(guò)許多跳線電纜查看鳥(niǎo)類游戲。畢竟,使用了四個(gè)接口,SPI (RFID讀取器),I2C (OLED顯示器),RS232 (DFPlayer Mini)和ADC (Poti)。
圖1:MP3播放器的結(jié)構(gòu)與SH1106
有幾件事需要考慮。DFPlayer Mini必須提供5V。因此,具有5V電平的脈沖也在他的PIN TX上,因?yàn)槭敲β狄_。由于ESP32只能承受3.3V到其gpio,電平必須通過(guò)電壓分壓器降低。我選擇了1kΩ和2.2kΩ。您還可以采用其他比例為1:2的值。相反,RX輸入端的DFPlayer可以很好地處理ESP32的3.3V信號(hào)。
如果揚(yáng)聲器用黑線放在GND上,則5V圈的電流約為。450馬!這是因?yàn)檫B接SP1和SP2引線為5V電平。因此,只將兩個(gè)揚(yáng)聲器連接到SP1和SP2,不要連接到GND。即使您只使用一個(gè)揚(yáng)聲器,它的線路也屬于SP1和SP2(圖2中黃色部分)。否則你必須通過(guò)ELKO連接揚(yáng)聲器。
圖2:帶有4gb SD卡的DFPlayer Mini
ESP32上的ADC輸入可以處理高達(dá)2.4V的張力。然而,電位器是3.3V。因此,我通過(guò)計(jì)算2.2kΩ的電阻來(lái)降低失調(diào)電壓。因此,電位器可以放在面包板上,我提供了一個(gè)5針筆帶的連接。
圖3:面包板蒙太奇的波蒂與筆條
你必須特別小心上面提到的顯示。SDA和SCK的連接是一致的,但是+VCC和GND的引腳與96“模塊(上面的筆條)在1.3”模塊(下面的筆條)中相互交換。我在圖4的電路中使用了一個(gè)1.3“模塊。
圖4:運(yùn)行中的SH1106
圖5:MP3播放器-電路
為了自主操作,我為16850的鋰離子電池提供了一個(gè)電池所有者。它可以通過(guò)封閉的電纜直接連接到ESP32,然后接管其他模塊的供應(yīng)。
圖6:電池所有者18650
連接圖可能有助于將電路放在一起。
圖7:連接計(jì)劃
一架ESP32接管了主要位置。為了使用它,需要兩個(gè)面包板,它們連接到中間的電源導(dǎo)軌上,這樣你就可以用引腳排的間隔到達(dá)那里,也可以在邊緣插入電纜。
ESP32的小兄弟,ESP8266,不適合我們的目的,因?yàn)樗荒芴峁┑诙€(gè),完整的接口,我們需要它來(lái)控制DFPlayer。
Uart是通用異步接收器/發(fā)射器的縮寫。我們還從tony的終端與控制器討論了這樣一個(gè)接口。ESP32 /ESP8266通過(guò)USB線纜與PC相連,主控板上的USB- rs232 - ttl轉(zhuǎn)換器將數(shù)據(jù)流量傳輸?shù)娇刂破鞯腢ART0接口。這反過(guò)來(lái)又提供給數(shù)據(jù)流sys.stdin。輸入命令從這個(gè)文件對(duì)象提供。sys。stdout通過(guò)UART0將輸出數(shù)據(jù)發(fā)送到tony的終端。因此,我們不能使用UART0向mini-MP3播放器發(fā)送命令并從中接收數(shù)據(jù)。一個(gè)UART接口只能有一個(gè)對(duì)應(yīng)物。ESP8266有第二個(gè)UART接口,但實(shí)際上只有一半,因?yàn)橹挥幸粭lTXD線(傳輸線),沒(méi)有RXD線(接收管理)可用。但也會(huì)有一個(gè)樹(shù)莓派Pico (W),它有兩個(gè)免費(fèi)提供的組件。程序是一樣的,只是pin分配不同。
Micropython -語(yǔ)言-模塊和程序
要安裝托尼,你會(huì)在這里找到一個(gè)詳細(xì)的說(shuō)明(英文版)。還有一個(gè)關(guān)于ESP芯片上的Micropython固件(截至2024年1月25日)如何被燒毀的描述。
Micropython是一種解釋器語(yǔ)言。Arduino IDE與Arduino IDE的主要區(qū)別在于,你只需要在ESP32上閃爍Micropython固件一次,以便控制器理解Micropython指令。您可以使用Thonny,μpycraft或ESPTOOL.PY。對(duì)于安東尼,我在這里描述了這個(gè)過(guò)程。
一旦固件閃過(guò),你就可以很容易地在對(duì)話框中與控制器對(duì)話,測(cè)試單個(gè)命令并立即看到答案,而無(wú)需事先編譯和傳輸整個(gè)程序。這正是Arduino IDE困擾我的地方。如果您可以檢查語(yǔ)法和硬件的簡(jiǎn)單測(cè)試,以便在編寫程序之前通過(guò)命令行嘗試和改進(jìn)函數(shù)和整個(gè)程序部分,則可以節(jié)省大量時(shí)間。出于這個(gè)目的,我總是喜歡創(chuàng)建小型測(cè)試程序。作為一種宏,它們總結(jié)了重復(fù)出現(xiàn)的命令。然后從這些程序片段開(kāi)發(fā)整個(gè)應(yīng)用程序。
自動(dòng)啟動(dòng)
如果程序要通過(guò)打開(kāi)控制器自動(dòng)啟動(dòng),請(qǐng)將程序文本復(fù)制到新創(chuàng)建的空白磁貼中。將此文件保存在工作區(qū)的boot.py下,并將其上傳到ESP芯片。該程序?qū)⒃谙麓螐?fù)位或開(kāi)機(jī)時(shí)自動(dòng)啟動(dòng)。
測(cè)試程序
tony - ide中當(dāng)前編輯器窗口中的程序通過(guò)F5按鈕手動(dòng)啟動(dòng)。這可以比鼠標(biāo)點(diǎn)擊開(kāi)始按鈕或通過(guò)菜單運(yùn)行更快地完成。只有程序中使用的模塊必須在ESP32的flash中。
在兩者之間,Arduino id ?
如果您以后將控制器與Arduino IDE一起使用,只需以通常的方式刷新程序。然而,ESP32/ESP8266隨后忘記了它曾經(jīng)說(shuō)過(guò)Micropython。相反,任何包含Arduino IDE或AT-Firmware或Lua或…可以很容易地提供micropython固件。這個(gè)過(guò)程總是像這里描述的那樣。
這個(gè)項(xiàng)目
概述
播放列表的選擇是在這個(gè)項(xiàng)目中通過(guò)RFID進(jìn)行的,播放列表的選擇是在這個(gè)項(xiàng)目中通過(guò)數(shù)據(jù)進(jìn)行的。在這個(gè)項(xiàng)目中,通過(guò)讀取地圖上的ID來(lái)選擇播放列表。然而,這顯然超出了本文的范圍,可能是另一個(gè)博客系列的主題。根據(jù)ID(8位十六進(jìn)制數(shù)字),ESP32可以指示DFPlayer Mini播放SD卡文件夾中的MP3文件。訂單名稱和編號(hào)與標(biāo)題編號(hào)一起顯示在顯示器上。用戶說(shuō)明也顯示在顯示屏中。
RFID閱讀器
由于SPI總線,布線也比I2C總線更復(fù)雜,只有2條線。SPI總線設(shè)備沒(méi)有硬件設(shè)備地址,但是它們有一個(gè)芯片選擇連接(CS),如果要對(duì)設(shè)備進(jìn)行尋址,它必須處于低電平。數(shù)據(jù)傳輸?shù)墓ぷ鞣绞揭灿幸稽c(diǎn)不同,它總是同時(shí)發(fā)送和接收。這里沒(méi)有必要說(shuō)明更接近的過(guò)程,因?yàn)轭怣frc522為我們做了這些。我們只會(huì)通知建造商后續(xù)任務(wù)和傳輸速度。傳輸工作與3.2兆赫的艦隊(duì)。相比之下,I2C工作頻率高達(dá)400kHz。
我們自己的函數(shù)readuid()讀取卡片的清晰標(biāo)識(shí),并將其作為十進(jìn)制數(shù)和十六進(jìn)制撥號(hào)返回。這些卡片是通過(guò)OLED顯示器請(qǐng)求的。因此,該函數(shù)不會(huì)阻塞整個(gè)進(jìn)程,超時(shí)確保有序退出。在這種情況下,返回值為None,而不是卡ID。
為了讓播放列表卡發(fā)揮作用,我們需要一張主卡。為此,我們從堆棧中取出任何卡片或芯片,讀取ID,從而在程序開(kāi)始時(shí)用十進(jìn)制值證明變量,如下所示:
Masteride = 4217116188。
在第一次啟動(dòng)時(shí),ESP32注意到仍然沒(méi)有包含播放列表卡數(shù)據(jù)的文件,需要主卡。識(shí)別后,將請(qǐng)求播放列表卡。讀取ID后,將其寫入文件,并再次請(qǐng)求主卡。繼續(xù)閱讀直到最后一張播放列表卡。如果在請(qǐng)求主卡后10秒內(nèi)沒(méi)有提供播放列表卡,則檢測(cè)過(guò)程結(jié)束并開(kāi)始主程序。為了完全從前面開(kāi)始,我們可以通過(guò)thony - console刪除播放列表卡id。當(dāng)然,也可以在tony編輯器窗口中編輯該文件。
Dfplayer迷你
與前鋒的溝通總是以同樣的方式進(jìn)行。發(fā)送和接收10字節(jié)的塊。這種積木的結(jié)構(gòu)是這樣的。類Dfplayer的方法broadcommand()負(fù)責(zé)正確的傳輸。
開(kāi)始-字節(jié)0x7e
版本號(hào)0xff
有效負(fù)載長(zhǎng)度0x06(從版本號(hào)到參數(shù)2包括1)
命令
反饋0x00(否)或0x01(是)
參數(shù)高
參數(shù)低
檢查高
檢查低
EndeByte 0 xef
命令代碼可以在數(shù)據(jù)表中找到。我用它來(lái)實(shí)現(xiàn)模塊dplayer .py方法中最重要的代碼。我們目前的項(xiàng)目只需要其中的幾個(gè)。但是看看文件pfplayer.py(2024年1月24日的Rev 1.3)
聲音文件的處理是用免費(fèi)工具Audacity,也很容易將聲音文件格式重新編碼為MP3。更大的努力意味著改變文件名,使其符合DFPlayer Mini的要求。這些文件位于以兩位數(shù)字命名的文件夾中。這些是播放列表。
圖8:SD卡的文件夾視圖
文件名可以保留其舊名稱,但必須提供一個(gè)由三位十進(jìn)制數(shù)組成的前綴。
圖9:帶有前綴的文件名
手動(dòng)重命名可能仍然可以處理幾個(gè)文件,如果超過(guò)十個(gè),就會(huì)變得非常煩人。這就是為什么我使用了另一個(gè)免費(fèi)工具Advanced Renamer。安裝文件邀請(qǐng)您從芯片服務(wù)器下來(lái)。
圖10:下載高級(jí)重命名器
安裝時(shí),只需跟隨助手即可。收集為SD卡上的文件夾選擇的文件的最佳方法是在工作目錄或SD卡上。標(biāo)記文件夾中的所有文件,并將包拉到重命名窗口。作為Batch方法,選擇Add,然后將其放入過(guò)濾器窗口1:添加屬性,如圖11所示。
圖11:高級(jí)重命名器中的過(guò)濾器設(shè)置
此窗口中的每個(gè)更改都會(huì)立即對(duì)預(yù)覽產(chǎn)生影響。要接管,請(qǐng)單擊右上方的“批量啟動(dòng)”。就是這樣。
圖12:源名稱和結(jié)果
MP3播放器
在所有的準(zhǔn)備工作之后,是時(shí)候?qū)?xiàng)目進(jìn)行編碼了。我們開(kāi)始吧。一如既往,節(jié)目從進(jìn)口業(yè)務(wù)開(kāi)始。如果您在編輯器窗口中打開(kāi)mp3player.py將是最好的,然后您可以在那里閱讀概述,同時(shí)我們將介紹這里的工作方式。
# mp3player.py
#適用于RC522 @ 13,56 mhz
從dfplayer導(dǎo)入dfplayer
進(jìn)口mfrc522
引腳,SoftI2C, SPI, ADC,復(fù)位
#從oled導(dǎo)入oled # vorssight: GND Vcc SCK SDA
從oled_SH1106導(dǎo)入OLED # vorssight: Vdd GND SCK SDA
從時(shí)間導(dǎo)入睡眠
從sys導(dǎo)入退出
從超時(shí)導(dǎo)入*
我們從DFPlayer .py中導(dǎo)入DFPlayer類,而從mfrc522.py中導(dǎo)入所有內(nèi)容。這兩個(gè)文件必須被放入ESP32的閃存中。兩個(gè)標(biāo)記都在電影管理器中,右鍵單擊,上傳到/。
模塊機(jī)提供接口操作的類。根據(jù)所使用的顯示模塊,必須激活或注釋以下兩行中的一行。
對(duì)于短暫的被動(dòng)休息,我們從時(shí)間模塊獲得睡眠()。我們使用exit() out of sys函數(shù)確保一個(gè)干凈的程序退出。從模塊超時(shí),我們得到所有(*)在我們的范圍,這是需要的非阻塞軟件定時(shí)器。當(dāng)從該模塊調(diào)用方法時(shí),該船尾并不適用于該模塊。
沒(méi)有星號(hào)的,例如:
超時(shí)。timeoutms (1000)
與明星:
Timeoutms (1000)
接下來(lái),在相應(yīng)的包中實(shí)例化對(duì)象。我們從ADC對(duì)象開(kāi)始,我們需要從電位器讀取張力。我們將控制DFPlayer Mini的音量。
卷= ADC(銷(36)
vol.atten (vol.ATTN_11DB)
vol.width (vol.WIDTH_10BIT)
強(qiáng)力器的研磨觸點(diǎn)連接GPIO36。如果弱變?yōu)?1 dB,則達(dá)到高達(dá)2.4V的掃描。我們將分辨率設(shè)置為10位。
RX_Pin = 16
TX_Pin = 17
busyPin = 27
df = DFPlayer (busyPinNbr = busyPin,
txd = TX_Pin,
rxd = RX_Pin,
體積= 15)
Sleep(2) #等待玩家初始化
numOfTitles = df.getNumberOfFiles ()
print(" title gesamt:", numOfTitles)
DFPlayer類設(shè)置ESP32本身的UART1。構(gòu)造器只需要將busy-Pin、RX-Pin和tx-Pin上的gpio編號(hào)連接即可。缺省情況下,Pin已連接。通過(guò)詢問(wèn)SD卡上的文件總數(shù)。
spi = spi(2,波特率= 3200000)
# cs = sda
RDR = mfrc522。MFRC522(spi, cs=5,波特率=3200000)
Spi2硬件接口占用GPIOS 18 (SCK), 23 (Mosi)和19 (Miso),還有5 (CS)。RFID板上的選片連接以SDA命名。我們將波特率定義為3200000Hz。
i2c = SoftI2C (sci =銷(22),sda =銷(21))
d = OLED (i2c)
對(duì)于顯示,我們實(shí)例化一個(gè)I2C對(duì)象,并在此過(guò)程中給出OLED對(duì)象的構(gòu)造函數(shù)。
主卡是向系統(tǒng)宣布播放列表標(biāo)簽的RFID日。我們?cè)诔绦蛲瓿珊罅⒓创_定數(shù)值,然后在此時(shí)輸入它。
MasterID=4217116188 # 0XFB5C161C
列表列表包含播放列表的名稱。
listen=[
"COUNTRY",
"BLACKMOORSNIGHT",
"YOUTUBE",
"SCHLAGER",
"HITS",
"VON CD"
"OLDIES"
]
下面是一些函數(shù)的聲明。Readuid()讀取標(biāo)簽的標(biāo)識(shí)號(hào)。我們交出OLED顯示對(duì)象,一個(gè)用于卡片類型的字符串和一段以毫秒為單位的時(shí)間,在此結(jié)束后,該功能將在任何情況下離開(kāi)。變量song是全局聲明的,這樣在函數(shù)中分配的值在主程序中可用。我不會(huì)在Display和ReplaB中討論所有版本,它們部分用于告知用戶和開(kāi)發(fā)過(guò)程中的故障排除,并通過(guò)自制文本進(jìn)行解釋。
非阻塞軟件計(jì)時(shí)器的獲取是通過(guò)Timeoutms()方法設(shè)置的。在Timeoutms()中,函數(shù)是隱藏的compare(),一個(gè)所謂的Closure.Timeoutms()返回一個(gè)引用compare(),我們將標(biāo)識(shí)符分配給它。與sleep()不同的是,其他指令可以在計(jì)時(shí)器期間執(zhí)行。因此,While循環(huán)一直運(yùn)行到函數(shù)reap(), alias compare(), True返回為止。這個(gè)過(guò)程的背景可以在裝飾器上的閉包文檔中找到。
ef readUID(display, kartentyp, timeout):
global song
display.clearFT(0, 1, 15, 2, False)
display.writeAt("PUT ON", 0, 1, False)
display.writeAt(kartentyp, 0, 2)
readTimeOut=TimeOutMs(timeout)
while not readTimeOut():
(stat, tag_type) = rdr.request(rdr.REQIDL)
if stat == rdr.OK:
(stat, raw_uid) = rdr.anticoll()
if stat == rdr.OK:
display.clearFT(0, 3, 15, 3)
display.writeAt("Card OK", 0, 3)
userID=0
for I in range(4):
userID=(userID<<8) | raw_uid[i]
userIDS="{:#X}".format(userID)
display.writeAt(userIDS+" ", 0, 4)
sleep(2)
df.reset()
song=0
return userID, userIDS
return None
使用RDR.MEQUEST(),讓我們放入一個(gè)輸入進(jìn)程。如果請(qǐng)求成功,我們將在下一步中獲取ID。如果這一步也成功了,讓我們開(kāi)始評(píng)估。從MFRC522中,我們得到一個(gè)字節(jié)- plet,我們分四個(gè)步驟將其轉(zhuǎn)換為32位數(shù)字。useride中前面的結(jié)果被推到左邊,8被推到左邊,插曲被裝飾。然后我們將整個(gè)結(jié)果轉(zhuǎn)換為十六進(jìn)制字符串,通常是8位數(shù)字。
有兩秒鐘的時(shí)間讀取顯示,然后我們將DFPlayer Mini放回去,并將歌曲計(jì)數(shù)器設(shè)置為0,因?yàn)檫€應(yīng)該通過(guò)讀取ID啟動(dòng)一個(gè)新的播放列表。如果讀取嘗試失敗或時(shí)間剛剛過(guò)期,則返回None,而不是數(shù)字和字符串形式的ID。
如果您已經(jīng)進(jìn)入程序,此時(shí),您已經(jīng)可以開(kāi)始讀取主卡的ID。或者,您可以mp3player.py Download并在第73行輸入以下說(shuō)明。然后保存并在編輯器窗口中啟動(dòng)程序。
退出()
根據(jù)已釋放的Repl-Prompt,輸入如下說(shuō)明。現(xiàn)在把你的萬(wàn)事達(dá)卡交給讀者。上述輸出數(shù)值為Masteride a。
Readuid (D,“Test”,6000)
0 xfb5c161c
(4217116188, ' 0 xfb5c161c ')
這個(gè)主卡使用下一個(gè)函數(shù)addid(),該函數(shù)負(fù)責(zé)注冊(cè)播放列表卡。如果ESP32的文件系統(tǒng)中還沒(méi)有名為slavecards.txt的文件,主程序?qū)⒃诘谝淮螁?dòng)時(shí)調(diào)用它。但是也可以手工調(diào)用addid()來(lái)創(chuàng)建文件和/或注冊(cè)其他播放列表標(biāo)簽。
首先我們要主卡并讀取ID。如果操作成功,則M從十進(jìn)制值和十六進(jìn)制字符串中接收Tupel,否則為None。我們通過(guò)解壓到主ID上的數(shù)字、字符串和偏移量來(lái)粉碎這個(gè)圖。當(dāng)閱讀指令完成后,還有三秒鐘的時(shí)間放入新的播放列表卡。
def addUID(display):
display.clearAll()
m=readUID(display, "Master", 3000)
print("Master", m)
if m is not None:
mid, mids= m
if mid==MasterID:
print("Master OK")
u=readUID(display, "Slavecard", 3000)
if u is not None:
uid, uids=u
if uid is not None and uid != MasterID:
with open("slavecards.txt", "a") as f:
f.write("{}\n".format(uids))
display.writeAt("New slave written", 0, 4)
display.writeAt("{}".format(uids), 0, 5)
sleep(5)
return True
Else:
display.writeAt("ERROR!!!", 0, 3)
display.writeAt("Card not added!", 0, 4)
return False
Else:
display.writeAt("ERROR!!!", 0, 3)
display.writeAt("Not mastercard", 0, 4)
sleep(3)
return False
和之前一樣,MSo現(xiàn)在包含U,讀取過(guò)程成功時(shí)的ID值。如果uid不是None并且該卡不是master卡,則該卡被注冊(cè)。使用wither-A文件對(duì)象創(chuàng)建,并在標(biāo)識(shí)符F下打開(kāi)附加文本行。我們還寫入讀入的十六進(jìn)制字符串,并附帶行結(jié)束符號(hào)“\ n”= 0x0a。通過(guò)離開(kāi)萎凋塊,文件將自動(dòng)關(guān)閉。所以我們不需要考慮這個(gè)必要的措施。顯示消息的讀取時(shí)間為5秒后,該函數(shù)返回True。必須處理兩個(gè)可能的錯(cuò)誤,RC522的讀取錯(cuò)誤和不正確的主卡。
在程序開(kāi)始時(shí)將讀取標(biāo)簽()調(diào)用并在ESP32文件系統(tǒng)根目錄下的一個(gè)文件slavecards.txt之后。當(dāng)天的空列表應(yīng)該記錄卡片的十六進(jìn)制字符串。凋零指令不能打開(kāi)文件,因?yàn)樗€不可用,當(dāng)天仍然為空,并且IF構(gòu)造的Else部分返回None。如果文件存在,則將line By line讀入,刪除行結(jié)束符號(hào)并將字符串附加到列表中,直到循環(huán)檢測(cè)到文件的結(jié)束。在這種情況下,列表不是空的,而是返回的。
def readTags():
tags=[]
with open("slavecards.txt", "r") as f:
for line in f:
tags.append(line.strip("\n"))
if tags:
return tags
Else:
return None
SD卡上的每個(gè)文件夾可以包含不同數(shù)量的音樂(lè)標(biāo)題。我們必須知道在一次循環(huán)中完成的數(shù)字,這樣才能進(jìn)行循環(huán)。Get()確定所有文件夾中的標(biāo)題數(shù)量,并將其放入列表文件帳戶中。我們從空列表開(kāi)始,讓我們自己小聲說(shuō)文件夾的數(shù)量。為了解決每個(gè)文件夾,我們?cè)谒膄or循環(huán)中簡(jiǎn)單地提到了第一個(gè)標(biāo)題,這樣你就不會(huì)被破裂和其他噪音所激怒,我們事先把音量調(diào)到0。
def getNumberOfTitels():
fileCount=[]
nof=df.getNumberOfFolders()
df.volume(0)
sleep(0.2)
for t in range(nof):
df.play(t, 0)
sleep(0.2)
df.stop()
sleep(0.2)
n=df.getNumberOfFilesInFolder()
d.writeAt("Track:{}".format(t), 0, 4, False)
d.writeAt("Songs:{}".format(n), 0, 5)
fileCount.append(n)
df.reset()
volume=int(vol.read()*100/1024)
df.volume(volume)
sleep(0.2)
return fileCount
在for循環(huán)中,我們將標(biāo)題的數(shù)量掛在后面的列表上。重置DFPlayer后,我們將音量恢復(fù)到電位器指定的值。返回標(biāo)題號(hào)列表。
作為最后一個(gè)函數(shù),我們聲明player()。在播放循環(huán)的運(yùn)行期間,會(huì)不斷讀取播放列表卡。一張新卡從剛剛播放的播放列表中退出。在本例中,變量acard將空字符串返回給主程序。所以這在函數(shù)中是可能的,我們?nèi)致暶髯兞俊榱俗屚婕艺_開(kāi)始,我們停止了它。然后進(jìn)入for循環(huán)。玩家在這里表現(xiàn)得很固執(zhí),跳過(guò)了第一個(gè)標(biāo)題,所以我讓循環(huán)的運(yùn)行索引S Start為-1。is playing()現(xiàn)在應(yīng)該立即返回我們檢查的內(nèi)容,然后文件夾T中的標(biāo)題S讓播放。
def player(d, t, nof):
global acard
df.stop()
for s in range(-1, nof):
if not df.isPlaying():
df.play(t, s)
d.clearFT(0, 5, 15, 5, False)
d.writeAt("Titel: {}".format(s), 0, 5)
while df.isPlaying():
volume=int(vol.read()*100/1024)
df.volume(volume)
u=readUID(d, "TAG TO STOP", 100)
if u is not None:
d.clearFT(0, 3, 15)
D.Cleart (0, 3, 15)
df.stop()
acard=""
return
d.clearFT(0, 3, 15)
df.stop()
在比賽進(jìn)行期間,還有很多事情要做。必須查詢電位器,并將值傳遞給DFPlayer。然后我們向RC522發(fā)出讀取命令并發(fā)出可能被拆除的信息。在100毫秒= 0.1秒后出現(xiàn)無(wú)返回,進(jìn)入下一輪While循環(huán)。但是如果注冊(cè)了一張新卡,我們停止DFPlayer并準(zhǔn)備使用card = “”播放一個(gè)新的播放列表。如果播放列表已經(jīng)完全播放,我們刪除顯示的下部,并給DFPlayer另一個(gè)停止命令。有時(shí)這讓各種命令都感到厭惡。這導(dǎo)致在開(kāi)發(fā)程序時(shí)出現(xiàn)各種令人失望的時(shí)刻,這總是使得有必要打開(kāi)新的解決方案。
有些變量必須為主程序初始化。
cards=[] # Liste der Karten-IDs leeren
acard="" # aktuelle Karten-ID
ncard="" # neue Karten-ID
song=0 # Stets mit Song 0 starten
第一個(gè)操作現(xiàn)在是讀取卡片id,如果文件slavecards.txt給出。當(dāng)程序第一次啟動(dòng)時(shí),這里沒(méi)有任何標(biāo)志。因此,我們使用try和except away來(lái)保護(hù)來(lái)自reap()的調(diào)用。我們?cè)贓xcept塊中創(chuàng)建文件。因此,我們通過(guò)Timeoutms()方法從接口中調(diào)用了一個(gè)非阻塞的軟件定時(shí)器allread()。當(dāng)計(jì)時(shí)器運(yùn)行時(shí),我們調(diào)用循環(huán)adduid() on。我們已經(jīng)討論過(guò)處理這個(gè)函數(shù)的方法。當(dāng)例程True返回時(shí),一個(gè)卡被注冊(cè),計(jì)時(shí)器被重新啟動(dòng)。如果沒(méi)有更多的卡片,我們只需等待計(jì)時(shí)器并在第二次嘗試中將IDS放入列表中。
試一試:
cards=readTags()
except OSError as e:
allRead=TimeOutMs(10000)
while not allRead():
if addUID(d):
allRead=TimeOutMs(10000)
d.clearFT(0, 3, 15, 4, False)
d.writeAt(" ALL CARDS READ", 0, 3)
cards=readTags()
If the list is not empty, it goes into the main loop that is constantly going through, even while a title is played.
IF Cards:
d.writeAt("***MP3-PLAYER***", 0, 0, False)
d.writeAt("PUT ON MP3-TAG", 0, 1, False)
d.writeAt("Hole die Anzahl", 0, 2, False)
d.writeAt("Songs/Folder", 0, 3)
filesInFolder=getNumberOfTitels()
d.clearFT(0, 2, 15)
df.stop()
while 1:
uid=readUID(d, "PLAYLIST-TAG", 1000)
if uid is not None:
ncard=uid[1]
volume=int(vol.read()*100/1024)
df.volume(volume)
我們?cè)囍x卡片。如果工作,我們顯示十六進(jìn)制字符串的變量Ncard到,并詢問(wèn)電位器下一步。
當(dāng)card的內(nèi)容與Ncard的內(nèi)容不匹配時(shí),開(kāi)始播放新播放列表。在這種情況下,將卡片已經(jīng)更新。
if acard != ncard:
acard=ncard
然后我們檢查列表卡中的ID是否包含在內(nèi)。如果是,我們確定條目的索引,并找到SD卡上的文件夾編號(hào)。我們將組織移交給播放列表player()。她獲得了對(duì)OLED對(duì)象的引用,文件夾編號(hào)和路上的標(biāo)題數(shù)量。
如果卡在卡中:
d.clearFT(0, 2, 15, 5, False)
t=cards.index(acard) # Ordnernummer
d.writeAt("PLAYLIST {}".format(t), 0, 3, False)
d.writeAt(listen[t], 0, 4)
player(d, t, filesInFolder[t])
卡片ID不在cards Found中,在進(jìn)入主循環(huán)的下一輪之前,我們得到一個(gè)錯(cuò)誤消息。
對(duì)于自主公司,不連接PC機(jī),必須將名稱為main.py的程序上傳到ESP32的flash中。該過(guò)程如上所述。或者,你也可以在“文件-菜單”中選擇“另存為”。然后選擇目標(biāo)Micropython設(shè)備。如果你現(xiàn)在感染了電池板上的ESP32,該程序在沒(méi)有PC的情況下啟動(dòng)。
會(huì)議快結(jié)束了。玩家的裝備還有其他選擇。如果你想要聲音更大,在DFPlayer Mini的立體聲輸出上放一個(gè)放大器。只需幾個(gè)按鈕,你就可以在標(biāo)題中滾動(dòng),通過(guò)無(wú)線局域網(wǎng)連接,你可以用一個(gè)Android應(yīng)用程序完全控制它,這個(gè)應(yīng)用程序很容易使用麻省理工學(xué)院的應(yīng)用程序- inventor 2就可以創(chuàng)建。
本文編譯自hackster.io





