新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 51單片機學習總結實例

        51單片機學習總結實例

        作者: 時間:2016-11-19 來源:網絡 收藏
        馬上大四了,即將找工作。所以便把我學過的東西總結一下,系統一下。

        接下來,就把我總結的結果跟大家分享下。

        本文引用地址:http://www.104case.com/article/201611/318259.htm

        這一章是51單片機,主要是程序實例。代碼參考郭天祥的單片機教材。

        是總括性的,適合于有一定單片機基礎的同學,也可以給初學者做一個系統的學習主線。

        這個博客里的涉及的源代碼大家可以在這里下載http://download.csdn.net/detail/zhaole20094463/4427745

        1.流水燈

        /流水燈/
        #include
        #include//包含_crol_函數所在的頭文件
        #define uint unsigned int //宏定義 定義uint 在大項目中更加的方便
        #define uchar unsigned char
        void delayms(uint);
        uchar aa;
        void main()
        {
        aa=0xfe;
        while(1)
        {
        P1=aa;
        delayms(500);
        aa=_crol_(aa,1);//aa左移一位
        }
        }
        void delayms(uint xms)//延時時間約為1ms通過程序單步執行,看運行時間可得到
        {
        uint i,j;
        for(i=xms;i>0;i--)
        for(j=110;j>0;j--);
        }

        通過調用系統函數的方式使流水燈實現循環左移。

        2.數碼管顯示程序

        /*鎖存器用的是74HC573高電平通,低電平鎖存*/
        /*作用:高阻態 ,數據鎖存 ,數據緩沖 (加強驅動能力)*/
        /*循環顯示1-A的數據*/
        #include
        #define uint unsigned int
        #define uchar unsigned char
        sbit dula=P2^6;
        sbit wela=P2^7;
        uchar num;
        uchar code table[]={數碼管段碼表};
        void main()
        {
        wela=1;//打開鎖存器
        P0=0xc0;//送入鎖存信號
        wela=0;//關閉鎖存器
        while(1)
        {
        for(num=0;num<16;num++)
        dula=1;
        P0=table[num];
        delayms(500);
        }
        }
        void delayms(uint xms)
        {
        uint i,j;
        for(i=xms;i>0;i--)
        for(j=110;j>0;j--);
        }

        3.獨立鍵盤檢測

        /*通過按鍵控制led亮滅*/
        #include
        #define uint unsigned int
        #define uchar unsigned char
        sbit key1=P3^4;
        sbit led=P1^0;
        void delay(uint z)
        {
        uint x,y;
        for(x=z;x>0;x--)
        for(y=110;y>0;y--);
        }
        void main()
        {
        P3=0xff;//在對51單片機進行按鍵檢測時,先要將引腳置1;
        while(1)
        {
        if(key1==0)
        {
        delay(5);
        if(key1==0)//按鍵消抖
        {
        led=0;
        num++;
        if(num==2)
        num=0;
        led=1;
        }
        }

        4.矩陣鍵盤檢測

        /*檢測矩陣鍵盤數碼管顯示0-F/
        矩陣鍵盤的四列與P3.4~P3.7相連
        4行與P3.0~P3.3
        #include
        #define uchar unsinged char
        #define uint unsigned int
        sbit dula=P2^6;
        sbint wela=P2^7;
        uchar code table[]={段碼表};
        void delayms(uint xms);
        {
        uint i,j;
        for(i=xms;i>0;i--)
        for(j=110;j>0;j--);
        }
        void display(uchar num)顯示函數
        {
        P0=table[num];
        dula=1;
        dula=0;
        }
        void matrixkeyscan()//矩陣鍵盤的檢測
        {
        uchar temp,key;
        P3=0xfe;//打開P3.7,P3.7置0.檢測高四位
        temp=P3;
        temp=temp&0xf0;
        if(temp!=0xf0)//是否有鍵被按下
        {
        delayms(10);
        temp=P3;
        temp=temp&0xf0;
        if(temp!=0xf0)//按鍵消抖
        {
        temp=P3;
        switch(temp)
        {
        case 0xee:key=0;break;
        case 0xde:key=1;break;
        case 0xbe:key=2;break
        case 0x7e:key=3:break;
        }
        while(temp!=0xf0)//檢測按鍵是否彈起,如果沒有彈起循環停在這里。
        {
        temp=P3;
        temp=temp&0xf0;
        }
        display(key);
        }
        }
        。。。。。。。。。。。。。。。。。。。
        如下程序依次增加
        令P3=0xfd,打開P3.6,P3.6置低,檢測高四位 依次為 4,5,6,7
        然后令P3= 0xfb 0xf7
        }
        void main()
        {
        P0=0;//關閉所有數碼管的段選
        dula=1;
        dula=0;
        P0=0xc0;
        wela=1;
        wela=0;
        while(1)
        {
        matrixkeyscan();//不停調用鍵盤掃描程序
        此程序關鍵在于這個函數,矩陣鍵盤的掃描算法
        }
        }

        5.1602液晶屏顯示子函數

        //
        這個程序主要是有這樣幾個子函數,關于lcd寫命令和寫數據的
        #include
        #define uchar unsigned char
        #define uint unsigned int
        uchar code table[]="zhaole20094463";
        uchar code table1[]="love Embedded systems";
        sbit lcden=P3^4;//lcd使能端
        sbit lcdrs=P3^5;//lcd數據命令選擇端
        uchar num;
        void delay(uint z)
        {
        uint x,y;
        for(x=z;x>0;x--)
        for(y=110;y>0;y--);
        }
        void write_com(uchar com)//lcd寫命令函數
        {
        lcdrs=0;
        P0=com;
        delay(5);
        lcden=1;
        delay(5);
        lceen=0;
        }


        void write_data(uchar date)//lcd寫數據
        {
        lcdrs=1;
        P0=date;
        delay(5);
        lcden=1;
        delay(5);
        lcden=0;
        }


        void init()
        {
        lcden=0;
        write_com(0x38);//設置16*2顯示,5*7點陣,8位數據接口
        write_com(0x0c);//設置開顯示,不顯示光標
        write_com(0x06);//寫第一個字符后地址指針加1
        write_com(0x01);//顯示清0,數據指針清0
        }
        void main()
        {
        init();
        write_com(0x80);//數據指針定位在第一行的第一個字處
        for(num=0;num<14;num++)
        {
        write_data(table[num]);
        delay(5);
        }
        write_com(0x80+0x40);//數據指針定位在第二行的第一個字處
        for(num=0;num<21;num++)
        {
        write_data(table1[num]);
        delay(5);
        }
        while(1);
        }

        5.2 12864顯示子函數

        #include
        #include
        #include


        #define uchar unsigned char
        #define uint unsigned int


        #define LCD_data P0;//數據口


        sbit LCD_RS=P3^5; //數據選擇輸入
        sbit LCD_RW=P3^6; //液晶讀寫控制
        sbit LCD_EN=P3^4; //液晶使能控制端
        sbit LCD_PSB=P3^7; //串并方式控制


        void delay_1ms(uint )
        {
        uint i,j;
        for(j=0j for(i=0;i<110;i++);
        }
        /*PS=L,RW=L,E=高脈沖,D0~D7=指令碼*/
        void write_cmd(uchar cmd)
        {
        LCD_RS=0;
        LCD_RW=0;
        LCD_EN=0;
        P0=cmd;
        delay_1ms(5);
        LCD_EN=0;
        }
        /*寫顯示數據到LCD*/
        /*RS=H,RW=L,E=高脈沖,D0~D7=數據
        void write_dat(uchar dat)
        {
        LCD_RS=1;
        LCD_RW=0;
        LCD_EN=0;
        P0=dat;
        delay_1ms(5);
        LCD_EN=1;
        dealy_1ms(5);
        LCD_EN=0;
        }
        /*設定顯示位置*/
        void LCD_pos(uchar X,uchar Y)
        {
        uchar pos;
        if(X==0)
        {X=0x80;}
        else if(X==1);
        {X=0x90;}
        else if(x==2)
        {X=0x88;}
        else if(X==3)
        {X=0x98;}
        pos=X+Y;
        write_cmd(pos);//顯示地址
        }


        /*LCD初始化設置*/
        void lcd_init()
        {
        LCD_PSB=1; //并口方式
        write_cmd(0x30);//基本指令操作
        delay_1ms(5);
        write_cmd(0x0C);//先是開,關光標
        delay_1ms(5);
        write_cmd(0x01);//清除LCD的顯示內容
        delay_1ms(5);
        }

        6.定時器中斷

        /*用定時器0的方式1實現第一個發光管以1s亮滅*/
        定時器/計數器4種工作方式
        1,方式0 13位計數器 高8位和低5位
        2,方式1 16位計數器
        3,方式2 自動恢復初值 8位
        4,方式3 只適用于T0,不適用于T1 8位

        45872初值的計算
        晶振:11.0592M
        機器周期:計數一次的時間=12*(1/11.0592M)51單片機是12個時鐘周期為一個機器周期
        =1.09US 指令周期由整數個機器周期組成
        45872 =50Ms/1.09us


        //
        #include
        #define uchar unsigned char
        #define uint unsigned int
        sbit led1=P1^0;
        uchar num;
        void main()
        {
        TMOD=0x01;//設置定時器0工作方式1
        TH0=(65535-45872)/256;//裝初值11.0592M晶振定時50ms為45872
        TL0=(65535-45872)%256;
        EA=1; //開總中斷
        ET0=1; //開定時器0中斷
        TR0=1; //啟動定時器0
        while(1) //程序停在這里等待中斷的發生
        }


        void T0_time() interrupt 1
        {
        TH0=(65535-45872)/256;
        TL0=(65535-45872)%256;
        num++;
        if(num==20)
        {
        num=0;
        led1=~led1;
        }
        }

        7.串口通信

        //
        上位機通過串口調試助手發送一個字符x,單片機收到字符后返回給上位機“I get x”
        串口波特率設置為9600bps。
        #include
        #define uchar unsigned char
        #define uint unsigned int
        uchar flag,a,i;
        uchar code table[]="I get";
        void init()
        {
        TMOD=0x20;//設置T1定時器工作方式為2 8位初值自動重裝的8位定時器
        TH1=0xfd;//T1定時器裝初值(高八位) 控制串口通信的波特率(由定時器1的溢出率控制)
        TL1=0xfd;///T1定時器裝入初值(低八位)
        TR1=1; //定時器1運行控制位 置一啟動定時器
        REN=1; //允許串口接收
        SM0=0;
        SM1=1; //設置串口工作方式為一
        EA=1; //全局中斷允許位 置一開全局中斷
        ES=1; //串口中斷允許位
        }


        void main()
        {
        init();
        ` while(1)
        {
        if(flag==1)
        {
        ES=0;
        for(i=0;i<6;i++)
        {
        SBUF=table[i];
        while(!TI)
        TI=0;//發送中斷標志 發送數據完成后觸發中斷 硬件置一 必須軟件清零
        }
        SBUF=a;// 串口發送數據
        while(!TI);
        TI=0;
        ES=1;
        flag=0;
        }

        }


        void ser() interrupt 4 //串口中斷服務程序
        {
        RI=0; // 收到數據硬件置一,由軟件清零
        a=SBUF; //將寄存器的值 賦給a
        flag=1; //標志位
        }
        注意:51單片機的特殊之處在于,SBUF既是串口接收寄存器也是串口發送寄存器,取決于
        SBUF所在賦值符號“=”左右的位置


        此程序中共用的串口中斷,


        定時器1中斷 特殊功能寄存器SBUF


        中斷響應的條件


        中斷源有中斷請求 此中斷源允許位為1 cpu開中斷(即EA=1)以上三個條件同時滿足


        串口通信設置


        確定串口通信波特率(編程TMOD寄存器定時器工作方式寄存器)

        計算定時器初值轉載THX TLX

        確定串行口工作方式(編程SCON寄存器串行口控制方式寄存器)

        串行口工作在中斷方式時,要進行中斷設置如TI,RI軟件清零

        8.I2C總線通信模擬子函數

        /*/
        因為51單片機沒有I2C總線,所以采用模擬I2C通信
        1,總線初始化
        void init()
        {
        SCL=1;
        delay();
        SDA=1;
        delay();
        }
        2,啟動信號
        void start()
        {
        SDA=1;
        delay(1);
        SCL=1;
        delay();
        SDA=0;
        delay();
        }
        3,應答信號
        void respons()
        {
        uchar i=0;
        SCL=1;
        delay();
        while((SDA==1)&&(i<255))
        i++;
        SCL=0;
        delay();
        }
        4,停止信號
        void stop()
        {
        SDA=0;
        delay();
        SCL=1;
        delay();
        SDA=1;
        delay();
        }
        5,寫一個字節
        void writebyte(uchar date)
        {
        uchar i,temp;
        temp=date;
        for(i=0;i<8;i++)
        {
        temp=temp<<1;
        SCL=0;
        delay();
        SDA=CY;
        delay();
        SCL=1;
        delay();
        }
        SCL=0;
        delay();
        SDA=1;
        delay();
        }
        6,讀一個字節
        uchar readbyte()
        {
        uchar i,k;
        SCL=0;
        delay();
        SDA=1;
        for(i=0;i<8;i++)
        {
        SCL=1;
        delay();
        k=(k<<1)|SDA;
        SCL=0;
        delay();
        }
        delay();
        return k;
        }

        9.看門狗

        //
        關于51單片機中的看門狗寄存器
        D5 EN_WDT 看門狗允許位
        D4 CLK_WDT 看門狗清零
        D3 IDLE_WDT 看門狗IDLE模式位
        PS0 PS1 PS2 看門狗定時器預分頻值
        這三個寄存器置不同的值決定不同的看門狗溢出時間
        看門狗溢出時間=(N*預分頻數*32768)/晶振頻率
        #include
        #define uchar unsigned char
        #define uint unsigned int
        sfr WDT_CONTR=0xe1;//定義看門狗寄存器 reg52.h中沒有對它進行定義
        sbit led1=P1^0;
        void delayms(uint xms)
        {
        uint i,j;
        for(i=xms;j>0;j--)
        for(j=110;j>0;j--);
        }

        void main()
        {
        WDT_CONTR=0x35;//0x35=0011 0101設置預分頻數為 64 溢出時間為2.0971s
        led1=0;
        delayms(500);
        led1=1;
        while(1)
        {
        delayms(1000);
        WDT_CONTR=0x35;//喂狗語句將D4不斷置1,一旦D4被清零則看門狗復位
        }
        }

        10.軟件實現系統復位

        STC ISP/IAP控制寄存器(ISP_CONTR)
        D7 ISPEN 功能允許位 0禁止編程改變flash 1允許
        D6 SWBS 0軟件選擇從用戶應用程序區啟動 1從ISP程序區啟動
        D5 SWRST 不操作 1產生系統軟件復位,硬件自動清零
        D2 WT2
        D1 WT1
        D0 WT0 編程設定CPU等待的最長時間,對flash進行讀操作,寫操作,擦除操作必須在這個時間內
        SWBS=0 SWRST=1(軟復位) 從用戶應用程序區(AP區)軟件復位并切換到用戶應用程序區開始執行程序
        從哪里復位取決于程序在哪里執行
        SWBS=1 SWRST=1 從ISP監控程序區軟件復位并切換ISP監控程序區開始執行程序
        使用方法:
        進行軟件復位時
        首先
        sfr ISP_CONTR=0xe7;定義ISP/IAP控制寄存器
        然后再需要軟件復位的地方加入如下語句即可
        ISP_CONTR=0x20//用軟件復位到用戶應用程序區(AP),重新開始執行程序

        11.DS18B20編程應用子函數

        //
        Ds18B20的編程子函數
        DS18B20是單總線接口的溫度傳感器,應用范圍很廣泛

        #include
        #include
        #define uchar unsigned char
        #define uint unsigned int
        sbit ds=P2^2;//溫度傳感器信號線
        uint temp;//定義整型的溫度數據
        float temp;//定義浮點型的溫度數據
        void delay(uint z)
        {
        uint x,y;
        for(x=z;x>0;x--)
        for(y=110;y>0;y--);
        }




        void dsreset(void)//DS18B20復位,初始化函數
        {
        uint i;
        ds=0;
        i=103;
        while(i>0)i--;
        ds=1;
        i=4;
        while(i>0)i--;
        }


        bit tempreadbit(void)//讀1位數據函數
        {
        uint i;
        bit dat;
        ds=0;i++;//i++起延時作用
        ds=1;i++;i++;
        dat=ds;
        i=8;while(i>0)i--;
        return(dat);
        }


        uchar tempread(void)//讀1個字節數據函數
        {
        uchar i,j,dat;
        dat=0;
        for(i=1;i<=8;i++)
        {
        j=tempreadbit();
        dat=(j<<7)|(dat>>1);//讀出的數據最低位在最前面,這樣剛好一個字節在dat里
        }
        return(dat);
        }
        void tempwritebyte(uchar dat)//向DS18B20寫一個字節數據函數
        {
        uint i;
        uchar j;
        bit testb;
        for(j=1;j<=8;j++)
        {
        testb=dat&0x01;
        dat=dat>>1;
        if(testb)//寫1
        {
        ds=0;
        i++;i++;
        ds=1;
        i=8;while(i>0)i--;
        }
        else//寫0
        {
        ds=0;
        i=8;while(i>0)i--;
        ds=1;
        i++;i++;
        }
        }
        }


        void tempchange(void)//DS18B20 開始獲取溫度并轉換
        {
        dsreset();
        delay(1);
        tempwritebyte(0xcc);//寫 跳過讀ROM指令
        tempwritebyte(0x44);//寫 溫度轉換指令
        }


        uint get_temp()
        {
        uchar a,b;
        dsreset();
        delay(1);
        tempwritebyte(0xcc);
        tempwritebyte(0xbe);//讀內部ram中的9字節
        a=tempread();//讀低8位
        b=tempreda();//讀高8位
        temp=b;
        temp<<=8;
        temp=temp | a;//兩個字節組合為1個字
        f_temp = temp*0.0625;//溫度在寄存器中為12位,分辨率為0.0625 廠家出廠時默認精度為12位,所以乘以0.0625
        temp=f_temp*10+0.5; //乘以10表示小數點后面只取一位,加0.5是為了四舍五入
        f_temp=f_temp+0.05;
        return temp;
        }

        12.內部ram的擴展

        51單片機存儲器模式一共有三種
        small模式 默認變量存儲在單片機內部的128B RAM中
        無聲明均以這個模式存儲
        compact模式 默認變量存儲在單片機內部的 256B RAM中
        關鍵字 pdata :unsinged char pdata a[100]
        large 模式 默認變量均存儲在64K的RAM區包括內部ram和外部ram
        關鍵字 xdata:unsingned char xdata a[100]
        三種模式的不同:訪問速度由快到慢

        這個博客里的涉及的源代碼大家可以在這里下載http://download.csdn.net/detail/zhaole20094463/4427745



        關鍵詞: 51單片機學習總

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 台南县| 阳信县| 兴隆县| 龙岩市| 枣庄市| 筠连县| 淄博市| 马山县| 奇台县| 西盟| 关岭| 金平| 廊坊市| 牙克石市| 绥化市| 汪清县| 长治市| 苗栗县| 西充县| 临潭县| 阳原县| 宁南县| 濉溪县| 于田县| 无棣县| 洛浦县| 溆浦县| 苏尼特右旗| 白银市| 顺昌县| 辛集市| 莱阳市| 兴文县| 徐水县| 彭泽县| 湘乡市| 开阳县| 毕节市| 南华县| 攀枝花市| 丘北县|