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

【经验分享】STM32G0学习手册——FreeRTOS信号量

[复制链接]
STMCU小助手 发布时间:2021-11-12 01:00
二值信号量的用法示例
8 {5 [# c) q& _5 [& n" ^1.创建好带有printf-stdarg.c的FreeRTOS的工程0 T: \7 D4 f6 s; z3 V7 l" r
$ m8 U% M/ _! {# b8 {; L5 R  _
2.修改main.c文件
( o4 k4 P( Q% S7 z/ t, k1 u8 L
- V  P: n& m+ S* G1 }
  1. /* USER CODE BEGIN Includes */
    ! c: y1 P* k  q, `# w& q- I

  2. ; v3 q- W# V2 }: {- T7 `
  3. #include "FreeRTOS.h"
    0 m! n5 P7 \! q. q) C' \  l
  4. #include "task.h"
    ! a% r" x+ l8 [1 Z8 e, k8 B
  5. #include "queue.h"' N* m8 @+ v6 ?- }9 y1 |
  6. #include "semphr.h"% S, y8 @+ U% }8 _
  7. #include <stdio.h>: s% C" Z6 C* F  r
  8. #include <string.h>! i( X/ q; u0 z: W% Y1 m/ q: d' j

  9. ' p; _& }* b& D, c" n
  10. /* USER CODE END Includes */3 B5 s8 I+ U8 j/ `% x1 D: U* U
  11. /* USER CODE BEGIN PV */7 a2 Y3 w$ e! b+ V

  12. / F  Q7 O- q( T+ K
  13. static TaskHandle_t AppTaskCreate_Handle = NULL;
    6 _1 k4 ]6 l! f/ x: ?9 Z
  14. static TaskHandle_t KeyTask_Handle = NULL;9 u; P, a( w# \
  15. static TaskHandle_t Led1Task_Handle = NULL;
    5 J# w0 y+ k0 N# ?2 g& T, W3 ]) M! E6 A. I
  16. & H3 F, h7 `! `  G) v5 u
  17. /*Create a binary semaphore handle*/
    5 u6 {; q4 }, x  j: L9 r
  18. static SemaphoreHandle_t Binary_Handle = NULL;
    ) W3 j. T, `7 ~, B" @
  19. , s3 |+ ^' c! N3 ?5 U0 |; K" O" ^
  20. extern int f_printf(const char *format, ...);6 ~; ?7 s3 A& t8 O* t( B( Q8 M

  21. : v* n  Y6 M9 _+ }& e* G7 F  J
  22. /* USER CODE END PV */
    . J" T; I1 i' H, w& M1 V& p
  23. /* USER CODE BEGIN PFP */
    $ Q. r# Z; K3 Y* j
  24. $ X+ D% G$ B9 C
  25. /*Create a task function*/
    ) l% I! W- @2 P5 J9 ^4 n. [
  26. static void AppTaskCreate(void);4 ~% E0 `7 T$ {2 [
  27. static void KeyTaskCreate(void);/ M" w. Z' g# g, G+ L. [( C$ o
  28. static void Led1TaskCreate(void);
    / Z1 d/ |3 Z. h, Z# c

  29. 4 D  Y' j1 G3 x
  30. /* USER CODE END PFP */+ @7 b; m9 |9 E( S' V% U
  31. , y$ ]7 D7 `+ y. g7 S  w+ E
  32. int main()' a" I3 ^( w. A9 d( _
  33. {
    ; h" k5 j8 o! k0 G7 j9 z
  34.   /*# h9 A1 M" t$ b
  35.   *
    ) \/ A. d- m/ P* g/ u- F
  36.   */
    4 G6 S5 L, V% ~& F& O! c2 h, E
  37.   /* USER CODE BEGIN WHILE */& A# V( x9 G, _" j7 c; r  e
  38.   UBaseType_t xReturn = pdPASS;
    , X& R* j) N' A' o
  39.         
    0 t9 X# V7 T5 [* {! e6 s, M, J" O
  40.         xReturn = xTaskCreate((TaskFunction_t)AppTaskCreate,
    * r" b1 X  K* K. o
  41.                               (const char *) "APPTASKCREATE",
    0 j# U! L- a. Y- y
  42.                                                   (uint16_t)     128,  k# p" S6 p( _/ _
  43.                                                   (void *)       NULL,+ R, I- d6 ?* g" }; Y6 K
  44.                                                   (UBaseType_t)  2,# j' ^& D1 E  S- F* p% @1 }
  45.                                                   (TaskHandle_t *)&AppTaskCreate_Handle);5 Z! z+ X" V; O; C* D, g/ V
  46.   if(xReturn ==pdPASS)
    8 y% I0 ~( E. F0 H6 K! o- z  a/ T
  47.         {
    % P3 t9 S' l1 \, H8 ~: n
  48.                 vTaskStartScheduler();: n5 h6 X+ Y; @! y( m+ q
  49.                 f_printf("start..\r\n");8 W; g5 g( v/ N( U* q9 B7 y
  50.         }
    8 T# ^4 R% S6 f" H+ O
  51.   while (1)) n7 ^" T+ f) B! d( m9 U
  52.   {
    ; m5 _  x9 t, }5 G6 }
  53.     /* USER CODE END WHILE */
    1 |' ?% f! s/ `7 Q& Z

  54. . ]- E& N& ]/ s' F
  55.     /* USER CODE BEGIN 3 */5 g) r3 i5 h/ p. F  a) s
  56.   }
    5 V. T2 q/ ]6 r& w% ?; C& b( K4 G
  57.   /* USER CODE END 3 */9 l' h0 q  W- J5 Z) t* O
  58. : t9 R* D1 i% [4 h

  59. 4 B8 v$ z- b; N. Z8 z3 F6 z
  60. }
    - B( w6 w/ j9 I  [; c4 H! r
  61. 4 c: u3 y. }, U
  62. " m6 y  x: @, T& L9 ?  c9 ~. c
  63. /* USER CODE BEGIN 4 */
    ) L7 o7 J# i% [1 n: r: j# Q' y7 h
  64. static void AppTaskCreate(void)
    / d; L7 O  }- V
  65. {
    4 U& `# r, _+ Q
  66.   UBaseType_t xReturn = pdPASS;
      Q( O- s( R3 q% H5 l& {6 r
  67. " n* t( L1 {) S7 y: \' T

  68. $ q5 _' j/ B% W3 Z- G
  69.   xReturn = xTaskCreate((TaskFunction_t) KeyTaskCreate,  k, Q+ m+ c1 |- p: B$ t* K
  70.                              (const char *)   "KEYTASKCREATE",
    . U' h& q4 S1 S( P5 j4 l' V. I( L
  71.                                                  (uint16_t)       128,
    : Y$ }- j+ L( a+ N: X# U* D
  72.                                                  (void *)         NULL,( |9 o' M- P. e6 ^
  73.                                                  (UBaseType_t )   2,
      }0 |! B7 b4 k# w* R+ _
  74.                                                  (TaskHandle_t *) &KeyTask_Handle);
    - A# s8 H; l, ]: z3 a% A
  75. 7 w% }' H5 H2 P0 k: H
  76.   xReturn = xTaskCreate((TaskFunction_t) Led1TaskCreate,
    . I7 A1 t0 K* P2 z3 d: V1 _, U
  77.                                                 (const char *)   "LED1TASKCREATE",2 l! ~. `% L3 n& B: T
  78.                                                 (uint16_t)       128,7 Q, o/ U' G% {' Q! T
  79.                                                 (void *)         NULL,* V5 l5 B+ t6 R
  80.                                                 (UBaseType_t)    1,% o4 o: l5 H  G6 p
  81.                                                 (TaskHandle_t *)&Led1Task_Handle);
    7 X; ?. Q) g* L3 Z
  82.         
    4 B/ X. X  Z  K
  83.     /*Create a binary semaphore*/1 A2 g, T- e0 v) O  i& g
  84.         Binary_Handle = xSemaphoreCreateBinary();
    0 a  q2 `8 N1 u4 X6 T
  85.         if(Binary_Handle !=NULL)
    : f  W: W& Y! X& z% O4 {
  86.                 f_printf("Create Semph_Binary PASS.\r\n");0 H4 P$ L, ?, E2 R  ~8 o" C
  87.         % @% I  y2 i9 \9 K' J$ ]4 F" t( P
  88.         if(xReturn == pdPASS)  A8 r1 |3 {& q- s9 c7 n3 }. G
  89.     vTaskDelete((TaskHandle_t)AppTaskCreate_Handle);               
    9 a( ~+ q  h& i/ Y1 r" j
  90. }
    ) {8 V& B; }, v) G- c  t, Q
  91. 7 C# g4 \( G( Q& h% M: }
  92. static void KeyTaskCreate(void)
    ' {: u# g1 [, T
  93. {
    ) \9 p6 _4 B4 v) P! v9 k' X
  94.   while(1)+ d/ O# j% t' p
  95.         {5 E' {8 {* d, |, j
  96.                 UBaseType_t xReturn = pdPASS;
    + r/ ~" z$ a& A$ M6 {
  97.                 if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))
    7 M8 }* S$ d# K% X% \/ p2 Y! s
  98.                 {9 y/ V' S+ ]  J# i  {7 }6 k
  99.                         f_printf("KEY TASK PASS.\r\n");- E/ R+ _0 r- |1 m+ ~$ O4 U
  100.                         vTaskDelay(100);3 Z5 A5 F* @7 B9 X
  101.                         if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))
    2 c5 R8 l5 ?4 _6 [; a6 \# ~
  102.                         {* d$ y: X+ z5 E& [, X4 o6 v
  103.                                 xReturn = xSemaphoreGive(Binary_Handle);
    2 \8 Q7 a) x) T
  104.                                 if(xReturn == pdPASS)
    & h; x0 R& x2 ^( T7 \
  105.                                         f_printf("GIVE BINARY PASS.\r\n");
    8 L: t9 w% [/ N7 E4 V2 ?4 n" o
  106.                                 else if(xReturn == errQUEUE_FULL)! w* @1 S+ V" ]; g/ a( v; `
  107.                                         f_printf("QUEUE IS FULL.\r\n");
    ) b9 \; v& s( w4 A& \
  108.                         }
    ) D( x9 x7 U3 ?) V+ ~2 v# M
  109.                 }5 I: P* a- b/ z
  110.                
    + R/ ?9 v& m) Q+ }5 ^! I9 n
  111.     vTaskDelay(100);
    - D+ V$ d2 r$ B& `
  112.         }) ^; u1 p2 K7 O4 i
  113. % q0 y/ {3 B, s* Z( \$ `( N6 q% R5 N
  114. }
    1 \9 I& c' a: W% m% X
  115. static void Led1TaskCreate(void): t4 E; u$ y7 Q
  116. {3 H4 @+ j$ M  q9 O: s% C9 p
  117.   while(1)& E! |+ R# o9 F  E5 C
  118.         {; ~# J$ ?/ }8 Z% c  q5 E, H
  119.                 UBaseType_t xReturn = pdPASS;' g! \$ y: C/ ?3 |2 o8 P& K
  120.                 ( U' _: ^$ a9 F5 Z9 x
  121.                 xReturn = xSemaphoreTake(Binary_Handle, portMAX_DELAY);# e/ n$ F& H$ c' }9 [2 P- ]$ N
  122.                 if(xReturn == pdPASS)4 A1 n( j" T) y) R
  123.                 {3 l& ?! k7 ]6 E' T4 K$ K5 a
  124.                         f_printf("TAKE BINARY PASS.\r\n");
    4 R5 s/ B- j% ^7 x) ^- ^7 R, f5 h
  125.                         HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_2);8 N, n' g. y" C' T' N- ~
  126.                 }7 |5 Y' H; S* `0 p. p
  127.                 4 |" \! i4 w- ?" e
  128.           vTaskDelay(100);
    1 u! Y" [6 l% J( e3 l# @6 H. W% U
  129.         }" e9 K" A5 L- q! _- s7 ?" x7 a
  130. }
    3 |4 h$ O) _6 i+ z
  131.   a% i# D- I) L9 X# i/ c8 {  R1 y
  132. /* USER CODE END 4 */
复制代码

4 M( Q& V3 p& u2 G4 D- C* g( u计数信号量的用法示例  @# W, [) W/ e2 a% V% f
1.创建好带有printf-stdarg.c的FreeRTOS的工程  L2 i: N' `6 p3 m9 b
6 w1 t1 A- s! m$ I2 C5 K9 t6 e$ {
2.修改main.c文件
2 w  ?. j) T+ `9 e7 Y
, [  |2 o0 I  Y( h2 O
  1. /* USER CODE BEGIN Includes */* k+ j2 F% ~/ M* b1 H$ K& r
  2. & E, E8 J' O$ W6 ~6 g: ]
  3. #include "FreeRTOS.h"" D% l' g9 U8 i$ L: g
  4. #include "task.h"7 T) H; V; h7 N  v* P
  5. #include "queue.h"
    / F1 g+ F8 [" {  {/ A' h! N1 [
  6. #include "semphr.h"
    ; s$ L+ z6 c" z* w6 ~+ V
  7. #include <stdio.h>6 I" T  l6 Q, c- w# }$ x9 C
  8. #include <string.h>/ {' j9 v: K3 T: @. L) F

  9. ( R0 m( c+ L$ ]: d/ ^
  10. /* USER CODE END Includes */
    1 q% P; h: q8 m( s& N) f; g# o6 k9 g
  11. /* USER CODE BEGIN PV */
    6 R7 F0 j( z" z& {
  12. static TaskHandle_t AppTaskCreate_Handle = NULL;3 k# W6 u! b7 `( a
  13. static TaskHandle_t KeyTask_Handle = NULL;- z6 i  g) P6 X4 B- a! R1 f8 U8 S
  14. static TaskHandle_t Led1_Handle = NULL;
      t* k4 }' o: l0 h

  15. ' q+ D- r! q" ^+ A2 T6 T6 B- }
  16. SemaphoreHandle_t SemaphCount_Handle = NULL;
      x4 E9 D8 D. q8 `" H
  17. % l; P, F( c- d9 w+ g8 [( s  d# r
  18. extern int f_printf(const char *format, ...);% ^0 K3 Q% x/ P' O0 D/ w
  19. ; P# W% x1 e; y# p2 k/ o
  20. /* USER CODE END PV */
    ) w& v# W6 b5 M2 P( m* [3 t
  21. ( p2 N, ?$ E& I  z- d% e6 P. r
  22. /* USER CODE BEGIN PFP */
    ; ~2 M' a' Z0 F* i4 R

  23. # m" f) d/ r: V0 R5 w/ n
  24. static void AppTaskCreate(void);% |2 H; ]8 f" S2 S( F! A# B
  25. static void KeyTaskCreate(void);6 u/ n; @/ y1 y4 W6 O
  26. static void LED1TaskCreate(void);7 u! {- Y% p+ O

  27. 7 }+ R1 R) V; T
  28. /* USER CODE END PFP */$ x) x( Q, o& d3 e$ a. M2 _
  29. & d0 w+ W# M* X) V5 s2 T
  30. int main()  J6 _/ B. E- M4 }! F* P
  31. {  _0 l9 N  `* T
  32.   ***  a+ f) s8 d, u' m5 `# {( n
  33. , O& H) m4 h/ a. R. ^
  34.   /* USER CODE BEGIN WHILE */. m6 M9 h, W' X$ ]3 l
  35. " \$ I" R7 c7 C& h
  36.   UBaseType_t xReturn = xTaskCreate((TaskFunction_t)AppTaskCreate,6 j. D" O# d3 w+ p3 f
  37.                                     (const char *)"APPTASKCREATE",# c) J3 a2 {1 x# T/ ^0 u5 J
  38.                                                                         (uint16_t)    128,
    ' I8 r6 g/ B2 Q5 j" @* V, f
  39.                                                                         (void *)      NULL,; E! M, M2 p* y2 D
  40.                                                                         (UBaseType_t) 2,4 E- Q" y# f1 {+ W5 r/ C8 E
  41.                                                                         (TaskHandle_t *)&AppTaskCreate_Handle);
    : b* O) o) B& V% L8 g
  42.         if(xReturn ==pdPASS)
    4 ~/ r$ i: |9 T; ]; Y8 W5 Y! D
  43.         {- z3 p8 \3 `! q4 R: A
  44.                 f_printf("TASK START.\r\n");% u# f( G  B1 z
  45.                 vTaskStartScheduler();- X$ r+ v6 J' a  [0 y3 f
  46.         }
      A) `( `( b  l3 G9 X
  47.   while (1)4 j/ R5 V" w) M2 [  l
  48.   {
    $ C6 P% s* V2 o: V
  49.     /* USER CODE END WHILE */2 w/ h  Z% I' B& K0 s- ~( O
  50. . d5 c" q$ G' O; |4 V7 v3 A
  51.     /* USER CODE BEGIN 3 */
    ! G' F' z/ U' ~2 s5 L1 O
  52.   }
    ! M# p8 @: s0 e, R. E& Z+ l
  53.   /* USER CODE END 3 */% \' m3 T8 q  S) s  ~
  54. }
    ' y& ^5 J0 m- G. w, ]
  55. + Z2 \9 ~. e$ C4 Q+ C8 q& l
  56. /* USER CODE BEGIN 4 */
    # V% {( [9 g! i: ]6 @+ P( ]0 t
  57. static void AppTaskCreate(void)6 f4 c9 G/ c) M0 s8 Y
  58. {8 ^+ l, E2 I7 E4 l# I  P6 h

  59. , j2 ~, O9 }5 r' Q
  60.   UBaseType_t xReturn ;
    0 c$ P9 G# s$ F( s, A+ v3 @- l& C" x
  61.         xReturn = xTaskCreate((TaskFunction_t)KeyTaskCreate,
    5 e+ |0 w/ ~! j9 @1 k; s
  62.                                     (const char *) "KEYTASKCREATE",# B/ g/ Z* {) s% q
  63.                                     (uint16_t)      128,  r) T  X; l" y5 ^; Q  z
  64.                                                                         (void *)       NULL,* U5 C1 V% W, z7 ], @  x* I
  65.                                                                         (UBaseType_t)   2,
    + }+ S/ {% {! U
  66.                                                                         (TaskHandle_t*)&KeyTask_Handle);6 V! K; t% j7 n  \
  67.   if(xReturn == pdPASS)$ z$ R  Q' g3 P9 k1 _" k
  68.                 f_printf("KEY CREATE PASS.\r\n");( [* X  G* j  [* @) j/ ~

  69. / W, o' G8 h- u) u* c; f
  70.   xReturn = xTaskCreate((TaskFunction_t)LED1TaskCreate,8 g9 |2 r1 b) Y
  71.                                                 (const char *)  "LED1TASKCREATE",+ j3 F6 k7 J2 L7 d/ K& P
  72.                                                 (uint16_t)      128,
    % N4 ~* H$ K! ?
  73.                                                 (void *)        NULL,
    ! ?) P' V" I7 X
  74.                                                 (UBaseType_t)   1,
    + [2 e) D+ f( `
  75.                                                 (TaskHandle_t*)&Led1_Handle);' m! T& d9 T9 r7 z* S9 p) @
  76. " N2 u$ ?& H5 r/ H5 f
  77.         SemaphCount_Handle = xSemaphoreCreateCounting(3,0);/ M8 R8 R& Q4 F! e( _' g
  78.         if(SemaphCount_Handle != NULL)
    . I3 c; H- I8 B  F) R- V; M
  79.                 f_printf("SEMAPHORE COUNT CREATE PASS.\r\n");8 k+ ]) f2 X: _' v% p. Y; m
  80.         : V: m/ S" X/ O3 Z7 w6 d* H
  81.   if(xReturn == pdPASS)3 `# V8 Q6 r& ^
  82.         {
    / x; J: m9 S- Y5 j0 g+ |" ~) \
  83.                 f_printf("LED CREATE PASS.\r\n");        , D, e5 t: {: k) C$ Z
  84.                 vTaskDelete((TaskHandle_t)AppTaskCreate_Handle);( Z' n# Z8 Y4 b+ i' C
  85.         }; d  ]  q" \/ k9 Q
  86. }; [5 e; b9 C. b, _

  87. : ]# V7 G  ^' f/ p8 ^' p! T' \
  88. ) O" G% ^/ ^) j# Z" `( ^# `
  89. static void KeyTaskCreate(void)4 b; s$ X: Q; K' _8 T' B
  90. {3 r. i. e, G5 L3 y1 Z  T- ~: I
  91.   while(1)$ J; b! l5 {1 A! o& M6 r0 T1 Y  `
  92.         {, k  E" I2 y7 _9 G2 p( s
  93.                 UBaseType_t xReturn = pdPASS;
    ) a4 x* b2 k) g1 B) \' G+ d! P
  94.     if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)). ]8 T& y0 u  j3 ^
  95.                 {4 Q5 E( d3 x0 o8 I
  96.                         vTaskDelay(100);
    $ |7 l  C3 F, f0 [8 I- w' z: c3 B! F
  97.                         if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))$ [' M0 U; z- f
  98.                         {
    + M1 t' \% ]! r7 `. B6 ]
  99.                                 f_printf("KEY PRESS.\r\n");7 t  ~8 y; f( I, k, I
  100.                                 xReturn = xSemaphoreGive(SemaphCount_Handle);3 ~. J2 f* L4 M8 u" i0 p: T
  101.                                 if(xReturn == pdPASS)
    0 k. _1 o, K4 x% q
  102.                                         f_printf("GIVE COUNTING PASS.\r\n");
    6 w5 P( }8 f+ Q. @# e
  103.                                 else if(xReturn == errQUEUE_FULL)
    - f  Q' b$ M* |+ ^- x! U% Y6 F
  104.                                         f_printf("QUEUE IS FULL.\r\n");5 a' v8 T- u7 x$ q
  105.                         }
    6 ~, K, ?! s% s$ u9 O2 g9 r
  106.                 }               
    0 T+ c; d3 B7 D. g
  107.                 vTaskDelay(10);
    1 C# ~: s* Q% ]8 j+ F
  108.         }, ?) t8 c% B" g( |  ^7 I
  109. }8 {5 T' k' ?: U: H- Q  ]; H8 j! a
  110. static void LED1TaskCreate(void)
    ' H% ?: R- k% H
  111. {
    2 G% z* G4 @- c5 t  X
  112.         while(1)8 T- H" L+ \0 Y, U3 [! T
  113.         {
    ' h: L) f% A% W+ c5 H
  114.                 UBaseType_t xReturn = pdPASS;& W1 L5 o( j7 b  f
  115.                
    1 c  y" m  C2 {6 Z
  116.                 xReturn = xSemaphoreTake(SemaphCount_Handle,portMAX_DELAY);% n" c8 R* q  m( D2 C
  117.                
    6 _' \0 E$ |9 W5 _
  118.                 if(xReturn == pdTRUE)
    8 E# {7 j% `/ B' o% g$ C* a
  119.                 {* d! R0 g8 S( M9 h, J9 T( d
  120.                         HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_1);
    " ~6 y# c4 y' z
  121.                         f_printf("Counting Take PASS.\r\n");& r& X6 l( D1 }
  122.                 }
    & C, T5 }/ b+ L$ |* \
  123.                 else if(xReturn == errQUEUE_EMPTY)
    % f9 y' v, F* v/ l5 i
  124.                         f_printf("semaphore is empty.\r\n");
    4 ]% e* x( W4 y" \9 E$ l0 M
  125.                 vTaskDelay(2000);- c) _2 f) a4 u, P
  126.         }
    * ^# g8 ^% r( _8 h
  127. }
    : O( H1 f/ {1 N0 @. g3 i
  128. /* USER CODE END 4 */
    1 d3 v" f, o' b  h. \* p0 y

  129. 3 ]# }$ M" }4 |' R" B% K* U
复制代码

& U, u3 \5 A$ b7 r+ Z: U
收藏 评论0 发布时间:2021-11-12 01:00

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版