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