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

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

[复制链接]
STMCU小助手 发布时间:2022-4-10 22:53
modbus命令码表:; Y/ P& T5 `6 C; Z8 o: B1 {3 f
( O+ r- _: e! x" A, G' d( G
b8032deb4d154657acd2f7f2942369d4.jpg
7 j/ E# n5 \5 O/ w4 U+ O9 l& k5 G" A. U' `: s
FreeModbus文件说明
" `: T% w# u, N# S
      解压freemodbus文件后打开,我们需要demo目录下的BARE,该目录下的代码是空的,STM32移植工作基本就是修改:portserial.c、porttimer.c、port.h这三个文件。
. i2 m4 w( B, i; R" B, r/ R 20200313143257958.png
  @/ P* L! ^+ L0 f$ W9 ?& p  o- e: |; i4 Q/ g8 G: X! `4 b- }6 _" Q
      mobus文件夹就是完整的源码,包含rtu、ascii、tcp:
  X3 ]# i( ~& ^2 N6 ]% B
2 c7 _* l( S2 }# s. y ZM%DLXPRB8$%[NN2%4Z1N.png # z. Y& a6 \( Y- v8 G* L  r

: n8 L% Q4 M' H2 P3 `% _7 R      我为了移植时在keil添加源文件和头文件方便,就把modbus所有的头文件和源文件放到了一个文件夹下,并创建了一个port.c文件,用于编写modbus所必需的回调处理函数:
/ Q1 S5 f1 P) c; N' |  E
, V4 I, j# ~% e4 a) h+ ?9 h 20200313144036579.png
' O. Z( X  x( ^, q" A- @
$ q& \3 j# ~2 m( j* u3 {STM32CUBEMX配置
* `, S2 u4 ?) ]& S
时钟配置,设置主频工作在72MHz下:
4 k/ X" t/ Q) _

' M; D0 d% E, r4 _# X# I  e JU1~N33M}I7K1(6K@JFN5~R.png
% R- e7 P: E$ y; f; h& q, `" ]. L$ _9 s: E
配置串口1,这里随便配置就行,在modbus移植过程中还会对串口重新初始化:

. N- F. N5 z- m: \( Z! E* Z/ a* p2 J6 d  y$ L2 M: X1 M+ t. P$ j
U25OQ_FHYD5WEXLFMI4V@RU.png ' ?- ]1 ?' ?  e9 l- \0 m

4 j  u6 ^8 J9 G7 ?配置定时器4,用于3.5个字符的定时检测,这里随便配置就行,在modbus移植过程中还会对定时器重新初始化:
! z* y/ t' e. v8 m

9 v- b; p' q) o) s H6{)WT`**CIHDAM02558GK.png # y& W2 I$ f% Q) A7 V" f

0 Y. Q# X/ J6 ^4 d! }中断配置,这里注意,串口的优先级是要比定时器优先高的:

. O& c! u8 O. D! M$ R( j* T# a. @5 k7 s, G0 k. X$ ]9 `1 f' p
G(RP`74TR)NPJFUK``Z%I2L.png
' K$ `  d( E2 ^- O; ?* J- h取消掉自动生成中断服务程序,在移植过程中我们要自己编写串口和定时器的中断服务程序:
* I# L, O! x' J: \; h
! h- o" i$ P, U& X ALHMK5Y615K6(`M{0[]YJ.png
1 ]# D. o. T% F- G# r+ B: D& c" Y, [. J0 b& u
移植代码修改
: _2 Y& Y. }0 J4 R9 N
生成代码后将modbus放到工程目录下:0 T( _8 ^# c' t
& i! `7 Z+ Z3 n( l% _3 @! h
5%(_LMGIM_8_YGL`]JGAB67.png
- T$ a5 ]& M; ^' Y* y
; M+ n- l, Z% Q. B% T7 K打开keil工程添加modbus源码:

: K- H. n, X; P1 d% ^6 |9 ^3 I! o5 o0 s7 J, c) Y  ~
F`8_YFACMNOAP28~2VHD{CO.png ! @: c% T, @' q+ z. D8 i8 g

& N- J! B6 R1 `* ^7 k0 ~  \添加包含头文件:
$ O, o  u1 d" R5 V

$ k# T! H' W. Z, U% q `7BMVXA`R9SQBTGT`B@{]X7.png ) y: z, `/ `( B8 m7 I; T
' F, r/ Z8 X+ h' I% r
修改modbus定时器初始化源代码porttimer.c文件: ^# N$ J9 l  b4 Y
       定时器的修改比较容易,将定时器设置为每50us的时长记一个数,传入的usTim1Timerout50us变量给自动装载即可,prvvTIMERExpiredISR函数需要在定时器中断服务函数中调用,它的作用是用于通知modbus协议栈3.5个字符的等待时间已经到达;由于我们在STM32CUBEMX中取消掉了定时器和串口的中断服务函数程序,所以我们在该文件中添加定时器的中断服务程序,修改后的代码如下:2 F4 [5 C) ?+ U/ u0 a# P' q
0 v$ D3 K" ?7 d; s
  1. BOOL0 J. F1 g8 N/ a# B: F+ l
  2. xMBPortTimersInit( USHORT usTim1Timerout50us )
    + a. L2 h) T7 I  v: }: |6 f- i
  3. {; a6 J1 g* Y0 w% ]0 R; L& n1 t
  4.     TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    0 g: ~- F% p, o
  5.     TIM_MasterConfigTypeDef sMasterConfig = {0};
    # m' z% }" W1 N8 @& u* t; l
  6. - D8 c) O$ E/ y, j2 n0 T4 n" s
  7.     htim4.Instance = TIM4;) U, @8 J- a8 v) d( S! _+ r
  8.     htim4.Init.Prescaler = 3599;                                                                // 50us记一次数
    9 L7 l; t" D3 e. n! d
  9.     htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
    . b! c2 O9 N4 c
  10.     htim4.Init.Period = usTim1Timerout50us - 1;                                        // usTim1Timerout50us * 50即为定时器溢出时间: _6 @; J! i5 J' t
  11.     htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;! U9 H6 i& k! I! b4 d
  12.     htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;% p3 ^3 G$ ^- f# @" E) x1 l
  13.     if (HAL_TIM_Base_Init(&htim4) != HAL_OK)9 d5 X; O$ z# T
  14.     {
    9 n$ k; I) V4 h: f' e  C7 @
  15.         return FALSE;& j' t1 U% h; a1 O
  16.     }4 {, W0 D4 [+ U+ |$ T* l& S, F
  17.     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    . I/ b$ X) J9 U% f/ y; m; o. }6 W
  18.     if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)- Y9 p# @. r# h/ e
  19.     {6 p+ P# |% }% ]1 N2 o: ?
  20.         return FALSE;
    1 Z8 N7 u" n1 {. `" R( C7 @1 f
  21.     }) H, o1 N/ V( l; q
  22.     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    ! f6 ^% p: H9 p
  23.     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    / D: i/ S& q8 ]7 [- W/ d
  24.     if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)" M5 x* h) k2 @& L' c
  25.     {
    ( n' ?/ m3 t9 S* U( L+ G* B
  26.         return FALSE;
      E* m4 g5 W2 V' h. U
  27.     }
    7 X9 W- m5 g/ j+ ^2 T. ?  T$ X
  28. # a! X& {  d* \, s6 Y
  29.     __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE);                                        // 使能定时器更新中断7 D8 B& X/ R# j1 Q% q
  30.     return TRUE;1 a* x( E# h; A% U; Q& Y3 L$ t
  31. }
    - p! n1 f! Z' v# z% v

  32. / u2 S' [& H+ Q' K5 y2 W* w0 o
  33. inline void! J4 U$ O$ K0 V1 D: `
  34. vMBPortTimersEnable(  )
    6 y, Y2 d7 a8 y$ R4 ?; a. U
  35. {
    9 Q+ `4 r) q6 ?2 }2 i3 n
  36.     __HAL_TIM_SET_COUNTER(&htim4, 0);                // 清空计数器
    % Y' ^1 I: f7 g- c9 @
  37.     __HAL_TIM_ENABLE(&htim4);                                // 使能定时器
    ' |, b+ x! v# ]6 H
  38. }
    2 N5 `; A& S- e' f' m
  39. 5 k  v, N: A4 f/ V' D
  40. inline void
    ) M! G2 c$ G+ L4 c" M
  41. vMBPortTimersDisable(  )
    & q5 g4 k& N8 Y+ X- Q& @
  42. {
    - g9 O# V' t9 J
  43.     __HAL_TIM_DISABLE(&htim4);                                // 禁能定时器. G5 O( o- ^2 p9 E& A( Q' l
  44. }
    2 E" t& w: o0 z( W. u

  45. 9 f8 Q; b6 H6 M% ^, ]* x$ ?" Y
  46. /* Create an ISR which is called whenever the timer has expired. This function
    ( p% [$ M8 `- l1 l, X; N3 ^) Y
  47. * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
      r( ?9 m% {' e8 T
  48. * the timer has expired.
    ' o4 p- A0 r5 Q1 c8 Y8 w
  49. */
    & e- O- u' O8 A; X+ h! a$ P
  50. static void prvvTIMERExpiredISR( void )8 h- x6 J4 q) }! u8 e7 @
  51. {
    ' j* A/ G. ?+ X& j( L
  52.     ( void )pxMBPortCBTimerExpired(  );# `$ u! X6 O  b6 F# x
  53. }4 [" D" P. [( E, p  Q/ Q

  54. 4 q/ S" J0 p" O' ]. _$ G
  55. /// 定时器4中断服务程序
    9 K1 Z! a) J' x
  56. void TIM4_IRQHandler(void)
    : W! Y% S7 b5 Q0 |8 j
  57. {
    2 b! X6 N5 I; `3 E
  58.     if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE))                        // 更新中断标记被置位! a. k; O: b) j8 q1 R' {) S
  59.     {
    4 X% y0 ?( Z1 y7 |) X8 Y
  60.         __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE);                // 清除中断标记- `1 o% D$ _" a! h( c5 v, F5 u# R
  61.         prvvTIMERExpiredISR();                                                                // 通知modbus3.5个字符等待时间到
    4 n' b' a1 y) w6 J# ^2 A
  62.     }
    & \% ?9 |7 ], X8 _$ W
  63. }% J2 l! Q' y; [) s
  64. & H) k3 }# y" E( _7 h
  65. / z: c6 r& h7 p. t  W
复制代码
, M4 o. ]2 S# j, N1 H2 e3 G
修改modbus串口初始化源代码portserial.c文件/ K9 U) U# B9 Z: {  k5 c
         ~~~~~~~~        在该文件中实现串口1的中断服务程序,prvvUARTTxReadyISR和prvvUARTRxISR函数需要填写进中断服务程序,前者得到作用为通知modbus协议栈串口已经空闲可以发送数据了,后者的作用为通知modbus串口1有数据到达,修改后的代码如下:& N6 g; Y! w# b# D* O& j; P1 K* `7 \

/ F; p- [  _4 `, e* V- b: n+ z
  1. /*
    ' a1 f! Y. i- K! F7 ?
  2. * FreeModbus Libary: BARE Port
    ) E7 y0 q& X# Q+ @# z$ l" X# Q
  3. * Copyright (C) 2006 Christian Walter <<a href="mailto:wolti@sil.at">wolti@sil.at</a>>: \0 c: W1 \) H
  4. *
    $ r- U* a9 J4 M. K* J/ W. n
  5. * This library is free software; you can redistribute it and/or  w- [+ r; g8 u
  6. * modify it under the terms of the GNU Lesser General Public) |! e3 P3 ^7 Y* x
  7. * License as published by the Free Software Foundation; either  D9 I8 T. \5 `' x/ `
  8. * version 2.1 of the License, or (at your option) any later version.
    3 n& c5 m3 \& w; F# C% ]
  9. *# v5 c# S7 K7 a* V# ~) R' D0 {
  10. * This library is distributed in the hope that it will be useful,  l# ]; [  m4 v% O
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of4 s2 u0 W' e' p+ d5 j
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    % X1 G/ W9 }4 m9 c/ G: k* j
  13. * Lesser General Public License for more details.
    : I7 f# R6 S" T5 ~
  14. *& b6 y" i3 L. ^9 h" x* X- c
  15. * You should have received a copy of the GNU Lesser General Public
    ! w4 X. C4 \7 J  \7 g6 q
  16. * License along with this library; if not, write to the Free Software
    ' }/ _# q% X0 p* Z
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA( Q9 z2 W. |6 l5 R- h8 ^6 `
  18. *9 y* i6 V5 d+ j  ~! m6 T
  19. * File: $Id$6 ?" k. O; e& I  F! s/ P
  20. */
    4 _( J. v3 u) q0 x, ^
  21. + o0 \4 X  _8 ^- A
  22. #include "port.h"
    ! T: l: `1 r; H) J
  23. #include "usart.h"
    + H( d. s' r# c

  24. ' l% F1 M3 W9 _% W  V* g
  25. /* ----------------------- Modbus includes ----------------------------------*/, B8 W1 F2 f9 F8 d7 y( J' J3 y
  26. #include "mb.h"
    9 k2 v; {8 u  `* l5 y6 X, Z5 ~
  27. #include "mbport.h"
    ) P7 p3 T9 K$ D* g' ^+ G
  28. ' j8 u6 z1 W  k1 i% ^$ R" w6 X
  29. /* ----------------------- static functions ---------------------------------*/
    ( }( M  Q5 d0 o% `& v- \9 }
  30. static void prvvUARTTxReadyISR( void );
    + T3 R2 Q0 _$ b7 ~5 s% i  ?. W
  31. static void prvvUARTRxISR( void );# ?$ p2 t1 i0 }6 }) s- y

  32. 1 N/ c3 ]+ K) g* ~4 s0 ^
  33. /* ----------------------- Start implementation -----------------------------*/
    6 W7 @6 }# _# _- Y& @
  34. void
    ) |$ M& D. ^; R- l; X% y; N" m
  35. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
    . @7 P+ S; v) d& _. g
  36. {
    6 P2 }$ O; ?8 R. D" z! I. a
  37.     if(xRxEnable)6 F6 I% G. I+ G- r7 \+ [
  38.     {! }+ d. X$ p+ a: q5 y) Z! W2 |' W
  39.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断! E$ j. ^0 U' D4 d4 u
  40.     }
    ; D) x0 x  M; I$ Z- z
  41.     else6 l. O) F" w$ i* n" ^
  42.     {
    . p8 G) b8 o8 b. v. {
  43.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断( N. w$ `. w& y
  44.     }9 n" {6 Z; Y+ k6 S0 z( ~

  45. 4 z2 F1 W7 w9 H2 |
  46.     if(xTxEnable)
    , {/ u$ P+ ^. q  J* ], Y- o
  47.     {
    1 o( `& J" i1 ~  N1 Y' _- Z) W0 h/ o8 R
  48.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断
    * r3 f8 s+ n, z4 f: k( ~
  49.     }7 `/ g  U9 V5 _7 }3 f& }
  50.     else
    + n& N: f9 I) v: B
  51.     {
    - W# ]; \# t; D2 _. l
  52.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断. b8 m+ N2 `, C5 B# D/ I; O
  53.     }* v9 O- {& D4 m# V, ?% T
  54. }$ E3 [, o4 L: J( E, F/ c4 p1 E

  55. 0 ?$ @8 }1 C6 U5 t( m
  56. BOOL
    / D) q2 P# E# C( k( k9 N: f
  57. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )( [* |. B' S  q6 z1 |  C$ N
  58. {
    # l, W4 L/ }) g
  59.     huart1.Instance = USART1;
    0 t) l+ `+ i/ l/ |) b5 E9 f
  60.     huart1.Init.BaudRate = ulBaudRate;
    2 j, d0 I" Z. k/ `7 M; M* \
  61.     huart1.Init.StopBits = UART_STOPBITS_1;  m9 @" f, c  t% n# H& S" C
  62.     huart1.Init.Mode = UART_MODE_TX_RX;
    ) i0 H& H& k4 f! V7 _  z$ _
  63.     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    , I, @+ w( ]9 M7 |# P* Y5 P
  64.     huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    " _7 i1 J% T& |
  65. 6 l! z! c; k) U: M
  66.     switch(eParity)* Q1 C9 S* [  C, U1 ]
  67.     {
    6 q9 Y" @! n3 u1 R1 [6 J
  68.         // 奇校验
    5 q6 v7 I2 w" \
  69.     case MB_PAR_ODD:
    6 Q1 N0 g# T$ A% \. m$ a6 _
  70.         huart1.Init.Parity = UART_PARITY_ODD;
    . J8 y5 d4 D7 m7 f( v7 {0 @- k
  71.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits3 V' u: c. t+ ~4 F, V0 r8 j/ W6 ?
  72.         break;
    1 w" m  l' i. ?. W/ s' a4 H  }
  73.         & s3 i1 |. j& V5 o+ \2 R; T2 x
  74.         // 偶校验  Q) e4 E* K) F  s# G
  75.     case MB_PAR_EVEN:
    $ r/ G* @* j" W) W4 r+ y
  76.         huart1.Init.Parity = UART_PARITY_EVEN;
    0 z/ t/ D9 o$ c: T5 ^7 H, P4 Y
  77.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits5 e" B+ [; A* K. B. j/ g' H
  78.         break;
    . k3 M/ c0 T  @- U! _
  79.         ' A0 q# P) v& ^+ F9 {
  80.         // 无校验2 x. t( C& _! N7 }
  81.     default:7 v8 D9 x0 v$ r" z8 U' _
  82.         huart1.Init.Parity = UART_PARITY_NONE;0 z& |; S+ x1 O& [
  83.         huart1.Init.WordLength = UART_WORDLENGTH_8B;                        // 无奇偶校验数据位为8bits
    ' o& q9 z! H# `& I1 y
  84.         break;
    / p) V5 Z- A8 U4 F% p# H$ j
  85.     }
    7 K, i+ R4 N, @( F' M8 \% Q
  86.     return HAL_UART_Init(&huart1) == HAL_OK ? TRUE : FALSE;
    , s: W& Y; X2 e$ W6 N* ]
  87. }6 N7 V9 |/ T) _' P8 ?$ V, S( ?* t

  88. 1 F4 x$ u  |0 X+ ^7 d
  89. BOOL
    8 I0 @) _& i$ ~/ |' `1 B
  90. xMBPortSerialPutByte( CHAR ucByte )& i! r8 c# v" ~, i8 b- _* _4 |
  91. {
    0 r: n5 K# k8 v* P  m
  92.     USART1->DR = ucByte;  h5 W( e* O9 Z8 B2 M) N, Y
  93.     return TRUE;8 h, k' n  {5 U
  94. }  N2 K6 r% M9 P6 [

  95. 6 ^7 \: f4 B/ V  O
  96. BOOL: T: t" C; i8 D3 [7 l# i6 f/ ]
  97. xMBPortSerialGetByte( CHAR * pucByte )
    * U3 t7 @# A# q- B3 m2 r
  98. {
    - }; m. I1 ~$ M9 g0 P( q0 D: k9 K
  99.     *pucByte = (USART1->DR & (uint16_t)0x00FF);
    1 \/ P4 g  ^0 t1 ~
  100.         return TRUE;
    3 l8 Z6 V/ j6 s; ?2 j+ c5 s/ |
  101. }& P0 m+ r$ }; T

  102. / X( ]; c3 P2 B  W
  103. /* Create an interrupt handler for the transmit buffer empty interrupt
    & R, T' m% H; n7 n
  104. * (or an equivalent) for your target processor. This function should then4 {9 d4 j1 d  e7 U! r3 ~8 s
  105. * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that# V0 W) n: K& J# v" u) Z
  106. * a new character can be sent. The protocol stack will then call
    $ N/ I5 j/ q- V2 E, o$ Z4 z
  107. * xMBPortSerialPutByte( ) to send the character.5 B$ _) c5 N+ q* s3 q
  108. */; q3 W% l! c# |7 i
  109. static void prvvUARTTxReadyISR( void )
    7 _6 q2 e: L8 I# W$ r6 U% U2 b
  110. {
    ( z2 a/ M, T, X1 O- o
  111.     pxMBFrameCBTransmitterEmpty(  );
    0 {0 \* U  \$ S, F
  112. }( R( T8 R7 J  \" _7 r7 T% E% ?

  113. 1 |: r+ P' V% f: R7 j/ s
  114. /* Create an interrupt handler for the receive interrupt for your target
    9 S; {. Z# {9 @0 p4 j
  115. * processor. This function should then call pxMBFrameCBByteReceived( ). The5 @0 p: Y# g! h, N+ N, ?
  116. * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
    ( l; K3 H: L+ q% h; v1 A& ~  j
  117. * character.
    2 H/ u& x# h, s/ k% c
  118. */, v" J# {. [% z1 @4 g+ P$ D; S
  119. static void prvvUARTRxISR( void )
    - q- y8 l  C1 K8 E1 K. L
  120. {
    6 K2 a: ~: L. z/ i
  121.     pxMBFrameCBByteReceived(  );1 d% t2 {% g& w' J  Y
  122. }
    5 e# O9 C  h( B; u+ }

  123. , |5 w& _7 E6 ]; F) U/ E
  124. void USART1_IRQHandler(void)
    & ?" c/ A9 M  Y2 x: F, n0 b
  125. {8 r+ `8 @' ]9 p- x% X2 v8 d
  126.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))                        // 接收非空中断标记被置位
    0 r( l; T* k1 B0 \' ^
  127.     {0 H4 F0 G7 x& O# ~5 u: t6 V4 }9 D
  128.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);                        // 清除中断标记
    # Z& P. Y- l# Y( `
  129.         prvvUARTRxISR();                                                                                // 通知modbus有数据到达$ V: p( J  t& `2 E- ^
  130.     }  _: }& f3 G9 q9 M1 C
  131. . D9 H# n6 Z. @, `2 Z( d
  132.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE))                                // 发送为空中断标记被置位2 u+ E3 n3 h# v4 G+ h8 ^
  133.     {' y: K! U. ?8 x; u' a2 t% V
  134.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TXE);                        // 清除中断标记3 d% ~: F( _( h1 ]; T4 K3 m* H
  135.         prvvUARTTxReadyISR();                                                                        // 通知modbus数据可以发松3 a+ A3 Z! A# z3 N" P0 Z
  136.     }. O5 E, F5 J5 n9 I; ^
  137. }
复制代码

4 F5 }3 C4 q8 s4 Z5 @, S注意一点,一般如果使用了485芯片的话,那么同一时刻只能接收或者发送,可以将函数vMBPortSerialEnable修改成这样:' L- R- u4 @3 Y0 W; F

1 o+ U( X1 t4 W0 L, X& G% ]
  1. void2 e9 s0 ~7 a$ Y! C$ u) ~
  2. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )% g6 B" A- y' z3 j0 s
  3. {6 G8 I8 g$ U# o0 j/ F9 Z) Z& h
  4.     if(xRxEnable)' P8 w9 s7 e. n; s& i) D( a
  5.     {2 W8 X, ^8 ~% ^& e: y- N1 a- f8 ?
  6.             //" D/ Q% \7 ~. Q$ c
  7.         // 在此处将485芯片设置为接收模式5 ~' U; O) J8 l4 O
  8.         //$ M  M4 w. w/ i+ _9 ~9 A3 _
  9.                 /* do something */
    3 W8 }' I3 z7 N& D
  10.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断
    & A) Y. _9 D& {! F5 S9 V$ f
  11.     }
    2 Y$ l0 z! c! |3 w0 o: ^6 Q- U. q
  12.     else
    1 E6 K& j) K: n# j$ s+ @
  13.     {8 Y0 K6 ?0 j4 _, R& }
  14.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断
    / B' R) `+ n8 `9 y0 M: d2 g
  15.     }$ P3 }5 d+ M: y' S0 ~. j% K
  16. + ?( l! n7 F6 T% g
  17.     if(xTxEnable)
    ( o$ b( o, D- b; U6 }6 o
  18.     {( T7 O) S/ n4 v) w' @2 M: s
  19.             //
    7 v$ q" Y2 A6 l( L4 A$ f. j! u5 |
  20.         // 在此处将485芯片设置为发送模式, I( b3 U/ R4 q& C2 H2 h: k
  21.         //  c8 I8 Q3 E) o; v$ K: ~0 l
  22.         /* do something */
    % ~. `4 P. {9 b8 w
  23.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断% c7 O) e* Z/ E" M' k6 n
  24.     }6 R+ B% m5 y2 ]# U2 H0 P
  25.     else  d- I# I7 `. g
  26.     {
      N6 h  w* P  i0 K
  27.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断
    9 j# @" m1 ?6 M" E  K  x$ X
  28.     }' q: O: Y. ^' K5 Z
  29. }
复制代码
- H% Q7 c2 M9 `7 x' }
编写modbus命令处理回调函数port.c文件
4 ~; v% P3 F0 u6 G( a/ m1 ]- |7 p本例程只实现了读取输入寄存器和保持寄存器的功能,详细代码如下:
( y( |% F, }1 K) l& Q

0 N; f* A- |2 z( `* \& f% J
  1. #include "mb.h"
    ) @! q1 ^$ q+ o$ [& o" s. E
  2. #include "mbport.h"* Z6 A4 `" @4 _2 e; y
  3. % ^# b" l' ~+ G# k. R+ g

  4. 2 u2 r6 ^# s6 Z+ E0 V% \$ ~
  5. // 十路输入寄存器6 B% G( G/ v0 Q1 z
  6. #define REG_INPUT_SIZE  10
    5 G3 n$ o% A+ `, j
  7. uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];
    $ t* |$ `$ U. d# M' |
  8. 5 m; H8 A4 {+ a" ], W* R  h
  9. 7 j, C1 t- I; H& X5 P
  10. // 十路保持寄存器
    ) p( \; H, y4 I. w: d6 @4 x) p
  11. #define REG_HOLD_SIZE   10
    8 _- d" l  N0 k! _
  12. uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];
    1 r; z' i' p2 F0 c! W$ \

  13.   ]% u2 R; {% U6 v: p
  14. . N/ F. {" f0 U( S: T
  15. // 十路线圈
    ) z) g7 d$ q( B9 z" r6 t5 z. t) s
  16. #define REG_COILS_SIZE 10' ?9 ^& D/ ]6 ^9 z" o; `
  17. uint8_t REG_COILS_BUF[REG_COILS_SIZE];
    9 [2 P" N: q) z+ _5 ]

  18. 5 n# T/ w& `0 x( N2 R- H& n- L0 r
  19. 4 O7 l$ f+ q; M! c6 T! `
  20. // 十路离散量
    1 w& A$ \- d$ H) }
  21. #define REG_DISC_SIZE  10
    : H; j$ j4 N4 Y& m9 P  {
  22. uint8_t REG_DISC_BUF[10];( V# d5 i- [; T5 w- [" {8 C

  23. % o" M# a6 W- r. {
  24. 2 s& |' v5 J, _8 X; o0 F: N2 ]2 `
  25. /// CMD4
    , o# K; t, K/ l
  26. eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )) b. i* {& W9 k
  27. {
    : P( b0 u0 J& [" F/ N
  28.     USHORT usRegIndex = usAddress - 1;
    $ L# h7 i# x- @  A
  29.   T& n6 ^0 L2 T8 k8 `9 ~
  30.     // 非法检测9 ^( u: U& U* k4 v. v  I8 t: T
  31.     if((usRegIndex + usNRegs) > REG_INPUT_SIZE)# R9 s  V' V9 V  z+ ]9 Z- V
  32.     {
    ' R# `! r0 I* m) ^. j2 c0 t
  33.         return MB_ENOREG;9 B) @2 B5 u/ t8 J0 H" N
  34.     }5 ?# r+ t6 c8 ^" `$ n( r8 [
  35. / k$ L( ]! b+ N7 w* c
  36.     // 循环读取
    * z$ u3 N1 p0 {
  37.     while( usNRegs > 0 )( t, ?' [) ^5 m3 o3 q3 q
  38.     {) w( B4 {! P# t. n- A
  39.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 );
    9 l+ a2 \/ f8 S, D- b
  40.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );
    * h8 {+ Y# r# |( R: J( o* ?
  41.         usRegIndex++;% z- h& x0 k; [7 G0 A' V7 Y
  42.         usNRegs--;
    . C* [, q6 h. O4 `0 y
  43.     }
    $ S) S% b/ \$ R

  44. $ @3 ?1 k! N: [% Q
  45.     // 模拟输入寄存器被改变
    8 T) A( _! L0 U/ }$ r6 m
  46.     for(usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++)$ n+ d5 u# b6 K0 S3 x
  47.     {
    ( b6 O) [/ G! |  b# A, X9 T* d8 d
  48.         REG_INPUT_BUF[usRegIndex]++;  C$ v) a' ]; x3 o9 g: |- H7 m* V! u# N
  49.     }; s6 l1 d$ ~% @: m( k2 @
  50. * t( m  v; l8 h6 y% X' C/ m6 C7 X
  51.     return MB_ENOERR;* O# K# R( S  H$ n% w" p+ M
  52. }
    2 f5 z. _6 ^4 b: P7 a

  53. 4 M7 J) w3 ?2 F: w
  54. /// CMD6、3、165 s7 M# p0 @7 ^2 b
  55. eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
    % r- o% f1 r; K
  56. {
    8 y  w' }. \2 ?3 p8 N3 {% c* Z0 Z
  57.     USHORT usRegIndex = usAddress - 1;  / r% {  \9 `  l+ @1 Q

  58. 7 ~+ V! D9 X7 q" F- f% O
  59.     // 非法检测
    - H: u. e" c$ o
  60.     if((usRegIndex + usNRegs) > REG_HOLD_SIZE)' s, _& w4 _, v/ \7 C7 S
  61.     {
    % C5 n6 s* y. A# ]: }* g) y
  62.         return MB_ENOREG;
    ! u" a$ D! M! w6 \" `9 T% K; K3 ~& i3 f
  63.     }" L1 [; `/ R, A9 g& m0 a" a
  64. . c- [" V" f3 i' V+ P
  65.         // 写寄存器
    $ V2 H" ?" [, M8 V. d% x9 N
  66.     if(eMode == MB_REG_WRITE)
    + Q8 t3 c2 \. n4 x* q
  67.     {
    , P7 F1 I% U( L( _, y/ l
  68.         while( usNRegs > 0 )
    2 B; U0 N" D7 H3 R3 W
  69.         {
      c8 _. s1 F( ^9 u( v/ a! @
  70.                         REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];8 h2 ]' M, c* M/ R3 ^" k* ^
  71.                         pucRegBuffer += 2;3 D% w$ L0 Z5 f* {# a/ w. a# ~
  72.             usRegIndex++;8 z7 u8 ]+ J" O% q& ~
  73.             usNRegs--;$ P  v( N% x6 k- j
  74.         }) I5 t! j! \* s. d/ T
  75.     }; ]; n9 j9 B! H. b' b1 J, `5 I. ?
  76.         
    & N9 i: K& P7 P0 t/ P
  77.         // 读寄存器
    * ]& c7 N! h+ G- s) P
  78.     else
    ! P3 x8 z: y- C7 N" C! [3 _. W  c. T
  79.     {
    ( n0 \% Q  E% O+ ~
  80.         while( usNRegs > 0 )
    # ?) ?; O$ t3 H  P# q  L9 f# h: {
  81.         {
    6 p8 a: l- ^' n) j  K6 Z5 C
  82.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );5 R( X$ E# x5 a
  83.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );
    9 E7 I2 d% M" x) X
  84.             usRegIndex++;! b+ x4 m; R# e/ z
  85.             usNRegs--;* ?6 B4 Q: A3 m% N+ ~
  86.         }
      h8 a1 N" C2 @$ R5 H" v$ R3 }
  87.     }; {; v. J0 W1 ~0 [
  88. 0 W+ }! S3 N0 J
  89.     return MB_ENOERR;
    1 m9 D* [$ X+ u% R3 ]. g
  90. }# P5 }& b. L) e) ^" o! M' u- K7 G

  91. 8 \* H$ m0 F  \2 E
  92. /// CMD1、5、15* V& G: h# P# y. o" r
  93. eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )2 }" k/ S$ v, G
  94. {& y/ o( N0 N5 ]) [
  95.     USHORT usRegIndex   = usAddress - 1;7 Q' I$ X$ q  N
  96.     USHORT usCoilGroups = ((usNCoils - 1) / 8 + 1);7 O: M9 z) n  y7 B* z. f* W
  97.     UCHAR  ucStatus     = 0;
    ) i8 x0 `% }) R. t# f0 U
  98.     UCHAR  ucBits       = 0;
    ! I# G- t0 u3 H( F0 a0 z7 f' m
  99.     UCHAR  ucDisp       = 0;
    * Z# v9 t; v% W$ c6 x+ G
  100. + S. y6 P" z, x5 h9 T
  101.     // 非法检测
    9 C; L( p6 E3 a  ?7 x1 j
  102.     if((usRegIndex + usNCoils) > REG_COILS_SIZE)2 D, W: U8 x% t& C
  103.     {
    $ _8 t; k4 z! `7 o' j4 X% d* i1 n
  104.         return MB_ENOREG;
    4 \8 W8 a/ x( [& f# ^; e1 I, |4 e
  105.     }
    ! W/ s( D7 v& N7 g

  106. " Z7 V1 w) d# @# u
  107.     // 写线圈: R1 b. [! U7 y8 t3 r# v
  108.     if(eMode == MB_REG_WRITE)) I4 e: D' i' v
  109.     {- J. L% m3 T; f8 d; [
  110.         while(usCoilGroups--)) n7 @  z9 F$ k+ j, o' j
  111.         {3 f3 a+ x& @- f! j0 M8 a/ U& }
  112.             ucStatus = *pucRegBuffer++;& q3 [4 e) z1 u9 j. k4 F  I
  113.             ucBits   = 8;
    ( |! ?* L$ V& l) B6 m1 {
  114.             while((usNCoils--) != 0 && (ucBits--) != 0)0 h* L/ _8 T$ w) `0 V7 V
  115.             {
    * y+ n8 W5 |) a! L
  116.                 REG_COILS_BUF[usRegIndex++] = ucStatus & 0X01;0 x3 H' d4 {- i' b
  117.                 ucStatus >>= 1;' Q" j# G, z+ e* E& p6 g8 L6 r
  118.             }8 V  L* C) H9 B( B- K: i: d
  119.         }
    ) g" c* a  X0 \6 A" a8 _1 D
  120.     }
    4 @5 e* `" H4 `% L. K$ {

  121. ) ]% W0 x8 z9 s1 H8 l4 [
  122.     // 读线圈
    1 @3 \, L/ A* d1 Z: Z# n
  123.     else
      s8 c7 j, M" n9 V: ^+ @0 }
  124.     {
    1 H2 w& h% j5 B; X3 i7 U
  125.         while(usCoilGroups--)8 R) v6 o& K+ b7 q" F6 T+ S, g
  126.         {
    # D0 H4 |' p* `5 @1 ~) J
  127.             ucDisp = 0;
    6 `, s2 W. G  f( M: y6 K
  128.             ucBits = 8;
    5 F1 J# K( S* G4 G
  129.             while((usNCoils--) != 0 && (ucBits--) != 0)/ \* Z- z( g3 ?7 T2 o* @2 X2 o
  130.             {
    7 d6 u% F, c9 m
  131.                 ucStatus |= (REG_COILS_BUF[usRegIndex++] << (ucDisp++));
    / \8 X: {  F' i" |0 r. z
  132.             }
    1 q6 K0 J5 C7 T$ \
  133.             *pucRegBuffer++ = ucStatus;4 j0 u' M+ ^: B/ J6 _( X
  134.         }
    : c: X% ?! t0 e4 Q
  135.     }
    4 \  F: R  N* a- J- n' S6 j" h
  136.     return MB_ENOERR;
    : ~# y; J2 e' W
  137. }+ n& `3 Y0 U- {: \1 {! ~8 o# |

  138. 2 D) m" ~5 P0 s# K! d

  139. * ]3 J3 R9 \- G$ t. W
  140. /// CMD4; B( X9 C+ n  |) X3 o7 Y
  141. eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
    * l2 B0 \" E1 K; i+ W& ?
  142. {! D: g! I% h/ |3 G. ^7 ?9 Z3 F) @% R
  143.     USHORT usRegIndex   = usAddress - 1;
    ) b/ n+ N$ R/ y" Z" R( O5 A
  144.     USHORT usCoilGroups = ((usNDiscrete - 1) / 8 + 1);
    9 \( e: X& _8 W3 J
  145.     UCHAR  ucStatus     = 0;4 {- m8 _3 s  b
  146.     UCHAR  ucBits       = 0;  o, M) g6 ?# J7 w8 P: i8 y
  147.     UCHAR  ucDisp       = 0;
    $ J* M% M; R& X
  148. + `5 Q* \% `% B( I4 D. i
  149.     // 非法检测
    ; |! Y6 P9 o* \) [) |* X( D
  150.     if((usRegIndex + usNDiscrete) > REG_DISC_SIZE)5 O6 H' s" Z: w5 g. ?- x, B
  151.     {6 Y- N% M* g( K( }% z
  152.         return MB_ENOREG;
    ; ^/ [6 ^7 T' M# n& ?* B( K
  153.     }% {0 a, _! J) W: q1 ~

  154. 5 B  ?& P4 [, S0 X+ }# P) J8 i" e; ?
  155.         // 读离散输入
    1 K2 ~1 G7 g6 ^! [' a) H
  156.         while(usCoilGroups--)& \6 k& T( d/ I) d: W& M6 y# ?
  157.         {( H! L9 w* r# b) O. ~% p/ N- E
  158.                 ucDisp = 0;1 A/ x8 B# a0 Q$ U
  159.                 ucBits = 8;2 Z5 t- L( N; G
  160.                 while((usNDiscrete--) != 0 && (ucBits--) != 0)
    ; G2 e, L) J. o2 ?
  161.                 {! g* S9 K  l% J- S; N8 [
  162.                         if(REG_DISC_BUF[usRegIndex])
    : T6 U) j/ U' T& K8 I/ R: ~
  163.                         {
    ! R, F) K1 p4 u0 T+ t
  164.                                 ucStatus |= (1 << ucDisp);
    ' S1 t. J  b' f2 k7 D
  165.                         }1 \- y2 u0 P8 C9 L3 P
  166.                         ucDisp++;4 @& Z; r- ?* j) Y+ i8 j& A! I
  167.                 }
    ; e/ q) j: |& Y5 ^/ s* l! J) l
  168.                 *pucRegBuffer++ = ucStatus;+ b6 o1 I: j# Y! ]& H2 X" C$ I
  169.         }: \. r* j% s+ P6 N, t
  170. , t# _. N# m3 E; ?
  171.     // 模拟改变, z9 x/ w' _4 J& ]
  172.     for(usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++)/ Y4 i7 e( U# Y+ s5 N
  173.     {
    ! `& [8 ~3 p6 s7 u- `# I8 y6 s
  174.         REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];
    . d/ c: w9 A- o% E7 A; G
  175.     }2 V  P  n* k0 G$ c& c. O

  176. " H) V% e$ x+ b
  177.     return MB_ENOERR;
    ; [0 F2 A8 @6 }( g$ t
  178. }
复制代码

/ U( y9 a; C1 k- g5 f主函数

: M3 y; `' r7 H
  1. int main(void)" [; m3 `; h8 Y( T2 a
  2. {
      A% o8 N/ F7 p* @! M7 T$ H& s
  3.     HAL_Init();1 ~$ G& S' X! o9 Z  u) k
  4.     SystemClock_Config();
    - i% h, g" \, v: r# a: R
  5.     MX_GPIO_Init();* j6 R' B; R' t$ [* o
  6.     eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_ODD);                // 初始化modbus为RTU方式,波特率9600,奇校验7 o( C$ T) ]" M
  7.     eMBEnable();                                                                        // 使能modbus协议栈
    ) L, N6 r+ y! e

  8. $ M6 L6 y  A* J  E" Y2 Y
  9.     for( ;; )' `$ N: {' K6 G7 W/ C
  10.     {
    - I) ^0 X' p; X6 u
  11.         eMBPoll();                                                                        // 轮训查询
    8 a! g" A/ Q: U& M% q
  12.     }
      L& B9 W' N) D- E- n% Z8 y
  13. }
复制代码

4 b" h- \. B: w0 a移植测试" O  t* w6 b& M8 J9 C2 f
, B1 b. N% U# E; I# C6 d
20200313154857173.gif $ G- g: r- l( y& r

" o6 n5 m4 D8 `8 B, Vends…
0 T1 F- h9 N. @" v& v- D
- k' I; D3 j' u: @
2 P9 l* z( S0 L& r
7 A' [8 X9 Q( _, {% x  d! z
收藏 评论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 手机版