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

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

[复制链接]
STMCU小助手 发布时间:2022-4-10 22:53
modbus命令码表:
4 X  _+ I$ _7 T8 ]1 C2 t4 @
* x: Q$ h1 E9 q! D! ^3 O
b8032deb4d154657acd2f7f2942369d4.jpg & y- x) d6 P3 d& l) [

, L/ d6 n7 N# T* D- wFreeModbus文件说明
' G. f5 p  L( u
      解压freemodbus文件后打开,我们需要demo目录下的BARE,该目录下的代码是空的,STM32移植工作基本就是修改:portserial.c、porttimer.c、port.h这三个文件。
' w0 k. ^1 g/ n0 y% W- R3 c 20200313143257958.png
( Y! ]8 Z$ X2 T+ O- S, I3 ^8 B+ j% X
      mobus文件夹就是完整的源码,包含rtu、ascii、tcp:; {3 z, D2 R- y+ h- X

' ^  {+ R: m; t# r ZM%DLXPRB8$%[NN2%4Z1N.png
4 |: w6 ]9 |0 u* q# o
: V7 P, L% v. P3 l& ~! W. O7 l      我为了移植时在keil添加源文件和头文件方便,就把modbus所有的头文件和源文件放到了一个文件夹下,并创建了一个port.c文件,用于编写modbus所必需的回调处理函数:9 R% T* _& u% B0 ]

2 u/ ~9 Q; h% Q7 @, q5 N% a 20200313144036579.png ) }1 z2 y! D, Q
* d/ z7 ^" \8 K! T, c1 N
STM32CUBEMX配置

% t+ e, l* B% w: U时钟配置,设置主频工作在72MHz下:
" T' T+ j2 ~) t: b

, C& k( m. Z1 ^8 k) y1 B JU1~N33M}I7K1(6K@JFN5~R.png 6 R. m% [5 j- _' V- K

: e" y0 i; P* l2 D配置串口1,这里随便配置就行,在modbus移植过程中还会对串口重新初始化:

1 L8 {, Y7 R  o4 h  w, j3 ?2 }9 [, }) z! Y1 U* P6 w9 {
U25OQ_FHYD5WEXLFMI4V@RU.png
; p! l: v3 `! a. o$ c" J: i& b+ {& n5 d7 X4 d+ _
配置定时器4,用于3.5个字符的定时检测,这里随便配置就行,在modbus移植过程中还会对定时器重新初始化:

# L9 m/ j: W3 }2 \6 N
+ Z# |, I: t: L H6{)WT`**CIHDAM02558GK.png
% G8 {- J8 f: j# z9 E
+ M0 p+ x  Q8 d1 X2 w  Q) A$ [中断配置,这里注意,串口的优先级是要比定时器优先高的:

1 @, [1 ?" w- J2 d1 i/ F1 Z" u
/ p0 L' n8 p3 k+ n) L) @/ | G(RP`74TR)NPJFUK``Z%I2L.png
# z' b" r. d0 R4 {) }取消掉自动生成中断服务程序,在移植过程中我们要自己编写串口和定时器的中断服务程序:4 G/ a) p* n! W* R5 K9 f

/ m3 _! [. E; ~ ALHMK5Y615K6(`M{0[]YJ.png 2 m- N4 }" [" ^( S

5 e7 v6 B7 w+ O& ?移植代码修改

# _/ X" p+ J! \9 ^' W( m7 r生成代码后将modbus放到工程目录下:
% Y6 w( u, q9 R# C% s7 [: m& J& p) B1 ?) W
5%(_LMGIM_8_YGL`]JGAB67.png
& u: ^" U/ h, R
2 Y& D) P; Z% u7 P/ ~2 s4 b打开keil工程添加modbus源码:

  i& M- U4 Q& K8 q* J$ ]/ Y  K/ k! z
F`8_YFACMNOAP28~2VHD{CO.png
& H: g; n- X# x/ r3 F
  k; J% z6 u9 w添加包含头文件:
( A& J% g' B7 p, w
! U* g) E( A  j
`7BMVXA`R9SQBTGT`B@{]X7.png
5 Q+ R! h+ c( [* @% A- ~; G
4 r8 D: I4 h7 ]" o修改modbus定时器初始化源代码porttimer.c文件
8 r) H; z9 h% B# r( [       定时器的修改比较容易,将定时器设置为每50us的时长记一个数,传入的usTim1Timerout50us变量给自动装载即可,prvvTIMERExpiredISR函数需要在定时器中断服务函数中调用,它的作用是用于通知modbus协议栈3.5个字符的等待时间已经到达;由于我们在STM32CUBEMX中取消掉了定时器和串口的中断服务函数程序,所以我们在该文件中添加定时器的中断服务程序,修改后的代码如下:
7 l% y! W' E0 m! q3 \! x' k: Q* z. x$ W+ s& |
  1. BOOL$ n5 o$ {# A, H  H/ p. ^3 ?7 Z: e
  2. xMBPortTimersInit( USHORT usTim1Timerout50us )4 |, D8 e2 z2 y* O4 D$ ~, K" C
  3. {# W" v9 {1 C7 n' z$ Q; N
  4.     TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    0 Y! P- W+ j$ [$ W: l# r* n( t$ [
  5.     TIM_MasterConfigTypeDef sMasterConfig = {0};$ r: u$ ?5 Q" T4 C, t7 z
  6. 6 P: D, Z* d$ m+ s: n, A
  7.     htim4.Instance = TIM4;
      S# H- R3 m# }$ k9 L! `& w
  8.     htim4.Init.Prescaler = 3599;                                                                // 50us记一次数
    1 R$ z1 \1 Q, l- s2 i5 U' ?8 O
  9.     htim4.Init.CounterMode = TIM_COUNTERMODE_UP;" V( v! V  R) s
  10.     htim4.Init.Period = usTim1Timerout50us - 1;                                        // usTim1Timerout50us * 50即为定时器溢出时间. o4 c& l6 i; c5 I: O! M, W6 O
  11.     htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;; q2 X3 E1 H8 ]2 j
  12.     htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    ) I+ s2 H7 w2 d+ M
  13.     if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
    " A1 ?7 H3 B! u0 q
  14.     {
    5 C; r# h5 I1 g+ ?8 O0 y- v
  15.         return FALSE;
    6 D4 t% p0 S# ~; r
  16.     }0 E0 o! w9 c- m
  17.     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    " v% C* m; i; a" e( ]8 d9 o8 y
  18.     if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
    ' y( e$ Z* I" Y# }0 t6 q  L
  19.     {. k* {& I& E& i
  20.         return FALSE;3 _& s- i' z* I
  21.     }7 [+ p- o, }' q6 U, i  D
  22.     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;2 S, R6 p. b. h
  23.     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    6 T1 I) B( L. D
  24.     if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
    1 R5 A+ a- ^, Z: ^" ^# ]$ A6 ~
  25.     {
    3 d3 r) @- l  B  v3 a& k
  26.         return FALSE;
    - ~) O4 M4 S7 a3 L
  27.     }
    8 s1 g6 K9 l( j4 `6 }

  28. & e$ y/ f) n! m0 V2 [
  29.     __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE);                                        // 使能定时器更新中断4 y1 u- x# D+ _4 e
  30.     return TRUE;0 q: }6 d4 i. c
  31. }
    ' a- C9 V" O- A& o8 W$ S
  32. ' ]. S: f% S/ l9 s% R
  33. inline void& H7 A8 w4 q9 D# ?( U  Z+ \  |/ ^
  34. vMBPortTimersEnable(  )
    # N2 Z) Z/ ^( G$ D  N
  35. {3 A7 }' K8 g$ N( i1 C
  36.     __HAL_TIM_SET_COUNTER(&htim4, 0);                // 清空计数器2 `7 [! D0 |" d+ E+ {
  37.     __HAL_TIM_ENABLE(&htim4);                                // 使能定时器# L, T1 B* L. e  o9 P$ B9 U
  38. }+ y4 W& c9 c( M% v5 {& e
  39. / I$ z/ D  _7 x4 ~( A& }$ d
  40. inline void
    0 Q4 O3 T+ l" ?* m6 x# n9 W8 p9 `
  41. vMBPortTimersDisable(  )
    , r: T8 \: M3 _7 I; v, g5 w
  42. {7 V4 U2 k$ D4 B" ?1 W: S
  43.     __HAL_TIM_DISABLE(&htim4);                                // 禁能定时器; s+ x2 t. F: _4 t
  44. }- C6 _" C* \9 p$ p" |( B& [
  45. 6 d. y* C: r7 B- C' b: h. L7 @, V
  46. /* Create an ISR which is called whenever the timer has expired. This function
    ) u/ x" O1 O; z8 h3 r
  47. * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that  h' ]  ~! d7 s4 p" y
  48. * the timer has expired.
    : B  ?) r3 U+ Q) W; ~3 g
  49. */
    / w  }  q% p7 `- b7 k. k
  50. static void prvvTIMERExpiredISR( void )
    3 u' W# @9 Q1 L3 b
  51. {
    & ]8 z- y; x9 w% r* A4 q
  52.     ( void )pxMBPortCBTimerExpired(  );3 w& y! ~. V) }& M9 ~
  53. }3 N) }) n: o; e5 [, W! T3 R
  54. 7 g! e- q! @4 u' Q
  55. /// 定时器4中断服务程序" c5 s- i8 ]5 B7 r3 y/ N# }. M
  56. void TIM4_IRQHandler(void)+ A3 o3 _7 Y8 h% K7 n6 N; Q
  57. {( z8 Q  k" b5 Z+ W4 _+ e; Q
  58.     if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE))                        // 更新中断标记被置位
    ) A0 H( [% F& _0 g- `8 e! X
  59.     {
    . T6 a8 `9 H& F4 k& ^# E
  60.         __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE);                // 清除中断标记
    ' T- V$ q6 Y: f, a' _8 ^
  61.         prvvTIMERExpiredISR();                                                                // 通知modbus3.5个字符等待时间到
    . b5 }5 t9 F' J7 L( K$ P  c4 n
  62.     }
    & R( X5 e" `& T8 n4 o1 i0 W; `
  63. }; d- z5 j9 `7 A9 k

  64. 9 ]5 Q" q: S5 z) Y
  65. 2 {$ @& y/ A( N. R
复制代码

$ X0 I: ?" Y! X! Y修改modbus串口初始化源代码portserial.c文件0 X" J0 q  u/ }: g  h# z
         ~~~~~~~~        在该文件中实现串口1的中断服务程序,prvvUARTTxReadyISR和prvvUARTRxISR函数需要填写进中断服务程序,前者得到作用为通知modbus协议栈串口已经空闲可以发送数据了,后者的作用为通知modbus串口1有数据到达,修改后的代码如下:1 S" [2 ~5 v0 \8 [; `
% w+ d7 r5 C. @
  1. /*; l1 `3 [' e9 l) N) ~
  2. * FreeModbus Libary: BARE Port2 ]6 @: g# o# \2 t% X' M) f' Y+ n
  3. * Copyright (C) 2006 Christian Walter <<a href="mailto:wolti@sil.at">wolti@sil.at</a>>
    , P) u  k* ], y- u) X
  4. *# j: _9 y# _" _9 F, G
  5. * This library is free software; you can redistribute it and/or9 E' K" t3 ]' i" `1 h. w2 y8 S
  6. * modify it under the terms of the GNU Lesser General Public
    " V+ k; ]) B" W0 b1 l3 F. B
  7. * License as published by the Free Software Foundation; either, g& ^) a2 b6 P: H& n( |
  8. * version 2.1 of the License, or (at your option) any later version.
    # U8 a5 U$ G3 D
  9. *
    9 x: n; b- R& _" O/ o$ N( i7 W
  10. * This library is distributed in the hope that it will be useful,2 x. s' }% S& @
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of9 a( H3 ?- ]/ \2 }: f% {' p+ T. k& X
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU9 }9 U% B* j) `9 [6 y
  13. * Lesser General Public License for more details.
    % a" u. U& t- i1 {. U2 W3 S) z
  14. *
    : E8 E# B' l& |2 r
  15. * You should have received a copy of the GNU Lesser General Public
    ) E( c  `1 A7 W0 w) p/ c
  16. * License along with this library; if not, write to the Free Software- @6 ~- H. C# n/ c, R+ ~' z1 U0 C+ c
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA% y# u" c5 g5 x& f* f. V
  18. *
    1 O# l5 ^% [9 ]9 ]' V; o
  19. * File: $Id$
    # E6 P* L4 E4 A4 a1 V  w
  20. */
    $ R! ^. x& `9 g# o. k# Y$ ?
  21. 9 ^5 g' V+ j+ V
  22. #include "port.h"
    - D8 h  @7 {7 Z+ }
  23. #include "usart.h"
    * d) T# m0 h& E7 n. Y6 ?% `
  24.   X4 t/ W' B* {0 K/ r' {
  25. /* ----------------------- Modbus includes ----------------------------------*/9 C. X9 h( o' u
  26. #include "mb.h"
    0 _) |6 w. {) `$ ^% ~0 Y
  27. #include "mbport.h"$ V! u' |8 E) k  Q# M- q
  28. ; i) B; W3 w0 _
  29. /* ----------------------- static functions ---------------------------------*/
    : o% [% a2 F: w; ^" Y# o* {$ [% \
  30. static void prvvUARTTxReadyISR( void );7 b7 ^8 F  S- c, V
  31. static void prvvUARTRxISR( void );
    " d- |( J1 X- _1 }# ~
  32. 4 H& D. [1 w: c6 P% K0 ^7 n* e
  33. /* ----------------------- Start implementation -----------------------------*/
    6 a: _: \% f4 b' o" x! q/ m
  34. void) [# T3 a, p2 I% S) K
  35. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
    4 h( o8 x5 v4 O1 I# V
  36. {
    , j$ G1 W; p+ s% |$ A, L2 `
  37.     if(xRxEnable)
    8 J8 O) o* \5 v0 v1 o3 T4 Y
  38.     {5 G  R8 k* Z0 t
  39.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断
    & h" p) v4 X3 J9 b& G" h9 w; a* s
  40.     }
    . o- H$ |) G; w% Z
  41.     else
    ) K" n9 w. o: b/ ?
  42.     {
    1 x0 F2 U1 ]( e  l
  43.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断
    + t% C& r# Q9 s% P. n( j
  44.     }
    5 _5 P  U9 Q& j, Q% ?
  45. 3 K# d2 m1 t9 W
  46.     if(xTxEnable)# S  b0 W6 _2 B7 V) m9 i
  47.     {! r- H7 R' ]2 @# E' S2 k+ N& e
  48.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断
    $ w, W$ n5 l" ~, u. _. H
  49.     }
    8 e: R/ {! S% K1 f
  50.     else5 \, ?7 |. q) i+ p! A
  51.     {  t  m& ?7 y) f; @2 a
  52.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断
    $ x6 s7 H" o2 w! C5 v
  53.     }
    * y- _, N3 K  s
  54. }; \2 v& k+ Z  f! n

  55. 8 b6 ]3 B' b' @% N2 z; W; G
  56. BOOL
    & \8 N6 U8 q4 f6 ^. _6 _
  57. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )9 a, {0 V5 ^! p; W) k( z  W
  58. {3 b# H* _. w) }) d4 V
  59.     huart1.Instance = USART1;1 O; t2 }4 G1 g. x* A) W' M8 e- F! |
  60.     huart1.Init.BaudRate = ulBaudRate;
    # N9 r& |! l* F
  61.     huart1.Init.StopBits = UART_STOPBITS_1;' V1 y& C; M" }% y, z- X# V8 o
  62.     huart1.Init.Mode = UART_MODE_TX_RX;
    6 Y8 p4 J8 b2 \: s% A
  63.     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    2 M6 y8 u$ W3 N) @
  64.     huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    # B" }* Y8 S9 m6 z% ]

  65. + I2 J7 b) o3 c6 j7 h  [
  66.     switch(eParity)+ }* b& P/ Y0 R1 `  k9 q4 v8 S
  67.     {3 a( `- p7 [' m: O, U  c
  68.         // 奇校验( b* t/ n3 V# S5 x# }" e; {. x1 T: `' \
  69.     case MB_PAR_ODD:
    * V  o0 H5 ]: s9 D
  70.         huart1.Init.Parity = UART_PARITY_ODD;
    " G7 Y) l9 R1 b5 u. q
  71.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits8 b# I2 t* p7 c1 f8 M
  72.         break;+ R2 }# H+ H7 u3 D# g& v
  73.         ( l* k' k  `0 X( X
  74.         // 偶校验3 L! e/ K; B! V, T5 d
  75.     case MB_PAR_EVEN:5 h0 V0 }* }9 ^
  76.         huart1.Init.Parity = UART_PARITY_EVEN;
    2 v: G8 Z+ o# i
  77.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits7 l7 f0 `& T( {3 s
  78.         break;
    3 Y' n' s" `" {
  79.         % c) C- G3 _8 d& `# W. W# v
  80.         // 无校验# b* r; h4 O* Q' T; ?, ?
  81.     default:: O5 q( H) w( F1 c, T& s
  82.         huart1.Init.Parity = UART_PARITY_NONE;
    9 ~( l1 D" V* P# X7 q% E
  83.         huart1.Init.WordLength = UART_WORDLENGTH_8B;                        // 无奇偶校验数据位为8bits7 x  e* \; V- ~; O5 i
  84.         break;3 O6 @7 L4 @3 b2 R- G7 a
  85.     }
    ) Q9 f1 Z3 N0 K3 v
  86.     return HAL_UART_Init(&huart1) == HAL_OK ? TRUE : FALSE;% v- r6 s/ _4 [
  87. }
    ' T3 ]6 c9 }# ~. i0 ]

  88. 4 U$ @+ I# T0 X. M3 @: w! M
  89. BOOL, O, Q6 H/ g6 ?: V) b
  90. xMBPortSerialPutByte( CHAR ucByte )
    2 K6 O, W! X1 z/ I; Q9 r( R) ?
  91. {
    4 X$ y' ]$ ~. A& N
  92.     USART1->DR = ucByte;
    6 p& X: S" i7 n2 h
  93.     return TRUE;
    : Y! L# u8 Y2 V; e
  94. }# a( E; ], T: h4 i0 X. @

  95. ; l5 ?' H0 J% ~5 a4 T$ }1 ^4 i
  96. BOOL
    " J* {* A* {8 t4 ?4 `
  97. xMBPortSerialGetByte( CHAR * pucByte )
    5 m& w$ \: w; f8 E
  98. {2 ~) }8 ~. U) ]+ j( J/ N& U
  99.     *pucByte = (USART1->DR & (uint16_t)0x00FF);
    ! N& y" Y# D1 D0 N
  100.         return TRUE;8 k- V. z7 t2 i0 |
  101. }
    9 [0 P  K' j- \9 k5 r

  102. 8 W& r( m8 o" j4 o5 I. E3 z; s! c
  103. /* Create an interrupt handler for the transmit buffer empty interrupt
    & E9 T# |$ u5 H, v
  104. * (or an equivalent) for your target processor. This function should then
      l; y0 f' |9 {, v
  105. * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
    / u2 @( E+ ]7 x5 K( o
  106. * a new character can be sent. The protocol stack will then call
    ! t: l1 t% e2 {" m- b) P
  107. * xMBPortSerialPutByte( ) to send the character.
    0 q: f2 l5 \" @/ B. m
  108. */5 ?5 i7 ~# t( D6 v' ?
  109. static void prvvUARTTxReadyISR( void )
    ' w3 W. F# v+ N
  110. {
      R, Z7 t% Y& }, y! M
  111.     pxMBFrameCBTransmitterEmpty(  );! c9 |" Y; k! E& f6 ~0 f
  112. }/ o' }7 e7 `* d8 c- `, ^' Y* j8 v( E
  113. + Q6 x" J3 t  G. s
  114. /* Create an interrupt handler for the receive interrupt for your target
    ! D1 Q0 G1 A" p/ |0 F
  115. * processor. This function should then call pxMBFrameCBByteReceived( ). The
    , G2 r4 N# P8 b: L2 o& [
  116. * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the1 `5 p- X& c. ^$ X7 T: g
  117. * character.
    ) ?/ x  X6 p/ h4 x- R' ~& F7 O+ u
  118. */: Q% U+ E1 p) l( @, c
  119. static void prvvUARTRxISR( void )
    / e1 l5 {8 A( B# I+ o+ g' ^6 F
  120. {/ t; \4 ]% x, T$ U
  121.     pxMBFrameCBByteReceived(  );
    - M5 r/ B, J5 Z: ~% z4 L
  122. }
    % y' {9 s! r/ V: X8 S* T

  123. $ Y3 }3 O+ P5 Y' G  Y  b* P# ^
  124. void USART1_IRQHandler(void)
    6 J1 N% q" X0 f+ d$ K, C! `
  125. {
    9 [- ]; T9 H0 b8 p2 w
  126.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))                        // 接收非空中断标记被置位6 q0 {9 E6 B8 p7 ~0 W* V
  127.     {
    7 \- u- `0 e; a& l  z0 q
  128.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);                        // 清除中断标记: e6 c1 O" X  \, g; u& E. M
  129.         prvvUARTRxISR();                                                                                // 通知modbus有数据到达
    : e$ g$ R8 @! x/ p, T+ M4 V
  130.     }$ n1 E6 r  c/ \
  131. ( g' M$ \  _; F3 p% [) ?
  132.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE))                                // 发送为空中断标记被置位9 M+ U5 `% s, T/ W
  133.     {, W2 B0 ^. N  ~
  134.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TXE);                        // 清除中断标记9 ?1 l2 ?* }7 _$ ]+ D4 w
  135.         prvvUARTTxReadyISR();                                                                        // 通知modbus数据可以发松8 L, ^" @2 V" [- F
  136.     }% f' F' Y1 L, L( j3 |5 W. \& D
  137. }
复制代码

" t( ~/ W: j2 _) R注意一点,一般如果使用了485芯片的话,那么同一时刻只能接收或者发送,可以将函数vMBPortSerialEnable修改成这样:
2 ~8 g2 x7 I- \+ Q" @+ G
8 G) a9 N/ U% }1 ?8 }: l0 Z8 q
  1. void4 ]6 l5 P, T/ r! F
  2. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )+ l' W" K# k- L1 q( V; {0 ~
  3. {
    , S# }0 d* f0 H
  4.     if(xRxEnable)! }( Y* A  b( G& F
  5.     {
    ; K  H9 M8 |* @; ]' U
  6.             //
    6 e6 `3 F' R2 _5 b) a6 [
  7.         // 在此处将485芯片设置为接收模式4 Z$ @4 l/ ^9 I3 t$ A
  8.         //
    / L$ ]: r6 \+ v, w* n
  9.                 /* do something */
    6 B# t% T! D# k- m; n! o
  10.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断
    8 X1 B9 d% M* ^# Z' j; T7 P: i  z% s
  11.     }1 C8 {, K) s. U) d, l8 i6 P) {9 z
  12.     else5 }; G6 [; v+ \8 T7 e3 W) Y
  13.     {5 \6 {! M7 I1 r4 J2 Z7 E- v
  14.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断/ E' q" ^: D# ]1 @
  15.     }
    # U3 i3 h( {9 Y  D

  16. ( o" w4 ]7 r+ l( ?( C/ Y' |
  17.     if(xTxEnable)2 R, {2 F9 L- O' l, A
  18.     {- \. Y0 [/ `. j6 V6 D
  19.             //" Y, n+ Q/ e& s) x+ D. a) @
  20.         // 在此处将485芯片设置为发送模式, Q4 S) N5 o$ A9 r  h
  21.         //
    - F, q9 }& P' ]* D" d5 j
  22.         /* do something */9 G9 b' p& p' Q7 O. v
  23.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断1 n, e7 {! Y. n* B: s( t
  24.     }; X! y( y) {7 {  o
  25.     else
    + y( k: b* |  v1 K4 P. z/ p9 ?4 e. s. y" C
  26.     {; u: h, t5 z' R8 g, @  u/ n
  27.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断( {( V; `/ Q3 x2 h! X3 y: U
  28.     }
    " U8 y6 s3 p6 l9 R! F
  29. }
复制代码

7 `* K" g. O/ {6 e; q/ U* e9 a) G
编写modbus命令处理回调函数port.c文件4 P) `& n, Y$ V7 q! r! a" i
本例程只实现了读取输入寄存器和保持寄存器的功能,详细代码如下:
& S+ e# a# a, w) i% A( {! z

! j3 t) g5 Y6 `9 t- W6 M6 i
  1. #include "mb.h"5 ^' ~8 }/ D- T  K; [
  2. #include "mbport.h"" G2 D" I5 t3 i" F

  3. 1 y4 X% S# r$ @
  4. 3 ?6 A0 V/ e& i
  5. // 十路输入寄存器( p7 F9 l. H% b3 `! D
  6. #define REG_INPUT_SIZE  10
    & J6 O# m! A0 c) R$ M$ E
  7. uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];2 B) x# y/ V( V. Z, u

  8. 2 [4 w5 M9 x. W2 b6 n
  9. + z  c; S' p/ T& v+ Q
  10. // 十路保持寄存器
    ( X  F. L5 i* z
  11. #define REG_HOLD_SIZE   107 J+ w3 l: t- K% c2 V# T
  12. uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];
    . c& c% L- n$ ~, b3 I: m% m& m
  13. / H+ I/ o1 Q5 c$ G8 N

  14. - j3 x* I; c: b+ F9 Z+ F2 F$ z
  15. // 十路线圈  }2 S' H7 I3 a+ v
  16. #define REG_COILS_SIZE 10" h) D% L. r2 k  K0 y2 h' R  |
  17. uint8_t REG_COILS_BUF[REG_COILS_SIZE];, ?/ }; ^; d, K7 T& }. f& P
  18.   T( y6 c8 s8 y- Y; u

  19. 4 k1 j! r! w- G( a
  20. // 十路离散量
    * O+ ~: K7 \' c2 _8 M: B5 d* u
  21. #define REG_DISC_SIZE  10
    4 A2 ]4 a8 R' P
  22. uint8_t REG_DISC_BUF[10];6 N: R% b3 F1 Y$ o7 ?/ K

  23. $ y' {' }. {0 m, E2 [  h( R3 j7 P
  24. & E4 {& j5 |- u- B' _
  25. /// CMD4
    # g1 J( u" t1 x4 `* K
  26. eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )3 y. f6 Z3 o, G" z, ~8 ^
  27. {
    % p, s  q& B% p$ H* v( f5 ^$ O& e
  28.     USHORT usRegIndex = usAddress - 1;
    + D7 A; P. T$ U
  29. . }. f8 b' K1 B3 T' V
  30.     // 非法检测
    $ e& I8 G) M) r2 K+ n
  31.     if((usRegIndex + usNRegs) > REG_INPUT_SIZE)7 f- W! n9 ^3 r
  32.     {( Q" U1 F9 F4 s* y4 g
  33.         return MB_ENOREG;" c; K3 q: u1 u2 _% B) e& L
  34.     }0 I7 C% Y6 u4 R7 X) i  ~$ w

  35. & ^# t/ X$ a4 O2 h1 k, Q/ }
  36.     // 循环读取
    : \* Y3 {" h% q
  37.     while( usNRegs > 0 )
    6 t( d9 q3 v0 Z* d  ?6 i
  38.     {
    6 U3 p- A3 x, S6 N+ J; B( m
  39.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 );  [6 C5 ?& W& o8 [  ?' x
  40.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );/ \# i2 _' R( o
  41.         usRegIndex++;- W1 F3 S- Z) W( Y9 M
  42.         usNRegs--;) `+ C/ ?- t% q+ ~3 m# c
  43.     }1 a6 b' ~# x) L% e* C
  44. ' m5 B/ T3 p) v$ W) X0 h
  45.     // 模拟输入寄存器被改变2 T* Q/ R0 q# T9 A  b. t
  46.     for(usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++)* x8 y) b* ]) M8 C" @3 @6 y
  47.     {* G0 E! Y* x) i
  48.         REG_INPUT_BUF[usRegIndex]++;& E, w2 b! p$ N; w0 |
  49.     }
    . O& h. Y$ U1 C7 F9 o4 d4 A/ E+ ~

  50. 3 x. f0 I$ P0 _: B! E
  51.     return MB_ENOERR;& [+ M2 M- D2 ]
  52. }" Z9 t  q/ [8 X

  53. 8 w# }4 e* x. |1 A$ F4 B* x5 j
  54. /// CMD6、3、16
    0 e$ \* [! c# N* L. k" o1 _. s8 }
  55. eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )4 [9 q5 m. i$ N7 s3 C8 B( Z
  56. {
    $ ]8 X" ^' C0 N* h( T8 ]
  57.     USHORT usRegIndex = usAddress - 1;  
    ' [+ e( E5 N7 J; P- _1 d
  58. , _1 Z" B& n: K1 V" v
  59.     // 非法检测# C/ c/ y9 l  L3 J% |4 ^) k
  60.     if((usRegIndex + usNRegs) > REG_HOLD_SIZE)
    - I2 \& b9 ?" G  G0 i6 v- G, H0 m
  61.     {; b7 R4 `9 ]- L/ p$ n3 F: v; k! v" e
  62.         return MB_ENOREG;; V5 j' D8 @$ W5 P! L
  63.     }( }3 U7 j: K# \9 f. `
  64. 8 ]! [! p# j# y+ h: ~
  65.         // 写寄存器' u3 k' h) K  F. I5 Q  j' a
  66.     if(eMode == MB_REG_WRITE)
    0 d" O& O  P" D% v& _  l
  67.     {
    ; `( n" c: F* Y0 ~8 g
  68.         while( usNRegs > 0 )% d2 B. t" s; s  i7 R$ q% o6 J
  69.         {% c# e; v, j# o
  70.                         REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];7 p; W7 Q1 s) W( h- o9 [# j% E
  71.                         pucRegBuffer += 2;
    " _6 D* o9 Q! z/ }  n9 S6 d2 x5 L
  72.             usRegIndex++;
    ' R9 n) Z2 u. G
  73.             usNRegs--;$ {. H$ x: Q  Q4 c7 Q
  74.         }) _- t2 M# w  x& Z7 ^9 \0 H2 J
  75.     }
    + h, v- l( P1 y0 k
  76.         
    7 s0 l; A% ?2 R& q
  77.         // 读寄存器
    . ~: p4 V& ^3 g  Z- M
  78.     else
    4 ~6 v# A$ s; j7 h
  79.     {
    9 G+ z, e4 r; }8 C* B# g) `
  80.         while( usNRegs > 0 )
    % c/ y2 l( }$ k
  81.         {
    6 e# g# t! z- y5 R7 d
  82.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );
    ! ]. g6 {2 c# h1 `. Q7 Y/ E5 I
  83.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );
    ' h4 T% V- j. ~+ S- u( }
  84.             usRegIndex++;! t9 W, W* k( |3 y$ G3 ]
  85.             usNRegs--;
      Z3 S4 b+ B% W* R. J
  86.         }
    * ]# h* }. E* b; I! H9 m' Y0 j( `
  87.     }
    , f& j" D  ?$ I+ C1 P* P) S
  88. 7 d, j4 Z+ [8 h5 b  d" }& [0 w
  89.     return MB_ENOERR;
    % Y$ ]& m) F) t" R) p* d
  90. }
    ' Z* U* y4 b0 ?7 Y

  91. * e9 {# x  E( c  w) P* a/ Q
  92. /// CMD1、5、15
    . A4 i# Q7 M- N4 b6 N3 g+ G
  93. eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
    0 ~8 c7 \& x9 ], X* Y' V  e
  94. {& p" P+ J- F- N$ v8 b
  95.     USHORT usRegIndex   = usAddress - 1;4 _. a3 k& T* k9 M3 j* N
  96.     USHORT usCoilGroups = ((usNCoils - 1) / 8 + 1);
    / _" M7 [, o- _
  97.     UCHAR  ucStatus     = 0;2 z" x+ F1 Z* R! b- m
  98.     UCHAR  ucBits       = 0;- _% c, M( [# t3 `% g6 b
  99.     UCHAR  ucDisp       = 0;+ o% R2 H% y- r% R) I9 A
  100. / {2 I! g; u9 `! T  a; E
  101.     // 非法检测
    $ p6 n! t- x: ~! a) q4 P* n( R  U
  102.     if((usRegIndex + usNCoils) > REG_COILS_SIZE). T# k# {$ h& l+ _1 e
  103.     {
    6 _& F% r& A" y' Z( |2 c$ V
  104.         return MB_ENOREG;
    $ ?0 |7 b' b( u/ j
  105.     }
    + G% _6 m3 r& o6 P

  106. ( j9 i/ x0 n* E+ y* r$ |" d6 T
  107.     // 写线圈
    % j- j( L% `4 A; z% x" D; V7 _% U  ?
  108.     if(eMode == MB_REG_WRITE)" }8 M( {- U8 Q% m6 x: o6 P  J
  109.     {- _3 J  G, q, e+ A# J% n0 y6 I
  110.         while(usCoilGroups--)9 `" P3 s/ _/ G
  111.         {! m/ P% Z* V6 ~& N- L+ Z
  112.             ucStatus = *pucRegBuffer++;
    ; m( h  `; ~, A) U+ _
  113.             ucBits   = 8;4 G0 J+ k' F9 F; W4 @
  114.             while((usNCoils--) != 0 && (ucBits--) != 0)
    9 q+ d6 V6 G& i- f- {
  115.             {1 y  J' s0 e' ]
  116.                 REG_COILS_BUF[usRegIndex++] = ucStatus & 0X01;
    & g& H$ ~5 K/ n9 Y
  117.                 ucStatus >>= 1;
    ! c# j+ H1 a2 j; a, N( D$ _
  118.             }8 f8 C% n1 ]* b$ N! x& y
  119.         }
    8 x% F  j" D& g; F+ c
  120.     }. X4 h3 h: y& V  s; v

  121. & Y# }5 J& S$ j
  122.     // 读线圈
    ! I( D' d; L* ^# X+ T
  123.     else
    4 a) ?6 {5 @7 i; ]/ H) _
  124.     {
    6 E7 G: _: l3 O5 _# s6 h- {: a
  125.         while(usCoilGroups--)
      U3 i5 v! f) d' i
  126.         {
    ) R% i+ L/ P9 s1 ~- Q! b
  127.             ucDisp = 0;: ~' b* l/ O  }" r5 C5 `! T
  128.             ucBits = 8;
    + E# F& @8 V( X  v- _/ m
  129.             while((usNCoils--) != 0 && (ucBits--) != 0)
    " s* x6 r) v+ S' }
  130.             {
    9 j5 e! c2 E6 _; `" M$ W' n) u* l; Q
  131.                 ucStatus |= (REG_COILS_BUF[usRegIndex++] << (ucDisp++));# d* X$ P$ y, O
  132.             }5 r( A" |( v4 a/ C, Q4 P9 R, T! m
  133.             *pucRegBuffer++ = ucStatus;
    + `9 y8 f( \# }2 S$ ~& V! Z9 V8 w$ W
  134.         }8 P5 t! c! O$ {8 Z
  135.     }% L# z0 k6 {. V. I  I# T1 z
  136.     return MB_ENOERR;
    2 T# }4 R" k2 `8 t1 p4 w( N
  137. }3 x5 ^+ o2 M+ c; `1 C" @

  138. . n) b  }( O8 G; m

  139. 8 M4 d/ V  P/ p' F/ {; x
  140. /// CMD4
    # B. b: X% y3 @' D
  141. eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
    7 a3 ~4 \9 g$ ^
  142. {2 G0 U5 G4 ^* w7 I3 c! W+ d5 S0 Y
  143.     USHORT usRegIndex   = usAddress - 1;( m; i3 I- K; t  T8 [
  144.     USHORT usCoilGroups = ((usNDiscrete - 1) / 8 + 1);; F0 `+ p8 l" ~5 A
  145.     UCHAR  ucStatus     = 0;
    / n; ~, s, v+ {6 E
  146.     UCHAR  ucBits       = 0;1 A- v. u  ^, p( R% ?( f; p; c
  147.     UCHAR  ucDisp       = 0;
    4 K' S  J" B3 n( c
  148. & h8 f( }3 O8 e. E& k
  149.     // 非法检测, `. O/ ?, @" t5 Y" W. [4 C6 u
  150.     if((usRegIndex + usNDiscrete) > REG_DISC_SIZE)
      L6 p  K$ n, t) j% b- b  ]  U1 u
  151.     {
    - z' D, }6 E1 j8 p. G
  152.         return MB_ENOREG;
      L. a8 D/ F8 L- U& W7 I
  153.     }) {; y4 ]4 r0 h  g: p* R$ {
  154. ; F" A2 t) s7 Z! D# z
  155.         // 读离散输入
    6 i/ S! s: J2 {
  156.         while(usCoilGroups--)3 W7 V# e; E8 J3 i; m# W; ^
  157.         {
    ) E- P' [% X1 W' |
  158.                 ucDisp = 0;6 f3 w9 W. l+ U6 N& e; E" b: o
  159.                 ucBits = 8;9 C) u6 D; p3 F; h  o
  160.                 while((usNDiscrete--) != 0 && (ucBits--) != 0)" A1 S/ h: s2 h( W+ m3 }' @1 ?
  161.                 {
    ' A+ `) Q+ j* Z8 O! D
  162.                         if(REG_DISC_BUF[usRegIndex]): w$ R* ~/ M1 L0 W7 j6 ]  X1 S! j2 T
  163.                         {
    ( o  Z, X- y, m- j
  164.                                 ucStatus |= (1 << ucDisp);
    6 B: J! }& t0 g/ o
  165.                         }- \. D. @( ]/ H- `7 _+ R- C" w
  166.                         ucDisp++;
    ' B( h+ ~$ F6 K- m, V1 Z4 R) u
  167.                 }
    ; c* F/ c* L2 O6 V
  168.                 *pucRegBuffer++ = ucStatus;
    ' F: r% D$ ~! s/ }
  169.         }2 k; T" W0 B4 @" Y; J  V& S: C! Z
  170. : I$ t( d. p. C9 t2 l" i
  171.     // 模拟改变* K9 m- A- W( S
  172.     for(usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++)3 `" S# O* O; @; o5 Z% A
  173.     {$ ~* z/ \, g  G/ J& J
  174.         REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];. |. N! x6 Z: s+ Z3 ]- v2 X
  175.     }
    + P6 F) c5 |- h7 l6 y. \" H' w
  176. " p- N. l! t0 b8 x/ H% D' y4 u4 b; L
  177.     return MB_ENOERR;
    % j# ~/ T4 }8 {  R
  178. }
复制代码
2 {0 v/ B5 T* F/ W, `
主函数
) d# c) ]# K; n+ U5 e( S
  1. int main(void), L6 U5 w  s: {6 O# k- C
  2. {
    - g5 K" o2 a$ d* Z  t; X
  3.     HAL_Init();9 V' Y- w9 C: F; c8 Y. K% T2 Z
  4.     SystemClock_Config();( [- Y8 R0 q% Z* K4 R
  5.     MX_GPIO_Init();
    / P* S2 F- b$ Q. m* i$ A4 g
  6.     eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_ODD);                // 初始化modbus为RTU方式,波特率9600,奇校验
    1 k# s. k3 }8 @7 U; _. D% a
  7.     eMBEnable();                                                                        // 使能modbus协议栈3 _5 g7 e  w( w4 ^2 p2 U

  8. # V6 e6 G0 [! G# j5 l* _* M% S0 Z; q
  9.     for( ;; )% n3 g$ G8 b( G7 Y
  10.     {; _( ], Q7 ^  f1 g. o
  11.         eMBPoll();                                                                        // 轮训查询
    * W( B# u% ]' U$ B" U! n/ T
  12.     }6 \' K0 G- T3 M& }. g) N$ L) B; d  i
  13. }
复制代码

4 M* w2 Q2 j4 E  q. s8 @$ e  @* C移植测试
7 E! F  g* a& y+ R% d/ B2 Y% l9 Q* y
20200313154857173.gif   J/ z( z5 I" ]: B( E

* F! d7 ~, N2 O6 }* w4 W7 uends…
2 O8 N3 _  b' \. {& b# }$ i+ L; j$ |

1 X, O5 [$ n5 n) k5 V, e
5 G3 e0 b! J# U2 [
收藏 评论1 发布时间:2022-4-10 22:53

举报

1个回答
zzzff 回答时间:前天 10:31

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

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版