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

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

[复制链接]
STMCU小助手 发布时间:2022-4-10 22:53
modbus命令码表:9 u4 N. C9 R+ D
3 v3 T! b1 U+ O4 d: i
b8032deb4d154657acd2f7f2942369d4.jpg
% [" k  h5 w( S3 k+ x9 m9 `0 Y# e, X4 q
FreeModbus文件说明
/ N* w4 W4 s. V" Z4 ^& a' B
      解压freemodbus文件后打开,我们需要demo目录下的BARE,该目录下的代码是空的,STM32移植工作基本就是修改:portserial.c、porttimer.c、port.h这三个文件。: ]* ]3 F8 M3 a# x" g  c
20200313143257958.png 5 G  c6 Q2 b! W+ r$ m3 b8 E$ P
2 q, v+ z; Y9 d9 V
      mobus文件夹就是完整的源码,包含rtu、ascii、tcp:
$ Y  G1 l( R6 R/ G0 ]0 N
% M% {' ]0 {6 I$ E4 X" D3 L ZM%DLXPRB8$%[NN2%4Z1N.png
5 w. H4 G. _) M) ?& q2 e+ g0 a( T0 l1 p9 v- o
      我为了移植时在keil添加源文件和头文件方便,就把modbus所有的头文件和源文件放到了一个文件夹下,并创建了一个port.c文件,用于编写modbus所必需的回调处理函数:
) Y; P  ~) k  @8 r% P1 C9 a3 X" i$ Y8 J9 U
20200313144036579.png
% `3 P( Q! [  I2 p" {+ G
4 P- @2 J1 r5 _6 b: r' z+ @STM32CUBEMX配置
8 f: J) E1 u9 N# |) I
时钟配置,设置主频工作在72MHz下:

6 E0 b& R7 k: c; I0 H- R$ A: Y( j' F
* w: q; |9 U; M JU1~N33M}I7K1(6K@JFN5~R.png
# s* p1 S7 S- u) T& {! x& A& R( U0 Z% r- P( O( ~9 S
配置串口1,这里随便配置就行,在modbus移植过程中还会对串口重新初始化:

# P" {1 |" ]& Z: `' l
3 Q1 P4 Z" g& i/ `3 }& v8 N4 W U25OQ_FHYD5WEXLFMI4V@RU.png
! J. T) @3 i( f6 `! S% P( `" _" W5 G" {% r' X1 q  M* d9 p( X5 n
配置定时器4,用于3.5个字符的定时检测,这里随便配置就行,在modbus移植过程中还会对定时器重新初始化:

6 D# F- s: k  M7 P: ^" e( |- A9 f" {; C% L6 C' g
H6{)WT`**CIHDAM02558GK.png ( |1 E$ G# Q! Y: m7 R* g1 x

& x) a( v; w1 S中断配置,这里注意,串口的优先级是要比定时器优先高的:

4 h1 w7 g  x- {; U9 \+ ?' D
9 @+ }' j4 U. G4 \ G(RP`74TR)NPJFUK``Z%I2L.png
* p8 M( _$ p; y5 r& Z5 w0 q2 q取消掉自动生成中断服务程序,在移植过程中我们要自己编写串口和定时器的中断服务程序:$ i/ X% M1 ?& L" h- b

( t: o" f- \: `( k, g; ]1 V2 M ALHMK5Y615K6(`M{0[]YJ.png ! W! j1 Z( C* p' Z6 E, m- \4 v& \2 [6 s
# [0 X9 w4 e  R  ]
移植代码修改

, b9 S& X) D  A% f2 a- L; J/ [生成代码后将modbus放到工程目录下:$ `7 M8 B2 ^9 J9 x" `( h
0 P% `: @) z% v
5%(_LMGIM_8_YGL`]JGAB67.png 1 D: Y! k4 `3 M, ~9 W* P
4 z8 Z6 ^$ N: E+ b% Z
打开keil工程添加modbus源码:

4 G" C" c: |( P  Q- M8 o' y
3 o7 v5 C: x, @. w7 j% b F`8_YFACMNOAP28~2VHD{CO.png ! X6 z& P# k+ r! ]7 V

; a2 S. i6 b8 E# S; F添加包含头文件:

- V% f! Z! K& `; K/ t& P3 s  h# U2 ^' X
`7BMVXA`R9SQBTGT`B@{]X7.png : Y2 Q; |8 u) t4 i3 H
  m9 U0 `, H" U' R
修改modbus定时器初始化源代码porttimer.c文件/ ]/ G7 ?4 E+ M( I" W; n
       定时器的修改比较容易,将定时器设置为每50us的时长记一个数,传入的usTim1Timerout50us变量给自动装载即可,prvvTIMERExpiredISR函数需要在定时器中断服务函数中调用,它的作用是用于通知modbus协议栈3.5个字符的等待时间已经到达;由于我们在STM32CUBEMX中取消掉了定时器和串口的中断服务函数程序,所以我们在该文件中添加定时器的中断服务程序,修改后的代码如下:
; K5 Y! ]% A3 w6 T+ F) H
( C1 d/ g9 R# a# A; A$ L& I" S
  1. BOOL
    % K+ Z( M# p/ Y
  2. xMBPortTimersInit( USHORT usTim1Timerout50us )5 c9 x% G7 K# K) _  Q" P
  3. {6 D, \; [9 h/ n4 X% J
  4.     TIM_ClockConfigTypeDef sClockSourceConfig = {0};% ~+ X" j! i) [$ b: i6 ^
  5.     TIM_MasterConfigTypeDef sMasterConfig = {0};8 n7 l6 s, o4 P! B  L. g0 C: `

  6. + B+ B2 b$ T: O4 k+ j" _7 T
  7.     htim4.Instance = TIM4;2 |; r, |  ~) S9 e3 S
  8.     htim4.Init.Prescaler = 3599;                                                                // 50us记一次数
    % x& \4 s( r0 {7 T1 _. M3 ~; z
  9.     htim4.Init.CounterMode = TIM_COUNTERMODE_UP;' g8 v; [2 A( R
  10.     htim4.Init.Period = usTim1Timerout50us - 1;                                        // usTim1Timerout50us * 50即为定时器溢出时间7 A1 R, V: {3 l) \2 y' U; P0 a
  11.     htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    " C# T. d% X( |) w  W2 I
  12.     htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    9 ]$ c0 m& u, k4 a- w( M
  13.     if (HAL_TIM_Base_Init(&htim4) != HAL_OK)( Y, b& ~# U% E" E% C2 W
  14.     {9 U8 W: s& a% z
  15.         return FALSE;
    ; ~  z0 A5 n' u4 s0 D/ m
  16.     }
    9 Q) }9 Q; F, ]$ L
  17.     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    ! O) _# Z# Q, U" J7 d, f
  18.     if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
    9 F, a) `6 S% g+ B/ d$ R
  19.     {
    2 e- e5 m; O" i0 n9 k
  20.         return FALSE;$ B1 @, }( |: d. b
  21.     }
    ( G' L: H9 i) @$ y$ F4 @
  22.     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;4 x! I1 H* E; O( B0 J, J+ B# |
  23.     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    ; d9 u$ v" [" J4 y( M. b. }
  24.     if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)$ g4 n- K; h7 L+ p
  25.     {
    6 h5 J) M* _! x: e, L: l' Z% l( g
  26.         return FALSE;2 B# \, P/ O7 k
  27.     }
    & I! L+ w2 N% S  I+ O2 g! t

  28. ! N( b9 b- L3 n1 R7 u+ _/ ^
  29.     __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE);                                        // 使能定时器更新中断' w: t& \+ F$ [, P
  30.     return TRUE;
    2 J; m$ i- x$ N% w* s
  31. }
    5 k  W( h, n! Y- V% K. H

  32. : [4 Z# p# o5 p2 @
  33. inline void+ c; p* @& D0 [! w7 [- R, U' e& t/ O
  34. vMBPortTimersEnable(  )' S3 o' }# i+ l! e* e1 D' R: `
  35. {: B% A0 K! B/ g+ W& B
  36.     __HAL_TIM_SET_COUNTER(&htim4, 0);                // 清空计数器& s9 f3 E- n6 {: w3 `
  37.     __HAL_TIM_ENABLE(&htim4);                                // 使能定时器* h6 \# r" S5 Z# |& }5 Z& J
  38. }
    4 p: D9 w, I5 x2 f

  39. / x0 u) }% W$ J+ C% r7 J/ G
  40. inline void
    : V; f( ~. m: P9 a) \
  41. vMBPortTimersDisable(  )
    8 Q" q6 X  I6 h  T' W/ @$ ~: Z
  42. {# `% `% V* V2 E  Y
  43.     __HAL_TIM_DISABLE(&htim4);                                // 禁能定时器9 D- J6 E' t7 [2 Y  L2 r% f! R
  44. }) X+ [4 |& ?$ b( \/ J3 R, l

  45. 0 U0 j5 [4 v) E3 z9 ~. ]" v
  46. /* Create an ISR which is called whenever the timer has expired. This function
    5 Y( c4 E. Z! f! `
  47. * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that# |# \2 I! k! N7 q; X% I" m+ ?
  48. * the timer has expired.
    3 s" a( h! P* R0 N' A
  49. */
    7 V5 F0 R, W8 S
  50. static void prvvTIMERExpiredISR( void )5 Y4 q. ^/ r0 p, n+ ^# h0 P
  51. {
    ' Y+ [' p+ x) y2 v/ I2 g
  52.     ( void )pxMBPortCBTimerExpired(  );) m4 i8 E* u8 B  H6 w% j
  53. }
    5 U1 a' |) g3 c) s2 e
  54. $ ~  K# w! t5 x) l/ d: U4 f, _0 h
  55. /// 定时器4中断服务程序, ]6 W2 I' O* ]# U4 U
  56. void TIM4_IRQHandler(void)2 p6 Q/ g/ _, f8 X% G
  57. {
    4 o9 f! b' S4 w, I
  58.     if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE))                        // 更新中断标记被置位  l& |9 N" f) }9 Q4 S9 s
  59.     {
    : g3 G. ^1 Y& [  P, X( L, O
  60.         __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE);                // 清除中断标记$ U4 K& x8 c! ]% a
  61.         prvvTIMERExpiredISR();                                                                // 通知modbus3.5个字符等待时间到( s% E+ |7 s% g* P4 ?5 _
  62.     }
    % K" n! G5 `0 y3 @: P! O3 M  r- A
  63. }: A- w& y" Y: ~
  64. 1 c7 j8 G( n3 O/ N6 p. k

  65. , p0 l9 c6 p( X* i) m( `( N
复制代码
( u3 x. I( |% t/ z6 _! d
修改modbus串口初始化源代码portserial.c文件
0 u) Z5 ]$ F$ J! ]9 H, G  l: j' \         ~~~~~~~~        在该文件中实现串口1的中断服务程序,prvvUARTTxReadyISR和prvvUARTRxISR函数需要填写进中断服务程序,前者得到作用为通知modbus协议栈串口已经空闲可以发送数据了,后者的作用为通知modbus串口1有数据到达,修改后的代码如下:
9 `  ~6 `  v. ^, p9 W8 b- T9 y/ M4 R# m7 C3 {! a
  1. /*
    / w, g1 l8 _3 `9 Y
  2. * FreeModbus Libary: BARE Port
    1 E* T1 C. [! M) j0 g
  3. * Copyright (C) 2006 Christian Walter <<a href="mailto:wolti@sil.at">wolti@sil.at</a>>% O+ |( N- _* D" \. R& f
  4. *; f' `' t! K  ^9 G6 f5 m
  5. * This library is free software; you can redistribute it and/or) o- B- ^  ]" z) ]" I" u
  6. * modify it under the terms of the GNU Lesser General Public
    1 z) B- y8 |3 G; g' {6 p" _
  7. * License as published by the Free Software Foundation; either  _, ]& ?" V( Q9 c/ M
  8. * version 2.1 of the License, or (at your option) any later version.
    ) d6 T; R: G% I) e$ E+ j
  9. *
    3 K; ?3 f8 X* S6 P2 \, O: s
  10. * This library is distributed in the hope that it will be useful,
    5 L1 z4 m0 s3 }3 i1 A" x3 I  K
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1 M; Q- P1 G- a: B7 ]
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    - F8 y' J) d3 m5 l9 S. U
  13. * Lesser General Public License for more details.
    1 \* _1 E1 i/ Z" j+ f' y& G& \
  14. *
    ( T0 @; E3 t- p5 X3 F% h6 ], L" u) O
  15. * You should have received a copy of the GNU Lesser General Public
    $ r" q' g8 O3 ~
  16. * License along with this library; if not, write to the Free Software0 w5 n# a  y8 w+ z0 Z0 X$ d1 L3 j
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    ) f& @2 V, y$ h, k
  18. *, W- N' C. t$ c) d
  19. * File: $Id$
    - R  v7 d$ ?/ z' a, a
  20. */* }# V' a6 {, A+ m1 p- g

  21. 9 s* d# p- Q% V" `& i9 Y  E+ |. z
  22. #include "port.h"
    0 n. l+ X; _9 K
  23. #include "usart.h"
    2 Q) j6 N6 d' j- ~- E

  24. - i6 e4 E. B! W3 J
  25. /* ----------------------- Modbus includes ----------------------------------*/
    ; o0 |, l% }* ?) D: T. W* P0 x/ K* M
  26. #include "mb.h"
    ; X+ |6 A; j) ]( y
  27. #include "mbport.h"$ I# p& T! g8 ^* n7 b0 g& A) P

  28. 0 M0 E. n  s' ?) F- ]" p7 I
  29. /* ----------------------- static functions ---------------------------------*/
    - B: s7 }) h: j7 N% |- c
  30. static void prvvUARTTxReadyISR( void );
    0 M, t# X$ e0 u
  31. static void prvvUARTRxISR( void );+ `' z, v$ H* J  o' `8 J+ W! D# u
  32. # v2 c1 o4 u  N& ^* L
  33. /* ----------------------- Start implementation -----------------------------*/
    / H9 H7 o5 N0 P0 g+ Z
  34. void* D: Q& g0 E0 {2 \8 A1 J0 v
  35. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )4 }  E3 ?  v3 W
  36. {6 P7 r) @- X. M3 S& _
  37.     if(xRxEnable)& N: ~. `/ V' Y4 J: D' o
  38.     {
    4 Z& o& X$ w* \* |
  39.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断/ W9 E! o. a) d1 C; \
  40.     }
    # O* N8 ~2 G( p, L9 I# x
  41.     else2 V: c5 @3 F( _5 |; T
  42.     {' y! z6 h. e1 m; c: ^6 |$ n# p
  43.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断* M4 U; O: b1 u1 ?1 I  r# p$ v
  44.     }' N( B: l+ N: ?, T$ ?2 o
  45. ) }: ?% K# V& V
  46.     if(xTxEnable)
    ' D& I4 }( [. B
  47.     {
    ) @% R! D" n( {% @- x3 T
  48.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断. S5 ~1 [) ~6 p" f  @$ X9 a
  49.     }
    8 Y  }! k9 u7 P! i4 S+ ]
  50.     else  o; o) W/ u( V$ G2 }
  51.     {
    - O$ e2 ^! U# R8 n& H
  52.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断$ t2 k. j  F. ~0 [! u. [6 Z* d
  53.     }8 ?8 _" s% A* y
  54. }
    3 r5 x) F0 l/ s0 D: F
  55. $ e: {1 G9 H/ f) w. A, s
  56. BOOL
    " v0 \. b8 M0 D& c- F% e$ Y; Y6 d
  57. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
    * w: b( }* a- R) v! R
  58. {
    ! E7 w% l$ a5 I7 g9 {& M0 v2 ]
  59.     huart1.Instance = USART1;0 D$ f6 N$ A4 P! D
  60.     huart1.Init.BaudRate = ulBaudRate;
    3 ^9 D3 ?# c, S
  61.     huart1.Init.StopBits = UART_STOPBITS_1;
    " P1 u7 p0 o. P! b" U$ y: a
  62.     huart1.Init.Mode = UART_MODE_TX_RX;# X% O# Y1 S, V& }
  63.     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    " Q/ p5 G& Q4 z
  64.     huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    , d5 g8 T  w& }- M* B

  65. 5 e$ L& Q4 J8 b( O3 R+ H
  66.     switch(eParity)9 c% \2 v6 W( P: B
  67.     {5 H9 z7 f1 P6 q: j6 ?& }
  68.         // 奇校验
    / Q! `9 m/ K7 B/ G
  69.     case MB_PAR_ODD:3 ~, Z% X+ e( x. n* h
  70.         huart1.Init.Parity = UART_PARITY_ODD;
    6 |: _  e7 s% h& K$ I7 B( J
  71.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits5 C1 R  C$ l/ t& y6 x3 i- V
  72.         break;7 X  H" ?) N8 T' R
  73.         
    5 f. Y9 Q6 n+ R" f+ u/ d7 j
  74.         // 偶校验& a( T7 I# d9 h1 c8 L
  75.     case MB_PAR_EVEN:
    0 X  w  t. V& h" p8 ]& H
  76.         huart1.Init.Parity = UART_PARITY_EVEN;6 c: J9 |- {: @; \; y5 u
  77.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits2 @9 h7 [( R$ C& W! e
  78.         break;
    3 X+ a) e( }! O7 M3 y
  79.         
    1 L* l* s! O1 n# Z: r& M" N
  80.         // 无校验  V8 F" i+ L8 \3 ]2 V; _  s
  81.     default:
    - E  ?6 b, x- t5 M5 o- o
  82.         huart1.Init.Parity = UART_PARITY_NONE;
    8 m$ C" y6 ]# H/ M
  83.         huart1.Init.WordLength = UART_WORDLENGTH_8B;                        // 无奇偶校验数据位为8bits3 v5 q% z! E2 D( a
  84.         break;
    $ E" h4 G% y# q# ^% j
  85.     }
    ) N/ v* k; }) y  r1 w
  86.     return HAL_UART_Init(&huart1) == HAL_OK ? TRUE : FALSE;6 a( W) l" S; O/ f
  87. }0 O- [# y4 S& f# h! k. I" a
  88. ! G' N% x6 l, I: o) T2 [( |
  89. BOOL
    1 V! L# K' h& Z
  90. xMBPortSerialPutByte( CHAR ucByte )
    0 j4 C# v# x4 O2 X3 D
  91. {0 q/ E' h) \/ Q7 d  D( v2 W: F
  92.     USART1->DR = ucByte;
    - W/ D2 `; b( B/ i0 x2 d9 z
  93.     return TRUE;, I. r# M. p# e6 h. M( s7 g
  94. }$ J: r! z, D9 [% v4 j

  95. * w( p( m/ L4 {8 y7 u
  96. BOOL! m" f/ r) D  {: M
  97. xMBPortSerialGetByte( CHAR * pucByte )
    4 S5 q5 B, G1 {' H% A, l9 ~
  98. {
    " D4 g) Q& q7 \, B; J
  99.     *pucByte = (USART1->DR & (uint16_t)0x00FF);+ P( J4 Y" a  H  d! Y1 o6 q
  100.         return TRUE;) g) p" b" g1 {& c  `$ _
  101. }6 b9 A0 m/ ?# z; S( n! q: y6 S* ~

  102. ; G3 t; W2 G; i& t2 Y8 l( J4 a! ^; e- x
  103. /* Create an interrupt handler for the transmit buffer empty interrupt
    3 a+ I. t8 J! F& K
  104. * (or an equivalent) for your target processor. This function should then
    5 ~5 s; x" D7 n' x! w& O
  105. * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
    7 O4 s1 H4 G- Y3 Y- d
  106. * a new character can be sent. The protocol stack will then call& X* T& Q# J( T
  107. * xMBPortSerialPutByte( ) to send the character.+ P& @' F# S" y8 b2 @
  108. */% Z" y4 A3 a4 `0 d$ I
  109. static void prvvUARTTxReadyISR( void )
    / O$ A5 e4 c7 C* Y6 M+ G/ _9 O
  110. {
    0 @: V3 P' x, l' K' i
  111.     pxMBFrameCBTransmitterEmpty(  );
    ' e$ I$ R2 k( R/ G) T  C8 l
  112. }; i: J: u, M% m+ M1 Z8 U
  113. ! {7 f! ?/ k5 D# }2 }
  114. /* Create an interrupt handler for the receive interrupt for your target$ U; }; ^4 T) E
  115. * processor. This function should then call pxMBFrameCBByteReceived( ). The1 _5 d! Y! N; w% M6 o5 {4 a$ F
  116. * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
    5 X" l, Z0 Z5 t3 t6 B3 H
  117. * character.
    , R# \- p, Y7 M! i% s
  118. */: l, R  Q( k1 Z4 C; x8 T
  119. static void prvvUARTRxISR( void ), ~: A$ h: k) P: S( B4 t* W
  120. {' y. z: E5 L+ X( i; x( c) s8 s. C) w9 ^' V
  121.     pxMBFrameCBByteReceived(  );: s( H2 d( F' `6 E9 N
  122. }, u9 {1 _( ~- z9 S. C

  123. $ }1 B7 O6 Y# ~- j0 F
  124. void USART1_IRQHandler(void)4 y' o4 e- X8 i$ B7 U! p: ~! G' F
  125. {
    . P1 M0 _, F5 Q, k8 o9 @9 I1 ^2 n
  126.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))                        // 接收非空中断标记被置位
      i1 K  E, @: [* O* p7 n1 S) [
  127.     {/ D  K' K+ `6 S+ I) y
  128.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);                        // 清除中断标记5 w! Q9 Z& j$ u- h' G& z+ [+ g
  129.         prvvUARTRxISR();                                                                                // 通知modbus有数据到达: A% C' }4 \  P7 z: Z8 Z3 T
  130.     }: X* [5 N  n! `9 \
  131. 5 F, o( t1 c0 e$ {: z* w
  132.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE))                                // 发送为空中断标记被置位# M- X3 d3 T: k2 w) K; P( y* w
  133.     {$ c5 }( V% B& z! Y! y0 s. C% y
  134.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TXE);                        // 清除中断标记
    8 N. w4 s1 d. O1 U- `9 k
  135.         prvvUARTTxReadyISR();                                                                        // 通知modbus数据可以发松' I7 j# e9 T$ y5 D& V9 p
  136.     }$ @0 t, ]2 m; O" H
  137. }
复制代码
: M- e6 V" n: v* ~% b
注意一点,一般如果使用了485芯片的话,那么同一时刻只能接收或者发送,可以将函数vMBPortSerialEnable修改成这样:8 x8 K% h0 |. B+ R6 R6 b' t

8 d* O5 o; @" b9 _6 H
  1. void6 C$ H- u3 Y2 }/ S# ?4 {, _/ {! A
  2. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
    3 _) ^  h$ @. s" p
  3. {
    ' z* G& m  ^: A/ w  o# l
  4.     if(xRxEnable)
    1 G8 N, @+ u& B
  5.     {
    * q& w! c; i# ~3 p( K+ w8 w1 K
  6.             //
    % p  P( h; i7 `5 c/ v: o
  7.         // 在此处将485芯片设置为接收模式# U& |, @* J  u7 z
  8.         //# h' n/ {1 g: @0 B/ P4 u9 u  |
  9.                 /* do something */" b5 k+ ^% m' K' ~( S* A  _2 J
  10.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断5 I% q& r/ D' N9 A- x7 Q
  11.     }7 ]+ E& `, C$ T- `
  12.     else
    5 v, f3 `; n8 b6 g5 X
  13.     {9 F% k5 m7 \/ V0 Z: l6 X% y! V
  14.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断: f0 _( `2 S4 q5 }  W1 w# E  U" z
  15.     }
    7 c/ ]. Z! b* W

  16. 5 ^! I5 z6 G+ ~3 H, @
  17.     if(xTxEnable)
    # ]# O9 [: b+ D0 d  t% p8 v
  18.     {
    * w% v. K* n5 ^6 i# s
  19.             //
    & A9 r8 m+ S/ B- k' e) l) ?$ j
  20.         // 在此处将485芯片设置为发送模式9 K: V9 F( F) e1 B/ C/ z* b3 m
  21.         //
    # M& G; {! Z" ~6 B4 p/ c" z9 M
  22.         /* do something */
    ( G) j4 j( W0 M/ Z; J3 h
  23.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断
    ! D$ g! T7 N3 H
  24.     }3 v  P% ?4 F/ ?5 U
  25.     else  v) k6 c7 c5 T) L2 R
  26.     {5 \2 [) f1 v* F
  27.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断
    # J9 U; s& {2 ?) B4 Y8 |& ^: W4 C6 K
  28.     }" W" W3 P2 R# z! a% i; \/ }
  29. }
复制代码
8 A* P5 V/ M* e' a7 q" F( i
编写modbus命令处理回调函数port.c文件% q! \" ~" ?# W7 N; `
本例程只实现了读取输入寄存器和保持寄存器的功能,详细代码如下:! m: M& @& z8 K9 q
& v5 j/ l+ |+ w. X3 w
  1. #include "mb.h"
    ! m3 t! q" f' C- x* M& u
  2. #include "mbport.h". R- `6 w( S6 k$ V9 n

  3. 1 D6 Y% ^3 I$ g% a. g; `

  4. 0 y/ C) C% r1 g2 N" b6 T$ _
  5. // 十路输入寄存器" f! |2 w0 H: J! ]7 T, k# g  ~  _6 S
  6. #define REG_INPUT_SIZE  10
    " k$ U: _! Z; b/ o/ r# _3 [$ ~
  7. uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];+ L- |( h2 {5 U5 I& i, ^2 [' Z0 u

  8. : l9 D! ]" i: r" q6 S
  9. 1 s$ y/ U; H. K! H2 \, q9 `
  10. // 十路保持寄存器5 k# b6 g9 `4 m' C
  11. #define REG_HOLD_SIZE   10
    & H. x3 f. V; r
  12. uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];
    2 @* g( ^0 G7 R! t' O
  13. 6 }' {# O, I0 q; J' k1 {
  14. ; K2 L$ F8 X) F7 K2 h
  15. // 十路线圈
    * M) H) M% z% T1 v/ i7 v  W- a$ ?
  16. #define REG_COILS_SIZE 10
    , X# j# {) t, T% h
  17. uint8_t REG_COILS_BUF[REG_COILS_SIZE];
    # I; b  H/ O7 z

  18. 8 j/ C& y6 w' T, e

  19. , V, r" Z6 V: o2 k0 Q3 k+ J
  20. // 十路离散量+ z5 O  i1 N# u$ F& r
  21. #define REG_DISC_SIZE  10
    : L1 @, Y  O2 ^
  22. uint8_t REG_DISC_BUF[10];6 t8 x1 f5 M1 S! z
  23. - s& i9 ^: S; `: J5 |( x

  24. ( L5 R# V% ?+ A: s' c
  25. /// CMD4
    . a4 S  g9 l  ]% J/ \
  26. eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
      w( c& E1 M" `* J# g/ l& Y# f+ R1 b# Z
  27. {
    2 g- |5 n7 S( h6 k' A3 [
  28.     USHORT usRegIndex = usAddress - 1; % n1 M- e7 {* a* o
  29. 2 f$ J! D; j2 h: R) V9 n
  30.     // 非法检测
    - g9 X; E$ {$ X
  31.     if((usRegIndex + usNRegs) > REG_INPUT_SIZE)! m2 H: x1 d5 o
  32.     {
    ) d- @& j/ a" \" y! k" F6 G/ A
  33.         return MB_ENOREG;/ G- B: J# c) d% U
  34.     }" K9 j( k- i9 ]$ @3 g
  35. ; N4 |5 O5 d5 k4 w
  36.     // 循环读取
    . r4 }9 B2 R9 h& Y) \, M% A
  37.     while( usNRegs > 0 )
    ' ~' a2 Y3 h: e0 S' X
  38.     {
    - B( `4 }6 t- b% @
  39.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 );: W/ m$ G, f4 x, l' _6 @) \
  40.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );
    $ K0 M) `$ F8 s4 ]1 Q
  41.         usRegIndex++;
    1 I& t- A7 ^* i( ?/ x# R) l
  42.         usNRegs--;/ F7 a: I: P  H2 p* J
  43.     }; n: [5 H5 e& b- m3 ~, r* r

  44. ) \8 V8 L+ [- \/ B/ e8 G, ~
  45.     // 模拟输入寄存器被改变
    : s0 C" _( W5 X! Y# M% _2 Y3 I% u
  46.     for(usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++)
    4 I7 N5 f7 I+ E  s0 O/ J
  47.     {- J- E9 ]  ]& i$ A
  48.         REG_INPUT_BUF[usRegIndex]++;
    # |% M# `! N) q2 K& b, ?
  49.     }8 b* W) W9 b4 B0 A, i$ W
  50. ! G% }( j' B/ D! U  e
  51.     return MB_ENOERR;
    ( R5 ]$ a) H7 `) k$ W( w; @
  52. }
    & }/ l; q" t2 V, X3 t7 H
  53. $ t" X% j4 X) T+ R' p' ~; o4 k
  54. /// CMD6、3、16
    6 [: R$ h/ y! R" s" _. d. q; ]. J
  55. eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )7 b& {) ^* P1 T( `& X5 w2 |
  56. {
    # D$ Y3 q. _6 Z# E/ e
  57.     USHORT usRegIndex = usAddress - 1;  2 V* T/ i! Z+ B/ ?% ^  q

  58. / r3 ?  J% ^1 P/ p( j' {
  59.     // 非法检测# f7 P6 Z# T  Z' d$ x
  60.     if((usRegIndex + usNRegs) > REG_HOLD_SIZE)5 q( T- I+ \+ l/ h" r, U
  61.     {# `4 ~5 \; Z# d
  62.         return MB_ENOREG;9 q6 Q0 x9 k1 c8 P
  63.     }' M! M$ Z8 k7 b! N0 t- F+ y# v
  64. % N) y% D6 X8 j0 g6 ^- \& u
  65.         // 写寄存器
    ; J( B( n" S* l
  66.     if(eMode == MB_REG_WRITE)
    5 i8 W/ z3 ~! I
  67.     {' ]" `' @' R4 w2 C" Z3 V2 r/ b
  68.         while( usNRegs > 0 )0 }9 z- D! R% e! e
  69.         {
      n% ~, B' m" A5 S7 ]6 x! G  e: ?
  70.                         REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];
    / [, l8 r: b  z: F5 d% [
  71.                         pucRegBuffer += 2;
    : T" Z3 Z" {7 t' V) \& [
  72.             usRegIndex++;
    * n% Q# J1 h) _% g( J
  73.             usNRegs--;" F* i5 L9 ?8 T. s9 d+ m2 t; p0 `
  74.         }; n" {' n1 k6 H. e) P: N
  75.     }. O" W/ f$ C7 p- X1 K4 o
  76.         " V' F3 z: m: z
  77.         // 读寄存器
    ' F6 ^, s7 y3 {  G
  78.     else
    6 r9 X. S7 H- l6 y" h) G
  79.     {
    ) \  z) S. k7 W; k
  80.         while( usNRegs > 0 ). U+ O; ]9 d& r1 g5 \( M
  81.         {1 q8 G0 Z/ ?0 |! u" p
  82.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );
    ) W1 S: L. o; d$ k* G1 f: F. `
  83.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );
    , p' X, n1 b8 m, \' G+ |
  84.             usRegIndex++;/ r4 {5 |' N5 k
  85.             usNRegs--;6 G% O9 i. g4 J, }7 l
  86.         }: K- ~5 u- E; q7 g7 X# i5 o
  87.     }
    9 l+ T+ b* Y- e

  88. " h4 I. e. R5 M8 ^$ e
  89.     return MB_ENOERR;
    8 s+ i: p0 s+ c' L" t6 w3 {- ~+ B: o
  90. }
    ! v1 J* q1 t5 \8 G

  91. : e9 l" W' Q$ H, U' h7 B% n3 h
  92. /// CMD1、5、157 k) o3 D! a2 l9 \' X5 v
  93. eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )3 e/ p* ]! \+ ?) Z  f! g* d# |+ ^
  94. {7 F- S( g/ y5 z+ B* R
  95.     USHORT usRegIndex   = usAddress - 1;
    5 }6 M7 s- F2 l& S
  96.     USHORT usCoilGroups = ((usNCoils - 1) / 8 + 1);& B& L: R. d0 u7 L6 T& o' j
  97.     UCHAR  ucStatus     = 0;
    # a. T, }& x7 B; ^
  98.     UCHAR  ucBits       = 0;
    / p" k# q+ P5 U9 a. l
  99.     UCHAR  ucDisp       = 0;$ T* ?2 I: D* z* R

  100. : W+ u! }0 B0 y5 T  m/ e, t
  101.     // 非法检测
    & B+ n) G$ Y  K0 m, F9 A
  102.     if((usRegIndex + usNCoils) > REG_COILS_SIZE); i7 q: A. p% K3 W8 X5 o- ]" y
  103.     {
    " W! }3 W# I/ G' P; [3 \
  104.         return MB_ENOREG;  Q7 `; ^: L& u6 M) u
  105.     }# w! e5 t: D2 t( x: m# j

  106. ! n% J- w- c: A5 _/ Y
  107.     // 写线圈! e4 M6 T4 |9 k9 }% [# k1 }
  108.     if(eMode == MB_REG_WRITE)- |2 v5 e# @7 x9 H+ L
  109.     {$ n9 L4 N; o% |. X3 S
  110.         while(usCoilGroups--)
    6 q& K% P* J% k' I; ?
  111.         {
    - t6 a: {( z; @4 _' y
  112.             ucStatus = *pucRegBuffer++;, E- a8 ~) B& T0 x0 L! a. x' p( U, n
  113.             ucBits   = 8;. }8 T; Z$ a" ~# C! h* d$ R
  114.             while((usNCoils--) != 0 && (ucBits--) != 0). d1 T. y" b4 x2 }) [
  115.             {
    ( f. C5 \4 K1 `$ d
  116.                 REG_COILS_BUF[usRegIndex++] = ucStatus & 0X01;
    . f; s9 |- L! w4 `4 n& Z% t
  117.                 ucStatus >>= 1;
    9 h$ p0 c. U2 V% e
  118.             }5 ?6 f2 U( G# V
  119.         }8 ], f7 C2 w, c" Y
  120.     }
    + S) k# \! F0 H- r$ z; w/ a
  121. " D% H" }8 f( r* q4 E
  122.     // 读线圈! h; o% c( d7 T! T# W3 \
  123.     else
    5 p6 X; z, V" k* y# d6 |0 R
  124.     {
    # c" \% }# H! h! s; j
  125.         while(usCoilGroups--)
    ( A) T1 `% f6 M) v! {; b
  126.         {
    * x4 ]0 Y2 d: f1 F
  127.             ucDisp = 0;/ J( S) ^: a( _- M! ]8 }; ?: E0 }
  128.             ucBits = 8;7 G  G- f3 J2 \- e# @* o
  129.             while((usNCoils--) != 0 && (ucBits--) != 0)0 H( w+ i; G9 R! [
  130.             {
    * \- g/ U8 s- [) ^9 p
  131.                 ucStatus |= (REG_COILS_BUF[usRegIndex++] << (ucDisp++));2 m! ]) h- u% t: C! h: _) o0 l: x
  132.             }3 T' {& \& w/ U$ M
  133.             *pucRegBuffer++ = ucStatus;
    " T, f! t9 U! O& l
  134.         }" y( ?( G- ^9 k4 l! j
  135.     }2 ^/ O+ K8 D2 V5 m. N
  136.     return MB_ENOERR;6 e7 H) u  o' J+ Z! I+ p/ y6 k; u
  137. }  f5 o4 j" E0 T- \, p

  138. - v3 V$ a5 m% }6 E

  139. 4 X* W2 Q1 ?! {9 r  ^
  140. /// CMD4" ?: F5 u+ T7 Z  G* k
  141. eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
    7 A# k' r3 |( |4 @1 [1 z
  142. {: U' M- ?. ^7 k1 W6 v
  143.     USHORT usRegIndex   = usAddress - 1;
      k9 J  W6 P0 U' l4 ?
  144.     USHORT usCoilGroups = ((usNDiscrete - 1) / 8 + 1);
    ( y% C% X& [) R+ k! M
  145.     UCHAR  ucStatus     = 0;1 T; ?9 {$ Y9 z8 k. X
  146.     UCHAR  ucBits       = 0;
    9 G! F. `4 y/ N+ q4 }4 A
  147.     UCHAR  ucDisp       = 0;
    4 G" h. X1 Q! o

  148. 6 Y- E# R; {$ n3 v1 y
  149.     // 非法检测" t: O6 z. @& D! X! i& d% `2 [0 c
  150.     if((usRegIndex + usNDiscrete) > REG_DISC_SIZE)
    & F  m6 a. P8 a+ \
  151.     {" w; b- d* @4 m2 A8 k. G5 T8 e' t
  152.         return MB_ENOREG;& B. j1 D1 v; F  b
  153.     }
    # p3 b. o+ P( E0 o" _( _' H

  154. . t) {" z3 _, T5 M
  155.         // 读离散输入) L- S- u/ F3 m% [6 r
  156.         while(usCoilGroups--)
    + V1 @. ]9 D# y% F% ?
  157.         {
    4 H8 A4 J7 m+ _" N: f. y, Y) f
  158.                 ucDisp = 0;, E1 h: r: G1 x4 v# b
  159.                 ucBits = 8;$ f! ?7 U  t% w3 q; I( t4 A' e6 k" }. q
  160.                 while((usNDiscrete--) != 0 && (ucBits--) != 0)8 i  E( F0 u6 M3 N5 S* r
  161.                 {( R& q* W3 b1 s% X9 u* R" ]+ a
  162.                         if(REG_DISC_BUF[usRegIndex])" N" n1 u3 z& F# ~1 T
  163.                         {
    4 }% X& w( ?& ]8 `
  164.                                 ucStatus |= (1 << ucDisp);3 S; c- @3 {9 N! b2 h5 ]
  165.                         }, u5 v( `7 L7 j2 `
  166.                         ucDisp++;! Z' w" z# U) Q# b( v+ [' ^
  167.                 }1 t' q, b! W0 R6 R' B) Q
  168.                 *pucRegBuffer++ = ucStatus;
    ; r9 P# o" Y- K5 E, a; }
  169.         }7 k+ J7 [5 a. r9 H

  170. 8 ]% q0 Y& U! O" _& L
  171.     // 模拟改变
    2 [) [( B0 r5 |: H3 k0 M
  172.     for(usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++)
    & F% \$ K. S# Y2 `- Z! I- O/ U, D; J
  173.     {
    2 _7 }; Y# B- M$ x- s3 K
  174.         REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];
    $ l( y- u* A7 m
  175.     }
    # ~9 W& s4 h) s" r& W

  176. : a5 g% }8 B! }3 X6 c
  177.     return MB_ENOERR;* G! n0 w5 Y' W
  178. }
复制代码
6 v: i7 v" {. D0 l# G2 `3 O# C
主函数

/ L$ u, K" K, B3 @. w" ~, P) D+ v
  1. int main(void)
    & r4 V' t; Q2 g# I: F3 t
  2. {
    ; @- r$ m/ c9 _% j
  3.     HAL_Init();3 F$ u8 e5 p4 M/ M; y
  4.     SystemClock_Config();
    6 D& _$ S( Z. D$ {* Y! ~5 v
  5.     MX_GPIO_Init();* D: p9 o! t" u! A! S9 B
  6.     eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_ODD);                // 初始化modbus为RTU方式,波特率9600,奇校验
    & |" \: y2 u4 W4 F& [. X/ o
  7.     eMBEnable();                                                                        // 使能modbus协议栈
    * x9 D- H! Q5 ~) N" g

  8. 9 R: B) W, ]# X! `+ g1 u5 ^# x
  9.     for( ;; )
    8 [3 G* z9 y" Y( R. B9 u
  10.     {
    / [! I( z. x6 [% F+ u
  11.         eMBPoll();                                                                        // 轮训查询% r5 A4 i: ]1 ~% F, a$ B. p/ v6 [+ h- o
  12.     }
    * [  R" u+ S% f1 j
  13. }
复制代码
/ q6 ~2 o- M3 j; O
移植测试0 ?5 o: S1 T( `4 t0 N$ _

( ?* e; S8 ^6 A$ n 20200313154857173.gif
! i5 S/ P; v) Z1 ^
3 J3 b0 g+ u( v0 W# j# G3 lends…+ w( w/ B, T3 [# ~

1 T; E/ V3 ]5 k- H
3 x) \& ~5 b; \/ Q8 t0 U  e0 Y8 O$ K9 k: r9 h& y9 G
收藏 评论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 手机版