|
1.新建项目
! y& A2 k# Q, G. i* Y/ `
在PIO的Home页面新建项目,项目名称freertos_modbus,选择开发板为 MonkeyPi_STM32_G070RB,开发框架选择libopencm3; - 1upload_protocol = cmsis-dap) `# F) b8 `, }8 S2 _7 X+ }
- 2debug_tool = cmsis-dap
复制代码
+ P# d1 z1 A; V8 Q/ _0 z8 B) W& K. s9 ` B
2 编写程序2.1 添加 freeModbus 库然后从FreeModbus源码中的 demo\BARE\port中复制文件到工程的src\modbus_port文件夹下,最后的文件夹结构如下: 这里使用RS485,因此需要对RS485使能端口进行配置,其他为串口的配置,然后在发送和接收中断时候调用modbus相关接口进行处理: / ?, Q7 [7 }; v% P/ a2 G
- 1{
# W4 W! B# o5 j1 M$ f/ J0 y - 2 "name": "FreeModbus",: g( E9 I! K& Z5 R
- 3 "version": "master",+ Y$ q- O5 q$ E# K" Y* V- x i
- 4 "repository":{
% l2 D$ G1 v2 |+ \# E: `% l0 Q7 k3 m - 5 "type":"git",. N: U9 g/ I* @
- 6 "url":"https://github.com/cwalter-at/freemodbus"3 q+ V+ X/ w) h
- 7 },7 H! x" _. `! a4 |1 g$ t
- 8 "build": {" y8 u5 I' C# R/ G
- 9 "flags": [
$ J# c6 [! D, I, z( t - 10 "-Iascii",8 X) p* E" B% j; M, g0 f* W
- 11 "-Ifunctions",
: N: J+ r5 M7 d* D0 ]6 e7 b9 d - 12 "-Iinclude",/ R' _" T4 y5 l' }
- 13 "-Irtu",
0 s( R* q. `/ I - 14 "-Itcp"/ K5 M4 w' a7 [! f3 W1 e$ ~
- 15 ],
0 S5 x8 g- S8 E8 I' b7 k& C - 16 "srcFilter": [7 N( [# |2 R. L7 v# v& ^7 Z
- 17 "+<*>"
/ a4 u3 B# U- \' V7 U- X - 18 ]( @. }3 k$ ?! `
- 19 }0 Q/ g4 ^ z7 ~! j* N
- 20}
复制代码
& U6 {! a3 S& f6 S0 Q, }$ w8 W% q ]% B# Z8 l V6 Y6 ]
然后从FreeModbus源码中的 demo\BARE\port中复制文件到工程的src\modbus_port文件夹下,最后的文件夹结构如下:& J& o" o5 M- z3 ]
; Y8 |1 Z7 {8 X8 R3 p# y. o3 ^* w$ U Y
) M! w4 t0 h" z' m2 Z1 \! Y' Y! K
" O9 J4 e& ^1 ~" q; ?& l
2.2移植* g5 e5 e: _" b; D8 c* H
portevent:5 R4 K5 _! ?8 [( R* l7 K9 Q O
- 1/* ----------------------- Modbus includes ----------------------------------*/
. A& z1 O- V: v - 2#include "mb.h"; {& ^3 E- Z6 W. A4 _: i6 y
- 3#include "mbport.h"
3 f c& y) u3 S! A - 4#include "FreeRTOS.h"5 {/ ^$ _2 N, C) ^: o4 R/ Y
- 5#include "task.h"
. q- N! Q7 i+ R - 6
8 a5 _+ d9 J) X8 m- U' Y% n* ^3 N - 7/* ----------------------- Variables ----------------------------------------*/" Y0 S% Z3 C. U$ k- I
- 8static eMBEventType eQueuedEvent;; M' @# z% V3 q. G- i% ?/ }
- 9static BOOL xEventInQueue;
" q( y/ F2 t& s. u3 J& f& F" b - 10static uint32_t modbus_last_active_time = 0;
2 A+ f+ j( @8 x) l* K8 ? - 11
, }) H6 \4 i7 Z8 R( ~ - 12uint32_t get_modbus_last_active_time(void)
3 y6 N- W) Q0 W! w4 k' A - 13{
9 E# C6 m+ ^6 ?" v - 14 return modbus_last_active_time;
8 ^8 }! J2 a& d7 q" { - 15}9 l; k: @% g, x% {. | K3 e( F( A
- 16
2 y4 ^$ j; Y$ V5 K' k/ J* p9 x - 17/* ----------------------- Start implementation -----------------------------*/5 V0 d; T, C9 }# i8 z2 g& T
- 18BOOL
! h# Q. r1 B$ C$ E( [8 L( h2 `( V - 19xMBPortEventInit( void )
$ [. ^3 P* x! Z a$ d/ f5 |1 @+ u - 20{# W, a0 V& y& n/ a8 |0 _0 L% j
- 21 xEventInQueue = FALSE;/ F& S) D$ P: {3 Z* q, O9 M1 s
- 22 return TRUE;4 X- _, ^9 m. O Y5 u1 H
- 23}
% x3 W% b l Y1 @ P. {7 C3 g - 24: Y2 c0 U& R0 `2 L3 G) G
- 25BOOL, ^' P' B! H V- x6 [& Q) u/ _
- 26xMBPortEventPost( eMBEventType eEvent )! Z3 \8 W4 {7 f& i0 |
- 27{
0 d! D3 F: b, \1 F4 @2 z9 w - 28 xEventInQueue = TRUE;
* p* p6 [& }6 X; {8 f - 29 eQueuedEvent = eEvent;
/ k* o% r2 j' o# C1 z& [ X - 30
" b) l! l. k! O/ r - 31 if (eEvent == EV_EXECUTE) {/ D- r/ [4 I# a7 w
- 32 modbus_last_active_time = xTaskGetTickCount();
5 h, t M+ z5 I2 ]$ v/ S0 s - 33 }
" }& }: W- ~& h8 r' x0 O - 34 return TRUE;
6 O% b$ a: e- ]" u7 J" f' z" a - 35}+ d) z4 g% R* Z9 G3 |. E7 {: B
- 36; n( y5 _1 m' i; d; ^) G
- 37BOOL
- z" F5 G Z- g6 N9 D4 M - 38xMBPortEventGet( eMBEventType * eEvent ). G2 G4 J! q1 n) S
- 39{
. E( [( v' P# k) j) x - 40 BOOL xEventHappened = FALSE;& \6 F" l: v/ F, L2 N) Z( d
- 41& W) w1 n& n" P
- 42 if( xEventInQueue )
! Q4 K1 z, o5 Y - 43 {
& J8 }, l$ C: K/ {" q: w - 44 *eEvent = eQueuedEvent;3 @) _/ n9 R# q* I/ k( P ~
- 45 xEventInQueue = FALSE;: i# `$ Q4 U/ r1 N3 `! J
- 46 xEventHappened = TRUE;; s$ y! J5 _7 ]% R! n
- 47 }
3 }+ F$ w H7 z6 i' \ - 48 return xEventHappened;
. ]7 o& {: i# N. { - 49}
复制代码
! S- X9 [2 C" @; c+ ?, G& O r
portserial2 M9 y+ V& k. ^; M7 J! B, _$ x
这里使用RS485,因此需要对RS485使能端口进行配置,其他为串口的配置,然后在发送和接收中断时候调用modbus相关接口进行处理:
p7 N0 X2 J9 f2 P5 f
; q+ ^; o# J, V+ S- 1#include "port.h"+ v2 p8 _- y/ X5 K. ^" W4 Z: p
- 2
1 ~. o% _" ^# G - 3#include "FreeRTOS.h"# a7 z2 @( `: Q* g0 M7 p# Q
- 4#include "queue.h"; \* k K: v; U3 _+ h5 o' j
- 5
6 y+ c9 X V- E5 `* b9 A8 F - 6#include <libopencm3/cm3/nvic.h>7 s# c; ^ T( z
- 7#include <libopencm3/stm32/usart.h>
$ i' C2 R) ]; q - 8#include <libopencm3/stm32/rcc.h>5 G% C9 R5 l4 m. {7 ~
- 9#include <libopencm3/stm32/gpio.h>
d" I7 j4 ]- m" J1 U% `+ v - 10
- W* o9 ?% B( |+ p' E9 w - 11/* ----------------------- Modbus includes ----------------------------------*/
' W0 s1 v X* i+ |( s0 u) v2 k - 12#include "mb.h"
" D2 k( r+ i; p1 z) U m - 13#include "mbport.h"5 ]: a9 f! i& p( M5 K( ]
- 14
/ g8 T e4 H& L" e/ C - 15/* ----------------------- static functions ---------------------------------*/* j8 w- q1 Q6 l
- 16
. Z7 B5 e! d6 g" @" I, @& i - 17xQueueHandle uart_queue;' \ E2 ?* H6 o) Y
- 18; ] `0 o1 u; @9 L$ ~) j( w
- 19#define RS485_1_CLOCK RCC_GPIOB* M. h) M* f/ a$ T H5 N' \3 ?
- 20#define RS485_1_EN_PORT GPIOB2 F* u' C* [( w7 W$ a
- 21#define RS485_1_EN_PIN GPIO8
L2 ?4 E8 P4 t: P2 W0 M - 22/ k0 O" ^4 f& u8 ~' S
- 23static void rs485_delay(int n)3 X- n1 A x) i- A" I8 Y
- 24{
9 A: t2 p W, ]* [ - 25 while (--n) {
4 C$ c9 Y/ r; \0 e0 K3 ~ - 26 __asm__ volatile ("nop");0 R9 _. v7 k: B0 G' j
- 27 } Q9 X4 |" R: t; W4 b
- 28}/ [! x2 ]; g" j9 g- }7 J
- 29* e2 b" I. h V7 l
- 30static inline void rs485_1_rx_mode(void)5 @* T U |, W% H+ q
- 31{
) _' n: ?/ W/ F! n9 N( m - 32 gpio_clear(RS485_1_EN_PORT, RS485_1_EN_PIN);
* b7 @) {$ A' h - 33}' n5 s8 q7 \2 T) D3 p
- 34, o' B# w0 w( H* D( O/ W/ R9 s
- 35static inline void rs485_1_tx_mode(void)( N# s, j6 a& T+ O! w* G% U6 U( f# D
- 36{, r" X0 S) e, i' o$ C/ N
- 37 gpio_set(RS485_1_EN_PORT, RS485_1_EN_PIN);
/ @* G" C! u8 C: R - 38}
1 k9 b7 g3 w0 r: W! {; H: F( E - 39- G7 D, \! L, V9 a
- 40static inline void rs485_gpio_init(void)
3 }, o9 i7 E! K8 D& x - 41{+ G; S0 t O% t6 p! m0 X1 o6 F
- 42 rcc_periph_clock_enable(RS485_1_CLOCK);1 v" w: B# \0 ?5 ?
- 43 gpio_mode_setup(RS485_1_EN_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, RS485_1_EN_PIN);" e# s1 d% O0 [% D& G9 k4 U
- 449 G5 U2 v2 p) A
- 45 rs485_1_rx_mode();, Y. a1 G9 T8 P: C
- 46}4 i) T. e1 ~ f1 S# ^
- 475 K* o9 A- e6 O% u4 y" D& T
- 48/* ----------------------- Start implementation -----------------------------*/+ O7 l% s# z1 _9 I0 \
- 49void
9 o3 Y& j9 b' m/ M. _ - 50vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
n e7 U3 M7 r* ~' v; A# f - 51{* t& y0 e: ^2 v& ?) B$ T) r" n) z
- 52 /* If xRXEnable enable serial receive interrupts. If xTxENable enable9 n- Z0 S( y- V9 i
- 53 * transmitter empty interrupts.
2 w3 J5 q0 I* K; I+ a - 54 */) O0 l" I0 A1 \' _& z
- 55 if (xRxEnable) {& i+ _2 c! E8 k# C+ J8 ]' g, `& _- T! D5 {
- 56 rs485_delay(10000);
5 E5 R" _. B! w, q7 A: b - 57 rs485_1_rx_mode();
7 B8 y) n! T; G4 ]& u6 M/ ]4 y - 58 rs485_delay(10000);: ?2 B2 t3 B; E; g- J
- 59 usart_enable_rx_interrupt(USART1);' D; X3 l) w4 Y: W; L
- 60 }% L$ G, N& t( \- `
- 61 else {
) @# q$ m* G% _; Y2 p4 X - 62 usart_disable_rx_interrupt(USART1);
" p v7 B+ V- T$ S, X. t - 63 }; z7 E. d3 ]. @6 ~9 d; ] S. h/ j9 S
- 64
" s8 o& I9 X9 i - 65 if (xTxEnable) {1 a' Z* P2 P( j/ O1 T) b- h- X+ y
- 66 rs485_delay(10000);& e& h! `" ~& D' E g
- 67 rs485_1_tx_mode();0 O0 j' I+ ~3 \
- 68 rs485_delay(10000);# c5 |" e1 H! o) s0 y4 W
- 69 usart_enable_tx_interrupt(USART1);: ^$ W2 K% q8 {, g1 v$ I
- 70 }
( m, `7 u# U# {+ a4 J) J) I0 h - 71 else {/ e/ z& Y5 s8 d2 u3 N
- 72 usart_disable_tx_interrupt(USART1);3 O3 R1 y& g8 j
- 73
; e% Q. N2 v9 ^7 \- F - 74 }
$ ^+ M' [) M% E" ]/ d) n) U) ? - 75}
+ ~8 p3 j0 m- [. S4 J! H1 P) m x - 76
3 e& H' D. m z8 F) Z/ B& ]! G - 77BOOL
' ?8 A: I9 I8 f0 c8 ` - 78xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
' i$ \, l! D+ ^7 s6 N& Y' E+ v6 l - 79{# W# P4 t5 `1 E- u5 }
- 80 nvic_enable_irq(NVIC_USART1_IRQ);
' U0 |/ C0 O" Z; i- U9 Y - 81
8 G/ R' e& z" l( ?- i q - 82 rcc_periph_clock_enable(RCC_GPIOB);
5 E3 K9 \ B+ v( p - 83 gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6 | GPIO7);
$ j7 L- u4 j7 ^; W" u8 L$ n( N - 84 gpio_set_af(GPIOB, GPIO_AF0, GPIO6 | GPIO7);& i0 z3 e5 }, s) j/ {6 x
- 85! [+ l; @+ L# ~4 ^
- 86 rcc_periph_clock_enable(RCC_USART1);
3 t f% {8 g' v - 87
O; ?: g* @' K M) C/ s2 X - 88 /* Set up USART/UART parameters using the libopencm3 helper functions */* N6 q# @' Y# Z% ~
- 89 usart_set_baudrate(USART1, ulBaudRate);
4 k. H9 i8 O7 l5 Z& n' {. n - 90 usart_set_databits(USART1, ucDataBits);! @: F1 S# @0 \, Z. P
- 91 usart_set_stopbits(USART1, USART_STOPBITS_1);5 }. b! D7 P1 a$ E: {) F% P
- 92 usart_set_mode(USART1, USART_MODE_TX_RX);- R0 H% Z6 X! g% \0 F
- 93! L9 R& d, V) `) x- t8 j/ J
- 94 switch (eParity) {
* m8 x- p& N- N5 d - 95 case MB_PAR_ODD:8 ]- v0 T& M O0 C) V4 b
- 96 usart_set_parity(USART1, USART_PARITY_ODD);+ N/ p7 \ J' k2 d
- 97 break;7 q. ?/ Y$ q+ @, T- x
- 98 case MB_PAR_EVEN:: o6 y) O/ K; ~$ j A
- 99 usart_set_parity(USART1, USART_PARITY_EVEN);
; [$ k+ A) t% `$ k& |" P - 100 break;
$ u0 E% E+ s7 f% i - 101 default:
0 A: v4 Z" H1 z - 102 usart_set_parity(USART1, USART_PARITY_NONE);
7 b5 o: R6 n( t t5 B - 103 break;6 `( K/ `, L! w" E: ]
- 104 }
" q+ L$ F' ]$ R5 S4 J/ c+ J4 y+ H, w - 105
! Z, e z6 N- V% F - 106 usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);; C+ v( S4 T+ ]
- 107
" _4 V9 j4 {% Q5 C - 108 usart_enable(USART1);
3 |! p2 c ?+ W' L - 109/ X y/ j3 }8 T/ Y
- 110 rs485_gpio_init();
$ A- b# z. W4 o$ t. \2 ] - 111
1 r( }( M2 F/ h3 [( X* e - 112 return TRUE; X0 s' j$ G* O
- 113}# L' W" r; x& I
- 114) p( k, H! a' V
- 115BOOL" K# U$ X' J, [
- 116xMBPortSerialPutByte( CHAR ucByte ). Y/ @0 h* J: w6 C: L2 ~
- 117{
" E' T: `0 s, G4 a3 _' ]( U8 @8 ? - 1184 s* _; w' q1 m) U& V6 c% t
- 119 usart_send_blocking(USART1, (uint16_t) ucByte); 3 w3 u. }3 u! \! b p
- 120/ G. y$ q ?% U
- 121 return TRUE;! e- G7 J7 K9 W: x8 f8 L: u( _
- 122}
1 u* Y, ~/ b* Q6 R - 123
* K' c Q* C! G+ c. z% Z - 124BOOL! n( T$ q, N7 s3 Q& P- N
- 125xMBPortSerialGetByte( CHAR * pucByte ); l# s. X( S' G( N, n
- 126{" J+ m* h! Z( U9 {3 t
- 127 *pucByte = usart_recv(USART1);
; \' Y4 j' g4 j! ?3 H; ~1 | - 128" m4 P* i* M0 p# Z: C* g9 b
- 129 return TRUE;
# L! ?8 l0 [/ i" w$ o( h" i' a - 130}$ @. W/ X$ `" L2 M
- 131" @7 R. _6 o. Q+ _; N% Q0 Z
- 132
5 l9 B8 ]" Y% @$ A - 133uint32_t uart1_isr, uart1_icr;
$ j' T: c. a) m5 s1 _ - 134
$ N/ A$ c0 ]3 t ] - 135void usart1_isr(void)
! I4 d* x3 r8 I7 E - 136{/ U$ C0 P7 m9 W5 S
- 137
# ]% p; a4 H m$ N' f: r n - 138 /* Check if we were called because of RXNE. */
9 o' v8 L4 k7 k7 d( ~' H/ t' ` - 139 if (((USART_CR1(USART1) & USART_CR1_RXNEIE) != 0) && j: t( a# l/ u5 X+ q2 I( D% ?/ Y
- 140 ((USART_ISR(USART1) & USART_ISR_RXNE) != 0)) {" s" t9 C( E# Q6 L: e8 I
- 141
- K. w8 B' i! O3 s2 Q - 142 /* Retrieve the data from the peripheral. */6 X# v g& s- g/ t7 i; M$ w
- 143 // usart_recv(USART1);) o' z5 Q; G# ^7 C: @ Z. Z
- 144
7 y% z$ O3 u: A* x" w - 145 pxMBFrameCBByteReceived();
9 N& G% [9 Z3 S( B - 146 n. z1 |$ P' s* {8 \ O) c
- 147 }
: n. f ]7 L" V' A7 f1 @$ ?, w4 d - 148
% x G' S$ R" V0 d0 Q/ V - 1491 x. N& t4 T2 w+ E
- 150 /* Check if we were called because of TXE. */
) {4 s& u' d; u9 p' X - 151 if (((USART_CR1(USART1) & USART_CR1_TXEIE) != 0) &&
+ ~/ q7 M( v) ?; a' w - 152 ((USART_ISR(USART1) & USART_ISR_TXE) != 0)) {
4 ^- a# y7 Y- S4 G7 S& s - 153* j |5 P8 x' T1 R7 I
- 154 /* Put data into the transmit register. */
. b8 I. U" r4 o4 T1 X0 I0 m - 155 //usart_send(USART1, data);1 _% f8 Z/ O% C3 \
- 156) c- ^% P2 s6 x+ I( W2 d
- 157 pxMBFrameCBTransmitterEmpty();) S# Q) L6 r$ U! X% }5 I) R
- 158% z3 C' |, t" t, i3 R: r5 R/ B
- 159 }# w3 e( ^, a- V* V
- 1603 x. c( C/ d( X- C, C0 Z
- 161}
复制代码 porttimer9 n3 _) P( w A/ Z. P1 q ] t
- 1#include "port.h", R$ d# {3 R1 f i
- 2
# |+ T4 l: i' ]+ u/ A( o3 T - 3#include <libopencm3/cm3/nvic.h>
1 z/ P) W0 e: u, }1 H$ j2 Z, ?5 I - 4#include <libopencm3/stm32/rcc.h>
; ~) K9 z5 M8 Z0 P% J - 5#include <libopencm3/stm32/timer.h>: _( {6 Y; f( m8 d% r# y# e0 Q
- 6
+ ]8 v. J- q. D' E - 7/* ----------------------- Modbus includes ----------------------------------*/
* z) j: p5 O* Z$ e- Z - 8#include "mb.h"0 e. U2 O J# R" @/ U
- 9#include "mbport.h": A' ? g5 X1 [
- 10! k1 c7 j- a8 H; U2 |1 s
- 11/* ----------------------- static functions ---------------------------------*/8 a# Z0 |, n4 f, w
- 12static void prvvTIMERExpiredISR( void );7 R& ^# F) X* M
- 139 z/ O. y h$ {' X' q2 V- d+ _
- 14/* ----------------------- Start implementation -----------------------------*/9 l. X3 g& h% m/ ~0 y9 I" Z
- 15BOOL, B% L/ @$ @9 f/ T$ }; {; Q
- 16xMBPortTimersInit( USHORT usTim1Timerout50us )
6 n0 ^1 A v% m* c - 17{! w$ }! C$ J6 V4 I9 E& U) [! [9 h
- 18 rcc_periph_clock_enable(RCC_TIM2); w, B4 G8 C0 ?5 P1 W
- 19 nvic_enable_irq(NVIC_TIM2_IRQ);
* k* p7 F6 N9 W z' h( B; q& G - 20 rcc_periph_reset_pulse(RST_TIM2);) u. m0 j% e1 g1 ~0 l, \- H
- 21; v! B5 h% w7 r8 f5 k
- 22 timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
% l0 G1 e) q1 a6 c - 23: s3 n: |' T7 H# H/ p I+ }% u
- 24 timer_set_prescaler(TIM2, (rcc_apb1_frequency/ 20000));7 O) Y+ {7 e, r0 i
- 25% v! O8 z S: |
- 26 timer_disable_preload(TIM2);
7 N+ m l- r. U8 W$ h F* j+ ? - 27 timer_continuous_mode(TIM2);
5 n9 W+ h! @* T( A2 K! Q- X - 28- w( n' `/ [& r, A: G# G
- 29 timer_set_period(TIM2, usTim1Timerout50us);
$ L& i- c( n/ _. V# _9 r, q1 p - 30 timer_enable_counter(TIM2);
6 a5 U+ [/ G6 n9 f: V - 314 n4 n: z& c' q6 c
- 32 timer_enable_irq(TIM2, TIM_DIER_UIE);
* r K7 d, u- K' a$ j4 @ - 33+ p2 l3 A/ Q V* j
- 34 return TRUE;; F5 j& v4 {% e: j$ H
- 35}
+ s* A$ @+ b/ w: \5 ^ - 36
( ]$ _2 K9 }( e( d - 37
; o. O- G' m e - 38inline void
6 _3 ]7 v9 M+ }7 e - 39vMBPortTimersEnable( )
/ ~' [- M6 L7 n: U( Z - 40{- r! R& E$ T$ _6 F4 c( o T4 V- H
- 41 timer_set_counter(TIM2, 0);
Q ^; A9 x9 N7 Y: m+ c9 n6 }0 ` - 42 timer_enable_counter(TIM2);
0 S% k: O7 [6 w" |' j6 S4 T- C - 43}# ^& w' m( [4 G+ J2 E1 [4 L
- 440 c3 Z0 T M/ Y/ Z9 J- M
- 45inline void
1 k+ c8 L) O$ C; w - 46vMBPortTimersDisable( )
2 x! a0 _" l1 Z9 G! v - 47{
+ s2 g3 F, v# p" \ ~" ^$ R - 48 timer_disable_counter(TIM2);
" K+ x, @3 G) v' s - 49}" A9 R! v+ s. `- K! m) B
- 50
2 D5 N1 r6 U5 @, w8 V; O! S - 51/* Create an ISR which is called whenever the timer has expired. This function
6 S& i0 }% u1 C8 e$ b - 52 * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that" O, k8 e# y4 T& U
- 53 * the timer has expired.
' `" ~3 k9 p5 H' [ - 54 */
; N% K/ H8 c& V- l# [ - 55static void prvvTIMERExpiredISR( void )
" ]+ U) j* Q9 b - 56{
( H+ n( N7 c, F* R - 57 ( void )pxMBPortCBTimerExpired( );0 j2 L# A8 h' \2 O
- 58}
! m: f9 }' q2 P# r- n - 598 s* x/ }( M' j2 E1 k3 i
- 60void
$ j2 e6 [# ^6 H; c( h/ T4 p - 61vMBPortTimersDelay( USHORT usTimeOutMS )! M5 [7 S& a4 B$ C, l
- 62{
, \! b5 u! X/ H+ W; p; P! ` - 63 vTaskDelay(pdMS_TO_TICKS(usTimeOutMS));# z9 b7 D+ k' |& `6 P! `- H
- 64}# U3 `6 H1 j1 `% c' ?5 r/ b
- 658 h' k2 D! r% W+ q" L: H I
- 66void tim2_isr(void)
! F, d5 F! W$ G/ X- e$ p# @0 E2 p4 O - 67{+ j( u- T$ p* [+ O' T
- 68 if (timer_get_flag(TIM2, TIM_SR_UIF)) {
8 n0 F1 I2 ^9 x! N5 r$ s - 69
4 D9 H5 Q# {- Y5 h6 _- D7 {. G - 70 /* Clear compare interrupt flag. */
- m5 P: K2 K% E: z6 ~" y - 71 timer_clear_flag(TIM2, TIM_SR_UIF);
" j( d% R0 G, U0 }; W - 72
' V8 g: X8 p* ? - 73 prvvTIMERExpiredISR();
! |" U& D; B/ W3 k& H) W* o# Q. g - 74
1 V& D# S/ F) D" a* w. t" t+ K o - 75 }
0 K% m' L. l: B5 ^/ C7 A - 76}
复制代码 开启定时器和中断,用于modbus时序控制; y8 y3 o" p! g+ Q
$ z# x2 B! e- y" l. w9 ~0 B* P" X+ y
2.2使用
' q5 K o; l7 S2 x6 a9 M6 A在src目录新建 modbus_cb.h 和 modbus_cb.c 两个文件,实现寄存器、线圈的读写回调:8 b! C. s6 L$ R
- 1/// CMD4
; U5 b, z) Y9 m+ h. K - 2eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs );
7 N: P+ y( o) m9 p7 {( E6 z3 _ - 3
6 L5 j; t/ t5 [8 M - 4/// CMD6、3、16, L W* d0 ?2 L
- 5eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode );
9 X! \5 P' Y( x; w3 G) ~3 s' E - 6
& B$ d' A$ S& U/ z3 {0 W - 7/// CMD1、5、15
# m! V Y' d z, p" @& [ - 8eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode );3 J% v* T7 d, \
- 9' G' I9 V& Y+ N% c8 J& w' ?
- 10/// CMD4
5 V& A+ _% }3 |5 c: S& T - 11eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete );
复制代码
! Z% Q- a3 F0 {: ?& T
. V; j& A! S- X9 v1 X! q
* f) t7 k8 h% L' ^) U基本的实现示例如下:+ E0 k$ Z3 R8 h' I
- 1#include "modbus_cb.h"3 K7 j) u( B# t) U+ l
- 2#include "stdbool.h"
, E P2 q2 C3 G% p - 3 M( ?8 K, @9 s3 k5 P
- 4extern log(const char* fmt, ...);
$ ?. d. T- q! a9 N - 5" u% c& n6 c7 i
- 6// 输入寄存器
1 q3 r% h* X9 ?! s/ w' n4 r - 7#define REG_INPUT_SIZE 328 m+ ]$ s9 j! O& y, C3 e) c
- 8uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];) T6 _) `3 T0 i7 q
- 9
@% v) I+ i2 f Z) }0 u - 10// 保持寄存器
. Q+ {2 v2 @: v$ Q- ^ - 11#define REG_HOLD_SIZE 32; J( f% [* {+ o9 [! L. Z
- 12uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];2 v9 z* [( Y# t7 `
- 13
. B( U. S/ ]+ t% _$ h - 14// 线圈寄存器
/ s5 z6 g% E4 d8 R1 p% v) I - 15#define REG_COILS_SIZE 16
9 v% S ?( |4 P# F - 16uint8_t REG_COILS_BUF[REG_COILS_SIZE];
- x& K% K8 c3 C2 ]! o! L) p" I+ V - 17
* ?# N r5 J7 ~4 X8 |0 i6 O+ W - 18// 离散量
+ |- ~1 a& `7 Q+ y - 19#define REG_DISC_SIZE 8
0 ]' P+ H. A% g( C. C: y - 20uint8_t REG_DISC_BUF[REG_DISC_SIZE];) K' b+ F9 ]9 Q% D
- 21
' W$ T/ v9 @5 j& R1 t! g - 22/// CMD4, C h% }+ I$ Q& I
- 23eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
2 N- s- \$ i% [ - 24{/ z+ g. X( B7 K* S1 {4 _
- 25 USHORT usRegIndex = usAddress - 1; / Y% K/ G1 b5 u4 h
- 26
, U# [" B1 @5 T1 L E' Q; K - 27 // 非法检测
9 _2 Y7 K( }8 i, ^ - 28 if((usRegIndex + usNRegs) > REG_INPUT_SIZE)" D4 v' f) d2 ^0 f8 G( E
- 29 {
& C8 H- r! h+ F' t - 30 return MB_ENOREG;
8 \! [ k7 q, d( m - 31 }) A, J( }: h" [& g. P; D* d9 w: y
- 32
& r+ k% l6 ?% {$ V7 d/ s - 33 log(" CMD4, 寄存器输入.");* D+ ?" z+ X4 ^- f/ V% m0 \8 `
- 34: D5 G/ Y0 B7 u2 q1 j5 n
- 35 // 填充数据
, T2 g6 S! K4 }6 `9 v$ w* W6 L% T - 36 REG_INPUT_BUF[0] = 0x01;4 T6 |) o. q/ K1 s" V8 y+ ^
- 37 REG_INPUT_BUF[1] = 0x02;
, ~/ H6 S( x# Z! l, q - 388 G2 D0 Q5 P: Q7 b+ e% X. p! R
- 39 // 循环读取
: L( T) [; z: B* H - 40 while ( usNRegs > 0 ) {8 q( Q0 o( Z2 [7 i& c9 P; j
- 41 *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 );
7 Z" j {. s$ y" I8 V6 c) r1 k - 42 *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );4 g' f; j* f( r3 \- ]- N
- 43 usRegIndex++;1 \8 ^0 G+ y5 Z+ }& k: ?9 }
- 44 usNRegs--;) Z. J( n# @0 f6 C0 f
- 45 }
3 x( p% E% _; G+ { - 468 L6 e) H7 }( s2 K( b) t
- 47 return MB_ENOERR;7 ]( W1 J# m3 X% [
- 48}
1 ` A# }1 `& T& b - 49, Q& {; H* u- v( G; g
- 50/// CMD6、3、16
! u- p' p: D/ q4 i - 51eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )7 K( i* _# e! C9 Z! Y7 a
- 52{
/ L- w6 U7 E: H. \ - 53 USHORT usRegIndex = usAddress - 1;
r t+ W: k2 L. n6 A# l( I - 548 c& \* f7 x0 j2 z( p: c
- 55 // 非法检测
% x" d0 N* o' m# }; u2 n - 56 if((usRegIndex + usNRegs) > REG_HOLD_SIZE) {! \' H: }4 W: D# m
- 57 return MB_ENOREG;
9 Q k% G/ A/ V% S" k$ A) K - 58 }( s' E( h4 e! v, s+ i
- 59
+ s2 b8 G( _6 o/ V0 F. u - 60 log(" CMD3,6,16, 保持寄存器读写.");1 F) C8 ?% t& V; f: c: q b: u
- 61
- r5 o1 g! |- ^ - 62 // 写寄存器
7 P, n q( @; z' K+ _ - 63 if (eMode == MB_REG_WRITE) {" W* q" W5 b3 a! s6 X. t
- 64 while ( usNRegs > 0 ) {
* d% n+ I% d7 c# i( \+ I$ Y - 65 uint16_t value;
% n1 v5 F9 z& c7 i - 66. F2 S F+ O; T
- 67 value = (pucRegBuffer[0] << 8) | pucRegBuffer[1];/ |8 E, ~$ P& d# e! R& @% c4 Q
- 68
+ w7 U( f( ]* p3 W' ] c) y - 69 log(" 写寄存器值:%d", value);9 G0 a% j5 p: n* A
- 70
# D) M$ q' q$ O% P% Q0 P0 x - 71 pucRegBuffer += 2;
2 s6 _% W1 \3 c! _2 h1 @ - 72 usRegIndex++;
' v2 S; w/ h9 { - 73 usNRegs--;
0 f7 d" b6 J* W4 B/ L - 74% i$ F j2 R( k4 n3 a' _' Z* _4 N
- 75 }3 x$ X/ m4 t- y
- 76
0 h3 _, h4 X0 M1 N5 w P1 V3 C0 u - 77 }
6 S4 P; m% R, Q( J5 j% g4 t, J' h, n - 78 // 读寄存器
& l' \/ b1 |4 V8 ]" w4 C5 \6 q - 79 else {8 @' l; d7 i7 ]- L9 ^' W2 p
- 800 R: v, y- i% ^* H: Y( a7 z
- 81 log(" 读寄存器.");& Y- n8 }: N' T( Y
- 82
! \' r% Y7 H; [) p - 83 REG_HOLD_BUF[0] = 0x32;% S* J+ v7 l' i0 s I+ ^1 y3 _
- 84 REG_HOLD_BUF[1] = 0x33;
2 ^( ?* k7 N2 V$ \* s - 850 B$ i |2 C3 [) _* I4 O
- 86 while ( usNRegs > 0 ) {
9 p+ ~' @+ D# T, D9 h0 L, k - 87 *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );8 N3 g9 K4 i" L% p: I
- 88 *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );
; ?# E7 B' ]$ _8 J. K" i+ T; X* g0 M - 89 usRegIndex++;- }4 B$ a. G% e% C1 ^7 B+ ^& @0 v
- 90 usNRegs--;
/ |; G1 o: i# k; j- L n7 p - 91 }. d, F* H7 U/ ?
- 92 }$ \4 p; Q- Z* ]# F k
- 93; _# F5 k1 c h, X. I
- 94 return MB_ENOERR;* o& @+ b' N. x* Y" u. L( A
- 95}
5 A% f r+ i) G; K' E6 R Y - 96
+ Q! b- ~3 `) j$ S - 97/// CMD1、5、15
1 @3 A1 J1 |, U: @; _5 _: l- N* V - 98eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )6 m3 J& B% _7 E7 Z
- 99{
, S9 J I+ i9 s* _+ V* P* g - 100
6 U. i1 h3 d" n' l - 101 USHORT usRegIndex = usAddress - 1;
& @" H5 i" j1 t. T+ R - 102 USHORT usCoilGroups = ((usNCoils - 1) / 8 + 1);- A. w# J( C' i2 T9 G& H1 b
- 103 UCHAR ucStatus = 0;
7 I# `$ n* D% t2 \ - 104 UCHAR ucBits = 0;% h( k; x, ]: o h& D/ l/ n' P
- 105 UCHAR ucDisp = 0;
* J+ ^& p1 F/ A& g7 R8 j% ~ - 106
6 V, H& N _; C1 C* P. ^ - 107 // 非法检测, _# f! B& z! \, b
- 108 if ((usRegIndex + usNCoils) > REG_COILS_SIZE) {
) q5 ]. u5 J$ h% q# I! \ - 109 return MB_ENOREG;
$ d) K/ X/ p0 U* h W' Z/ ?, w& e - 110 }5 X+ M9 ~+ v6 }" ?5 {: @
- 1114 R. h% [; N: s, [& w) n% i0 T! E' k5 l8 u
- 112 log(" CMD1,5,15, 线圈读写.");6 ?7 b4 ~5 K3 s" X" T
- 113
3 m: }, t: \ w. M - 114 // 写线圈
+ v+ \% l, m) I; W& P h ^/ Q7 s9 ^ - 115 if (eMode == MB_REG_WRITE) {
* H2 e3 P' r/ |; B3 a- z - 116& c# q& H1 h/ H' a3 `
- 117 while (usCoilGroups--) {8 X5 J3 ]4 j- j$ l! m
- 1186 @, Q0 @8 ]; X+ F! R: ?/ o
- 119 ucStatus = *pucRegBuffer++;' R, _8 S9 N' `% i+ D# ^; n/ T0 b
- 120 ucBits = 8;: Q' A- J/ z' U B4 }5 y. a0 {
- 1216 n4 N* Z( k7 Z( G
- 122 while((usNCoils) != 0 && (ucBits) != 0) {
" E" _8 {+ B0 g, c2 v- T) r - 123 bool flag = ucStatus & 0x01;2 Y0 ~, H$ ] r! L1 m
- 124
4 {0 Y7 D# B5 R% F6 ] - 125 switch (usRegIndex) {. z5 x; U# `* W4 v+ s9 w
- 126
; Z; E% n2 B r- F+ v - 127 case 0:) F4 O6 X% i/ |2 K, h
- 128 log(" 线圈0 : %d", flag);//
. l0 X0 o4 g; c# p- P$ z - 129 break;* _# G: ^; N, }
- 130
$ \3 }0 A E% o D - 131 case 1:
% t1 ]+ n* Z( a3 }$ v5 Z* W) l - 132 log(" 线圈1 : %d", flag);
% D" d5 q7 m2 M: z - 133 break;
. a3 O {: V1 f Z6 H - 134
: v" V& D0 c6 s; b( R3 @ - 135 default:+ B: E9 S; J ^% g
- 136
0 z7 r! o4 W/ L0 N' Z5 n - 137 break;
* N0 A- w/ {& q" C F - 138+ R1 B9 b% x& @' K& x
- 139 }+ ~# G6 K5 ]* c
- 140
' @4 P0 L* b O2 H8 [. f. C - 141 usRegIndex++;
) h/ Y8 E* C' g' \- h - 142 ucStatus >>= 1;
6 ^. Q# X U( k2 s B$ j4 J - 143 usNCoils--;
- J+ p# _* k& _0 h }/ _: N - 144 ucBits--;1 G9 M+ T: |2 Q1 i" C
- 145 }/ b* K$ A! J0 `' q5 i/ k- _: S. _
- 146
/ }5 b! \1 |, w# Q: P5 x9 r - 147 }
$ ?* T1 f( L o$ k4 n7 t - 148 }
6 o, Z6 u/ e9 { - 149 // 读线圈
" t& o& l% k) C6 d1 v4 _: n6 j - 150 else {3 r' h4 r' E5 k1 d$ y3 [& i! w
- 151
+ Z- g! M! q5 O" I6 i. X - 152 REG_COILS_BUF[0] = 1; [. l! i( L; M
- 153 REG_COILS_BUF[1] = 0;% s1 B+ V" ~! N$ `
- 154
7 U$ H/ Z+ ?) q0 J - 155 while (usCoilGroups--) {
5 p) s; z2 _8 c3 J - 156 ucDisp = 0;; K4 a" C/ U' \
- 157 ucBits = 8;
6 \- T- Z7 S1 A d; g$ ~ - 158 ucStatus = 0;
6 F6 i: L8 i3 s3 f - 159
) o1 {4 q% g1 \' G$ s - 160 while((usNCoils) != 0 && (ucBits) != 0) {) d8 ~. i; t) g
- 161 ucStatus |= (REG_COILS_BUF[usRegIndex++] << (ucDisp++));- Y j5 u& z7 L" Z$ _6 g; ]
- 162 usNCoils--;$ O$ r$ a+ }+ ^" Q+ V D8 u
- 163 ucBits--; |. d- K8 G3 P7 I
- 164 }
5 h ~0 J# r% [1 `9 N5 b. I - 165
% ]' r J' w! j - 166 *pucRegBuffer++ = ucStatus;
9 G$ S& u! D% Y1 ^- @; N - 167 }$ X3 b, |& S/ ?: F- ^
- 168 }+ {- P8 z% \! J8 r7 m
- 1695 M2 u/ i9 p5 P! j. B( N
- 170 return MB_ENOERR; R* E; j" d% l9 u& G; L8 J0 I% G6 o
- 171}
- b c# |+ P1 |+ g4 t! y1 B+ s: d - 172
$ _" J, S5 I4 _% Z8 _ - 173/// CMD48 r: r+ g: E# R: K _
- 174eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
v$ @4 Y! l, l) H- \ - 175{ {3 u1 T; i9 N5 k; a
- 176 USHORT usRegIndex = usAddress - 1;
8 P9 `; A* {. ]7 v. ~3 b0 K - 177 USHORT usCoilGroups = ((usNDiscrete - 1) / 8 + 1);
0 g% O w. H0 l" x - 178 UCHAR ucStatus = 0;
& f, q/ t- ?7 ?. i; c2 N - 179 UCHAR ucBits = 0;
I# `) T$ U8 E, ^7 b - 180 UCHAR ucDisp = 0;
+ t4 S9 b2 \ l4 [, ~! k2 f: d) p3 j - 181
* c( M+ b* \9 x- B# b - 182 // 非法检测
x3 Y9 z) [4 Z- e# m6 h b, C& Y - 183 if ((usRegIndex + usNDiscrete) > REG_DISC_SIZE) {
& U3 R2 F I1 m, h4 q( k W" j - 184 return MB_ENOREG;$ M; k. N+ R' {/ P- v6 w
- 185 }) Q+ e7 D2 C- m. h: V8 ]
- 186
6 M7 i4 @4 G. A. ` P0 G - 187 log(" CMD4, 离散寄存器写入.");1 \! J5 O( l& ~
- 188" x8 P; B. ]* f1 O! Q; S3 l% A
- 189 // 读离散输入
- i" K) c8 \ d4 }3 t - 190 while (usCoilGroups--) {
& F" d- W" s; l9 ^. c& ` - 191 ucDisp = 0;/ U2 ` C$ j% l' c
- 192 ucBits = 8;; c& @" x4 P5 N( H7 O7 z
- 193 ucStatus = 0;6 ^1 H/ r/ g# B) A! K' @) p7 Q
- 1947 \/ d" m5 v6 Y* [! ~
- 195 while((usNDiscrete != 0) && (ucBits != 0))
3 C, r0 B& Q! z" }3 h4 @ T - 196 {8 A0 Q `) Y& V' w' Y4 J
- 197 switch (usRegIndex) {" w+ t0 H9 x" L3 q
- 198 case 0:
& R& {4 z! j. R, P - 199 ucStatus = 0x10;
) z2 f3 f) o: r r; B - 200 break;
2 N$ j" z6 n G5 R5 N. X, v% Q7 ] - 201 }: t- K1 D3 w# Z! Z- d' \, G
- 202
% c2 L8 I; n- I$ O# _1 M - 203 usRegIndex++;
8 A6 ]0 a) U B( Z+ m8 z - 204 ucDisp++;
- [- i& _7 G+ k - 205 usNDiscrete--;" m9 H5 ^% S! Q! F% t
- 206 ucBits--;& ^9 {& H( E$ D& n& |
- 207 }
3 p1 F+ C: j: B+ M, K - 208 *pucRegBuffer++ = ucStatus;7 b8 L! i" n5 h( B7 K
- 209 }
: R9 R7 `! n ^: `- y9 T - 210
9 {/ X6 b2 T0 m7 J) D - 211 return MB_ENOERR;3 X; D; ]! w0 L& v
- 212}
复制代码 - ?% Y% g) I: w( ~$ J
在main中创建modbus任务:7 w8 }' O3 [( f" q
- 1static void task_modbus_handle(void *param)
, {, J: C7 V4 j/ M& C - 2{. }0 _+ M# F6 a
- 3
4 P7 u0 ^3 r3 T6 r - 4 eMBErrorCode eStatus; w* `# _4 }! ^6 a7 b6 _
- 50 D4 Y2 x0 V" a9 _5 m" ^+ w
- 6 log(" task modbus start.");
" N* E+ e1 Q" T* t - 7
' z3 ~ C0 ]) R5 w' R( r" n - 8 eStatus = eMBInit( MB_RTU, 0x01, 0, 9600, MB_PAR_NONE );
% K3 m5 \" T- @ - 9- d/ T9 V4 {/ K5 z$ ~/ @9 I5 `, O
- 10 /* Enable the Modbus Protocol Stack. */9 F3 D+ Y$ C$ m" j! ~3 K* N
- 11 eStatus = eMBEnable();2 T. T- K$ I' o" R9 K
- 12& g+ n5 A" \' V
- 13 (void)eStatus;
$ [. Y- ~' d7 a' B x. ^8 R% B; z - 14) g% { h W5 o+ R, s' r( V
- 15 for( ;; ) {
3 s; S* A( n/ d$ z q8 c - 16 ( void )eMBPoll();
+ Y; |8 Q+ {- T" F( y+ Q - 17 vTaskDelay(pdMS_TO_TICKS(10));2 [6 r: ?8 t4 D7 c5 x' K
- 18 }
- u4 B# C0 Z$ A. q6 T# Y# S! } - 19
' W: \: V' A' b3 D - 20}
复制代码 : x$ K P( p2 V5 W9 y$ n/ L/ u
2 s. @1 P1 [, d; e Q3 烧写测试* T: w9 F _6 Z: ~7 r
将开发板连接到USB转485模块,然后使用modbus poll程序进行测试:; D) P( B& e( X1 c9 |* ?0 w. I6 d
8 E& M& J* H8 Z0 N" B
7 y" Q3 a, V& T" y7 ^转载自: MakerInChina.cn $ n9 {. b- K' q1 |
2 k" p1 O: j. R. T! E+ R7 \8 B% b2 Z/ i5 u4 o
|