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