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

【经验分享】STM32F103:定时器中断 time——通用定时器TIM3使用

[复制链接]
STMCU小助手 发布时间:2022-5-3 22:25
一、STM32F103定时器
; B* F9 ]) t4 a" Y, I- {* i8 `4 Q- `- i& [" q* `
U}CZ4YCWOWR(@]TXY~F3~X8.png
. r' v: @0 }& _9 x0 {/ F  Y
; T% K! d. y  q二、STM32F103通用定时器
/ l1 [/ C0 s9 M% b1. 主要功能2 X- z$ `& P+ o; y
通用TIMx (TIM2、TIM3、TIM4和TIM5)定时器功能包括:
* n$ K! }$ Q4 W  V  w# K& |位于低速的APB1总线上(注意:高级定时器是在高速的APB2总线上);8 p% }, W' ^- x0 |
16位向上、向下、向上/向下自动装载计数器(TIMx_CNT);
9 L) G$ `% z- Z6 w& d! D1 f16位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为1~65536之间的任意数值;
1 C! g: ]0 j) B& g- z, I; s4个独立通道(TIMx_CH1~4),这些通道可以用来作为:输入捕获、输出比较、PWM生成(边缘或中间对齐模式)、单脉冲模式输出;6 k$ c* X1 ^5 W! U
使用外部信号控制定时器和定时器互连的同步电路;
0 B; b$ X# n+ i7 A# `如下事件发生时产生中断/DMA:更新(计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发))、触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)、输入捕获、输出比较;
# Q+ H! z* C) Q3 s9 _7 C# t6 J支持针对定位的增量(正交)编码器和霍尔传感器电路;  l# O; y2 G( X) {5 B# U
触发输入作为外部时钟或者按周期的电流管理;' c* ~5 V% o. d8 }
每个通用定时器都是完全独立的,没有互相共享的任何资源。
# E' X- D- t: q6 L, T' E2. 时基单元- X+ o/ r: n! K! x9 {1 ?% V
时基单元包含:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动装载寄存器(TIMx_ARR)三部分。1 f. p! F$ i& q
对不同的预分频系数,计数器的时序图为:
2 f$ j5 ~3 G' I8 ?2 T0 z
: x- z* ]0 x* Y% M$ B PKN[$BDPFW_036PR61X}}BM.png
2 S% C& [+ g. z8 y$ r" t& }7 B( @" [3 m3 ^( ]
3. 计数器模式
  @/ @) r$ B7 A向上计数模式
+ v+ ?+ t+ e4 k) r: g! @
3 {" ]3 U! S6 Q) s5 K' s
B}RV2~$HAMFD[ZPC(1TE12K.png
, f+ z. X# U: O; F/ }4 ^
" h8 V' Y, m$ g$ `/ u* g向下计数模式
: e; j- x- X! V! l* }) ?  V2 l$ u
& L- U* a  N" V. @
XB$CGMBDRM747}6~2TZ1Y9Y.png ( L, Y# q+ x# ^# f, R

% [( o; U. j! U/ b, p% N4 i中央对齐模式(向上/向下计数)

- k2 p( K$ k) I$ W8 x3 C, e% I1 I! S) V6 U0 L' B' ]- E1 l
_R~%{0NJ5~{PU98ND0P[XK0.png
& K1 F0 Q4 `: N6 v. ~5 Y% l8 t+ U; B& ~9 X( c
4. 时钟选择+ ?, e% k) H0 ]
计数器时钟可由下列时钟源提供:
# i& C1 T" X  m. n3 k& X4 k9 C5 Q& Y; G
内部时钟(TIMx_CLK)1 O" Z, m) G$ N% @1 q0 F9 A' t
外部时钟模式1:外部捕捉比较引脚(TIx)
' \& I4 t5 S. I; f外部时钟模式2:外部引脚输入(TIMx_ETR)
# K# o7 O& P1 J! {内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。
8 A  k1 k  u- n5 N$ M: C3 K, N* m' m
: \- i2 R( Y+ G( s- _内部时钟源
. M/ s' ~# d0 m; k7 d2 O+ L. c1 o
% r4 Y( I, {6 n; l9 C %~`O]HSK8Q74}2%I_HVQ_AP.png + O  K8 N! H  o0 N  n

. n4 w. r6 ~$ O. B3 I/ p0 k从图中可以看出:由AHB时钟经过APB1预分频系数转至APB1时钟,再通过倍频器转至TIMxCLK时钟(即内部时钟CK_INT、CK_PSC),最终经过PSC预分频系数转至CK_CNT。
6 V$ _4 S" w8 b5 T4 m4 [; S0 t  l8 C& k& y( G( I
当APB1的预分频器系数为1时,这个倍频器就不起作用了,定时器的时钟频率等于APB1的频率;, S. M# y) U; I# H: A
当APB1的预分频系数为其它数值(即预分频系数为2、4、8或16)时,这个倍频器起作用,定时器的时钟频率等于APB1时钟频率的两倍。' f7 l2 A+ S5 R! r/ E

3 J; J( e; w0 \) l默认情况下:* N, ~# T9 ?) M0 B- U
AHB总线时钟——STM32F103是72MHz,APB1时钟=36M。
7 q2 ^) H7 `2 ^5 T9 l8 y3 l. v所以APB1的分频系数=AHB/APB1时钟=2。
8 @) j% J1 A) \9 h7 O通用定时器时钟CK_INT=2*36M=72M。+ r9 I: m- [+ T" F
最终经过PSC预分频系数转至CK_CNT。6 q2 d% X6 S9 y9 ]% p! s  L
$ N' m+ d  X" r, K$ i% r$ u2 \: K
时间计算
' P$ S) g9 K# v) JTout= ((arr+1)*(psc+1))/Tclk;
' D: h2 v# Y/ p1 @& B& g2 C1 KTclk:TIM3的输入时钟频率(单位为MHz)。
6 ^% Q9 e* f. m3 {Tout:TIM3溢出时间(单位为us)。
( c; `# [  d" E3 P例:计时1s,输入时钟频率为72MHz。
4 D' p+ F$ ^$ f$ G0 W* @! x  arr = 9999,psc = 7199。. q3 i- ]; w6 g2 Y' o
  Tout = ((arr+1)*(psc+1))/Tclk = ((9999+1) *(7199+1))/72=1M(us)=1(s)9 \! A, c2 d# V& j* ]

3 N; Y/ Y- R+ H5 V% n! r! o1 I H_007WUT62FXL2JQ7VKEYGN.png
& M; y% x# T0 w' Q. @
9 O" P' u& c! S. y7 U' {5. 相关配置寄存器2 @" x3 Q( d- D4 q* Y" [( c
计数器当前值寄存器(TIMx_CNT). ?, @' e2 f+ M" N& U1 _
7 O' r/ B' |0 u2 k  w
7@JWBF5XPB[1BWFH9VZOAD2.png 8 f& I# U" r0 g2 s; x
  H  z' u) R7 v6 b6 q
预分频寄存器(TIMx_PSC)
+ i* r$ @, {/ p/ ~2 H
( V2 ]7 u1 o- |0 d9 }& r
W$]]{%OED6{AFRCM6LGD]IT.png
. o  s0 ?+ B/ v# a' q
$ R' I& G8 r0 @& a. S自动重装载寄存器(TIMx_ARR)& R2 |" f  d' ~3 m
# H; s6 {8 ~3 R& K
V_QT0)X_}_J%$YMRMF$H.png + `5 H# l' c8 }/ d
8 H4 I( a  ]4 h
控制寄存器(TIMx_CR1)
% W; R* {, t" f4 H! s) \3 Z* G* Y
0 V7 G/ z7 W+ \$ ~7 n' T$ L
~[6WPBO~LMO0OMW5_]ZL.png
, @* K! _7 ?7 x1 F( F
0 v+ ~$ ~; W( |! _' P ]T$BA}P]8K$ZY[~17F5A{GC.png / u: `: N7 H" {3 m( Q
  c4 `" e) {* n' g' K
DMA/中断使能寄存器(TIMx_DIER)
8 }2 M& G4 V* g8 q1 ]) M% D6 w* D# ~
}6$MI-@RO7W@M~K}KX%{C.png + J+ w( Q  @' h* k5 g
$ c- b. p9 g1 a, {/ I; i( D9 ]. Q% V
ZO}RIM8%({YU2[9QSX}[Z_7.png
+ W+ O. a- K& f- h& p7 \
2 d6 {) c4 t+ r7 C$ M5 t) k, A( r+ S5 Y三、编写定时器中断——time
6 k5 ]1 C. N* h6 e% K1. 相关配置库函数

7 w: R4 x7 P$ q1个初始化函数/ a4 S! Q1 X% m8 v
  1. void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
复制代码

. q9 f, E: [/ z' W) i  x! Q2 X, x作用:用于对预分频系数、计数方式、自动重装载计数值、时钟分频因子等参数的设置。+ x+ N4 i7 ^2 |% g+ S

( u1 {+ L3 }& x$ X% ?1 u+ J2个使能函数
0 Q3 P. X7 O' N' H1 g
  1. void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);        //使能定时器
    ! y8 i5 O/ x8 }. ]
  2. void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);        //使能定时器中断
复制代码
- z1 ~! Q9 H" a/ }0 ?
4个状态标志位获取函数

# G# O2 _9 O& K5 }+ L& r. ]& ]
  1. FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);//获取状态标志位+ ~8 \& Y" O9 }( S
  2. void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);//清除状态标志位# T; i% B8 h! f# i8 V& W& T
  3. ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);//获取中断状态标志位6 [9 f' E3 p3 Z# P4 z7 F5 {
  4. void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);//清除中断状态标志位
复制代码
- J( ]0 ]* p+ T6 W. \/ t1 |0 j( u
2. 具体步骤
+ y; s4 l$ C# a0 n! @. Q' E
1.使能定时器时钟。调用函数:RCC_APB1PeriphClockCmd();
3 h) Y4 g+ t! x2 n4 g8 G6 w2.初始化定时器,配置ARR、PSC。调用函数:TIM_TimeBaseInit();
& S6 U: n" o& c. M, ]3.开启定时器中断,配置NVIC。调用函数:void TIM_ITConfig();NVIC_Init();& u" V1 }( k! H+ C9 y
4.使能定时器。调用函数:TIM_Cmd();% k& l( m0 e# b4 z
5.编写中断服务函数。调用函数:TIMx_IRQHandler()。% p# A8 @) T, t! {8 R9 Q$ b
1 Y  Y+ I% F1 q4 j- n
3. 具体程序8 t8 G/ Z' V# w2 a; y9 [& E
time.h

' N  R0 [. B2 v; N% s3 p# p$ A
  1. #ifndef __TIME_H
      B- {. V) j; Z. P, I8 V$ O3 j. H  u
  2. #define __TIME_H         8 V8 a& b' H9 e* Q* S5 Q( B" J6 a0 t
  3. #include "stm32f10x.h"
    ( |5 N. S1 n3 {9 Z! |' D' L2 B4 l
  4. 2 _  W; s/ B( Y% z% w3 E8 {2 A
  5. //创建一个时间结构体2 `8 Z1 P* ?5 j
  6. typedef struct
    7 r& ~# @  ]' j- x
  7. {
    % H1 v0 D# h+ c7 w  w
  8.         u32     Tnum;
      i0 v  E/ Y; R- y' r; K6 W
  9.         u8                T100ms;/ _4 @4 h2 h( X3 {9 `& y/ ^
  10.         u8           T200ms;. z; t  t- J* ~! {6 S% Q6 }; N( x
  11.         u8           T500ms;
    ( z& H- Y# @; P1 S: p
  12.         u8                 T1s;
    - [  j3 z$ I) [! L% F3 {
  13.         u8                 T5s;4 \% @3 P, Y) W6 L& ?. ~, l" i
  14.         u8           T1min;
    4 R6 ?, U4 ^: e1 M
  15. }TIME_t;. W3 I$ u" t! ?
  16. & d8 H0 w5 |: _2 T# O* f
  17. extern TIME_t TIME;                //将时间结构体变量设为全局变量" g' Z% I# Z! q+ J  n
  18. / B  ?* m5 P- T
  19. void TIM3_Init(u16 arr,u16 psc);7 Q- n& e" j4 X* Y* p
  20. + f6 w& \# M3 Z
  21. #endif
复制代码

8 O/ h0 k3 p; z: btime.c

  M! L( m* D% f: }3 L6 n* {2 P/ ~% h
  1. #include "time.h"( e4 a% r- U! ~4 _& @
  2. : v7 g/ t9 t, ~- }0 Y
  3. TIME_t TIME;$ M& w/ m" s6 }1 u/ S

  4. . H: [3 E- e4 Q
  5. //通用定时器 3 中断初始化" v3 O. q  E" _3 Y& r0 g" m6 v2 }6 E& w
  6. //这里时钟选择为 APB1 的 2 倍,而 APB1 为 36M! f6 [$ x5 T9 `1 [) \* T" w
  7. //arr:自动重装值。1 j6 Y7 i4 K) t* w" k
  8. //psc:时钟预分频数
    * @& v! A& `6 H7 O& D1 p; M$ a
  9. //这里使用的是定时器 3!
    & B. F: x: A7 }" X5 q
  10. void TIM3_Init(u16 arr,u16 psc)( q. k" y* @  x) H+ n; D
  11. {3 o4 m6 h" t9 ]5 M
  12.         TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;! S9 t; O+ U# m) w
  13.         NVIC_InitTypeDef NVIC_InitStructure;
    5 S- D1 y5 W* ]+ p0 R6 O! U, \
  14.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟 TIM3 使能  t3 x5 U' A2 ]7 K. g6 ]
  15.         //定时器 TIM3 初始化
    * Z1 C5 c) a$ D) ~
  16.         TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载寄存器周期的值/ j( T: h( T- S/ I
  17.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置时钟频率除数的预分频值
    % o. K: `* U7 d& X
  18.         TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割
    ( P7 u3 @# ]& d! l
  19.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数
    & G$ Q* s3 k! v9 n; F" D, Y
  20.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);  //初始化 TIM3( Y' K$ I7 p1 T
  21.         TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE );  //允许更新中断
    . p1 X+ U* n( c' D/ `
  22.         //中断优先级 NVIC 设置
    : M, ^; d1 M+ t& I) d" @! _- F
  23.         NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3 中断
    & \) A3 `$ c- [2 e+ m6 l
  24.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级 0 级! W4 B% Y  ]: @/ ]
  25.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //从优先级 1 级* L/ M0 `2 M4 Y- j2 h
  26.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  //IRQ 通道被使能5 A( R9 ]* Z/ ^: z6 [: s
  27.         NVIC_Init(&NVIC_InitStructure);   //初始化 NVIC 寄存器  Q+ [# z( }3 [- w+ h3 {8 G8 N) z
  28.                 : \: ?) E- b: @) J; \% ~
  29.         TIM_Cmd(TIM3, ENABLE);                  // TIM38 Q. y# i5 ?2 N2 k% p+ `
  30. }" Y. C5 x: E2 y. y. k  C

  31. # J+ Y# K& V2 w! l4 j7 W, M- W

  32. / k7 P; B, j+ t, C( \+ F& N
  33. //定时器 3 中断服务程序
    & E: j7 y3 o: t) j9 K) [. z
  34. void TIM3_IRQHandler(void) //TIM3 中断/ x! d: E0 h. h1 }0 L
  35. {
    , B6 o. f8 e) C# ?% b6 o1 {. f8 v- L
  36.         if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查 TIM3 更新中断发生与否
    + u/ P/ F1 ~' ?/ e$ c1 \5 I2 R& N
  37.         {. d# Z) m4 O2 [0 X
  38.                 TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除 TIM3 更新中断标志5 V' N# I; e7 C& G  ?/ L" g1 V
  39.                 //每100ms一次。        ' U8 `: w3 X# \8 Z, v4 G
  40.                 //这里可以编写功能程序; R( Z2 r4 D4 _6 H. I* K4 z' g
  41.                
    . G2 _: D# c0 I* _" U5 y
  42.                 if(TIME.Tnum>=24*60*60*10)        {        TIME.Tnum=0;        }        //一天的时间清零一次
    7 O, C9 i/ I3 s3 p
  43.                 else                                                {        TIME.Tnum++;        }6 q6 e* x) J; ^0 S  H0 x
  44.                 TIME.T100ms=1;
    ' W" p8 b. l! \. D) Q
  45.                 if(TIME.Tnum%2==0)                        {        TIME.T200ms=1;        }
    1 n( j6 X6 V* K5 y
  46.                 if(TIME.Tnum%5==0)                        {        TIME.T500ms=1;        }3 }9 P  w  q' Q" W5 k3 W
  47.                 if(TIME.Tnum%10==1)                        {        TIME.T1s=1;                }$ @" ]' V$ x- u$ d' D3 K
  48.                    if(TIME.Tnum%30==2)                        {        TIME.T3s=1;                }
    . D. h2 T7 [+ A- m% J' ^  ~
  49.                 if(TIME.Tnum%600==3)                {        TIME.T1min=1;        }
    : w3 J2 ~( l( y- U& I% a
  50. ' w9 N7 u" N) R
  51.                 //在中断中执行任务,优点是准时,缺点是容易打断其他任务,不建议在中断中执行任务,可以在主函数中执行任务。+ }6 `0 M8 f' ^# L0 h# S
  52.                 if(TIME.T100ms==1)
    & ^' u  I8 S, ?
  53.                 {
    " V* E5 V7 |- i: {
  54.                         TIME.T100ms=0;  Q1 t: }: |; w" m
  55.                         //100ms要执行的任务
    / q. |8 q3 D" }* D3 j" y/ K7 {- y
  56.                 }
    1 \  d4 A6 O8 _2 V
  57.                 if(TIME.T200ms==1), A" y4 L) Z' T9 I9 u1 c: Z
  58.                 {7 V0 I, R! _0 K: a7 q
  59.                         TIME.T200ms=0;
    % C" M6 y5 @; T3 ~3 X2 U
  60.                         //200ms要执行的任务6 ~- R+ h/ u' ^) y+ z4 z- f6 T9 Q
  61.                 }
    ( q' l0 f/ o/ g* ~
  62.                 //。等* |* j5 x# y* O( z0 U- }- H* w" k
  63.                 //。中间省略7 Y. T2 e* I" W' {
  64.                 //。等& \- F5 ~2 B, g  C# t! N' r
  65.                 if(TIME.T1min==1)
    ) ?1 e; q% L. q3 X, y
  66.                 {' C& M6 j) I# [! a- j+ z) @
  67.                         TIME.T1min=0;2 E6 l8 x6 \5 b* A: e0 H
  68.                         //1min要执行的任务
    $ r/ h* n+ A; g' e; R$ _
  69.                 }: H5 p1 U% ?3 U. T$ j. P
  70.         }
    ' `& v6 O6 E' [& H/ j! q
  71. }
复制代码

- q5 ^1 q& }& Z5 Dmain.c
! r2 \# C' x2 ]3 ~
  1. #include "stm32f10x.h"
    5 A0 e+ g6 r* D  T
  2. #include "time.h"
    ( y% x; @. m  R$ f% h' u
  3. 3 l0 r( d7 Z- @- n

  4. + `+ t5 {+ D) J1 t
  5. int main()
    ! e7 y' \3 ]/ ]# ]
  6. {
    4 e. F9 C4 j. y+ [4 @
  7.         /**# I% e7 c& A( x: ]' r
  8.         其它初始化省略
    % Y9 L; t: q% C) s
  9.         **/
    0 i) M4 y. e4 N
  10.         TIM3_Init(1999,7199);        //10Khz的计数频率,计数到1000为100ms9 E7 C' L7 \1 @6 }" J/ y- R. b
  11.         3 F: u# x2 _: ~* s1 D# C" u( \) ~
  12.         while(1)
    * X. U- A, ]% m8 A' H" O) }
  13.         {
      }, g# V* i  y2 i
  14.                 /**$ `' x3 C( \9 T" E1 R* u9 u
  15.                         其他功能程序
    7 x4 @0 W6 |2 w9 a: c0 A
  16.                 **/2 c, O2 ~6 j" P9 D  I- O/ `
  17.                 ( \2 h9 R: @% P* l  P( t
  18.                 if(TIME.T100ms==1)6 R, g; a2 J1 {
  19.                 {( i+ u! r* f" }, ^  J0 K" o
  20.                         TIME.T100ms=0;
      M# H# i( D. c  h: }! }
  21.                         //100ms要执行的任务
    " }) J& [+ Q0 U8 }1 u* A" Z
  22.                 }
    ' B) p6 U  |) {. K
  23.                 if(TIME.T200ms==1)
    4 Q; R# ^4 F- G0 X  _) q" R
  24.                 {; }# k' t7 l4 n, B
  25.                         TIME.T200ms=0;
    ; }  \8 _; l! k& G/ t
  26.                         //200ms要执行的任务
    / l) E3 b$ [% h. K$ `
  27.                 }' O, M0 E" p5 i0 B
  28.                 //。等
    , M) M5 G5 N* n0 }6 b
  29.                 //。中间省略! c0 {2 u. J' v. F' b; I
  30.                 //。等
    1 g) B  K+ j9 p
  31.                 if(TIME.T1min==1), u0 Q$ L3 d2 E% ~8 `
  32.                 {
    " V, `  V9 X+ n& \
  33.                         TIME.T1min=0;) d& m3 k9 u2 ?, a
  34.                         //1min要执行的任务$ `( C( Z4 J# J" F4 u" m4 F/ N) G
  35.                 }
    + F9 t; p3 R9 F, o( S! c- V

  36. - S6 g& Z6 D! e' q- O
  37.         }
    2 z0 k7 r* N7 L
  38. }
复制代码

2 o! ]! [1 x8 y2 w  A8 u- S# D% v% v( ~1 J0 {, E

+ l/ Y; f2 s' [4 [9 W8 N% e' l
" P, Y8 Z3 K0 ]" C3 W* d
收藏 评论0 发布时间:2022-5-3 22:25

举报

0个回答

所属标签

相似分享

官网相关资源

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