你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32的CAN环回测试

[复制链接]
攻城狮Melo 发布时间:2023-6-28 14:42
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 微信图片_20230628143758.png
! 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% ]
微信图片_20230628143755.png + 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
微信图片_20230628143751.png 1 R# T1 n1 y6 [! a+ f

5 J7 @( f  b- z& U  w- r8 g
1 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
  1. typedef struct; t, D: W$ B- k* I+ c" ?7 R- x: M4 C6 J
  2. {0 m# J# k1 n1 A8 |( {; _: L% P; u
  3.   uint32_t Prescaler;       /* 配置 CAN 外设的时钟分频,可设置为 1-1024*/; a* k5 X9 f' a' w& g/ J% g
  4.   uint32_t Mode;            /* 配置 CAN 的工作模式,回环或正常模式 */
    ! t( b9 M- k/ y8 ~
  5.   uint32_t SyncJumpWidth;   /* 配置 SJW 极限值 */
    4 g4 n1 E" d% |+ |  j% Z4 O' b1 N. t6 p
  6.   uint32_t TimeSeg1;        /* 配置 BS1 段长度 */
    : |  ]  k# h, a: l* Z! ?- F
  7.   uint32_t TimeSeg2;        /* 配置 BS2 段长度 */, C! ~4 C" |3 f# b
  8.   FunctionalState TimeTriggeredMode;    /* 是否使能 TTCM 时间触发功能 */
    + g) a8 m7 a2 d8 B. `7 J, S% i
  9.   FunctionalState AutoBusOff;           /* 是否使能 ABOM 自动离线管理功能 */8 T% n5 D6 o. j3 k
  10.   FunctionalState AutoWakeUp;           /* 是否使能 AWUM 自动唤醒功能 */
    + p" w1 u; L' a: H$ \
  11.   FunctionalState AutoRetransmission;   /* 是否使能 NART 自动重传功能 */
    , C5 q3 x0 q3 f  N3 J8 @3 o  k0 |
  12.   FunctionalState ReceiveFifoLocked;    /* 是否使能 RFLM 锁定 FIFO 功能 */
    - o! q& V. i4 v* [$ ]; I
  13.   FunctionalState TransmitFifoPriority; /* 配置 TXFP 报文优先级的判定方法 */
    1 V. l/ ~5 A, P& l# s. M- W
  14. } 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
  1. typedef struct
    % T5 b9 t+ N, |  P. b9 K6 @: n
  2. {3 K. k% E- c: u+ \; Y
  3.   uint32_t StdId;       /* 存储报文的标准标识符 11 位,0-0x7FF. */
    & p4 Y/ ^. M, r) `9 g
  4.   uint32_t ExtId;       /* 存储报文的扩展标识符 29 位,0-0x1FFFFFFF. */( s- ~9 q& B5 [, u
  5.   uint32_t IDE;        /* 存储 IDE 扩展标志 */
    7 U- t. D: i* o8 }3 T0 V0 u
  6.   uint32_t RTR;        /* 存储 RTR 远程帧标志 */7 ?9 U. a5 p* A
  7.   uint32_t DLC;        /* 存储报文数据段的长度,0-8 */
    , _! _$ @: R  S# v" J
  8.   FunctionalState TransmitGlobalTime;   L, n' f  ~4 m/ a$ e7 X
  9. } CAN_TxHeaderTypeDef;
    ) H) ]. `! ^* [3 R" v

  10. : k, P& W9 S0 t6 V$ p) U0 x" F0 Q
  11. typedef struct" C+ Q7 H2 C0 m9 ~8 P
  12. {
    ' I: X+ i" _1 y) y
  13.   uint32_t StdId;      /* 存储报文的标准标识符 11 位,0-0x7FF. */
    5 J, `  [1 K. M' A) r4 S
  14.   uint32_t ExtId;      /* 存储报文的扩展标识符 29 位,0-0x1FFFFFFF. */
    : Y* l1 g& g- V
  15.   uint32_t IDE;        /* 存储 IDE 扩展标志 */
    5 d! I9 m) {1 V3 x' t: H2 q
  16.   uint32_t RTR;        /* 存储 RTR 远程帧标志 */* [0 d5 v* F7 y+ d5 h% Z' T
  17.   uint32_t DLC;        /* 存储报文数据段的长度,0-8 */0 Y  t8 Q: t# _% g3 K1 Z
  18.   uint32_t Timestamp;
    ; X; k/ w% f' j8 |
  19.   uint32_t FilterMatchIndex; 8 c$ a7 c( W" K, K- ?$ Q
  20. } 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
  1. typedef struct1 t; u  z6 ~1 K$ R0 h4 J
  2. {
    0 n( b/ c% ], }1 m7 }
  3.   uint32_t FilterIdHigh;         /*CAN_FxR1 寄存器的高 16 位 */# z% h' n' D/ }7 ?' a4 j9 \. F
  4.   uint32_t FilterIdLow;          /*CAN_FxR1 寄存器的低 16 位 */
    4 M3 B* N! @$ g" E& I2 K2 t& N: g
  5.   uint32_t FilterMaskIdHigh;     /*CAN_FxR2 寄存器的高 16 位 */
    # R$ ^9 U' _7 L" K
  6.   uint32_t FilterMaskIdLow;      /*CAN_FxR2 寄存器的低 16 位 */! }/ L1 G4 G' e, K2 o4 B2 {
  7.   uint32_t FilterFIFOAssignment; /* 设置经过筛选后数据存储到哪个接收 FIFO */- t: w, v, {& p7 t, H1 s, Y1 ~
  8.   uint32_t FilterBank;           /* 筛选器编号,范围0-27,CAN1是0-13,CAN2是14-27 */
    % i( }) S0 E# K! w0 {" l
  9.   uint32_t FilterMode;           /* 筛选器模式 */4 O7 A& w6 B, _) v% j
  10.   uint32_t FilterScale;          /* 设置筛选器的尺度 */7 y  k0 O8 |- f! i3 _
  11.   uint32_t FilterActivation;     /* 是否使能本筛选器 */
    ! e6 ]' G1 k& y  L3 p
  12.   uint32_t SlaveStartFilterBank; /* CAN2起始过滤器组 */
    ' a; K; B5 I% A& Y+ t/ r+ }
  13. } 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
  1. //下面的设置只使能了FIFO0,并不过滤任何消息1 s8 i4 a6 c7 `) T
  2. void CAN_Filter_Config(){$ A% T) l) i$ s  X8 c
  3.   CAN_FilterTypeDef sFilterConfig;
    % H+ W% ^4 Y2 ]# \" }( d$ A
  4. 7 I6 `( F: n- l5 _5 l
  5.   sFilterConfig.FilterBank = 0;      //筛选器编号, CAN1是0-13, CAN2是14-27
    ; }, z- y+ T1 y# t+ r: {
  6.   sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //采用掩码模式
    . s* x$ p; i8 ~( ~7 U: O
  7.   sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //设置筛选器的尺度, 采用32位# p# s3 D4 E1 G3 l2 v
  8.   sFilterConfig.FilterIdHigh = 0X0000;    //过滤器ID高16位,即CAN_FxR1寄存器的高16位! T+ J5 G  S8 C& l! `, h0 ]% H
  9.   sFilterConfig.FilterIdLow = 0X0000;     //过滤器ID低16位,即CAN_FxR1寄存器的低16位
    6 V& Y( R7 [1 R! C3 q2 {
  10.   sFilterConfig.FilterMaskIdHigh = 0X0000;   //过滤器掩码高16位,即CAN_FxR2寄存器的高16位/ |4 _+ R' w& t$ r
  11.   sFilterConfig.FilterMaskIdLow = 0X0000;    //过滤器掩码低16位,即CAN_FxR2寄存器的低16位
    4 w# O& N+ B. \. q1 I
  12.   sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //设置经过筛选后数据存储到哪个接收FIFO3 |8 X) D1 }. M) b% I
  13.   sFilterConfig.FilterActivation = ENABLE;   //是否使能本筛选器
    ' M5 K7 Y9 C' c+ x9 h
  14.   sFilterConfig.SlaveStartFilterBank = 14;   //指定为CAN1分配多少个滤波器组( R4 p4 f6 g* `% b

  15. ! W: j. \2 [; }2 w) D2 z3 F
  16.   if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)) b; j# R$ y, s  C. E: o$ U
  17.   {
    ; b1 b4 ~0 ~5 Y) j+ j/ a9 D+ s
  18.     Error_Handler();$ D+ o$ Q0 t2 b( N) x
  19.   }- Z. L: K$ X0 b' q! L
  20. }
复制代码

( 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 `
  1. uint8_t CAN1_Send_Msg(uint8_t *msg, uint8_t len){
      D& I" R1 v* s) B, F4 L3 W% J
  2.   uint16_t i = 0;
    8 Y5 s5 `9 L/ Z* ?$ ^
  3.   uint32_t txMailBox;
    $ s/ e) B8 C. {8 l4 D* r  v) u, n
  4.   uint8_t send_buf[8];
    * L4 H. u' x+ s5 S' b; x7 Z/ W
  5. 9 m5 J% u* w, j% _8 [! X
  6.   txHeader.StdId = 12;, K& }  D7 u% F# [, i5 L8 ?
  7.   txHeader.ExtId = 12;
    % \5 t9 i3 _- f8 t
  8.   txHeader.IDE = CAN_ID_STD;2 W5 \* P3 r5 b' g+ b) `/ D# ^
  9.   txHeader.RTR = CAN_RTR_DATA;
    1 Q0 `7 ?. J+ e1 U) G
  10.   txHeader.DLC = len;, ?0 Q/ k; l% U

  11. 8 c" t, ^! f0 Z+ G) l3 M% C5 ?
  12.   for(i = 0; i < len; i++)
    4 ?! Z% N1 l4 ?: T
  13.     send_buf[i] = msg[i];) W& o% i* N* `

  14. 8 M  Z1 q$ W) N' h
  15.   if(HAL_CAN_AddTxMessage(&hcan1, &txHeader, send_buf, &txMailBox) != HAL_OK)& B8 G4 @$ X+ R6 y
  16.     return 1; 8 W0 |! n) g! P+ y! M6 d
  17.   return 0;+ {4 p8 O' X* o$ F. H) s) S* W
  18. }
    ' q  _( X# M, y# A/ v! u

  19. # p. j6 R3 ]3 s: `9 F2 x
  20. uint8_t CAN1_Recv_Msg(uint8_t *buf){" l0 ~$ _- W/ k# ]/ Y' j
  21.   uint16_t i = 0;
    2 f8 ]9 ]  A" S0 y  }! g4 a
  22.   HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &rxHeader, buf);
    ) Q+ ], E3 p% K- R/ y: e$ H  @9 [% i
  23. ! x' z8 J0 ?5 s  n: L
  24.   if(rxHeader.IDE == CAN_ID_STD); t# ]( `6 x- T0 \
  25.     printf("StdId ID: %d\r\n", rxHeader.StdId);
    . M& E: U' |$ i2 E5 i! C( X8 d$ V
  26.   else1 U8 l+ s5 \" [
  27.     printf("ExtId ID: %d\r\n", rxHeader.ExtId);
    / k+ z0 a+ ~* _! H2 E( L
  28. ' r( M/ `' S& }0 Y3 L9 w! [  v
  29.   printf("CAN IDE: %d\r\n", rxHeader.IDE);
    , v# g, L  r3 T. J6 ^9 X6 l
  30.   printf("CAN RTR: %d\r\n", rxHeader.RTR);
    $ G2 }7 z  o. u# `0 P0 @
  31.   printf("CAN DLC: %d\r\n", rxHeader.DLC);
    6 g, f4 o6 t- _' |
  32.   printf("Recv Data: ");  g/ p: h4 l! X6 A; y' E
  33. 3 m- Y4 B  P6 p' R) Y
  34.   for(i = 0; i < rxHeader.DLC; i++)) ]5 f# R  A( W9 p! i3 ]
  35.     printf("%c",buf[i]);/ H% i9 s5 ~- t3 k: x
  36. 2 k" ~4 @  u' }( C
  37.   printf("\n");& F7 r9 Z1 u: M' Y
  38.   return rxHeader.DLC;. P( j- G) \( y/ H. i7 i6 w3 G
  39. }
复制代码
# 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 j
7 j, @! b4 e+ M
  1. void MX_CAN1_Init(void){
    " g! j" S, W  i9 E2 _7 f1 L
  2.   ......
    , k( p* q' S1 d* U" S
  3.   /* USER CODE BEGIN CAN1_Init 2 */
    / d. C9 P3 t  [$ p
  4.   CAN_Filter_Config();
    " w/ }- h' ]: v# G, T6 R  }
  5.   HAL_CAN_Start(&hcan1);
    ) K( F& T* a+ E  e$ O
  6.   /* USER CODE END CAN1_Init 2 */
    / ?, Q" o0 O6 `) f' O$ b3 Q
  7. }
复制代码
) 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
  1. int main(void){
    ' Z! M; V9 l: o1 D: I/ O
  2.   HAL_Init();
      `) L/ F6 L* G" Z7 h& }
  3.   SystemClock_Config();9 F9 T2 l% u0 m: n9 ~
  4.   MX_GPIO_Init();- ?7 b# Q6 S3 Q8 n
  5.   MX_CAN1_Init();, H8 U5 z2 R/ I: @
  6.   MX_USART1_UART_Init();
    4 r9 q" @2 L: _/ e
  7.   /* USER CODE BEGIN 2 */
      J4 L" q: r. k+ V$ o* _
  8.   uint8_t ret,i;" A+ P% h7 v5 \% U5 @4 a- }+ r2 S
  9.   printf("CAN Testing....!\r\n");
    ; }+ G+ ?9 b: f$ q
  10.   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
  11.   uint8_t rxdata[8];& A: g! G% p1 `5 F1 L$ r
  12.    /* USER CODE END 2 */
    3 H6 W+ e  R! b& Q' i
  13.    /* Infinite loop */
    ! C7 L0 T5 B; t! R0 Z
  14.    /* USER CODE BEGIN WHILE */- e* ?4 [' V# i# i  h! i" F  ^! w
  15.   while (1)7 L- H+ p2 }6 f- q# s1 u7 |' R
  16.   {
    ! ?1 D4 T3 m# g0 b/ G/ G
  17.     HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_1);3 G: L; v$ N. F9 x6 s! v
  18.     HAL_Delay(1000);
    / |& x! ~. f8 u8 ^
  19.     printf("Start Send data...\r\n");: |$ b: G" C6 L* V6 S& R
  20.   
    / {- E/ ?5 l4 e+ E" v2 x
  21.     ret = CAN1_Send_Msg(txdata, 8);' h; W2 K6 ~$ x; e5 v/ Y
  22.     if(ret == 0)
      t  h" P: w  |9 l& f. n8 ~
  23.       printf("CAN Send success!\r\n");, d! j& ?5 O- U2 n$ V5 J
  24.     else
    $ P& q& Q, ?# b4 _) z
  25.       printf("CAN Send failed!\r\n");/ l, N! W! `  m" W$ p" U) D& x
  26.   2 r0 r5 L  w; Q9 t4 |3 B
  27.     CAN1_Recv_Msg(rxdata);
    2 w' o+ e8 n5 T" b3 i. M
  28.     printf("+++++++++++++++++++++++++++++++\r\n");) T# l8 G0 {7 e1 P
  29.     /* USER CODE END WHILE */
    8 L4 t5 ~" `- C& \
  30.     /* USER CODE BEGIN 3 */
    $ A9 @/ G5 q- ]5 X! s  i
  31.   }
    5 w& x$ X' R& R8 v. h/ S
  32.   /* USER CODE END 3 */0 f; e( \* ]: q- \) ^
  33. }
复制代码
+ ~! 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& n
8 v. e; f6 N( V2 X; M+ t
微信图片_20230628143747.png + ?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
收藏 评论0 发布时间:2023-6-28 14:42

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版