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


前言

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;
			}
	}	
}

总结

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
STM32CubeMX是ST官方推出的一款图形化配置工具,可以帮助开发者快速配置STM32系列单片机的引脚、时钟、外设等,同时也可以生成基于HAL库的初始化代码。对于CAN通讯的配置,可以按照以下步骤进行: 1. 打开STM32CubeMX工具,选择对应的芯片型号。 2. 在Pinout & Configuration选项卡中,选择CAN1或CAN2外设,然后在右侧的配置面板中进行引脚配置,包括RX和TX引脚的选择、模式配置等。 3. 在Configuration选项卡中,选择CAN外设,然后在右侧的配置面板中进行相应的配置,包括波特率、传输模式、过滤器等。 4. 生成代码并导入到IDE中,然后在代码中调用HAL库提供的相关CAN API函数,进行CAN通讯的初始化和数据收发操作。 以下是一个简单的CAN通讯发送数据的代码示例: ```c #include "stm32f4xx_hal.h" CAN_HandleTypeDef hcan; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_CAN1_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_CAN1_Init(); CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailbox; uint8_t TxData[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; TxHeader.StdId = 0x123; TxHeader.ExtId = 0; TxHeader.RTR = CAN_RTR_DATA; TxHeader.IDE = CAN_ID_STD; TxHeader.DLC = 8; TxHeader.TransmitGlobalTime = DISABLE; while (1) { if (HAL_CAN_GetTxMailboxesFreeLevel(&hcan) != 0) { HAL_CAN_AddTxMessage(&hcan, &TxHeader, TxData, &TxMailbox); break; } } while (1) { } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 8; RCC_OscInitStruct.PLL.PLLN = 168; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; HAL_RCC_OscConfig(&RCC_OscInitStruct); RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5); } static void MX_CAN1_Init(void) { hcan.Instance = CAN1; hcan.Init.Prescaler = 4; hcan.Init.Mode = CAN_MODE_NORMAL; hcan.Init.SyncJumpWidth = CAN_SJW_1TQ; hcan.Init.TimeSeg1 = CAN_BS1_8TQ; 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 = ENABLE; if (HAL_CAN_Init(&hcan) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } CAN_FilterTypeDef sFilterConfig; sFilterConfig.FilterBank = 0; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; sFilterConfig.FilterIdHigh = 0x0000; sFilterConfig.FilterIdLow = 0x0000; sFilterConfig.FilterMaskIdHigh = 0x0000; sFilterConfig.FilterMaskIdLow = 0x0000; sFilterConfig.FilterFIFOAssignment = 0; sFilterConfig.FilterActivation = ENABLE; sFilterConfig.SlaveStartFilterBank = 14; if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } } static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF9_CAN1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } ``` 以上代码初始化了CAN1外设,并发送了一个标准ID为0x123,数据为8个字节的CAN数据帧。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值