打印
[应用相关]

谈STM32的CAN过滤器

[复制链接]
楼主: l63t89
手机看帖
扫描二维码
随时随地手机跟帖
41
l63t89|  楼主 | 2022-4-30 20:06 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
引脚如下:

PD0: CAN1_Rx

PD1: CAN1_Tx

PG6: LED1

PG8: LED2

PI9:  LED3

PC7: LED4

使用特权

评论回复
42
l63t89|  楼主 | 2022-4-30 20:07 | 只看该作者
时钟树如下设置:

使用特权

评论回复
43
l63t89|  楼主 | 2022-4-30 20:08 | 只看该作者
在配置中的NVIC中,打开CAN1 RX0接收中断,如下图所示:

使用特权

评论回复
44
l63t89|  楼主 | 2022-4-30 20:11 | 只看该作者

使用特权

评论回复
45
l63t89|  楼主 | 2022-4-30 20:14 | 只看该作者
其他的没有什么特殊设置,生成工程后的main函数如下:
int main(void)
{

  /* USER CODE BEGIN 1 */
  static CanTxMsgTypeDef        TxMessage;
  static CanRxMsgTypeDef        RxMessage;
  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_CAN1_Init();

  /* USER CODE BEGIN 2 */
  hcan1.pTxMsg =&TxMessage;
  hcan1.pRxMsg =&RxMessage;
  CANFilterConfig_Scale32_IdList();                        //列表模式-32位宽
//CANFilterConfig_Scale16_IdList();                        //列表模式-16位宽
//CANFilterConfig_Scale32_IdMask_StandardIdOnly();        //掩码模式-32位宽(只有标准CAN ID)
//CANFilterConfig_Scale32_IdMask_ExtendIdOnly();        //掩码模式-32位宽(只用扩展CAN ID)
//CANFilterConfig_Scale32_IdMask_StandardId_ExtendId_Mix(); //掩码模式-32位宽(标准CANID与扩展CAN ID混合)
//CANFilterConfig_Scale16_IdMask();                        //掩码模式-16位宽
  HAL_CAN_Receive_IT(&hcan1,CAN_FIFO0);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

}

使用特权

评论回复
46
l63t89|  楼主 | 2022-4-30 20:16 | 只看该作者
如上代码所示,示例中将采用各种过滤器配置来演示,在测试时我们可以只保留一种配置,也可以全部打开,为了确保每种配置的准确性,这里建议只保留其中一种配置进行测试。

使用特权

评论回复
47
l63t89|  楼主 | 2022-4-30 20:18 | 只看该作者
另外,接收中断回调函数如下所示:
void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan)
{
  if(hcan->pRxMsg->StdId ==0x321)
  {
    //handle the CAN message
    HandleCANMessage(hcan->pRxMsg);                //处理接收到的CAN报文
  }
  if(hcan->pRxMsg->ExtId ==0x1800f001)
  {
     HandleCANMessage(hcan->pRxMsg);                //处理接收到的CAN报文
  }
  HAL_GPIO_WritePin(LED4_GPIO_Port,LED4_Pin,GPIO_PIN_SET);    //若收到消息则闪烁下LED4
  HAL_Delay(200);
  HAL_GPIO_WritePin(LED4_GPIO_Port,LED4_Pin,GPIO_PIN_RESET);  
  HAL_CAN_Receive_IT(&hcan1,CAN_FIFO0);
}

使用特权

评论回复
48
l63t89|  楼主 | 2022-4-30 21:40 | 只看该作者
接下来将分别介绍过滤器的4中工作模式以及所对应的代码示例。

使用特权

评论回复
49
l63t89|  楼主 | 2022-4-30 21:40 | 只看该作者
4.2.   32位宽的列表模式

使用特权

评论回复
50
l63t89|  楼主 | 2022-4-30 22:14 | 只看该作者
如上图所示,在32位宽的列表模式下,CAN_FxR1与CAN_FxR2都用来存储希望通过的CAN ID,由于是32位宽的,因此既可以存储标准CAN ID,也可以存储扩展CAN ID。注意看上图最底下的各位定义,可以看出,从右到左,首先,最低位是没有用的,然后是RTR,表示是否为远程帧,接着IDE,扩展帧标志,然后才是EXID[0:17]这18位扩展ID,最后才是STID[0:10]这11位标准ID,也就是前面所说的基本ID。在进行配置的时候,即将希望通过的CAN ID写入的时候,要注意各个位对号入座,即基本ID放到对应的STD[0:10],扩展ID对应放到EXID[0:17],若是扩展帧,则需要将IDE设为“1”,标准帧则为“0”,数据帧设RTR为“0”,远程帧设RTR为“1”。、

使用特权

评论回复
51
l63t89|  楼主 | 2022-4-30 22:14 | 只看该作者
示例代码如下:

static void CANFilterConfig_Scale32_IdList(void)
{
  CAN_FilterConfTypeDef  sFilterConfig;
  uint32_t StdId =0x321;                                //这里写入两个CAN ID,一个位标准CAN ID
  uint32_t ExtId =0x1800f001;                        //一个位扩展CAN ID
  
  sFilterConfig.FilterNumber = 0;                                //使用过滤器0
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;                //设为列表模式
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;        //配置为32位宽
  sFilterConfig.FilterIdHigh = StdId<<5;                        //基本ID放入到STID中
  sFilterConfig.FilterIdLow = 0|CAN_ID_STD;                        //设置IDE位为0
  sFilterConfig.FilterMaskIdHigh = ((ExtId<<3)>>16)&0xffff;
  sFilterConfig.FilterMaskIdLow = (ExtId<<3)&0xffff|CAN_ID_EXT;        //设置IDE位为1
  sFilterConfig.FilterFIFOAssignment = 0;                        //接收到的报文放入到FIFO0中
  sFilterConfig.FilterActivation = ENABLE;
  sFilterConfig.BankNumber = 14;
  
  if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

使用特权

评论回复
52
l63t89|  楼主 | 2022-4-30 22:15 | 只看该作者
这里需要说明一下,由于我们使用的是cube库,在cube库中,CAN_FxR1与CAN_FxR2寄存器分别被拆成两段,CAN_FxR1寄存器的高16位对应着上面代码中的FilterIdHigh,低16位对应着FilterIdLow,而CAN_FxR2寄存器的高16位对应着FilterMaskIdHigh,低16位对应着FilterMaskIdLow,这个CAN_FilterConfTypeDef的的4个成员FilterIdHigh,FilterIdLow,FilterMaskIdHigh,FilterMaskIdLow,不应该单纯看其名字,被其名字误导,而应该就单纯地将这4个成员看成4个uint_16类型的变量x,y,m,n而已,后续其他示例也是同样理解,不再重复解释。这4个16位的变量其具体含义取决于当前过滤器工作与何种模式,比如当前32位宽的列表模式下,FilterIdHigh与FilterIdLow一起用来存放一个CAN ID,FilterMaskIdHigh与FilterMaskIdLow用来存放另一个CAN ID,不再表示其字面所示的mask含义,这点我们需要特别注意。

使用特权

评论回复
53
l63t89|  楼主 | 2022-4-30 22:16 | 只看该作者
在上述代码示例中,我们分别将标准CAN ID和扩展CAN ID放入到CAN_FxR1与CAN_FxR2寄存器中。对于标准CAN ID,对比 图11,由于标准CAN ID只拥有标准ID,所以,只需要将标准ID放入到高16位的STID[0:10]中,高16位最右边被EXID[13:17]占着,因此,需要将StdId左移5位才能刚好放入到CAN_FxR1的高16位中,于是有了:
sFilterConfig.FilterIdHigh = StdId<<5;

使用特权

评论回复
54
l63t89|  楼主 | 2022-4-30 22:18 | 只看该作者
另一个扩展CAN ID ExtId类型,将其基本ID放入到STID中,扩展ID放入到EXID中,最后设置IDE位为1。就这样配置好了。

使用特权

评论回复
55
l63t89|  楼主 | 2022-4-30 22:19 | 只看该作者
如上图所示,在16位宽的列表模式下,FilterIdHigh,FilterIdLow,FilterMaskIdHigh,FilterMaskIdLow这4个16位变量都是用来存储一个标准CAN ID,这样,就可以存放4个标准CAN ID了,需要注意地是,此种模式下,是不能处理扩展CANID,凡是需要过滤扩展CAN ID的,都是需要用到32位宽的模式。

使用特权

评论回复
56
l63t89|  楼主 | 2022-4-30 23:39 | 只看该作者
于是有以下代码示例:
static void CANFilterConfig_Scale16_IdList(void)
{
  CAN_FilterConfTypeDef  sFilterConfig;
  uint32_t StdId1 =0x123;                                                //这里采用4个标准CAN ID作为例子
  uint32_t StdId2 =0x124;
  uint32_t StdId3 =0x125;
  uint32_t StdId4 =0x126;
  
  sFilterConfig.FilterNumber = 1;                                //使用过滤器1
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;                //设为列表模式
  sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;        //位宽设置为16位
  sFilterConfig.FilterIdHigh = StdId1<<5;         //4个标准CAN ID分别放入到4个存储中
  sFilterConfig.FilterIdLow = StdId2<<5;
  sFilterConfig.FilterMaskIdHigh = StdId3<<5;
  sFilterConfig.FilterMaskIdLow = StdId4<<5;
  sFilterConfig.FilterFIFOAssignment = 0;                        //接收到的报文放入到FIFO0中
  sFilterConfig.FilterActivation = ENABLE;
  sFilterConfig.BankNumber = 14;
  
  if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

使用特权

评论回复
57
kiwis66| | 2022-5-5 09:33 | 只看该作者
一直没用过这功能,学习了

使用特权

评论回复
58
Uriah| | 2022-10-7 08:07 | 只看该作者

需要在做项目的过程中经历磨难

使用特权

评论回复
59
Bblythe| | 2022-10-7 11:06 | 只看该作者

结构化模块化的程序设计的思想,使最基本的要求

使用特权

评论回复
60
Pulitzer| | 2022-10-7 14:05 | 只看该作者

写程序不难,但是程序怎么样才能写的好,写的快,那是需要点经验积累的

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则