modbus命令码表:
4 X _+ I$ _7 T8 ]1 C2 t4 @
* x: Q$ h1 E9 q! D! ^3 O
& y- x) d6 P3 d& l) [
, L/ d6 n7 N# T* D- wFreeModbus文件说明' G. f5 p L( u
解压freemodbus文件后打开,我们需要demo目录下的BARE,该目录下的代码是空的,STM32移植工作基本就是修改:portserial.c、porttimer.c、port.h这三个文件。
' w0 k. ^1 g/ n0 y% W- R3 c
( Y! ]8 Z$ X2 T+ O- S, I3 ^8 B+ j% X
mobus文件夹就是完整的源码,包含rtu、ascii、tcp:; {3 z, D2 R- y+ h- X
' ^ {+ R: m; t# r
4 |: w6 ]9 |0 u* q# o
: V7 P, L% v. P3 l& ~! W. O7 l 我为了移植时在keil添加源文件和头文件方便,就把modbus所有的头文件和源文件放到了一个文件夹下,并创建了一个port.c文件,用于编写modbus所必需的回调处理函数:9 R% T* _& u% B0 ]
2 u/ ~9 Q; h% Q7 @, q5 N% a
) }1 z2 y! D, Q
* d/ z7 ^" \8 K! T, c1 N
STM32CUBEMX配置
% t+ e, l* B% w: U时钟配置,设置主频工作在72MHz下:" T' T+ j2 ~) t: b
, C& k( m. Z1 ^8 k) y1 B
6 R. m% [5 j- _' V- K
: e" y0 i; P* l2 D配置串口1,这里随便配置就行,在modbus移植过程中还会对串口重新初始化:
1 L8 {, Y7 R o4 h w, j3 ?2 }9 [, }) z! Y1 U* P6 w9 {
; p! l: v3 `! a. o$ c" J: i& b+ {& n5 d7 X4 d+ _
配置定时器4,用于3.5个字符的定时检测,这里随便配置就行,在modbus移植过程中还会对定时器重新初始化:
# L9 m/ j: W3 }2 \6 N
+ Z# |, I: t: L
% G8 {- J8 f: j# z9 E
+ M0 p+ x Q8 d1 X2 w Q) A$ [中断配置,这里注意,串口的优先级是要比定时器优先高的:
1 @, [1 ?" w- J2 d1 i/ F1 Z" u
/ p0 L' n8 p3 k+ n) L) @/ |
# z' b" r. d0 R4 {) }取消掉自动生成中断服务程序,在移植过程中我们要自己编写串口和定时器的中断服务程序:4 G/ a) p* n! W* R5 K9 f
/ m3 _! [. E; ~
2 m- N4 }" [" ^( S
5 e7 v6 B7 w+ O& ?移植代码修改
# _/ X" p+ J! \9 ^' W( m7 r生成代码后将modbus放到工程目录下:
% Y6 w( u, q9 R# C% s7 [: m& J& p) B1 ?) W
& u: ^" U/ h, R
2 Y& D) P; Z% u7 P/ ~2 s4 b打开keil工程添加modbus源码:
i& M- U4 Q& K8 q* J$ ]/ Y K/ k! z
& H: g; n- X# x/ r3 F
k; J% z6 u9 w添加包含头文件:( A& J% g' B7 p, w
! U* g) E( A j
5 Q+ R! h+ c( [* @% A- ~; G
4 r8 D: I4 h7 ]" o修改modbus定时器初始化源代码porttimer.c文件
8 r) H; z9 h% B# r( [ 定时器的修改比较容易,将定时器设置为每50us的时长记一个数,传入的usTim1Timerout50us变量给自动装载即可,prvvTIMERExpiredISR函数需要在定时器中断服务函数中调用,它的作用是用于通知modbus协议栈3.5个字符的等待时间已经到达;由于我们在STM32CUBEMX中取消掉了定时器和串口的中断服务函数程序,所以我们在该文件中添加定时器的中断服务程序,修改后的代码如下:
7 l% y! W' E0 m! q3 \! x' k: Q* z. x$ W+ s& |
- BOOL$ n5 o$ {# A, H H/ p. ^3 ?7 Z: e
- xMBPortTimersInit( USHORT usTim1Timerout50us )4 |, D8 e2 z2 y* O4 D$ ~, K" C
- {# W" v9 {1 C7 n' z$ Q; N
- TIM_ClockConfigTypeDef sClockSourceConfig = {0};
0 Y! P- W+ j$ [$ W: l# r* n( t$ [ - TIM_MasterConfigTypeDef sMasterConfig = {0};$ r: u$ ?5 Q" T4 C, t7 z
- 6 P: D, Z* d$ m+ s: n, A
- htim4.Instance = TIM4;
S# H- R3 m# }$ k9 L! `& w - htim4.Init.Prescaler = 3599; // 50us记一次数
1 R$ z1 \1 Q, l- s2 i5 U' ?8 O - htim4.Init.CounterMode = TIM_COUNTERMODE_UP;" V( v! V R) s
- htim4.Init.Period = usTim1Timerout50us - 1; // usTim1Timerout50us * 50即为定时器溢出时间. o4 c& l6 i; c5 I: O! M, W6 O
- htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;; q2 X3 E1 H8 ]2 j
- htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
) I+ s2 H7 w2 d+ M - if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
" A1 ?7 H3 B! u0 q - {
5 C; r# h5 I1 g+ ?8 O0 y- v - return FALSE;
6 D4 t% p0 S# ~; r - }0 E0 o! w9 c- m
- sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
" v% C* m; i; a" e( ]8 d9 o8 y - if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
' y( e$ Z* I" Y# }0 t6 q L - {. k* {& I& E& i
- return FALSE;3 _& s- i' z* I
- }7 [+ p- o, }' q6 U, i D
- sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;2 S, R6 p. b. h
- sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
6 T1 I) B( L. D - if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
1 R5 A+ a- ^, Z: ^" ^# ]$ A6 ~ - {
3 d3 r) @- l B v3 a& k - return FALSE;
- ~) O4 M4 S7 a3 L - }
8 s1 g6 K9 l( j4 `6 }
& e$ y/ f) n! m0 V2 [- __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE); // 使能定时器更新中断4 y1 u- x# D+ _4 e
- return TRUE;0 q: }6 d4 i. c
- }
' a- C9 V" O- A& o8 W$ S - ' ]. S: f% S/ l9 s% R
- inline void& H7 A8 w4 q9 D# ?( U Z+ \ |/ ^
- vMBPortTimersEnable( )
# N2 Z) Z/ ^( G$ D N - {3 A7 }' K8 g$ N( i1 C
- __HAL_TIM_SET_COUNTER(&htim4, 0); // 清空计数器2 `7 [! D0 |" d+ E+ {
- __HAL_TIM_ENABLE(&htim4); // 使能定时器# L, T1 B* L. e o9 P$ B9 U
- }+ y4 W& c9 c( M% v5 {& e
- / I$ z/ D _7 x4 ~( A& }$ d
- inline void
0 Q4 O3 T+ l" ?* m6 x# n9 W8 p9 ` - vMBPortTimersDisable( )
, r: T8 \: M3 _7 I; v, g5 w - {7 V4 U2 k$ D4 B" ?1 W: S
- __HAL_TIM_DISABLE(&htim4); // 禁能定时器; s+ x2 t. F: _4 t
- }- C6 _" C* \9 p$ p" |( B& [
- 6 d. y* C: r7 B- C' b: h. L7 @, V
- /* Create an ISR which is called whenever the timer has expired. This function
) u/ x" O1 O; z8 h3 r - * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that h' ] ~! d7 s4 p" y
- * the timer has expired.
: B ?) r3 U+ Q) W; ~3 g - */
/ w } q% p7 `- b7 k. k - static void prvvTIMERExpiredISR( void )
3 u' W# @9 Q1 L3 b - {
& ]8 z- y; x9 w% r* A4 q - ( void )pxMBPortCBTimerExpired( );3 w& y! ~. V) }& M9 ~
- }3 N) }) n: o; e5 [, W! T3 R
- 7 g! e- q! @4 u' Q
- /// 定时器4中断服务程序" c5 s- i8 ]5 B7 r3 y/ N# }. M
- void TIM4_IRQHandler(void)+ A3 o3 _7 Y8 h% K7 n6 N; Q
- {( z8 Q k" b5 Z+ W4 _+ e; Q
- if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE)) // 更新中断标记被置位
) A0 H( [% F& _0 g- `8 e! X - {
. T6 a8 `9 H& F4 k& ^# E - __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE); // 清除中断标记
' T- V$ q6 Y: f, a' _8 ^ - prvvTIMERExpiredISR(); // 通知modbus3.5个字符等待时间到
. b5 }5 t9 F' J7 L( K$ P c4 n - }
& R( X5 e" `& T8 n4 o1 i0 W; ` - }; d- z5 j9 `7 A9 k
9 ]5 Q" q: S5 z) Y- 2 {$ @& y/ A( N. R
复制代码
$ X0 I: ?" Y! X! Y修改modbus串口初始化源代码portserial.c文件0 X" J0 q u/ }: g h# z
~~~~~~~~ 在该文件中实现串口1的中断服务程序,prvvUARTTxReadyISR和prvvUARTRxISR函数需要填写进中断服务程序,前者得到作用为通知modbus协议栈串口已经空闲可以发送数据了,后者的作用为通知modbus串口1有数据到达,修改后的代码如下:1 S" [2 ~5 v0 \8 [; `
% w+ d7 r5 C. @
- /*; l1 `3 [' e9 l) N) ~
- * FreeModbus Libary: BARE Port2 ]6 @: g# o# \2 t% X' M) f' Y+ n
- * Copyright (C) 2006 Christian Walter <<a href="mailto:wolti@sil.at">wolti@sil.at</a>>
, P) u k* ], y- u) X - *# j: _9 y# _" _9 F, G
- * This library is free software; you can redistribute it and/or9 E' K" t3 ]' i" `1 h. w2 y8 S
- * modify it under the terms of the GNU Lesser General Public
" V+ k; ]) B" W0 b1 l3 F. B - * License as published by the Free Software Foundation; either, g& ^) a2 b6 P: H& n( |
- * version 2.1 of the License, or (at your option) any later version.
# U8 a5 U$ G3 D - *
9 x: n; b- R& _" O/ o$ N( i7 W - * This library is distributed in the hope that it will be useful,2 x. s' }% S& @
- * but WITHOUT ANY WARRANTY; without even the implied warranty of9 a( H3 ?- ]/ \2 }: f% {' p+ T. k& X
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU9 }9 U% B* j) `9 [6 y
- * Lesser General Public License for more details.
% a" u. U& t- i1 {. U2 W3 S) z - *
: E8 E# B' l& |2 r - * You should have received a copy of the GNU Lesser General Public
) E( c `1 A7 W0 w) p/ c - * License along with this library; if not, write to the Free Software- @6 ~- H. C# n/ c, R+ ~' z1 U0 C+ c
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA% y# u" c5 g5 x& f* f. V
- *
1 O# l5 ^% [9 ]9 ]' V; o - * File: $Id$
# E6 P* L4 E4 A4 a1 V w - */
$ R! ^. x& `9 g# o. k# Y$ ? - 9 ^5 g' V+ j+ V
- #include "port.h"
- D8 h @7 {7 Z+ } - #include "usart.h"
* d) T# m0 h& E7 n. Y6 ?% ` - X4 t/ W' B* {0 K/ r' {
- /* ----------------------- Modbus includes ----------------------------------*/9 C. X9 h( o' u
- #include "mb.h"
0 _) |6 w. {) `$ ^% ~0 Y - #include "mbport.h"$ V! u' |8 E) k Q# M- q
- ; i) B; W3 w0 _
- /* ----------------------- static functions ---------------------------------*/
: o% [% a2 F: w; ^" Y# o* {$ [% \ - static void prvvUARTTxReadyISR( void );7 b7 ^8 F S- c, V
- static void prvvUARTRxISR( void );
" d- |( J1 X- _1 }# ~ - 4 H& D. [1 w: c6 P% K0 ^7 n* e
- /* ----------------------- Start implementation -----------------------------*/
6 a: _: \% f4 b' o" x! q/ m - void) [# T3 a, p2 I% S) K
- vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
4 h( o8 x5 v4 O1 I# V - {
, j$ G1 W; p+ s% |$ A, L2 ` - if(xRxEnable)
8 J8 O) o* \5 v0 v1 o3 T4 Y - {5 G R8 k* Z0 t
- __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); // 使能接收非空中断
& h" p) v4 X3 J9 b& G" h9 w; a* s - }
. o- H$ |) G; w% Z - else
) K" n9 w. o: b/ ? - {
1 x0 F2 U1 ]( e l - __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE); // 禁能接收非空中断
+ t% C& r# Q9 s% P. n( j - }
5 _5 P U9 Q& j, Q% ? - 3 K# d2 m1 t9 W
- if(xTxEnable)# S b0 W6 _2 B7 V) m9 i
- {! r- H7 R' ]2 @# E' S2 k+ N& e
- __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE); // 使能发送为空中断
$ w, W$ n5 l" ~, u. _. H - }
8 e: R/ {! S% K1 f - else5 \, ?7 |. q) i+ p! A
- { t m& ?7 y) f; @2 a
- __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE); // 禁能发送为空中断
$ x6 s7 H" o2 w! C5 v - }
* y- _, N3 K s - }; \2 v& k+ Z f! n
8 b6 ]3 B' b' @% N2 z; W; G- BOOL
& \8 N6 U8 q4 f6 ^. _6 _ - xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )9 a, {0 V5 ^! p; W) k( z W
- {3 b# H* _. w) }) d4 V
- huart1.Instance = USART1;1 O; t2 }4 G1 g. x* A) W' M8 e- F! |
- huart1.Init.BaudRate = ulBaudRate;
# N9 r& |! l* F - huart1.Init.StopBits = UART_STOPBITS_1;' V1 y& C; M" }% y, z- X# V8 o
- huart1.Init.Mode = UART_MODE_TX_RX;
6 Y8 p4 J8 b2 \: s% A - huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
2 M6 y8 u$ W3 N) @ - huart1.Init.OverSampling = UART_OVERSAMPLING_16;
# B" }* Y8 S9 m6 z% ]
+ I2 J7 b) o3 c6 j7 h [- switch(eParity)+ }* b& P/ Y0 R1 ` k9 q4 v8 S
- {3 a( `- p7 [' m: O, U c
- // 奇校验( b* t/ n3 V# S5 x# }" e; {. x1 T: `' \
- case MB_PAR_ODD:
* V o0 H5 ]: s9 D - huart1.Init.Parity = UART_PARITY_ODD;
" G7 Y) l9 R1 b5 u. q - huart1.Init.WordLength = UART_WORDLENGTH_9B; // 带奇偶校验数据位为9bits8 b# I2 t* p7 c1 f8 M
- break;+ R2 }# H+ H7 u3 D# g& v
- ( l* k' k `0 X( X
- // 偶校验3 L! e/ K; B! V, T5 d
- case MB_PAR_EVEN:5 h0 V0 }* }9 ^
- huart1.Init.Parity = UART_PARITY_EVEN;
2 v: G8 Z+ o# i - huart1.Init.WordLength = UART_WORDLENGTH_9B; // 带奇偶校验数据位为9bits7 l7 f0 `& T( {3 s
- break;
3 Y' n' s" `" { - % c) C- G3 _8 d& `# W. W# v
- // 无校验# b* r; h4 O* Q' T; ?, ?
- default:: O5 q( H) w( F1 c, T& s
- huart1.Init.Parity = UART_PARITY_NONE;
9 ~( l1 D" V* P# X7 q% E - huart1.Init.WordLength = UART_WORDLENGTH_8B; // 无奇偶校验数据位为8bits7 x e* \; V- ~; O5 i
- break;3 O6 @7 L4 @3 b2 R- G7 a
- }
) Q9 f1 Z3 N0 K3 v - return HAL_UART_Init(&huart1) == HAL_OK ? TRUE : FALSE;% v- r6 s/ _4 [
- }
' T3 ]6 c9 }# ~. i0 ]
4 U$ @+ I# T0 X. M3 @: w! M- BOOL, O, Q6 H/ g6 ?: V) b
- xMBPortSerialPutByte( CHAR ucByte )
2 K6 O, W! X1 z/ I; Q9 r( R) ? - {
4 X$ y' ]$ ~. A& N - USART1->DR = ucByte;
6 p& X: S" i7 n2 h - return TRUE;
: Y! L# u8 Y2 V; e - }# a( E; ], T: h4 i0 X. @
; l5 ?' H0 J% ~5 a4 T$ }1 ^4 i- BOOL
" J* {* A* {8 t4 ?4 ` - xMBPortSerialGetByte( CHAR * pucByte )
5 m& w$ \: w; f8 E - {2 ~) }8 ~. U) ]+ j( J/ N& U
- *pucByte = (USART1->DR & (uint16_t)0x00FF);
! N& y" Y# D1 D0 N - return TRUE;8 k- V. z7 t2 i0 |
- }
9 [0 P K' j- \9 k5 r
8 W& r( m8 o" j4 o5 I. E3 z; s! c- /* Create an interrupt handler for the transmit buffer empty interrupt
& E9 T# |$ u5 H, v - * (or an equivalent) for your target processor. This function should then
l; y0 f' |9 {, v - * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
/ u2 @( E+ ]7 x5 K( o - * a new character can be sent. The protocol stack will then call
! t: l1 t% e2 {" m- b) P - * xMBPortSerialPutByte( ) to send the character.
0 q: f2 l5 \" @/ B. m - */5 ?5 i7 ~# t( D6 v' ?
- static void prvvUARTTxReadyISR( void )
' w3 W. F# v+ N - {
R, Z7 t% Y& }, y! M - pxMBFrameCBTransmitterEmpty( );! c9 |" Y; k! E& f6 ~0 f
- }/ o' }7 e7 `* d8 c- `, ^' Y* j8 v( E
- + Q6 x" J3 t G. s
- /* Create an interrupt handler for the receive interrupt for your target
! D1 Q0 G1 A" p/ |0 F - * processor. This function should then call pxMBFrameCBByteReceived( ). The
, G2 r4 N# P8 b: L2 o& [ - * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the1 `5 p- X& c. ^$ X7 T: g
- * character.
) ?/ x X6 p/ h4 x- R' ~& F7 O+ u - */: Q% U+ E1 p) l( @, c
- static void prvvUARTRxISR( void )
/ e1 l5 {8 A( B# I+ o+ g' ^6 F - {/ t; \4 ]% x, T$ U
- pxMBFrameCBByteReceived( );
- M5 r/ B, J5 Z: ~% z4 L - }
% y' {9 s! r/ V: X8 S* T
$ Y3 }3 O+ P5 Y' G Y b* P# ^- void USART1_IRQHandler(void)
6 J1 N% q" X0 f+ d$ K, C! ` - {
9 [- ]; T9 H0 b8 p2 w - if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE)) // 接收非空中断标记被置位6 q0 {9 E6 B8 p7 ~0 W* V
- {
7 \- u- `0 e; a& l z0 q - __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE); // 清除中断标记: e6 c1 O" X \, g; u& E. M
- prvvUARTRxISR(); // 通知modbus有数据到达
: e$ g$ R8 @! x/ p, T+ M4 V - }$ n1 E6 r c/ \
- ( g' M$ \ _; F3 p% [) ?
- if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE)) // 发送为空中断标记被置位9 M+ U5 `% s, T/ W
- {, W2 B0 ^. N ~
- __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TXE); // 清除中断标记9 ?1 l2 ?* }7 _$ ]+ D4 w
- prvvUARTTxReadyISR(); // 通知modbus数据可以发松8 L, ^" @2 V" [- F
- }% f' F' Y1 L, L( j3 |5 W. \& D
- }
复制代码
" t( ~/ W: j2 _) R注意一点,一般如果使用了485芯片的话,那么同一时刻只能接收或者发送,可以将函数vMBPortSerialEnable修改成这样:
2 ~8 g2 x7 I- \+ Q" @+ G
8 G) a9 N/ U% }1 ?8 }: l0 Z8 q- void4 ]6 l5 P, T/ r! F
- vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )+ l' W" K# k- L1 q( V; {0 ~
- {
, S# }0 d* f0 H - if(xRxEnable)! }( Y* A b( G& F
- {
; K H9 M8 |* @; ]' U - //
6 e6 `3 F' R2 _5 b) a6 [ - // 在此处将485芯片设置为接收模式4 Z$ @4 l/ ^9 I3 t$ A
- //
/ L$ ]: r6 \+ v, w* n - /* do something */
6 B# t% T! D# k- m; n! o - __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); // 使能接收非空中断
8 X1 B9 d% M* ^# Z' j; T7 P: i z% s - }1 C8 {, K) s. U) d, l8 i6 P) {9 z
- else5 }; G6 [; v+ \8 T7 e3 W) Y
- {5 \6 {! M7 I1 r4 J2 Z7 E- v
- __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE); // 禁能接收非空中断/ E' q" ^: D# ]1 @
- }
# U3 i3 h( {9 Y D
( o" w4 ]7 r+ l( ?( C/ Y' |- if(xTxEnable)2 R, {2 F9 L- O' l, A
- {- \. Y0 [/ `. j6 V6 D
- //" Y, n+ Q/ e& s) x+ D. a) @
- // 在此处将485芯片设置为发送模式, Q4 S) N5 o$ A9 r h
- //
- F, q9 }& P' ]* D" d5 j - /* do something */9 G9 b' p& p' Q7 O. v
- __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE); // 使能发送为空中断1 n, e7 {! Y. n* B: s( t
- }; X! y( y) {7 { o
- else
+ y( k: b* | v1 K4 P. z/ p9 ?4 e. s. y" C - {; u: h, t5 z' R8 g, @ u/ n
- __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE); // 禁能发送为空中断( {( V; `/ Q3 x2 h! X3 y: U
- }
" U8 y6 s3 p6 l9 R! F - }
复制代码
7 `* K" g. O/ {6 e; q/ U* e9 a) G编写modbus命令处理回调函数port.c文件4 P) `& n, Y$ V7 q! r! a" i
本例程只实现了读取输入寄存器和保持寄存器的功能,详细代码如下:
& S+ e# a# a, w) i% A( {! z
! j3 t) g5 Y6 `9 t- W6 M6 i- #include "mb.h"5 ^' ~8 }/ D- T K; [
- #include "mbport.h"" G2 D" I5 t3 i" F
1 y4 X% S# r$ @- 3 ?6 A0 V/ e& i
- // 十路输入寄存器( p7 F9 l. H% b3 `! D
- #define REG_INPUT_SIZE 10
& J6 O# m! A0 c) R$ M$ E - uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];2 B) x# y/ V( V. Z, u
2 [4 w5 M9 x. W2 b6 n- + z c; S' p/ T& v+ Q
- // 十路保持寄存器
( X F. L5 i* z - #define REG_HOLD_SIZE 107 J+ w3 l: t- K% c2 V# T
- uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];
. c& c% L- n$ ~, b3 I: m% m& m - / H+ I/ o1 Q5 c$ G8 N
- j3 x* I; c: b+ F9 Z+ F2 F$ z- // 十路线圈 }2 S' H7 I3 a+ v
- #define REG_COILS_SIZE 10" h) D% L. r2 k K0 y2 h' R |
- uint8_t REG_COILS_BUF[REG_COILS_SIZE];, ?/ }; ^; d, K7 T& }. f& P
- T( y6 c8 s8 y- Y; u
4 k1 j! r! w- G( a- // 十路离散量
* O+ ~: K7 \' c2 _8 M: B5 d* u - #define REG_DISC_SIZE 10
4 A2 ]4 a8 R' P - uint8_t REG_DISC_BUF[10];6 N: R% b3 F1 Y$ o7 ?/ K
$ y' {' }. {0 m, E2 [ h( R3 j7 P- & E4 {& j5 |- u- B' _
- /// CMD4
# g1 J( u" t1 x4 `* K - eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )3 y. f6 Z3 o, G" z, ~8 ^
- {
% p, s q& B% p$ H* v( f5 ^$ O& e - USHORT usRegIndex = usAddress - 1;
+ D7 A; P. T$ U - . }. f8 b' K1 B3 T' V
- // 非法检测
$ e& I8 G) M) r2 K+ n - if((usRegIndex + usNRegs) > REG_INPUT_SIZE)7 f- W! n9 ^3 r
- {( Q" U1 F9 F4 s* y4 g
- return MB_ENOREG;" c; K3 q: u1 u2 _% B) e& L
- }0 I7 C% Y6 u4 R7 X) i ~$ w
& ^# t/ X$ a4 O2 h1 k, Q/ }- // 循环读取
: \* Y3 {" h% q - while( usNRegs > 0 )
6 t( d9 q3 v0 Z* d ?6 i - {
6 U3 p- A3 x, S6 N+ J; B( m - *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 ); [6 C5 ?& W& o8 [ ?' x
- *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );/ \# i2 _' R( o
- usRegIndex++;- W1 F3 S- Z) W( Y9 M
- usNRegs--;) `+ C/ ?- t% q+ ~3 m# c
- }1 a6 b' ~# x) L% e* C
- ' m5 B/ T3 p) v$ W) X0 h
- // 模拟输入寄存器被改变2 T* Q/ R0 q# T9 A b. t
- for(usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++)* x8 y) b* ]) M8 C" @3 @6 y
- {* G0 E! Y* x) i
- REG_INPUT_BUF[usRegIndex]++;& E, w2 b! p$ N; w0 |
- }
. O& h. Y$ U1 C7 F9 o4 d4 A/ E+ ~
3 x. f0 I$ P0 _: B! E- return MB_ENOERR;& [+ M2 M- D2 ]
- }" Z9 t q/ [8 X
8 w# }4 e* x. |1 A$ F4 B* x5 j- /// CMD6、3、16
0 e$ \* [! c# N* L. k" o1 _. s8 } - eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )4 [9 q5 m. i$ N7 s3 C8 B( Z
- {
$ ]8 X" ^' C0 N* h( T8 ] - USHORT usRegIndex = usAddress - 1;
' [+ e( E5 N7 J; P- _1 d - , _1 Z" B& n: K1 V" v
- // 非法检测# C/ c/ y9 l L3 J% |4 ^) k
- if((usRegIndex + usNRegs) > REG_HOLD_SIZE)
- I2 \& b9 ?" G G0 i6 v- G, H0 m - {; b7 R4 `9 ]- L/ p$ n3 F: v; k! v" e
- return MB_ENOREG;; V5 j' D8 @$ W5 P! L
- }( }3 U7 j: K# \9 f. `
- 8 ]! [! p# j# y+ h: ~
- // 写寄存器' u3 k' h) K F. I5 Q j' a
- if(eMode == MB_REG_WRITE)
0 d" O& O P" D% v& _ l - {
; `( n" c: F* Y0 ~8 g - while( usNRegs > 0 )% d2 B. t" s; s i7 R$ q% o6 J
- {% c# e; v, j# o
- REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];7 p; W7 Q1 s) W( h- o9 [# j% E
- pucRegBuffer += 2;
" _6 D* o9 Q! z/ } n9 S6 d2 x5 L - usRegIndex++;
' R9 n) Z2 u. G - usNRegs--;$ {. H$ x: Q Q4 c7 Q
- }) _- t2 M# w x& Z7 ^9 \0 H2 J
- }
+ h, v- l( P1 y0 k -
7 s0 l; A% ?2 R& q - // 读寄存器
. ~: p4 V& ^3 g Z- M - else
4 ~6 v# A$ s; j7 h - {
9 G+ z, e4 r; }8 C* B# g) ` - while( usNRegs > 0 )
% c/ y2 l( }$ k - {
6 e# g# t! z- y5 R7 d - *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );
! ]. g6 {2 c# h1 `. Q7 Y/ E5 I - *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );
' h4 T% V- j. ~+ S- u( } - usRegIndex++;! t9 W, W* k( |3 y$ G3 ]
- usNRegs--;
Z3 S4 b+ B% W* R. J - }
* ]# h* }. E* b; I! H9 m' Y0 j( ` - }
, f& j" D ?$ I+ C1 P* P) S - 7 d, j4 Z+ [8 h5 b d" }& [0 w
- return MB_ENOERR;
% Y$ ]& m) F) t" R) p* d - }
' Z* U* y4 b0 ?7 Y
* e9 {# x E( c w) P* a/ Q- /// CMD1、5、15
. A4 i# Q7 M- N4 b6 N3 g+ G - eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
0 ~8 c7 \& x9 ], X* Y' V e - {& p" P+ J- F- N$ v8 b
- USHORT usRegIndex = usAddress - 1;4 _. a3 k& T* k9 M3 j* N
- USHORT usCoilGroups = ((usNCoils - 1) / 8 + 1);
/ _" M7 [, o- _ - UCHAR ucStatus = 0;2 z" x+ F1 Z* R! b- m
- UCHAR ucBits = 0;- _% c, M( [# t3 `% g6 b
- UCHAR ucDisp = 0;+ o% R2 H% y- r% R) I9 A
- / {2 I! g; u9 `! T a; E
- // 非法检测
$ p6 n! t- x: ~! a) q4 P* n( R U - if((usRegIndex + usNCoils) > REG_COILS_SIZE). T# k# {$ h& l+ _1 e
- {
6 _& F% r& A" y' Z( |2 c$ V - return MB_ENOREG;
$ ?0 |7 b' b( u/ j - }
+ G% _6 m3 r& o6 P
( j9 i/ x0 n* E+ y* r$ |" d6 T- // 写线圈
% j- j( L% `4 A; z% x" D; V7 _% U ? - if(eMode == MB_REG_WRITE)" }8 M( {- U8 Q% m6 x: o6 P J
- {- _3 J G, q, e+ A# J% n0 y6 I
- while(usCoilGroups--)9 `" P3 s/ _/ G
- {! m/ P% Z* V6 ~& N- L+ Z
- ucStatus = *pucRegBuffer++;
; m( h `; ~, A) U+ _ - ucBits = 8;4 G0 J+ k' F9 F; W4 @
- while((usNCoils--) != 0 && (ucBits--) != 0)
9 q+ d6 V6 G& i- f- { - {1 y J' s0 e' ]
- REG_COILS_BUF[usRegIndex++] = ucStatus & 0X01;
& g& H$ ~5 K/ n9 Y - ucStatus >>= 1;
! c# j+ H1 a2 j; a, N( D$ _ - }8 f8 C% n1 ]* b$ N! x& y
- }
8 x% F j" D& g; F+ c - }. X4 h3 h: y& V s; v
& Y# }5 J& S$ j- // 读线圈
! I( D' d; L* ^# X+ T - else
4 a) ?6 {5 @7 i; ]/ H) _ - {
6 E7 G: _: l3 O5 _# s6 h- {: a - while(usCoilGroups--)
U3 i5 v! f) d' i - {
) R% i+ L/ P9 s1 ~- Q! b - ucDisp = 0;: ~' b* l/ O }" r5 C5 `! T
- ucBits = 8;
+ E# F& @8 V( X v- _/ m - while((usNCoils--) != 0 && (ucBits--) != 0)
" s* x6 r) v+ S' } - {
9 j5 e! c2 E6 _; `" M$ W' n) u* l; Q - ucStatus |= (REG_COILS_BUF[usRegIndex++] << (ucDisp++));# d* X$ P$ y, O
- }5 r( A" |( v4 a/ C, Q4 P9 R, T! m
- *pucRegBuffer++ = ucStatus;
+ `9 y8 f( \# }2 S$ ~& V! Z9 V8 w$ W - }8 P5 t! c! O$ {8 Z
- }% L# z0 k6 {. V. I I# T1 z
- return MB_ENOERR;
2 T# }4 R" k2 `8 t1 p4 w( N - }3 x5 ^+ o2 M+ c; `1 C" @
. n) b }( O8 G; m
8 M4 d/ V P/ p' F/ {; x- /// CMD4
# B. b: X% y3 @' D - eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
7 a3 ~4 \9 g$ ^ - {2 G0 U5 G4 ^* w7 I3 c! W+ d5 S0 Y
- USHORT usRegIndex = usAddress - 1;( m; i3 I- K; t T8 [
- USHORT usCoilGroups = ((usNDiscrete - 1) / 8 + 1);; F0 `+ p8 l" ~5 A
- UCHAR ucStatus = 0;
/ n; ~, s, v+ {6 E - UCHAR ucBits = 0;1 A- v. u ^, p( R% ?( f; p; c
- UCHAR ucDisp = 0;
4 K' S J" B3 n( c - & h8 f( }3 O8 e. E& k
- // 非法检测, `. O/ ?, @" t5 Y" W. [4 C6 u
- if((usRegIndex + usNDiscrete) > REG_DISC_SIZE)
L6 p K$ n, t) j% b- b ] U1 u - {
- z' D, }6 E1 j8 p. G - return MB_ENOREG;
L. a8 D/ F8 L- U& W7 I - }) {; y4 ]4 r0 h g: p* R$ {
- ; F" A2 t) s7 Z! D# z
- // 读离散输入
6 i/ S! s: J2 { - while(usCoilGroups--)3 W7 V# e; E8 J3 i; m# W; ^
- {
) E- P' [% X1 W' | - ucDisp = 0;6 f3 w9 W. l+ U6 N& e; E" b: o
- ucBits = 8;9 C) u6 D; p3 F; h o
- while((usNDiscrete--) != 0 && (ucBits--) != 0)" A1 S/ h: s2 h( W+ m3 }' @1 ?
- {
' A+ `) Q+ j* Z8 O! D - if(REG_DISC_BUF[usRegIndex]): w$ R* ~/ M1 L0 W7 j6 ] X1 S! j2 T
- {
( o Z, X- y, m- j - ucStatus |= (1 << ucDisp);
6 B: J! }& t0 g/ o - }- \. D. @( ]/ H- `7 _+ R- C" w
- ucDisp++;
' B( h+ ~$ F6 K- m, V1 Z4 R) u - }
; c* F/ c* L2 O6 V - *pucRegBuffer++ = ucStatus;
' F: r% D$ ~! s/ } - }2 k; T" W0 B4 @" Y; J V& S: C! Z
- : I$ t( d. p. C9 t2 l" i
- // 模拟改变* K9 m- A- W( S
- for(usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++)3 `" S# O* O; @; o5 Z% A
- {$ ~* z/ \, g G/ J& J
- REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];. |. N! x6 Z: s+ Z3 ]- v2 X
- }
+ P6 F) c5 |- h7 l6 y. \" H' w - " p- N. l! t0 b8 x/ H% D' y4 u4 b; L
- return MB_ENOERR;
% j# ~/ T4 }8 { R - }
复制代码 2 {0 v/ B5 T* F/ W, `
主函数) d# c) ]# K; n+ U5 e( S
- int main(void), L6 U5 w s: {6 O# k- C
- {
- g5 K" o2 a$ d* Z t; X - HAL_Init();9 V' Y- w9 C: F; c8 Y. K% T2 Z
- SystemClock_Config();( [- Y8 R0 q% Z* K4 R
- MX_GPIO_Init();
/ P* S2 F- b$ Q. m* i$ A4 g - eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_ODD); // 初始化modbus为RTU方式,波特率9600,奇校验
1 k# s. k3 }8 @7 U; _. D% a - eMBEnable(); // 使能modbus协议栈3 _5 g7 e w( w4 ^2 p2 U
# V6 e6 G0 [! G# j5 l* _* M% S0 Z; q- for( ;; )% n3 g$ G8 b( G7 Y
- {; _( ], Q7 ^ f1 g. o
- eMBPoll(); // 轮训查询
* W( B# u% ]' U$ B" U! n/ T - }6 \' K0 G- T3 M& }. g) N$ L) B; d i
- }
复制代码
4 M* w2 Q2 j4 E q. s8 @$ e @* C移植测试
7 E! F g* a& y+ R% d/ B2 Y% l9 Q* y
J/ z( z5 I" ]: B( E
* F! d7 ~, N2 O6 }* w4 W7 uends…
2 O8 N3 _ b' \. {& b# }$ i+ L; j$ |
1 X, O5 [$ n5 n) k5 V, e
5 G3 e0 b! J# U2 [ |
我的是stm32g071系列,移植上去不行怎么办