基于CubeMX-STM32F302_CAN通信

1、简介

STM32F302的内核为Cortex-M4。

bxCAN是基本扩展CAN(Basic Extended CAN)的缩写,它支持CAN协议2.0A和2.0B。它的设计目标是,以最小的CPU负荷来高效处理大量收到的报文。它也支持报文发送的优先级要求(优先级特性可软件配置)。对于安全紧要的应用, bxCAN提供所有支持时间触发通信模式所需的硬件功能。

2、准备

2.1、软件

1、HAL 库版本:STM32Cube FW_F3 V1.11.2

2.2、开发工具

1、STM32CubeMX 6.2.0

2、Keil uVision5 V5.34.0.0

2.3、代码测试时间

2021年7月25日

2.4、参考文档

STM32F302参考手册:RM0365

STM32F3 HAL库用户手册:UM1786

3、CubeMX 工程配置

3.1、参数配置

在该项配置中的波特率配置如下图所示。其中Tpclk为经过分频的时钟,其中bxCAN在外设时钟APB1上为36MHz,经过分频为6MHz。

其中TS1配置为2、TS2配置为3。波特率为1MHz。此处配置可参考下面图片进行理解。

 基于CubeMX-STM32F302_CAN通信_第1张图片

 基于CubeMX-STM32F302_CAN通信_第2张图片

 基于CubeMX-STM32F302_CAN通信_第3张图片

 3.2、中断配置

 基于CubeMX-STM32F302_CAN通信_第4张图片

3.3、中断优先级配置

基于CubeMX-STM32F302_CAN通信_第5张图片

4、代码配置

4.1、配置标识符过滤

硬件过滤的做法节省了CPU开销, 每个过滤器组x由2个32位寄存器, CAN_FxR0 和 CAN_FxR1 组成。

主要的配置寄存器为:CAN_FM1R、CAN_FS1R、CAN_FA1R。参考下图,此处我们配置为:1 个 32 位过滤器-标识符屏蔽模式

看图可以了解到过滤器中的低三位是 IDE、RTR、0 三个,在扩展帧中ID 的位数为29位,所以我们定义的 ID 低29位是有效位,高三位我们通过移位操作去除掉。

我们跳转到 CAN 通信滤波器配置函数中就可以看出来,

参数 FilterIdHigh、 FilterIdLow 对应寄存器 CAN_FxR1、

参数 FilterMaskIdHigh、 FilterMaskIdLow 对应寄存器 CAN_FxR2。

对照下表我们就知道如何进行配置。

基于CubeMX-STM32F302_CAN通信_第6张图片

4.2、滤波器配置初始化

根据上述讲解我们将相应的 ID 左移三位,对应到 ID 的区域,配置 IDE 为1(我们用的扩展帧格式),代码如下图所示

记得初始化过滤器的结构体,此处代码截图未截到:CAN_FilterTypeDef My_CanFilter0,My_CanFilter1,My_CanFilter2,My_CanFilter3;

如果要过滤多个 ID 可以增加对滤波器(在STM32F302CBT6中共有13个滤波器),对应的参数为 FilterBank(0-12)

 基于CubeMX-STM32F302_CAN通信_第7张图片

代码:

    My_CanFilter0.FilterActivation = ENABLE;
	My_CanFilter0.FilterBank = 0;
	My_CanFilter0.FilterFIFOAssignment = CAN_FilterFIFO0;
	My_CanFilter0.FilterScale = CAN_FILTERSCALE_32BIT;
	My_CanFilter0.FilterMode = CAN_FILTERMODE_IDMASK;
  
	My_CanFilter0.FilterIdHigh = ((CAN_IMU_ID<<3)>>16)&0xffff;
	My_CanFilter0.FilterIdLow = ((CAN_IMU_ID<<3)&0xffff)|CAN_ID_EXT;
	My_CanFilter0.FilterMaskIdHigh = ((DeviceMask<<3)>>16)&0xffff;
	My_CanFilter0.FilterMaskIdLow = ((DeviceMask<<3)&0xffff)|CAN_ID_EXT;
  
	if(HAL_CAN_ConfigFilter(&hcan,&My_CanFilter0) != HAL_OK)
	{
		Error_Handler();
	}
	
  
	My_CanFilter1.FilterActivation = ENABLE;
	My_CanFilter1.FilterBank = 1;
	My_CanFilter1.FilterFIFOAssignment = CAN_FilterFIFO0;
	My_CanFilter1.FilterScale = CAN_FILTERSCALE_32BIT;
	My_CanFilter1.FilterMode = CAN_FILTERMODE_IDMASK;
  
	My_CanFilter1.FilterIdHigh = ((CAN_ROLL_ID<<3)>>16)&0xffff;
	My_CanFilter1.FilterIdLow = ((CAN_ROLL_ID<<3)&0xffff)|CAN_ID_EXT;
	My_CanFilter1.FilterMaskIdHigh = ((DeviceMask<<3)>>16)&0xffff;
	My_CanFilter1.FilterMaskIdLow = ((DeviceMask<<3)&0xffff)|CAN_ID_EXT;
  
	if(HAL_CAN_ConfigFilter(&hcan,&My_CanFilter1) != HAL_OK)
	{
		Error_Handler();
	}
	
	
	My_CanFilter2.FilterActivation = ENABLE;
	My_CanFilter2.FilterBank = 2;
	My_CanFilter2.FilterFIFOAssignment = CAN_FilterFIFO0;
	My_CanFilter2.FilterScale = CAN_FILTERSCALE_32BIT;
	My_CanFilter2.FilterMode = CAN_FILTERMODE_IDMASK;
  
	My_CanFilter2.FilterIdHigh = ((CAN_PITCH_ID<<3)>>16)&0xffff;
	My_CanFilter2.FilterIdLow = ((CAN_PITCH_ID<<3)&0xffff)|CAN_ID_EXT;
	My_CanFilter2.FilterMaskIdHigh = ((DeviceMask<<3)>>16)&0xffff;
	My_CanFilter2.FilterMaskIdLow = ((DeviceMask<<3)&0xffff)|CAN_ID_EXT;
	
	if(HAL_CAN_ConfigFilter(&hcan,&My_CanFilter2) != HAL_OK)
	{
		Error_Handler();
	}
	
	
	My_CanFilter3.FilterActivation = ENABLE;
	My_CanFilter3.FilterBank = 3;
	My_CanFilter3.FilterFIFOAssignment = CAN_FilterFIFO0;
	My_CanFilter3.FilterScale = CAN_FILTERSCALE_32BIT;
	My_CanFilter3.FilterMode = CAN_FILTERMODE_IDMASK;
  
	My_CanFilter3.FilterIdHigh = ((CAN_YAW_ID<<3)>>16)&0xffff;
	My_CanFilter3.FilterIdLow = ((CAN_YAW_ID<<3)&0xffff)|CAN_ID_EXT;
	My_CanFilter3.FilterMaskIdHigh = ((DeviceMask<<3)>>16)&0xffff;
	My_CanFilter3.FilterMaskIdLow = ((DeviceMask<<3)&0xffff)|CAN_ID_EXT;
	
	if(HAL_CAN_ConfigFilter(&hcan,&My_CanFilter3) != HAL_OK)
	{
		Error_Handler();
	}

4.3、添加中断使能及CAN的启动

在 HAL 库中 CAN 有两种 API 来使能或关闭相应的中断,我测试的是两者的效果相同。

大家可以测试一下留言讨论一下

API:

HAL_CAN_ActivateNotification 开启相应的中断

HAL_CAN_DeactivateNotification 禁用相应的中断

__HAL_CAN_ENABLE_IT 开启相应的中断

__HAL_CAN_DISABLE_IT 禁用相应的中断

代码:

//	if(HAL_CAN_ActivateNotification(&hcan,CAN_IT_TX_MAILBOX_EMPTY|CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
//	{
//		Error_Handler();
//	}
	__HAL_CAN_ENABLE_IT(&hcan,CAN_IT_TX_MAILBOX_EMPTY|CAN_IT_RX_FIFO0_MSG_PENDING);
	
	if(HAL_CAN_Start(&hcan) != HAL_OK)
	{
		Error_Handler();
	}
  /* USER CODE END CAN_Init 2 */

}

4.4、中断函数的配置

在以上配置中我们使能的中断是发送邮箱空中断&接收FIFO0挂起中断

在中断处理文件中 stm32f3xx_it.c 的相应中断函数 USB_HP_CAN_TX_IRQHandler\USB_LP_CAN_RX0_IRQHandler 找到CAN的中断处理 HAL_CAN_IRQHandler

HAL_CAN_IRQHandler 中找到配置使能的中断处理代码(我们只使用了接收挂起中断),找到对应的处理,使用回调函数

HAL_CAN_RxFifo0MsgPendingCallback 进行相应中断的处理

基于CubeMX-STM32F302_CAN通信_第8张图片

 中断回调处理代码:

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	if(hcan->Instance == CAN)
	{
		HAL_CAN_GetRxMessage(hcan,CAN_FilterFIFO0,&My_RxHeader,Rx_DataBuff);
	}
	
	if(My_RxHeader.IDE == CAN_ID_STD)
	{
		if(My_RxHeader.StdId == 0x00500000)
		{
		
		}
	}
	if(My_RxHeader.IDE == CAN_ID_EXT)
	{
		if(My_RxHeader.ExtId == 0x00500000)
		{
			led(1);
		}
		if(My_RxHeader.ExtId == 0x00510000)
		{
			led(2);
		}
		if(My_RxHeader.ExtId == 0x00520000)
		{
			led(3);
		}
		if(My_RxHeader.ExtId == 0x00530000)
		{
			led(4);
		}
	}
}

4.4、主函数的配置

添加测试代码

 基于CubeMX-STM32F302_CAN通信_第9张图片

 代码:

 while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  
	  printf("CAN通信测试 帧ID = %x \r\n",CAN_YAW_ID);
	  
	  CAN_SendData(&hcan,0x00510000,Rx_DataBuff,8);
  }
  /* USER CODE END 3 */

5、测试

 基于CubeMX-STM32F302_CAN通信_第10张图片

你可能感兴趣的:(#,STM32,CAN,ARM,STM32,嵌入式)