
簡介面向STM32嵌入式開發者的HT1621B液晶驅動模塊示例工程基于意法半導體硬件抽象層庫開發聚焦通過串行外設接口控制HT1621B完成字符與簡單圖形顯示。工程共4個文件包括C源文件、頭文件、Markdown說明文檔及備份文件整體體積僅約3KB結構精簡非常適合快速閱讀和二次開發。已有162人瀏覽學習說明該示例對研究LCD驅動具備一定參考價值。通過分析工程代碼可以學習HAL庫下通用輸入輸出口與串行外設接口的初始化配置、數據收發流程理解HT1621B命令寫入、數據傳輸和顯示控制的具體實現。項目還給出了液晶驅動代碼的組織方式便于移植到不同STM32系列也可作為課堂實訓或項目立項的參考模板。對于剛接觸STM32液晶驅動的開發者該工程能幫助快速建立串行通信和顯示控制的基本思路避免從零摸索寄存器級操作有效縮短開發周期。1. HT1621B 配 STM32 HAL先知道它是段式屏驅動HT1621B 是一顆段式 LCD 驅動芯片它管的是數碼管、單位符號、狀態標記這種固定筆畫不是點陣屏。STM32 HAL 主庫的做法是把這一顆芯片的初始化、寫命令、寫顯示 RAM 封裝成一個不依賴具體業務的驅動模塊上層只要往緩存里寫段數據底層自動刷到玻璃上。標題里的 stm32ht1621b就是這類主庫的典型形態一個 .c 一個 .h拷進哪個工程都能用。之所以值得寫一遍是因為 HT1621B 的三線時序看著簡單但命令幀、地址自增、偏壓設置、上電清屏這幾件事的順序一旦搞錯屏幕就是一片白或一片亂碼調試起來比點陣屏更容易懵。這篇把協議、驅動、調參和排錯串起來講適合第一次畫段碼屏方案的工程師直接照抄。2. HT1621B 的三線時序和指令集想讓 MCU 干活先背協議寫驅動前別把芯片當黑盒。HT1621B 的通信協議非常固定整個芯片只有一類寫時序、兩類幀格式吃透這三件事驅動代碼基本就能一遍跑通。2.1 三線還是四線為什么模擬 SPI 更常見HT1621B 支持 3 線CS、WR、DATA和 4 線多一根 RD 讀引腳兩種接法。只做顯示寫入的場合用三根 GPIO 就夠讀回顯示 RAM 這個功能在段碼屏方案里幾乎用不上絕大多數國產表頭、家電面板的驅動庫也都只實現寫。踩過坑的工程師基本會直接選 GPIO 模擬而不是把芯片掛到 STM32 的硬件 SPI 外設上原因有兩個。第一HT1621B 的寫時序要求 WR 上升沿鎖存 DATA且 CS 低電平期間整幀連續發送。STM32 SPI 的 CPOL/CPHA 組合雖然能湊出上升沿采樣但幀長度是 12 位或 10 位起步和 SPI 的 8/16 位幀對不齊每次收發都要做位重排代碼比模擬時序還難看。第二段碼屏刷新率要求極低幾十赫茲就夠硬件 SPI 的高帶寬在這里沒有意義反而白白占掉一組外設。所以這個主庫的底層只需要三根推挽 GPIO 加一條移位發送循環CubeMX 里連定時器都不用開。發送的關鍵是保證 DATA 先變化、WR 再跳變。具體到波形CS 拉低后先把要發送的一位放到 DATA 上再將 WR 拉低再拉高完成一個上升沿采樣。這里有一個新手常犯的錯誤就是先拉 WR 再改 DATA結果芯片采到的是上一拍的舊電平整個屏顯示錯亂。后面ht1621_send_frame就是按“先 DATA 后 WR”的順序寫的。2.2 通信幀分兩類命令幀和寫數據幀長度不一樣HT1621B 的所有寫操作都包含一個固定前導碼101后續內容取決于當前是命令還是數據。命令幀總長 12 位前 3 位是101后 9 位是命令字。初始化只需要三條命令按執行順序是系統配置、系統使能、顯示開關。常見庫里的寫法是下面這套 9 位命令值很多開源驅動和國產屏廠示例代碼都沿用這組數字命令功能9 位命令值說明系統配置1/3 偏壓 內部 RC 振蕩器0x034決定 LCD 偏壓產生方式和系統時鐘來源系統使能0x002打開內部系統時鐘和偏壓發生器顯示開0x006允許 COM/SEG 輸出驅動 LCD顯示關0x004關閉 LCD 驅動輸出RAM 數據保留表格里的值直接傳給命令發送函數函數內部會在前面拼上101。注意不同廠家的源碼里系統配置一項可能出現 0x034、0x02C、0x004 等不同寫法本質是同一命令的位定義順序有差異接屏前對照 datasheet 的 System Configuration Command 位圖核對一遍比在實物上瞎試快得多。寫數據幀的結構稍微不同先發101前導再發 6 位地址對應 SEG0 到 SEG31之后連續發多個 4 位數據。每 4 位數據代表一個 SEG 對應的 4 個 COM 位發送完一個 SEG 地址自動加一。所以刷整屏的正確姿勢是拉低 CS發101發地址 0然后連續發 32 個 4 位數據最后拉高 CS。不需要在每段數據之間重復發地址。2.3 顯示 RAM 是 32x4 的位圖不是字節流這一點決定了主庫的緩存結構。HT1621B 內部有一塊 32 x 4 的顯示 RAM行地址對應 SEG0 到 SEG31每個地址里存 4 個 bit分別對應 COM0 到 COM3。某一位為 1表示該 SEG 和該 COM 交叉處的 LCD 段被施加驅動電壓為 0 則不顯示。所以驅動層最合理的做法是維護一個 32 字節的緩存數組每個字節只用低 4 位bit0 對應 COM0bit1 對應 COM1以此類推。上層代碼只改這個數組刷新函數把整個數組按順序推給 HT1621B。這樣的好處有兩個一是 32 字節很小任何 MCU 都能輕松放進 RAM二是把“顯示內容”和“寫入時序”徹底解耦主庫可以做到只暴露ht1621_set_seg和ht1621_refresh兩個接口應用層不需要知道協議細節。3. 用 STM32 HAL 把 HT1621B 最小驅動寫出來理論落在代碼上主庫的第一版不需要復雜架構。下面是 CubeMX 配置、底層位發送、初始化順序三件事照做就能亮。3.1 CubeMX 最小配置只開三個推挽 GPIO在 CubeMX 里給 HT1621B 分配三個引腳這里以 CSPB10、WRPB1、DATAPB2 為例。每個 Pin 的 GPIO mode 設為 Output Push Pull速度選 High初始電平設 High這樣 CS 默認處于釋放狀態避免上電瞬間芯片被誤選中。其他外設全部不開。引腳分配不是固定的只要避開調試引腳和晶振引腳就行。特別注意 STM32F103 的 PA13/PA14 是 SWDIO/SWCLK很多人在 F103 上把 CS 放到 PA15 或 PB3結果下載一次程序后第二次就連接不上調試器這就是引腳沖突。段碼屏驅動對引腳沒有特殊要求優先選普通 IO。CubeMX 生成工程后在main.c里加兩個頭文件或直接新建ht1621b.c/h作為獨立主庫模塊。推薦后者這樣換工程時只需要拷貝這兩個文件并改引腳宏定義。3.2 核心發送函數先置數據再拉 WR底層只需要一個函數按 MSB first 發送若干位。所有命令和數據都是移位循環實現的// ht1621b.c #include ht1621b.h #include main.h static void ht1621_send_frame(uint16_t frame, uint8_t bits) { for (int i bits - 1; i 0; i--) { // 先置數據再拉 WR保證上升沿采到的是當前位 HAL_GPIO_WritePin(HT1621_DATA_GPIO_Port, HT1621_DATA_Pin, (frame i) 1U ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(HT1621_WR_GPIO_Port, HT1621_WR_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(HT1621_WR_GPIO_Port, HT1621_WR_Pin, GPIO_PIN_SET); } }函數先把當前位放到 DATA 引腳上然后讓 WR 產生一個低到高的跳變。bits參數決定發送長度的原因是命令幀需要發 3 位前導和 9 位命令字數據幀需要發 3 位前導、6 位地址和 4 位數據。三段都用這同一個函數。在此基礎上封裝命令發送和段數據寫入void ht1621_write_cmd(uint16_t cmd9) { HAL_GPIO_WritePin(HT1621_CS_GPIO_Port, HT1621_CS_Pin, GPIO_PIN_RESET); ht1621_send_frame(0x5, 3); // 前導碼 101 ht1621_send_frame(cmd9 0x1FF, 9); // 9 位命令字 HAL_GPIO_WritePin(HT1621_CS_GPIO_Port, HT1621_CS_Pin, GPIO_PIN_SET); } void ht1621_write_data(uint8_t addr, const uint8_t *buf, uint8_t len) { HAL_GPIO_WritePin(HT1621_CS_GPIO_Port, HT1621_CS_Pin, GPIO_PIN_RESET); ht1621_send_frame(0x5, 3); // 前導碼 101 ht1621_send_frame(addr 0x3F, 6); // 6 位地址SEG0-SEG31 for (uint8_t i 0; i len; i) { ht1621_send_frame(buf[i] 0x0F, 4); // 每個 SEG 的 4 個 COM 位 } HAL_GPIO_WritePin(HT1621_CS_GPIO_Port, HT1621_CS_Pin, GPIO_PIN_SET); }ht1621_write_cmd的參數是 9 位命令字內部用掩碼保證不會把多余位發出去。ht1621_write_data的地址范圍是 0 到 31對應 SEG 編號連續發送len個 4 位數據地址自動遞增。緩沖區里的每個字節低 4 位就是 COM0 到 COM3 的開關狀態。3.3 初始化順序關顯示、配偏壓、清屏、再開顯示HT1621B 上電后顯示 RAM 內容不確定如果先開顯示再清屏屏幕會閃一下隨機內容玻璃上還會留下殘影。正確順序是先把顯示關掉配置系統參數使能系統時鐘把 RAM 清干凈最后開顯示。整套初始化函數如下#include string.h static uint8_t seg_cache[32]; // 顯示緩存低 4 位有效 void ht1621_init(void) { ht1621_write_cmd(0x034); // 系統配置1/3 偏壓內部 RC 振蕩器 ht1621_write_cmd(0x002); // 系統使能啟動偏壓發生器和時鐘 memset(seg_cache, 0, sizeof(seg_cache)); ht1621_write_data(0x00, seg_cache, 32); // 清空顯示 RAM ht1621_write_cmd(0x006); // 顯示開LCD 開始輸出驅動波形 }注意0x034是 9 位值不要寫成長整型或其他位數。清屏必須在系統使能之后、顯示開之前完成這是 HT1621B 驅動里最容易忽略的一步。很多用戶反映“上電花屏一下然后正常”就是少了這次寫全 0 操作。給上層暴露兩個操作接口就夠用了一個改緩存一個刷屏void ht1621_set_seg(uint8_t seg, uint8_t com_bits) { if (seg 32) { seg_cache[seg] com_bits 0x0F; } } void ht1621_refresh(void) { ht1621_write_data(0x00, seg_cache, 32); }這段代碼用ht1621_set_seg(seg, 0x0F)讓某一段全亮用ht1621_refresh()把緩存推到芯片。編輯期間所有測試都可以圍繞這兩個函數進行不需要再碰底層時序。4. 顯示緩存與偏壓參數把 HT1621B 調到不閃不鬼影驅動能亮只是第一步段碼屏真正難的是顯示穩定、對比度正常、功耗可控。這一章把緩存設計、偏壓選擇、低功耗處理三個點講透。4.1 段碼映射表必須在主庫里做一次重排32 字節緩存的排序方式是 SEG 優先每個字節內是 COM 位。但實際 LCD 玻璃上的引腳順序并不總是和芯片的 SEG0 到 SEG31 一一對應很多國產段碼屏的走線會把 SEG 順序打亂甚至 COM 和 SEG 的連接方式跟 datasheet 的示意完全不同。所以主庫要單獨留一層的段碼映射表把“邏輯段號”翻譯成“物理 SEG 號”// 邏輯段號到物理 SEG 編號的重排表按實際屏的引腳定義填寫 static const uint8_t seg_map[32] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; void ht1621_set_seg(uint8_t seg, uint8_t com_bits) { if (seg 32) { seg_cache[seg_map[seg]] com_bits 0x0F; } }如果屏廠提供的引腳定義是 SEG20 對應邏輯段 0把seg_map[0]改成 20 就行。沒有這張表每次換屏都要改動刷新邏輯主庫的復用價值就沒了。數字 0 到 9 的段碼表同理不同玻璃的 COM/SEG 走線不同網上抄來的段碼表大概率對不上需要按自己的屏逐個位試出來。4.2 偏壓、振蕩器、背極掃描三個參數要按玻璃選HT1621B 能調的參數不多但每一個都直接影響顯示效果。下面是三個關鍵參數的對照參數可選值影響選擇建議偏壓 BIAS1/2、1/3決定 LCD 驅動電壓檔位偏壓不夠會對比度差偏高會出現串擾鬼影按屏廠規格選不確定時先試 1/3系統時鐘源內部 RC、外部 32.768k 晶振內部 RC 夠顯示用外部晶振用于計時類應用純顯示用 RC帶時鐘功能接晶振背極掃描數由 HT1621B 硬件固定支持 4 COM必須和 LCD 玻璃的 COM 數一致玻璃是幾 COM 就配幾 COM軟件改不了偏壓是最容易踩坑的地方。1/3 偏壓驅動電壓分三檔對比度普遍比 1/2 好但功耗更高反過來如果屏玻璃本身按 1/2 偏壓設計強行用 1/3 會出現筆畫變淡或全亮時發灰的現象。調試時把系統配置命令從0x034改到對應 1/2 偏壓的寫法對比一下哪個更干凈比對著 datasheet 猜快得多。另外一個常被忽略的細節是 HT1621B 的偏壓發生器需要外部電容配合。VLCD引腳上的電容太小驅動電壓會紋波大表現出來就是畫面輕微閃爍。這個電容一般在 0.1uF 到 1uF 之間放在芯片附近和 STM32 的 VDD 濾波電容分開布局。4.3 低功耗關顯示和關振蕩器要分開做段碼屏方案經常用在電池設備上HT1621B 的功耗控制比 STM32 本身的睡眠管理更重要。芯片有三個功耗等級全速顯示、顯示關但系統時鐘運行、完全停止。注意“顯示關”不等于“系統停止”0x004只關 LCD 驅動輸出內部振蕩器和偏壓發生器可能還在跑功耗仍有幾百微安。真正進低功耗要兩步void ht1621_sleep(void) { ht1621_write_cmd(0x004); // 先關顯示驅動 ht1621_write_cmd(0x000); // 再關系統時鐘和偏壓發生器 } void ht1621_wakeup(void) { ht1621_write_cmd(0x034); // 重新配置偏壓和振蕩器 ht1621_write_cmd(0x002); // 重新使能系統 ht1621_refresh(); // RAM 內容還在直接刷新 ht1621_write_cmd(0x006); // 打開顯示 }喚醒函數里必須重新把偏壓和振蕩器配一遍因為系統使能命令是跟隨時鐘停振一起失效的。顯示 RAM 在芯片斷電前仍然保留所以醒來之后不用清屏直接刷新緩存內容即可。如果ht1621_sleep和 STM32 的HAL_PWR_EnterSTOPMode配合使用整機待機功耗能做到很低段碼屏的優勢就在這里。5. 現場調一塊 HT1621B 屏按這三步定位問題拿到一塊新屏或者新板子不要一頭扎進業務代碼先用固定畫板把鏈路打通。下面三個技巧能把大部分問題在半小時內定位。5.1 先上全亮畫板確認接線和 COM 位序寫一個臨時函數把所有段寫滿void ht1621_burn_test(void) { for (uint8_t i 0; i 32; i) { ht1621_set_seg(i, 0x0F); } ht1621_refresh(); }如果整屏全亮說明三線時序、初始化順序、偏壓設置都正常剩下只是位序問題。如果只有部分段亮看亮的是哪些 SEG 和 COM能直接反推玻璃的引腳排布。如果完全沒反應用示波器或邏輯分析儀看 CS 拉低期間 WR 上有沒有脈沖DATA 上有沒有101前導基本能區分是 MCU 沒發數據還是芯片沒工作。5.2 邏輯分析儀核對幀結構重點看 101 前導三線模擬時序用邏輯分析儀最直觀接 CS、WR、DATA 三根線采樣率設 1MHz 以上。抓一段ht1621_write_cmd(0x006)的波形正常應該看到 CS 低電平期間出現連續 12 個 WR 脈沖DATA 按 101 000000110 排列。這里有一個常見誤會很多人以為命令值是 0x006 就只發 6 個脈沖實際上前面還有 3 位前導和 9 位命令字總共 12 個。如果波形里只有 8 個脈沖說明發送函數沒把 9 位命令字發全。5.3 常見異常一覽現象可能原因排查方向上電花屏后正常初始化沒清 RAM確認系統使能后刷新全 0全亮但個別段不亮玻璃引腳虛焊或走線斷短接測試點跳過玻璃排查缺筆畫且對比度低偏壓檔和玻璃不匹配換 1/2 與 1/3 做交叉對比有規律閃爍VLCD 電容過小或電源紋波大加大電容到 1uF檢查參考地關不掉某些段緩存和 RAM 位序反了把字節內 COM 位順序倒過來試看起來是“寫代碼”的坑其實一半是硬件走線和玻璃規格的坑。HT1621B 這個芯片本身非常皮實只要時序正確、偏壓匹配、RAM 清過剩下的顯示問題基本都是硬件層面造成的。最后再說一句實操經驗段碼玻璃的引腳 1 位置各家不統一換屏廠時最優先核對的就是 SEG 順序表和偏壓規格這兩個對齊了驅動一行都不用改。本文還有配套的精品資源點擊獲取