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