新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 51單片機入門1

        51單片機入門1

        作者: 時間:2016-11-23 來源:網絡 收藏
        我們在單片機最小系統上接個LED,看我們能否點亮它!對了,上面也有好幾次提到過單片機最小系統了,所謂單片機最小系統就是在單片機
        上接上最少的外圍電路元件讓單片機工作。一般只須連接晶體、VCC、GND、RST即可,一般情況下,AT89C51的31腳須接高電平。
        #include//頭文件定義。或用#include其具體的區別在于:后者定義了更多的地址空間。
        //在Keil安裝文件夾中,找到相應的文件,比較一下便知!
        sbit P1_0 = P1 ^ 0;
        void main (void)
        {
        while(1)
        {
        P1_0 = 0;//低電平有效,如果把LED反過來接那么就是高電平有效
        }
        }

        就那么簡單,我們就把接在單片機P1_0上的LED點亮了,當然LED是低電平,才能點亮。因為我們把LED的正通過電阻接至VCC。
        P1_0 = 0; 類似與C語言中的賦值語句,即把 0 賦給單片機的P1_0引腳,讓它輸出相應的電平。那么這樣就能達到了我們預先的要求了。
        while(1)語句只是讓單片機工作在死循環狀態,即一直輸出低電平。如果我們要試著點亮其他的LED,也類似上述語句。這里就不再講了。
        點亮了幾個LED后,是不是讓我們聯想到了繁華的街區上流動的彩燈。我們是不是也可以讓幾個LED依次按順序亮呢?答案是肯定的!其
        實顯示的原理很簡單,就是讓一個LED滅后,另一個立即亮,依次輪流下去。假設我們有8個LED分別接在P1口的8個引腳上。硬件連接,在
        P1_1--P1_7上再接7個LED即可。例程如下:
        #include

        sbit P1_0 = P1 ^ 0;
        sbit P1_1 = P1 ^ 1;
        sbit P1_2 = P1 ^ 2;
        sbit P1_3 = P1 ^ 3;
        sbit P1_4 = P1 ^ 4;
        sbit P1_5 = P1 ^ 5;
        sbit P1_6 = P1 ^ 6;
        sbit P1_7 = P1 ^ 7;

        void Delay(unsigned char a)
        {
        unsigned char i;
        while( --a != 0)
        {
        for(i = 0; i < 125; i++);//一個 ; 表示空語句,CPU空轉。
        }//i 從0加到125,CPU大概就耗時1毫秒
        }

        void main(void)
        {
        while(1)
        {
        P1_0 = 0;
        Delay(250);
        P1_0 = 1;

        P1_1 = 0;
        Delay(250);
        P1_1 = 1;

        P1_2 = 0;
        Delay(250);
        P1_2 = 1;

        P1_3 = 0;
        Delay(250);
        P1_3 = 1;

        P1_4 = 0;
        Delay(250);
        P1_4 = 1;

        P1_5 = 0;
        Delay(250);
        P1_5 = 1;

        P1_6 = 0;
        Delay(250);
        P1_6 = 1;

        P1_7 = 0;
        Delay(250);
        P1_7 = 1;
        }
        }


        sbit 定義位變量,unsigned char a 定義無符字符型變量a,以節省單片機內部資源,其有效值為0~255。main函數調用Delay()函數。
        Delay函數使單片機空轉,LED持續點亮后,再滅,下一個LED亮。while(1)產生循環。





        (三)

        上面我們講了如何使LED產生流動,但是你是否發現一個問題:寫的太冗長了!能不能再簡單點呢?可以!可以使用C51的內部函數
        INTRINS.H實現。函數unsigned char _crol_(unsigned char a, unsigned char n) 可以使變量a循環左移n位,如果我們先給P1口賦
        0000 0001那么當n為1時,便會產生和上面一樣的效果!
        #include
        #include

        void Delay(unsigned char a)
        {
        unsigned char i;
        while( --a != 0)
        {
        for(i = 0; i < 125; i++);
        }
        }

        void main(void)
        {
        unsigned char b, i;
        while(1)
        {
        b = 0xfe;
        for(i = 0; i < 8; i++)
        {
        P1 = _crol_(b, 1);
        b = P1;
        Delay(250);
        }
        }
        }



        INTRINS.H函數中的unsigned char _cror_(unsigned char a, unsigned char n)右移也可以實現同樣的效果!這里就不再累述。
        流水燈的花樣很多,我還寫過那種拉幕式的流動等,程序很簡單,有興趣的朋友,可以自己試著寫寫!
        對了,講了那么多,有些朋友一定還不知道編譯軟件怎么用?這里給大家介紹幾個吧?WAVE(偉福)大家一定聽說過吧!還有一個
        就是KEIL2,我用的就是KEIL2,下面就來講講如何使用KEIL2這個編譯軟件!
        1.安裝軟件,這個應該不用再講了吧!
        2.安裝完后,啟動KEIL軟件左擊Project-->New Project-->輸入文件名-->選擇我們所以使用的芯片(這里我們一般用到Atmel的
        AT89C51或AT89C2051,點確定。
        3.點File-->New-->輸入我們編寫的程序,保存為.C文件。(一般情況下,我們保存的文件名和前面的工程名一樣。)

        4.展開Target 1 -->右擊Source Group 1 -->Add Files to Group Source Group 1-->選擇剛才保存的.C文件點擊ADD后,關閉對
        話框。這樣.C文件就被加到了Source Group 1 下。
        5.右擊Target 1-->Optionsfor Target 1 -->Target中填寫晶體的大小,Output中,在Create HEX Files 前打上鉤,點確
        定。
        6.點Project-->Rebuild All Traget Files ,若提示
        creating hex file from "XXX"...
        "XXX" - 0 Error(s), 0 Waring(s).
        表示編譯和生成HEX文件成功!接下來的就是把HEX文件燒到單片機中,或是仿真器上,看是否達到預先的目的!
        嘿嘿!現在是否自己好有成就感了,如果讓你去做個流水彩燈,開發一個簡單的產品,只要加上驅動電路,就可以做出漂亮的流動彩燈
        了!到現在為止,你應該知道單片機的功能有多強大了吧,如果單純的用數字電路或模擬電路的知識去設計一個流動彩燈,可能要花點工夫
        和時間才行,有了單片機,那就不一樣了,你只要寫程序控制他就行!有人說過這樣一句話,也并不無道理的,學單片機,程序思想很重要!






        (四)

        呵呵,朋友!相信你的流水燈也做的不錯了吧,現在能玩出幾種花樣了?你可能會說,只要你想得到,想怎么流就怎么流!呵呵,是的。
        但是工程師們設計這么一個單片機,并不是只為了讓它做流水燈的,那樣也太浪費點了吧 ... ^_^
        學過數字電路的朋友,一定動手做過8路或者6路的搶答器。用純粹的數字電路知識來做,自己設計電路,感到比較困難!搶答器上用的顯
        示器多為7段數碼管,這里我們來講講,如何用單片機讓數碼管顯示0-9。搶答器的實現,我們放到后面再來探討,因為搶答器還涉及了鍵盤的
        內容。8段數碼管分為共陰和共陽兩種。8段數碼管是由8個LED組成(還包括一個小數點)。若為共陽,則8個LED的陽級是連接在一起的,同理
        若為共陰,則陰極連接在一起。8個LED對應的標號如下:
        a
        __
        f || b
        |__|
        |g | c
        e |__| . dp
        d
        一般情況下,為了計算或取碼的方便,我們把a-dp依次接到單片機某個口上的Px.0--Px.7上。x表示0,1,2,3其中的一個。這樣我們只
        要給某個口,賦一個值,則相應的LED段就被點亮,但是在硬件連接上要注意了:單片機可能不能直接驅動LED,所以我們可以通過控制三級管
        的導通或截止,來控制LED的亮與滅!
        如果我們把共陰的數碼管的a--dp依次接到單片機的P0.0--P0.7上,注意:P0口需接上拉電阻。何為上拉電阻,簡單的說,就是把電平拉
        高,以提高驅動能力。那么比如:P0 = 0X3F;則顯示為數字 0 。因為0X3F 即為2進制的 0011 1111 我們低位往高位數,依次為1111 1100,
        其I/O的電平分別為高、高、高、高、高、高、低、低,即對應的a--dp 為亮、亮、亮、亮、亮、亮、滅、滅,由上圖我們可以看出g和dp段不
        亮其他段均亮,即為我們所看到的數字 0 字樣。其他的數字或字符,也同理可以得到。但是有些朋友就會問,那我們每取一個字模,豈不是
        很麻煩?還有自己考慮高低電平什么的?^-^ 呵呵,其實網上有很多LED取模軟件,如果有一定計算機編程語言的朋友,也可以試著自己寫個
        取模的程序,讓計算機為我們計算,諸如上述0X3F的數值。
        #include

        void Delay(unsigned char a)
        {
        unsigned char i;
        while( --a != 0)
        {
        for(i = 0; i < 125; i++);
        }
        }

        void main(void)
        {
        P0 = 0X3F;//顯示 0
        Delay(250);//延時
        P0 = 0X00;//短暫的關閉顯示,若不關閉,可能會造成顯示模糊不清。

        P0 = 0X06; //顯示 1
        Delay(250);
        P0 = 0X00;

        ...//以下顯示數字2-F,略。
        }

        看到這里,想必大家一定可以把0-F顯示出來了吧!但是如果要你顯示兩位數,三位數呢?或許,有的朋友會這么想:在P0口上接一個
        數碼管,再在P1口上接個數碼管!但是,如果要顯示4位、5位的數字呢?那豈不是一塊AT8951都接不過來!難到就不能接4位或5位以上的嗎?
        肯定不是的!
        說到這里,我們來講講數碼管的顯示方式,可分為兩種:動態掃描和靜態顯示。上面我們所說的即為靜態顯示。但是如果我們采用動態掃
        描顯示,那么就可以解決上面的問題,即可以顯示多個數碼管了。上面我們所說的靜態顯示把數碼管的COM腳接至VCC或GND端,其他的接至PX
        口上,這樣只要PX口上輸出相應的高低電平,就可以顯示對應的數字或字符。但是如果我們采用動態掃描的方法,比如顯示6個數碼管,硬件
        連接可以這樣解決:a--dp還是接至P0.0--P0.7上,還有6個COM腳再接至另外口的P2.0--P2.5。P0口作段選(控制數字字符)P2口作位選(選

        通哪個數碼管導通)這樣我們控制P0和P2口就可以控制6個數碼管了。但是,細心的朋友,會問這樣的問題:P2位選,是讓數碼管一個一個亮
        的,那還是不能控制6個一起亮或滅嘛!? ^_^ 想想好象是對的哦?怎么辦...難道錯了?
        嘿嘿,問你個問題?黑夜里,拿著一支煙,在你面前快速的晃動,你會發現什么樣的現象?是不是原本不連續的點變成了一條看上去連
        續的曲線或者直線!再回過頭來,仔細想想我們的數碼管!原理是一樣的,你可別忘了,我們的單片機可是一個計算機哦,計算機的運算速
        度,大家可想而知吧!
        這里再說說51單片機的機器周期和時鐘周期等概念。所謂機器周期就是訪問一次存儲器的時間。而1個機器周期包括12個時鐘周期。如果
        單片機工作在12M晶體下,那么一個時鐘周期為:1/12微妙。一個機器周期12*1/12 = 1微妙。如果晶體為6M,時鐘周期和機器周期各是多少呢
        ?在匯編中,我們還要關心,指令執行的機器周期長短不一,有1個周期、2個周期和4個周期等。
        說著說著,跑了這么遠了...還是回到原來的話題,如果我們把位選的P2也看作上面的“煙”一劃而過,那么我們看到的是不是6個一起亮
        或一起滅了!^_^哈哈,原來如此...記住,在任何某一時刻,有且只有一個數碼管能發光。如果你能把這句話理解了,你是真明白
        我的意思了!朋友,現在給你個任務,讓6個數碼管分別顯示1、2、3、4、5、6。看你自己可以搞定不?你自己先試著寫寫看咯...

        #include

        void Delay(unsigned char a)
        {
        unsigned char i;
        while( --a != 0)
        {
        for(i = 0; i < 125; i++);
        }
        }

        void main(void)
        {
        while(1)
        {
        P0 = 0x06;//1的碼段
        P2 = 0x01;//選通一位,或者P2_0 = 1;
        Delay(20);//延時約20毫秒
        P0 = 0X00;//關閉顯示

        P0 = 0x5b;//2的碼段
        P2 = 0x02; //選通一位,或者P2_1 = 1;
        Delay(20);
        P0 = 0X00;

        P0 = 0x4f;//3的碼段
        P2 = 0x04; //選通一位,或者P2_2 = 1;
        Delay(20);
        P0 = 0X00;

        P0 = 0x66;//4的碼段
        P2 = 0x08; //選通一位,或者P2_3 = 1;
        Delay(20);
        P0 = 0X00;

        P0 = 0x6d;//5的碼段
        P2 = 0x10;//選通一位,或者P2_4 = 1;
        Delay(20);
        P0 = 0X00;

        P0 = 0x7d;//6的碼段
        P2 = 0x20;//選通一位,或者P2_5 = 1;
        Delay(20);
        P0 = 0X00;
        }
        }




        (五)

        相信大家一定見過數字時鐘,教學樓大廳一定有吧。每次路過,基本上只是隨便瞟上一眼,根本沒去想過他的工作原理什么。但是今天
        你也可以把他做出來了,是不是覺得自己很有成就感呢!呵呵! ^_^
        接上面所講的,我們先來做個簡單的實驗:在一個數碼管上輪流顯示0--9這10個數字。還楞著干什么,快動手寫程序呀!好象有點難哦,
        要不先不要往下看了,嘿嘿,關機吧,自己先去想想,怎么樣?
        #include

        unsigned char code SEG_TAB[ ] ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //0-9數字

        void Delay(unsigned int a)//unsigned int 定義為無符整形,取值范圍為0--32768
        {
        unsigned char i;
        while( --a != 0)
        {
        for(i = 0; i < 125; i++);
        }
        }

        void main(void)
        {
        unsigned char i;
        while(1)
        {
        for(i = 0; i < 10; i++)
        {
        P0 = SEG_TAB[ i ];//取SEG_TAB數組中的值
        P2 = 0X01;
        Delay(1000);
        }
        }
        }

        是不是顯示從0--9,跳動顯示,你的心是不是也跟著一起跳呀,離我們的目標又邁進了一步!不錯,繼續努力!
        上面只顯示了一個數碼管的數字0--9,但是怎么樣要讓他顯示6個數字呢?這樣我們就可以做個時鐘出來玩玩了!還記不記得我們前面
        講過的P2口的位選作用!嘿嘿,沒忘記就好!
        #include

        unsigned char hour = 12, min = 0, sec = 0;
        unsigned char code SEG_TAB[ ] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //0-9數字

        void Delay(unsigned char a)
        {
        unsigned char i;
        while( --a != 0)
        {
        for(i = 0; i < 125; i++);
        }
        }

        void disp(void)
        {
        P0 = SEG_TAB[ sec % 10 ];//顯示秒的個位
        P2 = 0X01;
        Delay(15);
        P2 = 0;

        P0 = SEG_TAB[ sec / 10 ];//顯示秒的十位
        P2 = 0X02;
        Delay(15);
        P2 = 0;

        P0 = SEG_TAB[ min % 10 ];//顯示分的個位
        P2 = 0X04;
        Delay(15);
        P2 = 0;

        P0 = SEG_TAB[ min / 10 ];//顯示分的十位
        P2 = 0X08;
        Delay(15);
        P2 = 0;

        P0 = SEG_TAB[ hour % 10 ];//顯示時的個位
        P2 = 0X10;
        Delay(15);
        P2 = 0;

        P0 = SEG_TAB[ hour / 10 ];//顯示時的十位
        P2 = 0X20;
        Delay(15);
        P2 = 0;
        }

        void main(void)
        {
        while( 1 )
        {
        disp( );
        }
        }


        關鍵詞: 51單片機入

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 夏河县| 綦江县| 八宿县| 汝州市| 沐川县| 焦作市| 白水县| 株洲县| 武隆县| 乳源| 车险| 晋江市| 南昌市| 绥中县| 通许县| 洮南市| 望奎县| 苗栗市| 彩票| 永登县| 思南县| 庆云县| 龙江县| 新绛县| 富蕴县| 荣成市| 延吉市| 乌恰县| 尼木县| 临沂市| 尼勒克县| 林州市| 咸阳市| 金门县| 城口县| 永善县| 黑河市| 崇明县| 泰州市| 寿光市| 湖北省|