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

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

[复制链接]
安臣 发布时间:2015-5-28 15:58
借鉴博客:http://blog.csdn.net/flydream0/article/details/8148791
1 D' n8 w. A6 Y6 {9 |# n9 |0 l, w- M% T; ?7 I; T
CAN ID值的结构分析7 @- Q* K- ?* ]+ K

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

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

8 h' P+ e9 T9 S$ r

                                                                                     图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。那么知道这些有什么用呢?接下来的代码示例中你就会有什么用了。
8 R! a8 D0 b6 v; _$ o+ z' [( G5 d

4.2 位宽为32位的屏蔽模式
9 u0 o$ z) R; m# l; @, b

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

如下图所示:

                                                                                 图10

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


2 ~- V( x2 `, ~$ R5 z# K

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

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


6 @. w- i* K( N5 g

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

  1. CAN_FilterInitTypeDef  CAN_FilterInitStructure;
      E: S$ l) v3 s( I$ z
  2. U16 std_id =0x7e9;
    ( W" |* l7 Z$ z' B7 N: S
  3. U32 ext_id =0x1800f001;; a) S6 V+ y8 P( O4 w
  4. U32 mask =0;
    ( I+ i$ I" P; b

  5. " M, [) a. \6 ~: i  W; @
  6. CAN_FilterInit(&CAN_FilterInitStructure);     //初始化CAN_FilterInitStructrue结构体变量$ F  }- s. @% j# J" w
  7. CAN_FilterInitStructure.CAN_FilterNumber=0;      //设置过滤器组0,范围为0~13
    / @2 J0 N2 y% W+ j! {$ x" t
  8. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;    //设置过滤器组0为屏蔽模式
    % V$ T: I' h! t: Q
  9. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   //设置过滤器组0位宽为32位
    9 O# c3 q5 U  q$ A$ d
  10. 4 M+ n. z# l& \5 I* c6 b$ [
  11. //标识位寄存器的设置* E; Q5 {% U  g& ]1 i7 w9 v) i
  12. //ext_id<<3对齐,见上图9,再>>16取高16位
    - z0 N, B( H5 Q. j
  13. CAN_FilterInitStructure.CAN_FilterIdHigh=((ext_id<<3) >>16) &0xffff;  //设置标识符寄存器高字节。
    8 O. N5 I% J! f8 `. n
  14. CAN_FilterInitStructure.CAN_FilterIdLow=(U16)(ext_id<<3) | CAN_ID_EXT;   //设置标识符寄存器低字节
    + `0 S/ X4 {! f: j6 f& F) i
  15. //这里也可以这样设置3 F  w! h  Z& _. R9 k# G
  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位后才能对齐.- D! O! I  O  x1 n: J
  17. //CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_EXT;   //设置标识符寄存器低字节,这里也可以设置为CAN_ID_STD7 k4 C; p0 }* x$ e5 x% X
  18. * s+ W* g7 h0 \3 j" w  V
  19. //屏蔽寄存器的设置
    2 I4 V+ F( i( i
  20. //这里的思路是先将标准CAN ID和扩展CAN ID对应的ID值先异或后取反,为什么?异或是为了找出两个CAN ID有哪些位是相同的,是相同的位则说明需要关心,需要关心的位对应的屏蔽码位应该设置为1,因此需要取反一下。最后再整体左移3位。5 J$ u$ k- _3 t: b- m; q& p
  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位.
    ' w, a5 o7 E' e8 Z) h" ?5 u- S- }! M
  22. mask ^=ext_id;//将对齐后的标准CAN与扩展CAN异或后取反
    6 U. y9 T) b- S7 t2 I: b# X! E$ u
  23. mask =~mask;) ~, u. l$ w9 _( @' M
  24. mask <<=3;//再整体左移3位5 A" z& e( G6 q+ J) k( ^
  25. mask |=0x02; //只接收数据帧,不接收远程帧' ~; a5 T! ?! \# S4 E
  26. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(mask>>16)&0xffff; //设置屏蔽寄存器高字节  M$ C! v9 {$ e+ A4 W$ U" H( _% R
  27. CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask&0xffff;   //设置屏蔽寄存器低字节
    0 e+ e/ f- T' ]0 y% V0 j5 [, A- k

  28. 1 i+ k( N+ y, O- e" M
  29. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;  //此过滤器组关联到接收FIFO0
    2 Y8 a+ N6 Y/ p- @8 Y; i
  30. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组
    $ H. c) T2 V$ K
  31. CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器
    0 v6 K; {+ K( G3 ^9 Y+ m5 C& ~
复制代码

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

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

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

                                                                                                   图11

  1. CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    * Y- _9 Z/ Z3 a) o  M7 U6 S8 z0 p/ T
  2. U16 std_id =0x7e9;
    , I; B5 j+ o% \; N, k$ c; D
  3. U32 ext_id =0x1800f001;+ l8 x9 C5 ~" t' I! K5 d% x
  4. CAN_FilterInit(&CAN_FilterInitStructure); //初始化CAN_FilterInitStructrue结构体变量) X) F2 L+ K" |. \/ S% l
  5. CAN_FilterInitStructure.CAN_FilterNumber=0;     //设置过滤器组0,范围为0~13
    1 o0 t& x- k5 f
  6. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList;    //设置过滤器组0为标识符列表模式6 @& u/ @, `; o* q- y
  7. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   //设置过滤器组0位宽为32位( t+ x6 ]$ h# m4 V) s: Q
  8. 2 e6 i1 e8 |9 e8 x( p* }5 u
  9. //设置屏蔽寄存器,这里当标识符寄存器用% X: E* l' w2 V" S' n
  10. CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5) ;  //为什么左移5位?与上面相同道理,这里不再重复解释
    : n% @8 A/ F$ ?: r
  11. CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_STD; //设置标识符寄存器低字节,CAN_FilterIdLow的ID位可以随意设置,在此模式下不会有效。
    6 W7 |4 e0 I' c' ^4 \1 H6 ^4 t
  12. - L$ z& D) n) h3 V* S
  13. //设置标识符寄存器# W% a; c  a9 M/ E% [
  14. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节1 P1 z8 o% x% E' T7 _3 b% V( @
  15. CAN_FilterInitStructure.CAN_FilterMaskIdLow=((ext_id<<3)& 0xffff) | CAN_ID_EXT;   //设置屏蔽寄存器低字节! i* ^+ r( }6 @2 c" ]$ _

  16. 7 q: e( D: W. U0 _4 [( o
  17. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;  //此过滤器组关联到接收FIFO0
    . K6 W+ \* g$ N5 v* x
  18. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组
    0 L* \2 Y3 r: ?; `8 {$ A- K
  19. CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器
    * c' Q  b6 d$ f2 Y" u6 V
复制代码
4.4 位宽为16位的屏蔽码模式

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

                                                                                                          图12

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

3 h$ p! V) S* M) [6 X
4.5 位宽为16位的标识符列表模式

                                                                                              图13
5 D3 p+ O/ ~. F5 U6 W  ~

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

" X: E8 L8 n+ q& K

以上是别人博客转载的


3 ?0 a* d4 U' P

下面是i我自己的代码

  1. /**
    & \: u# F, J: c  ?) M  r  h
  2. * @brief This function config can's fiflter.
    0 F4 g7 u6 H7 \; w2 q! K* d
  3. */
    2 J0 |/ ]% o4 K3 y- ]4 O) }
  4. void Can_FilterConfig(void). X6 j3 V8 \" u  n$ Q8 i
  5. {. q# {1 j' x) X, R0 Q- {
  6.         CAN_FilterConfTypeDef FilterConfig;: J/ }* W8 Q! |2 h8 n% W1 |
  7.        
    . d' m" Y: a% |# v- m
  8.         FilterConfig.FilterIdHigh         = ((ext_id<<3) >>16) &0xffff;% R0 z. s4 \9 V1 w) x6 b
  9.         FilterConfig.FilterIdLow          = (uint16_t)(ext_id<<3) | CAN_ID_EXT | CAN_RTR_DATA;4 d( ^$ ?# e: U! K
  10.         FilterConfig.FilterMaskIdHigh     = 0xfff8;
    + S1 y. E( _/ \% D
  11.         FilterConfig.FilterMaskIdLow      = 0x07ff;# \4 |9 @- F& O/ ?/ ^
  12.         FilterConfig.FilterFIFOAssignment = 0x00;
    3 M+ _* ?* v+ G) [1 Y9 Z4 m" u' O
  13.         FilterConfig.FilterNumber         = 0x00;1 _, t0 {* c' R  u0 W; W
  14.         FilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;/ b- z, M* Y: G! M
  15.         FilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;! q. J- i. ?0 j! w* M
  16.         FilterConfig.FilterActivation     = ENABLE;
    $ L6 D! i3 g+ \1 D
  17.         hcan.Instance = CAN;' E# ]  }8 ]" A6 @& ~. E
  18.         HAL_CAN_ConfigFilter(&hcan, &FilterConfig);
    * P5 R% e+ A% c9 a2 g- s% T
  19. }
    8 r/ g6 z. ?3 g1 u2 L
  20. /**
    0 t/ ^' n" _; r: A3 U7 v  x
  21. * @brief This function is can send pross.
    2 ?6 v2 n2 V1 j1 z
  22. */
    ( v6 x% m9 X( `( I, \: K
  23. void Can_Assignin_Send_Pross(uint8_t *pbuf)
    . v- Y- _9 H, h# r  Q
  24. {, p( |+ L+ d' N
  25.         hcan.Instance = CAN;
    . Y$ r3 j/ ~& w. f, Y
  26.         hcan.pTxMsg = &TxMsgStruct;
    * e+ T# I6 S) f" M
  27.         hcan.pRxMsg = &RxMsgStruct;8 Z4 x( L4 e" i" r

  28. ! G/ u& G$ b! `6 {; _+ k
  29.         TxMsgStruct.ExtId = 0x18ff0004;
    ( v1 l3 n+ i7 Q3 t# G# p/ S  u
  30.         TxMsgStruct.IDE   = CAN_ID_EXT  ;
    , }- h) S) I7 J$ V+ O
  31.         TxMsgStruct.RTR   = CAN_RTR_DATA;$ v/ h. O! x# \" N, q( m% q' l
  32.         TxMsgStruct.DLC   = 6;
    & U0 z; F, c& e
  33.         TxMsgStruct.Data[0] = pbuf[0];
    8 O- x( T; ~3 a4 Z# X& |- j- G5 n
  34.         TxMsgStruct.Data[1] = pbuf[1];
    8 `0 [( H7 ]  R) ?7 r7 H
  35.         TxMsgStruct.Data[2] = pbuf[2];% I4 n  M$ B9 a" d
  36.         TxMsgStruct.Data[3] = pbuf[3];
    9 r" s& Z' K" Z7 t
  37.         TxMsgStruct.Data[4] = pbuf[4];
    + `8 L; \9 O& @' y
  38.         TxMsgStruct.Data[5] = pbuf[5];
      w# c. A; @0 p5 {
  39.         HAL_CAN_Transmit(&hcan,0);        4 A3 Q$ d* r+ r% J6 c

  40. ( O3 p$ t( v' N' M/ q! i. c
  41.         HAL_CAN_Receive_IT(&hcan, 0x00);
    4 U( c% H/ {8 B
  42. }
    ) v' m- z3 J2 I9 U1 S+ g
  43. /**
    # a0 ]7 S. Y( d
  44. * @brief This function handles CEC and CAN interrupts.
      A2 J+ N4 i+ z4 N
  45. */0 u+ b0 b4 l1 c2 K
  46. void Can_Assignin_Rev_Pross(uint8_t *pbuf)
    % j' k; r& k' G
  47. {
    , [' a  ]1 c6 s, b; b  t
  48.         hcan.Instance = CAN;
    ! y* ?1 v4 k  J5 _( D% {
  49.         hcan.pRxMsg = &RxMsgStruct;1 f+ p2 B6 l- _! j+ _0 V: B
  50.   pbuf[0] = RxMsgStruct.Data[0]; 3 m! c) S- G/ {) }+ R! Y+ |* F
  51.         pbuf[1] = RxMsgStruct.Data[1]; 4 f3 Z# u) ?) J3 n
  52.         pbuf[2] = RxMsgStruct.Data[2]; 1 w( b7 B' O5 t/ ?
  53.         pbuf[3] = RxMsgStruct.Data[3];
    6 ?, ?% A: s0 i4 G
  54.         pbuf[4] = RxMsgStruct.Data[4]; ) @! s8 f* z8 U- i) g# {; j
  55. }
复制代码

" H, P9 |3 F. [: j& k2 u
: R1 C* A4 O& ]+ x7 Q. A% t8 z6 u- o4 E$ I2 P0 I$ O5 F" f

can.rar

下载

3.8 MB, 下载次数: 561

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

举报

24个回答
安臣 回答时间:2016-6-16 21:16:44
watershade 发表于 2016-5-10 21:04
7 C* T; E, a' f  Q/ Z$ ^' o2 l! X最近在玩CANopen,多交流呀。安臣移植canFestival吗

' {+ Q' x% M6 u% i1 t) n+ ^) j6 l没有啊  
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管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版