stm32中的CAN通讯列表模式配置解析与源码

 STM32之CAN ---CAN ID过滤器分析与设置 CAN_FilterInit

 
  1. /* Setup the identifier information */

  2. if (format == STANDARD_FORMAT)

  3. { /* Standard ID */

  4. CAN_msgMask |= (u32)(mask << 21) | CAN_ID_STD;

  5. }

  6. else

  7. { /* Extended ID */

  8. CAN_msgMask |= (u32)(mask << 3) | CAN_ID_EXT;

  9. }

  10. if (format == STANDARD_FORMAT)

  11. { /* Standard ID */

  12. CAN_msgId |= (u32)(id << 21) | CAN_ID_STD;

  13. }

  14. else

  15. { /* Extended ID */

  16. CAN_msgId |= (u32)(id << 3) | CAN_ID_EXT;

  17. }

  18. CAN1->sFilterRegister[CAN_filterIdx].FR1 = CAN_msgId; /* 32-bit identifier */

  19. CAN1->sFilterRegister[CAN_filterIdx].FR2 = CAN_msgMask; /* 32-bit Mask */

选择两个32位筛选器,列表模式的话就是14*2=28个CAN帧。
假如我想要筛选一个0x10f46601的帧,它的二进制为:
0001 0000 1111 0100 0110 0110 0000 0001
而筛选器为:
xxxx xxxx xxxx xxxx xxxx xxxx xxxx x100 ,后面的100是因为扩展数据帧
也就是说把上面要筛选的帧弄到这个筛选的X中,即:
1 0000 1111 0100 0110 0110 0000 0001 100 ,整理一下有:
1000 0111 1010 0011 0011 0000 0000 1100 ==0x87a3 300c
整到结构体中就是 

 
  1. CAN_FilterInitStructure.CAN_FilterIdHigh= 0x87a3; //授时帧0x10f46601//要过滤的ID高位

  2. CAN_FilterInitStructure.CAN_FilterIdLow= 0x300c;

  3. 1212

观察上面可知:0001 0000 1111 0100 011 // 0 0110 0000 0001
所以CAN_FilterIdHigh=(0x10f46601>>13) & 0xffff
CAN_FilterIdLow= ((0x10f46601<<3) | 0x04) & 0xffff
完整配置如下,筛选3*2=6个帧

 
  1. static void CAN_Filter_Config()

  2. {

  3. CAN_FilterInitTypeDef CAN_FilterInitStructure;

  4. /*CAN过滤器初始化*/

  5. CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器组0

  6. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList; //工作在列表模式//工作在标识符屏蔽位模式

  7. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //过滤器位宽为单个32位。

  8. /* 使能报文标示符过滤器按照标示符的内容进行比对过滤,扩展ID不是如下的就抛弃掉,是的话,会存入FIFO0。 */

  9. CAN_FilterInitStructure.CAN_FilterIdHigh= 0x87a3; //授时帧0x10f46601//要过滤的ID高位

  10. CAN_FilterInitStructure.CAN_FilterIdLow= 0x300c;

  11. CAN_FilterInitStructure.CAN_FilterMaskIdHigh = (((0x10f46602)>>13)&0xffff); //授时帧0x10f46602

  12. CAN_FilterInitStructure.CAN_FilterMaskIdLow= (((((uint32_t)0x10f46602)<<3)|(0x00000004))&0xffff);

  13. CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; //过滤器被关联到FIFO0

  14. CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; //使能过滤器

  15. CAN_FilterInit(&CAN_FilterInitStructure);

  16. CAN_FilterInitStructure.CAN_FilterNumber=1; //过滤器组1

  17. CAN_FilterInitStructure.CAN_FilterIdHigh=((((0x08840001|(Derailment_Addr<<8) ))>>13)&0xffff); //收到主机1给予的控制帧

  18. CAN_FilterInitStructure.CAN_FilterIdLow=(((((uint32_t)(0x08840001|(Derailment_Addr<<8) ))<<3)|(0x00000004))&0xffff);

  19. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=((((0x08840002|(Derailment_Addr<<8) ))>>13)&0xffff); //收到主机2给予的控制帧

  20. CAN_FilterInitStructure.CAN_FilterMaskIdLow=(((((uint32_t)(0x08840002|(Derailment_Addr<<8) ))<<3)|(0x00000004))&0xffff);

  21. CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; //过滤器被关联到FIFO0

  22. CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; //使能过滤器

  23. CAN_FilterInit(&CAN_FilterInitStructure);

  24. CAN_FilterInitStructure.CAN_FilterNumber=2; //过滤器组2

  25. CAN_FilterInitStructure.CAN_FilterIdHigh= (((( 0x04780001|(Derailment_Addr<<8) ))>>13)&0xffff); //收到主机1关于报警帧的响应

  26. CAN_FilterInitStructure.CAN_FilterIdLow= (((((uint32_t)( 0x04780001|(Derailment_Addr<<8) ))<<3)|(0x00000004))&0xffff);

  27. CAN_FilterInitStructure.CAN_FilterMaskIdHigh= (((( 0x04780002|(Derailment_Addr<<8) ))>>13)&0xffff); //收到主机2关于报警帧的响应

  28. CAN_FilterInitStructure.CAN_FilterMaskIdLow= (((((uint32_t)( 0x04780002|(Derailment_Addr<<8) ))<<3)|(0x00000004))&0xffff);

  29. CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; //过滤器被关联到FIFO0

  30. CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; //使能过滤器

  31. CAN_FilterInit(&CAN_FilterInitStructure);

  32. CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); /*CAN通信中断使能*/

  33. }

4、can总线的id过滤
对扩展数据帧过滤:

CAN_FilterInitStructure.CAN_FilterNumber   = 0; 
CAN_FilterInitStructure.CAN_FilterMode     = CAN_FilterMode_IdMask; 
CAN_FilterInitStructure.CAN_FilterScale    = CAN_FilterScale_32bit; 
CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)CAN_ID<<3)&0xFFFF0000)>>16; 
CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)CAN_ID<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; 
CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF; 
CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFF; 

对标准数据帧过滤:

CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)CAN_ID0<<21)&0xFFFF0000)>>16; 
CAN_FilterInitStructure.CAN_FilterIdLow=(((u32)CAN_ID0<<21)|CAN_ID_STD|CAN_RTR_DATA)&0xFFFF; 
CAN_FilterInitStructure.CAN_FilterMaskIdHigh   = 0xFFFF; 
CAN_FilterInitStructure.CAN_FilterMaskIdLow    = 0xFFFF; 

假如要对标准远程帧进行过滤,那么:

只需要将

CAN_FilterInitStructure.CAN_FilterIdLow=(((u32)CAN_ID0<<21)|CAN_ID_STD|CAN_RTR_DATA)&0xFFFF; 改成:

CAN_FilterInitStructure.CAN_FilterIdLow=(((u32)CAN_ID0<<21)|CAN_ID_STD|CAN_RTR_REMOTE)&0xFFFF;

5、can总线的帧格式

远程帧格式:

6、can总线的逻辑电平

can总线的物理连接有两根线:CANH和CANL,以差分的形式输出。

(有的时候有地线,作为屏蔽线使用)

can总线的高电平 3.5v,表示逻辑0

can总线的低电平 1.5v,表示逻辑1

7、CAN总线的波特率计算

can时钟是RCC_APB1PeriphClock,要注意CAN时钟频率 
CAN波特率 = RCC_APB1PeriphClock/CAN_SJW CAN_BS1 CAN_BS2/CAN_Prescaler; 
如果CAN时钟为8M, CAN_SJW = 1,CAN_BS1 = 8,CAN_BS2 = 7,CAN_Prescaler = 2 
那么波特率就是=8M/(1 8 7)/2=250K 

8、can总线的仲裁机制

根据仲裁来判断优先级:

    (1) 若在同一时刻,标准格式的报文与扩展格式的报文同时抢占总线,且它们的基础ID相同,则发标准格式的报文节点就会PK成功。这是因为扩展格式在基本ID后,紧接着是SRR位,与IDE位,且这两位都是隐性位。而在标准格式中,这两位分别对应的位为RTR与r1,其中RTR既可以为隐性位,也可以为显性位,,但是r1必须为显性位。由仲裁规则可以此时标准帧必定胜出。

    (2)  同理,如果在同一时刻,具有相同格式,且具有相同ID的数据帧与远程帧争夺总线控制权,那么数据帧必定胜出。因为RTR显性表示数据帧,隐性表示远程帧。


stm32的can总线的配置如下:
      CAN_InitStructure.CAN_TTCM=DISABLE;//禁止时间触发通信模式
      CAN_InitStructure.CAN_ABOM=DISABLE;
      CAN_InitStructure.CAN_AWUM=DISABLE;
      CAN_InitStructure.CAN_NART=DISABLE;//CAN报文只被发送1次,不管发送的结果如何(成功、出错或仲裁丢失) 
      CAN_InitStructure.CAN_RFLM=DISABLE;
      CAN_InitStructure.CAN_TXFP=DISABLE;
      CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;
      //CAN_Mode_LoopBack
      //CAN_Mode_Normal
      CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
      CAN_InitStructure.CAN_BS1=CAN_BS1_5tq;//1--16
      CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;//1--8
      CAN_InitStructure.CAN_Prescaler=2;

      CAN_Init(&CAN_InitStructure);
       /* CAN filter init */
      CAN_FilterInitStructure.CAN_FilterNumber=0;//选择过滤器0
      CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//指定过滤器被设置为标识符屏蔽模式
      CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//给出过滤器位宽为32位
 

 
  1. 下面根据设置的参数不同来决定can总线can总线的配置情况:

  2. 1、对扩展数据帧进行过滤:(只接收扩展数据帧)

  3.       CAN_FilterInitStructure.CAN_FilterIdHigh   = (((u32)slave_id<<3)&0xFFFF0000)>>16;

  4.       CAN_FilterInitStructure.CAN_FilterIdLow   = (((u32)slave_id<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;

  5.       CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;

  6.       CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFF;

  7. (注:标准帧数据帧、标准远程帧和扩展远程帧均被过滤)

  8. 2、对扩展远程帧过滤:(只接收扩展远程帧)

  9.       CAN_FilterInitStructure.CAN_FilterIdHigh   = (((u32)slave_id<<3)&0xFFFF0000)>>16;

  10.       CAN_FilterInitStructure.CAN_FilterIdLow   = (((u32)slave_id<<3)|CAN_ID_EXT|CAN_RTR_REMOTE)&0xFFFF;

  11.       CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;

  12.       CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFF;

  13. 3、对标准远程帧过滤:(只接收标准远程帧)

  14.       CAN_FilterInitStructure.CAN_FilterIdHigh   = (((u32)slave_id<<21)&0xffff0000)>>16;

  15.       CAN_FilterInitStructure.CAN_FilterIdLow   = (((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_REMOTE)&0xffff;

  16.       CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;

  17.       CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFF;

  18. 4、对标准数据帧过滤:(只接收标准数据帧)

  19.       CAN_FilterInitStructure.CAN_FilterIdHigh   = (((u32)slave_id<<21)&0xffff0000)>>16;

  20.       CAN_FilterInitStructure.CAN_FilterIdLow   = (((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_DATA)&0xffff;

  21.       CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;

  22.       CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFF;

  23. 5、对扩展帧进行过滤:(扩展帧不会被过滤掉)

  24.       CAN_FilterInitStructure.CAN_FilterIdHigh   = (((u32)slave_id<<3)&0xFFFF0000)>>16;

  25.       CAN_FilterInitStructure.CAN_FilterIdLow   = (((u32)slave_id<<3)|CAN_ID_EXT)&0xFFFF;

  26.       CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;

  27.       CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFC;

  28. 6、对标准帧进行过滤:(标准帧不会被过滤掉)

  29.       CAN_FilterInitStructure.CAN_FilterIdHigh   = (((u32)slave_id<<21)&0xffff0000)>>16;

  30.       CAN_FilterInitStructure.CAN_FilterIdLow   = (((u32)slave_id<<21)|CAN_ID_STD)&0xffff;

  31.       CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;

  32.       CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFC;

  33. 注:slave_id为要过滤的id号。

4.1 CAN ID值的结构分析
              在讲到代码实例之前,首先大家都弄懂一件事,当给定一个CAN ID,如0x1800f001,当然这个是扩展ID,这里要问的是,这个CAN ID的值本身包含两部分,即基本ID与扩展ID,即么你知道这个扩展ID0x1800f001的哪些位是基本ID,哪些位又是扩展ID?(在基本CANID格式下不存在这个问题)

如上图,基本格式不存在扩展ID,而扩展格式中ID0~ID17为Extension ID,而ID18~ID28为Base ID.

因此CAN ID值0x1800f001用二进制表示为:0b 0001 1000 0000 0000 1111 0000 0000 0001,用括号分别区别为:0b 000[1 1000 0000 00][00 1111 0000 0000 0001],红色部分为扩展ID,蓝色部分为基本ID。那么知道这些有什么用呢?接下来的代码示例中你就会有什么用了。
 

4.2 位宽为32位的屏蔽模式

在此种模式下中过滤多个CAN ID,此时,过滤器包含两个寄存器,屏蔽码寄存器和标识符寄存器。此模式下最多只存在一个屏蔽过滤器。

如下图所示:

如上图,上面的ID为标识符寄存器,中间部分的MASK为屏蔽码寄存器。每个寄存器都是32位的。最下边显示的是与CAN ID各位定位的映射关系。由4.1的知识很快可以发现,上图最下边的映射关系恰好等于扩展CAN值左移3位再补上IDE(扩展帧标识),RTR(远程帧标志)。

因此,我们初步得出这样的推论:对于一个扩展CAN ID,不能单纯地将它看到的一个数,而应该将它看成两部分,基本ID和扩展ID(当然标准CAN ID只包含基本ID部分),过滤器屏蔽码寄存器和标识符寄存器也应该看成多个部分,然后问题就变成了如何将CAN ID所表示的各部分如何针对过滤器寄存器各部分对号入座的问题了。

对号入座的方法多种多样,但万变不离其心,主要是掌握其核心思想即可:1:在各种过滤器模式下,CAN ID与寄存器相应位置一定要匹配;2:在屏蔽方式下,屏蔽码寄存器某位为1表示接收到的CAN ID对应的位必须对验证码寄存器对应的位相同。

下面给出一个代码例子,假设我们要接收多个ID:0x7e9,0x1800f001,前面为标准ID,后面为扩展ID,要同时能接收这两个ID,那么该如何设置这个过滤器呢?

 
  1. CAN_FilterInitTypeDef CAN_FilterInitStructure;

  2. U16 std_id =0x7e9;

  3. U32 ext_id =0x1800f001;

  4. U32 mask =0;

  5. CAN_FilterInit(&CAN_FilterInitStructure); //初始化CAN_FilterInitStructrue结构体变量

  6. CAN_FilterInitStructure.CAN_FilterNumber=0; //设置过滤器组0,范围为0~13

  7. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //设置过滤器组0为屏蔽模式

  8. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //设置过滤器组0位宽为32位

  9. //标识位寄存器的设置

  10. //ext_id<<3对齐,见上图9,再>>16取高16位

  11. CAN_FilterInitStructure.CAN_FilterIdHigh=((ext_id<<3) >>16) &0xffff; //设置标识符寄存器高字节。

  12. CAN_FilterInitStructure.CAN_FilterIdLow=(U16)(ext_id<<3) | CAN_ID_EXT; //设置标识符寄存器低字节

  13. //这里也可以这样设置

  14. //CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5; //设置标识符寄存器高字节.这里为什么是左移5位呢?从上图可以看出,CAN_FilterIdHigh包含的是STD[0~10]和EXID[13~17],标准CAN ID本身是不包含扩展ID数据,因此为了要将标准CAN ID放入此寄存器,标准CAN ID首先应左移5位后才能对齐.

  15. //CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_EXT; //设置标识符寄存器低字节,这里也可以设置为CAN_ID_STD

  16. //屏蔽寄存器的设置

  17. //这里的思路是先将标准CAN ID和扩展CAN ID对应的ID值先异或后取反,为什么?异或是为了找出两个CAN ID有哪些位是相同的,是相同的位则说明需要关心,需要关心的位对应的屏蔽码位应该设置为1,因此需要取反一下。最后再整体左移3位。

  18. mask =(std_id<<18);//这里为什么左移18位?因为从ISO11898中可以看出,标准CAN ID占ID18~ID28,为了与CAN_FilterIdHigh对齐,应左移2位,接着为了与扩展CAN对应,还应该再左移16位,因此,总共应左移2+16=18位。也可以用另一个方式来理解:直接看Mapping的内容,发现STDID相对EXID[0]偏移了18位,因此左移18位.

  19. mask ^=ext_id;//将对齐后的标准CAN与扩展CAN异或后取反

  20. mask =~mask;

  21. mask <<=3;//再整体左移3位

  22. mask |=0x02; //只接收数据帧,不接收远程帧

  23. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(mask>>16)&0xffff; //设置屏蔽寄存器高字节

  24. CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask&0xffff; //设置屏蔽寄存器低字节

  25. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0; //此过滤器组关联到接收FIFO0

  26. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组

  27. CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器

总结可知,当过滤器为屏蔽模式时,标识符寄存器对应的ID内容可为任意一需求接收的ID值,当同时要接收标准帧和扩展帧时,标识符寄存器对应IDE位也随意设置,屏蔽寄存器的IDE位设置为0,表示不关心标准帧还是扩展帧。而屏蔽寄存器对应的ID内容为各需求接收的ID值依次异或的结果再取反。

4.3 位宽为32位的标识符列表模式
在此种模式下,过滤器组包含的两个寄存器含义一样,此模式下只多存在两个标识符列表过滤器如下图:

 
  1. CAN_FilterInitTypeDef CAN_FilterInitStructure;

  2. U16 std_id =0x7e9;

  3. U32 ext_id =0x1800f001;

  4. CAN_FilterInit(&CAN_FilterInitStructure); //初始化CAN_FilterInitStructrue结构体变量

  5. CAN_FilterInitStructure.CAN_FilterNumber=0; //设置过滤器组0,范围为0~13

  6. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList; //设置过滤器组0为标识符列表模式

  7. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //设置过滤器组0位宽为32位

  8. //设置屏蔽寄存器,这里当标识符寄存器用

  9. CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5) ; //为什么左移5位?与上面相同道理,这里不再重复解释

  10. CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_STD; //设置标识符寄存器低字节,CAN_FilterIdLow的ID位可以随意设置,在此模式下不会有效。

  11. //设置标识符寄存器

  12. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节

  13. CAN_FilterInitStructure.CAN_FilterMaskIdLow=((ext_id<<3)& 0xffff) | CAN_ID_EXT; //设置屏蔽寄存器低字节

  14. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0; //此过滤器组关联到接收FIFO0

  15. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组

  16. CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器

4.4 位宽为16位的屏蔽码模式

在此模式下,最多存在两个屏蔽码过滤器,如下图:

32位宽的列表模式

 
  1. 32位宽的列表模式

  2. static void CANFilterConfig_Scale32_IdList(void)

  3. {

  4. CAN_FilterConfTypeDef sFilterConfig;

  5. uint32_t StdId =0x321; //这里写入两个CAN ID,一个位标准CAN ID

  6. uint32_t ExtId =0x1800f001; //一个位扩展CAN ID

  7. sFilterConfig.FilterNumber = 0; //使用过滤器0

  8. sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; //设为列表模式

  9. sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //配置为32位宽

  10. sFilterConfig.FilterIdHigh = StdId<<5; //基本ID放入到STID中

  11. sFilterConfig.FilterIdLow = 0|CAN_ID_STD; //设置IDE位为0

  12. sFilterConfig.FilterMaskIdHigh = ((ExtId<<3)>>16)&0xffff;

  13. sFilterConfig.FilterMaskIdLow = (ExtId<<3)&0xffff|CAN_ID_EXT; //设置IDE位为1

  14. sFilterConfig.FilterFIFOAssignment = 0; //接收到的报文放入到FIFO0中

  15. sFilterConfig.FilterActivation = ENABLE;

  16. sFilterConfig.BankNumber = 14;

  17. if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)

  18. {

  19. Error_Handler();

  20. }

  21. }

16位宽的列表模式

 
  1. static void CANFilterConfig_Scale16_IdList(void)

  2. {

  3. CAN_FilterConfTypeDef sFilterConfig;

  4. uint32_t StdId1 =0x123; //这里采用4个标准CAN ID作为例子

  5. uint32_t StdId2 =0x124;

  6. uint32_t StdId3 =0x125;

  7. uint32_t StdId4 =0x126;

  8. sFilterConfig.FilterNumber = 1; //使用过滤器1

  9. sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; //设为列表模式

  10. sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; //位宽设置为16位

  11. sFilterConfig.FilterIdHigh = StdId1<<5; //4个标准CAN ID分别放入到4个存储中

  12. sFilterConfig.FilterIdLow = StdId2<<5;

  13. sFilterConfig.FilterMaskIdHigh = StdId3<<5;

  14. sFilterConfig.FilterMaskIdLow = StdId4<<5;

  15. sFilterConfig.FilterFIFOAssignment = 0; //接收到的报文放入到FIFO0中

  16. sFilterConfig.FilterActivation = ENABLE;

  17. sFilterConfig.BankNumber = 14;

  18. if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)

  19. {

  20. Error_Handler();

  21. }

  22. }

32位宽掩码模式

4.4.1. 只针对标准CAN ID
 
  1. static void CANFilterConfig_Scale32_IdMask_StandardIdOnly(void)

  2. {

  3. CAN_FilterConfTypeDef sFilterConfig;

  4. uint16_t StdIdArray[10] ={0x7e0,0x7e1,0x7e2,0x7e3,0x7e4,

  5. 0x7e5,0x7e6,0x7e7,0x7e8,0x7e9}; //定义一组标准CAN ID

  6. uint16_t mask,num,tmp,i;

  7. sFilterConfig.FilterNumber = 2; //使用过滤器2

  8. sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //配置为掩码模式

  9. sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //设置为32位宽

  10. sFilterConfig.FilterIdHigh =(StdIdArray[0]<<5); //验证码可以设置为StdIdArray[]数组中任意一个,这里使用StdIdArray[0]作为验证码

  11. sFilterConfig.FilterIdLow =0;

  12. mask =0x7ff; //下面开始计算屏蔽码

  13. num =sizeof(StdIdArray)/sizeof(StdIdArray[0]);

  14. for(i =0; i<num; i++) //屏蔽码位StdIdArray[]数组中所有成员的同或结果

  15. {

  16. tmp =StdIdArray[i] ^ (~StdIdArray[0]); //所有数组成员与第0个成员进行同或操作

  17. mask &=tmp;

  18. }

  19. sFilterConfig.FilterMaskIdHigh =(mask<<5);

  20. sFilterConfig.FilterMaskIdLow =0|0x02; //只接收数据帧

  21. sFilterConfig.FilterFIFOAssignment = 0; //设置通过的数据帧进入到FIFO0中

  22. sFilterConfig.FilterActivation = ENABLE;

  23. sFilterConfig.BankNumber = 14;

  24. if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)

  25. {

  26. Error_Handler();

  27. }

  28. }

4.4.2. 只针对扩展CAN ID

如下代码示例:

 
  1. static void CANFilterConfig_Scale32_IdMask_ExtendIdOnly(void)

  2. {

  3. CAN_FilterConfTypeDef sFilterConfig;

  4. //定义一组扩展CAN ID用来测试

  5. uint32_t ExtIdArray[10] ={0x1839f101,0x1835f102,0x1835f113,0x1835f124,0x1835f105,

  6. 0x1835f106,0x1835f107,0x1835f108,0x1835f109,0x1835f10A};

  7. uint32_t mask,num,tmp,i;

  8. sFilterConfig.FilterNumber = 3; //使用过滤器3

  9. sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //配置为掩码模式

  10. sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //设为32位宽

  11. sFilterConfig.FilterIdHigh =((ExtIdArray[0]<<3) >>16) &0xffff;//数组任意一个成员都可以作为验证码

  12. sFilterConfig.FilterIdLow =((ExtIdArray[0]<<3)&0xffff) | CAN_ID_EXT;

  13. mask =0x1fffffff;

  14. num =sizeof(ExtIdArray)/sizeof(ExtIdArray[0]);

  15. for(i =0; i<num; i++) //屏蔽码位数组各成员相互同或的结果

  16. {

  17. tmp =ExtIdArray[i] ^ (~ExtIdArray[0]); //都与第一个数据成员进行同或操作

  18. mask &=tmp;

  19. }

  20. mask <<=3; //对齐寄存器

  21. sFilterConfig.FilterMaskIdHigh = (mask>>16)&0xffff;

  22. sFilterConfig.FilterMaskIdLow = (mask&0xffff)|0x02; //只接收数据帧

  23. sFilterConfig.FilterFIFOAssignment = 0;

  24. sFilterConfig.FilterActivation = ENABLE;

  25. sFilterConfig.BankNumber = 14;

  26. if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)

  27. {

  28. Error_Handler();

  29. }

  30. }

4.4.3. 标准CAN ID与扩展CAN ID混合过滤

如下代码所示:

 
  1. static void CANFilterConfig_Scale32_IdMask_StandardId_ExtendId_Mix(void)

  2. {

  3. CAN_FilterConfTypeDef sFilterConfig;

  4. //定义一组标准CAN ID

  5. uint32_t StdIdArray[10] ={0x711,0x712,0x713,0x714,0x715,

  6. 0x716,0x717,0x718,0x719,0x71a};

  7. //定义另外一组扩展CAN ID

  8. uint32_t ExtIdArray[10] ={0x1900fAB1,0x1900fAB2,0x1900fAB3,0x1900fAB4,0x1900fAB5,

  9. 0x1900fAB6,0x1900fAB7,0x1900fAB8,0x1900fAB9,0x1900fABA};

  10. uint32_t mask,num,tmp,i,standard_mask,extend_mask,mix_mask;

  11. sFilterConfig.FilterNumber = 4; //使用过滤器4

  12. sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //配置为掩码模式

  13. sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //设为32位宽

  14. sFilterConfig.FilterIdHigh =((ExtIdArray[0]<<3) >>16) &0xffff; //使用第一个扩展CAN ID作为验证码

  15. sFilterConfig.FilterIdLow =((ExtIdArray[0]<<3)&0xffff);

  16. standard_mask =0x7ff; //下面是计算屏蔽码

  17. num =sizeof(StdIdArray)/sizeof(StdIdArray[0]);

  18. for(i =0; i<num; i++) //首先计算出所有标准CAN ID的屏蔽码

  19. {

  20. tmp =StdIdArray[i] ^ (~StdIdArray[0]);

  21. standard_mask &=tmp;

  22. }

  23. extend_mask =0x1fffffff;

  24. num =sizeof(ExtIdArray)/sizeof(ExtIdArray[0]);

  25. for(i =0; i<num; i++) //接着计算出所有扩展CAN ID的屏蔽码

  26. {

  27. tmp =ExtIdArray[i] ^ (~ExtIdArray[0]);

  28. extend_mask &=tmp;

  29. }

  30. mix_mask =(StdIdArray[0]<<18)^ (~ExtIdArray[0]); //再计算标准CAN ID与扩展CAN ID混合的屏蔽码

  31. mask =(standard_mask<<18)& extend_mask &mix_mask; //最后计算最终的屏蔽码

  32. mask <<=3; //对齐寄存器

  33. sFilterConfig.FilterMaskIdHigh = (mask>>16)&0xffff;

  34. sFilterConfig.FilterMaskIdLow = (mask&0xffff);

  35. sFilterConfig.FilterFIFOAssignment = 0;

  36. sFilterConfig.FilterActivation = ENABLE;

  37. sFilterConfig.BankNumber = 14;

  38. if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)

  39. {

  40. Error_Handler();

  41. }

  42. }

4.5.   16位宽掩码模式

 
  1. static void CANFilterConfig_Scale16_IdMask(void)

  2. {

  3. CAN_FilterConfTypeDef sFilterConfig;

  4. uint16_t StdIdArray1[10] ={0x7D1,0x7D2,0x7D3,0x7D4,0x7D5, //定义第一组标准CAN ID

  5. 0x7D6,0x7D7,0x7D8,0x7D9,0x7DA};

  6. uint16_t StdIdArray2[10] ={0x751,0x752,0x753,0x754,0x755, //定义第二组标准CAN ID

  7. 0x756,0x757,0x758,0x759,0x75A};

  8. uint16_t mask,tmp,i,num;

  9. sFilterConfig.FilterNumber = 5; //使用过滤器5

  10. sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //配置为掩码模式

  11. sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; //设为16位宽

  12. //配置第一个过滤对

  13. sFilterConfig.FilterIdLow =StdIdArray1[0]<<5; //设置第一个验证码

  14. mask =0x7ff;

  15. num =sizeof(StdIdArray1)/sizeof(StdIdArray1[0]);

  16. for(i =0; i<num; i++) //计算第一个屏蔽码

  17. {

  18. tmp =StdIdArray1[i] ^ (~StdIdArray1[0]);

  19. mask &=tmp;

  20. }

  21. sFilterConfig.FilterMaskIdLow =(mask<<5)|0x10; //只接收数据帧

  22. //配置第二个过滤对

  23. sFilterConfig.FilterIdHigh = StdIdArray2[0]<<5; //设置第二个验证码

  24. mask =0x7ff;

  25. num =sizeof(StdIdArray2)/sizeof(StdIdArray2[0]);

  26. for(i =0; i<num; i++) //计算第二个屏蔽码

  27. {

  28. tmp =StdIdArray2[i] ^ (~StdIdArray2[0]);

  29. mask &=tmp;

  30. }

  31. sFilterConfig.FilterMaskIdHigh = (mask<<5)|0x10; //只接收数据帧

  32. sFilterConfig.FilterFIFOAssignment = 0; //通过的CAN 消息放入到FIFO0中

  33. sFilterConfig.FilterActivation = ENABLE;

  34. sFilterConfig.BankNumber = 14;

  35. if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)

  36. {

  37. Error_Handler();

  38. }

  39. }

stm32中的CAN通讯列表模式配置解析与源码_canmsg[model+current_control_id].id-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux内核是一个开源的操作系统内核,它的驱动源码详解主要是指对Linux内核的设备驱动模块进行解析和分析。 Linux内核的驱动源码通常分为两类:字符设备驱动和块设备驱动。字符设备驱动主要用于处理串行通信设备、音频设备、输入设备等,而块设备驱动则用于处理硬盘、闪存等块设备。驱动源码的详解主要涉及对设备驱动的初始化、注册、操作和断处理等方面的内容。 在驱动源码详解,我们可以了解到驱动模块的初始化过程,包括对设备资源的分配、设备的注册和初始化函数的调用。通过对设备驱动的分析,我们能够理解驱动模块与硬件设备之间的交互方式,包括读写操作、断处理和设备的状态管理等。 驱动源码详解还涉及对设备的操作方法,包括打开设备、关闭设备、读写设备等。这部分内容主要关注设备驱动的各个函数的作用和调用顺序,以及数据的传递和处理方式。 此外,在驱动源码详解还可以了解到设备的断处理,包括断的注册、断处理函数的编写和断处理的调用流程。断处理是设备驱动非常重要的一部分,了解断处理的过程和方法对于理解设备驱动的工作原理和性能优化是很有帮助的。 综上所述,Linux内核的驱动源码详解内容丰富,主要涵盖了设备驱动的初始化、注册、操作和断处理等方面的内容。通过对驱动源码的详细解析,我们可以更加深入地理解Linux内核的工作原理和设备驱动的工作方式,为后续的驱动开发和性能优化提供有力的支持。 ### 回答2: Linux驱动源码详解是指对Linux操作系统的驱动程序源代码进行深入解析和讲解的过程。Linux操作系统采用开放源代码模型,其内核和驱动程序的源代码可以被开发者自由获取并进行修改和学习。 在Linux系统,硬件设备的操作和管理主要通过驱动程序来实现。驱动程序的作用是将操作系统与硬件设备之间进行通讯和交互,实现设备的初始化、数据传输等功能。而Linux驱动源码详解的目的就是帮助开发者深入了解驱动程序的实现原理和工作机制。 在Linux驱动源码详解,开发者可以学习到以下内容: 1. 驱动程序的基本结构和框架:了解驱动程序的基本组成部分,如设备注册、设备初始化、设备打开、设备关闭等流程。 2. 设备操作和断处理:学习如何通过驱动程序向设备发送命令、读取数据以及接收设备断信号等。 3. 数据传输和缓冲区管理:了解数据在驱动程序的传输方式、缓冲区的管理和操作。 4. 设备的状态管理和错误处理:学习如何管理设备的状态,处理设备异常和错误情况。 5. 设备驱动的注册和注销:掌握如何将驱动程序注册到系统并进行设备绑定,以及如何在不使用设备时进行注销。 通过对Linux驱动源码的详解,开发者可以深入了解驱动程序的实现细节,提高对驱动开发的理解和能力。同时,也可以通过学习和参考已有的驱动源码,为特定硬件设备开发定制化的驱动程序。 ### 回答3: Linux的驱动源码是指运行在Linux操作系统上的设备驱动程序的代码。驱动程序负责与硬件设备进行通信,使操作系统能够识别设备并与之交互。 Linux的驱动源码详解可以从以下几个方面展开: 1. 设备驱动模型:Linux使用一种称为设备树(Device Tree)的数据结构来描述系统的硬件设备,这是一种独立于架构的设备描述方法。驱动源码包含了设备树的解析和操作代码。 2. 设备注册和初始化:驱动源码会包含设备的注册和初始化代码,通过这些代码,驱动程序向操作系统注册设备并准备好与设备进行通信所需的资源。 3. 设备访问和控制:驱动源码会包含设备的读写和控制操作的代码,以实现对设备的访问和控制。这些代码负责与设备进行数据传输和状态控制。 4. 断和异常处理:驱动源码还包含断和异常处理的代码。当硬件设备发生断或异常时,驱动程序会相应地进行处理,以确保系统的稳定运行。 5. 资源管理:驱动源码会包含设备资源的管理代码,用于管理设备的内存、寄存器和断等资源,以确保设备能够正常运行。 6. 驱动开发接口:Linux提供了一系列的API和接口,用于驱动开发。驱动源码会使用这些接口来实现设备的注册、读写、内存分配等功能。 通过对Linux的驱动源码进行详细解析,可以深入理解设备驱动程序的工作原理和实现方式,从而能够编写高效、可靠的设备驱动程序,提高系统的性能和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值