一、CAN总线通信初始化配置
# b8 o$ e9 R5 d6 \0 C6 R1. CAN总线通信初始化配置流程
! p& S9 U m+ g, d5 A* v' NCAN总线GPIO和时钟配置* W" A7 l9 ^; P( m. z
CAN总线接收中断优先级配置
- a1 E8 `$ u' I8 o6 o; vCAN总线初始化配置
% v" Y( n7 ]3 v2. CAN总线GPIO和时钟配置
, }3 ~5 j( P4 |. a8 CCAN引脚配置
, g/ p( | t+ b# k. J( L4 W' u* C- c) o0 @0 S3 V
% ^& d! U) I4 V, X: V
$ [- z P, Y, b0 N# b7 r x/ B g$ x2 C/ d
( h$ i4 w+ H" r1 D( q- N
CAN时钟配置:
" ~ }6 N6 o( w/ h& l
: Z8 v. r) ?' {
/ O/ S5 D% {, q. m* v& q6 w3 h3 A% E& _/ s4 Z
+ T! ~, I4 Q4 D: [6 E, D
: Y) E. N0 L. S! O% D1 y. s
" B5 N: i; ?9 V! z# K( jPA11和PA12引脚,CAN GPIO初始化,具体代码如下:% Y$ z% w% ~- K2 V& E! `4 h
$ ^& H: r0 a2 C; P
- /*CAN GPIO 和时钟配置 */# M- `8 Y5 V) B3 V6 z8 o# x# e
- void CAN_GPIO_Config(void)% d! |9 [8 p) v
- {4 @! Q$ w1 I7 n
- GPIO_InitTypeDef GPIO_InitStructure;
( E) m' ^. O- h' I3 f) d- o* W - /*GPIOA端口时钟使能*/
) X y& X% x+ U( }) Z4 S6 { - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); + d+ d- X9 }. c1 F+ w5 R
- /* CAN1 模块时钟使能 */
* r2 I2 F1 I2 q* w6 y - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
# z) g+ r8 X. Z5 {: {4 J: W- j - 1 i0 {6 D$ l& n# ]" R
- /* Configure CAN pin: RX */ // PA11
7 B \- Q- Y0 ]: ^1 j; H6 l - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
/ O6 _4 K8 t( T; u) V8 B* X8 |% @ - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入! v$ x5 N3 c! H. c5 w; V
- GPIO_Init(GPIOA, &GPIO_InitStructure);$ o$ ~& q% J8 m6 Y
- . F% v- [* M; Y
- /* Configure CAN pin: TX */ // PA12
! G# ?2 P7 |% V! D* ^% Z! n - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;& `3 x% k/ e* O8 k* ]. _
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
/ g' L0 o" {. V( M+ q B, W - GPIO_Init(GPIOA, &GPIO_InitStructure);
/ V. H; a3 i/ [8 p% _, y2 b - }
复制代码 # U. l- O4 Z& n# d; J; w8 v
PB8和PB9引脚,CAN GPIO初始化,具体代码如下:* G+ C' J) u# T% n$ _7 U5 G
; T5 E# Q1 w& g" Z; x* E- /*CAN GPIO 和时钟配置 */
n, M0 f( p& X! W7 ?$ E, O - void CAN_GPIO_Config(void)
' @% T" L O$ Z- I, n - {. b0 R0 ?3 z. A
- GPIO_InitTypeDef GPIO_InitStructure;
6 v) Q# f j5 z( T* G8 l7 @; Z - /* 复用功能和GPIOB端口时钟使能*/ 1 Q B# l$ ^: h
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);
+ k# B4 a, ^, p
; t, |; }: t0 C& |; [- /* CAN1 模块时钟使能 */
! j# u x1 A) u. S& I - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); ! N n, X+ y) e! N5 u! j
- 3 P2 a G* h" ^7 `5 n9 w
- /* Configure CAN pin: RX */ // PB8
7 `; Y2 c H0 K - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;9 U4 P2 I7 _, D6 k8 L$ I
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
" o+ K' T; p3 ^3 i; l- m7 U% @" W - GPIO_Init(GPIOB, &GPIO_InitStructure);$ q- o6 f5 l- g5 [
* h3 a) m0 S5 p( y5 k: k- /* Configure CAN pin: TX */ // PB9
: T% n. V5 ~6 ?" _ - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
" W; q8 B1 f7 ~3 v; {9 T$ i! l - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
) D. |2 P7 [( T* S+ N" y - GPIO_Init(GPIOB, &GPIO_InitStructure);
~" B& h+ D- R: d; c+ l1 H - 4 _" m6 a+ o0 l7 [2 D B
- //#define GPIO_Remap_CAN GPIO_Remap1_CAN1
: C; m0 z4 z4 M5 W# i' f! T$ e - GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
& z( P3 ]' o, i1 N- M1 q3 t; M) O - }
复制代码 7 F0 b3 f" V! R2 j
3. CAN总线接收中断优先级配置
* d+ P$ `% ?9 V: z9 g具体代码如下:! O r1 W0 p6 k# |9 J
# ~! p2 X$ \' z' E1 o- /*CAN RX0 中断优先级配置 */
( B4 u, f1 y; k% q9 r - void CAN_NVIC_Configuration(void)
/ n9 M* }5 s! W, a9 H1 z - {' T4 z9 T$ L Q' `1 z
- NVIC_InitTypeDef NVIC_InitStructure;; X6 E0 I3 R6 U% Y _
- /* Configure the NVIC Preemption Priority Bits */
: E: [: j0 _0 X) c - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);! g- h/ R# \# J0 p: s4 w
- 5 D0 a" O- E' U7 }( U
- /* enabling interrupt */1 _# z3 z8 y9 _8 V' i* I
- NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;. _( ^& x1 i+ p# p' O ^, f
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;8 [3 L) Y. t" X
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
2 N( D3 o. a0 D1 S - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;+ @* j5 |) U% Z& a6 B$ o x' }
- NVIC_Init(&NVIC_InitStructure);* P, n2 J/ p8 H5 k
- }
复制代码
& t3 e1 ?) C, B4. CAN总线初始化配置2 l! {- L+ p( ^
具体代码如下:
# B$ z: W- y) g# C
7 @! M3 i' N0 x- void CAN_INIT(void) . k9 e8 t1 \# `1 y+ k
- {0 W8 r& u6 v& i2 T* b+ P
- CAN_InitTypeDef CAN_InitStructure;
& G P$ j1 r8 m7 g0 h( T1 \5 a - CAN_FilterInitTypeDef CAN_FilterInitStructure;
, z8 j+ G: C+ z! g/ M7 l$ h - |7 U1 g( e4 ?
- /* CAN register init */7 x& M8 O1 E C
- CAN_DeInit(CAN1); //将外设CAN的全部寄存器重设为缺省值
4 Z+ }! m2 M# L' E* z M - CAN_StructInit(&CAN_InitStructure);//把CAN_InitStruct中的每一个参数按缺省值填入" l& \) ~) H' O, w! x( m' b
- * t% J+ F! d9 R9 ]' l4 ^! Z1 i' g* L
- /* CAN cell init */
# z! C' q) X5 ] - CAN_InitStructure.CAN_TTCM=DISABLE;//没有使能时间触发模式% V. ?$ ^4 j; N+ x( y x3 \
- CAN_InitStructure.CAN_ABOM=DISABLE;//没有使能自动离线管理
3 M; q* \( m; @$ d& Y - CAN_InitStructure.CAN_AWUM=DISABLE;//没有使能自动唤醒模式6 j6 H5 G a- l9 G7 n# z
- CAN_InitStructure.CAN_NART=DISABLE;//没有使能非自动重传模式
. n, h! Y2 O: Q. U: c - CAN_InitStructure.CAN_RFLM=DISABLE;//没有使能接收FIFO锁定模式4 `% ^- q" R2 ~0 U
- CAN_InitStructure.CAN_TXFP=DISABLE;//没有使能发送FIFO优先级
; ~; P: ^) c N3 ?7 X5 z - CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式$ o& o6 Z5 m7 r6 P5 g2 I
- CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; //重新同步跳跃宽度1个时间单位
3 ^3 e- Y2 L! e - CAN_InitStructure.CAN_BS1=CAN_BS1_3tq; //时间段1为3个时间单位( E7 f! o5 |7 w9 b4 Z& Z5 G
- CAN_InitStructure.CAN_BS2=CAN_BS2_2tq; //时间段2为2个时间单位
8 @" c) u9 A3 V5 p1 v" P. D - CAN_InitStructure.CAN_Prescaler=24; //时间单位长度为24 250k1 l, k# M" d# x: y% I/ @# e! g8 ?- w
- CAN_Init(CAN1,&CAN_InitStructure);% s9 H2 ?, p+ i1 n, T" J
- //波特率为:36M/24(1+3+2)=0.25 即250K
1 Y* N! o3 `6 v4 \ - : e! T) K& X$ T2 C$ e6 a
- /* CAN filter init */% }4 {; z1 r, x% u
- CAN_FilterInitStructure.CAN_FilterNumber=1;//指定过滤器为1% ?" q9 F5 V o& e0 G$ u% w
- CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//指定过滤器为标识符屏蔽位模式
* n, T4 x9 B8 c: C8 M- x2 j - CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//过滤器位宽为32位+ m$ {# a3 w# L+ }1 a2 K3 I
- CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;// 过滤器标识符的高16位值1 ~9 N, r) j+ J# w( m
- CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;// 过滤器标识符的低16位值4 f$ s! i, O" C4 U: i0 x
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//过滤器屏蔽标识符的高16位值1 l5 [# ~* P' z9 I' M0 r
- CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;// 过滤器屏蔽标识符的低16位值; b7 A, n/ ~# i) r# D
- CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;// 设定了指向过滤器的FIFO为0% K" ~% y: V( j; r2 D
- CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;// 使能过滤器3 {% ]; W% E# l$ U- l0 p
- CAN_FilterInit(&CAN_FilterInitStructure);// 按上面的参数初始化过滤器$ G2 o0 y2 G. g9 C0 L7 a% Q
- 2 Y8 E: t% I @3 V5 P4 u! t: q
- /* CAN FIFO0 message pending interrupt enable */
4 m0 h8 S4 K# n, Q - CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE); //使能FIFO0消息挂号中断$ |& V( A( K; v& L
- }
复制代码 " w, u; Z! n7 B6 R& G( }
二、CAN总线通信——波特率计算
' S, D, w9 j4 \. c6 h7 X1. CAN总线时间特性5 j& B( K$ I. h# ~" ^' t
同步段(SYNC_SEG):通常期望位的变化发生在该时间段内。其值固定为1个时间单元(1 x tCAN)。- V; _- Z% C* N* |8 I
时间段1(BS1):定义采样点的位置。它包含CAN标准里的PROP_SEG和PHASE_SEG1。其值可以编程为1到16个时间单元,但也可以被自动延长,以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。7 l9 y5 e1 ?$ R# Q7 l
时间段2(BS2):定义发送点的位置。它代表CAN标准里的PHASE_SEG2。其值可以编程为1到8个时间单元,但也可以被自动缩短以补偿相位的负向漂移。5 \# f' O# i1 s- q N7 Y
- o7 T; |; L) q' ~1 w# Q
+ c7 N9 {- a/ ], g; h3 f/ N+ x2 h/ h* a; t* @; p
2. 波特率计算公式
% ]7 C' ^8 b) A0 ^* ECAN波特率=APB1时钟频率/BRP分频器/(1+tBS1+tBS2)
& E' w2 `; S' d0 q) C! l# X) k" T% n: V9 I' I3 V/ B
一般APB1时钟频率为36Mhz。如下图常见CAN总线的波特率设置。+ l* t' z: w4 E( V2 X
' Z, s$ G2 a( @$ B- s( O2 q
+ W! C% [0 M6 `; X1 m, k2 Z
" n1 G$ U- Z* h% C1 U& O+ h4 }" R7 c) o) `
3. CAN波特率有关的寄存器" S! ^% z- t8 X3 r* ]
! A" _2 \5 Z# `4 n: l, f+ \! k( Z; Z
& L' M5 h9 _& R2 y# e" x& A" r# y) J% ]- i n+ [( {9 R
+ o: n# |$ C" k3 s3 ~
+ U b0 y* q) s- c* \
* V* ^3 E/ X! k& v ]
9 k/ f. f4 T* R1 @8 }# y |