【经验分享】STM32F103:CAN总线通信——初始化/波特率 - STM32团队 ST意法半导体中文论坛

一、CAN总线通信初始化配置
1. CAN总线通信初始化配置流程
5 E: E) o( `8 o7 a# x# g0 l
CAN总线GPIO和时钟配置
CAN总线接收中断优先级配置
CAN总线初始化配置* @% z' r7 n5 u, F
2. CAN总线GPIO和时钟配置; M( R9 K# i8 Z
CAN引脚配置- D( Y) P* B! @9 d% n' u: z
6 d' R$ x( K! Y  G5 }

st-img

 . _' \: H7 b' E% ~

st-img




CAN时钟配置:7 W6 _- e, V8 I& w
2 P  A# b+ i7 K, y$ p" f

st-img


5 T& ~+ m3 N  P+ ?6 [4 e

st-img


( R  X% ^7 n, p& k* A$ z
4 {3 O% q8 ?( j- V! \5 Q" l" \6 _
PA11和PA12引脚,CAN GPIO初始化,具体代码如下:6 ^/ N4 `6 t" X2 X7 F# [4 o2 G# o
 
  1. /*CAN GPIO 和时钟配置 */' u+ H. n7 p5 F& x
  2. void CAN_GPIO_Config(void)
  3. {# x" @4 F5 h5 }
  4.         GPIO_InitTypeDef GPIO_InitStructure;
  5.         /*GPIOA端口时钟使能*/         6 t3 [9 D3 R* H; h- g
  6.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);                                                                                                                         ) Z* t' l3 o: B1 ~4 @; [6 l
  7.         /* CAN1 模块时钟使能 */
  8.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); ! L! w6 N9 w  Y
  9.         /* Configure CAN pin: RX */         // PA11
  10.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;3 z: `$ p6 k, [
  11.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;         // 上拉输入
  12.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  13. - W: Y( [4 w# B) _# \7 J1 f; P* }. @
  14.         /* Configure CAN pin: TX */   // PA12: _5 T2 b: W( \, d9 z
  15.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  16.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出# \1 d+ j& z+ P/ N
  17.         GPIO_Init(GPIOA, &GPIO_InitStructure);8 e/ O4 L  G, U) t) x, ~5 U$ C
  18. }
复制代码
! n6 r5 W: p9 a& h# ~
PB8和PB9引脚,CAN GPIO初始化,具体代码如下:
0 z- S5 {- X9 f# \0 D9 s4 c
  1. /*CAN GPIO 和时钟配置 */
  2. void CAN_GPIO_Config(void)  ?- o+ f' m3 I6 T" R
  3. {5 a8 X8 y0 o2 i- m9 r# V; h
  4.         GPIO_InitTypeDef GPIO_InitStructure; 1 g+ ^3 e, ~. X; l2 g- V4 Z2 k6 s
  5.         /* 复用功能和GPIOB端口时钟使能*/         7 k2 T1 |% b0 M) m( P; r
  6.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                                                                         , [" j7 V+ u7 ~# q. ^1 ~/ _
  7. ' F  x, q) \: ^4 u) B; U
  8.         /* CAN1 模块时钟使能 */( q- T( W' J8 w. c! l" l
  9.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); + |1 Y  |! j( h! v' W$ q# L" ]
  10. % k7 w9 a+ }2 E2 K4 y+ K4 u. v2 C
  11.         /* Configure CAN pin: RX */         // PB8" s1 g3 a% L6 p- c
  12.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  13.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;         // 上拉输入
  14.         GPIO_Init(GPIOB, &GPIO_InitStructure);7 u, u$ A. l- J7 S5 C* q' D
  15. 0 z# n& [5 T3 x- ]8 Z7 z$ k
  16.         /* Configure CAN pin: TX */   // PB95 [7 A( }* U* B9 f# K0 q6 {9 H
  17.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出; }/ P3 t, V1 v! {
  19.         GPIO_Init(GPIOB, &GPIO_InitStructure);
  20.         //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 - H$ y6 R, X* G# x1 X
  21.         GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);  
  22. }
复制代码
: {8 W/ s! b- ]. w/ N
3. CAN总线接收中断优先级配置
具体代码如下:
; H' d) E( j. p9 `
  1. /*CAN RX0 中断优先级配置  */
  2. void CAN_NVIC_Configuration(void) 9 m- {( Z! y* u4 Z" e( O% ~
  3. {0 _, m/ l! `5 i( t+ X; m/ u8 n
  4.     NVIC_InitTypeDef NVIC_InitStructure;  Z7 f! w. b0 M1 ]
  5.           /* Configure the NVIC Preemption Priority Bits */  
  6.           NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);/ Q/ L% f- }' g5 P
  7. $ @% R: {- e8 r
  8.         /* enabling interrupt */5 O& q' K' [: ^" u9 s$ \% i  N
  9.           NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;
  10.           NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  11.           NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;) V" t! j: h1 K3 E7 O' a7 \
  12.           NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  13.           NVIC_Init(&NVIC_InitStructure);" _; N0 ?& ~( ]5 L, X( l. j$ X7 h
  14. }
复制代码

4. CAN总线初始化配置
具体代码如下:
 
  1. void CAN_INIT(void) , C+ l6 h8 k# ?! l6 U  ]- l
  2. {& |. B  k4 b9 t0 T3 f- k
  3.         CAN_InitTypeDef        CAN_InitStructure;8 Z5 U* f( |. h+ E( M" P
  4.         CAN_FilterInitTypeDef  CAN_FilterInitStructure;
  5. ! C7 a! s6 _8 g/ R0 v9 j
  6.         /* CAN register init */- b4 v4 a1 N/ L- o* [4 f5 L- q
  7.         CAN_DeInit(CAN1);        //将外设CAN的全部寄存器重设为缺省值
  8.         CAN_StructInit(&CAN_InitStructure);//把CAN_InitStruct中的每一个参数按缺省值填入
  9. ; n! y! D' P( e/ t( f: j; F
  10.         /* CAN cell init */
  11.         CAN_InitStructure.CAN_TTCM=DISABLE;//没有使能时间触发模式
  12.         CAN_InitStructure.CAN_ABOM=DISABLE;//没有使能自动离线管理
  13.         CAN_InitStructure.CAN_AWUM=DISABLE;//没有使能自动唤醒模式0 y) Z, ]5 M% S) l. h2 H3 E
  14.         CAN_InitStructure.CAN_NART=DISABLE;//没有使能非自动重传模式; P# c4 g& y+ O! n9 }: p
  15.         CAN_InitStructure.CAN_RFLM=DISABLE;//没有使能接收FIFO锁定模式6 N5 d8 \) _6 B+ O0 l# }
  16.         CAN_InitStructure.CAN_TXFP=DISABLE;//没有使能发送FIFO优先级
  17.         CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;        //CAN设置为正常模式
  18.         CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;                 //重新同步跳跃宽度1个时间单位, y/ ?0 R. e# _" ]: ]. U
  19.         CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;                 //时间段1为3个时间单位( w, ^/ X" \. O% `, o; n
  20.         CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;                 //时间段2为2个时间单位
  21.         CAN_InitStructure.CAN_Prescaler=24;                  //时间单位长度为24           250k7 d: H& y+ _: k0 n0 d
  22.         CAN_Init(CAN1,&CAN_InitStructure);
  23.                                                       //波特率为:36M/24(1+3+2)=0.25 即250K4 I' R$ V0 C3 Q$ S
  24.         /* CAN filter init */
  25.         CAN_FilterInitStructure.CAN_FilterNumber=1;//指定过滤器为10 T  Q, W6 z& b; j% D: q
  26.         CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//指定过滤器为标识符屏蔽位模式
  27.         CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//过滤器位宽为32位
  28.         CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;// 过滤器标识符的高16位值$ a' b, g# H0 M& {2 ~3 n
  29.         CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;//         过滤器标识符的低16位值
  30.         CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//过滤器屏蔽标识符的高16位值) G! e; i  s( R1 V# _
  31.         CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;//        过滤器屏蔽标识符的低16位值: l; b- `$ U4 y; c# C1 W, r
  32.         CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;// 设定了指向过滤器的FIFO为0
  33.         CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;// 使能过滤器
  34.         CAN_FilterInit(&CAN_FilterInitStructure);//        按上面的参数初始化过滤器! d' s* e2 D" |- K9 ?9 h7 g% P  h7 o
  35.         /* CAN FIFO0 message pending interrupt enable */
  36.         CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE); //使能FIFO0消息挂号中断
  37. }  
复制代码
0 Y" Z9 y( K- w) g* J; g' Z6 P- Y
二、CAN总线通信——波特率计算' U9 [0 N9 G: l+ t9 R
1. CAN总线时间特性
同步段(SYNC_SEG):通常期望位的变化发生在该时间段内。其值固定为1个时间单元(1 x tCAN)。
时间段1(BS1):定义采样点的位置。它包含CAN标准里的PROP_SEG和PHASE_SEG1。其值可以编程为1到16个时间单元,但也可以被自动延长,以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。
时间段2(BS2):定义发送点的位置。它代表CAN标准里的PHASE_SEG2。其值可以编程为1到8个时间单元,但也可以被自动缩短以补偿相位的负向漂移。) P) ~  ~- I, N2 c' S" B4 G
6 J8 T( x( A# e1 }! T7 h

st-img



2. 波特率计算公式) S# j+ l8 G8 M3 T  `0 K
CAN波特率=APB1时钟频率/BRP分频器/(1+tBS1+tBS2)

一般APB1时钟频率为36Mhz。如下图常见CAN总线的波特率设置。
  C% c: I8 U% ]$ z, T) E

st-img

 , W4 [7 U5 ]! n* a6 i7 t

st-img

 ; d7 F9 h/ C- x
" N) W4 c7 Z9 l
3. CAN波特率有关的寄存器$ g4 U' i/ T8 Z+ c$ V+ E

 

st-img


st-img


 
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐