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

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

[复制链接]
STMCU小助手 发布时间:2022-4-10 22:53
modbus命令码表:* c1 y1 n) q( T! n
# a6 b% ]* l/ D0 [, ?& t2 X
b8032deb4d154657acd2f7f2942369d4.jpg
! P0 d  [: P! X( X; I/ L5 }) f
( d. {9 E* L0 n% F9 k( mFreeModbus文件说明
. [  V! |* T. f% n( }
      解压freemodbus文件后打开,我们需要demo目录下的BARE,该目录下的代码是空的,STM32移植工作基本就是修改:portserial.c、porttimer.c、port.h这三个文件。& d0 ?4 F  G7 h% }. s
20200313143257958.png
" |8 L' U/ _) Y- ?8 y2 x; N
6 T+ c" g: [4 S      mobus文件夹就是完整的源码,包含rtu、ascii、tcp:2 V- ]6 U: G5 R- Q1 y0 l7 V
/ C2 X" q1 q: w0 {
ZM%DLXPRB8$%[NN2%4Z1N.png
  L( g! d7 Q% Y) a* J$ K
+ u1 ?6 x. Q/ E# d8 E% K' S      我为了移植时在keil添加源文件和头文件方便,就把modbus所有的头文件和源文件放到了一个文件夹下,并创建了一个port.c文件,用于编写modbus所必需的回调处理函数:
: R  U8 [! b9 [0 r; k8 e1 B* N% |# i# ~/ U$ P
20200313144036579.png   a" Q3 J. c+ M: `) Q6 E
$ B: \  Y; T/ U4 R
STM32CUBEMX配置

7 ?. g+ n7 p8 ?% D: [时钟配置,设置主频工作在72MHz下:

. k! b# c0 D, Q/ A# B9 `
/ ?% r, S  h4 n* K) t9 m9 D JU1~N33M}I7K1(6K@JFN5~R.png
6 |. I! ]- W: v% R; A
! b+ j. y4 Y4 }配置串口1,这里随便配置就行,在modbus移植过程中还会对串口重新初始化:
/ {# O- l. ~9 U

$ o: f  D4 r  j/ v) {$ E& o3 R U25OQ_FHYD5WEXLFMI4V@RU.png ) L8 _9 Z& V* Q

, ~' ?7 E* W; p9 f7 c3 A配置定时器4,用于3.5个字符的定时检测,这里随便配置就行,在modbus移植过程中还会对定时器重新初始化:

# h& I, Z. `# Y' i6 o# I
5 i+ Z2 Q* T0 b- Y0 t9 D H6{)WT`**CIHDAM02558GK.png
# J7 T5 L6 c' @5 `  L, M5 C* m
& o+ k$ N: t9 |" k4 r5 K1 q中断配置,这里注意,串口的优先级是要比定时器优先高的:

8 s, B% Y2 v0 X+ y% d( ]5 X. K4 G2 ~5 x; b
G(RP`74TR)NPJFUK``Z%I2L.png * a3 S. L+ X' Y& [
取消掉自动生成中断服务程序,在移植过程中我们要自己编写串口和定时器的中断服务程序:& e! e4 K' a; M% P& n
# V$ ^: h! p) H
ALHMK5Y615K6(`M{0[]YJ.png - F+ l  q* m1 a; T. j
+ \% C- E+ \! k. D1 M5 l9 g9 x
移植代码修改

1 L; G+ p. b7 p. f生成代码后将modbus放到工程目录下:. j$ N" O  h# }" A6 ~" D

. W2 j; g; y9 N, s# s9 q
5%(_LMGIM_8_YGL`]JGAB67.png 1 y: p) O' ^, D! i
! g! l' O8 F% \1 l* G
打开keil工程添加modbus源码:
$ c0 X& m' b9 T% v4 f  b% ~3 G
7 b1 I# o" h9 E$ C! ~) U
F`8_YFACMNOAP28~2VHD{CO.png " J1 \9 C) D/ @: p+ J1 P, X' H! Q

4 o9 p% t' ~% j2 `添加包含头文件:
6 Y7 k- ?2 F1 @, O

2 e  \" X# I' z8 Y `7BMVXA`R9SQBTGT`B@{]X7.png
$ ]- @9 x+ U/ v* N2 B6 ^% ?! T: E% C$ R- _: u" d. v
修改modbus定时器初始化源代码porttimer.c文件
2 w. u# j2 u2 L; T, s  `- h       定时器的修改比较容易,将定时器设置为每50us的时长记一个数,传入的usTim1Timerout50us变量给自动装载即可,prvvTIMERExpiredISR函数需要在定时器中断服务函数中调用,它的作用是用于通知modbus协议栈3.5个字符的等待时间已经到达;由于我们在STM32CUBEMX中取消掉了定时器和串口的中断服务函数程序,所以我们在该文件中添加定时器的中断服务程序,修改后的代码如下:  J* k6 T. d, T1 m' F. ]
7 A  [4 o# d# r; P$ h9 Q6 P
  1. BOOL
    * q6 V8 B* L6 U& T9 Y- [/ P
  2. xMBPortTimersInit( USHORT usTim1Timerout50us )
    & [1 m/ @' Q" k& x
  3. {
    / ~  U$ q! V* c2 k$ e" S
  4.     TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    6 r; K/ a8 _' O3 n
  5.     TIM_MasterConfigTypeDef sMasterConfig = {0};
    3 K7 M+ X7 R1 v' u
  6. % z6 y3 B  A8 a2 p
  7.     htim4.Instance = TIM4;
    8 p, A5 h, G: u  I) l5 h* q4 g
  8.     htim4.Init.Prescaler = 3599;                                                                // 50us记一次数7 A6 E5 S) }/ _
  9.     htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
    - A1 J7 y5 R. \
  10.     htim4.Init.Period = usTim1Timerout50us - 1;                                        // usTim1Timerout50us * 50即为定时器溢出时间
    # L" H3 v5 z+ A0 @# _4 n
  11.     htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;7 C$ G) c5 i$ F" a6 m
  12.     htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    , G3 Y( w  y( ]6 `1 E6 R1 _
  13.     if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
    : p# M  _8 R5 u) v2 I+ l
  14.     {
    - v1 x) b5 C0 x( U
  15.         return FALSE;9 y( n; ^; P/ }! }$ |
  16.     }0 w; i2 ^- L7 l
  17.     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    ( N5 K- ]) C, ~, w. s5 p  a- `
  18.     if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
    + F7 d9 v6 x! _4 i7 D
  19.     {" m% r" P% `2 I: l& r; z2 T
  20.         return FALSE;8 T9 j$ i5 T; u+ b; s! R4 }
  21.     }
    $ T! v7 k2 a8 b4 f. d" c: i0 T. y
  22.     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    ; \0 M2 |. \% d" N. F! l
  23.     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    2 U# x6 {8 h! |3 @8 ^
  24.     if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)7 f* N- P2 q4 h4 Q- f/ H8 F
  25.     {3 r6 j; w2 O7 i8 a& [8 t
  26.         return FALSE;1 N" u$ T- Y3 J: {8 f
  27.     }
    " U) i' C. H  f

  28. . M  [% w8 w6 Z. I5 t- s
  29.     __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE);                                        // 使能定时器更新中断
    . G$ v( g5 Y2 C1 h- R  R  x
  30.     return TRUE;
    / i* ~& `( T2 P% N$ \
  31. }0 ^1 g! H& ]! }+ D

  32. ; C) D8 B3 m( |
  33. inline void. T7 |/ N; |" ~' \& b. S1 j
  34. vMBPortTimersEnable(  )7 E# W# t8 g* [/ g
  35. {4 w( [. d9 z: P, H2 x1 A
  36.     __HAL_TIM_SET_COUNTER(&htim4, 0);                // 清空计数器2 q+ h% Z, I( [5 N
  37.     __HAL_TIM_ENABLE(&htim4);                                // 使能定时器
      m6 D$ x$ i, E  L; u# Y
  38. }( Z* s) m( @6 r# t

  39. / u+ C% _( L) _& M2 W1 j
  40. inline void. b6 b3 O' N7 j: {- V
  41. vMBPortTimersDisable(  )
    4 n7 |  v: w. R; n
  42. {+ q2 z4 {9 V5 J0 V8 n1 q9 R' d- S% f
  43.     __HAL_TIM_DISABLE(&htim4);                                // 禁能定时器
    ; p3 a+ ?! C9 {0 a/ T) o
  44. }/ W9 t* ^. ?7 C: {) B& h" Q2 J) I
  45. . n# ~" t8 Y& }) `
  46. /* Create an ISR which is called whenever the timer has expired. This function( b% ], Z, }, U
  47. * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that5 {" H, I; Z9 t; ^
  48. * the timer has expired.
    7 K3 t+ f- p) B+ E1 j- W8 p
  49. */! Q' l0 O8 g. ]. l- K; P
  50. static void prvvTIMERExpiredISR( void ): t/ I# t& K$ \4 i( b7 m3 k2 r
  51. {1 l/ t/ p* S' [+ z5 h- V# Y
  52.     ( void )pxMBPortCBTimerExpired(  );# z# V* L& V6 L+ n2 h& d
  53. }2 j  G) v. A. X& E0 p2 W4 g
  54. % A7 ?" ^) t, v, H( T5 s+ s
  55. /// 定时器4中断服务程序
    - |9 G8 n+ R' X5 @9 j9 v
  56. void TIM4_IRQHandler(void)
    " N5 E* ?& ~( ^* P- S: i
  57. {
    , G1 b, m5 _( d6 u6 E* m
  58.     if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE))                        // 更新中断标记被置位
    7 n4 G( w+ `* F/ {0 |  r3 |
  59.     {7 [: V: `2 w& k* Q; M9 q
  60.         __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE);                // 清除中断标记
    # @" P: Y9 ]. o! d- J
  61.         prvvTIMERExpiredISR();                                                                // 通知modbus3.5个字符等待时间到
    9 `" G" W- p, {
  62.     }
    . V. Q: S4 p+ H5 @, C* J$ e! c
  63. }4 v% E7 A3 e; E

  64. ( N, _" W3 J& R/ I' N+ S0 I) x* o
  65. $ Z1 R: [8 W" q* Y' ^% w5 Y  P
复制代码
) [! v/ q$ E  g
修改modbus串口初始化源代码portserial.c文件
% f9 g3 d* p8 M5 p, q         ~~~~~~~~        在该文件中实现串口1的中断服务程序,prvvUARTTxReadyISR和prvvUARTRxISR函数需要填写进中断服务程序,前者得到作用为通知modbus协议栈串口已经空闲可以发送数据了,后者的作用为通知modbus串口1有数据到达,修改后的代码如下:8 u! z- Q% I$ T# [
: c3 m1 V) l* v
  1. /*. ^  A* }! J  {! Y. G9 t
  2. * FreeModbus Libary: BARE Port
    * Y2 _( w9 G# ^* h3 W( q$ M
  3. * Copyright (C) 2006 Christian Walter <<a href="mailto:wolti@sil.at">wolti@sil.at</a>>
    : n) f$ m6 w9 Q& z4 V7 x
  4. *
    8 d; V- q# n, c
  5. * This library is free software; you can redistribute it and/or6 F, P. P- P2 m( @' C
  6. * modify it under the terms of the GNU Lesser General Public5 w; f& C: F! w3 [! p: o  P6 g* ~
  7. * License as published by the Free Software Foundation; either
    % y5 u1 v, n/ l) I( y$ V3 s
  8. * version 2.1 of the License, or (at your option) any later version.% \- o' y9 S1 T# g) {0 Y
  9. *; `, {8 M" Z9 J/ X
  10. * This library is distributed in the hope that it will be useful,! ~1 d  Z( D  c% c
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
    0 G+ e1 K9 k/ e% M! z) Q) A; d
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    9 K! S( C5 L6 T0 h/ D
  13. * Lesser General Public License for more details.: d  D' t! i* B2 L; M
  14. *, ~3 ?4 K& R( m- T. [
  15. * You should have received a copy of the GNU Lesser General Public9 }6 M: L) m7 e, ^
  16. * License along with this library; if not, write to the Free Software3 w7 E2 A9 g& Q- U) L0 }+ F' `
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    / o! N; f& b; Q1 Z* |/ P
  18. *: c* {" ?5 q& }2 c( k
  19. * File: $Id$
    0 Y1 U/ Q0 b. ~
  20. */
      o, Q" h2 z! `9 _5 x9 K7 y
  21. ' k) g9 n/ p, B9 \. m! K1 i! V
  22. #include "port.h"" y: Y) }  ~: q9 V8 b# W0 K
  23. #include "usart.h"- b4 w6 Q% l& e$ d6 K

  24. * _8 P% ]0 G' o$ o# \
  25. /* ----------------------- Modbus includes ----------------------------------*/1 @$ K- }' Z0 z# u* }6 B- i) ~
  26. #include "mb.h"! O. U- l# x0 i2 }4 z
  27. #include "mbport.h"4 X% ^+ E3 ^( D% |% e3 l6 {
  28. 4 c$ C* C' p3 M! \+ o
  29. /* ----------------------- static functions ---------------------------------*/
    + U3 T. o1 D9 I; o5 U
  30. static void prvvUARTTxReadyISR( void );
    % N- L) D- }1 N3 d0 F2 i" d, e
  31. static void prvvUARTRxISR( void );. g) R. f3 }: _0 [

  32. : o0 e0 _" c( m
  33. /* ----------------------- Start implementation -----------------------------*/
    % w0 j+ w& K/ x0 U, X0 i, [
  34. void7 P* t6 h2 E5 B! \. x0 |& ^5 A
  35. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )  _9 Z( X) E5 v. i
  36. {
    8 _7 a# G  Y! d- d
  37.     if(xRxEnable)
    1 {+ Z- z, n4 d' w7 H+ M' c
  38.     {* Z$ q1 V/ W6 y
  39.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断6 f1 k* r  p) R" M8 N3 k# [, U
  40.     }
      K9 z8 F; D# p  ^& F7 w( d% V; R
  41.     else
    ) l1 V  t1 [* o" V/ j: N4 d
  42.     {
    9 V' t& N  V$ \6 L
  43.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断
    ' l) y9 t! J' w, E5 }- `1 u. [3 D
  44.     }! Q  J1 c+ v2 C$ t( i

  45. / E$ L; c9 l8 K9 C: D  e
  46.     if(xTxEnable)
    / Y$ w1 C% ?: a/ J7 V9 k4 `6 Y
  47.     {( [% `, k$ Z9 J5 z  l' a$ N
  48.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断
    . U: o, t) |/ C0 _1 R+ K% X" u9 _/ Y
  49.     }
    " y2 b( a$ k0 {& l0 n1 Q8 K
  50.     else
    ' I, i8 N2 S, V! Y8 {' O/ p2 ?
  51.     {
    * K" k0 S6 T" E! P
  52.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断
    $ S5 _2 R4 \# f  Z
  53.     }
    , j9 B  n0 g8 V, _6 v0 L) X# i+ @
  54. }, U1 n3 E/ Q- t" }. s2 b

  55. & |2 Q3 g5 A, B2 l
  56. BOOL- j6 X) f+ f# R% Z2 S3 a+ K9 R1 R! `
  57. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )/ z, U+ o' p9 W7 _
  58. {
    * @! D2 B7 x) C, ]/ g
  59.     huart1.Instance = USART1;
    ( D; _* M* H0 {! F
  60.     huart1.Init.BaudRate = ulBaudRate;( R4 o) g# K* W
  61.     huart1.Init.StopBits = UART_STOPBITS_1;
    * M; o) ]* Z) {" f: m
  62.     huart1.Init.Mode = UART_MODE_TX_RX;
    5 e# _) g; r; _' s. o( l) o$ l/ P
  63.     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    4 K. x8 U5 C8 l
  64.     huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    , ~- S$ E$ Y$ V
  65. ) L  V+ x- ]# Q- Z% \, H% a7 x4 J
  66.     switch(eParity)
    5 t6 G4 u8 N- `: P
  67.     {
    4 ^9 _: K6 J  b( P3 P, Q. @: E
  68.         // 奇校验
    * ?' o( [4 ?- j4 C
  69.     case MB_PAR_ODD:' \/ u2 S+ R# [9 O. d) f! @; a
  70.         huart1.Init.Parity = UART_PARITY_ODD;
    0 t$ V9 i0 M( ]9 d* Q3 z; ]. M" }/ d& l
  71.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits
    # d0 X3 A( m2 n  e
  72.         break;/ B5 b* ]6 {4 l+ `1 j
  73.         3 n5 C' f, M8 ]7 H! r3 p3 L( F
  74.         // 偶校验
    ) M+ z: B' V# I) j) T& T4 K/ E
  75.     case MB_PAR_EVEN:: s5 p+ K! X* q- }
  76.         huart1.Init.Parity = UART_PARITY_EVEN;+ c5 X; c! Z* f+ h' _" T) n3 u
  77.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits
    ; g+ c! d3 M3 @6 H# I) |
  78.         break;
    & W! {9 q3 z# |4 i) w7 c: j
  79.         ' Q& N/ M* I2 o8 A0 c* o
  80.         // 无校验
    " d' J+ L# H: r" K, ~
  81.     default:
    ) n1 s* n% ^" D3 P4 `
  82.         huart1.Init.Parity = UART_PARITY_NONE;
    - q9 b1 n! ]4 D! T
  83.         huart1.Init.WordLength = UART_WORDLENGTH_8B;                        // 无奇偶校验数据位为8bits
    ' y3 [/ }3 e, c" `4 ]% k
  84.         break;  b. }/ A" a% t' I+ G
  85.     }8 y1 L% [/ u3 z& M. s( S
  86.     return HAL_UART_Init(&huart1) == HAL_OK ? TRUE : FALSE;2 H- _2 ^4 p9 U8 W
  87. }* X; s) t1 c8 W6 k9 M0 e5 U" ~

  88. 5 X9 b9 t# n' y" k
  89. BOOL
    1 d" {5 z: L0 W& ?
  90. xMBPortSerialPutByte( CHAR ucByte )
    / K4 i* D0 ^! I0 }% p4 E
  91. {! i9 Y; C5 I" g8 m/ \& V" a
  92.     USART1->DR = ucByte;
    1 P5 _4 x+ E- n* k# ^8 P
  93.     return TRUE;
    + O0 n5 B& s8 A$ @( n9 i# m
  94. }/ R" e! z8 l' j1 k8 U( l' s

  95. ( Y1 b# `/ _# [6 t5 i! k, k
  96. BOOL0 ?. T9 `2 l. g9 |( a: X1 a
  97. xMBPortSerialGetByte( CHAR * pucByte )- N3 |+ @& p- A/ l9 h
  98. {
    - B* t' V3 V$ Q3 [  e( @* A
  99.     *pucByte = (USART1->DR & (uint16_t)0x00FF);, j- b' q" H/ q7 T* k% h
  100.         return TRUE;
    ! `2 z0 b+ a5 f4 a
  101. }% p+ f( ?  [( N6 l: A, z+ k" O
  102. / o# F1 w$ q. h1 K
  103. /* Create an interrupt handler for the transmit buffer empty interrupt/ x- k1 z( S6 Z
  104. * (or an equivalent) for your target processor. This function should then) }3 D& ^1 B- }6 X
  105. * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that5 A% L. M2 v0 a$ x7 l" S
  106. * a new character can be sent. The protocol stack will then call
    ' ~5 e. \( K3 D! r
  107. * xMBPortSerialPutByte( ) to send the character.
    $ P: K3 V6 p# p+ {
  108. */
    9 S% X; n/ G+ f7 h# K
  109. static void prvvUARTTxReadyISR( void )
    9 R+ P/ h( @0 u6 |: J8 g; v6 k& h
  110. {7 j3 H3 U; G$ D  }1 _% L
  111.     pxMBFrameCBTransmitterEmpty(  );" x5 s1 K) B9 t5 Q
  112. }3 r1 X% s% U( g
  113. : a  ~8 @" E1 Y# H( K4 h
  114. /* Create an interrupt handler for the receive interrupt for your target
    $ G* |3 {2 c8 X& |1 c% N7 a
  115. * processor. This function should then call pxMBFrameCBByteReceived( ). The5 A( b1 p; `# z1 b7 [
  116. * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
    1 H/ W5 {' U# ~5 `' M  [
  117. * character.
    . V  y0 @6 A  @6 g+ v  m! [) T
  118. */
    4 \2 l+ G' Y- q& l$ x# v1 X7 E
  119. static void prvvUARTRxISR( void )9 i/ p1 N! F+ E" m1 f' t! o. T
  120. {
    & q+ ]& ^# F( o8 `1 m
  121.     pxMBFrameCBByteReceived(  );
    & d* p3 a. J/ b0 g' C6 z; K
  122. }7 s  [& G8 t( V6 N
  123. ( Z( u& L( L' m/ A1 N
  124. void USART1_IRQHandler(void)( C" j" V3 B9 Q- G
  125. {
    ! i' m( \4 m0 n7 @6 E' ?6 {
  126.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))                        // 接收非空中断标记被置位) R3 c( @% l4 e6 T% |5 M0 G2 N
  127.     {4 [5 i* s; @4 W3 n- A
  128.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);                        // 清除中断标记
    5 Z1 |3 u0 N/ W+ P5 ~3 v
  129.         prvvUARTRxISR();                                                                                // 通知modbus有数据到达
    ( O8 X8 R* ^% ~( r* D1 v4 H* a
  130.     }+ g8 t/ ~! P/ n) \

  131. 2 [* z- V* }: \0 n0 z; h
  132.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE))                                // 发送为空中断标记被置位& z8 N! N- j( L4 k* O: |. J
  133.     {
    % @5 z9 `  L3 d9 ~( M( w, Z# O
  134.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TXE);                        // 清除中断标记
    ; y! a  |5 }, R2 c4 S" W" K
  135.         prvvUARTTxReadyISR();                                                                        // 通知modbus数据可以发松
    " Q8 w4 Z' L* t# s$ u
  136.     }4 f& S" D8 {* O
  137. }
复制代码
% D* r9 B( ~8 F  @8 A1 S+ H
注意一点,一般如果使用了485芯片的话,那么同一时刻只能接收或者发送,可以将函数vMBPortSerialEnable修改成这样:
+ l. s$ F. j2 ?4 ]
2 Y5 e* a9 e) v  Q1 l- A" V2 q2 M
  1. void
    $ u+ G- i6 z. e4 e. R& c
  2. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )7 e7 R* {1 P& c9 p  p. \
  3. {
    3 s) u# M  ~/ i& G' S* u& _0 V
  4.     if(xRxEnable)/ Q$ @$ N( J9 @2 R1 e5 _
  5.     {
    & f; o1 B1 r3 m: a+ M
  6.             //
    6 p  Z+ e0 l; V
  7.         // 在此处将485芯片设置为接收模式
    7 u& g: N  u6 r+ W, w. o' J/ Z
  8.         //
    0 y/ L' N) Z3 L6 ~
  9.                 /* do something */9 V: x! H! t  e
  10.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断) q: \9 ]& {+ C7 X1 ?  o8 h/ T# U
  11.     }: d% _5 V, |9 k+ i( _
  12.     else' I, v% B' H; b0 w0 G- P4 ?( @
  13.     {
    ; u/ b- B0 P) S0 S  A. l/ R, @
  14.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断* Z! H2 S/ t4 m5 I. ~: I
  15.     }0 Q# e! M0 `9 \8 V
  16. : p* z& j7 E0 _% l
  17.     if(xTxEnable)6 v; Y" v: @$ ?; X1 G! f, D
  18.     {
    ' |- ?5 x4 G" q
  19.             //% h" m% D' C- }( t2 x. `+ {8 o  G0 [2 f
  20.         // 在此处将485芯片设置为发送模式
    2 D& D6 N# T6 i# Z# m
  21.         //
    - z0 J" B" G9 a- J
  22.         /* do something */
    & [1 O: G0 G; @1 L" D9 m
  23.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断
    + d" l$ D* P- i
  24.     }* D: `/ l: O: E- e% g
  25.     else
    / \! y( f* b* {+ Q2 L+ z
  26.     {
    # k% |  A; A2 M; @! G
  27.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断5 q& ?3 W: l9 o% f5 H
  28.     }
    9 U+ ]( G& X* s- y9 ~7 b: ?8 O
  29. }
复制代码
$ b7 Y% s- p7 g" l& [$ ]$ @0 A5 h) J
编写modbus命令处理回调函数port.c文件# r& B* X# D8 V1 E9 C# M
本例程只实现了读取输入寄存器和保持寄存器的功能,详细代码如下:
* `. S! m' k" \. p/ ~. L: t

5 L8 d* D7 M9 j: f+ j; `
  1. #include "mb.h"
    ' B5 J4 j! A. z! C/ f7 w! V
  2. #include "mbport.h"" g- r5 @- _9 j# p% ?- r

  3. % L$ C7 B! F' t- w1 ?* y. [0 ~
  4. ! c, b2 y+ F7 x7 Z- I
  5. // 十路输入寄存器0 ~" w# P7 `( N7 f2 ^% p7 @8 M+ N7 p
  6. #define REG_INPUT_SIZE  10
    0 V- d* s" y; w1 p- u
  7. uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];8 o( V7 z- y- q9 C/ l

  8. 9 `' v2 \1 y: ^" m- p/ _

  9. ' r* U0 i9 p: |
  10. // 十路保持寄存器
    8 i( H2 N- W2 A; S
  11. #define REG_HOLD_SIZE   10
    & m& ~3 `0 E1 s" K$ m! |% J
  12. uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];* C/ y/ Q* W) |) e% n  s2 L8 r. ?
  13.   c9 b! J- m; H* j# c
  14. # O- o( ]+ V% I6 J2 Z) q9 d
  15. // 十路线圈
    " V4 A1 @9 r6 {
  16. #define REG_COILS_SIZE 10
      O5 I+ K' N/ y* R
  17. uint8_t REG_COILS_BUF[REG_COILS_SIZE];+ @2 G8 P6 w$ Y8 R4 a
  18.   c* \; S- y  y4 y0 X/ w
  19. ) N$ x; e5 V) [1 W* v. w
  20. // 十路离散量) S  A- |2 c$ k# y6 P" s
  21. #define REG_DISC_SIZE  10
    / W& Q' ]9 B& c& w  W
  22. uint8_t REG_DISC_BUF[10];
    $ z3 |- e) o* e
  23. " o7 g) ~8 O5 s* V1 [  M& u1 I

  24. - R* S% _5 p4 K1 X; {& d% B8 H
  25. /// CMD4
    2 \/ V/ q7 _( F2 i
  26. eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
    8 X1 U) x- X' ~/ J! T  U6 M
  27. {
    : y8 j  r- t' M; y5 Q7 R% d' q
  28.     USHORT usRegIndex = usAddress - 1; + n% i) N) z7 M- B4 ?

  29. 7 a% s0 T# ]! L$ }( K
  30.     // 非法检测1 m! z- K& |% Y. z0 d* g% R/ j
  31.     if((usRegIndex + usNRegs) > REG_INPUT_SIZE)4 o0 b5 S8 @5 h3 w( r$ W! Y1 }* ]$ E
  32.     {
    8 n# i; d. X$ n" u" t
  33.         return MB_ENOREG;' i, A. v! \0 W- P1 @( W. b4 W
  34.     }- P" |- E3 Y6 J5 T8 E# ]9 A0 Q

  35. 6 D' c/ t$ ^9 c/ I1 r: r
  36.     // 循环读取0 x9 n7 b+ P$ ^
  37.     while( usNRegs > 0 )
    , M6 _& @6 d; N
  38.     {9 s2 z' Y) i) a2 s; s* P" L
  39.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 );
    2 `! g; v7 A% v# s. \) X9 t* o& x
  40.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );* l# o! `9 z4 R6 m& H
  41.         usRegIndex++;1 C. Y1 m; v" g. K+ A$ m
  42.         usNRegs--;
    : x! S  f8 T* l8 |# ]' k% r, {
  43.     }( y8 Y: C1 J' d/ M: u8 M8 h! ]
  44. 2 ~1 H5 \3 L! E6 j
  45.     // 模拟输入寄存器被改变
    & ]3 C, Y$ K4 B. X* o$ g
  46.     for(usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++)
    1 O/ C" o, R, }+ t
  47.     {
    * n8 @: K0 A( J7 e' @
  48.         REG_INPUT_BUF[usRegIndex]++;7 h- R7 h2 c0 ]! a9 T
  49.     }& ~$ x% U6 }) c- c
  50. ! E2 s9 r) i: ?
  51.     return MB_ENOERR;
      v8 {5 |- R" l& G
  52. }% {5 v0 x' {. i

  53. ) B; _0 u% J/ j( L6 R
  54. /// CMD6、3、16
    6 n- _/ t, O2 v
  55. eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )' I9 r2 G+ z- h1 r
  56. {
    6 v  K# d1 ^- F) U  u
  57.     USHORT usRegIndex = usAddress - 1;  ) C: Y) F3 L7 D8 T. {

  58. ) L5 ]( V, m: W5 b" ]& D
  59.     // 非法检测
    ! V5 o7 d: O. h+ h/ y; j; I. s
  60.     if((usRegIndex + usNRegs) > REG_HOLD_SIZE)
    ; D( S* j0 M. W
  61.     {
    . \' [- F6 p: u' F1 {# n
  62.         return MB_ENOREG;
    4 u; l9 G8 F% r1 L  H" W# b
  63.     }
    / w. k+ E' m, o, q

  64. ! n  C6 y! o" m
  65.         // 写寄存器
    7 j  V) |8 R& Y5 ?0 T
  66.     if(eMode == MB_REG_WRITE)5 b; q/ t5 T. X7 P
  67.     {( Y$ ^, o( g+ [8 W7 O& u0 D
  68.         while( usNRegs > 0 )
    - P& _* G, u3 J0 C. i6 i3 k1 S6 V
  69.         {
    * S) n5 {2 x5 O- u
  70.                         REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];
    ) Y( e  l( O$ e7 \% Q
  71.                         pucRegBuffer += 2;
    1 {" O  ?4 d& r
  72.             usRegIndex++;% a9 t2 C. Q" C' h
  73.             usNRegs--;# _' f1 Q7 u- I1 u
  74.         }9 u' K, V) w) W  [# T2 |% V) ]
  75.     }
    0 f* D$ e1 v$ t& M9 ^% y
  76.         
    4 m9 l. Q0 G  a6 U
  77.         // 读寄存器
    . r' Y  h4 b. v; Y' f# n8 v0 Q
  78.     else: a3 L( e) f" V5 c& D  I
  79.     {
    ( Q3 M& J, T- V
  80.         while( usNRegs > 0 )
    9 |+ X9 D1 K8 D! r% [7 p, @
  81.         {
    2 L( o& H' O' M
  82.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );
    ! G- b/ U5 c, I5 p, r6 A! w0 x5 B) g
  83.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );
    $ a- t& I9 t% B  }2 j: C
  84.             usRegIndex++;
    6 {* T( f1 `1 t( R+ w- D9 y  d
  85.             usNRegs--;
    ; F/ B4 p6 _" E8 C
  86.         }' J& U- P. f. J# u
  87.     }7 b# y7 k# l; S! x5 Y
  88. 6 |, \- ^. @8 ?+ }4 [
  89.     return MB_ENOERR;7 v8 d9 A  M! K; h( l9 [
  90. }  C- x9 W' N6 i% J) f% f

  91. # _7 d5 j9 Q0 d2 |6 B  u# U
  92. /// CMD1、5、15
    + F! i: z7 |) h+ P) E. d# w9 z
  93. eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
    % M2 f3 i6 e$ N  y4 M  G5 k: ~6 g
  94. {/ U$ }7 R" x1 x2 A- @% E4 ^# ]
  95.     USHORT usRegIndex   = usAddress - 1;9 u. y* W4 {. \/ N3 o- z* L* @5 X
  96.     USHORT usCoilGroups = ((usNCoils - 1) / 8 + 1);; e8 z' ?2 r& _; R7 }* W6 L" R
  97.     UCHAR  ucStatus     = 0;
    6 |+ y2 C* _: @- @6 F  Y1 O: l
  98.     UCHAR  ucBits       = 0;
    2 F$ @7 f! j9 Z6 c
  99.     UCHAR  ucDisp       = 0;+ J5 H$ G; c4 [' X& B2 o

  100. ; \. [8 f3 }0 V& @1 s
  101.     // 非法检测
    * a/ d: o5 \0 X- }. M2 t" T. J% R( U4 `9 `
  102.     if((usRegIndex + usNCoils) > REG_COILS_SIZE)* L; N( R" s' W3 G. f9 w
  103.     {
    ; m. a' V4 F/ l: j1 V8 ?
  104.         return MB_ENOREG;8 G) ~. T2 R. o* [
  105.     }3 D' M0 F3 i3 r  ]# Q
  106. . X8 A& |  p: Q0 C: C( x2 n* ]
  107.     // 写线圈
    7 u9 o1 L; r: F! s. K7 e- _8 X8 K
  108.     if(eMode == MB_REG_WRITE)1 q, D+ Q4 o9 O- N7 _
  109.     {
    & d. J0 C8 `4 l7 ?( w5 m
  110.         while(usCoilGroups--)
    ; a; [: c4 F3 O2 [% E' n0 Z# V# T* V
  111.         {1 Z6 o" B+ P$ D5 v9 x% g
  112.             ucStatus = *pucRegBuffer++;5 e/ c  h" V/ e" E8 _
  113.             ucBits   = 8;* h6 V  v# J! A6 p' r
  114.             while((usNCoils--) != 0 && (ucBits--) != 0)0 F3 w7 g$ l/ p+ @
  115.             {$ g! S$ i% I+ f$ o  a9 E% @
  116.                 REG_COILS_BUF[usRegIndex++] = ucStatus & 0X01;
    ( ~1 e: v* F6 x* G, j* K8 Z4 ^
  117.                 ucStatus >>= 1;: X2 a1 i6 M! Z, E, l
  118.             }, W8 U9 w4 D7 I: W7 U8 V4 P) z' {
  119.         }
    9 o! [' M+ D/ T$ D2 D) Q% A
  120.     }
    5 w8 Z6 }2 g8 m5 m4 }
  121. % e" U: F# Q: b/ S1 G( o8 e0 A
  122.     // 读线圈9 [# J8 @  g4 I
  123.     else
    ' Q1 [6 [0 ^/ q) c! S
  124.     {  g! j% B  N4 r0 m* @6 I, B7 z! u; j
  125.         while(usCoilGroups--)/ v# M( @: q! I  d5 e
  126.         {& P' j0 T+ _; m7 C
  127.             ucDisp = 0;5 d- a& s# l$ l; o  c( Z
  128.             ucBits = 8;
    0 x  k% z* [4 {0 }3 q
  129.             while((usNCoils--) != 0 && (ucBits--) != 0)
    0 V' O0 K$ t( b
  130.             {
    ! G7 d1 K5 P) G5 o3 _2 M
  131.                 ucStatus |= (REG_COILS_BUF[usRegIndex++] << (ucDisp++));6 u7 E' @' X- O# k8 H5 ~+ e, ^
  132.             }
    + k# w6 R4 |% c- h& o
  133.             *pucRegBuffer++ = ucStatus;
    " X7 q$ i" g: a/ x! F# h
  134.         }
    - z' I7 e6 e) M1 ~
  135.     }1 Y" T2 o( a1 q/ z
  136.     return MB_ENOERR;
    # i1 {4 f5 J/ r
  137. }
    * f" t+ K  H6 B
  138. & f+ g6 f" s4 G( z$ ]2 C$ n
  139. - p# ]0 t6 `2 k' ?, Z, D
  140. /// CMD4
    % a3 U$ }, l# K
  141. eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )8 i; |* {7 C% R! m- X  d
  142. {' {9 x4 m, _8 u3 m2 S" c
  143.     USHORT usRegIndex   = usAddress - 1;2 b5 K, N" O/ C7 c6 G# d. x
  144.     USHORT usCoilGroups = ((usNDiscrete - 1) / 8 + 1);/ O6 ~- q6 g2 g9 t$ L' n# [7 k
  145.     UCHAR  ucStatus     = 0;4 R2 k  P6 w+ g6 M0 F2 X
  146.     UCHAR  ucBits       = 0;
    % P3 v: [4 q6 ~9 {: V$ d2 u
  147.     UCHAR  ucDisp       = 0;& q- F' o' s: n9 I. ?' I" s
  148. 1 U, [. Z; m" o& u$ Q9 V
  149.     // 非法检测( N! V- o" |- {7 W6 Z1 b) _2 `$ H
  150.     if((usRegIndex + usNDiscrete) > REG_DISC_SIZE)
    / a7 {" G/ _1 C
  151.     {1 K4 ^' }  y) u5 L" P9 Z5 h8 Y5 ?
  152.         return MB_ENOREG;
    8 Z2 r  [  ]9 Y
  153.     }1 B6 H+ f, T2 ~8 f  e# n7 c# N
  154. ! e* e  @( F. S+ [: U! b- s. s- [
  155.         // 读离散输入
    . j7 {& g+ E  U/ R( u1 \: n
  156.         while(usCoilGroups--)+ B6 u" Z/ s- u" V
  157.         {
    5 U7 x9 k. [/ f; d, ~
  158.                 ucDisp = 0;9 ], o9 \* a1 `/ g
  159.                 ucBits = 8;# p' }" ^/ A. I3 b
  160.                 while((usNDiscrete--) != 0 && (ucBits--) != 0)
    + u( p5 I8 R* y, e6 A* W, ^
  161.                 {
    4 J7 [5 a; n3 t; R" A
  162.                         if(REG_DISC_BUF[usRegIndex])
      s* M) m4 ]# P% K  ?# o
  163.                         {$ I( i+ B) w7 I8 k) X
  164.                                 ucStatus |= (1 << ucDisp);
    : M1 A! E9 V, n4 s' p
  165.                         }
    " t, J- n7 ?& p, a3 a& [; |( d: g
  166.                         ucDisp++;
    / ?  c8 ]/ N- F0 A% I/ p- H* l
  167.                 }
    , S" G) ^& S. L; D2 P6 q* J
  168.                 *pucRegBuffer++ = ucStatus;
    2 s4 d4 A8 r, w, N
  169.         }
    " `! T2 W# [  b# M" V

  170. ( D( ~5 h) `& d2 C" P
  171.     // 模拟改变
    1 }( X; Z$ `/ p+ a
  172.     for(usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++)
    : ?7 J- L0 R6 E/ v# @
  173.     {
    ( A5 O8 o3 h3 y2 F9 x
  174.         REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];
    ) b: k! x( ^+ v- g
  175.     }/ X7 S4 k0 \, t3 W: k
  176. . f0 J* K/ }  Z+ z, @
  177.     return MB_ENOERR;
    3 Y3 \! s/ B/ s" p
  178. }
复制代码

1 m8 P( t: c  z% i  j2 i主函数
5 J. z& {! o) p0 H, P
  1. int main(void)
    , h, q) ?& ?" l/ Z8 Q6 c
  2. {
    . j# F5 L; t7 G% w# ]# l
  3.     HAL_Init();$ M+ W2 ~/ V: x9 _% y% h
  4.     SystemClock_Config();
    5 |% w/ [' r' ?' O! b/ V  i8 ^% ?
  5.     MX_GPIO_Init();
    9 }2 J" g% E1 h" N6 t' _, L
  6.     eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_ODD);                // 初始化modbus为RTU方式,波特率9600,奇校验- B" T$ r" e& o0 K  w& ]+ _. J
  7.     eMBEnable();                                                                        // 使能modbus协议栈# }) |: m& f: k! g  s' F/ D
  8. : A) E0 E. S5 C7 h" ]% z( j
  9.     for( ;; )' u% S: I3 ~: D
  10.     {
    ( m# }  ]2 Y* }6 |+ t
  11.         eMBPoll();                                                                        // 轮训查询
    5 `# V3 s3 \3 b/ X* U6 P& R
  12.     }
    " ]' ]) J4 F' g  c6 g: w
  13. }
复制代码

! d7 a6 ?- o5 n* t2 b. N移植测试
  d. T, G% x2 d& m" s& \6 E7 C- y1 |8 {( V& R% ~9 a
20200313154857173.gif
  ~' s  C8 v: A4 T7 H
( ~+ J+ ]- E2 J5 P8 V5 H/ V! M$ }* bends…1 O% B$ E4 F1 ^( G1 u

' }. H" q6 k% n+ g5 n1 y# E
7 w2 d" S2 g0 c& C# E. Q4 ~: ?3 [# N# a( \/ t0 a6 W5 O) r
收藏 评论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 手机版