十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

STM32F429双CAN测试程序详解:从引脚映射到Bus Off恢复

STM32F429双CAN测试程序详解:从引脚映射到Bus Off恢复 简介面向STM32F429嵌入式开发者的双CAN通道测试程序用于验证CAN1与CAN2两个独立控制器的初始化配置、报文收发和中断处理适合汽车电子、工业自动化领域的中初级开发者学习。程序基于HAL库实现围绕ISO 11898协议标准详细覆盖位定时与波特率设定、报文头结构体填充、发送与接收FIFO管理、滤波器规则配置、中断服务函数编写以及位错误、帧错误等异常的检测与恢复流程。通过该程序读者可以直观理解双路CAN并行工作时的消息仲裁机制学习如何让两个CAN通道同时收发不同优先级的报文并快速搭建起自己的双通道通信测试环境。资源压缩包约9.52MB已有169人学习下载开发者可借这套示例程序掌握双CAN通道的初始化与收发流程并将其中的代码逻辑直接移植到实际项目的第二路CAN应用场景。1. STM32F429双CAN通道测试程序为什么先要处理CAN2依赖CAN1这个前提STM32F429内部带有两个bxCAN控制器但设计成主从结构CAN1为主CAN2为从。所谓“从”不只是名称上的区别——CAN2没有独立完整的过滤器存储与位时序配置必须依赖CAN1已经被正确使能并退出初始化状态才能进入正常工作模式。我见过不少工程师拿到“CAN2Channels_STM32F429的双CAN通道测试程序”这类需求时直接在HAL库中单独初始化CAN2结果启动时报错最后发现CAN1根本没有使能。本文按最常见的STM32CubeMX加HAL库方案把双CAN测试程序的落地路径讲清楚引脚怎么映射、位时序参数怎么填、过滤器如何在CAN1与CAN2之间切分最后落到波形验证与Bus Off恢复策略。适合做车载网关、工业CAN节点或产线工装板的软硬件工程师新手也能按步骤在F429开发板上跑通双通道互收。2. STM32F429双CAN测试程序的引脚映射与收发器电路2.1 CAN1/CAN2在STM32F429上的引脚复用选项对比搭建测试程序的第一步是确定CAN1与CAN2各自用哪组引脚。STM32F429上两个CAN控制器都复用AF9功能每个控制器都有多组可选引脚但不同封装和不同板卡上可用的组合不一样。CAN1常用PA11(RX)/PA12(TX)、PB8/PB9以及144脚及以上封装的PD0/PD1CAN2常用PB5/PB6和PB12/PB13。下表是常用组合。CAN通道RX引脚TX引脚AF编号板级注意点CAN1PA11PA12AF9多数F429核心板默认引出CAN1PB8PB9AF9与I2C1、SPI1部分引脚重叠CAN1PD0PD1AF9144脚及以上封装才可用CAN2PB5PB6AF9与I2C1、SPI1引脚邻近CAN2PB12PB13AF9与SPI2的NSS/SCK接近我在实际项目中的选择顺序是CAN1用PA11/PA12CAN2用PB5/PB6。原因是这两组在大多数开发板上已经引出或容易飞线。选引脚时先看复用冲突再看PCB布线是否方便。CubeMX中的操作很简单在Pinout视图里把对应引脚用鼠标拉成CAN1_RX、CAN1_TX或CAN2_RX、CAN2_TX软件会自动把复用功能设成AF9。需要注意的是同一个控制器不要两组引脚混用比如CAN1的RX用PA11、TX用PB9这在功能上可行但容易让后续排查的人困惑测试程序里尽量保持一对引脚。2.2 双路CAN收发器与120Ω终端电阻怎么接CAN控制器输出的是3.3V逻辑电平不能直接挂总线必须经过收发器。常用的有TJA1050、SN65HVD230或隔离型的ISO1050。TJA1050是5V供电输入阈值兼容3.3V逻辑可以直接与F429的GPIO相连SN65HVD230是3.3V供电适合低压系统。双通道的连接方式完全一致以TJA1050为例PA12 (CAN1_TX) -- TJA1050 TXD PA11 (CAN1_RX) -- TJA1050 RXD PB6 (CAN2_TX) -- 另一片TJA1050 TXD PB5 (CAN2_RX) -- 另一片TJA1050 RXD CANH 与 CANL 之间跨接120Ω终端电阻这里的核心是终端电阻布局。CAN总线协议要求物理线路两端各有一个120Ω电阻而不是每个节点都加。当两个CAN通道通过同一根双绞线互测时只需要在双绞线两端各跨接一个120Ω电阻。如果只在板内测试且线缆很短可以先不接终端电阻但此时总线信号反射会让波形边沿变差逻辑分析仪看到的位宽度会不稳定。要验证物理层时终端电阻不能省。2.3 共地与供电对can通信测试的影响测试程序跑不通时我一般先量三个点收发器供电电压是否正确、TXD引脚静态电平是否为高、两个测试节点是否真正共地。CAN是差分信号但收发器有一个共模输入范围TJA1050约为-7V到12V。如果两端设备的地电位差超出这个范围总线上会出现大量错误帧表现就是“can初始化失败”或者发送一直报错。双通道在同一块板上互测时两片收发器必须共地不同板卡通过长线连接时最好使用隔离收发器。还有一个经常被忽略的点CAN控制器空闲时TXD应为高电平如果量到低电平说明硬件复位后引脚状态没有正确配置或者控制器正处于Bus Off状态。3. 用CubeMX完成STM32F429双CAN配置与位时序设定3.1 使能CAN2前必须使能CAN1时钟树与初始化顺序在CubeMX中勾选CAN1和CAN2只解决了外设时钟使能问题。F429的bxCAN模块中CAN2作为从控制器只有在CAN1正常工作后才能真正参与总线通信。具体到CubeMX的Clock Configuration页面需要确认CAN时钟源来自APB1且APB1时钟不超过42MHz。当SYSCLK设为168MHz时APB1分频系数为4得到42MHz这是F429上最常见的组合。如果外部晶振是25MHz需要在RCC配置里选择对应的HSE值否则PLL算出来的系统时钟会偏离预期。代码层面初始化顺序是先HAL_CAN_Init(hcan1)再HAL_CAN_Init(hcan2)不要反过来。启动顺序也一样先HAL_CAN_Start(hcan1)再HAL_CAN_Start(hcan2)。关闭时顺序反过来先停CAN2再停CAN1。3.2 500kbps下BS1、BS2、SJW参数与采样点计算CAN位时间由四段组成同步段、传播时间段、相位缓冲段1和相位缓冲段2。在STM32的HAL库中传播时间段和相位缓冲段1合并为TimeSeg1也就是BS1相位缓冲段2单独为TimeSeg2即BS2。同步段固定为1个时间量子tq。采样点位于BS1结束后、BS2开始前这个位置直接关系通信的可靠性。核心公式是tq (BRP 1) / fAPB1位时间 (1 BS1 BS2) 个tq波特率 fAPB1 / ((BRP1) × (1BS1BS2))采样点 (1 BS1) / (1 BS1 BS2) × 100%以fAPB142MHz、目标波特率500kbps为例。令BS111、BS22位时间就是14个tq此时BRP1 42MHz / (500k × 14) 6所以BRP取5。采样点 (111)/14 85.7%落在CAN协议推荐的80%到87.5%区间内。按这个思路可以得到一组常用的完整参数。目标波特率Prescaler(BRP)BS1BS2SJW实际波特率采样点1 Mbps211211.000 Mbps85.7%500 kbps51121500 kbps85.7%250 kbps111121250 kbps85.7%125 kbps231121125 kbps85.7%SJW同步跳跃宽度用于补偿时钟偏差取值一般不超过BS2这里设成1tq即可。如果追求更低的采样点可以改成BS110、BS23位时间同样是14tq采样点变为78.6%适合线缆较长、信号边沿较缓的场景。这里需要说明STM32F429的双CAN只支持CAN2.0帧若项目后续要评估canfd和can的区别CAN FD的采样点和位速率切换逻辑与这里不同需要换支持CAN FD的控制器和收发器。3.3 28个过滤器在CAN1与CAN2之间的切分F429的bxCAN模块共享28个硬件过滤器组编号0到27不是每个CAN独立拥有。硬件通过CAN_FMR寄存器中的CAN2SB位决定CAN2从哪一组开始使用。例如CAN2SB14时绝对编号0到13给CAN1绝对编号14到27给CAN2。CubeMX的NVIC设置页里会自动生成这部分配置但测试程序中还要手动确认结构体字段一致。HAL库中给CAN2配置过滤器时FilterBank字段写的是相对CAN2起始组的偏移量CAN2的FilterBank0对应绝对组号14。给CAN1配置时才是绝对编号。这个差异几乎每个双CAN项目都会遇到很多“can初始化失败”其实只是过滤器配置越界。4. STM32F429双CAN测试程序的核心HAL代码从回环到交叉收发4.1 先跑Loopback回环自测验证控制器本身没问题不要在未验证控制器的情况下就去检查外部总线。先把CAN1和CAN2都配置为Loopback模式此时发送报文不经过收发器直接在芯片内部回到本节点的接收FIFO。回环模式可以验证CAN内核、FIFO、中断和过滤器配置是否正常。需要特别注意的是回环模式仍然受硬件过滤器控制因此要先配一个全通过滤器掩码全部置0表示接收所有ID。CAN_FilterTypeDef filterAll; filterAll.FilterActivation ENABLE; filterAll.FilterBank 0; filterAll.FilterMode CAN_FILTERMODE_IDMASK; filterAll.FilterScale CAN_FILTERSCALE_32BIT; filterAll.FilterIdHigh 0x0000U; filterAll.FilterIdLow 0x0000U; filterAll.FilterMaskIdHigh 0x0000U; filterAll.FilterMaskIdLow 0x0000U; filterAll.FilterFIFOAssignment CAN_RX_FIFO0; HAL_CAN_ConfigFilter(hcan1, filterAll);这段代码的作用是让CAN1接收所有标准帧。FilterMode选择IDMASK掩码为0表示不漏过任何ID如果把掩码设为0x7FF左移5位则只匹配一个指定ID。FilterBank设为0是CAN1可用的过滤器组。回环模式下发送端和接收端是同一个CAN节点所以需要同时调用HAL_CAN_Start启动控制器并打开接收中断。CAN_TxHeaderTypeDef txHeader; txHeader.StdId 0x123; txHeader.ExtId 0; txHeader.IDE CAN_ID_STD; txHeader.RTR CAN_RTR_DATA; txHeader.DLC 4; uint8_t txData[4] {0x11, 0x22, 0x33, 0x44}; uint32_t mailbox 0; if (HAL_CAN_AddTxMessage(hcan1, txHeader, txData, mailbox) HAL_OK) { // 回环模式下发送完成后本节点会收到同一帧 }HAL_CAN_AddTxMessage的四个参数分别是CAN句柄、发送报头结构体、数据缓冲区和邮箱索引。函数执行成功后报文首先进入硬件邮箱总线仲裁成功后发送。回环模式下CANH/CANL引脚上不会有信号波形属于预期行为不要拿示波器去量。4.2 Normal模式交叉测试CAN1发送、CAN2接收中断回环验证通过后将两个CAN都切换到Normal模式接入外部收发器和双绞线。同一个总线上有两个发送节点时can总线仲裁由ID位值决定ID小的优先级高。我们的测试程序固定由CAN1发送ID0x123的报文CAN2设置过滤器只接收这个ID从而验证双通道链路。// CAN1 发送节点 hcan1.Init.Mode CAN_MODE_NORMAL; HAL_CAN_Init(hcan1); HAL_CAN_Start(hcan1); // CAN2 接收节点 hcan2.Init.Mode CAN_MODE_NORMAL; HAL_CAN_Init(hcan2); HAL_CAN_Start(hcan2); HAL_CAN_ActivateNotification(hcan2, CAN_IT_RX_FIFO0_MSG_PENDING);启动CAN2后调用HAL_CAN_ActivateNotification把FIFO0有报文挂起的中断通知打开。这一步容易漏漏掉后即使硬件接收到了报文也不会进入中断回调。void CAN2_RX_IRQHandler(void) { HAL_CAN_IRQHandler(hcan2); } void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { CAN_RxHeaderTypeDef rxHeader; uint8_t rxData[8]; if (hcan-Instance CAN2) { HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, rxHeader, rxData); // 检查 rxHeader.StdId应为 0x123 } }中断回调里通过判断hcan-Instance区分是哪个CAN控制器触发的避免CAN1的报文进入接收逻辑。HAL_CAN_GetRxMessage每次从FIFO0弹出一帧并把报头信息填入rxHeader、数据拷贝到rxData。由于FIFO深度只有3个邮箱回调中应尽快把rxData复制到用户缓冲区否则连续大量报文到来时可能溢出。4.3 双CAN过滤器配置FilterBank从相对编号写下面这段是给CAN2配置只接收ID0x123的过滤器。双CAN环境下过滤器组划分必须与CAN2SB一致否则CAN2的报文会落到CAN1的FIFO里。CAN_FilterTypeDef filter; filter.FilterActivation ENABLE; filter.FilterBank 0; // 相对CAN2起始组的偏移对应绝对组号14 filter.FilterMode CAN_FILTERMODE_IDMASK; filter.FilterScale CAN_FILTERSCALE_32BIT; filter.FilterIdHigh (0x123U 5) 0xFFFFU; filter.FilterIdLow 0x0000U; filter.FilterMaskIdHigh (0x7FFU 5) 0xFFFFU; filter.FilterMaskIdLow 0x0000U; filter.FilterFIFOAssignment CAN_RX_FIFO0; filter.SlaveStartFilterBank 14; // CAN2从绝对组号14开始 HAL_CAN_ConfigFilter(hcan2, filter);为什么ID要左移5位因为bxCAN的32位过滤器寄存器布局中标准ID占用位28到位18写入高16位时需要将11位ID整体左移5位。屏蔽位的0x7FF左移5位表示只比较ID字段其他位全部置1表示不关心。FilterBank字段在CAN2句柄下写的是相对偏移HAL库内部会自动加上SlaveStartFilterBank的值。如果HAL_CAN_ConfigFilter返回HAL_ERROR优先检查该组号是否超出当前通道可用的范围。4.4 双CAN初始化失败的高频原因排查如果HAL_CAN_Init或HAL_CAN_Start返回错误按顺序检查五项一是CAN1有没有同时使能并先启动二是APB1时钟是否超过42MHz超出后CAN位时序计算基准就错了三是两个hcan句柄的Instance是否接反四是过滤器组索引是否越界或重叠五是波特率参数中BS1加BS2是否至少为2tq。这五点在单CAN项目里不一定全部触发在双CAN测试中却是高频根因。另有一个容易忽略的坑CAN2启动失败时hcan2.ErrorCode可能标记为HAL_CAN_ERROR_NOT_INITIALIZED容易让人误以为初始化函数本身没执行实际原因是CAN1还未进入正常模式。5. 双CAN测试程序的验证技巧波形检查与Bus Off恢复5.1 在TXD/RXD上抓位时序核对2微秒位宽上位机显示“发送成功”不代表物理总线没有问题。把逻辑分析仪接到CAN1_TXD引脚触发方式选下降沿因为帧起始SOF是显性电平对应逻辑0。以500kbps为例单个位时间应为2微秒发送数据0xAA时波形应当是10101010的交替序列。如果测量到的位宽偏差超过5%或波形边沿明显抖动回到第三章的参数表检查BS1和BS2必要时把采样点调整为80%。双通道互测时可以在CAN2的RXD引脚上抓到几乎相同的帧与CAN1_TXD之间的延迟只有几十纳秒。若在CAN2_RXD上抓不到帧问题出在总线连接或收发器而不是CAN1的发送代码。5.2 主动制造Bus Off并编写恢复回调测试Bus Off恢复的常用方法是把CANH与CANL短接一到两秒造成持续显性电平错误。发送节点的TEC寄存器会不断累加超过255后进入Bus Off状态表现为TXD引脚持续高电平不再发送任何帧。HAL库通过错误回调上报该状态回调中可以对故障通道做重新初始化。void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan) { if (hcan-Instance CAN2 (hcan-ErrorCode HAL_CAN_ERROR_BOF) ! 0U) { HAL_CAN_Stop(hcan); HAL_CAN_Start(hcan); } }这段代码的作用是将Bus Off状态的CAN2重新拉回正常。HAL_CAN_Stop先停止控制器并清除错误状态HAL_CAN_Start再重新激活。也可以在Init结构体中把AutoBusOff设为ENABLE由硬件在总线空闲后自动恢复但回调中的日志记录仍然有用方便确认哪一路发生过故障。实际项目中我倾向AutoBusOffENABLE加回调记录兼顾自动恢复与可观测性。5.3 连续压测与负载率自检只跑一帧不能说明问题。把发送端改成分批次循环发送1000帧接收端累加收到的帧数最后比对计数并记录最大连续丢帧数。若计数一致说明双CAN链路稳定。也可以借助CAN上位机工具观察总线负载率是否与理论计算一致。例如每秒发送200帧、每帧约120位时理论负载率为200×120/500k 4.8%。实测值如果明显高于这个数字往往是有其他节点在不停重发错误帧这时优先检查终端电阻和电位差。测试程序的最后一步把上述波形、计数和负载率三个数据填入测试记录双CAN通道的验证才算完整。本文还有配套的精品资源点击获取
返回列表