破解LED燈柱閃爍之謎

01 LED顯示柱
1.1 背景介紹
??在博文 ?線上比賽無線充電組仲裁申請以及檢查結(jié)果[1] 記錄了第十七屆智能車競賽[2]全國總決賽中山魂八隊(duì)比賽受到參賽隊(duì)伍質(zhì)疑的問題。為何受到質(zhì)疑,主要一個原因來自于網(wǎng)絡(luò)直播比賽過程中,遠(yuǎn)程觀看山魂八隊(duì)車模顯示電壓的 LED 燈柱出現(xiàn)三個一排的點(diǎn)亮以及所發(fā)生的的突然變亮和變暗的情況。在 ?對于山東威海-無線充電組技術(shù)報(bào)告中的疑問及其回復(fù)[3] 給出了山魂八隊(duì)的技術(shù)報(bào)告及其相關(guān)質(zhì)疑和回復(fù)。特別是技術(shù)報(bào)告中顯示了山魂八隊(duì)無線充電組 LED 燈柱的硬件 原理圖以及循環(huán)點(diǎn)亮的程序算法。
??那么,根據(jù)上面的技術(shù)資料,是否可以重現(xiàn) LED 燈柱以及顯示特性呢? 本文就搭建相應(yīng)的實(shí)驗(yàn)電路進(jìn)行測試。

1.2 測試方案
??由于只是測試山魂八隊(duì) LED 燈柱的顯示特性,所以并不完全按照他們的硬件電路進(jìn)行搭建,而是將其中的顯示基本原理保持一致即可。 下面分別給出測試硬件和軟件設(shè)計(jì)方案。
1.2.1 燈柱顯示
??根據(jù) ?第十七屆智能車競賽技術(shù)報(bào)告-無線充電組-山東大學(xué)(威海)[4] 可以知道他們將燈柱中的 15 個 LED 分成5×3 的陣列,每一行由三個 LED 組成,通過一個 MOS 管驅(qū)動。 使用一片 Infineon 公司的 LED 專用驅(qū)動芯片 TLD2331 來驅(qū)動三列。 通過動態(tài)掃描的方式完成 15 個 LED 的點(diǎn)亮。

??為了簡化測試的過程,這里只是在面包板上搭建了前兩行 LED 顯示燈柱。組成 2×3 的陣列。具體電路如下圖所示。

1.2.2 ESP32平臺
??控制信號使用了MicroPython ESP32 平臺,相關(guān)的技術(shù)資料參見 ?ESP32-S模塊轉(zhuǎn)接板設(shè)計(jì)與實(shí)現(xiàn)[5] 。下面是將該接口板的原理圖轉(zhuǎn)帖過來。

(1)端口配置
??使用其中GPIO32,33,35,26,27分別控制 LED 燈柱的行與列。實(shí)際上通過測試發(fā)現(xiàn), ESP32 的所有 GPIO 中,并不是所有的 GPIO ?都適合做輸出端口,最終使用其中的 32,33,25,27,26 來驅(qū)動 LED 燈柱。
(2)軟件編程
??根據(jù) MicroPython ?ESP32[6] 編程文檔,控制六個 LED 燈柱閃爍, 閃爍的頻率大約是 50Hz。 由于是軟件控制,所以實(shí)際閃爍頻率為 49.73Hz。
from?machine????????????????import?Pin
import?time
led?=?Pin(5,?Pin.OUT)
row1?=?Pin(32,?Pin.OUT)
row2?=?Pin(33,?Pin.OUT)
row3?=?Pin(25,?Pin.OUT)
col1?=?Pin(26,?Pin.OUT)
col2?=?Pin(27,?Pin.OUT)
print("Test?LED?.")
row1.on()
row2.on()
row3.on()
while?True:
????col1.on()
????col2.on()
????led.on()
????time.sleep_ms(10)
????col1.off()
????col2.off()
????led.off()
????time.sleep_ms(10)
1.3 測試結(jié)果
1.3.1 攝像機(jī)觀察結(jié)果
??通過攝像機(jī)觀察閃爍的燈柱, 可以看到LED燈柱亮度平穩(wěn),沒有閃爍。這與人眼觀察到的現(xiàn)象是相同的。

1.3.2 通過手機(jī)觀察結(jié)果
??通過手機(jī)觀察 LED 燈柱亮度,可以看到 LED ?燈柱在閃爍。

1.3.3 使用硬件中斷
??由于前面利用了軟件延遲,所以 LED 閃爍的頻率不是準(zhǔn)確的 50Hz,下面利用 ESP32 的硬件時(shí)鐘中斷,產(chǎn)生更加準(zhǔn)確的 50Hz 閃爍。
(1)實(shí)驗(yàn)程序
from?machine????????????????import?Pin,Timer
import?time
led?=?Pin(5,?Pin.OUT)
row1?=?Pin(32,?Pin.OUT)
row2?=?Pin(33,?Pin.OUT)
row3?=?Pin(25,?Pin.OUT)
col1?=?Pin(26,?Pin.OUT)
col2?=?Pin(27,?Pin.OUT)
print("Test?LED?.")
row1.on()
row2.on()
row3.on()
ledcount?=?0
flag?=?0
def?ledflash(_):
????global?ledcount,flag
????ledcount?+=?1
????if?ledcount?>=?10:
????????if?flag?*?0:
????????????flag?=?1
????????????col1.on()
????????????col2.on()
????????else:
????????????flag?=?0
????????????col1.off()
????????????col2.off()
????????ledcount?=?0
time0?=?Timer(0)
time0.init(period=1,?mode=Timer.PERIODIC,?callback=ledflash)
while?True:
????led.on()
????time.sleep_ms(10)
????led.off()
????time.sleep_ms(10)
(2)手機(jī)觀察現(xiàn)象
??下面是使用手機(jī)拍攝的 LED 燈柱亮度閃爍的情況。

(3)攝像頭觀察情況
??下面是使用 HDMI 接口的攝像頭拍攝到的 LED 燈柱亮度閃爍的情況。

1.3.4 分析結(jié)果
??通過上面測試,可以看到 LED 燈柱如果采用高頻閃爍的時(shí)候, 由于閃爍頻率很高,由于視覺暫留現(xiàn)象,人眼看到是平均的亮度。 但是在手機(jī)攝像頭中,可能觀察到的是亮度閃爍的情況。這也解釋了在比賽中遠(yuǎn)程觀察到的 LED 燈柱呈現(xiàn)閃爍的情況。
02 比賽程序
??為了說明比賽中山魂八隊(duì)無線充電隊(duì) LED 燈柱的如下奇特現(xiàn)象:
觀察到其 LED 燈柱似乎是三個一組同時(shí)點(diǎn)亮和熄滅;
在運(yùn)行中會出現(xiàn) LED 燈虛亮 的情況;
??下面根據(jù) ?第十七屆智能車競賽技術(shù)報(bào)告-無線充電組-山東大學(xué)(威海)[2] 中給出的 LED 燈柱控制核心程序進(jìn)行測試,看是否能夠復(fù)現(xiàn)出上述現(xiàn)象,并進(jìn)行解釋。
2.1 LED控制軟件
2.1.1 山魂八隊(duì)原始程序
??下面是山魂八隊(duì)的控制程序。從整體上分為兩部分, 前面是設(shè)置控制行 MOS 管是否導(dǎo)通,后面部分設(shè)置 TLD2331 的三列輸出。 根據(jù)程序可以知道,GPIO輸出為 0 的時(shí)候, TLD2331輸出高電平。

2.1.2 ESP32測試程序
??在一開始,完全根據(jù)上述單片機(jī) ?C 語言程序的邏輯,編寫了對應(yīng)的 MicroPython 程序進(jìn)行測試,發(fā)現(xiàn)該程序運(yùn)行后, LED 燈柱點(diǎn)亮?xí)r出現(xiàn)問題。
(1)MicroPython測試程序
??下面是測試 MicroPython 程序。
from?machine????????????????import?Pin,Timer
import?time
print("Test?LED?.")
led?=?Pin(5,?Pin.OUT)
row1?=?Pin(32,?Pin.OUT)
row2?=?Pin(12,?Pin.OUT)
row3?=?Pin(13,?Pin.OUT)
col1?=?Pin(26,?Pin.OUT)
col2?=?Pin(27,?Pin.OUT)
col3?=?Pin(14,?Pin.OUT)
col1.off()
col2.off()
col3.off()
row1.off()
row2.off()
row3.off()
ledcount?=?0
flag?=?0
voltage_light?=?1
column_count?=?0
def?ledflash(_):
????global?ledcount,flag,voltage_light,column_count
????column_count????+=?1
????if?column_count?>=?4:?column_count?=?0
????light_row???????=?voltage_light//3
????light_column????=?voltage_light%3
????if?column_count?*?0:
????????if?light_row?>=?0:??col1.on()
????????else:?col1.off()
????elif?column_count?*?1:
????????if?light_row?>=?1:??col2.on()
????????else:?col2.off()
????elif?column_count?*?2:
????????if?light_row?>=?2:??col3.on()
????????else:?col3.off()
????if?column_count?<?light_row:
????????row1.on()
????????row2.on()
????????row3.on()
????elif?column_count?>?light_row:
????????row1.off()
????????row2.off()
????????row3.off()
????else:
????????if?light_column?*?0:
????????????row1.on()
????????????row2.off()
????????????row3.off()
????????elif?light_column?*?1:
????????????row1.on()
????????????row2.on()
????????????row3.off()
????????elif?light_column?*?2:
????????????row1.on()
????????????row2.on()
????????????row3.on()
????????else:
????????????row1.off()
????????????row2.off()
????????????row3.off()
time0?=?Timer(0)
time0.init(period=1,?mode=Timer.PERIODIC,?callback=ledflash)
while?True:
????led.on()
????time.sleep_ms(250)
????led.off()
????time.sleep_ms(250)
????voltage_light?+=?1
????if?voltage_light?>=?6:
????????voltage_light?=?0
(2)出現(xiàn)的問題
??上述程序是每隔 0.5 秒,將表示電壓的 voltage_light 變量增 1。當(dāng)?shù)竭_(dá) 6 時(shí)返回0。本希望能夠看到 LED 燈柱逐步從 1 個 LED 點(diǎn)亮,逐步增加到 6 個 LED 都點(diǎn)亮。但實(shí)際運(yùn)行結(jié)果是:
前三個 LED 可以順序點(diǎn)亮;
但后面三個 LED 則同時(shí)點(diǎn)亮;
??這個現(xiàn)象與山大威海無線充電組車模在比賽時(shí)表現(xiàn)的狀況很相似,他們比賽的時(shí)候也是三個 LED 一組同時(shí)點(diǎn)亮。

2.1.3 問題解決
(1)錯誤分析
??上面錯誤來源于山大威海編程中的錯誤。 按照 LED 矩陣掃描原理,每一次只能夠選擇一個 MOS 管導(dǎo)通,但是按照前面論文中的程序,可以看到隨著 voltage_light 增加, 導(dǎo)通的 MOS 管會逐步增多。這就會使得同時(shí)點(diǎn)亮的行之間相互干擾。 具體表現(xiàn)上就是除了第一行之外,其它各行的三個 LED 都是同時(shí)被點(diǎn)亮。
??比如: 當(dāng)變量 voltage_light 在 3 ?5 之間時(shí), MOS 管 T1,T2 都會導(dǎo)通,這樣就會使得前面的 L1 ?L6 都會被同時(shí)點(diǎn)亮。

(2)修改代碼
??實(shí)際上,程序代碼可以進(jìn)行簡化,根據(jù) column_count 分別控制 col1,col2,col3 為高電平。 如下面代碼所示:
col1.off()
col2.off()
col3.off()
if?column_count?*?0:???col1.on()
elif?column_count?*?1:?col2.on()
elif?column_count?*?3:?col3.on()
(3)運(yùn)行效果
??將原來的程序進(jìn)行簡化之后,LED燈柱的顯示就正常了。隨著 voltage_light 變量的增加,燈柱逐步點(diǎn)亮。

2.2 LED閃爍與虛亮
??在前面給出了 LED 燈柱在攝像頭中閃爍的情況,下面再對比 LED 燈柱在攝像機(jī)和攝像頭下不同的閃爍情況。設(shè)置 ESP32 測試程序定時(shí)器中斷的周期為 5ms,那么程序掃描周期為 20ms,與前面測試燈柱閃爍的頻率一致。
2.2.1 不同攝像頭下的閃爍
(1)攝像機(jī)下的圖像
??在攝像機(jī)下, 可以看到 LED 燈柱亮度是恒定的,看不出任何閃爍的情況。

(2)手機(jī)下的圖像
??使用手機(jī)拍攝 LED 燈柱,可以看到它的亮度出現(xiàn)非常明顯的閃爍現(xiàn)象。

??以上對比可以看到在普通手機(jī)攝像頭里,對于掃描頻率較低的LED燈柱會出現(xiàn)比較明顯的閃爍現(xiàn)象。因此,為了避免這種閃爍,最簡單的辦法就是提高LED矩陣掃描頻率,也可以通過修改掃描頻率,來避免這種明顯的拍頻的現(xiàn)象。
2.2.2 虛亮現(xiàn)象
(1)什么是虛亮現(xiàn)象?
??上述程序中,還存在著一個 “虛亮現(xiàn)象”,也就是 LED 燈在未點(diǎn)亮之前會被微弱的點(diǎn)亮。 比如在點(diǎn)亮 LED1,LED2的時(shí)候,對應(yīng)的 LED4,LED5 也會被 “微弱的點(diǎn)亮” 。 ?下圖是截取了測試電路板在點(diǎn)亮 LED1、LED2 的時(shí)候,觀察到 LED4、LED5 也被點(diǎn)亮的情況。

??由于測試電路板上的 LED 是依靠 ESP32 的端口驅(qū)動,所以輸出電流很小。 如果是 TLD2331 驅(qū)動,這種虛亮 的 LED 會在瞬間變得非常亮, 根據(jù)前面閃爍現(xiàn)象可以知道,在手機(jī)攝像頭所拍攝到的視頻中,這些瞬間點(diǎn)亮的 LED 會被看成點(diǎn)亮的LED。 這種虛亮現(xiàn)象也就能回答在 ?線上比賽無線充電組仲裁申請以及檢查結(jié)果[7] ?同學(xué)提示的疑問,也就是看到過 12 46 8.... ? 這樣不連續(xù)點(diǎn)亮的情況。
(2)怎么產(chǎn)生的虛亮?
??虛亮問題的產(chǎn)生也是由 山大威海 無線充電隊(duì) LED 燈柱程序引起的。原始程序是先對控制行輸出的 IO 口進(jìn)行設(shè)置,然后再對控制列的 IO 口進(jìn)行設(shè)置。問題在于開始設(shè)置行 IO 口的時(shí)候,并沒有關(guān)閉列 IO 口,這樣就會在切換行 IO 口時(shí),前面打開的列 IO 口會點(diǎn)亮后面一行的 LED。這樣就會在行列 IO 口改變中間的時(shí)候,使得后面一行的 LED 可能會被瞬間點(diǎn)亮。
(3)如何消除虛亮現(xiàn)象?
??實(shí)際上只要在每一個進(jìn)入中斷進(jìn)行 LED 矩陣掃描的時(shí)候,先對列禁止輸出,然后依次設(shè)置行 IO 和列 IO 狀態(tài),就可以避免“虛亮” 現(xiàn)象了。下面是修改后的 LED 中斷掃描程序。
def?ledflash(_):
????global?ledcount,flag,voltage_light,column_count
????column_count????+=?1
????if?column_count?>=?4:?column_count?=?0
????light_row???????=?voltage_light//3
????light_column????=?voltage_light%3
????row1.off()
????row2.off()
????row3.off()
????col1.off()
????col2.off()
????col3.off()
????if?column_count?*?0:???col1.on()
????elif?column_count?*?1:?col2.on()
????elif?column_count?*?3:?col3.on()
????if?column_count?<?light_row:
????????row1.on()
????????row2.on()
????????row3.on()
????elif?column_count?>?light_row:
????????row1.off()
????????row2.off()
????????row3.off()
????else:
????????if?light_column?*?0:
????????????row1.on()
????????????row2.off()
????????????row3.off()
????????elif?light_column?*?1:
????????????row1.on()
????????????row2.on()
????????????row3.off()
????????elif?light_column?*?2:
????????????row1.on()
????????????row2.on()
????????????row3.on()
????????else:
????????????row1.off()
????????????row2.off()
????????????row3.off()
??下面是攝像機(jī)拍攝到的程序修改后的 LED 燈柱點(diǎn)亮的情況,已經(jīng)徹底消除了 “虛亮” 的現(xiàn)象了。

※ 總??結(jié) ※
??智能車競賽山大威海無線充電隊(duì)伍在遠(yuǎn)程比賽過程中,視頻顯示他們的 LED 燈柱出現(xiàn)的奇怪現(xiàn)象,包括有:(1) 三個 LED 同時(shí)點(diǎn)亮; (2) 出現(xiàn) LED 虛亮的現(xiàn)象。 本文根據(jù) 山大威海提交的技術(shù)報(bào)告中的硬件和軟件,使用自制 ESP32 電路板,利用 MicroPython 編程,測試了 LED 燈柱電路和控制軟件。指出了山大威海技術(shù)報(bào)告中 LED燈柱控制軟件存在的問題,并提出了修改辦法。在一定程度上解釋了遠(yuǎn)程比賽視頻中出現(xiàn)的錯誤現(xiàn)象。
??人們總以為眼見為實(shí),但實(shí)際過程中,眼睛看到的未必是實(shí)際情況。下面一個動圖是在推文 ?數(shù)碼內(nèi)外,天壤之別[8] ?顯示了某人家監(jiān)控拍攝到屋檐下小鳥飛行的情況。 為何這個小鳥翅膀不動但能夠靈活的左右飛行呢?

個人一旦成為群體的一員,他很難對他所作所為承擔(dān)責(zé)任,這時(shí)每個人都會暴露出自己的自由放縱而不受到約束的一面。群體追求的、相信的從來不是什么真相和理性,而是盲從、殘忍、偏執(zhí)和狂熱,只知道簡單而極端的感情?!稙鹾现姟?/p>
參考資料
[1]
線上比賽無線充電組仲裁申請以及檢查結(jié)果: https://blog.csdn.net/zhuoqingjoking97298/article/details/126536052?spm=1001.2014.3001.5501
[2]第十七屆智能車競賽: https://blog.csdn.net/zhuoqingjoking97298/article/details/110253008
[3]對于山東威海-無線充電組技術(shù)報(bào)告中的疑問及其回復(fù): https://blog.csdn.net/zhuoqingjoking97298/article/details/126575012?spm=1001.2014.3001.5501
[4]第十七屆智能車競賽技術(shù)報(bào)告-無線充電組-山東大學(xué)(威海): https://zhuoqing.blog.csdn.net/article/details/126573548
[5]ESP32-S模塊轉(zhuǎn)接板設(shè)計(jì)與實(shí)現(xiàn): https://zhuoqing.blog.csdn.net/article/details/115563474
[6]MicroPython ?ESP32: https://docs.micropython.org/en/latest/esp32/quickref.html
[7]線上比賽無線充電組仲裁申請以及檢查結(jié)果: https://zhuoqing.blog.csdn.net/article/details/126536052
[8]數(shù)碼內(nèi)外,天壤之別: https://mp.weixin.qq.com/s?__biz=MzA5NjQyNjc2NQ&mid=2452246873&idx=1&sn=5328041eb1c9ee48ac5afb4ad8a82ba2&chksm=876ebf3bb019362d29b157ea9cf58841ac56cc144736f10d1dc567d8b9b06f6111853b442206&token=556705145&lang=zh_CN#rd*