研究生
最后登录1970-1-1
在线时间 小时
注册时间2019-5-23
|
请问一下有人遇到过CAN多设备通讯出现一对一通讯是正常的,一堆多后设备就会导致主机获取不到从机数据,但是从机是可以接收到主机数据的,而且从机给主机响应发送的数据我使用CAN工具是捕获到数据的,就是主机没有方法触发中断也没有办法接收数据。设备工作的逻辑是F407作为主机,每3秒查询一套设备的数据,从机设备每隔10ms发送响应数据,总共回复20条数据。下面是从机的软件,定位到的原因就是从机导致的问题,主机解析其它厂家的标准模块都是正常的。这个坑查了一周都没有找到哪里的问题。
#include "can.h"
#include "can_protocol.h"
#include "delay.h"
#include "timer.h"
#include <string.h>
static volatile bool can_bus_off_flag = false;
static volatile uint8_t can_tx_err = 0;
static volatile uint8_t can_rx_err = 0;
static volatile uint32_t can_bus_off_tick = 0; // 总线离线恢复计时
/**
* @brief 进入CAN初始化模式
* @param 无
* @retval 成功返回true,超时返回false
*/
static bool CAN_Enter_Init_Mode(void)
{
uint32_t timeout = 1000;
CAN1->MCR |= CAN_MCR_INRQ;
while ((CAN1->MSR & CAN_MSR_INAK) == 0)
{
if (--timeout == 0) return false;
Delay_Us(1);
}
return true;
}
/**
* @brief 退出CAN初始化模式
* @param 无
* @retval 成功返回true,超时返回false
*/
static bool CAN_Exit_Init_Mode(void)
{
uint32_t timeout = 1000;
CAN1->MCR &= ~CAN_MCR_INRQ;
while ((CAN1->MSR & CAN_MSR_INAK) != 0)
{
if (--timeout == 0) return false;
Delay_Us(1);
}
return true;
}
/**
* @brief CAN硬件初始化
* @param 无
* @retval 无
*/
void CAN_Hardware_Init(void)
{
CAN_InitTypeDef CAN_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
// 1. 时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
// 2. GPIO配置 (PB8=CAN_RX 上拉输入, PB9=CAN_TX 复用推挽)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 3. CAN1引脚重映射
GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
// 4. CAN控制器复位
CAN_DeInit(CAN1);
// 5. CAN参数配置 (125K波特率)
CAN_StructInit(&CAN_InitStructure);
CAN_InitStructure.CAN_TTCM = DISABLE; // 禁用时间触发通信模式
CAN_InitStructure.CAN_ABOM = ENABLE; // 自动总线离线管理
CAN_InitStructure.CAN_AWUM = DISABLE; // 禁用自动唤醒
CAN_InitStructure.CAN_NART = DISABLE; // 使能自动重传
CAN_InitStructure.CAN_RFLM = DISABLE; // 禁用接收FIFO锁定
CAN_InitStructure.CAN_TXFP = DISABLE; // 禁用发送FIFO优先级
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;// 正常模式(从机)
// 波特率计算: APB1=36MHz / ((1+6+1)*36) = 125K
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; // 同步跳转宽度: 1TQ
CAN_InitStructure.CAN_BS1 = CAN_BS1_6tq; // 时间段1: 6TQ
CAN_InitStructure.CAN_BS2 = CAN_BS2_1tq; // 时间段2: 1TQ
CAN_InitStructure.CAN_Prescaler = 36; // 预分频器
CAN_Init(CAN1, &CAN_InitStructure);
// 6. 滤波器配置 (接收所有扩展帧)
CAN_FilterInitStructure.CAN_FilterNumber = 0;
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
// 7. 中断配置
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 统一中断分组
// 接收中断 (FIFO0消息挂起)
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 错误中断 (总线错误/离线/警告)
NVIC_InitStructure.NVIC_IRQChannel = CAN1_SCE_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
// 8. 使能中断
CAN_ITConfig(CAN1, CAN_IT_FMP0 | CAN_IT_ERR, ENABLE);
// 9. 初始化状态标志
can_bus_off_flag = false;
can_tx_err = 0;
can_rx_err = 0;
can_bus_off_tick = 0;
}
/**
* @brief 发送CAN扩展帧
* @param id: 32位扩展帧ID
* @param data: 数据指针(空指针时发送空数据)
* @param len: 数据长度(0~8)
* @retval 发送成功返回true,失败返回false
*/
bool CAN_Send_Frame(uint32_t id, const uint8_t *data, uint8_t len)
{
CanTxMsg TxMessage;
uint8_t mailbox;
uint32_t timeout = CAN_TX_TIMEOUT_CNT;
uint8_t tx_status;
// 1. 总线离线时直接返回失败
if (can_bus_off_flag || (CAN1->ESR & CAN_ESR_BOFF))
return false;
// 2. 限制数据长度(0~8)
len = (len > 8) ? 8 : len;
// 3. 初始化发送结构体
memset(&TxMessage, 0, sizeof(CanTxMsg));
TxMessage.StdId = 0; // 无标准ID
TxMessage.ExtId = id; // 扩展ID
TxMessage.IDE = CAN_Id_Extended; // 扩展帧模式
TxMessage.RTR = CAN_RTR_Data; // 数据帧
TxMessage.DLC = len; // 数据长度
if (data != NULL && len > 0)
memcpy(TxMessage.Data, data, len);
// 4. 申请发送邮箱
mailbox = CAN_Transmit(CAN1, &TxMessage);
if (mailbox == CAN_TxStatus_NoMailBox)
return false;
// 5. 等待发送完成
while (timeout--)
{
tx_status = CAN_TransmitStatus(CAN1, mailbox);
if (tx_status == CAN_TxStatus_Ok) // 发送成功
return true;
else if (tx_status == CAN_TxStatus_Failed) // 发送失败
{
CAN_CancelTransmit(CAN1, mailbox); // 取消发送
return false;
}
Delay_Us(10); // 10µs轮询一次
}
// 6. 发送超时: 取消发送并返回失败
CAN_CancelTransmit(CAN1, mailbox);
return false;
}
/**
* @brief CAN接收中断服务函数 (USB_LP_CAN1_RX0_IRQn)
* @param 无
* @retval 无
*/
void USB_LP_CAN1_RX0_IRQHandler(void)
{
CanRxMsg RxMessage;
uint32_t err_flag = CAN_GetFlagStatus(CAN1, CAN_FLAG_FOV0);
// 1. 处理FIFO溢出错误
if (err_flag != RESET)
{
CAN_ClearFlag(CAN1, CAN_FLAG_FOV0);
}
// 2. 处理接收FIFO中的所有消息
while (CAN_GetITStatus(CAN1, CAN_IT_FMP0) != RESET)
{
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
// 仅处理扩展帧
if (RxMessage.IDE == CAN_Id_Extended)
{
//内部软件过滤,不是设备地址直接退出
CAN_Process_ReceivedMessage(RxMessage.ExtId, RxMessage.Data, RxMessage.DLC);
}
}
// 3. 清除中断挂起位
CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0);
}
/**
* @brief CAN错误中断服务函数 (CAN1_SCE_IRQn)
* @param 无
* @retval 无
*/
void CAN1_SCE_IRQHandler(void)
{
// 1. 检查错误中断标志
if (CAN_GetITStatus(CAN1, CAN_IT_ERR) != RESET)
{
// 2. 更新错误计数
can_tx_err = (CAN1->ESR >> 16) & 0xFF; // 发送错误计数(0~255)
can_rx_err = (CAN1->ESR >> 24) & 0x7F; // 接收错误计数(0~127)
// 3. 检测总线离线
if ((CAN1->ESR & CAN_ESR_BOFF) != 0)
{
can_bus_off_flag = true;
can_bus_off_tick = Get_SysTick(); // 记录离线时刻(需实现SysTick获取函数)
}
// 4. 清除错误中断挂起位
CAN_ClearITPendingBit(CAN1, CAN_IT_ERR);
}
}
/**
* @brief 获取CAN总线状态
* @param 无
* @retval CAN_Bus_Status
*/
CAN_Bus_Status can_get_state(void)
{
// 1. 总线离线
if (CAN1->ESR & CAN_ESR_BOFF)
return CAN_Bus_Off;
// 2. 错误被动状态 (TX/RX错误计数≥128)
if (can_tx_err >= 128 || can_rx_err >= 128)
return CAN_Error_Passive;
// 3. 错误警告状态 (TX/RX错误计数≥96)
if (can_tx_err >= 96 || can_rx_err >= 96)
return CAN_Error_Warning;
// 4. 正常状态
return CAN_Normal;
}
/**
* @brief 获取最后一次错误码
* @param 无
* @retval 错误码 (0~7)
*/
uint8_t can_get_error_status(void)
{
return CAN_GetLastErrorCode(CAN1);
}
/**
* @brief 获取接收错误计数
* @param 无
* @retval 接收错误计数值(0~127)
*/
uint8_t can_get_rx_err_cnt(void)
{
return can_rx_err;
}
/**
* @brief 获取发送错误计数
* @param 无
* @retval 发送错误计数值(0~255)
*/
uint8_t can_get_tx_err_cnt(void)
{
return can_tx_err;
}
/**
* @brief CAN总线状态处理与自动恢复
* @param 无
* @retval 无
*/
void can_process(void)
{
// 1. 总线离线且达到恢复延时
if (can_bus_off_flag && (Get_SysTick() - can_bus_off_tick >= CAN_BUS_RECOVERY_MS))
{
// 2. 进入初始化模式
if (CAN_Enter_Init_Mode())
{
// 3. 复位CAN控制器
CAN_DeInit(CAN1);
Delay_Ms(10);
// 4. 重新初始化CAN
CAN_Hardware_Init();
// 5. 退出初始化模式
CAN_Exit_Init_Mode();
// 6. 清除离线标志
can_bus_off_flag = false;
}
can_bus_off_tick = Get_SysTick(); // 更新恢复计时
}
}
|
|