算與實(shí)戰(zhàn)應(yīng)用)
1. 上拉、下拉電阻到底是什么做嵌入式硬件越久越發(fā)現(xiàn)最基礎(chǔ)的東西反而最容易被忽略。上拉電阻和下拉電阻看起來只是兩個(gè)電阻一個(gè)接到電源一個(gè)接到地但很多奇奇怪怪的問題比如按鍵誤觸發(fā)、I2C通信死鎖、MOS管誤導(dǎo)通翻到最后都是這兩個(gè)電阻設(shè)置不當(dāng)。先說定義。上拉電阻就是把一個(gè)信號(hào)引腳通過電阻連接到高電平通常接VCC下拉電阻就是把一個(gè)信號(hào)引腳通過電阻連接到低電平通常接GND。它們的核心作用只有一個(gè)給一個(gè)不確定的引腳一個(gè)確定的默認(rèn)電平。數(shù)字電路里的引腳并不總是穩(wěn)定輸出高或低。很多引腳在不輸出、不輸入的時(shí)候會(huì)處于高阻態(tài)也就是既不主動(dòng)拉高也不主動(dòng)拉低。這時(shí)候引腳上的電壓完全取決于外部環(huán)境。如果旁邊沒有任何電路給它一個(gè)明確的電平它就相當(dāng)于一根懸空的天線附近有一點(diǎn)干擾信號(hào)電壓就會(huì)跟著跳。1.1 用按鍵電路理解上拉和下拉我經(jīng)常用一個(gè)按鍵電路給新手講這個(gè)問題。假如一個(gè)按鍵一端接GPIO一端接GND。如果不接任何電阻按鍵按下時(shí)GPIO讀到低電平松開后GPIO懸空讀到的值就可能一會(huì)兒高一會(huì)兒低甚至受到旁邊電機(jī)、繼電器、電源紋波的影響亂跳。這時(shí)候在GPIO和VCC之間接一個(gè)10k電阻松開時(shí)GPIO被電阻拉高到VCC按下時(shí)GPIO又被按鍵直接拉到GND邏輯就非常干凈了。反過來如果按鍵一端接VCC一端接GPIO那GPIO就應(yīng)該通過下拉電阻接到GND。松開時(shí)引腳被拉到低電平按下時(shí)引腳被拉到高電平。這就是上拉和下拉最樸素的用法不是把電平“拉”到多強(qiáng)而是把電平“釘”在一個(gè)確定的位置。1.2 上拉和下拉不是串聯(lián)是并聯(lián)新手經(jīng)常把上拉電阻和限流電阻搞混。這里有個(gè)簡單的判斷方法如果電阻的一端接在信號(hào)線上另一端接VCC或GND那它就是上拉或下拉電阻。如果電阻是串在信號(hào)通路中間比如LED限流電阻、串口線上的匹配電阻那是另一類作用。上拉下拉是并聯(lián)在信號(hào)和電源軌之間的不是信號(hào)通路的必經(jīng)之路。這個(gè)區(qū)別很重要因?yàn)椴⒙?lián)電阻會(huì)影響電平的驅(qū)動(dòng)能力。上拉電阻越小對(duì)引腳電平的“控制力”越強(qiáng)但同時(shí)消耗的電流也越大。這就是后面要說的強(qiáng)上拉和弱上拉。2. 強(qiáng)上拉和弱上拉怎么選阻值怎么算很多人一看到“強(qiáng)上拉”“弱上拉”就覺得是兩種特殊的元器件其實(shí)并不是。強(qiáng)和弱是相對(duì)的說法本質(zhì)區(qū)別在上拉電阻的阻值大小。阻值小比如1k、2.2k這是強(qiáng)上拉。它的特點(diǎn)是能提供較大的電流信號(hào)上升沿很陡抗干擾能力強(qiáng)適合高速總線和高頻開關(guān)信號(hào)。但代價(jià)也很明顯靜態(tài)功耗大并且在引腳輸出低電平時(shí)會(huì)有比較大的電流從上拉電阻流進(jìn)引腳這對(duì)引腳的灌電流能力提出了要求。阻值大比如47k、100k這是弱上拉。它的特點(diǎn)是電流很小省電一般只負(fù)責(zé)維持一個(gè)默認(rèn)電平。但它把信號(hào)拉高的能力很弱上升沿很緩如果信號(hào)線上電容稍微大一點(diǎn)波形就會(huì)變成一條斜線導(dǎo)致接收端采樣錯(cuò)誤。2.1 為什么不能直接接一根導(dǎo)線到VCC或GND有人可能會(huì)想既然要默認(rèn)高電平直接用導(dǎo)線把引腳接到VCC不就行了嗎不行。如果信號(hào)線上還連著其它開漏輸出或者推挽輸出對(duì)方輸出低電平時(shí)就等于把VCC直接短路到地瞬間大電流會(huì)燒毀引腳或電源。電阻在這里起的是限流作用。阻值選得好既能保證默認(rèn)電平又不會(huì)在低電平狀態(tài)下產(chǎn)生超過器件承受能力的電流。所以上拉下拉電阻不是可有可無的“保險(xiǎn)”而是電路正常工作的一部分。2.2 I2C上拉電阻具體取多大算一遍就明白很多人在網(wǎng)上問“I2C上拉電阻取多大”完美的回答永遠(yuǎn)是“看計(jì)算”。這里我展開講一次。I2C的SDA和SCL是開漏輸出只能拉低不能主動(dòng)拉高所以必須靠外部上拉電阻把總線拉高。上拉電阻有兩個(gè)邊界最小值由低電平灌電流決定Rmin (VCC - VOL) / IOL其中VOL是器件允許的最大低電平IOL是器件在低電平時(shí)的灌電流能力。比如3.3V系統(tǒng)VOL0.4VIOL3mA那Rmin就是(3.3-0.4)/0.003約966Ω。實(shí)際不能取比這個(gè)更小的值否則低電平拉不下去。最大值由總線上升時(shí)間決定Rmax tr / (0.8473 × Cbus)tr是I2C協(xié)議要求的最大上升時(shí)間標(biāo)準(zhǔn)模式100kbps是1000ns快速模式400kbps是300ns。Cbus是總線電容包括走線、過孔和每個(gè)器件的輸入電容一般估100pF到300pF。舉個(gè)例子。VCC3.3V總線電容按150pF算工作在400kbps快速模式tr300ns。Rmin已經(jīng)算出來約966ΩRmax300ns/(0.8473×150pF)約2.36kΩ。那上拉電阻就應(yīng)該選在1k到2.2k之間比較合適。如果只是標(biāo)準(zhǔn)100kbps模式Rmax約7.87kΩ取4.7k就非常穩(wěn)。網(wǎng)上很多經(jīng)驗(yàn)帖直接說“I2C上拉用4.7k”那是在較短走線、標(biāo)準(zhǔn)速率、3.3V系統(tǒng)的前提下的經(jīng)驗(yàn)值。如果走線特別長或者速率上到400k甚至1M4.7k就不一定靠譜了。我自己的習(xí)慣是先按公式算一遍再用示波器看上升沿如果邊沿還太慢就繼續(xù)減小阻值。3. 上拉、下拉電阻的常見作用比你想的多很多人以為上拉下拉只是“防懸空”其實(shí)在真實(shí)電路里它們的用途遠(yuǎn)不止這一項(xiàng)。我梳理了幾個(gè)最常見的場景基本覆蓋了日常開發(fā)中的絕大多數(shù)需求。3.1 配合開漏輸出使用最典型的就是I2C開漏輸出電路本身只能輸出低電平和釋放總線輸出電壓的高電平完全靠外部上拉電阻決定。I2C、1-Wire、以及很多MCU的P0口都是這種結(jié)構(gòu)。上拉電阻的值決定了總線空閑電平、上升沿速度和整體功耗。這里有個(gè)額外的好處開漏輸出配上拉電阻還能做電平轉(zhuǎn)換。比如MCU是3.3V系統(tǒng)但外部EEPROM是5V系統(tǒng)可以把上拉電阻接到5V只要MCU引腳支持5V耐壓總線上高電平就是5V低電平由MCU或EEPROM拉低到接近0V兩邊都能正確識(shí)別。如果用推挽輸出直接接反而容易出問題。3.2 設(shè)定上電默認(rèn)狀態(tài)防止亂啟動(dòng)復(fù)位引腳、BOOT選擇引腳、I2C地址選擇引腳、使能引腳這些地方通常都需要在芯片上電時(shí)有一個(gè)確定的電平。比如BOOT引腳決定MCU從Flash啟動(dòng)還是從串口啟動(dòng)如果這個(gè)引腳懸空上電后可能隨機(jī)進(jìn)入錯(cuò)誤模式程序跑不起來或者異常跑飛。這種場景下上拉或下拉電阻的值一般不用太小10k到100k都行因?yàn)椴恍枰峁╇娏髦恍枰峁┮粋€(gè)明確的電平。但也要注意有些引腳內(nèi)部已經(jīng)有弱上拉外部再接一個(gè)很小的下拉就會(huì)和內(nèi)部上拉打架最終電平不一定是你想要的值。所以設(shè)計(jì)前一定要看芯片數(shù)據(jù)手冊(cè)里有沒有內(nèi)部上拉或下拉。3.3 柵極下拉電阻MOS管電路里必須重視最近很多人搜索“柵極下拉電阻”其實(shí)是在MOS管驅(qū)動(dòng)電路里踩了坑。MOS管的柵極是電壓控制輸入阻抗極高正常工作時(shí)幾乎不取電流。但正是因?yàn)樽杩垢邧艠O只要懸空一點(diǎn)點(diǎn)靜電或者周圍走線耦合過來的噪聲都可能改變柵極電壓導(dǎo)致MOS管誤導(dǎo)通。對(duì)于N-MOS管一般會(huì)在柵極和源極之間加一個(gè)10k到100k的下拉電阻保證沒有驅(qū)動(dòng)信號(hào)時(shí)柵極電壓是0V管子處于關(guān)斷狀態(tài)。對(duì)于P-MOS管則相反需要在柵極和源極之間加上拉電阻保證默認(rèn)關(guān)斷。這個(gè)電阻太大會(huì)讓抗干擾能力變差太小會(huì)增加驅(qū)動(dòng)電路的功耗和驅(qū)動(dòng)負(fù)擔(dān)10k到100k是比較常見的范圍。3.4 Type-C的CC下拉電阻不是防懸空是身份識(shí)別還有一個(gè)很多人搜的熱門詞是“Type-C下拉電阻”。USB Type-C接口里的CC1和CC2引腳在設(shè)備端也就是sink端通常要各接一個(gè)5.1kΩ下拉電阻到GND。這個(gè)電阻不是為了防止引腳懸空而是讓電源端識(shí)別出“這是一個(gè)設(shè)備”并根據(jù)CC引腳上的電壓判斷插拔狀態(tài)和設(shè)備能力。如果把5.1k換成1k或者10kType-C的握手邏輯就會(huì)出問題電源端可能不供電或者無法識(shí)別設(shè)備。很多人會(huì)把這個(gè)5.1k下拉和普通GPIO下拉混為一談結(jié)果做出來的Type-C板子插上沒反應(yīng)。所以看到“Type-C下拉電阻”時(shí)不要套普通下拉的經(jīng)驗(yàn)它是一個(gè)協(xié)議層面的識(shí)別電阻阻值要按照USB Type-C規(guī)范來。4. 拉電流、灌電流、吸電流方向比大小更重要標(biāo)題里這幾個(gè)詞是很多人的盲區(qū)拉電流、灌電流、吸電流。我見過不少人能把這三個(gè)詞背下來但一到分析電路就亂了。其實(shí)只要抓住“電流從哪來、到哪去”這個(gè)方向問題就能徹底弄清楚。先給結(jié)論拉電流也叫source current是指引腳輸出高電平時(shí)電流從引腳向外流出被外部負(fù)載“拉”走。比如GPIO直接驅(qū)動(dòng)一個(gè)LED到地?zé)袅習(xí)r電流從GPIO流出這就是拉電流。灌電流也叫sink current是指引腳輸出低電平時(shí)外部電路的電流從引腳“灌”進(jìn)去。比如LED接在VCC和GPIO之間GPIO輸出低電平讓燈亮電流從VCC經(jīng)過LED再流進(jìn)引腳。吸電流在很多中文資料里和灌電流是同一個(gè)意思。它強(qiáng)調(diào)從器件內(nèi)部視角看“吸收”外部流入的電流。不同工程師叫法可能不同但本質(zhì)上對(duì)應(yīng)的都是sink current。4.1 用LED電路看懂拉電流和灌電流我用一個(gè)最簡單的LED電路來展示。假設(shè)MCU供電3.3VLED正向壓降2V工作電流5mA。如果是拉電流接法LED負(fù)極接GND正極通過限流電阻接GPIO。GPIO輸出高電平時(shí)電流從GPIO流向LED再流向GND。限流電阻就是(3.3 - 2)/5mA 260Ω實(shí)際取270Ω或330Ω都行。此時(shí)GPIO提供的是拉電流。如果是灌電流接法LED正極接VCC負(fù)極通過限流電阻接GPIO。GPIO輸出低電平時(shí)電流從VCC流經(jīng)LED、電阻最后灌進(jìn)GPIO。限流電阻同樣是260Ω左右。此時(shí)GPIO承擔(dān)的是灌電流。這兩種接法在功能上都能點(diǎn)亮LED但要注意MCU數(shù)據(jù)手冊(cè)里的IOH和IOL參數(shù)往往不一樣。有些MCU的灌電流能力比拉電流能力強(qiáng)因?yàn)檩敵龅碗娖綍r(shí)內(nèi)部導(dǎo)通的是功率更大的NMOS管。老式的51單片機(jī)P0口開漏輸出輸出高電平要靠外部上拉拉電流能力就很弱灌電流能力相對(duì)強(qiáng)一些。4.2 上拉電阻和灌電流能力的關(guān)系上拉電阻選得太小最大的坑就在灌電流。當(dāng)一個(gè)開漏輸出引腳輸出低電平時(shí)上拉電阻和引腳內(nèi)部導(dǎo)通管會(huì)形成一條從VCC到GND的通路。如果上拉電阻只有100ΩVCC3.3V那灌電流就是33mA。很多芯片單個(gè)引腳的絕對(duì)最大灌電流只有20mA這么搞很容易損壞引腳。這也是為什么即便只是接一個(gè)上拉電阻也要看引腳的低電平灌電流規(guī)格。數(shù)據(jù)手冊(cè)里通常會(huì)寫IOL和VOL比如“VOL0.4V時(shí)IOL8mA”這表示在低電平不超過0.4V的前提下引腳最多能承受8mA的灌電流。上拉電阻的最小值就應(yīng)該保證灌電流不超過這個(gè)值。4.3 為什么說“吸電流”容易讓人誤解我在論壇上見過不少爭論有人說“吸電流就是拉電流”有人說“吸電流就是灌電流”。其實(shí)中文命名本身就不統(tǒng)一爭論意義不大。最可靠的辦法是看器件手冊(cè)里的英文參數(shù)source current是輸出電流sink current是輸入電流。凡是說“這個(gè)引腳能吸多少電流”大概率指的都是sink current也就是灌電流。以后遇到拉電流、灌電流、吸電流混用的場景先問一句“電流是從引腳流出去還是流進(jìn)引腳”。把方向搞清楚比糾結(jié)叫法重要得多。5. 實(shí)操經(jīng)驗(yàn)與常見問題排查前面講了原理和計(jì)算最后分享一些我實(shí)際調(diào)板子踩過的坑和經(jīng)驗(yàn)。這些東西在芯片數(shù)據(jù)手冊(cè)里基本不會(huì)寫但真的能幫你少走很多彎路。5.1 選阻值的快速參考表給一個(gè)我常用的經(jīng)驗(yàn)區(qū)間新手可以直接抄作業(yè)但用之前最好還是結(jié)合手頭的芯片參數(shù)驗(yàn)證一遍。場景建議阻值說明按鍵檢測(cè)10k-100k只設(shè)默認(rèn)電平電流越小越好I2C標(biāo)準(zhǔn)模式100k4.7k-10k總線短、電容小用10k長線用4.7kI2C快速模式400k2.2k-4.7k按RC計(jì)算上升沿不陡就減阻值開漏輸出電平轉(zhuǎn)換1k-10k兼顧速度和灌電流能力MOS管柵極下拉/上拉10k-100k默認(rèn)鎖定關(guān)閉或打開狀態(tài)Type-C CC下拉5.1k協(xié)議要求不能隨意改復(fù)位/BOOT引腳10k-47k只需上電時(shí)電平確定這個(gè)表格不是標(biāo)準(zhǔn)答案但足夠應(yīng)對(duì)大部分項(xiàng)目。如果你發(fā)現(xiàn)一個(gè)電路怎么調(diào)都不對(duì)先檢查阻值是不是落在了完全不合理的區(qū)間里。5.2 電阻位置和布線同樣影響效果上拉下拉電阻不是隨便找個(gè)地方焊上就行。位置放錯(cuò)了照樣會(huì)出現(xiàn)信號(hào)抖動(dòng)或時(shí)序問題。我的習(xí)慣是把上拉電阻放在靠近接收端的位置尤其是I2C總線和復(fù)位信號(hào)。如果電阻放得太遠(yuǎn)從電阻到芯片引腳之間的那截走線仍然處在高阻狀態(tài)容易耦合噪聲。對(duì)于Type-C的5.1k下拉也要盡量靠近CC引腳避免檢測(cè)電壓被走線電阻或寄生電容影響。另外一條總線上只能有一組上拉。如果主控板和從設(shè)備板都加了上拉兩個(gè)電阻并聯(lián)后總值變小低電平時(shí)灌電流就會(huì)變大可能超出器件能力。在模塊化設(shè)計(jì)里一定要約定好哪塊板子負(fù)責(zé)上拉。5.3 常見問題速查表照著排查我把自己遇到過和幫別人排查過的問題整理成了一張表。遇到現(xiàn)象直接對(duì)著查大多數(shù)情況都能定位到上拉或下拉的問題?,F(xiàn)象最可能原因排查和解決按鍵狀態(tài)亂跳引腳懸空沒有上拉/下拉加10k-100k上下拉配合軟件消抖I2C通信時(shí)好時(shí)壞NACK頻繁上拉太弱總線電容偏大用示波器看上升沿?fù)Q成2.2k或1k低電平輸出拉不到0V以下上拉太強(qiáng)灌電流超限增大上拉電阻檢查IOL參數(shù)靜態(tài)功耗異常大上下拉電阻太小換成10k以上量靜態(tài)電流MOS管一上電就導(dǎo)通柵極懸空噪聲耦合N-MOS加10k-100k下拉P-MOS加上拉Type-C接上后不供電CC下拉電阻值不對(duì)sink端CC1/CC2接5.1k到GND最后再分享一個(gè)小技巧。用萬用表判斷一個(gè)引腳是不是懸空時(shí)不要只看電壓讀數(shù)因?yàn)槿f用表內(nèi)阻本身就會(huì)影響高阻引腳的電平。最好用示波器探頭點(diǎn)在引腳上用手靠近板子看波形有沒有擾動(dòng)。如果波形在VCC和GND之間飄忽不定那十有八九就是缺少上拉或下拉。這個(gè)時(shí)候一顆10k電阻往往就能解決看起來玄乎的問題。