modbus命令码表:* c1 y1 n) q( T! n
# a6 b% ]* l/ D0 [, ?& t2 X
! 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
" |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 {
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
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
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
) 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
# 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
* a3 S. L+ X' Y& [
取消掉自动生成中断服务程序,在移植过程中我们要自己编写串口和定时器的中断服务程序:& e! e4 K' a; M% P& n
# V$ ^: h! p) H
- 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
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
" 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
$ ]- @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
- BOOL
* q6 V8 B* L6 U& T9 Y- [/ P - xMBPortTimersInit( USHORT usTim1Timerout50us )
& [1 m/ @' Q" k& x - {
/ ~ U$ q! V* c2 k$ e" S - TIM_ClockConfigTypeDef sClockSourceConfig = {0};
6 r; K/ a8 _' O3 n - TIM_MasterConfigTypeDef sMasterConfig = {0};
3 K7 M+ X7 R1 v' u - % z6 y3 B A8 a2 p
- htim4.Instance = TIM4;
8 p, A5 h, G: u I) l5 h* q4 g - htim4.Init.Prescaler = 3599; // 50us记一次数7 A6 E5 S) }/ _
- htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
- A1 J7 y5 R. \ - htim4.Init.Period = usTim1Timerout50us - 1; // usTim1Timerout50us * 50即为定时器溢出时间
# L" H3 v5 z+ A0 @# _4 n - htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;7 C$ G) c5 i$ F" a6 m
- htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
, G3 Y( w y( ]6 `1 E6 R1 _ - if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
: p# M _8 R5 u) v2 I+ l - {
- v1 x) b5 C0 x( U - return FALSE;9 y( n; ^; P/ }! }$ |
- }0 w; i2 ^- L7 l
- sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
( N5 K- ]) C, ~, w. s5 p a- ` - if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
+ F7 d9 v6 x! _4 i7 D - {" m% r" P% `2 I: l& r; z2 T
- return FALSE;8 T9 j$ i5 T; u+ b; s! R4 }
- }
$ T! v7 k2 a8 b4 f. d" c: i0 T. y - sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
; \0 M2 |. \% d" N. F! l - sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
2 U# x6 {8 h! |3 @8 ^ - if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)7 f* N- P2 q4 h4 Q- f/ H8 F
- {3 r6 j; w2 O7 i8 a& [8 t
- return FALSE;1 N" u$ T- Y3 J: {8 f
- }
" U) i' C. H f
. M [% w8 w6 Z. I5 t- s- __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE); // 使能定时器更新中断
. G$ v( g5 Y2 C1 h- R R x - return TRUE;
/ i* ~& `( T2 P% N$ \ - }0 ^1 g! H& ]! }+ D
; C) D8 B3 m( |- inline void. T7 |/ N; |" ~' \& b. S1 j
- vMBPortTimersEnable( )7 E# W# t8 g* [/ g
- {4 w( [. d9 z: P, H2 x1 A
- __HAL_TIM_SET_COUNTER(&htim4, 0); // 清空计数器2 q+ h% Z, I( [5 N
- __HAL_TIM_ENABLE(&htim4); // 使能定时器
m6 D$ x$ i, E L; u# Y - }( Z* s) m( @6 r# t
/ u+ C% _( L) _& M2 W1 j- inline void. b6 b3 O' N7 j: {- V
- vMBPortTimersDisable( )
4 n7 | v: w. R; n - {+ q2 z4 {9 V5 J0 V8 n1 q9 R' d- S% f
- __HAL_TIM_DISABLE(&htim4); // 禁能定时器
; p3 a+ ?! C9 {0 a/ T) o - }/ W9 t* ^. ?7 C: {) B& h" Q2 J) I
- . n# ~" t8 Y& }) `
- /* Create an ISR which is called whenever the timer has expired. This function( b% ], Z, }, U
- * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that5 {" H, I; Z9 t; ^
- * the timer has expired.
7 K3 t+ f- p) B+ E1 j- W8 p - */! Q' l0 O8 g. ]. l- K; P
- static void prvvTIMERExpiredISR( void ): t/ I# t& K$ \4 i( b7 m3 k2 r
- {1 l/ t/ p* S' [+ z5 h- V# Y
- ( void )pxMBPortCBTimerExpired( );# z# V* L& V6 L+ n2 h& d
- }2 j G) v. A. X& E0 p2 W4 g
- % A7 ?" ^) t, v, H( T5 s+ s
- /// 定时器4中断服务程序
- |9 G8 n+ R' X5 @9 j9 v - void TIM4_IRQHandler(void)
" N5 E* ?& ~( ^* P- S: i - {
, G1 b, m5 _( d6 u6 E* m - if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE)) // 更新中断标记被置位
7 n4 G( w+ `* F/ {0 | r3 | - {7 [: V: `2 w& k* Q; M9 q
- __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE); // 清除中断标记
# @" P: Y9 ]. o! d- J - prvvTIMERExpiredISR(); // 通知modbus3.5个字符等待时间到
9 `" G" W- p, { - }
. V. Q: S4 p+ H5 @, C* J$ e! c - }4 v% E7 A3 e; E
( N, _" W3 J& R/ I' N+ S0 I) x* o- $ 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
- /*. ^ A* }! J {! Y. G9 t
- * FreeModbus Libary: BARE Port
* Y2 _( w9 G# ^* h3 W( q$ M - * Copyright (C) 2006 Christian Walter <<a href="mailto:wolti@sil.at">wolti@sil.at</a>>
: n) f$ m6 w9 Q& z4 V7 x - *
8 d; V- q# n, c - * This library is free software; you can redistribute it and/or6 F, P. P- P2 m( @' C
- * modify it under the terms of the GNU Lesser General Public5 w; f& C: F! w3 [! p: o P6 g* ~
- * License as published by the Free Software Foundation; either
% y5 u1 v, n/ l) I( y$ V3 s - * version 2.1 of the License, or (at your option) any later version.% \- o' y9 S1 T# g) {0 Y
- *; `, {8 M" Z9 J/ X
- * This library is distributed in the hope that it will be useful,! ~1 d Z( D c% c
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
0 G+ e1 K9 k/ e% M! z) Q) A; d - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 K! S( C5 L6 T0 h/ D - * Lesser General Public License for more details.: d D' t! i* B2 L; M
- *, ~3 ?4 K& R( m- T. [
- * You should have received a copy of the GNU Lesser General Public9 }6 M: L) m7 e, ^
- * License along with this library; if not, write to the Free Software3 w7 E2 A9 g& Q- U) L0 }+ F' `
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/ o! N; f& b; Q1 Z* |/ P - *: c* {" ?5 q& }2 c( k
- * File: $Id$
0 Y1 U/ Q0 b. ~ - */
o, Q" h2 z! `9 _5 x9 K7 y - ' k) g9 n/ p, B9 \. m! K1 i! V
- #include "port.h"" y: Y) } ~: q9 V8 b# W0 K
- #include "usart.h"- b4 w6 Q% l& e$ d6 K
* _8 P% ]0 G' o$ o# \- /* ----------------------- Modbus includes ----------------------------------*/1 @$ K- }' Z0 z# u* }6 B- i) ~
- #include "mb.h"! O. U- l# x0 i2 }4 z
- #include "mbport.h"4 X% ^+ E3 ^( D% |% e3 l6 {
- 4 c$ C* C' p3 M! \+ o
- /* ----------------------- static functions ---------------------------------*/
+ U3 T. o1 D9 I; o5 U - static void prvvUARTTxReadyISR( void );
% N- L) D- }1 N3 d0 F2 i" d, e - static void prvvUARTRxISR( void );. g) R. f3 }: _0 [
: o0 e0 _" c( m- /* ----------------------- Start implementation -----------------------------*/
% w0 j+ w& K/ x0 U, X0 i, [ - void7 P* t6 h2 E5 B! \. x0 |& ^5 A
- vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ) _9 Z( X) E5 v. i
- {
8 _7 a# G Y! d- d - if(xRxEnable)
1 {+ Z- z, n4 d' w7 H+ M' c - {* Z$ q1 V/ W6 y
- __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); // 使能接收非空中断6 f1 k* r p) R" M8 N3 k# [, U
- }
K9 z8 F; D# p ^& F7 w( d% V; R - else
) l1 V t1 [* o" V/ j: N4 d - {
9 V' t& N V$ \6 L - __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE); // 禁能接收非空中断
' l) y9 t! J' w, E5 }- `1 u. [3 D - }! Q J1 c+ v2 C$ t( i
/ E$ L; c9 l8 K9 C: D e- if(xTxEnable)
/ Y$ w1 C% ?: a/ J7 V9 k4 `6 Y - {( [% `, k$ Z9 J5 z l' a$ N
- __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE); // 使能发送为空中断
. U: o, t) |/ C0 _1 R+ K% X" u9 _/ Y - }
" y2 b( a$ k0 {& l0 n1 Q8 K - else
' I, i8 N2 S, V! Y8 {' O/ p2 ? - {
* K" k0 S6 T" E! P - __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE); // 禁能发送为空中断
$ S5 _2 R4 \# f Z - }
, j9 B n0 g8 V, _6 v0 L) X# i+ @ - }, U1 n3 E/ Q- t" }. s2 b
& |2 Q3 g5 A, B2 l- BOOL- j6 X) f+ f# R% Z2 S3 a+ K9 R1 R! `
- xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )/ z, U+ o' p9 W7 _
- {
* @! D2 B7 x) C, ]/ g - huart1.Instance = USART1;
( D; _* M* H0 {! F - huart1.Init.BaudRate = ulBaudRate;( R4 o) g# K* W
- huart1.Init.StopBits = UART_STOPBITS_1;
* M; o) ]* Z) {" f: m - huart1.Init.Mode = UART_MODE_TX_RX;
5 e# _) g; r; _' s. o( l) o$ l/ P - huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
4 K. x8 U5 C8 l - huart1.Init.OverSampling = UART_OVERSAMPLING_16;
, ~- S$ E$ Y$ V - ) L V+ x- ]# Q- Z% \, H% a7 x4 J
- switch(eParity)
5 t6 G4 u8 N- `: P - {
4 ^9 _: K6 J b( P3 P, Q. @: E - // 奇校验
* ?' o( [4 ?- j4 C - case MB_PAR_ODD:' \/ u2 S+ R# [9 O. d) f! @; a
- huart1.Init.Parity = UART_PARITY_ODD;
0 t$ V9 i0 M( ]9 d* Q3 z; ]. M" }/ d& l - huart1.Init.WordLength = UART_WORDLENGTH_9B; // 带奇偶校验数据位为9bits
# d0 X3 A( m2 n e - break;/ B5 b* ]6 {4 l+ `1 j
- 3 n5 C' f, M8 ]7 H! r3 p3 L( F
- // 偶校验
) M+ z: B' V# I) j) T& T4 K/ E - case MB_PAR_EVEN:: s5 p+ K! X* q- }
- huart1.Init.Parity = UART_PARITY_EVEN;+ c5 X; c! Z* f+ h' _" T) n3 u
- huart1.Init.WordLength = UART_WORDLENGTH_9B; // 带奇偶校验数据位为9bits
; g+ c! d3 M3 @6 H# I) | - break;
& W! {9 q3 z# |4 i) w7 c: j - ' Q& N/ M* I2 o8 A0 c* o
- // 无校验
" d' J+ L# H: r" K, ~ - default:
) n1 s* n% ^" D3 P4 ` - huart1.Init.Parity = UART_PARITY_NONE;
- q9 b1 n! ]4 D! T - huart1.Init.WordLength = UART_WORDLENGTH_8B; // 无奇偶校验数据位为8bits
' y3 [/ }3 e, c" `4 ]% k - break; b. }/ A" a% t' I+ G
- }8 y1 L% [/ u3 z& M. s( S
- return HAL_UART_Init(&huart1) == HAL_OK ? TRUE : FALSE;2 H- _2 ^4 p9 U8 W
- }* X; s) t1 c8 W6 k9 M0 e5 U" ~
5 X9 b9 t# n' y" k- BOOL
1 d" {5 z: L0 W& ? - xMBPortSerialPutByte( CHAR ucByte )
/ K4 i* D0 ^! I0 }% p4 E - {! i9 Y; C5 I" g8 m/ \& V" a
- USART1->DR = ucByte;
1 P5 _4 x+ E- n* k# ^8 P - return TRUE;
+ O0 n5 B& s8 A$ @( n9 i# m - }/ R" e! z8 l' j1 k8 U( l' s
( Y1 b# `/ _# [6 t5 i! k, k- BOOL0 ?. T9 `2 l. g9 |( a: X1 a
- xMBPortSerialGetByte( CHAR * pucByte )- N3 |+ @& p- A/ l9 h
- {
- B* t' V3 V$ Q3 [ e( @* A - *pucByte = (USART1->DR & (uint16_t)0x00FF);, j- b' q" H/ q7 T* k% h
- return TRUE;
! `2 z0 b+ a5 f4 a - }% p+ f( ? [( N6 l: A, z+ k" O
- / o# F1 w$ q. h1 K
- /* Create an interrupt handler for the transmit buffer empty interrupt/ x- k1 z( S6 Z
- * (or an equivalent) for your target processor. This function should then) }3 D& ^1 B- }6 X
- * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that5 A% L. M2 v0 a$ x7 l" S
- * a new character can be sent. The protocol stack will then call
' ~5 e. \( K3 D! r - * xMBPortSerialPutByte( ) to send the character.
$ P: K3 V6 p# p+ { - */
9 S% X; n/ G+ f7 h# K - static void prvvUARTTxReadyISR( void )
9 R+ P/ h( @0 u6 |: J8 g; v6 k& h - {7 j3 H3 U; G$ D }1 _% L
- pxMBFrameCBTransmitterEmpty( );" x5 s1 K) B9 t5 Q
- }3 r1 X% s% U( g
- : a ~8 @" E1 Y# H( K4 h
- /* Create an interrupt handler for the receive interrupt for your target
$ G* |3 {2 c8 X& |1 c% N7 a - * processor. This function should then call pxMBFrameCBByteReceived( ). The5 A( b1 p; `# z1 b7 [
- * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
1 H/ W5 {' U# ~5 `' M [ - * character.
. V y0 @6 A @6 g+ v m! [) T - */
4 \2 l+ G' Y- q& l$ x# v1 X7 E - static void prvvUARTRxISR( void )9 i/ p1 N! F+ E" m1 f' t! o. T
- {
& q+ ]& ^# F( o8 `1 m - pxMBFrameCBByteReceived( );
& d* p3 a. J/ b0 g' C6 z; K - }7 s [& G8 t( V6 N
- ( Z( u& L( L' m/ A1 N
- void USART1_IRQHandler(void)( C" j" V3 B9 Q- G
- {
! i' m( \4 m0 n7 @6 E' ?6 { - if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE)) // 接收非空中断标记被置位) R3 c( @% l4 e6 T% |5 M0 G2 N
- {4 [5 i* s; @4 W3 n- A
- __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE); // 清除中断标记
5 Z1 |3 u0 N/ W+ P5 ~3 v - prvvUARTRxISR(); // 通知modbus有数据到达
( O8 X8 R* ^% ~( r* D1 v4 H* a - }+ g8 t/ ~! P/ n) \
2 [* z- V* }: \0 n0 z; h- if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE)) // 发送为空中断标记被置位& z8 N! N- j( L4 k* O: |. J
- {
% @5 z9 ` L3 d9 ~( M( w, Z# O - __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TXE); // 清除中断标记
; y! a |5 }, R2 c4 S" W" K - prvvUARTTxReadyISR(); // 通知modbus数据可以发松
" Q8 w4 Z' L* t# s$ u - }4 f& S" D8 {* O
- }
复制代码 % 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- void
$ u+ G- i6 z. e4 e. R& c - vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )7 e7 R* {1 P& c9 p p. \
- {
3 s) u# M ~/ i& G' S* u& _0 V - if(xRxEnable)/ Q$ @$ N( J9 @2 R1 e5 _
- {
& f; o1 B1 r3 m: a+ M - //
6 p Z+ e0 l; V - // 在此处将485芯片设置为接收模式
7 u& g: N u6 r+ W, w. o' J/ Z - //
0 y/ L' N) Z3 L6 ~ - /* do something */9 V: x! H! t e
- __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); // 使能接收非空中断) q: \9 ]& {+ C7 X1 ? o8 h/ T# U
- }: d% _5 V, |9 k+ i( _
- else' I, v% B' H; b0 w0 G- P4 ?( @
- {
; u/ b- B0 P) S0 S A. l/ R, @ - __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE); // 禁能接收非空中断* Z! H2 S/ t4 m5 I. ~: I
- }0 Q# e! M0 `9 \8 V
- : p* z& j7 E0 _% l
- if(xTxEnable)6 v; Y" v: @$ ?; X1 G! f, D
- {
' |- ?5 x4 G" q - //% h" m% D' C- }( t2 x. `+ {8 o G0 [2 f
- // 在此处将485芯片设置为发送模式
2 D& D6 N# T6 i# Z# m - //
- z0 J" B" G9 a- J - /* do something */
& [1 O: G0 G; @1 L" D9 m - __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE); // 使能发送为空中断
+ d" l$ D* P- i - }* D: `/ l: O: E- e% g
- else
/ \! y( f* b* {+ Q2 L+ z - {
# k% | A; A2 M; @! G - __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE); // 禁能发送为空中断5 q& ?3 W: l9 o% f5 H
- }
9 U+ ]( G& X* s- y9 ~7 b: ?8 O - }
复制代码 $ 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; `- #include "mb.h"
' B5 J4 j! A. z! C/ f7 w! V - #include "mbport.h"" g- r5 @- _9 j# p% ?- r
% L$ C7 B! F' t- w1 ?* y. [0 ~- ! c, b2 y+ F7 x7 Z- I
- // 十路输入寄存器0 ~" w# P7 `( N7 f2 ^% p7 @8 M+ N7 p
- #define REG_INPUT_SIZE 10
0 V- d* s" y; w1 p- u - uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];8 o( V7 z- y- q9 C/ l
9 `' v2 \1 y: ^" m- p/ _
' r* U0 i9 p: |- // 十路保持寄存器
8 i( H2 N- W2 A; S - #define REG_HOLD_SIZE 10
& m& ~3 `0 E1 s" K$ m! |% J - uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];* C/ y/ Q* W) |) e% n s2 L8 r. ?
- c9 b! J- m; H* j# c
- # O- o( ]+ V% I6 J2 Z) q9 d
- // 十路线圈
" V4 A1 @9 r6 { - #define REG_COILS_SIZE 10
O5 I+ K' N/ y* R - uint8_t REG_COILS_BUF[REG_COILS_SIZE];+ @2 G8 P6 w$ Y8 R4 a
- c* \; S- y y4 y0 X/ w
- ) N$ x; e5 V) [1 W* v. w
- // 十路离散量) S A- |2 c$ k# y6 P" s
- #define REG_DISC_SIZE 10
/ W& Q' ]9 B& c& w W - uint8_t REG_DISC_BUF[10];
$ z3 |- e) o* e - " o7 g) ~8 O5 s* V1 [ M& u1 I
- R* S% _5 p4 K1 X; {& d% B8 H- /// CMD4
2 \/ V/ q7 _( F2 i - eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
8 X1 U) x- X' ~/ J! T U6 M - {
: y8 j r- t' M; y5 Q7 R% d' q - USHORT usRegIndex = usAddress - 1; + n% i) N) z7 M- B4 ?
7 a% s0 T# ]! L$ }( K- // 非法检测1 m! z- K& |% Y. z0 d* g% R/ j
- if((usRegIndex + usNRegs) > REG_INPUT_SIZE)4 o0 b5 S8 @5 h3 w( r$ W! Y1 }* ]$ E
- {
8 n# i; d. X$ n" u" t - return MB_ENOREG;' i, A. v! \0 W- P1 @( W. b4 W
- }- P" |- E3 Y6 J5 T8 E# ]9 A0 Q
6 D' c/ t$ ^9 c/ I1 r: r- // 循环读取0 x9 n7 b+ P$ ^
- while( usNRegs > 0 )
, M6 _& @6 d; N - {9 s2 z' Y) i) a2 s; s* P" L
- *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 );
2 `! g; v7 A% v# s. \) X9 t* o& x - *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );* l# o! `9 z4 R6 m& H
- usRegIndex++;1 C. Y1 m; v" g. K+ A$ m
- usNRegs--;
: x! S f8 T* l8 |# ]' k% r, { - }( y8 Y: C1 J' d/ M: u8 M8 h! ]
- 2 ~1 H5 \3 L! E6 j
- // 模拟输入寄存器被改变
& ]3 C, Y$ K4 B. X* o$ g - for(usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++)
1 O/ C" o, R, }+ t - {
* n8 @: K0 A( J7 e' @ - REG_INPUT_BUF[usRegIndex]++;7 h- R7 h2 c0 ]! a9 T
- }& ~$ x% U6 }) c- c
- ! E2 s9 r) i: ?
- return MB_ENOERR;
v8 {5 |- R" l& G - }% {5 v0 x' {. i
) B; _0 u% J/ j( L6 R- /// CMD6、3、16
6 n- _/ t, O2 v - eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )' I9 r2 G+ z- h1 r
- {
6 v K# d1 ^- F) U u - USHORT usRegIndex = usAddress - 1; ) C: Y) F3 L7 D8 T. {
) L5 ]( V, m: W5 b" ]& D- // 非法检测
! V5 o7 d: O. h+ h/ y; j; I. s - if((usRegIndex + usNRegs) > REG_HOLD_SIZE)
; D( S* j0 M. W - {
. \' [- F6 p: u' F1 {# n - return MB_ENOREG;
4 u; l9 G8 F% r1 L H" W# b - }
/ w. k+ E' m, o, q
! n C6 y! o" m- // 写寄存器
7 j V) |8 R& Y5 ?0 T - if(eMode == MB_REG_WRITE)5 b; q/ t5 T. X7 P
- {( Y$ ^, o( g+ [8 W7 O& u0 D
- while( usNRegs > 0 )
- P& _* G, u3 J0 C. i6 i3 k1 S6 V - {
* S) n5 {2 x5 O- u - REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];
) Y( e l( O$ e7 \% Q - pucRegBuffer += 2;
1 {" O ?4 d& r - usRegIndex++;% a9 t2 C. Q" C' h
- usNRegs--;# _' f1 Q7 u- I1 u
- }9 u' K, V) w) W [# T2 |% V) ]
- }
0 f* D$ e1 v$ t& M9 ^% y -
4 m9 l. Q0 G a6 U - // 读寄存器
. r' Y h4 b. v; Y' f# n8 v0 Q - else: a3 L( e) f" V5 c& D I
- {
( Q3 M& J, T- V - while( usNRegs > 0 )
9 |+ X9 D1 K8 D! r% [7 p, @ - {
2 L( o& H' O' M - *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );
! G- b/ U5 c, I5 p, r6 A! w0 x5 B) g - *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );
$ a- t& I9 t% B }2 j: C - usRegIndex++;
6 {* T( f1 `1 t( R+ w- D9 y d - usNRegs--;
; F/ B4 p6 _" E8 C - }' J& U- P. f. J# u
- }7 b# y7 k# l; S! x5 Y
- 6 |, \- ^. @8 ?+ }4 [
- return MB_ENOERR;7 v8 d9 A M! K; h( l9 [
- } C- x9 W' N6 i% J) f% f
# _7 d5 j9 Q0 d2 |6 B u# U- /// CMD1、5、15
+ F! i: z7 |) h+ P) E. d# w9 z - eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
% M2 f3 i6 e$ N y4 M G5 k: ~6 g - {/ U$ }7 R" x1 x2 A- @% E4 ^# ]
- USHORT usRegIndex = usAddress - 1;9 u. y* W4 {. \/ N3 o- z* L* @5 X
- USHORT usCoilGroups = ((usNCoils - 1) / 8 + 1);; e8 z' ?2 r& _; R7 }* W6 L" R
- UCHAR ucStatus = 0;
6 |+ y2 C* _: @- @6 F Y1 O: l - UCHAR ucBits = 0;
2 F$ @7 f! j9 Z6 c - UCHAR ucDisp = 0;+ J5 H$ G; c4 [' X& B2 o
; \. [8 f3 }0 V& @1 s- // 非法检测
* a/ d: o5 \0 X- }. M2 t" T. J% R( U4 `9 ` - if((usRegIndex + usNCoils) > REG_COILS_SIZE)* L; N( R" s' W3 G. f9 w
- {
; m. a' V4 F/ l: j1 V8 ? - return MB_ENOREG;8 G) ~. T2 R. o* [
- }3 D' M0 F3 i3 r ]# Q
- . X8 A& | p: Q0 C: C( x2 n* ]
- // 写线圈
7 u9 o1 L; r: F! s. K7 e- _8 X8 K - if(eMode == MB_REG_WRITE)1 q, D+ Q4 o9 O- N7 _
- {
& d. J0 C8 `4 l7 ?( w5 m - while(usCoilGroups--)
; a; [: c4 F3 O2 [% E' n0 Z# V# T* V - {1 Z6 o" B+ P$ D5 v9 x% g
- ucStatus = *pucRegBuffer++;5 e/ c h" V/ e" E8 _
- ucBits = 8;* h6 V v# J! A6 p' r
- while((usNCoils--) != 0 && (ucBits--) != 0)0 F3 w7 g$ l/ p+ @
- {$ g! S$ i% I+ f$ o a9 E% @
- REG_COILS_BUF[usRegIndex++] = ucStatus & 0X01;
( ~1 e: v* F6 x* G, j* K8 Z4 ^ - ucStatus >>= 1;: X2 a1 i6 M! Z, E, l
- }, W8 U9 w4 D7 I: W7 U8 V4 P) z' {
- }
9 o! [' M+ D/ T$ D2 D) Q% A - }
5 w8 Z6 }2 g8 m5 m4 } - % e" U: F# Q: b/ S1 G( o8 e0 A
- // 读线圈9 [# J8 @ g4 I
- else
' Q1 [6 [0 ^/ q) c! S - { g! j% B N4 r0 m* @6 I, B7 z! u; j
- while(usCoilGroups--)/ v# M( @: q! I d5 e
- {& P' j0 T+ _; m7 C
- ucDisp = 0;5 d- a& s# l$ l; o c( Z
- ucBits = 8;
0 x k% z* [4 {0 }3 q - while((usNCoils--) != 0 && (ucBits--) != 0)
0 V' O0 K$ t( b - {
! G7 d1 K5 P) G5 o3 _2 M - ucStatus |= (REG_COILS_BUF[usRegIndex++] << (ucDisp++));6 u7 E' @' X- O# k8 H5 ~+ e, ^
- }
+ k# w6 R4 |% c- h& o - *pucRegBuffer++ = ucStatus;
" X7 q$ i" g: a/ x! F# h - }
- z' I7 e6 e) M1 ~ - }1 Y" T2 o( a1 q/ z
- return MB_ENOERR;
# i1 {4 f5 J/ r - }
* f" t+ K H6 B - & f+ g6 f" s4 G( z$ ]2 C$ n
- - p# ]0 t6 `2 k' ?, Z, D
- /// CMD4
% a3 U$ }, l# K - eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )8 i; |* {7 C% R! m- X d
- {' {9 x4 m, _8 u3 m2 S" c
- USHORT usRegIndex = usAddress - 1;2 b5 K, N" O/ C7 c6 G# d. x
- USHORT usCoilGroups = ((usNDiscrete - 1) / 8 + 1);/ O6 ~- q6 g2 g9 t$ L' n# [7 k
- UCHAR ucStatus = 0;4 R2 k P6 w+ g6 M0 F2 X
- UCHAR ucBits = 0;
% P3 v: [4 q6 ~9 {: V$ d2 u - UCHAR ucDisp = 0;& q- F' o' s: n9 I. ?' I" s
- 1 U, [. Z; m" o& u$ Q9 V
- // 非法检测( N! V- o" |- {7 W6 Z1 b) _2 `$ H
- if((usRegIndex + usNDiscrete) > REG_DISC_SIZE)
/ a7 {" G/ _1 C - {1 K4 ^' } y) u5 L" P9 Z5 h8 Y5 ?
- return MB_ENOREG;
8 Z2 r [ ]9 Y - }1 B6 H+ f, T2 ~8 f e# n7 c# N
- ! e* e @( F. S+ [: U! b- s. s- [
- // 读离散输入
. j7 {& g+ E U/ R( u1 \: n - while(usCoilGroups--)+ B6 u" Z/ s- u" V
- {
5 U7 x9 k. [/ f; d, ~ - ucDisp = 0;9 ], o9 \* a1 `/ g
- ucBits = 8;# p' }" ^/ A. I3 b
- while((usNDiscrete--) != 0 && (ucBits--) != 0)
+ u( p5 I8 R* y, e6 A* W, ^ - {
4 J7 [5 a; n3 t; R" A - if(REG_DISC_BUF[usRegIndex])
s* M) m4 ]# P% K ?# o - {$ I( i+ B) w7 I8 k) X
- ucStatus |= (1 << ucDisp);
: M1 A! E9 V, n4 s' p - }
" t, J- n7 ?& p, a3 a& [; |( d: g - ucDisp++;
/ ? c8 ]/ N- F0 A% I/ p- H* l - }
, S" G) ^& S. L; D2 P6 q* J - *pucRegBuffer++ = ucStatus;
2 s4 d4 A8 r, w, N - }
" `! T2 W# [ b# M" V
( D( ~5 h) `& d2 C" P- // 模拟改变
1 }( X; Z$ `/ p+ a - for(usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++)
: ?7 J- L0 R6 E/ v# @ - {
( A5 O8 o3 h3 y2 F9 x - REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];
) b: k! x( ^+ v- g - }/ X7 S4 k0 \, t3 W: k
- . f0 J* K/ } Z+ z, @
- return MB_ENOERR;
3 Y3 \! s/ B/ s" p - }
复制代码
1 m8 P( t: c z% i j2 i主函数5 J. z& {! o) p0 H, P
- int main(void)
, h, q) ?& ?" l/ Z8 Q6 c - {
. j# F5 L; t7 G% w# ]# l - HAL_Init();$ M+ W2 ~/ V: x9 _% y% h
- SystemClock_Config();
5 |% w/ [' r' ?' O! b/ V i8 ^% ? - MX_GPIO_Init();
9 }2 J" g% E1 h" N6 t' _, L - eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_ODD); // 初始化modbus为RTU方式,波特率9600,奇校验- B" T$ r" e& o0 K w& ]+ _. J
- eMBEnable(); // 使能modbus协议栈# }) |: m& f: k! g s' F/ D
- : A) E0 E. S5 C7 h" ]% z( j
- for( ;; )' u% S: I3 ~: D
- {
( m# } ]2 Y* }6 |+ t - eMBPoll(); // 轮训查询
5 `# V3 s3 \3 b/ X* U6 P& R - }
" ]' ]) J4 F' g c6 g: w - }
复制代码
! d7 a6 ?- o5 n* t2 b. N移植测试
d. T, G% x2 d& m" s& \6 E7 C- y1 |8 {( V& R% ~9 a
~' 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
|
我的是stm32g071系列,移植上去不行怎么办