你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F407 + LAN8720A + LWIP 实现TCP服务器

[复制链接]
STMCU小助手 发布时间:2022-4-11 10:16
环境说明:5 E1 ~& G( N0 V
开发板:某宝买的,STM32F407IG/ _) M- P# A" B; O/ t: g7 l7 `
STM32CUBEMX5.6: O! ^* B; z7 v: Q, o6 E
HAL Lib Version 1.25
% n" ^: ^; [6 A: v. G' t9 A  g, h) `. C8 W* j! n, Q4 c8 C# G
(一)配置时钟) |! A9 d0 q6 o- J& l5 U

) O1 m3 d- K& b9 `
20200521102314536.png
7 c, r- w: j, g! M7 ^2 a% m2 A
5 I0 n* D3 r: ]& E/ e(二)配置调试串口
# Y6 S8 A( p" T6 H5 T6 l! X  k( \! Y% g3 L" E8 R9 E
I6]UV8_AXHHT@95MQAJ(1YH.png 4 y/ a7 L: P& g; k  b
9 w' ]9 Q7 V5 Q( O4 b& X: b  H
(三)配置以太网ETH
) r7 i0 j: r. l6 D) O, S
(1)基础配置0 D0 E' c4 M. T0 T' ~2 Z2 e
5 e2 O4 K) x: V* N$ ?( d
2020052015571192.png : }& k; h1 H8 m7 b9 u1 v5 v

9 }% s4 V4 |  L! @2 }' g( b: _顺序依次说明:% G8 o: {& J/ J: E2 N2 s. C5 V
LAN8720A使用的是RMII接口进行配置寄存器& p2 k6 \6 v2 Q' K2 @' r, Z4 f
自动重连使能
* f9 U6 F3 {. @: I2 \7 g4 jMAC地址! I: W# n* e! A/ o5 g" T8 G/ H0 C
LAN8720A的物理地址(类似IIC的从设备地址),0或者1,LAN8720A上电后会读取RXER/PHYAD0引脚状态以此来确定设备地址,这里需要根据你自己实际的原理图进行配置,我的原理图是该引脚是悬空的,所以默认就是0。
3 k) V7 P/ q$ i) x
# O5 L  |2 A( o+ K. m 6T9{3DM_%]8`[7_TFFGM`YL.png * ]  l6 V- i" G

* M6 f: V, ?' w) i! ^9 A接收模式:可选轮询和中断,我选择了轮询模式。(注:在STM32CUBEMX中如果开启了LWIP那么只能选择轮询模式,实际上是可以使用中断方式的,不过需要自己移植修改lwip协议栈,课参考正点原子)
  X& H+ ?/ [: W+ L  O* R1 a
  u5 z' d; E# `. y校验:可选软件和硬件,我选择了由硬件去校验. D) f! e  G6 d5 z: R
( A: W8 y) Y9 i8 w
除此之外还有一个复位引脚ETH_RST,拉低是复位LAN8720A,根据你实际的原理图连线配置该IO为复用输出功能即可。1 Y& s, e, b1 ]( G" Z
* U8 M$ g, p% F' s; ^( |- }
(2)高级配置7 I$ H/ W" \! y& Q; Y) K

4 t0 p( y5 a* m2 c; E' o! T7 g 20200520161703441.png * r( J2 U& x4 a- {
      看下图,此处的配置就是根据实际的PHY芯片寄存器进行配置了,默认的是LAN8742A,而我们使用的是LAN8720A,所以需要更改为 user PHY,配置项默认即可。
9 v% x3 W0 N. g) @
# y- O0 n1 V# c' {- t' O8 e 20200520162350617.png
* ~9 ~; f: U) R+ l  N4 B( ~9 Q) g( Z. G; y% L
对于默认配置,我们将默认配置与LAN8720A的数据手册进行对比然后检查是否正确,以PHY Reset这一项为例,默认值是0x8000,去查看数据手册:7 _/ }: k8 s6 T. d
1 j  z* }! y! Y' z, N( V
BL~P[AYE[9F0MU$]%5G]_96.png
- M9 z: d8 p" r& F" J1 `! z6 V
" ?$ w* B2 \& H* d5 g9 N由上图的基本控制寄存器表可知该寄存器偏移地址为0,大小是16位,第15位是软件复位控制,=1是复位,默认为0,那么如果想要复位LAN8720A就需要将该寄存器的第15位置一,也就是0x8000,对比STM32CUBE的默认配置发现一致,其他配置项同理也是这么检查,检查完毕后发现默认配置是OK的。% W7 R9 s. I% o# [# M$ y2 V

5 ]5 n: H( i4 I6 A! p配置LWIP协议栈: x6 P( ^. z8 T; n/ P+ k
8 J( y+ G/ u' p2 \3 Q
_CUFRU6Z`A3ICCW4DR1SC%I.png , Q& R' g" \; }4 K+ j

5 V- u) X/ Z& q- J1 a如上图,需要开启状态改变回调函数和连接状态改变回调函数,否则无法实现网线的热拔插。& _5 ?6 J# u2 k) I9 u6 N9 l( B0 k
0 U+ ~$ F4 U6 Z2 ]; F6 n
工程代码修改
4 h% v  k) @: l文件ethernetif.c中找到函数low_level_init函数,添加复位LAN8720A代码:/ t% n/ k: g5 ]  ]+ w( j

. Y) X9 c3 P. n+ v& U 20200521094048989.png
( z6 m* R# M6 a2 m0 u8 T
/ D% K' D! _4 ?8 x在main函数的主循环中调用函数MX_LWIP_Process。
& ~* R, u. p( O0 A( N修改MX_LWIP_Process函数,在其中加入:0 @& t/ }: z3 V

6 I0 W( |3 t+ f3 l  Q% [ 20200521095027706.png ( A  N- X; W5 m- e% u. Y1 [
+ `+ g8 [' @- F3 y- @  c
这个函数的作用是检测当前网线的连接状态,如果状态发生改变(例如网线被拔插了一下),那么就会调用回调函数ethernetif_update_config,看函数名就知道这是更新配置,而这个函数尾部又调用了函数ethernetif_notify_conn_changed,看函数名可知道函数作用是通知连接状态改变,所以我们就更改此函数来达到热拔插自动重连的目的。  Q/ p: K& c/ p& ~

# N: Y1 G3 ~( T8 c 20200521100726742.png $ m. d: R' L' \! p

, d& \1 s) B( I; q. l到此,连接上网线ping测试一下即可。
' ~9 }% f# F$ [  ?; z5 k( y( G$ D; ]9 ]
(四)TCP服务器代码, }/ h- Z! n% _  ~. u) g) Y
下面代码的流程是:接收来自客户端的数据->将数据从lwip中拷贝出来->发回去。, a" w$ T6 d0 z1 b1 |
3 E% D, t5 p, ?  Y% G3 e# x# W
  1. #if 1: V/ |& ^0 N  n$ H
  2. & Z2 q' e6 T2 a& h6 @
  3. #include <stdio.h>
    0 j; j2 ~5 g% H' p9 ]
  4. #include <string.h>
    & |4 d0 p4 f. Z1 P" X' Q
  5. #include <stdint.h>
    ! Z/ \& I  E2 A
  6. #include "lwip/tcp.h". Z8 o9 J, {; W! ~3 V2 P+ u
  7. #include "lwip/err.h"% ~% c4 k8 u1 S! ?
  8. #include "lwip/memp.h"
    * g- T1 P9 ^% ~# O2 V( O7 m
  9. #include "lwip/inet.h"
    ) F4 o0 @  V- y+ H
  10. . a. H* n  C( @7 t3 G/ d$ O
  11. ' C. V) y* w/ u% x3 J
  12. / 回调函数控制宏 ' \/ Q" m  M4 W" {) ^' W! D
  13. #define USE_ERROR_CALLBACK 1
    . J  M# ~) I5 ~; u
  14. #define USE_SENT_CALLBACK 03 z1 A9 L6 L& V: \7 p7 q3 _# N
  15. #define USE_POLL_CALLBACK 0  d: ?0 O4 d+ ]  J& N3 q" y
  16. 7 d4 |: w8 Y: `  H

  17. 7 i: x+ y& O: G  O7 Y

  18. 7 R- {; W# d! B/ f' J% i2 U5 |8 |
  19. / 调试信息输出 //7 N5 c! d* X( }5 i
  20. #define DEBUG( s' ]/ L* b2 @2 H1 j

  21. $ n/ M/ o0 ?% u+ o2 C+ o: S8 G
  22. #ifdef DEBUG
    6 q; J8 T- W! J
  23. #define debug(fmt, ...) do{printf(fmt, ##__VA_ARGS__);}while(0)
    3 q( e' b3 z" t' [$ F
  24. #else6 C5 T! ]0 k, J' H
  25. #define debug(fmt, ...) do{;}while(0)
    8 W+ z0 h& X# a2 x7 W4 P# A! p: |
  26. #endif
    1 x9 s2 y# j8 x; h1 \0 q

  27. 5 z+ O7 c: H3 Z$ O  X

  28. 2 ?! a. p. L- i; w

  29. 9 r( Z& H* J6 n" |7 ]
  30. / tcp接收发送缓存 ///
    ) J+ F% p& U6 W3 H2 J9 Y1 G
  31. #define TCP_RX_LEN  8192
    7 E* w; j. d  e2 C0 @
  32. uint8_t TCP_RX_BUF[TCP_RX_LEN];
    . Z6 \( m+ A- U. I
  33. volatile uint16_t TCP_RX_STA = 0;  /* bit15:有无数据标志位        bit14-0:数据量计数 */. n* m/ o% O1 N' g' l" T* H

  34. 3 N: ^% @, D& M( Y4 e
  35. 2 i1 u- B5 u$ y8 N1 y; b0 ]

  36. 6 U; x1 ]5 V7 o
  37. / TCP结构句柄 ///
    ' s# v. D* v: }% `5 g
  38. struct tcp_pcb* tcppcb = NULL;
    . r* i4 k5 ~0 v

  39. - H6 c8 {! V# l8 b2 C) V* T& m
  40. % R% h% k% J& b" H$ V# o. R
  41. 4 T  m. A; B0 b8 F, C7 [
  42. / 本地函数定义 ///
    5 l9 m" K/ e" Y* y
  43. static void tcp_server_disconnect(struct tcp_pcb *tpcb);
    9 t8 K: B3 Z, j( e
  44. static uint32_t tcp_server_send(struct tcp_pcb *tpcb, const void* buf, uint32_t len);9 L& p* r9 [, H+ ]8 |8 L6 y
  45. $ r8 @# y" ~) w/ @7 }$ _2 ^
  46. # A0 Z8 l( u, }, d* }
  47. 1 N. F  Q9 u" l2 M  }' W
  48. / 私有函数实现  ///( |+ q- c$ s' k& `( [2 H& Z/ S5 L
  49. 8 X( h+ r9 E# m
  50. #if (USE_ERROR_CALLBACK == 1)
    ( Z! U6 {1 b5 P4 U5 c  c4 V
  51. static void error_callback(void *arg, err_t err)
    . I* d# i4 l; U% J% Q1 a
  52. {' R3 l7 n0 ~  A6 Y
  53.         debug("\r\n error_callback:%d.", err);
    ! \7 p  U6 L) Z5 g
  54. }1 P9 A& C: E$ k& I
  55. #endif
    1 J7 s; z: F" r! P& I

  56. 9 q: ]3 W+ d, j3 h3 ^7 U
  57. #if (USE_ERROR_CALLBACK == 1)
    $ u/ t$ j- @8 T1 F) x6 Q/ @- O2 N
  58. static void error_callback(void *arg, err_t err)
    6 J* l; }1 p# A" M& j: ?  R
  59. {6 q) D- Y) r; D: H" F, A
  60.         debug("\r\n error_callback:%d.", err);0 \/ k( o8 i& \9 W, O3 P/ ?4 U% v
  61.         switch(err)
    . u) d0 ]& x: G0 y; Z
  62.         {
    $ n1 m8 a; ^; @' M6 f7 P
  63.         /* PC上位机如果正常运行中闪退或者不良退出会出现这个错误,此时服务器需要释放掉连接  */
    ' U, J, p* N* Q3 p: q9 Q
  64.         case ERR_RST:
    ' z) @- }5 d" n
  65.         tcp_server_disconnect(tcppcb);
    , D3 I, i1 i; B" d5 f
  66.         break;$ a# {; X1 E6 s& J5 C
  67.         default:break;  j# g0 _' q. {1 h+ ]
  68.         }& Q& V( v; v, W- `
  69. }- C2 u; p9 `5 S+ r) ?
  70. 9 o' F; l4 \7 k0 o( t# r8 H8 S6 O
  71. #endif
    7 w" j% x5 o2 t9 x

  72. " V2 @' B! Y# I/ F. T
  73. static err_t recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)$ o$ n4 Z3 d/ |2 \- b
  74. {  t: @7 J1 M" c
  75.         if (p == NULL) /* 接收到空包表示对方断开连接 */6 R( o5 C( a: n) Y' ~8 \
  76.         {7 L# Z! r1 v. b0 q& u' M# c+ C! W
  77.                 tcp_server_disconnect(tpcb);
    ( T5 T# s. C& n
  78.                 err = ERR_CLSD;) d/ R) l0 `7 Z. Z
  79.         }
    % `6 w$ g( O2 s/ u8 N* B
  80.         else if (err != ERR_OK) /* 收到非空包但是出现错误 */' o, r9 i9 G5 l# O  r
  81.         {
    * Y; O8 V- z0 L, W) s
  82.                 pbuf_free(p);7 `! D' |, H5 i! z$ |
  83.         }
    ; _- U; g0 U5 k9 Q9 Y6 B
  84.         else /* 接收数据正常,遍历pbuf拷贝出接收到的数据 */
    ! M$ D0 O  Z* h
  85.         {
    4 j1 i; [% j; k* a" _. A
  86.                 struct pbuf* it = p;
    5 L5 `- ]% n6 F( @2 }3 U. S8 D
  87. 0 d% J8 R5 m9 j4 i: l/ [5 e
  88.                 if ((TCP_RX_STA & 0x8000) == 0) /* 当前缓存为空  */1 u8 S) y* N& J- K
  89.                 {9 O; Y8 C8 f1 C/ P8 X, H7 g
  90.                         for (it = p; it != NULL; it = it->next)
    2 k) d0 ?8 j: B3 y( B$ T  w2 A: j
  91.                         {* u: w/ J% `3 T
  92.                                 if (TCP_RX_STA + it->len > TCP_RX_LEN) /* 缓存满了 */
    ' \; N+ D7 o, N! [+ d
  93.                                         break;$ U+ S, I2 d9 x& {
  94.                                 memcpy(TCP_RX_BUF + TCP_RX_STA, it->payload, it->len);  /* 将接收到的数据拷贝到自己的缓存中  */% E" q2 y) I" q
  95.                                 TCP_RX_STA += it->len;. Y8 P& s6 z+ }
  96.                         }* I/ p* o$ H' J3 l
  97.                         TCP_RX_STA |= 0x8000;    /* 标记有数据收到 */% t& Q& }) o  S" ]
  98.                 }5 z$ `1 F& w+ o" t
  99.                 tcp_recved(tpcb, p->tot_len); /* 滑动TCP窗口 */0 D+ I- t; J% a1 _3 V" r1 D) e: i
  100.                 pbuf_free(p); /* 释放pbuf */
    5 h7 _0 L' V2 Z" K/ w8 T, j5 u
  101.         }$ \  q  K/ n% c: }) D# f
  102.         return err;2 \( l$ T( Y# o$ Y5 [: u
  103. }
    # T" k: N/ J6 O+ P6 M
  104. 0 l3 T) V) n9 t( N2 P
  105. " g' X$ W1 I1 B' ~/ O, x3 _
  106. static err_t accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
      B& M, w5 c, m# b
  107. {& ~- x& Z, T& H5 y0 v2 |$ O
  108.         if (tcppcb == NULL)& |! d" v. w$ F6 e2 i$ S. y9 W
  109.         {
    6 H) p! y0 a' a' q$ b
  110.                 if (err == ERR_OK)4 |2 a$ n  [2 G* K
  111.                 {
    9 z* r8 j: k* a- K5 U3 E
  112.                         tcppcb = newpcb;2 M; B& V; o) T. p  l  K
  113.                         tcp_arg(newpcb, NULL);
    - b9 A- Q8 K% P/ d' Y* K0 {: k2 T1 [
  114.                         tcp_recv(newpcb, recv_callback);, D9 g; X. t& o& Q9 g, c
  115. & @; ^2 F+ K5 K" e7 R# {5 ~: h
  116. #if (USE_ERROR_CALLBACK == 1)7 A) q5 M2 \6 ?) J- @
  117.                         tcp_err(newpcb, error_callback);
    9 C. m' k- A) l3 q( E( S
  118. #endif
    9 p% d) d( i5 |5 k- s1 g+ v/ e# @

  119.   f  D) G! X, h8 D
  120. #if (USE_SENT_CALLBACK == 1)9 [* {2 _6 o/ _( H% X
  121.                         tcp_sent(newpcb, sent_callback);
    . r* _3 m$ G9 h0 q) D9 r
  122. #endif$ q$ d7 A: y$ L" M6 [

  123. " n3 M$ q; z4 @  Z2 Z- V% w1 r
  124. #if (USE_POLL_CALLBACK == 1)! i$ d& {) b3 u3 B: }* I
  125.                         tcp_poll(newpcb, poll_callback, 1);: `3 a8 i0 B7 G0 ?7 p0 j2 {
  126. #endif4 J$ ~) Z( Q+ z
  127.                         debug("\r\n %s:%d connect.", inet_ntoa(newpcb->remote_ip), newpcb->remote_port);
      @% c% x3 b( z' ^* @2 ^7 ~. g
  128.                 }
    : h$ b3 b0 D" ~+ A  a2 t
  129.                 else0 q. p1 O. G9 n7 k% g. K; P2 ~
  130.                 {, {) [( e1 t' l- W2 a, ~
  131.                         tcp_server_disconnect(newpcb);$ ]7 F" c+ d7 y" x- I
  132.                 }6 C2 r9 U; ^- ]) g0 g
  133.         }* Q5 k; R" A% ?9 O0 _# L
  134.         else
    ; ^! l) H+ z+ [' ?0 p
  135.         {
    1 F1 y' _# \( ?. v4 r  E' i7 K
  136.                 tcp_abort(newpcb);
      ]& }. J! `7 {3 [/ e- M; r' s
  137.                 debug("\r\n already connected. ");
    # \, J" H: e* j  ]# t
  138.         }. h; @3 W# N1 E  X. t2 h% }8 ?
  139.         return err;
    - J  M9 N  @4 p( J5 N# f& H
  140. }+ a) G, ^0 `7 a# Y

  141. / G7 z# ^# {# i6 Y6 f/ D& g
  142. static void tcp_server_disconnect(struct tcp_pcb *tpcb); w6 y: z- S  }4 _
  143. {
    & T, \9 M6 d5 s1 g
  144.         tcp_arg(tpcb, NULL);
      d4 z; p+ M- U& |
  145.         tcp_recv(tpcb, NULL);
    % s+ m. i3 ~$ Z5 L" C% W
  146. 8 [6 B+ W% p+ Z" w1 |5 S# [6 z
  147. #if (USE_SENT_CALLBACK == 1)
    ( |& @" `$ x% _# O9 b
  148.         tcp_sent(tpcb, NULL);0 B/ C/ p" M5 m0 z1 h$ I
  149. #endif5 f* k$ \/ K& L3 m

  150. 1 q% ?) v' m( I3 O/ @" I
  151. #if (USE_POLL_CALLBACK == 1)
    * i& p* }% ?, V9 i, }
  152.         tcp_poll(tpcb, NULL, 0);
    2 A5 }3 ~( _) ~: y
  153. #endif
    ' a  d2 q, [# [

  154. ' A; d7 [$ i9 \4 a* n9 w* N# `
  155. #if (USE_ERROR_CALLBACK == 1)2 \& `7 z$ G# h) t3 S: z( S. }
  156.         tcp_err(tpcb, NULL);
    ' w& H% h9 D% l* I* V1 |
  157. #endif
    ( [5 d% U' L4 N! c
  158. " S8 J2 o$ r; a" j
  159.         tcp_abort(tpcb); /* 关闭连接并释放tpcb控制块 */
    : Q/ z; s( W, d* g6 n
  160.         tcppcb = NULL;! ^) b8 S3 e7 \+ ]
  161.         debug("\r\n disconnected.");
    $ [  m1 O8 w$ I
  162. }; J1 X) p: D3 I( z

  163. ( q# |% B+ z2 U$ Q. L: Q
  164. static uint32_t tcp_server_send(struct tcp_pcb *tpcb, const void* buf, uint32_t len)2 n6 E* }( m* a& Z6 U2 Q
  165. {' M, E$ ^& b! O5 O$ K, U& L9 U
  166.         uint32_t nwrite = 0, total = 0;
    5 s0 ]- N- h5 U7 m: l% w
  167.         const uint8_t* p = (const uint8_t *) buf;+ {* ]8 f! `. g4 y- j3 @$ R
  168.         err_t err = ERR_OK;
    * q5 ^% m+ g+ j# k; M9 k
  169.         if (!tpcb)
    * i0 U5 U- c% Y( F1 B7 b
  170.                 return 0;2 c( N4 k3 y3 f/ D5 v  S$ I
  171.         while ((err == ERR_OK) && (len != 0) && (tcp_sndbuf(tpcb) > 0))" ^2 {2 `1 w. Q
  172.         {6 w' f& l: A5 b) Y2 I" E
  173.                 nwrite = tcp_sndbuf(tpcb) >= len ? len : tcp_sndbuf(tpcb);5 [6 Q1 t# _+ a* ]7 d
  174.                 err = tcp_write(tpcb, p, nwrite, 1);
    0 S% l9 ~, `6 D
  175.                 if (err == ERR_OK)
    ' n4 W* `3 E9 r/ h
  176.                 {& u9 z7 {+ _* Q  D
  177.                         len -= nwrite;& Z6 x& J; v8 S: g2 f. \
  178.                         total += nwrite;+ [' n6 `& m2 W
  179.                         p += nwrite;
    : X, u! @) P7 T! i4 |3 z
  180.                 }* D) C! f* n( r0 U9 }1 |) T. M% L
  181.                 tcp_output(tpcb);2 r8 d2 @1 |( n; ?
  182.         }
    1 I- c' v1 J) e1 a+ X0 S: E  t" N
  183.         return total;
    5 a# C* Z/ V) q8 \
  184. }; E$ @- [5 ^1 R: W& p. z& }% a

  185. 1 A8 l: W$ @- z/ S3 w4 J# }
  186. / 导出以下函数供外部调用 ///
    ; U# g. n8 {, b6 A1 h
  187. 1 {/ e. I% N4 y8 p# Q
  188. //extern int tcp_server_start(uint16_t port);
    ) l( j9 P8 z' B; L1 N7 z( D
  189. //extern int user_senddata(const void* buf,uint32_t len);
    ) P7 y$ q% C, p1 J* m
  190. //extern int transfer_data();, I( Y4 G; p& @. N- R) a) g7 G

  191. " g/ u# p, |: K1 c2 b+ b, K% c
  192. 3 J  p- p+ x  L  V% j+ N' a6 }% ]
  193. /**8 A+ w" _, n8 B4 H5 f' S9 w
  194. * 启动TCP服务器
    4 S% b. p4 m/ Q8 H9 ]" u' p" N/ k
  195. * @param  port 本地端口号  N3 w& J0 U5 f2 h0 A3 b( i
  196. * @return      成功返回0& y, p( r- P6 ^, M, ]3 i
  197. */1 E; H4 s: T& c- U) E
  198. int tcp_server_start(uint16_t port)3 g# Q6 N8 D) R
  199. {, g5 Q' o% e! m; z3 i" L
  200.         int ret = 0;) \5 m% A4 C+ L: `2 _+ {* V6 x$ a
  201.         struct tcp_pcb* pcb = NULL;6 }1 h+ |, ]8 @& P/ N
  202.         err_t err = ERR_OK;
    ' D/ S: f, M. i1 g- x  x$ i

  203. - }0 n% ]( M2 M3 u8 k$ M1 W7 g! k1 I
  204.         /* create new TCP PCB structure */
    8 H$ A- W% ?/ {/ P! @$ Q1 ~5 |; m
  205.         pcb = tcp_new();/ `9 D3 }; W9 m7 q- i# r. b* |/ v
  206.         if (!pcb)
    . k$ s' }3 u! @+ Q$ _: H: t
  207.         {. a/ X: C2 t) r8 \0 U$ _; D; k
  208.                 debug("Error creating PCB. Out of Memory\n\r");
    5 G# D. }( n" P# f7 n+ d
  209.                 ret = -1;  r' M. p9 B# P1 x: x
  210.                 goto __exit;
    , V! b/ }$ c- S& I! |' d, S
  211.         }
    ) z* N7 f4 k/ j/ X. g, J: q

  212. 3 c# g' |* h- x; I
  213.         /* bind to specified @port */
    , i1 ^1 @$ e* j& S1 h  t
  214.         err = tcp_bind(pcb, IP_ADDR_ANY, port);
    , a: X! n/ N7 ^/ _$ P
  215.         if (err != ERR_OK): {' l* |" g. E* U; L
  216.         {
    2 }* V5 l) g2 V. }" N7 G' h" N. s
  217.                 debug("Unable to bind to port %d: err = %d\n\r", port, err);
    7 S9 q3 U4 @5 ]- J: r# @1 N
  218.                 ret = -2;
    ( b  v& b# U3 Q$ Q* h7 m! A
  219.                 goto __exit;
    , @2 }: P" d: g+ a& ?6 u
  220.         }5 ]: G$ O! z% \. q( T
  221. # s( S9 B% n: m/ ]6 \( V0 U
  222.         /* listen for connections */0 R# h& q) a/ T; E$ i7 g. o! E* Z
  223.         pcb = tcp_listen(pcb);
    ( D2 X+ @, [& c8 w) s
  224.         if (!pcb)
    8 y" q, ?; f) ~# H. Z
  225.         {
    - V2 k3 h& m% |2 O- v3 o, W  V
  226.                 debug("Out of memory while tcp_listen\n\r");) v4 @9 V( C! Y) Y6 k* G
  227.                 ret = -3;
    2 @& f' M2 J" l+ J
  228.         }
    4 F, A0 |. @3 D* ~

  229. 0 _3 T0 a2 H2 |, V5 s3 J7 o
  230.         /* specify callback to use for incoming connections */, X) T$ o4 j4 B/ Y0 ^9 s  n
  231.         tcp_accept(pcb, accept_callback);( C8 \3 G4 o% \" ^& w

  232. ( x9 O5 I! A1 {$ G1 a6 M& m
  233.         /* create success */+ e4 ~- f( E7 T, W* N
  234.         debug("TCP echo server started @ port %d\n\r", port);& C4 X; C$ j8 |0 u4 A2 E. p3 B
  235.         return ret;
    , N% g1 J$ B& h: W& p- u" {* h
  236. . W: G4 l8 p# Y# y  b# ^
  237. __exit:2 E# _# i" q: P7 Z# a: h. t& w0 d
  238.         if (pcb)" v  N. a0 e& P7 k/ [
  239.                 memp_free(MEMP_TCP_PCB, pcb);
    ( S% K3 ?) T4 [1 X+ u) k4 d0 |
  240.         return ret;
    2 n4 I5 H2 E: Q% B$ l2 O
  241. }  V3 r( h; [8 C, S2 r- n$ P* T. U: q

  242. 8 a0 x$ \$ g" n5 e$ P
  243. /*** x1 X0 R, @4 j& v! M, P; x
  244. * TCP发送数据1 l. s2 C. s0 m3 x1 Z" C6 m
  245. * @param  buf 待发送的数据
    $ A, G' J" W0 W+ H) g
  246. * @param  len 数据长度# Q  ], O) Y! a* R& a
  247. * @return     返回实际发送的字节数
    8 g% E& @7 x6 Q7 ]
  248. */! P  Y# o6 m8 r6 I
  249. int user_senddata(const void* buf, uint32_t len)+ Q) w2 M; O# l$ T) [3 B! k# W2 ^
  250. {! L/ Y* g. _& a/ w
  251.         return tcp_server_send(tcppcb, buf, len);3 J6 g1 C' G0 R5 K" }3 P
  252. }
    , h7 T7 A* U& I+ S0 [, \$ N

  253. + |2 x" d7 d' t) F
  254. /**# D$ j6 f7 h2 B' \( s! `+ P" X
  255. * 轮询函数,放置于main函数的while死循环中
    ( J$ w9 R6 Q# O/ T, e- S
  256. * @return 无$ V) a7 W) A2 Y' M
  257. */
    0 a7 p& q/ `; r* `4 a) L$ e% i
  258. int transfer_data()0 V4 ^& }! G, F9 W: I& u
  259. {
    ' v! p& Z$ E8 L- O5 m
  260.         uint32_t nsend = 0;
    - o/ h& w1 R) }* C# r
  261.         if (tcppcb != NULL && tcppcb->state == ESTABLISHED) /* 连接有效 */
    - r3 `1 K: d4 s9 L& K  s
  262.         {8 V; D8 t* w0 M1 f5 M4 t
  263.                 if (TCP_RX_STA & 0x8000)   /* 有数据收到  */% E7 L! f, z6 X( |/ I  F
  264.                 {
    * v4 m/ X5 ^! r; `+ q/ U! o; g
  265.                         nsend = user_senddata(TCP_RX_BUF, TCP_RX_STA & 0x7FFF);    /* 将接收到的数据发回去  */2 N% g, O% q$ M( i' j
  266.                         TCP_RX_STA = 0;3 u1 E5 H7 f0 S0 v1 c
  267.                         debug("\r\n send %d bytes success.", nsend);, Z/ _1 A4 J& X$ o5 W4 P
  268.                 }; r/ x0 U* M# R2 @" w0 N
  269.         }) w# N3 }+ r5 O/ y+ V7 O* C
  270.         return 0;: ~" z3 U: w- w) s' w
  271. }
    8 c6 Y- w8 S' Z, R3 n
  272. 0 }" |1 C$ [% H% }5 a% G
  273. #endif
复制代码

6 V& |* F2 T- y4 H: N$ H' u
, _- b& F  ]8 ^7 e/ U, S: {" ?' s8 R" C% @) [. I* Q" ?5 e! l* J
) P. O. f; f8 g0 e! W3 o2 ^
收藏 评论0 发布时间:2022-4-11 10:16

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版