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