打印
[STM32F1]

Stm32f103的can硬件滤波配置与调试

[复制链接]
346|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
需要实现一条can总线上连接许多can设备,如果can设备都接收can中断数据的话,cpu会消耗较多资源,于是想到了使用can模块的硬件滤波功能,can设备自身需要的几个stdid信号可以接收到,其他的都做硬件滤波过滤掉。
can的硬件滤波分精准识别(标识符识别列表)和mask(部分过滤)两种方式;有两个32bit寄存器,分别设置为16bit过滤或者32bit过滤,入下图所示(全0为不使用过滤器):
  sFilterConfig.FilterIdHigh = 0x0000;//32 位 ID                  不使用过滤器
  sFilterConfig.FilterIdLow = 0x0000;
  sFilterConfig.FilterMaskIdHigh = 0x0000;//32 位 MASK
  sFilterConfig.FilterMaskIdLow = 0x0000;       
标准std和扩展std的时序,如下图所示,扩展std跟stm32的filter寄存器正好偏移三位;标准std则是偏移5bit,需要在函数处理的时候,进行移位处理。


使用特权

评论回复
沙发
等你下课|  楼主 | 2022-4-30 23:53 | 只看该作者

使用特权

评论回复
板凳
等你下课|  楼主 | 2022-4-30 23:54 | 只看该作者
上图为stm32屏蔽寄存器对应的std的映射图,例字如下:
  CAN_FilterTypeDef  sFilterConfig;
  
  uint32_t StdId = 0x321;                                //这里写入两个CAN ID,一个位标准CAN ID
  uint32_t ExtId = 0x1800f001;                        //一个位扩展CAN ID
  
  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

使用特权

评论回复
地板
等你下课|  楼主 | 2022-4-30 23:55 | 只看该作者
后面的为完整的函数,各种掩码、不同滤波方式
#include "FreeRTOS.h"
#include "main.h"
#include "cmsis_os.h"
#include "can.h"
#include "can_filter.h"
#include "stdlib.h"
#include "string.h"

#ifdef USE_CAN_FILTER_IN_BOARD_XIANSHU
extern int g_device_id;
#endif

extern CAN_HandleTypeDef hcan;


/*******************************************************************************
* 函数名 : CANFilterConfig_AnyId
* 描  述 : 过滤器关闭,任何id数据都能接收
* 输  入 : 无
* 输  出 : 无
* 返回值 : 无
* 说  明 :
*******************************************************************************/
void CANFilterConfig_AnyId(void)
{
  //CAN_FilterConfTypeDef  sFilterConfig;
  CAN_FilterTypeDef sFilterConfig;

  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
  
  if(HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
  {
        Error_Handler();
  }
}


/*******************************************************************************
* 函数名 : CANFilterConfig_Scale32_IdMask_StandardIdOnly
* 描  述 : 32bit掩码滤波 只过滤接收函数中设置的那几个标准帧id的数据
* 输  入 : 无
* 输  出 : 无
* 返回值 : 无
* 说  明 :
*******************************************************************************/
void CANFilterConfig_Scale32_IdMask_StandardIdOnly(void)
{
  //CAN_FilterConfTypeDef  sFilterConfig;
  CAN_FilterTypeDef sFilterConfig;
  uint16_t                mask,num,tmp,i;

  #ifdef USE_CAN_FILTER_IN_BOARD_XIANSHU
  uint16_t StdIdArray[4] = {0}; //定义一组标准CAN ID

  StdIdArray[0] = BASE_ID_RECV | (g_device_id << 4) | CAN_HEART_BEAT;  //0x200,0x210...0x270
  StdIdArray[1] = BASE_ID_RECV | (g_device_id << 4) | CAN_GPIO_SET;  //0x201,0x211...0x271
  StdIdArray[2] = BASE_ID_RECV | (g_device_id << 4) | CAN_GPIO_GET;  //0x202,0x212...0x272
  StdIdArray[3] = BASE_ID_RECV | (g_device_id << 4) | CAN_VOICE_SET;  //0x203,0x213...0x273
  #else
  
  uint16_t StdIdArray[10] ={0x200,0x201,0x202,0x203,0x204,
                                                                0x205,0x206,0x207,0x208,0x209}; //定义一组标准CAN ID
  #endif
  
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;         //配置为掩码模式
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;        //设置为32位宽
  sFilterConfig.FilterIdHigh =(StdIdArray[0]<<5);                //验证码可以设置为StdIdArray[]数组中任意一个,这里使用StdIdArray[0]作为验证码
  sFilterConfig.FilterIdLow =0;
  
  mask =0x7ff;                                                //下面开始计算屏蔽码
  num =sizeof(StdIdArray)/sizeof(StdIdArray[0]);
  for(i =0; i<num; i++)         //屏蔽码位StdIdArray[]数组中所有成员的同或结果
  {
        tmp =StdIdArray[i] ^ (~StdIdArray[0]);        //所有数组成员与第0个成员进行同或操作
        mask &=tmp;
  }
  sFilterConfig.FilterMaskIdHigh =(mask<<5);
  sFilterConfig.FilterMaskIdLow =0|0x02;                //只接收数据帧
  
  sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;                //设置通过的数据帧进入到FIFO0中
  sFilterConfig.FilterActivation = ENABLE;                                                //激活过滤器
  sFilterConfig.FilterBank = 0;                  //过滤器0     0~13 数字越小,优先级越高
  
  if(HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
  {
        Error_Handler();
  }
}



/*******************************************************************************
* 函数名 : CANFilterConfig_Scale32_IdList
* 描  述 : 32bit列表滤波 精确识别id,可以同时识别出标准和扩展id号
* 输  入 : 无
* 输  出 : 无
* 返回值 : 无
* 说  明 :
*******************************************************************************/
void CANFilterConfig_Scale32_IdList(void)
{
  CAN_FilterTypeDef  sFilterConfig;
  
  uint32_t StdId = 0x321;                                //这里写入两个CAN ID,一个位标准CAN ID
  uint32_t ExtId = 0x1800f001;                        //一个位扩展CAN ID
  
  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.FilterBank = 14;                        //过滤器14     0~13 数字越小,优先级越高
  
  if(HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

/*******************************************************************************
* 函数名 : CANFilterConfig_Scale16_IdList
* 描  述 : 16bit列表滤波 精确识别id(只能识别标准id),一个滤波器只能识别4个标准id
* 输  入 : 无
* 输  出 : 无
* 返回值 : 无
* 说  明 :
*******************************************************************************/
void CANFilterConfig_Scale16_IdList(void)
{
  CAN_FilterTypeDef  sFilterConfig;
  uint32_t StdId1 =0x123;                                                //这里采用4个标准CAN ID作为例子
  uint32_t StdId2 =0x124;
  uint32_t StdId3 =0x125;
  uint32_t StdId4 =0x126;
  

  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.FilterBank = 14;
  
  if(HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}


/*******************************************************************************
* 函数名 : CANFilterConfig_Scale32_IdMask_ExtendIdOnly
* 描        述 : 32bit掩码滤波 只过滤接收函数中设置的那几个扩展帧数据
* 输        入 : 无
* 输        出 : 无
* 返回值 : 无
* 说        明 :
*******************************************************************************/
void CANFilterConfig_Scale32_IdMask_ExtendIdOnly(void)
{
  CAN_FilterTypeDef  sFilterConfig;
  //定义一组扩展CAN ID用来测试
  uint32_t ExtIdArray[10] ={0x1839f101,0x1835f102,0x1835f113,0x1835f124,0x1835f105,
                            0x1835f106,0x1835f107,0x1835f108,0x1835f109,0x1835f10A};
  uint32_t      mask,num,tmp,i;
  
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;                        //配置为掩码模式
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;                //设为32位宽
  sFilterConfig.FilterIdHigh =((ExtIdArray[0]<<3) >>16) &0xffff;//数组任意一个成员都可以作为验证码
  sFilterConfig.FilterIdLow =((ExtIdArray[0]<<3)&0xffff) | CAN_ID_EXT;
  
  mask =0x1fffffff;
  num =sizeof(ExtIdArray)/sizeof(ExtIdArray[0]);
  for(i =0; i<num; i++)                                //屏蔽码位数组各成员相互同或的结果
  {
    tmp =ExtIdArray[i] ^ (~ExtIdArray[0]);        //都与第一个数据成员进行同或操作
    mask &=tmp;
  }
  mask <<=3;                                                                    //对齐寄存器
  sFilterConfig.FilterMaskIdHigh = (mask>>16)&0xffff;
  sFilterConfig.FilterMaskIdLow = (mask&0xffff)|0x02;                 //只接收数据帧
  sFilterConfig.FilterFIFOAssignment = 0;
  sFilterConfig.FilterActivation = ENABLE;
  sFilterConfig.FilterBank = 14;
  
  if(HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}


/*******************************************************************************
* 函数名 : CANFilterConfig_Scale32_IdMask_StandardId_ExtendId_Mix
* 描  述 : 32bit掩码滤波 只过滤接收函数中设置的那几个扩展帧和标准帧数据
* 输  入 : 无
* 输  出 : 无
* 返回值 : 无
* 说  明 :
*******************************************************************************/
void CANFilterConfig_Scale32_IdMask_StandardId_ExtendId_Mix(void)
{
  CAN_FilterTypeDef  sFilterConfig;
  //定义一组标准CAN ID
  uint32_t StdIdArray[10] ={0x711,0x712,0x713,0x714,0x715,
                          0x716,0x717,0x718,0x719,0x71a};
  //定义另外一组扩展CAN ID
  uint32_t ExtIdArray[10] ={0x1900fAB1,0x1900fAB2,0x1900fAB3,0x1900fAB4,0x1900fAB5,
                            0x1900fAB6,0x1900fAB7,0x1900fAB8,0x1900fAB9,0x1900fABA};
  uint32_t      mask,num,tmp,i,standard_mask,extend_mask,mix_mask;
  
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;                //配置为掩码模式
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;        //设为32位宽
  sFilterConfig.FilterIdHigh =((ExtIdArray[0]<<3) >>16) &0xffff;        //使用第一个扩展CAN  ID作为验证码
  sFilterConfig.FilterIdLow =((ExtIdArray[0]<<3)&0xffff);
  
  standard_mask =0x7ff;                //下面是计算屏蔽码
  num =sizeof(StdIdArray)/sizeof(StdIdArray[0]);
  for(i =0; i<num; i++)                        //首先计算出所有标准CAN ID的屏蔽码
  {
    tmp =StdIdArray[i] ^ (~StdIdArray[0]);
    standard_mask &=tmp;
  }
  
  extend_mask =0x1fffffff;
  num =sizeof(ExtIdArray)/sizeof(ExtIdArray[0]);
  for(i =0; i<num; i++)                        //接着计算出所有扩展CAN ID的屏蔽码
  {
    tmp =ExtIdArray[i] ^ (~ExtIdArray[0]);
    extend_mask &=tmp;
  }
  mix_mask =(StdIdArray[0]<<18)^ (~ExtIdArray[0]);        //再计算标准CAN ID与扩展CAN ID混合的屏蔽码
  mask =(standard_mask<<18)& extend_mask &mix_mask;        //最后计算最终的屏蔽码
  mask <<=3;                                                    //对齐寄存器

  sFilterConfig.FilterMaskIdHigh = (mask>>16)&0xffff;
  sFilterConfig.FilterMaskIdLow = (mask&0xffff);
  sFilterConfig.FilterFIFOAssignment = 0;
  sFilterConfig.FilterActivation = ENABLE;
  sFilterConfig.FilterBank = 14;
  
  if(HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}




/*******************************************************************************
* 函数名 : CANFilterConfig_Scale16_IdMask
* 描        述 : 16bit掩码滤波 可以识别两组标准帧
* 输        入 : 无
* 输        出 : 无
* 返回值 : 无
* 说        明 :
*******************************************************************************/
void CANFilterConfig_Scale16_IdMask(void)
{
  CAN_FilterTypeDef  sFilterConfig;
  uint16_t StdIdArray1[10] ={0x7D1,0x7D2,0x7D3,0x7D4,0x7D5,        //定义第一组标准CAN ID
                          0x7D6,0x7D7,0x7D8,0x7D9,0x7DA};
  uint16_t StdIdArray2[10] ={0x751,0x752,0x753,0x754,0x755,        //定义第二组标准CAN ID
                          0x756,0x757,0x758,0x759,0x75A};
  uint16_t      mask,tmp,i,num;
  
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;                        //配置为掩码模式
  sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;                //设为16位宽
  
  //配置第一个过滤对
  sFilterConfig.FilterIdLow =StdIdArray1[0]<<5;                        //设置第一个验证码
  mask =0x7ff;
  num =sizeof(StdIdArray1)/sizeof(StdIdArray1[0]);
  for(i =0; i<num; i++)                                                        //计算第一个屏蔽码
  {
    tmp =StdIdArray1[i] ^ (~StdIdArray1[0]);
    mask &=tmp;
  }
  sFilterConfig.FilterMaskIdLow =(mask<<5)|0x10;    //只接收数据帧
  
  //配置第二个过滤对
  sFilterConfig.FilterIdHigh = StdIdArray2[0]<<5;        //设置第二个验证码
  mask =0x7ff;
  num =sizeof(StdIdArray2)/sizeof(StdIdArray2[0]);
  for(i =0; i<num; i++)                                        //计算第二个屏蔽码
  {
    tmp =StdIdArray2[i] ^ (~StdIdArray2[0]);
    mask &=tmp;
  }
  sFilterConfig.FilterMaskIdHigh = (mask<<5)|0x10;  //只接收数据帧
  

  sFilterConfig.FilterFIFOAssignment = 0;                //通过的CAN 消息放入到FIFO0中
  sFilterConfig.FilterActivation = ENABLE;
  sFilterConfig.FilterBank = 14;
  
  if(HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}



使用特权

评论回复
5
等你下课|  楼主 | 2022-4-30 23:55 | 只看该作者
上述函数在can初始化的时候进行调用就行了,

使用特权

评论回复
6
等你下课|  楼主 | 2022-4-30 23:56 | 只看该作者
void MX_CAN_Init(void)
{
        CAN_FilterTypeDef sFilterConfig;

  hcan.Instance = CAN1;
  hcan.Init.Prescaler = 32;//32;                //pclk0=32Mhz            /16=2Mhz   ;/32=1Mhz(default:100k)
  hcan.Init.Mode = CAN_MODE_NORMAL;
  hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan.Init.TimeSeg1 = CAN_BS1_4TQ;
  hcan.Init.TimeSeg2 = CAN_BS2_5TQ;
  hcan.Init.TimeTriggeredMode = DISABLE;
  hcan.Init.AutoBusOff = DISABLE;
  hcan.Init.AutoWakeUp = DISABLE;
  hcan.Init.AutoRetransmission = DISABLE;
  hcan.Init.ReceiveFifoLocked = DISABLE;
  hcan.Init.TransmitFifoPriority = DISABLE;


#if 1                //500k config   bitrate = 2Mhz/(SyncJumpWidth+TimeSeg1+TimeSeg2) = 500k
        hcan.Init.Prescaler = 16;                  //pclk0=32Mhz          /16=2Mhz
        hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
        hcan.Init.TimeSeg1 = CAN_BS1_2TQ;//CAN_BS1_2TQ
        hcan.Init.TimeSeg2 = CAN_BS2_1TQ;
#endif

  if (HAL_CAN_Init(&hcan) != HAL_OK)
  {
    Error_Handler();
  }


#if 1
        //CANFilterConfig_AnyId();
        CANFilterConfig_Scale32_IdMask_StandardIdOnly();
        //CANFilterConfig_Scale32_IdList();
        //CANFilterConfig_Scale16_IdList();
        //CANFilterConfig_Scale32_IdMask_ExtendIdOnly();
        //CANFilterConfig_Scale32_IdMask_StandardId_ExtendId_Mix();
        //CANFilterConfig_Scale16_IdMask();       
#endif       

        __HAL_CAN_ENABLE_IT(&hcan, 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(&gpcan_rx, mag_rxbuffer, CAN_RXBUFFER_SIZE);

}

使用特权

评论回复
7
sadicy| | 2022-5-1 17:19 | 只看该作者
can的话,除了在汽车上,其他地方还有哪里应用多

使用特权

评论回复
8
kiwis66| | 2022-5-2 14:58 | 只看该作者
学习了,开始使用can了

使用特权

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

本版积分规则

34

主题

389

帖子

0

粉丝