范例程序?qū)崙?zhàn)指南:從點(diǎn)燈到多外設(shè)工程搭建)
簡介這是一份面向嵌入式初學(xué)者與單片機(jī)開發(fā)者的STC單片機(jī)C語言范例程序合集圍繞ADC采樣、串口通信、EEPROM讀寫、ISP在系統(tǒng)編程、時鐘中斷、端口測試及優(yōu)化編程思想等核心功能展開適合用于課程實(shí)驗(yàn)、自學(xué)練手與項(xiàng)目參考。資源包共612個文件約14.88MB以plg、uv2、hex、opt、lnp等工程與燒錄文件為主配合h頭文件、c源碼、asm匯編及pdf說明文檔覆蓋ADC、PCA模擬全雙工串口、紅外收發(fā)、PWM、LCD驅(qū)動、按鍵掃描、看門狗等典型模塊并附實(shí)驗(yàn)箱布局圖與使用說明。目前已有5855人學(xué)習(xí)下載讀者可從中獲得可直接編譯運(yùn)行的完整工程、寄存器配置思路與硬件調(diào)試參考便于快速理解STC單片機(jī)各外設(shè)的編程方法提升實(shí)際開發(fā)效率。1. 從一塊“點(diǎn)不亮”的板子說起STC 單片機(jī)范例程序到底能幫你省下多少試錯時間很多人第一次接觸 STC 單片機(jī)卡住的地方往往不是寫不出代碼而是代碼寫完了燒不進(jìn)去、燈不亮、串口沒反應(yīng)。你手里可能有一塊最小系統(tǒng)板、一根 USB 轉(zhuǎn)串口線還有一份不知道從哪下載的例程打開一看全是寄存器操作注釋寥寥。STC 單片機(jī)范例程序這份資源解決的就是這個最實(shí)際的問題它把 GPIO 點(diǎn)燈、定時器、串口收發(fā)、ADC 采樣、PWM 輸出、EEPROM 讀寫這些常用外設(shè)的完整工程打包在一起每個工程都是可以直接編譯、直接燒錄的獨(dú)立項(xiàng)目。適合誰適合剛上手 STC 系列、不想從零搭工程模板的嵌入式新手也適合需要快速驗(yàn)證某個外設(shè)功能的熟手。你不需要先去啃幾百頁的數(shù)據(jù)手冊先把例程跑通再回頭對照寄存器理解會快得多。2. 工程結(jié)構(gòu)拆解拿到壓縮包后先看哪幾個文件2.1 目錄組織與工程模板的復(fù)用邏輯一份典型的 STC 單片機(jī)范例程序包解壓后通常不是一個大雜燴而是按外設(shè)功能分目錄。常見做法是每個功能一個獨(dú)立文件夾比如01_GPIO_LED、02_Timer0、03_UART1、04_ADC、05_PWM、06_EEPROM每個文件夾里放一個完整的 Keil 工程。這樣設(shè)計(jì)的好處是你不需要在同一個工程里靠宏定義切換功能直接打開對應(yīng)文件夾就能編譯燒錄互不干擾。我一般拿到這種包第一件事不是急著打開.uvproj而是先看根目錄有沒有Common或Library文件夾。如果有說明作者把延時函數(shù)、串口打印、類型定義這些公共代碼抽出來了各個例程通過相對路徑引用。這種結(jié)構(gòu)在二次開發(fā)時最省事你改一處公共代碼所有例程都能受益。如果沒有公共文件夾每個例程都是自包含的那就意味著代碼有重復(fù)改的時候要逐個同步。# 典型的目錄結(jié)構(gòu)示意 STC_Examples/ ├── 01_GPIO_LED/ │ ├── main.c │ ├── led.c │ ├── led.h │ └── project.uvproj ├── 02_Timer0/ │ ├── main.c │ ├── timer.c │ ├── timer.h │ └── project.uvproj ├── 03_UART1/ │ ├── main.c │ ├── uart.c │ ├── uart.h │ └── project.uvproj ├── Common/ │ ├── delay.c │ ├── delay.h │ ├── type.h │ └── uart_printf.c └── README.md上面這個結(jié)構(gòu)里Common文件夾是關(guān)鍵。delay.c提供毫秒和微秒級延時type.h做類型重定義uart_printf.c把printf重定向到串口。這些在每個例程里都會被引用。你打開01_GPIO_LED的工程在 Keil 的工程樹里應(yīng)該能看到Common組里面包含這些文件。如果看不到說明路徑?jīng)]配好需要手動添加。2.2 Keil 工程配置里最容易忽略的三個選項(xiàng)打開.uvproj之后先別急著點(diǎn)編譯。STC 單片機(jī)的工程配置有幾個地方和 STM32 不一樣配錯了就是“編譯通過但跑不起來”。第一個是芯片型號選擇。STC 的 Keil 支持包安裝后在 Device 列表里能搜到具體型號比如 STC89C52RC、STC12C5A60S2、STC15W4K56S4 等。選錯型號最直接的后果是寄存器地址不對程序跑飛。第二個是時鐘頻率設(shè)置。在Target選項(xiàng)卡的Xtal里填的數(shù)值會影響 Keil 仿真時的時序計(jì)算但真正決定串口波特率的是你代碼里寫的定時器初值。很多人在這里填 11.0592MHz代碼里卻按 12MHz 算結(jié)果串口出來全是亂碼。常見做法是晶振用 11.0592MHz串口波特率才準(zhǔn)如果板子上焊的是 12MHz那串口波特率就得用定時器 2 或者手動算誤差。第三個是輸出 HEX 文件的勾選。在Output選項(xiàng)卡里Create HEX File必須勾上否則編譯完沒有可燒錄文件。STC-ISP 下載軟件只認(rèn).hex或.bin不認(rèn).axf。// Common/delay.h 里常見的宏定義 #ifndef __DELAY_H #define __DELAY_H #include type.h // 假設(shè)系統(tǒng)時鐘為 11.0592MHz // 這兩個宏在 STC 例程里出現(xiàn)頻率極高 #define MAIN_Fosc 11059200L // 主頻單位 Hz #define DELAY_MS(ms) delay_ms(ms) #define DELAY_US(us) delay_us(us) void delay_ms(u16 ms); void delay_us(u16 us); #endif這段代碼里MAIN_Fosc這個宏很關(guān)鍵。很多例程的延時函數(shù)、串口波特率計(jì)算、定時器初值都依賴它。如果你板子上的晶振不是 11.0592MHz第一件事就是改這個宏然后重新編譯。改完還不算完串口波特率的定時器初值也要跟著重算否則通信還是有問題。2.3 從點(diǎn)燈例程看 STC 的 GPIO 模式配置STC 單片機(jī)和傳統(tǒng) 8051 最大的區(qū)別之一就是 GPIO 多了模式寄存器。以 STC15 系列為例每個端口都有PxM0和PxM1兩個寄存器組合起來決定引腳是準(zhǔn)雙向、推挽、高阻還是開漏。很多新手從 STM32 轉(zhuǎn)過來習(xí)慣性地直接給端口賦值結(jié)果 LED 亮度不對或者根本驅(qū)動不了。// 01_GPIO_LED/led.c 中的初始化片段 #include led.h void LED_Init(void) { // 配置 P1.0 為推挽輸出驅(qū)動 LED P1M1 ~0x01; // P1.0 模式位 M1 清零 P1M0 | 0x01; // P1.0 模式位 M0 置一 // 組合結(jié)果M10, M01 - 推挽輸出 P1_0 1; // 初始熄滅取決于硬件接法 } void LED_Toggle(void) { P1_0 !P1_0; // 翻轉(zhuǎn)電平 }這段代碼里P1M1和P1M0的位操作是 STC 特有的。推挽輸出模式下引腳能輸出較大電流直接驅(qū)動 LED 沒問題。如果是準(zhǔn)雙向模式輸出高電平時驅(qū)動能力很弱LED 可能微亮或者不亮。這就是為什么有些人說“代碼明明一樣我的燈就是不亮”——大概率是 GPIO 模式?jīng)]配對。3. 編譯與燒錄從 Keil 到 STC-ISP 的完整鏈路3.1 編譯前必須確認(rèn)的芯片型號與頭文件在 Keil 里打開工程后左側(cè)Project窗口里會列出所有源文件。先看Target名稱通常作者會寫成芯片型號。右鍵Options for Target在Device標(biāo)簽頁確認(rèn)選中的芯片和實(shí)際板子一致。如果列表里找不到你的型號說明 STC 的 Keil 支持包沒裝需要去 STC 官網(wǎng)下載安裝。頭文件方面STC 例程通常包含stc15.h、stc8.h或reg51.h。reg51.h是標(biāo)準(zhǔn) 8051 頭文件只包含基本寄存器沒有 STC 擴(kuò)展的PxM0、PxM1、AUXR等。如果你在代碼里用了這些擴(kuò)展寄存器但頭文件是reg51.h編譯會報“未定義標(biāo)識符”。常見做法是STC12 系列用stc12.hSTC15 系列用stc15.hSTC8 系列用stc8.h。這些頭文件在 STC-ISP 軟件里自帶也可以從官網(wǎng)下載。// main.c 中常見的頭文件包含順序 #include stc15.h // 芯片寄存器定義 #include type.h // 類型重定義 #include delay.h // 延時函數(shù) #include uart.h // 串口驅(qū)動 #include led.h // LED 驅(qū)動 void main(void) { UART_Init(9600); // 串口初始化波特率 9600 LED_Init(); // LED 初始化 while (1) { LED_Toggle(); delay_ms(500); // 延時 500ms printf(LED toggled\r\n); // 串口輸出調(diào)試信息 } }這段main函數(shù)的結(jié)構(gòu)很典型先初始化外設(shè)然后進(jìn)死循環(huán)。UART_Init(9600)里的參數(shù)是波特率改這個值的時候要同步改定時器初值。printf能用的前提是uart_printf.c里重定向了putchar或者用了TI中斷發(fā)送。如果串口助手收不到數(shù)據(jù)先檢查波特率、數(shù)據(jù)位、停止位是否和代碼一致再檢查硬件接線STC 的TXD接 USB 轉(zhuǎn)串口的RXDRXD接TXD共地。3.2 STC-ISP 下載軟件的參數(shù)設(shè)置與冷啟動編譯出.hex文件后打開 STC-ISP 軟件。第一步選芯片型號必須和 Keil 里選的一致。第二步選串口號插上 USB 轉(zhuǎn)串口線后軟件會自動識別如果沒識別到檢查驅(qū)動是否安裝。第三步打開.hex文件。第四步設(shè)置硬件選項(xiàng)比如是否使用內(nèi)部晶振、復(fù)位腳是否用作 IO。點(diǎn)擊“下載/編程”按鈕后軟件會提示“正在檢測目標(biāo)單片機(jī)”。這時候需要給單片機(jī)上電冷啟動——也就是先斷電點(diǎn)下載再上電。很多新手卡在這里因?yàn)榘遄右恢蓖ㄖ娷浖z測不到。冷啟動是 STC 單片機(jī) ISP 下載的固定流程因?yàn)樾酒想姇r會先運(yùn)行 Bootloader檢測串口是否有下載命令。提示如果一直檢測不到先檢查串口線是否插緊再檢查板子上的晶振是否起振。有些最小系統(tǒng)板需要手動按復(fù)位鍵有些則完全斷電再上電。下載成功后軟件會顯示“操作成功”。這時候板子上的 LED 應(yīng)該開始閃爍串口助手也能看到打印信息。如果 LED 不閃先量一下 LED 引腳電壓是否在翻轉(zhuǎn)再檢查 LED 極性是否接反。3.3 串口調(diào)試用 printf 定位問題的最快方式在嵌入式開發(fā)里串口打印是最樸素的調(diào)試手段但也是最有效的。STC 例程里通常會把printf重定向到串口這樣你就能用printf(變量值%d\r\n, val)這種方式輸出中間變量。重定向的代碼一般長這樣// Common/uart_printf.c 中的重定向?qū)崿F(xiàn) #include stc15.h #include uart.h // 重定向 putchar使 printf 輸出到串口 char putchar(char c) { while (!TI); // 等待上一個字節(jié)發(fā)送完成 TI 0; // 清除發(fā)送完成標(biāo)志 SBUF c; // 寫入發(fā)送緩沖區(qū) return c; }這段代碼里TI是串口發(fā)送完成標(biāo)志位SBUF是發(fā)送/接收緩沖區(qū)。while(!TI)會阻塞等待直到上一個字節(jié)發(fā)完。這種寫法簡單但如果在中斷里調(diào)用printf可能會死鎖。常見做法是主循環(huán)里用printf沒問題中斷里盡量只置標(biāo)志位不要直接打印。串口助手的設(shè)置要和代碼一致波特率 9600、數(shù)據(jù)位 8、停止位 1、無校驗(yàn)。如果收到亂碼先檢查晶振頻率和波特率是否匹配。11.0592MHz 晶振配 9600 波特率誤差為 012MHz 晶振配 9600 誤差約 0.16%短距離通信沒問題長距離可能丟包。4. 核心外設(shè)例程精講定時器、ADC 與 EEPROM4.1 定時器中斷從寄存器配置到中斷服務(wù)函數(shù)定時器是單片機(jī)最常用的外設(shè)之一STC 的定時器和標(biāo)準(zhǔn) 8051 兼容但多了AUXR寄存器來控制分頻。以定時器 0 為例工作模式 1 是 16 位定時器不自動重裝模式 2 是 8 位自動重裝。做精確延時或者波特率發(fā)生器通常用模式 2。// 02_Timer0/timer.c 中的初始化代碼 #include stc15.h #include timer.h void Timer0_Init(void) { AUXR ~0x80; // 定時器 0 時鐘為 12T 模式即 12 分頻 TMOD ~0x0F; // 清除定時器 0 模式位 TMOD | 0x01; // 定時器 0 工作模式 116 位定時器 // 假設(shè)晶振 11.0592MHz定時 50ms // 12T 模式下定時器計(jì)數(shù)頻率 11.0592MHz / 12 921600Hz // 50ms 需要計(jì)數(shù) 921600 * 0.05 46080 次 // 初值 65536 - 46080 19456 0x4C00 TH0 0x4C; TL0 0x00; ET0 1; // 使能定時器 0 中斷 EA 1; // 使能總中斷 TR0 1; // 啟動定時器 0 } // 中斷服務(wù)函數(shù)中斷號 1 對應(yīng)定時器 0 void Timer0_ISR(void) interrupt 1 { TH0 0x4C; // 重新加載初值 TL0 0x00; // 用戶代碼比如翻轉(zhuǎn) LED P1_0 !P1_0; }這段代碼里AUXR寄存器的T0x12位決定定時器時鐘是 12T 還是 1T。12T 模式下定時器計(jì)數(shù)頻率是晶振頻率的 1/12和傳統(tǒng) 8051 一致。1T 模式下計(jì)數(shù)頻率等于晶振頻率定時更精確但初值計(jì)算方式不同。TMOD的低 4 位控制定時器 00x01表示模式 1。中斷服務(wù)函數(shù)后面的interrupt 1是 Keil C51 的語法數(shù)字 1 對應(yīng)定時器 0 中斷向量。初值計(jì)算是新手最容易出錯的地方。TH0和TL0組成 16 位計(jì)數(shù)器從初值開始往上數(shù)數(shù)到 65536 溢出觸發(fā)中斷。所以初值 65536 - 需要計(jì)數(shù)的次數(shù)。需要計(jì)數(shù)的次數(shù) 定時時間 × 計(jì)數(shù)頻率。把這三個量搞清楚定時器就不會配錯。4.2 ADC 采樣通道選擇與參考電壓STC 的 ADC 模塊在 STC12、STC15、STC8 系列上都有通常是 10 位精度8 通道。用 ADC 的時候除了配置寄存器還要注意參考電壓。有些型號的參考電壓是內(nèi)部固定的有些可以外接。如果測出來的值一直不準(zhǔn)先檢查參考電壓是否穩(wěn)定。// 04_ADC/adc.c 中的采樣函數(shù) #include stc15.h #include adc.h u16 ADC_Read(u8 channel) { // 選擇通道P1ASF 寄存器對應(yīng) P1 口 P1ASF 1 channel; ADC_CONTR 0x80; // 使能 ADC 模塊 ADC_CONTR | channel; // 選擇通道 ADC_CONTR | 0x08; // 啟動轉(zhuǎn)換 while (!(ADC_CONTR 0x10)); // 等待轉(zhuǎn)換完成 ADC_CONTR ~0x10; // 清除完成標(biāo)志 // 返回 10 位結(jié)果高 8 位在 ADC_RES低 2 位在 ADC_RESL return ((u16)ADC_RES 2) | (ADC_RESL 0x03); }這段代碼里P1ASF寄存器把 P1 口的某個引腳設(shè)為模擬輸入。ADC_CONTR的0x80位使能 ADC0x08位啟動轉(zhuǎn)換0x10位是轉(zhuǎn)換完成標(biāo)志。結(jié)果拼接的時候ADC_RES是高 8 位ADC_RESL的低 2 位是低 2 位拼起來就是 10 位結(jié)果。如果只需要 8 位精度直接讀ADC_RES就行。實(shí)際使用中ADC 的輸入電壓范圍是 0 到 VCC。如果 VCC 是 5V10 位 ADC 的分辨率就是 5V / 1024 ≈ 4.88mV。測出來的值乘以 4.88mV 就是實(shí)際電壓。如果 VCC 不穩(wěn)定測出來的值會跳。常見做法是在 VCC 和 GND 之間并一個 0.1uF 電容濾掉高頻噪聲。4.3 EEPROM 讀寫掉電保存參數(shù)的實(shí)現(xiàn)STC 的 EEPROM 其實(shí)是 Data Flash用來保存掉電后需要保留的參數(shù)比如校準(zhǔn)值、用戶設(shè)置。操作 EEPROM 需要先擦除扇區(qū)再寫入。擦除和寫入都需要時間期間 CPU 會暫停。// 06_EEPROM/eeprom.c 中的讀寫函數(shù) #include stc15.h #include eeprom.h void EEPROM_Erase(u16 addr) { IAP_CONTR 0x80; // 使能 IAP IAP_CMD 0x03; // 扇區(qū)擦除命令 IAP_ADDRH addr 8; IAP_ADDRL addr 0xFF; IAP_TRIG 0x5A; // 觸發(fā)命令 IAP_TRIG 0xA5; IAP_CONTR 0x00; // 關(guān)閉 IAP } void EEPROM_Write(u16 addr, u8 dat) { IAP_CONTR 0x80; IAP_CMD 0x02; // 字節(jié)寫入命令 IAP_ADDRH addr 8; IAP_ADDRL addr 0xFF; IAP_DATA dat; IAP_TRIG 0x5A; IAP_TRIG 0xA5; IAP_CONTR 0x00; } u8 EEPROM_Read(u16 addr) { u8 dat; IAP_CONTR 0x80; IAP_CMD 0x01; // 字節(jié)讀取命令 IAP_ADDRH addr 8; IAP_ADDRL addr 0xFF; IAP_TRIG 0x5A; IAP_TRIG 0xA5; dat IAP_DATA; IAP_CONTR 0x00; return dat; }這段代碼里IAP_CONTR的0x80位使能 IAP 操作IAP_CMD選擇命令0x01讀、0x02寫、0x03擦除。IAP_TRIG需要依次寫入0x5A和0xA5才能觸發(fā)操作這是 STC 的固定流程順序不能反。擦除是按扇區(qū)進(jìn)行的一個扇區(qū)通常 512 字節(jié)擦除后整個扇區(qū)變成0xFF。寫入只能把1變成0所以寫之前必須先擦除。注意EEPROM 的擦寫次數(shù)有限通常 10 萬次左右。不要在主循環(huán)里頻繁寫 EEPROM否則壽命很快耗盡。常見做法是只在參數(shù)變化時寫或者加一個延時幾秒內(nèi)不重復(fù)寫。5. 避坑與排查STC 例程跑不起來時先查這五條5.1 編譯通過但下載失敗現(xiàn)象Keil 編譯無報錯生成.hex文件但 STC-ISP 一直提示“正在檢測目標(biāo)單片機(jī)”。原因通常是冷啟動流程不對或者串口被占用。解決先關(guān)閉其他占用串口的軟件比如串口助手然后給單片機(jī)斷電點(diǎn)擊下載按鈕再上電。如果還是不行換一根 USB 轉(zhuǎn)串口線有些線質(zhì)量差下載不穩(wěn)定。5.2 LED 不亮或亮度異?,F(xiàn)象程序下載成功但 LED 不亮或者微亮。原因大概率是 GPIO 模式?jīng)]配對。STC 的準(zhǔn)雙向模式輸出高電平驅(qū)動能力弱推挽模式才能正常驅(qū)動 LED。解決檢查PxM0和PxM1寄存器配置確保 LED 引腳設(shè)為推挽輸出。另外檢查 LED 極性有些板子是低電平點(diǎn)亮代碼里初始電平要對應(yīng)。5.3 串口亂碼或收不到數(shù)據(jù)現(xiàn)象串口助手收到亂碼或者完全沒數(shù)據(jù)。原因通常是波特率不匹配、晶振頻率和代碼不一致、接線錯誤。解決先確認(rèn)代碼里的MAIN_Fosc和實(shí)際晶振一致再確認(rèn)串口助手波特率和代碼一致最后檢查TXD和RXD是否交叉連接共地是否接好。如果用的是內(nèi)部晶振波特率誤差可能較大建議用外部晶振。5.4 定時器中斷不觸發(fā)現(xiàn)象定時器初始化了但中斷服務(wù)函數(shù)不執(zhí)行。原因可能是總中斷沒開、定時器沒啟動、中斷號寫錯。解決檢查EA 1和ET0 1是否都寫了檢查TR0 1是否啟動檢查中斷服務(wù)函數(shù)的interrupt編號是否和定時器對應(yīng)。定時器 0 是 1定時器 1 是 3定時器 2 是 5。5.5 ADC 采樣值跳動大現(xiàn)象ADC 讀出來的值不穩(wěn)定跳動幾十個數(shù)值。原因可能是參考電壓不穩(wěn)、模擬輸入引腳懸空、電源噪聲大。解決在 VCC 和 GND 之間加濾波電容模擬輸入引腳接一個下拉電阻避免懸空采樣時多讀幾次取平均值。如果對精度要求高外接一個穩(wěn)定的參考電壓源。6. 二次開發(fā)改造把例程變成自己的項(xiàng)目模板6.1 從單個例程到多外設(shè)協(xié)同的工程重組例程跑通之后下一步就是做自己的項(xiàng)目。你不可能把 LED 例程、串口例程、定時器例程各燒一遍而是要把它們合并到一個工程里。常見做法是新建一個工程文件夾把Common目錄復(fù)制過來再把需要的外設(shè)驅(qū)動文件按功能分組添加。比如drivers/led.c、drivers/uart.c、drivers/timer.c每個驅(qū)動配一個頭文件main.c只負(fù)責(zé)初始化和主循環(huán)邏輯。// 重組后的 main.c 結(jié)構(gòu) #include stc15.h #include type.h #include delay.h #include led.h #include uart.h #include timer.h #include adc.h void System_Init(void) { UART_Init(9600); // 串口初始化 LED_Init(); // LED 初始化 Timer0_Init(); // 定時器初始化 ADC_Init(); // ADC 初始化 } void main(void) { System_Init(); while (1) { u16 adc_val ADC_Read(0); // 讀通道 0 printf(ADC: %d\r\n, adc_val); delay_ms(1000); } }這種結(jié)構(gòu)的好處是每個驅(qū)動模塊獨(dú)立改一個不影響其他。System_Init集中初始化主循環(huán)只處理業(yè)務(wù)邏輯。如果你要做低功耗可以在主循環(huán)里加PCON | 0x01進(jìn)空閑模式定時器中斷喚醒。6.2 用宏定義做功能裁剪與參數(shù)配置例程里的參數(shù)比如波特率、定時時間、ADC 通道最好用宏定義抽出來放在一個config.h里。這樣換板子或者改需求的時候只改一個文件不用滿工程搜數(shù)字。// config.h 中的可配置參數(shù) #ifndef __CONFIG_H #define __CONFIG_H #define MAIN_Fosc 11059200L // 主頻 #define UART_BAUD 9600 // 串口波特率 #define TIMER0_MS 50 // 定時器 0 周期單位 ms #define ADC_CHANNEL 0 // ADC 通道 #define LED_PIN P1_0 // LED 引腳 #endif改MAIN_Fosc的時候延時函數(shù)和串口波特率都會跟著變前提是驅(qū)動代碼里用的是這個宏而不是硬編碼的數(shù)字。我見過很多例程延時函數(shù)里直接寫for(i0;i1000;i)這種延時不準(zhǔn)換晶振就廢了。合格的做法是用定時器做延時或者用_nop_()配合循環(huán)但循環(huán)次數(shù)要根據(jù)主頻算。6.3 驗(yàn)證改造是否成功的三個檢查點(diǎn)改造完工程燒錄之前先做三個檢查。第一編譯無警告。Keil 的警告往往藏著問題比如未使用變量、類型不匹配別忽略。第二串口打印正常。在main開頭打印一行版本信息確認(rèn)程序跑起來了。第三外設(shè)逐個驗(yàn)證。先點(diǎn)燈再串口再定時器最后 ADC。每加一個外設(shè)燒一次確認(rèn)沒問題再加下一個。這樣出問題的時候范圍小好定位。從那以后我每次拿到新的例程包都強(qiáng)制走一遍“先點(diǎn)燈、再串口、后中斷”的流程確認(rèn)基礎(chǔ)鏈路通了再往上堆功能。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取