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

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

[复制链接]
安臣 发布时间:2015-5-28 15:58
借鉴博客:http://blog.csdn.net/flydream0/article/details/8148791, w, G, L' Y$ T
4 `& ~% a7 B# i7 C7 C% j& ?
CAN ID值的结构分析
, x! ?" d) G5 i  x0 O; N, R

              在讲到代码实例之前,首先大家都弄懂一件事,当给定一个CAN ID,如0x1800f001,当然这个是扩展ID,这里要问的是,这个CAN ID的值本身包含两部分,即基本ID与扩展ID,即么你知道这个扩展ID0x1800f001的哪些位是基本ID,哪些位又是扩展ID?(在基本CANID格式下不存在这个问题)/ G# B% j& i# _- P8 H4 E8 b

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


0 Y2 Q" D0 Z1 K( x$ `$ y0 v

                                                                                     图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。那么知道这些有什么用呢?接下来的代码示例中你就会有什么用了。' w7 v/ @6 [! L7 K9 a

4.2 位宽为32位的屏蔽模式- Y* y! o" G, |/ l* F4 i

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

如下图所示:

                                                                                 图10

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


( R* {3 i/ [5 z% |# ?5 X- s5 T$ U

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

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


% W9 }) k6 x. C% T2 F: w+ }; |. {

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

  1. CAN_FilterInitTypeDef  CAN_FilterInitStructure;( \% c% F! a9 O  o  L
  2. U16 std_id =0x7e9;/ D& u, g7 ?  O
  3. U32 ext_id =0x1800f001;
    , p/ R  C. M- m: q
  4. U32 mask =0;
    3 a% B8 A8 F8 J5 i* K

  5.   X6 l4 a4 r8 Q8 h9 y
  6. CAN_FilterInit(&CAN_FilterInitStructure);     //初始化CAN_FilterInitStructrue结构体变量
    & f1 @" O; _1 y8 L% R3 e3 Q
  7. CAN_FilterInitStructure.CAN_FilterNumber=0;      //设置过滤器组0,范围为0~13, X7 O% z" ^/ k0 u) C5 R5 I
  8. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;    //设置过滤器组0为屏蔽模式2 B3 Q* @8 k# q( ]$ u* [
  9. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   //设置过滤器组0位宽为32位( r# |- d; h6 ]% W6 Z- w( o0 a

  10. + g. L# O8 i4 b+ ]$ l
  11. //标识位寄存器的设置  ^# i& ~7 h7 Y3 K  \6 B
  12. //ext_id<<3对齐,见上图9,再>>16取高16位
    7 w8 R! b( T+ A' p; q
  13. CAN_FilterInitStructure.CAN_FilterIdHigh=((ext_id<<3) >>16) &0xffff;  //设置标识符寄存器高字节。
    0 o" k1 v3 G0 F
  14. CAN_FilterInitStructure.CAN_FilterIdLow=(U16)(ext_id<<3) | CAN_ID_EXT;   //设置标识符寄存器低字节7 J" D( C  e% K4 g3 z* t: ~
  15. //这里也可以这样设置2 O0 M: Z* k# H  d
  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位后才能对齐.
    - `. r3 N3 R& a% @" k+ A) {
  17. //CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_EXT;   //设置标识符寄存器低字节,这里也可以设置为CAN_ID_STD
    9 R; P0 [+ O5 _3 i9 [, F

  18. 1 q& A) W" c5 G7 K
  19. //屏蔽寄存器的设置8 y* B; L8 v! r8 k2 _0 ~: z: s
  20. //这里的思路是先将标准CAN ID和扩展CAN ID对应的ID值先异或后取反,为什么?异或是为了找出两个CAN ID有哪些位是相同的,是相同的位则说明需要关心,需要关心的位对应的屏蔽码位应该设置为1,因此需要取反一下。最后再整体左移3位。4 r; X& ^" a( ~" t/ ~/ v* p" h
  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 g9 z% ]4 z% ?3 t
  22. mask ^=ext_id;//将对齐后的标准CAN与扩展CAN异或后取反
    $ Y8 ]# B* n$ V+ U. q) [7 A6 S
  23. mask =~mask;$ G* i$ x- w  ?) |0 [8 b2 m
  24. mask <<=3;//再整体左移3位
    " |0 T6 e- ]2 f2 c; c- s
  25. mask |=0x02; //只接收数据帧,不接收远程帧
    / [. \; r. O) G8 }! R9 O  A
  26. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(mask>>16)&0xffff; //设置屏蔽寄存器高字节
    9 [6 @4 M3 q+ I) j
  27. CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask&0xffff;   //设置屏蔽寄存器低字节! ~! P7 Z& G5 Q* o

  28. 5 S3 w" p5 W5 Q8 e8 _+ B6 H
  29. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;  //此过滤器组关联到接收FIFO0  N1 L) w# I' {. J
  30. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组
    / l3 A, ]& n. W9 b/ d
  31. CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器
    8 W2 g* f' j% ?8 c2 L
复制代码

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

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

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

                                                                                                   图11

  1. CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    1 l; [4 u* a" X- `) S! d" {
  2. U16 std_id =0x7e9;
    3 Z6 ~+ `( g9 s
  3. U32 ext_id =0x1800f001;
    2 ?9 N1 x8 K; R) ~$ w) u
  4. CAN_FilterInit(&CAN_FilterInitStructure); //初始化CAN_FilterInitStructrue结构体变量4 N8 O+ P% ]6 `- A$ I. _3 K
  5. CAN_FilterInitStructure.CAN_FilterNumber=0;     //设置过滤器组0,范围为0~134 ?! {! W3 @" b; b5 b
  6. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList;    //设置过滤器组0为标识符列表模式
    ) M4 K: h9 ~0 e! j+ E/ |& `" b2 f  J
  7. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   //设置过滤器组0位宽为32位) r3 V! Z/ }# ]! M" J) V
  8. 1 A, f1 l% G! O5 {
  9. //设置屏蔽寄存器,这里当标识符寄存器用: ~' G+ E& K3 ]" v" J9 @5 R
  10. CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5) ;  //为什么左移5位?与上面相同道理,这里不再重复解释2 A5 t# Z6 q; G1 F, h% s+ m
  11. CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_STD; //设置标识符寄存器低字节,CAN_FilterIdLow的ID位可以随意设置,在此模式下不会有效。) j0 `2 ?5 d2 u! q! f

  12. 1 r3 c5 a7 l$ X- i" e
  13. //设置标识符寄存器
    5 Y. R. N% ?! I. T5 L) y
  14. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=((ext_id<<3)>>16) & 0xffff; //设置屏蔽寄存器高字节
    - D! s5 N. `: G
  15. CAN_FilterInitStructure.CAN_FilterMaskIdLow=((ext_id<<3)& 0xffff) | CAN_ID_EXT;   //设置屏蔽寄存器低字节, N" I! F: p! ], J

  16. + R) t: S# S; ]9 S+ ]0 C+ e
  17. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;  //此过滤器组关联到接收FIFO0* \( K6 a, {- C( m4 Q
  18. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组* M* W' i6 X. C, f1 ~) k2 B
  19. CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器9 V: b, N. U$ Q# n& v, C
复制代码
4.4 位宽为16位的屏蔽码模式

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

                                                                                                          图12

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


4 s) [9 _. x0 j3 m: u9 }4.5 位宽为16位的标识符列表模式

                                                                                              图13
# P' h. h: }+ F) C! q' J+ a

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

; ^+ I; s$ r# @1 l! F

以上是别人博客转载的

2 R# l+ v6 _  P4 r

下面是i我自己的代码

  1. /**
    , g; A( B' A# b0 |/ l( r% U
  2. * @brief This function config can's fiflter.$ D6 @/ D6 I8 ?7 {+ N2 b9 S! f$ @
  3. */+ S, }! o% ~* P" \+ P- i+ O$ i: X% u
  4. void Can_FilterConfig(void), X3 r4 \! D3 m  i; E. V- x# [
  5. {
    * {; z( ?% m+ c
  6.         CAN_FilterConfTypeDef FilterConfig;
    1 ^6 |& H2 L2 U  Z) b& z. S# l
  7.        
    ) V0 `- p$ i. K6 P
  8.         FilterConfig.FilterIdHigh         = ((ext_id<<3) >>16) &0xffff;
    ; X( [; \$ x' @7 M9 H2 T3 a
  9.         FilterConfig.FilterIdLow          = (uint16_t)(ext_id<<3) | CAN_ID_EXT | CAN_RTR_DATA;
    1 u1 J) \% o4 s* j6 p6 z
  10.         FilterConfig.FilterMaskIdHigh     = 0xfff8;
    3 X( e  ?8 }# c$ C
  11.         FilterConfig.FilterMaskIdLow      = 0x07ff;
    . z6 y# B, g8 k
  12.         FilterConfig.FilterFIFOAssignment = 0x00;  ^! n% l+ M6 Z- d% G  q
  13.         FilterConfig.FilterNumber         = 0x00;0 a  c- s8 `8 V. v$ n
  14.         FilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;
    , P- I7 Y- R# k; D+ s* i
  15.         FilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;
    3 p6 P% M. L- }2 B) Z% I
  16.         FilterConfig.FilterActivation     = ENABLE;( @% U6 j5 x! I5 X6 \* O0 e+ o
  17.         hcan.Instance = CAN;% ]- D1 U2 G' i' c; x
  18.         HAL_CAN_ConfigFilter(&hcan, &FilterConfig);2 d( L, B$ ?5 k1 ?
  19. }
    3 R4 d0 W2 d8 {# K
  20. /**
    & t8 Y0 @- I1 p+ G' Y1 R- b
  21. * @brief This function is can send pross.' |" V! H) |7 ?" F
  22. */
    2 I0 M, t: d; v. A# L7 v
  23. void Can_Assignin_Send_Pross(uint8_t *pbuf)
    & J- i8 {, i- g* E+ |
  24. {
    $ z  r1 \3 _0 {' K2 @, }
  25.         hcan.Instance = CAN;
    & Z; T9 ^# a8 E2 J6 b
  26.         hcan.pTxMsg = &TxMsgStruct;4 S. _2 S8 ]4 L* O5 j9 B7 `
  27.         hcan.pRxMsg = &RxMsgStruct;
    , L/ N6 t; R! M, r1 g) D% L3 f! t
  28. / O  p0 C" s1 ]/ ~% u
  29.         TxMsgStruct.ExtId = 0x18ff0004;
    7 e6 {( P- P$ f+ Z  k6 ]$ t
  30.         TxMsgStruct.IDE   = CAN_ID_EXT  ;. {" z0 b( n6 w7 v1 A8 `4 U. X+ J
  31.         TxMsgStruct.RTR   = CAN_RTR_DATA;
    ; [9 u$ E7 ?6 Z% m" r% t+ t6 c7 r/ r
  32.         TxMsgStruct.DLC   = 6;
    * T/ T- ~5 @" a9 ^$ S, H( \
  33.         TxMsgStruct.Data[0] = pbuf[0];
    , D2 a/ Q, ]2 l
  34.         TxMsgStruct.Data[1] = pbuf[1];
    5 I8 s7 L& }! E5 V: T
  35.         TxMsgStruct.Data[2] = pbuf[2];
    ( k! T) m9 I7 X0 O0 j& e0 b
  36.         TxMsgStruct.Data[3] = pbuf[3];) o4 v3 J7 }$ e( i
  37.         TxMsgStruct.Data[4] = pbuf[4];8 f( L( G; y) }$ |1 u
  38.         TxMsgStruct.Data[5] = pbuf[5];; z* L& K- J6 l5 |
  39.         HAL_CAN_Transmit(&hcan,0);        + k4 \" I) h5 M8 Y  @! }- z; z
  40. ; C6 E: i/ R& I
  41.         HAL_CAN_Receive_IT(&hcan, 0x00);
    9 A/ H+ A" v; C3 ^) q) _
  42. }$ @' n# y2 @6 O& b0 J4 ~. l
  43. /**
    ( _0 e- k4 y5 X( S! D3 u; C3 m
  44. * @brief This function handles CEC and CAN interrupts.
    4 V2 }+ `/ ^0 D$ ]: a. l. H
  45. */
    ; J) e' k  e& F- K0 r' s
  46. void Can_Assignin_Rev_Pross(uint8_t *pbuf)
    6 }3 L. X. R8 h- K! u
  47. {
    . c3 M9 a/ k9 j/ k0 c: {* t9 M: r2 [
  48.         hcan.Instance = CAN;
    4 g3 j1 T' R- o% f9 @
  49.         hcan.pRxMsg = &RxMsgStruct;
    3 ^! _6 t, A& l& M+ U$ }
  50.   pbuf[0] = RxMsgStruct.Data[0];
      H) T+ R! ]" n  _/ Q1 u& a" P
  51.         pbuf[1] = RxMsgStruct.Data[1]; 5 r' @! V" K/ K) U6 ?
  52.         pbuf[2] = RxMsgStruct.Data[2];
    # X) h% Y& T9 |7 s' d  n
  53.         pbuf[3] = RxMsgStruct.Data[3];
    / s- l  V3 _& I4 N, V- M
  54.         pbuf[4] = RxMsgStruct.Data[4];
    ! j8 }/ ^4 b9 w- {  O
  55. }
复制代码

" }# E; W0 r! @
6 R! G( {0 u" y( p  J7 {% o6 P1 b# t+ `! l9 P7 s

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
+ J  _% {& H0 T) j, e7 t0 ?最近在玩CANopen,多交流呀。安臣移植canFestival吗

! ]/ m1 v8 W2 X' R! 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 手机版