你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

安臣学习stm32f072系列--------can通信事例  

[复制链接]
安臣 发布时间:2015-5-28 15:58
借鉴博客:http://blog.csdn.net/flydream0/article/details/8148791

CAN ID值的结构分析

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

                在回答这个问题之前我们来看看ISO11898的定义,如下图:


                                                                                     图9

如上图,基本格式不存在扩展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,此时,过滤器包含两个寄存器,屏蔽码寄存器和标识符寄存器。此模式下最多只存在一个屏蔽过滤器。

如下图所示:

                                                                                 图10

如上图,上面的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位的标识符列表模式

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

                                                                                                   图11

  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位的屏蔽码模式

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

                                                                                                          图12

由上图映射可知,最下面的映射只包含STDID0~ID10,因此,此模式下的两个屏蔽过滤器只能实现对标准ID的过滤。具体代码就不介绍了,参见上图的映射即可。


4.5 位宽为16位的标识符列表模式

                                                                                              图13

在此模式下,由于标识符寄存器的高16位和低16位,屏蔽寄存器的高16位和低16位都用来做标识符寄存器,因此,最多可存在4个标识符过滤器。同样,只能实现对标准帧的过滤。具体代码就不介绍了,参见上图的映射即可。


以上是别人博客转载的


下面是i我自己的代码

  1. /**
  2. * @brief This function config can's fiflter.
  3. */
  4. void Can_FilterConfig(void)
  5. {
  6.         CAN_FilterConfTypeDef FilterConfig;
  7.        
  8.         FilterConfig.FilterIdHigh         = ((ext_id<<3) >>16) &0xffff;
  9.         FilterConfig.FilterIdLow          = (uint16_t)(ext_id<<3) | CAN_ID_EXT | CAN_RTR_DATA;
  10.         FilterConfig.FilterMaskIdHigh     = 0xfff8;
  11.         FilterConfig.FilterMaskIdLow      = 0x07ff;
  12.         FilterConfig.FilterFIFOAssignment = 0x00;
  13.         FilterConfig.FilterNumber         = 0x00;
  14.         FilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;
  15.         FilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;
  16.         FilterConfig.FilterActivation     = ENABLE;
  17.         hcan.Instance = CAN;
  18.         HAL_CAN_ConfigFilter(&hcan, &FilterConfig);
  19. }
  20. /**
  21. * @brief This function is can send pross.
  22. */
  23. void Can_Assignin_Send_Pross(uint8_t *pbuf)
  24. {
  25.         hcan.Instance = CAN;
  26.         hcan.pTxMsg = &TxMsgStruct;
  27.         hcan.pRxMsg = &RxMsgStruct;

  28.         TxMsgStruct.ExtId = 0x18ff0004;
  29.         TxMsgStruct.IDE   = CAN_ID_EXT  ;
  30.         TxMsgStruct.RTR   = CAN_RTR_DATA;
  31.         TxMsgStruct.DLC   = 6;
  32.         TxMsgStruct.Data[0] = pbuf[0];
  33.         TxMsgStruct.Data[1] = pbuf[1];
  34.         TxMsgStruct.Data[2] = pbuf[2];
  35.         TxMsgStruct.Data[3] = pbuf[3];
  36.         TxMsgStruct.Data[4] = pbuf[4];
  37.         TxMsgStruct.Data[5] = pbuf[5];
  38.         HAL_CAN_Transmit(&hcan,0);       

  39.         HAL_CAN_Receive_IT(&hcan, 0x00);
  40. }
  41. /**
  42. * @brief This function handles CEC and CAN interrupts.
  43. */
  44. void Can_Assignin_Rev_Pross(uint8_t *pbuf)
  45. {
  46.         hcan.Instance = CAN;
  47.         hcan.pRxMsg = &RxMsgStruct;
  48.   pbuf[0] = RxMsgStruct.Data[0];
  49.         pbuf[1] = RxMsgStruct.Data[1];
  50.         pbuf[2] = RxMsgStruct.Data[2];
  51.         pbuf[3] = RxMsgStruct.Data[3];
  52.         pbuf[4] = RxMsgStruct.Data[4];
  53. }
复制代码



can.rar

下载

3.8 MB, 下载次数: 549

收藏 9 评论23 发布时间:2015-5-28 15:58

举报

23个回答
netlhx 回答时间:2015-5-28 16:37:31
高大上的东西,不懂也顶
风子 回答时间:2015-5-28 18:00:56
啊,正好我这两天也在研究这个
wambob 回答时间:2015-5-28 19:41:39
CAN,看过一本书,北航的
数码小叶 回答时间:2015-5-29 08:29:36
谢谢分享,学习一下
为什么是EEFOCUS小白 回答时间:2015-5-29 08:55:45
谢谢分享   
安臣 回答时间:2015-11-20 20:51:37
这个好帖居然没人顶
lkl0305 回答时间:2015-11-20 21:06:25
多谢分享
abclsl 回答时间:2015-11-23 20:29:13
请问你,是没有试过接收没有数据的远程帧呢
abclsl 回答时间:2015-11-23 20:29:33
顶起
123下一页

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版