多機串口通訊

來源:互聯網
上載者:User

多機串口通訊
★使用器件

使用了3塊80c51的單片機,其中U1為主機控制其他兩個從機U2,U3。每個單片機上都有一個數位管用來顯示資料。主機上有兩個按鍵KEY_1,KEY_2,分別用來控制不同的從機。

★實現目標

主要實現的目標就是通過寫多機通訊來瞭解他們其中的協議,以及簡單協議的寫法!本程式主要達到了一下效果,主機可以通過發送命令來控制從機:發送資料給從機、接收從機的資料。然後將從機或者主機顯示的資料顯示在數位管上。

★協議要求1、地址:主機的地址設定為0x01,從機1(U3)的地址為0x03,從機2(U2)的地址為0x022、命令:

0x01表示:主機向從機發送資料

0x02表示:從機向主機發送數劇

3、基本步驟:

●主機發送地址幀,從機接收到地址幀後就會與本機地址進行比對,如果正確則發送自己的地址應答;如果不正確,則丟棄資料,繼續監測等待資料;

●從機接收地址正確後,返回自己的地址作為應答訊號;如果主機接收到的資料與自己發送的地址資料相同,就會發送命令(是讓從機接收資料還是發送資料);如果與自己發送的地址資料不同,則發送0xff,當從機接收到資料得到RB8 ==1,則進入繼續監測等待資料。

●主機發送命令,從機接收到命令後,就會返回接收到的命令作為應答(沒有處理異常情況);主機監測到應答資料正確就會發送資料,並且等待從機的應答訊號(0x11),接收到應答訊號後,再發送第二個資料(這個地方主機沒有處理異常情況),指導發送資料結束

●發送資料接收後,主機會發送校正和,與從機接收的資料的校正和比較,如果檢驗和相同說明發送資料正確,然後就退出程式;如果檢驗和發送不正確則重新發送資料。

4、具體實現

串列口有一個很重要的寄存器: 

SM2為多機通訊控制位。當從機的SM2=1時,可以利用收到的RB8來控制RI。當RB8 = 1接收資料並且使RI = 1,當RB8 = 0時不接受資料;當SM2= 0時,無論RB8是否為1都會接收資料,並且使RI = 1。因此可以根據這個特點來區別地址和資料。從機首先將SM2置1,然後將要發送資料的TB8置1,從機接收到資料後就會比較地址是否與本機地址相同,如果相同就是將SM2置0,然後發送資料(TB = 0),而其他的從機仍然處於SM=1的狀態,接收不到資料。★電路圖
★程式實現主機:
#include <reg52.h>#define uint unsigned int#define uchar unsigned charsbit key_1 = P1^0;sbit key_2 = P1^1;sbit Led = P1^7;#define master_U1 0x01 //主機地址#define slave_U2 0x02  //從機地址#define slave_U3 0x03  //從機地址uchar tbuf[16] = {0x3f,0x06,0x5b,0x4f,   0x66,0x6d,0x7d,0x07,   0x7f,0x6f,0x77,0x7c,   0x39,0x5e,0x79,0x71};uchar rbuf[16];//待接收資料的數組void DelayUs2x(unsigned char t){   while(--t);}void DelayMs(unsigned char t){     while(t--){ //大致延時1mS DelayUs2x(245); DelayUs2x(245);}}void Uart_init(void){SCON |= 0xf8;//工作方式1,T1,R1置零,允許串列口接收資料TMOD |= 0x20;//定時器1,模式2 TH1 = 0xFD;TL1 = 0xFD;TR1 = 1;EA = 1;//開啟總中斷 ES = 1;//開啟串口中斷 }void master_send(uchar addr,uchar command){    uchar status,check,i = 0;SBUF = addr;//發送要操作的地址while(!TI);DelayMs(10);TI = 0;//發送從機地址    while(!RI);RI = 0;//等待從機地址回覆    if(addr!=SBUF)//如果返回的地址與要操作的地址不同{    SBUF=0xff;while(!TI);    TI=0;}else{    TB8=0;SBUF=command;while(!TI);TI = 0;//發送命令while(!RI);RI = 0;//等待從機的回複        status = SBUF; //從機發送確認命令if(status == 0x80){    TB8 = 1;}  else{if(status == 0x01)//主機知道從機已經準備好接收資料,就進入發送狀態{while(1){check = 0;for(i = 0;i < 16;i++){    SBUF = tbuf[i];while(!TI);TI = 0;    while(!RI);//等待從機返回確認訊號0x11    RI = 0;check += tbuf[i];//校正和DelayMs(2000);} SBUF = check;//向從機發送校正和while(!TI);//發送校正和給從地址TI = 0; while(!RI);RI = 0;//接收從地址返回的資料(0x00或者0xff)                       if(SBUF == 0x00){    break; }    //接收到0x00表明校正正確,則跳出發送函數,如果接收到0xff則表明校正出錯,重新發送    } }if(status == 0x02)//主機知道要接收來自從機的資料了{    while(1){    check = 0;   for(i = 0;i < 16; i++){    while(!RI);RI = 0;rbuf[i] = SBUF;P2 = rbuf[i];SBUF = 0x11;//每收到一個資料,發送0x11while(!TI);//表示接受到資料後的確認TI = 0;    check += rbuf[i];}        while(!RI);RI = 0;if(check == SBUF)//如果主機資料的校正和與從機的校正和相等,則返回主機0x00{ //否則,需要重新等待接收資料。    SBUF = 0x00;while(!TI);TI = 0;P2 = 0;break;}} }}  }  }void main(){Uart_init();P2 = 0;  Led = 1;    if(!key_1){    DelayMs(20);if(!key_1){    master_send(slave_U2,0x02);}} if(!key_2){DelayMs(20);if(!key_2){    master_send(slave_U3,0x01);}Led = 0;}}
從機1:
/**從機1 U3**/#include <reg52.h>#define uint unsigned int#define uchar unsigned char//#define slave_U2 0x02#define slave_U3 0x03sbit key = P1^0;static uchar tbuf[] = {0x3f,0x06,0x5b,0x4f,    0x66,0x6d,0x7d,0x07,    0x7f,0x6f,0x77,0x7c,    0x39,0x5e,0x79,0x71};static uchar rbuf[16];void Uart_receive();void Send_receive();void DelayUs2x(unsigned char t){   while(--t);}void DelayMs(unsigned char t){    while(t--){ //大致延時1mS DelayUs2x(245); DelayUs2x(245);}}void Uart_init()//串口初始化{    PCON = 0;    SCON |= 0xf8; TMOD |= 0x20;TH1 = 0xfd;TL1 = 0xfd;TR1 = 1; EA = 1;ES = 1;}void main(){P2 = 0;Uart_init();while(1);}void Ser_uart() interrupt 4{    uchar save;RI = 0;ES = 0;if(SBUF != slave_U3){    ES = 1;        goto end; //如果發送的從機地址與本從機地址不相符則,執行此語句。}    SM2 = 0;//設定為單擊模式SBUF = slave_U3;//發送從機地址給主機while(!TI);    TI = 0;while(!RI);//接收主機發來的命令RI = 0;    if(RB8 == 1)//如果返回的地址出錯誤,則發送0xff,RB8 = 1;{SM2 = 1;ES = 1;goto end;//進入等待地址幀模式}    save = SBUF;//將接收到的命令存在save中 if(save == 0x01)//如果接收的命令是0x01{    SBUF = 0x01;//向主機發送03表示確認,已經做好準備while(!TI);     TI = 0;Uart_receive();//進入接收狀態等待}    else{    if(save == 0x02){    SBUF = 0x02;//告訴主機,要準備發送資料了while(!TI);TI = 0;    Send_receive();//進入發送資料函數}else{   SBUF = 0x80;   while(!TI);   TI = 0;   SM2 = 1;   ES = 1;   goto end;}} end:;}void Uart_receive(){    uchar check,i;while(1){check = 0;for(i = 0;i < 16;i++){    while(!RI);RI = 0;rbuf[i] = SBUF;P2 = rbuf[i];//顯示接受到的資料SBUF = 0x11;//每收到一個資料,發送0x11while(!TI);//表示接受到資料後的確認TI = 0;check += rbuf[i];}    while(!RI);RI = 0;         if(SBUF == check)//如果主機資料的校正和與從機的校正和相等,則返回主機0x00{    SBUF = 0x00;while(!TI);TI = 0;P2 = 0;break;}  else//如果主機資料的校正和與從機的校正和不相等,則重新發送資料{    SBUF = 0xff;while(!TI);TI = 0;} }}void Send_receive(){    uchar check,i;while(1){    check = 0;for(i = 0;i < 11;i++){    SBUF = tbuf[i];while(!TI);TI = 0;check += tbuf[i];}SBUF = check;while(!TI);//發送校正資料TI = 0;   while(!RI);RI = 0;//等待校正結果,接收主地址返回的資料(0x00或者0xff)        if(SBUF == 0x00)break;//接收到0x00表明校正正確,則跳出發送函數,如果接收到0xff則表明校正出錯,重新發送      } while(1){    for(i = 0;i < 16;i ++)    P2 = rbuf[i];DelayMs(1000);}}
從機2::
/**從機2,電路圖U2**/#include <reg52.h>#define uint unsigned int#define uchar unsigned char#define slave_U2 0x02//#define slave_U3 0x03sbit Key = P1^0;static uchar tbuf[] = {0x3f,0x06,0x5b,0x4f,    0x66,0x6d,0x7d,0x07,    0x7f,0x6f,0x77,0x7c,    0x39,0x5e,0x79,0x71};static uchar rbuf[16];void Uart_receive();void Send_receive();static uchar rbuf[16];void DelayUs2x(unsigned char t){   while(--t);}void DelayMs(unsigned char t){     while(t--){ //大致延時1mS DelayUs2x(245); DelayUs2x(245);}}void Uart_init()//串口初始化{    PCON = 0;    SCON |= 0xf8; TMOD |= 0x20;TH1 = 0xfd;TL1 = 0xfd;TR1 = 1; EA = 1;ES = 1;}void main(){    P2 = 0;Uart_init();while(1);}void Ser_uart() interrupt 4{    uchar save;RI = 0;ES = 0;if(SBUF != slave_U2){    ES = 1;        goto end; //如果發送的從機地址與本從機地址不相符則,執行此語句。}    SM2 = 0;//設定為單擊模式SBUF = slave_U2;//發送從機地址給主機while(!TI);    TI = 0;while(!RI);//接收主機發來的命令RI = 0;    if(RB8 == 1)//如果返回的地址出錯誤,則發送0xff,RB8 = 1;{SM2 = 1;ES = 1;goto end;//進入等待地址幀模式}    save = SBUF;//將接收到的命令存在save中if(save == 0x01)//如果接收的命令是0x01{    SBUF = 0x01;//向主機發送01表示確認,已經做好準備while(!TI);    TI = 0;Uart_receive();//進入接收狀態等待}    else{    if(save == 0x02){    SBUF = 0x02;//告訴主機,要準備發送資料了while(!TI);TI = 0;        Send_receive();//進入發送資料函數//DelayMs(1000);}else{   SBUF = 0x80;   while(!TI);   TI = 0;   SM2 = 1;   ES = 1;   goto end;} }  end:;}void Uart_receive(){    uchar check,i;while(1){check = 0;for(i = 0;i < 11;i++){    while(!RI);RI = 0;tbuf[i] = SBUF;SBUF = 0x11;//每收到一個資料,發送0x11while(!TI);//表示接受到資料後的確認TI = 0;check += tbuf[i];}    while(!RI);RI = 0;        if(SBUF == check)//如果主機資料的校正和與從機的校正和相等,則返回主機0x00{    SBUF = 0x00;while(!TI);TI = 0;break;}else//如果主機資料的校正和與從機的校正和不相等,則重新發送資料{    SBUF = 0xff;while(!TI);TI = 0;} }}void Send_receive(){    uchar check,i;while(1){    check = 0;   for(i = 0;i < 16;i++){    SBUF = tbuf[i];while(!TI);TI = 0;while(!RI); RI = 0;check += tbuf[i];DelayMs(2000);}SBUF = check;while(!TI);//發送校正資料TI = 0;   while(!RI);RI = 0;//等待校正結果,接收主地址返回的資料(0x00或者0xff)        if(SBUF == 0x00)break;//接收到0x00表明校正正確,則跳出發送函數,如果接收到0xff則表明校正出錯,重新發送      }}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.