戰(zhàn):EmbeddedBuilder從Keil遷移與避坑指南)
簡(jiǎn)介EmbeddedBuilder-v1.3.5.21587 是專為 GD32F 系列 MCU 打造的集成開發(fā)工具面向從事工業(yè)控制、智能家居、物聯(lián)網(wǎng)等嵌入式方向的開發(fā)者無論入門新手還是資深工程師都能借助它完成代碼編寫、編譯、調(diào)試與項(xiàng)目管理。該版本為最新穩(wěn)定版內(nèi)建針對(duì) GD32F 優(yōu)化的 GCC 編譯器支持 C/C并集成 SWD、JTAG 在線調(diào)試能力可設(shè)置斷點(diǎn)、查看變量與讀寫內(nèi)存。壓縮包為 7z 格式體積約 321.37MB內(nèi)含示例工程與輔助工具等模塊覆蓋基礎(chǔ)外設(shè)驅(qū)動(dòng)、RTOS 演示、網(wǎng)絡(luò)通信等場(chǎng)景便于快速上手與移植。目前已有 1553 人學(xué)習(xí)下載適合需要一站式搭建 GD32F 開發(fā)環(huán)境、對(duì)照示例工程理解外設(shè)與庫用法的讀者參考使用。1. 從一次 Keil 工程遷移翻車說起這套 GD32 工具鏈到底能不能接上周幫一個(gè)做工業(yè)控制的朋友處理老項(xiàng)目遷移他們?cè)居?Keil MDK 維護(hù)一套 GD32F303 的電機(jī)控制代碼結(jié)果新來的同事把工程文件路徑改成了中文編譯直接報(bào)找不到啟動(dòng)文件。折騰了一下午最后換用 EmbeddedBuilder-v1.3.5.21587 重新建工程才把問題繞過去。這件事讓我意識(shí)到很多做嵌入式開發(fā)的人對(duì) GD32 的官方工具鏈其實(shí)處于「聽說過但沒真用過」的狀態(tài)——知道有這么個(gè)東西但不確定它跟 Keil、IAR 到底什么關(guān)系能不能直接吃現(xiàn)有的源碼換過去要改多少東西。EmbeddedBuilder-v1.3.5.21587 是 GD32F 系列 MCU 的官方嵌入式開發(fā)工具定位上屬于「配置 代碼生成 工程管理」三合一的 IDE 環(huán)境。它解決的核心問題不是編譯本身而是 GD32F 系列芯片的外設(shè)初始化配置和工程框架搭建。適合兩類人一是剛接觸 GD32F 系列、不想從零手寫寄存器配置的開發(fā)者二是手里有 GD32F 項(xiàng)目、想從 Keil/IAR 遷移到官方工具鏈的團(tuán)隊(duì)。如果你只是偶爾點(diǎn)個(gè)燈用 Keil 加標(biāo)準(zhǔn)庫也能跑但一旦涉及多外設(shè)協(xié)同、時(shí)鐘樹配置、中斷優(yōu)先級(jí)管理這套工具的圖形化配置優(yōu)勢(shì)就體現(xiàn)出來了。2. 工具鏈拆解EmbeddedBuilder 的工程結(jié)構(gòu)與 GD32F 固件庫依賴2.1 安裝包里到底裝了什么拿到 EmbeddedBuilder-v1.3.5.21587 的安裝包后先別急著雙擊下一步。我習(xí)慣先把安裝目錄結(jié)構(gòu)摸清楚因?yàn)楹竺娼üこ?、配路徑、調(diào)編譯器都跟這個(gè)有關(guān)。安裝完成后根目錄下通常有這么幾個(gè)關(guān)鍵文件夾目錄/文件作用是否必須保留eclipse/IDE 主體基于 Eclipse 框架是toolchain/集成的 GCC 工具鏈arm-none-eabi是plugins/GD32 芯片支持包和配置插件是workspace/默認(rèn)工作空間存放用戶工程可改路徑GD32FirmwareLib/GD32F 系列固件庫源碼建工程時(shí)引用這里有個(gè)容易忽略的點(diǎn)EmbeddedBuilder 本質(zhì)上是 Eclipse 加了一組 GD32 專用插件所以它的工程管理邏輯跟標(biāo)準(zhǔn) Eclipse 項(xiàng)目是一致的。這意味著你可以用 Eclipse 的那套快捷鍵、視圖布局、斷點(diǎn)管理但同時(shí)也意味著它的編譯系統(tǒng)走的是 GCC Makefile 那套跟 Keil 的 ARMCC 編譯鏈不是一回事。2.2 固件庫版本與芯片型號(hào)的對(duì)應(yīng)關(guān)系GD32F 系列固件庫分了好幾個(gè)分支F1、F3、F4、F5 各有一套。EmbeddedBuilder-v1.3.5.21587 安裝包里自帶的固件庫版本通常是 GD32F10x_Firmware_Library、GD32F30x_Firmware_Library 等。建工程時(shí)如果選錯(cuò)了固件庫版本編譯能過但運(yùn)行會(huì)出玄學(xué)問題——比如串口波特率對(duì)不上、定時(shí)器周期差一倍。常見做法是先確認(rèn)你手上芯片的具體型號(hào)比如 GD32F303RCT6然后去安裝目錄的GD32FirmwareLib/下找對(duì)應(yīng)的文件夾。如果找不到完全匹配的選同系列同 Flash 容量的版本再手動(dòng)替換啟動(dòng)文件和鏈接腳本。# 查看安裝目錄下自帶的固件庫版本 ls -d $EMBEDDED_BUILDER_HOME/GD32FirmwareLib/GD32F* # 輸出示例 # GD32F10x_Firmware_Library GD32F30x_Firmware_Library # GD32F4xx_Firmware_Library GD32F5xx_Firmware_Library這段命令的作用是快速列出安裝包自帶的固件庫分支。$EMBEDDED_BUILDER_HOME需要替換成你的實(shí)際安裝路徑。如果輸出里沒有你需要的系列說明這個(gè)版本的 EmbeddedBuilder 可能不帶該系列支持需要單獨(dú)下載固件庫包再手動(dòng)掛載。2.3 新建工程的正確姿勢(shì)很多人第一次用 EmbeddedBuilder 建工程習(xí)慣性地點(diǎn)「File → New → Project」然后選個(gè)空工程就開始寫代碼。這樣建出來的工程沒有芯片初始化代碼也沒有鏈接腳本編譯能過但燒進(jìn)去不跑。正確的流程是走「GD32 Project」向?qū)ile → New → GD32 Project → 選擇芯片系列如 GD32F30x → 選擇具體型號(hào)如 GD32F303RC → 選擇固件庫版本如 GD32F30x_Firmware_Library_V2.1.0 → 勾選需要的外設(shè)GPIO、USART、TIMER 等 → 設(shè)置時(shí)鐘源HXTAL 頻率、PLL 倍頻 → Finish向?qū)ё咄旰驣DE 會(huì)自動(dòng)生成main.c、gd32f30x_it.c、system_gd32f30x.c以及對(duì)應(yīng)的鏈接腳本.ld文件。這里的關(guān)鍵參數(shù)是時(shí)鐘源配置——HXTAL 頻率填錯(cuò)后面所有外設(shè)的時(shí)鐘都會(huì)跟著錯(cuò)。我一般會(huì)在生成后立刻打開system_gd32f30x.c確認(rèn)__SYSTEM_CLOCK宏定義的值跟實(shí)際晶振匹配。注意向?qū)Ю锕催x的外設(shè)只是幫你生成初始化框架代碼具體的引腳復(fù)用、中斷優(yōu)先級(jí)、DMA 通道這些還是要在代碼里手動(dòng)配。別指望圖形化界面能一鍵搞定所有事。3. 從 Keil 遷移到 EmbeddedBuilder源碼兼容性與編譯鏈切換3.1 源碼層面的兼容性判斷Keil 工程里的源碼能不能直接搬到 EmbeddedBuilder 里用取決于你原來用的是標(biāo)準(zhǔn)外設(shè)庫還是寄存器直接操作。如果是標(biāo)準(zhǔn)外設(shè)庫gd32f30x_gpio.c、gd32f30x_usart.c這些基本可以原樣搬因?yàn)?EmbeddedBuilder 自帶的固件庫跟 Keil 下用的標(biāo)準(zhǔn)庫是同一套源碼只是編譯鏈不同。但如果你原來用的是寄存器直接賦值比如GPIOA_CTL0 0x...那就要注意 GD32 的寄存器定義在 GCC 和 ARMCC 下可能有細(xì)微差異常見的是位域結(jié)構(gòu)體的對(duì)齊方式不同。我一般會(huì)先做一次「空編譯」測(cè)試把 Keil 工程里的.c和.h文件全部拷到 EmbeddedBuilder 新建的工程里不急著改代碼先點(diǎn)編譯??磮?bào)錯(cuò)類型——如果是「undefined reference」說明缺源文件或庫文件如果是「conflicting types」說明頭文件包含順序有問題如果是「section overflow」說明鏈接腳本的 Flash/RAM 分配跟實(shí)際芯片不匹配。3.2 鏈接腳本的修改要點(diǎn)EmbeddedBuilder 生成的鏈接腳本.ld文件里Flash 起始地址和大小是按向?qū)Ю镞x的芯片型號(hào)自動(dòng)填的。但如果你從 Keil 遷移過來Keil 的分散加載文件.sct里的地址分配可能跟這個(gè)不一樣。常見的情況是Keil 工程里把 Bootloader 和 App 分成了兩個(gè)區(qū)App 從0x08004000開始而 EmbeddedBuilder 默認(rèn)從0x08000000開始。/* gd32f30x_flash.ld 片段 */ MEMORY { FLASH (rx) : ORIGIN 0x08000000, LENGTH 256K RAM (rwx) : ORIGIN 0x20000000, LENGTH 48K }上面是默認(rèn)配置。如果你需要把 App 放到0x08004000就把ORIGIN改成0x08004000同時(shí)LENGTH減去 16K。改完鏈接腳本后還要確認(rèn)system_gd32f30x.c里的VECT_TAB_OFFSET宏定義也跟著改否則中斷向量表偏移不對(duì)一進(jìn)中斷就跑飛。3.3 編譯鏈差異導(dǎo)致的坑Keil 用 ARMCCEmbeddedBuilder 用 GCC兩者對(duì) C 標(biāo)準(zhǔn)的支持程度和默認(rèn)行為有差異。最常見的翻車場(chǎng)景是printf重定向——Keil 下你可能用了#pragma import(__use_no_semihosting)和自定義fputc搬到 GCC 下這套不管用要改用_write或_write_r。/* GCC 下的 printf 重定向?qū)懛?*/ #include sys/stat.h #include unistd.h int _write(int file, char *ptr, int len) { int i; for (i 0; i len; i) { while (USART_CTL0(USART0) USART_CTL0_TBE) 0); USART_DATA(USART0) (uint8_t)ptr[i]; } return len; }這段代碼把標(biāo)準(zhǔn)庫的_write函數(shù)重定向到 USART0 上這樣printf就能通過串口輸出。注意USART_CTL0_TBE是發(fā)送緩沖區(qū)空標(biāo)志不同系列的 GD32 這個(gè)宏名字可能略有不同F(xiàn)30x 系列是USART_CTL0_TBEF10x 系列可能是USART_FLAG_TBE具體查對(duì)應(yīng)固件庫的頭文件。提示如果編譯時(shí)報(bào)_write重復(fù)定義檢查鏈接選項(xiàng)里有沒有加-specsnosys.specs或-specsnano.specs這兩個(gè)參數(shù)會(huì)影響標(biāo)準(zhǔn)庫的鏈接行為。4. 外設(shè)配置實(shí)戰(zhàn)用圖形化界面配 GPIO 和 USART 的邊界條件4.1 GPIO 配置的隱藏參數(shù)EmbeddedBuilder 的圖形化 GPIO 配置界面看起來很簡(jiǎn)單選引腳、選模式、選上下拉、選輸出速度。但有幾個(gè)參數(shù)在界面上不顯眼卻直接影響功能。比如「輸出速度」這一項(xiàng)默認(rèn)是 50MHz如果你驅(qū)動(dòng)的是低速外設(shè)比如繼電器用 50MHz 的翻轉(zhuǎn)速率反而會(huì)引入振鈴和 EMI 問題。我一般會(huì)根據(jù)實(shí)際負(fù)載把速度降到 2MHz 或 10MHz。另一個(gè)容易忽略的是「復(fù)用功能重映射」。GD32F 系列的 USART、SPI、I2C 引腳很多都有重映射選項(xiàng)圖形化界面里如果只選了「USART0_TX」但沒選重映射生成的代碼里就不會(huì)調(diào)gpio_pin_remap_config()。結(jié)果就是引腳配置對(duì)了但功能出不來。/* 重映射配置示例把 USART0 映射到 PB6/PB7 */ gpio_pin_remap_config(GPIO_USART0_REMAP, ENABLE); gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6); gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_7);這段代碼先使能 USART0 的重映射然后把 PB6 配成復(fù)用推挽輸出TXPB7 配成浮空輸入RX。注意GPIO_MODE_AF_PP這個(gè)模式在 F30x 固件庫里叫GPIO_MODE_AF_PP在 F10x 里可能叫GPIO_MODE_AF_OD或別的建工程時(shí)選對(duì)固件庫版本很重要。4.2 USART 波特率計(jì)算的精度問題圖形化界面里填波特率比如 115200它會(huì)自動(dòng)算分頻系數(shù)。但 GD32 的 USART 波特率計(jì)算公式是baud fCK / (16 * USARTDIV)其中USARTDIV是一個(gè)定點(diǎn)數(shù)整數(shù)部分 12 位小數(shù)部分 4 位。當(dāng)fCK不是 16 的整數(shù)倍時(shí)算出來的實(shí)際波特率會(huì)有誤差。誤差超過 2% 就可能出現(xiàn)亂碼。我一般會(huì)在生成代碼后手動(dòng)驗(yàn)算一遍/* 驗(yàn)算 USART0 波特率PCLK2 120MHz目標(biāo) 115200 */ /* USARTDIV 120000000 / (16 * 115200) 65.104 */ /* 整數(shù)部分 65 0x41小數(shù)部分 0.104 * 16 ≈ 1.67 → 取 2 */ /* 實(shí)際波特率 120000000 / (16 * (65 2/16)) 115107.9 */ /* 誤差 (115107.9 - 115200) / 115200 ≈ -0.08%可接受 */如果誤差超過 2%常見做法是換一個(gè)更接近的 PCLK2 分頻值或者降低波特率到 57600。有些 GD32F 型號(hào)支持波特率自動(dòng)檢測(cè)但那個(gè)功能在標(biāo)準(zhǔn)庫里的配置比較繞新手不建議一上來就用。4.3 中斷優(yōu)先級(jí)配置的坑GD32F 系列的中斷優(yōu)先級(jí)分組跟 STM32 類似有 NVIC_PRIORITY_GROUP_0 到 GROUP_4 五種分組方式。EmbeddedBuilder 的圖形化界面里默認(rèn)用的是 GROUP_4也就是 4 位搶占優(yōu)先級(jí)、0 位響應(yīng)優(yōu)先級(jí)。如果你從 Keil 工程遷移過來原來用的是 GROUP_2那中斷嵌套行為會(huì)完全不一樣。/* 設(shè)置中斷優(yōu)先級(jí)分組為 GROUP_22 位搶占2 位響應(yīng) */ nvic_priority_group_set(NVIC_PRORITY_GROUP_2); /* 配置 USART0 中斷搶占優(yōu)先級(jí) 1響應(yīng)優(yōu)先級(jí) 0 */ nvic_irq_enable(USART0_IRQn, 1, 0);這段代碼先把優(yōu)先級(jí)分組設(shè)為 GROUP_2然后給 USART0 中斷分配搶占優(yōu)先級(jí) 1、響應(yīng)優(yōu)先級(jí) 0。注意nvic_irq_enable的第二個(gè)參數(shù)是搶占優(yōu)先級(jí)第三個(gè)是響應(yīng)優(yōu)先級(jí)順序別搞反。如果分組設(shè)成 GROUP_4那第二個(gè)參數(shù)的有效范圍是 0-15第三個(gè)參數(shù)無效。注意中斷優(yōu)先級(jí)分組一旦設(shè)定整個(gè)工程里所有中斷都按這個(gè)規(guī)則來。如果中途改了分組之前配好的中斷優(yōu)先級(jí)全部要重新算。5. 避坑與排查GD32F 工具鏈遷移中的五個(gè)血淚教訓(xùn)5.1 編譯通過但程序不跑現(xiàn)象EmbeddedBuilder 里編譯零報(bào)錯(cuò)燒錄也成功但板子上電后沒反應(yīng)串口無輸出。原因最常見的是啟動(dòng)文件選錯(cuò)了。GD32F303 的啟動(dòng)文件有startup_gd32f30x_hd.s高密度、startup_gd32f30x_xd.s超高密度、startup_gd32f30x_cl.s互聯(lián)型之分。如果芯片是 256K Flash 的 HD 型號(hào)但工程里鏈接的是 CL 的啟動(dòng)文件中斷向量表就對(duì)不上。解決打開工程屬性 → C/C Build → Settings → Tool Settings → Assembler → Includes確認(rèn)啟動(dòng)文件路徑指向正確的.s文件。同時(shí)檢查鏈接腳本里的LENGTH是否跟芯片實(shí)際 Flash 容量一致。5.2 串口輸出亂碼現(xiàn)象串口助手收到數(shù)據(jù)但全是亂碼換波特率也不行。原因除了前面說的波特率計(jì)算誤差還有一個(gè)常見原因是系統(tǒng)時(shí)鐘配置錯(cuò)誤。比如板子上焊的是 8MHz 晶振但system_gd32f30x.c里__SYSTEM_CLOCK配的是 108MHz而實(shí)際 PLL 倍頻是按 8MHz 算的結(jié)果系統(tǒng)時(shí)鐘跑到了 72MHzUSART 分頻系數(shù)全錯(cuò)。解決用示波器測(cè)一下 MCO 引腳輸出的時(shí)鐘頻率或者直接在main里翻轉(zhuǎn)一個(gè) GPIO用示波器看周期。確認(rèn)系統(tǒng)時(shí)鐘正確后再重新算 USART 波特率。5.3 中斷進(jìn)不去現(xiàn)象外設(shè)中斷使能了NVIC 也配了但中斷服務(wù)函數(shù)就是不執(zhí)行。原因EmbeddedBuilder 生成的gd32f30x_it.c里中斷服務(wù)函數(shù)的名稱必須跟啟動(dòng)文件里的向量表名稱完全一致。比如 USART0 的中斷函數(shù)名是USART0_IRQHandler如果你寫成了USART0_Handler鏈接器不會(huì)報(bào)錯(cuò)但向量表里填的是默認(rèn)的無限循環(huán)。解決打開啟動(dòng)文件.s搜索IRQHandler確認(rèn)你用的中斷函數(shù)名跟向量表里的一致。常見的中斷函數(shù)名在固件庫的gd32f30x_it.h里有聲明直接對(duì)照著寫。5.4 燒錄后需要手動(dòng)復(fù)位現(xiàn)象每次燒錄完程序必須按一下復(fù)位鍵才運(yùn)行否則沒反應(yīng)。原因EmbeddedBuilder 的燒錄配置里默認(rèn)可能沒有勾選「Reset after programming」。另外如果你用的是 SWD 接口燒錄器的復(fù)位引腳沒接也會(huì)導(dǎo)致燒錄后芯片不復(fù)位。解決在 Debug Configuration → Startup 里勾選「Reset and Delay」和「Halt」或者在燒錄器設(shè)置里把「Reset after programming」打開。如果硬件上復(fù)位引腳沒接可以在代碼里加一句NVIC_SystemReset()在main開頭但這不是長久之計(jì)。5.5 浮點(diǎn)運(yùn)算結(jié)果不對(duì)現(xiàn)象同樣的浮點(diǎn)計(jì)算代碼Keil 下結(jié)果正確EmbeddedBuilder 下結(jié)果偏差很大。原因GCC 和 ARMCC 對(duì)浮點(diǎn)數(shù)的處理方式不同。GD32F303 沒有硬件 FPU浮點(diǎn)運(yùn)算靠軟件模擬。GCC 默認(rèn)可能用了-mfloat-abihard或-mfloat-abisoftfp而芯片不支持硬件浮點(diǎn)導(dǎo)致結(jié)果異常。解決在工程屬性的 C/C Build → Settings → Tool Settings → Target Processor 里把 Float ABI 改成soft或者直接在編譯選項(xiàng)里加-mfloat-abisoft。同時(shí)確認(rèn)鏈接選項(xiàng)里沒有引入硬件浮點(diǎn)的庫。6. 進(jìn)階技巧用 EmbeddedBuilder 做多工程管理和版本回退6.1 多工程工作空間的隔離EmbeddedBuilder 基于 Eclipse天然支持多工程工作空間。我一般會(huì)按芯片系列建不同的 workspaceworkspace_f30x、workspace_f10x、workspace_f4xx。這樣切換項(xiàng)目時(shí)不用反復(fù)改編譯器路徑和固件庫引用。具體做法是啟動(dòng)時(shí)加-data參數(shù)指定工作空間路徑# 啟動(dòng)時(shí)指定工作空間 ./eclipse/embeddedbuilder -data /path/to/workspace_f30x如果不想每次敲命令可以在桌面快捷方式的目標(biāo)里加上這個(gè)參數(shù)。工作空間隔離的好處是每個(gè)空間里的工程配置、編譯器設(shè)置、調(diào)試配置互不干擾。壞處是占硬盤空間一個(gè)工作空間動(dòng)輒幾百 MB。6.2 固件庫版本的手動(dòng)切換有時(shí)候項(xiàng)目需要用到特定版本的固件庫而 EmbeddedBuilder 自帶的版本不匹配。這時(shí)候可以手動(dòng)把固件庫源碼拷到工程目錄下然后在工程屬性里把 include 路徑指向新拷進(jìn)來的目錄。具體步驟步驟操作注意點(diǎn)1下載目標(biāo)版本的 GD32F 固件庫確認(rèn)跟芯片系列匹配2解壓到工程目錄下的firmware/文件夾不要覆蓋 IDE 安裝目錄3工程屬性 → C/C General → Paths and Symbols刪掉舊的固件庫路徑4添加新路徑調(diào)整包含順序新路徑放在最前面5重新編譯檢查是否有重復(fù)定義舊路徑?jīng)]刪干凈會(huì)報(bào)錯(cuò)這個(gè)操作的風(fēng)險(xiǎn)在于不同版本的固件庫 API 可能有變化比如某個(gè)宏定義改名了、某個(gè)函數(shù)參數(shù)變了。切換后要全量編譯一次看有沒有undefined reference或implicit declaration警告。6.3 用 Git 管理 EmbeddedBuilder 工程EmbeddedBuilder 的工程目錄里有一堆 Eclipse 自動(dòng)生成的文件比如.project、.cproject、.settings/文件夾。這些文件如果直接提交到 Git換一臺(tái)機(jī)器拉下來可能因?yàn)槁窂讲煌鴪?bào)錯(cuò)。我一般會(huì)寫一個(gè).gitignore把跟機(jī)器相關(guān)的配置排除掉# Eclipse 自動(dòng)生成跟機(jī)器相關(guān) .settings/ .cproject .project .metadata/ # 編譯輸出 Debug/ Release/ *.o *.d *.elf *.bin *.hex # 保留源碼和鏈接腳本 !*.c !*.h !*.ld !*.s這個(gè).gitignore的作用是只提交源碼、頭文件、鏈接腳本和啟動(dòng)文件不提交 IDE 的元數(shù)據(jù)和編譯產(chǎn)物。這樣換機(jī)器拉下來后重新建一個(gè)空工程把源碼拷進(jìn)去再配一次編譯選項(xiàng)就行。雖然多了一步但避免了路徑?jīng)_突的玄學(xué)問題。6.4 一個(gè)驗(yàn)證編譯鏈?zhǔn)欠裾5募记擅看涡陆üこ袒蛘咔袚Q固件庫版本后我習(xí)慣先跑一個(gè)「最小驗(yàn)證」只點(diǎn)一個(gè) LED用定時(shí)器中斷翻轉(zhuǎn)同時(shí)串口輸出一句固定字符串。這個(gè)最小系統(tǒng)能跑通說明啟動(dòng)文件、時(shí)鐘配置、中斷向量表、鏈接腳本、串口重定向都沒問題。后面再加外設(shè)就是增量調(diào)試出了問題也好定位。/* 最小驗(yàn)證代碼片段 */ int main(void) { /* 系統(tǒng)時(shí)鐘初始化確認(rèn) __SYSTEM_CLOCK 跟晶振匹配 */ systick_config(); /* GPIO 初始化LED 推挽輸出 */ gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_0); /* USART0 初始化115200-8-N-1 */ usart_deinit(USART0); usart_baudrate_set(USART0, 115200); usart_word_length_set(USART0, USART_WL_8BIT); usart_stop_bit_set(USART0, USART_STB_1BIT); usart_parity_config(USART0, USART_PM_NONE); usart_transmit_config(USART0, USART_TRANSMIT_ENABLE); usart_enable(USART0); while (1) { gpio_bit_set(GPIOB, GPIO_PIN_0); delay_1ms(500); gpio_bit_reset(GPIOB, GPIO_PIN_0); delay_1ms(500); printf(minimal system running\r\n); } }這段代碼跑通后串口助手應(yīng)該每 500ms 收到一行minimal system running同時(shí) LED 閃爍。如果串口有輸出但 LED 不閃檢查 GPIO 時(shí)鐘是否使能如果 LED 閃但串口無輸出檢查 USART 引腳重映射和波特率。從那以后我每次拿到新的 GD32 工程或者切換工具鏈版本都強(qiáng)制先跑一遍這個(gè)最小驗(yàn)證確認(rèn)底層沒問題再往上加業(yè)務(wù)代碼。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取