查看: 30918|回复: 10

【小常識】從按鈕開關看上拉pull-up電阻下拉電阻是蝦密碗糕

[复制链接]
  • TA的每日心情
    擦汗
    2016-9-23 12:33
  • 签到天数: 170 天

    [LV.7]常住居民III

    发表于 2015-3-21 17:19 | 显示全部楼层 |阅读模式
    本帖最后由 tsaiwn 于 2015-3-25 01:48 编辑

    到底啥是上拉(pull-up)電阻和下拉(pull-down)電阻 ?
        在用 Arduino 做實驗時, 按鈕開關(Button/Switch)是很常見的應用,
    然後你常常看到文件說要接個電阻, 又看到"上拉電阻"或"下拉電阻"!
        電阻(resistor)應該大家多多少少都知道(大家都聽過歐姆定律),
    可是到底上拉(pull-up)和下拉(pull-down)是蝦密碗糕呢?

    首先, 不論"上拉電阻"或"下拉電阻", 它們都是電阻(廢話),
    它們一定是連接到你要讀取的輸入 pin (又是廢話),
    但是, 電阻另一端如果是連接到 + 或 VCC 那就叫做上拉(pull-up)電阻;
    反之, 電阻如果另一端是連接到 - 或 GND 那就叫做下拉(pull-down)電阻!
    就這樣?
    當然就只是連接方式不同啊, 阿不然你認為還要怎樣?

        把 pin 連接電阻再連接到 + 或 VCC,
    則 pin 腳空接時會是在 HIGH, 所以稱之為上拉(pull-up);
    反之, 把 pin 連到電阻再接到 - GND 則空接時將是 LOW,
    因此就稱之為下拉(pull-down).

    為何要接個電阻?
        這是因為當 MCU 的 GPIO 某 pin 被設定為 INPUT mode 時,
    是在輸入高阻抗(input impedance)狀態,
    意思是相當於另一端有串接個超級大的電阻擋住,
    那意味著 pin 在空接時就等於沒有連接到任何電路,
    此時用digitalRead(pin)去讀取它則常常因受到環境雜訊的影響,
    有時讀取到 HIGH 有時卻讀取到 LOW, 就是所謂的 floating 狀態!
    不過請注意, 以上只是比喻, pin 內部另一端並不是真的串接電阻,
    事實上是串接一個 MOSFET(MOS Field Effect Transistor)的電子閘(Gate),
    MOSFET 中文是金屬氧化物半導體場效應管, 這已經超出Arduino課程範圍)
        這樣按鈕沒按下也可能被誤判為有按下 !?
    為了確保它在穩定的狀態, 必須接個上拉電阻或下拉電阻!
    還有還有, 如果不接個電阻, 當你按下按鈕,
    就會把 VCC 直接連接到 GND, 那樣就短路(Short)燒趴電囉 !


    那到底要用上拉(pull-up)? 還是要用下拉(pull-down)?
        答案是都可以!
    不過要注意這時你寫的程序碼會有所不同 !

        通常建議是用上拉(pull-up)方式,
    (其實那是對早期 IC 才比較建議用上拉方式, 現在真的沒差!)
    也就是電阻一端連接 pin, 電阻另一端連接 + 或  VCC,
    這時按鈕開關當然是一端接到 pin, 另一端接到 GND;
    要注意, 這樣在按鈕開關沒按下時讀取 pin 結果是 HIGH,
    當按鈕按下之時讀取 pin 則會是 LOW 的狀態 !

        如果你是採用下拉(pull-down)方式連接,
    就是說, 把電阻一端連接 pin, 電阻另一端連接 - 或  GND,
    (此時按鈕開關當然是一端接到 pin, 另一端接到 + VCC);
    這樣在按鈕開關沒有按下時, 讀取 pin 答案是 LOW,
    當按下按鈕時, 讀取 pin 則會得到 HIGH 的狀態 !

        那到底要用幾歐姆(Ohm)的電阻來上拉或下拉 ?
    在 Arduino 官網上是建議用 10K歐姆的電阻:
       http://arduino.cc/en/Tutorial/DigitalPins

        其實一般來說, 10K 到 100K之間都是很好的選擇,
    現在用上拉電阻(連接到 + VCC)來解說,
    顯然在該 pin 空接時應該是 HIGH,
    可是, 如果上拉的電阻太大, 則空接時將因電阻太大使得 pin 的電壓太小,
    通常電壓太小(小於一半又小一些以下)就會被誤判為 LOW;
        反之, 如果上拉電阻太小, 那按鈕按下時就相當於 VCC 直接連到 GND,
    也就是相當於短路(Short)阿就燒趴電啦 !!


    使用內部上拉電阻(Internal pull-up)最方便 !
    Arduino 的設計者考慮 GPIO pin 可能拿來做數位輸入(Digital Input),
    所以每支 pin 內部都已經內建了一個 20K歐姆的上拉(Pull-up)電阻,
    你只要這樣:
       pinMode(pin, INPUT_PULLUP);
    這樣就可以啟動內建的上拉電阻, 省去外接一個上拉電阻的麻煩 :-)
        此時, 如果要測試按鈕,
    則只要拿一條杜邦線或任意的導線從 GND 拉出然後碰觸 pin,
    這樣就等於按下按鈕, digialRead(pin) 就會讀到 LOW 的值.
    (可以把沒用的網路線剪下撥開, 裡面就有八條電導線可以用!)

    請注意, 網路上有時會看到說以下兩句也可以:
       pinMode(pin, INPUT);           // set pin to input
       digitalWrite(pin, HIGH);       // turn on pullup resistors
    確實是可以這樣做沒錯! (現在版本仍可以)
    但是, 那是在 Arduino 1.0.1 版本以前才需要,
    因為以前版本的 pinMode( ) 沒有 INPUT_PULLUP 可以用 !!

    有時甚至會看到有人只寫了 digitalWrite(pin, HIGH);   
    連 pinMode(pin, INPUT);  都沒寫,
    那樣也是可以的, 這是因為 Arduino 啟動時已經把全部 GPIO 的pin設定為 INPUT,
    也就是說, 預設 (default, 默認)就是 INPUT 的 mode.


    既然 Arduino 開機之後, 預設(Default; 默認)所有的 GPIO pin 都是在 INPUT 的 pinMode,
    所以, 如果你想要使用某 pin 做 OUTPUT 輸出,
    但是如果忘了設定 pinMode(pin, OUTPUT);
    然後就直接 digitalWrite(pin, HIGH);
    則此時因為其實相當於做 pinMode(pin, INPUT_PULLUP);
    這時該 pin 如果連接 LED又串接個電阻(通常這樣你才會想 digitalWrite( )送出 HIGH 不是嗎 ?)
    則其電壓將會大約是 1.7 Volt, 不是你想要的 5 Volt,
    因此, 該 pin 所連接的 LED 將會有點暗暗的不夠亮 !
    (注意在 VCC 為 5 Volt 環境下, 3 Volt 以下將被 digitalRead( )判定為 LOW.)

      最後要注意的是, pin 13 不適合使用內部上拉電阻設定pin 13做輸入;
    雖然 Arduino 所有的 pin, 包括 pin 0 到 pin 13, 以及 A0 到 A5,
    都可以做數位輸出用 digitalWrite(pin, HIGH_or_LOW); 做輸出;
    但是做輸入 analogRead(pin) 的 是 GPIO pin 0 到 pin13;
    可是可是,
        因為 pin 13 出廠就串接一個 LED 燈又串接一個電阻,
    所以如果你使用 pinMode(13, INPUT_PULLUP);
    則連接按鈕後, digitalRead(13) 將不論如何讀都是 LOW的值 !
    因為即使按鈕按下, pin 13 大約也只有 1.7 Volt, 不是你想要的 5 Volt電壓!
    而通常在電源 5Volt 情況下, 低於 3Volt 是被認定為 0 的 !
    參考:  http://arduino.cc/en/Reference/Constants

        如果你堅持一定要用 pin 13 當作輸入,
    請設定 pinMode(13, INPUT);
    然後使用外接的上拉電阻或下拉電阻 !


    參考:
       http://arduino.cc/en/Tutorial/DigitalPins
       http://www.atmel.com/images/doc0856.pdf
       http://www.atmel.com/dyn/resources/prod_documents/DOC2559.PDF


    把補充資料複製到這方便大家參閱 ..

    使用上拉(Pull-up)電阻或是下拉(Pull-down)電阻,
    跟去抖動(debouncing)一點關係也沒有喔 !

    加個上拉電阻或下拉電阻的主要目的是消除引腳的輸入噪音(Input noise),
    就是前面說的因為輸入 pin 在輸入高阻抗(input impedance)狀態,
    相當於另一端有串接個超級大的電阻擋住,
    以至於 pin 在空接時常因受到環境雜訊的影響, 呈現所謂的 floating 狀態!


       抖動(Bouncing)的產生, 是因為人的手按下開關時, 因為開關機械接觸點不會立即密合,
    這使得在 MCU 看來, 瞬間等於按下又放掉, 放掉又按下, ...
    等於 0.1 秒內就這樣按放按放...數次甚至十幾次或數十次 !

       這個問題在大多數情況下並沒有問題, 例如, 你希望按鈕按下就 LED 亮, 放掉就熄滅,
    那不會有問題!
    因為抖動很快, LED忽亮忽滅肉眼無法察覺, 就算察覺你也不會在乎 :-)
    可是,
    如果你是希望按鈕按一下是 toggle, 就是說按一下, 按一下,
    那這時就會有問題!

    因為, 你以為按了一下, 如果程序感應到6下或是18下(偶數), 那豈非等於沒按到 !?
        要消除這個問題稱為去抖動(DeBouncing)處理,
    去抖動雖然可以用比較複雜的硬體電路解決這問題,

    但通常硬體電路都偷懶沒做;
    所以, 必須在程序碼內處理!
    最簡單的處理方法就是,
    使用 delay( )隔一下下再讀取做確認, 例如:
       int val = digitalRead(pin);
       delay(38);  // 0.038秒
       int val22 = digitalRead(pin);
       if(val22 != val) {
          delay(15);  val22 = digitalRead(pin);  // 不會這麼倒楣  :-)
       }
       delay(168);  // 故意不要連續讀取

       if(val == val22) {
          if(val == HIGH) {
             // 應該真的是 HIGH
          }else{
             // 應該真的是 LOW
          }
       } // 確定不是抖動
    用硬件去抖動處理可參考:
       http://www.labbookpages.co.uk/electronics/debounce.html

    其實有個簡單的方法,  就是並聯一個電容 !






    並聯一個電容幫忙去抖動

    並聯一個電容幫忙去抖動
  • TA的每日心情
    奋斗
    2018-12-14 06:20
  • 签到天数: 1458 天

    [LV.10]以坛为家III

    发表于 2015-3-24 09:34 | 显示全部楼层
    都是好兄弟!
  • TA的每日心情
    擦汗
    2016-9-23 12:33
  • 签到天数: 170 天

    [LV.7]常住居民III

     楼主| 发表于 2015-3-21 17:22 | 显示全部楼层
    本帖最后由 tsaiwn 于 2015-3-24 21:02 编辑

    補充一下,
    使用上拉(Pull-up)電阻或是下拉(Pull-down)電阻,
    跟去抖動(debouncing)一點關係也沒有喔 !
       抖動(Bouncing)的產生, 是因為人的手按下開關時,
    其實在 MCU 看來, 瞬間等於按下又放掉, 放掉又按下, ...
    等於 0.1 秒內就這樣按放按放...數十次 !

       這個問題在大多數情況下並沒有問題, 例如, 你希望按鈕按下就 LED 亮, 放掉就熄滅,
    那不會有問題!
    因為抖動很快, LED忽亮忽滅肉眼無法察覺, 就算察覺你也不會在乎 :-)
    可是,
    如果你是希望按鈕按一下是 toggle, 就是說按一下, 按一下,
    那這時就會有問題!

    因為, 你以為按了一下, 如果程序感應到6下或是18下(偶數), 那豈非等於沒按到 !?
        要消除這個問題稱為去抖動(DeBouncing)處理,
    去抖動雖然可以用比較複雜的硬體電路解決這問題,

    但通常硬體電路都偷懶沒做;
    所以, 必須在程序碼內處理!
    最簡單的處理方法就是,
    使用 delay( )隔一下下再讀取做確認, 例如:
       int val = digitalRead(pin);
       delay(38);  // 0.038秒
       int val22 = digitalRead(pin);
       delay(168);  // 故意不要連續讀取
       if(val == val22) {
          if(val == HIGH) {
             // 應該真的是 HIGH
          }else{
             // 應該真的是 LOW
          }
       } // 確定不是抖動
    用硬件去抖動處理可參考:
       http://www.labbookpages.co.uk/electronics/debounce.html



  • TA的每日心情
    奋斗
    2018-12-14 06:20
  • 签到天数: 1458 天

    [LV.10]以坛为家III

    发表于 2015-3-23 10:10 | 显示全部楼层
    很好的文章!谢谢!
  • TA的每日心情
    奋斗
    2018-12-14 06:20
  • 签到天数: 1458 天

    [LV.10]以坛为家III

    发表于 2015-3-23 10:12 | 显示全部楼层
    “蝦密碗糕”,几个意思?
  • TA的每日心情
    擦汗
    2016-9-23 12:33
  • 签到天数: 170 天

    [LV.7]常住居民III

     楼主| 发表于 2015-3-23 12:53 | 显示全部楼层
    z586 发表于 2015-3-23 10:12
    “蝦密碗糕”,几个意思?

    “蝦密碗糕” == “什麼東西” == “What is it ?”,
  • TA的每日心情
    奋斗
    2018-12-14 06:20
  • 签到天数: 1458 天

    [LV.10]以坛为家III

    发表于 2015-3-23 18:38 | 显示全部楼层
    我猜不出“碗糕”是什么东东!{:soso_e128:}
  • TA的每日心情
    擦汗
    2016-9-23 12:33
  • 签到天数: 170 天

    [LV.7]常住居民III

     楼主| 发表于 2015-3-23 20:50 | 显示全部楼层
    z586 发表于 2015-3-23 18:38
    我猜不出“碗糕”是什么东东!


    “碗糕” 原意是一種點心或甜點,
    裝在碗裡面, 用蒸熟的, 以前都是用米磨成粉之後加入配料蒸熟,
    很好吃  
  • TA的每日心情
    郁闷
    2018-12-6 22:21
  • 签到天数: 48 天

    [LV.5]常住居民I

    发表于 2015-3-23 21:24 | 显示全部楼层
    难道是台湾同胞?
    如果以上内容对你有帮助,你可以通过打赏支持作者
  • TA的每日心情
    擦汗
    2016-9-23 12:33
  • 签到天数: 170 天

    [LV.7]常住居民III

     楼主| 发表于 2015-3-23 22:00 | 显示全部楼层
    奈何col 发表于 2015-3-23 21:24
    难道是台湾同胞?

    報告站長,
    完全正確
    台灣, 新竹交通大學
    您需要登录后才可以回帖 登录 | 立即注册  

    本版积分规则

    热门推荐

    KittenBot杯第六届开源硬件开发大赛启动啦
    KittenBot杯第六届开源硬
    大赛简介: 第六届开源硬件开发大赛由Arduino中文社区发起 由KittenBot冠名赞助
    全过程展示:PWM自定义、测速、PID调速、PID自整定
    全过程展示:PWM自定义、
    arduino如何控制带驱动28步进电机
    arduino如何控制带驱动28
    有大佬知道吗,arduino不知道能不能发出脉冲信号
    Wifiduino(esp8266)+blinker+微信消息推送
    Wifiduino(esp8266)+bli
    最近呢,有个很小的项目 需要反馈现场电源工作状态,着急开发,没时间做方案。我又是
    因为DHT11是假的吗?
    因为DHT11是假的吗?
    用DHT11测温湿度时,监视窗口总是这样显示,这是为什么啊,求大佬告知!
    Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   ( 蜀ICP备14017632号-3 )
    快速回复 返回顶部 返回列表