CAN基础知识介绍文中介绍了CAN协议的基础知识,以及STM32F4芯片的CAN控制器相关知识,下面将通过实例,利用STM32CubeMX图形化配置工具,来实现CAN通讯的环回测试
2 O6 i, @: f' `$ @$ Y/ U& C7 o- [, X0 U" J$ d+ j3 m/ `, W$ C
1. STM32CubeMX配置+ s$ @# G9 }9 _1 g
! k% C" \( ]" J3 s$ ]# E) b% U/ e0 Q& a
⏩ CAN是挂载在APB1总线上,设置PCLK1时钟频率到最大45MHz5 ?( W8 M# O( } x: `
; F: Q4 H3 l6 L# b6 _$ R) M
! J( g6 g( k7 |' b; t7 a
" O1 [0 V" y- r- ?4 {
0 ]) T$ c! i8 S: E# e⏩ 激活CAN1,配置位时序参数,其他基本参数以及工作模式(此处设置为Loopback环回模式)
- {+ h2 H1 ~. \2 h; j
3 s2 G5 {# x- N$ p4 I4 S, I+ E( M" A* p+ t% ]
+ a0 w+ c0 A3 A( |8 I
: b+ P/ s4 l8 x2 k" sCAN波特率的计算公式:只需要知道BS1和BS2的设置,以及APB1的时钟频率,就可以方便的计算出波特率。比如设置TS1=8、TS2=6和BRP=6,在APB1频率为45Mhz的条件下,即可得到CAN通信的波特率=45000/6/(8+6+1)=500Kbps
; h% r4 l# [+ a! c& d8 K( } C$ `, I3 g- f3 M
1 R# T1 n1 y6 [! a+ f
5 J7 @( f b- z& U w- r8 g1 T2 A9 S8 M$ M4 ^
⏩ 激活USART1作为调试串口,配置相关LED对应的GPIO引脚作为指示灯
5 _. ~( e' G0 |) B% P( Y* U: n/ D% h. ]( L
5 ~: J" K4 R; \4 W- a2. MDK-ARM编程/ t( r) f0 v( K/ R8 A1 K6 q) P
9 s: K, @% @; e( `
2.1 几个重要的结构体" {( C5 r7 u7 A x* [( f! T7 e
4 }" R# l0 X$ K( T1 l9 `
5 A. C& J3 k: O9 `; K7 V- x⏩ 主控寄存器 CAN_MCR:负责管理 CAN 的工作模式8 `) d, _: Z9 @' D& S8 e
- typedef struct; t, D: W$ B- k* I+ c" ?7 R- x: M4 C6 J
- {0 m# J# k1 n1 A8 |( {; _: L% P; u
- uint32_t Prescaler; /* 配置 CAN 外设的时钟分频,可设置为 1-1024*/; a* k5 X9 f' a' w& g/ J% g
- uint32_t Mode; /* 配置 CAN 的工作模式,回环或正常模式 */
! t( b9 M- k/ y8 ~ - uint32_t SyncJumpWidth; /* 配置 SJW 极限值 */
4 g4 n1 E" d% |+ | j% Z4 O' b1 N. t6 p - uint32_t TimeSeg1; /* 配置 BS1 段长度 */
: | ] k# h, a: l* Z! ?- F - uint32_t TimeSeg2; /* 配置 BS2 段长度 */, C! ~4 C" |3 f# b
- FunctionalState TimeTriggeredMode; /* 是否使能 TTCM 时间触发功能 */
+ g) a8 m7 a2 d8 B. `7 J, S% i - FunctionalState AutoBusOff; /* 是否使能 ABOM 自动离线管理功能 */8 T% n5 D6 o. j3 k
- FunctionalState AutoWakeUp; /* 是否使能 AWUM 自动唤醒功能 */
+ p" w1 u; L' a: H$ \ - FunctionalState AutoRetransmission; /* 是否使能 NART 自动重传功能 */
, C5 q3 x0 q3 f N3 J8 @3 o k0 | - FunctionalState ReceiveFifoLocked; /* 是否使能 RFLM 锁定 FIFO 功能 */
- o! q& V. i4 v* [$ ]; I - FunctionalState TransmitFifoPriority; /* 配置 TXFP 报文优先级的判定方法 */
1 V. l/ ~5 A, P& l# s. M- W - } CAN_InitTypeDef;
复制代码 8 h# N7 B% @) Z" W
⏩ 发送及接收头结构体:主要用于构造发送报文,以及接收报文。收发发文时,需要自定义头结构体变量- [1 V: V0 E, K7 U) R
# T0 u" u0 k7 u) R! z' K
$ ]( `' t: W5 v# a- typedef struct
% T5 b9 t+ N, | P. b9 K6 @: n - {3 K. k% E- c: u+ \; Y
- uint32_t StdId; /* 存储报文的标准标识符 11 位,0-0x7FF. */
& p4 Y/ ^. M, r) `9 g - uint32_t ExtId; /* 存储报文的扩展标识符 29 位,0-0x1FFFFFFF. */( s- ~9 q& B5 [, u
- uint32_t IDE; /* 存储 IDE 扩展标志 */
7 U- t. D: i* o8 }3 T0 V0 u - uint32_t RTR; /* 存储 RTR 远程帧标志 */7 ?9 U. a5 p* A
- uint32_t DLC; /* 存储报文数据段的长度,0-8 */
, _! _$ @: R S# v" J - FunctionalState TransmitGlobalTime; L, n' f ~4 m/ a$ e7 X
- } CAN_TxHeaderTypeDef;
) H) ]. `! ^* [3 R" v
: k, P& W9 S0 t6 V$ p) U0 x" F0 Q- typedef struct" C+ Q7 H2 C0 m9 ~8 P
- {
' I: X+ i" _1 y) y - uint32_t StdId; /* 存储报文的标准标识符 11 位,0-0x7FF. */
5 J, ` [1 K. M' A) r4 S - uint32_t ExtId; /* 存储报文的扩展标识符 29 位,0-0x1FFFFFFF. */
: Y* l1 g& g- V - uint32_t IDE; /* 存储 IDE 扩展标志 */
5 d! I9 m) {1 V3 x' t: H2 q - uint32_t RTR; /* 存储 RTR 远程帧标志 */* [0 d5 v* F7 y+ d5 h% Z' T
- uint32_t DLC; /* 存储报文数据段的长度,0-8 */0 Y t8 Q: t# _% g3 K1 Z
- uint32_t Timestamp;
; X; k/ w% f' j8 | - uint32_t FilterMatchIndex; 8 c$ a7 c( W" K, K- ?$ Q
- } CAN_RxHeaderTypeDef;
复制代码 / e4 A+ a& b/ M% N- d# R; O
( o2 J1 ^3 D) R/ P! O
⏩ 过滤器结构体:STM32CubeMX不会初始化过滤器的相关内容,需要自己添加) \( O& u$ N8 q& @. v: _" A: V+ I
. ]: O @/ ]+ c/ }$ P- g- o7 c- `- P
- typedef struct1 t; u z6 ~1 K$ R0 h4 J
- {
0 n( b/ c% ], }1 m7 } - uint32_t FilterIdHigh; /*CAN_FxR1 寄存器的高 16 位 */# z% h' n' D/ }7 ?' a4 j9 \. F
- uint32_t FilterIdLow; /*CAN_FxR1 寄存器的低 16 位 */
4 M3 B* N! @$ g" E& I2 K2 t& N: g - uint32_t FilterMaskIdHigh; /*CAN_FxR2 寄存器的高 16 位 */
# R$ ^9 U' _7 L" K - uint32_t FilterMaskIdLow; /*CAN_FxR2 寄存器的低 16 位 */! }/ L1 G4 G' e, K2 o4 B2 {
- uint32_t FilterFIFOAssignment; /* 设置经过筛选后数据存储到哪个接收 FIFO */- t: w, v, {& p7 t, H1 s, Y1 ~
- uint32_t FilterBank; /* 筛选器编号,范围0-27,CAN1是0-13,CAN2是14-27 */
% i( }) S0 E# K! w0 {" l - uint32_t FilterMode; /* 筛选器模式 */4 O7 A& w6 B, _) v% j
- uint32_t FilterScale; /* 设置筛选器的尺度 */7 y k0 O8 |- f! i3 _
- uint32_t FilterActivation; /* 是否使能本筛选器 */
! e6 ]' G1 k& y L3 p - uint32_t SlaveStartFilterBank; /* CAN2起始过滤器组 */
' a; K; B5 I% A& Y+ t/ r+ } - } CAN_FilterTypeDef;
复制代码
i, g( b7 `+ W1 W E* A
' R; J3 E/ H, M" m2.2 程序编写. t6 b- a% p# w$ Z$ W
T8 V' n+ B' q, ]5 x6 I1 v1 `
9 S! J! ?+ e& W
⏩ 生成工程后,打开can.c文件,可见STM32CubeMX已经对位时序参数、其他基本参数以及工作模式进行了初始化。但是并没有初始化过滤器的相关内容,因此需要我们自己添加,并在CAN初始化时调用
( W* k6 V5 c2 G8 M- x/ {0 O& C# x+ K6 b8 ^ e7 }
7 b/ y6 X. a3 E
- //下面的设置只使能了FIFO0,并不过滤任何消息1 s8 i4 a6 c7 `) T
- void CAN_Filter_Config(){$ A% T) l) i$ s X8 c
- CAN_FilterTypeDef sFilterConfig;
% H+ W% ^4 Y2 ]# \" }( d$ A - 7 I6 `( F: n- l5 _5 l
- sFilterConfig.FilterBank = 0; //筛选器编号, CAN1是0-13, CAN2是14-27
; }, z- y+ T1 y# t+ r: { - sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //采用掩码模式
. s* x$ p; i8 ~( ~7 U: O - sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //设置筛选器的尺度, 采用32位# p# s3 D4 E1 G3 l2 v
- sFilterConfig.FilterIdHigh = 0X0000; //过滤器ID高16位,即CAN_FxR1寄存器的高16位! T+ J5 G S8 C& l! `, h0 ]% H
- sFilterConfig.FilterIdLow = 0X0000; //过滤器ID低16位,即CAN_FxR1寄存器的低16位
6 V& Y( R7 [1 R! C3 q2 { - sFilterConfig.FilterMaskIdHigh = 0X0000; //过滤器掩码高16位,即CAN_FxR2寄存器的高16位/ |4 _+ R' w& t$ r
- sFilterConfig.FilterMaskIdLow = 0X0000; //过滤器掩码低16位,即CAN_FxR2寄存器的低16位
4 w# O& N+ B. \. q1 I - sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //设置经过筛选后数据存储到哪个接收FIFO3 |8 X) D1 }. M) b% I
- sFilterConfig.FilterActivation = ENABLE; //是否使能本筛选器
' M5 K7 Y9 C' c+ x9 h - sFilterConfig.SlaveStartFilterBank = 14; //指定为CAN1分配多少个滤波器组( R4 p4 f6 g* `% b
-
! W: j. \2 [; }2 w) D2 z3 F - if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)) b; j# R$ y, s C. E: o$ U
- {
; b1 b4 ~0 ~5 Y) j+ j/ a9 D+ s - Error_Handler();$ D+ o$ Q0 t2 b( N) x
- }- Z. L: K$ X0 b' q! L
- }
复制代码
( T. P. T" H3 u, t8 H9 i⏩ 编写发送和接收数据函数:此处将格式固定为标准数据帧,ID为12
* W9 y3 T8 `$ D/ e, s! j- r, [! ~/ ]! H2 |( Y, h
# r/ V: Z9 K/ n8 X; p% l# w5 `
- uint8_t CAN1_Send_Msg(uint8_t *msg, uint8_t len){
D& I" R1 v* s) B, F4 L3 W% J - uint16_t i = 0;
8 Y5 s5 `9 L/ Z* ?$ ^ - uint32_t txMailBox;
$ s/ e) B8 C. {8 l4 D* r v) u, n - uint8_t send_buf[8];
* L4 H. u' x+ s5 S' b; x7 Z/ W - 9 m5 J% u* w, j% _8 [! X
- txHeader.StdId = 12;, K& } D7 u% F# [, i5 L8 ?
- txHeader.ExtId = 12;
% \5 t9 i3 _- f8 t - txHeader.IDE = CAN_ID_STD;2 W5 \* P3 r5 b' g+ b) `/ D# ^
- txHeader.RTR = CAN_RTR_DATA;
1 Q0 `7 ?. J+ e1 U) G - txHeader.DLC = len;, ?0 Q/ k; l% U
-
8 c" t, ^! f0 Z+ G) l3 M% C5 ? - for(i = 0; i < len; i++)
4 ?! Z% N1 l4 ?: T - send_buf[i] = msg[i];) W& o% i* N* `
-
8 M Z1 q$ W) N' h - if(HAL_CAN_AddTxMessage(&hcan1, &txHeader, send_buf, &txMailBox) != HAL_OK)& B8 G4 @$ X+ R6 y
- return 1; 8 W0 |! n) g! P+ y! M6 d
- return 0;+ {4 p8 O' X* o$ F. H) s) S* W
- }
' q _( X# M, y# A/ v! u
# p. j6 R3 ]3 s: `9 F2 x- uint8_t CAN1_Recv_Msg(uint8_t *buf){" l0 ~$ _- W/ k# ]/ Y' j
- uint16_t i = 0;
2 f8 ]9 ] A" S0 y }! g4 a - HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &rxHeader, buf);
) Q+ ], E3 p% K- R/ y: e$ H @9 [% i - ! x' z8 J0 ?5 s n: L
- if(rxHeader.IDE == CAN_ID_STD); t# ]( `6 x- T0 \
- printf("StdId ID: %d\r\n", rxHeader.StdId);
. M& E: U' |$ i2 E5 i! C( X8 d$ V - else1 U8 l+ s5 \" [
- printf("ExtId ID: %d\r\n", rxHeader.ExtId);
/ k+ z0 a+ ~* _! H2 E( L - ' r( M/ `' S& }0 Y3 L9 w! [ v
- printf("CAN IDE: %d\r\n", rxHeader.IDE);
, v# g, L r3 T. J6 ^9 X6 l - printf("CAN RTR: %d\r\n", rxHeader.RTR);
$ G2 }7 z o. u# `0 P0 @ - printf("CAN DLC: %d\r\n", rxHeader.DLC);
6 g, f4 o6 t- _' | - printf("Recv Data: "); g/ p: h4 l! X6 A; y' E
- 3 m- Y4 B P6 p' R) Y
- for(i = 0; i < rxHeader.DLC; i++)) ]5 f# R A( W9 p! i3 ]
- printf("%c",buf[i]);/ H% i9 s5 ~- t3 k: x
- 2 k" ~4 @ u' }( C
- printf("\n");& F7 r9 Z1 u: M' Y
- return rxHeader.DLC;. P( j- G) \( y/ H. i7 i6 w3 G
- }
复制代码 # X, [! c/ r8 q- W8 G: {( K
⏩ 默认Cubemx生成的代码并没有can start,没有调用HAL_CAN_Start(&hcan1) 来使能CAN,因此需要在CAN初始化代码中添加
% N* d5 b/ W$ [! D+ j" T
' \9 U: R" F! w! S) T8 _5 Y" g. Y2 j7 j, @! b4 e+ M
- void MX_CAN1_Init(void){
" g! j" S, W i9 E2 _7 f1 L - ......
, k( p* q' S1 d* U" S - /* USER CODE BEGIN CAN1_Init 2 */
/ d. C9 P3 t [$ p - CAN_Filter_Config();
" w/ }- h' ]: v# G, T6 R } - HAL_CAN_Start(&hcan1);
) K( F& T* a+ E e$ O - /* USER CODE END CAN1_Init 2 */
/ ?, Q" o0 O6 `) f' O$ b3 Q - }
复制代码 ) K$ Q1 L% p8 i) V) \
⏩ 主函数main.c中,代码如下7 K1 j9 M3 y6 ^; a# T1 @! M2 }
7 I% i2 x3 k3 p* b
7 x8 y7 i E) r: d% t V7 N
- int main(void){
' Z! M; V9 l: o1 D: I/ O - HAL_Init();
`) L/ F6 L* G" Z7 h& } - SystemClock_Config();9 F9 T2 l% u0 m: n9 ~
- MX_GPIO_Init();- ?7 b# Q6 S3 Q8 n
- MX_CAN1_Init();, H8 U5 z2 R/ I: @
- MX_USART1_UART_Init();
4 r9 q" @2 L: _/ e - /* USER CODE BEGIN 2 */
J4 L" q: r. k+ V$ o* _ - uint8_t ret,i;" A+ P% h7 v5 \% U5 @4 a- }+ r2 S
- printf("CAN Testing....!\r\n");
; }+ G+ ?9 b: f$ q - uint8_t txdata[8] = {76, 79, 79, 80, 66, 65, 67, 75};
7 a2 G. {4 h: H3 `0 W6 k0 C# J; z- I - uint8_t rxdata[8];& A: g! G% p1 `5 F1 L$ r
- /* USER CODE END 2 */
3 H6 W+ e R! b& Q' i - /* Infinite loop */
! C7 L0 T5 B; t! R0 Z - /* USER CODE BEGIN WHILE */- e* ?4 [' V# i# i h! i" F ^! w
- while (1)7 L- H+ p2 }6 f- q# s1 u7 |' R
- {
! ?1 D4 T3 m# g0 b/ G/ G - HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_1);3 G: L; v$ N. F9 x6 s! v
- HAL_Delay(1000);
/ |& x! ~. f8 u8 ^ - printf("Start Send data...\r\n");: |$ b: G" C6 L* V6 S& R
-
/ {- E/ ?5 l4 e+ E" v2 x - ret = CAN1_Send_Msg(txdata, 8);' h; W2 K6 ~$ x; e5 v/ Y
- if(ret == 0)
t h" P: w |9 l& f. n8 ~ - printf("CAN Send success!\r\n");, d! j& ?5 O- U2 n$ V5 J
- else
$ P& q& Q, ?# b4 _) z - printf("CAN Send failed!\r\n");/ l, N! W! ` m" W$ p" U) D& x
- 2 r0 r5 L w; Q9 t4 |3 B
- CAN1_Recv_Msg(rxdata);
2 w' o+ e8 n5 T" b3 i. M - printf("+++++++++++++++++++++++++++++++\r\n");) T# l8 G0 {7 e1 P
- /* USER CODE END WHILE */
8 L4 t5 ~" `- C& \ - /* USER CODE BEGIN 3 */
$ A9 @/ G5 q- ]5 X! s i - }
5 w& x$ X' R& R8 v. h/ S - /* USER CODE END 3 */0 f; e( \* ]: q- \) ^
- }
复制代码 + ~! v7 A a, P3 a# G' u
3. 下载测试- M3 G; ]6 I, ?/ C* F& V
/ P, E' Y. C, U7 J; k
, f% T& h) b0 |
编译无误后下载到开发板,可以看到系统运行时D1指示灯不断闪烁,串口不断的打印CAN环回测试的数据$ E/ Q, g% g. U
+ A4 s& W- Q! ^, I" e& n8 v. e; f6 N( V2 X; M+ t
+ ?7 Z( t+ p F& N
' i" |5 S+ N; S2 l& k ?& u( C8 H: r
, C4 y- q' M7 P4 _+ I! J
转载自: 嵌入式攻城狮
" [: A# ~' T1 G- _: \* D如有侵权请联系删除
' I' R7 B+ p9 ~& F( `1 {' L( P' u( L" ^3 S$ V- g
. J' ^9 n1 C z
, [/ ~& g/ ^6 ]( ?+ p: t- X& z; l
|