新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > avr單片機(jī)串口多機(jī)通訊及實(shí)例

        avr單片機(jī)串口多機(jī)通訊及實(shí)例

        作者: 時(shí)間:2016-12-03 來源:網(wǎng)絡(luò) 收藏
        在多機(jī)通信過程中,所有設(shè)備的 RS232接口是并在通信線上的,其中只能有一個(gè)設(shè)備為主機(jī),其他為從機(jī),通信由主機(jī)發(fā)起。數(shù)據(jù)幀一般采用1位起始位、9位數(shù)據(jù)位,其中第9位(RXB8)被用作為表征該幀是地址幀還是數(shù)據(jù)幀。當(dāng)幀類型表征位為“1”時(shí),表示該幀數(shù)據(jù)為一個(gè)地址幀;當(dāng)幀類型表征位為“0”時(shí),表示這個(gè)幀為一個(gè)數(shù)據(jù)幀。

          在AVR中,通過設(shè)置從機(jī)的UCSRA寄存器中標(biāo)志位MPCM,可以使能USART接收器對(duì)接收的數(shù)據(jù)幀進(jìn)行過濾的功能。如果使能了過濾功能,從機(jī)接收器對(duì)接收到的那些不是地址信息幀的數(shù)據(jù)幀將進(jìn)行過濾,不將其放入接收緩沖器中,這在多機(jī)通信中有效的方便了從機(jī)MCU處理數(shù)據(jù)幀程序的編寫(同標(biāo)準(zhǔn)51 結(jié)構(gòu)相比)。而發(fā)送器則不受MPCM位設(shè)置的影響。
          多機(jī)通信模式允許多個(gè)從機(jī)并在通信線路上,接收一個(gè)主機(jī)發(fā)出的數(shù)據(jù)。通過對(duì)接收到的地址幀中的地址進(jìn)行解碼,確定哪個(gè)從機(jī)被主機(jī)尋址。如果某個(gè)從機(jī)被主機(jī)尋址,它將接收接下來主機(jī)發(fā)出的數(shù)據(jù)幀,而其它的從機(jī)將忽略數(shù)據(jù)幀,直到再次接收到一個(gè)地址幀。(從機(jī)地址是由各個(gè)從機(jī)自己的軟件決定的)。
          對(duì)于在多機(jī)通信系統(tǒng)中的主機(jī)MCU,可以設(shè)置使用9位數(shù)據(jù)幀結(jié)構(gòu)(UCSZ=7)。當(dāng)發(fā)送地址幀時(shí),置第9位為“1”;發(fā)送數(shù)據(jù)幀時(shí),置第9位為 “0”。在這種情況下,從機(jī)也必須設(shè)置成接收9位數(shù)據(jù)幀結(jié)構(gòu)。
          多機(jī)通信方式的數(shù)據(jù)交換過程如下:
        1)設(shè)置所有從機(jī)工作在多機(jī)通信模式(MPCM=1)。
        2) 通信開始是由主機(jī)先發(fā)送一個(gè)地址幀,如8位數(shù)據(jù)為0X01(1號(hào)從機(jī)地址),第9位=“1”,呼叫1號(hào)從機(jī)。
        3)所有從機(jī)都接收和讀取該主機(jī)發(fā)出的地址幀。在所有從機(jī)的MCU中,RXC標(biāo)志位被置位,表示接收到地址幀。
        4)每一個(gè)從機(jī)MCU讀UDR寄存器,并判斷自己是否被主機(jī)尋址。如果被尋址,清UCSAR寄存器中的MPCM位,等待接收數(shù)據(jù);否則保持MPCM為 “1”,等待下一個(gè)地址幀的接收(該步應(yīng)由用戶軟件處理實(shí)現(xiàn)):
        A)作為1號(hào)從機(jī)的MCU處理過程為:收到地址幀后,判定讀取UDR數(shù)據(jù)0X01為自己的地址,將MPCM位置“0”,接收之后所有主機(jī)下發(fā)的數(shù)據(jù)幀,直到下一個(gè)地址幀為止。
        B)其它從機(jī)MCU的處理過程:收到地址幀后,判定讀取UDR數(shù)據(jù)0X01不是自己的地址,將MPCM位置“1”,這樣他們將忽略主機(jī)隨后發(fā)送的數(shù)據(jù)幀,直到主機(jī)再次發(fā)送地址幀。
        5)當(dāng)被尋址的從機(jī)MCU接收完最后一個(gè)數(shù)據(jù)幀后,將MPCM位置位,等待下一個(gè)地址幀的出現(xiàn)(該步也應(yīng)由用戶軟件處理實(shí)現(xiàn)),然后從步驟2開始重復(fù)。

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

        [轉(zhuǎn)]例子;

        通訊規(guī)則:
        1:時(shí)鐘7.3728 MHz/波特率9600/9個(gè)數(shù)據(jù)位/奇 校驗(yàn)/1個(gè)停止位/硬件多機(jī)通訊功能/
        2:通訊連接采用硬件MAX485,雙向單工
        3:每個(gè)上行/下行的數(shù)據(jù)包的字節(jié)個(gè)數(shù)都是一樣的(通訊數(shù)據(jù)量)
        4:每個(gè)上行/下行的數(shù)據(jù)包都采用CRC8校驗(yàn)
        5:數(shù)據(jù)接收采用中斷+查詢的方式
        6:總是由主機(jī)向從機(jī)發(fā)送一個(gè)數(shù)據(jù)包,從機(jī)收到數(shù)據(jù)包后向主機(jī)回復(fù)一個(gè)數(shù)據(jù)包
        7:不管是主機(jī)還是從機(jī),如果收到的數(shù)據(jù)包有任何錯(cuò)誤,都將丟棄該數(shù)據(jù)包,等 效于沒有接收
        8:從機(jī)之間不能相互通訊,必須通過主機(jī)才能交換數(shù)據(jù)
        9:無效地址是0,主機(jī)地址是1,從機(jī)地址是2.3.4......廣 播地址是255
        */
        #include
        #include
        #include
        #include //CRC校驗(yàn)函數(shù)就在這個(gè)文件里面

        #define amount 10 //設(shè)定通訊數(shù)據(jù)量(包括1個(gè) 地址幀,n個(gè)數(shù)據(jù)幀,1個(gè)校驗(yàn)幀)

        unsigned char send[amount]; //發(fā)件箱
        unsigned char inbox[amount]; //收件箱
        unsigned char n=0; //記憶中斷次數(shù)

        //--------------------------------------------------------------------
        interrupt[12] Rxd_isr(void) //接收中斷
        {
        unsigned char ERROR=0;
        if( UCSRA&4 || UCSRA&16 ) ERROR=1; //奇偶效驗(yàn)錯(cuò)誤或者幀錯(cuò)誤就記錄下來
        inbox[n]=UDR; //保存到收件箱
        n++; //記憶中斷次數(shù)
        if(ERROR) inbox[0]=0; //如果通訊有錯(cuò),收 件箱的地址幀就標(biāo)記成無效地址0
        }

        //---------------------------------------------------------------------
        void main(void)
        {
        usart_init(); //串口初始化
        UCSRA=0; //主機(jī)關(guān)閉地址篩選功能(多 機(jī)通訊功能)
        #asm("sei") //打開全局中斷
        while(1)
        {
        //-------------與從機(jī)2對(duì)話,與其他從機(jī)對(duì)話與下面的 程序類似-------------------
        n=0; //中斷次數(shù)清0
        inbox[0]=0; //收件箱地址清0
        //請(qǐng)更新準(zhǔn)備發(fā)送的數(shù)據(jù)
        //send[1]=?
        //......
        //send[n]=?
        send[0]=2; //改變這個(gè)地址就可以實(shí)現(xiàn)與某個(gè)從機(jī)對(duì)話
        send[amount-1]=crc8(send,amount-1); //計(jì)算發(fā)件箱的crc8校 驗(yàn)碼
        usart_out(send,amount); //將發(fā)件箱的數(shù)據(jù)send[]發(fā) 送出去;

        //等待,從機(jī)接收到數(shù)據(jù)后會(huì)回復(fù)數(shù)據(jù)的,如果是10個(gè) 字節(jié)數(shù)據(jù)量,不能少于13ms!!!
        //這個(gè)時(shí)間由人工計(jì)算,要考慮從機(jī)由于各種中斷延長(zhǎng)回復(fù)時(shí)間的可能

        delay_ms(15);

        //if(n<3)如果接收到的數(shù)據(jù)還不到3個(gè),那么就是通訊線路故障

        //如果收件箱已經(jīng)收到amount個(gè)數(shù)據(jù),并且crc8校 驗(yàn)成功就...
        if(n==amount && inbox[amount-1]==crc8(inbox,amount-1))
        {
        if(inbox[0]==1) //如果收件箱地址幀屬于本機(jī)就運(yùn)行下面的測(cè)試 代碼
        {
        DDRD.3=1;
        PORTD.3=1; delay_ms(10);
        PORTD.3=0; delay_ms(990);
        }

        if(inbox[0]==255)
        {
        //請(qǐng)?jiān)谶@里添加收到廣播數(shù)據(jù)的處理程序
        }
        }
        }
        } //end

        ---------------------------------------------------------------------------------
        從機(jī)
        ---------------------------------------------------------------------------------
        #include
        #include
        #include

        #define amount 10 //設(shè)定通訊數(shù)據(jù)量(包括1個(gè) 地址幀,n個(gè)數(shù)據(jù)幀,1個(gè)校驗(yàn)幀)
        #define address 2 //請(qǐng)?jiān)谶@里設(shè)定本機(jī)地址

        unsigned char send[amount]; //發(fā)件箱
        unsigned char inbox[amount]; //收件箱
        unsigned char n=0; //記憶中斷次數(shù)

        interrupt[12] Rxd_isr(void) //接收中斷
        {
        unsigned char ERROR=0;
        if( UCSRA&4 || UCSRA&16 ) ERROR=1; //記錄 奇偶效驗(yàn)錯(cuò)誤或者幀錯(cuò)誤
        inbox[n]=UDR; //把接收到的數(shù)據(jù)保存到 收件箱
        n++; //記憶接收的次數(shù)
        if(ERROR) //如果通訊有錯(cuò)....
        {
        n=0; //接收計(jì)數(shù)清0
        inbox[0]=0; //把地址改為無效地址0
        UCSRA|=0x01; //重新打開接收器的地址 幀篩選功能
        }

        //如果地址匹配本機(jī)或者是廣播地址就關(guān)閉地址篩選(多機(jī)通訊)功能
        if(inbox[0]==address ||inbox[0]==255) UCSRA&=254;

        if(n==amount) //接收到amount個(gè) 數(shù)據(jù)以后...
        {
        n=0; //接收計(jì)數(shù)清0
        UCSRA|=0x01; //重新打開接收器的地址 幀篩選功能
        if(inbox[amount-1]==crc8(inbox,amount-1)) //如果crc8校 驗(yàn)正確就...
        {
        if(inbox[0]==address) //如果地址匹配本機(jī)就回 復(fù)數(shù)據(jù)
        {
        send[0]=1; //發(fā)件箱地址指向主機(jī)
        send[amount-1]=crc8(send,amount-1);//產(chǎn)生發(fā)件箱的crc8校 驗(yàn)碼
        usart_out(send,amount); //發(fā)送發(fā)件箱的數(shù)據(jù)包send[]
        //請(qǐng)?jiān)谶@里備份你的收件箱信息
        }
        if(inbox[0]==255) //如果是廣播地址就...
        {
        //請(qǐng)?jiān)谶@里添加你的代碼
        //收到廣播數(shù)據(jù)請(qǐng)不要回復(fù)
        }
        }
        }
        }

        void main(void)
        {
        usart_init();
        #asm("sei")

        while (1)
        {
        //send[1]=?
        //......
        //send[n]=?
        };
        }


        ---------------------------------------------------------------------------------
        usart.h文件
        ---------------------------------------------------------------------------------
        //波特率9600/9個(gè)數(shù)據(jù)位/1個(gè)停止位/奇校驗(yàn)/收 發(fā)開啟/接收中斷
        void usart_init(void)
        {
        UCSRA=0x01;
        UCSRB=0x9C;
        UCSRC=0xB6;
        UBRRH=0x00;
        UBRRL=47;

        PORTD.4=0; //MAX485平時(shí)工作在接收狀態(tài)
        DDRD.4=1;
        }

        //-----------------------------------------------------------
        //從數(shù)組datas[]的首地址開始發(fā)送amount個(gè)數(shù)據(jù),其 中第0個(gè)數(shù)據(jù)是地址幀,其他是數(shù)據(jù)幀
        void usart_out(unsigned char *datas,unsigned char n)
        {
        unsigned char i=0;
        PORTD.4=1; //使MAX485處 于發(fā)送狀態(tài)
        while(i {
        if(i==0) UCSRB|=1; else UCSRB&=254;
        UDR=*(datas+i); //裝載數(shù)據(jù)開始發(fā)送
        while((UCSRA&64)==0); //等待發(fā)送結(jié)束
        UCSRA|=64; //清除發(fā)送結(jié)束標(biāo)志
        i++; //發(fā)送次數(shù)統(tǒng)計(jì)
        }
        PORTD.4=0; //使MAX485處 于接收狀態(tài)
        }

        ---------------------------------------------------------------------------------
        crc8校驗(yàn)程序
        ---------------------------------------------------------------------------------
        unsigned char crc8(unsigned char *ptr, unsigned char len)
        {
        unsigned char i;
        unsigned char crc=0;
        while(len--!=0)
        {
        for(i=1; i!=0; i*=2)
        {
        if((crc&1)!=0) {crc/=2; crc^=0x8C;}
        else crc/=2;
        if((*ptr&i)!=0) crc^=0x8C;
        }
        ptr++;
        }
        return(crc);
        }



        評(píng)論


        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 漾濞| 察雅县| 大方县| 梅州市| 湖口县| 沙坪坝区| 青阳县| 石嘴山市| 奈曼旗| 报价| 三亚市| 宁南县| 古浪县| 融水| 两当县| 英德市| 曲水县| 宜良县| 安岳县| 鄂州市| 台前县| 肇东市| 敖汉旗| 昌都县| 开封市| 杭锦旗| 霸州市| 宜章县| 锦州市| 汶川县| 邢台市| 武冈市| 大方县| 博客| 延吉市| 会东县| 峨边| 房产| 融水| 且末县| 黄陵县|