<tr id="tp1vn"><td id="tp1vn"><dl id="tp1vn"></dl></td></tr>
  1. <p id="tp1vn"></p>
  2. <sub id="tp1vn"><p id="tp1vn"></p></sub>
    <u id="tp1vn"><rp id="tp1vn"></rp></u>
    <meter id="tp1vn"></meter>
      <wbr id="tp1vn"><sup id="tp1vn"></sup></wbr>
      日韩第一页浮力,欧美a在线,中文字幕无码乱码人妻系列蜜桃 ,国产成人精品三级麻豆,国产男女爽爽爽免费视频,中文字幕国产精品av,两个人日本www免费版,国产v精品成人免费视频71pao
      網易首頁 > 網易號 > 正文 申請入駐

      UDSonCAN 多幀傳輸完全指南:首幀、連續幀、流控幀一網打盡

      0
      分享至


      1. 引言

      UDS (Unified Diagnostic Services,統一診斷服務) 是汽車電子領域最主流的診斷協議,通常運行于 CAN 總線之上,形成 UDSonCAN。然而 UDS 單條報文最大可達 4095 字節,而標準 CAN 數據場僅 8 字節(CAN FD 可達 64 字節,本文以經典 CAN 為例)。為了在有限帶寬上可靠傳輸大塊數據,ISO 15765-2(即傳輸層,TP)定義了分段與重組機制,通過單幀、首幀、連續幀和流控幀這四類協議數據單元(PDU),實現了從單幀到多幀的無縫傳輸。理解這一機制,是開發 UDS 診斷棧的基礎。

      本文將深入淺出地剖析 UDSonCAN 的傳輸層核心機制,并用 C++ 代碼示例展示如何實現發送方與接收方的關鍵邏輯。

      2. UDSonCAN 協議棧架構

      UDSonCAN 遵循 OSI 模型分層:

      • 應用層:UDS 服務(如 0x10 診斷會話控制、0x22 讀數據等)

      • 傳輸層:ISO 15765-2,負責分段與重組

      • 數據鏈路層:CAN 幀 (ID, DLC, 8 字節數據)

      傳輸層 PDU 通過 CAN 數據場中的第一個字節(或前兩個字節)的N_PCI(協議控制信息)來區分幀類型。

      幀類型

      N_PCI 值 (高半字節)

      縮寫

      單幀

      0x0

      SF

      完整消息 ≤ 7 字節

      首幀

      0x1

      FF

      多幀消息的第一幀,攜帶總長度

      連續幀

      0x2

      CF

      后續數據塊,帶序列號

      流控幀

      0x3

      FC

      接收方控制發送方節奏(塊大小、間隔時間)


      3. 單幀傳輸(Single Frame)

      當 UDS 請求或響應總長度≤ 7 字節時,使用單幀。格式如下:

      字節0: SF 標識 (0x0) + 有效數據長度 (低4位)
      字節1~7: 應用層數據 (最多7字節)

      示例:請求22 F1 86(讀 DID 0xF186),長度 3 字節 → 單幀 PCI =0x03(高4位0,低4位3),CAN 數據為03 22 F1 86 00 00 00 00

      C++ 發送單幀示例

      #include  
      
      #include

      // 假設底層發送CAN幀的函數
      extern bool CanSendFrame(uint32_t canId, const std::vector& data);

      bool SendSingleFrame(uint32_t canId, const std::vector& udsData) {
      if (udsData.size() > 7) return false; // 超長需多幀
      std::vector canData(8, 0);
      canData[0] = static_cast(udsData.size()); // 高4位0,低4位長度
      std::copy(udsData.begin(), udsData.end(), canData.begin() + 1);
      return CanSendFrame(canId, canData);
      }
      4. 多幀傳輸機制(Multi-frame)

      當 UDS 消息長度超過 7 字節時,發送方將其拆分為:

      • 一個首幀(FF):告知總長度

      • 若干個連續幀(CF):攜帶后續數據

      • 接收方通過流控幀(FC)管理發送速率

      4.1 首幀(First Frame)

      字節0: FF標識 (0x1) + 總長度高4位
      字節1: 總長度低8位
      字節2~7: 前6字節數據

      總長度是一個 12 位值(最大 4095),拆分到字節0低4位和字節1整個8位。

      4.2 連續幀(Consecutive Frame)

      字節0: CF標識 (0x2) + 序列號 SN (低4位, 0~15)
      字節1~7: 后續7字節數據

      序列號從 1 開始,每發一幀加 1,循環 0~15。用于檢測丟幀。

      4.3 流控幀(Flow Control)

      接收方在收到 FF 后,若緩沖區允許,需發送 FC 告知發送方:

      • 塊大小(BS):允許連續發送的 CF 幀數(0 表示無限)

      • 最小間隔時間(STmin):兩幀 CF 之間的最小間隔(ms 或 100us 單位)

      字節0: FC標識 (0x3) + 流控狀態 (通常0=繼續發送, 1=等待, 2=溢出)
      字節1: 塊大小 BS
      字節2: 最小間隔 STmin (編碼格式見標準)
      字節3~7: 未使用,填0
      5. 多幀傳輸時序與狀態機

      典型的多幀發送(請求讀取大量數據,如 0x22 讀長 VIN 碼):

      診斷儀(發送方)                     ECU(接收方)
      | |
      |---- FF (總長度=50, 前6字節) ---->|
      | | 解析FF,分配緩沖區
      |<---- FC (BS=5, STmin=10ms) ------|
      | |
      |---- CF (SN=1, 7字節) ----------->|
      | (等待10ms) |
      |---- CF (SN=2, 7字節) ----------->|
      | (等待10ms) |
      |---- CF (SN=3, 7字節) ----------->|
      | (等待10ms) |
      |---- CF (SN=4, 7字節) ----------->|
      | (等待10ms) |
      |---- CF (SN=5, 7字節) ----------->| 收到5幀后
      | | 發送新的FC
      |<---- FC (BS=5, STmin=10ms) ------|
      |---- CF (SN=6, 7字節) ----------->|
      ... ...

      接收方狀態機簡化如下:

      • WAIT_FF:等待首幀,超時則中止

      • WAIT_CF:等待連續幀,并計數,每 BS 幀后等待新 FC

      • WAIT_FC(發送方視角):發送完 FF 后等待 FC,超時重試或中止

      6. C++ 代碼示例:實現發送方和接收方核心邏輯

      以下代碼演示了發送方如何將任意長度的 UDS 消息分段發送,以及接收方如何重組為完整消息。為簡潔起見,省略了超時、錯誤重傳等細節,僅突出核心機制。

      6.1 發送方類UdsTpSender

      #include  
      
      #include
      #include
      #include
      #include


      class UdsTpSender {
      public:
      using CanTxFunc = std::function& data)>;
      UdsTpSender(CanTxFunc txFunc) : txFunc_(txFunc) {}
      // 發送UDS消息(可能拆分為多幀)
      bool Send(uint32_t canId, const std::vector& udsData) {
      if (udsData.size() <= 7) {
      return SendSingleFrame(canId, udsData);
      } else {
      return SendMultiFrame(canId, udsData);
      }
      }
      private:
      bool SendSingleFrame(uint32_t canId, const std::vector& data) {
      std::vector canData(8, 0);
      canData[0] = static_cast(data.size()); // SF PCI
      std::copy(data.begin(), data.end(), canData.begin() + 1);
      return txFunc_(canId, canData);
      }
      bool SendMultiFrame(uint32_t canId, const std::vector& udsData) {
      // 1. 發送首幀 (FF)
      uint16_t totalLen = static_cast(udsData.size());
      std::vector ffData(8, 0);
      ffData[0] = 0x10 | ((totalLen >> 8) & 0x0F); // 高4位=1, 低4位=長度高4位
      ffData[1] = totalLen & 0xFF;
      // 拷貝前6字節數據到 ffData[2..7]
      size_t firstChunk = std::min(6, udsData.size());
      std::copy(udsData.begin(), udsData.begin() + firstChunk, ffData.begin() + 2);
      if (!txFunc_(canId, ffData)) return false;
      // 2. 等待接收方流控幀 (實際應使用異步接收回調,這里簡化為同步獲取)
      // 實際項目中需要配合接收隊列和超時機制。此處僅展示收到FC后的行為。
      // 假設我們通過回調得到FC參數: bs, stmin
      // 本示例模擬一個默認FC: BS=0(無限), STmin=0(無間隔)
      uint8_t blockSize = 0; // 0表示無限
      uint8_t stMin = 0; // 0ms
      // 偽代碼:實際應等待接收FC幀,解析其字節1和字節2
      // WaitForFlowControl(bs, stmin);
      // 3. 發送連續幀
      size_t offset = firstChunk;
      uint8_t seqNum = 1;
      while (offset < udsData.size()) {
      // 如果 blockSize > 0,需要每發送 blockSize 幀后等待新的FC
      // 本示例簡化:連續發完所有CF
      std::vector cfData(8, 0);
      cfData[0] = 0x20 | (seqNum & 0x0F); // CF PCI + 序列號
      size_t copySize = std::min(7, udsData.size() - offset);
      std::copy(udsData.begin() + offset, udsData.begin() + offset + copySize,
      cfData.begin() + 1);
      if (!txFunc_(canId, cfData)) return false;
      offset += copySize;
      seqNum = (seqNum + 1) & 0x0F;
      // 遵守STmin延時
      if (stMin > 0) {
      std::this_thread::sleep_for(std::chrono::milliseconds(stMin));
      }
      }
      return true;
      }
      CanTxFunc txFunc_;
      };
      6.2 接收方類UdsTpReceiver

      接收方需要維護多個會話(不同 CAN ID 可能同時多幀傳輸),為簡明,僅處理單會話。

      class UdsTpReceiver {
      public:
      enum State { WAIT_FF, WAIT_CF };
      void OnCanFrame(uint32_t canId, const std::vector& canData) {
      if (canData.empty()) return;
      uint8_t pci = canData[0] >> 4;
      uint8_t lenLow = canData[0] & 0x0F;
      switch (pci) {
      case 0x0: { // 單幀
      size_t dataLen = lenLow;
      std::vector udsMsg(canData.begin() + 1, canData.begin() + 1 + dataLen);
      OnCompleteMessage(canId, udsMsg);
      break;
      }
      case 0x1: { // 首幀
      uint16_t totalLen = (lenLow << 8) | canData[1];
      // 前6字節數據位置 canData[2..7]
      reassembled_.clear();
      reassembled_.reserve(totalLen);
      size_t firstChunk = std::min(6, totalLen);
      reassembled_.insert(reassembled_.end(), canData.begin() + 2, canData.begin() + 2 + firstChunk);
      expectedSeq_ = 1;
      remaining_ = totalLen - firstChunk;
      state_ = WAIT_CF;
      // 發送流控幀 (BS=0無限, STmin=0)
      SendFlowControl(canId, 0, 0);
      break;
      }
      case 0x2: { // 連續幀
      if (state_ != WAIT_CF) return;
      uint8_t seq = lenLow;
      if (seq != expectedSeq_) {
      // 序列號錯誤,可發送溢出流控或忽略
      return;
      }
      size_t copySize = std::min(7, remaining_);
      reassembled_.insert(reassembled_.end(), canData.begin() + 1, canData.begin() + 1 + copySize);
      remaining_ -= copySize;
      expectedSeq_ = (expectedSeq_ + 1) & 0x0F;
      if (remaining_ == 0) {
      OnCompleteMessage(canId, reassembled_);
      state_ = WAIT_FF;
      }
      break;
      }
      case 0x3: // 流控幀(接收方不應收到主動發送的FC,除非作為發送方)
      default:
      break;
      }
      }
      void SetMessageCallback(std::function&)> cb) {
      onComplete_ = cb;
      }
      private:
      void SendFlowControl(uint32_t canId, uint8_t blockSize, uint8_t stMin) {
      std::vector fc(8, 0);
      fc[0] = 0x30; // FC PCI + flowStatus=0(繼續發送)
      fc[1] = blockSize;
      fc[2] = stMin;
      // 實際需要調用底層發送,此處略
      // CanSendFrame(canId, fc);
      }
      State state_ = WAIT_FF;
      std::vector reassembled_;
      uint8_t expectedSeq_;
      size_t remaining_;
      std::function&)> onComplete_;
      };
      6.3 集成示例

      #include  
      


      int main() {
      auto txFunc = [](uint32_t id, const std::vector& data) {
      std::cout << "Tx CAN ID 0x" << std::hex << id << ": ";
      for (auto b : data) printf("%02X ", b);
      std::cout << std::endl;
      return true;
      };
      UdsTpSender sender(txFunc);
      std::vector longUds = {0x22, 0xF1, 0x86, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
      sender.Send(0x7DF, longUds);
      // 接收側模擬
      UdsTpReceiver receiver;
      receiver.SetMessageCallback([](uint32_t id, const std::vector& msg) {
      std::cout << "Rcvd complete UDS (" << msg.size() << " bytes): ";
      for (auto b : msg) printf("%02X ", b);
      std::cout << std::endl;
      });
      // 模擬收到首幀和連續幀...
      // receiver.OnCanFrame(0x7DF, {0x10, 0x0A, 0x22, 0xF1, 0x86, 0x01, 0x02, 0x03});
      // receiver.OnCanFrame(0x7DF, {0x21, 0x04, 0x05, 0x06, 0x07, 0x00, 0x00, 0x00});
      return 0;
      }
      7. 關鍵注意事項
      • 流控幀的 STmin 編碼:ISO 15765-2 定義了多種間隔值,如 0x00~0x7F 表示 0~127 ms,0xF1 表示 100 μs 等。實現時需解析并精確延時。

      • 多會話并發:不同 CAN ID 或不同診斷會話可能同時傳輸多幀,接收方需按(canId, sourceAddr)維護獨立的重組緩沖區。

      • 超時處理:發送 FF 后等待 FC 超時(通常 1000ms),接收方等待 CF 超時(通常 100ms),需有定時器機制。

      • 錯誤恢復:序列號錯誤、緩沖區溢出時應發送 FC 狀態 = 溢出(0x2)或中止多幀傳輸。

      8. 總結

      UDSonCAN 的單幀與多幀傳輸機制,通過精巧的四類 PCI 類型和流控握手,實現了有限帶寬下的可靠大塊數據傳輸。理解 SF、FF、CF、FC 的含義及狀態轉換,是開發車載診斷工具、ECU 固件或仿真器的基礎。本文提供的 C++ 核心代碼展示了發送與重組的基本骨架,實際產品中還需加入超時管理、多會話并發、錯誤恢復等模塊,但萬變不離其宗——ISO 15765-2 定義的這一套簡單而強大的協議,正是汽車診斷可靠性的基石。

      掌握從單幀到多幀的“傳輸奧秘”,你將能輕松應對各種 UDS 診斷開發場景。

      特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。

      Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

      相關推薦
      熱點推薦
      魯比奧稱烏軍是全歐洲最強大的軍隊,澤連斯基下令回應俄羅斯空襲

      魯比奧稱烏軍是全歐洲最強大的軍隊,澤連斯基下令回應俄羅斯空襲

      山河路口
      2026-05-15 12:35:13
      未婚女孩隱私部位膿腫南京明基醫院要求住院手術 女孩換家三甲醫院開了4塊錢藥治好

      未婚女孩隱私部位膿腫南京明基醫院要求住院手術 女孩換家三甲醫院開了4塊錢藥治好

      墜入二次元的海洋
      2026-05-15 19:16:40
      徹底瞞不住了,何九華承認自己當爹,稱孩子已2歲,王鷗回應打臉

      徹底瞞不住了,何九華承認自己當爹,稱孩子已2歲,王鷗回應打臉

      小樾說歷史
      2026-05-14 11:42:08
      87-82險勝!京媒撕開遮羞布:張鎮麟這招“作弊碼”,打疼了誰?

      87-82險勝!京媒撕開遮羞布:張鎮麟這招“作弊碼”,打疼了誰?

      舟望停云
      2026-05-16 01:10:30
      小寶與王某雷,誰探訪花的數量更多?

      小寶與王某雷,誰探訪花的數量更多?

      挪威森林
      2026-01-31 12:15:26
      深圳一建筑工地兩名工人從6樓墜亡?當地住建確認涉事項目有安全事故發生致2人死亡,已要求項目停工整改

      深圳一建筑工地兩名工人從6樓墜亡?當地住建確認涉事項目有安全事故發生致2人死亡,已要求項目停工整改

      大風新聞
      2026-05-15 17:32:44
      恭喜!陳思誠又當爹!26歲小女友曬生日照,一臉孕相得到父母認可

      恭喜!陳思誠又當爹!26歲小女友曬生日照,一臉孕相得到父母認可

      八卦王者
      2026-05-14 11:39:43
      24桿147!斯諾克新紀錄誕生:中國7人上榜,常冰玉進賬133萬獎金

      24桿147!斯諾克新紀錄誕生:中國7人上榜,常冰玉進賬133萬獎金

      劉姚堯的文字城堡
      2026-05-15 10:01:41
      心理學有個殘忍真相:子女長大后不心疼你,從來不是他不懂感恩,也不是他薄情寡義,而是你早年這兩種“隱形傷害”,親手關閉他心疼人開關

      心理學有個殘忍真相:子女長大后不心疼你,從來不是他不懂感恩,也不是他薄情寡義,而是你早年這兩種“隱形傷害”,親手關閉他心疼人開關

      心理觀察局
      2026-05-07 10:05:05
      朱雀二號改進型成功復飛!長六甲再送18顆“千帆”衛星入軌

      朱雀二號改進型成功復飛!長六甲再送18顆“千帆”衛星入軌

      NASA愛好者
      2026-05-15 03:36:06
      被曝涉黃,觸目驚心!網友怒了: 看得脊背發涼

      被曝涉黃,觸目驚心!網友怒了: 看得脊背發涼

      每日經濟新聞
      2026-05-13 21:30:06
      26連勝+三殺北京!上海強得可怕,許利民怒砸廣告牌,李楠也無解

      26連勝+三殺北京!上海強得可怕,許利民怒砸廣告牌,李楠也無解

      萌蘭聊個球
      2026-05-15 21:47:04
      卸磨殺驢的結果!文胖:詹皇愿去別隊拿中產,也不愿降薪3000萬

      卸磨殺驢的結果!文胖:詹皇愿去別隊拿中產,也不愿降薪3000萬

      錢說體育
      2026-05-15 09:05:10
      美媒問“10年后,世人會怎么評價這次訪問”,特朗普的回答不一般

      美媒問“10年后,世人會怎么評價這次訪問”,特朗普的回答不一般

      阿龍聊軍事
      2026-05-15 14:52:46
      案件:廣東一女子與弟弟布置婚房,丈夫看到監控后,當場錘死妻子

      案件:廣東一女子與弟弟布置婚房,丈夫看到監控后,當場錘死妻子

      紅豆講堂
      2025-01-02 15:00:02
      馬斯克表示:他絕對能建造出比中國任何公共交通系統都更好的系統

      馬斯克表示:他絕對能建造出比中國任何公共交通系統都更好的系統

      華史談
      2026-04-14 13:00:13
      我跟女總裁說:你要是我媳婦我一天揍你3頓,隔天她帶5個保鏢堵我

      我跟女總裁說:你要是我媳婦我一天揍你3頓,隔天她帶5個保鏢堵我

      千秋文化
      2026-05-13 19:47:04
      東契奇3年3次季后賽傷停,帕金斯:正滑向"恩比德陷阱"

      東契奇3年3次季后賽傷停,帕金斯:正滑向"恩比德陷阱"

      溫柔且自由
      2026-05-16 02:05:22
      北京3將低迷太致命了!杰曼陳盈駿被鎖死,曾凡博帶傷攻守全迷!

      北京3將低迷太致命了!杰曼陳盈駿被鎖死,曾凡博帶傷攻守全迷!

      籃球資訊達人
      2026-05-16 01:53:46
      16對16,這場國宴誰坐了C位

      16對16,這場國宴誰坐了C位

      梳子姐
      2026-05-15 20:47:03
      2026-05-16 06:23:00
      新能源自動駕駛 incentive-icons
      新能源自動駕駛
      專注于半導體行業資訊
      977文章數 347關注度
      往期回顧 全部

      科技要聞

      直降千元起步!蘋果華為率先開啟618讓利

      頭條要聞

      黃仁勛在北京喝豆汁痛苦皺眉 問“這是什么東西”

      頭條要聞

      黃仁勛在北京喝豆汁痛苦皺眉 問“這是什么東西”

      體育要聞

      德約科維奇買的球隊,從第6級聯賽升入法甲

      娛樂要聞

      方媛為何要來《桃花塢6》沒苦硬吃?

      財經要聞

      騰訊掉隊,馬化騰戳破真相

      汽車要聞

      高爾夫GTI刷新紐北紀錄 ID. Polo GTI迎全球首秀

      態度原創

      家居
      數碼
      教育
      房產
      藝術

      家居要聞

      110㎡淡而有致的生活表達

      數碼要聞

      聯想發布ThinkPad T14 Gen 7 支持LPCAMM2可更換內存

      教育要聞

      老師掌摑多名學生后續,系一名書法教師,當地公布處罰結果

      房產要聞

      老黃埔熱銷之下,珠江春,為何去化僅3成?

      藝術要聞

      讓人拍案叫絕的圖片

      無障礙瀏覽 進入關懷版 主站蜘蛛池模板: 亚洲中文精品人人永久免费| www.xxxx中国视频| 亚洲人成色777777无码| 午夜激情网站| 99国产揄拍国产精品人妻| 久热香蕉av在线爽青青| 色婷婷激情四射| 无码人妻毛片丰满熟妇精品区| 成年女人免费视频播放体验区| 亚洲精品午夜无码电影网| 老太脱裤让老头玩ⅹxxxx| 日韩一二三区中文字幕| 亚洲鸥美日韩精品久久| 日本精品中文字幕| 一区二区三区激情免费视频| 98精品国产综合久久| 欧美嫩交一区二区三区| 亚洲成人综合导航| 欧美人与禽交zozo在线观看| 久久精品国产精品亚洲38| 国产首页一区二区不卡| 人妻少妇精品无码专区二区| 国产精品一区二区av片| 思思99re6国产在线播放| 精品少妇av蜜臀av| 福利导航视频| 猫咪AV成人永久网站在线观看| 久久亚洲第一视频黄色| 少妇高潮流白浆在线观看| 高清免费毛片| 亚洲一区二区精品极品| A级毛片视频免费观看不卡 | 在线欧美精品一区二区三区| 国产免费高清视频在线观看不卡| 99精品久久久中文字幕| 国产成人精品一区二三区| 一本一道狠狠躁东京热| 精品91精品91精品国产片| 亚洲欧洲精品国产二码| 曲阳县| 国产理论精品|