欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136
標題:
51單片機串口接收數據完畢檢測程序
[打印本頁]
作者:
張小不懂
時間:
2020-4-29 15:03
標題:
51單片機串口接收數據完畢檢測程序
這兩天買了個藍牙模塊研究,發現串口接收到的數據沒有規律,不好檢測到底接收完了沒有。查閱了些資料發現了比較好的方法,為了幫助跟我一樣的萌新可以更好的學習,我決定發個帖子,也算是給自己做個筆記。
1、IDLE中斷
IDLE就是串口收到一幀數據后,發生的中斷。什么是一幀數據呢?比如說給單片機一次發來1個字節,或者一次發來8個字節,這些一次發來的數據,就稱為一幀數據,也可以叫做一包數據。
如何判斷一幀數據結束,就是我們今天討論的問題。因為很多項目中都要用到這個,因為只有接收到一幀數據以后,你才可以判斷這次收了幾個字節和每個字節的內容是否符合協議要求。
看到這個第一反應就是“好東西”,可惜51單片機好像沒有,所以只是做了粗略的了解,有興趣的各位可以去找些資料看看,隨便查一下資料還挺多的
2、自定義結束符
在一幀數據尾部添加一個字符,比如傳輸的每一幀數據尾部都是“#”,當單片機接收到“#”后,說明已經接收完畢,然后立個Flag,就可以開始處理這些接收到的數據了,如下:
u8 xdata RxLen=0; //接收計數
u8 xdata RxFlag=0; //接收完畢標志位
u8 xdata Uart4_Rx_Buffer[33]; //接收到的數據
void Uart4_Init() //藍牙串口4,選擇定時器2為波特率發生器,波特率57600
{
S4CON = 0x10; //8位數據,可變波特率
S4CON &= 0xBF; //串口4選擇定時器2為波特率發生器
AUXR |= 0x04; //定時器2時鐘為Fosc,即1T
T2L = 0x7E; //設定定時初值
T2H = 0xFF; //設定定時初值
AUXR |= 0x10; //啟動定時器2
IE2|=0X10; //打開串口中斷4
EA=1; //打開總中斷
}
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++;
}
}
}
void BLE_Allot() //數據分配
{
if(RxFlag)
{
RxFlag=0;
RxLen=0;
/*干一些你想干的事情*/
}
}
復制代碼
3、用另外一個定時器檢測
具體的思路是,因為每一位傳輸的時間間隔由波特率決定都是一樣,所以每一個字節的傳輸時間也是一樣的。那么我們每傳輸一個字節時,把定時器初值復位,
以保證定時器不會溢出。
定時器時間取傳輸一個字節的1.5倍,
這樣一來,當定時器超時時候,就意味著串口接收數據停止了。此時同樣立一個flag
開始處理這些接收到的數據,如下:
PS:大佬用的是滴答定時器,我發現51單片機還是沒有,欲哭無淚,所以只好自己做一個了
u8 xdata RxLen=0; //接收計數
u8 xdata RxFlag=0; //接收完畢標志位
u8 xdata Uart4_Rx_Buffer[33]; //接收到的數據
void Timer1_Init() //定時器1初始化
{
AUXR |= 0x40; //定時器時鐘1T模式
TMOD &= 0x0F; //設置定時器模式
TL1 = 0x82; //設置定時初值
TH1 = 0xE7; //設置定時初值
TF1 = 0; //清除TF1標志
TR1 = 0; //這里先不開始計時,等傳輸信號的時候開始計時
ET1=1;
EA=1;
}
void Timer0_Rountine() interrupt 3
{
TR1 = 0; //定時器1停止計時
TF1 = 0; //清除TF1標志
RxFlag=1; //串口接收完畢
}
void Uart4_Init() //藍牙串口4,選擇定時器2為波特率發生器,波特率57600
{
S4CON = 0x10; //8位數據,可變波特率
S4CON &= 0xBF; //串口4選擇定時器2為波特率發生器
AUXR |= 0x04; //定時器2時鐘為Fosc,即1T
T2L = 0x7E; //設定定時初值
T2H = 0xFF; //設定定時初值
AUXR |= 0x10; //啟動定時器2
IE2|=0X10; //打開串口中斷4
EA=1; //打開總中斷
}
void S4_Routine() interrupt 18 //串口4中斷函數
{
if(S4CON&0x01) //接收中斷
{
S4CON&=0xFE; //清除接收中斷
Uart4_Rx_Buffer[RxLen]=S4BUF; //將數據放到數組中
RxLen++; //下次進來數據存放地址+1
TR1=0; //定時器1停止計時(這里搞了好久,一定要先停止,不然會出現錯誤)
TL1=0x82; //設置定時初值
TH1=0xE7; //設置定時初值
TR1=1; //定時器1開始計時
}
}
void BLE_Allot() //數據分配
{
if(RxFlag)
{
RxFlag=0; //標志清零
RxLen=0; //計數清零
/*干一些你想干的事情*/
}
}
復制代碼
最后,感謝大佬在網上發布的好資料能給我們參考,也希望大佬能進來多討論,多給點意見和建議
作者:
張小不懂
時間:
2020-4-29 15:21
第三種方法定時器傳輸時間計算方法:比如波特率為57600,那么每秒鐘傳輸的字節數為:57600/8=7200B/S,那么一個字節需要的時間約為:1s/7200B=139uS,所以一個字節的1.5倍時間約為:209uS
作者:
華麗的來了
時間:
2020-5-2 21:34
感謝大佬分享 學習到了
作者:
1045964948
時間:
2021-10-11 17:08
使用了你的程序,感謝分享
作者:
aking991
時間:
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;
}
這是我之前項目作的,當然不只這種方法,還有很多,這個方法我現在都不用了,只是看你這么寫,給參考一下
作者:
188610329
時間:
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次,有點累……
歡迎光臨 (http://www.raoushi.com/bbs/)
Powered by Discuz! X3.1