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