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

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

[复制链接]
安臣 发布时间:2015-5-28 15:58
借鉴博客:http://blog.csdn.net/flydream0/article/details/8148791
$ _- `' g3 X% n
* s  E! o, E2 x+ v* q
CAN ID值的结构分析) P  P* X2 `2 ^

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

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

7 `4 ^$ G. l# 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。那么知道这些有什么用呢?接下来的代码示例中你就会有什么用了。
0 n! I& Q) g0 K0 j7 }& x

4.2 位宽为32位的屏蔽模式
* R) g3 Z3 _2 g$ w4 Y+ [) [" ^

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

如下图所示:

                                                                                 图10

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


8 c% m) v8 s* i& e5 p  p' q' \* R

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

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

; \7 n. E% g3 J6 k& D6 x$ X% ~2 E

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

  1. CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    + {" E6 D' f9 }9 K1 p
  2. U16 std_id =0x7e9;) D% j! V% I% I3 X* x5 N, h2 l
  3. U32 ext_id =0x1800f001;7 [' {. A! Z3 w2 a2 [1 z9 z+ t
  4. U32 mask =0;6 g! a- Q1 s- S7 s% ~5 o! s! D0 B

  5. * U2 f# n! P7 e$ O2 j
  6. CAN_FilterInit(&CAN_FilterInitStructure);     //初始化CAN_FilterInitStructrue结构体变量8 o# c& t/ {+ w( q# |  n" n8 w
  7. CAN_FilterInitStructure.CAN_FilterNumber=0;      //设置过滤器组0,范围为0~13
    $ p) c+ e2 D, G; ]' i5 a
  8. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;    //设置过滤器组0为屏蔽模式
    # e: i' J8 x7 v0 t$ A
  9. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   //设置过滤器组0位宽为32位
    . G, J; e  g* o) e: E! S; n. j
  10. / x  z5 b9 R# V! ^: ]
  11. //标识位寄存器的设置
    4 u0 U1 ?  ]+ D0 ^& D% O
  12. //ext_id<<3对齐,见上图9,再>>16取高16位
    8 ?8 K1 C2 U7 f7 m2 `- L4 E
  13. CAN_FilterInitStructure.CAN_FilterIdHigh=((ext_id<<3) >>16) &0xffff;  //设置标识符寄存器高字节。
    : q" Z- `5 J& V# j9 r. E3 k  H1 E
  14. CAN_FilterInitStructure.CAN_FilterIdLow=(U16)(ext_id<<3) | CAN_ID_EXT;   //设置标识符寄存器低字节/ t* L4 r; }! p6 ]
  15. //这里也可以这样设置
    # L( u8 F. [7 P( v
  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位后才能对齐.
    % R, `( `1 V4 O6 i
  17. //CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_EXT;   //设置标识符寄存器低字节,这里也可以设置为CAN_ID_STD7 K: q$ Q/ k+ Q# O

  18. $ e; h9 ~$ k% R" O7 S2 C2 E
  19. //屏蔽寄存器的设置1 j4 M' E) _! A8 j5 E6 S: x
  20. //这里的思路是先将标准CAN ID和扩展CAN ID对应的ID值先异或后取反,为什么?异或是为了找出两个CAN ID有哪些位是相同的,是相同的位则说明需要关心,需要关心的位对应的屏蔽码位应该设置为1,因此需要取反一下。最后再整体左移3位。; V5 Q' O. b; I4 D4 @
  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位.
    / u! x  {: A$ R/ R" _
  22. mask ^=ext_id;//将对齐后的标准CAN与扩展CAN异或后取反% `7 m' ^* G& b4 S/ J. {
  23. mask =~mask;
    $ [6 W0 Q; r& Y' [  l) m
  24. mask <<=3;//再整体左移3位
    * v. r+ {: j8 c3 u( U2 S. [. A
  25. mask |=0x02; //只接收数据帧,不接收远程帧9 N; H+ Z" a: I
  26. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(mask>>16)&0xffff; //设置屏蔽寄存器高字节
    0 J  k% _4 v6 q! o5 c
  27. CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask&0xffff;   //设置屏蔽寄存器低字节
    : ]/ J# ^$ }1 J5 |
  28. 0 q( i' ~7 _# C/ c" z: U
  29. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;  //此过滤器组关联到接收FIFO09 l: b* W# f- x" M5 l! J! f5 j5 T& W
  30. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组# u/ A2 r. C0 h& T
  31. CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器' ~; p3 I  ~- o1 F/ U! |2 m
复制代码

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

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

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

                                                                                                   图11

  1. CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    , u5 ?* k' O4 W8 X1 j
  2. U16 std_id =0x7e9;+ _5 {! G; G  [# H' c0 l2 q
  3. U32 ext_id =0x1800f001;; D/ t( H$ R$ ?3 A. N$ l
  4. CAN_FilterInit(&CAN_FilterInitStructure); //初始化CAN_FilterInitStructrue结构体变量- B* C  L5 |0 X$ T$ {2 D
  5. CAN_FilterInitStructure.CAN_FilterNumber=0;     //设置过滤器组0,范围为0~13
    9 K0 T/ f8 D4 z, y- x2 \
  6. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList;    //设置过滤器组0为标识符列表模式
    2 C% H+ A& O7 h- G' I( V6 `
  7. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   //设置过滤器组0位宽为32位, a/ e* ]1 ]% _+ f0 G
  8. ; O: |! u5 s) x( U: F
  9. //设置屏蔽寄存器,这里当标识符寄存器用" F7 g; c& r- `: d7 |
  10. CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5) ;  //为什么左移5位?与上面相同道理,这里不再重复解释
    , @1 s6 U& W, s( Y  W- s% T2 S
  11. CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_STD; //设置标识符寄存器低字节,CAN_FilterIdLow的ID位可以随意设置,在此模式下不会有效。
    % ]& e% L" m, v$ [9 P1 F- |7 ~

  12. $ D' E; @9 D+ t8 J
  13. //设置标识符寄存器
    ) V0 u, W; a2 y2 v. e" Y5 Z6 D
  14. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节) a8 j- H! j9 D, f/ F; z" ?' s/ ~* a5 x
  15. CAN_FilterInitStructure.CAN_FilterMaskIdLow=((ext_id<<3)& 0xffff) | CAN_ID_EXT;   //设置屏蔽寄存器低字节
    ' _% {/ z/ _; d( H: G" l. x, A
  16. : J) Z# Z: G3 j9 [
  17. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;  //此过滤器组关联到接收FIFO0% c6 T4 H- H: R0 E+ h7 n* {7 I
  18. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组/ a  H; h' P) ^
  19. CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器+ [/ ^. u2 B, E0 |1 ]" T3 Y; ?1 J1 e
复制代码
4.4 位宽为16位的屏蔽码模式

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

                                                                                                          图12

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

+ @8 f' C4 ^, ~7 U; j6 I. b: q
4.5 位宽为16位的标识符列表模式

                                                                                              图13
: x+ G4 v$ H" A. Z. V

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

. C: ^! Q7 y  k' b& c

以上是别人博客转载的

! V. m4 V$ p( m; R

下面是i我自己的代码

  1. /**$ V/ A" w4 w3 J+ @& e# S9 h5 M% D
  2. * @brief This function config can's fiflter.
    " l/ O0 W3 d2 _  {/ J8 \# G
  3. */
    : v, [$ o6 F# g& h
  4. void Can_FilterConfig(void)0 J3 {1 E' B' Z; z, |# `) [
  5. {" u7 b3 J+ n! C/ v5 P1 U
  6.         CAN_FilterConfTypeDef FilterConfig;% x4 l# n6 e4 I. ^0 H3 r
  7.        
    - B$ m3 E; g$ K
  8.         FilterConfig.FilterIdHigh         = ((ext_id<<3) >>16) &0xffff;9 Z) v! _9 t5 G7 F& p: K
  9.         FilterConfig.FilterIdLow          = (uint16_t)(ext_id<<3) | CAN_ID_EXT | CAN_RTR_DATA;  i3 B6 ]  O- M/ w  C2 w
  10.         FilterConfig.FilterMaskIdHigh     = 0xfff8;
    . X2 V' n' W4 ?9 o. R1 u* M; i
  11.         FilterConfig.FilterMaskIdLow      = 0x07ff;
    / {9 K5 N- c" w0 a0 [/ \
  12.         FilterConfig.FilterFIFOAssignment = 0x00;
    ( I6 b, v1 I/ C8 t, i# ]! l, f
  13.         FilterConfig.FilterNumber         = 0x00;
    6 Z  E; w  w" Z1 t
  14.         FilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;+ L8 e& x4 h  x7 Z
  15.         FilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;
    9 I9 u9 n+ ^8 ?  `/ |3 {0 ~
  16.         FilterConfig.FilterActivation     = ENABLE;0 s/ E- ^+ L- a- K: t0 \. }
  17.         hcan.Instance = CAN;
    9 n$ U1 \3 Z4 u3 R9 _% A( t/ ]
  18.         HAL_CAN_ConfigFilter(&hcan, &FilterConfig);/ T/ J" h. A" b% ^. W  c
  19. }3 n  Z2 I; K, o2 v, T7 {
  20. /**
    9 M/ E: O6 f7 r
  21. * @brief This function is can send pross.
    ; v  \9 t8 W5 H
  22. */
      q) j$ u, ]; H6 S$ D2 e3 k, m  q
  23. void Can_Assignin_Send_Pross(uint8_t *pbuf)
    , w/ i; T8 r& m* t1 `% _
  24. {1 W4 z6 C8 a- d! i/ F& W
  25.         hcan.Instance = CAN;& P& m9 t% F" b9 x8 L7 f: J0 R; \0 {
  26.         hcan.pTxMsg = &TxMsgStruct;, G8 e' P- F8 Q3 p
  27.         hcan.pRxMsg = &RxMsgStruct;/ U( e  K. B. m; `/ C( a
  28. ! r* N. X6 d8 g! N
  29.         TxMsgStruct.ExtId = 0x18ff0004;
    7 q7 L7 Y2 ~, c4 |2 L1 O
  30.         TxMsgStruct.IDE   = CAN_ID_EXT  ;
    , d$ v5 l8 ?0 N9 y
  31.         TxMsgStruct.RTR   = CAN_RTR_DATA;
    , l1 i% ]! q9 R3 ]
  32.         TxMsgStruct.DLC   = 6;& Z3 I7 R+ b6 I6 [( u& W6 c$ _, p3 @
  33.         TxMsgStruct.Data[0] = pbuf[0];' k+ L( k8 n7 Q0 S* B) S; S
  34.         TxMsgStruct.Data[1] = pbuf[1];" u: ]! Y' Y0 m+ i
  35.         TxMsgStruct.Data[2] = pbuf[2];6 `5 S8 E9 m# S, R) F+ |* A9 s
  36.         TxMsgStruct.Data[3] = pbuf[3];6 Y9 S4 c1 |' x- R
  37.         TxMsgStruct.Data[4] = pbuf[4];
    6 d" I* g2 P$ S6 }4 v8 b
  38.         TxMsgStruct.Data[5] = pbuf[5];
    9 r- C( d9 Z( m) C2 @: s! o
  39.         HAL_CAN_Transmit(&hcan,0);       
    ! z1 C" m$ Q6 N: I
  40. * J! }% a1 t5 _/ q$ A  Z: h
  41.         HAL_CAN_Receive_IT(&hcan, 0x00);) `0 d  F9 |& p8 Q( C0 G
  42. }
    ; G8 n6 i. C5 B8 P  H6 q* B
  43. /**; @: x4 Z  G: }5 B2 g& x' r
  44. * @brief This function handles CEC and CAN interrupts.
    , T/ h( F; H4 y+ N# Y: Z$ u
  45. */
    * y2 e7 h  I0 v4 c9 P% s
  46. void Can_Assignin_Rev_Pross(uint8_t *pbuf)3 m* }' P0 `( s& \
  47. {
    % u" f2 i0 T2 w0 d3 M' {2 V
  48.         hcan.Instance = CAN;
    4 `8 f& ?/ U$ m) i
  49.         hcan.pRxMsg = &RxMsgStruct;$ u, p% O1 U! z  D
  50.   pbuf[0] = RxMsgStruct.Data[0];
    + l+ ?  X; l* c7 D. k1 ^
  51.         pbuf[1] = RxMsgStruct.Data[1]; 6 I: s( `9 a. S0 F
  52.         pbuf[2] = RxMsgStruct.Data[2];
    4 q8 h, I& n7 ~  B
  53.         pbuf[3] = RxMsgStruct.Data[3]; - _, [/ @5 ~. z$ x" f1 b9 a
  54.         pbuf[4] = RxMsgStruct.Data[4]; / S, ]+ H3 O- n9 ~9 L
  55. }
复制代码
- J$ u6 s" p) {5 G3 n4 R* a- h0 {/ ]

5 H/ m$ g" I% j2 K/ K3 q, b; u$ ?2 h1 k' w4 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
. Z- q( E2 a7 k! l1 ^7 [, D/ X最近在玩CANopen,多交流呀。安臣移植canFestival吗

) @; F6 u- B  f( c% F# K没有啊  
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 手机版