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