
做工业控制的同行早晚会碰上CAN总线。不管是PLC之间的数据交换、伺服驱动器的控制、AGV小车的调度还是传感器采集网络的搭建CAN总线几乎无处不在。网络上那篇《工业控制网络之CAN总线详解》把这条总线的框架讲得很系统但我在项目里反复用下来发现真正让工程师头疼的往往不是协议本身而是现场那些“看手册没问题、一跑就翻车”的细节。这篇文章就把CAN总线从原理到实战拆开揉碎聊聊协议设计的特点、工程配置的要点、接收方式怎么选、负载率怎么算、现场排查怎么做希望能给正在上手CAN的你一点实际帮助。1. 别把CAN总线当成“高级串口”——先搞清楚它在工业控制网络里的定位1.1 工业控制网络为什么需要CAN从点对点到多主网络早年做工业控制最常用的现场通信方式就是RS485。RS485本身价格便宜、抗干扰能力也不错但在一个稍微复杂的控制系统中它的主从轮询模式很快就会变成瓶颈。假设一个系统里有20个设备主机要依次查询每个设备的状态一轮查询下来可能就要几十毫秒甚至更久。这还没算上设备响应超时、重发、线路故障等特殊情况。如果系统里还有几个实时性要求高的轴控制或安全联锁信号RS485这种轮询机制就很难满足要求。CAN总线诞生的初衷正是为了解决这类问题。它不是“某个主机说了算”的从站结构而是一个真正的多主总线。每一个节点只要有发送需求都可以主动往总线上发报文节点之间通过报文ID进行仲裁谁优先谁后发由协议自动完成。这相当于把原本集中式、主从式的通信方式改造成了一种分布式、事件驱动的通信模型。在工业控制网络里这种模型的价值非常直接设备状态变化可以立刻上报不需要等主机来问控制指令也能在毫秒级内到达执行机构新节点接入时只要配置好ID和过滤规则整个系统的改动成本也低得多。要理解CAN在工业控制网络中的位置可以把通信架构想象成小区的快递投放。RS485像是需要收件人主动去物业查有没有快递所有通知都靠物业安排而CAN则是每个快递员都能随时过来投递包裹上贴好了优先级标签如果两个人同时到达邮编号码小ID小的先投放。对于工厂这种追求响应速度的场景CAN这套逻辑显然顺手得多。1.2 CAN总线的三层选型逻辑成本、实时性与可靠性当然多主只是CAN的一个特点真正让它在工业控制网络里站住脚的是成本、实时性和可靠性三者的平衡。我画过一条对比线在很多工程师心里大概是这样的RS485便宜但实时性差维护成本高以太网性能强但交换机、网线、协议栈成本都不低而且确定性网络比如TSN还没完全普及CAN则刚好卡在中间两根双绞线加总线收发器就能搭起一整套通信网络带宽虽然不高但对大多数控制器和传感器节点来说完全够用而且实时性和可靠性明显优于RS485。很多人对CAN的带宽有误解总觉得500kbps太慢。但实际工程项目里大多数传感器节点每次发送的报文只有几个字节500kbps波特率下一个8字节报文加开销也才100多位算下来一毫秒大约能发四个报文。对于一个轴控制周期1ms的系统这个吞吐能力是足够的。真正影响选型的不是“快不快”而是“能否在确定时间内完成通信”。CAN的CSMA/CA加优先级仲裁机制保证了高优先级报文在总线繁忙时也能在有限时间内被发送出去这种确定性恰恰是工业控制网络最看重的指标。从可靠性角度看CAN的物理层和链路层也做了大量冗余设计。差分信号双线传输抗共模干扰能力强CRC校验覆盖整个报文五位连续相同电平强制插入填充位还有完善的错误检测和错误计数机制。这套机制在汽车、工业现场、医疗设备等强电磁干扰环境中经过了几十年的验证成熟度非常高。所以我个人的选型建议是如果你做的是点位分散、报文短、实时性要求高的工业控制网络CAN几乎是不需要犹豫的方案。1.3 学习CAN总线的两条主线协议理解和工程落地学习CAN总线很容易走偏。我见过不少同事一上来就抱着协议规范啃把数据帧、远程帧、错误帧、过载帧背得滚瓜烂熟结果真到现场一接设备波形乱跳、错误帧狂刷依然一头雾水。反过来也有一些人只会在配置工具里点鼠标出了问题就发截图问别人从不看协议内容这样的人遇到系统性的总线问题同样无能为力。正确的路径应该是两条腿走路协议理解是内功工程落地是招式。协议层面至少要掌握物理层电平定义、帧结构、仲裁机制、错误检测和位时序同步这些硬核内容工程层面则需要会用CAN分析仪抓波形、会配置收发器和控制器寄存器、会计算负载率和采样点、会通过错误帧特征反推故障原因。这篇文章的结构就是按这两条主线来的前面几章讲协议原理后面几章讲实战配置和排查技巧建议读者先建立整体框架再针对自己项目里遇到的问题按图索骥。2. CAN总线的工作原理从电平到帧结构一次讲透2.1 物理层核心差分信号与显性/隐性电平CAN总线的物理层用的是差分信号也就是两根线CAN_H和CAN_L配合传递信息。总线上只有两种逻辑状态显性Dominant和隐性Recessive。显性对应逻辑0隐性对应逻辑1。发送节点在发隐性位时会把CAN_H和CAN_L都拉到某个电平附近在发显性位时CAN_H被拉高、CAN_L被拉低形成一个差分电压。收端通过比较两线之间的压差来判断当前是显性还是隐性因此对单根线上的共模干扰有很强的抑制能力。这个机制解释了很多现场问题的根源。比如CAN_H和CAN_L之间要接120Ω终端电阻就是因为差分线在高速翻转时如果末端阻抗不匹配会产生信号反射导致总线电平畸变进而出现位错误或CRC错误。两个终端电阻一个在总线一端、一个在另一端正好让信号在传输线末端被吸收而不是反弹。有人图省事只在分析仪上接了一个电阻节点之间又没加短距离测试也许没事但线一长、节点一多立刻就会出问题。还有一个容易忽略的细节总线空闲时所有节点都处于隐性电平这时候总线上是没有驱动电流的。所以CAN收发器普遍需要满足“隐性电平偏置”的要求如果节点断电或收发器损坏不能影响其他节点正常收发。实际工程中我发现一些劣质收发器在节点掉电后会把总线拉偏导致整条总线通信异常排查起来特别隐蔽。2.2 报文格式与无损仲裁机制CAN的报文格式通俗讲就是一帧一帧的数据包。最常用的数据帧结构大致包括帧起始SOF、仲裁场、控制场、数据场、CRC场、ACK场和帧结束EOF。其中仲裁场里最关键的是报文ID标准帧ID是11位扩展帧ID是29位。报文ID不但是报文的“名字”还决定了总线上多个节点同时发送时的优先级ID数值越小优先级越高。仲裁过程是CAN最巧妙的地方。两个节点同时发送时它们会逐位比较ID。CAN总线电气特性里显性电平可以覆盖隐性电平所以当某个节点发出隐性位而另一个节点发出显性位时总线上的电平是显性。发出隐性位的节点会检测到总线状态与自己发送的不一致于是立刻退出仲裁等待下个周期再发发出显性位的节点则继续发送整个仲裁过程不打断数据也不浪费时间这就是所谓的“无损仲裁”。这带来一个工程思维上的转变CAN网络里的帧优先级不是靠配置仲裁器而是靠报文ID设计。ID越小的报文比如急停、连锁信号必须留给最高优先级周期性采集数据、参数设置等则可以放在中低优先级段。我见过一个项目组态工程师把所有节点的报文ID都设成了0x100附近导致一个点击发时另一个点的延迟飙升后来重新规划ID段才解决。ID分段这件事一定要在系统设计阶段就做好规划别看它简单后面改起来非常痛苦。2.3 位时序与同步波特率、采样点到底怎么定CAN总线上每个节点都有自己的时钟源虽然晶振精度通常都在几十ppm以内但对通信协议来说接收方必须在正确的时刻采样总线电平才能准确还原每一位。为此CAN把每一位时间划分成四段同步段、传播段、相位缓冲段1和相位缓冲段2。同步段用于检测总线的跳变沿传播段用于补偿传输延迟两个相位缓冲段用来微调采样点位置并配合重同步机制修正时钟偏差。采样点在位时间里的相对位置是工程配置里异常重要的参数。采样点太早信号还没稳定容易采到毛刺采样点太晚留给相位缓冲段2的余量不足重同步能力变差。绝大多数资料推荐采样点在75%~90%之间很多控制器默认在80%左右。我习惯按波特率、总线长度和收发器延迟算一下再设500kbps及以上的高速CAN采样点建议往85%靠125kbps及以下可以放宽到70%~80%。波特率的选择还与总线长度密切相关。CAN标准里给出了典型数据1Mbps时最大总线长度约40米500kbps时约100米250kbps时约200米125kbps时约500米。当然这只是理论值实际还受线缆质量、收发器驱动能力、节点数量和拓扑结构影响。我做的项目里有一条装配线总线长度接近120米用的250kbps测试时发现波形边沿明显变缓把采样点改成80%之后才稳定下来。如果现场距离比较长最好用示波器确认一下总线波形别只看速率表定参数。3. 报文类型、错误帧与总线故障处理3.1 标准帧与扩展帧、数据帧与远程帧的区别CAN协议里一共有四种帧数据帧、远程帧、错误帧、过载帧。数据帧用来承载数据远程帧用来请求对方发送数据错误帧在节点检测到错误时自动发送过载帧用于请求延迟下一条数据帧。帧格式上标准帧使用11位ID扩展帧使用29位ID扩展帧发送时在仲裁场里多出一段扩展ID两者不能混用否则会出现仲裁判断错误。实际工程项目里远程帧用得很少。原因很简单远程帧没有数据场发送方收到远程帧后还需再回一个数据帧这增加了一次总线交互对多数控制系统来说没有性能优势。更常见的做法是直接用数据帧周期上报或事件上报把“请求”改成“订阅”这样既省总线时间也避免远程帧在某些控制器实现里的兼容性坑。标准帧和扩展帧的选择则要根据应用需求来定。如果系统节点少ID规划简单标准帧足够了11位ID可以定义两千多个不同报文对于控制网络来说绰绰有余。如果系统庞大、需要分组和路由扩展帧的29位ID会更灵活。需要注意同一总线上最好不要混用标准帧和扩展帧尤其当ID段设计重叠时容易导致仲裁结果不符合预期。3.2 错误帧为什么重要错误检测与错误计数错误帧在CAN协议里是一等公民。每个节点都在实时监视总线一旦发现异常就会立刻发送错误帧通知其他节点这个报文有问题并请求重传。CAN的检错机制一共有五种位错误、填充错误、CRC错误、形式错误、应答错误。位错误是发送节点发送电平时监视总线发现与自己发送不一致填充错误是因为CAN规定连续五个相同电平后必须插一个反相填充位收端如果发现填充位不合法就报错CRC错误是收端计算CRC与发送端CRC不一致形式错误是帧格式里固定值位比如EOF、界定符不符合规范应答错误是发送节点在ACK场没收到接收节点的有效应答。为了控制故障节点对总线的破坏CAN协议设计了两套错误计数器发送错误计数器TEC和接收错误计数器REC统称为错误计数。节点每检测到一个错误计数器会加一定数值成功发送或接收一个报文计数器会减1。当任一计数器超过127节点进入“被动错误”状态只能被动接收不能主动发送错误标志当TEC超过255节点进入“总线关闭”状态彻底脱离总线不再参与通信。这套机制非常关键一个坏节点不至于无限发错误帧把整条总线拖死它会被逐步“隔离”出去。工程上错误帧的频率和特征是最好的诊断入口。如果总线上错误帧偶尔出现一两次可能只是干扰如果周期性出现很可能有节点发送时序异常或采样点不合理如果错误帧数量持续上涨尤其是夹杂“总线关闭”事件那基本可以断定有节点硬件或软件存在问题。我处理过一起现场故障一个执行器节点一上电总线错误帧就开始刷屏其他节点全部通信超时。后来用分析仪连续抓包发现这个节点在接收到一个特定ID的报文后会立刻报填充错误最后定位到这个节点的收发器芯片周围一颗电阻虚焊导致总线电平漂移触发误判。3.3 总线故障排查用错误帧定位问题的实战思路排查CAN总线问题我总结了一套比较实用的流程先判断问题范围再分位置对照最后用波形和错误类型定位。第一步用CAN分析仪挂到总线上统计错误帧类型和错误帧频率。如果错误帧非常多先把总线上的节点逐个断电观察错误帧是否消失这一步能快速缩小范围。第二步用示波器或差分探头量总线波形重点看显性电平幅度、隐性电平偏置、边沿时间、通道间是否有明显压差。第三步对照错误类型判断方向CRC错误多通常与阻抗不匹配、线缆过长或采样点偏早有关填充错误或形式错误多往往指向波特率不一致或收发器质量问题位错误多则要检查总线抢占和节点ID冲突。排查过程中还有两个容易被忽略的坑一是地电位不一致CAN虽然采用差分传输但收发器本身需要共模范围如果两个节点之间地电位差过大比如相隔很远的设备各自接地会导致收发器超出共模输入范围出现大量错误帧。解决办法是检查现场接地必要时用隔离收发器或CAN隔离模块。二是终端电阻的位置很多人只在CAN分析仪上接了一个120Ω电阻但总线两端各需要一个如果总线两端没有正确接终端电阻信号反射会引发随机错误。4. CAN总线接收方式怎么选中断接收还是DMA接收4.1 两种接收方式的原理与差异在单片机或嵌入式系统里CAN控制器收到报文后CPU怎么把它读出来直接关系到系统的实时性和CPU占用。最常见的两种方式就是中断接收和DMA接收。中断接收的思路是CAN控制器收到一个报文并存入接收FIFO后触发接收中断CPU进入中断服务函数从FIFO中读出报文再根据报文ID进行分类处理。这种方式响应及时报文什么时候到CPU几乎实时就能知道。DMA接收则略有不同CAN控制器收到报文后不直接打断CPU而是由DMA控制器按照配置好的内存地址把报文从FIFO搬到RAM缓冲区等DMA传送完成后再触发一次DMA完成中断CPU这时才来处理缓冲区里的数据。听起来DMA好像更“高级”因为它可以让CPU少跑很多次FIFO读取操作。但CAN报文的特殊性在于它的每个报文都很短标准帧加数据最多也才十几字节DMA的优势主要体现在大批量数据传输上。如果总线上每秒有几千个报文用DMA确实能明显降低CPU占用但每秒几十到几百个报文的情况下中断接收的开销其实完全可以接受而DMA在配置、管理和错误处理上的复杂度反而可能带来更多问题。4.2 选型依据实时性、CPU负载、丢帧风险选中断还是DMA不能拍脑袋主要考虑三个指标实时性、CPU负载和丢帧风险。实时性方面中断接收天然占优因为报文到达瞬间CPU就被打断去读取而DMA方案要等DMA搬完才通知CPU会有一段延迟。对于位置同步、急停保护这类实时性要求极高的应用我倾向用中断接收并且在中断里只做“搬运置标志位”不做复杂业务逻辑确保响应时间可控。CPU负载方面如果系统里还有其他高频率任务比如控制环路、显示刷新、通信栈而且CAN报文量很大那么DMA可以把CPU从频繁的FIFO轮询和读取中解放出来。我做过一个多轴运动控制项目单条CAN总线上每秒报文量接近8000帧用普通中断接收时CPU占用比较高后来换成DMA接收CPU占用率大概降了十几个百分点。如果报文量远没到这个量级那么DMA带来的收益很小没必要为了“用DMA”而增加复杂度。丢帧风险方面两者都有各自的坑。中断接收的常见问题是中断嵌套和响应不及时如果系统里还有一个更高优先级的中断长时间占用CPUCAN接收中断被挂起FIFO满了之后来不及读新报文就会溢出丢帧。DMA接收的问题则在于如果缓冲区处理速度跟不上DMA搬运速率或者频繁触发完成中断时CPU还没处理完上一批数据同样会丢数据而且丢数据后的定位和恢复往往比中断模式更麻烦。还要注意不同MCU厂家的CAN控制器和DMA通道集成度差异有些芯片的DMA触发源、FIFO水位配置方式完全不同不能把一套代码直接搬到另一家芯片上。4.3 工程实践中的推荐配置根据我做过的大小项目个人建议按以下优先级来选如果总线报文中只有少量告警和控制指令通信量不大直接用中断接收加FIFO过滤把接收中断优先级设置好数据处理放到主循环或低优先级任务里。如果通信量中等比如每秒几百帧还是优先用中断接收但在接收中断里做严格的临界区保护防止处理线程和中断互相干扰。只有通信量很大、CPU占用又受到严格限制时才考虑DMA接收并且要做好缓冲区管理和丢帧检测。无论哪种方式有几点必须做到第一CAN控制器的硬件过滤器要充分利用让不关心的报文直接不进入FIFO这是降低CPU负担最有效的手段第二要开错误中断和总线关闭中断实时监测节点状态万一总线错误计数超过阈值至少要让系统知道第三接收标志位和缓冲区要设计成环形结构配合一个“读位置”和“写位置”处理速度慢时至少能看出丢过多少数据。我在一个产品中就是这么做的现场曾出现过一次CAN控制器进入bus-off的情况正是依靠错误中断报警才在第一时间发现并处理了故障节点。5. 负载率计算与网络容量规划5.1 负载率的定义与计算公式总线负载率是衡量CAN总线占用情况的核心指标定义为实际传输的比特数占总线理论最大传输能力的比例通常用百分比表示。计算方式并不复杂核心是先把每一类报文的“总位长”算清楚再乘以该报文的发送频率最后除以波特率。报文总位长要覆盖整个帧在总线上占用的所有位包含帧起始、仲裁场、控制场、数据场、CRC场、ACK场、帧结束和帧间隔。标准数据帧中如果不考虑位填充一个8字节数据帧大概占111位1位SOF 12位仲裁场 6位控制场 64位数据 16位CRC场 2位ACK 7位EOF 3位帧间隔。但这里有个坑CAN协议规定仲裁场和数据场之间如果出现连续五个相同位就必须插入一个反相填充位这意味着实际占用位数会比理论值多出一些。具体多多少和报文内容相关所以工程估算时一般会在理论帧长基础上加10%~15%的余量。很多设备厂商文档里直接给出一个8字节标准帧约128位就是考虑了这个因素。5.2 一个可复现的负载率计算示例假设一个控制系统使用500kbps波特率某节点以10ms周期向上位机发送一帧8字节状态报文。理论帧长111位加15%余量后约128位。每秒钟发送100帧那么每秒占用总线12800位。500kbps等于每毫秒500位每秒钟有500000位。负载率就等于12800除以500000约2.56%。这个值看起来很低但如果系统里这样的节点有20个每个都以10ms周期发8字节报文总线负载率就会到50%左右。再加上一些随机事件上报、心跳报文和错误重传负载率超过60%是很容易的事。再举一个极端的例子如果设计时没做规划每个节点都按2ms周期发报文导致总线上每秒有5000帧报文500kbps下负载率会超过100%总线必然瘫痪。所以设计CAN网络一定要按最坏情况估算负载而不是按平均报文流量。比如报警集中时刻、启动瞬间的初始化报文风暴、节点异常时的反复重传这些都要预留带宽。5.3 负载率对实时性和可靠性的影响负载率不仅影响吞吐量更直接影响实时性。在CAN总线上高优先级报文通过仲裁可以先发总线上负载率升高时低优先级报文的等待时间会显著变长。可以这样理解网络空闲时低优先级报文可能几毫秒内就能发出去负载率超过60%后低优先级报文可能被高优先级报文一次次“插队”最坏情况下等待时间远超应用可接受的阈值。这就是为什么很多工业通信协议如CANopen会对PDO过程数据对象的发送周期和ID优先级做严格要求。从可靠性角度看负载率过高还会形成恶性循环。负载率接近100%时任何节点发送失败后进入重传新报文又继续产生总线几乎一直被占用错误帧没有机会插入节点错误计数器却在不断累加最终导致多个节点进入bus-off状态。我在一个焊装线的调试中遇到过类似情况开始时负载率大概70%测试阶段一直正常后来多了几个摄像头诊断报文之后总线开始偶发超时越到后面越严重直到多个节点自动退出总线。后来把诊断报文改成只在维护模式下发送运行时通过网关转发问题就消失了。所以负载率建议控制在30%以下运行峰值不要超过50%一旦接近60%就该优化报文策略了。6. CAN总线测试的场景、工具与实测记录6.1 常用测试工具与最小测试环境搭建CAN总线调试离不开工具。最低配的是带CAN外设的开发板配合串口打印能验证基本收发往上走是各种USB-CAN分析仪市面上几百到几千元的都有功能差异主要在抓包性能、错误标记、波形分析能力上再专业一点可以用示波器加差分探头直接看总线物理层波形定位电平畸变、反射和干扰问题。我测试时通常至少搭一套这样的最小环境两个CAN节点可以是开发板或实际设备一条双绞线或线缆模拟实际走线总线两端各接一个120Ω终端电阻再加上一个USB-CAN分析仪并联到总线上用作监视和抓包。所有节点的波特率、采样点必须统一这一步看似简单却是很多现场问题的根源。测试前先用分析仪发一个标准报文看能否在两个节点之间正常通信然后再逐步增加节点和报文量。6.2 典型测试场景回环测试、多节点压力测试、抗干扰测试在验证CAN系统稳定性时我会分三步做测试。第一步是回环测试把单个节点的CAN控制器设成回环模式Loopback Mode不经过总线收发器直接验证控制器内部收发通路。这种测试主要是确认软件驱动、FIFO、中断处理这一层没有逻辑错误。第二步是正常模式的双节点通信测试确认两点之间能按预定波特率收发然后逐步增加报文长度、降低发送间隔观察是否有丢帧和错误帧。第三步是多节点压力测试把若干个节点挂到总线上每个节点按设计指标的最高频率发送报文持续运行几小时甚至一整夜看总线负载、错误计数和节点任务超时情况。抗干扰测试更不能少。工业现场电磁环境复杂变频器启停、继电器吸合、大电机运转都会产生干扰。我的做法是在测试环境中放置一台变频器或接触器在设备启停瞬间让CAN总线持续通信观察是否出现错误帧。如果条件有限至少也要在总线靠近动力线缆的走线布局下做一轮测试。有个项目在现场调试时发现只要某台伺服驱动器一上电CAN总线上就出现周期性CRC错误后来把CAN线缆和伺服电机动力线分开走线并加装共模磁环错误帧才降为零。这类问题模拟环境里不容易复现更考验现场调试的耐心。6.3 现场测试中的常见问题与排查技巧现场测试中踩过的坑比协议手册里写的多得多。第一个常见问题是终端电阻接法不标准。有的设备内部已经焊了终端电阻外接分析仪又加了一个两个电阻并联后等效阻抗变成60Ω导致信号波形畸变。正确做法是先用万用表量一下总线两端的直流电阻总线空闲时两个设备之间的终端电阻并联值应该约60Ω如果量出来是120Ω说明有一端没接如果是低于60Ω说明有设备内部已经接了电阻需要避开重复接。第二个常见问题是波特率看似一致实际配置有出入。很多控制器支持自动波特率检测但检测结果不一定可靠。排查时可以用分析仪抓总线上设备发出的报文手动解析位宽度判断实际波特率是多少。第三个常见问题是采样点设置不一致尤其在同一总线混用不同厂商的设备时。有的设备默认采样点在75%另一个在87.5%短距离通信可能正常距离一长或温度一变就偶发错误。我建议在项目配置阶段就把所有设备型号和采样点参数登记在册统一规划。第四个容易被忽视的问题是地环路。当多个节点分别接地且接地点电位存在差异时会导致CAN收发器共模电压异常表现为通信时好时坏。处理方法是合理规划接地方式要么采用单点接地要么在节点间使用隔离收发器。还有一种更隐蔽的情况便携式CAN分析仪通过USB连到电脑电脑电源适配器与现场设备地电位不一致插上分析仪瞬间就导致大量错误帧。针对这个问题我习惯在需要接电脑调试时使用带隔离的USB-CAN工具并且把电脑的电源适配器拔掉、只用电池供电试试。最后再分享一个基于经验的小技巧排查CAN总线问题时手头常备一个小型手持万用表和无源逻辑分析仪。先用万用表量CAN_H和CAN_L的对地电压再量两者之间的差分电压基本能判断总线电平状态是否正常。比如总线空闲时CAN_H和CAN_L对地电压应该都在2.5V附近两者之间压差几乎为0如果有节点主动发送差分电压会到2V左右。这些电压值看起来简单但很多总线故障在波形图上复杂难辨按电压快速排查很可能省下大量时间。CAN总线这东西做得越深入越会发现协议知识只是起点真正有价值的是能把物理信号和协议行为对应起来在关键时刻快速定位问题。希望这篇文章能帮你减少一些弯路上的摸索。