ARTICLE DETAIL

资讯详情

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

25.STM32H743 FDCAN

25.STM32H743 FDCAN FDCANFlexible Data-Rate CAN是CAN总线的升级版本兼容传统CAN 2.0同时支持更高的传输速率数据段最高8Mbps和更大的单帧数据量64字节传统CAN仅8字节。STM32H743内置2个独立的FDCAN外设FDCAN1/FDCAN2支持CAN FD协议是工业控制、汽车电子、物联网等场景中实现高速、可靠通信的核心外设。一、STM32H743 FDCAN 核心硬件特性STM32H743的FDCAN模块属于APB1/APB2总线外设FDCAN1挂APB2FDCAN2挂APB1核心特性如下特性说明协议兼容支持CAN FDISO 11898-1:2015、传统CAN 2.0A/B可配置为CAN FD或CAN 2.0模式传输速率仲裁段Arbitration Phase≤1Mbps兼容传统CAN数据段Data Phase≤8Mbps单帧数据长度传统CAN08字节CAN FD064字节通信模式正常模式、环回模式自测、静默模式仅收不发滤波机制32个可配置滤波器掩码/列表模式支持标准ID11位/扩展ID29位过滤中断支持接收完成、发送完成、错误中断、总线离线中断等数据传输方式邮箱发送3个发送邮箱、FIFO接收2个接收FIFO总线容错支持总线错误自动恢复、离线自动重连典型应用工业现场总线通信、汽车ECU通信、智能设备组网、多节点数据交互FDCAN 核心信号信号名称功能典型引脚STM32H743备注FDCAN_TX发送线PB9FDCAN1/ PB13FDCAN2需外接CAN收发器如TJA1050转差分信号FDCAN_RX接收线PB8FDCAN1/ PB12FDCAN2同上关键FDCAN_TX/RX为TTL电平必须外接CAN收发器如TJA1050、SN65HVD230转换为CAN总线的差分电平CAN_H/CAN_L否则无法通信。二、FDCAN 通信原理FDCAN的通信本质是“多节点通过CAN总线以广播方式收发数据帧”核心概念和流程如下1. 核心概念仲裁段/数据段仲裁段传输帧ID用于总线仲裁优先级速率≤1Mbps兼容传统CAN数据段传输实际数据CAN FD模式下速率可提升至8Mbps帧类型传统CAN帧ID11/29位 数据0~8字节CAN FD帧ID 数据0~64字节 BRS位速率切换 ESI位错误状态滤波器STM32通过滤波器筛选需要接收的帧如仅接收ID为0x123的帧无关帧直接丢弃邮箱/FIFO发送邮箱存储待发送的帧最多3个发送完成后清空接收FIFO存储接收到的帧最多2个读取后需释放。2. 通信流程初始化配置FDCAN时钟、引脚、波特率仲裁段/数据段配置滤波器如接收ID为0x123的帧启用FDCAN外设和中断可选。发送数据填充帧结构体ID、数据长度、数据内容、帧类型将帧写入发送邮箱硬件自动发送发送完成后触发中断可选。接收数据总线上的帧经滤波器筛选后存入接收FIFO触发接收中断可选读取FIFO中的帧数据释放接收FIFO准备接收下一帧。波特率计算关键FDCAN波特率由“预分频器时间段”决定公式波特率 FDCAN时钟频率 / (预分频器 × (时间段1 时间段2 1))示例常用配置仲裁段1MbpsFDCAN时钟80MHz预分频器8时间段16时间段23 → 80/(8×(631))1Mbps数据段4Mbps预分频器2时间段16时间段23 → 80/(2×(631))4Mbps。三、STM32H743 FDCAN 配置步骤时钟配置步骤3HAL库核心API新手必记函数功能HAL_FDCAN_Init()初始化FDCAN外设核心函数HAL_FDCAN_ConfigFilter()配置滤波器筛选接收帧HAL_FDCAN_AddMessageToTxFifo()将帧写入发送FIFO发送数据HAL_FDCAN_GetRxMessage()从接收FIFO读取帧接收数据HAL_FDCAN_ActivateNotification()启用中断通知接收/发送完成HAL_FDCAN_GetState()获取FDCAN状态就绪/忙/错误HAL_FDCAN_GetError()获取FDCAN错误码常用帧结构体FDCAN_TxHeaderTypeDef tx_header; // 发送帧头 FDCAN_RxHeaderTypeDef rx_header; // 接收帧头 uint8_t tx_data[64]; // 发送数据缓冲区 uint8_t rx_data[64]; // 接收数据缓冲区四、实战代码示例示例1FDCAN初始化环回模式自测无外设也能测环回模式下发送的帧会被自身接收验证FDCAN配置正确性#include stm32h7xx_hal.h #include stdio.h #include string.h /* FDCAN句柄CubeMX自动生成 */ FDCAN_HandleTypeDef hfdcan1; /* USART1句柄串口输出115200 8N1 */ UART_HandleTypeDef huart1; /* 帧结构体 */ FDCAN_TxHeaderTypeDef fdcan_tx_header; FDCAN_RxHeaderTypeDef fdcan_rx_header; uint8_t fdcan_tx_buf[8] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; uint8_t fdcan_rx_buf[8]; /* 错误处理函数 */ void Error_Handler(void) { while(1) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // LED快闪表示错误 HAL_Delay(200); } } /** * brief 重定向printf到串口 */ int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t*)ch, 1, 10); return ch; } /** * brief FDCAN中断回调函数接收完成 */ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) { if((RxFifo0ITs FDCAN_IT_RX_FIFO0_NEW_MESSAGE) ! RESET) { // 读取接收FIFO中的帧 if(HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, fdcan_rx_header, fdcan_rx_buf) HAL_OK) { printf(Received Frame: ID0x%X, Len%d, Data, fdcan_rx_header.Identifier, fdcan_rx_header.DataLength); for(uint8_t i0; ifdcan_rx_header.DataLength; i) { printf(%02X , fdcan_rx_buf[i]); } printf(\r\n); HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // LED闪一下表示接收完成 } // 重新启用接收通知 HAL_FDCAN_ActivateNotification(hfdcan, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0); } } int main(void) { /* 初始化HAL库、系统时钟、GPIOLED、FDCAN1、USART1 */ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); // PA5为LED推挽输出 MX_FDCAN1_Init(); // FDCAN1初始化环回模式 MX_USART1_UART_Init(); // 串口初始化 HAL_StatusTypeDef status; printf(STM32H743 FDCAN Loopback Test\r\n); // 1. 配置发送帧头 fdcan_tx_header.Identifier 0x123; // 帧ID fdcan_tx_header.IdType FDCAN_STANDARD_ID; // 标准ID11位 fdcan_tx_header.TxFrameType FDCAN_DATA_FRAME; // 数据帧 fdcan_tx_header.DataLength FDCAN_DLC_BYTES_8; // 数据长度8字节 fdcan_tx_header.ErrorStateIndicator FDCAN_ESI_ACTIVE; fdcan_tx_header.BitRateSwitch FDCAN_BRS_ON; // 启用速率切换CAN FD fdcan_tx_header.FDFormat FDCAN_FD_CAN; // CAN FD模式 fdcan_tx_header.TxEventFifoControl FDCAN_NO_TX_EVENTS; fdcan_tx_header.MessageMarker 0; // 2. 启用接收中断通知 if(HAL_FDCAN_ActivateNotification(hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) ! HAL_OK) { Error_Handler(); } // 3. 发送帧环回模式下会被自身接收 printf(Sending Frame: ID0x123, Len8, Data01 02 03 04 05 06 07 08\r\n); status HAL_FDCAN_AddMessageToTxFifoQ(hfdcan1, fdcan_tx_header, fdcan_tx_buf); if(status ! HAL_OK) { printf(Send Frame Error: %d\r\n, status); Error_Handler(); } while (1) { // 每隔1秒重发一次 HAL_Delay(1000); HAL_FDCAN_AddMessageToTxFifoQ(hfdcan1, fdcan_tx_header, fdcan_tx_buf); } }示例2FDCAN正常模式通信双节点两个STM32H743节点通过CAN总线通信节点1发送数据节点2接收数据节点1发送端代码int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_FDCAN1_Init(); // 正常模式非环回 MX_USART1_UART_Init(); printf(FDCAN Transmitter Node\r\n); // 配置发送帧头同示例1 fdcan_tx_header.Identifier 0x123; fdcan_tx_header.IdType FDCAN_STANDARD_ID; fdcan_tx_header.TxFrameType FDCAN_DATA_FRAME; fdcan_tx_header.DataLength FDCAN_DLC_BYTES_8; fdcan_tx_header.BitRateSwitch FDCAN_BRS_ON; fdcan_tx_header.FDFormat FDCAN_FD_CAN; while (1) { // 填充发送数据递增 for(uint8_t i0; i8; i) { fdcan_tx_buf[i]; } // 发送帧 printf(Send Data: ); for(uint8_t i0; i8; i) { printf(%02X , fdcan_tx_buf[i]); } printf(\r\n); HAL_FDCAN_AddMessageToTxFifoQ(hfdcan1, fdcan_tx_header, fdcan_tx_buf); HAL_Delay(1000); } }节点2接收端代码int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_FDCAN1_Init(); // 正常模式 MX_USART1_UART_Init(); printf(FDCAN Receiver Node\r\n); // 启用接收中断 HAL_FDCAN_ActivateNotification(hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0); while (1) { // 主循环无需操作中断处理接收 HAL_Delay(100); } } // 接收中断回调函数同示例1 void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) { if((RxFifo0ITs FDCAN_IT_RX_FIFO0_NEW_MESSAGE) ! RESET) { HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, fdcan_rx_header, fdcan_rx_buf); printf(Received Data: ); for(uint8_t i0; ifdcan_rx_header.DataLength; i) { printf(%02X , fdcan_rx_buf[i]); } printf(\r\n); HAL_FDCAN_ActivateNotification(hfdcan, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0); HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); } }示例3FDCAN 64字节大数据传输CAN FD特性利用CAN FD的64字节数据长度传输大尺寸数据int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_FDCAN1_Init(); MX_USART1_UART_Init(); uint8_t big_tx_data[64]; // 填充64字节测试数据 for(uint8_t i0; i64; i) { big_tx_data[i] i; } // 配置发送帧头64字节 FDCAN_TxHeaderTypeDef big_tx_header; big_tx_header.Identifier 0x456; big_tx_header.IdType FDCAN_STANDARD_ID; big_tx_header.TxFrameType FDCAN_DATA_FRAME; big_tx_header.DataLength FDCAN_DLC_BYTES_64; // 64字节 big_tx_header.BitRateSwitch FDCAN_BRS_ON; big_tx_header.FDFormat FDCAN_FD_CAN; printf(FDCAN 64 Bytes Data Test\r\n); while (1) { // 发送64字节数据 HAL_FDCAN_AddMessageToTxFifoQ(hfdcan1, big_tx_header, big_tx_data); printf(Sent 64 Bytes Data: 00~3F\r\n); HAL_Delay(2000); } }五、常见问题与避坑指南1. FDCAN初始化失败HAL_FDCAN_Init返回错误原因1时钟配置错误FDCAN时钟源未配置如PCLK20或预分频器设置为0→ 解决CubeMX中确保FDCAN时钟源为PCLK280MHz预分频器≥1原因2引脚配置错误FDCAN_TX/RX引脚未设为Alternate Function模式或引脚号错误→ 解决核对引脚FDCAN1PB8/RX、PB9/TX确保模式为AF9FDCAN原因3总线未初始化FDCAN外设未进入正常模式或仲裁段/数据段参数冲突→ 解决初始化后调用HAL_FDCAN_Start(hfdcan1)启动FDCAN。2. 发送帧无响应接收不到数据原因1未接CAN收发器/终端电阻FDCAN_TX/RX直接接CAN总线无TJA1050转换差分电平或总线未接120Ω终端电阻→ 解决必须外接CAN收发器且CAN_H/CAN_L之间接120Ω电阻原因2波特率不匹配发送端和接收端波特率配置不同如一端1Mbps一端500kbps→ 解决双节点波特率参数预分频器、时间段1/2必须完全一致原因3滤波器配置错误接收端滤波器ID/掩码设置错误过滤掉了目标帧→ 解决测试时可禁用滤波器接收所有帧或确保掩码为全1全匹配原因4CAN FD模式未启用帧头的FDFormat设为FDCAN_CLASSIC_CAN无法传输64字节数据→ 解决CAN FD模式需设FDFormatFDCAN_FD_CANBRSFDCAN_BRS_ON。3. 中断不触发/回调函数无响应原因1未启用中断通知未调用HAL_FDCAN_ActivateNotification()启用接收/发送中断→ 解决发送前启用对应中断如FDCAN_IT_RX_FIFO0_NEW_MESSAGE原因2NVIC中断未开启CubeMX中未勾选FDCAN中断或优先级过低→ 解决NVIC Settings中启用FDCAN中断优先级设为High原因3回调函数名错误未实现HAL_FDCAN_RxFifo0Callback()或函数参数错误→ 解决确保回调函数名与HAL库一致参数为FDCAN_HandleTypeDef *hfdcan。4. 仅能发送8字节无法发送64字节原因1帧头数据长度配置错误DataLength设为FDCAN_DLC_BYTES_88字节而非FDCAN_DLC_BYTES_64→ 解决CAN FD模式下数据长度可设为FDCAN_DLC_BYTES_16/32/64原因2未启用BRS位BitRateSwitch设为FDCAN_BRS_OFF无法切换到高速数据段→ 解决启用BRS位FDCAN_BRS_ON才能使用CAN FD的高速和64字节特性原因3对方节点不支持CAN FD接收端为传统CAN节点仅支持8字节无法接收64字节帧→ 解决双节点均配置为CAN FD模式。5. 总线错误/离线Error State原因1总线短路/断路CAN_H/CAN_L短路或总线未接电源→ 解决用万用表测CAN_H≈3.5V、CAN_L≈1.5V检查接线原因2发送频率过高连续发送帧导致总线负载率80%触发错误→ 解决降低发送频率如≥10ms/帧或优化通信协议原因3节点地址冲突多个节点发送相同ID的帧总线仲裁失败→ 解决为每个节点分配唯一的帧ID或采用应答机制。六、调试顺序1. 入门步骤第一步环回模式自测验证FDCAN配置和代码正确性无需外设第二步外接CAN收发器实现单节点发送PC CAN分析仪接收验证硬件第三步双STM32节点通信实现8字节数据收发第四步拓展到64字节CAN FD数据传输第五步添加滤波器、错误处理、总线重连机制。2. 调试技巧CAN分析仪调试用USB-CAN分析仪如周立功USBCAN连接CAN总线抓取帧数据验证发送/接收是否正确示波器调试测CAN_H/CAN_L电平正常CAN_H≈3.5VCAN_L≈1.5V发送帧时应有电平跳变分步测试先测试传统CAN 8字节通信再切换到CAN FD 64字节先禁用滤波器接收所有帧再逐步配置滤波器错误日志打印HAL_FDCAN_GetError()的错误码定位总线错误原因如位错误、填充错误。3. 重点注意事项终端电阻CAN总线两端必须接120Ω终端电阻靠近总线首尾节点否则信号反射导致通信失败波特率一致性所有节点的仲裁段/数据段波特率必须完全一致否则无法通信数据对齐64字节数据缓冲区需按32位对齐用__attribute__((aligned(4)))修饰容错处理添加总线错误检测和自动重连机制如离线后重新初始化FDCAN。4. 实际应用练习工业通信实现多节点传感器数据采集温度、压力通过FDCAN上传到主节点汽车电子模拟ECU通信发送/接收汽车CAN总线帧如车速、转速容错通信添加帧重传、校验和机制确保数据传输可靠性协议适配适配CANopen协议工业常用实现标准化通信。七、实际调试使用can分析仪此CAN转USB使用的是自定义USB类。需要安装驱动安装过程略。安装完毕后配置上位机软件这里使用正点原子H7开发板使用自带的例程即可。按下wakeup键切换到normal模式。注意此开发板的CAN和USB复用所以需要将跳线帽跳到CAN模式下。按下KEY0后上位机软件监控到CAN数据。
返回列表