欧美性猛交xxxx免费看_牛牛在线视频国产免费_天堂草原电视剧在线观看免费_国产粉嫩高清在线观看_国产欧美日本亚洲精品一5区

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

函數(shù)進(jìn)階與按鍵(1)

冬至子 ? 來源:金沙灘工作室 ? 作者:金沙灘工作室 ? 2023-06-14 10:50 ? 次閱讀

用戶與單片機(jī)之間的信息交互需要依賴于兩類設(shè)備:輸入設(shè)備和輸出設(shè)備。前邊講的LED小燈、數(shù)碼管、點(diǎn)陣都是輸出設(shè)備,本章我們就來學(xué)習(xí)一下最常用的輸入設(shè)備——按鍵,同時(shí)還會(huì)學(xué)到一些硬件電路的基礎(chǔ)知識(shí)與C語言函數(shù)的一些進(jìn)階知識(shí)。

8.1 單片機(jī)最小系統(tǒng)解析

8.1.1 電源

我們?cè)趯W(xué)習(xí)過程中,很多指標(biāo)都是直接用的概念指標(biāo),比如我們說+5V代表1,GND代表0等等。但在實(shí)際電路中的電壓值并不是完全精準(zhǔn)的,那這些指標(biāo)允許范圍是什么呢?隨著我們所學(xué)的內(nèi)容不斷增多,大家要慢慢培養(yǎng)一種閱讀數(shù)據(jù)手冊(cè)的能力。

比如,我們要使用STC89C52RC單片機(jī)的時(shí)候,找到它的數(shù)據(jù)手冊(cè)第11頁,看第二項(xiàng)——工作電壓:5.5V~3.4V(5V單片機(jī)),這個(gè)地方就說明這個(gè)單片機(jī)正常的工作電壓是個(gè)范圍值,只要電源VCC在5.5V~3.4V之間都可以正常工作,電壓超過5.5V是絕對(duì)不允許的,會(huì)燒壞單片機(jī),電壓如果低于3.4V,單片機(jī)不會(huì)損壞,但是也不能正常工作。而在這個(gè)范圍內(nèi),最典型、最常用的電壓值就是5V,這就是后面括號(hào)里“5V單片機(jī)”這個(gè)名稱的由來。除此之外,還有一種常用的工作電壓范圍是2.7V~3.6V、典型值是3.3V的單片機(jī),也就是所謂的“3.3V單片機(jī)”。日后隨著大家接觸更多的器件,對(duì)這點(diǎn)會(huì)有更深刻的理解。

現(xiàn)在我們?cè)夙槺愣嗔私庖稽c(diǎn),大家打開74HC138的數(shù)據(jù)手冊(cè),會(huì)發(fā)現(xiàn)74HC138手冊(cè)的第二頁也有一個(gè)表格,上邊寫了74HC138的工作電壓范圍,最小值是4.75V,額定值是5V,最大值是5.25V,可以得知它的工作電壓范圍是4.75V~5.25V。這個(gè)地方講這些目的是讓大家清楚的了解,我們獲取器件工作參數(shù)的一個(gè)最重要、也是最權(quán)威的途徑,就是查閱該器件的數(shù)據(jù)手冊(cè)。

8.1.2 晶振

晶振通常分為無源晶振和有源晶振兩種類型,無源晶振一般稱之為crystal(晶體),而有源晶振則叫做oscillator振蕩器)。

有源晶振是一個(gè)完整的諧振振蕩器,它是利用石英晶體的壓電效應(yīng)來起振,所以有源晶振需要供電,當(dāng)我們把有源晶振電路做好后,不需要外接其它器件,只要給它供電,它就可以主動(dòng)產(chǎn)生振蕩頻率,并且可以提供高精度的頻率基準(zhǔn),信號(hào)質(zhì)量也比無源信號(hào)要好。

無源晶振自身無法振蕩起來,它需要芯片內(nèi)部的振蕩電路一起工作才能振蕩,它允許不同的電壓,但是信號(hào)質(zhì)量和精度較有源晶振差一些。相對(duì)價(jià)格來說,無源晶振要比有源晶振價(jià)格便宜很多。無源晶振兩側(cè)通常都會(huì)有個(gè)電容,一般其容值都選在10pF~40pF之間,如果手冊(cè)中有具體電容大小的要求則要根據(jù)要求來選電容,如果手冊(cè)沒有要求,我們用20pF就是比較好的選擇,這是一個(gè)長(zhǎng)久以來的經(jīng)驗(yàn)值,具有極其普遍的適用性。

有源晶振通常有4個(gè)引腳,VCC,GND,晶振輸出引腳和一個(gè)沒有用到的懸空引腳(有些晶振也把該引腳作為使能引腳)。無源晶振有2個(gè)或3個(gè)引腳,如果是3個(gè)引腳的話,中間引腳接是晶振的外殼,使用時(shí)要接到GND,兩側(cè)的引腳就是晶體的2個(gè)引出腳了,這兩個(gè)引腳作用是等同的,就像是電阻的2個(gè)引腳一樣,沒有正負(fù)之分。對(duì)于無源晶振,用我們的單片機(jī)上的兩個(gè)晶振引腳接上去即可,而有源晶振,只接到單片機(jī)的晶振的輸入引腳上,輸出引腳上不需要接,如圖8-3和圖8-4所示。

圖片

圖8-3 無源晶振接法

圖片

圖8-4 有源晶振接法

8.1.3 復(fù)位電路

我們先來分析一下KST-51開發(fā)板上的復(fù)位電路,如圖8-5所示。

圖片

圖8-5 單片機(jī)復(fù)位電路

當(dāng)這個(gè)電路處于穩(wěn)態(tài)時(shí),電容起到隔離直流的作用,隔離了+5V,而左側(cè)的復(fù)位按鍵是彈起狀態(tài),下邊部分電路就沒有電壓差的產(chǎn)生,所以按鍵和電容C11以下部分的電位都是和GND相等的,也就是0V。我們這個(gè)單片機(jī)是高電平復(fù)位,低電平正常工作,所以正常工作的電壓是0V,沒有問題。

我們?cè)賮矸治鰪臎]有電到上電的瞬間,電容C11上方電壓是5V,下方是0V,根據(jù)我們初中所學(xué)的知識(shí),電容C11要進(jìn)行充電,正離子從上往下充電,負(fù)電子從GND往上充電,這個(gè)時(shí)候電容對(duì)電路來說相當(dāng)于一根導(dǎo)線,全部電壓都加在了R31這個(gè)電阻上,那么RST端口位置的電壓就是5V,隨著電容充電越來越多,即將充滿的時(shí)候,電流會(huì)越來越小,那RST端口上的電壓值等于電流乘以R31的阻值,也就會(huì)越來越小,一直到電容完全充滿后,線路上不再有電流,這個(gè)時(shí)候RST和GND的電位就相等了也就是0V了。

從這個(gè)過程上來看,我們加上這個(gè)電路,單片機(jī)系統(tǒng)上電后,RST引腳會(huì)先保持一小段時(shí)間的高電平而后變成低電平,這個(gè)過程就是上電復(fù)位的過程。那這個(gè)“一小段時(shí)間”到底是多少才合適呢?每種單片機(jī)不完全一樣,51單片機(jī)手冊(cè)里寫的是持續(xù)時(shí)間不少于2個(gè)機(jī)器周期的時(shí)間。復(fù)位電壓值,每種單片機(jī)不完全一樣,我們按照通常值0.7VCC作為復(fù)位電壓值,復(fù)位時(shí)間的計(jì)算過程比較復(fù)雜,我這里只給大家一個(gè)結(jié)論,時(shí)間t=1.2RC,我們用的R是4700歐,C是0.0000001法,那么計(jì)算出t就是0.000564秒,即564us,遠(yuǎn)遠(yuǎn)大于2個(gè)機(jī)器周期(2us),在電路設(shè)計(jì)的時(shí)候一般留夠余量就行。

按鍵復(fù)位(即手動(dòng)復(fù)位)有2個(gè)過程,按下按鍵之前,RST的電壓是0V,當(dāng)按下按鍵后電路導(dǎo)通,同時(shí)電容也會(huì)在瞬間進(jìn)行放電,RST電壓值變化為4700VCC/(4700+18),會(huì)處于高電平復(fù)位狀態(tài)。當(dāng)松開按鍵后就和上電復(fù)位類似了,先是電容充電,后電流逐漸減小直到RST電壓變0V的過程。我們按下按鍵的時(shí)間通常都會(huì)有幾百毫秒,這個(gè)時(shí)間足夠復(fù)位了。按下按鍵的瞬間,電容兩端的5V電壓(注意不是電源的5V和GND之間)會(huì)被直接接通,此刻會(huì)有一個(gè)瞬間的大電流沖擊,會(huì)在局部范圍內(nèi)產(chǎn)生電磁干擾,為了抑制這個(gè)大電流所引起的干擾,我們這里在電容放電回路中串入一個(gè)18歐的電阻來限流。

如果有的同學(xué)已經(jīng)想開始DIY設(shè)計(jì)自己的電路板,那單片機(jī)最小系統(tǒng)的設(shè)計(jì)現(xiàn)在已經(jīng)有了足夠的理論依據(jù)了,可以考慮嘗試了?;A(chǔ)比較薄弱的同學(xué)先不要著急,繼續(xù)跟著往下學(xué),把課程都學(xué)完了再動(dòng)手操作也不遲,磨刀不誤砍柴工。

8.2 函數(shù)的調(diào)用

在一個(gè)程序的編寫過程中,隨著代碼量的增加,如果把所有的語句都寫到main函數(shù)中,一方面程序會(huì)顯得的比較亂,另外一個(gè)方面,當(dāng)同一個(gè)功能需要在不同地方執(zhí)行時(shí),我們就得再重復(fù)寫一遍相同的語句。此時(shí),如果把一些零碎的功能單獨(dú)寫成一個(gè)函數(shù),在需要它們時(shí)只需進(jìn)行一些簡(jiǎn)單的函數(shù)調(diào)用,這樣既有助于程序結(jié)構(gòu)的清晰條理,又可以避免大塊的代碼重復(fù)。

在實(shí)際工程項(xiàng)目中,一個(gè)程序通常都是由很多個(gè)子程序模塊組成的,一個(gè)模塊實(shí)現(xiàn)一個(gè)特定的功能,在C語言中,這個(gè)模塊就用函數(shù)來表示。一個(gè)C程序一般由一個(gè)主函數(shù)和若干個(gè)其他函數(shù)構(gòu)成。主函數(shù)可以調(diào)用其它函數(shù),其它函數(shù)也可以相互調(diào)用,但其它函數(shù)不能調(diào)用主函數(shù)。在我們的51單片機(jī)程序中,還有中斷服務(wù)函數(shù),是當(dāng)相應(yīng)的中斷到來后自動(dòng)調(diào)用的,不需要也不能由其它函數(shù)來調(diào)用。

函數(shù)調(diào)用的一般形式是:

函數(shù)名 (實(shí)參列表)

函數(shù)名就是需要調(diào)用的函數(shù)的名稱,實(shí)參列表就是根據(jù)實(shí)際需求調(diào)用函數(shù)要傳遞給被調(diào)用函數(shù)的參數(shù)列表,不需要傳遞參數(shù)時(shí)只保留括號(hào)就可以了,傳遞多個(gè)參數(shù)時(shí)參數(shù)之間要用逗號(hào)隔開。

那么我先舉例看一下函數(shù)調(diào)用使程序結(jié)構(gòu)更加條理清晰方面的作用。回顧一下圖6-1所示的程序流程圖和為實(shí)現(xiàn)它而編寫的程序代碼,相對(duì)來說這個(gè)主函數(shù)的結(jié)構(gòu)就比較復(fù)雜了,很難一眼看清楚它的執(zhí)行流程。那么如果我們把其中最重要的兩件事——秒計(jì)數(shù)和數(shù)碼管動(dòng)態(tài)掃描功能都用單獨(dú)的函數(shù)來實(shí)現(xiàn)會(huì)怎樣呢?來看程序。

圖片

圖片

圖片

圖片

看一下,主函數(shù)的結(jié)構(gòu)是不是清晰的多了——每隔1ms就去干兩件事,至于這兩件事是什么交由各自的函數(shù)去實(shí)現(xiàn)。還請(qǐng)大家注意一點(diǎn):原來程序中的i、cnt、sec這三個(gè)變量在放到單獨(dú)的函數(shù)中后,都加了static關(guān)鍵字而變成了靜態(tài)變量。因?yàn)樵瓉淼膍ain()永遠(yuǎn)不會(huì)結(jié)束所以它們的值也總是得到保持的,但現(xiàn)在它們?cè)诟髯缘墓δ芎瘮?shù)內(nèi),如不加static修飾那么每次函數(shù)被調(diào)用時(shí)它們的值就都成了初值了,借此也把靜態(tài)變量再加深一下理解吧。

當(dāng)然,這是我們刻意把程序功能做了這樣的劃分,主要目的還是來講解函數(shù)的調(diào)用,對(duì)于這個(gè)程序即使你不劃分函數(shù)也復(fù)雜不到哪里去,但繼續(xù)學(xué)下去你就能領(lǐng)會(huì)到劃分功能函數(shù)的必要了?,F(xiàn)在我們還是把注意力放在學(xué)習(xí)函數(shù)調(diào)用上,有以下幾點(diǎn)需要大家注意:

1、函數(shù)調(diào)用的時(shí)候,不需要加函數(shù)類型。我們?cè)谥骱瘮?shù)內(nèi)調(diào)用SecondCount()和LedRefresh()時(shí)都沒有加void。

2、調(diào)用函數(shù)與被調(diào)用函數(shù)的位置關(guān)系,C語言規(guī)定:函數(shù)在被調(diào)用之前,必須先被定義或聲明。意思就是說:在一個(gè)文件中,一個(gè)函數(shù)應(yīng)該先定義,然后才能被調(diào)用,也就是調(diào)用函數(shù)應(yīng)位于被調(diào)用函數(shù)的下方。但是作為一種通常的編程規(guī)范,我們推薦main函數(shù)寫在最前面(因?yàn)樗鸬教峋V挈領(lǐng)的作用),其后再定義各個(gè)功能函數(shù),而中斷函數(shù)則寫在文件的最后。那么主函數(shù)要調(diào)用定義在它之后的函數(shù)怎么辦呢?我們就在文件開頭,所有函數(shù)定義之前,開辟一塊區(qū)域,叫做函數(shù)聲明區(qū),用來把被調(diào)用的函數(shù)聲明一下,如此,該函數(shù)就可以被隨意調(diào)用了。如上述例程所示。

3、函數(shù)聲明的時(shí)候必須加函數(shù)類型,函數(shù)的形式參數(shù),最后加上一個(gè)分號(hào)表示結(jié)束。函數(shù)聲明行與函數(shù)定義行的唯一區(qū)別就是最后的分號(hào),其它的都必須保持一致。這點(diǎn)請(qǐng)尤其注意,初學(xué)者很容易因粗心大意而搞錯(cuò)分號(hào)或是修改了定義行中的形參卻忘了修改聲明行中的形參,導(dǎo)致程序編譯不過。

8.3 函數(shù)的形式參數(shù)和實(shí)際參數(shù)

上一個(gè)例程中在進(jìn)行函數(shù)調(diào)用的時(shí)候,不需要任何參數(shù)傳遞,所以函數(shù)定義和調(diào)用時(shí)括號(hào)內(nèi)都是空的,但是更多的時(shí)候我們需要在主調(diào)函數(shù)和被調(diào)用函數(shù)之間傳遞參數(shù)。在調(diào)用一個(gè)有參數(shù)的函數(shù)時(shí),函數(shù)名后邊括號(hào)中的參數(shù)叫做實(shí)際參數(shù),簡(jiǎn)稱實(shí)參。而被調(diào)用的函數(shù)在進(jìn)行定義時(shí),括號(hào)里的參數(shù)叫做形式參數(shù),簡(jiǎn)稱形參。我們用個(gè)簡(jiǎn)單程序例子做說明。

圖片

這個(gè)演示程序雖然很簡(jiǎn)單,但是函數(shù)調(diào)用的全部?jī)?nèi)容都囊括在內(nèi)了。主調(diào)函數(shù)main和被調(diào)用函數(shù)add之間的數(shù)據(jù)通過形參和實(shí)參發(fā)生了傳遞關(guān)系,而函數(shù)運(yùn)算完后把值傳遞給了變量c,函數(shù)只要不是void類型,就都會(huì)有返回值,返回值類型就是函數(shù)的類型。關(guān)于形參和實(shí)參,還有以下幾點(diǎn)需要注意。

1、函數(shù)定義中指定的形參,在未發(fā)生函數(shù)調(diào)用時(shí)不占內(nèi)存,只有函數(shù)調(diào)用時(shí),函數(shù)add中的形參才被分配內(nèi)存單元。在調(diào)用結(jié)束后,形參所占的內(nèi)存單元也被釋放,這個(gè)前邊講過了,形參是局部變量。

2、實(shí)參可以是常量,也可以是簡(jiǎn)單或者復(fù)雜的表達(dá)式,但是要求他們必須有確定的值,在調(diào)用發(fā)生時(shí)將實(shí)參的值傳遞給形參。如上邊這個(gè)程序也可以寫成:c = add(1, a+b);

3、形參必須要指定數(shù)據(jù)類型,和定義變量一樣,因?yàn)樗緛砭褪蔷植孔兞俊?/p>

4、實(shí)參和形參的數(shù)據(jù)類型應(yīng)該相同或者賦值兼容。和變量賦值一樣,當(dāng)形參和實(shí)參出現(xiàn)不同類型時(shí),則按照不同類型數(shù)值的賦值規(guī)則進(jìn)行轉(zhuǎn)換。

5、主調(diào)函數(shù)在調(diào)用函數(shù)之前,應(yīng)對(duì)被調(diào)函數(shù)做原型聲明。

6、實(shí)參向形參的數(shù)據(jù)傳遞是單向傳遞,不能由形參再回傳給實(shí)參。也就是說,實(shí)參值傳遞給形參后,調(diào)用結(jié)束,形參單元被釋放,而實(shí)參單元仍保留并且維持原值。

8.4 按鍵

8.4.1 獨(dú)立按鍵

常用的按鍵電路有兩種形式,獨(dú)立式按鍵和矩陣式按鍵,獨(dú)立式按鍵比較簡(jiǎn)單,它們各自與獨(dú)立的輸入線相連接,如圖8-6所示。

圖片

圖8-6 獨(dú)立式按鍵原理圖

4條輸入線接到單片機(jī)的IO口上,當(dāng)按鍵K1按下時(shí),+5V通過電阻R1然后再通過按鍵K1最終進(jìn)入GND形成一條通路,那么這條線路的全部電壓都加到了R1這個(gè)電阻上,KeyIn1這個(gè)引腳就是個(gè)低電平。當(dāng)松開按鍵后,線路斷開,就不會(huì)有電流通過,那么KeyIn1和+5V就應(yīng)該是等電位,是一個(gè)高電平。我們就可以通過KeyIn1這個(gè)IO口的高低電平來判斷是否有按鍵按下。

這個(gè)電路中按鍵的原理我們清楚了,但是實(shí)際上在我們的單片機(jī)IO口內(nèi)部,也有一個(gè)上拉電阻的存在。我們的按鍵是接到了P2口上,P2口上電默認(rèn)是準(zhǔn)雙向IO口,我們來簡(jiǎn)單了解一下這個(gè)準(zhǔn)雙向IO口的電路,如圖8-7所示。

圖片

圖8-7 準(zhǔn)雙向IO口結(jié)構(gòu)圖

首先說明一點(diǎn),就是我們現(xiàn)在絕大多數(shù)單片機(jī)的IO口都是使用MOS管而非三極管,但用在這里的MOS管其原理和三極管是一樣的,因此在這里我用三極管替代它來進(jìn)行原理講解,把前面講過的三極管的知識(shí)搬過來,一切都是適用的,有助于理解。

圖8-7方框內(nèi)的電路都是指單片機(jī)內(nèi)部部分,方框外的就是我們外接的上拉電阻和按鍵。這個(gè)地方大家要注意一下,就是當(dāng)我們要讀取外部按鍵信號(hào)的時(shí)候,單片機(jī)必須先給該引腳寫“1”,也就是高電平,這樣我們才能正確讀取到外部按鍵信號(hào),我們來分析一下緣由。

當(dāng)內(nèi)部輸出是高電平,經(jīng)過一個(gè)反向器變成低電平,NPN三極管不會(huì)導(dǎo)通,那么單片機(jī)IO口從內(nèi)部來看,由于上拉電阻R的存在,所以是一個(gè)高電平。當(dāng)外部沒有按鍵按下將電平拉低的話,VCC也是+5V,它們之間雖然有2個(gè)電阻,但是沒有壓差,就不會(huì)有電流,線上所有的位置都是高電平,這個(gè)時(shí)候我們就可以正常讀取到按鍵的狀態(tài)了。

當(dāng)內(nèi)部輸出是個(gè)低電平,經(jīng)過一個(gè)反相器變成高電平,NPN三極管導(dǎo)通,那么單片機(jī)的內(nèi)部IO口就是個(gè)低電平,這個(gè)時(shí)候,外部雖然也有上拉電阻的存在,但是兩個(gè)電阻是并聯(lián)關(guān)系,不管按鍵是否按下,單片機(jī)的IO口上輸入到單片機(jī)內(nèi)部的狀態(tài)都是低電平,我們就無法正常讀取到按鍵的狀態(tài)了。

這個(gè)和水流其實(shí)很類似的,內(nèi)部和外部,只要有一邊是低電位,那么電流就會(huì)順流而下,由于只有上拉電阻,下邊沒有電阻分壓,直接到GND上了,所以不管另外一邊是高還是低,那電平肯定就是低電平了。

從上面的分析就可以得出一個(gè)結(jié)論,這種具有上拉的準(zhǔn)雙向IO口,如果要正常讀取外部信號(hào)的狀態(tài),必須首先得保證自己內(nèi)部輸出的是1,如果內(nèi)部輸出0,則無論外部信號(hào)是1還是0,這個(gè)引腳讀進(jìn)來的都是0。

8.4.2 矩陣按鍵

在某一個(gè)系統(tǒng)設(shè)計(jì)中,如果需要使用很多的按鍵時(shí),做成獨(dú)立按鍵會(huì)大量占用IO口,因此我們引入了矩陣按鍵的設(shè)計(jì)。如圖8-8所示,是我們的KST-51開發(fā)板上的矩陣按鍵電路原理圖,使用8個(gè)IO口來實(shí)現(xiàn)了16個(gè)按鍵。

圖片

圖8-8 矩陣按鍵原理圖

如果獨(dú)立按鍵理解了,矩陣按鍵也不難理解,那么我們一起來分析一下。圖8-8中,一共有4組按鍵,我們只看其中一組,如圖8-9所示。大家認(rèn)真看一下,如果KeyOut1輸出一個(gè)低電平,KeyOut1就相當(dāng)于是GND,是否相當(dāng)于4個(gè)獨(dú)立按鍵呢。當(dāng)然這時(shí)候KeyOut2、KeyOut3、KeyOut4都必須輸出高電平,它們都輸出高電平才能保證與它們相連的三路按鍵不會(huì)對(duì)這一路產(chǎn)生干擾,大家可以對(duì)照兩張?jiān)韴D分析一下。

圖片

圖8-9 矩陣按鍵變獨(dú)立按鍵示意圖

8.4.3 獨(dú)立按鍵的掃描

原理搞清楚了,那么下面我們就先編寫一個(gè)獨(dú)立按鍵的程序,把最基本的功能驗(yàn)證一下。

圖片

圖片

本程序固定在KeyOut1上輸出低電平,而KeyOut2~4保持高電平,就相當(dāng)于是把矩陣按鍵的第一行,即K1~K4作為4個(gè)獨(dú)立按鍵來處理,然后把這4個(gè)按鍵的狀態(tài)直接送給LED9~6這4個(gè)LED小燈,那么當(dāng)按鍵按下時(shí),對(duì)應(yīng)按鍵的輸入引腳是0,對(duì)應(yīng)小燈控制信號(hào)也是0,于是燈就亮了,這說明上述關(guān)于按鍵檢測(cè)的理論都是可實(shí)現(xiàn)的。

絕大多數(shù)情況下,按鍵是不會(huì)一直按住的,所以我們通常檢測(cè)按鍵的動(dòng)作并不是檢測(cè)一個(gè)固定的電平值,而是檢測(cè)電平值的變化,即按鍵在按下和彈起這兩種狀態(tài)之間的變化,只要發(fā)生了這種變化就說明現(xiàn)在按鍵產(chǎn)生動(dòng)作了。

程序上,我們可以把每次掃描到的按鍵狀態(tài)都保存起來,當(dāng)一次按鍵狀態(tài)掃描進(jìn)來的時(shí)候,與前一次的狀態(tài)做比較,如果發(fā)現(xiàn)這兩次按鍵狀態(tài)不一致,就說明按鍵產(chǎn)生動(dòng)作了。當(dāng)上一次的狀態(tài)是未按下而現(xiàn)在是按下,此時(shí)按鍵的動(dòng)作就是“按下”;當(dāng)上一次的狀態(tài)是按下而現(xiàn)在是未按下,此時(shí)按鍵的動(dòng)作就是“彈起”。顯然,每次按鍵動(dòng)作都會(huì)包含一次“按下”和一次“彈起”,我們可以任選其一來執(zhí)行程序,或者兩個(gè)都用,以執(zhí)行不同的程序也是可以的。下面就用程序來實(shí)現(xiàn)這個(gè)功能,程序只取按鍵K4為例。

圖片

圖片

圖片

先來介紹出現(xiàn)在程序中的一個(gè)新知識(shí)點(diǎn),就是變量類型——bit,這個(gè)在標(biāo)準(zhǔn)C語言里邊是沒有的。51單片機(jī)有一種特殊的變量類型就是bit型。比如unsigned char型是定義了一個(gè)無符號(hào)的8位的數(shù)據(jù),它占用一個(gè)字節(jié)(Byte)的內(nèi)存,而bit型是1位數(shù)據(jù),只占用1個(gè)位(bit)的內(nèi)存,用法和標(biāo)準(zhǔn)C中其他的基本數(shù)據(jù)類型是一致的。它的優(yōu)點(diǎn)就是節(jié)省內(nèi)存空間,8個(gè)bit型變量才相當(dāng)于1個(gè)char型變量所占用的空間。雖然它只有0和1兩個(gè)值,但也已經(jīng)可以表示很多東西了,比如:按鍵的按下和彈起、LED燈的亮和滅、三極管的導(dǎo)通與關(guān)斷等等,聯(lián)想一下已經(jīng)學(xué)過的內(nèi)容,它是不是能用最小的內(nèi)存代價(jià)來完成很多工作呢?

在這個(gè)程序中,我們以K4為例,按一次按鍵,就會(huì)產(chǎn)生“按下”和“彈起”兩個(gè)動(dòng)態(tài)的動(dòng)作,我們選擇在“彈起”時(shí)對(duì)數(shù)碼管進(jìn)行加1操作。理論是如此,大家可以在板子上用K4按鍵做做實(shí)驗(yàn)試試,多按幾次,是不是會(huì)發(fā)生這樣一種現(xiàn)象:有的時(shí)候我明明只按了一下按鍵,但數(shù)字卻加了不止1,而是2或者更多?但是我們的程序并沒有任何邏輯上的錯(cuò)誤,這是怎么回事呢?于是我們就得來說說按鍵抖動(dòng)和消抖的問題了。

8.4.4 按鍵消抖

通常按鍵所用的開關(guān)都是機(jī)械彈性開關(guān),當(dāng)機(jī)械觸點(diǎn)斷開、閉合時(shí),由于機(jī)械觸點(diǎn)的彈性作用,一個(gè)按鍵開關(guān)在閉合時(shí)不會(huì)馬上就穩(wěn)定的接通,在斷開時(shí)也不會(huì)一下子徹底斷開,而是在閉合和斷開的瞬間伴隨了一連串的抖動(dòng),如圖8-10所示。

圖片

圖8-10 按鍵抖動(dòng)狀態(tài)圖

按鍵穩(wěn)定閉合時(shí)間長(zhǎng)短是由操作人員決定的,通常都會(huì)在100ms以上,刻意快速按的話能達(dá)到40-50ms左右,很難再低了。抖動(dòng)時(shí)間是由按鍵的機(jī)械特性決定的,一般都會(huì)在10ms以內(nèi),為了確保程序?qū)Π存I的一次閉合或者一次斷開只響應(yīng)一次,必須進(jìn)行按鍵的消抖處理。當(dāng)檢測(cè)到按鍵狀態(tài)變化時(shí),不是立即去響應(yīng)動(dòng)作,而是先等待閉合或斷開穩(wěn)定后再進(jìn)行處理。按鍵消抖可分為硬件消抖和軟件消抖。

硬件消抖就是在按鍵上并聯(lián)一個(gè)電容,如圖8-11所示,利用電容的充放電特性來對(duì)抖動(dòng)過程中產(chǎn)生的電壓毛刺進(jìn)行平滑處理,從而實(shí)現(xiàn)消抖。但實(shí)際應(yīng)用中,這種方式的效果往往不是很好,而且還增加了成本和電路復(fù)雜度,所以實(shí)際中使用的并不多。

圖片

圖8-11 硬件電容消抖

在絕大多數(shù)情況下,我們是用軟件即程序來實(shí)現(xiàn)消抖的。最簡(jiǎn)單的消抖原理,就是當(dāng)檢測(cè)到按鍵狀態(tài)變化后,先等待一個(gè)10ms左右的延時(shí)時(shí)間,讓抖動(dòng)消失后再進(jìn)行一次按鍵狀態(tài)檢測(cè),如果與剛才檢測(cè)到的狀態(tài)相同,就可以確認(rèn)按鍵已經(jīng)穩(wěn)定的動(dòng)作了。將上一個(gè)的程序稍加改動(dòng),得到新的帶消抖功能的程序如下。

圖片

圖片圖片

大家把這個(gè)程序下載到板子上再進(jìn)行試驗(yàn)試試,按一下按鍵而數(shù)字加了多次的問題是不是就這樣解決了?把問題解決掉的感覺是不是很爽呢?

這個(gè)程序用了一個(gè)簡(jiǎn)單的算法實(shí)現(xiàn)了按鍵的消抖。作為這種很簡(jiǎn)單的演示程序,我們可以這樣來寫,但是實(shí)際做項(xiàng)目開發(fā)的時(shí)候,程序量往往很大,各種狀態(tài)值也很多,while(1)這個(gè)主循環(huán)要不停的掃描各種狀態(tài)值是否有發(fā)生變化,及時(shí)的進(jìn)行任務(wù)調(diào)度,如果程序中間加了這種delay延時(shí)操作后,很可能某一事件發(fā)生了,但是我們程序還在進(jìn)行delay延時(shí)操作中,當(dāng)這個(gè)事件發(fā)生完了,程序還在delay操作中,當(dāng)我們delay完事再去檢查的時(shí)候,已經(jīng)晚了,已經(jīng)檢測(cè)不到那個(gè)事件了。為了避免這種情況的發(fā)生,我們要盡量縮短while(1)循環(huán)一次所用的時(shí)間,而需要進(jìn)行長(zhǎng)時(shí)間延時(shí)的操作,必須想其它的辦法來處理。

那么消抖操作所需要的延時(shí)該怎么處理呢?其實(shí)除了這種簡(jiǎn)單的延時(shí),我們還有更優(yōu)異的方法來處理按鍵抖動(dòng)問題。舉個(gè)例子:我們啟用一個(gè)定時(shí)中斷,每2ms進(jìn)一次中斷,掃描一次按鍵狀態(tài)并且存儲(chǔ)起來,連續(xù)掃描8次后,看看這連續(xù)8次的按鍵狀態(tài)是否是一致的。8次按鍵的時(shí)間大概是16ms,這16ms內(nèi)如果按鍵狀態(tài)一直保持一致,那就可以確定現(xiàn)在按鍵處于穩(wěn)定的階段,而非處于抖動(dòng)的階段,如圖8-12。

圖片

圖8-12 按鍵連續(xù)掃描判斷

假如左邊時(shí)間是起始0時(shí)刻,每經(jīng)過2ms左移一次,每移動(dòng)一次,判斷當(dāng)前連續(xù)的8次按鍵狀態(tài)是不是全1或者全0,如果是全1則判定為彈起,如果是全0則判定為按下,如果0和1交錯(cuò),就認(rèn)為是抖動(dòng),不做任何判定。想一下,這樣是不是比簡(jiǎn)單的延時(shí)更加可靠?

利用這種方法,就可以避免通過延時(shí)消抖占用單片機(jī)執(zhí)行時(shí)間,而是轉(zhuǎn)化成了一種按鍵狀態(tài)判定而非按鍵過程判定,我們只對(duì)當(dāng)前按鍵的連續(xù)16ms的8次狀態(tài)進(jìn)行判斷,而不再關(guān)心它在這16ms內(nèi)都做了什么事情,那么下面就按照這種思路用程序?qū)崿F(xiàn)出來,同樣只以K4為例。

圖片

圖片

圖片

圖片

這個(gè)算法是我們?cè)趯?shí)際工程中經(jīng)常使用按鍵所總結(jié)的一個(gè)比較好的方法,介紹給大家,今后都可以用這種方法消抖了。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 單片機(jī)
    +關(guān)注

    關(guān)注

    6043

    文章

    44623

    瀏覽量

    638763
  • 振蕩器
    +關(guān)注

    關(guān)注

    28

    文章

    3854

    瀏覽量

    139385
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7614

    瀏覽量

    137775
  • STC89C52RC
    +關(guān)注

    關(guān)注

    15

    文章

    64

    瀏覽量

    38679
  • GND
    GND
    +關(guān)注

    關(guān)注

    2

    文章

    540

    瀏覽量

    38910
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    開發(fā)第1個(gè)LVGL程序與實(shí)現(xiàn)按鍵操作

    開發(fā)第1個(gè)LVGL程序與實(shí)現(xiàn)按鍵操作
    的頭像 發(fā)表于 01-07 13:49 ?804次閱讀
    開發(fā)第<b class='flag-5'>1</b>個(gè)LVGL程序與實(shí)現(xiàn)<b class='flag-5'>按鍵</b>操作

    【RA-Eco-RA4E2-64PIN-V1.0開發(fā)板試用】使用按鍵SW1實(shí)現(xiàn)單擊,雙擊,長(zhǎng)按等多種按鍵功能

    ;lt;stdbool.h> #include \"multi_button.h\" 以下是按鍵處理函數(shù) void BTN1
    發(fā)表于 12-17 22:17

    SUMIF函數(shù)與SUMIFS函數(shù)的區(qū)別

    1. 函數(shù)定義 SUMIF函數(shù) :用于對(duì)滿足單一條件的單元格求和。其基本語法為 SUMIF(range, criteria, [sum_range]) ,其中: range :應(yīng)用條件的區(qū)域
    的頭像 發(fā)表于 10-30 09:51 ?1615次閱讀

    電容式觸摸按鍵按鍵擴(kuò)展方法

    電子發(fā)燒友網(wǎng)站提供《電容式觸摸按鍵按鍵擴(kuò)展方法.pdf》資料免費(fèi)下載
    發(fā)表于 09-27 11:43 ?0次下載
    電容式觸摸<b class='flag-5'>按鍵</b>的<b class='flag-5'>按鍵</b>擴(kuò)展方法

    面試???1函數(shù)指針與指針函數(shù)、數(shù)組指針與指針數(shù)組

    在嵌入式開發(fā)領(lǐng)域,函數(shù)指針、指針函數(shù)、數(shù)組指針和指針數(shù)組是一些非常重要但又容易混淆的概念。理解它們的特性和應(yīng)用場(chǎng)景,對(duì)于提升嵌入式程序的效率和質(zhì)量至關(guān)重要。一、指針函數(shù)函數(shù)指針指針
    的頭像 發(fā)表于 08-10 08:11 ?996次閱讀
    面試常考+<b class='flag-5'>1</b>:<b class='flag-5'>函數(shù)</b>指針與指針<b class='flag-5'>函數(shù)</b>、數(shù)組指針與指針數(shù)組

    函數(shù)信號(hào)發(fā)生器的各類按鍵

    發(fā)生器的功能,了解其按鍵的功能和使用方法至關(guān)重要。本文將詳細(xì)介紹函數(shù)信號(hào)發(fā)生器的各類按鍵,旨在為讀者提供全面而深入的了解。
    的頭像 發(fā)表于 05-30 16:05 ?1305次閱讀

    使用系統(tǒng)滴答定時(shí)中斷,基于按鍵的狀態(tài)機(jī)怎么只能1個(gè)1個(gè)+,不能連+?

    使用系統(tǒng)滴答定時(shí)中斷,基于按鍵的狀態(tài)機(jī)怎么只能1個(gè)1個(gè)+,不能連+ #define KEY1_USERGPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13
    發(fā)表于 05-16 06:27

    函數(shù)信號(hào)發(fā)生器按鍵介紹

    函數(shù)信號(hào)發(fā)生器是電子測(cè)試領(lǐng)域中不可或缺的重要工具,它能夠模擬產(chǎn)生各種波形信號(hào),如正弦波、方波、三角波等,廣泛應(yīng)用于電路測(cè)試、信號(hào)模擬、科學(xué)研究等多個(gè)領(lǐng)域。函數(shù)信號(hào)發(fā)生器的按鍵設(shè)計(jì)是其功能實(shí)現(xiàn)的重要組成部分,本文將對(duì)
    的頭像 發(fā)表于 05-15 16:14 ?2137次閱讀

    PHP用戶定義函數(shù)詳細(xì)講解

    描述 在所有編程和腳本語言中,函數(shù)是可以在程序中重復(fù)使用的語句塊。在 PHP 中,函數(shù)的概念與另一種語言(如“C”)中的概念相同。標(biāo)準(zhǔn) PHP 發(fā)行版中有 1,000 多個(gè)內(nèi)置函數(shù)。除
    的頭像 發(fā)表于 03-20 14:27 ?451次閱讀

    回調(diào)函數(shù)(callback)是什么?回調(diào)函數(shù)的實(shí)現(xiàn)方法

    回調(diào)函數(shù)是一種特殊的函數(shù),它作為參數(shù)傳遞給另一個(gè)函數(shù),并在被調(diào)用函數(shù)執(zhí)行完畢后被調(diào)用?;卣{(diào)函數(shù)通常用于事件處理、異步編程和處理各種操作系統(tǒng)和
    發(fā)表于 03-12 11:46 ?3161次閱讀

    ELF 1技術(shù)貼|在NXP源碼基礎(chǔ)上適配開發(fā)板的按鍵功能

    至ELF1開發(fā)板。接下來,我們將詳細(xì)闡述適配過程中關(guān)于按鍵功能實(shí)現(xiàn)的完整步驟。值得一提的是,ELF1開發(fā)板上預(yù)置了標(biāo)識(shí)為K1、K2、K3的三個(gè)按鍵
    的頭像 發(fā)表于 03-08 16:58 ?1011次閱讀
    ELF <b class='flag-5'>1</b>技術(shù)貼|在NXP源碼基礎(chǔ)上適配開發(fā)板的<b class='flag-5'>按鍵</b>功能

    函數(shù)指針與回調(diào)函數(shù)的應(yīng)用實(shí)例

    通常我們說的指針變量是指向一個(gè)整型、字符型或數(shù)組等變量,而函數(shù)指針是指向函數(shù)。 函數(shù)指針可以像一般函數(shù)一樣,用于調(diào)用函數(shù)、傳遞參數(shù)。
    的頭像 發(fā)表于 03-07 11:13 ?440次閱讀
    <b class='flag-5'>函數(shù)</b>指針與回調(diào)<b class='flag-5'>函數(shù)</b>的應(yīng)用實(shí)例

    CY8C4025用到了觸摸按鍵,在初始化時(shí)調(diào)用了以下函數(shù),請(qǐng)問這三個(gè)函數(shù)運(yùn)行時(shí)間是不固定的嗎?

    CY8C4025用到了觸摸按鍵,在初始化時(shí)調(diào)用了以下函數(shù),請(qǐng)問這三個(gè)函數(shù)運(yùn)行時(shí)間是不固定的嗎?在一個(gè)項(xiàng)目中發(fā)現(xiàn)不同的板子運(yùn)行時(shí)間不同,同一個(gè)板子也有可能是不同的,例如上電的時(shí)候按著按鍵
    發(fā)表于 02-21 07:17

    RK3568驅(qū)動(dòng)指南|驅(qū)動(dòng)基礎(chǔ)進(jìn)階篇-進(jìn)階5 自定義實(shí)現(xiàn)insmod命令實(shí)驗(yàn)

    RK3568驅(qū)動(dòng)指南|驅(qū)動(dòng)基礎(chǔ)進(jìn)階篇-進(jìn)階5 自定義實(shí)現(xiàn)insmod命令實(shí)驗(yàn)
    的頭像 發(fā)表于 02-20 14:10 ?787次閱讀
    RK3568驅(qū)動(dòng)指南|驅(qū)動(dòng)基礎(chǔ)<b class='flag-5'>進(jìn)階</b>篇-<b class='flag-5'>進(jìn)階</b>5 自定義實(shí)現(xiàn)insmod命令實(shí)驗(yàn)

    為什么要進(jìn)行按鍵消抖?按鍵抖動(dòng)的原理 按鍵消抖的方法

    按鍵消抖通常的按鍵所用開關(guān)為機(jī)械彈性開關(guān),當(dāng)機(jī)械觸點(diǎn)斷開、閉合時(shí),由于機(jī)械觸點(diǎn)的彈性作用,一個(gè)按鍵開關(guān)在閉合時(shí)不會(huì)馬上穩(wěn)定地接通,在斷開時(shí)也不會(huì)一下子斷開。
    的頭像 發(fā)表于 02-17 17:07 ?1.9w次閱讀
    為什么要進(jìn)行<b class='flag-5'>按鍵</b>消抖?<b class='flag-5'>按鍵</b>抖動(dòng)的原理 <b class='flag-5'>按鍵</b>消抖的方法