一、CAN总线通信初始化配置/ b1 E; H" A7 ~
1. CAN总线通信初始化配置流程- q3 l5 n: d6 [3 ?( r2 h
CAN总线GPIO和时钟配置
' \+ `& c! G, J# \- g' x; h2 VCAN总线接收中断优先级配置, j! W- ]6 j# D2 B
CAN总线初始化配置
- \- K6 m2 Q9 R' X D2. CAN总线GPIO和时钟配置
2 i; k& A& h* X% qCAN引脚配置
+ }1 ~4 h# C- y( H- x% r6 s8 S
3 d' j5 q4 K/ ^& g. c3 n% |5 h3 x! n
8 q' V, u* M3 N9 Y# E% A
$ Y4 k6 x6 c5 y; R
+ W9 U2 h8 w; d; h
7 C! W) e O1 O) N' R/ N0 {
CAN时钟配置:+ D: B: A: a% b W' k: \
+ X' C7 ^4 b2 l& M# g3 f1 i4 B
P" v5 u2 t( |8 a7 \- D4 a2 f
! y+ T" S7 k+ ]$ L6 h0 s
% x' n$ ], L7 ?& @4 Z' G6 M1 [2 m1 \: a- e" M3 p" h8 z
& y: j- b: [. Q& p$ M( J) w7 s" k2 J
PA11和PA12引脚,CAN GPIO初始化,具体代码如下:
5 T% I) @ O, A2 @& _
& l5 ^" Y+ _$ l0 W& m/ Y- /*CAN GPIO 和时钟配置 */& r. g# x! p) A! ^. [; n6 u+ S$ l0 r
- void CAN_GPIO_Config(void)3 X3 [: s" y1 l$ P; G
- {* _) C! w5 M4 `1 S/ y
- GPIO_InitTypeDef GPIO_InitStructure; o6 r+ k7 L$ G0 M$ l0 s
- /*GPIOA端口时钟使能*/
4 v2 u2 W3 n4 J* O$ H - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 2 t* Q3 a$ D9 o# D3 W" h
- /* CAN1 模块时钟使能 */, h: i! Q8 D( @6 q0 X
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
7 u9 w% H' F) W& w - 7 l! m" A9 f5 @5 r
- /* Configure CAN pin: RX */ // PA11
; f) x7 V& c- f - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;8 }. H1 i8 W+ t# _
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入0 {) O! O5 g. _3 Y3 ?3 m9 U
- GPIO_Init(GPIOA, &GPIO_InitStructure);
# K j! r$ b9 _. E - 9 Z" O5 ], ^' U! X3 a! U( u
- /* Configure CAN pin: TX */ // PA12
3 C6 d* O3 }( s# e' i j+ v8 G - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;# v+ l: q1 B8 W3 y2 G
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出 b' U/ }# j, F V
- GPIO_Init(GPIOA, &GPIO_InitStructure);
5 t7 T0 s5 S, K: t - }
复制代码 & C: M6 k' p! G( J
PB8和PB9引脚,CAN GPIO初始化,具体代码如下:, f9 k5 F. ^* K% K" [
' U9 \6 \# i1 i4 x! Y
- /*CAN GPIO 和时钟配置 */3 J. z9 J b* `9 _5 p
- void CAN_GPIO_Config(void)
8 _; q6 G% ]+ f/ M. u6 c/ z - {
8 g# i; I7 z2 {5 Q* G/ r - GPIO_InitTypeDef GPIO_InitStructure;
+ i# ]4 X) y/ b. L0 z - /* 复用功能和GPIOB端口时钟使能*/
" ?6 C$ Y( K. J* p( p! |! E: B - RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);
: R: _6 n/ S8 ~! n
# B5 T _- i! H- /* CAN1 模块时钟使能 */
, b; \$ {! V+ e* w. \3 y - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
9 B" ~" n* W B6 L% G8 i6 \' t$ ^
9 ^( G% O5 G; `3 z& Z# {- /* Configure CAN pin: RX */ // PB8) u$ b" T/ e) B/ L- D+ S4 y. W
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
* a$ i5 [" [$ `" C) ]( u - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入, o8 b9 W" j1 q" K q* s
- GPIO_Init(GPIOB, &GPIO_InitStructure);
1 D/ X7 W# n3 x- y4 Q* v! a - - b$ [3 f" V- O9 l
- /* Configure CAN pin: TX */ // PB9
* |; D0 d3 \5 c) Y7 V+ `0 r- } - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;" @: _. W" Z: H t/ e s
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
$ S8 |) }, ]: J- p* W - GPIO_Init(GPIOB, &GPIO_InitStructure);
0 A0 m1 i/ U! b8 j- Y1 I
6 H: K4 E, X; U4 o- //#define GPIO_Remap_CAN GPIO_Remap1_CAN1 $ {/ m7 ?, U+ Q6 M0 U
- GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
; w( J' X2 C# T9 o# Z3 ` - }
复制代码 ) o: m* ^/ S, m7 Z- [
3. CAN总线接收中断优先级配置
. b% K, g% i9 Q" B C具体代码如下:
9 t J! F: S( z8 l! L5 F5 y
5 ~& E9 Y7 b* F( o% u0 w( _ O1 k0 @- /*CAN RX0 中断优先级配置 */! ?# e) R3 h5 f% L9 j
- void CAN_NVIC_Configuration(void)
2 h( x S, c+ V) Z9 s6 U* Z - {
8 r# O, N G6 W8 u- X - NVIC_InitTypeDef NVIC_InitStructure;" E+ Y' e, H k4 c. }
- /* Configure the NVIC Preemption Priority Bits */ ( b, Z$ J% z; Y1 B W
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
3 h- ^3 Q* t! z/ B+ Y
! y/ Z+ {6 c+ l, J* W5 z* q- /* enabling interrupt */- u; q6 u6 a+ |" O5 i9 H
- NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;
* h6 C4 c+ j3 o8 _: t! r - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;6 f4 u3 [. `8 l+ b
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
1 z% ^$ c. i4 @* V! Q$ _ - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
* r* Z' T: _. w! X+ l, B - NVIC_Init(&NVIC_InitStructure);
3 G; k0 ^; l1 N! e9 B. d - }
复制代码
j- o2 m6 i0 h- o* J7 Y4. CAN总线初始化配置
% I! E# R9 r% n$ e X7 y' j具体代码如下:1 i" N, R/ ]) Z1 s2 P
' m1 @- e p, e) S- void CAN_INIT(void) ) ^' k* @, g9 t! G/ r
- {) X! R z; Z8 X, O2 r
- CAN_InitTypeDef CAN_InitStructure;
0 ?! U8 v8 u* f3 t9 I - CAN_FilterInitTypeDef CAN_FilterInitStructure;
' p- q9 T% I, m \) J4 D5 ?6 M* n
1 S# `. E5 C* v- /* CAN register init */
8 M- ~" Q& V1 O0 f - CAN_DeInit(CAN1); //将外设CAN的全部寄存器重设为缺省值
+ \- r& {9 T" F! L7 G - CAN_StructInit(&CAN_InitStructure);//把CAN_InitStruct中的每一个参数按缺省值填入# j6 z1 t; ^% R0 p, O
- ' M: i x# w# T
- /* CAN cell init */
3 m( h7 P- P- k' s$ V - CAN_InitStructure.CAN_TTCM=DISABLE;//没有使能时间触发模式
) ` u. H$ p" }! p$ c - CAN_InitStructure.CAN_ABOM=DISABLE;//没有使能自动离线管理
5 v) \2 T& }+ R/ {4 W W - CAN_InitStructure.CAN_AWUM=DISABLE;//没有使能自动唤醒模式, r+ F+ J: a& {1 a* z
- CAN_InitStructure.CAN_NART=DISABLE;//没有使能非自动重传模式
5 o3 @! W" H0 i. w1 o9 U - CAN_InitStructure.CAN_RFLM=DISABLE;//没有使能接收FIFO锁定模式4 u; Q- G4 Z+ d1 N, Y
- CAN_InitStructure.CAN_TXFP=DISABLE;//没有使能发送FIFO优先级
( B# {- j7 ?& j8 z - CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式& D) S2 a* t2 ~
- CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; //重新同步跳跃宽度1个时间单位
) F% Y4 ^9 \! r3 G - CAN_InitStructure.CAN_BS1=CAN_BS1_3tq; //时间段1为3个时间单位
& g' o5 _, `1 C' x3 X# E - CAN_InitStructure.CAN_BS2=CAN_BS2_2tq; //时间段2为2个时间单位& o& I/ O- t- W( B4 \& \ T
- CAN_InitStructure.CAN_Prescaler=24; //时间单位长度为24 250k
. N/ v$ |; r8 f7 k) ^# { - CAN_Init(CAN1,&CAN_InitStructure);
' K: \% G( J) `3 S3 h N - //波特率为:36M/24(1+3+2)=0.25 即250K
) R. |' `; m5 Y4 k- c: v9 U* R5 E
+ }2 R/ G# q8 K% L- /* CAN filter init */3 e+ V3 P* U: R/ V! g/ O' Q. Z- e
- CAN_FilterInitStructure.CAN_FilterNumber=1;//指定过滤器为1# q: M) S- G0 j' [& Y: y$ T/ u
- CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//指定过滤器为标识符屏蔽位模式' @% ?3 }& K5 X2 N( s! {: l
- CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//过滤器位宽为32位* ]* A9 v% |! B& `
- CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;// 过滤器标识符的高16位值, q# z% A7 x6 _! m. ?( Y
- CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;// 过滤器标识符的低16位值
5 l# o* s6 r; s& @9 ?6 q/ h# W7 k. k4 C - CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//过滤器屏蔽标识符的高16位值
. g& i# ^: ^! x0 f3 V - CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;// 过滤器屏蔽标识符的低16位值7 n0 p7 G3 b5 ^
- CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;// 设定了指向过滤器的FIFO为05 p- b+ P1 \0 g8 Z
- CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;// 使能过滤器
5 {! O% R; j; Y$ m - CAN_FilterInit(&CAN_FilterInitStructure);// 按上面的参数初始化过滤器9 X% o" [5 v* O4 I
0 t9 g; o) ~9 B1 _- /* CAN FIFO0 message pending interrupt enable */
! b1 _& T. F z! {- B7 a - CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE); //使能FIFO0消息挂号中断
5 k8 l( ~6 o7 J! S9 Q4 N - }
复制代码
* N: b% C( \ q+ f二、CAN总线通信——波特率计算
6 Z8 g. c( g8 b* i: c' M0 B8 f: e1. CAN总线时间特性
' k8 W1 y9 Z& x, ` o* _% I/ a同步段(SYNC_SEG):通常期望位的变化发生在该时间段内。其值固定为1个时间单元(1 x tCAN)。
7 q8 y0 ^: H( G2 J时间段1(BS1):定义采样点的位置。它包含CAN标准里的PROP_SEG和PHASE_SEG1。其值可以编程为1到16个时间单元,但也可以被自动延长,以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。
0 r! d2 ~& }) K/ n时间段2(BS2):定义发送点的位置。它代表CAN标准里的PHASE_SEG2。其值可以编程为1到8个时间单元,但也可以被自动缩短以补偿相位的负向漂移。1 K* z( L. k) V6 m$ w/ V; j3 A
- n9 i9 q1 b7 \2 _' }' ?& P3 R% U
+ i4 I2 P! D+ Q) E3 ~6 M
1 `" R) w5 i! W- z2. 波特率计算公式5 T6 ^: j @" K7 k4 F& Z
CAN波特率=APB1时钟频率/BRP分频器/(1+tBS1+tBS2)
- P* ?1 k+ N* @5 ~, i; h6 S9 w* R+ C0 l8 E
一般APB1时钟频率为36Mhz。如下图常见CAN总线的波特率设置。
/ C2 Z1 ^, \- k/ P! B
5 B/ N c4 L0 N& }
& H3 I2 F- n2 D. S
# ]3 }; g5 e4 x! W @! b
$ N+ z8 j2 U6 ~7 W3 p: N
3. CAN波特率有关的寄存器! O5 d' n! S. h% N* Y
, V8 j& Y( n+ O+ \% S" A& c& D- z0 L
$ \# M8 A; B8 S
3 v# l9 T/ {% Y# G! |$ _8 Z" x4 E
" S& j8 y. p" z! k! a
- H" s% Q& K4 {: X; m# ?
* x. A8 I+ V' V) ?2 o; C V' m& H s$ I# C) @) m; h
|