亚洲春色中文字幕久久久-三上亚,一吻二脱三床四吻胸,国产真实伦对白视频全集,在线毛片观看,精品成品入口黄网,国产毛aⅴ片久久久,亚洲AV色香蕉一区二区三区老师,萧皇后A级艳片,色情日本视频更新,99久久亚洲精品日本无码

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

串行通信數(shù)據(jù)包解析不正常

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
#
ID:705846 發(fā)表于 2026-6-6 17:01 | 只看該作者 回帖獎勵 |正序?yàn)g覽 |閱讀模式


通過PC機(jī)串口發(fā)送hex數(shù)據(jù) 5A 02 01 02 5F。返回給PC的數(shù)據(jù)不穩(wěn)定,有時是5A 02, 有時是5A 01, 并且每次都返回四次。請大家?guī)兔Ψ治鲆幌略颉伌u引玉。謝謝。

unsigned char tempsbuf;

typedef enum{
        WAIT_HEADER,
        WAIT_LEN,
        WAIT_DATA,
        WAIT_CHECKSUM
} ParserState;

typedef struct Parser{
        ParserState state; //當(dāng)前狀態(tài)
        unsigned char len;        //數(shù)據(jù)長度
        unsigned char buf_data[3]; //數(shù)據(jù)緩沖區(qū)
        unsigned char index;        //數(shù)據(jù)接收計數(shù)
        unsigned char checksum;        //檢驗(yàn)和
} Parser;

void parser_init(Parser *p){
        p->state=WAIT_HEADER;
        p->len=0;
        p->index=0;
        p->checksum=0;
}

int parser_input_byte(Parser *p,unsigned char byte){
        switch(p->state){
                //1、等待幀頭0x5a
                case WAIT_HEADER:
                        if(byte==0x5A){
                                p->checksum=byte; //累加校驗(yàn)
                                p->state=WAIT_LEN;
                        }
                break;
                //2、等待長度
                case WAIT_LEN:
                        p->len=byte;
                        p->checksum+=byte;
                        p->index=0;
                        p->state=WAIT_DATA;
                break;
                //3、等待數(shù)據(jù)
                case WAIT_DATA:
                        p->buf_data[p->index++]=byte;
                        //p->index++;
                        p->checksum+=byte;
                        if(p->index>=p->len){p->state=WAIT_CHECKSUM;}
                break;
                //4、等待校驗(yàn)
                case WAIT_CHECKSUM:
                        p->state=WAIT_HEADER; //解析完成回到初始狀態(tài)
                                if(byte==p->checksum){
                                        return 1;
                                }
                                break;
        }       
        return 0;
}


void Uart() interrupt 4 //串行中斷函數(shù)
{
        if(TI)
                {                       
                        TI=0; //清楚TI傳送完成標(biāo)記
                }
               
        if(RI){       
                RI=0;
                tempsbuf=SBUF;
               
        }
       



Parser p;
parser_init(&p);

void main(){
    while(1)
        {
               
                if(parser_input_byte(&p,tempsbuf)){
                SendByte(p.buf_data[0]);
                SendByte(p.buf_data[1]);
                }
        }

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

使用道具 舉報

6#
ID:705846 發(fā)表于 2026-6-9 09:46 | 只看該作者
人中狼 發(fā)表于 2026-6-8 16:02
接收數(shù)據(jù)的判斷應(yīng)該在串口接收中斷里判斷

對的。在接收中斷內(nèi)判定是好很多,但還是有誤碼問題。
回復(fù)

使用道具 舉報

5#
ID:1064915 發(fā)表于 2026-6-9 08:47 | 只看該作者
這段代碼實(shí)現(xiàn)了一個基于狀態(tài)機(jī)的串口數(shù)據(jù)包解析器,結(jié)構(gòu)基本正確,但存在幾個嚴(yán)重且典型的問題,在實(shí)際項(xiàng)目中可能導(dǎo)致數(shù)據(jù)錯亂、死循環(huán)甚至程序崩潰。下面逐一分析。

1. 代碼功能簡述
  • 協(xié)議格式:幀頭 0x5A + 長度(len) + 數(shù)據(jù)(len字節(jié)) + 校驗(yàn)和(累加和)
  • 校驗(yàn)方式:累加和(包含幀頭、長度、全部數(shù)據(jù)字節(jié))
  • 狀態(tài)機(jī):WAIT_HEADER → WAIT_LEN → WAIT_DATA → WAIT_CHECKSUM → 回到 WAIT_HEADER
  • 成功解析后:發(fā)送 buf_data[0] 和 buf_data[1](假定長度至少為2)


2. 存在的關(guān)鍵問題① 主循環(huán)與中斷完全無同步 —— 數(shù)據(jù)競爭 / 重復(fù)解析 / 丟字節(jié)if(RI){    RI=0;    tempsbuf=SBUF;}// main loopif(parser_input_byte(&p,tempsbuf)){    ...}
  • tempsbuf 在中斷中被寫入,主循環(huán)隨時讀取,沒有任何互斥或標(biāo)志位。
  • 主循環(huán)運(yùn)行極快,會在同一個字節(jié)上反復(fù)調(diào)用 parser_input_byte,導(dǎo)致狀態(tài)機(jī)被多次喂入相同數(shù)據(jù),完全打亂解析邏輯。
  • 同時,當(dāng)新字節(jié)到來時,tempsbuf 可能正在被主循環(huán)讀取,造成數(shù)據(jù)競爭。

正確做法:使用 volatile 標(biāo)志位,中斷置位,主循環(huán)檢測后清除并處理。
volatile bit hasNewByte = 0;// 中斷中:tempsbuf = SBUF;hasNewByte = 1;// 主循環(huán):if(hasNewByte) {    hasNewByte = 0;    if(parser_input_byte(&p, tempsbuf)) { ... }}
② 數(shù)據(jù)緩沖區(qū) buf_data[3] 沒有長度保護(hù),極易溢出unsigned char buf_data[3;...p->buf_data[p->index++ = byte;if(p->index >= p->len) { p->state = WAIT_CHECKSUM; }
  • 如果通信對方發(fā)來的 len 大于 3,index 會超過數(shù)組邊界,直接破壞內(nèi)存(溢出到后續(xù)成員或棧)。
  • 必須在 WAIT_LEN 收到長度后檢查合法性,否則應(yīng)當(dāng)視為無效幀并丟棄。

case WAIT_LEN:    p->len = byte;    if(p->len > sizeof(p->buf_data)) {        p->state = WAIT_HEADER;  // 長度非法,復(fù)位        break;    }    ...
③ 同步恢復(fù)能力極差,錯誤字節(jié)極易造成永久失步
  • 當(dāng)前狀態(tài)機(jī)在 WAIT_HEADER 下只認(rèn) 0x5A,任何非幀頭字節(jié)都被直接丟棄。
  • 一旦因干擾或丟字節(jié)導(dǎo)致狀態(tài)機(jī)偏離,數(shù)據(jù)區(qū)出現(xiàn)的 0x5A 會被誤認(rèn)為幀頭,從而產(chǎn)生一整幀錯誤解析,且無校驗(yàn)失敗后的顯式復(fù)位(雖然校驗(yàn)失敗后會回到 WAIT_HEADER,但已錯誤地消費(fèi)了若干字節(jié),后續(xù)幀頭完全錯位)。
  • 更健壯的做法:增加幀尾、轉(zhuǎn)義機(jī)制,或超時復(fù)位。

④ parser_init(&p) 位置錯誤 —— C 語言不允許在文件作用域執(zhí)行函數(shù)Parser p;parser_init(&p);   // ← 這行不能在全局作用域調(diào)用void main() { ... }
這種寫法在某些編譯器下可能被當(dāng)作聲明甚至報錯。必須移到 main 內(nèi)部:
void main() {    parser_init(&p);    while(1) { ... }}
⑤ 校驗(yàn)和在失敗后未清除,且校驗(yàn)包含幀頭本身
  • p->checksum 初始為 0,在收到 0x5A 時置為 0x5A,然后累加長度和數(shù)據(jù)。最后與收到的校驗(yàn)字節(jié)比較。
  • 這要求發(fā)送方的校驗(yàn)和也必須包含幀頭,否則永遠(yuǎn)校驗(yàn)失敗。這一點(diǎn)不常見(通常校驗(yàn)只覆蓋長度+數(shù)據(jù)),需確認(rèn)協(xié)議雙方一致。
  • 校驗(yàn)失敗后,p->checksum 未清零,下次 WAIT_HEADER 會重新賦值為 0x5A,所以無累積問題,但邏輯上最好在校驗(yàn)分支內(nèi)做明確清理以增強(qiáng)可讀性。

⑥ main 函數(shù)缺少串口初始化
  • 寄存器未配置(波特率、工作方式等),中斷使能未開啟,實(shí)際完全無法接收數(shù)據(jù)。真實(shí)代碼需要加入串口初始化。

⑦ 發(fā)送函數(shù) SendByte 未定義,且 while(1) 內(nèi)無其他保護(hù)
  • 若 SendByte 是阻塞查詢方式發(fā)送,且沒有流控,高速連續(xù)解析可能丟失發(fā)送數(shù)據(jù)。不過這不屬于當(dāng)前代碼片段的核心問題。


3. 改進(jìn)后的代碼框架(關(guān)鍵部分)volatile bit hasNewByte = 0;unsigned char tempsbuf;// ... Parser 定義、parser_init、parser_input_byte(加入長度檢查) ...void Uart() interrupt 4 {    if(TI) {        TI = 0;    }    if(RI) {        RI = 0;        tempsbuf = SBUF;        hasNewByte = 1;    }}void main() {    Parser p;    parser_init(&p);    Uart_Init();  // 假設(shè)已實(shí)現(xiàn)    while(1) {        if(hasNewByte) {            hasNewByte = 0;            if(parser_input_byte(&p, tempsbuf)) {                SendByte(p.buf_data[0);                SendByte(p.buf_data[1);            }        }    }}
并且在 WAIT_LEN 中添加:
if(byte > sizeof(p->buf_data)) {    p->state = WAIT_HEADER;    break;}
總結(jié)
代碼展現(xiàn)了狀態(tài)機(jī)解析思想,但缺少實(shí)時系統(tǒng)中的同步機(jī)制、無邊界檢查、初始化位置錯誤,是典型的“能跑但一有干擾就崩”的嵌入式代碼。上述幾點(diǎn)修正后,才能在實(shí)際串口通信中穩(wěn)定工作。

回復(fù)

使用道具 舉報

地板
ID:1064915 發(fā)表于 2026-6-9 08:38 | 只看該作者
串口初始化,誤差大
回復(fù)

使用道具 舉報

板凳
ID:1133081 發(fā)表于 2026-6-8 20:00 | 只看該作者
樓主說明下通訊協(xié)議
回復(fù)

使用道具 舉報

沙發(fā)
ID:384109 發(fā)表于 2026-6-8 16:02 | 只看該作者
接收數(shù)據(jù)的判斷應(yīng)該在串口接收中斷里判斷
回復(fù)

使用道具 舉報

樓主
ID:161164 發(fā)表于 2026-6-8 13:16 | 只看該作者
啥芯片?晶振多少?串口初始化代碼呢?
回復(fù)

使用道具 舉報

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

本版積分規(guī)則

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

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

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