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

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

[复制链接]
STMCU小助手 发布时间:2022-4-10 22:53
modbus命令码表:6 H% Y. |) W# A' u
# |9 H9 i$ j  t5 }
b8032deb4d154657acd2f7f2942369d4.jpg
8 j7 t2 K+ h$ s/ R& d2 o" z2 ?# \5 l) E7 w! a& X
FreeModbus文件说明
0 M+ l) _- v& w# f: ~; d- T
      解压freemodbus文件后打开,我们需要demo目录下的BARE,该目录下的代码是空的,STM32移植工作基本就是修改:portserial.c、porttimer.c、port.h这三个文件。
; l% W: x, Y" x, J3 ] 20200313143257958.png ! m' _/ x& s7 Q* \. T, S0 @. _
) {8 L3 `5 c0 T. ~" @4 Z
      mobus文件夹就是完整的源码,包含rtu、ascii、tcp:. `& ^; {8 v" F, H0 N" q0 {7 s) e9 B
1 X2 O) E, j/ }' b4 R
ZM%DLXPRB8$%[NN2%4Z1N.png ! q% X6 ~) s) w5 @- }

0 v2 p8 |4 w9 t! A) [      我为了移植时在keil添加源文件和头文件方便,就把modbus所有的头文件和源文件放到了一个文件夹下,并创建了一个port.c文件,用于编写modbus所必需的回调处理函数:9 M8 S! \& \" e# N/ m0 ^* W

! C0 o' l: X% ~; X1 d 20200313144036579.png ' W7 F" X; G7 D; d: r

( y9 G! M4 \* z  GSTM32CUBEMX配置
; G5 R9 Y( F- H# d
时钟配置,设置主频工作在72MHz下:
" x! ~* @- m- z6 O8 {  C8 {
' A% k( u2 p8 S8 e
JU1~N33M}I7K1(6K@JFN5~R.png
2 g( c# v% k9 \1 ~7 J6 O% |% l' B5 R* z- c
配置串口1,这里随便配置就行,在modbus移植过程中还会对串口重新初始化:

6 n! {' G, Y# w. o  `0 u# }
) e9 X4 D* z' H; e U25OQ_FHYD5WEXLFMI4V@RU.png " a0 [6 d7 u- K# l! ?

/ r2 D( p, _/ z! e# G9 ?配置定时器4,用于3.5个字符的定时检测,这里随便配置就行,在modbus移植过程中还会对定时器重新初始化:
3 W! m$ l8 |2 l* h! R1 z
8 q+ m' v9 f5 n- J8 c9 X7 r6 b/ F7 x
H6{)WT`**CIHDAM02558GK.png - Y& U/ s* D" u9 E

- }' h: G+ @5 W( j0 d中断配置,这里注意,串口的优先级是要比定时器优先高的:

. o7 ?1 j9 {2 j6 v4 W5 t  n$ w, e2 C6 d4 ]" A2 O
G(RP`74TR)NPJFUK``Z%I2L.png
0 G' u* @$ I* [# O% ^取消掉自动生成中断服务程序,在移植过程中我们要自己编写串口和定时器的中断服务程序:- r; A; \% D: _) W

2 g" d# k) c8 Q  w& p' Q! F0 _ ALHMK5Y615K6(`M{0[]YJ.png
; n' V- T- E8 e# `
. d1 {) j8 [" F1 V移植代码修改
: c/ v9 j9 B2 x
生成代码后将modbus放到工程目录下:
9 P9 U1 p' t% T% q3 w0 @( T( o1 L: d6 V% u
5%(_LMGIM_8_YGL`]JGAB67.png 8 b0 z2 r3 \, m7 O( E8 |$ Q7 N
% N$ R! E( y0 p  v' P& p
打开keil工程添加modbus源码:

' N8 G. n9 Z8 S( Y; w0 x. Y- Z  P
F`8_YFACMNOAP28~2VHD{CO.png
; P2 E3 r. D1 ~3 `) f8 z1 W/ m& R, p8 J% @, x/ I) p' V8 S- Q4 c, e
添加包含头文件:
9 G( a& @" {  e' A' Z

, r! J7 P9 l# g6 Z9 @# d. `( V. x! _ `7BMVXA`R9SQBTGT`B@{]X7.png $ K1 b" |3 D; W. r4 Q

" `  D: {  }! G# E, ^修改modbus定时器初始化源代码porttimer.c文件
  W+ }; z. V. F( s, x8 R       定时器的修改比较容易,将定时器设置为每50us的时长记一个数,传入的usTim1Timerout50us变量给自动装载即可,prvvTIMERExpiredISR函数需要在定时器中断服务函数中调用,它的作用是用于通知modbus协议栈3.5个字符的等待时间已经到达;由于我们在STM32CUBEMX中取消掉了定时器和串口的中断服务函数程序,所以我们在该文件中添加定时器的中断服务程序,修改后的代码如下:
  q4 k# T, M! V' y" A6 G$ y! T5 y, @; U  `8 A; l4 O% ]
  1. BOOL
    4 p# H2 C5 V/ f6 A
  2. xMBPortTimersInit( USHORT usTim1Timerout50us )1 l& r5 @; k' Z* ?& ?0 a
  3. {6 b; j2 ?; v3 Q+ c1 W6 W6 d& B
  4.     TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    ! G- i6 J; H& p3 [: {* G
  5.     TIM_MasterConfigTypeDef sMasterConfig = {0};7 `% y/ V9 E' Z9 Z! P
  6. " |: U' }- g3 m3 _1 a2 T' @
  7.     htim4.Instance = TIM4;
    & E+ X' R8 J( R* E4 L
  8.     htim4.Init.Prescaler = 3599;                                                                // 50us记一次数( _! k+ i, {! p/ E3 w
  9.     htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
    $ {" |4 D6 A, p' _2 X
  10.     htim4.Init.Period = usTim1Timerout50us - 1;                                        // usTim1Timerout50us * 50即为定时器溢出时间* x) D) v6 ?* ~, ^( Q# K8 x
  11.     htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;: a5 s4 z- U5 _* V: J) B3 V7 D
  12.     htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    4 x' P6 i- }0 t! G0 u- M
  13.     if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
    " H# K5 ~, y: [# u
  14.     {- l* l" z; c. p9 K
  15.         return FALSE;+ c; n; t2 @7 A5 n' a5 j/ F, p
  16.     }
    / f7 k, M) o: ^0 z0 ^& h6 c5 W0 ~3 K
  17.     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    9 C" L: b' Y2 M' }8 c6 N; ]) r
  18.     if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)! e& E6 d5 |- L$ {# B* I* z% ^
  19.     {
    0 I& }! Z$ t8 [* ?, _* |3 T- \( L
  20.         return FALSE;' M; K" v6 T8 c, n1 p
  21.     }
    3 K/ G% Z4 Z7 Q" |: D
  22.     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;3 s3 w: n& T7 @: Q- ?/ d
  23.     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    : f. V/ c  s0 ^! [3 D
  24.     if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
    * t+ K. Q# H% ^5 x
  25.     {8 \& j$ h1 [" @; t) v
  26.         return FALSE;$ `+ ?! p& H$ E" ^3 P7 I% |
  27.     }
    " x9 @9 f( C( u  Z
  28. / _3 M2 |7 E- P+ s! F
  29.     __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE);                                        // 使能定时器更新中断$ l8 B* b8 }1 K  w3 t  g. k# k  b
  30.     return TRUE;5 ~% h5 y" v+ n
  31. }
    5 F, G( K/ s' i4 g( |

  32. / X7 c: c- T/ m8 [+ V0 U# Y; L
  33. inline void0 ]1 K7 h0 J( U5 e
  34. vMBPortTimersEnable(  )
    6 q2 c$ a" I6 `! v0 T& P
  35. {. C6 k  Z2 {) x# r& }
  36.     __HAL_TIM_SET_COUNTER(&htim4, 0);                // 清空计数器* @. N+ i- N+ S1 q/ w
  37.     __HAL_TIM_ENABLE(&htim4);                                // 使能定时器
    9 o) c/ w0 n! u% y( M
  38. }
    ; \5 P+ \5 N$ ~0 ]7 \- \% ~

  39. ) G# x# i. z% t* u
  40. inline void
    3 K# V. D) M# z/ s8 ?5 l2 ?4 _
  41. vMBPortTimersDisable(  )& o. r' z) m! e6 S
  42. {
    4 v2 J4 x6 T( S0 f, M, v
  43.     __HAL_TIM_DISABLE(&htim4);                                // 禁能定时器* n6 n7 P, V; G6 v* R& I0 u
  44. }4 [, z! f% R6 J5 @! P
  45. , c& e( |: m" v! ?  f
  46. /* Create an ISR which is called whenever the timer has expired. This function0 R) r! n+ W  T6 b  A$ D4 C! [! v
  47. * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that7 p. @1 r$ \0 P! b* `+ ]% M
  48. * the timer has expired.+ R/ q! m* ?- {6 L2 `
  49. */2 m1 S0 D1 w( e! [+ f. P" \8 s
  50. static void prvvTIMERExpiredISR( void )
    $ C7 H2 [- k: @5 y4 F$ F3 \
  51. {
    ( x. Z( a: W9 }$ m: f5 N$ E2 B7 [
  52.     ( void )pxMBPortCBTimerExpired(  );
    0 W) e, Q9 ~! T( y6 O
  53. }
    9 K4 Q+ T: q6 I% @/ o3 p* ~, t! ?

  54. 7 V  O8 S2 [+ Q9 g
  55. /// 定时器4中断服务程序
    : G9 h( m/ b" {0 }$ s6 a0 b
  56. void TIM4_IRQHandler(void)
    , z: m  v, F5 M2 |
  57. {
    $ y3 Y2 d! m: d% l, I, {/ _
  58.     if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE))                        // 更新中断标记被置位
    " d5 U$ x0 R3 J# C5 v
  59.     {
    9 j! p5 f6 z  C) Z$ o
  60.         __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE);                // 清除中断标记3 O4 i, g+ n% C1 a+ E7 B2 K
  61.         prvvTIMERExpiredISR();                                                                // 通知modbus3.5个字符等待时间到
    * [9 k: j1 |5 O: I; T# o9 S
  62.     }
    , G7 t9 i# A% B0 H- K" v
  63. }
    5 G) l1 E$ ?6 y0 @" G4 K/ \+ i; T
  64. ' d8 i5 C2 v& L$ F! i4 t9 Q, f* Y
  65. ; X9 i& L. m1 r& u# e6 D# D+ H
复制代码

; `, O) ~4 U( u. \" ~7 |修改modbus串口初始化源代码portserial.c文件
1 D6 ?% z0 ?1 q5 k% W: s* b         ~~~~~~~~        在该文件中实现串口1的中断服务程序,prvvUARTTxReadyISR和prvvUARTRxISR函数需要填写进中断服务程序,前者得到作用为通知modbus协议栈串口已经空闲可以发送数据了,后者的作用为通知modbus串口1有数据到达,修改后的代码如下:
) h3 [2 O4 q  N6 M+ L( e
8 Q+ l& G5 d) F2 j5 [0 q& S! X; w
  1. /*
    3 T/ r) Q0 Q7 [& U
  2. * FreeModbus Libary: BARE Port
      {/ O6 |# e6 q" b* f
  3. * Copyright (C) 2006 Christian Walter <<a href="mailto:wolti@sil.at">wolti@sil.at</a>>( m2 I, a1 S' |8 e) Q8 v6 }, k
  4. *' k( [: V5 r& B
  5. * This library is free software; you can redistribute it and/or* c! [* {3 [/ C& J) X8 p
  6. * modify it under the terms of the GNU Lesser General Public" N5 O  ?7 Q  t
  7. * License as published by the Free Software Foundation; either6 T1 H9 f( L6 t0 f. J
  8. * version 2.1 of the License, or (at your option) any later version.
    7 Q) T* [- O  B$ F' a( w0 s! D+ ~
  9. *" W6 [; P, T+ ~. W
  10. * This library is distributed in the hope that it will be useful,, E6 {) f+ i* P( P+ _7 B/ E/ \
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of% l9 d9 m; D$ z0 q( k4 \- t
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1 ]6 o) g+ Z, g- Z/ ~$ \. V
  13. * Lesser General Public License for more details.
    5 g- B, Z' G& v: u
  14. *
    # P( Z0 O! d9 y0 d+ P9 q/ p
  15. * You should have received a copy of the GNU Lesser General Public
    ! s) ^5 Q8 ]5 Q2 `/ @
  16. * License along with this library; if not, write to the Free Software$ p. i% J$ k/ \8 g6 P* v
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA: Z) R" K* `! x. E- F& V9 P& f% e
  18. *% n/ ?( s* i( ~, r6 A0 V8 m
  19. * File: $Id$0 e8 Z0 `; E+ D6 \$ v  r
  20. */
    ; x" k0 O$ K) \$ w' ]% ?  U

  21. - M3 h5 }' _4 P2 F
  22. #include "port.h"
    3 N' v+ X/ ]7 R; K$ i8 J3 \- P
  23. #include "usart.h"
    ) u) W6 k, t5 Z, p$ q% a

  24. # {" w& T# U: X" g5 Z& A! ^
  25. /* ----------------------- Modbus includes ----------------------------------*/' K) {: {8 T( G8 I
  26. #include "mb.h"1 E0 V! }; l) }6 w  n5 c/ a
  27. #include "mbport.h"; `* h" a) L" z8 l
  28. % p" p: F# j$ q% |" ~* ^. g5 N
  29. /* ----------------------- static functions ---------------------------------*/
    $ y5 K8 W" N; ?' K
  30. static void prvvUARTTxReadyISR( void );
    + y: l; N- ~, Q" m+ h6 h+ u
  31. static void prvvUARTRxISR( void );
    5 ]5 X) G0 X4 `3 w2 ]

  32. 9 u! A4 E* e* x1 u! s5 {
  33. /* ----------------------- Start implementation -----------------------------*/7 j0 [* b/ w7 n6 ]
  34. void
    8 ~' k& P  |+ k7 a8 p" H/ G: ?
  35. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )1 k# r; R# M0 W3 n5 x
  36. {
    5 X& W3 `) {+ Q: t5 ^( O) _
  37.     if(xRxEnable)
    ' }# o9 l. x" f8 ~
  38.     {
    : L) ~. F/ {  B2 q6 b; A1 Q
  39.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断9 L- O4 M9 q9 y+ X
  40.     }
    7 Y4 f6 l4 z; F" T; t* {+ q- q
  41.     else
    $ E; J1 x) X, s( k  M, J
  42.     {
    . k1 y9 o$ s3 B+ n) l
  43.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断0 @; w4 V& M4 t: E' b
  44.     }
    # ]8 r" X9 `5 E: ?7 V& }

  45. : l5 S. Z( w  q  U
  46.     if(xTxEnable)9 Z- {1 f, ^# D5 f% q
  47.     {) u7 H7 I4 |/ R) H1 T' r
  48.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断
    - d9 u& d  y, _7 b  {% ^' A
  49.     }
    ) t$ s; z$ s' w/ Y) h3 F
  50.     else9 p+ n' J: ~6 f0 K+ _  P
  51.     {
    4 e6 l3 W; {5 Q' P& U' g% P- s) Z
  52.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断
    3 L  N: m& y$ B6 \( B8 B' K6 H0 G1 A3 E
  53.     }* k) k9 }% D0 R0 \
  54. }
    ) p* i: a+ V; |/ \$ r9 K4 D' @
  55. ( @! d0 P8 h: ~- G2 n- Z  x
  56. BOOL
    6 e( [' Q" s- J3 ^% I" X9 L
  57. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )5 p; M- X! g* U0 |2 q
  58. {: t- |, N5 N% A
  59.     huart1.Instance = USART1;2 M2 O: T2 S2 N2 L" X# ]
  60.     huart1.Init.BaudRate = ulBaudRate;5 S1 e( n: y0 A
  61.     huart1.Init.StopBits = UART_STOPBITS_1;) {3 P3 K4 f7 Y8 j
  62.     huart1.Init.Mode = UART_MODE_TX_RX;
    * P  f9 U9 Z' P, m$ U& ?
  63.     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;7 c) p8 \) O0 Z3 N$ c+ l9 N
  64.     huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    ) D, c& v8 ~! z' Q! a

  65. $ ?7 ^: q- c$ F3 ^" g
  66.     switch(eParity)
    9 w- A) ?1 |% W/ m; ~8 I  S+ U
  67.     {& z% b& E1 G) _  a& a
  68.         // 奇校验
    ! M. X, P6 d) z% X: ~
  69.     case MB_PAR_ODD:
    ( B3 T  r7 C3 f7 J9 }( G
  70.         huart1.Init.Parity = UART_PARITY_ODD;! S9 U3 b8 F* j. F& m% g+ t
  71.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits
    4 b) n; Q* l% k* E$ Q+ i# Z# {- v. y4 r
  72.         break;8 P' p$ _7 k# N
  73.         
    8 C  p" f, `% n8 U% [) y
  74.         // 偶校验1 n& j3 j- w& v9 o" g3 B
  75.     case MB_PAR_EVEN:
    . j! X* U$ J3 _" @! w" H8 p6 ]0 O
  76.         huart1.Init.Parity = UART_PARITY_EVEN;
    4 R1 N& x+ m- P
  77.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits
    + S- f! X# j6 Q' B, C: [- U: k
  78.         break;2 l( a: ^6 m( F! [' c. Z
  79.         : \1 P/ t5 |% x4 J
  80.         // 无校验
    # X5 {9 [* @( n8 m
  81.     default:
    4 ]: s: |4 C, K, u! k- S3 `1 M9 O
  82.         huart1.Init.Parity = UART_PARITY_NONE;
    * r; e' O5 X: X! v  e. U1 g
  83.         huart1.Init.WordLength = UART_WORDLENGTH_8B;                        // 无奇偶校验数据位为8bits6 Y, q" F3 k7 C9 y+ L7 x
  84.         break;
    % C' @' c. j& E  Y7 v
  85.     }
    . U6 Q6 l1 N# M4 R6 T
  86.     return HAL_UART_Init(&huart1) == HAL_OK ? TRUE : FALSE;
    ; D3 D" _3 x% K) F
  87. }
    ( d: J6 u' T0 R1 R) s: O

  88. . C$ k# U, X/ l& C1 S
  89. BOOL' [+ \+ D" H9 j# x
  90. xMBPortSerialPutByte( CHAR ucByte ); v& Z' T& O6 C* @/ n
  91. {+ I8 K* k- q1 @& n- [
  92.     USART1->DR = ucByte;% g, g/ ^4 v$ t. m9 H
  93.     return TRUE;% r" ?( l$ b. J" c8 {: z! _
  94. }" u5 v  X6 g, \+ n6 u1 f

  95. ) J# a9 Y0 ]: K3 [  w+ r/ q4 o1 G$ W
  96. BOOL  N: F: M  P- l+ w0 z! C
  97. xMBPortSerialGetByte( CHAR * pucByte )+ v) D8 h( u% K0 F1 [
  98. {9 v# ]$ t! a+ W2 d/ F1 f
  99.     *pucByte = (USART1->DR & (uint16_t)0x00FF);/ _7 m" q7 ]3 R3 {9 v
  100.         return TRUE;& E: h2 T& Q( Z% c0 O$ ~
  101. }
    3 c% ~) p/ d5 D1 |

  102. $ t: {7 R' I: P- s' f! C% r
  103. /* Create an interrupt handler for the transmit buffer empty interrupt& i7 s3 g( i; A3 ^" C
  104. * (or an equivalent) for your target processor. This function should then
    / m+ \3 G# q- {- z& g/ w
  105. * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
    # ^9 X. j* j2 t8 A. R  q3 p6 I  z
  106. * a new character can be sent. The protocol stack will then call
    / I3 _6 U* o+ a: c
  107. * xMBPortSerialPutByte( ) to send the character.
    9 o' L9 A, R6 y: t4 J3 P3 H& _
  108. */
    - E+ E0 G& D' {+ o" [. T, J$ f+ N/ f+ [
  109. static void prvvUARTTxReadyISR( void )* k. ~- ^8 l$ J9 ]  K: E9 X: E! B( V
  110. {
    / f" Y  g  W( n6 c
  111.     pxMBFrameCBTransmitterEmpty(  );" D" v5 x! Y5 G- J
  112. }1 ^! g2 e5 p: ~# @/ ?/ @. B" C
  113. # }/ Q7 k' O4 y  V# g* l
  114. /* Create an interrupt handler for the receive interrupt for your target# \5 V" N: _$ z8 j
  115. * processor. This function should then call pxMBFrameCBByteReceived( ). The4 B3 o* W4 h& \$ t; w- B
  116. * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the* k2 Y; ^! V% s8 P+ F' D( A1 G8 _
  117. * character.8 I1 ~6 x7 u" V. o* E8 P
  118. */
    8 e0 G1 t) [- K
  119. static void prvvUARTRxISR( void )9 {# C3 Y5 ^" E) R0 h
  120. {$ r( ]; o' t3 x
  121.     pxMBFrameCBByteReceived(  );
    ' _  R7 h. B5 j$ E1 k( F8 u
  122. }
    4 t9 n' H+ m% g% ]- u) J4 v4 A( k
  123. . ]- q8 L5 p' Y  F& V& K. W
  124. void USART1_IRQHandler(void)% G+ h! ~, B" g* m
  125. {
    * I' e: t8 p1 c2 {6 ]# x9 `  v$ g9 ^6 o
  126.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))                        // 接收非空中断标记被置位
      H6 W% e6 p, j1 G8 J9 a
  127.     {
    ! t* S! {( i# W9 ]' \0 j9 P: J4 V' ]
  128.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);                        // 清除中断标记
    7 N  e: p" F" j# k
  129.         prvvUARTRxISR();                                                                                // 通知modbus有数据到达
    - e  N0 r0 `: l& H  `# E4 d6 D* a  r
  130.     }' K5 y- @7 i6 _  j7 h7 C$ T$ k
  131. 6 s! ]5 o3 V" e3 P$ P
  132.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE))                                // 发送为空中断标记被置位4 @& D: m) I. t! p  s
  133.     {
    ' p9 D1 d9 c7 s* o) K! u, s
  134.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TXE);                        // 清除中断标记
    6 I& b4 R* T1 [, V! H  q/ b% \
  135.         prvvUARTTxReadyISR();                                                                        // 通知modbus数据可以发松( e9 V& [. T9 {* x, V7 x
  136.     }* k, c" K+ x# ^% v! f
  137. }
复制代码

/ {# I$ Q& r+ a+ ]6 p* o注意一点,一般如果使用了485芯片的话,那么同一时刻只能接收或者发送,可以将函数vMBPortSerialEnable修改成这样:# M5 ?) j2 x! U$ {5 r: N

  b. E. [3 v3 M% O1 k: I
  1. void
    - Y0 x$ i" C! V/ ~1 r
  2. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )2 W7 [$ R8 }' d; J8 S; P8 R! M  k9 j
  3. {3 E+ k4 z+ t( t9 O! ^2 @1 t
  4.     if(xRxEnable)- ~) n! h$ j0 q% X3 }$ y" ]
  5.     {% {4 ~4 m5 U( h& f  t; h' p' |3 J: J
  6.             //
    / |/ J  i( o( M; P/ t  r( v* K
  7.         // 在此处将485芯片设置为接收模式
    * Q) D4 @: I3 x! x7 t
  8.         //
    4 j+ ?3 W  T- m/ r- x& X$ k+ J
  9.                 /* do something */- b1 @9 K# I" Z+ a: t/ ^; R# _: k) y
  10.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断" ~. ?4 n' y, g* E( k/ X- T
  11.     }
      Y4 I) U& Y  J& U% ~: M8 z+ _
  12.     else3 f3 r' p; k% Q2 z
  13.     {
    9 C$ |! l+ q' A  c
  14.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断
    & t: j6 S: j2 e: o( a" }
  15.     }& H( D2 Q! r% P: s! u9 ~" h

  16. - V" i, w' G/ c. Y9 x$ h
  17.     if(xTxEnable)- O6 `4 r( i: q0 Y+ t
  18.     {
    ) t, J' d$ H. h/ b, G+ A
  19.             //! b2 ?1 y- o% A9 i% E
  20.         // 在此处将485芯片设置为发送模式
    # E' t5 S" v' \2 `
  21.         //
    : B# D2 u5 _* Z+ w
  22.         /* do something */: |; Q  B: S& y5 j4 J! R
  23.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断' a, p( u0 L: k" B1 U% `
  24.     }% b0 e( n) l- [$ S
  25.     else
    ) {; G, y0 ?2 m4 L4 @1 v
  26.     {7 n$ y2 R3 r( a$ Z
  27.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断
    % y5 w9 g; `1 K: F' h5 I/ d; p
  28.     }; s& R8 \% ~; k7 f5 N3 q
  29. }
复制代码

. S8 K# c0 t8 g$ ]* O. F
编写modbus命令处理回调函数port.c文件
. N: O( a7 O* F7 b6 ^6 |0 S本例程只实现了读取输入寄存器和保持寄存器的功能,详细代码如下:
) W5 f4 ^/ R8 v3 }
% o* }) M. @5 Z( A5 [
  1. #include "mb.h"" q: i4 O. ~1 g1 Z# L
  2. #include "mbport.h"5 U9 A5 u( a) f% v, @
  3. , U6 t6 r7 d1 w5 m) S: @
  4. 0 g0 ~( u! {( h' I- o
  5. // 十路输入寄存器
    3 f5 F$ u( A5 z$ t' h
  6. #define REG_INPUT_SIZE  10
    4 T1 a* ?, p  {% ~. q( ~# `
  7. uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];/ d; l" b; n! L0 I$ o
  8. 8 ?- I2 @: p& i2 x

  9. ; k. C; ?( R  k& o( k9 c
  10. // 十路保持寄存器
    ' E& e. A5 J9 h4 z5 C8 D2 a
  11. #define REG_HOLD_SIZE   108 d2 B! [% |* k! e' \: N
  12. uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];
    - v5 p6 M& o% g! a

  13. 5 e& U# ~4 D3 ^1 T

  14. " q/ k- O. V; T$ O& N: `0 c6 v
  15. // 十路线圈
    ; U; h$ i- R1 @) N
  16. #define REG_COILS_SIZE 10
    " O8 Y& E; E0 w5 X7 c  |- S/ z
  17. uint8_t REG_COILS_BUF[REG_COILS_SIZE];
    % V2 x+ i# @9 r1 G1 ?8 |: v

  18. ! ]% R2 i9 s& o! j
  19. ; `6 A! p- _! ]3 V: s/ }6 a! V7 ~
  20. // 十路离散量1 a, g) H; t$ q6 b6 D0 Y
  21. #define REG_DISC_SIZE  104 e: G) C6 _' N" i- i! K5 ~
  22. uint8_t REG_DISC_BUF[10];2 G+ O) Z2 L3 s: z5 Q( w" }; p6 a2 p4 E
  23. ' s8 X% S9 ^3 G& t7 {  W7 y

  24. / S; E( C2 l  X8 B# d* H
  25. /// CMD4
    ; \) G( c8 E- R' u2 O6 J, a
  26. eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
    ' ]1 c8 [/ Q1 M5 G! A: K
  27. {! v8 r& m4 i( w! l7 D
  28.     USHORT usRegIndex = usAddress - 1;
    2 ~/ ^, Y3 T6 ~* b- E
  29. / A6 X/ ~' Q1 J: [
  30.     // 非法检测( t' f- h6 ?6 F: ?
  31.     if((usRegIndex + usNRegs) > REG_INPUT_SIZE)
    9 a! |+ o5 n0 D
  32.     {
    & y( M7 C9 X2 ?! U' _
  33.         return MB_ENOREG;, q+ N( R) ~( Z
  34.     }
    $ F3 G2 A* C$ T, q" f" k

  35. # N. _  p: S+ {) l5 k
  36.     // 循环读取& ]+ A7 `0 q1 D# O" ^7 F; p' r
  37.     while( usNRegs > 0 )$ J4 [, c5 ^7 H% o0 g1 u
  38.     {9 J& I. Y0 a. _- \" p  \# |
  39.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 );+ Z1 B. E) {" f3 M4 i1 G# E" k% C8 o7 m
  40.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );
    6 ^8 r+ ^$ G  H
  41.         usRegIndex++;3 ^- z, j5 i) s& p6 O3 V
  42.         usNRegs--;  r+ y/ |' S0 a/ K" h1 e! e1 x
  43.     }1 e8 ?, V1 f$ m0 \9 C2 U+ E

  44. ' ?& P' K$ z5 y* R
  45.     // 模拟输入寄存器被改变6 w( U, p5 U5 V! W- m
  46.     for(usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++)$ J8 o, E! [9 c& f9 o# M2 i+ p
  47.     {
    4 n+ p/ n3 M. Z7 r( d1 ^! H
  48.         REG_INPUT_BUF[usRegIndex]++;
    % T9 Y2 ?' I9 I- r# X
  49.     }: r0 y- p+ Z* c7 b9 \4 @
  50. / h' J( o& N! E9 i" j
  51.     return MB_ENOERR;- \% |1 C- S8 A
  52. }
    ! F- O9 p2 W. N4 J4 Z( Z- K" }

  53. & P1 S  Y/ |4 M( f
  54. /// CMD6、3、16
    / e( ^/ @' ?4 Y9 v+ Z( [
  55. eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
    5 |) p! E+ x6 F1 y# m3 @
  56. {
    - t- I; {5 Z  @( U. ^" q. t
  57.     USHORT usRegIndex = usAddress - 1;  ( Q! S# ~' U6 ]- L/ v1 Y* i
  58. $ i, E/ F. s, {9 e" h4 _3 B
  59.     // 非法检测
    + z. {* b0 {% m# W
  60.     if((usRegIndex + usNRegs) > REG_HOLD_SIZE)+ I: U6 g8 f2 Y7 }- J# X9 y: d1 ]
  61.     {
    + F+ S& U7 G; l2 X. [
  62.         return MB_ENOREG;/ \+ f. |/ M5 a# O
  63.     }+ y1 [4 h- D: u, g% X7 W! P7 F
  64. 6 _- T3 g4 b, o( {, Z8 @$ V6 K
  65.         // 写寄存器
      z; b+ G) I$ e! x" N% @
  66.     if(eMode == MB_REG_WRITE)
    4 n* T% A2 y3 N" ~7 L2 Q4 Z: B. f
  67.     {' F2 a( ~( T3 ]
  68.         while( usNRegs > 0 )
    . h2 Q+ l5 R" Y. V  H  S) _* _
  69.         {
    7 e4 \5 s9 U5 x6 g
  70.                         REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];
    ! [- u1 U2 q1 C6 N( H" k% S
  71.                         pucRegBuffer += 2;% @" j( S( r, h% S6 E, v
  72.             usRegIndex++;
    9 o& P3 v, X  q* I, V. s2 x$ b
  73.             usNRegs--;2 R  F/ M% p  D7 U) r" ^5 A
  74.         }' ?/ ?. X# V* d/ _
  75.     }
    3 e  T0 y' E& x5 Z  W
  76.         
    ' H$ s2 J7 m, D2 P
  77.         // 读寄存器5 p7 n; `+ K0 E
  78.     else
    7 q# e6 Z. t$ b3 ?9 M
  79.     {
    * @0 q: [$ K- N# B* ?0 j
  80.         while( usNRegs > 0 )
    2 E8 {% b: A$ v- _. G, m
  81.         {
    - m9 X9 t" m2 L* C: c
  82.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );
    / k3 m, v' Z& u; h
  83.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );
    4 K' N3 \; g( c7 l  W
  84.             usRegIndex++;/ x- @. t- a* }; s$ v/ P: F" r
  85.             usNRegs--;" Q% Q+ O* y8 e2 W' U
  86.         }7 N) e+ \5 i5 v) u: V
  87.     }
    ! A9 U& ^; Z$ P; i: f/ o

  88. ' q: ^6 W, G. k
  89.     return MB_ENOERR;9 \9 g" y# w2 |5 z9 E
  90. }& S- a$ K  {: v( t

  91. 1 p% m2 J5 A2 V* \" U
  92. /// CMD1、5、15" P3 {9 A; A$ o& C: W
  93. eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )4 z$ u+ }8 S6 y3 {7 c0 E2 i
  94. {
    0 L2 ^6 {; d+ [2 a, o
  95.     USHORT usRegIndex   = usAddress - 1;
    : h+ |9 f+ H2 _; b/ n7 i/ M0 |
  96.     USHORT usCoilGroups = ((usNCoils - 1) / 8 + 1);/ ?! D2 |- p8 f3 |/ J
  97.     UCHAR  ucStatus     = 0;! k2 l  w2 J( W# n
  98.     UCHAR  ucBits       = 0;
      z1 h8 Y# S. L8 J* @" b% g) G
  99.     UCHAR  ucDisp       = 0;$ A" |9 p, {- x8 F! Y$ k; t2 x5 R

  100. 9 {- r5 H( g+ \2 k: a3 c; o; y5 G
  101.     // 非法检测
    , `) l+ \2 D0 J: ?
  102.     if((usRegIndex + usNCoils) > REG_COILS_SIZE)
    9 y8 {) I  K: ^/ z! U
  103.     {! s$ W8 ]% ^0 T# Y( H: W
  104.         return MB_ENOREG;
    $ D/ I% `2 C% O0 r
  105.     }4 o+ {# b. ~) s0 N' y

  106. & L3 k- n# q  @5 ~( B
  107.     // 写线圈
    + V# ^# B7 e6 \- r3 k% O- s3 ?
  108.     if(eMode == MB_REG_WRITE), g  H3 B$ U2 p9 W, |) a9 a
  109.     {
      h5 `0 L1 V9 x4 Y! s9 }
  110.         while(usCoilGroups--)) u, x/ D( ^: h+ \% [4 @
  111.         {' f4 C! q& F" G5 \: g/ }6 O, t4 m! I
  112.             ucStatus = *pucRegBuffer++;
    ' L* F9 c1 a' c' C' A2 b+ b0 V
  113.             ucBits   = 8;  v: O: T8 b2 A- m/ B4 f* b
  114.             while((usNCoils--) != 0 && (ucBits--) != 0)
    * c; S2 {/ O( I% D3 V1 v
  115.             {3 _$ S! c. V1 T/ ^' o
  116.                 REG_COILS_BUF[usRegIndex++] = ucStatus & 0X01;
    : V# `" M" A! _: C1 N
  117.                 ucStatus >>= 1;) v6 E$ D+ i$ @9 [
  118.             }  {6 d* b6 L; @0 u$ c. |6 M
  119.         }1 @* s& d# c' U2 F8 X( I' G6 b
  120.     }
    8 N$ E8 i: B! o$ }* J

  121. - f2 n& E: c: _" W
  122.     // 读线圈
    7 N6 m1 Q' _' O% `
  123.     else
    , p; G3 _. z; [% n# _
  124.     {
    ( H. T9 P- I: G5 v- s4 U: }
  125.         while(usCoilGroups--)
    & a/ M8 L' U1 X, _$ s
  126.         {
    * p  l2 b( A% `9 V% @& G5 s# D) ^' K
  127.             ucDisp = 0;6 s  E9 `# _& y! D, V5 f% e
  128.             ucBits = 8;
    ' m3 C7 ~8 ~7 v3 n7 M0 K8 U; E4 M
  129.             while((usNCoils--) != 0 && (ucBits--) != 0)
    0 P7 r) f1 P9 E& m. P/ u2 O1 |
  130.             {
    - K5 q. S( z/ F$ [" V" l  e% h( @
  131.                 ucStatus |= (REG_COILS_BUF[usRegIndex++] << (ucDisp++));/ o: f' Q: h# ?) D* x
  132.             }
    5 Q) j, a0 `, m7 ]/ @# v7 s
  133.             *pucRegBuffer++ = ucStatus;0 K& O# _1 c! @
  134.         }
    3 u; b% P+ ]" C8 B
  135.     }0 i% R4 N, B9 {( i& ?
  136.     return MB_ENOERR;' L! P2 X9 j5 g; b
  137. }+ ?3 Q$ r  V3 N, d3 d2 o

  138. # p5 D+ C. B, g+ v# Z8 ]; [
  139. % g5 `3 _. ?7 ?8 X- B) \# M0 N, U
  140. /// CMD4
    & O) s0 P* w2 J/ u
  141. eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
    ; v7 [4 m$ O$ |: K0 y& B
  142. {/ Z* P7 s0 _% K) `% {0 |- j8 K* z5 Z
  143.     USHORT usRegIndex   = usAddress - 1;  \& L; X& J( g! d7 {
  144.     USHORT usCoilGroups = ((usNDiscrete - 1) / 8 + 1);9 E" F6 k; i9 m2 x4 e+ U( ]
  145.     UCHAR  ucStatus     = 0;( p/ q: J: `  ?! c! P
  146.     UCHAR  ucBits       = 0;# d' {; }- e0 C9 o2 r# J
  147.     UCHAR  ucDisp       = 0;
    ! Q2 y7 {0 a# C2 C4 C) x8 K2 h+ Y0 Y

  148. " B* Q0 B' l7 s
  149.     // 非法检测
    $ b( [' Z# O/ N9 D. t
  150.     if((usRegIndex + usNDiscrete) > REG_DISC_SIZE)+ j2 R( ^" m/ f# `  _# W$ E
  151.     {
    0 w& p- o" `/ ^8 c% L. ?
  152.         return MB_ENOREG;
    / @) {% X, A2 \( R
  153.     }
    1 a3 L  V" ]2 a! {1 _
  154. , n3 y2 J/ H( Q+ ^
  155.         // 读离散输入. O' C7 g. D8 D# x+ y. a
  156.         while(usCoilGroups--)
    ! Y! S' T1 c; I, ^( @
  157.         {
    2 {6 _* j' D2 j9 E
  158.                 ucDisp = 0;1 P3 u' i( B  f9 F! Q" I5 J9 D% H
  159.                 ucBits = 8;
    4 S  y/ m: O7 V- [# B/ B4 j* O$ b0 @
  160.                 while((usNDiscrete--) != 0 && (ucBits--) != 0)  w9 B1 T( E9 @4 n  v+ }
  161.                 {1 ]( x0 V& F" N. p" G6 ~
  162.                         if(REG_DISC_BUF[usRegIndex]). n$ H) Z3 J+ @$ i$ c; j
  163.                         {
    $ p* d9 T! b( X+ Y2 y
  164.                                 ucStatus |= (1 << ucDisp);
    1 h1 E0 p7 q  `2 J  T
  165.                         }8 [1 H$ C& y9 H, T+ K  M/ W
  166.                         ucDisp++;
    - s0 S4 O# X% P1 w
  167.                 }
    # i9 h! {6 F7 E# l$ c' n
  168.                 *pucRegBuffer++ = ucStatus;
    9 ~1 z% e& R8 C% H$ F
  169.         }( _+ p- `: U! X" k
  170. ( |& p9 X, \5 O" z' q& K  T. j
  171.     // 模拟改变7 j' D+ V: u2 w0 P
  172.     for(usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++)) W9 L- L3 I/ v
  173.     {* f& e8 _7 B2 a8 S! G9 t
  174.         REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];9 b' w# I5 c( d
  175.     }
    $ L8 N& L; b  R& k! x

  176. / h- h1 P1 Z1 r1 I. @1 |. l9 \
  177.     return MB_ENOERR;
    * @9 J! \( r9 M5 b
  178. }
复制代码

) Y$ U. m. E; N; O- U5 l主函数
, W4 b/ b  y. b. j' n' g  L+ E
  1. int main(void)- R' M, S3 n# ~
  2. {1 b& @8 b) K" T5 U/ R7 ~7 h  ^) r2 Q
  3.     HAL_Init();1 }4 h3 m2 e' g0 y/ O
  4.     SystemClock_Config();2 G, z6 d% P! M& w: E
  5.     MX_GPIO_Init();
    - H1 u$ o  @4 {9 v4 E
  6.     eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_ODD);                // 初始化modbus为RTU方式,波特率9600,奇校验
    . n; _+ A" x7 \6 \
  7.     eMBEnable();                                                                        // 使能modbus协议栈
    8 b6 G2 |# s( i& D3 F8 n2 \
  8. 0 \) k/ t% f4 w* ^
  9.     for( ;; )
    / ?% x, G5 g3 X  o
  10.     {
    - v9 {6 s# M5 p
  11.         eMBPoll();                                                                        // 轮训查询
    , G. }; }, C# b" Y( p0 [
  12.     }- \5 _- ^- G$ o0 x
  13. }
复制代码

" q9 z1 @  v  M2 G' n; Y6 j移植测试* K# b% C- |5 w. T
' Q$ J( D* P; \8 B; E
20200313154857173.gif
( w: @+ q* [) ?0 s
  j  K, b& ?# k3 k' D9 Zends…
9 @+ h3 ^/ T% O. B8 V$ w3 ]6 E; H4 a( \8 N- J6 m% P/ _& A" }
5 j2 L0 I- a! D/ C; |6 X& p
0 N( B2 [  Y6 M% x# u+ O4 @
收藏 评论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 手机版