赞
踩
现象:全局变量在 CAN 中断中存储数据,并设置同步标志,在主程序中检测标志后,打包并转发 CAN 数据,会出现 CAN 数据错乱
现象分析:CAN 数据打包处理过程中,新的数据到来,导致数据包部分覆盖;
解决方法:1. 在打包过程中,使用中断屏蔽,保护全局 CAN 数据;2. 使用环形缓冲区保存数据;3.使用队列同步数据
方法分析:方法1裸机平台最简单,但会造成中断响应不及时,丢失部分数据,同样会干扰其他中断数据的接收,比如串口中断等;方法2需要对数据结构进行处理,协商存放和取出的规则;方法3利用 RTOS 平台特性,简单高效,数据处理最为安全可靠
数据结构
#define BSP_CAN_DATA_LEN 8
typedef struct
{
CAN_RxHeaderTypeDef hdr;
uint8_t payload[BSP_CAN_DATA_LEN];
} bsp_ecu_can_t;
创建队列
osMessageQueueId_t canQueueHandle;
const osMessageQueueAttr_t canQueue_attributes = {
.name = "canQueue"};
canQueueHandle = osMessageQueueNew(50, sizeof(bsp_ecu_can_t), &canQueue_attributes);
中断接收数据
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcanx) { bsp_ecu_can_t data = {0}; osStatus_t stat = osOK; if (hcanx->Instance == hcan.Instance) { // 读取接收数据 if (HAL_CAN_GetRxMessage(hcanx, CAN_RX_FIFO0, &data.hdr, data.payload) == HAL_OK) { // 推送队列 stat = osMessageQueuePut(canQueueHandle, &data, 0, 0); if (stat != osOK) { LOG_D("canQueueHandle: %d", osMessageQueueGetCount(canQueueHandle)); LOG_D("Can inData Put Fail!: %d", stat); } // 重新开启接收 HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING); } } }
线程处理数据
void bsp_ecu_can_data_queue_handle(void)
{
bsp_ecu_can_t msg = {0};
// 取数据
if (osMessageQueueGet(canQueueHandle, &msg, 0, osWaitForever) == osOK)
{
// TODO: 数据处理
// todo_can_process(msg);
LOG_V("CAN --> CAT1: %d", osMessageQueueGetCount(canQueueHandle));
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。