一、CAN总线通信初始化配置# _) h1 y1 G! ?; \6 k
1. CAN总线通信初始化配置流程( j/ u, x1 Z8 M- n3 k6 n+ \: R
CAN总线GPIO和时钟配置$ J, B) e8 J+ M* v- }
CAN总线接收中断优先级配置. g- p* p2 @* I
CAN总线初始化配置
1 U w' a- e" p- T2. CAN总线GPIO和时钟配置9 J* b# n' M) g# [9 u- ]
CAN引脚配置% l+ @( e: O8 @
* f- N4 n# i1 I# ^8 h
/ g: C6 v y0 S8 h8 D: |$ k$ x& ]
9 P0 @5 F& J, K* L* r. J
8 T$ P8 g8 q* R q
C: H% l) Y! }" A1 J0 ECAN时钟配置:
% H6 T8 W" A. [6 x4 [0 a: N
! x6 C- T% m. i( M8 G
: p7 Q, e+ w s9 x- ?' Z
- W1 N& k+ y& h7 M2 Y8 P
$ h8 W4 U# e( J' l# `4 P& _
X$ q1 G" _. {# L) f: M! M; s
2 Z9 M$ k0 b6 @& u
PA11和PA12引脚,CAN GPIO初始化,具体代码如下:
" V: E R: r0 K9 _& u2 j" \+ v, Y% N) h3 @' ^$ F3 O6 S8 K" Q# P \% Z) Z
- /*CAN GPIO 和时钟配置 */
, V, k9 n1 A1 p$ s7 S! H - void CAN_GPIO_Config(void)
& m2 x8 M7 {) y1 O' o6 Y) X4 h - {" x7 Y3 c; w- @/ d' {' X
- GPIO_InitTypeDef GPIO_InitStructure; ! f! o# T$ @' |; V0 u- L8 \
- /*GPIOA端口时钟使能*/ 9 t7 E1 y* P: J, ^
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
* E0 E3 {0 r; A+ k+ L- c7 l! H - /* CAN1 模块时钟使能 */. Y N0 g# n# f$ z* k. ^9 ^
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
6 t# e: T6 G7 w" G" C
# L! W$ a, P0 v9 g, e0 x6 V) n7 r- /* Configure CAN pin: RX */ // PA11
. i/ |1 u6 l2 j8 W4 y - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
' s" G1 @4 P% {5 I) m - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
/ f; d0 U* p( m( s5 |: c. F0 a% e/ K0 ~ - GPIO_Init(GPIOA, &GPIO_InitStructure);/ b7 i2 @8 r5 O6 }; y
, p* e5 p: X9 J: u/ C) U- /* Configure CAN pin: TX */ // PA12
# e3 O- R% S/ j ^+ r - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;3 P% Y' g7 M. \! P
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
3 V5 Z3 A9 A; O1 n" ^- J1 D - GPIO_Init(GPIOA, &GPIO_InitStructure);
/ {( e5 U/ @$ m/ Q2 p# T - }
复制代码 + L4 t. R9 P, ]6 L! `4 @
PB8和PB9引脚,CAN GPIO初始化,具体代码如下:! |9 V% B F7 C5 O
' C. `" y; d# g% C3 _! Q* A! V* Y
- /*CAN GPIO 和时钟配置 */
+ R# B: A2 F" |7 j$ u9 M$ H" S - void CAN_GPIO_Config(void)
" x0 v( U7 y0 @' b- O1 k. m/ ? - {: y# ]* N4 @! |' z- ~4 V' f
- GPIO_InitTypeDef GPIO_InitStructure; 0 d" {5 \- d" R: X A4 E6 H
- /* 复用功能和GPIOB端口时钟使能*/
; }. c0 y$ u8 p1 y - RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE); 5 N. {% u, g$ R8 S2 T, h/ |, ?
- . V8 s- z k3 I1 T; i; P0 h
- /* CAN1 模块时钟使能 */% D" U; {% d1 L8 t1 ^
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
( j7 n* t: n9 U3 u! Y- {1 p - # H( k- s1 {7 f. n5 Z" s4 p* e
- /* Configure CAN pin: RX */ // PB8
# m! n9 m" _4 |$ Z% R2 l - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
0 b/ n+ G# r. M3 {3 s& { - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
# E4 B* X( c. N8 K9 Q( o - GPIO_Init(GPIOB, &GPIO_InitStructure);
+ [+ H" | z8 q6 Q* ~2 l - . d: x' @$ R2 @, V, x' c2 }
- /* Configure CAN pin: TX */ // PB9
# D- C, m) n! G r# \ - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;9 {) ?; e- [! e% d2 ^4 w1 n
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出0 `: ], A* l; w" t' M
- GPIO_Init(GPIOB, &GPIO_InitStructure);% y' F8 H. R; R& Q U) K8 A( a
9 n3 u; j' n3 n2 _5 `- //#define GPIO_Remap_CAN GPIO_Remap1_CAN1 R) |' ], ~1 e& z3 ?6 |
- GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
" z3 ]* B& M* F7 c; }0 s) U - }
复制代码 5 n0 ^* t4 f( L, H; I! e
3. CAN总线接收中断优先级配置
- S- f* _; t, T0 d: i$ T- g/ E( F具体代码如下:
- k. N; d& t6 a9 L2 n2 P. U. }6 D4 H4 M7 D
- /*CAN RX0 中断优先级配置 */
1 M+ d8 G% S7 J2 s" [1 y- }) X# w - void CAN_NVIC_Configuration(void)
7 b W/ \( E# \! g" _4 f" ^+ E! M9 \ - {+ P2 ~% Y5 R) B
- NVIC_InitTypeDef NVIC_InitStructure;
7 p3 ^4 R% `2 b: [6 ?8 w# q - /* Configure the NVIC Preemption Priority Bits */ 2 @) E' p2 K" |
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);/ d& W& D( J4 H6 A- D* c, q- E
- . Z& P& D3 r- N- G; Z
- /* enabling interrupt */
& u) o; w* L' q3 o8 r: a+ k1 z - NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;) ]9 X) }. E9 m6 O9 Z) ]! W3 @
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
6 Y0 e. |- ]7 J8 o8 A - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;; e1 f, J$ X- |9 w/ @( `: P, R6 R
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;) e ~; Z2 L% s" J) I5 A* y
- NVIC_Init(&NVIC_InitStructure);
6 Q) s+ q3 d* W7 ~" A - }
复制代码 4 {- S. K+ \5 O+ }; U! s7 p
4. CAN总线初始化配置% S+ C" k+ P1 t) C) k: l! E
具体代码如下:
/ N {9 k: }* }: U4 f
. `3 }- V5 |# G! h. z- void CAN_INIT(void)
9 {' J" N* d" F/ |, l! g1 V - {
, Z/ L6 T P+ N# N( E, o - CAN_InitTypeDef CAN_InitStructure;
/ D9 ?3 B) x% y" O/ A! r - CAN_FilterInitTypeDef CAN_FilterInitStructure;
( a) R7 r* X9 |6 J; E2 J0 i9 b - 7 ]% _ \; Z+ g9 P
- /* CAN register init */ _# c/ `% o0 f. y* G
- CAN_DeInit(CAN1); //将外设CAN的全部寄存器重设为缺省值
& }. Z- ^# R4 ~9 b9 x+ ?" s - CAN_StructInit(&CAN_InitStructure);//把CAN_InitStruct中的每一个参数按缺省值填入
" T3 X, |: Q/ d" S% B k2 E' ` - # X0 Q, @4 H& s% {; n. p
- /* CAN cell init */
" v1 c! ^3 o+ b! U, y6 E - CAN_InitStructure.CAN_TTCM=DISABLE;//没有使能时间触发模式
6 J" P4 W( M6 u$ l$ p - CAN_InitStructure.CAN_ABOM=DISABLE;//没有使能自动离线管理2 m' z7 j2 ^/ ~1 R7 X
- CAN_InitStructure.CAN_AWUM=DISABLE;//没有使能自动唤醒模式7 u" O H: r: K5 a& }& e( i. V1 p
- CAN_InitStructure.CAN_NART=DISABLE;//没有使能非自动重传模式7 B s* y. M* d" f6 l" ?# V, w
- CAN_InitStructure.CAN_RFLM=DISABLE;//没有使能接收FIFO锁定模式! Z6 l3 B6 U* r
- CAN_InitStructure.CAN_TXFP=DISABLE;//没有使能发送FIFO优先级8 ]- | ?% `, @4 ^/ e
- CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式8 ?1 g! o, G3 P/ I3 h
- CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; //重新同步跳跃宽度1个时间单位) @4 B$ D* ]# V4 F/ V
- CAN_InitStructure.CAN_BS1=CAN_BS1_3tq; //时间段1为3个时间单位
9 h" M9 G, r* c2 I - CAN_InitStructure.CAN_BS2=CAN_BS2_2tq; //时间段2为2个时间单位- _) Z k5 }" |9 L
- CAN_InitStructure.CAN_Prescaler=24; //时间单位长度为24 250k( D6 {5 I6 g9 C6 a3 \6 ^3 j
- CAN_Init(CAN1,&CAN_InitStructure);. G& Q# ?' I; l& h8 Z- P
- //波特率为:36M/24(1+3+2)=0.25 即250K/ z4 i) o/ P( f# I
; ]8 w8 j. _8 e5 t& w7 x5 _- /* CAN filter init */5 d, N$ r8 \* M" z* o6 ~5 j& `9 F
- CAN_FilterInitStructure.CAN_FilterNumber=1;//指定过滤器为1
: r0 c( ~( h. v6 H1 _ - CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//指定过滤器为标识符屏蔽位模式; D1 z' @1 T4 v# I2 m( e& {' n' U; [0 U9 g
- CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//过滤器位宽为32位
& j. s6 B+ ^8 H - CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;// 过滤器标识符的高16位值
4 p: v' Q Q. N. A9 y& n - CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;// 过滤器标识符的低16位值1 C. f- F& p* d3 M1 W5 B* t4 v
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//过滤器屏蔽标识符的高16位值: d5 H* {! ?& [; b1 C- \) G4 f
- CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;// 过滤器屏蔽标识符的低16位值
( R" V2 _4 i( e* T3 h. Q6 b3 { - CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;// 设定了指向过滤器的FIFO为0" V5 R* ~* H( o1 I
- CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;// 使能过滤器
$ @ S- a/ I# H - CAN_FilterInit(&CAN_FilterInitStructure);// 按上面的参数初始化过滤器1 l+ {! y$ w8 M7 m( A# {5 N3 j
2 S5 v: v" ~$ ]- i& u- /* CAN FIFO0 message pending interrupt enable */ - ^& i* P0 V- s2 j$ J0 H" o
- CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE); //使能FIFO0消息挂号中断4 G& }6 o, b9 v" P
- }
复制代码
) ?4 N1 l9 R" X二、CAN总线通信——波特率计算) w# S! z, a ]9 x& y" p
1. CAN总线时间特性$ ]5 e% H N- R/ b
同步段(SYNC_SEG):通常期望位的变化发生在该时间段内。其值固定为1个时间单元(1 x tCAN)。
& g( k3 e, r4 I* }& @- R9 ^时间段1(BS1):定义采样点的位置。它包含CAN标准里的PROP_SEG和PHASE_SEG1。其值可以编程为1到16个时间单元,但也可以被自动延长,以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。4 U. `) }1 F% N- z! p% G' }" g0 Y
时间段2(BS2):定义发送点的位置。它代表CAN标准里的PHASE_SEG2。其值可以编程为1到8个时间单元,但也可以被自动缩短以补偿相位的负向漂移。
* G; _0 @, ~3 y% v
; ~5 A. W+ ~8 M" Z) r8 [
9 l' }3 I- S5 h4 b5 c* A% q9 G- |2 `2 P- j8 x' Q, U& D
2. 波特率计算公式( k. w& ~8 M8 P- q3 Y$ n6 Y/ E
CAN波特率=APB1时钟频率/BRP分频器/(1+tBS1+tBS2)) W( M. E* w5 a4 E& q5 U
- |8 {( i( r! p# d$ A! ~; u一般APB1时钟频率为36Mhz。如下图常见CAN总线的波特率设置。+ y+ z$ Y/ f( V& n z% D
; m2 n. W. |% k, l7 N2 K
6 s( M+ \4 N. j8 r$ y
) V) ]* i, U: f' S: A* ]* i. B" q4 m1 r6 ~ m. o
3. CAN波特率有关的寄存器5 ]4 E( i) s3 }8 O0 q( H
6 G7 a) J1 [1 G- Y
: q+ E% e- N1 K
( i9 ?% l+ |: B! I3 a9 P
& @; y! Q2 e ?$ W; @+ L$ R
( X* T3 T! ~, Y/ O0 u5 b
( s' q. l C$ S/ Y9 K7 C
7 c$ S+ q5 Z9 z& T |