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

STM32的CAN现场总线应用总结

[复制链接]
sayuenala 发布时间:2016-1-28 10:13
CAN现场总线的应用最重要的就是其接口端口映射、初始化及数据的发送、接收。
1.接口映射
STM32中的CAN物理引脚可以设置成三种:默认模式、重定义地址1模式、重定义地址2模式。
CAN信号可以被映射到端口A、端口B或端口D上,如下表所示,对于端口D,在36、48和64脚的封装上没有重映射功能。
8 Q  S( \# K; d, n* A7 P9 @
表1:CAN复用功能重映射
  
复用功能
  
CAN_REMAP[1:0]="00"
CAN_REMAP[1:0]="10"
CAN_REMAP[1:0]="11"
CAN_RX
PA11
PB8
PD0
CAN_TX
PA12
PB9
PD1
重映射不适用于36脚的封装
当PD0和PD1没有被重映射到OSC_IN和OSC_OUT时,重映射功能只适用于100脚和144脚的封装上
----------------------------------------------------------------------------------------------------------------------
默认模式
  1. /* Configure CAN pin: RX */2 U: ?4 a5 d3 `. B* u! d# y
  2.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    1 z8 I% f- s0 I" L' C' O
  3.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;: }+ K- l$ h0 V! [
  4.   GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);4 @8 E7 t( Z  h9 M6 k: T2 z3 I
  5.   
      d6 V( ]; A% `4 r
  6.   /* Configure CAN pin: TX */
    / o. V1 l  x" n3 K( m1 @8 J
  7.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;' o0 d% a: \+ x
  8.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;4 L- t& I  c# f* j
  9.   GPIO_Init(GPIOA, &GPIO_InitStructure);
    ( U- E$ d3 P) x
复制代码
----------------------------------------------------------------------------------------------------------------------
  i- V  k, |: K$ W9 c8 |$ t
重定义地址1模式
  1. /* Configure CAN pin: RX */9 {# A2 |( ?( X# @" c+ f6 n4 P' m6 }
  2.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    6 j' R, a# H, O& o0 b0 I
  3.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    9 e& q0 R* i% K
  4.   GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);4 d: g1 E# d' X3 L, T' v; p
  5.   
    : S7 W1 C# @& z& x( W
  6.   /* Configure CAN pin: TX */" G( S5 D' ~8 w, |) M* L; d
  7.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    " j% Y- N! N! K& F
  8.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    8 K! c$ C" ]" b! G
  9.   GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);
    ! I# e; ^3 D9 U
  10.   
    2 r7 P0 l3 u+ k8 H( [4 S
  11.   /*Configure CAN Remap 重映射 */- D' i8 N% D" F" W  v7 l  @( C* n; @# L
  12.   GPIO_PinRemapConfig(GPIO_Remap1_CAN,ENABLE);
    - h/ e% r  a# G. I
  13. ----------------------------------------------------------------------------------------------------------------------
    $ A0 ]& k9 [* R3 n
  14. /* Configure CAN pin: RX */
    5 _) v; V8 F/ k% }% p
  15.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    $ i7 P, \# U( w; e/ \  E  m
  16.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    8 W5 z; L! l3 W9 ?, _, t
  17.   GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);
    9 y& F) T% i( w- f, C+ Y
  18.   
    ' x+ V1 J: L' Y. H# X! q+ |  M
  19. /* Configure CAN pin: TX */! Y, h+ h. P6 d
  20.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;/ Y# k/ W' B5 z% M
  21.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;3 e6 [; m- K5 W# n* h) @# a2 l
  22.   GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);
    # f% J7 o& P- _) k2 u" {; I& W' \' `
  23.   9 a' x* ~9 m/ n* ]8 |
  24.   /*Configure CAN Remap 重映射 */$ u/ F- ~! `3 q3 E6 S1 Z! F
  25.   GPIO_PinRemapConfig(GPIO_Remap2_CAN,ENABLE);' e9 L9 }# k0 V  X6 z
复制代码
----------------------------------------------------------------------------------------------------------------------

  c6 |3 y8 b! d
设置完CAN的引脚之后还需要打开CAN的时钟:
  1. /* CAN Periph clock enable */
    " s  x/ E6 A1 Q7 b
  2.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN,ENABLE);
    . t3 r6 V  ~: X4 U" M* s; P5 u: x1 V
复制代码
2. 初始化
2.1.2 CAN报文过滤器初始化
STM32共有14组过滤器,每组过滤器包括了2个可配置的32位寄存器:CAN_FxR0和CAN_FxR1。
可以将过滤器组配置成屏蔽位模式,这样CAN_FxR0中保存的就是标识符匹配值,CAN_FxR1中保存的是屏蔽码,即CAN_FxR1中如果某一位为1,则CAN_FxR0中相应的位必须与收到的帧的标志符中的相应位吻合才能通过过滤器;CAN_FxR1中为0的位表示CAN_FxR0中的相应位可不必与收到的帧进行匹配。
还可以将过滤器组配置成标识符列表模式,此时CAN_FxR0和CAN_FxR1中的都是要匹配的标识符,收到的帧的标识符必须与其中的一个吻合才能通过过滤。
对CAN报文过滤器的初始化实际上就是对接收FIFO邮箱标识符寄存器(CAN_RixR)(x=0,1)的设置。这些寄存器如下图所示:
  
31
  
  
30
  
  
29
  
  
28
  
  
27
  
  
26
  
  
25
  
  
24
  
  
23
  
  
22
  
  
21
  
  
20
  
  
19
  
  
18
  
  
17
  
  
16
  
  
STID[10:0]
  
EXID[17:13]
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  * [, b4 c+ f/ B( H2 o$ ], B
  
  
/ }2 f6 @8 O) d& T6 S  p" D  
  
9 E% _$ j! F- p5 `) B9 g0 ^! b5 V  
  . C: A( i9 e5 f4 L! U
  
  
8 Y: T  \* b. X/ o, C9 k! N  j: j  
  
, p1 q' Y. B/ B3 h  
  : L3 P8 }- I7 m: }2 I( r+ n
  
  ' g) i  M' P+ y1 R. Q
  
  
# L9 N; W$ j6 E3 g6 z8 L0 _% u% j  
  
& c: N; [! J/ I! s, Q  
  + e0 Y4 U( m! v( H
  
  4 K; a; R+ k* H& Y  |/ p6 t3 t
  
  
. C: r5 T' f. z8 b/ l7 d7 }  
  " _. N* e& G/ ]' d- S- J) |& @! o) z
  
  , N" z  d/ A8 y7 {
  
  
+ A; [# H9 |( E  
  
15
  
  
14
  
  
13
  
  
12
  
  
11
  
  
10
  
  
9
  
  
8
  
  
7
  
  
6
  
  
5
  
  
4
  
  
3
  
  
2
  
  
1
  
  
0
  
  
EXID[12:0]
  
IDE
RTR
Res.
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
  
r
  
6 K3 d. I0 q5 m0 V; C
CAN_RIxR寄存器各位域定义:
  
位
  
定义
31:21
   STID[10:0]:标准标识符 标识符的标准部分
20:3
   EXID[17:0]: 扩展标识符 标识符的扩展部分(如果使用了扩展标识符)
2
  IDE:标识符选择   0:标准标识符;1:扩展标识符
1
  RTR:远程发送请求 0:数据帧;1:远程帧
0
  保留位
" e/ T) t& c1 u& M* L/ H% i+ c0 I
注意:CAN_FilterIdHigh是指高16位,CAN_FilterIdLow是低16位,应该将需要得到的帧和过滤器的设置值坐对齐起。
采用stm32f10x标准外设库时过滤器的完整设置如下:
  1. CAN_FilterInitTypeDef  CAN_FilterInitStructure;        //定义一个过滤器5 X% O, Y6 c$ y& Z
  2. CAN_FilterInitStructure.CAN_FilterNumber=0;        //选定第一组过滤器        
    / w: Z* h' [5 G& K- J
  3.   CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//屏蔽位模式: `/ L7 u, h- }/ p2 s0 ~
  4.   CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;        //32位
    , O' k8 d) B" E. a
  5.   CAN_FilterInitStructure.CAN_FilterIdHigh=(0x0010 << 5);        //接收ID为10的消息,11位标准帧因此左移5位
    / w2 K4 n) {- |; ~+ n+ `4 {
  6.   CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;; J! o5 y1 U  y: g
  7.   CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;
    ( n) @$ O' F5 T# K* m2 D
  8.   CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
    # [* O2 h1 G) F2 u+ A' ~
  9.   CAN_FilterInitStructure.CAN_FilterFIFOAssignment=0;        //第一组过滤器指向FIFO0
    ( R) G& i- U% G- I" D  P- C* g4 v
  10.   CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
    6 R) z1 ]: ?1 r) }. K; o! w9 P
  11.   CAN_FilterInit(&CAN_FilterInitStructure);
    . A1 f/ i4 O7 M+ g) ~- C, a6 T
复制代码
3.数据发送
CAN_Transmit()函数的操作包括:
1. [选择一个空的发送邮箱]
2. [设置Id]*
3. [设置DLC待传输消息的帧长度]
4. [请求发送]
请求发送语句:
CAN->sTxMailBox[TransmitMailbox].TIR|= TMIDxR_TXRQ;//对CAN_TIxR寄存器的TXRQ位置1,来请求发送
采用stm32f10x标准外设库时CAN发送的完整方法如下:
  1. CanTxMsg TxMessage;        //定义发送信息
    1 [2 E- Q, F  `  k
  2. TxMessage.StdId = 0x0110;        //设定标识符(采用标准标识符时,硬件会自动把数据左移5位)
    0 k0 `( [6 n' }+ e
  3. TxMessage.ExtId=0x0000;        //设定扩展标识符(非必须,采用标准标识符时可不设定)6 K$ G7 I$ o, m
  4. TxMessage.RTR = CAN_RTR_DATA;        //设定待传输消息的帧类型
    ; J1 O9 C1 i8 ?8 ?
  5. TxMessage.IDE = CAN_ID_STD;        //设定消息标识符的类型3 p3 s- D% ]; G
  6. TxMessage.DLC = X;        //设定待传输消息的帧的长度" D, x* u4 W, D2 W
  7. TxMessage.Data[0] = 0xXX;        //写入要传送的数据,最多可写8个字节
    1 r) j" I2 A0 k7 u) Y! K/ m
  8.                                 .4 V- \# ^4 a: f3 }$ ]! v2 k% k9 N9 V
  9.                                 .
    % z& q, Z& U9 T( f2 G. u
  10. TxMessage.Data[7] = 0xXX;; Z3 K3 v6 K1 t1 k0 L) i2 S2 c9 s' u
  11. 2 m- {( q8 g" x" `' Z4 ^& }3 v
  12. CAN_Transmit(CAN1, &TxMessage);        //开始一个消息的传输
    9 {0 T3 E* r7 i* m
复制代码
4.数据接收
0 k0 ]+ T( t2 D% w: w% B/ A
CAN数据的接收可以放在一个中断中,以下为一完整中断接收程序:
  1. void USB_LP_CAN1_RX0_IRQHandler(void)
    " s5 a3 v+ I; @% D8 A, E5 r
  2. {
    & f' a* [. ^  U! o( K
  3. CanRxMsg RxMessage;& M4 p+ W* g1 @) T$ A7 f3 L2 C

  4. % v5 Z) R3 |7 g! ?# ]% u& A1 e
  5.   RxMessage.StdId=0x0004;' i2 Q9 a' {. u$ L2 V
  6.   RxMessage.IDE=0;
    7 J! T. L9 P0 ^
  7.   RxMessage.DLC=2;
    # H; n* k6 G. ~/ I
  8.   RxMessage.FMI=0;
    ) z# l* v% \% Z
  9.   RxMessage.Data[0]=0x00;
    5 x* B. O+ P: h: i8 X, }
  10.   RxMessage.Data[1]=0x00;* Y4 P8 J4 E6 f5 \8 C2 j; G1 @

  11. 7 m  v6 K. z0 X) T# n$ |( P* f
  12. CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);. I5 ^( i% u5 f
  13. % y6 ~* N6 b; W7 N
  14. CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);        # u) y* D9 b; o
  15. }
      W) G  Z% U0 Q
复制代码

- z7 u: A$ }& w
4 Y5 T/ i% r3 |" P
. \$ @1 u# E# N0 H, J

& M  {' W# w% h$ h* t
赞 收藏 6 评论7 发布时间:2016-1-28 10:13

举报

7个回答
cedarsong 回答时间:2016-1-28 11:23:03
分析的不错,挺好,值得学习!
( w, r  }) p8 Q; H5 \
沐紫 回答时间:2016-1-28 13:44:25
谢谢分享
mark0668 回答时间:2016-1-29 00:38:31
不错,感谢分享
星星王 回答时间:2016-1-29 09:13:27
感谢楼主分享
motianlun1111 回答时间:2016-2-13 13:17:51
大家不看的吗,楼主这是自己写的吗? CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);有清除这个的标志位的吗?3.5的库,大家好好看看,我最讨厌那种一知半解的人出来还祸害其他人的认知的
kxajd001 回答时间:2016-2-16 14:17:44
好帖子,学习下
赵工123 回答时间:2017-8-17 15:59:14
本帖最后由 赵工123 于 2017-8-22 10:18 编辑 2 }) A- T& B7 |( c9 j3 Q( X
  Y* s. a- n, A8 q4 ~; L9 {
冗余双CAN现场总线STM32F105开发板KeilC++源程序,欢迎 大家 交流交流
0 d, V7 k/ Q* u5 q8 ?9 W3 h- y; Phttps://www.stmcu.org.cn/module/foru ... 916&fromuid=33990245 [. Q1 S0 }2 g% ^" D' R, f6 p" n5 b
(出处: 意法半导体STM32/STM8技术社区)  ~; r% n, x; p  ~- J# S6 t

# T9 n9 |9 Y: c# G+ i3 r6 {& ?: s- }. E

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版