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

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

[复制链接]
安臣 发布时间:2015-5-28 15:58
借鉴博客:http://blog.csdn.net/flydream0/article/details/81487919 s  S  Z7 ]3 O0 S/ k
+ E- d2 h6 A; D/ a# N7 Z+ V& i
CAN ID值的结构分析
/ p; ^% G  p' y# [

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

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


& U: b* o, k6 ?! b) [

                                                                                     图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。那么知道这些有什么用呢?接下来的代码示例中你就会有什么用了。
7 E/ O: [% R1 @& W* O- O

4.2 位宽为32位的屏蔽模式2 s* O) U3 |$ j  u# I- r

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

如下图所示:

                                                                                 图10

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


  V+ w8 T: G# t4 q! s$ n

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

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

* P1 [% i! ?& `6 {, z

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

  1. CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    2 e, h2 N" ^' f; u
  2. U16 std_id =0x7e9;
    / t  |1 u! ~8 I+ A0 u8 {, l3 L+ X
  3. U32 ext_id =0x1800f001;
    1 e2 |) w7 r; A% l2 l1 l
  4. U32 mask =0;/ `% }  H7 {5 V( V( p$ p8 j
  5. 0 [7 @) [( E4 V) P
  6. CAN_FilterInit(&CAN_FilterInitStructure);     //初始化CAN_FilterInitStructrue结构体变量
    2 I. b( i2 Z, }6 _" X
  7. CAN_FilterInitStructure.CAN_FilterNumber=0;      //设置过滤器组0,范围为0~13; i+ C/ j' T6 o5 s$ w: k, s1 L
  8. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;    //设置过滤器组0为屏蔽模式
    4 x& p- p, Z5 O
  9. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   //设置过滤器组0位宽为32位
    / ?( l. p0 K8 h/ }9 a4 r( d
  10. 1 ~# T) H& x/ P9 p: B
  11. //标识位寄存器的设置
    * ~* }5 O' `2 t3 S" x5 K, i  b& u
  12. //ext_id<<3对齐,见上图9,再>>16取高16位
    & i& k: R- R5 Z( \" F4 F
  13. CAN_FilterInitStructure.CAN_FilterIdHigh=((ext_id<<3) >>16) &0xffff;  //设置标识符寄存器高字节。
    ' Q/ L/ Q/ f- Q3 l4 R
  14. CAN_FilterInitStructure.CAN_FilterIdLow=(U16)(ext_id<<3) | CAN_ID_EXT;   //设置标识符寄存器低字节3 G- p' _' ]$ o% h3 ]. ?- O
  15. //这里也可以这样设置
    5 C0 m! Z: t) a+ b" Y
  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位后才能对齐.; z, @- c, ]; H9 L
  17. //CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_EXT;   //设置标识符寄存器低字节,这里也可以设置为CAN_ID_STD
    5 R  x! c3 w# d% |* |
  18. % L$ M8 K: C: z- L% q
  19. //屏蔽寄存器的设置/ `2 |  P+ R3 R- ]
  20. //这里的思路是先将标准CAN ID和扩展CAN ID对应的ID值先异或后取反,为什么?异或是为了找出两个CAN ID有哪些位是相同的,是相同的位则说明需要关心,需要关心的位对应的屏蔽码位应该设置为1,因此需要取反一下。最后再整体左移3位。
    8 ]( R# ]* m7 p, K! y+ n$ h$ I* \
  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位.
    4 ], k1 k7 m" `  ?1 q/ ?3 K
  22. mask ^=ext_id;//将对齐后的标准CAN与扩展CAN异或后取反
    ; t; A& p  k* P$ f- `
  23. mask =~mask;
    ; Y3 c0 I* ?* I3 @4 A
  24. mask <<=3;//再整体左移3位
    6 W6 C5 X' r8 [
  25. mask |=0x02; //只接收数据帧,不接收远程帧: b8 s9 o' s. x1 Z
  26. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(mask>>16)&0xffff; //设置屏蔽寄存器高字节
    ( B- G7 e, R2 P8 y, P' J- z
  27. CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask&0xffff;   //设置屏蔽寄存器低字节4 N# k: j* Q3 J" R# U' \7 q' p/ {2 c" z

  28. 2 W+ L) h/ ?5 U0 w
  29. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;  //此过滤器组关联到接收FIFO00 y# C! T! E7 `
  30. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组1 ]$ W. }1 G7 w: V# b& J2 |' q
  31. CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器# l9 L: {' H* O' N  `$ z: B( C9 F) \
复制代码

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

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

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

                                                                                                   图11

  1. CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    2 L- J' f& |3 m* s
  2. U16 std_id =0x7e9;
    2 Q( B# m  N( `* k2 O( [% b
  3. U32 ext_id =0x1800f001;2 i+ u/ \3 k% r* Z- X9 k3 R, p5 W
  4. CAN_FilterInit(&CAN_FilterInitStructure); //初始化CAN_FilterInitStructrue结构体变量" ~. ^% Q0 L: P  E& H- F
  5. CAN_FilterInitStructure.CAN_FilterNumber=0;     //设置过滤器组0,范围为0~13; h8 S9 g: H; A
  6. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList;    //设置过滤器组0为标识符列表模式
    8 f5 i2 q. c8 U4 b: ?+ c  p
  7. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   //设置过滤器组0位宽为32位" X' h0 A6 F& n9 K- M
  8. " }* P) I) q* U1 b
  9. //设置屏蔽寄存器,这里当标识符寄存器用6 m1 C+ l/ V# P9 j; O  t
  10. CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5) ;  //为什么左移5位?与上面相同道理,这里不再重复解释
    0 t( f, D2 M' Y# |
  11. CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_STD; //设置标识符寄存器低字节,CAN_FilterIdLow的ID位可以随意设置,在此模式下不会有效。
    . b6 r2 C3 G+ \/ K1 l) `0 ?

  12. ' _$ f+ \& k( @- P: u
  13. //设置标识符寄存器' [1 o; z8 y. L* v% v; ^  \" w: ]
  14. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节
    + N6 l1 Q2 Q# [' b: O/ J/ i
  15. CAN_FilterInitStructure.CAN_FilterMaskIdLow=((ext_id<<3)& 0xffff) | CAN_ID_EXT;   //设置屏蔽寄存器低字节
      |% V) B' b% v5 M

  16. 8 \' [, x$ K3 K3 c4 C. c
  17. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;  //此过滤器组关联到接收FIFO0
      f/ D0 f: r, H9 _$ u0 g% x
  18. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组
    : a( N5 k) o# M0 a  b
  19. CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器
    1 K  G  Z# P# O. L1 I
复制代码
4.4 位宽为16位的屏蔽码模式

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

                                                                                                          图12

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


  U2 ]" ^6 v7 f+ I+ r; _! ]4.5 位宽为16位的标识符列表模式

                                                                                              图13
5 ^# K9 s! R! ?# t' A# t: w

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

; h6 d8 `4 W6 o

以上是别人博客转载的


8 `1 A; u0 s: m) a

下面是i我自己的代码

  1. /**
    " H! [+ q' v5 U. M
  2. * @brief This function config can's fiflter.
    ) n# o. w- S: ?0 x& t" i( }( c
  3. */
    # w# @) w+ d+ Q! f/ R
  4. void Can_FilterConfig(void)4 @; W6 }) ]" @9 e6 {. D
  5. {/ A( w/ @5 X9 s7 O1 Z- k& N2 o9 d
  6.         CAN_FilterConfTypeDef FilterConfig;0 {/ A& n1 x( N
  7.         ' j+ v2 v' r- _" l/ Z
  8.         FilterConfig.FilterIdHigh         = ((ext_id<<3) >>16) &0xffff;! g; @+ k5 W' h" ^# Z0 ?( E
  9.         FilterConfig.FilterIdLow          = (uint16_t)(ext_id<<3) | CAN_ID_EXT | CAN_RTR_DATA;5 X( a: s3 f7 O, r' p) \; N
  10.         FilterConfig.FilterMaskIdHigh     = 0xfff8;3 n; }" d) ^1 y3 D0 h
  11.         FilterConfig.FilterMaskIdLow      = 0x07ff;1 `3 r9 C" @$ a8 o9 R
  12.         FilterConfig.FilterFIFOAssignment = 0x00;
    $ O+ h! B: s8 a6 t: Y0 Z, J
  13.         FilterConfig.FilterNumber         = 0x00;! O7 J3 ^* d. q, C% V
  14.         FilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;
    % P3 g0 t# u5 ?+ S3 ~9 F
  15.         FilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;
    8 }% t9 Z$ `4 v) `# ?3 u
  16.         FilterConfig.FilterActivation     = ENABLE;1 c9 M' ~/ z7 n. y
  17.         hcan.Instance = CAN;( t; w$ S1 y! b3 M3 Q
  18.         HAL_CAN_ConfigFilter(&hcan, &FilterConfig);
    - e/ f: e7 M9 i! D/ c# a1 _
  19. }3 a. _  I3 N$ s0 S
  20. /**" q- T. T2 [# U7 T' q
  21. * @brief This function is can send pross.+ e* |0 }- y! m0 j
  22. */
    , a* v# p" u& ?+ z# ?: ]( f8 B
  23. void Can_Assignin_Send_Pross(uint8_t *pbuf)& y, s8 o8 @6 y. i$ q, G" q
  24. {* b5 H' ~; \4 g) ^3 e& K' {  T; U
  25.         hcan.Instance = CAN;
    0 ]* a: _/ q: n) U4 E
  26.         hcan.pTxMsg = &TxMsgStruct;
    ) p6 n5 Q% o% H1 q$ _# n
  27.         hcan.pRxMsg = &RxMsgStruct;
    4 _, H; ]% H7 r: x! D9 [* R
  28. 7 a- l% N7 h; \# O- a& V$ A
  29.         TxMsgStruct.ExtId = 0x18ff0004;
    5 o/ q  B1 h& q
  30.         TxMsgStruct.IDE   = CAN_ID_EXT  ;" E7 c& C8 a; ]. `+ x
  31.         TxMsgStruct.RTR   = CAN_RTR_DATA;
    ' u" G4 m, w/ J+ P
  32.         TxMsgStruct.DLC   = 6;
    : {0 u6 W5 H% i/ x( i; S# e
  33.         TxMsgStruct.Data[0] = pbuf[0];3 U! h. a& S2 r0 A1 X* `
  34.         TxMsgStruct.Data[1] = pbuf[1];
    0 q1 n8 U2 D' S/ W9 u
  35.         TxMsgStruct.Data[2] = pbuf[2];; q4 I0 o! K1 m1 E5 f8 F
  36.         TxMsgStruct.Data[3] = pbuf[3];/ H* P+ n7 z1 K( c2 x
  37.         TxMsgStruct.Data[4] = pbuf[4];
    ; Z, k+ w) z+ d* [! q, @
  38.         TxMsgStruct.Data[5] = pbuf[5];
    % {! @3 E# r5 c$ V9 x. }
  39.         HAL_CAN_Transmit(&hcan,0);       
    2 U5 u9 V& x+ J2 }/ K7 G* v
  40. # N& c, \: `$ V& K) M% V' y, W# t
  41.         HAL_CAN_Receive_IT(&hcan, 0x00);5 @# a3 F9 S+ i1 E% Y. C& d
  42. }' R2 ^  [# |/ \: B: r1 E' R$ e% E9 X
  43. /**
      ?3 Y" B% @* o6 F+ P( m9 S2 g
  44. * @brief This function handles CEC and CAN interrupts.
    % s+ c$ `. D$ N% g3 A1 T
  45. */# H2 r7 k" k3 i  t' n. A1 x) w) \' d2 u
  46. void Can_Assignin_Rev_Pross(uint8_t *pbuf)' w8 \4 s6 ^% \6 A5 U& R' ]) L' Y
  47. {
    - F0 x, @5 K5 t2 c- ^4 B
  48.         hcan.Instance = CAN;8 e/ c3 U6 Q4 I3 D
  49.         hcan.pRxMsg = &RxMsgStruct;
    % K9 Q4 b. N" `
  50.   pbuf[0] = RxMsgStruct.Data[0]; * J0 a" y) _! Z' |
  51.         pbuf[1] = RxMsgStruct.Data[1];
    2 ^+ f! v- p  p
  52.         pbuf[2] = RxMsgStruct.Data[2];
    5 R5 V7 T% j# v8 L9 @
  53.         pbuf[3] = RxMsgStruct.Data[3];
    1 }2 o* M, ]# Q7 s4 E
  54.         pbuf[4] = RxMsgStruct.Data[4];
    2 L' U6 \. o; J) z/ H$ Q# y
  55. }
复制代码
3 l+ O9 w1 n8 |% R8 Z

% n4 K& X# Y+ \% ?9 o, L
/ \/ `! i+ o: U, L4 Z

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+ Y& {& u0 u. b% R) U
最近在玩CANopen,多交流呀。安臣移植canFestival吗
: ^$ w- X! B2 @4 c6 C* G8 o9 Q
没有啊  
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 手机版