STM32 HAL庫移植LTDC+SDRAM驅動RGB屏:從標準庫到CubeMX實戰(zhàn)
1. 項目概述從“拿來主義”到“知其所以然”最近在調一塊基于STM32F407ZGT6的板子屏幕用的是正點原子探索者開發(fā)板配套的4.3寸RGB屏型號通常是ATK-4342。原子哥的例程跑起來很流暢但那是基于標準庫的。現(xiàn)在項目要求用HAL庫和CubeMX來配置直接照搬例程里的那些LCD_Init()、LCD_Clear()函數(shù)十有八九會卡住。這個移植過程表面上是改幾個引腳和時序實際上是對STM32的LTDCLCD-TFT Display Controller外設、SDRAM控制器以及整個圖形顯示系統(tǒng)底層機制的一次深度梳理。我花了幾天時間把原子例程里“黑盒”的部分一個個撬開適配到CubeMX生成的工程里踩了不少坑也總結了一套比較穩(wěn)的流程。如果你也在做類似的事情希望這篇記錄能幫你省點時間。2. 核心思路與方案選型為什么是LTDCSDRAM在動手之前得先搞清楚正點原子這個LCD例程的顯示架構。它之所以流暢核心在于硬件加速。2.1 顯示方案對比FSMC模擬 vs. LTDC驅動很多初學者會用FSMCFlexible Static Memory Controller來模擬8080并口時序驅動LCD這種方式對于小尺寸、低分辨率的屏幕比如320x240是可行的。但對于探索者這塊800x480的RGB屏FSMC就力不從心了。RGB屏需要持續(xù)不斷地刷新像素數(shù)據(jù)數(shù)據(jù)量巨大8004802 Bytes/幀 ≈ 750KB用FSMC軟件刷屏會極度消耗CPU資源導致系統(tǒng)卡頓。而STM32F407自帶的LTDCLCD-TFT Display Controller是一個專為驅動RGB接口液晶屏設計的硬件外設。它的工作模式是CPU或DMA將一幀圖像數(shù)據(jù)存入一個稱為“幀緩沖區(qū)”的內存區(qū)域LTDC控制器會自動、周期性地從該緩沖區(qū)讀取數(shù)據(jù)轉換成RGB時序信號輸送給屏幕。這個過程完全由硬件完成不占用CPU時間從而實現(xiàn)流暢的顯示。2.2 幀緩沖區(qū)存放何處內部SRAM vs. 外部SDRAM下一個關鍵問題是幀緩沖區(qū)放哪里一幀800x480的RGB565圖像需要750KB內存。STM32F407的內部SRAM只有192KB顯然不夠。因此必須使用外部存儲器。正點原子探索者板載了一顆32MB的SDRAM型號通常為W9825G6KH。我們的方案就是利用STM32的FMCFlexible Memory Controller來驅動這片SDRAM并將其中的一部分區(qū)域比如首地址0xC0000000開始的750KB劃定為LTDC的幀緩沖區(qū)。這樣LTDC從SDRAM中讀取數(shù)據(jù)CPU也向SDRAM中寫入要顯示的新圖像互不干擾。這是高性能嵌入式GUI的通用基礎。所以移植的核心就是三件事用CubeMX正確配置LTDC包括像素時鐘、時序參數(shù)、層配置等。用CubeMX正確配置FMC以驅動SDRAM這是圖像數(shù)據(jù)的“家”。重寫原子例程的底層驅動函數(shù)將原來直接操作寄存器標準庫風格的代碼改為操作CubeMX生成的HAL庫數(shù)據(jù)結構并確保地址映射正確。3. CubeMX工程配置詳解這里假設你已經(jīng)有了一個基本的STM32F407的CubeMX工程。我們重點看LTDC和FMC的配置。3.1 LTDC配置步驟與參數(shù)計算在Pinout Configuration標簽頁的Multimedia分類下找到LTDC并啟用。1. 時鐘配置Clock Configuration LTDC的時鐘源是PLLSAI。我們需要先配置主時鐘樹確保為LTDC提供合適的像素時鐘。通常系統(tǒng)時鐘HCLK配置為168MHz。在Clock Configuration標簽頁找到PLLSAI配置。我們需要生成PLLSAI_R時鐘作為LTDC的時鐘源。計算公式LTDC_CLK (HSE / PLL_M) * PLLSAI_N / PLLSAIDIV_R以驅動800x480屏幕常見的30fps為例所需像素時鐘大約在30MHz左右。一個可行的配置是PLL_M 8(如果HSE8MHz)PLLSAI_N 384PLLSAIDIV_R 8則LTDC_CLK (8MHz / 8) * 384 / 8 48MHz。這個頻率是足夠的實際刷新率最終由LTDC的時序參數(shù)決定。2. 參數(shù)配置Parameter Settings 這是最關鍵也最容易出錯的部分。你需要正點原子屏幕的數(shù)據(jù)手冊通常在產(chǎn)品wiki頁面能找到。Display Resolution: 設為800x480。Timing Configuration:Horizontal Synchronization (HSYNC): 對應數(shù)據(jù)手冊中的thp即行同步脈沖寬度。例如40(單位是像素時鐘周期)。Horizontal Back Porch (HBP): 對應thb行同步后沿。例如48。Active Width: 就是有效像素寬度800。Horizontal Front Porch (HFP): 對應thf行同步前沿。例如40。Total Width: 系統(tǒng)會自動計算為HSYNC HBP Active Width HFP 928。垂直方向Vertical的參數(shù)同理VSYNC,VBP,Active Height,VFP。例如VSYNC10,VBP33,Active Height480,VFP10Total Height533。Signal Polarity: 根據(jù)屏幕手冊設置同步信號極性。常見配置是HSYNC和VSYNC低有效DE數(shù)據(jù)使能高有效。這個必須嚴格按手冊來否則可能無顯示或顯示錯位。Background Color: 初始化時的背景色默認黑色即可。3. 層配置Layer Settings LTDC支持兩個疊加層我們通常只使用第一層。啟用Layer1。Window Position:X00,Y00,Width800,Height480。Pixel Format: 選擇RGB565。這與正點原子例程及我們常用的16位顏色格式一致。Color Frame Buffer Start Address:這是重點這里先填一個內部SRAM的地址作為臨時緩沖比如0x20000000讓LTDC先工作起來。等我們在代碼里初始化好SDRAM后再通過HAL庫函數(shù)動態(tài)修改這個地址到SDRAM區(qū)域如0xC0000000。Alpha和Default Color保持默認。配置完成后CubeMX會自動為你分配LTDC所需的引腳RGB數(shù)據(jù)線、同步信號、時鐘等檢查一下是否與探索者底板原理圖一致即可。3.2 FMCSDRAM配置步驟在Pinout Configuration標簽頁的Connectivity分類下找到FMC并啟用選擇SDRAM1。1. 參數(shù)配置 你需要根據(jù)板載SDRAM芯片如W9825G6KH的數(shù)據(jù)手冊填寫。Bank: 選擇Bank 1或Bank 2根據(jù)原理圖連接。探索者通常接在Bank 1對應FMC的SDCKE1和SDNE1。Column Bits Number: 列地址位數(shù)。對于W9825G6KH是9 bits。Row Bits Number: 行地址位數(shù)。同上是13 bits。Memory Data Width: 數(shù)據(jù)位寬。通常是16 bits。CAS Latency: 列地址選通潛伏期。設為2。Write Protection:Disabled。Timing:Load Mode Register to Active:TMRD通常設為2個時鐘周期。Exit Self-refresh delay:TXSR手冊中典型值約70ns換算成時鐘周期如FMC時鐘90MHz周期11.1ns設為7。Row Cycle Delay:TRC典型值約63ns設為6。Row Precharge Delay:TRP典型值約15ns設為2。Row to Column Delay:TRCD典型值約15ns設為2。SDRAM Common Clock:2表示時鐘分頻產(chǎn)生穩(wěn)定的同步時鐘。SDRAM Burst Read: 啟用。2. 引腳檢查 FMC的引腳非常多地址線、數(shù)據(jù)線、控制線。CubeMX會自動分配但務必核對原理圖確保SDCKE1、SDNE1、SDCLK、SDNWE等關鍵控制線正確。注意SDRAM的初始化時序非常敏感。如果配置后無法正常讀寫首先檢查時序參數(shù)尤其是TRCTXSR它們需要根據(jù)具體的FMC核心時鐘頻率在Clock Configuration中查看HCLK和SDRAM芯片手冊精確計算??梢韵扔迷拥臉藴蕩炖虆?shù)作為參考。4. 代碼移植與驅動層重寫生成代碼后我們進入MDK-ARM或STM32CubeIDE工程。移植工作主要圍繞lcd.c和lcd.h展開。4.1 SDRAM初始化與測試CubeMX生成的代碼在main.c中會調用MX_FMC_Init()。但這個函數(shù)只完成了FMC控制器的配置并沒有發(fā)送命令序列來初始化SDRAM芯片本身。我們需要補充這個步驟。通常我們會創(chuàng)建一個sdram.c/h文件。在其中實現(xiàn)一個SDRAM_Init()函數(shù)。這個函數(shù)的內容可以直接參考正點原子標準庫例程中的sdram_init函數(shù)但需要將其中的寄存器操作FMC_Bank5_6-SDCR等改為HAL庫提供的函數(shù)。更高效的做法是使用HAL庫自帶的SDRAM初始化序列。HAL庫提供了HAL_SDRAM_Init()、HAL_SDRAM_SendCommand()等函數(shù)。我們需要做的是在main()函數(shù)中MX_FMC_Init()之后調用HAL_SDRAM_Init()。然后使用HAL_SDRAM_SendCommand()依次發(fā)送預充電、自動刷新、設置模式寄存器等命令。命令參數(shù)如模式寄存器值需要根據(jù)具體SDRAM芯片手冊填寫。// 示例片段 (sdram.c) SDRAM_HandleTypeDef hsdram1; // CubeMX已聲明 void SDRAM_Init_Sequence(void) { FMC_SDRAM_CommandTypeDef command; __IO uint32_t tmpmrd 0; // 1. 時鐘配置使能命令 command.CommandMode FMC_SDRAM_CMD_CLK_ENABLE; command.CommandTarget FMC_SDRAM_CMD_TARGET_BANK1; command.AutoRefreshNumber 1; command.ModeRegisterDefinition 0; HAL_SDRAM_SendCommand(hsdram1, command, 0xFFFF); // 2. 延時至少100us HAL_Delay(1); // 簡單延時實際應用建議用精確延時 // 3. 預充電所有存儲區(qū)命令 command.CommandMode FMC_SDRAM_CMD_PALL; command.CommandTarget FMC_SDRAM_CMD_TARGET_BANK1; HAL_SDRAM_SendCommand(hsdram1, command, 0xFFFF); // 4. 自動刷新命令執(zhí)行至少2次 command.CommandMode FMC_SDRAM_CMD_AUTOREFRESH_MODE; command.CommandTarget FMC_SDRAM_CMD_TARGET_BANK1; command.AutoRefreshNumber 8; // 刷新次數(shù) for(int i0; i2; i) { HAL_SDRAM_SendCommand(hsdram1, command, 0xFFFF); } // 5. 設置模式寄存器命令 // 模式寄存器值(MRD)需要計算 Burst Length, CAS Latency, Operating Mode等 // 對于W9825G6KH突發(fā)讀、CAS2、順序模式MRD可能是0x230 tmpmrd (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 | SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | SDRAM_MODEREG_CAS_LATENCY_2 | SDRAM_MODEREG_OPERATING_MODE_STANDARD | SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; command.CommandMode FMC_SDRAM_CMD_LOAD_MODE; command.CommandTarget FMC_SDRAM_CMD_TARGET_BANK1; command.ModeRegisterDefinition tmpmrd; HAL_SDRAM_SendCommand(hsdram1, command, 0xFFFF); // 6. 設置刷新速率 // 需要通過HAL_SDRAM_ProgramRefreshRate()設置值根據(jù)SDRAM刷新周期和FMC時鐘計算 HAL_SDRAM_ProgramRefreshRate(hsdram1, 0x0569); // 示例值需精確計算 }初始化完成后務必編寫一個簡單的SDRAM讀寫測試函數(shù)例如向SDRAM的起始地址寫入一個已知模式如0xAA55AA55再讀回來驗證。這是后續(xù)顯示正常的基礎保障。4.2 LTDC初始化與幀緩沖區(qū)重定向CubeMX生成的MX_LTDC_Init()函數(shù)已經(jīng)完成了LTDC外設的基本配置。我們接下來要做兩件事將LTDC的幀緩沖區(qū)地址指向SDRAM。 在main.c的main()函數(shù)中MX_LTDC_Init()之后調用HAL庫函數(shù)修改層緩沖區(qū)地址。// 獲取LTDC層1的配置句柄 LTDC_LayerCfgTypeDef *pLayerCfg hltdc.LayerCfg[0]; // 層1索引為0 // 修改幀緩沖區(qū)地址為SDRAM首地址 pLayerCfg-FBStartAdress (uint32_t)0xC0000000; // 重新配置該層 HAL_LTDC_ConfigLayer(hltdc, pLayerCfg, 0);初始化SDRAM中的顯存區(qū)域。 在指向SDRAM后我們需要將整個幀緩沖區(qū)清空為背景色或者填充一幅初始圖像??梢詫懸粋€簡單的函數(shù)void LCD_Clear(uint32_t Color) { uint32_t *pixel (uint32_t*)0xC0000000; // 800*480像素RGB565每個像素2字節(jié)。按32位(4字節(jié))操作更快。 for(uint32_t i0; i800*480/2; i) { // 將16位顏色組合成32位寫入 *pixel ((Color 0xFFFF) 16) | (Color 0xFFFF); } // 如果需要強制刷新可以觸發(fā)LTDC的Reload __HAL_LTDC_RELOAD_IMMEDIATE_CONFIG(hltdc); }4.3 關鍵驅動函數(shù)移植與優(yōu)化現(xiàn)在我們可以開始移植正點原子lcd.c中的核心函數(shù)了。原子例程的函數(shù)大多是直接操作FSMC或GRAM地址進行讀寫。我們需要將其改造為基于SDRAM幀緩沖區(qū)的操作。核心思路將屏幕上的一個像素點(x, y)映射到SDRAM幀緩沖區(qū)中的特定地址。 對于RGB565格式800x480的屏幕計算公式為像素地址 幀緩沖區(qū)基地址 (y * 800 x) * 21. 畫點函數(shù)LCD_DrawPoint 這是最基本的函數(shù)其他高級函數(shù)畫線、填充、顯示字符都基于它。void LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t color) { // 參數(shù)檢查 if(x 800 || y 480) return; // 計算內存地址 uint32_t addr SDRAM_FRAME_BUFFER_ADDR (y * 800 x) * 2; // 寫入顏色值16位 *(__IO uint16_t*)addr color; }2. 讀點函數(shù)LCD_ReadPoint 用于讀取屏幕上某點的顏色在實現(xiàn)觸摸校準、圖像處理時有用。uint16_t LCD_ReadPoint(uint16_t x, uint16_t y) { if(x 800 || y 480) return 0; uint32_t addr SDRAM_FRAME_BUFFER_ADDR (y * 800 x) * 2; return *(__IO uint16_t*)addr; }3. 填充函數(shù)LCD_Fill 快速填充一個矩形區(qū)域是清屏、畫矩形的基礎。這里需要優(yōu)化性能直接操作32位數(shù)據(jù)總線。void LCD_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color) { uint16_t width ex - sx 1; uint16_t height ey - sy 1; uint32_t color32 ((uint32_t)color 16) | color; // 組合成32位顏色 for(uint16_t i0; iheight; i) { uint32_t *pixel (uint32_t*)(SDRAM_FRAME_BUFFER_ADDR ((syi) * 800 sx) * 2); // 一次寫入2個像素 for(uint16_t j0; jwidth/2; j) { *pixel color32; } // 如果寬度是奇數(shù)補一個像素 if(width 1) { *(__IO uint16_t*)pixel color; } } // 可選局部刷新 // LTDC_Reload(hltdc, LTDC_RELOAD_VERTICAL_BLANKING); }4. 字符顯示函數(shù)LCD_ShowChar和字符串顯示LCD_ShowString 這部分邏輯與原子例程幾乎一致因為字模數(shù)據(jù)是通用的。主要改動是調用我們新寫的LCD_DrawPoint或LCD_Fill函數(shù)來繪制像素。注意字模的取模方式橫向/縱向高位在前/在后必須與原子例程保持一致。5. 圖片顯示函數(shù)LCD_ShowImage 將存儲在外部Flash或數(shù)組中的圖片數(shù)據(jù)RGB565格式復制到幀緩沖區(qū)的指定位置。這里可以使用memcpy函數(shù)但要注意地址對齊和性能。對于大圖可以考慮使用DMA2D如果STM32支持來加速。void LCD_ShowImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint16_t *pImage) { uint32_t dst_addr; for(uint32_t i0; iheight; i) { dst_addr SDRAM_FRAME_BUFFER_ADDR ((yi) * 800 x) * 2; memcpy((void*)dst_addr, (void*)(pImage i*width), width*2); } }5. 調試過程與常見問題排查移植過程很少一帆風順以下是我遇到的一些典型問題及解決方法。5.1 問題排查清單現(xiàn)象可能原因排查步驟與解決方案屏幕全白/全黑/無任何顯示1. LTDC時鐘或時序配置錯誤。2. 屏幕背光未開啟。3. 同步信號極性錯誤。4. SDRAM未初始化或初始化失敗LTDC讀取到錯誤數(shù)據(jù)。1.檢查硬件用萬用表或示波器測量背光電壓、LCD電源電壓通常3.3V或5V。2.檢查時序用邏輯分析儀或示波器抓取LTDC的PCLK、HSYNC、VSYNC、DE信號與數(shù)據(jù)手冊對比。這是最直接的證據(jù)。3.簡化測試先將LTDC幀緩沖區(qū)地址設為內部SRAM并填充一個純色如紅色。如果此時能顯示純色問題在SDRAM如果仍無顯示問題在LTDC配置或屏幕硬件。4.檢查SDRAM運行SDRAM讀寫測試函數(shù)確保能正確寫入和讀出數(shù)據(jù)。屏幕花屏、條紋、錯位1. SDRAM時序參數(shù)如CAS Latency, TRC, TRP不匹配。2. 幀緩沖區(qū)地址計算錯誤或寫入越界。3. LTDC的像素格式RGB565與屏幕或寫入數(shù)據(jù)格式不匹配。4. SDRAM數(shù)據(jù)線有干擾或虛焊。1.校準SDRAM時序嘗試微調TRC、TXSR等參數(shù)尤其是降低FMC時鐘速度HCLK分頻測試是否改善。2.檢查地址計算在LCD_DrawPoint函數(shù)中設置斷點觀察寫入的地址是否在預期的SDRAM范圍內。3.檢查數(shù)據(jù)格式確保LCD_ShowImage等函數(shù)使用的源數(shù)據(jù)是RGB565格式。4.檢查硬件連接檢查SDRAM芯片的焊接特別是數(shù)據(jù)線D0-D15。顯示內容部分正確但閃爍或撕裂1. 幀緩沖區(qū)大小不足或地址重疊。2. LTDC刷新率與屏幕不匹配。3. CPU與LTDC同時訪問SDRAM產(chǎn)生沖突帶寬不足。1.檢查緩沖區(qū)確保分配的幀緩沖區(qū)大小至少為800*480*2字節(jié)且沒有其他數(shù)據(jù)占用該區(qū)域。2.計算刷新率刷新率 LTDC_CLK / (Total_Width * Total_Height)。確保在屏幕支持的范圍內通常30-60Hz。3.啟用FMC的寫緩沖在CubeMX的FMC配置中嘗試啟用Write FIFO或Write Burst功能。4.使用雙緩沖分配兩個幀緩沖區(qū)LTDC顯示一個時CPU更新另一個然后在垂直消隱期切換。這需要修改LTDC的配置函數(shù)。字符或圖片顯示錯亂1. 字模取模方式與顯示函數(shù)邏輯不匹配。2.LCD_ShowChar函數(shù)中的坐標計算錯誤。3. 圖片數(shù)據(jù)數(shù)組在編譯時被優(yōu)化或存放地址不對。1.統(tǒng)一取模方式確認使用的字庫生成軟件如PCtoLCD2002的設置掃描方式、輸出格式與LCD_ShowChar函數(shù)中的像素提取邏輯完全一致。2.單步調試跟蹤LCD_ShowChar畫第一個字符的前幾個像素看寫入的地址和顏色值是否正確。3.檢查常量數(shù)組將圖片數(shù)據(jù)聲明為const全局數(shù)組并檢查map文件確認其被正確鏈接到Flash中。5.2 調試心得與技巧分步驗證隔離問題不要試圖一次性把所有功能都調通。正確的順序是第一步只配置LTDC幀緩沖區(qū)用內部SRAM測試純色填充。確保LTDC硬件和屏幕基本工作。第二步單獨配置和測試SDRAM進行大規(guī)模的連續(xù)讀寫測試確保內存穩(wěn)定。第三步將LTDC幀緩沖區(qū)切換到SDRAM再次測試純色填充。第四步移植并測試最基本的LCD_DrawPoint和LCD_Fill函數(shù)。第五步移植高級功能字符、圖片。善用工具邏輯分析儀是調試LTDC時序的利器幾百塊錢的國產(chǎn)貨就夠用。直接看HSYNC、VSYNC、DE和PCLK的關系比瞎猜強一百倍。ST-Link Utility或STM32CubeProgrammer可以實時查看和修改SDRAM指定地址的內容驗證CPU是否寫入了正確的數(shù)據(jù)。串口打印在關鍵步驟如SDRAM初始化、地址計算后打印信息輔助判斷程序執(zhí)行流。關注Cache和DMA當CPU頻率較高時如果開啟了數(shù)據(jù)緩存D-CacheCPU對SDRAM的寫入可能不會立即生效導致LTDC讀到舊數(shù)據(jù)。在涉及幀緩沖區(qū)操作的函數(shù)中可以考慮在寫入后調用SCB_CleanDCache_by_Addr()函數(shù)清理緩存。同樣如果使用DMA2D加速也要注意緩存一致性問題。參考官方例程ST官方在STM32CubeF4包中提供了LTDC和SDRAM的示例工程STM32Cube_FW_F4_Vxx\Projects\STM32F4xx-Nucleo\Examples\LTDC。雖然硬件平臺不同但其HAL庫的調用方式、初始化流程極具參考價值尤其是SDRAM的初始化命令序列。移植成功后你將獲得一個基于CubeMX和HAL庫的、驅動高性能RGB屏的穩(wěn)定基礎。在這個基礎上你可以進一步集成TouchGFX、LVGL等圖形庫或者開發(fā)自己的UI應用顯示性能和開發(fā)效率都會比FSMC模擬方式有質的提升。整個過程的精髓在于理解“數(shù)據(jù)流”CPU準備圖像數(shù)據(jù) - 存入SDRAM幀緩沖區(qū) - LTDC自動按時序讀出并發(fā)送給屏幕。把握住這個鏈條問題就都能定位和解決。

相關新聞

學生黨降AI率怎么省錢?2026年20款免費試用工具盤點

學生黨降AI率怎么省錢?2026年20款免費試用工具盤點

2個實測免費的降AIGC率工具,順利通過ai率查重! AI 檢測本身就沒有公開 算法 ,降 AI 工具更像黑箱。如果降AI率連一次免費試用都不給,那風險太大了。萬一AI率沒有降下來,又不能退,少則幾元多則幾十。 對于學…

2026/7/30 3:21:45 閱讀更多
Java字符串搜索:從contains()底層原理到多模式匹配實戰(zhàn)

Java字符串搜索:從contains()底層原理到多模式匹配實戰(zhàn)

1. 項目概述:從“找茬”到“定位”的字符串搜索在日常的Java開發(fā)中,我們經(jīng)常需要處理一個看似簡單卻無處不在的任務:判斷一個字符串里是否包含了另一個字符串。比如,用戶輸入了一段評論,我們需要檢查其中是否含有敏感詞…

2026/7/30 3:21:45 閱讀更多
Objective-C Block內存布局與實現(xiàn)原理詳解

Objective-C Block內存布局與實現(xiàn)原理詳解

1. Block內存布局深度解析在編程領域,Block是一種特殊的語法結構,它允許我們將代碼塊作為參數(shù)傳遞或存儲在變量中。理解Block的內存布局對于編寫高效、安全的代碼至關重要。今天我們就來徹底拆解Block在內存中的組織方式。Block本質上是一個對象&#xf…

2026/7/30 4:31:47 閱讀更多
[GESP202606 四級] 掃雷

[GESP202606 四級] 掃雷

B4557 [GESP202606 四級] 掃雷 https://www.luogu.com.cn/problem/B4557 中國計算機學會(CCF)2026年6月C四級講解——掃雷 https://www.bilibili.com/video/BV1MCMg6AEXR/ B4557 [GESP202606 四級] 掃雷 https://www.bilibili.com/video/BV1ZKTj6ZEVh/ 2…

2026/7/30 0:01:06 閱讀更多