对我启发较大的是 App_Link_Thread_Entry 线程,这个线程会定期检测网络物理连接。9 t( J! ?5 f3 @+ e/ z2 X% M9 h
接下来是 App_Main_Thread_Entry 线程,这个线程主要是完成联网的准备工作。还有就是对 App_Link_Thread_Entry 线程数据的初始化。 - $ E% f3 f6 `; [5 Y
- /* Exported macro ------------------------------------------------------------*/
! c' M0 f. o6 B, i, g - /* USER CODE BEGIN EM */
2 \: ?- G, L; o5 ` \- n: O - #define PRINT_IP_ADDRESS(addr) do { \9 i9 ~+ H' a: k1 R
- printf("STM32 %s: %lu.%lu.%lu.%lu \n", #addr, \
5 U8 l$ Y( i' y - (addr >> 24) & 0xff, \/ k& y {: y& y! [9 r+ h
- (addr >> 16) & 0xff, \3 {* g6 D( y, Y- `* A8 I
- (addr >> 8) & 0xff, \3 ?+ a+ {) L5 f1 X3 J. g- i
- (addr & 0xff)); \
! h3 X. A+ {( F! ]1 N - } while(0)
复制代码
) |- j9 V. n4 g: C# l. W4 {
主要的工作线程是 App_SNTP_Thread_Entry,这个线程完成整个过程。 - /**/ [/ w6 N3 \2 i! b6 Q: L7 z" u
- * @brief SNTP thread entry.
5 X* y$ J7 P& G - * @param thread_input: ULONG user argument used by the thread entry
7 I& G$ V2 b( \1 H1 y$ d- Y - * @retval none8 z' W8 ~5 n9 j* s8 [# k& _
- */
& h* l% a2 T- |9 W+ R3 q; [1 C - /* Define the client thread. */
( J1 s- ]5 x$ ~/ { - static void App_SNTP_Thread_Entry(ULONG info)# X1 F/ g9 \+ |1 E
- {
3 F/ f& h8 C* e) N. w - UINT ret;# b5 p. O$ g& }+ W0 j. R$ K
- RtcHandle.Instance = RTC;5 ]( E, ]$ v* P+ l$ ?4 x
- ULONG seconds, fraction;
, {6 I1 L# h! t# J1 T - ULONG events = 0;* E: [$ t; Q# \+ A. D) r" w+ E, _
- UINT server_status;
0 F; i% q) C4 u2 T, e w - NXD_ADDRESS sntp_server_ip;$ o o1 u6 b l v
- NX_PARAMETER_NOT_USED(info);
! [: g( V( I2 X; F0 r - sntp_server_ip.nxd_ip_version = 4;# K1 S; S l0 ]& [
- /* Create a DNS client */
) U0 ^" D- B/ r7 V+ X: \ - ret = dns_create(&DnsClient);
5 }( Q! e0 _' G, E' Q* R; a - if (ret != NX_SUCCESS)
/ x# m% T+ q9 H3 B, D; X' ` J - {) Y2 Y) H \- b1 d! Y# Z
- Error_Handler();& ]$ @$ C! _5 a. ^' v
- }
- N; @' U4 P0 H# N - /* Look up SNTP Server address. */: U+ a7 ?4 K( }% Y: m( V
- ret = nx_dns_host_by_name_get(&DnsClient, (UCHAR *)SNTP_SERVER_NAME, W6 _& u6 F5 y2 M0 O2 R6 O. o
- &sntp_server_ip.nxd_ip_address.v4, NX_APP_DEFAULT_TIMEOUT);
$ e% _* o. F+ f& r9 D4 }4 i - /* Check for error. */5 F9 k; d$ c6 x3 i6 o
- if (ret != NX_SUCCESS)
; I0 V" w; Z8 f8 d% O9 U - {3 @5 G% Q( V9 s% o2 u2 a) i; i) s
- Error_Handler();# G) r& N2 H6 p
- }
) a* Y& P) ]7 g# h - /* Create the SNTP Client */
' ^* ^: X I7 U% h4 N - ret = nx_sntp_client_create(&SntpClient, &NetXDuoEthIpInstance, iface_index, &NxAppPool, NULL, kiss_of_death_handler, NULL);
6 Y' z( r" C5 p, t - /* Check for error. */
+ C) F, R7 H7 h3 `% d7 C - if (ret != NX_SUCCESS)
. G4 H" {2 t! P4 Y5 U - {
. S7 [7 L$ f/ }6 @3 R - Error_Handler();
/ ?& P5 ^" | h5 e4 F - }
+ L# i3 h6 ~5 R& Y R - /* Setup time update callback function. */
) \7 w6 Z8 o H B& P - nx_sntp_client_set_time_update_notify(&SntpClient, time_update_callback);, i7 M2 y7 y+ x. X& x. ^8 E5 Y
- /* Use the IPv4 service to set up the Client and set the IPv4 SNTP server. */
# t; Z( R6 n- D. a0 N& r - ret = nx_sntp_client_initialize_unicast(&SntpClient, sntp_server_ip.nxd_ip_address.v4);
$ ]* m1 O# o$ W, X$ s' q% a - if (ret != NX_SUCCESS)/ m# `. r8 r: V8 d5 s, E
- {
7 \' B1 f3 z. h4 `: K+ L, V - Error_Handler();3 t! z0 B9 f" O: q
- }# f8 D# J$ H( _# r6 @) T4 t0 J, Q5 v
- /* Run whichever service the client is configured for. */
$ \- V5 i( M$ w) \) B - ret = nx_sntp_client_run_unicast(&SntpClient);9 @( s4 I; L; U! O
- if (ret != NX_SUCCESS)6 y+ E1 E# M8 F1 O- [: S( ?& o) }+ n
- {
9 X) s" M6 @& P4 z# E - Error_Handler();
! d2 T/ @7 V1 I5 L4 Q6 j - }. V ]" J' v7 |+ D
- else
! Y) |0 K4 @9 K4 G2 D8 M3 [( d! u. | - {2 J% f6 u5 @1 `! X+ j2 [8 z4 g2 G
- PRINT_CNX_SUCC(); ^% q$ v v2 m; j; b
- }2 L( } w6 e9 ~ T, V% L
- /* Wait for a server update event. */: Y- }5 _! I! D( G; |3 ^' o
- tx_event_flags_get(&SntpFlags, SNTP_UPDATE_EVENT, TX_OR_CLEAR, &events, PERIODIC_CHECK_INTERVAL);
# p4 f& l* ]( O3 b' K4 O$ i6 N - if (events == SNTP_UPDATE_EVENT)
3 B5 s6 F" }" |: _& c# H( V6 M - {
W6 _/ v! ]) c% R - /* Check for valid SNTP server status. */5 V0 S5 |$ @, b) ?! X
- ret = nx_sntp_client_receiving_updates(&SntpClient, &server_status); \' D% P/ a2 m0 F0 C
- if ((ret != NX_SUCCESS) || (server_status == NX_FALSE)): O+ ^9 b6 m/ K& f! a. U
- {
4 [" u; u/ e- V1 n0 ^ - /* We do not have a valid update. */
. T3 _8 f+ L8 y9 u2 l - Error_Handler();- E/ p7 \" p% n9 @( K6 Y+ i
- }1 w4 m: M9 @$ J0 r" R: m
- /* We have a valid update. Get the SNTP Client time. */; u" @. _$ q1 a* R9 R% }* y+ p# ^
- ret = nx_sntp_client_get_local_time_extended(&SntpClient, &seconds, &fraction, NX_NULL, 0);4 U) `3 B9 ^! |) |6 j7 B
- ret = nx_sntp_client_utility_display_date_time(&SntpClient,buffer,64);
+ S& D# z& ?7 ~3 H; } - if (ret != NX_SUCCESS)+ ]5 I6 ~& { Q9 r* W, C( [
- {
' A, v( q- H8 x6 x: o8 c" S6 [" m - printf("Internal error with getting local time 0x%x\n", ret); j, `" j# {& D0 p7 \. A
- Error_Handler();
. f6 P+ E, n$ n - }& _7 R0 ^1 M: n2 U% ]7 C
- else
! w: [8 A n; D" N; _ - {( Y9 f- m/ n+ v! l2 }$ f
- printf("\nSNTP update :\n");
6 H4 Y! a; i$ r7 S" Z$ Q - printf("%s\n\n",buffer);
1 y* F1 P2 X: e+ [- C1 d - }
* i2 n( W$ e: S7 y - }! d- }1 A7 a( I4 s& ]7 G
- else9 A+ ~% ^" b4 o2 c
- {/ f; ~7 y: Y5 N% r2 o
- Error_Handler();
. T# i0 l' q& H" ?% C - }
$ s7 \$ @$ T2 t! @ - /* Set Current time from SNTP TO RTC */
8 _4 _) S }3 i+ o3 ? - rtc_time_update(&SntpClient);0 p3 ^+ }; z, f3 Z0 T, R! e
- /* We can stop the SNTP service if for example we think the SNTP server has stopped sending updates */5 @8 D& X7 o4 A0 @+ g
- ret = nx_sntp_client_stop(&SntpClient);# q& w- Z" X) S+ ?' z4 p: u
- if (ret != NX_SUCCESS)* M" s" M, Q" m& z6 d* ]
- {' i( r, r! G% y2 b6 _" x
- Error_Handler();# U; y7 z/ x: h8 X5 y# N) N3 J
- }& A5 x; H6 t/ N
- /* When done with the SNTP Client, we delete it */
5 e! v; H# e' _5 f/ c! n" T/ H - ret = nx_sntp_client_delete(&SntpClient);/ b% h% |' H" F# f* ]8 _+ J
- if (ret != NX_SUCCESS)
/ l+ G/ V: F; j: E# H - {
2 \' j8 G& {0 |( n$ A - Error_Handler();
) E Q5 E; J1 V+ ?4 X+ x- o% E/ h% g5 H - }4 G ?- m8 D; t. \7 D
- /* Toggling LED after a success Time update */
2 h* c( k, e% h' z8 Q+ w( k* x - while(1)
1 g# x- N( }! n% r: c - {
+ } W5 @& X0 K4 Q4 B1 \2 l! Z - /* Display RTC time each second */
X2 v- ^/ e6 H( u, { - display_rtc_time(&RtcHandle);9 X$ h4 O5 P+ z3 T7 d' Z8 h% O
- HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
# `) K4 B+ e; e - /* Delay for 1s */
+ c% t: e. }& T# r# c' T! G0 x - tx_thread_sleep(100);: I5 t/ l u3 k' m8 j" F
- }
& I3 @2 o4 K7 d) M) Y/ w$ j* d6 Z - }
复制代码4 K; u |; R2 M1 ]4 I$ {* ^: M
这个程序目的是完成 SNTP 获取,设置到操作系统参数和 RTC 设置中,就可以不断地获取时间了。
' w: ~' C2 Q2 @
可以看到时间显示出来了。但这里需要注意一个“坑”,就是发现时间好像和计算机显示的时间对不上,因为这个时间与UTC时间在不同时区,随即找到以下程序, - /* EPOCH_TIME_DIFF is equivalent to 70 years in sec# ]6 p# s8 t1 ~9 k* W# t2 P. E
- calculated with www.epochconverter.com/date-difference; P$ U n7 R* d6 l. s
- This constant is used to delete difference between :* v. m" V0 Z) F
- Epoch converter (referenced to 1970) and SNTP (referenced to 1900) */
6 V8 d6 Z6 N4 a* ]* g+ d" K - time_t timestamp = client_ptr->nx_sntp_current_server_time_message.receive_time.seconds - EPOCH_TIME_DIFF;
复制代码
9 {0 _" \- M: l+ V; \
将程序修改成: - /* EPOCH_TIME_DIFF is equivalent to 70 years in sec
* O: ?1 x) j: \! D - calculated with www.epochconverter.com/date-difference- b9 p; ^8 |" C& R3 z8 T, F5 M
- This constant is used to delete difference between :0 b& m0 d5 J2 Y
- Epoch converter (referenced to 1970) and SNTP (referenced to 1900) */
1 o' c9 a1 f2 k" Y( C9 B- f0 s) o - time_t timestamp = client_ptr->nx_sntp_current_server_time_message.receive_time.seconds - EPOCH_TIME_DIFF + 28800U;
复制代码3 O4 A% b4 M+ f
这样转换成 UTC 0800 时区时间。
p% n7 w. |7 h
后记:这个程序经长达3小时测试,未发现任何中断现象。反复的ping单片机地址,TTL 值一直很稳定,相比 lwIP 程序改善很多。
5 _; y# |4 L; y! R9 Q& H
7 W; |9 Y2 N6 Q: P+ z
来源:EEWORLD论坛网友 bigbat 版权归原作者所有 ; A+ D5 W+ k' H: [3 e0 x
/ z% a3 O- p- Y' M
|