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

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

[复制链接]
STMCU小助手 发布时间:2022-4-10 22:53
modbus命令码表:
, ]/ m0 l4 H4 s. ]* Q
: Z. q( g' N) r" z; ^# T3 `
b8032deb4d154657acd2f7f2942369d4.jpg ( R$ a/ U8 C: Z" q
) M( P! c0 b. Y4 d  j" E  ^
FreeModbus文件说明
, O4 s! |& P3 b  O
      解压freemodbus文件后打开,我们需要demo目录下的BARE,该目录下的代码是空的,STM32移植工作基本就是修改:portserial.c、porttimer.c、port.h这三个文件。: z4 S: p/ S8 Z) o
20200313143257958.png
* N6 x' r. R" r  S9 U% b
+ P: E9 l# [2 ~  a4 C5 w      mobus文件夹就是完整的源码,包含rtu、ascii、tcp:1 \' E% @& y- Y" [( F$ J
: C/ U' g; u9 ~! j: \! B
ZM%DLXPRB8$%[NN2%4Z1N.png
2 t& t5 [! u4 D2 h
  R9 g! J6 C4 b, G7 {      我为了移植时在keil添加源文件和头文件方便,就把modbus所有的头文件和源文件放到了一个文件夹下,并创建了一个port.c文件,用于编写modbus所必需的回调处理函数:
* a- I; P$ x# i( g9 [
9 P: R6 q/ Z: ~ 20200313144036579.png
0 e2 L8 r+ |+ l8 b4 x/ K% q, L6 J: f: }8 G) X- r+ t
STM32CUBEMX配置

  m. H; B& }2 i时钟配置,设置主频工作在72MHz下:

8 J2 G, y) ]. U: ^& l7 Z/ @) U5 B5 ?; Y4 l. E2 B8 E
JU1~N33M}I7K1(6K@JFN5~R.png
- S6 R. H" T: M6 ^2 u2 w9 i1 \, F; q6 o1 p
配置串口1,这里随便配置就行,在modbus移植过程中还会对串口重新初始化:
9 d. [7 |# ?! w
* M% p  q& w: d+ T; P
U25OQ_FHYD5WEXLFMI4V@RU.png
& ]) B# F. u0 E+ }2 H/ |2 X; y1 e
6 W6 _2 ^0 g9 `. _% L配置定时器4,用于3.5个字符的定时检测,这里随便配置就行,在modbus移植过程中还会对定时器重新初始化:

: Q! @* q$ {$ w: Q  s, S
: g- ^  v8 n, G H6{)WT`**CIHDAM02558GK.png
4 R, X) X9 J2 a8 m3 D- B
! j6 D6 F$ ^8 x8 P* N& t+ _9 {! G中断配置,这里注意,串口的优先级是要比定时器优先高的:

2 |5 g( l3 S: y5 ]1 |9 [
1 N" _! J. K: q G(RP`74TR)NPJFUK``Z%I2L.png
& `- H. G  i8 J5 u! z! H" G取消掉自动生成中断服务程序,在移植过程中我们要自己编写串口和定时器的中断服务程序:
' o/ ]- l, p1 s* K* m+ Y6 S* d, ~2 f5 X
ALHMK5Y615K6(`M{0[]YJ.png
5 V; e" J$ k' R( ?& X1 Q! }4 w# H2 S1 F, b
移植代码修改

0 x9 z, U! }9 @生成代码后将modbus放到工程目录下:& G: {+ s) w/ {+ i  k4 u7 q

  o, p" `. k! A$ m+ H0 ^  n1 p0 g
5%(_LMGIM_8_YGL`]JGAB67.png & n* p$ U( x) u- T" r
* w+ |! R# }/ n; U
打开keil工程添加modbus源码:

. Z+ l; d& c2 Q) U/ {3 y
6 ]1 R0 V& w" U* m( j F`8_YFACMNOAP28~2VHD{CO.png
1 Q. Q7 w6 E) @" ]: @
2 O* U- _2 [1 t0 v' G* ^添加包含头文件:
  `0 Z- k+ j, w/ S% h2 j

# G+ A& o4 b: S  g  g) ? `7BMVXA`R9SQBTGT`B@{]X7.png / E4 R+ _; Y4 }8 F+ \

! T* w( |- V7 F$ h3 _2 _* F% [修改modbus定时器初始化源代码porttimer.c文件
0 C$ g9 m% X& X. h  p/ }       定时器的修改比较容易,将定时器设置为每50us的时长记一个数,传入的usTim1Timerout50us变量给自动装载即可,prvvTIMERExpiredISR函数需要在定时器中断服务函数中调用,它的作用是用于通知modbus协议栈3.5个字符的等待时间已经到达;由于我们在STM32CUBEMX中取消掉了定时器和串口的中断服务函数程序,所以我们在该文件中添加定时器的中断服务程序,修改后的代码如下:" M" ^, Z4 j6 q. G

  \! [' c2 ^$ @3 p$ Y
  1. BOOL8 e" y( I9 c; ]
  2. xMBPortTimersInit( USHORT usTim1Timerout50us )8 N3 @- o3 q# O! S
  3. {( G9 B+ C7 g6 x% c( {/ Q
  4.     TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    6 B4 U4 q8 J8 o& l
  5.     TIM_MasterConfigTypeDef sMasterConfig = {0};9 e- N. R" B# S
  6. 4 W8 _. N6 F% {1 U+ G/ K2 p
  7.     htim4.Instance = TIM4;/ U3 \( K5 E; B1 ]8 C) p4 k; D0 B
  8.     htim4.Init.Prescaler = 3599;                                                                // 50us记一次数
    . u' J$ i/ [3 v6 q8 W
  9.     htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
    3 B! A6 m! s) \: m" T
  10.     htim4.Init.Period = usTim1Timerout50us - 1;                                        // usTim1Timerout50us * 50即为定时器溢出时间+ S9 [) [% @6 S6 {" Q
  11.     htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
      }0 [5 l2 r; ~# K% M+ J7 {
  12.     htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    * T/ w" C/ C6 S3 \3 G/ l+ p
  13.     if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
    " q. v% a) s6 k3 }
  14.     {3 }% W! q6 v- _; f8 ^9 m0 D
  15.         return FALSE;
    5 D5 V0 D, G1 r
  16.     }
    ( i7 E$ S  ^* L; L# [' q
  17.     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    ' w( u' m6 Q3 J1 G+ c
  18.     if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
    $ _; y! H8 @4 c$ u9 z/ b8 |6 I
  19.     {
    ( x: I0 `3 W3 c1 g! k
  20.         return FALSE;
    # w* g5 {1 J* e0 N9 y! Q# M
  21.     }
    $ U' z, j% E: d. E6 F3 f* V, _( C
  22.     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;# K, E) P2 |7 K8 ?7 [, F
  23.     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;* Y0 m8 o3 w5 f& B* D: A. c7 t5 }% O
  24.     if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)! d- I3 k& T2 y4 _+ R
  25.     {' }8 e* Z# X* a, M# Q$ h
  26.         return FALSE;$ g2 G6 s6 \( w% x& c; w
  27.     }; ]. m! v: N  _
  28. 9 Y( d* C$ i8 L$ j5 n. D0 I
  29.     __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE);                                        // 使能定时器更新中断8 D0 N6 p+ L4 _0 _0 R
  30.     return TRUE;
    - b* ^4 w' B; M2 [* q6 E
  31. }7 g9 P8 B% Q. M4 i& W2 `9 x
  32. 0 k+ _8 H5 Y4 n8 i. |
  33. inline void; k+ |; N# N+ j0 k/ ^4 }
  34. vMBPortTimersEnable(  )
    % y! V+ ^& q! d1 j
  35. {
    3 @- \. [! k- C6 N' L
  36.     __HAL_TIM_SET_COUNTER(&htim4, 0);                // 清空计数器
    " \/ k; A: X2 D2 z: P
  37.     __HAL_TIM_ENABLE(&htim4);                                // 使能定时器
    ; a$ s/ z& I0 s- o! P) N" _
  38. }
    & G" |* U. {+ b* a
  39. 7 X1 b  D/ f2 b) ?8 A/ E
  40. inline void
    6 q/ j7 C, L3 S: r+ N1 ~1 B! x
  41. vMBPortTimersDisable(  )
    " v6 W2 L7 B$ E
  42. {: w, E" X: U; T
  43.     __HAL_TIM_DISABLE(&htim4);                                // 禁能定时器8 T6 U. S, q: H# e' X
  44. }: v9 Y3 w2 Y! s& U* o  X$ N% u9 P9 N  D

  45. # T6 C: A4 S% j% Y/ M9 q% }
  46. /* Create an ISR which is called whenever the timer has expired. This function/ C5 ]. H" f+ `' {. V2 @
  47. * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that- f( P1 V: I& f' G# ]1 S- r% {
  48. * the timer has expired.
    4 P8 ~) [2 [! i: N" ^% |
  49. */
    1 k' }6 R0 @$ g
  50. static void prvvTIMERExpiredISR( void )9 t0 @& h$ ^4 {2 P; z. W
  51. {
    6 o# O9 y" U0 P, g7 k+ Z% p1 n
  52.     ( void )pxMBPortCBTimerExpired(  );& G3 B: u" G7 j" b. G$ s, `
  53. }/ _: |/ O- S( Z0 R
  54. ' x) q3 ~, b. N# ?
  55. /// 定时器4中断服务程序
    % ~9 S2 Z5 n1 v: _
  56. void TIM4_IRQHandler(void)) p- L. O9 s# y
  57. {
    5 f; ]' v6 D; [( z, L4 m
  58.     if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE))                        // 更新中断标记被置位
    4 z+ S* i. M' M% {/ d* ?/ `$ O" a
  59.     {
    5 o2 F& Z! E5 W0 v  k
  60.         __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE);                // 清除中断标记/ ]2 k0 Q1 N0 n
  61.         prvvTIMERExpiredISR();                                                                // 通知modbus3.5个字符等待时间到2 \% T) T1 ^8 @$ c1 d( Z
  62.     }
    + l/ D7 h5 t$ g& G) h3 G
  63. }
    ( R( q0 x! ]- F6 E

  64. / w. S& K3 R  M8 V! J; H

  65. 7 i# W" N% s. E' C- v' m1 o5 X
复制代码
2 v. v  r* \% @+ u: R3 [8 H& Z; o3 Q
修改modbus串口初始化源代码portserial.c文件0 Y4 u8 [2 r; F
         ~~~~~~~~        在该文件中实现串口1的中断服务程序,prvvUARTTxReadyISR和prvvUARTRxISR函数需要填写进中断服务程序,前者得到作用为通知modbus协议栈串口已经空闲可以发送数据了,后者的作用为通知modbus串口1有数据到达,修改后的代码如下:2 T! |+ k% B, u, o9 D

$ f+ ^+ b' o8 B9 e" d
  1. /*9 a- H" T( N5 I& @! I: @" U8 i6 V2 U
  2. * FreeModbus Libary: BARE Port! k- R8 v. c# }1 T& l( y
  3. * Copyright (C) 2006 Christian Walter <<a href="mailto:wolti@sil.at">wolti@sil.at</a>>4 ~" ?/ A' @/ R- T; J% i3 J
  4. *  a2 |+ u/ z4 I: Z" o
  5. * This library is free software; you can redistribute it and/or# H9 h# H+ o# w; L  k- |
  6. * modify it under the terms of the GNU Lesser General Public
    ; L, G  m5 e$ G4 h2 E
  7. * License as published by the Free Software Foundation; either, ?/ O5 h# X! p& Z# u
  8. * version 2.1 of the License, or (at your option) any later version.
    2 f4 U* ^, Y. @
  9. *
    3 R* R# w" J- j  @- ]  w6 H- a5 k
  10. * This library is distributed in the hope that it will be useful,9 ~. z: C0 G; }% z6 Y+ L
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of- ?0 ]+ H  _' f% f( y7 N! n9 Z
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    5 a: o1 X: l/ L! U: c/ b- R
  13. * Lesser General Public License for more details.
    6 s2 l8 z$ p+ r7 `
  14. *2 \) _0 c" p/ t, ^. P
  15. * You should have received a copy of the GNU Lesser General Public
    7 S' M5 {/ K* K" X
  16. * License along with this library; if not, write to the Free Software4 I) Q4 `" s! X# M4 K/ f
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    + S3 F6 ]# Z$ I! `; q  J
  18. *  d, f1 D* D" j+ E) O# A
  19. * File: $Id$" O. z5 o1 e5 t! Z
  20. */
    , h9 T" l# `  r) g' H- f  h3 e

  21. . }5 r% _0 x0 N& K) j0 [, E) |- P' R
  22. #include "port.h"9 ?1 a: a5 l" l- C
  23. #include "usart.h", A( r+ Z* I: I  R" W7 t! x
  24. 5 q4 K( Z  W% V! I. C  X1 s
  25. /* ----------------------- Modbus includes ----------------------------------*/& i7 X4 G9 W9 K' g+ ^; l, @* I
  26. #include "mb.h"
    2 k) d; H" R8 e- R4 b( s, t% W. `
  27. #include "mbport.h"
    * U. W) H$ y, U. k# l1 |1 w
  28. ( X7 o' L/ ~: _! B5 a- _
  29. /* ----------------------- static functions ---------------------------------*/; f9 h3 e; O- \4 `8 [! ?
  30. static void prvvUARTTxReadyISR( void );
    ) ?9 Z  W( L  ]9 ~$ a1 ~8 {9 j5 f
  31. static void prvvUARTRxISR( void );
    - \7 M) F6 J; \! z3 I2 c
  32. * F! ~& D$ r5 h  Z6 N- M$ X
  33. /* ----------------------- Start implementation -----------------------------*/
    0 ~9 @5 t' F: A" o- g- B8 H
  34. void8 Y& z4 H" y8 l- T7 A0 N8 m& |+ _
  35. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
    8 k3 r$ b, ^5 I
  36. {
    : Z3 o- Q0 f9 m
  37.     if(xRxEnable)
    * m3 z# K- A6 j2 U
  38.     {
    7 c, W9 g) P% q  G: x, @
  39.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断
    ( F1 b' d0 c! U0 M% |# k. Q8 h
  40.     }
    * J( H* c# h" ^& N0 z
  41.     else7 G' f0 S6 d8 F( D& S4 N5 Q5 Y
  42.     {
    # H' j: H. x# e' j8 e
  43.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断6 [0 [  e2 @$ x0 ]& {# \7 t7 C4 b
  44.     }0 b* u( `7 w7 C% b

  45. + f& n0 W" E* e) u9 J, i
  46.     if(xTxEnable); f2 u& a; g, B7 g' u! K$ z
  47.     {# D: ^' ^9 Z, m# ?2 r) I
  48.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断
      K. F8 l( \$ ]( n$ ~4 C( K# Z2 z
  49.     }) w% s+ D( I# R0 W7 o
  50.     else8 E$ P4 l& a* l
  51.     {
    * ?8 O0 D" f/ \5 U/ A
  52.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断% u- M5 b) }! S* Y2 X/ w5 x  ~4 g
  53.     }
    . R2 `2 o0 V! p8 J1 y1 ~  s9 v
  54. }
    9 C6 B5 P# q; o! i7 F. S! @9 W
  55. , T6 B$ @4 ~/ `* W3 r2 }
  56. BOOL
    ) \: w( Z/ z; _5 ]2 }8 Q8 L
  57. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )  O/ |5 \* T, F% P
  58. {
    ; T/ q" J1 I0 B7 H5 _
  59.     huart1.Instance = USART1;
    4 D( r! w7 Q$ v8 a" X* L- d
  60.     huart1.Init.BaudRate = ulBaudRate;
    & g1 Q/ q5 h/ p; `/ p7 F" e& f/ k  Q
  61.     huart1.Init.StopBits = UART_STOPBITS_1;
    % s  R8 @% M( l) @' X
  62.     huart1.Init.Mode = UART_MODE_TX_RX;- @- p- ]6 O4 ?0 ]* S. J3 w+ P0 c
  63.     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;% k8 N' W& R' y* f) P2 q3 u
  64.     huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    4 l' o, k! m6 b2 J7 n
  65. * B3 R2 c. d; g3 R% M/ N, y
  66.     switch(eParity)6 b  h! U3 V4 H8 p9 U# q
  67.     {$ X" N0 p/ w: j
  68.         // 奇校验" d# u* p& v  p, F5 b# l
  69.     case MB_PAR_ODD:
    ! M9 a( d7 t$ o7 _; T' z5 b
  70.         huart1.Init.Parity = UART_PARITY_ODD;
    7 S1 ~' _4 `9 D, v) U
  71.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits  k3 i4 D9 X6 v/ [
  72.         break;
    9 N) V, M  ]; h, Q
  73.         6 S( j5 Y6 ~# W7 i
  74.         // 偶校验& j' r3 ~& X/ x% u
  75.     case MB_PAR_EVEN:
    # Z( F! t. a0 U4 Z8 j
  76.         huart1.Init.Parity = UART_PARITY_EVEN;  h, a! Y% m1 a, |- n4 z2 P
  77.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits* d& {3 p2 H" x! n4 G
  78.         break;
    3 Z% Y+ |/ e# n7 m
  79.         ( c* k3 g) g$ w1 Y: t
  80.         // 无校验
    " Q1 A4 O# g3 A+ x" {) X  W1 B
  81.     default:
    / A+ ]8 \# y  W% r& w
  82.         huart1.Init.Parity = UART_PARITY_NONE;
    9 l- `7 f% |9 J
  83.         huart1.Init.WordLength = UART_WORDLENGTH_8B;                        // 无奇偶校验数据位为8bits
    5 A5 i, g* r; u; z4 r: D
  84.         break;1 b3 n0 e# v2 J$ n
  85.     }
    3 k* s0 Q! u1 r
  86.     return HAL_UART_Init(&huart1) == HAL_OK ? TRUE : FALSE;. A+ B& i: Q% s+ {% r. ?* p
  87. }
    4 J$ z4 U/ V+ r  X% A2 Z: k
  88. ! o; a4 b% T: ], {
  89. BOOL
    , `1 p6 m5 o* U( c
  90. xMBPortSerialPutByte( CHAR ucByte )3 X5 L$ U7 M& u  k! P/ w; P
  91. {7 d& y4 @! O4 Z2 X+ v! \% g
  92.     USART1->DR = ucByte;) s" ]  M) Q- |& p5 d; m& H- |
  93.     return TRUE;
    % l6 G, A' Y& J; \( i( b
  94. }+ c" r/ H, A% n% F9 e

  95. ! Y; r* N$ a4 c" @
  96. BOOL
    * o! j" Q% T( d  R, U
  97. xMBPortSerialGetByte( CHAR * pucByte )
    4 B0 c. N* z9 U
  98. {/ }4 J- e1 O6 q4 @3 e
  99.     *pucByte = (USART1->DR & (uint16_t)0x00FF);
      p' ~/ g# }4 E" @3 i6 v$ ?% a
  100.         return TRUE;
    6 s: N: O1 W" ]
  101. }
    : C! {. {) T& k+ @. R9 m
  102. % ~5 f  ?. N8 w, Z3 d9 N
  103. /* Create an interrupt handler for the transmit buffer empty interrupt
    3 `! h8 q/ c% A& l
  104. * (or an equivalent) for your target processor. This function should then
    1 w& G9 `; u1 z' N5 {* g5 A/ f8 m/ O! {
  105. * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
    ! O6 K. Z6 X7 x; D: Z* u9 n- i4 [, @9 m
  106. * a new character can be sent. The protocol stack will then call! h1 x' `* ?  T  o1 a; x. q3 r  L
  107. * xMBPortSerialPutByte( ) to send the character.9 D  w6 P7 h, M; Z5 p# Y. L
  108. */9 A% k6 r$ N" V$ j' w
  109. static void prvvUARTTxReadyISR( void )
    . Y7 }1 H+ ^, _" s- \
  110. {
    2 |6 P6 h. {( p( d- N6 U, t4 `
  111.     pxMBFrameCBTransmitterEmpty(  );
    , K1 V2 d- p; _/ F( p. M1 i, l
  112. }. U8 B$ c" Y- @/ a6 @0 ?' Z8 m
  113. 3 O6 C9 E7 h4 h8 w
  114. /* Create an interrupt handler for the receive interrupt for your target
    # s/ N+ ?% ~+ y# J
  115. * processor. This function should then call pxMBFrameCBByteReceived( ). The8 u: a' K( L% X6 C- y
  116. * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the4 X( s! h7 E' w* b( u5 _; g9 D9 w
  117. * character.
    $ h9 A3 X' p& W0 x
  118. */
    , s3 s! B5 K6 l& a
  119. static void prvvUARTRxISR( void )
    ; M9 n) V3 y( b3 w# u% n
  120. {
    : W  k: ^. v. a( ^
  121.     pxMBFrameCBByteReceived(  );5 z" e5 |8 G% d# @& u2 w
  122. }
    / C. i" l( q" e. D; ?, c0 h
  123. 4 X2 k8 P& O# @3 x: A% V
  124. void USART1_IRQHandler(void)
    - L0 T# B3 c. r( [' \& Y4 Y; j
  125. {
    + K! D' x, y8 \: i! @$ B) B2 p
  126.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))                        // 接收非空中断标记被置位& C6 X/ j' s+ V$ W# C
  127.     {
    " y! ~5 L9 z7 C7 U, M* z
  128.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);                        // 清除中断标记
    + `# a, s/ D8 b& e
  129.         prvvUARTRxISR();                                                                                // 通知modbus有数据到达
    & o6 d' e. F& l6 c3 F0 A; M
  130.     }
    ; ^3 `! A3 A8 Z" D- }9 ]2 O. D

  131. ! A; K( m+ Y* f3 p% `0 A
  132.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE))                                // 发送为空中断标记被置位
    4 o% |. I2 n! F- C3 G6 ]
  133.     {) j5 a3 A3 I0 J3 z% L5 c. ?
  134.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TXE);                        // 清除中断标记) J" O4 g# j" h( k( ]% P. X! V
  135.         prvvUARTTxReadyISR();                                                                        // 通知modbus数据可以发松& R/ t* V, b' }, d* @0 T8 g# G
  136.     }" n! d$ q5 M' l9 N# k4 I
  137. }
复制代码

$ T$ t, d+ ~0 M: [' O1 n注意一点,一般如果使用了485芯片的话,那么同一时刻只能接收或者发送,可以将函数vMBPortSerialEnable修改成这样:; u) \) G4 d: G: n+ F/ |

. S4 o; f7 f! e+ E
  1. void8 h# g9 s3 p" C& U8 D6 J
  2. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )2 D0 f: {) I+ r1 w' n. W
  3. {
    ) i, ~, n1 v, W8 n) T
  4.     if(xRxEnable)5 g4 [! n1 G1 I" J) s0 ~5 I+ ]
  5.     {
    & F0 j. _" I- N' q$ \' ^- j" K
  6.             //
    ! d8 m; C( m" e  @: y5 e
  7.         // 在此处将485芯片设置为接收模式' \; H1 t  ]! c" Y: O
  8.         /// f' F1 h0 C* }7 [
  9.                 /* do something */. ^* W  `7 D4 E  h3 h
  10.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断4 {3 ~3 D* L8 p. W* r3 i
  11.     }8 D; N. V$ a' _
  12.     else
    5 r' g* F0 q1 T# _: k( }) H/ D
  13.     {
    9 ]* P, C7 C) Q$ ^$ Q
  14.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断% [2 z( z# x) O0 U
  15.     }5 z& h4 u! K7 s2 [& }
  16. - D. c3 C4 }3 O
  17.     if(xTxEnable)) l& K# M/ c9 s0 q- A* P8 {
  18.     {
    , s9 W7 y$ q( ^
  19.             //- ?8 N4 i& Z) Q# U: X9 y
  20.         // 在此处将485芯片设置为发送模式$ q5 ?1 t7 a4 [- [5 c
  21.         //- B: p# G/ J: p3 {7 g/ y1 \
  22.         /* do something */
    * I8 X/ {" L6 U( p8 O$ d
  23.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断
    5 A. L% F( @7 J2 @- T$ l, y
  24.     }
    & h+ Z4 _+ U) O0 V3 X
  25.     else
    8 P. M3 l- `* y- a* P9 y
  26.     {( C$ h4 P/ n) A) M
  27.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断
    # L- V1 U% B6 V1 Y
  28.     }# b) L, G* X# g2 R
  29. }
复制代码

7 a0 C' H1 w% t0 `& L
编写modbus命令处理回调函数port.c文件
+ }. N9 A7 v/ L( v本例程只实现了读取输入寄存器和保持寄存器的功能,详细代码如下:+ Z1 R7 B8 L, q4 |0 c0 |

; w% g/ l, e4 O5 J6 V9 @7 o
  1. #include "mb.h") V6 n) k# c0 H# Y4 h
  2. #include "mbport.h"
    ! }5 w$ R0 Y. a# J* t

  3. 6 K7 g: }( v  @5 `" [7 C4 h/ j
  4. # p- P. x* I2 V$ I$ z5 b$ z
  5. // 十路输入寄存器
    ; ]. X; k* Q) A/ V  f5 u% ?
  6. #define REG_INPUT_SIZE  10
    % H3 k' w5 @8 }1 E/ Q
  7. uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];, |4 Q- n) N+ l4 F5 d
  8. 1 w% F9 Y4 o0 `( Y# g: y
  9. ! j+ a5 \* {$ Z8 Q/ P7 c
  10. // 十路保持寄存器
    " n* S  m  {# |4 M# i: v
  11. #define REG_HOLD_SIZE   10
    5 O! c- ^. k% W( r8 Y; i
  12. uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];% ?2 C( m% J/ I, R2 }! k1 |
  13. & |6 O0 u1 s! [& |% }9 e" z

  14. 3 V* |( A% d- ~1 K! H4 H5 n- F
  15. // 十路线圈
    1 H' a0 E7 ^4 J; E% j( V) E- q
  16. #define REG_COILS_SIZE 10* N3 v$ I; h. c% I
  17. uint8_t REG_COILS_BUF[REG_COILS_SIZE];$ G. ^6 t' J9 n

  18. ' O/ u+ [8 Z; ^3 A7 H
  19. ' E. K$ l- y) p+ D7 U
  20. // 十路离散量5 [5 g& w* S5 a8 b9 R* r" p4 ^1 t
  21. #define REG_DISC_SIZE  10
    # B& J4 L) p) x0 r% T: P
  22. uint8_t REG_DISC_BUF[10];
    + N; e3 a1 z4 g" j+ p) Z% c

  23. 8 S& P+ M  ?5 V

  24. 0 q. D" I; [4 x$ U% |" ^
  25. /// CMD4
    ) z0 w0 k% [" ~, E" c: P: \! U
  26. eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )$ i8 ^' s/ I. A- B( I/ k; u
  27. {
    ! Y* \$ s$ _$ _' Y# P' u
  28.     USHORT usRegIndex = usAddress - 1; # j1 Z; A7 P) H7 n3 _( o- z

  29. 7 r/ m3 @0 o  ~9 e6 `
  30.     // 非法检测
    5 y( S3 V8 d% _4 [8 Y6 U6 A6 h
  31.     if((usRegIndex + usNRegs) > REG_INPUT_SIZE)1 _) o2 T8 {6 j& ~1 m
  32.     {
    ( R/ j, H! |! ?/ A, |, I7 b5 o
  33.         return MB_ENOREG;5 W! c( W" z. [: M- d. _
  34.     }
    & O: L3 V0 \  \
  35. * k2 ^; [  t/ x, P/ M4 \% X
  36.     // 循环读取
    : ?6 z$ [+ P" ^! Z0 O  e0 v/ c
  37.     while( usNRegs > 0 )# a4 h2 N# z$ w; S
  38.     {
    ; B* W  D" |+ `* O
  39.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 );- `9 d; q6 F  n9 J/ R( f
  40.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );. Y" B/ U1 A. W; P5 u
  41.         usRegIndex++;( N* p" v( E% Y( M( Y7 G3 v
  42.         usNRegs--;
    5 F: z* n; H# g/ X
  43.     }1 X" U( t5 C1 ~3 y' @/ j5 h
  44. ( s" c; _  Q% P9 ^# s
  45.     // 模拟输入寄存器被改变
    ' K* J- e1 X9 \
  46.     for(usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++)
    6 T0 ~2 D0 ~# T, ?. T( s% Z
  47.     {0 _! [/ t9 D( D
  48.         REG_INPUT_BUF[usRegIndex]++;
    9 I1 o  H2 `: M! W3 }
  49.     }
    5 `7 F. W+ v5 \  x  b

  50. , }6 k6 }* w: Y8 \, Z- J
  51.     return MB_ENOERR;  L' O; p! |9 {
  52. }3 u0 }5 ]- c6 v6 a" ]5 E

  53. / m, B6 @1 t: h+ G# N
  54. /// CMD6、3、16' ^- v, d) Q+ m3 Y7 Z  j/ P, ~
  55. eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
    . E$ X5 k% R) [$ [' a) B
  56. {/ D/ s1 z1 l# l8 a! f7 t3 [8 p3 |
  57.     USHORT usRegIndex = usAddress - 1;  % M; o4 R' M3 C! ]1 c) {
  58. 8 _5 F+ z* O; D$ e
  59.     // 非法检测
    ( e  `- ]+ D( z3 D: f
  60.     if((usRegIndex + usNRegs) > REG_HOLD_SIZE)
    : O) L& X7 u0 p: S4 u, |, \- O
  61.     {' \5 X2 {, g5 m# G; i' `, i+ k
  62.         return MB_ENOREG;
    ! a# \' q, ]. S- H' P4 o
  63.     }
    % M/ o1 Z' f# }- Z( A  B% G$ @( q3 F  I  w
  64. 0 G, S+ \3 }$ g; o: i
  65.         // 写寄存器
    $ {3 d6 k- `! L0 K" s
  66.     if(eMode == MB_REG_WRITE)
    / X( P7 V$ J/ X5 j, \+ R
  67.     {8 q5 `7 r6 j1 k/ B9 }5 p* ?# }
  68.         while( usNRegs > 0 )
    ( ~) D; d. S9 E  j/ m
  69.         {
      ^% p' z8 `1 F3 S. J: ]! ]
  70.                         REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];
    * X2 }& T2 ?! v6 u/ X
  71.                         pucRegBuffer += 2;+ o& N+ L/ t9 G" U
  72.             usRegIndex++;0 @9 @2 w# S% z- ?- `. O+ N
  73.             usNRegs--;. E! m5 T3 Q* i+ H3 W" w7 [& V% s
  74.         }
    / X4 i# n( G4 X/ {, {  Y5 G; j
  75.     }$ N, m9 [2 d1 z( E
  76.         
    # N( L& z% t8 t/ U0 u
  77.         // 读寄存器# h/ M7 @+ V" J; c3 }
  78.     else7 m2 E1 O. V2 O  P
  79.     {7 r) ~' Z  @% M$ r0 U/ e; }
  80.         while( usNRegs > 0 )) P3 Y" J9 P) t4 y$ C
  81.         {" J* B5 R& p. A
  82.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );' n" H4 L6 }  e1 I$ Z
  83.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );; A8 H/ k( I: m9 t7 F' l- r
  84.             usRegIndex++;
    ; B' a+ r! ]0 x; P
  85.             usNRegs--;
    0 y3 E. r' W6 g* O+ c( G% v- g
  86.         }, S; T0 _! E# w' p% |3 x! f; s! u' H
  87.     }* O; r$ M7 M% ?* H" |# ^
  88. : ^' h2 i) i7 g) @4 Z4 ^0 x
  89.     return MB_ENOERR;, K) J$ F; h: F) p& f
  90. }
      @+ O. R4 T  H% Y$ M8 m: }
  91. ( o: p# w2 I  c' V% {- K8 j
  92. /// CMD1、5、15
    ' g1 j0 C2 t: M; b7 h) w/ Z- G
  93. eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
    5 T' h- F, n3 |4 m* {$ \: D
  94. {  e) k/ c8 b2 `# i$ S3 J* N& i8 K% Z1 [
  95.     USHORT usRegIndex   = usAddress - 1;
    ) `( U2 S' A8 w9 C4 X
  96.     USHORT usCoilGroups = ((usNCoils - 1) / 8 + 1);
      W; v3 [/ d' `( j5 e6 Y1 B
  97.     UCHAR  ucStatus     = 0;
    / d+ |( l: m7 O" G
  98.     UCHAR  ucBits       = 0;" _5 M" O* ]8 a: y& Z4 Q7 e
  99.     UCHAR  ucDisp       = 0;
    4 e0 k4 Y; {# h0 \

  100. ; P8 G6 @1 d; |* d) `% a: {- l
  101.     // 非法检测
    + z8 R. r) U: c( q/ R, B/ e
  102.     if((usRegIndex + usNCoils) > REG_COILS_SIZE)
    6 z) ^+ m1 g- m& t) O3 l# F
  103.     {5 G3 S; ~' u" [: g% [2 k) z
  104.         return MB_ENOREG;6 W) f# P2 [# i, O3 Q
  105.     }
    0 ~  u' p6 O0 ?1 }. M
  106. ! m3 L4 \6 A0 b/ F
  107.     // 写线圈3 I6 Y. w% a' ^3 E' z0 G" Z
  108.     if(eMode == MB_REG_WRITE)
    : n9 z  n& \  _8 B7 q& E+ Z
  109.     {
    8 E. _6 k6 ?: t$ K# a
  110.         while(usCoilGroups--): F  ]' p9 B* l. y2 \1 o
  111.         {" P8 i; o  U3 ~- U$ A( i2 B
  112.             ucStatus = *pucRegBuffer++;
    ' A1 Q' r; j8 ?. s, T- n: g
  113.             ucBits   = 8;2 N' U& D2 d, t( F3 H9 p5 F( ?
  114.             while((usNCoils--) != 0 && (ucBits--) != 0)
    9 F6 w5 g, }" V1 {1 U% ~$ _
  115.             {. [9 I: F8 l) @! U8 N! s
  116.                 REG_COILS_BUF[usRegIndex++] = ucStatus & 0X01;
    ( Y3 D4 e. D" P3 t# Z) f! a
  117.                 ucStatus >>= 1;; P3 r0 Z4 H; z, o0 ?
  118.             }
    3 P/ R2 H/ k3 n5 |% K
  119.         }
    0 A" j, M% I. q3 \  g+ [
  120.     }# \) L# u: w, F1 A; g0 t: O

  121. ) G6 D7 _! Z* ~7 D3 ~2 ?* A- ?7 C. D
  122.     // 读线圈8 ^+ `# F2 R' z1 D$ U
  123.     else
    " Q, w% T1 o* s+ q& u' \
  124.     {
    ' s, e+ U  @" ?7 p
  125.         while(usCoilGroups--)8 f/ f' r$ l1 n) }
  126.         {
    & a$ v: E# }1 }/ g+ G3 ^0 A% p
  127.             ucDisp = 0;' J3 m9 o* j$ B4 Y% k6 e+ [
  128.             ucBits = 8;3 d! T7 p+ E+ X8 y
  129.             while((usNCoils--) != 0 && (ucBits--) != 0)
    # B3 ^) i/ S3 M. G, c
  130.             {
    2 Q" b/ R' t7 E" p
  131.                 ucStatus |= (REG_COILS_BUF[usRegIndex++] << (ucDisp++));: X  y5 V+ P2 S# V3 V4 t+ P
  132.             }
    ; h5 `& A7 C4 |5 S
  133.             *pucRegBuffer++ = ucStatus;
    % ~7 ]4 U! C! _  Y1 O: R
  134.         }
    / k7 F: K( y. i7 H( [8 L) N# @; v
  135.     }+ d1 L% L! v, ^4 ]3 e% o
  136.     return MB_ENOERR;- m( ]+ T' l1 D
  137. }3 d( [9 R' D7 b7 q& n" X$ X  ^
  138. 4 C- V( @5 P7 P% Z, B- v* q7 @

  139. ) K- T1 n  d, V  V3 i5 V
  140. /// CMD4+ c: I! L; t- _, Y7 k: e
  141. eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
      p. _* w* D( r
  142. {! b. \9 K5 L) f2 V( y# ~+ A) B
  143.     USHORT usRegIndex   = usAddress - 1;
    1 v+ n/ O" A: ]9 A
  144.     USHORT usCoilGroups = ((usNDiscrete - 1) / 8 + 1);
    . H3 d3 i) i' V; z. @/ W
  145.     UCHAR  ucStatus     = 0;
      {3 B( L2 j, }4 [% ^& b
  146.     UCHAR  ucBits       = 0;! w- G# h7 J1 w8 ]
  147.     UCHAR  ucDisp       = 0;
    : O) l% y/ M2 p+ E( ~) D- S- n. g
  148. + T; Y& P  I. O
  149.     // 非法检测
    # R9 J& I4 ?5 B% b6 I, N+ O" e5 @/ w
  150.     if((usRegIndex + usNDiscrete) > REG_DISC_SIZE)
    % J1 j* D; R0 C$ ]; v5 @
  151.     {
    - E( q" i0 R' ?1 n2 e5 q7 c
  152.         return MB_ENOREG;; Y8 _; {0 B' b: y' m
  153.     }
    6 l, U1 p% j/ C+ ?0 j

  154. 3 w/ J$ r+ J$ o9 G/ t2 L5 C* n
  155.         // 读离散输入2 ~5 b  ?) o0 P: Z
  156.         while(usCoilGroups--)
    - Y% o# p! z5 o* F+ T# z
  157.         {
      d" b: z7 I% c( @
  158.                 ucDisp = 0;5 D8 _& \3 Z0 b/ J8 J3 ?3 C* O
  159.                 ucBits = 8;: j. B- `* B8 r% L6 H
  160.                 while((usNDiscrete--) != 0 && (ucBits--) != 0)
    3 m* j6 x8 m, w  ^* r7 V! W
  161.                 {
    ; n' u7 L$ n5 U( y7 g
  162.                         if(REG_DISC_BUF[usRegIndex])
    & q; C8 W) A0 H; X" |8 z0 Q8 f
  163.                         {* d' k8 @9 J7 \
  164.                                 ucStatus |= (1 << ucDisp);( O+ I! a- ~( r5 a
  165.                         }" p3 J  Q& }" q. w
  166.                         ucDisp++;
    ! V6 l1 H$ v' R1 x# |" }% w* a
  167.                 }
    ' C& t! [* S9 Y: g# C8 L' ^6 T7 Z
  168.                 *pucRegBuffer++ = ucStatus;! u. M' ^& I: P* g1 I: R3 w
  169.         }5 E7 ?9 Y" H( C0 L& @8 r
  170. , u% E) `* R) B, X' y2 J& d! G$ u
  171.     // 模拟改变! a2 T3 h4 q/ \" R
  172.     for(usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++)
    , X4 Z$ r/ j8 N
  173.     {
    4 u, J- S2 h) {7 m% q
  174.         REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];* b! m6 q6 ~4 W' x$ W4 J" i7 |
  175.     }& o* M/ d$ Z" x0 A: ^6 s: T9 b, t6 B
  176. # z& A5 Z4 K+ s8 m  V) l
  177.     return MB_ENOERR;
    6 \) w- Z/ h  I$ R
  178. }
复制代码
2 B. ?. F" B. P
主函数

& C2 t- g, ?" D& ]7 h. c7 m
  1. int main(void)
    7 S- Q- Y- n2 X& D6 }1 B
  2. {$ {7 v! P9 e; _7 ~+ O
  3.     HAL_Init();% P/ i/ _" _1 s; B: P
  4.     SystemClock_Config();3 a4 y; L( p# n* M3 m" a9 G/ n
  5.     MX_GPIO_Init();3 Y  b6 a; H/ t! W, M% e
  6.     eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_ODD);                // 初始化modbus为RTU方式,波特率9600,奇校验
    ' L/ N; H; {4 \7 }! l9 X
  7.     eMBEnable();                                                                        // 使能modbus协议栈3 V4 N! h6 Y4 g
  8. # n6 S5 F9 l9 l, a3 S
  9.     for( ;; )
    . ^* V7 K& [$ M8 B+ ?# w& `
  10.     {) E; Y7 D8 E3 }" c% d5 _- P
  11.         eMBPoll();                                                                        // 轮训查询
    $ z  U" k, j2 C* z9 v! k/ K
  12.     }
    : T" i7 X' Z! B- J" A
  13. }
复制代码
; P4 h% R7 @  A) I2 n; Z1 g/ E
移植测试
1 Q' p( Q% K* k+ _0 {
( P# W( a" S6 W 20200313154857173.gif - N, ~2 s# _. \6 W: O* z1 l2 A
4 ~0 M( N8 D$ o5 l( b0 }  I9 R
ends…% r5 c# T7 D: n9 Z) j
! ~* u9 O# N9 s7 u8 `
5 `) v4 r0 `' h8 m6 b& ^/ X9 l, h
# e, C! ^/ t) d* g6 B6 h
收藏 评论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 手机版