引腳全解析:從最小系統(tǒng)到調(diào)試實戰(zhàn))
簡介從AT89S51到AT89C2051內(nèi)容對ATMEL公司51系列兩款常用單片機(jī)的引腳功能做了細(xì)致梳理既講清標(biāo)準(zhǔn)40引腳AT89S51的電源、晶振、控制及P0~P3四組可編程I/O口分布也介紹了20引腳精簡版AT89C2051的引腳復(fù)用、內(nèi)置模擬比較器及低至2.7V的工作電壓特點適合單片機(jī)初學(xué)者對照學(xué)習(xí)也可作為硬件選型和開發(fā)設(shè)計的速查參考。資源為單個doc文檔大小137KB文檔將引腳按電源、晶振、控制、I/O分類講解并配有封裝圖示、引腳排列順序及復(fù)位電路說明方便讀者直接打印或離線查閱。目前已有2745人學(xué)習(xí)下載結(jié)合文中對復(fù)位、時鐘、ALE、EA等控制引腳的詳細(xì)注釋能夠幫助讀者快速建立51單片機(jī)硬件引腳的整體認(rèn)知減少開發(fā)中反復(fù)查手冊的摸索時間是一份實用且易讀的入門級參考資料。1. 一枚 40 腳的芯片真正決定系統(tǒng)能否跑起來的往往只有幾個腳很多剛接觸 51 單片機(jī)的人第一次拿到 DIP-40 封裝芯片時第一反應(yīng)是去背引腳圖P0 在哪、P3 在哪、哪個是晶振腳。但真到了自己焊板子翻車往往不是因為記不住引腳號而是因為某個引腳的電平狀態(tài)和你想象的不一樣。最典型的三個現(xiàn)象P0 口寫高電平LED 卻不亮下載器連不上芯片按了復(fù)位鍵程序還是原地不動。這三個問題最后查下來全是指針腳細(xì)節(jié)——上拉、復(fù)位時序、晶振回路。這篇內(nèi)容就是把 51 單片機(jī) 40 個引腳從“能用”講到“用好”。適合兩類人一類是用面包板搭最小系統(tǒng)的新手需要一份能照著接線的完整明細(xì)另一類是已經(jīng)寫過幾段點燈程序、但被引腳復(fù)用和外部總線搞得頭疼的開發(fā)者。我會按電源、晶振、復(fù)位、I/O 端口、燒錄連接、調(diào)試排查這條線展開。搞清楚這些絕大多數(shù)引腳相關(guān)的玄學(xué)其實都是可以量化的。2. 電源、晶振與復(fù)位三個引腳把最小系統(tǒng)“激活”2.1 電源與去耦VCC 與 GND 不是插上就完事DIP-40 封裝的 51 單片機(jī)電源引腳固定在兩個對角上40 腳是 VCC20 腳是 GND。這個布局在 PCB 時代很合理電源從一側(cè)進(jìn)、地再從另一側(cè)出電流路徑能覆蓋整顆芯片。但在面包板上這個對角布局很容易讓人偷懶隨便飛兩根線跳過整個芯片區(qū)域結(jié)果就是芯片供電回路太長紋波和噪聲都進(jìn)到復(fù)位和晶振電路里。我一般會在 VCC 和 GND 之間放兩顆電容一顆 100nF 的瓷片電容放在芯片電源引腳附近用來濾掉高頻噪聲另一顆 10uF 電解電容放在稍遠(yuǎn)位置穩(wěn)定整個供電。如果是 5V 供電的老款 51這個組合基本夠用。如果你用的是 3.3V 版本要注意 I/O 輸出高電平的幅度也會跟著變成 3.3V后面接 5V 器件時要考慮電平轉(zhuǎn)換。這里有個容易忽略的點51 的 VCC 和 GND 是“裸腳”不像有些芯片內(nèi)部已經(jīng)帶了電源穩(wěn)壓和反接保護(hù)。電源反接一次芯片大概率直接報廢。所以第一次上電前用萬用表蜂鳴檔量一下 20 腳和 40 腳之間的阻值確認(rèn)不是短路再插電。這個習(xí)慣能救下不少芯片。2.2 晶振回路XTAL1/XTAL2 的電容取值與走線晶振相關(guān)引腳有兩個19 腳 XTAL1 是振蕩器輸入18 腳 XTAL2 是振蕩器輸出。51 單片機(jī)內(nèi)部有一個反相放大器XTAL1 和 XTAL2 分別接放大器的輸入和輸出外部晶振通過這兩個引腳和單片機(jī)內(nèi)部電路構(gòu)成一個振蕩回路。最常見的接法是晶振接在 XTAL1 和 XTAL2 之間兩個引腳各接一個電容到 GND電容取值通常在 22pF 到 30pF 之間。以 12MHz 晶振為例我一般用 22pF如果是 6MHz 或更低的頻率負(fù)載電容可以選大一些比如 30pF。這個電容的作用是匹配晶振的負(fù)載電容同時限制振蕩回路里的諧波。取值偏太大會導(dǎo)致起振變慢或停振偏太小則波形質(zhì)量差極端情況下也會停振。晶振的走線是另一個容易被忽略的細(xì)節(jié)。在面包板上晶振要盡量靠近 18 腳和 19 腳兩個電容的回流路徑要短不要繞過芯片另一側(cè)再回到 GND。在 PCB 上晶振下方盡量不要走其他信號線尤其是時鐘線和復(fù)位線否則高頻振蕩信號會耦合到那些線上。判斷晶振是否起振最直接的辦法是用示波器看 XTAL2 的波形。沒有示波器時可以用萬用表直流檔量 XTAL2 的電壓正常起振時這個引腳的直流電壓大約在 VCC 的一半左右。如果量到 0V 或 VCC說明振蕩器沒工作。用示波器探頭量的時候要注意用 x10 檔x1 檔探頭電容太大可能直接把晶振壓停。2.3 RST 復(fù)位引腳上電時序與手動復(fù)位按鍵RST 是 9 腳高電平復(fù)位。所謂復(fù)位就是讓單片機(jī)內(nèi)部程序計數(shù)器、特殊功能寄存器回到初始狀態(tài)然后從程序入口重新執(zhí)行。51 的復(fù)位要求是RST 引腳保持至少兩個機(jī)器周期的高電平。以 12MHz 晶振為例一個機(jī)器周期是 1us兩個周期也就是 2us看起來很短但實際電路要考慮的是上電瞬間的時序。典型復(fù)位電路是一顆 10uF 電容和一顆 10k 電阻組成 RC 回路。電容接在 RST 和 VCC 之間電阻接在 RST 和 GND 之間。上電瞬間電容兩端電壓不能突變RST 直接被拉到接近 VCC 的高電平隨著電容通過 10k 電阻放電RST 電壓逐漸下降最終回落到 0V。這個過程的持續(xù)時間大約是 RC 乘積也就是 10k 和 10uF 對應(yīng)約 100ms 的時間常數(shù)。100ms 對于 2us 的復(fù)位要求來說非常充足。手動復(fù)位按鍵一般并聯(lián)在這顆 10uF 電容兩端。按鍵按下時電容被短路RST 直接接到 VCC進(jìn)入復(fù)位狀態(tài)松開后電容重新充電RST 繼續(xù)保持一段時間高電平然后才釋放。這個設(shè)計能讓復(fù)位動作既可靠又不會在松開瞬間產(chǎn)生誤觸發(fā)。調(diào)試時最容易踩的坑是復(fù)位電容選太大。有些人為了“穩(wěn)妥”用 47uF結(jié)果導(dǎo)致 RST 高電平時間長達(dá)幾百毫秒。如果下載器是通過 RST 引腳控制進(jìn)入下載模式的過長的復(fù)位時間會讓握手失敗表現(xiàn)為“能燒錄但需要反復(fù)上電”。反過來說電容太比如 0.1uF上電瞬間的高電平維持時間不足復(fù)位還沒完成程序就開始跑了容易出現(xiàn)啟動異常。3. 四個 I/O 端口P0、P1、P2、P3 的角色分工與復(fù)用陷阱3.1 P0 口的開漏輸出為什么必須外接上拉電阻P0 口在 DIP-40 封裝里占用 32 到 39 腳共 8 個引腳。從 8051 時代開始P0 就是特殊的。它除了做通用 I/O還要承擔(dān)外部總線的分時復(fù)用功能——訪問外部程序存儲器或外部數(shù)據(jù)空間時P0 先輸出低字節(jié)地址再讀取數(shù)據(jù)。因為這個雙重角色P0 的每個引腳內(nèi)部沒有上拉管輸出級是開漏結(jié)構(gòu)。開漏結(jié)構(gòu)意味著引腳內(nèi)部只能主動拉低不能主動拉高。你向 P0 寫 1引腳并不會輸出高電平而是變成高阻狀態(tài)。如果外部沒有任何上拉引腳電平就懸空用萬用表量出來可能是一個隨機(jī)電壓甚至緩慢漂移。這就是很多人做點燈實驗時P0 口 LED 不亮的根本原因。解決辦法是在 P0 的 8 個引腳外部統(tǒng)一接一組上拉電阻到 VCC。上拉阻值常用 4.7k 到 10k。我一般用 10k功耗小信號邊沿稍緩但足夠驅(qū)動 TTL 電平如果 P0 要驅(qū)動 LED 或較長的 PCB 走線換成 4.7k 會更穩(wěn)。注意上拉電阻的供電要和單片機(jī) VCC 一致否則外部上拉到 5V、單片機(jī)工作在 3.3V會往 I/O 引腳灌入額外電流。P0 作為輸入引腳時同樣需要外部上拉。因為輸入狀態(tài)下如果引腳懸空讀回來的電平會不穩(wěn)定。一個常見做法是P0 整組接上拉排阻無論當(dāng)前是輸出還是輸入都保證引腳有一個確定的默認(rèn)電平。不過也有例外。近年不少 51 內(nèi)核的增強(qiáng)型單片機(jī)把 P0 改成了準(zhǔn)雙向結(jié)構(gòu)內(nèi)部自帶弱上拉不需要外部上拉也能輸出高電平。遇到這類芯片上拉電阻不接也能亮燈但接上會更穩(wěn)。所以拿到一款新芯片第一件事是查數(shù)據(jù)手冊里 I/O 結(jié)構(gòu)說明而不是想當(dāng)然認(rèn)為 P0 一定是開漏。3.2 P1/P2/P3 口的準(zhǔn)雙向結(jié)構(gòu)讀引腳前先寫 1P1 口占用 1 到 8 腳P2 口占用 21 到 28 腳P3 口占用 10 到 17 腳。這三個端口和 P0 最大的區(qū)別是內(nèi)部都帶弱上拉屬于準(zhǔn)雙向口。準(zhǔn)雙向這個詞聽起來拗口實際行為很好理解引腳輸出高電平時內(nèi)部上拉管提供一個小電流把引腳拉到 VCC這個電流很小通常只有幾十到幾百微安級別而輸出低電平時內(nèi)部下拉管能力很強(qiáng)可以灌入較大電流。所以準(zhǔn)雙向口“拉低”能力強(qiáng)“拉高”能力弱。這種結(jié)構(gòu)帶來一個直接影響當(dāng)你要把引腳當(dāng)作輸入來讀必須先向該引腳寫 1把內(nèi)部弱上拉打開然后才能正確讀到外部電平。如果引腳之前輸出過 0此時直接讀引腳外部信號哪怕被拉高也會被內(nèi)部下拉管死死壓住讀回來的永遠(yuǎn)是 0。這是新手最容易踩的坑。正確流程是P1 0xFF; // 先把整個 P1 口置 1打開內(nèi)部弱上拉 key P1; // 再讀引腳此時讀到的是外部真實電平我在實際項目里按鍵掃描和撥碼開關(guān)讀取都會遵循這個順序。還有一個更隱蔽的坑51 的許多位操作和邏輯指令屬于“讀-修改-寫”指令比如P1 0xFE它讀的是端口鎖存器而不是引腳電平。這本來是為了避免外部負(fù)載影響邏輯但如果你對某個引腳做過短路測試鎖存器狀態(tài)和引腳實際電平不一致程序里再執(zhí)行這類操作結(jié)果會和你想象的不同。排查這類問題最簡單的方法就是把引腳先寫 1再讀一遍確認(rèn)。P2 口在訪問外部存儲器時會輸出高 8 位地址這時它不能做普通 I/O。如果你的程序里沒有外部擴(kuò)展總線P2 就放心當(dāng)普通 I/O 用。但如果在調(diào)試中發(fā)現(xiàn) P2 口某幾個引腳電平不受程序控制先去查 EA 引腳的接法。3.3 P3 口第二功能串口與中斷占用時的引腳保護(hù)P3 口每個引腳都有第二功能這是 51 系列最具特色、也最容易讓人記混的部分。下表列出最常見的復(fù)用關(guān)系引腳號第一功能第二功能典型用途10P3.0RXD串口接收11P3.1TXD串口發(fā)送12P3.2INT0外部中斷 013P3.3INT1外部中斷 114P3.4T0定時器 0 外部計數(shù)輸入15P3.5T1定時器 1 外部計數(shù)輸入16P3.6WR外部數(shù)據(jù)存儲器寫選通17P3.7RD外部數(shù)據(jù)存儲器讀選通使用第二功能時引腳不再受普通 P3 口寄存器控制。比如串口發(fā)送P3.1 由串口模塊自動驅(qū)動你想用P3 0x02強(qiáng)制拉高是沒用的反而可能干擾串口輸出。 我在調(diào)試串口時碰到過一個現(xiàn)象程序里每隔一段時間會讓 P3 口所有引腳輸出高電平結(jié)果串口發(fā)送的數(shù)據(jù)偶爾錯位。后來排查到就是這條語句把 P3.1 的發(fā)送狀態(tài)破壞了。給 P3 口做整組賦值之前一定要先確認(rèn)每個引腳當(dāng)前是否在用第二功能。外部中斷引腳 INT0 和 INT1 通常需要外部上拉。內(nèi)部雖然自帶弱上拉但如果外部信號源是開漏輸出的傳感器拉低能力很強(qiáng)拉高能力不足就要在外部加一顆 10k 上拉電阻保證信號上升沿干凈。中斷信號線上如果串了太長導(dǎo)線還應(yīng)該在靠近單片機(jī)引腳處加一個小電容濾除高頻抖動。我一般用 100nF既能濾掉毛刺又不會把正常邊沿脈沖拖慢太多。P3.6 和 P3.7 在未擴(kuò)展外部存儲器時是通用 I/O但訪問外部地址空間時會被硬件拉低選通。很多人把這倆腳當(dāng)普通輸出用結(jié)果程序里一訪問外部變量引腳電平就跳變。 如果你不用外部總線最好不要去操作 xdata 區(qū)或者干脆避開 P3.6 和 P3.7把它們留給真正需要頻繁讀寫的場合。4. 引腳常見問題與排查現(xiàn)象、原因與處理順序4.1 芯片發(fā)熱、VCC 與 GND 阻值異常引腳接錯或焊橋現(xiàn)象新焊的板子第一次通電芯片摸起來發(fā)燙電流表顯示電流遠(yuǎn)超正常值甚至達(dá)到幾百毫安。程序還沒下載芯片就已經(jīng)進(jìn)入異常狀態(tài)。原因絕大多數(shù)情況是 VCC 和 GND 之間有低阻抗路徑。常見的三種是電源引腳反接、PCB 焊錫橋連到了相鄰引腳、某個 I/O 引腳被外部電路強(qiáng)制接入高電平而程序或默認(rèn)狀態(tài)把它拉低形成大電流。DIP-40 封裝引腳間距大焊橋相對少見但面包板上插錯一排線的情況時有發(fā)生。解決先斷電把萬用表打到蜂鳴檔量 20 腳 GND 和 40 腳 VCC 之間的阻值。正常情況下有 100nF 電容存在蜂鳴器可能會短響一聲后停住這是因為電容充電如果持續(xù)鳴叫基本就是短路。這時把芯片從插座上取下來再量 PCB 或面包板上的 VCC 和 GND確認(rèn)是板子問題還是芯片本身問題。芯片單獨量 GND 和 VCC 之間的二極管壓降通常能讀到 0.4V 到 0.7V 的正向壓降如果兩個方向都接近 0芯片已經(jīng)損壞。處理順序上我堅持“先量后上電”。不要為了省事直接換芯片因為板子上的短路沒排除換一塊燒一塊。4.2 能燒錄但復(fù)位后不跑EA 引腳或晶振回路問題現(xiàn)象使用編程器下載程序時一切正常但拔掉下載線、重新上電后程序不運(yùn)行。I/O 口沒有任何輸出甚至 P0 口電平異常跳動。原因這個現(xiàn)象要分兩塊排查。第一塊是 EA 引腳31 腳。EA 引腳決定程序從內(nèi)部存儲器還是外部存儲器取指。使用帶內(nèi)部 Flash 的 51 單片機(jī)EA 必須接 VCC程序才會從內(nèi)部取指。如果 EA 懸空或者被外部電路拉低單片機(jī)默認(rèn)從外部程序存儲器取指而外部總線上什么都沒有內(nèi)部程序自然永遠(yuǎn)不會執(zhí)行。此時 P0 和 P2 會被地址/數(shù)據(jù)總線占住表現(xiàn)就是引腳電平不受程序控制。解決方法是把 31 腳直接接到 VCC注意不是通過上拉電阻含糊地拉高而是物理上接到電源正極。第二塊是晶振回路。如果晶振沒有起振程序也跑不起來但下載工具可能因為自身有時鐘源而顯示連接正常。用萬用表量 XTAL2 電壓如果在 VCC 一半附近說明振蕩器在工作如果量到 0V 或 VCC檢查晶振是否插反、電容是否虛焊、晶振兩個引腳之間是否被焊錫短路。根據(jù)“現(xiàn)象 → 原因 → 解決”的記錄習(xí)慣這條經(jīng)驗里我一般會提醒自己先量 EA 電壓再量 XTAL2 電壓這兩個引腳是跑系統(tǒng)之前必須確認(rèn)的點。順序不要反因為 EA 接錯的現(xiàn)象比晶振問題更有迷惑性。4.3 P0 寫高電平但輸出只有 0.5VLED 不亮現(xiàn)象程序中執(zhí)行P0 0xFF想讓 P0 口輸出高電平但用萬用表量引腳電壓只有 0.5V 左右接上去的 LED 不亮或者極暗。原因P0 口是開漏結(jié)構(gòu)內(nèi)部沒有上拉管寫 1 時引腳只是懸空。萬用表量到的 0.5V 實際上是 LED 或后續(xù)電路的漏電流在引腳上形成的壓降不是真正的高電平。這是 P0 口最典型的踩坑點本質(zhì)是 I/O 結(jié)構(gòu)問題不是程序邏輯問題。解決在 P0 外部整組接上拉電阻到 VCC阻值按驅(qū)動需求選擇。具體接法每個 P0 引腳通過 4.7k 到 10k 電阻接到 VCCLED 的限流電阻計算按外部上拉后的高電平電壓來算。如果用 4.7k 上拉、5V 供電LED 串聯(lián) 1k 電阻高電平點亮?xí)r電流大約是(5 - 2) / (4700 1000) ≈ 0.5mA亮度偏弱想讓 LED 更亮可以把 LED 改成低電平點亮方式LED 正極接 5V負(fù)極經(jīng)過 1k 電阻接到 P0P0 輸出 0 時 LED 亮此時灌入 P0 的電流約 3mA穩(wěn)定可靠。還有一種情況是P0 沒有外部上拉但芯片內(nèi)部的增強(qiáng)型準(zhǔn)雙向結(jié)構(gòu)把引腳拉到了高電平理論上能點亮 LED但驅(qū)動能力很弱。遇到這種“看起來能亮但負(fù)載一大就掉電”的情況外部上拉電阻仍然建議保留。4.4 按鍵輸入時讀到隨機(jī)電平準(zhǔn)雙向口和懸空引腳現(xiàn)象按鍵沒按下時程序讀到引腳電平有時是 1有時是 0按下后也不穩(wěn)定需要加很長的延遲才能消抖。原因按鍵一端接 I/O 引腳另一端接 GND這在很多例程里很常見。程序初始化后沒有先向該引腳寫 1內(nèi)部弱上拉沒有打開引腳處于高阻輸入狀態(tài)或者引腳雖然寫了 1但按鍵連接線太長吸收了周圍噪聲。準(zhǔn)雙向口的內(nèi)部上拉本來就很弱長導(dǎo)線在沒有外部上拉時就像一根天線讀到的電平自然不穩(wěn)定。解決初始化時把所有按鍵引腳寫成 1再配合外部 10k 上拉電阻增強(qiáng)驅(qū)動。如果按鍵數(shù)量多可以用上拉排阻一次性把一組引腳都拉高。軟件消抖部分常見的做法是檢測到電平變化后延時 10ms 再讀一次見下文示例void key_scan(void) { static unsigned char last_state 0xFF; unsigned char now_state; P1 0xFF; // 打開 P1 口所有引腳的弱上拉 now_state P1; // 讀一次引腳電平 if (now_state ! last_state) { delay_ms(10); // 延時消除機(jī)械抖動 now_state P1; // 再讀一次 if (now_state ! last_state) { last_state now_state; // 這里根據(jù)電平變化做按鍵響應(yīng) } } }參數(shù)說明10ms 是機(jī)械按鍵抖動的一般經(jīng)驗值硅膠按鍵可以縮短到 5ms老式輕觸開關(guān)用 10ms 更保險。外部上拉 10k 與引腳寄生電容組成的 RC 時間常數(shù)在微秒級不會影響 10ms 消抖邏輯。搞定這個外部上拉和讀前寫 1 的順序按鍵輸入基本就不再做“黑匣子”處理了。5. 引腳級最終驗證一塊萬用表加一段循環(huán)代碼把所有引腳測一遍新的板子到手我習(xí)慣先寫一段 GPIO 巡檢程序把每個端口以半個字節(jié)為單位翻轉(zhuǎn)再用萬用表逐個量。這樣能快速確認(rèn)引腳焊接、上拉電阻、端口寫讀是否存在問題。以下代碼用 P1 和 P3 口演示P0 需要外接上拉后同樣適用#include reg51.h void delay(void) { unsigned int i; for (i 0; i 30000; i); } void main(void) { unsigned char led_pattern; while (1) { // 第一次巡檢P1 口高四位輸出低低四位輸出高 P1 0x0F; delay(); // 第二次巡檢P1 口高四位輸出高低四位輸出低 P1 0xF0; delay(); // P3 口按 0x55 和 0xAA 翻轉(zhuǎn)覆蓋所有引腳 P3 0x55; delay(); P3 0xAA; delay(); // 讀回驗證先把引腳置 1再讀端口 P1 0xFF; led_pattern P1; if (led_pattern ! 0xFF) { // 有引腳被外部拉低說明存在不該出現(xiàn)的短路或負(fù)載 P2 0x00; } else { P2 0xFF; } delay(); } }代碼邏輯說明前兩組賦值分別覆蓋 P1 的 8 個引腳高低電平用萬用表量每個引腳應(yīng)該在 VCC 和 GND 之間交替跳變。P3 口的 0x55 和 0xAA 交替是為了驗證相鄰引腳之間沒有焊橋短路因為 0x55 的二進(jìn)制是 01010101相鄰引腳始終是相反電平如果相鄰引腳短路兩者會互相拉扯讀回來的值不會按預(yù)期變化。參數(shù)說明delay()里的 30000 在 12MHz 晶振下大約是幾十毫秒留足萬用表表筆接觸和讀數(shù)的時間。如果換用 11.0592MHz 晶振時間變化不大不需要調(diào)整。這段代碼不需要接額外外圍電路P2 口用作結(jié)果指示讀回正常時輸出 0xFF異常時輸出 0x00。實測時我遇到過一種情況P1 口讀回來的值一直少了某一位。程序里寫 0xFF讀到 0xFE說明 P1.0 被外部拉低。拆掉所有負(fù)載后恢復(fù)最終發(fā)現(xiàn)是插座引腳焊盤和相鄰的地平面之間殘留了助焊劑。這類問題如果沒有巡檢代碼查起來非常浪費時間。我現(xiàn)在做新板子流程固定成三步先量 VCC 與 GND再上電復(fù)位最后跑這段端口巡檢。三步都過了再往應(yīng)用層功能里走。那句“調(diào)試玄學(xué)大多出在引腳上”是我這幾年最深的體會。引腳電平是可以用萬用表直接量出來的不是靠猜的。如果你正被某個引腳怪問題困住不妨回歸到最基礎(chǔ)的端口巡檢一塊萬用表加一段循環(huán)代碼很快就能定位到是哪一根線、哪一個焊點出了問題。希望幫到你。本文還有配套的精品資源點擊獲取