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

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

[复制链接]
安臣 发布时间:2015-5-28 15:58
借鉴博客:http://blog.csdn.net/flydream0/article/details/8148791, s$ B8 n3 y; x# f; ]9 v
$ l( |& A8 P) j! C! N! v+ g
CAN ID值的结构分析
& Q* T$ y# g8 P* U* \

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

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


- p5 \9 F1 d' f

                                                                                     图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。那么知道这些有什么用呢?接下来的代码示例中你就会有什么用了。* A3 |* u% R6 [' T7 o- W3 H

4.2 位宽为32位的屏蔽模式- w7 l8 T) N5 K$ A5 W

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

如下图所示:

                                                                                 图10

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


0 M# `. m. G5 ^' p0 ?: H1 K) ^

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

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

: B3 b- C+ X3 M& s8 f

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

  1. CAN_FilterInitTypeDef  CAN_FilterInitStructure;& }$ g+ Y% w# S7 y$ J
  2. U16 std_id =0x7e9;# ?, V9 g7 g$ Z
  3. U32 ext_id =0x1800f001;
    ' h2 j; ^$ F5 D& m+ o. B6 `
  4. U32 mask =0;
    & X, u6 g7 }( `( ~3 N1 ~( N
  5. 0 q! V' D  A6 l
  6. CAN_FilterInit(&CAN_FilterInitStructure);     //初始化CAN_FilterInitStructrue结构体变量/ f. {/ ^; C3 s
  7. CAN_FilterInitStructure.CAN_FilterNumber=0;      //设置过滤器组0,范围为0~134 L* f% w) y2 R' d
  8. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;    //设置过滤器组0为屏蔽模式* g+ A! O7 m3 p) u
  9. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   //设置过滤器组0位宽为32位
    , W+ F0 V+ l4 e' o

  10. 3 H2 u* b& r2 n
  11. //标识位寄存器的设置: @& H: Z0 c5 H, Z
  12. //ext_id<<3对齐,见上图9,再>>16取高16位
    % I" \) D! s- c, [7 W
  13. CAN_FilterInitStructure.CAN_FilterIdHigh=((ext_id<<3) >>16) &0xffff;  //设置标识符寄存器高字节。
    ! |2 @5 f( d, m) x. d6 C( C
  14. CAN_FilterInitStructure.CAN_FilterIdLow=(U16)(ext_id<<3) | CAN_ID_EXT;   //设置标识符寄存器低字节- e2 [5 k5 [  u, a1 f: h2 n8 l
  15. //这里也可以这样设置; D1 C+ Q: d" _3 R, C% k
  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位后才能对齐.
    8 f. \- k9 S6 i5 u
  17. //CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_EXT;   //设置标识符寄存器低字节,这里也可以设置为CAN_ID_STD
    3 w2 @" v- i# V* `
  18. ; I2 C% a4 a! G
  19. //屏蔽寄存器的设置7 y' G2 o! [. a1 N2 V0 x
  20. //这里的思路是先将标准CAN ID和扩展CAN ID对应的ID值先异或后取反,为什么?异或是为了找出两个CAN ID有哪些位是相同的,是相同的位则说明需要关心,需要关心的位对应的屏蔽码位应该设置为1,因此需要取反一下。最后再整体左移3位。* z5 G" L1 h  L0 s
  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位.! `) O, V. S$ z0 p9 z6 w
  22. mask ^=ext_id;//将对齐后的标准CAN与扩展CAN异或后取反
    9 l' i# S, m* G( r; }* h
  23. mask =~mask;! f  m+ I4 L; l3 }/ u1 A5 G0 Z
  24. mask <<=3;//再整体左移3位$ S# K1 {# O+ I
  25. mask |=0x02; //只接收数据帧,不接收远程帧+ s0 m5 y) L, E6 l
  26. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(mask>>16)&0xffff; //设置屏蔽寄存器高字节
    ) P3 h0 ~& Z" ~1 D, s7 F
  27. CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask&0xffff;   //设置屏蔽寄存器低字节
    , _- X, s4 M' }1 I/ _2 U

  28. ! D9 g0 W1 O" M+ W" j
  29. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;  //此过滤器组关联到接收FIFO05 \( ]: h9 `5 |6 u( [' K
  30. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组8 e5 W+ w, i1 E, `" S
  31. CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器
    + {% l$ Z1 W0 C- \
复制代码

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

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

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

                                                                                                   图11

  1. CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    ( u; ~$ l  j: M  c( _1 b
  2. U16 std_id =0x7e9;  U9 y/ U+ E) m5 n# V+ |
  3. U32 ext_id =0x1800f001;
    7 C) P! A: D9 V: f+ @) \
  4. CAN_FilterInit(&CAN_FilterInitStructure); //初始化CAN_FilterInitStructrue结构体变量: \& v! I% }) |
  5. CAN_FilterInitStructure.CAN_FilterNumber=0;     //设置过滤器组0,范围为0~13
    6 o8 S. O7 K9 a% D# h) L
  6. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList;    //设置过滤器组0为标识符列表模式
    . S6 [9 S$ P4 {' O
  7. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   //设置过滤器组0位宽为32位
    , W) P8 F+ }  Z% k8 k" @
  8. ( M7 J# E% V( @/ T
  9. //设置屏蔽寄存器,这里当标识符寄存器用
    # ?( b) n) E$ z. ?' E
  10. CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5) ;  //为什么左移5位?与上面相同道理,这里不再重复解释
    4 i$ L0 e4 ^4 C' w9 s2 p
  11. CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_STD; //设置标识符寄存器低字节,CAN_FilterIdLow的ID位可以随意设置,在此模式下不会有效。7 n0 ]  Y! @2 g

  12. & L3 r6 C1 C  ]; s
  13. //设置标识符寄存器
    ; [0 L) A  K; h. R: b/ v
  14. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节
    . W4 J+ ?5 L/ T* r* F- c
  15. CAN_FilterInitStructure.CAN_FilterMaskIdLow=((ext_id<<3)& 0xffff) | CAN_ID_EXT;   //设置屏蔽寄存器低字节6 S# v0 d7 y. L5 E& X
  16. $ m4 T: {/ w) ~# A, p' @3 P+ @# G% t
  17. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;  //此过滤器组关联到接收FIFO0
    % S& ]8 ?) F, j5 s
  18. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组$ a9 N7 b$ k' K5 E6 V1 n$ K' f2 P
  19. CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器
    # I! M( l- W+ u0 V# i) ^
复制代码
4.4 位宽为16位的屏蔽码模式

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

                                                                                                          图12

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


4 J4 I' j& H! k, @0 P4.5 位宽为16位的标识符列表模式

                                                                                              图13
1 B$ {0 U# j4 M

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


. S: r0 A  @9 b/ }( J- P

以上是别人博客转载的

$ U& V/ Z- E' A: f

下面是i我自己的代码

  1. /**" ?+ V, k. L6 x+ b& L
  2. * @brief This function config can's fiflter.
    . Y8 a# e8 W' Z$ ?* I# B' s
  3. */5 t) z9 u$ Z+ D6 a& f
  4. void Can_FilterConfig(void)' F8 {% r" T. x" T
  5. {7 c5 X  S0 I7 E9 V1 V
  6.         CAN_FilterConfTypeDef FilterConfig;6 n8 d- ?1 Q' o3 e
  7.        
    ( S" g" K$ o- g" o0 I
  8.         FilterConfig.FilterIdHigh         = ((ext_id<<3) >>16) &0xffff;
    ( |' z$ x1 I" }9 D8 F
  9.         FilterConfig.FilterIdLow          = (uint16_t)(ext_id<<3) | CAN_ID_EXT | CAN_RTR_DATA;
    ; S( A% {' R. e( T, K* Z8 s
  10.         FilterConfig.FilterMaskIdHigh     = 0xfff8;
    % V1 E0 L8 R6 v- w2 |
  11.         FilterConfig.FilterMaskIdLow      = 0x07ff;& ]) ]- \" S, p3 f+ e
  12.         FilterConfig.FilterFIFOAssignment = 0x00;
    " t' @( L, M1 p4 p+ F" V2 V- f
  13.         FilterConfig.FilterNumber         = 0x00;& q0 U7 {1 ]: [' u5 E1 N, T
  14.         FilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;
    . o. E4 J+ Q- |' v6 z
  15.         FilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;
    : E/ r0 q: W9 S; A0 a& {$ ]9 f
  16.         FilterConfig.FilterActivation     = ENABLE;
    $ o5 v% @+ n) ~" P
  17.         hcan.Instance = CAN;
    / L+ ~5 ^" v8 l
  18.         HAL_CAN_ConfigFilter(&hcan, &FilterConfig);
    : y4 C5 B+ k- x, d$ G+ a
  19. }
    0 O/ {/ A9 j: P, @1 o, j) I
  20. /**, h' |( P( Y1 e; c4 I1 D, Z
  21. * @brief This function is can send pross.( f4 w: s3 g; e- p) T; A
  22. */7 X6 w/ `, L2 n. n
  23. void Can_Assignin_Send_Pross(uint8_t *pbuf)% ]; G! \8 x$ z
  24. {
    * \0 d, f) X4 w5 E# `
  25.         hcan.Instance = CAN;
    7 n* t  p) @" p/ j7 ^9 O
  26.         hcan.pTxMsg = &TxMsgStruct;/ O1 `* N6 ~9 O" I. [7 g3 F) V
  27.         hcan.pRxMsg = &RxMsgStruct;* M" c# b, W& N* Z7 r1 H5 M# X

  28. : Z4 D% f1 Y; s8 k3 L  Q% a5 f! R  e
  29.         TxMsgStruct.ExtId = 0x18ff0004;5 _; J$ V: O0 z, v% ]9 f
  30.         TxMsgStruct.IDE   = CAN_ID_EXT  ;5 n5 C) Q% m3 Y
  31.         TxMsgStruct.RTR   = CAN_RTR_DATA;
    $ P# \7 m2 k7 V' E  H& u
  32.         TxMsgStruct.DLC   = 6;
    ' F3 |; W, |3 N% I0 m
  33.         TxMsgStruct.Data[0] = pbuf[0];: c4 \1 {  \3 n0 f# A  C7 C6 a9 ~
  34.         TxMsgStruct.Data[1] = pbuf[1];
    , E& H% Y( t) o! {
  35.         TxMsgStruct.Data[2] = pbuf[2];
    ' _+ ?! C" b4 o1 E, w
  36.         TxMsgStruct.Data[3] = pbuf[3];1 L+ j' W6 y& U) d4 t
  37.         TxMsgStruct.Data[4] = pbuf[4];2 t3 o  y# F! i
  38.         TxMsgStruct.Data[5] = pbuf[5];7 b% g9 j' E! U/ B; o& }
  39.         HAL_CAN_Transmit(&hcan,0);       
    % S8 {1 K1 u, T

  40. 0 X4 F* Q( I8 L
  41.         HAL_CAN_Receive_IT(&hcan, 0x00);0 w8 @6 R$ j4 e& X
  42. }& H2 M. f& K+ z  I6 E6 V
  43. /**
    ( S# x0 i0 }  \) B8 J
  44. * @brief This function handles CEC and CAN interrupts.- o8 b+ W& [: X, A; c2 e$ t! E
  45. */
    9 g4 F; H$ u) l$ W- ^" [# T
  46. void Can_Assignin_Rev_Pross(uint8_t *pbuf)' N( k0 Q6 n& ^. P; e
  47. {
    0 O- {7 \  t7 i& h
  48.         hcan.Instance = CAN;
    7 A; b; d& A' U* {& @2 P; V
  49.         hcan.pRxMsg = &RxMsgStruct;
    ' z, N+ b) ^% E6 W, ^( O. X
  50.   pbuf[0] = RxMsgStruct.Data[0]; % P' }9 z& B7 Q$ S* y* K, Y* x/ D7 A* f
  51.         pbuf[1] = RxMsgStruct.Data[1]; 0 Y, y. W6 C% v- R' z# |5 l# {7 e& _. F
  52.         pbuf[2] = RxMsgStruct.Data[2]; ! k; E( j( ~9 w! n8 B2 S& m$ A
  53.         pbuf[3] = RxMsgStruct.Data[3]; : v$ E* |* T- z* a  o/ n" S
  54.         pbuf[4] = RxMsgStruct.Data[4];
    / S9 Z3 Z! A5 T) A- R) ?
  55. }
复制代码

1 \, }2 O# X1 y# @* ?3 Z* f
/ a4 R* e8 |1 i( A4 }- R" y  C4 F" [' y: A5 T9 S) p7 z4 J  ]

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:048 [8 H. o6 m/ A
最近在玩CANopen,多交流呀。安臣移植canFestival吗
4 p4 b* l/ L0 m# w" M1 o% T. M
没有啊  
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 手机版