JQ6500 STOP 爆音除錯實錄
從「按 STOP 後無法續播」到 V1.8.8 Reset Only+Deferred Re-init
水井三寶智慧互動展覽系統|ESP32 × JQ6500 × Web Control × Debugging
在「水井三寶智慧互動展覽系統」中,JQ6500 負責播放白馬、烏龜、姻緣花等故事。系統原本在故事自然播放完畢後,可以正常切換到下一個故事;但只要使用手機 Web 按下 STOP,中途停止播放,再選另一個故事,就會出現「無法再次播放」的問題。更麻煩的是,後續雖然成功解決續播問題,STOP 時卻又出現明顯的「啵、啵」兩聲爆音。這篇文章完整記錄這次除錯過程,以及最後得到的工程經驗。
一、最初的問題:自然播完正常,STOP 後卻無法續播
最早觀察到的現象非常明確:
這表示問題不在一般播放流程,而是在「人工中止」之後,JQ6500 的內部狀態沒有回到可重新播放的狀態。
二、第一個錯誤認知:把 0x0E 當成 STOP
早期程式使用:
0x7E, 0x02, 0x0E, 0xEF
原本把它命名為:
jqStop();
後來重新檢查指令語意後發現,0x0E 實際上是 PAUSE,不是真正的 STOP。這正好解釋為什麼人工停止後,播放器可能停留在 PAUSED 狀態,下一次使用 Play-by-index 指令時不一定能正常重新起播。
裝置通訊最怕「指令名稱寫得像真的」。如果函式叫 jqStop(),開發者很容易直接相信它就是 Stop,而忽略真正協定中的語意。
三、V1.8.5:改用 RESET 解決無法續播
後來改用 JQ6500 的 RESET 指令:
0x7E, 0x02, 0x0C, 0xEF
流程改成:
這一版最大的成果是:STOP 後終於可以正常再播放下一個故事。
但新的問題出現了:
四、V1.8.6:先把音量設成 0,仍然沒有解決
第一個直覺是:會不會是 JQ6500 音量太大,所以 RESET 的瞬態被放大?
因此嘗試:
程式另外設計了 Raw Volume Control,讓 STOP 過程中的暫時音量 0 不會改動手機設定,也不會寫入 NVS。
void jqSendVolumeRaw(uint8_t volume)
{
// 只送命令
// 不修改 currentVolume
// 不寫入 NVS
}
但實測結果仍然是:
這個結果非常重要,因為它告訴我們:問題不是數位音量參數本身。
五、V1.8.7:拿掉 PAUSE,只保留 RESET
接下來進一步做變因隔離。
如果兩聲分別是:
那拿掉 PAUSE 後,理論上應該只剩一聲。
因此 STOP 改成:
結果卻仍然是:
這表示「第一聲=Pause、第二聲=Reset」這個推論並不成立。
六、V1.8.8:STOP 時真的只做 RESET
為了徹底排除後續初始化造成的影響,V1.8.8 採用最乾淨的實驗方式:
真正的初始化全部延後到下一次使用者按 PLAY 時:
這個版本有兩個重要結果:
| 測試項目 | 結果 |
|---|---|
| STOP 後再選下一個故事 | ✅ 正常播放 |
| STOP 當下爆音 | ⚠️ 仍然是「啵、啵」兩聲 |
七、最後可以得到什麼結論?
經過 V1.8.5 → V1.8.8 的逐步排除,可以相當有把握地判斷:
目前系統是 JQ6500 直接推喇叭,沒有使用外部功放:
因此 RESET 時內部音訊級的關閉與重新建立偏壓,都直接反映到 Speaker 上。
八、為什麼會出現兩聲?
雖然 STOP 程式只有送一次 RESET,但 JQ6500 內部在 Reset 過程可能經歷:
也就是說,兩聲未必需要兩個外部命令;一個 RESET 本身就可能包含兩個類比輸出瞬態。
九、這次除錯最重要的方法:一次只改一個變因
這次能真正找到原因,不是因為一次改很多程式,而是把可能因素逐步拆開:
| 版本 | STOP策略 | 結果 |
|---|---|---|
| V1.8.5 | Pause → Reset → Init | 可續播,但啵、啵 |
| V1.8.6 | Volume 0 → Pause → Reset | 仍啵、啵 |
| V1.8.7 | Reset → Init | 仍啵、啵 |
| V1.8.8 | STOP 只 Reset;Init 延後到 PLAY | 仍啵、啵 |
除錯不是一直「加功能」,而是要有意識地做變因隔離。每一版只改一個關鍵行為,才能知道真正是哪一個因素造成結果。
十、什麼問題已經解決?什麼問題還沒解決?
| 項目 | 目前狀態 |
|---|---|
| 自然播放完畢後再播下一首 | ✅ 正常 |
| 手機中途 STOP | ✅ 正常停止 |
| STOP 後再播下一首 | ✅ V1.8.8 已正常 |
| 手機 Realtime Status | ✅ 正常 |
| 手機音量控制 | ✅ 正常 |
| 音量寫入 NVS | ✅ 關機重開可保留 |
| 姻緣花 24 顆柔和彩虹旋轉 | ✅ 正常 |
| STOP 爆音 | ⚠️ 還有「啵、啵」兩聲 |
十一、目前最合理的工程判斷
在功能已穩定的前提下,繼續修改 delay 或音量命令,效益已經很低。
目前最合理的判斷是:
STOP 爆音屬於 JQ6500 直接驅動 Speaker 時,RESET 造成的類比輸出瞬態。若要完全消除,下一步應從硬體音訊架構處理,而不是持續修改 Web 或狀態機。
十二、未來真正要消除爆音,應該怎麼做?
如果正式展覽版要完全消除爆音,可以把音訊路徑改成:
STOP 時先:
這樣 JQ6500 即使仍然產生 RESET transient,也不會直接送到 Speaker。
十三、這個案例對《網際網路應用》課程有什麼價值?
表面上看,這只是「STOP 後有爆音」的硬體問題;但實際上,它很適合讓學生理解完整系統除錯。
| 層級 | 這次檢查的內容 |
|---|---|
| Web | 手機是否真的送出 STOP Request |
| ESP32 Application | handleStop() 與 State Machine 是否正確 |
| UART | JQ6500 收到的是 Pause 還是 Reset |
| Device State | Reset 後是否可以重新播放 |
| Audio Hardware | 爆音是否來自 DAC/功放輸出瞬態 |
也就是說,一個看似簡單的 STOP 按鈕,其實橫跨:
十四、從這次經驗學到的五件事
函式名稱叫 Stop,不代表實際送出的命令真的是 Stop。
不能因為自然播放正常,就假設 STOP 後也會進入相同狀態。
RESET 時 DAC/功放的工作點仍可能產生 transient。
Pause、Reset、Volume、Select Flash、Restore Volume 必須逐項隔離。
這時應該停止一直改程式,改從系統架構處理。
十五、結語:失敗的版本也是教材
從 V1.8.5 到 V1.8.8,表面上像是在「反覆修改 STOP」,但真正累積的是一套非常有價值的工程判斷過程。
我們先解決「STOP 後不能再播放」,再逐步確認爆音不是音量、不是 Pause、不是 Select Flash、也不是重新初始化造成,最後把問題定位到 JQ6500 本身 RESET 時的音訊輸出瞬態。
這也是「水井三寶智慧互動展覽系統」作為大學《網際網路應用》與 IoT 實作教材的重要價值:學生看到的不只是一個成功作品,而是一個真實系統如何一步一步從問題、測試、假設、修正走向穩定。
JQ6500 ESP32 STOP RESET UART Pop Noise Debugging Realtime Web IoT 水井三寶 USR
沒有留言:
張貼留言