欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 11038|回復(fù): 2
打印 上一主題 下一主題
收起左側(cè)

安全可靠的串口通訊協(xié)議之校驗(yàn)

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:128229 發(fā)表于 2016-6-27 22:06 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
(1)開(kāi)場(chǎng)白:

串口通訊的協(xié)議各種各樣,五花八門。有的協(xié)議沒(méi)有校驗(yàn),有的協(xié)議有校驗(yàn),它們的存在都有它們的道理。沒(méi)有校驗(yàn)的協(xié)議,感覺(jué)更簡(jiǎn)單直接,傳輸與處理的速度更 加快。有校驗(yàn)的協(xié)議,感覺(jué)用起來(lái)更加放心點(diǎn)。這節(jié)將要介紹我常用校驗(yàn)的三道防火墻。它們分別是提取數(shù)據(jù)頭,判斷數(shù)據(jù)總數(shù),判斷所有字節(jié)的累加和。在上一節(jié) 中略加修改即可完成本節(jié)的實(shí)驗(yàn)。

(2)功能需求:

   無(wú)論是單片機(jī)還是上位機(jī),最好在固定協(xié)議前多發(fā)送一個(gè)填充的無(wú)效字節(jié)0x00,因?yàn)橛布颍谝粋(gè)字節(jié)往往容易丟失。

           通訊協(xié)議: EB 00 55   XX YY YY YY YY CY

           其中前三位 EB 00 55為數(shù)據(jù)頭,XX為數(shù)據(jù)長(zhǎng)度,YY為數(shù)據(jù),CY為前面所有字節(jié)的累加和。累加和的意思是所有數(shù)據(jù)相加,你只要定義一個(gè)字節(jié)變量用來(lái)接收所有數(shù)據(jù)的累加和,那么超過(guò)一個(gè)字節(jié)的部分會(huì)自動(dòng)丟棄。比如以下數(shù)據(jù):

           EB 00 55 04 02 12 56 A2 50

           其中 EB 00 55為數(shù)據(jù)頭,04為數(shù)據(jù)總數(shù),02 12 56  A2為數(shù)據(jù),50為前面所有字節(jié)的累加和。累加和可以用電腦系統(tǒng)自帶的計(jì)算器來(lái)驗(yàn)證。打開(kāi)電腦上的計(jì)算器,點(diǎn)擊“查看”下拉的菜單,選“科學(xué)型”,然后選 左邊的“十六進(jìn)制”,最后選右邊的“字節(jié)”,然后把前面所有的字節(jié)相加,它們的和就是50,沒(méi)錯(cuò)吧。



任意時(shí)刻,從電腦“串口調(diào)試助手”上位機(jī)收到的一堆數(shù)據(jù)中,只要此數(shù)據(jù)滿足以上我介紹的三道防火墻,那么就往上位機(jī)發(fā)送“eb  00 aa”表示確認(rèn),同時(shí)蜂鳴器叫一聲。如果校驗(yàn)出錯(cuò),則往上位機(jī)發(fā)送“eb  00 55”表示出錯(cuò)。

(3)硬件原理:

把單片機(jī)串口通訊的那兩個(gè)引腳經(jīng)過(guò)一個(gè)MAX3232之后直接跟電腦的9針串口通訊。我發(fā)現(xiàn)很多朋友會(huì)選MAX232這個(gè)芯片,而我本人更加推薦用 MAX3232。因?yàn)镸AX232只支持5V,不是寬壓的,而MAX3232不但支持5V,還支持3V。每個(gè)人的記憶力都很寶貴,用232串口我只選 MAX3232,不管它是用5V工作還是3V工作。就像74系列的芯片,我的心中只有你(74HC)沒(méi)有它(74LS),一樣的道理,74HC是寬 壓,74LS不是寬壓。

(4)源碼適合的單片機(jī):PIC18f4520,晶振為22.1184MHz,波特率115200

(5)源代碼講解如下:

#include<pic18.h>         //包含芯片相關(guān)頭文件

//補(bǔ)充說(shuō)明:吳堅(jiān)鴻程序風(fēng)格是這樣的,凡是輸出IO后綴都是_dr,凡是輸入的//IO后綴都//是_sr

#define  beep_dr  LATA2  //蜂鳴器輸出

//補(bǔ)充說(shuō)明:吳堅(jiān)鴻程序風(fēng)格是這樣的,凡是做延時(shí)計(jì)數(shù)閥值的常量

//前綴都用cnt_表示。

#define cnt_voice_time   150  //蜂鳴器響的聲音長(zhǎng)短的延時(shí)閥值

#define cnt_send   300            //確保接收緩沖區(qū)沒(méi)有繼續(xù)接收數(shù)據(jù),是變量

//send_cnt的溢出閥值

Void usart_service();        //串口通訊服務(wù)程序,放在main函數(shù)里

unsigned char asy_recieve();  //把串口緩沖區(qū)的數(shù)據(jù)一個(gè)個(gè)提取出來(lái)

void eusart_send(unsigned char t_data); //串口發(fā)送一個(gè)字節(jié)的數(shù)據(jù)

Void Buf_clear() ;  //把余下的緩沖區(qū)清零

void Delay11(unsigned int MS); //延時(shí)函數(shù)

//補(bǔ)充說(shuō)明:吳堅(jiān)鴻程序風(fēng)格是這樣的,凡是計(jì)數(shù)器延時(shí)的變量

//后綴都用_cnt表示。

unsigned int voice_time_cnt;        //蜂鳴器響的聲音長(zhǎng)短的計(jì)數(shù)延時(shí)

unsigned int send_cnt=0;            //一串?dāng)?shù)據(jù)從上位機(jī)發(fā)過(guò)來(lái)的時(shí)候,他們每個(gè)字節(jié)之間//的延時(shí)間隔很短,如果他們的延時(shí)間隔一旦超過(guò)了這個(gè)send_cnt變量的延時(shí),那么就////認(rèn)為他們的一串?dāng)?shù)據(jù)已經(jīng)發(fā)送完畢

//補(bǔ)充說(shuō)明:吳堅(jiān)鴻程序風(fēng)格是這樣的,凡是涉及統(tǒng)計(jì)數(shù)量的變量

//后綴都用_total表示。

unsigned int RCREG_total;            //統(tǒng)計(jì)串口緩沖區(qū)已經(jīng)收了多少個(gè)數(shù)據(jù)

unsigned int RCREG_read_total;   //統(tǒng)計(jì)已經(jīng)從串口緩沖區(qū)讀出了多少個(gè)數(shù)據(jù)

unsigned char valid_total;            //一串?dāng)?shù)據(jù)中的有效數(shù)據(jù)總量

//補(bǔ)充說(shuō)明:吳堅(jiān)鴻程序風(fēng)格是這樣的,凡是用來(lái)更新的標(biāo)識(shí)變量,比如液晶刷屏,或者有新接收的串口數(shù)據(jù)更新等等,后綴一律用_update表示

Unsigned char  send_update=0;  //一旦有數(shù)據(jù)從上位機(jī)發(fā)送過(guò)來(lái),就會(huì)引發(fā)串口接收中////斷,在串口中斷里,我把send_update=1表示目 前正在接收數(shù)據(jù),警告單片機(jī)先不要//猴急,等串口中斷把所有從上位機(jī)連續(xù)發(fā)送過(guò)來(lái)的一堆數(shù)據(jù)接收完,再處理。那么什么///時(shí)候才知道發(fā)送的數(shù)據(jù)已經(jīng)發(fā) 送完畢了呢?用send_cnt識(shí)別。因?yàn)樵诖谥袛嗬铮?//每次都會(huì)把send_cnt=0,而在main函數(shù)里,一旦發(fā)現(xiàn) send_update==1,send_cnt就//會(huì)開(kāi)始自加,當(dāng)它超過(guò)某個(gè)數(shù)值的時(shí)候,就會(huì)自動(dòng)把send_update=0,表示目前已經(jīng)沒(méi)// 有數(shù)據(jù)發(fā)送了。而如果有數(shù)據(jù)不斷從上位機(jī)傳來(lái),send_cnt永遠(yuǎn)也不會(huì)超過(guò)某個(gè)數(shù)值,//因?yàn)槊總(gè)中斷它都被清零,這個(gè)原理跟看門口狗喂狗的原理很 像。

//補(bǔ)充說(shuō)明:吳堅(jiān)鴻程序風(fēng)格是這樣的,凡是用來(lái)接收數(shù)據(jù)的緩沖區(qū)數(shù)組后綴都用_buf表//示

Unsigned char RCREG_buf[50];  //串口接收緩沖區(qū),讀者可以根據(jù)實(shí)際項(xiàng)目設(shè)置大小

Unsigned char RCREG_buf_temp[50];  //臨時(shí)處理串口數(shù)據(jù)的緩沖區(qū),可以不用那么大

//補(bǔ)充說(shuō)明:吳堅(jiān)鴻程序風(fēng)格是這樣的,凡是自鎖變量名, 后綴都用_lock表示。

Unsigned char send_lock=0;

//補(bǔ)充說(shuō)明:吳堅(jiān)鴻程序風(fēng)格是這樣的,凡是在main函數(shù)中用的中間變量,前綴m_,后//綴用_char或者_(dá)int表示類型

Unsigned int m_int;      //中間變量,只要是用在main函數(shù)里,誰(shuí)都可以重復(fù)用。

Unsigned char receive_sum;               //一串?dāng)?shù)據(jù)中的累加和,注意,必須定義成字節(jié)變//量,這樣運(yùn)算中它會(huì)自動(dòng)丟棄超過(guò)一個(gè)字節(jié)的位。

//主程序

main()

{

ADCON0=0x00;  

ADCON1=0x0f;                               //全部為數(shù)字信號(hào)

    ADCON2=0xa1;                               //右對(duì)齊

    RBPU=0;                                      //上拉電阻

    SSPEN=0;                                    //決定RA5不作為串口

   TRISA2=0;  //蜂鳴器輸出

    BRG16=0;         //設(shè)置串口通信寄存器

    BRGH=0;

    SPBRGH=0x00;

    SPBRG=0x02;     //22.1184MHz晶振,115200波特率

    SYNC=0;

    SPEN=1;

    TX9=0;

    TXEN=1;

    TXIF=1;

    RX9=0;

    CREN=1;

    RCIE=1;

    PEIE=1;

    GIE=1;

    T1CON=0x24;     //定時(shí)器中斷配置

    TMR1H=0xFE;

TMR1L=0xEF;

    TMR1IF=0;

    TMR1IE=1;

    TMR1ON=1;

    TMR1IE=1;

//補(bǔ)充說(shuō)明,以上的內(nèi)容為寄存器配置,每種不同的單片機(jī)會(huì)有點(diǎn)差異,

//大家不用過(guò)度關(guān)注以上寄存器的配置,只要知道有這么一回事即可

    beep_dr=0;                               //關(guān)蜂鳴器,上電初始化IO

   while(1)   

   {

                     CLRWDT(); //喂看門狗,大家不用過(guò)度關(guān)注此行

                usart_service();        //串口通訊服務(wù)

}

}



//中斷

void interrupt timer1rbint(void)

{

    if(RCIE==1&&RCIF==1)   //串口中斷,一次只能接受一個(gè)字節(jié)

{

        RCIE=0;

        RCIF=0;

        ++RCREG_total;   //以下代碼是鴻哥的在所有串口項(xiàng)目中用到的標(biāo)準(zhǔn)代碼

        if(RCREG_total>50)  //超過(guò)緩沖區(qū)

        {

           RCREG_total=50;

        }

        RCREG_buf[RCREG_total-1]=RCREG;  //依次把上位機(jī)來(lái)的數(shù)據(jù)存入數(shù)組緩沖區(qū)

        send_update=1;    //通知單片機(jī)目前正在接收數(shù)據(jù)

        send_cnt=0;         //及時(shí)喂狗,雖然main函數(shù)那邊不斷在累加,但是只要串口的數(shù)//據(jù)還沒(méi)發(fā)送完畢,那么它永遠(yuǎn)也長(zhǎng)不大,因?yàn)槊總(gè)中斷都被清零,很可憐。

        RCIE=1;

}

    if(TMR1IE==1&&TMR1IF==1)    //定時(shí)中斷

        {



               TMR1IF=0;     //定時(shí)中斷標(biāo)志位關(guān)閉

                TMR1ON=0;    //定時(shí)中斷開(kāi)關(guān)關(guān)閉

      if(voice_time_cnt)                       //控制蜂鳴器聲音的長(zhǎng)短

                 {

                        beep_dr=1;         //蜂鳴器響

                      --voice_time_cnt;        //蜂鳴器響的聲音長(zhǎng)短的計(jì)數(shù)延時(shí)

                 }

                else

                {

                    Asm(“nop”);   //添加此行空指令為了使else的內(nèi)容跟if的內(nèi)容對(duì)稱,意義////不大

beep_dr=0;      //蜂鳴器停止

                }

      TMR1H=0xFe;   //重新設(shè)置定時(shí)時(shí)間間隔

    TMR1L=0x00;

      TMR1ON=1;        //定時(shí)中斷開(kāi)關(guān)打開(kāi)

    }

}

void usart_service()  //串口服務(wù)程序,在main函數(shù)里

{

     if(send_update==1)  //說(shuō)明目前串口正在接收數(shù)據(jù),不要讀緩沖區(qū)數(shù)據(jù)

     {

        send_lock=1;     //開(kāi)自鎖標(biāo)志

        ++send_cnt;    //只要有數(shù)據(jù)接收,send_cnt每次都被串口中斷清零

        if(send_cnt>cnt_send)   //延時(shí)一段時(shí)間,確認(rèn)緩沖區(qū)沒(méi)有繼續(xù)接受數(shù)據(jù)

        {

            send_cnt=0;

            send_update=0;  

        }

     }

     Else  //說(shuō)明當(dāng)前沒(méi)有繼續(xù)接收數(shù)據(jù)了

     {

         if(send_lock==1)    //在數(shù)據(jù)已經(jīng)接收完畢,并且還沒(méi)有處理過(guò)數(shù)據(jù)的情況下

         {

            send_lock=0;    //處理一次就鎖起來(lái),不用每次都進(jìn)來(lái),除非有新接收的數(shù)據(jù)

            while(RCREG_read_total<RCREG_total)   //說(shuō)明還沒(méi)有把緩沖區(qū)的數(shù)據(jù)讀取完

            {

              CLRWDT();

RCREG_buf_temp[0]= RCREG_buf_temp[1];  //數(shù)據(jù)移動(dòng),方便截取關(guān)鍵字

RCREG_buf_temp[1]= RCREG_buf_temp[2];

               RCREG_buf_temp[2]=asy_recieve();

               if(RCREG_buf_temp[0]==0xeb&&  RCREG_buf_temp[1]==0x00&& RCREG_buf_temp[2]==0x55)  //數(shù)據(jù)頭”eb 00  55”判斷

               {

                                              //把余下有效的數(shù)據(jù)都取出來(lái)

                       RCREG_buf_temp[3]=asy_recieve();  //數(shù)據(jù)量

                       Valid_total= RCREG_buf_temp[3];

                       For(m_int=0;m_int< Valid_total;m_int++)  //提取有效數(shù)據(jù)

                       {

                                 RCREG_buf_temp[4+ m_int]=asy_recieve();  

}

RCREG_buf_temp[4+ Valid_total]=asy_recieve();  //自帶校驗(yàn)和

Receive_sum=0;         //累加校驗(yàn)和計(jì)算

                       For(m_int=0;m_int< (Valid_total+4);m_int++)  //累加校驗(yàn)和計(jì)算

                       {

                                Receive_sum=Receive_sum+ RCREG_buf_temp[m_int];

}

If(Receive_sum== RCREG_buf_temp[4+ Valid_total])   //校驗(yàn)和正確

{

RCREG_buf_temp[0]=0;    //把臨時(shí)處理數(shù)據(jù)清零,方便下次接收

RCREG_buf_temp[1]=0;

RCREG_buf_temp[2]=0;

                                eusart_send(0x00); //串口發(fā)送多一個(gè)填充無(wú)效字節(jié),避免硬件原因引起第一個(gè)字節(jié)丟失

                                eusart_send(0xeb); //串口發(fā)送應(yīng)答的數(shù)據(jù)

eusart_send(0x00); //串口發(fā)送應(yīng)答的數(shù)據(jù)

eusart_send(0xaa); //串口發(fā)送應(yīng)答的數(shù)據(jù)

                                 voice_time_cnt= cnt_voice_time;    //蜂鳴器響“滴”一聲就停

}

Else    //校驗(yàn)和出錯(cuò)

{

RCREG_buf_temp[0]=0;    //把臨時(shí)處理數(shù)據(jù)清零,方便下次接收

RCREG_buf_temp[1]=0;

RCREG_buf_temp[2]=0;

                                eusart_send(0x00); //串口發(fā)送多一個(gè)填充無(wú)效字節(jié),避免硬件原因引起第一個(gè)字節(jié)丟失

                                eusart_send(0xeb); //串口發(fā)送應(yīng)答的數(shù)據(jù)

eusart_send(0x00); //串口發(fā)送應(yīng)答的數(shù)據(jù)

eusart_send(0x55); //串口發(fā)送應(yīng)答的數(shù)據(jù)

}

                       break;   //退出循環(huán)

               }



           }

         Buf_clear();   //把余下的緩沖區(qū)清零,方便下一堆數(shù)據(jù)接收與處理



        }

     }

}

Void Buf_clear()   //把余下的緩沖區(qū)清零

{

         Unsigned char buf_clear_temp;

            while(RCREG_read_total<RCREG_total)   //說(shuō)明還沒(méi)有把緩沖區(qū)的數(shù)據(jù)讀取完

            {

                 CLRWDT();

                 buf_clear_temp =asy_recieve();

             }

}

unsigned char asy_recieve()  //把串口緩沖區(qū)的數(shù)據(jù)一個(gè)個(gè)提取出來(lái)

{

      unsigned char RCREG_dt;

      ++RCREG_read_total;    //已經(jīng)讀出了多少個(gè)數(shù)據(jù)

      RCREG_dt=RCREG_buf[RCREG_read_total -1];

      if(RCREG_read_total >=RCREG_total) //只要把全部數(shù)據(jù)都讀完,馬上把緩沖區(qū)清零

         {

          RCREG_read_total =0;

          RCREG_total=0;

         }

      return RCREG_dt;

}

void eusart_send(unsigned char t_data) //串口發(fā)送一個(gè)字節(jié)的數(shù)據(jù)

{

unsigned int error_delay;

     TXREG=t_data;   //發(fā)送數(shù)據(jù)

     error_delay=0;//等待把數(shù)據(jù)發(fā)送完畢

     while(1)   //這里也可以省略,直接用延時(shí)替代

   {

        CLRWDT();

        if(TXIF==1)   //等待把數(shù)據(jù)發(fā)送完畢

        {

           break;

        }

        Else            

        {

          ++error_delay;

          if(error_delay>200)  //超時(shí)也要退出,不能死等

          {

              break;

          }

       }

     }

     Delay11(1);     //此處最玄機(jī),要特別注意。每發(fā)送完一個(gè)字節(jié),由于不同的項(xiàng)目,這//里的延時(shí)間隔都不一樣,讀者根據(jù)實(shí)際情況來(lái)改。這里最容易出問(wèn)題,必須要延時(shí),尤 其是連續(xù)發(fā)送一堆數(shù)據(jù)的時(shí)候。讀者也可以自己把這種死延時(shí)改成計(jì)數(shù)延時(shí)的方式。

}

//延時(shí)函數(shù)

void Delay11(unsigned int MS)

{

     unsigned char us,usn;

     while(MS!=0)            //for 12M

           {

               CLRWDT();

                  usn = 2;

                 while(usn!=0)

                       {       CLRWDT();

                             us=0xf5;

                             while (us!=0){us--;};

                             usn--;

                       }

                 MS--;

           }

}

(6)小結(jié):

          累加和就是把前面所有字節(jié)相加,然后把結(jié)果放在一個(gè)字節(jié)的變量上,超過(guò)一個(gè)字節(jié)范圍的部分會(huì)自動(dòng)丟棄。



分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏3 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:83553 發(fā)表于 2016-6-29 11:32 | 只看該作者
“因?yàn)橛布颍谝粋(gè)字節(jié)往往容易丟失”------能否說(shuō)一下為什么。
回復(fù)

使用道具 舉報(bào)

板凳
ID:370386 發(fā)表于 2018-7-20 16:10 | 只看該作者
如果有個(gè)源程序下載該多好
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表