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

【经验分享】STM32 基于 Nucleo 板 CAN 总线的建立

[复制链接]
STMCU小助手 发布时间:2022-2-12 18:48
前言
! P3 z" X: j1 y* |( JSTM32 NUCLEO 开发平台是 ST 最新发布的易用性好、可扩展性佳的低成本平台。开发平台具有 mbed 功能支持 Arduino 接口,同时还提供 ST Morpho 扩展排针,可连接微控制器的所有周边外设,可以利用 Arduino 巨大生态系统优势,便于快速实现STM32 学习和评估! 这儿我们评估它的 CAN 外设功能。! F, [  }% [8 S- M* {) z
一、环境搭建; W  [* r0 b5 Q' [& o2 j
1、软件:
9 }. {) ~: r6 `- E! sSTM32Cube\Repository\STM32Cube_FW_F1_V1.3.0\Projects\STM3210E_EVAL\Examples\CAN\CAN_Networking\EWARM! J2 f* Y6 ^" a5 j% ]* y' V! Y
2、硬件:' q$ u) c8 o, V) M. L9 P: ?' i
NUCLEO-F103RB(STM32F103RBT6)3 \4 I3 Q- k5 f
3、原理图如下:; y* H( J$ s, {  Z: i' k+ l9 P
7 {8 [. G7 \, A1 }
ZZ]5XV{X7BN4S[QE9CA1F6G.png , X& k. k3 X: P5 T& P
8 _+ O% V4 I  ?2 B- r: B
上面原理图是针对 SN65HVD230 的,. x4 r' |2 T9 R+ J
因为 PB8 是 CAN_TX,是 MCU 端的发送,需要到 CAN transfer 的输入引脚,即引脚 D(Driverinput);
8 N* L+ y& \, l0 a- \# A; {3 S3 t因为 PB9 是 CAN_RX,是 MCU 端的接收,是 CAN transfer 的输出引脚,即引脚 R(Recv output);3 p' A$ z# z7 z3 P/ y2 o8 c
9 W/ G/ N$ t/ n& @$ E& X/ R3 F9 X
S)3(A{UFVJQQ0LKRP8PCBQ7.png 8 t: u8 S8 J0 ]6 _; `) J  W3 _
' d8 j& k' J* V, g7 V( m
二、Porting
9 A' |  N0 c# L9 `7 S- H7 ?由于参考的是 STM3210E_EVAL 的示例程序,在用到 STM32F103RBT6 的 Nucleo 板子上的时候,需要做一些 porting 的工* y& ^# }, u) L1 h& @
作。* P2 b0 N8 k1 w/ D* y- H; v, O2 f
1、系统时钟  v) q& ~7 j- v7 n+ n1 J1 R& L
在 10E 的 EVAL 板子上,使用的是 HSE,而 Nucelo 上默认的是没有焊接 HSE,所以使用到的是 HIS;利用 CubeMX 生成代码:系统时钟为 36MHz;
  ]5 R0 r# K5 e
3 z- i$ [/ D# h) ] 1A(AYMMZY%I4I11OE70N877.png
, a' t  |+ A# d
! s/ ^1 w' z5 X* |3 ]4 l. K供给 CAN 外设的时钟:是 APB1 的时钟 18MHz;; ]6 Y: Q: e4 w# }7 ?6 L) Y
  1. void SystemClock_Config(void)& ^- q4 N. |- W+ e" [9 u& j" \
  2. {
    4 F& k& B4 i) ]& |
  3. RCC_OscInitTypeDef RCC_OscInitStruct;+ V7 p8 f5 ]) L/ C  M
  4. RCC_ClkInitTypeDef RCC_ClkInitStruct;
    4 F# r% }2 m1 U( L) Q
  5. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;* _- ]: h7 @. |: \; a
  6. RCC_OscInitStruct.HSIState = RCC_HSI_ON;1 L, E7 r0 Y! z" a
  7. RCC_OscInitStruct.HSICalibrationValue = 16;
    " t7 ?, E% `) c
  8. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;, V6 [2 n: m. N+ ~) h% Y% r
  9. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
    8 G2 F/ {6 Y: M/ A# }2 m
  10. RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;" q0 h" i# K; k: E6 q5 _
  11. HAL_RCC_OscConfig(&RCC_OscInitStruct);
    + `( b' F( O, H5 \- M' Y
  12. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
    ; M/ `3 U) v5 K, G
  13. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;2 v; I/ |( E+ Y+ {5 @
  14. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    7 I) }5 c! `& P0 R5 }
  15. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;/ C) _  z) E8 g0 }
  16. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    ( a' p( r4 [$ x( M) E$ u: I+ K
  17. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    . \% g0 u8 e  T. c! [! @
  18. HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
    7 J* l6 Q7 O. H( |' |
  19. HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);) E( B0 h$ r( f  S% v" ?
  20. HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);& |, R, [6 H' @3 x
  21. /* SysTick_IRQn interrupt configuration */; F+ f- J# Y+ p3 [3 X6 W- I& G
  22. HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
    ' d& D: Y4 b; T  }
  23. }
复制代码

8 T# l/ X+ }' _  [1 s- Y$ ]2、CAN 的接收/发送引脚/ ]6 t: J* l2 ?3 ^' T/ k9 _1 _
仍然可以都为 PB8 (TX) 和 PB9 (RX) ,不需要改变;
' v3 \& Y5 r3 ^: [" n! }3、CAN 的波特率# E8 y" z* B5 i2 j& |
(自己想设置的是 500K):
; k3 h, L/ k$ X+ o; p$ g0 C1 Z+ E2 U2 u- ^( ]; l
3%]@KA5XRL8X0)BS8]@V.png
. V* Q% ]( A. m( Q+ a( h) Q
, B3 o: D! L7 `0 s' C) R8 U @FK:Z$RE2V`4FI06OUD(X.png
* j9 R8 C: S$ K# r* x2 e
8 A! W3 J, X# {4 |
  1. CanHandle.Init.Mode = CAN_MODE_NORMAL;/ U* d3 \6 g! h) u& o
  2. CanHandle.Init.SJW = CAN_SJW_1TQ;
    ( G# I" G1 S! }( A
  3. CanHandle.Init.BS1 = CAN_BS1_3TQ; // TS1[3:0] + 1* G8 `4 C' r# X  ]0 E5 E; ]- x
  4. CanHandle.Init.BS2 = CAN_BS2_5TQ; // TS2[2:0] + 1
    & U+ p; u$ I  z! i1 a3 }( {
  5. CanHandle.Init.Prescaler = 4; // BRP[9:0] + 1$ c$ K2 i6 |6 E. l* ?
  6. CanHandle.Init.NART = ENABLE;
复制代码

9 ]! r9 t# y1 h/ r) o所以,理论上,根据计算公式,
3 T4 @. \8 ?; [) h: T; HNominalBitTime = 1 × tq + tBS1 + tBS2 = (TS1[3:0] + 1 + TS2[2:0] + 1 + 1)* (BRP[9:0] + 1) x tPCLK;
, f0 Y. z5 G+ M0 J" D( u/ _所以,NominalBitTime = 9* 4* tPCLK; = Freq(APB1)/36 = 18/36 = 0.5MHz = 500K;+ t) q  k3 Z" J4 U
4、User 部分
4 `/ _8 \- O2 }* K# N6 H3 [: z4 i程序中设计到:
. C$ X- }' E/ K& d, [9 g! \
  1. while (BSP_PB_GetState(BUTTON_KEY) != KEY_NOT_PRESSED)
复制代码

7 J& T# B- |6 |, B3 I在 10E-EVAL 板子上,用到的是 PG.08,而在 nucleo 上使用到的是 PC.13! @8 ?/ f7 D6 v0 }6 r! P( w
  1. #if 0
    2 {; l3 }# E  s/ n  S; S* O
  2. #define KEY_BUTTON_PIN GPIO_PIN_8 /* PG.08*/
    4 f+ O4 x9 f6 q
  3. #define KEY_BUTTON_GPIO_PORT GPIOG; G/ P7 v: N" `
  4. #define KEY_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE()
    6 M& A& \2 u' L4 {  X5 @
  5. #define KEY_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOG_CLK_DISABLE()
    6 A. q* u9 }' {) }& }( B
  6. #define KEY_BUTTON_EXTI_IRQn EXTI9_5_IRQn* V& _& Z% W  c6 h) P9 ?
  7. #endif) }' t. i) F: g$ H3 w" G4 g- Z5 P: r
  8. #if 1/ }+ `! D  t' M
  9. #define KEY_BUTTON_PIN GPIO_PIN_13 /* PC.13*/( N1 H! q4 \! {9 d: h, q, y
  10. #define KEY_BUTTON_GPIO_PORT GPIOC
    : q+ P  p' V5 p7 A6 d$ `
  11. #define KEY_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()0 R' i: m; E1 D6 m' k$ }
  12. #define KEY_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE()
    9 v7 X4 k. }) b& `8 T
  13. #define KEY_BUTTON_EXTI_IRQn EXTI15_10_IRQn
    & w) U7 J; O0 f0 N
  14. #endif
复制代码
5 \, k9 j9 L& r% b; y, [9 O
RMDZ8MBAIQQD(NT`5EGYU.png
" R: |, n/ ^! S6 z
4 O. H8 V) q6 ]至此,移植好了;
8 k* W! ~9 H& k$ B6 g2 Q+ P) D, ?! x
* @- G! r/ r/ A3 A( M  ~三、全速运行! G# M9 k' ]+ F  i1 K
1、按下 USER Button,会发出 CAN 报文,CAN 的 PC 端软件能够收到。
' I( q& d' G7 X0 I6 o& [5 b' C! M. A* K  d( e( @/ j: b' u
SH[I_1~IWL[]C98HQ59CY8S.png 6 |1 G/ u4 @9 ]9 L/ M- i

( c% c: L+ Q6 I% M( Z7 d6 a2、CAN 的 PC 端软件发送报文,软件中的中断函数也会进入中断。& ~# a2 A; `; P) V+ O/ F
; ]: W* a* m6 h8 m
(3H6T$R@C`Q@~UH(_UCBE(O.png
! Y! V7 j+ N7 n# p. O2 G. p/ W2 x: ~; ]( V  R6 S( o
说明,CAN 的发送和接收这一基本的操作已经完成了。对于 CAN 的复杂的运用特点,可以在该基础上进一步衍生。" J$ g6 @( j# l, I1 d; z0 `; M
附录:
/ a0 @1 O' n4 |; |* b5 l" p: m1、针对现有的 CAN 的总线协议:在数据区域只有固定的 8Byte;也就是说一个 CAN 报文发送的数据只有 8 个,我们的单片机的寄存器也只提供了 8 个寄存器,符合当前的 CAN 的协议;如果客户想发送多个>8 的数据,需要在其上层协议中,用软件去多次发送。也许在下一代的 CAN 总线中,会对这一特点进行改变。* T+ L/ \* \! k; B0 D) j4 @2 s8 X

7 G- a' _& _4 h7 v* \9 c SDWPZ(GFX74NPP]IX$SB~SW.png
- x/ ^" D# N# Z; _( g. B
  |, v- Y/ L" Q" x1 X7 k* T2、CanHandle.Init.NART = ENABLE 的说明;
1 E' m  Y$ {; s  U在基于"STM32Cube_FW_F4_V1.10.0
' W6 N& j) }) A! Z! B\Projects\STM324x9I_EVAL\Examples\CAN\CAN_Networking" , 如果只用一块 STM32F429-EVAL 调用HAL_CAN_Transmit()的发送函数,会发现 CAN Controller 会不断的发送数据, 这是因为在我们提供的示例中,是需要两块板子互联的,在 CAN 协议中,如果消息没有被正确的接收,它将会 be retransmitted infinitely by the transmitter until it will be acknowledged by the receiver ,而正我们的环境中,只有一块板子,而没有 receiver。6 ^3 C$ a. s( B# w7 E

% J# h9 m; l5 {& `7 J
赞 收藏 评论0 发布时间:2022-2-12 18:48

举报

0个回答

所属标签

相似技术帖

官网相关资源

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