<acronym id="xonnx"></acronym>
      <td id="xonnx"></td>
    1. <pre id="xonnx"></pre>

      1. 專注電子技術學習與研究
        當前位置:單片機教程網 >> MCU設計實例 >> 瀏覽文章

        AVR單片機學習(五)按鍵與數碼管的程序設計

        作者:zww 1988   來源:本站原創   點擊數:  更新時間:2014年04月18日   【字體:
        按鍵與數碼管的程序設計
      2. AVR  IO口的輸入模式與上拉電阻
      3. 選擇結構語句與按鍵的查詢方式程序設計
      4. 數碼管基本原理
      5. 掃描方式顯示多位數碼管
      6. 一、輸入狀態IO寄存器設置

          1、DDRx 某一位置0,相應位的IO口被設置為輸入

           2、PORTx某一位置1,使能對應IO口相應位的上拉電阻

          3、PINx的對應位是輸入的數據,0或1

         
        選擇結構語句

        一、關系運算符和關系表達式

        小于< 小于等于<= 大于> 大于或等于== 不等于!=

        二、邏輯運算符和邏輯表達式

        邏輯與&&邏輯或||邏輯非!

        三、if 語句結構

        if(表達式1)語句1

        else if(表達式2)語句2

        else 語句3

        四、switch 語句結構

        switch(表達式)

        {case 常量1:表達式1

        case 常量2:表達式2

        .........

        default:表達式n}


        按鍵的查詢方式程序設計

        一、PIND & (1<<6)

        二、1<<6

        1、1左移6位,即:0b01000000

        怎么判斷一個按鍵按下了呢?首先看下圖是4個按鍵

         



         






        第一個是PD2 上一段接VCC  其他都是一段接IO(PD3  PD6 PD7)口另一端接地線。

        所以當按鍵閉合時候相應IO都輸入一個0,當按鍵抬起來的時候IO輸入多少呢?

        所以這些IO口必須將上拉電阻進行使能,將按鍵打開相當于輸入一個1.所以我們判斷這3個按鍵按沒按下去的話,就判斷輸入是不是0就行了。

        對于第一個按鍵如果按下輸入是1,當抬起來時候由于AVR內部不帶下拉電阻的,所以按鍵打開時候輸入是0.

        所以就需要判斷某一位是0,還是1.某一位是0還是1就用到了& 與運算了。 1 跟1 與就1  1 與0 就是0

        上面代碼(temp& (1<<6))  (temp & 0b01000000) temp本身值不變,只是結果來判斷某一位是0還是1

        比如:PD6 上的K3    因為PD6   所以 PIND &(1<<6)的結果就行了 

        三、PIND & (1<<6)

        1、移除第6位之外其他位清零

        2、第6位保持輸入的值

        四、與選擇結構語句的結合

        1、判斷PIND & (1<<6)的值,執行相應代碼

         

         除非你上電之前一直講按鍵按下,否則上電的一瞬間程序就執行到while(1);了所以要將他們加入到死循環里面如下圖


        這樣就實現了按鍵的不停的檢測。 其實DDRD 上電默認都是0  所以清0  置為輸入也沒有意義。

        程序在if判斷設置斷點然后全速執行可以看到只要沒有按鍵按下程序進不去斷點,如果我們在板子上按下K3則如下圖所示進入斷點,再按下單步執行蜂鳴器響了如圖。



        所以這個程序就達到了我們的目的。

        現在換一種判斷 就是按鍵被按下而不是沒被按下 用邏輯非


        這樣達到了預想的目標。但是這樣只能判斷一個按鍵如果多個按鍵怎么辦呢?2種辦法 

        一、采用if elseif else

        if (){

            elseif{

            }

            elseif {

            }

            else{

         

            }

        }

        二、采用

        switch (表達式){

        case  相符合的條件  {

            break;

        }

        case 相符合的條件 {

            break;

        }

        default{

         

        }

        }

        一、用if 實現

        #include
        int main(void){
         //PD6 設置為輸入  K3
         DDRD &= ~(1 << 6);
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<6);
         //PD7 設置為輸入  K4
         DDRD &= ~(1 << 7); 
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<7);
         //PD2 設置為輸入  K1
         DDRD &= ~(1 << 2); 
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<2);//這個上拉不上拉沒關系因為上拉是百K的電阻所以開關打開還是認為是低電平
         //PD3 設置為輸入  K2
         DDRD &= ~(1 << 3); 
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<3);

         //蜂鳴器PA3 設置方向寄存器為輸出
         DDRA |= (1<<3);
         //蜂鳴器關掉
         PORTA &= ~(1<<3);
         //流水燈端口全部設為輸出
         DDRB = 0xff;
          while(1){
          //判斷PIND 這位是否為1 為真的話就是按鍵沒有按下
          if (!(PIND & (1<<6))){ //本來沒有按下 進入 現在變成了沒有按下 不進入了取非了  被按下進入了 PD6
           //按鍵被按下用蜂鳴器表示一下 PA3
            PORTA |= (1<<3);
          }
          else if(!(PIND & (1<<7))){ //PD7  K4按下讓流水燈產生動作   必須上面使能K4上拉電阻
           PORTB |= (1<<0);//第一個燈發光 就是等于1
          }
          else if (PIND & (1<<2)){//因為按下的時候是低電平接的是電源
           //第二個燈發光
           PORTB |= (1<<1);
          }
          else if (!(PIND & (1<<3))){
           //第三個燈發光
           PORTB |= (1<<2);
          }
          else{
           //變成了按鍵沒有按下 
             PORTA &= ~(1<<3); //蜂鳴器
           PORTB = 0;//燈
          }
          //看到沒有按下一直響的,按下就不響了。
         }
        }

        ---------------------------------------------------------------

        二、用switch 來實現就需要一次性將這四位讀回來。 代碼如下

        #include
        int main(void){
         //PD6 設置為輸入  K3
         DDRD &= ~(1 << 6);
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<6);
         //PD7 設置為輸入  K4
         DDRD &= ~(1 << 7); 
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<7);
         //PD2 設置為輸入  K1
         DDRD &= ~(1 << 2); 
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<2);//這個上拉不上拉沒關系因為上拉是百K的電阻所以開關打開還是認為是低電平
         //PD3 設置為輸入  K2
         DDRD &= ~(1 << 3); 
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<3);
         //蜂鳴器PA3 設置方向寄存器為輸出
         DDRA |= (1<<3);
         //蜂鳴器關掉
         PORTA &= ~(1<<3);
         //流水燈端口全部設為輸出
         DDRB = 0xff;
          while(1){
           //首先一次性將這4個位都讀回來   2 3 6 7 腳
           switch(PIND & 0b11001100) {
            case 0b11001100: {//只有第一個按鍵按下 0b11001100  接的電源按下是1
             //LED 0 發光
             PORTB |= (1<<0);
             break;
            }
            case 0b11000000: {//只有第 二個按鍵按下 0b11001100  接的電源抬起是0
             //LED 0 發光
             PORTB |= (1<<1);
             break;
            }
            case 0b10001100: {//只有第三個按鍵按下 0b11001100  接的電源抬起是0
             //LED 0
             PORTB |= (1<<2);
             break;
            }
            case 0b01001100: {//只有第四個按鍵按下 0b11001100  接的電源抬起是0
             //LED 0 發光
             PORTB |= (1<<3);
             break;
            }
            default :{   //都沒有按下 0b11001000  因為有下拉
             //變成了按鍵沒有按下 
               PORTA &= ~(1<<3); //蜂鳴器
               PORTB = 0;//燈

               break;
            }
           }
          
           //判斷PIND 這位是否為1 為真的話就是按鍵沒有按下
          
         }
        }

        -------------------------------------------------------------------------

        以上都是查詢方式因為都是在while循環一邊一邊的查詢,按鍵有動作就執行相應的代碼這樣很耽誤CPU的時間的,在下一篇博客我會稍微降講用中斷的方式來編寫按鍵的程序。下面繼續說呵呵、

        八段數碼管 

        一、八段數碼管

        1、八段數碼管由八段LED構成

        2、各LED陰極或陽極并在一起,稱為“位選線”:共陰、共陽

        3、其余8個引腳各自引出,稱為“段選線”,各段可以分別控制




        記住一般一位的數碼管有10個腳

        個人理解:( 其中2腳是連在一起的是公共端。其他8個是段選  比如1、6接電源 其他接IO口個人理解的)

        多位合一的數碼管

        一、多位合一的數碼管

        1、將多個八段數碼管的段選線分別并在一起,位選線引出如下圖



        由上圖看出是4位 應該是8個段選線(7段加一個點)  4個位選線  共12根線  。

        com0 ---- com3 是位選 

        a-g 加 dp   是段選。

        多位數碼管的使用

        1、多位數碼管的各個位均可以單獨顯示不同的數據,但一個時刻只能點亮一位、(點快點人眼看不出來)

        2、依次點亮多位數碼管中的各個位,由于人眼的視覺暫留效應,看起來是同時點亮

        3、如下圖是電路圖 硬件電路是下圖設計的

         




        它的每一段相當于一個發光二極管,電流大約是10個mA左右(5--10)mA,因此段選可以直接用單片機的IO驅動是足夠的不論是拉電流還是灌電流,這里面我們用的是一個共陰極的數碼管,因此應該是向外拉電流,而段選線我們可以計算下段選線上最大電流時多少?假設每段都點亮沒段是10mA的話,那么位選線上也就是10*8 = 80mA 所以我們不能用IO口,一般的單片機不可能輸出這么大的電流,所以我采用一個三極管來進行驅動,共陰極的數碼管一般要用NPN型的數碼管,它的接法如下圖的樣子。


        再來張清楚點的下圖


        可以看到C0 接的是COM0 位選線,IO口通過1K電阻接到三極管基極上,如果IO是個高電平的話電流就通過三極管到射極流下來的,因此三極管達到飽和,CO點相當于導通相當于接地。4個段選分別接到PA4到PA7 四個IO口上因此我們寫程序首先將PA4 輸出一個1 PA5 PA6 PA7 全都輸出0 這樣我們選中第0個第一位數碼管此時在PB口上輸出的數據就會顯示在數碼管上面。編寫程序:

         



        設置一個斷點然后再單步調試(F10)?纯此@示的是那一段。同時流水燈也亮了,因為是同一個IO口。這樣對應PB上的每一段都找到了。

        好了這樣我們就去編寫一下數碼管的段碼;

        首先是顯示1   只要將需要點亮的各個段置1就實現了段碼的功能,具體的編寫過程自己去畫畫看



        這是我自己用數組的形式定義的。

        首先是什么類型的數組  名稱  元素個數

        0-9

        A-F

        全部顯示出來就是16個元素,一個字符型數 加一個逗號分開。一直放16個,使用時候要從第0個開始下標從0開始的。

        #include
        int main(void){
         //PD6 設置為輸入  K3
         DDRD &= ~(1 << 6);
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<6);
         //PD7 設置為輸入  K4
         DDRD &= ~(1 << 7); 
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<7);
         //PD2 設置為輸入  K1
         DDRD &= ~(1 << 2); 
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<2);//這個上拉不上拉沒關系 因為上拉是百K的電阻所以開關打開還是認為是低電平
         //PD3 設置為輸入  K2
         DDRD &= ~(1 << 3); 
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<3);
         //蜂鳴器PA3 設置方向寄存器為輸出
         DDRA |= (1<<3);
         //蜂鳴器關掉
         PORTA &= ~(1<<3);
         //數碼管全部置為輸出
         DDRB = 0xff;
         //位選線高四位全部置1 也是輸出 因為是置其中4位所以用|=
         DDRA |= 0Xf0;
         char scandata[16]={
         0b10101111,//0
         0b10100000,//1
         0b11000111,//2
         0b11100110,//3
         0b11100000,//4
         0b01101110,//5
         0b01101111,//6
         0b10100010,//7
         0b11101111,//8
         0b11101110,//9
         0b11100111,//A
         0b01101101,//b
         0b00001111,//c
         0b11000001,//d
         0b01001111,//E
         0b01001111//F
         
         };
          while(1){
           //數碼管也需要掃描所以也用死循環 while(1)
           //先將數碼管的第一位點亮  選中位選
           PORTA |=(1<<4); 
           //再將數據送到PB口上哪一段對應哪一位 要事先測量下 編一個程序測量下 
           PORTB = scandata[0];//顯示0
           PORTB = scandata[1];//顯示1
           PORTB = scandata[2];//顯示2
           PORTB = scandata[3];//顯示3
           PORTB = scandata[4];//顯示4
           PORTB = scandata[5];//顯示5
           PORTB = scandata[6];//顯示6
           PORTB = scandata[7];//顯示7
           PORTB = scandata[8];//顯示8
           PORTB = scandata[9];//顯示9
           PORTB = scandata[10];//顯示A
           PORTB = scandata[11];//顯示B
           PORTB = scandata[12];//顯示C
           PORTB = scandata[13];//顯示D
           PORTB = scandata[14];//顯示E
           PORTB = scandata[15];//顯示F

          }
        }
        //這就是數碼管用段碼顯示。那么怎么對數碼管掃描顯示呢?

        我們可以遵循這樣一個順序,首先將數碼管位選中,送數據  PORTA 選中  PORTB送上數據然后打開相應這一位。讓他顯示出來,顯示出來之后呢?再讓這一位熄滅可以把所有四位都熄滅  位選 PORTA &0x0f;高四位清0這樣就完成了數碼管的高四位顯示。

        #include
        int main(void){
         int j ;

         //PD6 設置為輸入  K3
         DDRD &= ~(1 << 6);
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<6);
         //PD7 設置為輸入  K4
         DDRD &= ~(1 << 7); 
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<7);
         //PD2 設置為輸入  K1
         DDRD &= ~(1 << 2); 
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<2);//這個上拉不上拉沒關系 因為上拉是百K的電阻所以開關打開還是認為是低電平
         //PD3 設置為輸入  K2
         DDRD &= ~(1 << 3); 
         //輸入狀態下將數據寄存器使能上拉電阻
         PORTD |= (1<<3);
         //蜂鳴器PA3 設置方向寄存器為輸出
         DDRA |= (1<<3);
         //蜂鳴器關掉
         PORTA &= ~(1<<3);
         //數碼管全部置為輸出
         DDRB = 0xff;
         //位選線高四位全部置1 也是輸出 因為是置其中4位所以用|=
         DDRA |= 0Xf0;
         char scandata[16]={
         0b10101111,//0
         0b10100000,//1
         0b11000111,//2
         0b11100110,//3
         0b11100000,//4
         0b01101110,//5
         0b01101111,//6
         0b10100010,//7
         0b11101111,//8
         0b11101110,//9
         0b11100111,//A
         0b01101101,//b
         0b00001111,//c
         0b11000001,//d
         0b01001111,//E
         0b01001111//F
         
         };
          while(1){
           //數碼管也需要掃描所以也用死循環 while(1)
           //先將數碼管的第一位點亮  選中位選
           PORTA |=(1<<4); 
           //再將數據送到PB口上哪一段對應哪一位 要事先測量下 編一個程序測量下 
           PORTB = scandata[0];//顯示0
           for (j=0;j<400;j++);//延時
           PORTA &= 0x0f;
           PORTA |= (1<<5);
           PORTB = scandata[1];
           PORTA &= 0x0f;
           for (j=0;j<400;j++);//延時
           PORTA |= (1<<6);
           PORTB = scandata[2];
           PORTA &= 0x0f;
           for (j=0;j<400;j++);//延時
           PORTA |= (1<<7);
           PORTB = scandata[3];
           for (j=0;j<400;j++);//延時
           PORTA &= 0x0f;
           //單步仿真看看  就是1位亮了0  熄滅 2位亮1  熄滅 3位亮2  熄滅  4位亮3 熄滅  一直循環
           //全速執行看看顯示4個數字 可以看到亮度不怎么亮的,因為 點亮熄滅只有那么一小段時間是發光的
           //所以如果要增加亮度只需要加一個延時程序  聲明一個變量j  在看效果  全速執行亮度是明顯增加了
        //這就是數碼管程序掃描的程序設計
           
          }
        }

         

         

         

         

        關閉窗口

        相關文章

        欧美性色欧美精品视频,99热这里只有精品mp4,日韩高清亚洲日韩精品一区二区,2020国自产拍精品高潮