久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 6703|回復: 5
打印 上一主題 下一主題
收起左側

51單片機串口接收數據完畢檢測程序

[復制鏈接]
跳轉到指定樓層
樓主
ID:675145 發表于 2020-4-29 15:03 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
這兩天買了個藍牙模塊研究,發現串口接收到的數據沒有規律,不好檢測到底接收完了沒有。查閱了些資料發現了比較好的方法,為了幫助跟我一樣的萌新可以更好的學習,我決定發個帖子,也算是給自己做個筆記。
1、IDLE中斷
IDLE就是串口收到一幀數據后,發生的中斷。什么是一幀數據呢?比如說給單片機一次發來1個字節,或者一次發來8個字節,這些一次發來的數據,就稱為一幀數據,也可以叫做一包數據。
如何判斷一幀數據結束,就是我們今天討論的問題。因為很多項目中都要用到這個,因為只有接收到一幀數據以后,你才可以判斷這次收了幾個字節和每個字節的內容是否符合協議要求。

看到這個第一反應就是“好東西”,可惜51單片機好像沒有,所以只是做了粗略的了解,有興趣的各位可以去找些資料看看,隨便查一下資料還挺多的
2、自定義結束符
在一幀數據尾部添加一個字符,比如傳輸的每一幀數據尾部都是“#”,當單片機接收到“#”后,說明已經接收完畢,然后立個Flag,就可以開始處理這些接收到的數據了,如下:
  1. u8 xdata RxLen=0;                                //接收計數
  2. u8 xdata RxFlag=0;                                //接收完畢標志位
  3. u8 xdata Uart4_Rx_Buffer[33];        //接收到的數據

  4. void Uart4_Init()        //藍牙串口4,選擇定時器2為波特率發生器,波特率57600
  5. {
  6.         S4CON = 0x10;                //8位數據,可變波特率
  7.         S4CON &= 0xBF;                //串口4選擇定時器2為波特率發生器
  8.         AUXR |= 0x04;                //定時器2時鐘為Fosc,即1T
  9.         T2L = 0x7E;                        //設定定時初值
  10.         T2H = 0xFF;                        //設定定時初值
  11.         AUXR |= 0x10;                //啟動定時器2
  12.         
  13.         IE2|=0X10;                        //打開串口中斷4
  14.         EA=1;                                //打開總中斷
  15. }
  16. void  S4_Routine() interrupt 18        //串口4中斷函數
  17. {               
  18.         if(S4CON&0x01)                //接收中斷
  19.         {
  20.                 S4CON&=0xFE;        //清除接收中斷
  21.                 Uart4_Rx_Buffer[RxLen]=S4BUF;
  22.                 if(Uart4_Rx_Buffer[RxLen] == '#')        //是結束符,說明接收完畢,就可以拿著RxFlag出去搞事情了
  23.                 {
  24.                         RxFlag=1;
  25.                 }
  26.                 else                                                                //不是結束符,老實接收下一個數據
  27.                 {
  28.                         RxLen++;
  29.                 }
  30.         }                        
  31. }
  32. void BLE_Allot()        //數據分配
  33. {
  34.         if(RxFlag)
  35.         {
  36.                 RxFlag=0;
  37.                 RxLen=0;
  38.                 /*干一些你想干的事情*/
  39.         }
  40. }
復制代碼
3、用另外一個定時器檢測

具體的思路是,因為每一位傳輸的時間間隔由波特率決定都是一樣,所以每一個字節的傳輸時間也是一樣的。那么我們每傳輸一個字節時,把定時器初值復位,以保證定時器不會溢出。定時器時間取傳輸一個字節的1.5倍,這樣一來,當定時器超時時候,就意味著串口接收數據停止了。此時同樣立一個flag開始處理這些接收到的數據,如下:
PS:大佬用的是滴答定時器,我發現51單片機還是沒有,欲哭無淚,所以只好自己做一個了
  1. u8 xdata RxLen=0;                                //接收計數
  2. u8 xdata RxFlag=0;                                //接收完畢標志位
  3. u8 xdata Uart4_Rx_Buffer[33];        //接收到的數據
  4. void Timer1_Init()        //定時器1初始化
  5. {
  6.         AUXR |= 0x40;        //定時器時鐘1T模式
  7.         TMOD &= 0x0F;        //設置定時器模式
  8.         TL1 = 0x82;                //設置定時初值
  9.         TH1 = 0xE7;                //設置定時初值
  10.         TF1 = 0;                //清除TF1標志
  11.         TR1 = 0;                //這里先不開始計時,等傳輸信號的時候開始計時
  12.         
  13.         ET1=1;
  14.         EA=1;
  15. }
  16. void Timer0_Rountine() interrupt 3
  17. {
  18.         TR1 = 0;        //定時器1停止計時
  19.         TF1 = 0;        //清除TF1標志        
  20.         RxFlag=1;        //串口接收完畢
  21. }
  22. void Uart4_Init()        //藍牙串口4,選擇定時器2為波特率發生器,波特率57600
  23. {
  24.         S4CON = 0x10;                //8位數據,可變波特率
  25.         S4CON &= 0xBF;                //串口4選擇定時器2為波特率發生器
  26.         AUXR |= 0x04;                //定時器2時鐘為Fosc,即1T
  27.         T2L = 0x7E;                        //設定定時初值
  28.         T2H = 0xFF;                        //設定定時初值
  29.         AUXR |= 0x10;                //啟動定時器2
  30.         
  31.         IE2|=0X10;                        //打開串口中斷4
  32.         EA=1;                                //打開總中斷
  33. }
  34. void  S4_Routine() interrupt 18        //串口4中斷函數
  35. {               
  36.         if(S4CON&0x01)                //接收中斷
  37.         {
  38.                 S4CON&=0xFE;        //清除接收中斷
  39.                 Uart4_Rx_Buffer[RxLen]=S4BUF;        //將數據放到數組中
  40.                 RxLen++;                //下次進來數據存放地址+1
  41.                 TR1=0;                        //定時器1停止計時(這里搞了好久,一定要先停止,不然會出現錯誤)               
  42.                 TL1=0x82;                //設置定時初值
  43.                 TH1=0xE7;                //設置定時初值
  44.                 TR1=1;                        //定時器1開始計時               
  45.         }        
  46. }
  47. void BLE_Allot()        //數據分配
  48. {
  49.         if(RxFlag)
  50.         {
  51.                 RxFlag=0;        //標志清零
  52.                 RxLen=0;        //計數清零
  53.                 /*干一些你想干的事情*/
  54.         }
  55. }
復制代碼
最后,感謝大佬在網上發布的好資料能給我們參考,也希望大佬能進來多討論,多給點意見和建議



評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

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

使用道具 舉報

沙發
ID:675145 發表于 2020-4-29 15:21 | 只看該作者
第三種方法定時器傳輸時間計算方法:比如波特率為57600,那么每秒鐘傳輸的字節數為:57600/8=7200B/S,那么一個字節需要的時間約為:1s/7200B=139uS,所以一個字節的1.5倍時間約為:209uS
回復

使用道具 舉報

板凳
ID:424977 發表于 2020-5-2 21:34 | 只看該作者
感謝大佬分享 學習到了
回復

使用道具 舉報

地板
ID:876099 發表于 2021-10-11 17:08 | 只看該作者
使用了你的程序,感謝分享
回復

使用道具 舉報

5#
ID:65956 發表于 2021-10-12 08:39 | 只看該作者
我說問問,如果用你這個,當一幀來時存在著兩個23(#的十六進制數是23),那怎么辦?所以說這個并不是最終的好辦法
void  S4_Routine() interrupt 18        //串口4中斷函數
{               
        if(S4CON&0x01)                //接收中斷
        {
                S4CON&=0xFE;        //清除接收中斷
                Uart4_Rx_Buffer[RxLen]=S4BUF;
                if(Uart4_Rx_Buffer[RxLen] == '#')        //是結束符,說明接收完畢,就可以拿著RxFlag出去搞事情了
                {
                        RxFlag=1;
                }
                else                                                                //不是結束符,老實接收下一個數據
                {
                        RxLen++;
                }
        }                        
}
第2種你用定時器0作接收超時的想法是對的,但應是這樣的才不用這說的那么麻煩
/*******串口1接收中斷程序******************************************************
//接收時打開T0定時計數器(通過主函數再判斷是否接收超時)
//*****************************************************************************/
void Uart_Isr() interrupt 4 //using 1
{
        if(RI)
        {
                 RI = 0;
                //---------------------------------------
                TL0 = 0x00;                                        //設置定時初值
                TH0 = 0x4C;                                        //設置定時初值
                TF0 = 0;                                        //清除TF0標志
                ET0 = 0;                                            //關閉T0的溢出中斷
                TR0 = 1;                                        //定時器0開始計時
                //---------------------------------------
                 S1_busy = 1;                                        //忙
                S1_Rec_data = SBUF;
                S1_Rectemp[S1_number] = S1_Rec_data;
                S1_number++;                                        //個數加1
                if(S1_number>=100);                                //判斷是否超出設置的最大緩存區
                {
                        S1_number = 0;
                }
                step1 = S1_number;                                 
        }
        S1_busy = 0;
}
這是我之前項目作的,當然不只這種方法,還有很多,這個方法我現在都不用了,只是看你這么寫,給參考一下
回復

使用道具 舉報

6#
ID:624769 發表于 2021-10-12 23:33 | 只看該作者
張小不懂 發表于 2020-4-29 15:21
第三種方法定時器傳輸時間計算方法:比如波特率為57600,那么每秒鐘傳輸的字節數為:57600/8=7200B/S,那么 ...

更正一下, 串口傳輸時,無效驗的話,10位為一個字節,有效驗的話,11位為一個字節,因為有起始和停止位。
另外,計算超時其實不用那么麻煩,按增強型51大多是4分波特率的,所以,你定時器2既然做了波特率發生器,那么,串口接受完成一個字節后,被RI觸發后,只要開T2中斷, 然后賦值超時計數(比如:Time_Out) = 105; 別問我這105怎么來的,反正有人算過加上N次試驗,105是最佳值,反正按4分波特率算就是2個半字節的超時吧,然后T2中斷,最低優先級,每次--, 減到0了,置標志位就可以了。這樣做的好處是,不用刻意用多一個定時器,而且,不管你波特率變成多少,超時判斷的字節數是不變的。
當然,標準51會累點,16分波特率,得減420次,有點累……
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 国产在线中文字幕 | 欧美日韩一区二区在线观看 | 伊人伊人 | 欧美精品在线播放 | 九九九久久国产免费 | 9191av | 成人亚洲视频 | 亚洲一区二区三区观看 | 国产精品a久久久久 | 中文字幕日韩欧美 | 亚洲成人免费 | 日韩欧美在线观看视频网站 | 日本一二区视频 | 一区二区三区不卡视频 | 91精品一区 | 日韩欧美专区 | 欧美网址在线观看 | 亚洲va欧美va人人爽午夜 | 国产视频中文字幕在线观看 | 红桃视频一区二区三区免费 | 在线免费观看黄网 | 欧美一区二区在线免费观看 | www.日韩在线 | 国产精品美女久久久 | 成人福利电影 | 一区二区精品视频 | 久久一区精品 | 日韩免费成人av | 欧美99 | 久久99精品久久久久久 | 国产精品不卡一区 | 蜜臀久久 | 国产精品色 | 精品欧美一区二区三区久久久 | 射欧美 | 久久久精品综合 | 91视视频在线观看入口直接观看 | 国产激情| 午夜免费网站 | 精品亚洲一区二区三区 | 国产一区二区三区四区 |