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

    80C51串行口通信

    作者:佚名   來源:本站原創   點擊數:  更新時間:2014年04月19日   【字體:

    80C51串行口的結構



    TXD  是80C51單片機的P3.1口

    RXD  是80C51單片機的P3.0口

    T1 溢出率 是定時器1 的溢出率  SMOD  是發送速率倍頻的   16分頻  T1每溢出一次發送一位,里面復雜咱們不管,每次發送完后TI 申請中斷,就是串口每次發送完一個字節去申請一個中斷,每接受完一個字節它也要申請一次中斷。接受完了通過移位寄存器  SBUF 取走。發送也用SBUF .

     

    單片機上有兩個物理上獨立的接受,發送緩沖器SBUF,它們占用同一地址99H;接受器是雙緩沖結構;發送緩沖器,因為發送時CPU是主動的,不會產生重疊錯誤。

    解釋下這句話意思:物理上獨立的但是地址相同,但是具體內部構造咱們不去了解它。2個寄存器一個負責發一個負責收,接受是雙緩沖的結構。如果去取數據  A=SBUF   ; 發送數據  SBUF =A;   就是說SBUF =A 就把A 發出去了。  A= SBUF 就是 把 SBUF 的值給取出來給了A。單片機的串口就是這么簡單。主要要搞好中斷和比特率。

    80C51串行口的控制寄存器

       SCON 是一個特殊功能寄存器,用以設定串行口的工作方式、接受/發送控制以及設置狀態標志;


    有此圖課看出地址誒98H 能對8整除 所以可以進行位操作。
    ●SMO 和SM1為工作方式選擇位,可選擇四種工作方式:如下圖



    串行口有4種工作方式。 0 、1、2、3。  f方式0 可以看出  是移位寄存器就是一位一位移位了,波特率是固定的晶振除以12    Fosc(oscillator 振蕩器),方式1 是10位異步收發器(8位數據),波特率可變。一下 2、3 類同。我們主要掌握方式1就OK。用的最多的也是方式1。波特率用軟件控制,設置多少就多少。由于選擇方式1 所以SMO SM1 就是   。

    ●SM2,多機通信控制位,主要用于方式2和方式3。當接收機的SM2=1時可以利用收到的RB8來控制是否激活RI(RB8=0時不激活RI,收到的信息丟棄;RB8=1時收到的數據進入SBUF,并激活RI,進而在中斷服務中將數據從SBUF讀走)。當SM2=0時,不論收到的RB8為0和1,均可以使收到的數據進入SBUF,并激活RI(即此時RB8不具有控制RI激活的功能)。通過控制SM2,可以實現多機通信。

    在方式0時,SM2必須是0。在方式1時,若SM2=1,則只有接收到有效停止位時,RI才置1。
          因為我們就是1個單片機所以SM2就是0了。有效停止位用到RB8  有用到校驗的時候

    ●REN,允許串行接收位。由軟件置REN=1,則啟動串行口接收數據;若軟件置REN=0,則禁止接收。

        所以我們需要設置為1,就能接受數據了。 REN=1;

     


    ●TB8,在方式2或方式3中,是發送數據的第九位,可以用軟件規定其作用?梢杂米鲾祿钠媾夹r炍,或在多機通信中,作為地址幀/數據幀的標志位。
    在方式0和方式1中,該位未用。

      而我們用方式1 所以不設置也可以,給0也沒問題,因為這個寄存器上電時候全都是0.


    ●RB8,在方式2或方式3中,是接收到數據的第九位,作為奇偶校驗位或地址幀/數據幀的標志位。在方式1時,若SM2=0,則RB8是接收到的停止位。

       因為我們是方式1所以不用管它了。SM2=0 所以這里接到是停止位。因為我們不用校驗位 TB8  RB8 都設置0就行了。

     

     

     

    ●TI,發送中斷標志位。在方式0時,當串行發送第8位數據結束時,或在其它方式,串行發送停止位的開始時,由內部硬件使TI置1,向CPU發中斷申請。在中斷服務程序中,必須用軟件將其清0,取消此中斷申請。

    ●RI,接收中斷標志位。在方式0時,當串行接收第8位數據結束時,或在其它方式,串行接收停止位的中間時,由內部硬件使RI置1,向CPU發中斷申請。也必須在中斷服務程序中,用軟件將其清0,取消此中斷申請。

    TI  RI 這兩位比較重要  TI 是發送停止位 硬件置1,  申請中斷,響應中端時候必須清0,這個中斷就退出了,不然就會又進入中斷了。RI 類似。所剛開始的時候是硬件置1 所以不用管 。  給0 0 就行了。

    PCON 寄存器中有一位SMOD與串行口工作有關:



    PCON寄存器是單片機的跟電源有關系的。  比如讓單片機進入、休眠、掉電、低功耗狀態等。其他幾位可以去找找看資料。

         SMOD(PCON.7)  波特率倍增位。在串行口方式1、方式2、方式3時,波特率與SMOD有關,當SMOD=1時,波特率提高一倍。復位時,SMOD=0。

    就是工作的時候你想讓波特率加倍就把SMOD =1就行了。咱們不用設置它

     

    80C51串行口的工作方式

    一、方式0
       方式0時,串行口為同步移位寄存器的輸入輸出方式。主要用于擴展并行輸入或輸出口。數據由RXD(P3.0)引腳輸入或輸出,同步移位脈沖由TXD(P3.1)引腳輸出。發送和接收均為8位數據,低位在先,高位在后。波特率固定為fosc/12。  
       1、方式0輸出



    方式0咱們就不用看了

     二、方式1
        方式1是10位數據的異步通信口。TXD為數據發送引腳,RXD為數據接收引腳,傳送一幀數據的格式如圖所示。其中1位起始位,8位數據位,1位停止位。 

     

     寫入SBUF  就是SBUF = 0X01 這就寫入了、停一下 TXD 就發起始  數據  停止   停止開始的時候TI就置1.說明數據就發完了。

    2、方式1輸入


    方式1的輸入就是接受端


        用軟件置REN為1時,接收器以所選擇波特率的16倍速率采樣RXD引腳電平,檢測到RXD引腳輸入電平發生負跳變時,則說明起始位有效,將其移入輸入移位寄存器,并開始接收這一幀信息的其余位。接收過程中,數據從輸入移位寄存器右邊移入,起始位移至輸入移位寄存器最左邊時,控制電路進行最后一次移位。當RI=0,且SM2=0(或接收到的停止位為1)時,將接收到的9位數據的前8位數據裝入接收SBUF,第9位(停止位)進入RB8,并置RI=1,向CPU請求中斷。

     

    這樣理解 是收到起始位  就收 數據 從低位 開始收 收到 停止位中間 RI 置1

    三、方式2和方式3(我這里提供點資料,用的幾率不大)

       方式2或方式3時偉11位數據的異步通信口。TXD位數據發送引腳,RXD 為數據的接受引腳。




        方式2和方式3時起始位1位,數據9位(含1位附加的第9位,發送時為SCON中的TB8,接收時為RB8),停止位1位,一幀數據為11位。方式2的波特率固定為晶振頻率的1/64或1/32,方式3的波特率由定時器T1的溢出率決定。
    1、方式2和方式3輸出

     
         發送開始時,先把起始位0輸出到TXD引腳,然后發送移位寄存器的輸出位(D0)到TXD引腳。每一個移位脈沖都使輸出移位寄存器的各位右移一位,并由TXD引腳輸出。
         第一次移位時,停止位“1”移入輸出移位寄存器的第9位上,以后每次移位,左邊都移入0。當停止位移至輸出位時,左邊其余位全為0,檢測電路檢測到這一條件時,使控制電路進行最后一次移位,并置TI=1,向CPU請求中斷。

    2、方式2和方式3輸入

     

     

     


        接收時,數據從右邊移入輸入移位寄存器,在起始位0移到最左邊時,控制電路進行最后一次移位。當RI=0,且SM2=0(或接收到的第9位數據為1)時,接收到的數據裝入接收緩沖器SBUF和RB8(接收數據的第9位),置RI=1,向CPU請求中斷。如果條件不滿足,則數據丟失,且不置位RI,繼續搜索RXD引腳的負跳變。

     

     


    四、波特率的計算   這個重點一定要掌握
        在串行通信中,收發雙方對發送或接收數據的速率要有約定。通過軟件可對單片機串行口編程為四種工作方式,其中方式0和方式2的波特率是固定的,而方式1和方式3的波特率是可變的,由定時器T1的溢出率來決定。
        串行口的四種工作方式對應三種波特率。由于輸入的移位時鐘的來源不同,所以,各種方式的波特率計算公式也不相同。
    方式0的波特率 =  fosc/12
    方式2的波特率 =(2SMOD/64)· fosc        smod 要么0 要么1  32分子1  和64分子1 晶振頻率
    方式1的波特率 =(2SMOD/32)·(T1溢出率)
    方式3的波特率 =(2SMOD/32)·(T1溢出率)

    這就是公式不要問為什么了,T1的溢出率怎么計算呢?看下面

     

          當T1作為波特率發生器時,最典型的用法是使T1工作在自動再裝入的8位定時器方式(即方式2,且TCON的TR1=1,以啟動定時器)。這時溢出率取決于TH1中的計數值。

    定時器作為波特率發生器時,就是定時器工作在方式2 自動重裝
             T1 溢出率 = fosc /{12×[256 -(TH1)]}

    T1 溢出率就是1秒鐘溢出多少次。如果你裝滿  就255 256-255=1  12*1 =12  12M晶振 除以12 =1 所以就是1秒溢出一次。依次類推你算下。
         在單片機的應用中,常用的晶振頻率為:12MHz和11.0592MHz。所以,選用的波特率也相對固定。常用的串行口波特率以及各參數的關系如表所示。



    現在算一個波特率

    如11.0592的晶振


    我們直接設置 SMOD =0  那么2的0次方 等于1
    因為  11059200 除以 9600 = 1152    、



    為什么選用11.0592的晶振就是波特率好算  上面 是一個整數1152 所以波特率容易算。  如果用12MHZ 結果會有小數。就會有誤差不精確。如果串口通訊就會出錯,因為晶振采樣率采錯位置了。

     

    得到TH1 = 253  換成16進制=FD 查上表  一致,F在很多人圖方便直接用軟件來計算了。但是這個過程還是必須的要了解的。 還有一點是就是SMOD 這一位是設置倍頻的。

           串行口工作之前,應對其進行初始化,主要是設置產生波特率的定時器1、串行口控制和中斷控制。具體步驟如下:

    • 確定T1的工作方式(編程TMOD寄存器);
    • 計算T1的初值、裝載TH1/TL1;
    • 啟動T1(變成TCON中的TR1位)
    • 確定串行口控制(編程SCON寄存器);

       串行口在中斷方式工作時,要進行中斷設置(編程IE、IP寄存器)。(就是如果用中斷還得配置 串行口優先級IP 寄存器  IE寄存器)

    • 單片機串行口應用舉例

               在計算機組成的測控系統中,經常要利用串行通信方式進行數據傳輸。80C51單片機的串行口為計算機間的通信提供了極為便利的條件。利用單片機的串行口還可以方便地擴展鍵盤和顯示器,對于簡單的應用非常便利。這里僅介紹單片機串行口在通信方面的應用。

    一、單片機與單片機的通信。

    (一)、點對點的通信 
    1、硬件連接

     

    (二)、多機通信

    個人理解:這個串口多機通信其實跟I2C 同步通信協議差不多。區別是串口是異步的。而I2C是同步通信的。是在時鐘沿的跳變期間發生變化作為開始。(之前本人學過ARM I2C總線協議,大概還記得點)。

      1、硬件連接
       單片機構成的多機系統常采用總線型主從式結構。所謂主從式,即在數個單片機中,有一個是主機,其余的是從機,從機要服從主機的調度、支配。80C51單片機的串行口方式2和方式3適于這種主從式的通信結構。當然采用不同的通信標準時,還需進行相應的電平轉換,有時還要對信號進行光電隔離。在實際的多機應用系統中,常采用RS-485串行標準總線進行數據傳輸。



    2、通信協議
    所有從機的SM2位置1,處于接收地址幀狀態。
    主機發送一地址幀,其中8位是地址,第9位為地址/數據的區分標志,該位置1表示該幀為地址幀。  
    所有從機收到地址幀后,都將接收的地址與本機的地址比較。對于地址相符的從機,使自己的SM2位置0(以接收主機隨后發來的數據幀),并把本站地址發回主機作為應答;對于地址不符的從機,仍保持SM2=1,對主機隨后發來的數據幀不予理睬。
    從機發送數據結束后,要發送一幀校驗和,并置第9位(TB8)為1,作為從機數據傳送結束的標志。

     主機接收數據時先判斷數據接收標志(RB8),若RB8=1,表示數據傳送結束,并比較此幀校驗和,若正確則回送正確信號00H,此信號命令該從機復位(即重新等待地址幀);若校驗和出錯,則發送0FFH,命令該從機重發數據。若接收幀的RB8=0,則存數據到緩沖區,并準備接收下幀信息。
    主機收到從機應答地址后,確認地址是否相符,如果地址不符,發復位信號(數據幀中TB8=1);如果地址相符,則清TB8,開始發送數據。
    從機收到復位命令后回到監聽地址狀態(SM2=1)。否則開始接收數據和命令。

     

     3、應用程序
    主機發送的地址聯絡信號為:00H,01H,02H ,… …(即從機設備地址),地址FFH為命令各從機復位,即恢復SM2=1。
    主機命令編碼為:01H,主機命令從機接收數據;02H,主機命令從機發送數據。其它都按02H對待。

     

     
    RRDY=1:表示從機準備好接收。
    TRDY=1:表示從機準備好發送。
    ERR=1: 表示從機接收的命令是非法的。
         程序分為主機程序和從機程序。約定一次傳遞數據為16個字節,以01H地址的從機為例。

    我們重點是要會程序去控制單片機和計算機來傳輸數據。
     -------------------------------------------------------------------------------------

    寫一個程序:

    思路:首先得讓單片機能收到數據,這數據怎么給單片機呢?我們用計算機來發,用串口調試助手,記住不能和下載程序工具STC-ISP用同一個串口,不然會沖突,到時候軟件會提示串口不存在等信息。如果是同一個串口那么你可以先把串口調試助手關閉串口然后再下載程序。



    我們寫一個程序需求:

    上位機通過串口調試助手,隨便發送一個數,如果單片機收到這個數,就讓單片機點亮一個發光二極管。調試程序就這樣,先看它能不能收到數然后再判斷是什么數,做什么樣的動作。我們先收到這個數就把發光二極管點亮,收不到就不亮。

    #include

     

    void main(){

    //進了主函數就不停的檢測收到的數據,那就大循環

          //我們設成了8位異步收發器了。方式1

     TR1 =1; //啟動定時器1 TCON 控制寄存器中   打開定時器。

         //TCON 低四位用于控制外部中斷,高四 位 用于控制定時、計數的啟動好申請中斷。

        //TF1   TF0  他倆硬件自動置1 置0  可以用作查詢測試

         // TR1  TR0 是T1 的運行控制位   是由軟件控制

     TMOD = 0x20;    //1   是2  是2 0   設置定時器1 為工作方式2.

       //TMOD 高4位控制 T1 定時器  T0 控制T0 定時器

    TH1 = 0XFD;//算的 9600  

    TL1 = 0xFD;//也就是TL1 裝滿了 TH1 自動裝 TL1 這就是方式2

    REN =1;// 把SCON 寄存器的REN 位 置 1  表示 接受。

      SM0= 0;

      SM1=1;//如果不設置這2位 就默認 0 當移位寄存器用了。所以必須設置

     

     

     

      while(1){

                  

          //2種方法  :1 查詢RI是否置位 如果置位了,說明收到了數據。

          //2.如果置位了 會想單片機申請中斷,那么我們就寫一個中斷函數,因為中斷是自動進入的,已有中

    //斷就自動進入。第一個叫查詢法 第二種叫中斷法 。我們先寫查詢法。

        if (1== RI )//是0 的為真 一直循環在這里,若果收到一幀數據 硬件自動置1  為假  跳出來執行下面

       {

        RI= 0;//先把RI 清0  這樣就保證還能進行下一幀數據

        //P1 = 0XFE;

        P1 = SBUF ; // 這樣你發的數據就放在SBUF 里了 然后把SBUF 再賦值給P1 ;

     

        }

        //1?、為什么會復位也亮呢?原因是 沒有設定模式 SM0 SM1;   解決就不亮了

     

        //2?、還是發送  不亮  為什么呢?收不到數據?說明沒有設置波特率 無法檢測這個數 ,

          //只有把定時器設置成方式2.因為定時器方式2是8位重裝的。所以可以用在溢出的話就能算波特率了。

     

    //設置比特率之前需設置TMOD

        //以上2 ?注意啊。 就OK了

     }

     

    }

     

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

    //到這里你發 55  aa   就能讓燈  亮  0101 0101   1010  1010  呵呵

    //正好8位一個字節發過去 賦值給P1 口上去了。  改成4800  就不對了 因為采樣率不對了,就不準了

    //上面是查詢法,if  不能用while () 判斷

    //在工程中  呢 就是前幾個字節表示什么 ,后面幾個東西表示什么用程序實現。

    、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

    用中斷法實現下

    #include

     

     

    void main(){

    //開定時總開關

    EA =1 ;

    ES =1 ;//使能串口中斷

    TMOD =0X20;//定時器方式2

    TR1=1;//運行定時器

     

    TH1= 0XFD;/裝值

    TL1= 0XFD;

    REN =1;//串口使能接受

    SM0D0 = 0;//串口工作模式  8位異步模式

    SMOD1 = 1;

     

      while(1){

         

          

     

        }

     

    }

    void serial() interrupt 4 {

     RI=0;

     P1 = SBUF;

     

     

    //串口和定時器很像  哦! 串口收到數通知單片機,讓單片機處理這個數,

    //定時器溢出 通知單片機讓單片機重新裝置。

    //剛下載有數據收到 當有燈亮 所復位下就OK了

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

    接下來我們讓單片機收到什么東西再發回來。就是發送這一塊。

    #include

     

    usning char  flag, a;

    void main(){

    EA =1;

    ES =1;

    TMOD =0X20;

    TR1 =1;

    TH1 = 0XFD;

    TL1 =0XFD ;//9600 波特率

    SMOD0=0;//設置串口工作模式

    SMOD1 =1;

    REN =1; //讓串口能夠接受

       while(1){

          if (1==flag){

             flag =0 

          

             SBUF = a;//同一個地址但是是兩個SBUF 當這樣賦值時候就是賦值給發送的SBUF

          }

     

       }

    }

     

    void serial() interrupt 4

    {

       RI=0;

       P1 = SBUF ;  //表示接受緩沖區 就是等號左右的區別決定 是接受 發送SBUF

       a= SBUF;

       flag =1;

     

    }

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

    //上面程序有個問題是已下載程序  復位就一直收到FF  原因:

    //因為 單片機上電會判斷有沒有上位機下載程序,而我們下載程序了已經有中斷  把  flag 賦值了 

    // SBUF =a 發完了 TI 置1  又進入中斷4   也就是 RI TI 都進入 interrupt 4  So 循環發送。死循環

    //一直發數據   發了數據就置1   置1 就中斷循環

    ======================================

    解決方法如下

     

    #include

     

    usning char  flag, a;

    void main(){

    EA =1;

    ES =1;

    TMOD =0X20;

    TR1 =1;

    TH1 = 0XFD;

    TL1 =0XFD ;//9600 波特率

    SMOD0=0;//設置串口工作模式

    SMOD1 =1;

    REN =1; //讓串口能夠接受

       while(1){

          if (1==flag){

             flag =0 

             ES =0;//串口中斷關掉了 //再發就不會 進中斷

             SBUF = a;//同一個地址但是是兩個SBUF 當這樣賦值時候就是賦值給發送的SBUF

            //也可以是字符 SBUF = ‘b’ 也行  如果你寫SBUF =128  那么他是16進制顯示 80 

        //其實可以128分開 ‘ 1’ ‘ 2’  ‘ 8’ 發3次  多數可以寫個for 循環分離開 循環發出來。

             //檢測是否發完了

             while (!TI);//發完了 置1  取非    我覺得應該取反  而不是邏輯非   沒發完等在這里

                 TI =0;//清 0  手動清0  到這里不會產生中斷因為上面中斷關了 呵呵

                 ES =1;//打開串口中斷 

           

          }

        }

    }

     void serial() interrupt 4

    {

       RI=0;

       P1 = SBUF ;  //表示接受緩沖區 就是等號左右的區別決定 是接受 發送SBUF

       a= SBUF;

       flag =1;

     

    }

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

    注意:如果發的不是十六進制  比如發1  收到是31 ASCII碼的對應關系。C語言書后面有。1 對應31   

    如果發  hello everyone!  返回來hello everyone! 對應ASCII碼有  如果十六進制發55a 收到55 因為你發的不夠 16進制數 a 就給你去掉了

    //自己認為單片機只有REN  控制單片機允許接收,為什么沒有TEN 控制單片機允許發送的位呢

    //還有 TI RI  位都是單片機內部硬件  發送 接收完一幀 數據自動置1   需程序員 清 0

    //使用中斷法 控制串口需要注意: 

    //用串口記得設置定時器 裝初值 、串口模式  接收允許 開中斷 (總中斷和串口中斷)

    關閉窗口

    相關文章

    亚洲一区二区制服在线|在绩专区欧美自拍日韩|青春娱乐网97超碰人人射|在线观看国产网址你懂的