stm32 cubemx can通讯(2)过滤器设置说明代码分析

文章目录

  • 前言
  • 一、基础知识快速理解
    • 1.1 理解CAN标识符:
    • 1.2 过滤器的工作原理:
    • 1.3 如何配置过滤器:
  • 二、过滤器模式的选择(监听多个ID)
    • 2.1 使用掩码模式多个过滤器匹配多标准ID:
    • 2.2 使用掩码来匹配多个ID:(待写)
    • 2.3 使用列表模式来匹配多个标准ID:
  • 三、相关代码测试
    • 3.1 测试列表模式__标准ID
    • 3.2 测试掩码模式__标准ID
    • 3.3 测试回调函数接收到的ID
  • 总结


前言

stm32 cubemx can通讯(1)回环模式

过滤器可以说是can中最重要的东西,我也认为这个是一个相当复杂的一个东西。
一个刚刚学习的小白,以下文字只是自我学习的笔记,若有写错或不明确的地方请大佬指正。
CAN过滤器是一个非常重要的功能,它允许你只接收你关心的CAN消息,从而提高效率和性能。


一、基础知识快速理解

1.1 理解CAN标识符:

在CAN总线上,每个消息都有一个唯一的标识符(ID)。这个ID可以是11位(标准ID)或29位(扩展ID)。ID不仅仅是用来标识消息来源,而且还决定了消息的优先级:ID小的消息优先级更高。

1.2 过滤器的工作原理:

过滤器的工作原理是将传入的ID与预设的ID进行比较,然后决定是否接收这个消息。过滤器可以工作在两种模式下:

  • 列表模式 (Identifier List mode):
    在这种模式下,你可以为每个过滤器指定一个或多个ID。只有与这些ID匹配的消息才会被接收。
  • 掩码模式 (Identifier Mask mode):
    在这种模式下,你为每个过滤器指定一个ID和一个掩码。只有与这个ID匹配的消息才会被接收。掩码允许你定义哪些位是重要的(即需要匹配的)和哪些位可以忽略。例如,一个掩码0xFF0表示你只关心ID的高8位,而不关心低4位。

1.3 如何配置过滤器:

(下面只要知道大致流程就行不要知道sFilterConfig这些东西是啥,后面会说)

1.3节都是基于标准ID
首先, 我们考虑一个例子:我们只希望接收ID为0x123的消息,其他消息都忽略。

设置选择的过滤器:
sFilterConfig.FilterBank = 0; // 使用过滤器0

设置过滤器模式为掩码模式:
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;

使用32位模式:
这使得我们可以处理标准ID和扩展ID。
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;

指定我们关心的ID和掩码:
因为0x123是一个标准ID,我们可以这样配置:

sFilterConfig.FilterIdHigh = 0x123 << 5; // 11位ID需要左移5位
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0xFFFF; // 只关心高16位
sFilterConfig.FilterMaskIdLow = 0x0000; 

这样的配置意味着:我们只接收高16位是0x123,低16位可以是任何值的消息。由于标准ID只有11位,低16位永远是0,所以这正是我们想要的。

为什么左移5位?
STM32的CAN过滤器使用了一种特殊的方式来处理标准11位和扩展29位的ID。为了在32位寄存器中放入11位的标准ID,我们需要将其左移5位。这是硬件的要求,不是我们随便决定的。
所以,如果你有一个标准ID0x123,其二进制形式是:
100100011
为了将它放入STM32的过滤器寄存器,你需要将它左移5位:
100100011 00000
这就是为什么我们使用<< 5。

为什么只关心高16位
当我们说“只关心高16位”,其实是指在32位的掩码或ID中,我们只设置或匹配高16位。STM32的CAN过滤器将32位分为了两个16位的部分:FilterIdHigh和FilterIdLow。在我们的例子中,由于我们只处理一个11位的标准ID,所以我们只需要在FilterIdHigh部分设置它,而将FilterIdLow部分设置为0。

关于11位与16位的区别:
实际上,我们并不真的关心整个16位,只关心其中的高11位。但由于简化和兼容性的考虑,我们通常设置整个16位。
如果我们想要严格限制为只匹配高11位,并且确保其他位不匹配,我们可以使用0xF800作为掩码。这表示我们关心高11位(1111 1000 0000 0000),而不关心低5位。
总之,为了简化操作,我们通常使用0xFFFF作为掩码来接收所有与指定ID匹配的标准CAN消息。但如果你想要更精确的匹配,你可以调整掩码以只匹配高11位。

设置FIFO:
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
这意味着匹配的消息将被放入FIFO0。

二、过滤器模式的选择(监听多个ID)

当想要监听多个标准ID的时候,有几种方法可以实现:

简而言之,掩码告诉硬件哪些位是我们关心的,而过滤器则告诉硬件我们希望这些位的值是什么。如果接收到的消息与过滤器匹配(只在我们关心的位上),那么消息将被接受。

2.1 使用掩码模式多个过滤器匹配多标准ID:

STM32的CAN控制器提供了多个过滤器(具体数量取决于具体的STM32型号)。每个过滤器可以配置为匹配一个或多个ID。
例如,你想要监听两个标准ID:0x123和0x456。你可以设置两个过滤器,每个过滤器匹配一个ID。

// 过滤器0匹配0x123
sFilterConfig.FilterBank = 0;  // 使用过滤器0
sFilterConfig.FilterIdHigh = 0x123 << 5;
sFilterConfig.FilterMaskIdHigh = 0xFFFF;
HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);
// 过滤器1匹配0x456
sFilterConfig.FilterBank = 1;  // 使用过滤器1
sFilterConfig.FilterIdHigh = 0x456 << 5;
sFilterConfig.FilterMaskIdHigh = 0xFFFF;
HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);

2.2 使用掩码来匹配多个ID:(待写)

这种方法取决于你想要监听的ID的特性。如果这些ID有一定的位集合,你可以使用掩码来匹配它们。

2.3 使用列表模式来匹配多个标准ID:

在列表模式下,过滤器会尝试匹配你所列举的任何ID。对于标准ID,一个过滤器可以匹配两个ID。对于扩展ID,过滤器只能匹配一个ID。

这里是一个如何使用列表模式来匹配四个标准ID(0x1, 0x2, 0x3, 0x4)的示例:

// 过滤器1匹配0x1和0x2
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;
sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; // 16-bit列表模式用于标准ID

sFilterConfig.FilterIdHigh = 0x1 << 5;    // ID1
sFilterConfig.FilterIdLow = 0x2 << 5;     // ID2

HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);

// 过滤器2匹配0x3和0x4
sFilterConfig.FilterBank = 1;
sFilterConfig.FilterIdHigh = 0x3 << 5;    // ID3
sFilterConfig.FilterIdLow = 0x4 << 5;     // ID4

HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);

为什么使用 CAN_FILTERSCALE_16BIT 而不是 CAN_FILTERSCALE_32BIT?
当我们使用标准ID(11位)并希望用单个过滤器同时匹配多个ID时,CAN_FILTERSCALE_16BIT 是有意义的。STM32的CAN硬件允许我们在16位过滤模式下为两个标准ID设置单个过滤器。因此,每个32位寄存器可以分为两个16位部分,每部分用于一个标准ID。这使得硬件更加高效地匹配两个不同的ID,而不需要额外的过滤器。

关于 sFilterConfig.FilterIdHigh 和 sFilterConfig.FilterIdLow 的顺序:
过滤器的初始化顺序是可以互换的。你可以首先设置 FilterIdLow,然后再设置 FilterIdHigh。硬件只是看这两个值和接收的消息ID进行比较,不关心你是如何设置这两个值的。
sFilterConfig.FilterIdLow = 0x1 << 5; sFilterConfig.FilterIdHigh = 0x2 << 5;
这也是有效的,它将会匹配ID为 0x1 和 0x2 的消息。

三、相关代码测试

我们接着使用回环模式类似的代码,
这时候由于使用到了usb_can调试器,所以你要有一个这个东西。emm
然后cubemx里面的回环模式给位normal模式就行。
把发送函数改成这样,改动的地方在于。现在使用的是标准id,由于标准id最大支持11位,所以就要求最大不要超过0x7ff,并把ide改为id_std

void CAN_senddata(CAN_HandleTypeDef *hcan)
{
   TXHeader.StdId=0x7ff;//0X7FF因为标准id最大11位
	 TXHeader.ExtId=0x0000000;
	 TXHeader.DLC=8;
	 TXHeader.IDE=CAN_ID_STD;
	 TXHeader.RTR=CAN_RTR_DATA;
	 TXHeader.TransmitGlobalTime = DISABLE;
	 HAL_CAN_AddTxMessage(hcan,&TXHeader,TXmessage,&pTxMailbox);
}

3.1 测试列表模式__标准ID

只需要这些代码在can_init的位置就可以了。
当使用01 和 02进行发送的时候可以产生中断。其他的不行

  /* USER CODE BEGIN CAN_Init 2 */
		
	CAN_FilterTypeDef sFilterConfig;
	
	sFilterConfig.FilterActivation = ENABLE;
	sFilterConfig.FilterBank = 0;
	sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;
	sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; // 16-bit列表模式用于标准ID
	sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;//采用FIFO0

	sFilterConfig.FilterIdHigh = 0x1 << 5;    // ID1
	sFilterConfig.FilterIdLow = 0x2 << 5;     // ID2
	if(HAL_CAN_ConfigFilter(&hcan,&sFilterConfig) != HAL_OK)//初始化过滤器
	{
	Error_Handler();
	}
	if(HAL_CAN_Start(&hcan) != HAL_OK)//打开can
	{
	Error_Handler();
	}
	if(HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)//开启接受邮箱0挂起中断
	{
	Error_Handler();
	}

  /* USER CODE END CAN_Init 2 */

3.2 测试掩码模式__标准ID

只需要这些代码在can_init的位置就可以了。
当使用01 和 02进行发送的时候可以产生中断。其他的不行

	CAN_FilterTypeDef sFilterConfig;
	
	sFilterConfig.FilterActivation = ENABLE;
	sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 16-bit列表模式用于标准ID
	sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;//采用FIFO0
// 过滤器匹配0x1
	sFilterConfig.FilterBank = 0;
	sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;	
	sFilterConfig.FilterIdHigh = 0x1 << 5;
	sFilterConfig.FilterMaskIdHigh = 0xFFFF;
	if(HAL_CAN_ConfigFilter(&hcan,&sFilterConfig) != HAL_OK)//初始化过滤器
	{
	Error_Handler();
	}
// 过滤器匹配0x1
	sFilterConfig.FilterBank = 1;
	sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;	
	sFilterConfig.FilterIdHigh = 0x2<< 5;
	sFilterConfig.FilterMaskIdHigh = 0xFFFF;
	
	if(HAL_CAN_ConfigFilter(&hcan,&sFilterConfig) != HAL_OK)//初始化过滤器
	{
	Error_Handler();
	}
	

3.3 测试回调函数接收到的ID

int  cc =0;
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)//接受邮箱0挂起中断回调函数
{
	if(hcan->Instance == CAN1)
	{
			// 获取数据
			HAL_CAN_GetRxMessage(hcan, CAN_FILTER_FIFO0, &RXHeader, RXmessage);

			// 根据接收到的ID进行处理
			switch (RXHeader.StdId)
			{
					case 0x1:
							// 对于ID 0x1的处理代码
							cc=1;
							break;

					case 0x2:
							// 对于ID 0x2的处理代码
							cc=2;
							break;
					default:
							// 其他未知ID的处理(如果需要)
							break;
			}
	}	
}

总结

你可能感兴趣的:(stm32,stm32,嵌入式硬件,单片机)