一、CAN总线通信初始化配置
9 [% F% M7 P* R1. CAN总线通信初始化配置流程
! F) X, p8 y! r: `CAN总线GPIO和时钟配置- {8 p; s# @% r F& t7 F
CAN总线接收中断优先级配置' D+ P0 f" V' z) J# D% n8 j
CAN总线初始化配置. E6 `) o u9 @2 t' `
2. CAN总线GPIO和时钟配置1 n( J8 i3 |$ C' T9 ^
CAN引脚配置
& U( h* z7 M0 g1 a. u f) ?7 v: t4 R& U- }; f4 k! y
- |* B( O5 w; f# N, O+ H
& i' n; m6 E3 ~$ D( p
0 N/ a4 \1 Y# T& p" q0 s& d: k5 \
/ P# Z. ~8 ^' ^CAN时钟配置:7 }7 T5 \. P' f# D: F& U4 p6 Q# Z
& q( P& J! Y6 m* W9 E; a
2 R# ?8 p3 i0 {5 R7 W! `$ t3 n
* C6 k' v; p( Z P" G$ G
" ]% g' h- B" i' x; M+ a3 q
0 ~& _1 F. w R3 B3 c v1 B) r% w4 m$ S& Y/ L9 {, R I: a
PA11和PA12引脚,CAN GPIO初始化,具体代码如下:
+ Q3 w/ `* X5 V# N5 o0 O3 }
& X- h. E3 ^; N) o, _5 F- /*CAN GPIO 和时钟配置 */2 E( F; f) Y8 P& _* O- v& T0 p
- void CAN_GPIO_Config(void)# i' h* a: v# R9 I s f* J% D! a
- {: m7 d( D* h6 g+ O) c. Y8 ?
- GPIO_InitTypeDef GPIO_InitStructure; 8 n+ U0 B0 d+ f7 T
- /*GPIOA端口时钟使能*/
' z5 L* X1 X v$ v T4 H L - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); ; s( l; a+ c. S. u
- /* CAN1 模块时钟使能 */
: [' Z. H6 b. I1 t, w% i - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); ( o% {# I/ B6 `9 p. I' }5 Q' w
- + ^; |) E6 a4 A |* U
- /* Configure CAN pin: RX */ // PA119 v& D3 N* Z! n1 [9 n7 u! h# p& Y
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; M+ Q6 b. E) C$ E1 F1 f; {
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入1 v5 ?" W+ E7 \3 B v( v
- GPIO_Init(GPIOA, &GPIO_InitStructure);3 j" ^( ^& G- v; `
- # T, x$ K/ m8 h2 N: ^% T5 Q
- /* Configure CAN pin: TX */ // PA12
) d. S3 W; l4 N' d - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
! C& t9 T* Y/ Z2 F) G) c2 j - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
; ?! w% U/ V* F. @9 C - GPIO_Init(GPIOA, &GPIO_InitStructure);
' X& b$ ?" a& Q) [% _7 m; L7 |$ [ - }
复制代码
, L: m7 J+ W/ g/ GPB8和PB9引脚,CAN GPIO初始化,具体代码如下:" O5 t" F* Q2 \# v9 V: S( }
0 @1 {. k q8 S1 f* X
- /*CAN GPIO 和时钟配置 */% N3 e/ {. b# r- c: f. s
- void CAN_GPIO_Config(void)
8 d- E$ u/ |9 o' U5 \7 \6 k - {
/ z: X' r- @9 f% ~7 x3 h; y - GPIO_InitTypeDef GPIO_InitStructure;
: x- R3 s9 c8 m5 j" D - /* 复用功能和GPIOB端口时钟使能*/ * {5 x/ u$ F+ i J
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);
4 J# Q3 Y5 h4 d" P% ]5 u - 6 R) p8 M! M7 Q9 |- U
- /* CAN1 模块时钟使能 */- i, I8 x9 ~# e9 N* a3 \
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
3 y, M7 F5 L/ k
# Y- |+ M; p% {- /* Configure CAN pin: RX */ // PB8- R- {" j' i9 _
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;) y2 k8 e3 l* t7 T4 A5 y0 E
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入) y0 }! W% h' K* i5 k# B/ c7 C8 \
- GPIO_Init(GPIOB, &GPIO_InitStructure);" P) Z# q+ j5 ?* A! Z$ ~1 m
- ! Q' H$ q; U j! r- n- {; I
- /* Configure CAN pin: TX */ // PB92 ?& y! }% J! ^: t& ^* @
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; l3 m1 B2 ^5 W: j7 ~0 x' U
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出: T- d6 W( y1 P1 o) Q
- GPIO_Init(GPIOB, &GPIO_InitStructure);- P$ m7 v3 \) n. t% I7 X
9 x4 D" u9 M. y4 n2 z2 h3 H, o- //#define GPIO_Remap_CAN GPIO_Remap1_CAN1
" v: E9 w3 ~8 T8 |7 u& K @ - GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE); 0 |% K/ a3 O# L5 x# D
- }
复制代码
& T2 r; L! x! M4 G, L* g3. CAN总线接收中断优先级配置
* s' V7 A9 m0 S2 S+ w具体代码如下:$ `+ G2 U0 ]1 m& [
. ^5 ~$ l5 Z% g% j1 U5 Q8 o- /*CAN RX0 中断优先级配置 */
X5 w) W& |4 A5 x+ Y - void CAN_NVIC_Configuration(void)
; j9 K( M3 \: e5 o5 O/ E4 O0 L - {! F q) K2 c* P: ~& c# F. F
- NVIC_InitTypeDef NVIC_InitStructure;
) H- l/ a; w3 }1 o7 V3 B/ S/ Z/ O/ O - /* Configure the NVIC Preemption Priority Bits */ ; Q' V2 g) a" E% ]9 r7 m
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
# A5 c" K5 o5 g! [! _7 L
, B' Q) _& g+ B6 d; z, X- /* enabling interrupt */
7 l, ~6 N1 A! M; Y/ i! U' G& r' {5 y - NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;" ?0 I' X* R& b# i$ b, c& s* k
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;. `( s" ]( k4 g" F
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;3 D# j' O3 _0 `% r" f
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;4 N1 Q4 n1 ^( S% K2 p8 T+ a
- NVIC_Init(&NVIC_InitStructure);
0 x9 _, X: \1 j1 T+ { - }
复制代码
: T& W/ a, Y2 Q8 R0 ?4 ^; n4. CAN总线初始化配置6 H6 z2 J4 ?/ p6 ]1 `$ Q# j$ b
具体代码如下:9 [: |* c4 j( H
7 j( i+ i6 A. |4 O
- void CAN_INIT(void)
; ?& l' _! A) h; L# f - {
$ g; s* A+ c8 O/ @/ V8 H# I) q" W - CAN_InitTypeDef CAN_InitStructure;
1 Y! {% S) {6 J m - CAN_FilterInitTypeDef CAN_FilterInitStructure;
( ]6 \1 ~! x& |7 V; A
4 G" B+ f" _9 I( z: k6 f- /* CAN register init */
- l8 B7 |' @: k4 N. J - CAN_DeInit(CAN1); //将外设CAN的全部寄存器重设为缺省值
; {' E# j: g' O - CAN_StructInit(&CAN_InitStructure);//把CAN_InitStruct中的每一个参数按缺省值填入
! r, y+ X5 u" x9 ~ { - , Q' S" _8 R/ G; I$ i
- /* CAN cell init */
. }7 h1 v% t& @8 [; @/ I) \ k; x - CAN_InitStructure.CAN_TTCM=DISABLE;//没有使能时间触发模式
/ t1 }$ i9 P' \# E) c. e9 \ - CAN_InitStructure.CAN_ABOM=DISABLE;//没有使能自动离线管理
' C& ~8 D+ _$ p( Z+ Z/ d - CAN_InitStructure.CAN_AWUM=DISABLE;//没有使能自动唤醒模式2 J- {( I2 t; c; L7 I3 W4 \
- CAN_InitStructure.CAN_NART=DISABLE;//没有使能非自动重传模式& ]5 [7 t I7 d! [7 w: J# L. C& @
- CAN_InitStructure.CAN_RFLM=DISABLE;//没有使能接收FIFO锁定模式
% S3 K7 k' z/ ~$ P - CAN_InitStructure.CAN_TXFP=DISABLE;//没有使能发送FIFO优先级8 o, o2 X# [7 Q
- CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式4 i5 B4 k5 |/ D! `$ k& U8 A
- CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; //重新同步跳跃宽度1个时间单位
* Q7 `8 {: Y1 m" L - CAN_InitStructure.CAN_BS1=CAN_BS1_3tq; //时间段1为3个时间单位$ f) L3 N# N* J3 I# P( l& \
- CAN_InitStructure.CAN_BS2=CAN_BS2_2tq; //时间段2为2个时间单位; m3 v9 [/ S5 N' B
- CAN_InitStructure.CAN_Prescaler=24; //时间单位长度为24 250k5 p2 n4 A" S' y" K4 k
- CAN_Init(CAN1,&CAN_InitStructure);& _8 l* G' ^% x0 s( ?1 }
- //波特率为:36M/24(1+3+2)=0.25 即250K
$ {$ i6 C5 k. @ - $ T: @+ e7 I# k
- /* CAN filter init */
! C3 D9 \% a8 r3 P - CAN_FilterInitStructure.CAN_FilterNumber=1;//指定过滤器为1: g' B6 j) D' T$ M: f( I5 m
- CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//指定过滤器为标识符屏蔽位模式, w! r( G+ e+ W- f. Y
- CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//过滤器位宽为32位
; B/ y" w4 ~$ p# B/ T% }9 ~1 G0 h' X - CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;// 过滤器标识符的高16位值
" h) P A( q1 O/ K5 T - CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;// 过滤器标识符的低16位值
; r3 Y4 g( H% X. W1 J - CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//过滤器屏蔽标识符的高16位值: }+ U1 ^: y: @ \5 X
- CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;// 过滤器屏蔽标识符的低16位值0 a6 j* e) }# A: J- Z7 Z3 n
- CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;// 设定了指向过滤器的FIFO为0
" Z( e: x! F6 u7 |; Z2 q - CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;// 使能过滤器+ N1 @3 U% X2 S, | ^8 U( U
- CAN_FilterInit(&CAN_FilterInitStructure);// 按上面的参数初始化过滤器: v* [0 M6 U- E* r
9 }$ }$ a. a) u$ m7 j- /* CAN FIFO0 message pending interrupt enable */ ; a6 \% _' ~, }' o
- CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE); //使能FIFO0消息挂号中断
+ {/ b% L' l5 n# ~ - }
复制代码 ; p+ p/ e4 g- O) S6 }: B/ D& x
二、CAN总线通信——波特率计算
& h% G6 |+ h5 ]- K0 A; v. y1. CAN总线时间特性- q- ]5 E4 X* u: [2 b
同步段(SYNC_SEG):通常期望位的变化发生在该时间段内。其值固定为1个时间单元(1 x tCAN)。
1 L6 H) ^* q3 `$ X时间段1(BS1):定义采样点的位置。它包含CAN标准里的PROP_SEG和PHASE_SEG1。其值可以编程为1到16个时间单元,但也可以被自动延长,以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。
$ i" X( l7 O6 j- F% C5 s: |1 n ^, l/ w) W时间段2(BS2):定义发送点的位置。它代表CAN标准里的PHASE_SEG2。其值可以编程为1到8个时间单元,但也可以被自动缩短以补偿相位的负向漂移。
+ h' u* |& [" u0 x( k# G4 o4 C* y) E: O* _* ?5 d
6 H! H( W5 [8 i" M. [# Y# m' u- X% }/ k4 f3 L3 a6 G/ v+ ^" y
2. 波特率计算公式
$ t* E0 y3 ~5 }8 SCAN波特率=APB1时钟频率/BRP分频器/(1+tBS1+tBS2)% s1 Y8 N$ K( p4 _. v7 D
# ]( i+ G/ N9 d- w; ?' w. W一般APB1时钟频率为36Mhz。如下图常见CAN总线的波特率设置。% _' a1 D/ }9 w( f3 D
& a8 ?& W4 P. }3 g0 L! S
4 M6 ]4 ?3 G' \' [+ G3 k* P# c3 I
% a t: m) g) Y5 {* ^1 B
& p5 O* ? A O. b0 W6 [
3. CAN波特率有关的寄存器
; C. y" ~1 [ _' F7 I5 b/ i8 c% L0 ] @% r- d7 a
% s4 E5 [4 g1 T# k# E6 ~; `3 z$ H& W' A' [( |, @% {0 P
4 I2 v! e1 O: R$ @
1 w2 X8 W& d+ |% q1 k9 m% t' i, S. y
8 i1 }, r0 O! S. z. x A |