当前位置:   article > 正文

Stm32f103的can模块配置和调试_stm32 can配置函数

stm32 can配置函数

起因
库版本不一致,网上找到的都是早期的函数调用,一些函数接口都不一样,现在重新写一份调试文档
条件
Mcu:stm32f103c8t6
Cube调用的库:STM32Cube_FW_F1_V1.8.1
Can的配置流程(先大致说一遍):stm32使用maibox(邮箱)的方式进行数据的收发,需要先配置can的pinmux,波特率,中断函数(其中mailbox的fifo也需要中断使能,否则虽然可以采用查询的方式读取数据,但是无法进入中断函数),滤波参数配置;之后需要跟另外一个can模块相连接通讯,否则调试会报错(这里使用了PC端的usbcan模块Ecantools软件);
详细配置
Cube配置:
在这里插入图片描述在这里插入图片描述

Can.c中,代码需要进行修改和添加:
Can波特率的配置有一定的公式,可以寻找对应的公式来设置下面红色的三个参数

在这里插void MX_CAN_Init(void)
{
	CAN_FilterTypeDef sFilterConfig;

  hcan1.Instance = CAN1;
  hcan1.Init.Prescaler = 18;		//pclk0=36Mhz 	   /18=2Mhz
  hcan1.Init.Mode = CAN_MODE_NORMAL;
  hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan1.Init.TimeSeg1 = CAN_BS1_2TQ;	//CAN_BS1_1TQ
  hcan1.Init.TimeSeg2 = CAN_BS2_1TQ;
  hcan1.Init.TimeTriggeredMode = DISABLE;
  hcan1.Init.AutoBusOff = DISABLE;
  hcan1.Init.AutoWakeUp = DISABLE;
  hcan1.Init.AutoRetransmission = DISABLE;
  hcan1.Init.ReceiveFifoLocked = DISABLE;
  hcan1.Init.TransmitFifoPriority = DISABLE;
  switch(g_board_dev.tboard_cfg.can_rate){
		case 0:
			hcan1.Init.Prescaler = 36;	//250k
  		break;
		case 1:
			hcan1.Init.Prescaler = 18;	//500khz
  		break;
		case 2:
			hcan1.Init.Prescaler = 9;	//1Mhz
  		break;
		default:
			hcan1.Init.Prescaler = 18;
  		break;
  }  
  if (HAL_CAN_Init(&hcan1) != HAL_OK)
  {
    Error_Handler();
  }

  sFilterConfig.FilterIdHigh = 0x0000;//32 位 ID
  sFilterConfig.FilterIdLow = 0x0000;
  sFilterConfig.FilterMaskIdHigh = 0x0000;//32 位 MASK
  sFilterConfig.FilterMaskIdLow = 0x0000; 	  
  sFilterConfig.FilterBank = 0; 		 //过滤器0
  sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; //过滤器0关联到FIFO0
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
  sFilterConfig.FilterActivation = ENABLE; //激活过滤器0

  HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig);

  __HAL_CAN_ENABLE_IT(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);//使能can中断
  //  CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.
  //CAN_ITConfig(CAN1, CAN_IT_FMP1, ENABLE);

  //buffer init
  Can_FifoBuf_Init(&gpmag_rx, mag_rxbuffer, MAG_RXBUFFER_SIZE);


}

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(USB_LP_CAN1_RX0_IRQn, 6, 0);
    HAL_NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
    HAL_NVIC_SetPriority(CAN1_RX1_IRQn, 6, 0);
    HAL_NVIC_EnableIRQ(CAN1_RX1_IRQn);
  /* USER CODE BEGIN CAN1_MspInit 1 */
	

  /* USER CODE END CAN1_MspInit 1 */
  }
}
中断接收函数:
void USB_LP_CAN1_RX0_IRQHandler(void)
{
  /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 0 */

  /* USER CODE END USB_LP_CAN1_RX0_IRQn 0 */
  HAL_CAN_IRQHandler(&hcan1);
  /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 1 */

  /* USER CODE END USB_LP_CAN1_RX0_IRQn 1 */
}

//uint8_t byData[8];
//CAN_RxHeaderTypeDef RxMsg;
//CanRxMsgTypeDefPriv tRxMsgPriv;

/*can中断回调函数*/  这里的一帧can数据,帧头和数据进行了分离,不像早先的库都放在了一个结构体里面
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	uint8_t byData[8];
	CAN_RxHeaderTypeDef RxMsg;
	CanRxMsgTypeDefPriv	tRxMsgPriv;
	HAL_StatusTypeDef HAL_RetVal;
	if(hcan ==&hcan1){	
		HAL_RetVal = HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxMsg,  byData);
		if ( HAL_OK==HAL_RetVal){										
		  //在这里接收数据
		  memcpy(&tRxMsgPriv.RxMsg, &RxMsg, sizeof(CAN_RxHeaderTypeDef));
		  memcpy(&tRxMsgPriv.Data, &byData, sizeof(byData));
		  //压入队列中去
		  Can_FifoBuf_PutByte(&gpmag_rx, tRxMsgPriv);
		}
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130

上述这样配置ok以后,可以使用下面的发送函数来进行发送

CAN_TxHeaderTypeDef TxMeg;
//发送数据函数
uint8_t CANx_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;
	TxMeg.StdId=ID;
	if(!hcan || ! pData ||!Len)  return 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;
		}
		while(0==FreeTxNum){
			FreeTxNum=HAL_CAN_GetTxMailboxesFreeLevel(hcan);
		}
		HAL_Delay(1);   //没有延时很有可能会发送失败
		HAL_RetVal=HAL_CAN_AddTxMessage(hcan,&TxMeg,pData+SendCNT,(uint32_t*)CAN_TX_MAILBOX0); 
		if(HAL_RetVal!=HAL_OK)
		{
			return 2;
		}
		SendCNT+=8;
	}
	
  return 0;
}
这个发送函数会报错,进入hardfault函数中去,只因HAL_CAN_AddTxMessage这个函数里面的一条语句需要屏蔽掉
    /* Check transmit mailbox value */
      if (transmitmailbox > 2U)
      {
        /* Update error code */
        hcan->ErrorCode |= HAL_CAN_ERROR_INTERNAL;

        return HAL_ERROR;
      }

      /* Store the Tx mailbox */
      //*pTxMailbox = (uint32_t)1 << transmitmailbox;		

如果不使用中断的方式接收can数据,也可以在主循环中采用查询的方式进行读取数据
HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &recv_test1, can_recv_data);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/802537
推荐阅读
相关标签
  

闽ICP备14008679号