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