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

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

[复制链接]
安臣 发布时间:2015-5-28 15:58
借鉴博客:http://blog.csdn.net/flydream0/article/details/8148791
" O" i  D% @0 ?% n) H8 d( r! M1 H" ^
CAN ID值的结构分析* f, L5 t' ?0 _8 H& A) G+ K6 J8 |

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

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


  |9 _' e" k, u' p% b8 K3 m. o0 z

                                                                                     图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。那么知道这些有什么用呢?接下来的代码示例中你就会有什么用了。
( k( g& L0 h' C5 `5 f

4.2 位宽为32位的屏蔽模式9 z& H0 _$ V1 m' |; \

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

如下图所示:

                                                                                 图10

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


/ S5 ^. }! u7 [- {( j

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

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


9 C! G- E3 M) h$ i. ]- |3 V; n

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

  1. CAN_FilterInitTypeDef  CAN_FilterInitStructure;) p* [. }' H; p) ]  D
  2. U16 std_id =0x7e9;
    0 j. t! W  J+ U/ A* ]! F
  3. U32 ext_id =0x1800f001;5 Y( P) N+ l/ \; J% @% |+ v. J
  4. U32 mask =0;( M7 E! Z0 u( j# C, w

  5. , B+ }& _) W' X
  6. CAN_FilterInit(&CAN_FilterInitStructure);     //初始化CAN_FilterInitStructrue结构体变量
    / x4 ^% q: U5 C' R! z
  7. CAN_FilterInitStructure.CAN_FilterNumber=0;      //设置过滤器组0,范围为0~13
    . J; d  }, t) {1 F# s
  8. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;    //设置过滤器组0为屏蔽模式
    ' w% @3 a0 e0 ~! F# w6 q
  9. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   //设置过滤器组0位宽为32位2 C$ j4 A/ w! X0 v- M( N& |1 o, x. w
  10. 6 \0 `5 ^% {; _5 P. H! Q6 s# b/ l
  11. //标识位寄存器的设置3 l1 K7 C1 O2 _5 e
  12. //ext_id<<3对齐,见上图9,再>>16取高16位) ^4 ?6 T8 a8 g# c' z1 l! B
  13. CAN_FilterInitStructure.CAN_FilterIdHigh=((ext_id<<3) >>16) &0xffff;  //设置标识符寄存器高字节。) S# |9 I% {% p" h, d. R$ T0 U8 g
  14. CAN_FilterInitStructure.CAN_FilterIdLow=(U16)(ext_id<<3) | CAN_ID_EXT;   //设置标识符寄存器低字节% N- m) i0 k7 [
  15. //这里也可以这样设置  H* B5 {) n2 ?+ w1 e) Y- Z6 |& ]
  16. //CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5;  //设置标识符寄存器高字节.这里为什么是左移5位呢?从上图可以看出,CAN_FilterIdHigh包含的是STD[0~10]和EXID[13~17],标准CAN ID本身是不包含扩展ID数据,因此为了要将标准CAN ID放入此寄存器,标准CAN ID首先应左移5位后才能对齐.
    4 P$ W  j. |. k0 Q
  17. //CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_EXT;   //设置标识符寄存器低字节,这里也可以设置为CAN_ID_STD9 H/ x' t% A5 U2 k/ K$ @
  18. 7 b) H* O! G3 b" ?
  19. //屏蔽寄存器的设置
    : M' ^5 L( Z" c
  20. //这里的思路是先将标准CAN ID和扩展CAN ID对应的ID值先异或后取反,为什么?异或是为了找出两个CAN ID有哪些位是相同的,是相同的位则说明需要关心,需要关心的位对应的屏蔽码位应该设置为1,因此需要取反一下。最后再整体左移3位。5 f' I' y' F$ B, d
  21. mask =(std_id<<18);//这里为什么左移18位?因为从ISO11898中可以看出,标准CAN ID占ID18~ID28,为了与CAN_FilterIdHigh对齐,应左移2位,接着为了与扩展CAN对应,还应该再左移16位,因此,总共应左移2+16=18位。也可以用另一个方式来理解:直接看Mapping的内容,发现STDID相对EXID[0]偏移了18位,因此左移18位.
    5 Y2 b( \+ j1 v  Z( b
  22. mask ^=ext_id;//将对齐后的标准CAN与扩展CAN异或后取反
    ) y1 z+ Y' D" s
  23. mask =~mask;% J5 ?- |/ X' }$ L  o
  24. mask <<=3;//再整体左移3位3 W8 h' p7 |# p) `2 `
  25. mask |=0x02; //只接收数据帧,不接收远程帧! J* W" Q% h$ K. Y/ M- z% v/ L' n
  26. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(mask>>16)&0xffff; //设置屏蔽寄存器高字节
    $ ]' ^# y( R' y2 P! V( v
  27. CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask&0xffff;   //设置屏蔽寄存器低字节
    8 T, h4 M2 i3 T: _3 I7 @  d& r: _1 ]
  28. 6 \' `) s9 n: T
  29. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;  //此过滤器组关联到接收FIFO0
    - ]- H' e6 t0 }( ~* [
  30. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组
    ( Z1 Y, c. n  e1 \' J5 W. ]" w
  31. CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器
    1 Q/ s5 B" r' n! w8 a
复制代码

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

4.3 位宽为32位的标识符列表模式

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

                                                                                                   图11

  1. CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    ; _0 L1 ]3 D) [" F& e! ?
  2. U16 std_id =0x7e9;: ^! \$ `7 G  C7 A3 M
  3. U32 ext_id =0x1800f001;8 b& O) J8 m; e$ O) H3 ]$ {
  4. CAN_FilterInit(&CAN_FilterInitStructure); //初始化CAN_FilterInitStructrue结构体变量
    , b+ w1 c: P. v: b$ V) ^( X0 Z- {# l
  5. CAN_FilterInitStructure.CAN_FilterNumber=0;     //设置过滤器组0,范围为0~13
    : O' h& s2 ]1 h4 D7 r- k% L2 i8 S
  6. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList;    //设置过滤器组0为标识符列表模式
    / X+ g" S- @) q) q* O5 C
  7. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   //设置过滤器组0位宽为32位
    5 Q3 e# c' Q7 c; K( b8 j/ C% M. W
  8. : T1 \( }5 D1 y& v% G, A. B
  9. //设置屏蔽寄存器,这里当标识符寄存器用- @$ {( X1 D. b6 |- P8 h# R
  10. CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5) ;  //为什么左移5位?与上面相同道理,这里不再重复解释
    - T( e5 u. p. @& U$ h
  11. CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_STD; //设置标识符寄存器低字节,CAN_FilterIdLow的ID位可以随意设置,在此模式下不会有效。
    $ i  z( C( K: {( o

  12. # _5 u7 t+ U, E1 D
  13. //设置标识符寄存器, I' Z! P7 }  ?% t
  14. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节& {, c, k; A# }$ l9 O
  15. CAN_FilterInitStructure.CAN_FilterMaskIdLow=((ext_id<<3)& 0xffff) | CAN_ID_EXT;   //设置屏蔽寄存器低字节: S0 U$ w! c- M  d
  16. 5 ?8 L% Z* n' u. i2 e
  17. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;  //此过滤器组关联到接收FIFO04 Y- l0 q: w- [, D% O& w
  18. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组
    9 a9 k) u/ B% j! W2 B$ B
  19. CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器: ^2 n# w  p! \  w
复制代码
4.4 位宽为16位的屏蔽码模式

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

                                                                                                          图12

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


( b7 Y4 B; [$ n( |. h4.5 位宽为16位的标识符列表模式

                                                                                              图13* y; B' e; a! U" T9 D# [

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

+ A2 E& n( O) c6 z$ i

以上是别人博客转载的

3 A$ Z3 X$ q( g! X. W, `; |) f

下面是i我自己的代码

  1. /**1 i8 F, F0 A$ \: o  ]) |' D& s. C# b
  2. * @brief This function config can's fiflter.& G( q6 t9 ?: X$ Y7 x0 V
  3. */
    & N+ r! a" U4 C$ {6 `& }
  4. void Can_FilterConfig(void)% S' x& I, Z2 n+ k7 Y
  5. {
    3 `0 c) E+ E! @4 J% }* l
  6.         CAN_FilterConfTypeDef FilterConfig;
      ~- ?+ L2 c8 ^& v6 ?
  7.         - J! k/ s4 A4 b5 {8 W0 [, Q
  8.         FilterConfig.FilterIdHigh         = ((ext_id<<3) >>16) &0xffff;
    : `  P1 U$ _& a( W' F+ Q
  9.         FilterConfig.FilterIdLow          = (uint16_t)(ext_id<<3) | CAN_ID_EXT | CAN_RTR_DATA;- F8 N' E2 M3 ^  g. {% ^- V
  10.         FilterConfig.FilterMaskIdHigh     = 0xfff8;
    7 q/ p7 F! T" d
  11.         FilterConfig.FilterMaskIdLow      = 0x07ff;7 |8 H9 C( ]1 Q" l  c
  12.         FilterConfig.FilterFIFOAssignment = 0x00;* L+ g" y% H# |, i
  13.         FilterConfig.FilterNumber         = 0x00;& F/ m* v$ R; i" g& u
  14.         FilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;
    8 e, J7 _. F9 P! \" L' j) G
  15.         FilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;+ |9 U8 U/ n( I3 ?( ~
  16.         FilterConfig.FilterActivation     = ENABLE;! @0 [/ W0 G6 M- |1 O+ M
  17.         hcan.Instance = CAN;
    7 V9 c, i2 R* [2 k( Q% |
  18.         HAL_CAN_ConfigFilter(&hcan, &FilterConfig);
    ( y0 F7 W) _1 W% Y5 o
  19. }
    , e0 L0 `. P- s: |" O7 E2 {
  20. /**
    , L) g- A8 a4 ?, |% T+ \( r
  21. * @brief This function is can send pross.$ a" K- u0 B! Q# u# i/ }, z
  22. */
    $ n3 q( q1 B4 j  t4 Y
  23. void Can_Assignin_Send_Pross(uint8_t *pbuf)
    * j$ b2 J& V3 }5 J! ]" }+ Y8 B
  24. {
    ) N/ c' X  E4 r% G5 z2 u# ]0 e
  25.         hcan.Instance = CAN;
    - @7 a7 [) _0 E2 Y( K' u1 b
  26.         hcan.pTxMsg = &TxMsgStruct;
    $ t! ?3 ^; }8 j- q1 W, |: c
  27.         hcan.pRxMsg = &RxMsgStruct;
    3 X1 t/ ^; @2 u' l% C
  28. 0 V+ d* w$ k5 [/ _- \
  29.         TxMsgStruct.ExtId = 0x18ff0004;
    " \( ~) }, t' w- F* ?  U1 P9 l
  30.         TxMsgStruct.IDE   = CAN_ID_EXT  ;4 z; K- f# [5 z, y) R; O) W
  31.         TxMsgStruct.RTR   = CAN_RTR_DATA;
    , R  D& u4 j/ O- S" P
  32.         TxMsgStruct.DLC   = 6;$ l0 R2 M6 u% _: T$ T' v
  33.         TxMsgStruct.Data[0] = pbuf[0];
    % I# }. ?+ j5 Y
  34.         TxMsgStruct.Data[1] = pbuf[1];% w2 g$ U9 l+ n. c8 ?9 j" w+ q
  35.         TxMsgStruct.Data[2] = pbuf[2];; s3 |2 Y2 D) l, C( W+ H& o3 ?
  36.         TxMsgStruct.Data[3] = pbuf[3];
    1 t+ u# i/ T, p' G7 d+ C
  37.         TxMsgStruct.Data[4] = pbuf[4];
    ; `' P4 Q9 X+ v! a% s
  38.         TxMsgStruct.Data[5] = pbuf[5];
    9 a' ]9 d/ }" t* H8 d, F& E# p6 u
  39.         HAL_CAN_Transmit(&hcan,0);        ' G% X& `5 T$ T0 c; @1 b+ O" f
  40. # Z6 R8 _* r1 c5 ]
  41.         HAL_CAN_Receive_IT(&hcan, 0x00);
    9 P6 J% R9 y2 @0 n; {* k
  42. }- [/ B! Q4 f0 v* w) Z) {. g, E0 j
  43. /**
    - Y" X( a  Z7 `
  44. * @brief This function handles CEC and CAN interrupts., Z! h, A( U6 n3 E9 T' `
  45. */" G4 ]7 a$ a/ q1 v/ m& _3 u
  46. void Can_Assignin_Rev_Pross(uint8_t *pbuf)9 B# [5 Y4 n( N- L0 ?2 B4 \
  47. {
    6 g3 D9 a9 n$ g: Z1 O
  48.         hcan.Instance = CAN;2 `9 x  I; l' {2 _. d
  49.         hcan.pRxMsg = &RxMsgStruct;9 I+ W. J" b+ `
  50.   pbuf[0] = RxMsgStruct.Data[0];
    * `# \5 v! |1 R
  51.         pbuf[1] = RxMsgStruct.Data[1]; ; H* ?3 U& N7 d. \1 r
  52.         pbuf[2] = RxMsgStruct.Data[2]; # d" z3 n5 W5 ]
  53.         pbuf[3] = RxMsgStruct.Data[3]; 3 t  L+ |* K: u: }9 _
  54.         pbuf[4] = RxMsgStruct.Data[4]; 5 e1 ^/ O( ~: W) B8 j( s. r
  55. }
复制代码
. p' `7 d# M8 r6 }- R$ \

  d4 C. O* n0 G8 v1 L' s+ Z- d6 B! T

can.rar

下载

3.8 MB, 下载次数: 562

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

举报

24个回答
安臣 回答时间:2016-6-16 21:16:44
watershade 发表于 2016-5-10 21:04, A9 T) @7 h7 u1 N# M( I; b
最近在玩CANopen,多交流呀。安臣移植canFestival吗
) L0 k0 m7 K: f$ z! [$ g% f
没有啊  
DarkG 回答时间:2017-1-4 16:29:50
用最新的F1 V14.0 收到CAN的消息 能进中断 但是进了中断之后就马上死机了
watershade 回答时间:2016-5-10 21:04:01
最近在玩CANopen,多交流呀。安臣移植canFestival吗
netlhx 回答时间:2015-5-28 16:37:31
高大上的东西,不懂也顶
风子 回答时间:2015-5-28 18:00:56
啊,正好我这两天也在研究这个
wamcncn 回答时间:2015-5-28 19:41:39
CAN,看过一本书,北航的
wyxy163@126.com 回答时间: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
顶起
阿平 回答时间:2016-3-21 23:08:01
学习中正需要
斜阳 回答时间:2016-5-10 18:03:40
跟着臣哥学CAN通信
wuchao147 回答时间:2016-8-10 13:20:09
dsfdsafsaf
12下一页

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版