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

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

[复制链接]
STMCU小助手 发布时间:2022-4-10 22:53
modbus命令码表:; n) `+ E1 [/ ~4 \; [
# G( b/ X" ]8 A( t7 Q8 i9 ?6 ^
b8032deb4d154657acd2f7f2942369d4.jpg
3 p/ K9 i5 C) u$ h& H: c# j; d" z! \" Y7 ~7 h5 F  {
FreeModbus文件说明
  t3 A. W2 h, H6 e
      解压freemodbus文件后打开,我们需要demo目录下的BARE,该目录下的代码是空的,STM32移植工作基本就是修改:portserial.c、porttimer.c、port.h这三个文件。
# x- U2 y! [: y* D 20200313143257958.png + n1 K9 p2 Y9 q/ M2 ]
: W1 y/ N9 \0 z0 m! Y" D
      mobus文件夹就是完整的源码,包含rtu、ascii、tcp:0 A4 ~) E1 ~: o4 Q5 Y& B
9 g. u9 \1 m* e" p
ZM%DLXPRB8$%[NN2%4Z1N.png
" `8 Z9 m( C- _6 m+ N* a  ?
1 Y% W& z  r7 o) e9 ~; T      我为了移植时在keil添加源文件和头文件方便,就把modbus所有的头文件和源文件放到了一个文件夹下,并创建了一个port.c文件,用于编写modbus所必需的回调处理函数:" H4 D% m, g2 x5 P8 O0 N+ ^- V

# f7 X# H" H0 \0 ? 20200313144036579.png $ r8 ~# i( \2 R) C
' C, I. V, J) W4 }
STM32CUBEMX配置

3 r8 P* N9 X/ b时钟配置,设置主频工作在72MHz下:
' ]  U. Q4 L5 N( B" I6 x

3 E- t& L' S2 x7 X! @  P% ?! @ JU1~N33M}I7K1(6K@JFN5~R.png 7 V: y, @" g( y+ S( Q. I8 W

. B( j3 o3 v* V: ~% w; P* N, ]  Y7 I配置串口1,这里随便配置就行,在modbus移植过程中还会对串口重新初始化:

/ S+ k, c! ~  j: c7 X1 k6 A
/ {8 w% `. M) p+ s U25OQ_FHYD5WEXLFMI4V@RU.png
$ l$ q# p$ u5 q! }! G+ v8 ]6 q7 a, O  W9 Q
配置定时器4,用于3.5个字符的定时检测,这里随便配置就行,在modbus移植过程中还会对定时器重新初始化:

: K; ^6 m3 X0 B4 v5 ~1 S; U# Y9 L0 Y4 [% `. p6 Y
H6{)WT`**CIHDAM02558GK.png
2 ^1 Q# h. \+ L+ C- }9 U# ^
1 c/ M! r: K  m9 R& D中断配置,这里注意,串口的优先级是要比定时器优先高的:

+ C( y" m! U( ?4 M  b2 n
5 r& o* m$ i. m+ r! K G(RP`74TR)NPJFUK``Z%I2L.png
4 D8 a5 E  c  ?: j# A5 w" C( N取消掉自动生成中断服务程序,在移植过程中我们要自己编写串口和定时器的中断服务程序:/ b5 h+ a8 o9 l8 u! ?

$ Z5 z/ R; n; Q$ y ALHMK5Y615K6(`M{0[]YJ.png
2 ]( Y; L  ~1 [4 }  u$ R" r* r7 S1 G( [' n# ?. Z
移植代码修改
& `8 ^& a$ r2 l- R, A0 C% z
生成代码后将modbus放到工程目录下:
) ^0 b0 c9 q* r# h3 S$ t% m. l
" x- B% ~8 w2 H( f: f) }
5%(_LMGIM_8_YGL`]JGAB67.png
0 k8 V: R( }. v! g: R* d
8 C* n6 H2 v& B: z1 l打开keil工程添加modbus源码:

/ _0 D7 R5 N, w$ t0 o
6 e9 ?$ G5 A) o2 R! v8 q F`8_YFACMNOAP28~2VHD{CO.png 3 h1 L5 J; q1 T. v  K# N

4 K% N/ u% J2 J  n2 j4 l! L添加包含头文件:
5 |& G  _5 q. V9 [* W

! l: s' C$ Q9 |( e1 h `7BMVXA`R9SQBTGT`B@{]X7.png
7 g' v; l! S# h9 m
7 Z' c. R; Y  I' U, u1 x修改modbus定时器初始化源代码porttimer.c文件
$ T( q9 D8 |# y! _8 ]4 r; ?1 x       定时器的修改比较容易,将定时器设置为每50us的时长记一个数,传入的usTim1Timerout50us变量给自动装载即可,prvvTIMERExpiredISR函数需要在定时器中断服务函数中调用,它的作用是用于通知modbus协议栈3.5个字符的等待时间已经到达;由于我们在STM32CUBEMX中取消掉了定时器和串口的中断服务函数程序,所以我们在该文件中添加定时器的中断服务程序,修改后的代码如下:4 {; q0 }; N4 U/ }

$ f7 G9 f: E0 `6 W
  1. BOOL
    ' L7 G: ?, t4 y7 m: b
  2. xMBPortTimersInit( USHORT usTim1Timerout50us )( H# u; _% F1 k, {; O: Q' V3 S3 E
  3. {: e# }1 W3 j% _' C: N& u* \. o
  4.     TIM_ClockConfigTypeDef sClockSourceConfig = {0};" v4 _# n- b1 L: O, G/ p) M: n
  5.     TIM_MasterConfigTypeDef sMasterConfig = {0};5 u5 X6 ?& ]0 C  U& h( b4 ?

  6. ! S& u3 x0 d0 i* A; Y( x. `. e. l
  7.     htim4.Instance = TIM4;
    : r) L- e" }0 b9 s
  8.     htim4.Init.Prescaler = 3599;                                                                // 50us记一次数
    ; J/ a# Q- p$ A+ V+ a' O& A* ^
  9.     htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
    ) }. \  I  U" A$ x. v6 y: C
  10.     htim4.Init.Period = usTim1Timerout50us - 1;                                        // usTim1Timerout50us * 50即为定时器溢出时间) F# }8 I' b* H: d) M2 I( A1 L
  11.     htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    ' P8 n2 [( L- C" m# V- C5 I
  12.     htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;7 D/ i# j# Z4 i, e
  13.     if (HAL_TIM_Base_Init(&htim4) != HAL_OK)0 O# p  s* b: [0 l% S: Z
  14.     {. s# Q* J+ A5 N3 X" s
  15.         return FALSE;
    9 G  H5 X2 p4 C) c' C. e% \
  16.     }) U  b9 X' F3 {$ h6 y4 Y8 A
  17.     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    6 Z) ~( g$ x6 ^" L
  18.     if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
    ; i1 r7 T' ?+ q- D4 E& D' F( F; z
  19.     {
    . B( ]2 ~3 O$ L: I
  20.         return FALSE;: e1 k$ V) v0 @8 z4 f; |$ ~
  21.     }$ b1 n9 G- G& A2 t7 _% `3 o6 w3 t" u
  22.     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    / G9 \" m5 V  c- q
  23.     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    6 b- U$ k' [9 t/ }
  24.     if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)+ d* O) B# O2 y
  25.     {
    ( [1 H8 `* x1 u, C" r: `4 t9 H( b5 O
  26.         return FALSE;5 R7 F+ B- n4 M
  27.     }: h& A! \9 W6 u0 K; z' B6 \. @
  28. $ J$ J* m3 I' j; F
  29.     __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE);                                        // 使能定时器更新中断& d; ^8 [( Z/ e" Y
  30.     return TRUE;; e/ h* y1 C4 n6 @/ `2 T
  31. }' U8 L) ^: u  Y9 Q8 B6 j  V5 {) U

  32. ( s; [* X/ p, I! h, u% ^
  33. inline void
    # u( ^/ h/ c& g1 p# I6 n8 t; w# q
  34. vMBPortTimersEnable(  )
    - P( f0 P1 o- q8 M3 a% s- \* b5 C
  35. {
    ) }$ a3 A* @9 S2 R
  36.     __HAL_TIM_SET_COUNTER(&htim4, 0);                // 清空计数器
    : |! n4 c7 H8 @% `+ A9 J* l, U, U
  37.     __HAL_TIM_ENABLE(&htim4);                                // 使能定时器
    7 E5 ~, o7 C8 Z! w8 Q
  38. }+ m. p. Q" k7 O

  39. 3 y1 B( P" B( U8 b1 h# V4 b% i
  40. inline void1 k$ q0 B5 U! I9 S  p5 T4 I# B
  41. vMBPortTimersDisable(  )" Y1 T% j  }, }- m
  42. {+ q+ M- F/ B/ u' p* Z
  43.     __HAL_TIM_DISABLE(&htim4);                                // 禁能定时器
    9 q7 s; ~; a: |# E8 _7 s& l
  44. }- a& p0 U1 {- G1 w1 q; d1 j
  45. : h: [3 F& Y' k0 f7 q
  46. /* Create an ISR which is called whenever the timer has expired. This function* q# ~$ H/ w5 C8 y. _* ?+ b1 ]
  47. * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
    9 h: y  ]+ F# {! S- U
  48. * the timer has expired.
    % i, m6 b- O* S0 `4 ^
  49. */  O! h3 ^9 H* g5 K$ M  P
  50. static void prvvTIMERExpiredISR( void )" w" X* I- A) H* D# _* u) l# V
  51. {
    3 o, E2 E- H; _" A3 D  o2 K1 p
  52.     ( void )pxMBPortCBTimerExpired(  );
    4 \0 t6 J4 Q6 R% x
  53. }7 J9 Y8 N" W" g

  54. 5 ^( t2 A& B% O1 D: _: G
  55. /// 定时器4中断服务程序/ Z% H7 E) M# J! n
  56. void TIM4_IRQHandler(void)
    $ k& N; ^* v# h8 B4 ]
  57. {4 G& S7 R, h- ?( o$ {. f- _, f3 f
  58.     if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE))                        // 更新中断标记被置位
    ' z' ~" Z0 n3 L) B1 H' h1 r  ?& R( z  f
  59.     {' _5 b+ X' ?; Z6 j
  60.         __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE);                // 清除中断标记; A9 k% l1 e6 y; I
  61.         prvvTIMERExpiredISR();                                                                // 通知modbus3.5个字符等待时间到2 T+ X/ E! V+ A6 F; y( o1 m8 Y
  62.     }/ w9 K5 `! q9 W. O
  63. }8 j& G) [' U  p/ h: y2 q

  64. ' Z8 y& d0 a* ]6 W$ ]1 |

  65. ; `& A% t6 k( C' _, P) h
复制代码

% N4 T* ~7 u5 V: T2 f7 w5 e, W修改modbus串口初始化源代码portserial.c文件! F* _' ^1 W( V- o! t' w( E$ U
         ~~~~~~~~        在该文件中实现串口1的中断服务程序,prvvUARTTxReadyISR和prvvUARTRxISR函数需要填写进中断服务程序,前者得到作用为通知modbus协议栈串口已经空闲可以发送数据了,后者的作用为通知modbus串口1有数据到达,修改后的代码如下:
7 J2 t6 j% x& |2 S) G8 {( d! a
: S  f3 Q8 O1 L' @) Q! |+ u
  1. /*$ y( o% C( \' ]. |2 h9 b
  2. * FreeModbus Libary: BARE Port3 H5 e& g* W. s! Q; i& z8 G
  3. * Copyright (C) 2006 Christian Walter <<a href="mailto:wolti@sil.at">wolti@sil.at</a>>
    2 ^( Q5 g/ x. q/ L* M' s- f5 y5 Z6 ?
  4. *
    0 f- o, `: O# G! i
  5. * This library is free software; you can redistribute it and/or
    + i2 ~% j, M( q
  6. * modify it under the terms of the GNU Lesser General Public
    ! Y/ j) Y* E3 a7 J1 `  g
  7. * License as published by the Free Software Foundation; either- O8 x( o  P& O4 W- \4 _4 O
  8. * version 2.1 of the License, or (at your option) any later version.. C2 Y* }/ p) D. H5 a6 B
  9. *. N0 M2 C3 {$ \- {9 U9 w$ n
  10. * This library is distributed in the hope that it will be useful,% u! k8 D5 D0 y
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of) k7 s. Y5 a1 J7 |( O& V0 o; g
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    9 J3 }  e" @/ X( [& Y& r
  13. * Lesser General Public License for more details.
    , N9 K  v' y2 x0 p
  14. *! `! B0 u" \8 x, A0 G
  15. * You should have received a copy of the GNU Lesser General Public
      |! e: r, |7 X5 t! B! c
  16. * License along with this library; if not, write to the Free Software
    2 y9 Z. u0 X* X0 M
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA+ X1 v) m' I9 f5 ]; V+ A
  18. *' u: R5 ^3 L, d6 X1 @( r7 E
  19. * File: $Id$
    ' ?$ u+ |, J8 k- P2 Y8 q7 i
  20. */" }& z" V" F$ D9 V) m" _7 I2 k

  21. 0 M, G8 T/ b+ {( ?8 V
  22. #include "port.h"
      b( c9 j0 {& w0 [
  23. #include "usart.h": R# ~1 H8 |' K' `

  24. ( p9 j9 H1 \: P6 s: T) z/ T
  25. /* ----------------------- Modbus includes ----------------------------------*/
    ! R, u1 A8 l! Y% S, J- b( s
  26. #include "mb.h"1 U/ y% q7 W4 ]9 C# \# j3 f8 Y' |/ B
  27. #include "mbport.h"# w# Y  S+ u5 f

  28. 9 F8 k" w% Q+ J7 W9 H+ u7 v& }
  29. /* ----------------------- static functions ---------------------------------*/$ w$ @8 W( M: ^
  30. static void prvvUARTTxReadyISR( void );
    ' p. s5 O6 M9 ]; f1 ^/ z) T5 A6 Y
  31. static void prvvUARTRxISR( void );
    1 v  H7 ]# B( l
  32. 7 A* ~" d, n# y) W" m+ M
  33. /* ----------------------- Start implementation -----------------------------*/
    ; n# x+ s- p- k$ F7 W8 D$ E
  34. void
    ! L, t3 |: ]( ~
  35. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ); F5 d& g* B3 u! X
  36. {: C; R( L; \" L5 j
  37.     if(xRxEnable)
    # t& P% W9 a8 b
  38.     {
    * }2 r2 U& r8 p
  39.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断
    ( s& y5 g% H" {+ d5 `
  40.     }
    & a, l1 E& _0 N3 R
  41.     else
    1 g4 H, i4 W! {1 Q& w# r" Z
  42.     {5 s8 P. d% R+ o7 L
  43.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断7 v  W$ y$ r  o' ~9 Y( _" {
  44.     }& ]2 |8 l( i% A4 O
  45. & p+ h! Y: @  `0 a, Q: J$ r
  46.     if(xTxEnable)9 j6 [% N- n1 t8 M, Q
  47.     {7 b  I" G1 ^& l5 I
  48.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断1 m/ d1 u7 A& g) X, a
  49.     }
    0 D, m% ~, Y& U  r) {
  50.     else" P& v1 d: d8 Z, q0 n
  51.     {
    3 s) n( t& [! R6 q/ |
  52.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断
    1 s* _/ O( g  C2 I1 A
  53.     }( A" v- T2 B7 n, e. H
  54. }2 P; I2 X7 B9 L( I: u6 s
  55. ( @2 e0 T. Z- V1 |. Q: N" C
  56. BOOL
    % T# B- E% J' U! c5 F
  57. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
    7 k' t8 ]  q9 T- N. b
  58. {% u9 s' ], R. k5 k3 \  j  t
  59.     huart1.Instance = USART1;( R8 t0 q6 C' X! i  _* r, `$ }
  60.     huart1.Init.BaudRate = ulBaudRate;
    : N0 [% e! P8 w+ {& d
  61.     huart1.Init.StopBits = UART_STOPBITS_1;3 k5 t4 a% N' J6 n
  62.     huart1.Init.Mode = UART_MODE_TX_RX;
    : K1 f. h* f; r* L0 d
  63.     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    4 Q# N& r9 ]; \3 i7 y! `: i
  64.     huart1.Init.OverSampling = UART_OVERSAMPLING_16;9 M: J3 U! P1 |" J1 |% Z" v, D
  65. 8 b5 F) W7 V4 x. t4 M, p+ S
  66.     switch(eParity), j; J& P% M" J5 I1 ?' Y- V) v0 F2 @  C
  67.     {
    8 V; M9 w; X) {0 d$ i
  68.         // 奇校验4 L  B! ^  l! f
  69.     case MB_PAR_ODD:9 @" |1 R8 i  D8 y
  70.         huart1.Init.Parity = UART_PARITY_ODD;
    5 _& U5 _5 D2 h
  71.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits- B) @6 I) l" F
  72.         break;5 \. }' T2 U( F. G% `0 N" {
  73.         
    " |) j6 M$ g& J) y
  74.         // 偶校验7 Q% ~. c2 y: V1 Q
  75.     case MB_PAR_EVEN:& G; N+ c- F7 T- g: \, [7 G, M
  76.         huart1.Init.Parity = UART_PARITY_EVEN;
    4 T& X, u+ k7 g. q6 u
  77.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits- ]- ~: {- x% E! K4 L
  78.         break;
    ' t2 V& c& D2 I0 E. v
  79.         " r! m( k# T! h6 t" ?4 }
  80.         // 无校验, ~" N- E0 N. F: \/ Q4 J
  81.     default:
    - Y( Z; @$ l, C  C  d( g
  82.         huart1.Init.Parity = UART_PARITY_NONE;( P. T5 v- H" U" v
  83.         huart1.Init.WordLength = UART_WORDLENGTH_8B;                        // 无奇偶校验数据位为8bits
    2 g0 ]" Z7 l$ {) J+ F* p
  84.         break;4 A4 ^9 a  q1 w) v" ~3 R8 Y3 x( J+ N
  85.     }2 {4 S( F8 j/ p, H4 H% _
  86.     return HAL_UART_Init(&huart1) == HAL_OK ? TRUE : FALSE;
    2 |+ k( e2 d4 R1 e
  87. }1 T* A7 K0 G. A9 g

  88. 7 A9 V' O) b" V1 `  L/ G3 X; }; N2 j2 J
  89. BOOL0 q: u6 Z" g, m) m
  90. xMBPortSerialPutByte( CHAR ucByte )' f! {+ ?1 c' W# x1 E  n7 X
  91. {- a3 e9 d8 P7 q0 k! c  V- B
  92.     USART1->DR = ucByte;
    + i2 m6 a0 n2 d. E
  93.     return TRUE;
    % R( r3 O& @- \
  94. }) G% W: M) n: w# _& f0 w6 O
  95. 6 k2 Z& O" k: g4 _
  96. BOOL
    # N+ S* k  ?5 F' m/ h- Y
  97. xMBPortSerialGetByte( CHAR * pucByte )
    1 p8 U! {7 G5 \9 S  c; A
  98. {
    1 x& [' A. Y0 K8 G3 U
  99.     *pucByte = (USART1->DR & (uint16_t)0x00FF);
    - _, [/ V6 O! v/ \( o% S
  100.         return TRUE;
    7 Y7 y8 ]& F9 S  _: f1 J
  101. }: M6 U0 q) \( H0 Q! a
  102. 6 D& g+ S. x9 v5 R4 S5 t  ~
  103. /* Create an interrupt handler for the transmit buffer empty interrupt
    " E# G8 P: Q2 c8 I" p2 P
  104. * (or an equivalent) for your target processor. This function should then
    , V8 x# z2 L8 j7 L1 f' l4 K6 x
  105. * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that7 @* J$ ~$ [! _7 `% K. V7 g
  106. * a new character can be sent. The protocol stack will then call
    8 Y" n* A' z* |! `1 z/ _. i$ h
  107. * xMBPortSerialPutByte( ) to send the character.
    5 T, a! d; w. X7 M1 |
  108. */
    2 k. ]1 p3 V( l- I8 D" W
  109. static void prvvUARTTxReadyISR( void )
    ' O8 [; @; z2 }+ F9 Z. ]* o0 a. }
  110. {5 _# X5 {2 Y9 C! g
  111.     pxMBFrameCBTransmitterEmpty(  );
    ; H$ H6 D% C% t4 ]7 g
  112. }8 f* y" G- @  r* J0 Y
  113. ! f5 N+ s" b/ A3 y/ ]4 G1 r
  114. /* Create an interrupt handler for the receive interrupt for your target" |3 Y2 ~# n  \# \
  115. * processor. This function should then call pxMBFrameCBByteReceived( ). The
    3 X- R" u( M( S) X; m
  116. * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the/ ~+ u1 `3 s, M. d9 k, A" G$ f
  117. * character.
    ' v& j" ~, \, A. \! h
  118. */
    3 I  O& N) P" \/ G* @
  119. static void prvvUARTRxISR( void )! h$ e5 [0 E5 f$ Y% A3 X
  120. {' J2 ^2 S' M6 R( {2 I
  121.     pxMBFrameCBByteReceived(  );6 ]2 h8 x  c  Y. n0 Y
  122. }+ Q* R6 k" o- a0 T2 y; G

  123. 6 g: A. E" Q* @. \7 S- u# l: T! R* C
  124. void USART1_IRQHandler(void)% v8 R% H: T% p/ x6 {* f
  125. {0 y* z, Y( `* ~8 y# O1 P6 ]! V
  126.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))                        // 接收非空中断标记被置位
    7 S9 M) @& A* g; C
  127.     {% c6 F* ~6 w! s2 j1 S0 c
  128.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);                        // 清除中断标记, `/ I. f( ~0 m9 b8 s6 o
  129.         prvvUARTRxISR();                                                                                // 通知modbus有数据到达
    5 F! A' b8 i. }7 u1 K" d+ M
  130.     }
    1 p! `; Z* g! a: _4 P

  131. $ J/ ~/ f+ {9 y8 @- a9 @# H
  132.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE))                                // 发送为空中断标记被置位
    9 J9 ]/ I5 T/ l% c& \$ }  ]
  133.     {
    ' j$ t1 N- B2 C
  134.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TXE);                        // 清除中断标记
    - `; D, e$ k4 B, ]( F9 j( j% t
  135.         prvvUARTTxReadyISR();                                                                        // 通知modbus数据可以发松
      {5 `1 t; \. T
  136.     }
    7 e6 N/ B1 p  o( v8 t) e
  137. }
复制代码
& }  ^% g' I0 B
注意一点,一般如果使用了485芯片的话,那么同一时刻只能接收或者发送,可以将函数vMBPortSerialEnable修改成这样:
' c% j* \6 o4 [  h! w$ ^
; D2 Z2 @& \. @2 v; }* Q$ s+ H
  1. void, y2 {% Z4 ?4 G- r4 D" f6 H
  2. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
    $ n+ b% {5 v6 |
  3. {
      ^# d/ ?: W/ ~' I7 n
  4.     if(xRxEnable)
    6 X0 ~- g, o- G( Z9 P" A  t0 N0 ~
  5.     {
    ( p& ^- O: a- i& {- G. R
  6.             //
    4 F' \! F5 W8 |+ r# @8 y4 A4 A0 c
  7.         // 在此处将485芯片设置为接收模式# J/ P2 U- n3 r. U3 S% f) ~" A
  8.         //' e" E  d8 g/ _) D$ I) b0 W5 \* l- [
  9.                 /* do something */9 {6 j+ {* J$ U7 p0 I0 m
  10.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断- @+ o& ~5 F0 v7 K) |2 k% k
  11.     }3 k+ N' u3 H8 Q/ f- h
  12.     else
    6 G" R$ b: D9 u$ {9 n7 @$ V6 B
  13.     {- V: d: M: d8 O( Q% a
  14.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断
    ( \& [; @: d+ W) b
  15.     }* D) K5 @  \& e% V7 K' X  R
  16. # H4 Q7 @8 w; s
  17.     if(xTxEnable). j- f8 ^- P2 D! y
  18.     {
    & x$ l$ r4 X& d9 q
  19.             //  v% O- _1 \( `! _/ x8 e, C
  20.         // 在此处将485芯片设置为发送模式3 ^9 L+ s. Z, i. t* F' _7 l
  21.         //
    , I" u1 ]5 [. Q3 `/ h3 G
  22.         /* do something */
    ! ?6 e' {( O# Z' E+ k& w9 Q+ e  R
  23.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断
    / [. ~7 c* I6 {& O, l# S) |
  24.     }) Z6 }" q. w, c/ j1 J
  25.     else) U0 [, ?/ j; h" H
  26.     {2 ]+ Y8 B9 W7 K  B
  27.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断# T: k' p+ `* D' z; m2 h7 K) X- @, d
  28.     }
    * E5 h0 `* N/ b! X0 ]! H5 P
  29. }
复制代码

6 T9 i; g6 M/ X: L' `
编写modbus命令处理回调函数port.c文件7 K# |) z& ?2 r/ j
本例程只实现了读取输入寄存器和保持寄存器的功能,详细代码如下:
+ H9 P- J. e" U' k0 `1 k) [
% B: I1 t, U$ b# P
  1. #include "mb.h"- |$ n5 Z0 w, [2 f+ m7 n7 a
  2. #include "mbport.h"- v( G* c  J$ d" g$ ^9 o
  3. # n, k) e( ^8 m6 k" O5 ]
  4. 7 L. L$ ]. a  u. n7 D" y0 s
  5. // 十路输入寄存器5 ]' a' m" c+ J7 \4 r$ q
  6. #define REG_INPUT_SIZE  10
    ) U) ]  F4 i2 s' D! @
  7. uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];
    3 n8 j' ^" K+ {( e5 D" B! v

  8. 8 s6 ]( ^- ~1 R& U9 q; T# v
  9. , l& z: C2 d0 V0 m5 Y2 b7 g
  10. // 十路保持寄存器
    2 |; t  x& \/ J- H0 G* g
  11. #define REG_HOLD_SIZE   109 S4 w0 C; @2 Y0 e; q
  12. uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];6 F. `" K, @3 \3 m" a$ ~

  13. * E! x1 R( ?$ Q' j$ N0 r

  14. ( ^" a* Y8 F' S4 w  N0 A
  15. // 十路线圈
    ' k1 C% Q4 q. Z
  16. #define REG_COILS_SIZE 10
    " j/ X3 W# W% Y1 A) D* ~6 i+ N
  17. uint8_t REG_COILS_BUF[REG_COILS_SIZE];
    $ `' [( o; F6 Y; ]0 B

  18. ; j" A; _' C7 X' c% Q

  19. 2 d1 d+ h2 x, T$ M
  20. // 十路离散量* [2 Q9 u0 F) K0 }+ Q" N8 O
  21. #define REG_DISC_SIZE  102 b) l2 {, Z) o: ?2 R1 r
  22. uint8_t REG_DISC_BUF[10];& r7 i4 U( l* T' \
  23. ' i) E0 V1 A  ~- t; u

  24. ' ?/ L' h7 |7 [% q: q# |0 @0 M
  25. /// CMD42 d1 }2 y1 J2 `. \2 W, Z
  26. eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )' L9 J: E. z2 }9 V0 O
  27. {
    ; i' A  R) Y4 n( k" Z: c
  28.     USHORT usRegIndex = usAddress - 1; $ x- `4 @. s0 b4 q' M
  29. 5 l7 q& Q" y& v& i
  30.     // 非法检测
    * L  D! V0 M3 c. P! o$ k% G
  31.     if((usRegIndex + usNRegs) > REG_INPUT_SIZE)
      ]* ~% v, j4 A& o& L# ]  n* D
  32.     {
    ! i- W) K0 v2 u" M- R9 m
  33.         return MB_ENOREG;; F0 @" H3 ]0 k  L  \& ~
  34.     }
    $ J! {( x7 v0 i
  35. : d3 o; H; i' R/ q7 r) C8 W! M
  36.     // 循环读取+ e( _  M  ], p
  37.     while( usNRegs > 0 )
    " M/ u# s1 t6 w, ?" x9 u$ }
  38.     {, b: }) H) l; u0 D2 q3 m, v
  39.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 );
    # ]4 @' u/ _1 F% d* ]: U. _& V( P3 N
  40.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );
    ; g# ]; p) b) \6 g
  41.         usRegIndex++;
    # h/ Z- O# ]9 C( y1 `9 S
  42.         usNRegs--;
    . V! d) g1 c$ V/ E9 X- E
  43.     }
    . K/ R% v$ c0 n" P5 d$ r# {8 k
  44. 2 y! d# s7 z+ _- ^$ m! H
  45.     // 模拟输入寄存器被改变2 u3 G! ]0 r2 r$ F0 M
  46.     for(usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++)  z1 f1 e0 E7 X  y' z: f9 E5 _
  47.     {7 P- x7 H# s0 S% F) [* [
  48.         REG_INPUT_BUF[usRegIndex]++;
    3 ?2 L3 V+ m% b
  49.     }
    ' n6 e! V* t$ y% z% z' Y' O

  50. / y" z7 p  e4 g. n% w  V) K  F
  51.     return MB_ENOERR;
    % r- V. o; }4 [7 s
  52. }( G5 A% y: d) y0 r/ e/ f3 w* M
  53. 5 r  h  L6 W# u7 w! S% H6 ?8 G* q
  54. /// CMD6、3、16  r) Y; j: R& S8 D& K
  55. eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
    ) e8 @4 B4 i2 q2 Y4 Q7 n5 o* V
  56. {- \* R4 |) _* J; D5 j$ c
  57.     USHORT usRegIndex = usAddress - 1;  2 q# z' v. ]2 C4 V$ a7 P1 M

  58. $ D# r" {8 \3 H# [  _+ M
  59.     // 非法检测% `. l5 l3 L: x/ O, l; ?
  60.     if((usRegIndex + usNRegs) > REG_HOLD_SIZE)7 \: H, o+ {- j- B2 e+ {
  61.     {# k/ _1 `9 z' A. B! j
  62.         return MB_ENOREG;4 E" X& m6 ?, h2 k
  63.     }
    % T* f$ J3 B" [) K& B+ t
  64. 2 \! X, U: f6 v
  65.         // 写寄存器$ c: u! B; O1 M; T+ Y& s5 H
  66.     if(eMode == MB_REG_WRITE)
    7 Q, l, C5 y& ]% e: W
  67.     {
    6 v& I4 s, w* A/ X% u; G
  68.         while( usNRegs > 0 )
    % V+ H- [% y1 [: B2 q* t
  69.         {+ R4 i; V5 M7 v2 o
  70.                         REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];3 E( k; c, l3 m) ^% I( X
  71.                         pucRegBuffer += 2;
    : u+ L8 ?4 S1 `* V  e
  72.             usRegIndex++;
    4 X' T- P4 ^: C. o: ?, A( t
  73.             usNRegs--;
    . s* n- H* q# a
  74.         }
    9 J1 f3 \; o9 f4 m( E
  75.     }2 \: [) `0 s0 x; m
  76.         9 r9 D+ m* l  ]
  77.         // 读寄存器
    + G3 ~3 m7 y' ]) i: w: V$ B5 s. e
  78.     else
    5 m+ i* ?! B/ X! [! v! \1 j% C
  79.     {/ C' A  P* W1 B; L& p' c
  80.         while( usNRegs > 0 )
    " H* W/ x9 b2 c9 c" Z% q
  81.         {
    0 V' x2 p2 v& Y
  82.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );. c- [5 L8 K3 Z7 \" a5 W
  83.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );% R* W- `) I, O
  84.             usRegIndex++;9 }$ K: i4 ?* D' Z; e( z' ~
  85.             usNRegs--;" v5 G3 x: |# f) F; [) f
  86.         }
    ( W3 {/ A3 u6 H- u' u6 }
  87.     }
    2 L9 S9 f' {" q/ @5 q( @2 P

  88. 7 f5 {5 R8 o3 ~/ K4 \2 G
  89.     return MB_ENOERR;' V3 f, }- t# m0 r2 }* r
  90. }
    - i, B6 e  P! E; F; S3 e
  91. 4 t( Q7 L' k' N5 g7 x% V% q8 l0 Q
  92. /// CMD1、5、15
    ; w5 n' k, z& E
  93. eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )3 R" w5 f0 j& U3 G8 H, z4 W) ]
  94. {
    6 ^; C$ P& v8 L3 }$ J
  95.     USHORT usRegIndex   = usAddress - 1;
    3 u9 O5 \7 v& W
  96.     USHORT usCoilGroups = ((usNCoils - 1) / 8 + 1);
    / {( k) B0 L+ A5 b: j: z. d
  97.     UCHAR  ucStatus     = 0;* \) N  N: r; }
  98.     UCHAR  ucBits       = 0;
    1 i# n/ U0 Z: p$ k5 e0 d* S
  99.     UCHAR  ucDisp       = 0;7 a& v( K( E8 |; A- J
  100. $ _8 N+ m  J& }" I7 f2 ^
  101.     // 非法检测" j/ B( {8 h8 u) l7 i; K0 T. e
  102.     if((usRegIndex + usNCoils) > REG_COILS_SIZE)
    + K& t* o5 @  w) t% [
  103.     {0 ?/ V" H  c0 ^, Y: ~% k0 Z; J  @! j
  104.         return MB_ENOREG;. H4 u! D% W/ E
  105.     }
    ( V. b; t  s' l2 E2 S% W, s. W0 n

  106. 9 _$ R8 T' ?' M$ ]6 g- `
  107.     // 写线圈, m2 T7 O# E* z/ u4 A5 O; I4 k4 {/ r
  108.     if(eMode == MB_REG_WRITE)
    , m9 ~# ^( \1 M! n" R7 B5 l  w
  109.     {8 S* ~2 t+ [: Q* \0 O9 H3 t! {' H
  110.         while(usCoilGroups--)" D: s# o1 a# m! {6 T" s' P
  111.         {5 ?. W% K$ Q, g2 }
  112.             ucStatus = *pucRegBuffer++;
    ! H: f; N5 k6 t8 ?
  113.             ucBits   = 8;* g, v/ b0 \1 G+ Z% R  p) X
  114.             while((usNCoils--) != 0 && (ucBits--) != 0)9 e) Y4 L7 y, m/ r
  115.             {6 a+ V! r8 W  L/ N) S
  116.                 REG_COILS_BUF[usRegIndex++] = ucStatus & 0X01;: A: y+ E* m6 `& ?! ^1 f9 }
  117.                 ucStatus >>= 1;: J9 N6 }! _! }: S! k
  118.             }
    / u5 r) U+ H. p$ e2 V
  119.         }
    ( K. R3 w4 x4 M) C
  120.     }/ E. t7 J4 G  g( U: D7 ^% s
  121. 0 X* Y  d* S- |2 z2 ?) O. g8 ]
  122.     // 读线圈! H5 Q( t9 F, ^+ h$ K3 e: n% [. U
  123.     else5 }. T) n: H2 D( e6 Y7 {" `/ T# t
  124.     {3 H+ Z! c* Q, W* t& p* ~# L2 ^
  125.         while(usCoilGroups--)
    + x3 t& z  }2 _+ [4 p( O8 d
  126.         {
    5 j3 u4 ^. f9 D1 X: D# _
  127.             ucDisp = 0;1 V/ _# N# A$ k; b" ]4 i
  128.             ucBits = 8;9 D# B$ Q/ ?5 q% z  W5 s# D8 y
  129.             while((usNCoils--) != 0 && (ucBits--) != 0)! J1 k7 n% _" K3 \, q; S. V* S
  130.             {5 w2 I) v+ U% Y1 ~5 q# ~9 ?& D
  131.                 ucStatus |= (REG_COILS_BUF[usRegIndex++] << (ucDisp++));
    ! P7 x* I  [" D% d' Y$ P% R
  132.             }
    & O% X. ?( \9 ^! n  v1 j
  133.             *pucRegBuffer++ = ucStatus;6 ~0 h9 }9 m" d+ N  l  e" M
  134.         }2 B7 E# N8 d; k4 E+ P; ]8 N
  135.     }
    7 M5 j# p. z. d; M! [! E) E
  136.     return MB_ENOERR;1 c3 b/ V7 a5 Y9 |& u
  137. }
    7 h( m' p& F) C- [8 R, T; G

  138. ( z, E! H9 s0 l0 Y0 d

  139. 0 {; f' y: p9 ~+ z# w# X, L8 Q
  140. /// CMD40 C; r! h1 [3 _
  141. eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
    0 h' [3 z2 ?% x0 X/ h
  142. {
    9 m3 [: O. b( x$ [: h- ~5 L6 s
  143.     USHORT usRegIndex   = usAddress - 1;$ ~  ?% ^3 U9 L, Z" c7 P4 I5 F* h& n8 Q
  144.     USHORT usCoilGroups = ((usNDiscrete - 1) / 8 + 1);
    " U' Y' H0 b# E5 I) H  b8 o
  145.     UCHAR  ucStatus     = 0;
    5 H  c  _- H  [
  146.     UCHAR  ucBits       = 0;
    * L6 r3 ^$ x% n) R) N& d" O
  147.     UCHAR  ucDisp       = 0;: y; H4 ]2 j* z9 k2 P. a

  148. ) t4 u: W: c9 `" r
  149.     // 非法检测+ l# {  h& O( Z' m
  150.     if((usRegIndex + usNDiscrete) > REG_DISC_SIZE)9 M- v8 Q2 R" y9 Y
  151.     {
    9 M0 D; u. {* P5 J# `/ V( W
  152.         return MB_ENOREG;# ^. l' q( ^  I( Z
  153.     }; D4 f' f( a. P* D1 r0 h. l

  154. & _& l2 a8 }) I% e% R; f0 N
  155.         // 读离散输入
    4 Z, P+ P, m; v3 [8 k
  156.         while(usCoilGroups--)
    : X  w3 \, \- A  N
  157.         {4 I, @: T% y- a: y8 a
  158.                 ucDisp = 0;! q* g* f) A/ A8 r& Q
  159.                 ucBits = 8;: E1 R) z) m! w2 r
  160.                 while((usNDiscrete--) != 0 && (ucBits--) != 0)( M3 e% ~5 A- f% _+ o- V# `: x- p) t
  161.                 {
    ! l7 [1 O4 n- O* I
  162.                         if(REG_DISC_BUF[usRegIndex])
      t4 L+ v  y, D, x- E# O! Q+ U
  163.                         {8 F& v) T+ q3 i) r  `1 L8 B
  164.                                 ucStatus |= (1 << ucDisp);
    # R9 ^& @* D& m, [" T) }" ?' k
  165.                         }
    . s( i* y& u1 t8 P1 g
  166.                         ucDisp++;
    . M! P, l  e6 Y; C1 ~$ r. `
  167.                 }
    ( f" y. U6 V# a
  168.                 *pucRegBuffer++ = ucStatus;% X0 u( a  q! l; B8 [
  169.         }
    ; v2 m* _) @( Z& E* I
  170. . O# i4 Y! O+ p2 f) E' v
  171.     // 模拟改变
    : `. a( w: c- R& L9 Z
  172.     for(usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++)
    ; o0 F* J1 \0 x; r
  173.     {% l0 H" q% `; G) A6 H
  174.         REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];
    * B* G2 n2 \9 O, k& Q' V5 y) f
  175.     }
    , [2 L% W& B6 R( ^: H

  176. . y; n/ p: s$ v* Q* |
  177.     return MB_ENOERR;
    & x6 [; i, P9 d+ U* O
  178. }
复制代码
) D4 J/ @5 s" U+ p
主函数
6 `- w  w0 z- G) a7 u7 F
  1. int main(void)2 U9 c9 k, ~1 f2 r3 x
  2. {
    : Z8 i) l# R- F+ o" `
  3.     HAL_Init();  s. q0 z/ ?* [) Z
  4.     SystemClock_Config();
    ; T/ @! V: i6 N7 }# z- E- a
  5.     MX_GPIO_Init();
    * S3 \+ Z9 ?3 Y) J, a
  6.     eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_ODD);                // 初始化modbus为RTU方式,波特率9600,奇校验9 ]& M( g6 l- G) W4 l& q
  7.     eMBEnable();                                                                        // 使能modbus协议栈1 @" M- {7 r6 P; r+ v% H

  8. 2 R5 ~2 T% w* O6 d) l
  9.     for( ;; )
    ' K# g( S- X% v( L9 B+ h
  10.     {
    ) n- b) T6 d; P) g: }
  11.         eMBPoll();                                                                        // 轮训查询2 W! W. W7 q9 T. y3 E. C. o
  12.     }* X! H; g4 a. c4 x0 L& b
  13. }
复制代码

5 h# X4 f, t" E1 I: f移植测试
1 T/ q& B2 t' r0 O
, A6 c) C% B5 \2 \% ]* d1 ? 20200313154857173.gif 1 f2 i  O2 B+ g* Q! T

$ f* n' X5 r, m7 n4 vends…+ p6 r" M1 I- b3 g

5 M/ ^$ R* c* P, B& @6 `* r
0 p6 l6 `3 l: I3 ~
2 O* Y" v/ t$ D6 {
收藏 评论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 手机版