1. 项目概述从寄存器手册到实战配置如果你在汽车电子或者工业控制领域搞过嵌入式开发那对CAN总线肯定不陌生。它就像设备之间的“神经系统”负责在各种嘈杂的电磁环境下稳定、可靠地传递控制指令和状态数据。但说实话光看芯片厂商提供的几百页参考手册尤其是里面密密麻麻的寄存器描述很容易让人头大。手册会告诉你每个位是干什么的但很少告诉你在实际项目中这些位到底该怎么组合为什么要这么配以及配错了会出什么幺蛾子。我最近在调一个基于Freescale现在是NXPS12系列MCU的项目核心就是用好它的S12MSCANV3控制器。手册里关于中断和寄存器配置的部分像CANRIER、CANTIER、CANRFLG这些读起来就像字典——准确但不够“友好”。这篇内容我就想结合自己踩过的坑和项目经验把这些寄存器“翻译”成能直接上手的配置逻辑。我们不止看每个位Bit的定义更要串起来理解一个CAN节点从初始化、收发数据到处理异常这些寄存器是如何联动工作的。目标很简单让你看完后能胸有成竹地配置出一个稳定、高效的CAN通信节点特别是中断驱动的应用。2. S12MSCANV3中断系统架构解析S12MSCANV3的中断设计得很清晰遵循了“标志位Flag” “使能位Enable”的经典模式。理解这个模式是灵活运用中断而非被中断牵着鼻子走的关键。2.1 中断产生的双要素标志与使能几乎所有微控制器的中断逻辑都类似需要两个条件同时满足才能跳转到中断服务程序ISR事件发生硬件置位标志位Flag这是由控制器内部状态机自动完成的。比如收到一帧新数据RXFReceive Buffer Full标志位会被硬件自动置1一个发送缓冲区变空对应的TXEx标志位会被置1。软件使能对应的中断使能位Interrupt Enable这是由开发者通过配置寄存器决定的。比如你想在收到数据时立刻得到通知就需要把RXFIERXF Interrupt Enable位置1。如果只置位了标志位而没有使能中断那么控制器只会“默默记下”这个事件通过标志位不会去打断CPU。在S12MSCANV3中标志位主要分布在CAN接收标志寄存器CANRFLG和CAN发送标志寄存器CANTFLG。而使能位则对应地分布在CAN接收中断使能寄存器CANRIER和CAN发送中断使能寄存器CANTIER。这种分离的设计带来了极大的灵活性。例如在系统初始化阶段你可能不想处理任何CAN中断那么就把所有使能位清零。你可以轮询Polling检查CANRFLG和CANTFLG寄存器来处理事务。当系统进入稳定运行需要实时响应时再打开相应的中断使能位切换到中断驱动模式。这种“标志位始终反映状态中断使能控制是否通知”的机制是高效事件处理的基础。2.2 核心中断源及其应用场景S12MSCANV3将中断源大致分为三类对应不同的应用需求接收中断核心是RXF标志。当一帧消息通过验收滤波被成功移入接收FIFO的前台缓冲区RxFG时此标志置位。使能RXFIE后会触发接收中断。这是数据消费型应用最常用的中断。例如电机控制器需要实时接收转速指令一旦指令到达必须立即处理不能等待轮询。发送中断核心是TXE0、TXE1、TXE2标志。这三个标志对应三个发送缓冲区。当某个缓冲区中的消息被成功发送到总线上或者发送请求被成功中止时对应的TXEx标志置位。使能TXEIE后会触发发送中断。这是数据生产型应用的关键。例如一个传感器节点需要周期上报数据。当它把一帧数据写入发送缓冲区并启动发送后就可以去做其他事情。等发送完成中断到来它就知道这个缓冲区已经空闲可以准备下一帧数据了实现了发送流程的流水线化。错误与状态变化中断这是一组更复杂但至关重要的中断由CANRIER中的多个位控制。过载中断OVRIE当接收FIFO已满但又有新消息到来时会发生数据溢出OVRIF标志置位。使能OVRIE后触发错误中断。这通常意味着数据消费速度跟不上生产速度是系统设计或中断优先级需要优化的信号。CAN状态变化中断CSCIE这是总线错误管理的核心。它本身是一个总使能。具体哪些状态变化能触发中断则由RSTATE[1:0]接收状态变化使能和TSTATE[1:0]发送状态变化使能这两个字段来精细控制。2.3 状态变化中断的精细控制RSTATE与TSTATERSTATE和TSTATE这两个字段的设计非常精妙它允许你根据错误的严重程度分层级地接收通知而不是任何风吹草动都进中断。CAN控制器内部有两个错误计数器接收错误计数器CANRXERR和发送错误计数器CANTXERR。根据计数值控制器和总线会处于不同状态RxOK / TxOK错误计数器小于128一切正常。RxErr / TxErr错误主动状态错误计数器在128-255之间。控制器能正常收发但会主动发送“主动错误帧”来告知总线错误。Bus-Off总线关闭状态发送错误计数器超过255。控制器会从总线上断开停止任何发送直到满足恢复条件。这是最严重的故障状态。RSTATE[1:0]和TSTATE[1:0]的4种编码决定了状态变化触发CSCIF中断的“灵敏度”00不因接收器/发送器状态变化产生任何CSCIF中断。完全关闭状态变化通知01仅当进入或离开“Bus-Off”状态时产生中断。只关心最严重的故障适用于那些只需要知道“通信是否彻底中断”的应用。10当进入或离开“RxErr/TxErr”或“Bus-Off”状态时产生中断。关心错误主动和总线关闭这是最常用的设置。当错误计数器超过128进入Error Active你就该收到警报开始检查线路质量或节点逻辑了而不是等到彻底Bus-Off。11任何状态变化都产生中断。最高灵敏度可能过于频繁适用于深度调试或需要监控每一个状态跳变的场景。实操心得在大部分汽车车身控制或工业IO模块中我通常将RSTATE和TSTATE配置为10。这样当节点因持续干扰进入Error Active状态时我就能在中断里记录错误日志或点亮预警灯给维护人员一个早期预警而不是等到通信完全瘫痪Bus-Off才被发现。Bus-Off恢复通常需要复杂的上下电或软件复位流程应尽量避免。3. 关键寄存器详解与配置策略理解了架构我们再来深入看看几个最关键的寄存器以及如何配置它们。3.1 接收中断使能寄存器CANRIER这个寄存器是接收相关中断的“总开关面板”。地址偏移为0x0005。位名称描述复位值配置建议7WUPIE唤醒中断使能。需与CANCTL0中的WUPE位同时使能才有效。0仅在节点需要进入低功耗睡眠模式并由CAN总线唤醒时才置1。常规应用置0。6CSCIECAN状态变化中断使能。总开关。0通常置1。只有打开它下面RSTATE/TSTATE的配置才有意义。5-4RSTATE[1:0]接收器状态变化中断灵敏度控制。00根据2.3节的描述选择。推荐10监测Error Active和Bus-Off。3-2TSTATE[1:0]发送器状态变化中断灵敏度控制。00同RSTATE推荐10。1OVRIE接收过载中断使能。0建议置1。数据溢出是严重问题需要及时处理。0RXFIE接收缓冲区满中断使能。0根据应用需求。若需实时处理数据置1若采用轮询置0。初始化模式INITRQ1 INITAK1下此寄存器被复位且不可写。这意味着你必须在退出初始化模式、进入正常模式前完成对它的配置。一个典型的配置代码片段假设使用C语言和寄存器映射头文件可能如下// 假设 CAN0_RIER 是映射到地址的寄存器指针 // 1. 首先确保进入初始化模式 (设置CANCTL0的INITRQ位等待INITAK置位) // 2. 配置波特率、验收滤波器等... // 3. 配置中断使能寄存器仍在初始化模式下但CANRIER在初始化模式下被复位需在退出前配置 // 注意手册指出CANRIER在初始化模式下被复位且不可写。因此配置应在退出初始化模式前一刻进行。 // 更常见的流程是在初始化模式下配置其他参数退出初始化模式后立即配置中断。 // 退出初始化模式清除INITRQ // 等待INITAK变为0... // 现在配置CANRIER CAN0_RIER 0x00; // 先全部清零 CAN0_RIER | (1 6); // 使能 CSCIE CAN0_RIER | (0b10 4); // 设置 RSTATE[1:0] 10 CAN0_RIER | (0b10 2); // 设置 TSTATE[1:0] 10 CAN0_RIER | (1 1); // 使能 OVRIE CAN0_RIER | (1 0); // 使能 RXFIE // WUPIE 保持为0不使能唤醒中断3.2 发送中断使能寄存器CANTIER这个寄存器控制三个发送缓冲区TXE0, TXE1, TXE2的空闲中断。地址偏移为0x0007。它非常简单只有低3位有效。位名称描述复位值配置建议2TXEIE2发送缓冲区2空中断使能0如果使用缓冲区2进行发送并希望发送完成时得到通知则置1。1TXEIE1发送缓冲区1空中断使能0同上。0TXEIE0发送缓冲区0空中断使能0同上。配置策略你是否使能某个TXEIE完全取决于你的发送策略。轮询发送将所有TXEIE置0。发送前循环检查CANTFLG寄存器找到TXEx1空闲的缓冲区填入数据然后清除该TXEx标志写1来启动发送。发送完成后需要再次轮询检查该标志是否变回1。中断发送将使用的缓冲区的TXEIE置1。发送流程变为检查CANTFLG找到一个空闲缓冲区TXEx1。通过CANTBSEL选中该缓冲区。填写标识符、数据长度码DLC、数据到CANTXFG区域。清除CANTFLG中对应的TXEx位写1启动发送。此时该位变为0。CPU可以处理其他任务。当消息成功发送到总线后硬件会自动将TXEx位置1。由于TXEIE已使能会触发发送中断。在发送中断服务程序ISR中你可以知道哪个缓冲区已空闲准备下一帧数据。注意事项CANTIER同样在初始化模式下被复位且不可写。配置时机同CANRIER。3.3 发送缓冲区选择寄存器CANTBSEL的妙用CANTBSEL地址偏移0x000A是一个硬件辅助的缓冲区选择器它能极大简化“查找下一个空闲发送缓冲区”的操作。工作原理你读取CANTFLG寄存器。假设TXE01,TXE10,TXE21即缓冲区0和2空闲则读到的值为0b00000101二进制仅低3位有效。你将这个值写入CANTBSEL寄存器。硬件会自动选择最低编号的、值为1的位所对应的缓冲区。在这个例子中最低编号的1是TXE0位0因此硬件会选择缓冲区0并将其映射到CANTXFG的寄存器空间。当你再读取CANTBSEL时返回值会是0b00000001明确告诉你当前选中了缓冲区0。手册给的汇编例子非常直观LDAA CANTFLG ; 读CANTFLG假设值0b00000110 (TXE1和TXE2空闲) STAA CANTBSEL ; 写入CANTBSEL硬件选择TXE1最低位为1的是位1 LDAA CANTBSEL ; 再读CANTBSEL返回值0b00000010 (确认选中缓冲区1)在C语言中的典型用法uint8_t get_free_tx_buffer(void) { uint8_t temp CAN0_TFLG; // 读取CANTFLG if (temp 0x07) { // 检查低三位是否有空闲的 CAN0_TBSEL temp; // 写入CANTBSEL硬件自动选择最低位空闲缓冲区 return CAN0_TBSEL; // 返回实际选中的缓冲区位图 } return 0; // 没有空闲缓冲区 } // 使用示例 uint8_t selected_buffer get_free_tx_buffer(); if (selected_buffer 0x01) { // 当前选中了缓冲区0通过CANTXFG寄存器空间配置发送 // CAN0_TXFG.IDR0 ...; } else if (selected_buffer 0x02) { // 当前选中了缓冲区1 } // ...这个机制避免了软件去解析CANTFLG的位图并查找最低有效位的繁琐操作由硬件一步完成提高了代码效率和可靠性。4. 中断服务程序ISR实战设计与避坑指南配置好寄存器只是开始中断服务程序ISR才是真正处理事件、体现逻辑的地方。设计不好的ISR会让系统变得不稳定或响应迟缓。4.1 中断服务程序的基本框架与流程一个健壮的CAN中断服务程序通常遵循以下流程确定中断源进入ISR后第一件事是读取中断标志寄存器对于接收和错误是CANRFLG对于发送是CANTFLG以确定具体是哪个事件触发了中断。S12MSCANV3可能有多个中断向量也可能共用一个向量需查阅具体芯片数据手册。处理事件根据标志位进行相应处理。RXF置位从RxFG接收前台缓冲区读取数据。读取完成后必须通过向CANRFLG寄存器的RXF位写1来清除该标志以释放缓冲区允许下一帧数据进入。TXEx置位表示对应发送缓冲区已空闲。可以准备下一帧要发送的数据。注意TXEx标志是“写1清除”来启动发送而发送完成后硬件会自动“置1”。在ISR中看到它置1通常不需要软件操作除非要重新启动发送。CSCIF置位表示总线状态发生变化。应读取CANRFLG中的RSTAT[1:0]和TSTAT[1:0]来获取当前精确状态Error Active, Error Passive, Bus-Off并执行相应的错误处理或恢复逻辑。处理完后需向CANRFLG的CSCIF位写1来清除该标志。OVRIF置位发生了数据溢出。这是一个严重警告意味着你的ISR处理速度太慢或总线负载过高。应记录错误并检查系统设计。清除标志写1。清除中断标志必要时在基于标志位查询的中断系统中在ISR退出前必须清除你在第一步中处理过的、在模块级别的中断标志。否则退出ISR后会立即再次进入导致死循环。对于S12系列通常需要向对应的标志位写1来清除。快速退出ISR应尽可能短小精悍。只做最必要的处理如拷贝数据、设置软件标志、记录状态将耗时的运算解析报文内容、更新复杂状态机放到主循环中基于软件标志去处理。4.2 数据一致性保护与临界区操作这是嵌入式中断编程的核心陷阱CAN控制器尤其需要注意。问题场景你正在主循环中读取CANRFLG寄存器检查RXF标志。就在你读取RXF值为1之后、开始读取RxFG缓冲区数据之前发生了CAN接收中断。ISR迅速处理了这帧数据并清除了RXF标志。然后中断返回主循环继续执行它基于之前读到的“RXF1”这个过时的信息去读取RxFG缓冲区。此时缓冲区里的数据可能已经是下一帧、半帧甚至是无效数据。手册中的警告在CANRFLG寄存器的描述里针对RXF标志有一句非常重要的Note:“To ensure data integrity, do not read the receive buffer registers while the RXF flag is cleared.”当RXF标志为0时不要读取接收缓冲区寄存器。但反过来在RXF为1时读取也必须保证这个“读标志-读数据”的操作是原子的不被中断打断。解决方案最安全的方法纯中断驱动。使能RXFIE所有数据都在ISR中读取并拷贝到软件缓冲区。主循环只处理软件缓冲区。这完全避免了竞争条件。如果必须轮询在读取CANRFLG和操作RxFG缓冲区之间关闭总中断或CAN模块中断。// 轮询接收示例需谨慎 disable_interrupts(); // 关总中断或至少关CAN接收中断 if (CAN0_RFLG RXF_MASK) { // 快速将RxFG中的数据拷贝到本地变量 my_data.idr0 CAN0_RXFG.IDR0; my_data.idr1 CAN0_RXFG.IDR1; // ... 拷贝所有需要的数据 // 清除RXF标志释放缓冲区 CAN0_RFLG RXF_MASK; // 写1清除 } enable_interrupts(); // 恢复中断 // 之后再用本地变量my_data进行慢速处理对于发送缓冲区手册指出当TXEx标志为0缓冲区已满且调度发送时对该缓冲区的读写访问会被阻塞。因此在配置发送缓冲区写IDR,DSR等时也应确保TXEx1通过CANTFLG确认并在操作期间避免被发送完成中断打断造成并发写。4.3 错误处理与总线恢复策略错误处理是CAN应用稳定性的基石。CSCIE中断是你的主要工具。错误主动Error Active状态处理当RSTAT/TSTAT变为01Error Passive时说明错误计数器已超过127。在ISR中你应该记录错误事件时间、错误计数器值CANRXERR/CANTXERR需在初始化或睡眠模式下读取。检查通信环境线路是否松动、终端电阻是否匹配、是否有强干扰源。可以考虑暂时降低发送优先级或频率。不要轻易复位CAN控制器它仍然在尝试通信。总线关闭Bus-Off状态处理当TSTAT变为00Bus-Off时是最严重的情况。S12MSCANV3提供了两种恢复方式由CANCTL1寄存器中的BORM位和CANMISC寄存器中的BOHOLD位控制。自动恢复BORM1控制器在检测到128次11个连续的隐性位总线空闲后自动将错误计数器清零并尝试恢复通信。这是最推荐的方式符合CAN标准且对软件透明。手动恢复BORM0控制器进入Bus-Off后将BOHOLD位置1并保持。软件需要监控到Bus-Off后先清除BOHOLD位写0然后控制器再等待128次总线空闲来恢复。这种方式让软件有更多的控制权但也增加了复杂性。在ISR中的操作检测到Bus-Off后如果采用自动恢复通常只需记录致命错误并报警。如果采用手动恢复则执行清除BOHOLD的操作。务必注意在Bus-Off状态下控制器无法发送任何帧包括错误帧。恢复过程是静默的。常见问题排查收不到中断检查CPU全局中断是否开启检查CAN模块中断是否在中断向量表中正确配置检查CANRIER/CANTIER是否已正确使能检查CANRFLG/CANTFLG中的标志位是否确实置位可能事件未发生。中断频繁触发系统卡死最可能的原因是在ISR中没有清除中断标志。导致一退出ISR由于标志位仍在立即再次进入中断。务必确认每个中断分支都清除了对应的标志位。数据丢失或错乱检查是否遵守了“数据一致性”原则。在轮询和中断混合使用时是否有关中断保护。检查接收FIFO是否溢出OVRIF这可能是ISR处理太慢或主循环消费数据太慢。发送一直失败检查CANTBSEL是否选择了正确的缓冲区检查TXEx标志是否为1空闲时才写入数据检查写入数据后是否通过向CANTFLG写1清除了TXEx位来启动发送检查总线波特率、终端电阻等物理层配置是否正确。5. 验收滤波器配置精讲中断帮你高效处理消息而验收滤波器Acceptance Filter则帮你从总线海量消息中只挑选出你关心的那些从而大幅减轻CPU负担。S12MSCANV3的滤波器配置是难点但用好了威力巨大。5.1 滤波器的工作原理与模式验收滤波器的核心是两组寄存器验收码寄存器CANIDAR0-7和验收掩码寄存器CANIDMR0-7。它们协同工作对接收到的报文标识符ID进行匹配检查。工作原理比特位比较接收到一帧报文其标识符被提取出来。将该标识符的每一个比特与对应的验收码寄存器CANIDARx的比特进行比较。验收掩码寄存器CANIDMRx的对应比特决定这一步比较是否重要如果掩码位 0表示“必须匹配”。接收ID的该位必须与验收码寄存器的对应位相等才算通过这一位的检查。如果掩码位 1表示“不关心”Don‘t Care。无论接收ID的这一位是0还是1都算通过检查。只有所有“必须匹配”的位都匹配成功这帧报文才会被存入接收FIFO并可能触发RXF中断。滤波器模式由CANIDAC寄存器的IDAM[1:0]位控制 这是灵活性的来源。它决定了如何将多达8个的验收码/掩码寄存器对共16个寄存器组织成不同的滤波单元。IDAM1IDAM0模式说明00两个32位滤波器使用 (CANIDAR0/1, CANIDMR0/1) 构成滤波器0 (CANIDAR4/5, CANIDMR4/5) 构成滤波器1。每个滤波器检查完整的29位扩展ID或11位标准ID的高位部分。01四个16位滤波器使用 (CANIDAR0, CANIDMR0), (CANIDAR1, CANIDMR1), (CANIDAR4, CANIDMR4), (CANIDAR5, CANIDMR5) 构成4个独立的滤波器。每个检查ID的一部分通常用于标准ID。10八个8位滤波器使用 CANIDAR0-3 和 CANIDAR4-7 与对应的掩码寄存器构成8个滤波器。每个检查ID的1个字节。11滤波器关闭不接收任何报文。可用于自测试或静默模式。5.2 标准标识符与扩展标识符的配置差异这是配置时最容易出错的地方因为标准ID11位和扩展ID29位的格式不同在寄存器中的存放位置也不同。扩展标识符29位使用全部的4个IDR寄存器IDR0-IDR3。因此在32位滤波器模式下你需要配置完整的32位验收码和掩码虽然只用了29位。在16位或8位模式下也需要对应地覆盖ID的各个部分。标准标识符11位只使用IDR0和IDR1的低3位IDR1的Bit7-5。这是一个关键点对于标准IDIDR2和IDR3是未使用的读为x。手册中的特别提醒为了正确接收标准标识符在掩码寄存器CANIDMR1,CANIDMR3,CANIDMR5,CANIDMR7中对应的最后三位AM[2:0]必须设置为1不关心。这是因为标准ID只有11位在32位或16位滤波器比较时会涉及到IDR1中除了ID[2:0]、RTR、IDE之外的其他位这些位在标准格式下是未定义的须被掩码忽略掉。5.3 配置示例接收特定ID范围的报文假设我们只希望接收标准ID为0x123和0x456的报文。步骤1选择滤波器模式。我们有两个具体的ID适合使用“四个16位滤波器”模式IDAM01。这样我们可以用两个滤波器分别匹配这两个ID。步骤2计算验收码和掩码。我们需要将11位ID映射到16位的滤波单元上。标准ID存放在IDR0和IDR1中ID[10:3]在 IDR0 的 Bit7-0。ID[2:0]在 IDR1 的 Bit7-5。IDR1的Bit4是RTRBit3是IDE标准格式下为0。对于ID0x123(二进制001 0010 0011)ID[10:3]0010 00110x23ID[2:0]001 左移到IDR1的Bit7-5位置即001 5 0x20RTR和IDE我们通常不关心可以设为0或用掩码忽略假设我们只接收数据帧RTR0且为标准格式IDE0。那么IDR1的完整值可能是0x20(0015) 0x00(RTR0, IDE0) 0x20。但我们使用16位滤波器它比较的是整个IDR0寄存器8位和IDR1寄存器8位的高5位Bit7-3不更准确地说在16位模式下每个滤波器使用一个CANIDARx和一个CANIDMRx它们各自对应一个字节。我们需要为ID0x123分配两个字节的滤波一个对应IDR0一个对应IDR1的高位部分。实际上配置流程通常是反向的我们设定验收码并用掩码来指定哪些位需要精确匹配。更实用的方法使用掩码进行范围过滤。如果我们想接收ID从0x100到0x1FF的所有报文即高3位ID[10:8]为001验收码CANIDAR0设为0x00因为ID[7:0]我们不关心用掩码屏蔽。掩码CANIDMR0设为0xE0二进制1110 0000。这意味着我们只关心IDR0的Bit7对应ID10、Bit6ID9、Bit5ID8。只有当它们与验收码对应位都是0匹配时才通过。这正好匹配ID[10:8]001注意001是二进制ID10是最高位为0。对于IDR1我们可能不关心ID[2:0]因为我们已经用高3位筛选了所以将对应的掩码位CANIDMR1的Bit7-5设为1不关心。同时我们可能希望只接收数据帧RTR0那么可以将IDR1的Bit4RTR位的掩码设为0必须匹配验收码对应位设为0。配置代码示例伪代码// 进入初始化模式 CAN0_CTL0 | INITRQ_MASK; while(!(CAN0_CTL1 INITAK_MASK)); // 等待初始化模式确认 // 设置滤波器模式为 四个16位滤波器 CAN0_IDAC (0b01 4); // IDAM[1:0] 01 // 配置滤波器0接收ID高3位为001的报文 (范围 0x100-0x1FF) CAN0_IDAR0 0x00; // 验收码ID[10:8]期望为0b001即IDR0的Bit70, Bit60, Bit51。但这里我们设为0通过掩码控制。 CAN0_IDMR0 0xE0; // 掩码只匹配IDR0的Bit7,6,5 (对应ID10,9,8)。0必须匹配。 // 配置滤波器0对应的IDR1部分不关心ID[2:0]只接收数据帧(RTR0)标准格式(IDE0) CAN0_IDAR1 0x00; // 期望值RTR0, IDE0 CAN0_IDMR1 0x18; // 掩码Bit4(RTR)和Bit3(IDE)必须匹配(0)Bit7-5(ID[2:0])不关心(1)。0x18 0001 1000 // 可以类似地配置滤波器1、2、3来接收其他ID... // CAN0_IDAR4, CAN0_IDMR4, CAN0_IDAR5, CAN0_IDMR5 对应滤波器1... // 退出初始化模式 CAN0_CTL0 ~INITRQ_MASK; while(CAN0_CTL1 INITAK_MASK); // 等待退出初始化模式调试技巧配置滤波器后如果收不到预期报文可以检查是否进入了初始化模式进行配置。使用CAN总线分析仪确认目标报文确实在总线上且ID正确。简化配置先将所有验收掩码寄存器CANIDMR0-7设为0xFF全部不关心看是否能收到所有报文。然后逐步收紧掩码定位问题。利用CANIDAC寄存器中的IDHIT[2:0]位。当一个报文被接收后这些位会指示是哪个滤波器命中的。这在调试复杂滤波规则时非常有用。
S12MSCANV3中断与寄存器配置实战:从原理到稳定CAN节点设计
发布时间:2026/6/26 10:28:41
1. 项目概述从寄存器手册到实战配置如果你在汽车电子或者工业控制领域搞过嵌入式开发那对CAN总线肯定不陌生。它就像设备之间的“神经系统”负责在各种嘈杂的电磁环境下稳定、可靠地传递控制指令和状态数据。但说实话光看芯片厂商提供的几百页参考手册尤其是里面密密麻麻的寄存器描述很容易让人头大。手册会告诉你每个位是干什么的但很少告诉你在实际项目中这些位到底该怎么组合为什么要这么配以及配错了会出什么幺蛾子。我最近在调一个基于Freescale现在是NXPS12系列MCU的项目核心就是用好它的S12MSCANV3控制器。手册里关于中断和寄存器配置的部分像CANRIER、CANTIER、CANRFLG这些读起来就像字典——准确但不够“友好”。这篇内容我就想结合自己踩过的坑和项目经验把这些寄存器“翻译”成能直接上手的配置逻辑。我们不止看每个位Bit的定义更要串起来理解一个CAN节点从初始化、收发数据到处理异常这些寄存器是如何联动工作的。目标很简单让你看完后能胸有成竹地配置出一个稳定、高效的CAN通信节点特别是中断驱动的应用。2. S12MSCANV3中断系统架构解析S12MSCANV3的中断设计得很清晰遵循了“标志位Flag” “使能位Enable”的经典模式。理解这个模式是灵活运用中断而非被中断牵着鼻子走的关键。2.1 中断产生的双要素标志与使能几乎所有微控制器的中断逻辑都类似需要两个条件同时满足才能跳转到中断服务程序ISR事件发生硬件置位标志位Flag这是由控制器内部状态机自动完成的。比如收到一帧新数据RXFReceive Buffer Full标志位会被硬件自动置1一个发送缓冲区变空对应的TXEx标志位会被置1。软件使能对应的中断使能位Interrupt Enable这是由开发者通过配置寄存器决定的。比如你想在收到数据时立刻得到通知就需要把RXFIERXF Interrupt Enable位置1。如果只置位了标志位而没有使能中断那么控制器只会“默默记下”这个事件通过标志位不会去打断CPU。在S12MSCANV3中标志位主要分布在CAN接收标志寄存器CANRFLG和CAN发送标志寄存器CANTFLG。而使能位则对应地分布在CAN接收中断使能寄存器CANRIER和CAN发送中断使能寄存器CANTIER。这种分离的设计带来了极大的灵活性。例如在系统初始化阶段你可能不想处理任何CAN中断那么就把所有使能位清零。你可以轮询Polling检查CANRFLG和CANTFLG寄存器来处理事务。当系统进入稳定运行需要实时响应时再打开相应的中断使能位切换到中断驱动模式。这种“标志位始终反映状态中断使能控制是否通知”的机制是高效事件处理的基础。2.2 核心中断源及其应用场景S12MSCANV3将中断源大致分为三类对应不同的应用需求接收中断核心是RXF标志。当一帧消息通过验收滤波被成功移入接收FIFO的前台缓冲区RxFG时此标志置位。使能RXFIE后会触发接收中断。这是数据消费型应用最常用的中断。例如电机控制器需要实时接收转速指令一旦指令到达必须立即处理不能等待轮询。发送中断核心是TXE0、TXE1、TXE2标志。这三个标志对应三个发送缓冲区。当某个缓冲区中的消息被成功发送到总线上或者发送请求被成功中止时对应的TXEx标志置位。使能TXEIE后会触发发送中断。这是数据生产型应用的关键。例如一个传感器节点需要周期上报数据。当它把一帧数据写入发送缓冲区并启动发送后就可以去做其他事情。等发送完成中断到来它就知道这个缓冲区已经空闲可以准备下一帧数据了实现了发送流程的流水线化。错误与状态变化中断这是一组更复杂但至关重要的中断由CANRIER中的多个位控制。过载中断OVRIE当接收FIFO已满但又有新消息到来时会发生数据溢出OVRIF标志置位。使能OVRIE后触发错误中断。这通常意味着数据消费速度跟不上生产速度是系统设计或中断优先级需要优化的信号。CAN状态变化中断CSCIE这是总线错误管理的核心。它本身是一个总使能。具体哪些状态变化能触发中断则由RSTATE[1:0]接收状态变化使能和TSTATE[1:0]发送状态变化使能这两个字段来精细控制。2.3 状态变化中断的精细控制RSTATE与TSTATERSTATE和TSTATE这两个字段的设计非常精妙它允许你根据错误的严重程度分层级地接收通知而不是任何风吹草动都进中断。CAN控制器内部有两个错误计数器接收错误计数器CANRXERR和发送错误计数器CANTXERR。根据计数值控制器和总线会处于不同状态RxOK / TxOK错误计数器小于128一切正常。RxErr / TxErr错误主动状态错误计数器在128-255之间。控制器能正常收发但会主动发送“主动错误帧”来告知总线错误。Bus-Off总线关闭状态发送错误计数器超过255。控制器会从总线上断开停止任何发送直到满足恢复条件。这是最严重的故障状态。RSTATE[1:0]和TSTATE[1:0]的4种编码决定了状态变化触发CSCIF中断的“灵敏度”00不因接收器/发送器状态变化产生任何CSCIF中断。完全关闭状态变化通知01仅当进入或离开“Bus-Off”状态时产生中断。只关心最严重的故障适用于那些只需要知道“通信是否彻底中断”的应用。10当进入或离开“RxErr/TxErr”或“Bus-Off”状态时产生中断。关心错误主动和总线关闭这是最常用的设置。当错误计数器超过128进入Error Active你就该收到警报开始检查线路质量或节点逻辑了而不是等到彻底Bus-Off。11任何状态变化都产生中断。最高灵敏度可能过于频繁适用于深度调试或需要监控每一个状态跳变的场景。实操心得在大部分汽车车身控制或工业IO模块中我通常将RSTATE和TSTATE配置为10。这样当节点因持续干扰进入Error Active状态时我就能在中断里记录错误日志或点亮预警灯给维护人员一个早期预警而不是等到通信完全瘫痪Bus-Off才被发现。Bus-Off恢复通常需要复杂的上下电或软件复位流程应尽量避免。3. 关键寄存器详解与配置策略理解了架构我们再来深入看看几个最关键的寄存器以及如何配置它们。3.1 接收中断使能寄存器CANRIER这个寄存器是接收相关中断的“总开关面板”。地址偏移为0x0005。位名称描述复位值配置建议7WUPIE唤醒中断使能。需与CANCTL0中的WUPE位同时使能才有效。0仅在节点需要进入低功耗睡眠模式并由CAN总线唤醒时才置1。常规应用置0。6CSCIECAN状态变化中断使能。总开关。0通常置1。只有打开它下面RSTATE/TSTATE的配置才有意义。5-4RSTATE[1:0]接收器状态变化中断灵敏度控制。00根据2.3节的描述选择。推荐10监测Error Active和Bus-Off。3-2TSTATE[1:0]发送器状态变化中断灵敏度控制。00同RSTATE推荐10。1OVRIE接收过载中断使能。0建议置1。数据溢出是严重问题需要及时处理。0RXFIE接收缓冲区满中断使能。0根据应用需求。若需实时处理数据置1若采用轮询置0。初始化模式INITRQ1 INITAK1下此寄存器被复位且不可写。这意味着你必须在退出初始化模式、进入正常模式前完成对它的配置。一个典型的配置代码片段假设使用C语言和寄存器映射头文件可能如下// 假设 CAN0_RIER 是映射到地址的寄存器指针 // 1. 首先确保进入初始化模式 (设置CANCTL0的INITRQ位等待INITAK置位) // 2. 配置波特率、验收滤波器等... // 3. 配置中断使能寄存器仍在初始化模式下但CANRIER在初始化模式下被复位需在退出前配置 // 注意手册指出CANRIER在初始化模式下被复位且不可写。因此配置应在退出初始化模式前一刻进行。 // 更常见的流程是在初始化模式下配置其他参数退出初始化模式后立即配置中断。 // 退出初始化模式清除INITRQ // 等待INITAK变为0... // 现在配置CANRIER CAN0_RIER 0x00; // 先全部清零 CAN0_RIER | (1 6); // 使能 CSCIE CAN0_RIER | (0b10 4); // 设置 RSTATE[1:0] 10 CAN0_RIER | (0b10 2); // 设置 TSTATE[1:0] 10 CAN0_RIER | (1 1); // 使能 OVRIE CAN0_RIER | (1 0); // 使能 RXFIE // WUPIE 保持为0不使能唤醒中断3.2 发送中断使能寄存器CANTIER这个寄存器控制三个发送缓冲区TXE0, TXE1, TXE2的空闲中断。地址偏移为0x0007。它非常简单只有低3位有效。位名称描述复位值配置建议2TXEIE2发送缓冲区2空中断使能0如果使用缓冲区2进行发送并希望发送完成时得到通知则置1。1TXEIE1发送缓冲区1空中断使能0同上。0TXEIE0发送缓冲区0空中断使能0同上。配置策略你是否使能某个TXEIE完全取决于你的发送策略。轮询发送将所有TXEIE置0。发送前循环检查CANTFLG寄存器找到TXEx1空闲的缓冲区填入数据然后清除该TXEx标志写1来启动发送。发送完成后需要再次轮询检查该标志是否变回1。中断发送将使用的缓冲区的TXEIE置1。发送流程变为检查CANTFLG找到一个空闲缓冲区TXEx1。通过CANTBSEL选中该缓冲区。填写标识符、数据长度码DLC、数据到CANTXFG区域。清除CANTFLG中对应的TXEx位写1启动发送。此时该位变为0。CPU可以处理其他任务。当消息成功发送到总线后硬件会自动将TXEx位置1。由于TXEIE已使能会触发发送中断。在发送中断服务程序ISR中你可以知道哪个缓冲区已空闲准备下一帧数据。注意事项CANTIER同样在初始化模式下被复位且不可写。配置时机同CANRIER。3.3 发送缓冲区选择寄存器CANTBSEL的妙用CANTBSEL地址偏移0x000A是一个硬件辅助的缓冲区选择器它能极大简化“查找下一个空闲发送缓冲区”的操作。工作原理你读取CANTFLG寄存器。假设TXE01,TXE10,TXE21即缓冲区0和2空闲则读到的值为0b00000101二进制仅低3位有效。你将这个值写入CANTBSEL寄存器。硬件会自动选择最低编号的、值为1的位所对应的缓冲区。在这个例子中最低编号的1是TXE0位0因此硬件会选择缓冲区0并将其映射到CANTXFG的寄存器空间。当你再读取CANTBSEL时返回值会是0b00000001明确告诉你当前选中了缓冲区0。手册给的汇编例子非常直观LDAA CANTFLG ; 读CANTFLG假设值0b00000110 (TXE1和TXE2空闲) STAA CANTBSEL ; 写入CANTBSEL硬件选择TXE1最低位为1的是位1 LDAA CANTBSEL ; 再读CANTBSEL返回值0b00000010 (确认选中缓冲区1)在C语言中的典型用法uint8_t get_free_tx_buffer(void) { uint8_t temp CAN0_TFLG; // 读取CANTFLG if (temp 0x07) { // 检查低三位是否有空闲的 CAN0_TBSEL temp; // 写入CANTBSEL硬件自动选择最低位空闲缓冲区 return CAN0_TBSEL; // 返回实际选中的缓冲区位图 } return 0; // 没有空闲缓冲区 } // 使用示例 uint8_t selected_buffer get_free_tx_buffer(); if (selected_buffer 0x01) { // 当前选中了缓冲区0通过CANTXFG寄存器空间配置发送 // CAN0_TXFG.IDR0 ...; } else if (selected_buffer 0x02) { // 当前选中了缓冲区1 } // ...这个机制避免了软件去解析CANTFLG的位图并查找最低有效位的繁琐操作由硬件一步完成提高了代码效率和可靠性。4. 中断服务程序ISR实战设计与避坑指南配置好寄存器只是开始中断服务程序ISR才是真正处理事件、体现逻辑的地方。设计不好的ISR会让系统变得不稳定或响应迟缓。4.1 中断服务程序的基本框架与流程一个健壮的CAN中断服务程序通常遵循以下流程确定中断源进入ISR后第一件事是读取中断标志寄存器对于接收和错误是CANRFLG对于发送是CANTFLG以确定具体是哪个事件触发了中断。S12MSCANV3可能有多个中断向量也可能共用一个向量需查阅具体芯片数据手册。处理事件根据标志位进行相应处理。RXF置位从RxFG接收前台缓冲区读取数据。读取完成后必须通过向CANRFLG寄存器的RXF位写1来清除该标志以释放缓冲区允许下一帧数据进入。TXEx置位表示对应发送缓冲区已空闲。可以准备下一帧要发送的数据。注意TXEx标志是“写1清除”来启动发送而发送完成后硬件会自动“置1”。在ISR中看到它置1通常不需要软件操作除非要重新启动发送。CSCIF置位表示总线状态发生变化。应读取CANRFLG中的RSTAT[1:0]和TSTAT[1:0]来获取当前精确状态Error Active, Error Passive, Bus-Off并执行相应的错误处理或恢复逻辑。处理完后需向CANRFLG的CSCIF位写1来清除该标志。OVRIF置位发生了数据溢出。这是一个严重警告意味着你的ISR处理速度太慢或总线负载过高。应记录错误并检查系统设计。清除标志写1。清除中断标志必要时在基于标志位查询的中断系统中在ISR退出前必须清除你在第一步中处理过的、在模块级别的中断标志。否则退出ISR后会立即再次进入导致死循环。对于S12系列通常需要向对应的标志位写1来清除。快速退出ISR应尽可能短小精悍。只做最必要的处理如拷贝数据、设置软件标志、记录状态将耗时的运算解析报文内容、更新复杂状态机放到主循环中基于软件标志去处理。4.2 数据一致性保护与临界区操作这是嵌入式中断编程的核心陷阱CAN控制器尤其需要注意。问题场景你正在主循环中读取CANRFLG寄存器检查RXF标志。就在你读取RXF值为1之后、开始读取RxFG缓冲区数据之前发生了CAN接收中断。ISR迅速处理了这帧数据并清除了RXF标志。然后中断返回主循环继续执行它基于之前读到的“RXF1”这个过时的信息去读取RxFG缓冲区。此时缓冲区里的数据可能已经是下一帧、半帧甚至是无效数据。手册中的警告在CANRFLG寄存器的描述里针对RXF标志有一句非常重要的Note:“To ensure data integrity, do not read the receive buffer registers while the RXF flag is cleared.”当RXF标志为0时不要读取接收缓冲区寄存器。但反过来在RXF为1时读取也必须保证这个“读标志-读数据”的操作是原子的不被中断打断。解决方案最安全的方法纯中断驱动。使能RXFIE所有数据都在ISR中读取并拷贝到软件缓冲区。主循环只处理软件缓冲区。这完全避免了竞争条件。如果必须轮询在读取CANRFLG和操作RxFG缓冲区之间关闭总中断或CAN模块中断。// 轮询接收示例需谨慎 disable_interrupts(); // 关总中断或至少关CAN接收中断 if (CAN0_RFLG RXF_MASK) { // 快速将RxFG中的数据拷贝到本地变量 my_data.idr0 CAN0_RXFG.IDR0; my_data.idr1 CAN0_RXFG.IDR1; // ... 拷贝所有需要的数据 // 清除RXF标志释放缓冲区 CAN0_RFLG RXF_MASK; // 写1清除 } enable_interrupts(); // 恢复中断 // 之后再用本地变量my_data进行慢速处理对于发送缓冲区手册指出当TXEx标志为0缓冲区已满且调度发送时对该缓冲区的读写访问会被阻塞。因此在配置发送缓冲区写IDR,DSR等时也应确保TXEx1通过CANTFLG确认并在操作期间避免被发送完成中断打断造成并发写。4.3 错误处理与总线恢复策略错误处理是CAN应用稳定性的基石。CSCIE中断是你的主要工具。错误主动Error Active状态处理当RSTAT/TSTAT变为01Error Passive时说明错误计数器已超过127。在ISR中你应该记录错误事件时间、错误计数器值CANRXERR/CANTXERR需在初始化或睡眠模式下读取。检查通信环境线路是否松动、终端电阻是否匹配、是否有强干扰源。可以考虑暂时降低发送优先级或频率。不要轻易复位CAN控制器它仍然在尝试通信。总线关闭Bus-Off状态处理当TSTAT变为00Bus-Off时是最严重的情况。S12MSCANV3提供了两种恢复方式由CANCTL1寄存器中的BORM位和CANMISC寄存器中的BOHOLD位控制。自动恢复BORM1控制器在检测到128次11个连续的隐性位总线空闲后自动将错误计数器清零并尝试恢复通信。这是最推荐的方式符合CAN标准且对软件透明。手动恢复BORM0控制器进入Bus-Off后将BOHOLD位置1并保持。软件需要监控到Bus-Off后先清除BOHOLD位写0然后控制器再等待128次总线空闲来恢复。这种方式让软件有更多的控制权但也增加了复杂性。在ISR中的操作检测到Bus-Off后如果采用自动恢复通常只需记录致命错误并报警。如果采用手动恢复则执行清除BOHOLD的操作。务必注意在Bus-Off状态下控制器无法发送任何帧包括错误帧。恢复过程是静默的。常见问题排查收不到中断检查CPU全局中断是否开启检查CAN模块中断是否在中断向量表中正确配置检查CANRIER/CANTIER是否已正确使能检查CANRFLG/CANTFLG中的标志位是否确实置位可能事件未发生。中断频繁触发系统卡死最可能的原因是在ISR中没有清除中断标志。导致一退出ISR由于标志位仍在立即再次进入中断。务必确认每个中断分支都清除了对应的标志位。数据丢失或错乱检查是否遵守了“数据一致性”原则。在轮询和中断混合使用时是否有关中断保护。检查接收FIFO是否溢出OVRIF这可能是ISR处理太慢或主循环消费数据太慢。发送一直失败检查CANTBSEL是否选择了正确的缓冲区检查TXEx标志是否为1空闲时才写入数据检查写入数据后是否通过向CANTFLG写1清除了TXEx位来启动发送检查总线波特率、终端电阻等物理层配置是否正确。5. 验收滤波器配置精讲中断帮你高效处理消息而验收滤波器Acceptance Filter则帮你从总线海量消息中只挑选出你关心的那些从而大幅减轻CPU负担。S12MSCANV3的滤波器配置是难点但用好了威力巨大。5.1 滤波器的工作原理与模式验收滤波器的核心是两组寄存器验收码寄存器CANIDAR0-7和验收掩码寄存器CANIDMR0-7。它们协同工作对接收到的报文标识符ID进行匹配检查。工作原理比特位比较接收到一帧报文其标识符被提取出来。将该标识符的每一个比特与对应的验收码寄存器CANIDARx的比特进行比较。验收掩码寄存器CANIDMRx的对应比特决定这一步比较是否重要如果掩码位 0表示“必须匹配”。接收ID的该位必须与验收码寄存器的对应位相等才算通过这一位的检查。如果掩码位 1表示“不关心”Don‘t Care。无论接收ID的这一位是0还是1都算通过检查。只有所有“必须匹配”的位都匹配成功这帧报文才会被存入接收FIFO并可能触发RXF中断。滤波器模式由CANIDAC寄存器的IDAM[1:0]位控制 这是灵活性的来源。它决定了如何将多达8个的验收码/掩码寄存器对共16个寄存器组织成不同的滤波单元。IDAM1IDAM0模式说明00两个32位滤波器使用 (CANIDAR0/1, CANIDMR0/1) 构成滤波器0 (CANIDAR4/5, CANIDMR4/5) 构成滤波器1。每个滤波器检查完整的29位扩展ID或11位标准ID的高位部分。01四个16位滤波器使用 (CANIDAR0, CANIDMR0), (CANIDAR1, CANIDMR1), (CANIDAR4, CANIDMR4), (CANIDAR5, CANIDMR5) 构成4个独立的滤波器。每个检查ID的一部分通常用于标准ID。10八个8位滤波器使用 CANIDAR0-3 和 CANIDAR4-7 与对应的掩码寄存器构成8个滤波器。每个检查ID的1个字节。11滤波器关闭不接收任何报文。可用于自测试或静默模式。5.2 标准标识符与扩展标识符的配置差异这是配置时最容易出错的地方因为标准ID11位和扩展ID29位的格式不同在寄存器中的存放位置也不同。扩展标识符29位使用全部的4个IDR寄存器IDR0-IDR3。因此在32位滤波器模式下你需要配置完整的32位验收码和掩码虽然只用了29位。在16位或8位模式下也需要对应地覆盖ID的各个部分。标准标识符11位只使用IDR0和IDR1的低3位IDR1的Bit7-5。这是一个关键点对于标准IDIDR2和IDR3是未使用的读为x。手册中的特别提醒为了正确接收标准标识符在掩码寄存器CANIDMR1,CANIDMR3,CANIDMR5,CANIDMR7中对应的最后三位AM[2:0]必须设置为1不关心。这是因为标准ID只有11位在32位或16位滤波器比较时会涉及到IDR1中除了ID[2:0]、RTR、IDE之外的其他位这些位在标准格式下是未定义的须被掩码忽略掉。5.3 配置示例接收特定ID范围的报文假设我们只希望接收标准ID为0x123和0x456的报文。步骤1选择滤波器模式。我们有两个具体的ID适合使用“四个16位滤波器”模式IDAM01。这样我们可以用两个滤波器分别匹配这两个ID。步骤2计算验收码和掩码。我们需要将11位ID映射到16位的滤波单元上。标准ID存放在IDR0和IDR1中ID[10:3]在 IDR0 的 Bit7-0。ID[2:0]在 IDR1 的 Bit7-5。IDR1的Bit4是RTRBit3是IDE标准格式下为0。对于ID0x123(二进制001 0010 0011)ID[10:3]0010 00110x23ID[2:0]001 左移到IDR1的Bit7-5位置即001 5 0x20RTR和IDE我们通常不关心可以设为0或用掩码忽略假设我们只接收数据帧RTR0且为标准格式IDE0。那么IDR1的完整值可能是0x20(0015) 0x00(RTR0, IDE0) 0x20。但我们使用16位滤波器它比较的是整个IDR0寄存器8位和IDR1寄存器8位的高5位Bit7-3不更准确地说在16位模式下每个滤波器使用一个CANIDARx和一个CANIDMRx它们各自对应一个字节。我们需要为ID0x123分配两个字节的滤波一个对应IDR0一个对应IDR1的高位部分。实际上配置流程通常是反向的我们设定验收码并用掩码来指定哪些位需要精确匹配。更实用的方法使用掩码进行范围过滤。如果我们想接收ID从0x100到0x1FF的所有报文即高3位ID[10:8]为001验收码CANIDAR0设为0x00因为ID[7:0]我们不关心用掩码屏蔽。掩码CANIDMR0设为0xE0二进制1110 0000。这意味着我们只关心IDR0的Bit7对应ID10、Bit6ID9、Bit5ID8。只有当它们与验收码对应位都是0匹配时才通过。这正好匹配ID[10:8]001注意001是二进制ID10是最高位为0。对于IDR1我们可能不关心ID[2:0]因为我们已经用高3位筛选了所以将对应的掩码位CANIDMR1的Bit7-5设为1不关心。同时我们可能希望只接收数据帧RTR0那么可以将IDR1的Bit4RTR位的掩码设为0必须匹配验收码对应位设为0。配置代码示例伪代码// 进入初始化模式 CAN0_CTL0 | INITRQ_MASK; while(!(CAN0_CTL1 INITAK_MASK)); // 等待初始化模式确认 // 设置滤波器模式为 四个16位滤波器 CAN0_IDAC (0b01 4); // IDAM[1:0] 01 // 配置滤波器0接收ID高3位为001的报文 (范围 0x100-0x1FF) CAN0_IDAR0 0x00; // 验收码ID[10:8]期望为0b001即IDR0的Bit70, Bit60, Bit51。但这里我们设为0通过掩码控制。 CAN0_IDMR0 0xE0; // 掩码只匹配IDR0的Bit7,6,5 (对应ID10,9,8)。0必须匹配。 // 配置滤波器0对应的IDR1部分不关心ID[2:0]只接收数据帧(RTR0)标准格式(IDE0) CAN0_IDAR1 0x00; // 期望值RTR0, IDE0 CAN0_IDMR1 0x18; // 掩码Bit4(RTR)和Bit3(IDE)必须匹配(0)Bit7-5(ID[2:0])不关心(1)。0x18 0001 1000 // 可以类似地配置滤波器1、2、3来接收其他ID... // CAN0_IDAR4, CAN0_IDMR4, CAN0_IDAR5, CAN0_IDMR5 对应滤波器1... // 退出初始化模式 CAN0_CTL0 ~INITRQ_MASK; while(CAN0_CTL1 INITAK_MASK); // 等待退出初始化模式调试技巧配置滤波器后如果收不到预期报文可以检查是否进入了初始化模式进行配置。使用CAN总线分析仪确认目标报文确实在总线上且ID正确。简化配置先将所有验收掩码寄存器CANIDMR0-7设为0xFF全部不关心看是否能收到所有报文。然后逐步收紧掩码定位问题。利用CANIDAC寄存器中的IDHIT[2:0]位。当一个报文被接收后这些位会指示是哪个滤波器命中的。这在调试复杂滤波规则时非常有用。