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

【经验分享】STM32 HAL库CAN总线收发、中断方式接收示例教程

[复制链接]
STMCU小助手 发布时间:2022-4-12 10:00
配置CAN$ P# n1 h, I+ G: A6 S
先了解几个关键词简称:

  q) w0 w1 P/ H! G7 _$ F' E+ Y) K0 ?4 I  K9 [- ]/ c
最小时间单位(Tq,Time Quantum)
$ c' b% C; B% d" _2 e, _: k同步段(SS,Synchronization Segment)1tq2 I9 _) @" g: k* G) z
传播时间段(PTS,Propagation Time Segment)1~8tq" m- b' p5 X$ z
相位缓冲段1(PBS1,Phase Buffer Segment1)1~8tq: e% H; i2 [' R' b$ w3 L" C1 E0 B& E
相位缓冲段2(PBS2,Phase Buffer Segment2)2~8tq
0 {5 c  ?* P* \, n- O! {再同步补偿宽度(SJW,reSynchronization Jump Width)1~4tq
# z7 r. z" C7 m  C. J3 J波特率分频器(BRP,Baud Rate Prescaler)
9 u- I! L6 d( gSTM32把传播时间段(PTS)和相位缓冲段1(PBS1)合并了,形成了时间段1(TS1)。, t) r- m7 R$ H4 Z
, k4 M8 H7 P3 y* z3 u; b$ u
CAN位时序寄存器(CAN_BTR)用于设置TS1、TS2、BRP、SJW等参数,这些参数直接决定CAN的波特率。6 _* w, C) d+ E6 `4 B" M8 B
) k3 ~/ d( w1 d0 P8 y8 Y
@RPJH23%IDIX8DXXKZZF4R7.png , Y# ^( z( G( g- Y1 H
4 J# o# g0 C9 K7 f
SJW[1:0]再同步补偿宽度- ^! \. L2 k  C2 H! C
9 T& r% L9 ]: z6 a* M
TS1[3:0]时间段13 V# P/ o- n  X: y8 S

4 j  ?* Y8 j6 r9 _' |1 x* B) bTS2[2:0]时间段2; x0 X" F! ~; [9 S& L9 t( K2 F
5 G) b+ `5 ^3 x% G
BRP[9:0]波特率分频器
8 f; c: ^( |" z& `# ^9 E; K
, [9 }/ u2 ~( z! W! w% a7 n6 b- r可以看到没有同步段(SS段),这是因为STM32已经将SS段固化为1。7 y) }7 r; M. m- O4 C) \' G" ]

  M0 f, w- s" u2 H. l, Z除去这几个参数,还需要设置分频,STM32F1系列一般是跑到72M主频,CAN是挂在36M的APB1时钟上,设置CAN的分频就是分的这个36M。
# K; r, K: r1 u5 L) B0 b6 _& D5 M5 i* i9 v/ i+ E3 Q) @6 Z
下面这张图是波特率计算公式:
- @. j. F+ W$ m" j
5 G+ ]$ c: ~9 _+ ^3 r 4f9a0ef7766841fc8671353d8cb869fe.png
* t% x$ d! v1 q/ y$ ?& T3 B; {9 L  O4 k6 I0 b3 b+ w6 G1 V! p$ B( C
整合一下波特率计算公式就是这样的:& v& Q# J9 i0 b4 u  {
7 q2 n% a3 t/ Z4 n; ^- T( H
波特率 = APB1 / [(1 + (TS1+1) + (TS2+1)) * (BRP+1)]' @$ ^1 e4 w2 s, ]- t; `* ~- b
0 H& R% I4 i- c5 G/ v6 S
在简化就是:波特率 = 时钟主频 / 分频 / (tq1 + tq2 + ss)
: z8 l0 k! s* d# Z. p: e6 H% Y& [/ g; S" O
其中SS就是同步段,已经恒为1,所以:波特率 = 时钟主频 / 分频 / (tq1 + tq2 + 1)+ E9 j* h4 K3 ~7 s
0 r# y7 e$ G- D7 ^8 n+ U2 ~
下面我们开始实际设置波特率,这里要注意,CAN的波特率最大为1Mbps。
5 F: z1 l' H, R& b7 D- I) q4 b9 F6 p$ O8 @  P
stm32f103的CAN的时钟主频是36M,分9频就是4M,设置tq1=5,tq2=2,ss恒等于1,那么:波特率 = 36MHz / 9分频 /(5 + 2 + 1) = 500KHz  I/ E8 {9 L, W1 s0 Y# `' P2 n( Q

9 |% t# T, \/ e8 ]另外还有一向是:再同步补偿宽度(reSynchronization Jump Width) 这个参数,其实就是一个由数个Tq组成的一个段,用来对同步误差进行补偿,可以简单理解为为了提高精准度的,例如两个CAN进行通讯时由于两个板子的晶振可能存在误差从而导致CAN的波特率没有500K那么精准,所以就需要设置一个补偿参数去修正,这个参数就需要根据你实际的板子情况去调整了。
5 l- W  E( H4 v
4 E" d" M  w" b: J7 B注意:stm32cubemx生成的CAN代码是不带过滤器的,需要自己手动添加。
! ]) n) d! _7 K  Z/ T. C/ B6 W9 Q$ ^$ g; Y: `2 M
XG3}YF2)VM[)56]LWKNMZE4.png
! H3 n4 Z2 k9 i  F: A
) A8 h0 V4 T2 ] 0O(JT%S7YRV7H$)3`V~R.png " K' {( _% L) ~) V7 ^1 {' {

4 [0 e* `& W" J) t: j3 A代码修改
; S9 I- f) j+ {7 o  Y8 e# [6 }( JSTM32CUBEMX生成的CAN配置代码是没有过滤器设置的,需要手动添加。
; C; _# j) u8 Q1 @- x/ r2 V4 c) s! F1 b: {6 C+ H5 W. R
  1. typedef struct9 X& Z9 ?- m  F7 i
  2. {% T4 C4 L8 t3 N, Y) V
  3.         uint32_t mailbox;
    $ {$ ~/ c- C: Y, g3 K
  4.         CAN_TxHeaderTypeDef hdr;
    ; A+ j/ s. r- ?& u  _
  5.         uint8_t payload[8];
    4 [" ^% g- o) a5 D6 B7 _% _$ Y  h  N
  6. }CAN_TxPacketTypeDef;  {+ ?1 g. C8 [+ k% O
  7. 5 E5 q$ W4 q( B- `5 S. `' X
  8. typedef struct" v+ P/ r2 x+ N$ L0 c8 p
  9. {
      j' k' K! B  Z5 j7 |6 j
  10.         CAN_RxHeaderTypeDef hdr;- `1 s, q9 d, y$ i% m. [
  11.         uint8_t payload[8];
    ' }, B7 p4 Z3 g3 [
  12. }CAN_RxPacketTypeDef;
复制代码
  1. /// CAN过滤器寄存器位宽类型定义) k( b8 i- Q' R* T, C; B8 @
  2. typedef union1 J, N& |+ w1 r/ L% I% V  C: d4 }
  3. {3 y( Q8 n: D1 U, e$ z% j
  4.     __IO uint32_t value;
    . \8 h  d& K* R5 T
  5.     struct
    6 @8 \9 d2 n& E0 d
  6.     {; I' o6 X3 j' y8 y  I
  7.         uint8_t REV : 1;                        ///< [0]    :未使用4 F2 G7 v8 a* E8 _
  8.         uint8_t RTR : 1;                        ///< [1]    : RTR(数据帧或远程帧标志位)
    % [1 H8 B5 s8 ?/ v: ?
  9.         uint8_t IDE : 1;                        ///< [2]    : IDE(标准帧或扩展帧标志位)7 }0 U; z* b9 X# F0 X
  10.         uint32_t EXID : 18;                        ///< [21:3] : 存放扩展帧ID6 e9 a7 g( O2 ~, \  V9 f
  11.         uint16_t STID : 11;                        ///< [31:22]: 存放标准帧ID  `9 J1 h: s( V6 ~3 U; D
  12.     } Sub;
    ; h  s# y2 D- V4 H
  13. } CAN_FilterRegTypeDef;2 ]! `' w& U$ x) X7 J& `
  14. 0 h0 f" I7 S, S" l

  15. 0 P' v6 U& s% n" _6 @
  16. #define CAN_BASE_ID 0                                                ///< CAN标准ID,最大11位,也就是0x7FF
    5 w$ ~4 @; `5 |( t) ]

  17. 1 E# B& Y" v" |% J) F$ A
  18. #define CAN_FILTER_MODE_MASK_ENABLE 1                ///< CAN过滤器模式选择:=0:列表模式  =1:屏蔽模式0 Y. o# P- Z0 }6 D6 V
  19. 3 R) K  X! o0 h$ |! B$ O$ o
  20. #define CAN_ID_TYPE_STD_ENABLE      1       ///< CAN过滤ID类型选择:=1:标准ID,=0:扩展ID6 t7 o, W8 D+ E- s

  21. 6 d! d1 r% ?9 e5 m) Z  {
  22. void CAN_Filter_Config(void)- p; `, K0 G! u
  23. {
    ! @( F. f; f7 w; g4 j- n) Y
  24.     CAN_FilterTypeDef sFilterConfig;
    ( ^, i/ q7 U/ k8 `$ {# q) Y- G
  25.     CAN_FilterRegTypeDef IDH = {0};
    7 c" Y3 O$ s: H2 A1 i
  26.     CAN_FilterRegTypeDef IDL = {0};$ U! u$ N8 B& |6 ~" H

  27. 1 X2 X3 Q1 D" e; `
  28. #if CAN_ID_TYPE_STD_ENABLE3 l3 M% w3 a. j1 p! r  _& Y) e
  29.     IDH.Sub.STID = (CAN_BASE_ID >> 16) & 0xFFFF;                // 标准ID高16位
    % \4 ]% [# L$ t5 Y
  30.     IDL.Sub.STID = (CAN_BASE_ID & 0xFFFF);                                // 标准ID低16位
    ) t5 @9 C8 R# W8 ^+ R( V0 s
  31. #else4 l1 ?/ U9 d: i
  32.     IDH.Sub.EXID = (CAN_BASE_ID >> 16) & 0xFFFF;                // 扩展ID高16位2 a9 A; r* W* H8 s
  33.     IDL.Sub.EXID = (CAN_BASE_ID & 0xFFFF);                                // 扩展ID低16位0 `0 J4 E) h% y3 M& e
  34.     IDL.Sub.IDE  = 1;                                                                        // 扩展帧标志位置位$ X6 g* I3 Q- b4 n4 f$ ^
  35. #endif: H! Z+ C9 D+ L6 \, U
  36.     sFilterConfig.FilterBank           = 0;                                                                                                // 设置过滤器组编号
    : E7 X1 P1 Y1 _# Z  i0 o
  37. #if CAN_FILTER_MODE_MASK_ENABLE
    9 i9 J$ C" |$ T6 H8 ~' @; X
  38.     sFilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;                                                        // 屏蔽位模式
    ; I* p2 O- U- Z: ^
  39. #else
    7 _6 t. m  P, @1 m3 o# j( D$ n* z/ a
  40.     sFilterConfig.FilterMode           = CAN_FILTERMODE_IDLIST;                                                        // 列表模式
    5 _# x0 D. f4 t
  41. #endif+ [2 W& ]& [$ N4 ?2 U
  42.     sFilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;                                                        // 32位宽) D+ E; s; B( M0 h1 y
  43.     sFilterConfig.FilterIdHigh         = IDH.value;                                                                                // 标识符寄存器一ID高十六位,放入扩展帧位
    - G4 f! T! b5 `! E
  44.     sFilterConfig.FilterIdLow          = IDL.value;                                                                                // 标识符寄存器一ID低十六位,放入扩展帧位' ~) j0 _! `2 e% d* d
  45.     sFilterConfig.FilterMaskIdHigh     = IDH.value;                                                                                // 标识符寄存器二ID高十六位,放入扩展帧位
    8 X# F  u$ Q3 S( a6 @' }6 f
  46.     sFilterConfig.FilterMaskIdLow      = IDL.value;                                                                                // 标识符寄存器二ID低十六位,放入扩展帧位
    $ G4 n- |  G; j0 O6 C6 [
  47.     sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;                                                                        // 过滤器组关联到FIFO0
    7 ]7 B5 T7 e- Y8 ~. i; j6 O/ G
  48.     sFilterConfig.FilterActivation     = ENABLE;                                                                                // 激活过滤器
    4 A9 n2 s% m) t0 x+ b, Q. W/ U. r
  49.     sFilterConfig.SlaveStartFilterBank = 14;                                                                                        // 设置从CAN的起始过滤器编号,本单片机只有一个CAN,顾此参数无效
    9 J- T% ?* K( S9 y
  50.     if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
    : u# U; ^$ B7 x) F# {( U! [0 g
  51.     {
    4 L" r% L. J7 d3 Y. W
  52.         Error_Handler();
    # [( P5 F( D4 L2 W! `( X' }- ~
  53.     }0 z7 K4 i8 V" E/ \. k  j) t8 \
  54. }4 V0 L( Z* z, ?8 M# L! [
  55. 4 b; W$ s2 j8 i' J& s
  56. uint8_t CAN_Transmit(CAN_TxPacketTypeDef* packet); |) T' ?5 F! [5 Z  G8 N. h; l- I8 }
  57. {! V' l  s; J2 `8 ]' Q$ N
  58.         if(HAL_CAN_AddTxMessage(&hcan, &packet->hdr, packet->payload, &packet->mailbox) != HAL_OK)
    - S$ T0 F8 V- @0 O! f% F6 n  X( m8 q
  59.                 return 1;/ ~. D2 j/ ]& D! ^
  60.         return 0;
    $ f3 R0 a" j! p/ b, j9 K) b
  61. }
    , ]' L( `  M/ G
  62. ( e9 L$ k  L9 o
  63. void CAN_Init(void)- @: F3 |$ I2 E. U1 G
  64. {
      z/ W* [3 x" h/ s. U1 P4 ]! c9 J6 \
  65.     MX_CAN_Init();
      M) M* c" D9 g
  66.     CAN_Filter_Config();
    + w$ k* y8 y' [
  67.     HAL_CAN_Start(&hcan);
    1 }1 ]. J. F0 s$ K- H3 ?8 B
  68.     HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);                                        // 使能CAN接收中断. P3 d! U  n0 J1 o1 [
  69. }- X. ^4 _! r& F: J& g+ m  o
  70. 3 o5 I2 X6 r( i' M6 w" D
  71. void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *canHandle)
    4 G! \4 w% j; R
  72. {6 `1 d: L2 Z+ M: Y7 Y8 k
  73.         static CAN_RxPacketTypeDef packet;' k) i" x  [, c$ M$ |
  74.         
    . k" d5 M! V+ W" L, B
  75.     // CAN数据接收
    $ d5 q, H' l8 s" L8 |3 b6 E
  76.     if (canHandle->Instance == hcan.Instance)$ V# M6 S. T; R( C- }
  77.     {
    ! I3 V/ A, t9 e& U
  78.         if (HAL_CAN_GetRxMessage(canHandle, CAN_RX_FIFO0, &packet.hdr, packet.payload) == HAL_OK)                // 获得接收到的数据头和数据
    / }. g9 T8 I) i9 g+ q
  79.         {+ l! |' M0 z) ]2 D$ Z
  80.                         printf("\r\n\r\n\r\n################### CAN RECV ###################\r\n");7 g0 J: I1 J/ a3 u  ]8 O: B
  81.                         printf("STID:0x%X\r\n",packet.hdr.StdId);7 Y/ A3 K' |: f8 d
  82.                         printf("EXID:0x%X\r\n",packet.hdr.ExtId);
    * n8 Q" ]' g7 |; n9 @% g+ x
  83.                         printf("DLC :%d\r\n", packet.hdr.DLC);/ K+ k$ d9 p3 q8 }8 n
  84.                         printf("DATA:");/ X6 ^5 B. n9 M, K! w. C" {
  85.                         for(int i = 0; i < packet.hdr.DLC; i++)
    . X7 j% [2 j7 T! A7 b% V6 Y, T
  86.                         {" B. l% }) `$ i. i) @
  87.                                 printf("0x%02X ", packet.payload<i>);
    1 M# B. l3 b& r- r
  88.                         }
    " Y5 x- U9 _, i6 t$ {+ @5 Q+ d
  89.            HAL_CAN_ActivateNotification(canHandle, CAN_IT_RX_FIFO0_MSG_PENDING);                                                // 再次使能FIFO0接收中断
    7 G4 t0 v% w7 B
  90.         }
    7 w7 B* s- T, r- N0 W
  91.     }
    + u9 s( v4 [" D# z+ e" b
  92. }</i>
复制代码

  1. / _8 T. _6 j% G( x& r+ V! o! t
  2. CAN_TxPacketTypeDef g_CanTxPacket;
    + X9 [$ m  i- j
  3. 5 u, o* \* ]) K4 i: V3 {
  4. void CAN_SetTxPacket(void)- b$ u3 c2 R& k, o7 z( t5 I
  5. {; t/ S' F& x' J; x
  6.         g_CanTxPacket.hdr.StdId = 0x321;                        // 标准ID
    : [! `0 \2 \% Q! ^! k9 f$ {5 _+ J- x
  7. //        g_CanTxPacket.hdr.ExtId = 0x10F01234;                // 扩展ID
    ; s9 O1 B9 ^) l% K! I6 X
  8.         g_CanTxPacket.hdr.IDE = CAN_ID_STD;                        // 标准ID类型& N% r# H: Q7 }8 u- t& f
  9. //        g_CanTxPacket.hdr.IDE = CAN_ID_EXT;                        // 扩展ID类型
    ; f1 V2 k+ @$ G, K4 ^/ n6 f
  10.         g_CanTxPacket.hdr.DLC = 8;                                        // 数据长度
    $ E4 o+ ~% J' X4 J/ o. x! }$ h
  11.         g_CanTxPacket.hdr.RTR = CAN_RTR_DATA;                // 数据帧
    ) K  J. w% n) x& C9 s
  12. //        g_CanTxPacket.hdr.RTR = CAN_RTR_REMOTE;                // 远程帧( t9 P* s+ G4 X: t
  13.         g_CanTxPacket.hdr.TransmitGlobalTime = DISABLE;+ i$ A4 T) p" P) b+ x
  14.         
      _. O. q, ~" m5 t
  15.         for(int i = 0; i < 8; i++)+ j8 W& v6 d0 W* \8 D+ C5 }, E
  16.         {
    7 _2 N1 g6 U9 B; Q/ g5 d
  17.                 g_CanTxPacket.payload<i> = i;$ u& }, ~6 r6 ^/ k# N
  18.         }
    4 u1 G$ S/ O8 Y, U8 S7 K
  19. }
    % }0 a# b: t, M5 p
  20. # A- q  J) }% q$ c  w
  21. int main()' Z7 U5 t: l7 _  {' N; ]2 a8 U6 Z  l
  22. {3 _1 K8 F' P# M( S5 q# H
  23.     HAL_Init();* G& [' [/ k0 v% n
  24.     SystemClock_Config();
    5 E/ N$ N% I: f$ |) l; E6 H
  25.     MX_GPIO_Init();
    : R! c* |" F  n' f, E$ P
  26.     MX_USART1_UART_Init();5 _+ `" o/ ]* e6 P! \, H! G* x
  27.     CAN_Init();
    . {5 W% |3 O) S$ M" D
  28.         printf("----------------------------------------\r\n");7 g& Y1 @) c" {8 V9 e$ F' M
  29. - q9 Q- {- R4 p+ V( c3 t
  30.         CAN_SetTxPacket();: @& B7 k; V( B+ s- w/ N/ `$ ^, `
  31.         4 L" b2 A& j1 v0 ]3 I! E, {8 z
  32.     while(1)  I0 I4 [4 A( _  v8 S* X
  33.     {' C( p3 Q# b, h: f3 `- S6 f) O8 ?
  34.                 if(CAN_Transmit(&g_CanTxPacket) != 0)) d- r9 [( X7 v# _+ r
  35.                         printf("failed\r\n");
    , e$ X; z  g, b& x9 e- i
  36.                 HAL_Delay(1000);4 B5 F* v% l) X+ W. A) D+ |! h
  37.     }
    ; |  j/ ]2 e5 b7 \# W: L
  38. }
    ) Y# |8 m" U' ?2 Z- M: c

  39.   v; u7 j4 _0 x3 ~4 L1 H
复制代码
! G$ m' v4 H6 z5 L, @0 R

, T' O+ @+ Y" G0 E( f( I
收藏 评论0 发布时间:2022-4-12 10:00

举报

0个回答

所属标签

相似分享

官网相关资源

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