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

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

[复制链接]
STMCU小助手 发布时间:2022-4-10 22:53
modbus命令码表:
6 T5 Y7 F2 \  s: r: x; i2 a) W+ l$ v, W: T
b8032deb4d154657acd2f7f2942369d4.jpg
5 b7 o* t* B6 B4 ~# q' h
0 A! E$ C; `. }- z1 P4 ~# ^8 H- LFreeModbus文件说明
" v4 f+ r  U( T; t
      解压freemodbus文件后打开,我们需要demo目录下的BARE,该目录下的代码是空的,STM32移植工作基本就是修改:portserial.c、porttimer.c、port.h这三个文件。6 N1 A% I6 |' y8 r: ?
20200313143257958.png   E2 k" ]. S7 [5 m4 }, O" O6 q
" [1 n9 m) r1 ]' f) K  g; v
      mobus文件夹就是完整的源码,包含rtu、ascii、tcp:
2 x9 R* C0 M4 j$ `
# \+ f8 y0 k6 F7 I4 D, W ZM%DLXPRB8$%[NN2%4Z1N.png % D" @  u2 C! _  L  Z, s, _
5 L9 i+ e! v' }- r+ n
      我为了移植时在keil添加源文件和头文件方便,就把modbus所有的头文件和源文件放到了一个文件夹下,并创建了一个port.c文件,用于编写modbus所必需的回调处理函数:3 t' c/ h: f4 l4 ?# }  `$ r

$ O6 |# O' ?- n$ M  U) a& G 20200313144036579.png 5 w2 ?( N; q  B0 @2 N

4 {# Q$ Z: B8 X: y" ~, z% I, MSTM32CUBEMX配置

6 s$ v5 g- ?9 E& A# o+ e( X1 f时钟配置,设置主频工作在72MHz下:
" [: K& |% t# |) N" X
. ~- I( {! b( p3 l, N
JU1~N33M}I7K1(6K@JFN5~R.png ( @! u( f% S* O( g
3 {% f& |8 @( r  o
配置串口1,这里随便配置就行,在modbus移植过程中还会对串口重新初始化:
. c* z" v3 {* I- q% A0 k: o

2 z: s5 m' U6 |) ]4 g" b; C+ I3 O U25OQ_FHYD5WEXLFMI4V@RU.png
/ U; L3 S# w7 @) N! M& c0 i6 X4 b# }" l4 Q: F! a0 ?
配置定时器4,用于3.5个字符的定时检测,这里随便配置就行,在modbus移植过程中还会对定时器重新初始化:
6 |" K# C, N( J4 n

6 f& H% ?, @6 Y; D% H6 V* O+ R2 x+ P H6{)WT`**CIHDAM02558GK.png 8 u/ ?8 u6 n4 j+ Z3 g- o3 `/ C
8 A3 Q% E7 N8 t) x7 l
中断配置,这里注意,串口的优先级是要比定时器优先高的:
: F, u, Z" c. u2 r

" N8 o3 p  T# H8 S/ s. T/ Q0 y G(RP`74TR)NPJFUK``Z%I2L.png
& Q9 S( Z2 A% q* {取消掉自动生成中断服务程序,在移植过程中我们要自己编写串口和定时器的中断服务程序:
1 p: w" c$ ]* r' R+ I( r  b
, H/ A% o' L# a5 r; j5 ~ ALHMK5Y615K6(`M{0[]YJ.png % E9 S% E" i: W4 b% L2 }

8 V' o% b* a' e2 b+ R0 ^移植代码修改

" p% [9 |& h2 W0 W! {生成代码后将modbus放到工程目录下:+ L  T& g# ]9 y& D  o: U9 u( o- o

4 i+ K  B/ v$ r+ b8 K- C
5%(_LMGIM_8_YGL`]JGAB67.png
/ B, o( w, U  R, J  x/ S
* Y. a3 \4 d/ J9 s( \" g打开keil工程添加modbus源码:
2 Z5 `" U5 t) H7 T' \6 ?; }
: j3 r; Y7 ~6 c9 k5 l8 E
F`8_YFACMNOAP28~2VHD{CO.png , f* j5 `8 ]. i+ n
. c$ g0 Y/ T* p& H' e* ]/ g
添加包含头文件:

# F0 k! ~/ b0 ?- e8 g3 p9 W: w- j+ F2 Q/ D6 I7 K
`7BMVXA`R9SQBTGT`B@{]X7.png 4 v: ?/ @! J' ~) j
, q1 n1 D4 y2 _9 b; \7 x6 C( `
修改modbus定时器初始化源代码porttimer.c文件! @1 N8 I. Y; \7 R& |- o5 l: i
       定时器的修改比较容易,将定时器设置为每50us的时长记一个数,传入的usTim1Timerout50us变量给自动装载即可,prvvTIMERExpiredISR函数需要在定时器中断服务函数中调用,它的作用是用于通知modbus协议栈3.5个字符的等待时间已经到达;由于我们在STM32CUBEMX中取消掉了定时器和串口的中断服务函数程序,所以我们在该文件中添加定时器的中断服务程序,修改后的代码如下:& w9 Z- Q2 w  q$ p- I

% b* E$ p) I, b4 g8 U+ [  E
  1. BOOL
    ) s& s; C0 V: ^" e* V+ p8 h( m- C
  2. xMBPortTimersInit( USHORT usTim1Timerout50us )
    $ ^3 H) Q6 p( @" @+ S8 S
  3. {7 U( {+ U, w/ D6 p& X
  4.     TIM_ClockConfigTypeDef sClockSourceConfig = {0};  [% a) b1 U6 k# l0 d7 {) Z& X
  5.     TIM_MasterConfigTypeDef sMasterConfig = {0};8 E" z5 S! b9 H7 l; o

  6. ! r3 [! u, R$ n8 ^
  7.     htim4.Instance = TIM4;
    6 e  ~% N: S9 h' o
  8.     htim4.Init.Prescaler = 3599;                                                                // 50us记一次数
    0 F: g6 S# J- T6 y5 t, l! l: e
  9.     htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
    $ Q, o$ w6 H# ?! n9 c3 s
  10.     htim4.Init.Period = usTim1Timerout50us - 1;                                        // usTim1Timerout50us * 50即为定时器溢出时间6 Z* Q6 r- g8 S
  11.     htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    1 B/ Y  K3 H5 w  L
  12.     htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    9 B" N' w; ^) b, _
  13.     if (HAL_TIM_Base_Init(&htim4) != HAL_OK)5 c( Q$ V5 T" M6 {6 }! A
  14.     {3 m  x. v7 X- m$ ~
  15.         return FALSE;8 l0 z# p# O1 N4 E: X: g/ s
  16.     }
    ( [- f. I8 c0 P2 |) C
  17.     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;7 a; I6 }; D1 k
  18.     if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
    " n% a# H* h7 {$ B: c5 M( ~
  19.     {# q  u* B  g% H) G7 N
  20.         return FALSE;
    2 u! q( G8 r6 A
  21.     }
    * f. V" }: L: P/ G# I( ^
  22.     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    7 ^, s# e! n! G8 C$ `* w
  23.     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    ) K* j4 ^* ?5 Y
  24.     if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK): H' P8 p3 \4 L- n
  25.     {
    # T0 w; ?5 ~$ Y
  26.         return FALSE;
    ' l5 Q  s! q# G/ ^8 Y2 ^
  27.     }
    3 _, _7 c5 F# w+ B* ~

  28. ( f6 l" e- }; K, R
  29.     __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE);                                        // 使能定时器更新中断
    7 ]% q0 W" c! E
  30.     return TRUE;) o: n; p. C5 f8 V1 ^, r- ]
  31. }
    : a: Y8 o  k0 \
  32. $ l7 k4 G. p" |1 @6 j+ n) H; `
  33. inline void
    6 e' H% {3 {+ H/ r: M; b$ W0 Z
  34. vMBPortTimersEnable(  )
    3 {/ l- n  P/ Q
  35. {+ g" [( C0 v6 W) R
  36.     __HAL_TIM_SET_COUNTER(&htim4, 0);                // 清空计数器5 H. ?# M9 r" s& Z$ v/ t' R; v
  37.     __HAL_TIM_ENABLE(&htim4);                                // 使能定时器
    8 S8 v# j. a9 [* H
  38. }
    : D! ]! v2 R9 \" Q7 B# i

  39. + X: S' U& }2 r" S+ f
  40. inline void5 W& e7 X( {, N! K! Q2 i5 c
  41. vMBPortTimersDisable(  ). ?: h0 _6 k+ F
  42. {2 q4 N2 h* z$ H+ f' E
  43.     __HAL_TIM_DISABLE(&htim4);                                // 禁能定时器! q" k2 M- y" P3 _" L. N
  44. }: G, u% C% Z. u' w9 a

  45. - X9 A' W+ Z! ^
  46. /* Create an ISR which is called whenever the timer has expired. This function* ^! \6 @  A1 e- e6 F$ J7 h& A1 F* A
  47. * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that; c, L5 M; K1 E4 ]9 S1 {5 ~
  48. * the timer has expired.
    9 o+ x/ I5 p  \6 Z$ d: ^# z
  49. */
    ' A4 d. m8 s4 o+ F3 z9 o. S
  50. static void prvvTIMERExpiredISR( void )
    ) [' h7 s% r. h" G, }/ J- c
  51. {! g" g3 J. o/ ]' m
  52.     ( void )pxMBPortCBTimerExpired(  );$ b; w0 w4 R7 H- j/ x3 P- S
  53. }( F* V9 v) ~- O9 _
  54. 3 o3 F4 m, _2 y8 A3 L3 C
  55. /// 定时器4中断服务程序
    ; D" o$ V2 W; \. q+ _* ]; R
  56. void TIM4_IRQHandler(void). z5 g! w. M$ v2 m: ?
  57. {; W6 `9 G9 S/ n* V, ^7 a- [
  58.     if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE))                        // 更新中断标记被置位
    1 k+ D( x! a4 k+ @# b' r
  59.     {
    : f. V6 q: {: j3 k/ B- o& b  q# [
  60.         __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE);                // 清除中断标记
    " Y: z: p$ v  P9 H3 Z; ]) |4 R
  61.         prvvTIMERExpiredISR();                                                                // 通知modbus3.5个字符等待时间到$ C: _1 ^* }) }, a7 M1 ~6 u+ D& l' b
  62.     }' T0 ?9 h6 D9 c$ z( b( P, g
  63. }
    , ~) i3 t* A: ~1 F; t

  64. & a1 ?1 @3 p) U! a* I: R5 a7 ]! \. x& ]
  65. 9 ~$ m9 P# |' E) g! l
复制代码

! j% l# X% ^( S, u+ q修改modbus串口初始化源代码portserial.c文件
$ e! `! O" ?  O. M4 I! k         ~~~~~~~~        在该文件中实现串口1的中断服务程序,prvvUARTTxReadyISR和prvvUARTRxISR函数需要填写进中断服务程序,前者得到作用为通知modbus协议栈串口已经空闲可以发送数据了,后者的作用为通知modbus串口1有数据到达,修改后的代码如下:
) ?( k# T! b- Z# y% e" l. Z- G; p4 X: x% V  T/ H8 v1 w
  1. /*
    9 k3 O. o; d: \
  2. * FreeModbus Libary: BARE Port
    1 ]1 o3 d$ V* \) y3 _- P
  3. * Copyright (C) 2006 Christian Walter <<a href="mailto:wolti@sil.at">wolti@sil.at</a>>) H) w$ I2 l7 Y- d( d* D
  4. *
    : E; J& O& [5 r6 C( P/ ^$ [
  5. * This library is free software; you can redistribute it and/or4 {' W5 o/ a: P& K1 C" r  X
  6. * modify it under the terms of the GNU Lesser General Public
    . S% V: C* \% c1 |  |
  7. * License as published by the Free Software Foundation; either( {( M: D) z% ^) P$ d
  8. * version 2.1 of the License, or (at your option) any later version.
    ! z+ r& N8 N" h9 U' n: ?
  9. *! i, Z9 N- ~0 c  ?  o5 c
  10. * This library is distributed in the hope that it will be useful,4 l$ t. Z3 e8 G
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + P9 n) K# @9 }) M
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    $ E5 w% ?$ z$ A7 L, M. S5 W
  13. * Lesser General Public License for more details.* c1 C7 V! Q$ B/ T5 u7 V
  14. *% p" V4 l0 N0 ?9 c
  15. * You should have received a copy of the GNU Lesser General Public8 c' {. y' m# G. _) n/ ?3 z4 c- g4 }
  16. * License along with this library; if not, write to the Free Software
    + ?$ ?0 F, l# X; G
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA# w& X& V! c4 R) U! E1 `
  18. *
    " W3 D, a/ S$ A- {. I* I
  19. * File: $Id$
    . E, }: x) P4 b; `# ~2 o' J) Q
  20. */! p6 \, w" N9 c+ J- }1 x: ]

  21. 5 w+ i" U: U& a/ `. }
  22. #include "port.h": t8 F* X6 W. \5 E! K. K3 F6 E" o
  23. #include "usart.h"  \) H5 h* `- ~# M+ q

  24. 1 {1 {* N( K0 H" w4 m' Y
  25. /* ----------------------- Modbus includes ----------------------------------*/
    / j; f2 k: J) m2 P+ [: Q# [0 g# A
  26. #include "mb.h"
    " e& N6 y9 {5 W0 _: K
  27. #include "mbport.h"+ X& J% X1 c+ u- r, Z+ b0 i4 j* G

  28. ' K! O7 u- X$ ]& ]+ b6 ]
  29. /* ----------------------- static functions ---------------------------------*/
    8 v) S. ]9 l8 i* N! Y$ k
  30. static void prvvUARTTxReadyISR( void );( G! }6 z" ^/ O7 q( u, \5 `' t' f
  31. static void prvvUARTRxISR( void );( L' l  w5 u  W, k: n$ U

  32. ! c+ B1 W9 Y% y0 u' i9 e+ }  t! R
  33. /* ----------------------- Start implementation -----------------------------*/
    $ ]: {( F# K. d" m: k, z* X& L
  34. void5 ]# v: q, r0 F$ Z$ }2 Z0 D
  35. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
    " k. T$ O8 L0 g; S9 `
  36. {& [  ]( f! S& ~+ ^2 g
  37.     if(xRxEnable)& [' i8 n; G- L8 J9 C$ `: n
  38.     {
    . g4 Y/ B& n' p, ?
  39.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断
    * a3 g* z# z' J. @
  40.     }; f* S, ^" |+ A
  41.     else  O5 n1 q' Z8 g* K' a" L( \: |4 `
  42.     {. ~8 V0 ]; i0 s$ T* C
  43.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断( {  _- W6 [# u  {/ \9 k9 z
  44.     }
    ' Y2 h$ @9 F7 y' }
  45. ; m% Z, \9 b1 ]! h& U0 f; B
  46.     if(xTxEnable)
    ! A( z* y9 u  {: m0 ~( a9 t* ], I
  47.     {
    ( t9 [8 g8 _7 q/ ~; Z5 e
  48.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断' n5 t) P1 }+ q: j! N/ l0 S  [& Y
  49.     }' o) q' l/ \# M9 d
  50.     else
    3 F" C/ d( p( }6 N. Z$ Q
  51.     {
    ) W. E% r+ \0 R
  52.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断
    % R+ [: F. m) B# B" L
  53.     }
    - P) p1 A. L( x/ m# D0 r1 @
  54. }
    / G# J& W* @( }9 _: p

  55. ( K. U  n5 W0 }3 R2 r" `
  56. BOOL2 A$ L) E- f. B
  57. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
    0 f" _. R* b, W5 c" Z3 I/ X
  58. {9 r  z" U2 K* S3 |2 M) Z
  59.     huart1.Instance = USART1;
    2 r  C5 ]: U% a) ^6 g1 K# W
  60.     huart1.Init.BaudRate = ulBaudRate;! _, v" K, X" M" K, r  D
  61.     huart1.Init.StopBits = UART_STOPBITS_1;
    * ^( F/ p; r7 @, [1 z
  62.     huart1.Init.Mode = UART_MODE_TX_RX;
    / p: P* U$ l  `3 w9 H6 |8 X$ y8 p
  63.     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;  ^( u: @/ S, V* ?% m4 [8 K9 `# b
  64.     huart1.Init.OverSampling = UART_OVERSAMPLING_16;$ ?5 d# X  i+ q, ]0 p9 ?: o* n' U

  65. 2 j; |. G1 e3 r& h8 {, l$ ?3 ~
  66.     switch(eParity)
    & f1 v4 V9 W# N6 G9 Y9 `
  67.     {
    2 c( @" [4 m% d1 \, ]6 j# S6 O; g
  68.         // 奇校验* {4 |0 d- e- w3 S
  69.     case MB_PAR_ODD:
    4 ^( d" u" \8 d3 {7 Y3 |
  70.         huart1.Init.Parity = UART_PARITY_ODD;$ h! \3 }+ T) y2 c( `7 V1 Z, G
  71.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits& {% P0 S& \* P7 K% u1 k/ o
  72.         break;' O! S3 }4 |) b2 N* Q
  73.         
    * J4 O/ t# c2 r$ y
  74.         // 偶校验
    ( V; h! _2 i# n5 B: M  o4 \' M* Z" N2 h
  75.     case MB_PAR_EVEN:0 _; I# z- @0 d; n- O6 C% G
  76.         huart1.Init.Parity = UART_PARITY_EVEN;) W0 I9 A$ d0 n) W8 w
  77.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits
    , t2 C6 b* i( c  t
  78.         break;* K! Y9 W+ }- I* t+ q8 k5 T
  79.         " K! K& w' P' @( u& V% B9 M
  80.         // 无校验
    ! R$ q' o, ^" }# u! \
  81.     default:
    % }" K" R+ W' P* a
  82.         huart1.Init.Parity = UART_PARITY_NONE;
    - B, e/ P5 {/ O8 N0 D' w
  83.         huart1.Init.WordLength = UART_WORDLENGTH_8B;                        // 无奇偶校验数据位为8bits5 ?* O; k: U1 s" }
  84.         break;
    1 a: ?# w/ z( v) V+ K! N
  85.     }( w2 r6 a" P$ K: S: i1 C
  86.     return HAL_UART_Init(&huart1) == HAL_OK ? TRUE : FALSE;) P- q; |& D4 T7 r* U1 l
  87. }4 ?5 N; M* j+ D8 b

  88. * Y7 r. }7 @3 @( ?  J
  89. BOOL
    4 x; A! _1 H7 D4 F
  90. xMBPortSerialPutByte( CHAR ucByte )$ w4 k* v9 ~4 K
  91. {+ S: Q8 Q6 v! _5 ^7 P' H
  92.     USART1->DR = ucByte;8 J2 I2 `* f$ I/ ?- f
  93.     return TRUE;2 ^; a9 D/ p+ t1 w
  94. }" K# w" N5 m/ O% H) b+ Y

  95. 0 }( T4 x1 R; F( s# r
  96. BOOL
    . ]" ?8 U& h; r9 ?" P! S/ ^
  97. xMBPortSerialGetByte( CHAR * pucByte )  q# E5 f) C0 w) _* o2 F
  98. {
    / @* w* V9 L; `9 s& e( X
  99.     *pucByte = (USART1->DR & (uint16_t)0x00FF);& I+ E! n" w* y5 ^; \2 N
  100.         return TRUE;( a6 p/ o9 u" O5 s" j
  101. }$ G4 {0 G5 Z- _: G9 j, c
  102. 8 z& B$ d% ?" @: g0 L
  103. /* Create an interrupt handler for the transmit buffer empty interrupt3 _3 P+ }- w; ?8 L
  104. * (or an equivalent) for your target processor. This function should then4 ?; V7 K* B. J" M; p
  105. * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that5 v  p- ?! |3 x6 {
  106. * a new character can be sent. The protocol stack will then call0 n6 o2 R4 ]! Q, Y$ l
  107. * xMBPortSerialPutByte( ) to send the character.
    ) i& Z& L, A! }' @. Z
  108. */
    9 |5 R. L2 y3 w* c" h
  109. static void prvvUARTTxReadyISR( void )
    ' T! R. S9 U( O& a
  110. {
    6 `1 [' U  |# F' A7 x' v
  111.     pxMBFrameCBTransmitterEmpty(  );
    * s0 w& ^2 d1 i, u
  112. }
    9 g; T: @) T: d7 Z  ?+ p% S9 l
  113. % o6 n2 G8 f& h- d  H: j
  114. /* Create an interrupt handler for the receive interrupt for your target3 L9 ^2 z# w/ J9 g: s# h
  115. * processor. This function should then call pxMBFrameCBByteReceived( ). The  W8 {  L9 x7 l  A9 O7 \! ]* r
  116. * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
    6 E9 H1 n# M6 R& j. k# f
  117. * character." H5 G* s. H* m+ @! z8 |
  118. */' t6 P! r/ W8 O6 L! o2 z
  119. static void prvvUARTRxISR( void )
    ' `$ N3 N5 z+ ]+ w* a' k
  120. {
    ' _7 t+ Y) e$ L3 A- W) R, M3 R
  121.     pxMBFrameCBByteReceived(  );( `4 n% w, G5 s$ ^
  122. }* B1 \$ L) D8 l8 Y+ T  h

  123. ! t+ U* [; M; q2 [2 K
  124. void USART1_IRQHandler(void)
    ; x7 X! `+ m4 m( r) l3 P
  125. {3 H6 I% Q- t6 @2 [
  126.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))                        // 接收非空中断标记被置位
    1 k& Y7 w! C) t/ X, |+ }. K4 l
  127.     {
    * ^# F) o( d% M$ s, H4 N
  128.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);                        // 清除中断标记6 f: p  \' @1 R6 u- P
  129.         prvvUARTRxISR();                                                                                // 通知modbus有数据到达* v: i: \1 `5 u3 O3 q. b/ y
  130.     }# y1 ^- ^8 O) w. b
  131. 9 \4 l/ k- F# ]+ ~9 n  u2 v
  132.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE))                                // 发送为空中断标记被置位+ C1 K* z8 r4 t' e3 s2 n
  133.     {: o! I' J4 L% F
  134.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TXE);                        // 清除中断标记
    ; m* w/ p. m2 ~7 ?/ D
  135.         prvvUARTTxReadyISR();                                                                        // 通知modbus数据可以发松& }1 i+ D' w8 A6 D( g
  136.     }; H, K% B, V' @& o3 b4 l7 s
  137. }
复制代码

) w- D: b9 z; [  S- t注意一点,一般如果使用了485芯片的话,那么同一时刻只能接收或者发送,可以将函数vMBPortSerialEnable修改成这样:. Y# j7 f9 ?; r" q: i  }  r- \
' Q& `& u+ E* g' N0 b
  1. void; Q7 ~- X2 s9 V  y8 {
  2. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )1 e: M$ V) }$ w+ ^3 x5 F, s7 i
  3. {
      m6 X) J; \* r
  4.     if(xRxEnable)' Z6 H1 y3 L  t1 C- o7 d" P
  5.     {* g0 q9 U! m+ X. [5 M& m0 k
  6.             //
    2 T0 I7 u% V9 J( g
  7.         // 在此处将485芯片设置为接收模式  q& M" ^! X  h
  8.         //
    8 o3 q6 o" }. u
  9.                 /* do something */
    7 R# a/ h) @* W" d0 A* }# E
  10.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断
    " y' P0 K# N" O  v% M4 f- X: `
  11.     }+ ]5 p  J5 O: y( ^4 {
  12.     else; L& x7 [% U  z' E: D" o
  13.     {
    ( w0 w- t% D) e" s
  14.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断) b$ D6 y, ]* M( d& R/ w
  15.     }) \1 n9 `  s& p8 H
  16. 8 E- {5 ~7 |2 l" e( L
  17.     if(xTxEnable)
    8 j: E; m6 r5 R
  18.     {
    & h2 c' K7 l  W) ^8 }
  19.             //
    , J$ t; K# h1 \* d1 G' C
  20.         // 在此处将485芯片设置为发送模式" N! l) ~- P" `0 S% H4 Z
  21.         //1 A" F' M4 C2 o- g  L# c  L
  22.         /* do something */4 \; N8 K$ e3 Z; B
  23.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断* L* n* J) J& N# G1 X) d
  24.     }
    9 E0 r+ v$ [$ M4 R6 x  S
  25.     else% ^0 m! M7 T9 E* |  ^8 y
  26.     {& C5 S) P/ R! B( R! B+ t8 Z8 Z8 Q
  27.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断' R3 h+ J9 }7 ^9 Y' X5 {" `( `
  28.     }! d+ E  ]. O, p' I% h. ?& t
  29. }
复制代码
# f7 u$ A/ d6 u: Z
编写modbus命令处理回调函数port.c文件3 M+ a5 U; G( W! p
本例程只实现了读取输入寄存器和保持寄存器的功能,详细代码如下:% q: Z$ Y' f- E% ^

; I8 ^" D. K) {/ \0 Q" I4 f
  1. #include "mb.h"% y! W! L/ p# A0 Y4 y! G8 X
  2. #include "mbport.h"
    ; N: z4 a9 ^  R0 I& m+ Q1 X/ [( G

  3. " W2 o$ v4 q. i% o: _% M* ?

  4. & T6 N+ D" _6 @
  5. // 十路输入寄存器
    8 o. B. q) s6 C) N: E
  6. #define REG_INPUT_SIZE  10
    . f8 g; }# K7 d8 V- n! f
  7. uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];; |- g2 z' W0 {8 G! g2 g
  8.   c( t( O: R6 a$ Q( e' B: r3 N

  9. . m$ Z* R7 `4 |
  10. // 十路保持寄存器
    * O$ S+ E/ E' @
  11. #define REG_HOLD_SIZE   10
    8 |2 H3 G' B8 L' h( Z
  12. uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];- i! ?& ]0 ~$ C+ ^% V
  13.   v6 v: J  z9 I+ E& \  \, |
  14. ! v/ n) M& \, `& M9 K
  15. // 十路线圈7 q6 m  ]9 R! ^' a/ j4 a8 Z' o& x/ v
  16. #define REG_COILS_SIZE 101 z# D) H( v* G8 u9 t) W3 j
  17. uint8_t REG_COILS_BUF[REG_COILS_SIZE];
    9 |6 D9 M3 D* w9 Y

  18. 5 H; S. q3 X% W0 a
  19. 4 X3 j1 S* }( E+ f; u3 T& j" y
  20. // 十路离散量: u: \, ~  s3 g& A( Q; n
  21. #define REG_DISC_SIZE  10
    + M& v  k* {8 B+ k8 c& C! v& n( Y) W# d
  22. uint8_t REG_DISC_BUF[10];" @) }$ ?  w5 A

  23. " h$ }* Y' U8 X" E

  24. % x, q* L% W# n, [/ J  W/ J
  25. /// CMD4
    & f) `! O/ m1 w% A! {
  26. eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
    9 h- l) ~! u5 R6 z( e
  27. {
    $ m4 c8 W' G# w* }3 V, M; R/ V
  28.     USHORT usRegIndex = usAddress - 1;
    ! d! a$ v+ ?" @! p

  29. 7 B( J0 H! f0 E7 M
  30.     // 非法检测/ ]: z: q' g( F  U) Z, F2 ~6 q
  31.     if((usRegIndex + usNRegs) > REG_INPUT_SIZE)
    $ q/ z  z6 {5 M; H: f
  32.     {5 f% x% J& u8 g
  33.         return MB_ENOREG;/ y* }0 D; ^+ M+ E. ^* u: _# b
  34.     }% y- d3 p( {2 @) z0 ^: `

  35. 2 G  ?. w  w! @! P& D. O
  36.     // 循环读取2 \$ c- g* H/ n+ Y( D
  37.     while( usNRegs > 0 )
    2 y7 F  d6 v8 G* ^4 n
  38.     {
    ! \3 t' m' F/ W2 O/ e% s) R6 \+ q
  39.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 );" N# g  ^9 Q" F
  40.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );
    0 s$ T! J# ~3 g% s
  41.         usRegIndex++;" U/ P6 D% p, m4 e; }9 n8 x- u
  42.         usNRegs--;9 J/ ^+ F8 n$ V2 n2 H8 }& G+ U
  43.     }/ y0 G* ~# v) q7 H

  44. 7 \/ ?6 e2 O4 l; Z$ c: R2 j) v
  45.     // 模拟输入寄存器被改变$ E% L" R& X" z% n$ @
  46.     for(usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++)8 f  B8 k6 v# A/ r
  47.     {
    6 a% k( p6 [+ l5 s
  48.         REG_INPUT_BUF[usRegIndex]++;, @, X. q- ~% I1 Y8 ~% \; ]
  49.     }2 n+ q: [2 g7 e5 G8 p4 E

  50. # |0 b, G6 d. {8 i' }. x: J% E
  51.     return MB_ENOERR;* l, w6 F7 S: Z- p
  52. }
    3 w( y" _% A7 j+ a0 p% J1 M
  53. / I' Z4 q& p5 `  a0 D# w: p7 `
  54. /// CMD6、3、16
    0 y: n9 X" v4 U' b
  55. eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
    2 q. |% D6 D0 [5 L7 p+ T: c7 a1 |% }
  56. {5 a& a& [9 E0 r( f
  57.     USHORT usRegIndex = usAddress - 1;  5 n# A% }: }+ p& U# ~

  58. 6 _' u8 e2 ~% ]0 j  \; Z' f2 I  Y
  59.     // 非法检测; E) f4 \! ?6 u7 B% O: |% W+ f
  60.     if((usRegIndex + usNRegs) > REG_HOLD_SIZE)9 Z( w; d/ p8 Y! g( n1 {! Q; k
  61.     {$ a) Z* y& R: a7 I
  62.         return MB_ENOREG;
    3 X' p6 M/ h9 v7 Q) q
  63.     }
      c1 s( x- D# q2 c8 y5 [0 x

  64. 6 C+ H! h5 Z) O8 O) X
  65.         // 写寄存器1 F: T# N% f$ d
  66.     if(eMode == MB_REG_WRITE)+ c. o  L7 Q) t3 k
  67.     {  n6 N! S2 ]- Z
  68.         while( usNRegs > 0 )
    % f7 \' H3 Y0 J& |: I) C! W
  69.         {+ s8 P/ G2 Y! _* e+ ~  [
  70.                         REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];
    + D2 ]- k8 T; ?4 S
  71.                         pucRegBuffer += 2;0 Y7 Y% Q- M; F% O
  72.             usRegIndex++;
    . P7 N$ q/ Y0 U5 K3 _- F! P
  73.             usNRegs--;6 }: x+ b  n% O( l# s# n2 D6 n
  74.         }; c& O( j  r! K7 A
  75.     }# F& o) `; k9 ^$ Z! E8 K
  76.         
    4 b7 P( {2 o4 m1 m0 C8 L( c2 g
  77.         // 读寄存器
    % u7 g4 v: n& h) ?( i
  78.     else: J. v0 i; d) l
  79.     {
    * S) _) T* ?/ {3 U* i: t. R9 f. _
  80.         while( usNRegs > 0 )
    1 [/ [1 d4 \6 x  [; X4 B
  81.         {/ m! f3 q2 j1 k
  82.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );
    % i( x$ ^: [# v3 s  t7 L
  83.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );
    0 B$ J6 l& ]3 u% o0 H9 B% }; ~. P
  84.             usRegIndex++;
    + Z3 W' }  Y) e1 O+ R
  85.             usNRegs--;. `" C* i) ]: q7 L1 q" M" y
  86.         }
    2 z" B6 _: a: z  _3 F
  87.     }
    & s7 D/ Z( Q! C* [
  88. . N% g" e2 v& L: l
  89.     return MB_ENOERR;8 L5 v+ f1 W4 I- @; {# s+ l
  90. }
    ) u" K& h+ H8 u3 f  t1 R1 s
  91. $ F) [' y$ s9 Q
  92. /// CMD1、5、15
    # m6 p6 I" H  j+ Z) d
  93. eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )! a3 ~+ k9 \+ h
  94. {
    - T7 ~7 P3 x, T) f+ V( y
  95.     USHORT usRegIndex   = usAddress - 1;1 R) }9 f5 L; }2 r$ v6 k% F1 M
  96.     USHORT usCoilGroups = ((usNCoils - 1) / 8 + 1);5 p- p5 D. y  h0 i# G8 c
  97.     UCHAR  ucStatus     = 0;
    : B2 k! Y; ^# s
  98.     UCHAR  ucBits       = 0;! T/ a: a5 ~; f7 Q0 D7 N! K# u
  99.     UCHAR  ucDisp       = 0;1 G" ^8 L% w( d

  100. & t' T7 Y3 \& ^3 {  ^/ m$ U9 Y
  101.     // 非法检测5 E( J" L$ }0 J; A% q3 z) o, Y
  102.     if((usRegIndex + usNCoils) > REG_COILS_SIZE)
    9 w+ O0 _9 @% T3 Y9 F1 ?  o& @
  103.     {% P9 @: a; |+ q% ^+ \- Y
  104.         return MB_ENOREG;
    + U! q# R% K1 s0 \7 [/ g4 }9 A; z
  105.     }
    5 X1 L# ~0 V* ]" q
  106. 8 \- D# g4 F; Z! Y! |
  107.     // 写线圈
    $ `+ B9 G$ @  v  M$ `
  108.     if(eMode == MB_REG_WRITE)
    9 ?& w: z1 w) m; G( r) d
  109.     {
    : j, U( _3 d5 i' D$ a3 S
  110.         while(usCoilGroups--)% f5 o' }+ W+ q1 c
  111.         {& g8 G/ F+ r+ x6 Q2 W
  112.             ucStatus = *pucRegBuffer++;
    ; F; q3 t+ `; ~
  113.             ucBits   = 8;! T5 ~( v) _; x! F. V: P
  114.             while((usNCoils--) != 0 && (ucBits--) != 0)
    : U& Z9 F; l. R0 F) I# m3 s9 S/ V" C+ r' I
  115.             {! m. }7 e) z& Q2 R2 F3 V# d
  116.                 REG_COILS_BUF[usRegIndex++] = ucStatus & 0X01;& M6 n" V9 A+ P. h5 m$ ^9 S$ M
  117.                 ucStatus >>= 1;
    " e; }' t( R7 P( w
  118.             }
    1 V( T1 p  z) q
  119.         }
    ( ?, Y# q- S1 Q* R! a# i
  120.     }
    * O7 G; q- ~# x( e) R  [% n

  121. 5 g+ U! {8 u" |' u; b( Q
  122.     // 读线圈
    ( s0 y" p- @& o) |5 A9 z# u
  123.     else
    & o% o& c7 g, g( L" X" v4 N/ R
  124.     {# H  K. z2 X  Q$ H1 J  u& u* h
  125.         while(usCoilGroups--)
    9 s! M) o% O- i! t
  126.         {; X- W9 D& V/ B. @6 f
  127.             ucDisp = 0;5 D) T& f" P% r7 n
  128.             ucBits = 8;6 O5 s# W: X2 L* A: R3 t) C
  129.             while((usNCoils--) != 0 && (ucBits--) != 0)
    * E) M- F6 y6 D* n; H( f
  130.             {
    , O) b4 H2 N5 A
  131.                 ucStatus |= (REG_COILS_BUF[usRegIndex++] << (ucDisp++));0 [9 C3 n6 t7 j
  132.             }
    ( m$ f  v* `% Y; O1 D) Y. p
  133.             *pucRegBuffer++ = ucStatus;+ F8 S/ c" g4 O9 C. v, P1 X1 ~3 f$ E
  134.         }
    : ]8 m' x* N% d* K
  135.     }! \( z1 i/ z8 Q9 [
  136.     return MB_ENOERR;
    ! b! r) p1 o3 g
  137. }
    - w0 Y# l4 D1 u8 p4 M8 Z8 {3 A9 ~
  138. : r4 m7 d. N! h  P
  139. $ k. [, u, `* q0 `
  140. /// CMD4
    6 K1 T2 z" ^4 D3 L& T' H' ^) O
  141. eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
    5 A( Y" K9 N; \% p# q: d. E! K
  142. {
    * v3 ]6 m) L. f7 ]: b; b
  143.     USHORT usRegIndex   = usAddress - 1;4 W6 c# O$ z2 F
  144.     USHORT usCoilGroups = ((usNDiscrete - 1) / 8 + 1);
    - s$ i+ |$ k% s9 N, ?
  145.     UCHAR  ucStatus     = 0;. Y% o0 E% U# ]3 n# X* b. d. J
  146.     UCHAR  ucBits       = 0;& [' U; _" ?0 |2 X) a0 o" j5 A4 [
  147.     UCHAR  ucDisp       = 0;( V* P* O# B9 @& y% a- U" h4 W& G

  148. # Y) ]3 Z- L, e2 {
  149.     // 非法检测" E: k( k- L. m% r. a
  150.     if((usRegIndex + usNDiscrete) > REG_DISC_SIZE)/ h9 \1 s! h+ ]% p! R3 V: \  u
  151.     {0 Q& R( K+ O7 P% r/ C* i8 X
  152.         return MB_ENOREG;' l" r  `7 f9 m& u
  153.     }" ^! m- n: w, c3 l& w6 }' i% |

  154. ) N' I* w- s* R+ V9 z. ^, j: x
  155.         // 读离散输入2 ~5 e* @4 q4 O. `* Z2 m- c* l; W
  156.         while(usCoilGroups--)
    4 o2 w" v& [& Z. i$ v
  157.         {
    . v& A# ?: Y' N, L# [5 |$ P
  158.                 ucDisp = 0;& v7 X. T1 t9 X) @0 x- A, \6 {
  159.                 ucBits = 8;
      Z9 \8 |$ O* }$ [& T- v, U* ^8 F
  160.                 while((usNDiscrete--) != 0 && (ucBits--) != 0)
    5 Y) G0 ~% P: F# i
  161.                 {( Z" _' i6 I% @, j
  162.                         if(REG_DISC_BUF[usRegIndex])
    1 P, N% A! p% ?) E& @
  163.                         {! g8 Z; D8 M0 o' ]  Z- Y
  164.                                 ucStatus |= (1 << ucDisp);" B; {9 `% U* y+ r* n
  165.                         }  x# {7 U4 @' x  N
  166.                         ucDisp++;3 @- t' M% W: ?! n% k7 k
  167.                 }$ k2 o' ~2 n  d& R0 D- _
  168.                 *pucRegBuffer++ = ucStatus;
    " C3 |$ s8 l0 O  O" o
  169.         }! U. g2 K3 ^( O. S3 v5 @* C
  170. 9 u- z  m% e3 P. p6 F: B9 l
  171.     // 模拟改变
    3 Z. r& A/ w+ L9 M! @
  172.     for(usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++)3 o" [3 |; w( t8 g% h# B/ W
  173.     {
    + q: l) _' E" i# P; a
  174.         REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];
    - |1 {9 R! e$ C4 N) j9 D6 ?) z
  175.     }
    + k6 I2 D: ?( {* ?  I# N( D

  176. . R) y6 e) M1 X" _
  177.     return MB_ENOERR;
    . \/ q. c. D, J: @( E5 k) p
  178. }
复制代码

5 l+ p' c+ c% U1 }3 G9 T) J主函数

+ m/ u: Y5 z* N* h5 _$ ^* H; c
  1. int main(void)
    9 u% x8 f7 D: U- M! {/ }  Q, R& {
  2. {
    9 A: n6 I, x7 N5 G4 x4 ~$ s
  3.     HAL_Init();
    1 u- k& R4 M' K6 j" z# I) x
  4.     SystemClock_Config();, G( c* V5 d% t+ }4 L$ A: H+ |: t
  5.     MX_GPIO_Init();
    5 g( R6 i2 M* I7 s+ V: m
  6.     eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_ODD);                // 初始化modbus为RTU方式,波特率9600,奇校验! x. r. h4 n% J7 S9 y
  7.     eMBEnable();                                                                        // 使能modbus协议栈+ Z! O3 K: G% d0 V  |
  8. 9 t4 v% E% G7 C# ^! g0 K' W! G
  9.     for( ;; )0 J% Y0 X+ F* n) g7 u. K
  10.     {1 i9 P- F; {* S' @! {
  11.         eMBPoll();                                                                        // 轮训查询
    8 E8 q! I$ Y' `& _
  12.     }6 ~( a" I1 d) y- n# ~
  13. }
复制代码
+ M" B0 ^) l0 D( F1 X+ x
移植测试
4 K* w/ }# u' Z" z( r' V. s# c; r4 Q7 ?) y# U
20200313154857173.gif
8 x) w1 J3 d' ?6 U# }
7 p% v/ ?  D3 m" M. Rends…
: G4 A; E$ l; L7 C" i5 v
% K4 h+ ?( k, e" m4 z3 N  ^9 L9 `7 c5 R+ p" b8 a+ c5 M
3 V- W' `  a, }) T# V
收藏 评论1 发布时间:2022-4-10 22:53

举报

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

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

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版