#include "hw_can.h" #include "main.h" #include "FreeRTOS.h" #include "task.h" void hwCanInit(void) { CAN_FilterTypeDef filter; /* 16-bit ID List 滤波: 每个 filter bank 容纳 4 个标准帧 ID * 标准帧 ID 必须左移 5 位 (STID 在寄存器位[15:5]) * * 本设备需接收 0x180-0x18A 全部 ID (多设备升级寻址范围) * 0x180-0x18A = 11 个 ID, 需 3 个 bank (12 槽位) * Bank0: 0x180-0x183 Bank1: 0x184-0x187 Bank2: 0x188-0x18B * 具体哪个ID是本设备的, 由软件层 IAP_CAN_RX_ID 精确过滤 */ /* Bank 0: 0x180-0x183 → FIFO0 */ filter.FilterIdHigh = 0x180U << 5; /* ID0 = 0x180 */ filter.FilterIdLow = 0x181U << 5; /* ID1 = 0x181 */ filter.FilterMaskIdHigh = 0x182U << 5; /* ID2 = 0x182 */ filter.FilterMaskIdLow = 0x183U << 5; /* ID3 = 0x183 */ filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; filter.FilterBank = 0; filter.FilterMode = CAN_FILTERMODE_IDLIST; /* ID List 方式 */ filter.FilterScale = CAN_FILTERSCALE_16BIT; /* 16位 */ filter.FilterActivation = CAN_FILTER_ENABLE; /* 使能 */ filter.SlaveStartFilterBank = 14; /* 全部分配给CAN1 */ if (HAL_CAN_ConfigFilter(&hcan, &filter) != HAL_OK) { } /* Bank 1: 0x184-0x187 → FIFO0 */ filter.FilterIdHigh = 0x184U << 5; /* ID0 = 0x184 */ filter.FilterIdLow = 0x185U << 5; /* ID1 = 0x185 */ filter.FilterMaskIdHigh = 0x186U << 5; /* ID2 = 0x186 */ filter.FilterMaskIdLow = 0x187U << 5; /* ID3 = 0x187 */ filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; filter.FilterBank = 1; HAL_CAN_ConfigFilter(&hcan, &filter); /* Bank 2: 0x188-0x18B → FIFO1 (0x18A 为寻址上限, 0x18B 预留) */ filter.FilterIdHigh = 0x188U << 5; /* ID0 = 0x188 */ filter.FilterIdLow = 0x189U << 5; /* ID1 = 0x189 */ filter.FilterMaskIdHigh = 0x18AU << 5; /* ID2 = 0x18A */ filter.FilterMaskIdLow = 0x18BU << 5; /* ID3 = 0x18B (预留) */ filter.FilterFIFOAssignment = CAN_FILTER_FIFO1; filter.FilterBank = 2; HAL_CAN_ConfigFilter(&hcan, &filter); HAL_CAN_Start(&hcan); /* 使能接收 FIFO 中断 + 发送完成中断 */ HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_RX_FIFO1_MSG_PENDING | CAN_IT_TX_MAILBOX_EMPTY); } uint8_t hwCanSend(uint32_t id, uint8_t *data, uint8_t dlc) { #if 1 CAN_TxHeaderTypeDef tx_header; uint32_t tx_mailbox; uint32_t wait = 20000; /* 无空闲发送邮箱时短超时忙等(不osDelay,避免任务挂起导致积压) */ /* 500kbps下一帧约130µs,3个邮箱最慢约400µs释放 */ while (HAL_CAN_GetTxMailboxesFreeLevel(&hcan) == 0) { if (--wait == 0) { return 0; /* 超时放弃(总线异常) */ } } /* 组织发送帧头 */ tx_header.StdId = id; /* 标准帧ID */ tx_header.ExtId = 0; /* 扩展帧ID未用 */ tx_header.IDE = CAN_ID_STD; /* 标准帧 */ tx_header.RTR = CAN_RTR_DATA;/* 数据帧 */ tx_header.DLC = dlc; /* 数据长度 0~8 */ /* 临界区保护HAL_CAN_AddTxMessage,防止RX中断中HAL_CAN_GetRxMessage 的HAL_LOCK冲突(仅几μs,不影响实时性) */ taskENTER_CRITICAL(); HAL_StatusTypeDef status = HAL_CAN_AddTxMessage(&hcan, &tx_header, data, &tx_mailbox); taskEXIT_CRITICAL(); if (status != HAL_OK) { return 0; } return 1; #else uint32_t mailbox; /* 选择空闲邮箱(直接读TSR寄存器) */ if (hcan.Instance->TSR & CAN_TSR_TME0) mailbox = 0; else if (hcan.Instance->TSR & CAN_TSR_TME1) mailbox = 1; else if (hcan.Instance->TSR & CAN_TSR_TME2) mailbox = 2; else return 0; /* 无空闲邮箱 */ /* 设置ID(标准帧,ID左移21位) */ hcan.Instance->sTxMailBox[mailbox].TIR = (id << 21) | CAN_RTR_DATA | CAN_ID_STD; /* 设置DLC */ hcan.Instance->sTxMailBox[mailbox].TDTR = dlc; /* 设置数据(直接写TDLR/TDHR寄存器,立即拷贝) */ hcan.Instance->sTxMailBox[mailbox].TDLR = ((uint32_t)data[3]<<24)|((uint32_t)data[2]<<16)|((uint32_t)data[1]<<8)|data[0]; hcan.Instance->sTxMailBox[mailbox].TDHR = ((uint32_t)data[7]<<24)|((uint32_t)data[6]<<16)|((uint32_t)data[5]<<8)|data[4]; /* 请求发送 */ hcan.Instance->sTxMailBox[mailbox].TIR |= CAN_TI0R_TXRQ; return 1; #endif }