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

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

[复制链接]
STMCU小助手 发布时间:2022-4-12 10:00
配置CAN$ z& }' ]; W3 e0 ~
先了解几个关键词简称:
& r$ a$ _8 q& I

( f. g! Y' |; u- E6 q+ f最小时间单位(Tq,Time Quantum)2 }. Z  i. E5 d! J# b! p
同步段(SS,Synchronization Segment)1tq7 P& V+ j/ z' o: z" \
传播时间段(PTS,Propagation Time Segment)1~8tq0 |: M+ q. G( H1 c
相位缓冲段1(PBS1,Phase Buffer Segment1)1~8tq
' _0 e6 Y! [4 Y1 k4 e. `, [8 F相位缓冲段2(PBS2,Phase Buffer Segment2)2~8tq. s- r2 \$ Q( v; _0 `
再同步补偿宽度(SJW,reSynchronization Jump Width)1~4tq
& g# b7 _1 ?" J# c0 y7 [+ R* P" U波特率分频器(BRP,Baud Rate Prescaler)
2 s( T* d: t0 ^STM32把传播时间段(PTS)和相位缓冲段1(PBS1)合并了,形成了时间段1(TS1)。' O4 \5 e/ G8 [2 ^. j

  r; ]: R. s- ?/ \0 Y8 FCAN位时序寄存器(CAN_BTR)用于设置TS1、TS2、BRP、SJW等参数,这些参数直接决定CAN的波特率。
. _5 K2 z: w; R8 r* r, Z: Y4 N9 T1 @
@RPJH23%IDIX8DXXKZZF4R7.png 0 k) s2 |$ g( U- y
( F* @* F4 @5 l2 {3 [2 z
SJW[1:0]再同步补偿宽度+ M  U* i. Y" x. W) G- M0 T9 E0 J
+ m( g2 K6 K9 V5 ^
TS1[3:0]时间段1
2 o8 {& u' S! s* z3 h- G$ I) I  q0 q+ @" @4 R7 y
TS2[2:0]时间段2
9 r) n) W' l& C1 w8 B; H; R0 I6 k
$ P" i6 b* A! V; zBRP[9:0]波特率分频器
. y  b" U$ C9 l* Z% X
$ ]& ?) M( C1 O4 ?; s可以看到没有同步段(SS段),这是因为STM32已经将SS段固化为1。
! z* d8 F6 f% Y' z8 n6 q* C& F, d& h8 A# Y- s  L
除去这几个参数,还需要设置分频,STM32F1系列一般是跑到72M主频,CAN是挂在36M的APB1时钟上,设置CAN的分频就是分的这个36M。
& l& m2 R% {9 }! J; f8 s1 X% I* m4 O. [, J- F: k8 l9 c
下面这张图是波特率计算公式:) V' W2 c# O  ]5 z0 A$ `6 \% R

" R( \5 ?0 K4 }7 z  v# ] 4f9a0ef7766841fc8671353d8cb869fe.png 4 S" s- }4 y5 o% b
9 B) W6 M% e0 O$ C+ M
整合一下波特率计算公式就是这样的:6 c( |0 h: @, z. x' F% P
. R" D- p- _0 e8 W5 Y) |, a5 {
波特率 = APB1 / [(1 + (TS1+1) + (TS2+1)) * (BRP+1)]: ^% V; `) r' q5 j0 r
  L5 T/ p  P" _+ `
在简化就是:波特率 = 时钟主频 / 分频 / (tq1 + tq2 + ss)
0 F/ E# V/ K" U. S1 i
7 }8 X% \( Q2 X( _) p1 i其中SS就是同步段,已经恒为1,所以:波特率 = 时钟主频 / 分频 / (tq1 + tq2 + 1)! B5 D1 D# C. V
- l  k8 c4 U( h4 \4 t
下面我们开始实际设置波特率,这里要注意,CAN的波特率最大为1Mbps。
) I: o, h4 O8 r* b8 E( l9 N" A) f; f2 i/ ~5 ~$ E+ y4 \- Q4 F
stm32f103的CAN的时钟主频是36M,分9频就是4M,设置tq1=5,tq2=2,ss恒等于1,那么:波特率 = 36MHz / 9分频 /(5 + 2 + 1) = 500KHz
0 ]) w* r, |( N6 `& @, }. ~7 \' j$ A! @& a1 v
另外还有一向是:再同步补偿宽度(reSynchronization Jump Width) 这个参数,其实就是一个由数个Tq组成的一个段,用来对同步误差进行补偿,可以简单理解为为了提高精准度的,例如两个CAN进行通讯时由于两个板子的晶振可能存在误差从而导致CAN的波特率没有500K那么精准,所以就需要设置一个补偿参数去修正,这个参数就需要根据你实际的板子情况去调整了。
! ^/ N: Z3 x+ ]9 D
# h) Z% M$ K" W: o- X5 X, t2 k注意:stm32cubemx生成的CAN代码是不带过滤器的,需要自己手动添加。+ c8 D. D9 V9 M" H8 k- ]' e

- \- r+ i) t% D- T$ w XG3}YF2)VM[)56]LWKNMZE4.png
, W8 P  f% J$ p  p& X
5 y8 H$ X$ V# _: _  H, t 0O(JT%S7YRV7H$)3`V~R.png
6 `7 p8 r' c" _% n- J( |+ N- E# T- ^9 x) v
代码修改. |/ Y: _6 W; ^1 g6 b' C
STM32CUBEMX生成的CAN配置代码是没有过滤器设置的,需要手动添加。" B; K8 V4 q/ N6 s5 s  ^% V5 e

. u  i) v: D" G' T: v0 A
  1. typedef struct) |3 Q0 h2 @: S  N4 V. `; w
  2. {1 N0 U( o! w  n' {
  3.         uint32_t mailbox;! T7 M! V) k* F1 z+ B  k5 G" ^
  4.         CAN_TxHeaderTypeDef hdr;( F& ]! e" O3 f% J. |: E: Q
  5.         uint8_t payload[8];- q  |( O" d5 `% \, m) o
  6. }CAN_TxPacketTypeDef;5 Z! P  x1 m  |8 f& \) W! J
  7. & s( f# @  l  p& x9 R$ _; h& \
  8. typedef struct
    ; M$ g% o, S6 b3 R; u: `
  9. {9 N, J& p. S: S4 d- D: h
  10.         CAN_RxHeaderTypeDef hdr;# I' |* P  n2 I1 _! _; O
  11.         uint8_t payload[8];
    0 ?# N2 ]- \5 g, U7 A0 w  S4 ~
  12. }CAN_RxPacketTypeDef;
复制代码
  1. /// CAN过滤器寄存器位宽类型定义
    ) g. T* P" U6 y7 Z0 W( I
  2. typedef union1 W! }! l* C6 J  d1 I4 Z
  3. {
    1 B" R2 y/ |: _/ m
  4.     __IO uint32_t value;
    4 T! M" q8 e3 W4 {! F0 ?
  5.     struct
    % v0 A7 |( s8 Z% ]" e
  6.     {  V' U: m2 Y5 N# A' S, \( e! a' _
  7.         uint8_t REV : 1;                        ///< [0]    :未使用& N3 O- ^# W- w( G# r
  8.         uint8_t RTR : 1;                        ///< [1]    : RTR(数据帧或远程帧标志位)
    , X) I; P' i4 L# S. e& s  q4 V1 _
  9.         uint8_t IDE : 1;                        ///< [2]    : IDE(标准帧或扩展帧标志位)
    9 O; B1 c/ R  n, s% x1 F  T
  10.         uint32_t EXID : 18;                        ///< [21:3] : 存放扩展帧ID
    0 E5 c( X$ D8 _4 s+ A$ O
  11.         uint16_t STID : 11;                        ///< [31:22]: 存放标准帧ID
    4 d" g: a6 j9 K# y
  12.     } Sub;6 s1 q! }1 a) O! R  Y
  13. } CAN_FilterRegTypeDef;- m0 I& n; s0 F% e4 w

  14. 4 T( }* y/ s) ~  v4 o8 J

  15. . }. {3 Y4 ?3 c' I& G* z5 g8 l, O
  16. #define CAN_BASE_ID 0                                                ///< CAN标准ID,最大11位,也就是0x7FF' L4 N9 j1 g, X( t- H
  17. $ f/ Q4 X& b0 w9 w5 j
  18. #define CAN_FILTER_MODE_MASK_ENABLE 1                ///< CAN过滤器模式选择:=0:列表模式  =1:屏蔽模式
    7 }/ f  N6 y( z9 s
  19. + P3 q' s; o+ D" `0 a) U
  20. #define CAN_ID_TYPE_STD_ENABLE      1       ///< CAN过滤ID类型选择:=1:标准ID,=0:扩展ID0 Z& C0 P) l5 b  _7 z
  21. 1 V7 g* a+ q/ p' o/ `% Z2 K
  22. void CAN_Filter_Config(void)* h+ _+ d4 d0 ]& g1 `
  23. {
      R5 N( A3 w/ ?
  24.     CAN_FilterTypeDef sFilterConfig;
      L% i/ r+ X8 L+ @( P
  25.     CAN_FilterRegTypeDef IDH = {0};
    7 l) l' I/ ~) p0 M/ U) @+ n2 G
  26.     CAN_FilterRegTypeDef IDL = {0};0 I+ j! G$ G% T9 l
  27. ; B9 ]+ q" x  w* _
  28. #if CAN_ID_TYPE_STD_ENABLE/ i" t- i# F8 Q4 Y, W" m4 M
  29.     IDH.Sub.STID = (CAN_BASE_ID >> 16) & 0xFFFF;                // 标准ID高16位
    ( G6 H. E9 z8 J; u: x* V
  30.     IDL.Sub.STID = (CAN_BASE_ID & 0xFFFF);                                // 标准ID低16位! N$ T+ `2 U0 I: [
  31. #else5 z! b1 J8 [& Q# y8 y# d
  32.     IDH.Sub.EXID = (CAN_BASE_ID >> 16) & 0xFFFF;                // 扩展ID高16位
    ! k6 U9 ~6 e3 e8 h2 E
  33.     IDL.Sub.EXID = (CAN_BASE_ID & 0xFFFF);                                // 扩展ID低16位
    " [9 ^8 N! o$ {- |0 S* J
  34.     IDL.Sub.IDE  = 1;                                                                        // 扩展帧标志位置位6 E! `7 e* _  P1 |( ?* G5 C
  35. #endif
    6 B0 a, o- |1 C( I- d
  36.     sFilterConfig.FilterBank           = 0;                                                                                                // 设置过滤器组编号2 n6 _9 O4 t; J8 P3 q
  37. #if CAN_FILTER_MODE_MASK_ENABLE+ R, X0 {7 v+ ~! L9 X. P1 M3 x2 m
  38.     sFilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;                                                        // 屏蔽位模式/ N- Y. N: I) y- h2 ~  g* g) |
  39. #else
    ! o/ N5 f7 }0 n" t' ?5 h
  40.     sFilterConfig.FilterMode           = CAN_FILTERMODE_IDLIST;                                                        // 列表模式
    - W+ a( X0 G4 `# I, P
  41. #endif
    . p* `4 Q  ?; C' F7 }5 T
  42.     sFilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;                                                        // 32位宽
    " v; ?8 p4 q0 i3 z5 G/ x
  43.     sFilterConfig.FilterIdHigh         = IDH.value;                                                                                // 标识符寄存器一ID高十六位,放入扩展帧位
    7 s: \) H5 U9 y# V- l4 Z9 U# Q  n
  44.     sFilterConfig.FilterIdLow          = IDL.value;                                                                                // 标识符寄存器一ID低十六位,放入扩展帧位+ ^' Q- g1 x4 @; P$ }% W
  45.     sFilterConfig.FilterMaskIdHigh     = IDH.value;                                                                                // 标识符寄存器二ID高十六位,放入扩展帧位) M) J$ Y; v# b- b
  46.     sFilterConfig.FilterMaskIdLow      = IDL.value;                                                                                // 标识符寄存器二ID低十六位,放入扩展帧位
    % _5 S& f! Q/ R1 d8 y
  47.     sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;                                                                        // 过滤器组关联到FIFO04 `% e# O% s! H% U4 E4 h3 {* }. W
  48.     sFilterConfig.FilterActivation     = ENABLE;                                                                                // 激活过滤器& T; d* u% V/ c) U! y1 W4 O) g* P6 [
  49.     sFilterConfig.SlaveStartFilterBank = 14;                                                                                        // 设置从CAN的起始过滤器编号,本单片机只有一个CAN,顾此参数无效
    0 J1 }# o* ]- Q# A& r% _' g/ Z, n
  50.     if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
    ( ?/ r  c/ N5 y& u! e+ j
  51.     {; [' Z0 _: Y& V+ |0 h$ x! A4 r( H
  52.         Error_Handler();
    9 R$ g  i  U7 Z
  53.     }
    2 Y/ s- H/ c8 _' {# u% d
  54. }' T( C0 Y  F- X' A4 z$ N

  55. 2 K% J2 _, j0 N( @
  56. uint8_t CAN_Transmit(CAN_TxPacketTypeDef* packet)2 V& N3 p: P( y
  57. {
    * q( U; [8 T- ]- [
  58.         if(HAL_CAN_AddTxMessage(&hcan, &packet->hdr, packet->payload, &packet->mailbox) != HAL_OK)3 |3 D0 I+ [) e! N2 Q* v# ]
  59.                 return 1;  D( j4 x. x% B  f! P  u* c# u
  60.         return 0;4 L  [, ~6 m! l) P3 I7 \2 V: p
  61. }
    # X, x  l& u: ~* Y. `+ Y# z$ b
  62. $ u3 W4 ?. q0 c* ?. I2 t
  63. void CAN_Init(void)
    & m! J+ O, q  w  v0 u  `
  64. {
    6 b2 g: a. g. V4 T
  65.     MX_CAN_Init();
    % V1 j+ r7 ^3 G% `1 H
  66.     CAN_Filter_Config();/ G- w8 ~& g8 L  Q
  67.     HAL_CAN_Start(&hcan);& Z+ k; i0 A- C
  68.     HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);                                        // 使能CAN接收中断# t9 B  k4 v3 m2 a1 ^
  69. }% x& i  X9 G+ `, j
  70. 6 i6 B; w8 ~9 C: i: w
  71. void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *canHandle)
    ' Z$ a$ B$ @% k; I- B" ]/ r
  72. {
    8 B/ H2 X+ T/ }- g* n- J, o
  73.         static CAN_RxPacketTypeDef packet;
    9 O, ~- }# L8 z  b8 q8 h4 d
  74.         ; Q: N6 r' x2 `! b$ m0 _
  75.     // CAN数据接收2 k3 b9 U, X0 T2 ?& n3 w% X
  76.     if (canHandle->Instance == hcan.Instance); p2 i$ X8 a- U; [% `7 i) h
  77.     {
    * e% W% |+ e8 B0 T+ \/ y
  78.         if (HAL_CAN_GetRxMessage(canHandle, CAN_RX_FIFO0, &packet.hdr, packet.payload) == HAL_OK)                // 获得接收到的数据头和数据! i8 B  s' s2 P! F& j( f+ A
  79.         {# r; _, t: J9 A, }  C! w3 W
  80.                         printf("\r\n\r\n\r\n################### CAN RECV ###################\r\n");% t+ d$ d+ M; N: D+ Q2 H
  81.                         printf("STID:0x%X\r\n",packet.hdr.StdId);+ |) ]/ _. G! H/ D! A
  82.                         printf("EXID:0x%X\r\n",packet.hdr.ExtId);
    ' @$ E: Z( O: {6 N* T: C
  83.                         printf("DLC :%d\r\n", packet.hdr.DLC);
    * x- ~, N1 y# p# N8 H% q+ z9 t
  84.                         printf("DATA:");
    9 b3 X& J$ x2 C
  85.                         for(int i = 0; i < packet.hdr.DLC; i++)# w) ~# q& O3 i* n" H
  86.                         {
    " l7 v/ x0 Z* c
  87.                                 printf("0x%02X ", packet.payload<i>);: P& ]% }  t# r9 T
  88.                         }
    ' D7 H' H3 X* n( k
  89.            HAL_CAN_ActivateNotification(canHandle, CAN_IT_RX_FIFO0_MSG_PENDING);                                                // 再次使能FIFO0接收中断
    # {. y( V# z/ c4 X: D, X4 ^
  90.         }# o7 j; j' H; ?1 I
  91.     }
    8 G9 O6 c7 x4 n4 o2 R1 Q. V2 U
  92. }</i>
复制代码
  1. 6 i1 f' v3 o4 z$ k6 D. ^
  2. CAN_TxPacketTypeDef g_CanTxPacket;
    3 a/ q5 r2 }, Q
  3. : a  f2 r- p" x2 s
  4. void CAN_SetTxPacket(void)9 ~  R0 {/ }, i1 E
  5. {
    % s( n* I+ Y2 ^+ [& V; e
  6.         g_CanTxPacket.hdr.StdId = 0x321;                        // 标准ID
    $ Q# N" X! Z& S+ A& X& [
  7. //        g_CanTxPacket.hdr.ExtId = 0x10F01234;                // 扩展ID' |. y; m; J7 i$ c
  8.         g_CanTxPacket.hdr.IDE = CAN_ID_STD;                        // 标准ID类型
    4 x# I  W9 P% r, D* `: i9 R
  9. //        g_CanTxPacket.hdr.IDE = CAN_ID_EXT;                        // 扩展ID类型
    ; E! O; h6 e+ T* c  G0 Y; x
  10.         g_CanTxPacket.hdr.DLC = 8;                                        // 数据长度
    - `+ v- I' Q# q. g+ z& ~! W% F
  11.         g_CanTxPacket.hdr.RTR = CAN_RTR_DATA;                // 数据帧
    ; T: e+ H% i! `  ^; g$ J9 q8 l
  12. //        g_CanTxPacket.hdr.RTR = CAN_RTR_REMOTE;                // 远程帧8 b8 r# D7 `, O; k& c# u# \, \( Y
  13.         g_CanTxPacket.hdr.TransmitGlobalTime = DISABLE;
    / ?0 `# x4 n/ Q) B
  14.         
    ) E, W9 P- I( l* ]; o# y3 E4 Y
  15.         for(int i = 0; i < 8; i++)4 o/ w2 J: V# o
  16.         {
    5 x4 c2 W0 T% o; i9 l, l
  17.                 g_CanTxPacket.payload<i> = i;9 n/ x) S, W2 N9 X0 V+ t2 D, t
  18.         }
    : G( b9 R! ~5 l% p+ ~. Z
  19. }
    1 Z$ j/ h* t7 F6 a5 o/ P

  20. # L' }1 M# J9 [: G( [' ^. h
  21. int main()* A) K. T0 U- h
  22. {
    # o7 v8 h, J( w8 L& K  f6 N5 s
  23.     HAL_Init();
    1 Z4 d# a5 N1 R' Y6 j1 n2 W
  24.     SystemClock_Config();( i7 T2 c6 s1 S9 H
  25.     MX_GPIO_Init();
    8 h4 S  d6 ^6 }7 e' S" ]  ]+ S
  26.     MX_USART1_UART_Init();
    5 \- ^7 P8 h' x; L+ B. v
  27.     CAN_Init();+ U* ?- _! L0 y0 Y- t+ F! X' T
  28.         printf("----------------------------------------\r\n");. N& v- }9 T3 r; k+ K

  29. 9 ^. q6 h# v$ g; k
  30.         CAN_SetTxPacket();
    , e6 u. |: s) g$ _* l/ C
  31.           d+ \% @+ a1 o, l2 [/ {
  32.     while(1)
    $ n" l+ M% }4 X' e. [0 G
  33.     {" x- @. B1 }6 n8 A! K
  34.                 if(CAN_Transmit(&g_CanTxPacket) != 0)
    7 g9 L" K6 y$ W. x5 C
  35.                         printf("failed\r\n");& A9 C2 C$ d6 [' \/ R" U* _
  36.                 HAL_Delay(1000);8 F9 E3 v- |+ q
  37.     }0 j1 m/ Y# y( g1 E. _% E
  38. }
    4 }+ I7 a2 o& ?

  39. $ e- ?" x  `: S3 ^7 t
复制代码
! g4 O7 z, X! o& r) I7 B# }( y

$ ?% O6 v# B* i9 q, g
赞 收藏 评论0 发布时间:2022-4-12 10:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版