ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

UDS诊断多帧传输详解:从ISO-TP首帧、流控帧到连续帧的实战拆解

UDS诊断多帧传输详解:从ISO-TP首帧、流控帧到连续帧的实战拆解 刚接触UDS诊断协议的同学十有八九会在多帧传输这块栽跟头。我见过不少人拿着CAN报文分析软件一看发送方发出的是10 0E 2E F1 90 ...接收方回了个30 00 14然后双方就开始疯狂刷21 xx xx xx看着像是有规律但真让自己解释每一帧的含义、算一算序列号怎么回卷又说不清了。这很正常多帧传输本身不是UDS的内容而是底层ISO-TPISO 15765-2干的活UDS只负责定义“服务ID和参数怎么编排”至于数据太长怎么拆、怎么发、怎么确认全部交给了ISO-TP。所以很多人查了一堆UDS资料还是看不懂报文就是因为没把ISO-TP这部分补上。这篇文章我打算抛开教科书式的定义直接用一条完整的实际报文从首帧FF到流控帧FC再到连续帧CF逐步拆给你看。同时把FF_DL、BS、STmin、SN这些关键参数掰开了讲清楚再附上我这些年调ECU踩过的坑和排查思路。无论你是刚入门做诊断测试还是正在写Bootloader刷写逻辑这篇文章应该能帮你把多帧传输这块彻底打通。1. 为什么单帧装不下诊断数据一个报文引发的“拆包”思考要理解多帧传输先得明白它到底解决了什么问题。经典CAN的数据场最长只有8个字节而ISO-TP为了表示“这一帧是什么类型”还要从这8个字节里拿出1到2个字节做协议控制信息PCIProtocol Control Information。以最常用的经典CAN标准帧为例单帧SFSingle Frame的PCI只占1个字节高四位是帧类型0x0低四位表示后续有效数据长度所以单帧最多能携带的有效数据只有7个字节。但是诊断业务可没这么“抠门”。比如用0x2E服务写入一组标定参数或者用0x34请求下载一段Firmware数据几百上千个字节都是常态。别说7个字节了CAN FD没普及之前64字节都不够看。这时候唯一的办法就是拆包把一条完整的UDS报文切成多个CAN帧按顺序发出去接收方再拼回来。这个“切”和“拼”的规则就是ISO-TP里的多帧传输机制。打个比方单帧传输就像你往普通信箱里塞一张明信片地址写上就能寄多帧传输则是寄一个大包裹包裹太沉不能一次搬完于是你分几个箱子装。这时候快递公司要求你第一个箱子上必须写明“总共几箱、每箱编号多少、总重量多少”快递员收到第一箱后告诉你“你可以一次搬几箱每隔多少秒搬一箱”然后你按这个节奏把剩下的箱子搬完收货人再按箱子上的编号拼回原样。放到CAN总线上第一个箱子就是首帧FF快递员的回复就是流控帧FC后面每个小箱子就是连续帧CF而箱子上的编号就是CF的序列号SN。理解了这层关系再看报文就顺了。ISO-TP一共定义了四种帧单帧SF、首帧FF、流控帧FC和连续帧CF。帧类型由CAN数据场第一个字节的高四位决定0x0是单帧0x1是首帧0x2是流控帧0x3是连续帧。所以只要看到报文数据场第一个字节的最高位是0x1或者0x3就能立刻反应过来这是一条多帧传输的报文。那么“到底多长才算长”这个阈值由接收方的接收能力决定但绝大多数ECU和诊断仪都遵守一个默认规则单帧最多7个字节有效数据经典CAN。如果一条UDS报文拆掉PCI之后的有效数据不超过7个字节就直接用单帧发一旦超过7个字节就必须走FF FC CF的多帧流程。需要注意的是有些ECU的接收缓冲区比较小或者发送方处于扩展寻址单帧有效数据还要再少一点比如只有6个字节甚至更少。具体以ECU的通信参数为准别想当然套7字节。从ISO七层模型看UDS工作在应用层ISO-TP工作在传输层和网络层CAN控制器负责数据链路层和物理层。应用层只负责生成“我要写哪些数据”传输层负责“数据太长怎么办”CAN控制器才不管什么诊断不诊断它只负责把8个字节放到总线上。这种分层的设计让UDS协议本身不需要关心底层是CAN还是CAN FD只要ISO-TP能把数据靠谱地搬过去就行。2. 认识ISO-TP的四种帧单帧、首帧、流控帧、连续帧很多资料喜欢一上来就甩PCI字节的位定义表格看得人头皮发麻。我的建议是先把四种帧的“长相”记熟再去看位定义就会轻松很多。下面我直接从CAN数据场的角度把这四种帧逐个过一遍。2.1 单帧SF与首帧FF的结构差异单帧的PCI叫PCI.SF第一个字节的高四位是0x0低四位是SF_DL表示这个单帧里携带了多少个有效数据字节。比如报文02 10 01 00 00 00 00 00第一个字节0x02高四位0x0说明是单帧低四位0x2说明后面有2个有效数据字节也就是10 01这正好是0x10ECU复位服务的请求。剩下5个字节是填充字节通常填0x00或者0xCC接收方直接忽略。首帧的PCI叫PCI.FF第一个字节的高四位是0x1低四位是FF_DL的高4位第二个字节是FF_DL的低8位两个拼起来是一个12位的数表示这条多帧传输的总长度范围是8到4095字节。为什么最小是8因为如果有效数据不超过7字节直接走单帧就行根本不需要多帧所以FF_DL的取值范围从8起步是合理的。FF的第三个字节开始才是真正的UDS数据也就是说FF携带的有效数据在经典CAN下最多是6个字节因为8字节DLC里有2个字节被PCI占了。判断一条报文是SF还是FF看第一个字节的高四位就行0x0是SF0x1是FF。这里有个细节容易看走眼比如报文12 34 56 ...高四位0x1有些初学者以为这是首帧实际上低四位0x2表示后面有2个数据字节34 56就是数据这是一个标准的单帧只是恰好数据长度是2。所以千万别只看字节开头是不是1一定要区分高四位和低四位。2.2 流控帧FC里那三个参数怎么读流控帧是接收方发给发送方的作用是告诉发送方“你可以继续发了但得按我的节奏来”。它的PCI是PCI.FC第一个字节高四位是0x2低四位是流控状态FSFlow Status第二个字节是块大小BSBlock Size第三个字节是最小间隔时间STminSeparation Time minimum。FS有三种值0x0表示ContinueToSendCTS意思是“同意你继续发”0x1表示WaitWT意思是“我还没准备好你等着”0x2表示OverflowOVFLW意思是“我的缓冲区爆了这条多帧传输作废”。实际调试中0x0最常见0x1偶尔在ECU启动刷写流程时能看到0x2基本属于异常状态一旦出现往往意味着BS、STmin没协商好或者接收方处理不过来。BS表示“一个块里最多允许发多少个连续帧”。BS 0时表示“我不限制你把剩下的CF一口气全发完”BS nn 0时表示“你最多连续发n个CF然后必须停下来等我再发一个FC我确认后你才能继续”。BS这个参数是很多人的盲区以为它和STmin一样只是限制发送速率其实它控制的是“发送节奏”后面第4节我会专门讲。STmin表示发送方在连续发送两个CF之间需要等待的最小时间间隔。它的单位不一定是毫秒具体编码规则比较复杂我会在4.1节单独展开。这里先记住STmin是用来防止发送方“狂发”导致接收方来不及处理的。2.3 连续帧CF的序列号和排列规则连续帧的PCI叫PCI.CF第一个字节高四位是0x3低四位是序列号SNSequence Number。SN从1开始每发一个CF就加1加到15之后回卷为0然后继续1、2、3……循环。注意FF本身不算序列号它不参与SN计数。第一个CF的SN一定是1之后是2、3、4……一直到15下一个是0再下一个是1。这个回卷规则让不少测试工具在解析长报文时犯迷糊明明是正常重传工具却报“序列号错误”这个坑我在5.1节细说。CF的有效数据长度经典CAN下最多7个字节因为它只占1个字节的PCI。CF的数据就是UDS报文被切剩下的部分接收方按照SN顺序把数据拼到FF已经收到的6个字节后面。只要最后拼出来的总长度等于FF_DL这条多帧传输就算完整接收成功了。可能存在一种特殊帧帧类型为0x3但SN字段是0的多帧帧。有些资料把它叫做“特殊多帧”或者“无序列号帧”实际用的很少我在这里就不展开了。正常项目里只要按标准CF处理就够用。3. 实战拆解一条多帧写请求的完整一生前面把四种帧的结构说清楚了但纸上谈兵没用最好的学习方法就是拿一条真实报文一行行对照。下面我用一个0x2EWriteDataByIdentifier按标识符写数据服务的例子带大家走一遍完整的FF→FC→CF→响应流程。3.1 用0x2E构造一个超过单帧能力的长请求假设我作为诊断仪要向ECU的DID 0xF190写入一串40字节的标定数据。0x2E服务的UDS报文格式是服务ID0x2E DID2字节 数据40字节所以整条UDS报文长度 1 2 40 43字节。43字节远超单帧7字节的上限必须走多帧。总长度43字节用16进制表示就是0x2B。那么FF_DL 43换算到PCI里第一个字节高四位是0x1低四位是FF_DL的高4位0x2所以第一个字节是0x12第二个字节是FF_DL的低8位0x2B。于是FF的PCI就是12 2B。FF在经典CAN下能携带6个字节的有效数据也就是UDS报文的前6个字节2E F1 90加上40字节数据中的前3个字节。假设数据是01 02 03 04 05 06 ... 2840个字节那前3个字节就是01 02 03。所以FF的实际报文是12 2B 2E F1 90 01 02 03DLC 8。3.2 每一帧报文的逐字节解读我模拟一段诊断仪和ECU之间完整的CAN报文记录时间戳单位是毫秒Tx表示诊断仪发出Rx表示ECU发出00000.000 Tx 7E0 8 12 2B 2E F1 90 01 02 03 00000.010 Rx 7E8 8 30 00 14 00 00 00 00 00 00000.030 Tx 7E0 8 21 04 05 06 07 08 09 0A 00000.050 Tx 7E0 8 22 0B 0C 0D 0E 0F 10 11 00000.070 Tx 7E0 8 23 12 13 14 15 16 17 18 00000.090 Tx 7E0 8 24 19 1A 1B 1C 1D 1E 1F 00000.110 Tx 7E0 8 25 20 21 22 23 24 25 26 00000.130 Tx 7E0 8 26 27 28 00 00 00 00 00 00000.160 Rx 7E8 8 06 6E F1 90 00 00 00 00逐条拆解第一条诊断仪发出12 2B 2E F1 90 01 02 03。这是首帧FF。PCI0x12表示帧类型是首帧FF_DL高4位是20x2B是FF_DL低8位合并得到总长度0x02B即43字节。从第三个字节开始是UDS报文的内容2E是服务IDF1 90是DID01 02 03是数据的前3字节。到这里这条0x2E请求已经“先到一部分了”。第二条ECU收到FF后回了30 00 14。这是流控帧FC。0x30表示帧类型是流控帧流控状态FS 0CTS继续发送BS 0x00表示不限制块大小STmin 0x14表示两个CF之间的最小间隔是20毫秒。后面的00是填充字节接收方不会去读。第三条到第七条是5个连续帧CF。第一个CF的SN是1所以PCI是0x21后面携带7个字节04 05 06 07 08 09 0A第二个CF的SN是2PCI是0x22携带7个字节0B 0C 0D 0E 0F 10 11依次类推。第五个CFSN5携带20 21 22 23 24 25 26。这时候计算一下FF带了6字节前4个CF各7字节共28字节第五个CF又带了7字节总共已经41字节。但总长度是43字节还需要2个字节于是第六个CF的SN应该为6PCI是0x26携带最后2个字节27 28后面补5个填充字节00。这里有一个非常关键的细节最后一个CF不一定满7个字节。比如例子中最后只剩2字节数据发送方直接发DLC 8数据场为26 27 28 00 00 00 00 00前3个字节是PCI有效数据后面是填充。接收方在拼接时只按FF_DL计算有效长度不会把填充字节当成数据。所以FF_DL43就是整个ISO-TP层有效数据的长度拼接完43个字节后多余部分自动丢弃。第八条ECU处理完这条写请求后回复06 6E F1 90 00 00 00 00。这是一个单帧SFPCI0x06表示单帧且后面有6个字节有效数据内容是6E F1 90 00 00 00。其中6E是0x2E服务的肯定响应F1 90回显了DID后面3个字节00 00 00其实是数据长度或厂商自定义信息要按具体协议规范读。因为响应很短根本不需要多帧。可以看到整个交互里请求方向用了1个FF 1个FC 6个CFUDS报文是完整的一整条但物理上被拆成了8帧CAN报文。用CANalyzer或者PCAN的报文窗口看中间其实还夹着ECU发来的FC这是很多新手最容易困惑的地方明明是我在发请求为什么ECU会在我发送过程中插一帧进来因为它要流控这是正常流程不是异常。3.3 反过来看ECU多帧响应时的流控方向上面是“请求多帧、响应单帧”的例子。实际调试中更常见的其实是“请求单帧、响应多帧”典型场景就是用0x22ReadDataByIdentifier读一大段VIN码、软件版本号或者标定数据。这时候发流控帧的是诊断仪而不是ECU。一次典型的响应多帧流程是这样诊断仪发送03 22 F1 90单帧读DID 0xF190ECU回复一个首帧比如10 2C 62 F1 90 ...表示这条响应总长度是0x2C即44字节并且已经把响应的前6个字节带来了。诊断仪收到FF之后会回一个FC比如30 00 00意思是“我允许你无限制连续发送两个CF之间也不要求间隔”。ECU收到FC后连续发出SN从1开始的若干CF直到响应数据全部发完。很多诊断仪实现里发送FC的时机非常讲究必须等收到FF之后才能发不能提前发也不能不发直接等。如果诊断仪迟迟不发FCECU那边会触发N_Bs超时认为通信异常直接终止这次响应。反过来诊断仪收到最后一个CF发现拼出来的长度和FF_DL一致才算完整收到一条响应。这个“完整收包”的判断逻辑也很重要有些工具对响应长度的校验很严格多一个字节、少一个字节都会报错。4. 参数选择背后的时间账BS、STmin怎么定才合理多帧传输跑得稳不稳、快不快很大程度上取决于流控帧里的BS和STmin参数。这两个参数看似简单仔细琢磨还是挺有门道的。ECU作为接收方它在流控帧里给的BS和STmin本质上是它处理能力的“公告”能扛多大压力、需要多少时间。诊断仪作为接收方时同理它在流控帧里给出的参数必须匹配它自身软件栈的接收能力。4.1 STmin的编码规则与典型取值STmin的编码规则我见过很多人记混这里直接给出一张表STmin值含义0x00不限制间隔发送方可以以最快速度连续发送0x01 - 0x7F间隔时间为1ms到127ms值本身对应毫秒数0x80 - 0xF0间隔时间为100us到10ms按100us步进0x80代表100us0x81代表200us以此类推0xF0代表10ms0xF1 - 0xF9间隔时间为1ms到9ms值减去0xF0就是毫秒数0xFA - 0xFF保留值通常不使用实际项目里ECU给的STmin最常见的是0x00、0x01、0x0A和0x14这几个值。0x00表示不要求间隔多见于对接收缓冲很有信心的ECU0x01是1ms刷写场景里比较常见0x14是20ms保守派ECU常用这个值处理速度偏慢。如果你发现某个ECU发了STmin0x01但还是丢CF那问题往往不在STmin本身而在ECU的应用层处理逻辑或者你用的诊断仪发送不够“干净”。这里有一个容易踩的坑STmin的计时起点是“上一个CF发送完成”到“下一个CF开始发送”的时间间隔不是两个CF开始发送的间隔。有些测试工具在计算发送时间时直接把两个CF的时间戳差值拿去和STmin比结果总比理论值大一点误以为没有违反STmin实际上工具自己的发送逻辑可能已经违规了。我自己遇到过类似情况最后是拿示波器看CAN总线电平才确认的。4.2 BS块大小对传输节奏的影响BS的含义前面提过0表示不限块n表示最多连发n个CF。为什么要有限块大小的设计因为接收方的缓冲区不一定能容纳整条多帧数据。比如ECU只有64字节的接收缓冲区但是诊断仪要一次性写入200字节的标定数据如果ECU发FC说BS0诊断仪一口气把几十个CF全发出去ECU缓冲区必然溢出最后只能回一个Overflow状态的FC整条传输作废。所以很多ECU在刷写场景里会把BS设成一个较小的值比如BS2或BS4。意思是诊断仪发2个或4个CF之后必须停下来等ECU再发一个FCECU确认自己缓冲区里的数据已经搬走、腾出空间了才允许诊断仪继续发。这样虽然牺牲了总线的吞吐率但保证了传输的可靠性。BS和STmin是配合使用的。BS限制的是“发多少个就要停下来等流控”STmin限制的是“每个CF之间至少间隔多久”。哪怕BS0也不意味着发送方可以无脑猛发STmin照样卡着你。反过来如果STmin0但BS很小发送方每发几个CF就要停下来等流控传输节奏依然被接收方牢牢控制着。我把两者的作用列成一张联想表参数控制对象典型取值场景BS0, STmin较小吞吐优先适合接收缓冲区足够大的ECU读取大段DID数据、刷写时ECU开启大缓冲区BS0, STmin较大流速控制适合处理速度慢的ECU老平台ECU、应用层处理耗时长的诊断服务BS0, STmin较小缓冲控制和吞吐折中刷写阶段ECU一边收数据一边擦FlashBS0, STmin较大双重限速最保守故障排查时临时用能有效规避丢帧4.3 传输时间的粗算方法与实测对比知道了BS和STmin其实可以粗算一条多帧传输花多少时间。还是用3.2节的例子总长43字节FF带了6字节剩余37字节。每个CF带7字节37除以7等于5余2所以需要6个CF。假设STmin20msBS0那么从第一个CF开始到最后一个CF结束理想情况下总耗时大概是6 - 1× 20ms 100ms因为5个间隔每个20ms。如果FF到第一个CF之间也要求STmin那就要再加上20ms具体看ECU的时序要求。这个公式看起来简单实际测试时我发现总会比理论值多出几毫秒。原因有两个一是CAN控制器本身有发送队列和仲裁延时特别是在总线负载高的时候一帧明明已经放入发送邮箱却因为总线被其他报文占用而延后二是接收方虽然设了STmin但它在发送FC的时候也可能有处理延时诊断仪收到FC之后才能发FF这段时间也会被计入总耗时。所以理论计算只能用来估算不要指望完全一致。如果BS 0比如BS2总耗时就要加上每次等待FC的时间。假设每次ECU收到2个CF之后过了10ms发下一个FC那么除了STmin造成的间隔每2个CF还会额外加10ms等待时间。用公式表达就是总耗时约等于总CF数 - 1个STmin间隔 块切换次数 × 每次FC等待时间。块切换次数等于ceil(总CF数 / BS) - 1如果BS不为0。做刷写工具的时候传输时间直接影响整包刷写耗时。我见过有人把STmin从20ms改成1ms整包数据刷写时间缩短了十几秒但随之而来的是ECU偶发超时。这种时候千万别只看平均值要看最差情况下的总线负载和ECU处理能力留足余量比一味求快重要得多。5. 多帧传输的常见坑与排查实录多帧传输的坑绝大多数不是协议理解问题而是实现细节问题。下面几条都是我在实际项目里踩过或者帮别人排查过的每条都对应一段真实经历。5.1 序列号回卷为什么会被误报错前面提到CF的SN从1递增到15之后回卷为0。也就是说当连续帧数量超过15个时第16个CF的SN是0第17个是1依此类推。这个回卷在UDS里是合法的但很多分析工具或者诊断仪协议栈实现不严谨看到SN从15变成0就认为“顺序错了”直接丢弃后续CF导致整条多帧传输失败。我第一次碰到这个问题是在刷写一个Bootloader传输层一次性要发200多个CF。用的诊断仪是某款开源软件改的每次传到第16帧就卡住。查了半天发现是解析代码里写了“if (sn ! previous_sn 1) return ERROR”完全没有处理15到0的回卷。后来改成“if (sn ! (previous_sn 1) % 16) return ERROR”问题立刻消失。如果你自己写ISO-TP接收逻辑一定要用取模运算判断序列号不要用简单的自增比较。顺带提醒一下发送侧也要注意在连续发送多帧时发送计数器到达15后必须回0不能停在15上继续发。有些工程师在发送循环里忘记回卷导致同一个SN重复出现接收方虽然能通过长度判断数据是完整的但很多严格实现会直接报“SN重复”拒绝接收。5.2 流控帧丢失导致的N_Bs超时ISO-TP定义了好几个超时参数普通工程师接触最多的就是N_Bs和N_Cr。N_Bs是发送方发出FF或CF后等待接收方回复FC的最大时间N_Cr是接收方等待下一个CF的超时时间。不同的OEM规范里具体数值不一样常见的是1000ms到1500ms。如果在N_Bs时间内没收到FC发送方会认为接收方“掉线”了终止这次传输并向上层报超时错误。流控帧丢失的原因通常有两个一是CAN总线错误电平导致整帧被重发或丢弃这种在总线负载高、终端电阻匹配不当时容易发生二是接收方的协议栈把FC帧错误地过滤掉了比如CAN ID过滤器只放行了某个范围的ID恰恰把FC对应的ID给滤掉了。我排查过一个案子诊断仪发出的所有多帧请求都超时ECU那边看总线明明发了FC但诊断仪就是收不到。后来发现诊断仪自身的接收过滤器把0x7E8这个ID给过滤了而ECU的响应ID恰好是0x7E8。ID配置问题跟协议栈一点关系都没有。排查这类问题我建议先在总线上挂一个独立的CAN记录仪不看诊断仪内部日志直接看总线报文。如果总线上确实有FC而诊断仪收不到问题一定在诊断仪内部过滤规则或接收缓存代码如果总线上根本没有FC那就要往ECU侧查看看ECU是不是收到了FF以及它的N_Bs计时起点是什么时候。5.3 FF_DL与实际数据长度不一致FF_DL是接收方判断“这条多帧传输该收多少数据”的唯一依据。如果发送方在首帧里写的FF_DL是43但后续CF加到一起凑不够43字节接收方会一直等等到N_Cr超时后报错如果实际发出来的数据超过43字节接收方拼接完43字节后会把多余的CF当成异常帧丢弃有时也会报“长度溢出”。这个错误更多出现在自己拼报文的调试工具里。比如先用脚本生成长度为50的数据但FF_DL写死了0x2B43结果CF一多接收方拼到43字节就停了。另一个常见原因是有些协议栈在发送时会把PCI字节也算进长度里导致FF_DL比实际多了2字节或更多。ISO-TP标准里FF_DL是指“传输层净荷长度”也就是去掉PCI之后的数据总长不包括UDS之外的东西。写代码的时候一定要用最终组成UDS报文的那个缓冲区长度去算FF_DL别拿中间缓冲区的长度去算。还有一个经验值ECU回复的多帧响应里如果FF_DL小于实际发送的数据长度有些严格实现的诊断仪会把多余CF全部丢掉导致响应看起来“只收到了一半”。这种问题在逆向解析别人ECU报文时容易遇到建议先用CAN工具把整段报文完整记录下来再逐帧核对FF_DL和CF数量而不是直接依赖诊断仪的解析结果。5.4 多帧传输和网络管理报文的“抢总线”问题最后说一个不少人忽略的坑多帧传输不是独占总线的。CAN总线是广播式异步总线诊断报文和网络管理报文、应用报文共用同一条物理链路。当ECU正在连续发送CF的时候如果总线上一堆高优先级的网络管理报文在跑CF的发送时机可能被不断推迟导致实际CF间隔远大于STmin甚至触发接收方的N_Cr超时。我记得有一次做整车的刷写测试诊断仪发完FC之后ECU迟迟不发下一个CF每次都卡在N_Cr边缘。后来用总线记录仪一看原来是整车某个控制器在不停地发周期报文把总线占掉了一大半带宽。ECU的CAN发送邮箱被这些周期报文挤占诊断CF只能排队。最后我们把刷写期间的网络管理报文停掉问题立刻消失。所以在做Bootloader刷写之前先确认总线负载情况该停的报文及时停掉别等超时了才想起来查总线负载。写在最后的几点个人体会多帧传输这块道理不复杂难的是把每一步的字节和时序都弄扎实。我习惯在调试前先手写一遍预计的报文流程把FF_DL、SN、STmin都算好再上总线去看实际报文哪里对不上哪里就是问题点。这个方法虽然土但排查效率很高比对着工具日志瞎猜要快得多。另外一个小技巧遇到“看起来快但总报错”的传输先把STmin加大到10ms以上试一次如果错误消失基本可以断定是接收方处理不及时。这时候先去查接收方的接收任务有没有被高优先级任务抢占而不是急着优化STmin。时序调优永远是最后一步前面的协议逻辑、缓冲区管理、任务调度都没问题再谈速度才有意义。
返回列表