野火小智模块

该模块是从优信电子店铺购买,宝贝详情中对SIT1042收发器芯片、模块的外部引脚进行了说明,文中描述芯片的VIO引脚为EN引脚,可悬空,收到的模块EN引脚的丝印为VIO,因为VIO引脚和EN连着的,当时觉得可能是新旧模块混发,也没在意。因此后续开发中EN/VIO引脚悬空。
在这里插入图片描述

在调试中遇到的问题

采用STM32F103核心板和野火小智CAN通信模块,用千目电子的USB-CAN转换器B1进行通信的调试。
首先利用江科大的代码进行测试,CAN盒子可以接收到核心板发送的报文,之后用STM32CUBEMX搭建CAN工程,配置好后,发送三次报文后就开始报错,且CAN盒一帧报文都未收到,调试模式下,发现三个邮箱都满了,TSR寄存器的值为0x8200 0000,刚开始以为是哪里配置出现了问题,反复查看代码,始终没找到问题,后续烧录回标准库代码后,依然无法通信,以为期间不小心改动了某些地方的代码,排查了一遍依然没有发现问题,始终无法通信。
将CAN模式改为环回模式后,32自身是可以收到自己发送的代码的,因此怀疑CAN模块、CAN盒的问题。
之后用示波器抓CAN盒发送的波形,波形没问题,说明CAN盒正确发送了报文,看来问题出在野火小智模块上。

查论坛中有个网友的现象和我这个一致,网友最后是因为核心板供电电压不够,导致的收发器模块无法正常工作,我使用直流电源单独给野火小智模块供电,并共地,问题依然没有解决,但是问题应该在模块上
查论坛中有个网友的现象和我这个一致,网友最后是因为核心板供电电压不够,导致的收发器模块无法正常工作,我使用直流电源单独给野火小智模块供电,并共地,问题依然没有解决,但是问题应该在模块上

硬件排查过程

CAN盒定时发送报文,用示波器抓收发器模块的RX引脚,RX引脚无波形。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
此时才反应过来是不是VIO引脚的问题,因此将VIO引脚连接到核心板的3V3上,示波器抓到了RX输出的波形。
在这里插入图片描述
在这里插入图片描述
之后去野火官方旗舰店查看该手册说明,引脚说明中明确说明VIO引脚接3V3。
在这里插入图片描述

附STM32 CAN代码配置

基于STM32f103,代码包含标准库和hal库,标准库移植江科大CAN封装函数,HAL库基于CUBEMX创建。
标准库:

void MyCAN_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	CAN_InitTypeDef CAN_InitStructure;
	CAN_InitStructure.CAN_Prescaler = 48;//波特率 = 36M/48/(1+2+3)=125k
	CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;//环回、静默、静默环回三种,非初始化、睡眠、标准模式选择
	CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;//间隔位时间
	CAN_InitStructure.CAN_BS1 = CAN_BS1_2tq;//
	CAN_InitStructure.CAN_BS2 = CAN_BS2_3tq;
	CAN_InitStructure.CAN_TTCM = DISABLE;//
	CAN_InitStructure.CAN_ABOM = DISABLE;//自动离线恢复
	CAN_InitStructure.CAN_AWUM = DISABLE;//自动唤醒模式
	CAN_InitStructure.CAN_NART = DISABLE;//不自动重发模式
	CAN_InitStructure.CAN_RFLM = DISABLE;//FIFO锁定模式,ENABLE的话,FIFO溢出,FIFO会丢弃当前接收的数据;DISABLE FIFO溢出,会覆盖原数据
	CAN_InitStructure.CAN_TXFP = DISABLE;//发送FIFO优先级,DISABLE由报文的标识符决定优先级,ENABLE由
	CAN_Init(CAN1, &CAN_InitStructure);//初始化CAN
	
	CAN_FilterInitTypeDef CAN_FilterInitStructure;
	CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
	CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;//所有ID均可通过
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;//选择FIFO0
	CAN_FilterInitStructure.CAN_FilterNumber = 0;//过滤器编号,选择0号过滤器
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;//32位屏蔽模式
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;//过滤器使能
	CAN_FilterInit(&CAN_FilterInitStructure);
}

void MyCAN_Transmit(uint32_t ID, uint8_t Length, uint8_t *Data)
{
	CanTxMsg TxMessage;
	TxMessage.StdId = ID;//标准ID
	TxMessage.ExtId = ID;//扩展ID
	TxMessage.IDE = CAN_Id_Standard;//标准
	TxMessage.RTR = CAN_RTR_Data;//数据帧     数据或遥测帧进行选择
	TxMessage.DLC = Length;//数据长度,0~8
	for (uint8_t i = 0; i < Length; i ++)
	{
		TxMessage.Data[i] = Data[i];
	}
	uint8_t TransmitMailbox = CAN_Transmit(CAN1, &TxMessage);//将结构体数据发送给CAN1,函数返回当前邮箱编号
	while (CAN_TransmitStatus(CAN1, TransmitMailbox) != CAN_TxStatus_Ok);//判断该邮箱状态,是否发送完毕
}

uint8_t MyCAN_ReceiveFlag(void)
{
	if (CAN_MessagePending(CAN1, CAN_FIFO0) > 0)
	{
		return 1;
	}
	return 0;
}

void MyCAN_Receive(uint32_t *ID, uint8_t *Length, uint8_t *Data)
{
	CanRxMsg RxMessage;
	
	CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//接收CAN1、FIFO0中的数据
	
	if (RxMessage.IDE == CAN_Id_Standard)
	{
		*ID = RxMessage.StdId;//判断是否为标准ID帧,是的话,将ID赋值给形参
	}
	else
	{
		//...
	}
	
	if (RxMessage.RTR == CAN_RTR_Data)//判断是否为数据帧,是的话就将接收结构体中的数据赋值到数组Data中
	{
		*Length = RxMessage.DLC;
		for (uint8_t i = 0; i < *Length; i ++)
		{
			Data[i] = RxMessage.Data[i];
		}
	}
	else
	{
		//...
	}
}

HAL库:

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 = 48;
  hcan.Init.Mode = CAN_MODE_NORMAL;
  hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan.Init.TimeSeg1 = CAN_BS1_2TQ;
  hcan.Init.TimeSeg2 = CAN_BS2_3TQ;
  hcan.Init.TimeTriggeredMode = DISABLE;
  hcan.Init.AutoBusOff = DISABLE;
  hcan.Init.AutoWakeUp = DISABLE;
  hcan.Init.AutoRetransmission = ENABLE;
  hcan.Init.ReceiveFifoLocked = DISABLE;
  hcan.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan) != HAL_OK)
  {
    Error_Handler();
		
  }
  /* USER CODE BEGIN CAN_Init 2 */
	while(CanSetFilter(&hcan) != HAL_OK);
	HAL_CAN_Start(&hcan);
  /* USER CODE END CAN_Init 2 */

}

void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(canHandle->Instance==CAN1)
  {
  /* USER CODE BEGIN CAN1_MspInit 0 */

  /* USER CODE END CAN1_MspInit 0 */
    /* CAN1 clock enable */
    __HAL_RCC_CAN1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**CAN GPIO Configuration
    PA11     ------> CAN_RX
    PA12     ------> CAN_TX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* CAN1 interrupt Init */
    HAL_NVIC_SetPriority(CAN1_RX1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(CAN1_RX1_IRQn);
  /* USER CODE BEGIN CAN1_MspInit 1 */

  /* USER CODE END CAN1_MspInit 1 */
  }
}

void HAL_CAN_MspDeInit(CAN_HandleTypeDef* canHandle)
{

  if(canHandle->Instance==CAN1)
  {
  /* USER CODE BEGIN CAN1_MspDeInit 0 */

  /* USER CODE END CAN1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_CAN1_CLK_DISABLE();

    /**CAN GPIO Configuration
    PA11     ------> CAN_RX
    PA12     ------> CAN_TX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);

    /* CAN1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn);
  /* USER CODE BEGIN CAN1_MspDeInit 1 */

  /* USER CODE END CAN1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

HAL_StatusTypeDef  CanSetFilter(CAN_HandleTypeDef *hcan)
{
	HAL_StatusTypeDef  Status;
	CAN_FilterTypeDef  CAN_FilterStruct;
	
	CAN_FilterStruct.FilterIdHigh=0x0000;
	CAN_FilterStruct.FilterIdLow=0x0000;
	CAN_FilterStruct.FilterMaskIdHigh=0x0000;
	CAN_FilterStruct.FilterMaskIdLow=0x0000;
	CAN_FilterStruct.FilterBank=0;
	CAN_FilterStruct.FilterFIFOAssignment=CAN_FILTER_FIFO0;
	
	CAN_FilterStruct.FilterMode=CAN_FILTERMODE_IDMASK;
	CAN_FilterStruct.FilterScale=CAN_FILTERSCALE_32BIT;
	CAN_FilterStruct.FilterActivation=ENABLE;

	Status= HAL_CAN_ConfigFilter(hcan, &CAN_FilterStruct);
	return Status;
}







void CanTransmit(CAN_HandleTypeDef *hcan,uint32_t ID,uint8_t Data[],uint32_t Length)
{
	uint32_t TxMail;
	
	CAN_TxHeaderTypeDef  CAN_TxStructure;
	HAL_StatusTypeDef Status;
	
	CAN_TxStructure.StdId=ID;
	CAN_TxStructure.ExtId=ID;
	CAN_TxStructure.IDE=CAN_ID_STD;
	CAN_TxStructure.RTR=CAN_RTR_DATA;
	CAN_TxStructure.DLC=Length;
	CAN_TxStructure.TransmitGlobalTime=DISABLE;

	Status=HAL_CAN_AddTxMessage(hcan, &CAN_TxStructure, Data, &TxMail);
	if(Status!=HAL_OK)
	{
		printf("Send Error:");
		printf("%d\r\n",Status);
	}

}

HAL库中:
HAL_StatusTypeDef CanSetFilter(CAN_HandleTypeDef hcan);
void CanTransmit(CAN_HandleTypeDef hcan,uint32_t ID,uint8_t Data[],uint32_t Length);
滤波器配置函数,发送及接受函数需要自己创建,其余为MX配置生成,其中需要注意的一点是在CAN_Init配置完后要添加
HAL_CAN_Start(&hcan);**函数,在stm32fxxx_hal_can.c库文件中有详细说明。
库文件中对配置CAN有具体的说明

存在的一些疑问

VIO引脚连接3V3 后,通信可正常进行,之后将VIO引脚断开,通信依然正常,模块重新上电后无法通信,需要对VIO引脚重新供电。

勘误

20250515
HAL库代码中使能的是CAN_RX1中断,滤波器中配置的为FIFO0,这里有错误注意,应改成FIFO1,不然进不了FIFO1接收中断回调函数。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐