网络优化网站温州网页制作
2026/4/17 0:38:31 网站建设 项目流程
网络优化网站,温州网页制作,wordpress 文章时间,网站推广工作职责详解针对STM32F1 系列旧版 CAN HAL 库#xff08;stm32f1xx_hal_can.c#xff0c;宏HAL_CAN_LEGACY_MODULE_ENABLED开启#xff09;#xff0c;全程贴合初学者视角#xff0c;从硬件连接、CubeMX 可视化配置、代码编写、实际测试一步步落地#xff0c;覆盖 ** 轮询模式收…详解针对STM32F1 系列旧版 CAN HAL 库stm32f1xx_hal_can.c宏HAL_CAN_LEGACY_MODULE_ENABLED开启全程贴合初学者视角从硬件连接、CubeMX 可视化配置、代码编写、实际测试一步步落地覆盖 ** 轮询模式收发入门必学、中断模式收发项目常用** 两个核心典型案例代码可直接复制使用同时结合你提供的 HAL 库源码解释关键函数的底层逻辑解决初学者 “配了不会用、写了收不到” 的核心问题。前置基础必看1. 库版本说明你提供的stm32f1xx_hal_can.c是STM32F1 专属的旧版 CAN HAL 库LegacySTM32 官方标注该库有 FIFO 管理限制但胜在 API 简单、初学者易上手适合入门新库修复了限制但 API 更复杂入门先掌握旧版再过渡即可。适用芯片STM32F103x6/xB/xE/xG、F105xC、F107xC如最常用的 F103ZET6/F103C8T6核心宏开启需在stm32f1xx_hal_conf.h中开启#define HAL_CAN_LEGACY_MODULE_ENABLED并关闭新版HAL_CAN_MODULE_ENABLED否则会报编译错误源码中已有该报错提示。2. CAN 硬件连接缺一不可初学者最易踩坑STM32 的 CAN 外设本身是CAN 控制器无法直接接 CAN 总线必须搭配CAN 收发器最常用TJA1050成本低、兼容性好硬件连接是 CAN 通信的基础接错则软件再对也无法通信。核心器件TJA1050 CAN 收发器模块供电多数 TJA1050 模块为5V 供电也有 3.3V 版按模块标注接需和 STM32 共 GND关键引脚连接TX/RX 交叉接核心要点TJA1050 引脚STM32F1 CAN 引脚功能说明TXDCAN_RX收发器 TX 接控制器 RX交叉连接RXDCAN_TX收发器 RX 接控制器 TX交叉连接VCC5V/3.3V模块供电GNDGND共地必须接CAN_HCAN 总线 H 端接外部 CAN 总线CAN_LCAN 总线 L 端接外部 CAN 总线120Ω 终端电阻CAN 总线两端需各接一个 120Ω 电阻TJA1050 模块多数自带跳线短接即可开启作用是消除总线信号反射短距离测试如板级测试可只开一个长距离总线必须两端都接。STM32F1 CAN 引脚硬件固定以 F103C8T6/F103ZET6 为例芯片型号CAN1_TXCAN1_RX备注STM32F103C8T6PA12PA11无 CAN2仅 CAN1STM32F103ZET6PA12/PD1PA11/PD0可重映射默认 PA11/PA12初学者直接用默认引脚无需重映射减少配置复杂度。3. CAN 关键基础概念入门只需记这 3 个1CAN 波特率计算核心必须匹配通信双方的波特率必须完全一致否则无法收发数据旧版 HAL 库中波特率由 CubeMX 直接配置初学者无需手动计算只需记典型值配置底层公式用于理解CAN波特率Prescaler×(1BS1BS2)APB1时钟频率​关键前提STM32F1 的 CAN 挂载在APB1 总线APB1 最大时钟频率为36MHzCubeMX 中配置系统时钟时APB1 预分频需设为 2若系统时钟 72MHzAPB1 时钟即为 36MHz典型配置500Kbps项目最常用Prescaler18BS11BS22 → 36M/(18×(112))500Kbps其他常用值1MbpsPrescaler9BS11BS22 → 36M/(9×4)1Mbps。2标准 ID / 扩展 ID标准 IDCAN_ID_STD11 位范围0~0x7FF入门首选足够满足绝大多数场景扩展 IDCAN_ID_EXT29 位范围0~0x1FFFFFFF用于多节点复杂总线入门暂不涉及。3CAN 过滤器必须配置否则收不到数据STM32 的 CAN 有过滤器组作用是筛选需要接收的 CAN 帧过滤掉无关帧减少 MCU 开销未配置过滤器CAN 无法接收任何数据初学者核心坑。入门配置过滤所有标准 ID接收所有帧方便测试无需筛选核心参数过滤器模式掩码模式CAN_FILTERMODE_IDMASK、过滤器尺度32 位CAN_FILTERSCALE_32BIT、FIFO 分配FIFO0。4. 工具准备硬件STM32F1 开发板、TJA1050 模块、CAN 分析仪USB 转 CAN如 CANalyst-II必备用于测试收发软件STM32CubeMX6.0、MDK-ARM Keil5支持 F1 系列、CAN 分析仪配套软件如 CANTest。通用前置步骤STM32CubeMX 配置两个案例共用所有 CAN 应用的基础是 CubeMX 配置一键生成初始化代码避开手动写寄存器初学者按步骤操作即可以下以STM32F103C8T6为例系统时钟 72MHzCAN1 波特率 500Kbps标准 ID接收所有帧。步骤 1新建项目选择芯片打开 CubeMX点击New Project搜索STM32F103C8T6选择对应芯片点击Start Project弹出Pinout Configuration页面默认即可点击OK。步骤 2配置系统时钟树核心F1 必须 72MHz点击左侧Clock Configuration进入时钟配置页面外部高速晶振HSE选择Crystal/Ceramic Resonator8MHz 晶振配置分频系数按图配置最终系统时钟 72MHzAPB136MHzPLLMUXHSEPLLMULx98M×972MAHB Prescaler/172MAPB1 Prescaler/236M满足 CAN 的 APB1 最大 36M 要求APB2 Prescaler/172M点击Apply完成时钟配置。步骤 3开启 CAN1 并配置核心参数回到Pinout Configuration左侧展开Connectivity点击CAN1模式选择Normal正常模式测试用回环模式Loopback无需硬件仅 MCU 自收自发后续可测试点击Parameter Settings配置 CAN 核心参数直接按以下值填500Kbps 波特率ModeNormal正常模式Prescaler18波特率分频系数SJW1tq同步跳转宽度默认BS11tq时间段 1BS22tq时间段 2其余 MCR 参数TTCM/ABOM/AWUM/NART/RFLM/TXFP全部选DISABLE入门默认ABOM 开启可自动总线恢复可选 ENABLE配置完成后CubeMX 会自动分配 CAN1 引脚PA11CAN_RXPA12CAN_TX无需手动配置。步骤 4配置 CAN 过滤器关键必须配仍在 CAN1 的Parameter Settings下拉找到Filter Configuration配置过滤器接收所有标准 ID入门首选Filter ModeMask Mode掩码模式Filter Scale32-bit32 位尺度Filter FIFO AssignmentFIFO 0分配到 FIFO0Filter Bank0过滤器组 0F103C8T6 有 14 个过滤器组选 0 即可Filter ActivationEnabled使能过滤器Filter ID Low/High0x0000/0x0000过滤 ID全 0 表示接收所有Filter Mask ID Low/High0x0000/0x0000掩码全 0 表示不筛选接收所有点击OK过滤器配置完成。步骤 5中断案例需加开启 CAN1 中断并配置 NVIC若做中断模式收发需开启 CAN1 的 FIFO0 中断并配置中断优先级左侧展开System Core点击NVIC找到CAN1 RX0 interrupts勾选Enabled开启 FIFO0 接收中断配置中断优先级入门无需严格配置按默认即可Preemption Priority1Sub Priority0点击Apply。步骤 6生成工程代码点击右上角Project Manager配置项目信息Project NameCAN_Demo自定义Project Location选择保存路径Toolchain/IDEMDK-ARM V5点击Code Generator勾选Generate peripheral initialization as .c/.h files分文件生成代码整洁点击GENERATE CODE生成完成后点击Open Project自动打开 Keil5 工程。案例 1轮询模式 CAN 收发入门必学最简单案例特点轮询模式查询模式通过HAL_CAN_Transmit()主动发送HAL_CAN_Receive()主动查询是否有数据接收无需中断代码最简单易理解适用场景简单的单节点通信、低频率数据收发如每秒发送一次数据核心函数从你提供的 HAL 库源码中调用HAL_CAN_Init()初始化、HAL_CAN_ConfigFilter()过滤器配置CubeMX 已生成、HAL_CAN_Transmit()轮询发送、HAL_CAN_Receive()轮询接收。代码编写Keil5 中修改仅需改main.c步骤 1定义 CAN 收发结构体全局 / 局部均可全局更方便在main.c的用户代码区 1/* USER CODE BEGIN 0 */定义 CAN 发送和接收结构体这两个结构体是旧版 CAN 库的核心源码中所有收发函数都基于它们/* USER CODE BEGIN 0 */ #include stdio.h // 若用串口打印需加 // CAN发送结构体CanTxMsgTypeDef是旧版库专属 CanTxMsgTypeDef TxMsg; // CAN接收结构体CanRxMsgTypeDef是旧版库专属 CanRxMsgTypeDef RxMsg; // 串口重定向可选用于打印接收数据方便调试 int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t*)ch, 1, HAL_MAX_DELAY); return ch; } /* USER CODE END 0 */若用串口打印需在 CubeMX 中开启 USART1配置波特率 115200引脚 PA9/PA10CubeMX 会自动生成huart1句柄。步骤 2初始化 CAN 发送结构体main 函数中MX_CAN1_Init 之后在main()函数中MX_CAN1_Init();之后的用户代码区 2初始化发送参数标准 ID8 字节数据数据帧int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ // 1. 系统初始化CubeMX自动生成 HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_CAN1_Init(); // CAN1初始化含过滤器配置 /* USER CODE BEGIN 2 */ // 初始化CAN发送结构体 TxMsg.StdId 0x123; // 标准ID自定义0~0x7FF通信双方需一致 TxMsg.IDE CAN_ID_STD; // 标准ID模式 TxMsg.RTR CAN_RTR_DATA;// 数据帧非远程帧 TxMsg.DLC 8; // 数据长度0~8这里发8字节 // 初始化发送数据自定义如0x01,0x02,...0x08 TxMsg.Data[0] 0x01; TxMsg.Data[1] 0x02; TxMsg.Data[2] 0x03; TxMsg.Data[3] 0x04; TxMsg.Data[4] 0x05; TxMsg.Data[5] 0x06; TxMsg.Data[6] 0x07; TxMsg.Data[7] 0x08; // 关联CAN句柄的发送结构体旧版库核心必须将TxMsg赋值给hcan1.pTxMsg hcan1.pTxMsg TxMsg; /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ // ************************** CAN轮询发送 ************************** // HAL_CAN_Transmit(Can句柄, 超时时间)超时时间HAL_MAX_DELAY表示一直等待 if(HAL_CAN_Transmit(hcan1, HAL_MAX_DELAY) HAL_OK) { printf(CAN发送成功数据0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\r\n, TxMsg.Data[0],TxMsg.Data[1],TxMsg.Data[2],TxMsg.Data[3], TxMsg.Data[4],TxMsg.Data[5],TxMsg.Data[6],TxMsg.Data[7]); // 发送后修改数据可选方便观察 for(uint8_t i0; i8; i) { TxMsg.Data[i]; if(TxMsg.Data[i] 0xFF) TxMsg.Data[i] 0x00; } } else { printf(CAN发送失败\r\n); } // ************************** CAN轮询接收 ************************** // HAL_CAN_Receive(Can句柄, FIFO编号, 超时时间)FIFO0过滤器分配的超时10ms if(HAL_CAN_Receive(hcan1, CAN_FIFO0, 10) HAL_OK) { // 接收成功打印数据RxMsg会被HAL库自动填充 printf(CAN接收成功ID0x%03X数据长度%d数据, RxMsg.StdId, RxMsg.DLC); for(uint8_t i0; iRxMsg.DLC; i) { printf(0x%02X , RxMsg.Data[i]); } printf(\r\n); } // 延时1秒降低收发频率 HAL_Delay(1000); } /* USER CODE END 3 */ }代码核心解释结合 HAL 库源码CanTxMsgTypeDef/CanRxMsgTypeDef旧版 CAN 库的专属收发结构体源码中HAL_CAN_Transmit()/HAL_CAN_Receive()均基于该结构体操作核心成员StdId标准 ID11 位IDEID 类型CAN_ID_STD/CAN_ID_EXTRTR帧类型CAN_RTR_DATA数据帧 /CAN_RTR_REMOTE远程帧DLC数据长度0~8Data[8]收发的 8 字节数据hcan1.pTxMsg TxMsg源码中HAL_CAN_Transmit()会通过hcan-pTxMsg获取发送数据必须赋值否则发送失败初学者核心坑HAL_CAN_Transmit(hcan1, HAL_MAX_DELAY)源码中该函数会先查询发送邮箱是否为空然后填充数据并请求发送超时时间HAL_MAX_DELAY表示一直等待直到发送成功HAL_CAN_Receive(hcan1, CAN_FIFO0, 10)源码中该函数会查询 FIFO0 是否有未处理的帧有则填充RxMsg并释放 FIFO超时 10ms 表示 10ms 内无数据则返回超时不阻塞主循环过滤器分配 FIFO0接收时必须指定CAN_FIFO0与 CubeMX 中过滤器配置的 FIFO 一致否则收不到数据。硬件测试步骤按前文连接硬件STM32 PA11/PA12 → TJA1050TX/RX 交叉接TJA1050 开启 120Ω 终端电阻5V 供电共 GNDTJA1050 的 CAN_H/CAN_L → CAN 分析仪的 CAN_H/CAN_LCAN 分析仪接电脑打开配套软件CANTestCAN 分析仪配置波特率500Kbps标准 ID打开总线下载代码到 STM32打开串口助手波特率 115200同时观察 CAN 分析仪和串口助手STM32 每秒发送一帧数据CAN 分析仪可收到串口助手打印 “发送成功”在 CAN 分析仪中手动发送标准 ID0x123的 8 字节数据STM32 可接收串口助手打印 “接收成功”。回环模式测试无需硬件快速验证代码若没有 CAN 分析仪可将 CubeMX 中 CAN 的模式改为Loopback回环模式STM32 会自收自发无需 TJA1050 和 CAN 分析仪下载代码后串口助手会同时打印 “发送成功” 和 “接收成功”快速验证代码正确性。案例 2中断模式 CAN 收发项目常用非阻塞案例特点中断模式发送完成 / 接收数据时触发中断通过回调函数处理收发逻辑主循环无阻塞CPU 可处理其他任务是实际项目的主流用法核心函数HAL_CAN_Receive_IT()开启接收中断、HAL_CAN_Transmit_IT()中断发送以及回调函数HAL_CAN_RxCpltCallback()接收完成回调、HAL_CAN_TxCpltCallback()发送完成回调关键旧版 CAN 库的中断接收需在回调函数中重新开启中断否则只能接收一帧数据初学者核心坑。代码编写基于案例 1 的 CubeMX 配置仅改main.c开启了 CAN1 RX0 中断步骤 1定义全局变量和收发结构体中断中需访问建议全局/* USER CODE BEGIN 0 */ #include stdio.h // CAN收发结构体全局中断回调中访问 CanTxMsgTypeDef TxMsg; CanRxMsgTypeDef RxMsg; // 串口重定向 int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t*)ch, 1, HAL_MAX_DELAY); return ch; } // 自定义发送标志可选按键触发发送模拟实际项目 uint8_t CanSendFlag 0; /* USER CODE END 0 */步骤 2main 函数初始化 开启接收中断 主循环处理int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ // 系统初始化CubeMX自动生成 HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_CAN1_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ // 初始化CAN发送结构体 TxMsg.StdId 0x123; TxMsg.IDE CAN_ID_STD; TxMsg.RTR CAN_RTR_DATA; TxMsg.DLC 8; TxMsg.Data[0] 0x01; TxMsg.Data[1] 0x02; TxMsg.Data[2] 0x03; TxMsg.Data[3] 0x04; TxMsg.Data[4] 0x05; TxMsg.Data[5] 0x06; TxMsg.Data[6] 0x07; TxMsg.Data[7] 0x08; // 关联发送结构体 hcan1.pTxMsg TxMsg; // 关联接收结构体旧版库hcan1.pRxMsg指向FIFO0的接收结构体 hcan1.pRxMsg RxMsg; // 开启CAN1 FIFO0接收中断核心中断接收的入口 if(HAL_CAN_Receive_IT(hcan1, CAN_FIFO0) ! HAL_OK) { printf(开启CAN接收中断失败\r\n); } else { printf(开启CAN接收中断成功等待接收数据...\r\n); } // 可选配置按键GPIO如PA0下降沿触发用于按键触发发送 // 此处省略GPIO配置可在CubeMX中开启PA0为EXTI0中断按键按下置位CanSendFlag /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ // 按键触发CAN中断发送模拟实际项目的外部触发 if(CanSendFlag 1) { CanSendFlag 0; // 清标志 // 中断发送HAL_CAN_Transmit_IT() if(HAL_CAN_Transmit_IT(hcan1) HAL_OK) { printf(CAN中断发送请求已提交\r\n); // 预修改下一次发送的数据 for(uint8_t i0; i8; i) { TxMsg.Data[i]; if(TxMsg.Data[i] 0xFF) TxMsg.Data[i] 0x00; } } else { printf(CAN中断发送请求失败\r\n); } } // 主循环处理其他任务如LED闪烁证明无阻塞 HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); HAL_Delay(500); } /* USER CODE END 3 */ }步骤 3重写 CAN 中断回调函数核心用户自定义逻辑在main.c的用户代码区 4重写 HAL 库的弱回调函数__weak修饰源码中为空用户可重写中断触发后会自动调用这些函数/* USER CODE BEGIN 4 */ // ************************** CAN接收完成回调函数 ************************** // 接收一帧数据后触发由HAL_CAN_IRQHandler()调用源码中可见 void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan) { if(hcan-Instance CAN1) { // 接收成功打印数据RxMsg已被HAL库填充 printf(CAN中断接收成功ID0x%03X长度%d数据, RxMsg.StdId, RxMsg.DLC); for(uint8_t i0; iRxMsg.DLC; i) { printf(0x%02X , RxMsg.Data[i]); } printf(\r\n); // 核心重新开启CAN接收中断 // 旧版CAN库的中断接收为「单次中断」接收一帧后需重新开启否则无法接收下一帧 if(HAL_CAN_Receive_IT(hcan1, CAN_FIFO0) ! HAL_OK) { printf(重新开启CAN接收中断失败\r\n); } } } // ************************** CAN发送完成回调函数 ************************** // 发送一帧数据后触发由HAL_CAN_IRQHandler()调用源码中可见 void HAL_CAN_TxCpltCallback(CAN_HandleTypeDef* hcan) { if(hcan-Instance CAN1) { printf(CAN中断发送完成\r\n); } } // ************************** CAN错误回调函数 ************************** // CAN通信出错时触发如总线掉、波特率不匹配 void HAL_CAN_ErrorCallback(CAN_HandleTypeDef* hcan) { if(hcan-Instance CAN1) { printf(CAN通信错误错误码0x%08X\r\n, HAL_CAN_GetError(hcan)); // 重新开启接收中断 HAL_CAN_Receive_IT(hcan1, CAN_FIFO0); } } // 可选按键外部中断回调函数PA0触发发送 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin GPIO_PIN_0) { CanSendFlag 1; // 置位发送标志主循环处理 } } /* USER CODE END 4 */代码核心解释结合 HAL 库源码HAL_CAN_Receive_IT(hcan1, CAN_FIFO0)源码中该函数会开启 CAN1 的 FIFO0 中断配置好中断优先级后有数据接收时会触发CAN1 RX0 interrupts并调用HAL_CAN_IRQHandler()中断服务函数HAL_CAN_IRQHandler()源码中该函数是 CAN 的中断总处理函数会判断中断类型接收 / 发送 / 错误然后调用对应的私有函数如CAN_Receive_IT()最终触发用户重写的回调函数重新开启接收中断旧版 CAN 库的HAL_CAN_Receive_IT()是单次中断接收一帧数据后会自动关闭中断必须在回调函数中重新调用该函数否则无法接收下一帧初学者最大坑HAL_CAN_Transmit_IT(hcan1)源码中该函数会提交发送请求发送完成后触发中断调用HAL_CAN_TxCpltCallback()主循环无需等待实现非阻塞发送弱回调函数源码中HAL_CAN_RxCpltCallback()/HAL_CAN_TxCpltCallback()被__weak修饰用户在main.c中重写后编译器会优先使用用户的函数这是 HAL 库的核心设计思想。测试步骤硬件连接同案例 1CAN 分析仪配置 500Kbps标准 ID下载代码到 STM32串口助手打印 “开启 CAN 接收中断成功”LED 开始闪烁证明主循环无阻塞CAN 分析仪发送数据向 STM32 发送标准 ID0x123的 8 字节数据串口助手立即打印 “中断接收成功”且能连续接收回调中重新开启了中断按键触发发送按下 PA0 按键STM32 通过中断发送数据CAN 分析仪可收到串口助手打印 “发送请求已提交”→“发送完成”若 CAN 总线出错如断开 CAN_H串口助手会打印错误码触发HAL_CAN_ErrorCallback()。案例 3CAN 回环模式测试无硬件快速验证代码若没有 TJA1050 和 CAN 分析仪可使用CAN 回环模式LoopbackSTM32 内部自收自发无需任何外部硬件快速验证 CAN 配置和代码的正确性CubeMX 中修改 CAN 模式为LoopbackNormal→Loopback重新生成代码用案例 2 的中断代码无需硬件连接直接下载按下按键触发发送STM32 会自己接收自己发送的数据串口助手同时打印 “发送完成” 和 “接收成功”快速验证代码无问题。初学者常见问题与避坑技巧按出现频率排序问题 1CAN 无法发送 / 接收无任何反应原因 解决方案未接 CAN 收发器TJA1050STM32 的 CAN 是控制器必须接收发器才能接总线TX/RX 未交叉接TJA1050 的 TXD 接 STM32 的 CAN_RXRXD 接 CAN_TX交叉是核心未开启 120Ω 终端电阻短接 TJA1050 的终端电阻跳线波特率不匹配通信双方波特率必须完全一致如 STM32500KCAN 分析仪也必须 500K未配置 CAN 过滤器CubeMX 中未配置过滤器或过滤器参数错误CAN 无法接收任何数据hcan1.pTxMsg未赋值旧版库必须将发送结构体赋值给hcan-pTxMsg否则发送失败。问题 2CAN 只能接收一帧数据后续无反应原因 解决方案中断模式下未重新开启接收中断旧版 CAN 库的HAL_CAN_Receive_IT()是单次中断接收一帧后必须在HAL_CAN_RxCpltCallback()中重新调用该函数才能接收下一帧案例 2 已处理。问题 3CAN 发送成功但接收不到数据原因 解决方案过滤器配置错误如过滤器模式选了列表模式或掩码非 0x0000导致过滤掉了数据入门直接用掩码模式 全 0 掩码接收所有帧接收时 FIFO 编号错误过滤器分配到 FIFO0接收时却用了 FIFO1改回 CAN_FIFO0回环模式未关闭若 CubeMX 中是 Loopback 模式外部 CAN 分析仪发送的数据无法被接收改回 Normal 模式。问题 4Keil 编译报错提示CanTxMsgTypeDef未定义原因 解决方案未开启旧版 CAN 库宏在stm32f1xx_hal_conf.h中开启#define HAL_CAN_LEGACY_MODULE_ENABLED并关闭#define HAL_CAN_MODULE_ENABLED否则冲突。问题 5中断收发时主循环阻塞原因 解决方案回调函数中执行了耗时操作中断回调函数应简洁高效仅做数据接收 / 标志置位耗时操作如复杂计算、延时放到主循环中处理。关键函数总结基于你提供的 HAL 库源码旧版stm32f1xx_hal_can.c的核心函数初学者只需掌握以下几个即可应对绝大多数场景函数名功能适用模式HAL_CAN_Init()CAN 外设初始化CubeMX 自动生成所有HAL_CAN_ConfigFilter()CAN 过滤器配置CubeMX 自动生成所有HAL_CAN_Transmit()轮询发送阻塞直到发送完成 / 超时轮询HAL_CAN_Receive()轮询接收阻塞直到接收完成 / 超时轮询HAL_CAN_Transmit_IT()中断发送提交请求后立即返回非阻塞中断HAL_CAN_Receive_IT()开启中断接收有数据时触发回调中断HAL_CAN_IRQHandler()CAN 中断总处理函数CubeMX 自动生成无需修改中断HAL_CAN_RxCpltCallback()接收完成回调用户重写中断HAL_CAN_TxCpltCallback()发送完成回调用户重写中断HAL_CAN_ErrorCallback()错误回调用户重写所有总结STM32F1xx_hal_can旧版的入门核心是先掌握硬件连接 CubeMX 配置再从轮询模式入手最后过渡到中断模式初学者只需牢记以下 3 个核心要点硬件核心STM32 CAN 控制器必须搭配 TJA1050 收发器TX/RX 交叉接开启 120Ω 终端电阻配置核心CubeMX 中必须配置时钟树APB136MHz CAN 波特率 过滤器接收所有帧过滤器是接收数据的前提代码核心轮询模式定义CanTxMsgTypeDef/CanRxMsgTypeDef赋值hcan-pTxMsg调用HAL_CAN_Transmit()/HAL_CAN_Receive()中断模式开启 CAN_RX0 中断重写回调函数接收完成后必须重新开启中断实现连续接收。掌握这三个案例后可轻松过渡到实际项目如多节点 CAN 通信、扩展 ID 使用、过滤器精准筛选 ID 等后续只需在现有代码基础上稍作修改即可。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询