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

基于STM32CubeMX的DS18B20温度传感器经验分享

[复制链接]
攻城狮Melo 发布时间:2023-7-1 18:38
1.DS18B20简介
% r5 W$ l/ V$ L. t  a" z6 qDS18B20是由DALLAS半导体公司推出的一种单总线接口的温度传感器,与传统的热敏电阻等测温元件相比,它是一种新型的体积小、用电压宽、与微处理器接口简单的数字化温度传感器。DS18B20的内部结构如下图示
& ~; v% f/ F( J1 w' I& e. s
$ D5 U0 ^6 ^7 i% Z
微信图片_20230701183641.png $ p+ W# j) u7 i4 q+ u4 v
( k  [; Q' m$ `1 h2 B! Q$ o* v( [) h
ROM中的64位序列号是出厂前就被光刻好的,可以看做是DS18B20的地址序列号。64位光刻ROM的排列是:8位产品类型标号+48位DS18B20序列号+8位循环冗余校验码。光刻ROM 的作用是使每一个DS18B20都各不相同,这样就可以实现一根总线上挂接多个DS18B20
4 K5 S! O3 \* F  T( j: i% H& M" D! Q* {5 w7 D
DS18B20的内部存储器(9个字节)包括一个高速暂存器RAM和一个EEPROM,EEPROM里存放高温和低温触发器和配置寄存器,存储器详细组成见下图:* s; _( w( `7 d0 c% l

  K- q7 C% w# q' ~  }/ ]
微信图片_20230701183638.png ) M7 B& G- _/ ]) b  P

7 Q& X# R; ^2 Z1 |* O2 Z" R- v配置寄存器是配置不同的位数来确定温度和数字的转化,其结构下图示:低五位都是1,TM是测试模式位(设置工作模式或测试模式,默认为0即工作模式),R1和R0用来设置精度,可设9~12位精度,对应的温度分辨率为0.5, 0.25, 0.125, 0.0625℃. z4 Z; A1 ~9 u" S. y0 G

  A/ a# ~# s% ]) v) z- `
微信图片_20230701183635.png   T) D0 ~# {8 r5 |' \
/ u  y2 P8 R5 w3 q1 \9 ^& X; h
所有的单总线器件都要求采样严格的信号时序,以保证设局的完整性。DS18B20的时序有:初始化时序、写(0和1)时序、读(0和1)时序。DS18B20发送所有的命令和数据都是字节的低位在前,下面介绍这几个信号的时序:
2 v5 U0 W; g  C/ J! `⏩ 初始化时序
% j/ D0 Y) O- }. r7 w+ M1 c' D+ Q内置闪存模块可以在通用地址空间直接寻址,任何32位数据的读操作都能访问闪存模块的内容并得到相应的数据。" m  _# d' r3 p8 g- N  M9 t
) q0 i& u" h. |
微信图片_20230701183632.png 5 H/ p+ U( @6 X. c" P

/ W9 p# U7 Q* ]7 b⏩ 写时序& j- |! F8 Y) Y  t  J9 k5 R1 N# O
写时序包括写0和写1时序。所有写时序至少需要60us,并且在2次独立的写时序之间至少需要1us的恢复时间,两种写时序均起始于主机拉低总线。写1时序,主机输出低电平,延时2us,然后释放总线,延时60us;写0时序,主机输出低电平,延时60us,然后释放总线,延时2us。写时序图如下! l& Z/ Y* M( Q9 R( d: ?" W" ?9 G
+ T& B" f( B& F+ [  k; ^  V" w+ r. g
微信图片_20230701183629.png
/ E$ d& P. M1 E$ N8 H4 R- N2 J$ b4 ]

4 x% C: e# @# A⏩ 读时序# h* O4 |( r) @) i
单总线器件仅在主机发出读时序时,才向主机传输数据,所以在主机发出读数据命令后,必须马上产生读时序,以便从机能够传输数据。所有读时序至少需要60us,且在2次独立的读时序之间至少需要1us的恢复时间。每个读时序都由主机发起,至少拉低总线1us,主机在读时序器件必须释放总线,并且在时序起始后的15us之内采样总线状态。典型的读时序过程为,主机输出低电平延时2us,然后主机转入输入模式延时12us,然后读取单总线当前的电平,然后延时50us
1 [1 q7 o& L3 }+ Z$ b$ c+ o9 J$ s5 P2 _0 }3 I4 w0 Y% I2 J$ W, k
微信图片_20230701183626.png   k/ y/ q8 _& G8 Y; \
$ J4 a1 A9 P. c4 {
DS18B20的典型温度读取过程:复位 --> 发SKIP ROM命令(0XCC) --> 发开始转换命令(0X44) --> 延时 --> 复位 --> 发SKIP ROM命令(0XCC) --> 发读存储器命令(0XBE) --> 连续读出两个字节数据(即温度) --> 结束+ ?+ ?  T6 o8 M2 K
! \' C+ u" s) U$ x, E. z) b
2.硬件设计1 G/ S# F5 O4 O# c- e/ k- m4 g
D1指示灯用来提示系统运行状态,DS18B20温度传感器用来检测环境温度,串口1用来打印温度值' V6 \, W6 q) d3 ]6 r& R' y
指示灯D1
/ L9 W  O& X. HUSART1串口* I" P7 E- c) D1 N: t' m. e
DS18B204 @/ w/ B0 P9 m7 i% a
TIM7(提供us延时)
7 `8 P+ V# Y7 }" S# M" b  D# L* U+ w+ {' z$ M; u) \+ b, A  a8 j
微信图片_20230701183622.png : m2 T. x, B# C2 @8 l& B
' B! `6 |" Z% L$ y! D1 d/ w4 t! |
3.软件设计
$ U- x8 q2 T# C8 Z1 D  ?3.1 STM32CubeMX设置
8 l+ c' G1 n( m1 h. d" D6 o. c# H➡️ RCC设置外接HSE,时钟设置为72M8 x# L" G4 V3 u$ o- M
➡️ PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
5 U  G# {, G. t➡️ USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位- U0 Z7 \2 ?& N7 y
➡️ PG11设置为GPIO推挽输出模式、上拉、高速
8 ]/ d0 e8 @% f! v2 r# I➡️ 激活TIM7,预分频因子设为72-1,向上计数,自动重载值为65535;因此计数器CNT_CLK = 1MHz,计数器周期为1us! d5 y, u, o% N( k
1 [3 `' O0 y1 o4 ~8 t! W
微信图片_20230701183619.png
$ n2 J0 w# M) E

$ n: @" j) a7 L  E' [2 I  X# q, t( @➡️输入工程名,选择路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码
& m- ~! b1 e& K, s% l. m2 T4 V

3 V, i2 E& w: C& j3 s' C* h6 {3.2 MDK-ARM软件编程2 i% L/ E$ z# w7 s; W
➡️ 在tim.c文件下实现微秒延时(us)函数
& z$ L; V: H* e/ `3 I" t) G
  1. void delay_us(uint16_t us){
    + x$ b6 A5 \2 E  B0 z
  2.   uint16_t differ = 0xffff-us-5;
    6 ~% n" D. H0 O3 u3 x+ f% c0 P
  3.   //设定TIM7计数器起始值                               
    8 h& u+ w1 V; o
  4.   __HAL_TIM_SET_COUNTER(&htim7,differ);       
    7 \) e- O8 Z6 W7 w' p1 K  z
  5.   //启动定时器& @) z/ B1 V" U! c" _
  6.   HAL_TIM_Base_Start(&htim7);                        ) a/ j+ ^% ~$ A# ?2 P) p4 L
  7.        
    / I5 }9 ]  }4 A# l  _& O
  8.   while(differ < 0xffff-5){   //判断$ `" {5 T' b# i  Z6 N, f
  9.     //查询计数器的计数值6 p2 }9 p* f1 l& ]! U
  10.     differ = __HAL_TIM_GET_COUNTER(&htim7);               
    % W( Z+ P1 L, X  v" Y- g, F; P
  11.   }
    : d7 ?: A/ q  m7 R  f! s
  12.   HAL_TIM_Base_Stop(&htim7);7 ?. w, X/ _* m
  13. }
复制代码
: w2 |+ J: m! {) R2 k. ~
➡️ 创建按键驱动文件ds18b20.c 和相关头文件ds18b20.h  a' ]  ?7 r1 f$ `
  1. void DS18B20_IO_IN(void){# q( ^- ?, ~- J" D5 ?3 K, `
  2.   GPIO_InitTypeDef GPIO_InitStructure;* I5 b" G8 P( Y) i) Y$ s
  3.   GPIO_InitStructure.Pin = GPIO_PIN_11;9 J' `! u  K# h( B- A
  4.   GPIO_InitStructure.Mode = GPIO_MODE_INPUT;# h( p/ j4 n, \# u# @4 y: R1 }
  5.   HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);7 n/ p% L+ V0 F: _$ ]9 D
  6. }8 _' N% O& q3 [

  7. 6 l) a' t3 J5 I4 I3 p" j
  8. void DS18B20_IO_OUT(void){
    + y9 p* V! u$ W7 r
  9.   GPIO_InitTypeDef GPIO_InitStructure;' ~+ J6 `- n6 j1 A
  10.   GPIO_InitStructure.Pin = GPIO_PIN_11;. u; R6 b6 E' u; a
  11.   GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    ) ~, v8 I7 q7 T+ ~
  12.   GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;; S; S& S: L5 [* Z4 e4 s0 r3 S# s
  13.   HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);. q& ?# s$ W9 U& H
  14. }8 ~3 a4 l8 D" B

  15. . ]7 n4 c* R" h: P9 g: r( ?- G
  16. void DS18B20_Rst(void){
    * k9 T( h! ?4 v, q2 ?% N% @' E
  17.   DS18B20_IO_OUT();/ U3 u+ @) n; h8 x# h2 J
  18.   DS18B20_DQ_OUT_LOW;- Y1 D$ @/ J! [+ N
  19.   delay_us(750);4 i# U9 i" O( D# p# e: ?9 T
  20.   DS18B20_DQ_OUT_HIGH;
    9 A2 Z- |/ N4 R
  21.   delay_us(15);
    4 j. v/ }: G) ~/ @$ V  X$ q
  22. }/ `) {( q8 }# L: ]6 n* m$ f
  23.         ! i( \8 g; k$ J& Y
  24. uint8_t DS18B20_Check(void){
    4 A0 x* C) b3 [% ^& ?
  25.   uint8_t retry = 0;
    3 F( M) s' N4 m& d" p7 h
  26.   DS18B20_IO_IN();
      W) u9 n+ d' B+ W9 E
  27.   while(DS18B20_DQ_IN && retry < 200){$ G, A0 w: u* \, ]$ }& f
  28.     retry++;
    & `# G  s+ A3 X7 c  b9 Q# T- [
  29.     delay_us(1);7 z1 d& C7 a1 {+ U& H3 `; b
  30.   }
    # I, l5 Q$ V( o: m! n
  31.        
    ! h2 S+ k  B. I- p: r
  32.   if(retry >= 200)' Q6 }/ I, ^; m9 V6 i- N( i/ X
  33.     return 1;& {8 p- t8 T6 H6 c
  34.   else
    " d8 p! I9 u  P% A0 k
  35.     retry = 0;' @4 Q! h( u! C: P9 d
  36.         8 i) Q5 J& O. k9 R3 q
  37.   while(!DS18B20_DQ_IN && retry < 240){
    $ O: T: N4 w) d; i! R/ }! y& r
  38.     retry++;
    / n  U. y0 c0 ^( @
  39.     delay_us(1);& W  F" }& {4 G
  40.   }# ^; I5 g8 K& i: A1 L- Q+ h
  41.        
    $ n2 V0 M4 |' |2 v2 @% V
  42.   if(retry >= 240): ^5 d" q  [" w% t  n
  43.     return 1;, T2 K, r  i' E6 L* O) _
  44.         5 U9 T& m7 ]7 |6 I
  45.   return 0;( v9 d0 v7 G. s
  46. }
    & K; v: b% @$ [
  47. + s- X5 T3 @9 ?+ d/ q3 y
  48. uint8_t DS18B20_Read_Bit(void){
    2 k: m. I: h" `
  49.   uint8_t data;
    6 F8 ?: e2 {3 m5 q: h6 H
  50.   DS18B20_IO_OUT();/ f' I8 Z2 j1 \: |
  51.   DS18B20_DQ_OUT_LOW;
    $ Z2 Z: a# s, A) A6 z' C7 o9 N5 ^
  52.   delay_us(2);; a7 ]: s0 v' C/ ~2 z4 R
  53.   DS18B20_DQ_OUT_HIGH;
    3 N/ v8 m5 `& ~) z
  54.   DS18B20_IO_IN();
    & ^+ l- n' m1 l" W6 B) t
  55.   delay_us(12);
    ( E! v2 _% _$ S; j: [! R$ b' }+ U
  56.        
    - J! W( U# u0 `7 A2 y
  57.   if(DS18B20_DQ_IN)
    : T6 Q# j9 T4 S4 }/ y" R
  58.     data = 1;8 m/ k/ V) D; B7 [
  59.   else
    6 F* E% S( J& R' L
  60.     data = 0;
    0 ^2 j7 a, g( m; v; r
  61.         : T% B( Q8 @$ H: d+ _' {  Y
  62.   delay_us(50);2 g" V4 i' l* N( ?1 i
  63.   return data;6 @" r" g( e( h( c; R! E
  64. }
      w; W& i% Y7 \  ~  Z! \

  65. + h" t+ r' w9 K" E  I6 Y! d
  66. uint8_t DS18B20_Read_Byte(void){
    8 x0 y9 Z: h! a0 p0 c6 o. Y. o) r
  67.   uint8_t i,j,data;; ]$ K2 _8 G, h: k! n- X" i% `$ p
  68.   data = 0;7 g- b& T1 p, C
  69.   for(i=1;i<=8;i++){" o; c* j9 G( T2 N9 i  n5 ^9 A, z% D
  70.     j = DS18B20_Read_Bit();, _: r% Y* |  Q* ]
  71.     data = (j<<7)|(data>>1);
    ( b+ |( ~% r# S2 \2 ?- j. w
  72.   }
    " x; m  U; B" }. h5 p! J3 S
  73.   return data;
    ) K& G) R) `5 o% P# w
  74. }
    4 y7 }0 Y# O3 Y5 `# Z2 \
  75. % `9 q; S" M; k
  76. void DS18B20_Write_Byte(uint8_t data){
    , |) O4 d& A0 e7 d% Z
  77.   uint8_t j;8 \& L) g8 i  P4 D9 k: M/ X
  78.   uint8_t testb;
    5 c$ T1 ~' p% V' u
  79.   DS18B20_IO_OUT();
    + a7 _0 p7 Z. ?' a
  80.   for(j=1;j<=8;j++){* e  y/ m8 x/ u7 _+ D) [* S
  81.     testb=data&0x01;
    : j$ X  y) ~- K' B
  82.     data=data>>1;
    : G; V3 A6 N: O0 `& b) Z( A
  83.     if(testb){
    - v. ~: `) Z! f& ~+ j
  84.       DS18B20_DQ_OUT_LOW;
    $ i* |4 ]$ A/ z5 T7 p
  85.       delay_us(2);
    ; s# b' W% l7 u/ U; `/ o3 M$ ^
  86.       DS18B20_DQ_OUT_HIGH;- [& |) K( u! ]7 w* u
  87.       delay_us(60);
      L* H% Z7 {* h+ i; Y" m5 ^8 z
  88.     }else{
    2 P- j4 U! r: T7 I1 i8 z
  89.       DS18B20_DQ_OUT_LOW;
    3 O: z- u5 U2 k  M2 K  j+ G
  90.       delay_us(60);
    & ]" o& p- z! s6 q  G+ x: ]5 u9 q
  91.       DS18B20_DQ_OUT_HIGH;
    . ~* l: i& w9 a6 P) u
  92.       delay_us(2);
    4 h: P! N0 z* J, B1 S$ _* U9 w. H
  93.     }  l' A4 a8 @  b
  94.   }! c4 h* C' Q& R! r0 _! u
  95. }; d- T, P$ r0 \# `6 p. Y! b) ?
  96. # d4 B4 c8 B4 f; P9 c( c* i- g' _6 }
  97. void DS18B20_Start(void){: H! T, \8 w: K, Y! }% X& \8 @- A
  98.   DS18B20_Rst();3 k9 G3 u7 M  c6 z2 @% h
  99.   DS18B20_Check();
    " n+ k; g9 D. ^2 \0 x' Y* T9 X; k
  100.   DS18B20_Write_Byte(0xcc);
    , ]& T; e4 m+ c% [* l
  101.   DS18B20_Write_Byte(0x44);# M2 {* `4 U. H! ?7 V0 B2 }2 G
  102. }; N0 t0 k0 C, x  Y- y
  103. ' i: k" }; @) d: @' L9 [% L) D4 E
  104. uint8_t DS18B20_Init(void){7 _4 p3 o* L) H% |) y
  105.   GPIO_InitTypeDef GPIO_InitStructure;
    / ]9 B# v# ]0 @
  106.   GPIO_InitStructure.Pin = GPIO_PIN_11;
    . L8 L; z  P; h
  107.   GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;  i7 Y! }: L! n. H/ ~
  108.   GPIO_InitStructure.Pull = GPIO_PULLUP;
      j% q" k8 ~/ M# T+ ^; c7 b3 l
  109.   GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;; s1 W9 V2 j3 }
  110.   HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);
    & d* q. [5 l) `
  111.        
    6 D' u4 m, R# w% t7 w: o
  112.   DS18B20_Rst();! m' b$ L6 r1 x3 L. x+ k. U
  113.   return DS18B20_Check();
    6 _1 C+ ?  q. ?% [2 d
  114. }
    ! {+ s0 g5 U7 @

  115. ; W5 l7 V* B$ w8 }
  116. short DS18B20_Get_Temperature(void){
    ! a( N  t3 [% E$ M" T
  117.   uint8_t temp;' w# p& J) ~3 p
  118.   uint8_t TL,TH;
    2 y$ h/ s$ K4 J0 O0 w# z: R
  119.   short temperature;
    0 x/ t7 O  C; ^& p, s
  120.        
    ) a* Z/ A5 c. A- C2 h& U7 g
  121.   DS18B20_Start();
    & w; e7 V+ e( i* D, T' G/ A# e2 v
  122.   DS18B20_Rst();9 q1 U) u( Y4 _$ V3 o
  123.   DS18B20_Check();+ b$ t4 i! q4 H0 C
  124.   DS18B20_Write_Byte(0xcc);
    8 `! h5 I# d* O- p( A
  125.   DS18B20_Write_Byte(0xbe);
    1 T2 C5 e. d9 U. Y4 @
  126.   TL = DS18B20_Read_Byte();
    * U; L6 j# l$ N; C) f2 Z
  127.   TH = DS18B20_Read_Byte();
    $ [+ g: U- L/ x2 z1 H, y
  128.         1 Q2 `4 C1 }+ @5 j/ i
  129.   if(TH>7){
    1 _; Z6 N5 s1 s- e6 d
  130.     TH = ~TH;
    0 G) {. ^# U5 m' U4 E- D. @! b' f
  131.     TL = ~TL;2 h* P- W. b; P) ~0 }
  132.     temp = 0;2 T9 w" W0 q0 \& U: U( H1 T* _
  133.   }else2 w0 L8 [! t) N& n# P
  134.     temp = 1;# i' F6 U% N9 o. P
  135.        
    ) T+ O8 _1 u" a& q8 Z* y9 l: r8 a/ N
  136.   temperature = TH;
    / _4 B2 l+ }. X2 f
  137.   temperature <<= 8;: Q# v; P! f7 |1 x- S
  138.   temperature += TL;
    $ ^  T2 R( S; N4 u. ]  O; L) M
  139.   temperature = (float)temperature*0.625;0 o. F1 m/ D0 f9 J4 U* z4 |; e/ [
  140.   if(temperature)/ |: _* U& ^* N* p+ e2 |% I7 U
  141.     return temperature;) u, P$ k' {! Y) S
  142.   else
    ( r: ]2 B1 Q* ~0 \9 m. ~
  143.     return -temperature;/ h) H1 _* v' ]9 U6 z5 v( M
  144. }
复制代码

) }# [8 B2 Q/ O6 S5 e+ u0 O➡️ 在main.c文件下编写ds18b20测试代码
5 o4 ~5 [% [& [' J1 I$ d7 P
  1. int main(void){. I/ ]  K8 y1 ^: K1 t
  2.   float temperature;
    ; `+ e# o1 g2 o, E
  3.   HAL_Init();
    0 S. @! _6 j' i1 K  i: m7 q0 @6 g
  4.   SystemClock_Config();
    3 J7 [2 W/ Z; K' O
  5.   MX_GPIO_Init();4 I- e% ^) a' C! Z8 d8 s; B% }
  6.   MX_TIM7_Init();
    / A( d; R5 K8 X4 }! |
  7.   MX_USART1_UART_Init();
    9 Q! `9 x# y  T* ^; K
  8.   /* USER CODE BEGIN 2 */
    # _" d. ~( e$ F% v  A
  9.   while(DS18B20_Init()){; ?+ ~1 e6 C- a# J. [% G) }5 K
  10.     printf("DS18B20 checked failed!!!\r\n");& z" o. n+ Y7 x& i. `: o! n
  11.     HAL_Delay(500);- r6 Z8 r% h6 n; c! r
  12.   }9 u) ^7 R' [2 P# v# u, b
  13.   printf("DS18B20 checked success!!!\r\n");& B  {# Y  ~/ x% h+ {" k
  14.   /* USER CODE END 2 */
    * e( o* R9 K4 i0 S' O; B  T7 q2 E4 u
  15.   while (1){
    9 K/ j: q  n/ _4 K- _& M- L6 A
  16.     temperature = DS18B20_Get_Temperature();! L* A0 e4 X, g' C
  17.     if(temperature < 0)0 ]/ l8 y  h) ~) v' T- D7 h5 ~
  18.       printf("temperature = -%.2f degree\r\n",temperature/10);) Y, C+ ]3 K  x
  19.     else
    7 X- R3 A. _3 g& s! g7 r4 _4 B
  20.       printf("temperature = %.2f degree\r\n",temperature/10);/ x$ j& w  B) g* T; Q
  21.                
    & Q7 {' h2 R& t6 G+ ~' U
  22.     HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
    . n" X4 |) a& u5 Y# [+ k
  23.     HAL_Delay(200);
    ) Z* {  \' z: O7 r
  24.   }
    ) E- l% u+ |1 W9 \  u
  25. }
复制代码

6 t7 V; A# x8 l5 q: p* _! F" o4.下载验证
0 j! W% L- B. v' W编译无误下载到开发板后,可以看到D1指示灯不断闪烁,串口不断打印出当前温度值5 c1 K& u0 o8 l) [
& u' j2 @" ]7 h& y# A
6 G  G. G, f3 N# J! B  n
微信图片_20230701183615.png / e% d/ n+ p' _+ M2 B8 z+ ^* Z

" X/ H! p! z/ \* p+ W转载自: 嵌入式攻城狮2 v6 @+ n1 e) t+ X; j& \
如有侵权请联系删除
7 c' B" G! X% l  m1 s& M5 a' q9 {. g) y. @' q1 c
8 x2 p& p' ?% d- f. Y
赞 收藏 评论0 发布时间:2023-7-1 18:38

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版