STM32 CUBE Can调试

STM32 CUBE Can调试

1、CAN配置

2、时钟配置

3、手动添加

需要注意的是STM32CUBE配置的代码需要再手动添加过滤器,并且将FIFO关联。

c 复制代码
/* CAN init function */
void MX_CAN_Init(void)
{

  /* USER CODE BEGIN CAN_Init 0 */

  /* USER CODE END CAN_Init 0 */

  /* USER CODE BEGIN CAN_Init 1 */

  /* USER CODE END CAN_Init 1 */
  hcan.Instance = CAN1;
  hcan.Init.Prescaler = 18;
  hcan.Init.Mode = CAN_MODE_NORMAL;
  hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan.Init.TimeSeg1 = CAN_BS1_8TQ;
  hcan.Init.TimeSeg2 = CAN_BS2_7TQ;
  hcan.Init.TimeTriggeredMode = DISABLE;
  hcan.Init.AutoBusOff = DISABLE;
  hcan.Init.AutoWakeUp = DISABLE;
  hcan.Init.AutoRetransmission = DISABLE;
  hcan.Init.ReceiveFifoLocked = DISABLE;
  hcan.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN CAN_Init 2 */
	/* 手动新增 */
	CAN_FilterTypeDef  CAN1_sFilterConfig;
	CAN1_sFilterConfig.FilterIdHigh = CAN1_ID_H;			//32位基础ID设置(高16位)
	CAN1_sFilterConfig.FilterIdLow = CAN1_ID_L;				//32位基础ID设置(低16位)
	CAN1_sFilterConfig.FilterMaskIdHigh = CAN1_MASK_H;		//32位屏蔽MASK设置(高16位)
	CAN1_sFilterConfig.FilterMaskIdLow = CAN1_MASK_L;		//32位屏蔽MASK设置(低16位)
	CAN1_sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;	//接收到的报文放入FIFO0位置
	CAN1_sFilterConfig.FilterBank = 0;						//过滤器0
	CAN1_sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;	//设为IDLIST列表模式/IDMASK屏蔽模式
	CAN1_sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;	//过滤器位宽度
	CAN1_sFilterConfig.FilterActivation = ENABLE;			//ENABLE激活过滤器,DISABLE禁止过滤器
	CAN1_sFilterConfig.SlaveStartFilterBank = 0;			//过滤器组设置(单个CAN总线时无用)
	if (HAL_OK!=HAL_CAN_ConfigFilter(&hcan, &CAN1_sFilterConfig))//判断开启是否成功
	{
		 /* Filter configuration Error */
		 Error_Handler();									//开启CAN总线失败的处理程序
	}
  /* USER CODE END CAN_Init 2 */

}

4、回调函数

c 复制代码
/**
 * @brief  CAN FIFO0的中断回调函数,在里面完成数据的接收
 * @param  hcan     CAN的句柄
 */
 
uint8_t date_CAN[8];//设为全局变量,用于接收CAN数据
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	if(hcan->Instance ==CAN1)
	{
		CAN_RxHeaderTypeDef RxHeader;  //接受句柄
		HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, date_CAN); //接收,CAN邮箱为0
		
		FPGA_Comm_Analysis(RxHeader.ExtId, date_CAN, RxHeader.DLC);
		
		return ;
	}
}

5、启动函数和发送函数

启动函数记得添加在while循环之前。

c 复制代码
HAL_CAN_ActivateNotification(hcan ,CAN_IT_RX_FIFO0_MSG_PENDING);

需要发送时调用发送函数:

c 复制代码
/*******************************************************
函数名称: 	Drv_Can_Write          
功能描述: 	
输 入:   	无

输 出:   	无                 
******************************************************/
uint8_t Drv_Can_Write(CAN_HandleTypeDef* hcan, uint32_t ID, uint8_t *pData,uint16_t Len)
{	
	uint8_t  ret=1;
	HAL_StatusTypeDef res = HAL_OK;
	uint32_t TxMailbox;
    CAN_TxHeaderTypeDef st_TxHeader;
	
	st_TxHeader.StdId=0;
	st_TxHeader.ExtId=ID;
	st_TxHeader.IDE=CAN_ID_EXT;
	st_TxHeader.RTR=0;
	st_TxHeader.DLC=Len;
	
	/*找到空的发送邮箱,把数据发送出去*/
	res = HAL_CAN_AddTxMessage(hcan, &st_TxHeader, pData, &TxMailbox);
	if(res != HAL_OK)
	{
		//printf("HAL_CAN_AddTxMessage TxMailbox = %d fail! result = %d", TxMailbox, res);
		ret = 0;
	}
	return ret;
}

/******************************************************
函数名称: 	Drv_Can_Start          
功能描述: 	
输 入:   	无

输 出:   	无                 
********************************************************/
void Drv_Can_Start(CAN_HandleTypeDef *hcan)
{
	HAL_CAN_ActivateNotification(hcan ,CAN_IT_RX_FIFO0_MSG_PENDING);
	HAL_CAN_Start(hcan);
}

6、使用方法(采用消息队列来做缓存)

7、数据不多在发送函数中获取空邮箱发送,否则循环等待空邮箱

c 复制代码
uint8_t  CAN1_SendNormalData(CAN_HandleTypeDef* hcan,uint16_t ID,uint8_t *pData,uint16_t  Len)
{
    HAL_StatusTypeDef HAL_RetVal;//判断状态的枚举
    uint16_t SendTimes,SendCNT=0;
    uint8_t  FreeTxNum=0;
    uint8_t  FreeLevelCount=0;
    uint32_t CAN_TX_BOX0;
    TxMeg.StdId=ID;
    TxMeg.IDE = CAN_ID_STD;//扩展帧标识(STD标准帧/EXT扩展帧)
    TxMeg.RTR = CAN_RTR_DATA;//远程帧标识(DATA数据帧/REMOTE远程帧)
    if(!hcan||!pData||!Len){
    	printf("\n\rCAN发送失败!\n\r"); //串口发送
    	return  HAL_ERROR;//如果总线名、数据、数量任何一个为0则返回值为1
    }
    SendTimes=Len/8+(Len%8?1:0);
    FreeTxNum=HAL_CAN_GetTxMailboxesFreeLevel(hcan);//得出空闲邮箱的数量
    TxMeg.DLC=8;
    while(SendTimes--){//循环判断分批发送是否结束
       if(0==SendTimes){//如果分批发送结束
           if(Len%8)TxMeg.DLC=Len%8;//则加入最后不足8个的数据内容
       }
       FreeLevelCount = 0;//防止死循环
       while(0 == FreeTxNum&&FreeLevelCount<10){
    	   	FreeLevelCount++;
    	   	HAL_Delay(1);
            FreeTxNum = HAL_CAN_GetTxMailboxesFreeLevel(hcan);
        }
       HAL_Delay(1);//延时防止速度过快导致的发送失败
       //开始发送数据(参数:总线名,设置参数,数据,邮箱号)
       HAL_RetVal=HAL_CAN_AddTxMessage(hcan,&TxMeg,pData+SendCNT,&CAN_TX_BOX0);
       if(HAL_RetVal!=HAL_OK){
    		   printf("\n\rCAN总线忙碌!\n\r"); //串口发送
    		   return  HAL_BUSY;//如果发送失败,则返回值为2
       }
       SendCNT+=8;
    }
    return HAL_OK;//如果发送成功结束,返回值为0
}
//CAN总线通信,使用CAN1,这是CAN专用的printf函数
//调用方法:CAN1_printf("123"); //向UART8发送字符123
void CAN1_printf (char *fmt, ...)
{
    char buff[CAN1_REC_LEN+1];  //用于存放转换后的数据 [长度]
    uint16_t i=0;
    va_list arg_ptr;
    va_start(arg_ptr, fmt);
    vsnprintf(buff, CAN1_REC_LEN+1, fmt,  arg_ptr);//数据转换
    i=strlen(buff);//得出数据长度
    if(strlen(buff)>CAN1_REC_LEN)i=CAN1_REC_LEN;//如果长度大于最大值,则长度等于最大值(多出部分忽略)
    CAN1_SendNormalData(&hcan,0x11,(uint8_t *)buff,i);//CAN发送数据函数(ID为0x11)
    va_end(arg_ptr);
}
相关推荐
weixin_5803820641 分钟前
STC51 P0 口 与P1 口输出
单片机·嵌入式硬件
爱吃奶酪的松鼠丶2 小时前
51单片机之使用Keil uVision5创建工程以及使用stc-isp进行程序烧录步骤
嵌入式硬件·51单片机·接口隔离原则
一只搬砖的猹3 小时前
PCA9685舵机控制板使用
stm32·单片机·嵌入式硬件·mcu·pwm·舵机·舵机驱动
零下273°4 小时前
51单片机俄罗斯方块开机动画
单片机·嵌入式硬件·51单片机
浅陌pa4 小时前
04:定时器
c语言·单片机·嵌入式硬件·51单片机
╰⋛⋋⊱⋋翅膀⋌⊰⋌⋚╯4 小时前
STM32-启动文件
stm32·单片机
爱吃奶酪的松鼠丶6 小时前
51单片机之引脚图(详解)
单片机·嵌入式硬件·51单片机
fengyuzhe139 小时前
STC 51单片机62——极简 4x4x4光立方
单片机·嵌入式硬件·51单片机
小小虫码9 小时前
处理STM32 DMA方式下的HAL_UART_ERROR_ORE错误
stm32·单片机·嵌入式硬件