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

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

[复制链接]
STMCU小助手 发布时间:2022-4-10 22:53
modbus命令码表:
0 K: b5 D, v7 Q4 A7 a' k
: w) s) \, D- U. Z
b8032deb4d154657acd2f7f2942369d4.jpg
- H! Y6 U1 n2 C5 Q- J  _; [2 l
5 w, R4 r9 J& t, T! Y7 dFreeModbus文件说明
( t$ l" ]% h+ `# i
      解压freemodbus文件后打开,我们需要demo目录下的BARE,该目录下的代码是空的,STM32移植工作基本就是修改:portserial.c、porttimer.c、port.h这三个文件。7 v# I1 u7 l4 J$ I  U5 Z; D% B
20200313143257958.png
! z: d. B% v2 @9 E6 m) W6 b7 P" q0 _, s1 Q5 j% D5 z9 a( t6 u
      mobus文件夹就是完整的源码,包含rtu、ascii、tcp:
7 M- P' a0 I1 `
* D- |8 J# I- J/ c: j2 S; V ZM%DLXPRB8$%[NN2%4Z1N.png 7 g9 @; q4 I5 }1 o  {# x4 T
. j$ A$ g  L  F0 p% b( K
      我为了移植时在keil添加源文件和头文件方便,就把modbus所有的头文件和源文件放到了一个文件夹下,并创建了一个port.c文件,用于编写modbus所必需的回调处理函数:
; k8 v( R/ O# H% H; c- ^0 C% D7 W  a) z# n; [! I
20200313144036579.png
+ P: G! {; c. E; }6 Y0 U# a: F  b4 u2 L4 b
STM32CUBEMX配置

- }' E9 R$ ^5 v# ^. f时钟配置,设置主频工作在72MHz下:
5 O6 U! A# a) \

- @) u( k, p, F" u( r6 C JU1~N33M}I7K1(6K@JFN5~R.png
3 f, T/ V) _  a: k5 T
4 g8 ^/ J6 Z6 s7 A配置串口1,这里随便配置就行,在modbus移植过程中还会对串口重新初始化:
/ `; c0 C$ G1 F& I) B+ J  l

+ X7 ]# A( O! H% s U25OQ_FHYD5WEXLFMI4V@RU.png
* C: r; x( S6 d6 ?, u/ m* F! d: f; G( S6 D, U7 K
配置定时器4,用于3.5个字符的定时检测,这里随便配置就行,在modbus移植过程中还会对定时器重新初始化:
! C/ F4 s6 D( h; a

: q6 x  G9 q% e, I& I* C  x1 e0 o8 W H6{)WT`**CIHDAM02558GK.png
3 q3 U  I' i6 ^9 g/ d0 \! d% C" M
( f  w. Y0 ~0 F+ e中断配置,这里注意,串口的优先级是要比定时器优先高的:

0 J% l" W# M7 h+ k) X/ y3 f8 V  z2 [1 {/ s% c
G(RP`74TR)NPJFUK``Z%I2L.png / z6 L. D# v- y% b
取消掉自动生成中断服务程序,在移植过程中我们要自己编写串口和定时器的中断服务程序:6 {6 Y$ U$ ~* n, c& t; a2 n1 v
; w' N" v% C8 x) p" q
ALHMK5Y615K6(`M{0[]YJ.png
2 J& z4 W" z/ F. s% e( u1 l2 Z* G5 a9 J
移植代码修改
( r+ u% v0 U- n1 r  G3 z
生成代码后将modbus放到工程目录下:5 {6 H7 b  p6 V. _" h$ Y' Q' b8 j
: C1 d) b! k4 `" s% a) C; y' e* r
5%(_LMGIM_8_YGL`]JGAB67.png , e3 b1 ?; U" h1 I6 ]. H
0 x- h  `$ @: S8 C8 ^- o2 l' C5 W" i
打开keil工程添加modbus源码:

+ _' J, h/ q- f- l
  \5 q" e! q/ n0 L1 x F`8_YFACMNOAP28~2VHD{CO.png
& I2 S) o: s  o2 q2 y
- b+ W; q. m8 j1 {. d添加包含头文件:

8 U0 O" C. f1 y6 ~
9 K: m- r, B+ \1 p. o  j0 I `7BMVXA`R9SQBTGT`B@{]X7.png + I: d/ N- _# [" U% O6 R9 r  S
; l! W, f9 z# e  w
修改modbus定时器初始化源代码porttimer.c文件7 n  d5 a% D. v( P
       定时器的修改比较容易,将定时器设置为每50us的时长记一个数,传入的usTim1Timerout50us变量给自动装载即可,prvvTIMERExpiredISR函数需要在定时器中断服务函数中调用,它的作用是用于通知modbus协议栈3.5个字符的等待时间已经到达;由于我们在STM32CUBEMX中取消掉了定时器和串口的中断服务函数程序,所以我们在该文件中添加定时器的中断服务程序,修改后的代码如下:
9 E. \2 x& d6 o3 H2 Y  j3 a7 n% E3 W1 [! N
  1. BOOL
    , M2 D( q9 s. s& p8 D* H; B5 m
  2. xMBPortTimersInit( USHORT usTim1Timerout50us ); d) D% I9 p' \
  3. {6 a' U# |, V8 O( ^* W% O
  4.     TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    - Z4 u: T: ~, _- v2 F3 i
  5.     TIM_MasterConfigTypeDef sMasterConfig = {0};% e. {" Q$ Y6 e' e2 u

  6. $ t9 c- d8 ~! J9 Q
  7.     htim4.Instance = TIM4;) b9 [2 L1 T4 P* d4 n8 \/ ?
  8.     htim4.Init.Prescaler = 3599;                                                                // 50us记一次数
    ( Q: r( T9 [: N% w- i" }
  9.     htim4.Init.CounterMode = TIM_COUNTERMODE_UP;$ v8 m. M* T6 A+ `: K# k2 H' z
  10.     htim4.Init.Period = usTim1Timerout50us - 1;                                        // usTim1Timerout50us * 50即为定时器溢出时间
      `0 A! U6 S9 |4 w: u' r; e9 m
  11.     htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    % `; q' E- d( N1 \: |
  12.     htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;  _" m* b& Q8 `* W& Q
  13.     if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
    , E$ u9 ]2 s& d
  14.     {
    & h7 k  d0 ~+ Y
  15.         return FALSE;- k2 I; j3 p7 f/ \5 Q$ @- f0 \
  16.     }5 F( k( R7 F- \% c, ^; q
  17.     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    : k7 _6 u# o! F
  18.     if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)! M9 @2 L2 w5 Y7 Z& {6 R8 x+ R
  19.     {
    : z6 V) [  s3 u' M! S3 E$ R
  20.         return FALSE;9 _4 P- T1 h4 u/ D
  21.     }
    - |% F9 n0 ?# @
  22.     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;- g# b7 W9 Q3 l0 U1 i* `! q/ W8 V
  23.     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;5 X% a% `$ a, E+ `
  24.     if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
    2 e6 O1 i9 c: i
  25.     {- s3 W1 }8 v* H  _* p  z% J' a
  26.         return FALSE;* s5 K) G( Z  B
  27.     }& g4 C2 x* ]7 W, n* E) @: x
  28. , a2 E5 `1 H) }+ e3 O0 N# L
  29.     __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE);                                        // 使能定时器更新中断
    & w4 v; Q# B" r9 J: z3 y
  30.     return TRUE;
    $ ^6 e% r8 p/ M! e# g- M
  31. }
    . V2 T) \# y" t4 q

  32. - d8 M4 U# v/ Y- P9 O6 A. O& l* I
  33. inline void3 \; G. E" X5 R. r0 S8 R
  34. vMBPortTimersEnable(  )8 N( n( j, b/ u
  35. {! ^! P8 e+ b5 {7 f. ~) U4 A8 G' Q
  36.     __HAL_TIM_SET_COUNTER(&htim4, 0);                // 清空计数器+ G" h" E7 W, h8 y
  37.     __HAL_TIM_ENABLE(&htim4);                                // 使能定时器
    . d! Q1 k1 G" f# D4 a. y8 P1 b
  38. }( `& g6 h, O7 P: U7 I! P" w

  39. 7 p. {5 J0 ?" ]: n, I
  40. inline void
    $ V) G+ A1 h+ a* d
  41. vMBPortTimersDisable(  )/ G# T# B  W$ e3 X1 E
  42. {
    & N/ z' w1 l, G
  43.     __HAL_TIM_DISABLE(&htim4);                                // 禁能定时器
    ! @7 t3 q" u' K; l0 m) ~0 k0 G
  44. }
    7 j  v( n9 g: V
  45. * k7 M. y! a% A( ^8 C' U( d
  46. /* Create an ISR which is called whenever the timer has expired. This function
    2 A  S4 x- Z. w3 N, A, t5 u
  47. * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that# m6 D( t* j9 A' X3 U
  48. * the timer has expired.
    & M, Q  u2 b& |) _; r
  49. */$ C4 i; s8 d6 P% {2 a. Y
  50. static void prvvTIMERExpiredISR( void )  z# g! r- R8 z# {: Y- `
  51. {- O1 v, R! U+ b' ~6 j
  52.     ( void )pxMBPortCBTimerExpired(  );# N4 g- {+ J& {  M$ O" Y
  53. }
    $ w5 A7 X9 n9 r; K1 m7 N+ E$ D- E

  54. # L6 v$ s! ^3 H% t' q: D, C+ }
  55. /// 定时器4中断服务程序
    , F8 S3 `, `' p1 i* H- E" v
  56. void TIM4_IRQHandler(void)
    9 X$ w0 f& A  U  v0 y: v% H* n
  57. {2 ]) `7 f% Y" P9 g6 r2 W# {
  58.     if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE))                        // 更新中断标记被置位
    + [9 f% t4 B! D* @# z1 Y2 l
  59.     {  N& |1 G/ n7 z7 I& c
  60.         __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE);                // 清除中断标记
    4 r5 K, o8 l3 W/ S3 y! [. X4 i
  61.         prvvTIMERExpiredISR();                                                                // 通知modbus3.5个字符等待时间到% Y7 N* W! s7 q% V: W
  62.     }
    - j9 w0 w4 g; p8 ~8 B6 a7 C+ D$ g
  63. }
    4 F2 y* C# y$ R3 p' u# H1 N
  64. 4 n- y, y0 B: c9 s$ ]% O
  65. ) E  H* @: v( F- Y- M
复制代码

- F! n7 X9 h. x1 F  H$ t7 y6 I修改modbus串口初始化源代码portserial.c文件! Z- V9 f. m6 N3 t
         ~~~~~~~~        在该文件中实现串口1的中断服务程序,prvvUARTTxReadyISR和prvvUARTRxISR函数需要填写进中断服务程序,前者得到作用为通知modbus协议栈串口已经空闲可以发送数据了,后者的作用为通知modbus串口1有数据到达,修改后的代码如下:
& V% y6 k- J% B
5 V, a4 b" @3 o( ^
  1. /*% }, n8 ^' w( a
  2. * FreeModbus Libary: BARE Port
    % K$ \; Z# J  r; }2 @. u
  3. * Copyright (C) 2006 Christian Walter <<a href="mailto:wolti@sil.at">wolti@sil.at</a>>$ M6 V! b) ?. e3 D, }
  4. *8 V$ }4 E4 h& E
  5. * This library is free software; you can redistribute it and/or
    4 q) E6 M7 G$ m" ^, u
  6. * modify it under the terms of the GNU Lesser General Public
    9 a* W9 h* s# ?4 X; Z
  7. * License as published by the Free Software Foundation; either, k% Y" X$ W1 r) Y) A
  8. * version 2.1 of the License, or (at your option) any later version.
    $ z" [7 W" w7 e6 ~/ N( {
  9. *2 g5 L: c5 F( A& L
  10. * This library is distributed in the hope that it will be useful,- [) N. _$ m3 Q
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of5 {, Q, ?! @6 p" h" |' r+ _0 j6 K5 E
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      }% D" o, v. X9 R
  13. * Lesser General Public License for more details.* k0 g8 l" O; O" l
  14. *, Q1 t0 ]0 o8 {! w+ X3 k
  15. * You should have received a copy of the GNU Lesser General Public
    . c8 g6 ]' z6 Z# ?; p$ R
  16. * License along with this library; if not, write to the Free Software
    ' E1 T' M& V% c; X/ ~; V$ W
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA) B8 ^  N# o8 v' v# ?
  18. *
    7 E" v& F) ^, D8 Q) ]  G
  19. * File: $Id$. r; O- r4 b9 Z$ ]3 y! @
  20. */) M9 z; w2 n1 U; S6 X
  21. 0 |, x% u& b5 D1 J
  22. #include "port.h"
    3 u$ B( W: H& U) t; T1 ~+ i1 X$ V
  23. #include "usart.h"* o* D+ r* Z2 I! I$ P- e

  24. $ N8 f4 B$ l* e' `, z. @' o* h- k0 K5 R
  25. /* ----------------------- Modbus includes ----------------------------------*/) R, T4 C( g, K- ~
  26. #include "mb.h"
    % b9 p2 x0 T+ V9 l
  27. #include "mbport.h"
    , h2 q$ `. ?+ P* @& G

  28. , M3 U# X" f$ E6 J9 L/ V6 o
  29. /* ----------------------- static functions ---------------------------------*/
    * j/ d& J1 c4 a( ?1 E7 {- Y
  30. static void prvvUARTTxReadyISR( void );
    : o: _0 }0 T! F' B
  31. static void prvvUARTRxISR( void );
    . n/ S$ I- K  K) v: @4 Q
  32. ' J$ _. i$ y% U( l- h8 @
  33. /* ----------------------- Start implementation -----------------------------*/. I. B: Q+ g0 h7 a' P
  34. void$ V1 t+ P) ?3 S. E5 T% N
  35. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )  e- N0 [0 y+ q' z8 X" Q" ?9 ~
  36. {
    ; |  y) O" G0 q0 N0 o1 q( q4 O* T
  37.     if(xRxEnable)6 |/ X" C* j; c; I/ ~" @, |. [
  38.     {- q" s2 L; B, P
  39.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断
    - k- O$ J% w& R  U
  40.     }
    ( [' k$ D3 F/ S; M
  41.     else
    ( v# I$ m' i; K1 U% c. I
  42.     {. Q6 C! q* t! a+ j0 [8 `! a
  43.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断
    0 M, t* j# A1 H9 E' o$ e; H
  44.     }( y& r/ a+ E% v) w: e: x' o0 s- l

  45. 1 x( y, Y% {. v- A
  46.     if(xTxEnable)
    8 A: ]$ g9 a$ h( e
  47.     {! s* @& P6 R" r$ U9 H- x
  48.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断- l$ b1 J0 X* v! E
  49.     }
    5 f8 b) V0 Q7 S  w, E
  50.     else
    ' P$ i) R: Q5 b/ O$ w
  51.     {6 r4 \# d' j" q" L
  52.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断* F& n5 @8 E4 Y* z# C
  53.     }
    7 n- u6 `4 Q8 X3 Z
  54. }( X6 Z1 U$ H3 f. g) X

  55. 9 `, Z6 \8 j4 z( R
  56. BOOL3 V* s+ ^1 A* F! x+ i6 _$ V
  57. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
    7 @! `" Y& u+ v0 S- u: m4 k: n$ V
  58. {* U8 W3 M$ A+ j% R* x
  59.     huart1.Instance = USART1;
    . s% {4 i, M4 Z' ?+ [" L
  60.     huart1.Init.BaudRate = ulBaudRate;
    . U$ ~. Q6 O# q; {1 r8 P
  61.     huart1.Init.StopBits = UART_STOPBITS_1;
    5 C5 B2 t- D5 R7 l
  62.     huart1.Init.Mode = UART_MODE_TX_RX;* c$ ?; i9 d, K
  63.     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;, E5 s6 ~; x4 p! g
  64.     huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    / Z' J# k/ a0 V# b& K$ E

  65. & r7 J( f% f3 w! B1 ^! Z* m2 m
  66.     switch(eParity)+ |; B5 D! P. B/ x* D( Z
  67.     {5 W. a4 ]9 f0 ]# i5 E
  68.         // 奇校验( G0 ~/ M, }" c$ T( g4 ^2 b0 b
  69.     case MB_PAR_ODD:4 l- R9 ]  i  |& O0 W
  70.         huart1.Init.Parity = UART_PARITY_ODD;) Q3 Z; }3 P1 {7 n
  71.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits) P0 z( S0 S* P( b- f  m6 u9 s
  72.         break;/ F3 s; T0 q; J8 Y; K/ K) A
  73.         
    4 H; j5 C6 h/ M/ q1 R, O
  74.         // 偶校验5 G. x9 h& w( B1 g# W: y
  75.     case MB_PAR_EVEN:
    2 u9 M$ s* X: ^: j3 m% J
  76.         huart1.Init.Parity = UART_PARITY_EVEN;
    9 p/ G" j$ M7 n9 A- @; [+ u
  77.         huart1.Init.WordLength = UART_WORDLENGTH_9B;                        // 带奇偶校验数据位为9bits; G& g+ O/ R2 a0 L: }* e! R
  78.         break;# x" t2 J; ^2 S
  79.         " J- F/ o* ^( V3 \$ ?
  80.         // 无校验
    ! b* k5 H& Y; ~9 |" z0 E
  81.     default:
    + R! l9 L3 n5 _4 s5 z* B3 R
  82.         huart1.Init.Parity = UART_PARITY_NONE;3 d' c  C2 }# Q- U
  83.         huart1.Init.WordLength = UART_WORDLENGTH_8B;                        // 无奇偶校验数据位为8bits
    4 h' O+ Q% L% F% G! q
  84.         break;
    6 R: B% c8 R7 `4 |2 E1 F( z
  85.     }/ M  Z5 B& i- D0 ^# [7 C
  86.     return HAL_UART_Init(&huart1) == HAL_OK ? TRUE : FALSE;
    ( E! I8 }1 D5 n4 i1 x! m
  87. }
    4 j8 L, c% A4 D6 Z
  88. & V; ], J1 h9 ~8 g# H) A; K
  89. BOOL7 v( v: i4 S! o* W$ b- W
  90. xMBPortSerialPutByte( CHAR ucByte )& x$ X1 L6 Q, s9 b& Y
  91. {0 D; C  A, p0 T9 {( L0 a% V: ]+ }
  92.     USART1->DR = ucByte;
    2 u; u) Y' w* _/ {; X2 e! u% x
  93.     return TRUE;" n+ n7 I+ m" @3 {
  94. }2 T4 Z" ?, O# [; F# t3 `: K* [

  95. : x3 V, }! a& W# j; q! ?3 X. z# Z
  96. BOOL
    2 u# i. a$ Q7 X$ W# @+ u) ]
  97. xMBPortSerialGetByte( CHAR * pucByte )
    ; [4 K5 {# [+ v. W$ I: x8 A
  98. {9 f8 b2 K; T: z3 g
  99.     *pucByte = (USART1->DR & (uint16_t)0x00FF);
    : B9 i! I6 y! x! K( x
  100.         return TRUE;1 `0 c5 R' o; m; ~! A- i. Q
  101. }4 o0 R3 O7 j  Y; C% Q& [

  102. 1 e) ]+ Q1 x9 Z- H$ W' W
  103. /* Create an interrupt handler for the transmit buffer empty interrupt% _/ j; d& e2 |) N) `2 x
  104. * (or an equivalent) for your target processor. This function should then! c6 `) ?: p8 q+ q
  105. * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that5 ]  I9 O# ^$ k% b4 m" e' a
  106. * a new character can be sent. The protocol stack will then call6 ~3 H/ `0 p& y' d( x) u) K
  107. * xMBPortSerialPutByte( ) to send the character.
    " R2 d+ C! ?7 s2 u% E+ B
  108. */: a' N: H/ n/ F' L. X% s' E1 e5 T
  109. static void prvvUARTTxReadyISR( void )
    5 U; H) Q( T, h: c4 z7 K* D
  110. {
    $ G: m  y' U0 t& P/ p/ x
  111.     pxMBFrameCBTransmitterEmpty(  );  A: N/ r) s0 ]/ A+ a4 {# T
  112. }& c$ U+ h' V8 g* M+ T8 {

  113. 4 C; a( g  _5 P3 |8 `2 H! y7 |. {; [
  114. /* Create an interrupt handler for the receive interrupt for your target
    # J2 @$ @6 h+ V; L4 `( V
  115. * processor. This function should then call pxMBFrameCBByteReceived( ). The
      G; {3 p. ]4 k
  116. * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
    + b2 s( H* ]% N: r2 {' z; O
  117. * character.
    $ ]  T* b% R1 v' G, i5 p' f
  118. */
    6 `  ]; G, H8 S
  119. static void prvvUARTRxISR( void )
    9 L' t: }- |- X* q
  120. {- x' {$ |4 p  W
  121.     pxMBFrameCBByteReceived(  );: v# K' Z4 K" G3 a' n
  122. }9 `6 c# `  ~7 W
  123. 2 d, [3 I. ?- f$ {3 w, L3 w
  124. void USART1_IRQHandler(void)
    & B1 ^+ g  v  D9 F$ e) E, y8 V! D
  125. {$ |2 J1 y" A9 S. z4 `! R% r
  126.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))                        // 接收非空中断标记被置位7 r. a6 i  a. ~8 \8 g6 c1 W
  127.     {
    + [+ j$ Q2 y7 G2 M# o  t
  128.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);                        // 清除中断标记
    4 k! ^0 }# r5 R6 A8 p: d$ n, u$ N) O
  129.         prvvUARTRxISR();                                                                                // 通知modbus有数据到达
    7 C; t5 l$ i/ m" h
  130.     }
    4 v  d: L0 o! y; Z+ Q: O
  131. " q; i+ v+ z3 p! X1 }9 r4 j
  132.     if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE))                                // 发送为空中断标记被置位
    ( \/ |/ j8 U! p3 @( D- {
  133.     {
    3 T* P' G# A1 O2 ]' X
  134.         __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TXE);                        // 清除中断标记
    , ?* H% F1 m: w! g) }* h9 K5 l$ R
  135.         prvvUARTTxReadyISR();                                                                        // 通知modbus数据可以发松
    ; ?) O" a$ G8 ?! s( T* ?* R9 R# z
  136.     }
    ! J$ ]( L. E3 j' c. Y; ~) @
  137. }
复制代码

, G* L. `8 ]: {: {5 _注意一点,一般如果使用了485芯片的话,那么同一时刻只能接收或者发送,可以将函数vMBPortSerialEnable修改成这样:. b9 o% S) M4 }9 q6 A
3 G/ \3 ~  Q, F7 K+ K
  1. void4 V' y) r, ~0 e+ w' V9 @
  2. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ). k  ~" X; x- b5 R. C
  3. {4 W9 x( ?; j6 F0 r- q* b
  4.     if(xRxEnable)
    9 g6 ?: a  V7 Y& p* y' k/ r6 T
  5.     {$ C; B! R# u# k; r- c7 h$ h( E  d
  6.             //5 b  v& c. b# P; F/ V( y, D" H
  7.         // 在此处将485芯片设置为接收模式
    ( ^& |5 I. _7 {# F/ |$ c4 e. b
  8.         //0 h' A' k5 M. k- M* A6 M
  9.                 /* do something */# h: c( ~/ J/ ^
  10.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);                // 使能接收非空中断
    " p5 U0 z) h# l+ z9 }
  11.     }
    % b8 J+ a4 C* k
  12.     else
    4 W2 f+ k2 b( f$ G; L
  13.     {8 M4 i! l2 n6 o
  14.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);                // 禁能接收非空中断& H4 z  {5 n3 U) }" w. s+ J
  15.     }2 d8 c2 v0 l2 o2 ^, ^

  16. # P+ h5 x1 ?0 e% x) J+ B6 Z
  17.     if(xTxEnable)1 X3 J# m1 g. l  Y0 b7 |
  18.     {
    ! t  f% q( W1 _' u0 @& O# A" ^
  19.             //( v2 n- r! v- @6 L" I+ F
  20.         // 在此处将485芯片设置为发送模式
    : K' @9 i! w5 [
  21.         //6 W$ z! J% x1 c3 \
  22.         /* do something */
    : Q0 i) F9 M/ Q, r- e; E
  23.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);                        // 使能发送为空中断
    . F  J3 q7 H/ t
  24.     }0 L& `8 i9 Y# n% _7 b, f; c! e# e
  25.     else: J6 f: t3 M6 A& x7 t7 P
  26.     {
    # r2 ?2 d8 }( B; _. k+ S1 R
  27.         __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);                // 禁能发送为空中断1 B2 ~! E8 c6 @# c: p# ]" z5 B
  28.     }9 \4 e$ x( @5 v, C# a
  29. }
复制代码

9 b! h# e0 }; M) A& E( d
编写modbus命令处理回调函数port.c文件
1 L5 g1 |0 ]' m3 l+ u本例程只实现了读取输入寄存器和保持寄存器的功能,详细代码如下:, T9 m5 h% V& D: Y  r9 G8 g

$ G! e% `* F- D8 \' q
  1. #include "mb.h"
    / D6 T  M3 H( a9 L3 x, T0 q
  2. #include "mbport.h"
      r2 \0 g7 L5 [/ b4 c8 E) w

  3. % b7 I4 s6 P6 H% |0 T& h* M. U! K  d

  4. 0 k0 P  p: e/ E  ^+ e+ t
  5. // 十路输入寄存器
    / a$ t* m) N) Q. {. P& |0 m
  6. #define REG_INPUT_SIZE  109 X/ p4 k. w) U, p
  7. uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];5 h& |: S( R& z4 {+ X: m  }. Y

  8. 5 d4 m6 w, F" C7 x) F

  9. * {" C- d/ x: G) p( A( N- o& G# e
  10. // 十路保持寄存器, f* w( S% B8 t1 Y
  11. #define REG_HOLD_SIZE   10: Q) ~9 Y: B6 T8 t
  12. uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];' p( G8 p; b0 Z$ T& l' _& i! O6 c
  13. 2 _& t5 G: g! |. k

  14. 2 L9 x! ]" \" q/ ?; a& f9 H0 r: ?7 Q
  15. // 十路线圈& A& ~/ y3 j) |" G) t
  16. #define REG_COILS_SIZE 10) ]8 u( f3 m$ ^
  17. uint8_t REG_COILS_BUF[REG_COILS_SIZE];2 N9 C  w2 h2 v- O& t- S0 q
  18. 5 ^3 t: H" Y* F) R8 j1 R" ]

  19. 9 ]- `. N2 f( U8 V/ z
  20. // 十路离散量
    9 ~" j$ p* h, G2 i
  21. #define REG_DISC_SIZE  10" A6 g7 I9 p$ [7 j9 W$ @
  22. uint8_t REG_DISC_BUF[10];
    ( V* x* b$ {+ \/ Q

  23. / e( v% _  U! s2 j8 [3 }9 s, ]' V3 q
  24. : F( Q3 L+ s& W( n& x. j( I" p( V
  25. /// CMD4& C( {. Z- R6 C, N/ x
  26. eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
    # h- c: x' X" z/ j* b
  27. {
    7 P* h* c) I% @8 c4 i+ `  u
  28.     USHORT usRegIndex = usAddress - 1;
    ; l7 L/ i; U% w, H7 X0 Q' q2 X

  29. ! P# ?5 E. t, h- Y6 o
  30.     // 非法检测- `  i6 m! G" x) H0 N4 `/ [
  31.     if((usRegIndex + usNRegs) > REG_INPUT_SIZE)/ p/ d; ]2 X' Q2 e. v
  32.     {6 H3 n2 `( I. e$ B9 @
  33.         return MB_ENOREG;* F2 ]# L1 O3 X6 E! R
  34.     }. m  l8 q2 V) i: D7 C0 a& e1 x

  35. : X0 _! r8 l) Y1 \$ ]2 n5 L! L0 p
  36.     // 循环读取
    . Y+ P' \, @0 a! \( r& A
  37.     while( usNRegs > 0 ); W8 w! p$ ?5 L9 F1 y
  38.     {: h0 X3 U* E0 n* Q6 I; _
  39.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 );
    7 o' {" D+ u1 W3 X3 A, \
  40.         *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );
    8 Z  D; i, N1 a
  41.         usRegIndex++;
    : Z  G- b9 [# \; k
  42.         usNRegs--;
    # }2 _5 O3 m5 r8 l4 z7 U) M
  43.     }; D. ~# v5 Y- x

  44. 4 H3 b7 F3 e0 X+ `* Q1 m6 I
  45.     // 模拟输入寄存器被改变/ ^8 K1 P0 `7 ?/ b0 d
  46.     for(usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++)
    , `7 p: q+ _' r& j& D  W
  47.     {
    0 V  J" f0 W; L( p) ?2 ]2 z" @' `3 X
  48.         REG_INPUT_BUF[usRegIndex]++;  ^. x: l: H7 t3 S' X" f
  49.     }4 l& i0 X" T  f! B

  50. " J" A/ {* }, R8 m, R+ `
  51.     return MB_ENOERR;8 l% J. x4 g4 A' ~- M- C. t: e# g. x
  52. }' }1 C9 n$ P7 q5 [) Z
  53. 2 w" |$ p$ j! E# n1 Y
  54. /// CMD6、3、16
    0 W' \" j9 ]8 j* c6 k; v
  55. eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
    ) n$ P8 C0 i' w
  56. {; C; {6 b& S, y- h
  57.     USHORT usRegIndex = usAddress - 1;  
    ' R2 @$ t. l8 {+ P
  58. $ `% c: G9 }5 P
  59.     // 非法检测3 U$ I/ J, M7 [6 O- }6 ~
  60.     if((usRegIndex + usNRegs) > REG_HOLD_SIZE)
    3 J, B* Q! U$ R5 |2 C( a
  61.     {, X$ C! w9 C3 q1 b, I  m1 _
  62.         return MB_ENOREG;- g2 G  y3 q  P9 {" N
  63.     }8 ^' S6 G+ S5 s: y
  64. + p# a. h; T. P/ _7 R* s
  65.         // 写寄存器
    8 |7 |4 i$ g+ k
  66.     if(eMode == MB_REG_WRITE)
    ' d' P# ?' t& N! X; A& k
  67.     {
    9 D3 _' w1 ]9 Q/ C: B! O- M1 b" r
  68.         while( usNRegs > 0 )' f" X5 Z% }. O+ a  v" J7 I
  69.         {
    3 E6 G; Q5 c: {% c/ [) Q6 L% ?
  70.                         REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];. h$ W4 D: T6 g* g# W. }6 s. O+ O6 P
  71.                         pucRegBuffer += 2;8 X: D' D+ v  U7 w, l$ w5 ~
  72.             usRegIndex++;  e4 |; k2 z4 d
  73.             usNRegs--;
    4 g$ _1 \3 i: e
  74.         }! [0 M3 D8 [: C* z4 y% q* ~
  75.     }6 S' k. r& s* X  U: j4 s2 M
  76.         " z; m, n4 N3 Y1 t
  77.         // 读寄存器# s/ s9 K2 [( R8 p. W/ d  u& ]3 p. W
  78.     else
    8 z! f  X3 H! O
  79.     {
    + g2 q% R3 n3 \) h% N! u  t/ {
  80.         while( usNRegs > 0 )& G3 a* H4 M( o3 b: b0 ]
  81.         {
    " h7 i. B1 d+ h" Z- I
  82.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );
    2 J' K( a% t# }, z6 M$ @
  83.             *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );
    4 i) q) ]* c) P: l) v" j
  84.             usRegIndex++;
    6 J/ S/ ?4 c5 [2 \+ g) T0 F- l
  85.             usNRegs--;
    1 u+ Y% k6 Z" G* e
  86.         }/ ^1 Z; V1 S0 M0 K' \, p  N) ^1 ]" C
  87.     }
    * z5 u4 Y* ]3 n, u) W# c
  88. . g. [- H" v& R! X" ]8 D
  89.     return MB_ENOERR;
    ! a5 G: @: _# Z7 f. Z- I1 |" s. z- t
  90. }! F* |8 `6 a% h

  91. 4 n& D1 o# J$ f/ V. ?2 i
  92. /// CMD1、5、156 K: L" v2 [( X4 k. a$ V$ I
  93. eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )1 o$ e, C4 g" ^* p' a% \
  94. {
    7 z' ^  f# i  b: }& A  D/ x
  95.     USHORT usRegIndex   = usAddress - 1;
    0 g& g! h2 C7 \6 C
  96.     USHORT usCoilGroups = ((usNCoils - 1) / 8 + 1);* u9 h2 H; s* I( F3 F. y0 a
  97.     UCHAR  ucStatus     = 0;
    ' {/ Q4 [, I  c' u! J& h
  98.     UCHAR  ucBits       = 0;
    & ]5 }' k, u& b: z: `5 Y
  99.     UCHAR  ucDisp       = 0;
    / R# }# I5 d5 [" V; k- C
  100. # q/ ^4 t2 D6 ?9 ^3 A! W* d2 m
  101.     // 非法检测5 v+ W5 V* i8 y
  102.     if((usRegIndex + usNCoils) > REG_COILS_SIZE)( |- H3 M/ Z8 n5 h* b7 c
  103.     {
    % X5 |! T9 Y% R* j  _, ?
  104.         return MB_ENOREG;$ ~& k& ?  u5 a( Z, L9 B
  105.     }$ o' S) [7 m" W7 z, l4 K9 m

  106. ) h3 m* k; c& P2 g. F. r" N  m* u
  107.     // 写线圈' H2 l8 b% T# k6 ~6 z5 o% H7 g7 z
  108.     if(eMode == MB_REG_WRITE)5 g$ s% H% v+ `
  109.     {- v- x" H) ^8 ?& ^4 ~3 p
  110.         while(usCoilGroups--)
    5 k) Z# S! r3 E" u) c" G
  111.         {) u. v& a6 O6 Z. }
  112.             ucStatus = *pucRegBuffer++;
    + {4 ]/ _  `* r
  113.             ucBits   = 8;: @2 }2 b" i2 \+ B# F$ U9 A5 I
  114.             while((usNCoils--) != 0 && (ucBits--) != 0)
    ! H2 A6 X! A, `+ s5 j
  115.             {% ^' P+ t& a) q1 L  x* q
  116.                 REG_COILS_BUF[usRegIndex++] = ucStatus & 0X01;
    + \3 P, }" i; `
  117.                 ucStatus >>= 1;
    3 a6 U# U  S( o1 S
  118.             }
    3 w7 Q1 ^8 ~  O' P
  119.         }8 p' a7 F) v! d! s; l3 i
  120.     }
    - L+ p+ I' b; z  @8 w4 S1 }

  121. & |% c" ]6 W2 w- F+ K8 a! F( Z
  122.     // 读线圈
    7 q. F1 y  Q# b+ q' L! C
  123.     else2 |% p% M1 t4 d6 O/ x" Z8 b6 B( C
  124.     {! i0 I; M% s, L0 o! Z1 u
  125.         while(usCoilGroups--)6 _& c: C0 P% n: X
  126.         {5 g8 T2 m% r: ?+ A' H$ a9 V5 y
  127.             ucDisp = 0;# s% h% Q# R8 _- j5 K% d8 t( ?
  128.             ucBits = 8;& [& T& Y( Q. S
  129.             while((usNCoils--) != 0 && (ucBits--) != 0)
    7 o# [0 L' ]! Y; r2 n& u8 x9 k
  130.             {
    8 U+ I, J3 o% x5 w3 _& c2 y
  131.                 ucStatus |= (REG_COILS_BUF[usRegIndex++] << (ucDisp++));
    2 J3 E5 b, A' B" t
  132.             }
    4 w' K, _5 P3 ]% T
  133.             *pucRegBuffer++ = ucStatus;
    ! f' C9 B( ]' l% P' ~
  134.         }+ ~% D3 X' n: D; N1 |& E, O0 A
  135.     }3 R) a6 }" x( q
  136.     return MB_ENOERR;
      j/ l* @$ S; o/ S: v, z
  137. }
    + I7 P& {2 n9 @' Y) v* Y

  138. 5 v0 a0 @. W3 [# u0 `! T" v4 a' F

  139. 1 ^" \# A" w& s. f
  140. /// CMD49 o- B; w/ F7 L& r, f) ^+ e
  141. eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
    9 {8 W4 Q4 n# s7 P5 }
  142. {7 o( i( W& p2 _) Z, r
  143.     USHORT usRegIndex   = usAddress - 1;4 a9 m# a- h# P9 T
  144.     USHORT usCoilGroups = ((usNDiscrete - 1) / 8 + 1);
    $ Q  t/ e, A& n3 p4 }0 F
  145.     UCHAR  ucStatus     = 0;1 \; }8 a% ?1 C4 X2 B+ W
  146.     UCHAR  ucBits       = 0;4 C" \/ Z* p+ z7 T- v; k' [
  147.     UCHAR  ucDisp       = 0;7 _( [% O4 J9 i. q
  148. ( T4 j8 o* V) f
  149.     // 非法检测+ z. c( W4 [9 K* E  y: p
  150.     if((usRegIndex + usNDiscrete) > REG_DISC_SIZE)
    0 k( Y/ ~: v( e: g
  151.     {
    7 [6 c3 W" |5 h7 Q" l. H6 w4 T
  152.         return MB_ENOREG;
    % `3 d" d$ U4 a
  153.     }; T+ S+ a% C! }. D2 d! q. p

  154. 3 p: ]2 ]. N# c$ W* N" i4 S
  155.         // 读离散输入2 {7 ^) \# E5 p
  156.         while(usCoilGroups--)2 q1 M: X8 S$ p
  157.         {
    4 Y, F, ^: _8 F
  158.                 ucDisp = 0;
    0 o; ?' N  \2 a& Z3 ~
  159.                 ucBits = 8;) |+ g4 D0 s. |" z
  160.                 while((usNDiscrete--) != 0 && (ucBits--) != 0)6 w# @$ L. y& \2 J
  161.                 {( S% n8 f- Z9 V, ]
  162.                         if(REG_DISC_BUF[usRegIndex])' O* o) x* s7 ]) J* A+ K) P
  163.                         {
    - i% X' i/ ?5 E( y3 Y* h
  164.                                 ucStatus |= (1 << ucDisp);! m& d, w, \8 N- x! X5 L) X
  165.                         }
    $ D# V% C. e3 W# D+ t
  166.                         ucDisp++;
    * G8 }: f% q# W: d0 u! x
  167.                 }
    % Y9 G; l  i3 {
  168.                 *pucRegBuffer++ = ucStatus;
    ! n4 {7 c- a3 B4 g5 D! s' ^( R4 b
  169.         }
    5 d! U7 }4 b8 b6 @" A( l
  170. : U7 B1 q# H, \0 a+ ]8 r  u9 R
  171.     // 模拟改变
    & F7 X, L, v0 s5 n7 }8 \
  172.     for(usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++)% Z9 C, l8 l4 m
  173.     {1 x) @- x/ J& ]; q7 Y" B% M
  174.         REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];" [4 Q8 z: }3 g! Q. e
  175.     }. `, p3 y2 A4 l
  176. ' p0 m" S# H* a/ O
  177.     return MB_ENOERR;
    . E6 Y6 o! {$ f: l" g& L& T) g
  178. }
复制代码

; Q+ k) B8 W, R7 ]6 P8 g4 a$ q主函数

/ B! o$ V2 {  _. R
  1. int main(void)
    " y4 o- \1 v( Z5 ^$ S+ i9 D& o
  2. {
    9 _, S% K6 ]8 c# q
  3.     HAL_Init();
    % d0 Q- @9 {& W1 M" D- P- b
  4.     SystemClock_Config();
    & W3 H# v" l) v4 W* m
  5.     MX_GPIO_Init();: p" Z$ r. v* {4 a' }9 \
  6.     eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_ODD);                // 初始化modbus为RTU方式,波特率9600,奇校验
    . [6 ]* p5 T; I6 _
  7.     eMBEnable();                                                                        // 使能modbus协议栈
    4 X9 q) h: r7 o( a3 n
  8. # D& _6 J& T, f* W- g
  9.     for( ;; )
    : I  z0 Q3 t3 z8 {9 [4 _: ^( n
  10.     {
    4 ~* l; h: `7 [  g" G0 B% f) U
  11.         eMBPoll();                                                                        // 轮训查询2 u& q* v: x2 v; B) \2 g
  12.     }6 u7 X7 y$ H3 S& i
  13. }
复制代码

! Z3 u% P: t. j( ]移植测试9 r8 G8 l. v# A6 y( ]

1 S  E3 C* |* w, S8 g2 R 20200313154857173.gif
5 P; n& \( B( ^0 t8 m0 L# a
& P; B* N0 v/ C3 X) }ends…
/ ^* f4 N& q9 i
# a: F1 g5 F0 b/ h8 `+ L
! T1 p  [6 [" \% j" v- @7 B4 x: N, R7 M5 C# I% t5 Q# g  t& A
收藏 评论1 发布时间:2022-4-10 22:53

举报

1个回答
zzzff 回答时间:2024-10-26 10:31:57

我的是stm32g071系列,移植上去不行怎么办

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版