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

【经验分享】STM32 HAL库移植FreeModbus详细步骤

[复制链接]
STMCU小助手 发布时间:2022-4-10 22:53
modbus命令码表:$ g& r1 j/ q( K: C# z/ Q0 f/ _

9 ?! {0 D7 [$ H$ h6 t8 e
b8032deb4d154657acd2f7f2942369d4.jpg 6 J+ u; H  j) I& N

! F9 N* d0 O  ]$ u3 E' [" GFreeModbus文件说明

& y3 k* v+ @$ z* j% z& j# t9 j      解压freemodbus文件后打开,我们需要demo目录下的BARE,该目录下的代码是空的,STM32移植工作基本就是修改:portserial.c、porttimer.c、port.h这三个文件。9 }! n- |5 F7 d4 I8 [
20200313143257958.png
1 l; {+ W/ r* @# a3 N
; q. D# V( P( O6 [      mobus文件夹就是完整的源码,包含rtu、ascii、tcp:
- X; ?$ K' k) u$ P8 h
0 a1 }! s8 d& J ZM%DLXPRB8$%[NN2%4Z1N.png
6 o  c* k" M  Z& k2 k  h5 t& @, y7 C8 [. T
      我为了移植时在keil添加源文件和头文件方便,就把modbus所有的头文件和源文件放到了一个文件夹下,并创建了一个port.c文件,用于编写modbus所必需的回调处理函数:
; B8 v2 T( b' y/ f# K: `. |. X) L: a: d4 o$ I0 @# r% U2 ]
20200313144036579.png
8 c$ X$ ]4 z6 K2 N% P! y! n  i, ?9 N% v) M( W& y0 N: s8 D
STM32CUBEMX配置

2 n' i( e# S. R0 A4 j时钟配置,设置主频工作在72MHz下:

' A% M- k, t% q4 `- D4 y# |2 P* Q* _, d9 k
JU1~N33M}I7K1(6K@JFN5~R.png 3 F5 q# j  v( _- q0 @

8 W5 }2 }8 J1 L; s配置串口1,这里随便配置就行,在modbus移植过程中还会对串口重新初始化:

$ w: t$ B0 {- T( s, m+ K- q. q5 o3 }7 P, k
U25OQ_FHYD5WEXLFMI4V@RU.png 8 Z" \6 n/ }, z! W9 \, Q
2 E' c) b" p$ H: G( I: J6 r
配置定时器4,用于3.5个字符的定时检测,这里随便配置就行,在modbus移植过程中还会对定时器重新初始化:

* V! f) O1 B$ b4 i7 [/ @" ?
9 p0 e$ N" q8 } H6{)WT`**CIHDAM02558GK.png 1 ~6 M4 l8 M! }
0 b( _3 [1 v6 O) |
中断配置,这里注意,串口的优先级是要比定时器优先高的:

' J5 V1 g8 z; n1 ~" y, M7 l. o0 N) h% O  }
G(RP`74TR)NPJFUK``Z%I2L.png 1 F& L% o' R, f- c! i8 j2 x% z: n3 e
取消掉自动生成中断服务程序,在移植过程中我们要自己编写串口和定时器的中断服务程序:
( F4 L! H& R8 y# C' y. G/ H. [3 n5 P& C) e8 l
ALHMK5Y615K6(`M{0[]YJ.png , ]6 c8 }3 q( K+ X& v4 f

0 ]) t, [" p. @移植代码修改

1 u! A: Y1 ?8 P, b$ U生成代码后将modbus放到工程目录下:: ?9 r' c5 G4 R( A) i$ Y

' w# S9 |; ~) b: Q5 _) m
5%(_LMGIM_8_YGL`]JGAB67.png 3 T" o7 V" B% K# B
) u, N, |/ `. O3 i1 a( J
打开keil工程添加modbus源码:

4 f0 l: {  C5 N1 |  V( }8 V9 f$ x* S6 M) a
F`8_YFACMNOAP28~2VHD{CO.png
1 Y. \3 v3 g! j7 [+ [) m  C3 x
, _+ A7 {0 A& A+ X$ e  X: e添加包含头文件:
, B1 W6 E  I, r; I( r

/ W0 c3 N: y4 r9 j  X" T `7BMVXA`R9SQBTGT`B@{]X7.png
/ Y9 b1 W( m; Z9 @, n' c% K3 g$ i/ j' o
修改modbus定时器初始化源代码porttimer.c文件9 i' N5 E3 k  z
       定时器的修改比较容易,将定时器设置为每50us的时长记一个数,传入的usTim1Timerout50us变量给自动装载即可,prvvTIMERExpiredISR函数需要在定时器中断服务函数中调用,它的作用是用于通知modbus协议栈3.5个字符的等待时间已经到达;由于我们在STM32CUBEMX中取消掉了定时器和串口的中断服务函数程序,所以我们在该文件中添加定时器的中断服务程序,修改后的代码如下:
" B  ~1 X1 p! a0 q2 H$ K
  b4 X  X& d5 q' L( w' z- l/ j# h3 T8 \
  1. BOOL+ V3 v& B# S9 m6 f9 |1 _1 U
  2. xMBPortTimersInit( USHORT usTim1Timerout50us )& @3 D  ~) d! L. f% ~
  3. {
    ! c5 ~+ x2 n* R$ I5 {# S- a1 k7 w/ L
  4.     TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    " M7 o; e" s! t8 o
  5.     TIM_MasterConfigTypeDef sMasterConfig = {0};
    % r8 `$ F3 T5 i
  6. - ?( t) O" j6 H, d0 E, D
  7.     htim4.Instance = TIM4;) e+ e0 ]6 M* n( F6 c
  8.     htim4.Init.Prescaler = 3599;                                                                // 50us记一次数( g2 N! {$ b, `* G, `, Y
  9.     htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
    7 Z: [. ]; O. _; H# u) b3 J
  10.     htim4.Init.Period = usTim1Timerout50us - 1;                                        // usTim1Timerout50us * 50即为定时器溢出时间
    ' y! S7 {1 A+ ]' O9 T5 f8 \  A
  11.     htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;7 C: c, D% a8 k7 V1 E4 Y
  12.     htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    , y; ?. q9 W! i: j! m5 m  e
  13.     if (HAL_TIM_Base_Init(&htim4) != HAL_OK): P$ x% Y$ f9 {7 W* T+ f
  14.     {
    4 l( O- [9 F$ M) r  I
  15.         return FALSE;* T9 Y, E) d" l) `9 K
  16.     }: ^6 f& V8 b  i( Q, O: ~- |8 N
  17.     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;- L0 ^3 H! X7 j2 ]1 i
  18.     if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)' t. I1 U) j& Z7 y* c
  19.     {
    . k% ?5 R2 K4 ?) N7 |( b
  20.         return FALSE;
    $ m" c$ J/ h# M" |9 m; s) _
  21.     }
    + D+ p3 R7 T2 p+ i/ @
  22.     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    2 h- X6 N  r0 f/ I: D. }
  23.     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    1 j* i, e$ u) {7 o+ d! i
  24.     if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
    3 n9 ]- [$ I$ l
  25.     {3 b4 l5 H" j/ G' R) ]
  26.         return FALSE;% C# F. R( f, l4 x- T( ^
  27.     }
    % ?; W# u. U: w/ k, z# y7 Z/ \
  28. ) p" O3 ^, p, P6 R8 c2 G
  29.     __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE);                                        // 使能定时器更新中断
    9 Z9 X, e5 ?& l- \0 [9 l- Z. L1 A
  30.     return TRUE;
    ; R7 ]. X4 z1 m1 @
  31. }
    - M( o+ h" y3 B' I

  32. 0 B6 u1 ^5 w# F
  33. inline void' X% Z5 ^% m2 ^, A% [, j
  34. vMBPortTimersEnable(  )
    3 V! k, I& k+ O+ p5 W  m) F
  35. {
    & i! X. }6 m- R3 J
  36.     __HAL_TIM_SET_COUNTER(&htim4, 0);                // 清空计数器4 f. m9 w" S0 K; e+ l
  37.     __HAL_TIM_ENABLE(&htim4);                                // 使能定时器
    . g5 w3 x6 D9 ]% u/ `
  38. }
    2 `% U) u  Q5 y' d, n: U
  39. ; a; @/ y. x3 x' M4 ^
  40. inline void. a4 y8 A+ y( |( l; |
  41. vMBPortTimersDisable(  )
    4 U+ _' j0 N* k' x; L, V8 C
  42. {
      F2 E8 H. X+ @9 M' J8 q1 y
  43.     __HAL_TIM_DISABLE(&htim4);                                // 禁能定时器
    ) z3 z5 H/ T( X. k9 v( L0 v
  44. }
    3 q4 @- e6 ]: l; m, j  L# d- e% C

  45. 2 D* }# v" O) H0 S
  46. /* Create an ISR which is called whenever the timer has expired. This function$ M$ \( G; w2 v. E( Y8 U
  47. * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that8 U" i8 U& l8 Q3 X
  48. * the timer has expired.
    . v; ?9 ]8 x( Y! l( [
  49. */4 i, Y8 \0 t5 P% q  K5 G
  50. static void prvvTIMERExpiredISR( void )
    9 W( ~7 [* o* P+ \- i# E' y% l
  51. {
    2 `1 N- y6 e! p
  52.     ( void )pxMBPortCBTimerExpired(  );- y6 x& h# r8 J8 y0 h
  53. }7 m/ Z6 o  q! J1 K
  54. 5 b$ r: m/ L0 I6 ?
  55. /// 定时器4中断服务程序
      D; Z5 t' F6 E/ `6 e  O
  56. void TIM4_IRQHandler(void)
    6 b3 L( B+ D- C. f: Y" X% b  x
  57. {- j, I* e9 P6 |/ }. `
  58.     if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE))                        // 更新中断标记被置位/ i) B2 ?* K; p" v; P; m1 B
  59.     {; j- G4 \7 {* Q9 a; k/ [" P
  60.         __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE);                // 清除中断标记
    7 a' ^& f9 q2 o2 \# H9 D1 ~
  61.         prvvTIMERExpiredISR();                                                                // 通知modbus3.5个字符等待时间到4 W, B9 H- D6 x
  62.     }3 E( t( @# O$ j; P# R
  63. }2 C. z* M2 v/ A2 t

  64. + ]! P$ v8 b; |0 m$ q0 e8 D% h

  65. ! z& z6 R4 L( X
复制代码
: J2 x" d( \1 i1 |
修改modbus串口初始化源代码portserial.c文件6 H' R9 l3 T. H1 W; |% r3 }9 [* G+ H
         ~~~~~~~~        在该文件中实现串口1的中断服务程序,prvvUARTTxReadyISR和prvvUARTRxISR函数需要填写进中断服务程序,前者得到作用为通知modbus协议栈串口已经空闲可以发送数据了,后者的作用为通知modbus串口1有数据到达,修改后的代码如下:+ }; Y# p- t% J! X9 W

6 _5 N% w+ A; @; S4 u' H
  1. /*
    - G' E) B# Q+ R" P. K1 l& e* w
  2. * FreeModbus Libary: BARE Port2 v) U9 c' \6 L" C
  3. * Copyright (C) 2006 Christian Walter <<a href="mailto:wolti@sil.at">wolti@sil.at</a>>, H+ [# ?9 O/ _" L4 D/ ]. K  J# G
  4. *. G/ }) a# v, O0 N1 _
  5. * This library is free software; you can redistribute it and/or
    ( q: A8 ]0 e/ t$ z$ {' b+ Y6 h
  6. * modify it under the terms of the GNU Lesser General Public
    + Z, D" _) }6 u0 v5 ~9 i
  7. * License as published by the Free Software Foundation; either: q' p6 }. j! m/ P
  8. * version 2.1 of the License, or (at your option) any later version.
    ! ?/ S1 K! |* D0 X5 y; l  Z. u; {9 I
  9. *
    ) X* E# g7 l3 o# p" O* }; Q7 O
  10. * This library is distributed in the hope that it will be useful,
    , O9 x" Z; P* U$ }
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
    ' W  d" o. W+ _
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1 l; {6 K9 P: c* n5 j4 Q
  13. * Lesser General Public License for more details.
    0 C' J! @8 s5 m! t  |. c0 _
  14. *
    0 h% t$ f% X; J" z+ f
  15. * You should have received a copy of the GNU Lesser General Public! V7 e- p( E: u/ M) j
  16. * License along with this library; if not, write to the Free Software
    % }& d0 U# X. L8 u. ?
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    6 }. E  C4 |' S3 R6 s6 b
  18. *
    0 _9 |3 ?. z3 x+ U  U9 [
  19. * File: $Id$
    $ R6 o% D: q' m. ?
  20. */
    , H' |/ @, E  v# D* @" [! m7 `

  21. + W1 `' w7 a- `" {( H5 k
  22. #include "port.h"
    0 s  h6 B" G1 C" {
  23. #include "usart.h"% O/ n, s  c1 F( V" ^. p, V
  24. . ?3 c: m) F  ~$ I# j
  25. /* ----------------------- Modbus includes ----------------------------------*/
    % U! @  }3 Q# A4 d% {1 ~& x
  26. #include "mb.h"
      M) o6 E8 H1 g% y# b- w. {
  27. #include "mbport.h"0 w- Z) S: W: R, y

  28. ' K# D7 a0 C5 t( ^1 e
  29. /* ----------------------- static functions ---------------------------------*/+ j8 Y( T' L9 H& F8 n- l% q
  30. static void prvvUARTTxReadyISR( void );, I: q! b# ]- d
  31. static void prvvUARTRxISR( void );3 d5 w" j. @2 P6 K& x
  32. 3 G8 B) l, d7 H1 ~% K% W
  33. /* ----------------------- Start implementation -----------------------------*/
    , L4 b6 r9 t4 ?- s
  34. void! a: u3 P7 E) |6 H5 [+ j
  35. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )! _9 x4 D. }9 V- B6 U; y
  36. {+ ]# X, L4 H. }$ r. ]
  37.     if(xRxEnable)
    1 }2 G+ I" Y/ `3 T1 j
  38.     {" h5 g4 X+ j6 c% M  }( u+ p: e+ _  J
  39.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断
    % i" N6 ^: d9 S# n' v, M! \
  40.     }8 J! s8 m2 X  e4 T2 e9 _
  41.     else$ y4 {% }1 x( }& ~: j- I# I
  42.     {
    & ]* _3 ?- Q9 B: m+ N. g
  43.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断# u0 {: M  i/ w4 E! V# I9 x! X% k! x
  44.     }" o3 \) {% h& j. \
  45. ; J7 j5 k/ b' c  F$ O% z: T. w
  46.     if(xTxEnable)4 O/ C. ~+ \) D. _  y8 g- ~! X$ l) e( O
  47.     {/ o: X4 d5 S+ B
  48.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断
    & V; l# S2 H8 o# V; y  ?* |
  49.     }3 m* w' H* \; p; H) ]7 M6 {( Q/ W
  50.     else( G6 q/ y' q0 F) Z9 |9 O
  51.     {* Q: f3 F2 L  v" ~2 c
  52.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断
      `/ g! @$ r0 B4 {" v. m
  53.     }, y0 l; r4 x: L+ g4 F
  54. }' h% Q) u& e6 ^2 X1 L

  55. ( @6 A# w+ Z6 S; z) e& {; R  m; N
  56. BOOL
    5 @  S4 {' m* e$ m' Q: w; C7 y/ @
  57. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
    $ r* E: t1 [5 [& ~5 _5 G8 g$ l( F
  58. {
    ' O3 b- E4 Y3 M
  59.     huart1.Instance = USART1;
    4 h; r, U& r0 f$ A: J' o  K4 Q0 u
  60.     huart1.Init.BaudRate = ulBaudRate;- t$ l8 ?9 H7 [2 L3 \% z1 r8 ^
  61.     huart1.Init.StopBits = UART_STOPBITS_1;. ]+ U" R. y2 R+ T) D- s: u
  62.     huart1.Init.Mode = UART_MODE_TX_RX;  l# X; u1 G: L2 J, L
  63.     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;) m. x- J  w# f" a6 w
  64.     huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    9 X" Y& o- c1 b) }

  65. , u4 |0 N3 w+ u# w  `
  66.     switch(eParity)
    # X3 P; [) ^! L
  67.     {
    " u% `* S; c8 E4 @
  68.         // 奇校验
      _, ]4 N$ B% {
  69.     case MB_PAR_ODD:) T. M* @- s$ z6 r+ {
  70.         huart1.Init.Parity = UART_PARITY_ODD;
    2 |" S0 u1 M" I7 V. o
  71.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits
    ' T9 b. F) l' G" r1 q. ^# @' D
  72.         break;8 U0 p  v6 A) K" B' F
  73.         3 s* o8 k; C2 u0 s) o# @
  74.         // 偶校验
      J" E" L3 S& g2 E5 N; o4 X$ ]
  75.     case MB_PAR_EVEN:
    2 _4 g! @9 s& g+ v* [
  76.         huart1.Init.Parity = UART_PARITY_EVEN;
    % J8 m; l1 J+ X
  77.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits+ L6 l, q# {( b- f5 C# j
  78.         break;
    - I; u! [; O# M# t
  79.         
    $ v* k$ L6 O) {, d" J$ ~
  80.         // 无校验
    ' i4 q0 w* p3 Q3 x& g) X
  81.     default:
    ; ]8 e) ]5 N- Q, \5 |% l
  82.         huart1.Init.Parity = UART_PARITY_NONE;) X- e  N8 D+ _5 W! S2 d: p* S
  83.         huart1.Init.WordLength = UART_WORDLENGTH_8B;                        // 无奇偶校验数据位为8bits0 j! y: T; s+ }& B' U8 `2 {4 K
  84.         break;
    $ C2 e! g1 q9 v2 y  d1 @3 \
  85.     }
    " g7 W9 L1 N4 ^
  86.     return HAL_UART_Init(&huart1) == HAL_OK ? TRUE : FALSE;
    ; v2 F9 d8 d9 t
  87. }
    . U, y) S8 l) R8 Q$ ^+ r
  88. ; X- ~: P+ z3 F" r# t
  89. BOOL0 j0 A4 g0 Y2 T2 A- {
  90. xMBPortSerialPutByte( CHAR ucByte )# e& Y. P# i$ h+ \7 R6 R: c( f
  91. {
    5 L: z5 V/ g) @3 Y6 l5 e
  92.     USART1->DR = ucByte;( J/ T- s, Y  n) Z* s
  93.     return TRUE;
    4 e$ h: A1 A+ m
  94. }
    7 X/ F; b$ i2 o9 N

  95. 9 M; S, A! X# C2 L+ g" ^6 J# f
  96. BOOL7 c: O; r9 [8 W* W* R# M: a
  97. xMBPortSerialGetByte( CHAR * pucByte )( p% B$ s& U$ c
  98. {
    ) |1 M- R+ w% E' l, B
  99.     *pucByte = (USART1->DR & (uint16_t)0x00FF);
    ' T0 {0 g3 y8 s5 G, J4 l5 i
  100.         return TRUE;# H% S" B8 Q& K  P2 k% E, \
  101. }" ^" h/ L! y- c! _8 J( O0 v& t

  102. / S# Q+ I) w3 j0 @  J0 w7 q3 b2 n
  103. /* Create an interrupt handler for the transmit buffer empty interrupt! D. `7 d' S# D6 ?# }
  104. * (or an equivalent) for your target processor. This function should then7 Y/ B0 v+ l& c! h4 t2 L( k
  105. * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that4 y. I5 ~, g3 i
  106. * a new character can be sent. The protocol stack will then call) a; A  e& d2 Q' k: z4 d9 o
  107. * xMBPortSerialPutByte( ) to send the character.* Y. s: m2 g& h
  108. */4 @. [9 y/ g0 h. r$ K& ~0 J; E% T6 S
  109. static void prvvUARTTxReadyISR( void )/ L4 y6 e; @4 Y8 V
  110. {7 H' \) B6 N: B% A+ ?
  111.     pxMBFrameCBTransmitterEmpty(  );' N/ s& l8 t# l/ t6 x: N( h
  112. }1 [7 H' ]8 q! D* X9 _$ l2 q- v
  113. 1 k! b! p& }* d3 o7 [4 g
  114. /* Create an interrupt handler for the receive interrupt for your target/ ?6 Z/ A( n: |% l. y- v7 Z0 _  C( z
  115. * processor. This function should then call pxMBFrameCBByteReceived( ). The
    & ^8 }1 g6 ]+ D5 M' @- f! ?$ q- y/ `
  116. * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
    + u0 r( L0 G# L
  117. * character.
    " v' f4 [8 ~7 r. M' d% V0 e3 d
  118. */9 e( @, c# X6 b0 p
  119. static void prvvUARTRxISR( void )
    2 m! E) P6 t8 y  v- u
  120. {
    , N" B! n2 X0 Y, j. R2 p' j
  121.     pxMBFrameCBByteReceived(  );; Z  c9 R* r3 D; O0 x
  122. }4 F5 a$ ^( H1 o# ?8 H) @( `4 P% k

  123. / d8 X* C5 s& t# y$ u7 [% \, g
  124. void USART1_IRQHandler(void)
    ! i( C- `4 q6 ^
  125. {
    + H* v1 P" ?) ?6 ?- f1 i
  126.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))                        // 接收非空中断标记被置位$ d) r) o! C: G- C4 n
  127.     {, c3 E7 J$ o6 T, d3 U6 I
  128.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);                        // 清除中断标记
    - h( y2 Z/ C' i1 O$ x/ a% r
  129.         prvvUARTRxISR();                                                                                // 通知modbus有数据到达- r( l7 q, Q% Z' b) u
  130.     }7 h5 g9 C! V/ j% ?

  131. # E  \  S, K# ^- K5 o
  132.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE))                                // 发送为空中断标记被置位
    . k& v6 x8 B0 [* r" c1 E* c1 m) j5 l: U
  133.     {
      h9 E# }2 d. x  x" \
  134.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TXE);                        // 清除中断标记
    9 z+ M' h. ^3 ^! N8 X# v+ W
  135.         prvvUARTTxReadyISR();                                                                        // 通知modbus数据可以发松
      h6 g6 D8 q/ v+ W2 n' |* G4 v
  136.     }2 T1 L! ^9 u* b. S+ Q5 T' s- w6 q
  137. }
复制代码
1 g2 A$ X. r' r' x
注意一点,一般如果使用了485芯片的话,那么同一时刻只能接收或者发送,可以将函数vMBPortSerialEnable修改成这样:
7 A) P; C* K" h) y; F2 [
" V' X2 W* Y, _7 j& O9 Y+ Q
  1. void
    : x: S5 L; C/ K. p5 [% B! z
  2. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
    , W; Y* `0 U5 h. }) M* d9 R+ C" l
  3. {/ F# f" M, M7 s) ~  v
  4.     if(xRxEnable)  f; d. L* Q& o( }: W3 u
  5.     {$ U( b0 n$ S' T8 l4 W
  6.             //  x; j9 {2 F. b& P) ?" Q: @) a* z
  7.         // 在此处将485芯片设置为接收模式
    * [6 K: V. R& @! c3 f; x
  8.         //# b. w* Q8 y" z+ C9 p. {7 Y: i3 @
  9.                 /* do something */
    ' k4 y) _$ ^% W- d* N, q
  10.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断% |& [* l" J" _7 m. V$ B. H8 c6 V
  11.     }! }# X4 r, E0 z0 X
  12.     else0 X+ ?, M% H1 p& S% R! c
  13.     {
    % e/ s% f1 P& h2 v2 C5 S. I; r
  14.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断
    9 M" Q) I* X' s3 Y
  15.     }' k6 `3 s9 `; q3 A+ P+ }

  16. 2 Z7 R/ s) g  x0 Z
  17.     if(xTxEnable)
    4 _, ]9 B5 i: }0 K
  18.     {2 L+ w7 i% U8 z7 W# X. _# Y7 y
  19.             //
    ' I# p  l3 }: d! J% c9 h
  20.         // 在此处将485芯片设置为发送模式
    4 K' G2 t1 s3 f4 W, f) d8 |# I) ~
  21.         //
    % z0 |! g6 F# A4 K  x3 T
  22.         /* do something */% _# |$ b  h& O. G  T, p) a
  23.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断. d; c3 w& h: C
  24.     }
    4 ?4 P4 [5 [5 e# U
  25.     else
    7 f$ k3 L# L! F& Z* n% \
  26.     {
    5 H. @- o' I- }$ c% I. ^' F
  27.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断" y6 V& O3 x! t/ k
  28.     }+ l* V6 `2 q( h9 M( [; A( ^/ B  o; j
  29. }
复制代码

+ s; ~6 X; w" ~/ U' W
编写modbus命令处理回调函数port.c文件; N; q# {7 e. }" u
本例程只实现了读取输入寄存器和保持寄存器的功能,详细代码如下:
& X3 n0 f1 a& z  r: r- `% g' t
. Y9 s! K9 w. i7 W* j' ^( q
  1. #include "mb.h"
    + ?5 ^% E* i# A" y" O
  2. #include "mbport.h"
    5 y! V7 ]. `6 G, }: c
  3. , v  t) U/ \. l% h$ r4 d

  4. 5 B+ F, }) |4 c0 g( q
  5. // 十路输入寄存器0 @0 {5 o' w& V) d
  6. #define REG_INPUT_SIZE  10
    # {0 h' _, g1 M0 U
  7. uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];
    2 |* M3 h5 V# j% z7 \3 _

  8. / \6 K" K  Z4 Q- C. @

  9. ; Y0 }! d: A2 A1 K) r$ m) }
  10. // 十路保持寄存器$ N2 N  \/ z5 T' n7 t
  11. #define REG_HOLD_SIZE   10
    , Z  V. }& D  D6 l( U( z8 l" e7 l/ d
  12. uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];
    1 s: A4 H2 _9 }. |8 ^

  13. 7 W6 `. t- `/ z& k
  14. 8 v  {# u, K7 n- z5 O, P' I
  15. // 十路线圈
    ! t5 k. |4 D. g: E
  16. #define REG_COILS_SIZE 10
    $ ~+ [6 ]( `7 ]- r
  17. uint8_t REG_COILS_BUF[REG_COILS_SIZE];
      m+ i) m& i2 J: Z* [! w2 u
  18. $ ]( u$ ^5 A2 |% K
  19. + j% p1 m1 u- p
  20. // 十路离散量) {/ U# O* Y3 {" N$ b- ^
  21. #define REG_DISC_SIZE  10
    0 p& u9 F& S) ~: b: x$ @
  22. uint8_t REG_DISC_BUF[10];
    9 V& O$ U0 E' w. o7 V

  23. 5 W' m/ F( }! S5 x
  24. , w9 M8 j+ n5 `: V$ c
  25. /// CMD4
    $ `& c$ Z+ U' ?  O! w' b; H2 h
  26. eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
    ; k# ?1 K3 d8 _2 X2 E$ d6 @! F: A9 {
  27. {' e% J8 D' l# X" v% F- k
  28.     USHORT usRegIndex = usAddress - 1;
    6 X. S! I( N9 v

  29. % D. f7 P6 ^6 j2 W+ C- ^8 W# ~& |
  30.     // 非法检测4 d- a. |' P$ J; R
  31.     if((usRegIndex + usNRegs) > REG_INPUT_SIZE)9 O8 P& s6 W7 B8 I! Y7 A8 P: w
  32.     {. ]% F9 u0 R6 }2 A/ v- P, f
  33.         return MB_ENOREG;/ m" C- k; v, X
  34.     }
    5 b2 B. L4 T( l0 |" q$ {
  35. - P. H3 d5 `' T+ T4 v/ R6 Y. l
  36.     // 循环读取
    7 N8 {5 d# a5 `! T
  37.     while( usNRegs > 0 )
    8 S) A5 V" r% Y* u- {$ O
  38.     {
    - t1 M4 [7 W) {; v' d) r$ L; a
  39.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 );* i1 V7 b6 f0 l( `
  40.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );
    9 N) H( E( c) R8 ^& R) a$ O! L
  41.         usRegIndex++;
    ) z) s" B6 E( u- S- X; x% g6 |* e
  42.         usNRegs--;
    . @3 G3 L6 A: B! r2 ~1 N
  43.     }
    2 v, |( X* Z! ~( }2 r

  44. / N, g, Z0 C# b  g, }
  45.     // 模拟输入寄存器被改变0 D" m- t$ D, w0 J2 z
  46.     for(usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++)4 @5 ]& B, N8 f1 [: `
  47.     {
    ) M" W1 L3 E4 i9 x7 B4 C, |5 d1 n
  48.         REG_INPUT_BUF[usRegIndex]++;
    * u& R; Q0 M2 j6 x3 P
  49.     }
    / i  b7 K+ w( h9 K5 c- J: v
  50. $ R; a1 X0 G5 ]) V9 o* m
  51.     return MB_ENOERR;
    4 {" @6 z' u" c6 k$ _
  52. }8 ^- c; R, G( d5 I+ t
  53. ; Z% k7 S) }, `( `0 x
  54. /// CMD6、3、16' ?' v) ?6 n& t% |2 I& h
  55. eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
    ) e8 e$ C0 M9 d: z& H
  56. {
    ! L5 S* {2 p" K: w" U! u$ z
  57.     USHORT usRegIndex = usAddress - 1;  " W9 h$ c- p9 t3 L
  58. + w2 ^/ _& U  a
  59.     // 非法检测
    / P0 \# A5 J" d$ {, ~
  60.     if((usRegIndex + usNRegs) > REG_HOLD_SIZE)" p! P* z. O( ]/ q* M  Z- `' Y
  61.     {7 j1 l, }9 t" S5 K4 y1 z
  62.         return MB_ENOREG;; N4 k, ^: g  a8 _/ R3 D, z
  63.     }% V4 w0 g* j- O
  64. - F5 h1 i. G# m$ G" s! W7 R8 f1 U
  65.         // 写寄存器" P3 P7 v9 S% h# h4 a- S1 E
  66.     if(eMode == MB_REG_WRITE)* [! N1 ~4 X& G) N. O: a& l
  67.     {1 q$ ~" |2 w' j  ]9 j! Q
  68.         while( usNRegs > 0 )4 N; O, J9 [' b1 M5 O
  69.         {
    9 o' P1 a6 W& A7 [7 e
  70.                         REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];
    ' b1 g8 j( d2 z- {
  71.                         pucRegBuffer += 2;* I2 W2 W3 Y8 N. H  H6 O% e
  72.             usRegIndex++;- j% N- M, Y# P, J0 B" t
  73.             usNRegs--;
    6 O' {5 c( |4 X: m
  74.         }
    9 p/ @6 f; ^: K7 ~! S
  75.     }% E9 q+ y- Q& x- _
  76.         + r0 R/ z0 Q& s; n+ V
  77.         // 读寄存器: d1 O4 v( K: W* @0 \
  78.     else
    - e- ?) F/ Q1 U0 A0 r9 w
  79.     {- L7 M' \7 B$ p2 U8 v, i" x. @
  80.         while( usNRegs > 0 )5 Y( W  ?3 K, o) m: ]
  81.         {
    & L. D7 R( i2 C' ]* v% K- n( U
  82.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );; K7 W6 Z# {2 m% [# ~6 j* ?; q
  83.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );
    # @3 ^" ^$ ~3 m- n3 e# b" _  W
  84.             usRegIndex++;
    ! d) W" L% C) m' A' h! B- B3 I! p" R
  85.             usNRegs--;
    " m# V" j) G, U- Y4 N& g% E
  86.         }$ u! T! m# e$ {5 {1 n' z& f2 b
  87.     }
    9 c  Y! ]7 H7 m1 [7 _
  88. 0 M. A, M: {5 Z5 x+ r
  89.     return MB_ENOERR;/ T" I: Q% L" c/ t
  90. }1 [* g) f/ e/ ?# x( K# G
  91. : R3 L7 l; g$ q+ G' l) H
  92. /// CMD1、5、15
    % r( G3 ^, x) \% d* E% r9 T
  93. eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )' U" n* A# E, K5 N- \
  94. {  ~) K! g9 u; C1 C! N
  95.     USHORT usRegIndex   = usAddress - 1;
    , O) ], e1 }% r) I
  96.     USHORT usCoilGroups = ((usNCoils - 1) / 8 + 1);! S& n7 u) [4 H$ D% L3 @7 \6 @: K
  97.     UCHAR  ucStatus     = 0;
    4 Z- H4 t" ^( o
  98.     UCHAR  ucBits       = 0;  I# v. |- b; z# ^# q# \
  99.     UCHAR  ucDisp       = 0;
    4 p# Z0 F" a# j4 V

  100. ! u4 z; e( z/ M
  101.     // 非法检测
    - {1 N' ?/ N, E" w* a
  102.     if((usRegIndex + usNCoils) > REG_COILS_SIZE)% F7 \9 ]  q% ?
  103.     {2 z" k/ R2 B: ]7 W
  104.         return MB_ENOREG;6 k. o5 D5 k. V, N4 w% k
  105.     }5 U$ M, Z: B, a; R% R" x. S* b
  106. 6 P6 W# @7 o4 ~
  107.     // 写线圈
    2 ^' L6 t8 d% T0 t! c* Y, T, |
  108.     if(eMode == MB_REG_WRITE)$ M/ @- Q) q: E
  109.     {
    ' Z3 {; X& D- M1 z
  110.         while(usCoilGroups--)& s3 n4 S0 }& g- v% b
  111.         {
    - e7 M# F' ~1 u0 Q
  112.             ucStatus = *pucRegBuffer++;
    $ }# b' q) }  ?" Q5 c4 s9 }& l
  113.             ucBits   = 8;
    : t9 {; d0 L; A6 R0 r/ q  D4 T
  114.             while((usNCoils--) != 0 && (ucBits--) != 0)
    % [# L( I% R. O; T) N% J; t% e
  115.             {
    ' b) S  W% E: S! d5 y" l: n$ V
  116.                 REG_COILS_BUF[usRegIndex++] = ucStatus & 0X01;
    * n' V, U* X. i7 f
  117.                 ucStatus >>= 1;( _( y- p+ s- y5 {/ j7 d
  118.             }
    7 J, R9 g+ g6 `' D2 z4 [( [
  119.         }$ a9 D" c2 x3 ]0 V) T
  120.     }
    : u/ T0 ?) d2 G2 s

  121. 9 e8 ^! r5 H6 X% F
  122.     // 读线圈
    % _6 {4 e8 M2 ?. I/ \. F, J
  123.     else4 I( u; C7 m% X) A- C
  124.     {0 j  u' y" X/ @3 I0 f$ b7 E1 ^1 B
  125.         while(usCoilGroups--)
    " C- v0 B( l' H' B* m" n) T0 h
  126.         {9 h1 g: k2 r7 W, Y' t
  127.             ucDisp = 0;# N9 S- p  k+ I# g$ r6 x( x) G+ T
  128.             ucBits = 8;) D# o( D* V3 E7 W( n) _  c
  129.             while((usNCoils--) != 0 && (ucBits--) != 0)7 f& O% Y, k/ Q4 @: v2 B5 h! g: {
  130.             {1 Q7 Z4 e' ^+ a* b
  131.                 ucStatus |= (REG_COILS_BUF[usRegIndex++] << (ucDisp++));
    1 w; ?8 d& s' }, a0 k
  132.             }: X. _, V  k& t- m' S
  133.             *pucRegBuffer++ = ucStatus;
    ! t4 L3 t1 }5 E  u: z
  134.         }
    # J9 o  u& s3 a  f- k0 P
  135.     }* a' a# Z0 Q; M& r# l
  136.     return MB_ENOERR;" b, i% O& W# t% }1 r; a) n& ]
  137. }+ \. u9 ?1 e- y0 q( w' U: {) {3 o
  138. / ], l0 Z) k" G& @

  139. 9 x4 h7 a0 D+ G- q0 K
  140. /// CMD4
    ( @$ n* @% N8 \1 q: H, \( ^. F$ G
  141. eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )( [5 ~( X1 k# w$ j& M  R
  142. {$ o1 j' k& O, }; u* t$ w
  143.     USHORT usRegIndex   = usAddress - 1;
    : x. n3 P6 I4 j  r. |, ^, r
  144.     USHORT usCoilGroups = ((usNDiscrete - 1) / 8 + 1);
    4 }/ Y' w; U( S! u
  145.     UCHAR  ucStatus     = 0;
    % [/ u* t/ r5 K9 b2 v
  146.     UCHAR  ucBits       = 0;% K% Y2 ?. }6 g/ z, K
  147.     UCHAR  ucDisp       = 0;- Y* b1 `! j' z$ l
  148. 5 P6 S8 J* P0 `) F
  149.     // 非法检测
      R0 w) v, Z) x/ p
  150.     if((usRegIndex + usNDiscrete) > REG_DISC_SIZE)  r2 _5 E* L& F- q. l0 r
  151.     {
    1 z0 A7 K3 o8 |$ @
  152.         return MB_ENOREG;
    % {5 J6 g- W( {. z& |+ p; ]
  153.     }3 O8 \* N0 Z" w# d2 b
  154. 3 t7 x" f. k0 ^/ r
  155.         // 读离散输入; L/ n; I2 E: B& \! Z+ y! \* p/ x
  156.         while(usCoilGroups--)
    & W, {5 d8 j. y
  157.         {
      e6 H$ M% J2 F7 _
  158.                 ucDisp = 0;
    ' U- k) \# F, s* L4 z8 [8 L
  159.                 ucBits = 8;
    9 z1 i& _5 n  E3 X& [
  160.                 while((usNDiscrete--) != 0 && (ucBits--) != 0)
    " e: ~3 J" k. y( _& d
  161.                 {' v" O3 C, E' c/ ?0 \
  162.                         if(REG_DISC_BUF[usRegIndex])" y# M5 T" b4 c( u, ?7 {
  163.                         {; F, h& l! d3 g% N! X
  164.                                 ucStatus |= (1 << ucDisp);5 F4 T' W+ @; M0 f# q9 v
  165.                         }
    ' t: l0 N) C1 w
  166.                         ucDisp++;
    ( x# d2 G. n( x9 T$ T+ d
  167.                 }/ a% V: F. z; W+ r; B3 l
  168.                 *pucRegBuffer++ = ucStatus;! Q, n  w6 m7 V/ \4 v
  169.         }# e4 J! l  O' \' M8 z( a+ @& q* s

  170. 2 d" i2 N2 {( q  P
  171.     // 模拟改变
    ! D  B: ~6 v7 O/ Q, T' c: x  e
  172.     for(usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++)
    " M8 D: [! N8 d7 c* |5 K/ M$ m
  173.     {
    & p+ G& {' T" v6 F- {
  174.         REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];
    & i$ J# `3 b; f) R$ O
  175.     }, [0 D+ `: x' x7 C" q( O! T, F( W% |4 A9 r
  176. 7 D8 O6 U5 t7 `2 t  [) ?) {
  177.     return MB_ENOERR;
    % o$ W1 Q% A* Y) L) M
  178. }
复制代码
" N0 M% F2 E' Z
主函数
/ A) o$ o  Q% w: u1 R( }0 Y% X- i
  1. int main(void)
    . E/ t7 @% X" q% ^- N
  2. {6 K! Z7 l- X  M
  3.     HAL_Init();
    6 `* a$ e6 `& r5 D! `; U: [
  4.     SystemClock_Config();) @9 \- y+ m2 h0 \# B& g- Q3 m' v
  5.     MX_GPIO_Init();
    . a; X, h! @4 U' ^- K$ s
  6.     eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_ODD);                // 初始化modbus为RTU方式,波特率9600,奇校验
    / \8 {! s' f, N! x/ e% F( u1 c6 ?8 A
  7.     eMBEnable();                                                                        // 使能modbus协议栈
    / T8 U; h0 f( s( _9 g: j

  8. , n) S/ L" h) o- ~2 v* p- j( }: I; j
  9.     for( ;; )
    1 A' P6 ~4 z* {  ^! n
  10.     {% d/ U5 y: X1 `4 h
  11.         eMBPoll();                                                                        // 轮训查询
    7 r$ S, ^, k* a! j3 M) _
  12.     }
    9 R* B  ]5 `8 f" G3 u) I: A" E, m' }
  13. }
复制代码

2 X% G8 K. H2 @, }移植测试: I0 t7 @. |0 R& R( {+ x0 v

/ N6 c, C2 J, k# q6 F) l 20200313154857173.gif % \. Y/ i. s1 W. F8 H
# O3 E# c2 @4 E4 ~" n# O5 Z# z: d* O
ends…( C0 m) T3 e8 x6 l
8 z3 R. {) N2 H- ]
8 g6 P6 q* t+ O) {
7 H1 ?% g& \+ H. o+ Q6 M" c7 Z
收藏 评论1 发布时间:2022-4-10 22:53

举报

1个回答
zzzff 回答时间:2024-10-26 10:31:57

我的是stm32g071系列,移植上去不行怎么办

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版