一、CAN总线通信初始化配置' C- ^- V6 A! }& F9 C( z
1. CAN总线通信初始化配置流程
* s& [, ^0 y! H1 HCAN总线GPIO和时钟配置 ~* j. ~1 B3 @, @+ Z
CAN总线接收中断优先级配置# P' d. p# F4 `) V) i
CAN总线初始化配置
" W7 ~& K4 p6 s4 Y2. CAN总线GPIO和时钟配置
" S7 _# @$ b, C# | |CAN引脚配置+ z- v" c8 f) U. Q0 u& T9 p S8 A
- h( k. O0 G$ q( ]4 w
: Y) u, f% h, r* ]+ W
3 W/ f( m) u% G, z
+ [! c l! Y7 P3 g7 G/ e. [: I/ j6 y3 m2 V7 @, ~, h
CAN时钟配置:
; c5 Q5 b3 p: w/ _/ z+ c4 I, W4 V- ]8 K j0 n2 F- j. p
( H7 w0 T$ ~/ S; M; x- @) A& s4 k1 i/ \- Z/ h
, h1 d+ v: k& L# F y7 ?
9 U C) B6 d6 x9 h7 q
; a7 _ W% Z% b4 W0 @8 jPA11和PA12引脚,CAN GPIO初始化,具体代码如下:
) P& `- f9 u2 F0 ~6 I5 [( u+ A, Q- k3 R" V$ S
- /*CAN GPIO 和时钟配置 */
9 e& i3 d! G7 I$ W - void CAN_GPIO_Config(void)
# | {" w) x) m: M$ _8 M, D - {
; B+ r0 u' d6 h, T% n+ Z- `1 c - GPIO_InitTypeDef GPIO_InitStructure; ' C3 B0 q J; F- q$ |$ N, s
- /*GPIOA端口时钟使能*/ 2 P% _' @4 \, [0 q+ `/ u& M
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); . c. \% \" j* N9 k. m% b
- /* CAN1 模块时钟使能 */
Q0 a+ i0 n9 B2 p7 \ - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
! ? x" ~3 g; b$ c* n; H) Q* L
0 P( V% b" x' M( o) ~3 q! z* e- /* Configure CAN pin: RX */ // PA112 S6 S0 [7 l e; s9 G0 w( F
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;( v" ?: q2 p# ~6 e% |
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入6 S4 e, j% E2 |# Z
- GPIO_Init(GPIOA, &GPIO_InitStructure); m: e9 Y7 }' W" W
- 7 Y5 \4 r, }4 k
- /* Configure CAN pin: TX */ // PA12
- |- j9 ?7 B/ O. Z' W9 { - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
; g3 `% l! f \/ v- k s2 | - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
9 K/ R( j( }; e) K - GPIO_Init(GPIOA, &GPIO_InitStructure);
* u& U8 o+ [& L! u; h& G - }
复制代码 7 J' v# p7 E" g1 A1 ]6 Q+ b& a
PB8和PB9引脚,CAN GPIO初始化,具体代码如下:
* F3 i4 _7 e' I0 ^6 x$ b
8 y% T9 N5 F3 {. k- /*CAN GPIO 和时钟配置 */
4 H `$ l) ?$ H" S, ~, w - void CAN_GPIO_Config(void)
* ~; [( \; d$ | ~# F- N - {
& d) ^- F3 \) B4 u* l- ?% o4 l: g - GPIO_InitTypeDef GPIO_InitStructure;
' P$ }3 l- G* m$ J6 G - /* 复用功能和GPIOB端口时钟使能*/ 6 M; F' g* ?& F% t0 l) N" d& ^8 l
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE); : A# y- w2 o$ G9 S
- % \% |3 h: z2 j" O5 O+ Y3 J" a7 V) x
- /* CAN1 模块时钟使能 */
2 E( Y$ {) [" |1 U. i8 ^" j - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); 8 @& Z1 w1 E5 x! O5 `; j
" l) U5 O/ W* j0 y h, ?- /* Configure CAN pin: RX */ // PB8
5 [( i# ? z5 _9 [. z- @5 L - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
1 Y( o0 P2 [: U% | - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入+ q+ R" c3 Q+ r' h7 g( @3 }
- GPIO_Init(GPIOB, &GPIO_InitStructure);# K0 K3 S) u9 X5 I
- 8 R! u: R' P9 B Z
- /* Configure CAN pin: TX */ // PB9
. [5 X# X2 k6 l3 K2 \6 Q - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
* |. K7 M/ A! P9 ] - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
9 R1 e/ V2 O0 ? - GPIO_Init(GPIOB, &GPIO_InitStructure);
5 \& Z0 F5 g$ j# \2 O - ! K/ f5 g, x8 l
- //#define GPIO_Remap_CAN GPIO_Remap1_CAN1 % h+ ]9 w3 J2 T* x' M
- GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE); 9 t- @3 q4 N$ K; E8 Y0 W
- }
复制代码 * n; I# w7 L" n5 d2 E/ ^2 r
3. CAN总线接收中断优先级配置5 K4 ~* Y8 q' t9 Z: ^1 s
具体代码如下:/ y( b: y5 F1 E5 I( {/ @
" N, t3 r: M" R' c* T
- /*CAN RX0 中断优先级配置 */
: H0 c( b. y& K8 J z - void CAN_NVIC_Configuration(void)
9 W( k, _- Q) ~" M4 k - {
. i. n! ?. m# j( U' J0 o" E - NVIC_InitTypeDef NVIC_InitStructure;
+ \ u4 ]7 C3 L! V5 n3 o - /* Configure the NVIC Preemption Priority Bits */ " z0 v3 U9 W Z
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);, @ g# q3 o- u0 `8 a
- : d3 ?8 i8 f7 g6 Z4 G1 C
- /* enabling interrupt */% r3 ^" v0 {* a$ X
- NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;5 Y2 ~; f4 Q2 Y4 B/ b" S
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
5 u2 Q% K: m( Y- m1 a" x. G* I - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;& R" }; }1 A, W& D: y
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
2 @. S5 S8 v1 L" A% Q$ M, D" } - NVIC_Init(&NVIC_InitStructure);
0 J( C1 ?8 Z5 _/ ~ - }
复制代码 ! K5 v) a: } ]; u9 q
4. CAN总线初始化配置% M+ @9 G4 N2 y$ D: B/ w. C/ L
具体代码如下:: Y2 r1 }/ d. ~) Y _+ k
3 @7 \* @# u( g8 A- void CAN_INIT(void) I( N$ H6 j$ {
- {
2 E" [9 d" A1 ~ - CAN_InitTypeDef CAN_InitStructure;7 [; O7 s/ p: P+ {. z2 n# z6 `2 D
- CAN_FilterInitTypeDef CAN_FilterInitStructure;" c" ~( x3 [! I, a: \
- - Q' J* f* k# t' J) t
- /* CAN register init */
+ O, G# I9 x# Y) H7 d( g k - CAN_DeInit(CAN1); //将外设CAN的全部寄存器重设为缺省值) m$ i( k0 C1 ]% ^& C
- CAN_StructInit(&CAN_InitStructure);//把CAN_InitStruct中的每一个参数按缺省值填入
) Y3 g( Q$ b3 Z/ m3 `% F$ b
5 K# S2 M7 k, d1 z- /* CAN cell init */
6 U5 u. F) E: M - CAN_InitStructure.CAN_TTCM=DISABLE;//没有使能时间触发模式1 c) r8 q# f6 ^4 ~! I1 w) ]# |" e, i
- CAN_InitStructure.CAN_ABOM=DISABLE;//没有使能自动离线管理* z& z6 \$ I6 U% m
- CAN_InitStructure.CAN_AWUM=DISABLE;//没有使能自动唤醒模式
2 O# N+ h4 _: z, ], v% D# I( X& I& P - CAN_InitStructure.CAN_NART=DISABLE;//没有使能非自动重传模式
4 `8 [- R' p! x. n - CAN_InitStructure.CAN_RFLM=DISABLE;//没有使能接收FIFO锁定模式' Q, t6 f6 q4 q' Y+ b% `# u
- CAN_InitStructure.CAN_TXFP=DISABLE;//没有使能发送FIFO优先级4 Z* P, G# C% b( F' |8 U6 F* w
- CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
- g* ]: s3 h; a5 _& y- s' h+ U - CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; //重新同步跳跃宽度1个时间单位
0 q5 V, o- C4 v8 i B - CAN_InitStructure.CAN_BS1=CAN_BS1_3tq; //时间段1为3个时间单位
! h) w) B6 f0 s: |8 W - CAN_InitStructure.CAN_BS2=CAN_BS2_2tq; //时间段2为2个时间单位 E6 S) ^1 L* q4 c9 [
- CAN_InitStructure.CAN_Prescaler=24; //时间单位长度为24 250k1 n/ o% h- C/ p: w6 W# u7 u
- CAN_Init(CAN1,&CAN_InitStructure);
# y: a) _' \) ?/ Z$ N$ n - //波特率为:36M/24(1+3+2)=0.25 即250K
0 h. O- m6 w: ^& ]" x# f& r( r - " R7 g* l8 x# T/ z+ O3 y$ M R( A1 T
- /* CAN filter init */& E3 M" |! H2 C# q' g
- CAN_FilterInitStructure.CAN_FilterNumber=1;//指定过滤器为1
2 z* j* u5 }( I2 P - CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//指定过滤器为标识符屏蔽位模式- @: W" I* Z! t, h$ i
- CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//过滤器位宽为32位* Y4 }+ r: a( ^4 e1 m
- CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;// 过滤器标识符的高16位值
5 m: Q: O. ~8 l0 a9 [ - CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;// 过滤器标识符的低16位值( E; t ?6 ~' T4 K9 E5 R
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//过滤器屏蔽标识符的高16位值
! q6 q' k, e3 n/ [2 \! B Q) i) C - CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;// 过滤器屏蔽标识符的低16位值- F7 f# ?- q7 z
- CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;// 设定了指向过滤器的FIFO为0
& _9 F. q/ n) A. { - CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;// 使能过滤器# u. R4 Q4 Z! X1 P" i1 _
- CAN_FilterInit(&CAN_FilterInitStructure);// 按上面的参数初始化过滤器* X0 O: R; W: ^8 |" Y
# X$ a# ~# P0 ?# V# H) }) F- d( g9 B- /* CAN FIFO0 message pending interrupt enable */ 7 I6 s6 Y% L5 E* [
- CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE); //使能FIFO0消息挂号中断
5 u( i. @( m7 m+ {! e8 B+ F4 C! F - }
复制代码
9 d) y3 L# \5 M, s3 a二、CAN总线通信——波特率计算, |1 _; F- r( k7 K" }. \
1. CAN总线时间特性! Q8 O7 N2 i& R& ?- i
同步段(SYNC_SEG):通常期望位的变化发生在该时间段内。其值固定为1个时间单元(1 x tCAN)。, f/ D- k0 \1 h, G& ~8 n$ }7 s: L
时间段1(BS1):定义采样点的位置。它包含CAN标准里的PROP_SEG和PHASE_SEG1。其值可以编程为1到16个时间单元,但也可以被自动延长,以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。
% a( T& M# _2 d+ o9 d时间段2(BS2):定义发送点的位置。它代表CAN标准里的PHASE_SEG2。其值可以编程为1到8个时间单元,但也可以被自动缩短以补偿相位的负向漂移。0 H* P. f' Y5 J* ]; N
5 |. G y' e( r) D) v# Y
% W0 n, ~3 _" F
+ `0 c/ x5 K9 N! u' \+ |$ q* L1 \
2. 波特率计算公式' f9 X, H( Q6 H/ ?
CAN波特率=APB1时钟频率/BRP分频器/(1+tBS1+tBS2)! E8 F# Q+ Q( p% E7 @+ t
. L. F3 k# n0 |1 n. }- c7 U; t
一般APB1时钟频率为36Mhz。如下图常见CAN总线的波特率设置。, J7 S6 E9 \& J! U
0 v' T3 m* c. O2 ?4 I0 K. k2 l
. `. k6 G* L* B, o
; M6 B# B8 w8 R
9 c5 |) T5 ?+ E3. CAN波特率有关的寄存器
& T$ T* K0 J2 y" A8 [
+ ~& n- T1 I- r3 H3 r
2 I( |% d5 Q/ Y; ~3 s$ W. o( D3 j g
( f- u i" i/ X% H {4 h3 J0 |
' B/ _6 j8 V6 _0 @$ X
; j2 Y- K/ w/ A) t" L& n# l+ g
$ `3 S& }4 k$ F2 O, t1 c: B& X! c/ Y" c- @/ U' ^2 F
|