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

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

[复制链接]
STMCU小助手 发布时间:2022-2-12 18:48
前言
/ O  o7 N3 T3 r# ?* W  u- mSTM32 NUCLEO 开发平台是 ST 最新发布的易用性好、可扩展性佳的低成本平台。开发平台具有 mbed 功能支持 Arduino 接口,同时还提供 ST Morpho 扩展排针,可连接微控制器的所有周边外设,可以利用 Arduino 巨大生态系统优势,便于快速实现STM32 学习和评估! 这儿我们评估它的 CAN 外设功能。
" U  K$ |9 h8 f& @- ?0 x5 R一、环境搭建% t. n2 y; I' ?7 B" ~
1、软件:
& v. v$ O: ~& KSTM32Cube\Repository\STM32Cube_FW_F1_V1.3.0\Projects\STM3210E_EVAL\Examples\CAN\CAN_Networking\EWARM
  x* e: h$ J/ x! T0 Z# u1 R2、硬件:
, `  y" f) V0 ?NUCLEO-F103RB(STM32F103RBT6); Z3 P, G+ `7 j  Z' }- y
3、原理图如下:
/ z, v! f4 x+ X# V' F8 g' {2 \7 a# n0 q4 C
ZZ]5XV{X7BN4S[QE9CA1F6G.png
2 F5 U8 X- O  k, q: a) L1 [( v! o8 p# N5 j
上面原理图是针对 SN65HVD230 的,- M2 x/ K8 U* ?/ ~
因为 PB8 是 CAN_TX,是 MCU 端的发送,需要到 CAN transfer 的输入引脚,即引脚 D(Driverinput);" p+ G6 |0 X! ]4 a/ \/ L
因为 PB9 是 CAN_RX,是 MCU 端的接收,是 CAN transfer 的输出引脚,即引脚 R(Recv output);
" |7 @$ c- L- s, A  z
" |8 h. H# W3 ~( o S)3(A{UFVJQQ0LKRP8PCBQ7.png
- U4 e6 p$ u: k6 N3 e: x" _9 b  |. B1 o
二、Porting9 l1 [: o9 S9 d8 V
由于参考的是 STM3210E_EVAL 的示例程序,在用到 STM32F103RBT6 的 Nucleo 板子上的时候,需要做一些 porting 的工
* N  v0 h) r2 v3 G作。" }- f+ s5 n6 \- R) s  z8 L
1、系统时钟
4 }+ C2 M. E  R; p* l) c/ a, F4 R1 J在 10E 的 EVAL 板子上,使用的是 HSE,而 Nucelo 上默认的是没有焊接 HSE,所以使用到的是 HIS;利用 CubeMX 生成代码:系统时钟为 36MHz;; \7 A0 e' _$ f1 I% R3 a
5 _/ }. K, ^* d" z
1A(AYMMZY%I4I11OE70N877.png   v+ I$ P$ D7 [0 q1 p4 ~
3 w+ N4 i# A# H. A$ R+ R3 y
供给 CAN 外设的时钟:是 APB1 的时钟 18MHz;" O: C: E: W5 ^
  1. void SystemClock_Config(void)
    / C# H2 D+ Y) d9 V: Q! I
  2. {5 t( y; Q" F) f6 o# \$ ~* p  t
  3. RCC_OscInitTypeDef RCC_OscInitStruct;
    ) S: d: ]- h0 O. l2 K- U& D
  4. RCC_ClkInitTypeDef RCC_ClkInitStruct;+ Q  R) Y, c' |# i5 R
  5. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;- H: A0 ?8 P& k; l! y- x+ h6 w/ l( _4 F
  6. RCC_OscInitStruct.HSIState = RCC_HSI_ON;% a$ p" f2 i9 }! b! c
  7. RCC_OscInitStruct.HSICalibrationValue = 16;
    - X8 l% w! v9 C! c$ T
  8. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;( T3 F" z, w: P2 R
  9. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
    / _1 v: \, Q# `0 I
  10. RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;% B5 ~4 d7 f9 p+ c2 L- ~! Y6 z: v/ n
  11. HAL_RCC_OscConfig(&RCC_OscInitStruct);
    ! |5 O/ H  s5 A6 o4 u# J
  12. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
    3 f8 ~9 R; I* |' `) u, g6 M2 K0 Y! v
  13. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;2 J* r' W" Q5 r& R. O
  14. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;3 m8 d8 s+ L8 I6 h% h9 l
  15. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;( g) y: n8 f0 w! ~/ a2 S
  16. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    . t. R- h& p1 l5 b( `& I8 A' u$ \
  17. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    2 V; w8 J. h3 Q( F, `! l2 h! @- R
  18. HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
    4 S) t/ \, i$ N
  19. HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);9 v8 a( x) _3 E  v3 S8 K$ _
  20. HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
    % m* }8 U  {. _7 a2 f5 K
  21. /* SysTick_IRQn interrupt configuration */
    ! f. F6 A# w1 O/ h: `4 r/ X+ B5 @
  22. HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
    # m& k/ W6 Z: i  {
  23. }
复制代码
2 V1 W7 g" a/ ^/ n* w
2、CAN 的接收/发送引脚
" R; m- o& g; _8 Y, F5 Q, C1 z7 ^仍然可以都为 PB8 (TX) 和 PB9 (RX) ,不需要改变;& {9 G& }: F+ g5 c4 T! @$ M: ?
3、CAN 的波特率
- M- A% x. i' N/ l; X& s(自己想设置的是 500K):) ]8 @* _- N  m  N# l5 l
" ]+ g3 b) I* u  d2 ~5 w
3%]@KA5XRL8X0)BS8]@V.png
; p( \4 j" ?( {( }: N6 [! F) u/ v
@FK:Z$RE2V`4FI06OUD(X.png . j- y3 V5 N% R3 _

9 v5 U9 `/ n6 ~( M8 |% m0 t6 {
  1. CanHandle.Init.Mode = CAN_MODE_NORMAL;" F* }. P/ F& {+ I- H5 D' a7 n
  2. CanHandle.Init.SJW = CAN_SJW_1TQ;
      e; B1 M) h( e2 U5 N5 X. q1 a
  3. CanHandle.Init.BS1 = CAN_BS1_3TQ; // TS1[3:0] + 1
    * T& e* I4 V: J8 i* t( I
  4. CanHandle.Init.BS2 = CAN_BS2_5TQ; // TS2[2:0] + 1
    & B8 |" X( p  d' y9 C1 i
  5. CanHandle.Init.Prescaler = 4; // BRP[9:0] + 17 \2 h0 \* r7 H, K) T
  6. CanHandle.Init.NART = ENABLE;
复制代码

- P1 g" t# u, H7 D3 h所以,理论上,根据计算公式,/ ~. b$ A$ b  {. \2 x" X
NominalBitTime = 1 × tq + tBS1 + tBS2 = (TS1[3:0] + 1 + TS2[2:0] + 1 + 1)* (BRP[9:0] + 1) x tPCLK;* C# ?5 V5 |# \/ Q
所以,NominalBitTime = 9* 4* tPCLK; = Freq(APB1)/36 = 18/36 = 0.5MHz = 500K;' X$ m6 C  {* i* z: n' m5 E
4、User 部分! R* C4 J; A$ }
程序中设计到:, w) @0 ~# d8 d5 {
  1. while (BSP_PB_GetState(BUTTON_KEY) != KEY_NOT_PRESSED)
复制代码
9 ?# P% q! h9 A4 b, F+ y
在 10E-EVAL 板子上,用到的是 PG.08,而在 nucleo 上使用到的是 PC.13
# _1 ]' V' ]$ e! x9 k3 [
  1. #if 0  ?% j- n9 D5 j$ f7 k9 T9 r. ~( \, U
  2. #define KEY_BUTTON_PIN GPIO_PIN_8 /* PG.08*/" ^- k6 i% _& f4 w
  3. #define KEY_BUTTON_GPIO_PORT GPIOG2 J1 V% _3 x, m' I
  4. #define KEY_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE()
    " D) G( D! {" y/ ?. W. y
  5. #define KEY_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOG_CLK_DISABLE()! \' }- D2 Y5 ~  _8 k7 M2 K
  6. #define KEY_BUTTON_EXTI_IRQn EXTI9_5_IRQn
      W  z" r5 B% C$ A. _
  7. #endif( z/ O$ y$ l1 r. ?9 ~% Z, B1 x
  8. #if 1. ~0 I6 K) k$ B6 h, }
  9. #define KEY_BUTTON_PIN GPIO_PIN_13 /* PC.13*/! X! }0 f) @2 |/ b( P
  10. #define KEY_BUTTON_GPIO_PORT GPIOC
    ' C6 p' J! ?% h6 T% h( d
  11. #define KEY_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
    + Y* U/ j: |. ?% s% j% y) T
  12. #define KEY_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE()2 a( r  s8 A, q/ V6 o, a
  13. #define KEY_BUTTON_EXTI_IRQn EXTI15_10_IRQn
    5 O  s7 V. ]1 ~8 F! J3 o7 p
  14. #endif
复制代码
; f6 }: F; H) _5 ?) |
RMDZ8MBAIQQD(NT`5EGYU.png
# Z5 {+ D6 o6 w- G6 L, X2 f' k! g" ^/ C" G5 [
至此,移植好了;
4 G. w& x( T6 ?2 V* f7 j8 S( D  @" g  P' K$ Q' U8 g
三、全速运行) w# k* S* z% g. ]7 w+ J5 g+ Y
1、按下 USER Button,会发出 CAN 报文,CAN 的 PC 端软件能够收到。
2 Z' M: t& `/ E; e
! L! @9 B# L# X- C, \% K SH[I_1~IWL[]C98HQ59CY8S.png
( K9 Z$ _( y. B# a# L' y
: S; i3 ?( t; Q  Y2 W2、CAN 的 PC 端软件发送报文,软件中的中断函数也会进入中断。5 y5 Y+ ~# A+ d

7 U5 A- o- x( O# h3 C0 n, l# k (3H6T$R@C`Q@~UH(_UCBE(O.png ) k- J6 v# a. z$ n' m% ~
& N1 N+ x8 {1 t: i+ {! s# c
说明,CAN 的发送和接收这一基本的操作已经完成了。对于 CAN 的复杂的运用特点,可以在该基础上进一步衍生。- r6 [8 d" i+ y) k3 T! _
附录:  I8 Z5 _6 P. u
1、针对现有的 CAN 的总线协议:在数据区域只有固定的 8Byte;也就是说一个 CAN 报文发送的数据只有 8 个,我们的单片机的寄存器也只提供了 8 个寄存器,符合当前的 CAN 的协议;如果客户想发送多个>8 的数据,需要在其上层协议中,用软件去多次发送。也许在下一代的 CAN 总线中,会对这一特点进行改变。
$ f) C7 a* g2 A, V9 j, n/ o3 E( U
6 p& l9 I0 O# M7 a9 x SDWPZ(GFX74NPP]IX$SB~SW.png
! A2 |0 t8 d' X8 ~$ }  y" C/ F2 ^+ A" B) h
2、CanHandle.Init.NART = ENABLE 的说明;  ~1 I1 y6 D8 s3 u  D9 A
在基于"STM32Cube_FW_F4_V1.10.0
/ v) d$ F3 {6 K  O0 _" O/ \\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。1 _4 x8 J9 q& e$ c' |" H% D

' H' p  G! e% s7 O. d* [, R
收藏 评论0 发布时间:2022-2-12 18:48

举报

0个回答

所属标签

相似技术帖

官网相关资源

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