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

基于STM32CubeMX的SPI总线经验分享

[复制链接]
攻城狮Melo 发布时间:2023-7-1 18:56
1.SPI总线及W25QXX芯片
1.1 SPI总线简介
SPI全称Serial Peripheral Interface,即串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在EEPROM、FLASH、实时时钟、AD转换器,还有数字信号处理器和数字信号解码器之间。SPI是一种高速的、全双工、同步通讯总线,在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局节省空间提供了方便,正是这种简单易用的特性,如今越来越多的芯片集成了这种通讯协议。下图是SPI内部结构简易图
. q6 P! _/ O9 \' @  p9 v
微信图片_20230701185542.png
" d/ W3 l2 t3 M6 L
从上图可以看出,主设备和从设备都有一个串行移位寄存器,主设备通过向它的SPI串行寄存器写入一个字节来发起一次传输,寄存器通过MOSI信号线将字节传送给从设备,从设备也将自已的移位寄存器中的内容通过MISO信号线返回给主设备。这样两个移位寄存器中的内容就被交换。外设的写操作和读操作时同步完成的,如果只进行写操作,主设备只需要忽略接收到的字节,如果主设备要进行读操作,就必须发送一个空字节来引发从设备的传输。
SPI接口一般使用4条线通讯,单向传输时也可以使用3条线,其中3条线为SPI总线(MISO,MOSI,SCLK),1条为SPI片选信号线(CS),它们的作用如下:
    - {! E9 q; b6 @  K) ^
  • MISO:主设备数据输入,从设备数据输出
  • MOSI:主设备数据输出,从设备数据输入
  • SCLK:时钟信号,由主设备产生

    2 v2 {: i/ k$ w9 u; S" M4 D
  • CS:从设备片选信号,由主设备控制
    : S& C5 F5 I- N2 p

    ' D5 M# f) F9 t* ]2 s
SPI使用MOSI/MISO信号线来传输数据,使用SCLK信号线进行数据同步。MOSI/MISO数据线在SCLK的每个时钟周期传输1位数据,且数据输入输出是同时进行的。数据传输时,MSB先行或LSB先行没有硬性规定,但是两个SPI通讯设备之间必须使用同样的协定,一般都会采用MSB先行模式。
0 v( \4 B6 K& _" C当有多个SPI从设备与SPI主设备相连时,设备的MOSI/MISO/SCLK信号线并联到相同的SPI总线上,即无论有多少个从设备,都共同使用者3条总线;而每个从设备都有独立的1条CS信号线,该信号线独占主设备的一个引脚,即有多少个从设备就有多少条片选信号线。当主设备要选择从设备时,把该从设备的CS信号线设置为低电平,该从设备即被选中(片选有效),接着主设备开始与从设备进行SPI通讯。/ u3 p7 k2 Y1 M5 ]
SPI总线根据时钟极性(CPOL)和时钟相位(CPHA)的配置不同,可以有四种工作方式:

    " U2 r  @. d* u) n
  • CPOL=0:串行同步时钟的空闲状态为低电平
  • CPOL=1:串行同步时钟的空闲状态为高电平
  • CPHA=0:在串行同步时钟的第一个跳变沿(上升或下降)数据被采样
    . R( @/ w6 Z9 f' \$ q$ F( m: X, k
  • CPHA=1:在串行同步时钟的第二个跳变沿(上升或下降)数据被采样

    4 j; h! F' s$ Q7 Q! h- }4 W7 ^8 \
    + H& [1 J" k. P, ?! E1 y
微信图片_20230701185539.png
$ q5 \# D( @2 v7 r
1.2 W25QXX芯片简介
W25QXX芯片是华邦公司推出的大容量SPI FLASH产品,该系列有W25Q16/32/62/128等。本例程使用W25Q64,W25Q64容量为64Mbits(8M字节):8MB的容量分为128个块(Block)(块大小为64KB),每个块又分为16个扇区(Sector)(扇区大小为4KB);W25Q64的最小擦除单位为一个扇区即4KB,因此在选择芯片的时候必须要有4K以上的SRAM(可以开辟4K的缓冲区)。W25Q64的擦写周期多达10万次,具有20年的数据保存期限。下表是W25QXX的常用命令表

- a0 |; Z( K" g: A0 l
微信图片_20230701185536.png
) k0 j, O! z, j& t0 ]8 y9 p3 t
2.硬件设计
D1指示灯用来提示系统运行状态,K_UP按键用来控制W25Q64数据写入,K_DOWN按键用来控制W25Q64数据读取,串口1用来打印写入和读取的数据信息

    # E+ {) s( T3 d# I
  • 指示灯D1
  • USART1串口
  • W25Q64
    ; I, o0 u3 X' G# M6 M, Z* b0 b
  • K_UP和K_DOWN按键: m( e2 Q% m6 R. j
    ' |+ J, }! F7 ^3 {9 Z" x
    " N+ ?: h- T/ x# U6 a) E/ J7 I
微信图片_20230701185531.png
: X+ ]  I7 J7 K" [' N

; O; y1 ~& v( \3 Q; Q" Y5 a# @
3.软件设计
3.1 STM32CubeMX设置
➡️ RCC设置外接HSE,时钟设置为72M
➡️ PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
➡️ USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位
➡️ PA0设置为GPIO输入模式、下拉模式;PE3设置为GPIO输入模式、上拉模式
➡️ PG13设置为GPIO推挽输出模式、上拉、高速(片选引脚)
➡️ 激活SPI2,不开启NSS,数据长度8位,MSB先输出,分频因子256,CPOL为HIGH,CPHA为第二个边沿,不开启CRC检验,NSS为软件控制
微信图片_20230701185526.png

- p" b5 t# r8 K! n% N$ W1 d: U. X2 ~/ R% ]; Z0 H; {$ n+ F
➡️输入工程名,选择路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码

5 M( ^% c( w! k0 \
3.2 MDK-ARM软件编程
➡️ 在spi.c文件下可以看到SPI2的初始化函数,片选管脚的初始化在gpio.c中

) ~8 t6 D" o+ b- s+ m8 ~% @+ s
  1. void MX_SPI2_Init(void){
    , k3 [. b: r: w
  2.   hspi2.Instance = SPI2;) O( X  m7 r0 m8 ]% i, |* L! Q
  3.   hspi2.Init.Mode = SPI_MODE_MASTER;//设置为主模式
    ) T1 x2 O6 }% t) s* W
  4.   hspi2.Init.Direction = SPI_DIRECTION_2LINES;//双线模式
    5 h9 [/ T- C" L+ n# |
  5.   hspi2.Init.DataSize = SPI_DATASIZE_8BIT;//8位数据长度
    6 Z3 t: {# G0 I! d1 e/ V" V0 N0 i
  6.   hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;//串行同步时钟空闲状态为高电平
    & g$ ?. `' F( @& ?( X! p) t9 z6 E
  7.   hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;//第二个跳变沿采样
    : e# V0 I9 i% {( n5 Z" Z2 M
  8.   hspi2.Init.NSS = SPI_NSS_SOFT;//NSS软件控制
    1 r/ ?& B. r* {& `( a- ^1 n
  9.   hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;//分配因子256) x5 }) r% t# z3 d. p8 g
  10.   hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;//MSB先行
    * h5 s# z7 g1 h+ S
  11.   hspi2.Init.TIMode = SPI_TIMODE_DISABLE;//关闭TI模式
    4 z7 W( B. k3 C/ @, z
  12.   hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;//关闭硬件CRC校验5 L8 g" c: n4 O! S  y7 m( d
  13.   hspi2.Init.CRCPolynomial = 10;
    ) M1 o' O( Y# r6 f* @$ B
  14.   if (HAL_SPI_Init(&hspi2) != HAL_OK){
    ( T+ @1 N9 e& W
  15.     Error_Handler();3 W5 F& B  c5 D! L7 M- {0 ?
  16.   }% q+ O+ b; J- Z% u- x& `/ a% }
  17. }! V- A4 s  N3 i
  18. $ M6 u/ f5 C( w$ L
  19. void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle){6 _4 B8 e' [9 U7 M: Q) L
  20.   GPIO_InitTypeDef GPIO_InitStruct = {0};" U5 x( c  g7 R5 y
  21.   if(spiHandle->Instance==SPI2){
    9 I; A% z1 I$ c0 `( `. C
  22.   __HAL_RCC_SPI2_CLK_ENABLE();  
    9 g; J; s+ F% o+ ~9 g: N. l
  23.   __HAL_RCC_GPIOB_CLK_ENABLE();- o# P$ `# ^/ _
  24.   /**SPI2 GPIO Configuration   
    , k/ i& ^- M! M8 G* X6 j# V- s2 I5 l6 Y, Y
  25.   PB13     ------> SPI2_SCK
    0 N7 Q% k3 N4 `
  26.   PB14     ------> SPI2_MISO5 U2 K8 z* B0 U
  27.   PB15     ------> SPI2_MOSI */% o0 ?' T+ {& ?. c! V
  28.   GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_15;
    6 x6 o/ T0 a( W4 R1 D) t( {
  29.   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;1 [/ k6 s8 `0 G+ c" ^! {+ ?9 o
  30.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    1 z$ F) X6 h8 D
  31.   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    - s5 R9 z8 k2 v% [
  32.   GPIO_InitStruct.Pin = GPIO_PIN_14;% R; e. \: l; N+ ?4 |
  33.   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    " o2 i4 V# s3 _
  34.   GPIO_InitStruct.Pull = GPIO_NOPULL;8 [! Q1 d9 {! g, f4 X4 {! Z
  35.   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    * W; w7 a- ]. U
  36.   }" y6 |" K( L" C# g+ Y9 A
  37. }
复制代码
* r- G2 C+ C2 F/ H/ z) N, V$ A& f) U- d
➡️ 创建按键驱动文件key.c 和相关头文件key.h
➡️ 创建包含W25Q64芯片的相关操作函数及驱动函数的文件w25qxx.c和w25qxx.h,这里仅介绍几个重要的函数,源文件下载方式见文末介绍
  1. //这里仅介绍几个重要的函数
    / K& R) [" a, x' @% ?8 u! x& q6 q
  2. void W25QXX_Init(void){5 c8 [' k8 d: w8 a
  3.   W25Qx_Disable();
    " P3 c& c% }" u. d3 Z) c1 F9 q
  4.   W25QXX_TYPE = W25QXX_ReadID();//读取芯片ID. ]/ B  v: E$ x% U* K9 r
  5.   printf("FLASH ID:%X\r\n",W25QXX_TYPE);
    9 O2 O1 _# u' W
  6.   if(W25QXX_TYPE == 0xc816)
    ; J) u8 N+ r4 z' r0 }% y/ N1 S
  7.     printf("FLASH TYPE:W25Q64\r\n");
    - [6 j5 e3 z- c5 E
  8. }
    4 e8 t- A$ u/ U7 r3 w
  9. + l4 n  `6 z* q6 [5 G* T
  10. uint16_t W25QXX_ReadID(void){
    6 U8 @- G# n: K3 q& E( l- k) h! n. G
  11.   uint16_t ID;
    3 [, D9 H8 s( k. ?
  12.   uint8_t id[2]={0};3 G7 ?- t4 l( d+ I  \0 K3 U
  13.   uint8_t cmd[4] = {W25X_ManufactDeviceID,0x00,0x00,0x00};//读取ID命令       
    ; K/ B4 e7 l7 Q# B1 n& N3 i
  14.   W25Qx_Enable();//使能器件$ p+ m" x# o) d$ ]+ C5 Z
  15.   HAL_SPI_Transmit(&hspi2,cmd,4,1000);' Q$ D4 d: p" d2 D
  16.   HAL_SPI_Receive(&hspi2,id,2,1000);" `+ B3 A; x0 X3 n3 O3 r/ Y
  17.   W25Qx_Disable();//取消片选        + J1 l$ @5 r8 V
  18.   ID = (((uint16_t)id[0])<<8)|id[1];) [0 T& [8 L' `7 y
  19.   return ID;
    ) ]. }  u% c3 C" X* @) `7 o% [
  20. }/ H* ]0 B. @+ A4 U% `
  21. ( E7 x0 j  d6 g9 O8 Y
  22. void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead){
    - s: K8 k. F# h0 I
  23.   uint8_t cmd[4] = {0};
    / ?" b( T7 H1 u, Z$ P0 n
  24.   cmd[0] = W25X_ReadData;//读取命令- D) l7 H- u$ ~) _$ q% }6 \
  25.   cmd[1] = ((uint8_t)(ReadAddr>>16));
    4 a) j, `1 M+ Z& `  J2 K
  26.   cmd[2] = ((uint8_t)(ReadAddr>>8));
    % D6 y; S9 U' f2 @+ t1 Y0 g* ^! S
  27.   cmd[3] = ((uint8_t)ReadAddr);7 q5 u% H) O1 T0 o: i5 t4 C
  28. , L, n3 J/ `/ M- ^2 k
  29.   W25Qx_Enable();//使能器件9 }  `8 y( K; _9 i7 _
  30.   HAL_SPI_Transmit(&hspi2,cmd,4,1000);
      Y8 d8 Y; E2 i' @% R
  31.   HAL_SPI_Receive(&hspi2,pBuffer,NumByteToRead,1000);
    , m1 V' {# h; W6 k' t7 y
  32.   W25Qx_Disable();//取消片选        : R7 b6 H! N6 _' j2 k7 ]
  33. }. J' _4 o  \/ L: D8 V- i8 V
  34. " r1 ]: }" u2 d# O4 u* a7 W. o
  35. void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite){
    6 x- I' H( z5 V& n
  36.   uint32_t secpos;3 ^& K, G8 d, y
  37.   uint16_t secoff;9 R! x# o7 Y- a+ b, r) w8 Y: w3 x7 P
  38.   uint16_t secremain;" p! b; e" Y  j& \
  39.   uint16_t i;
    ) {' S2 H3 s" h. |. y" h( ]$ t- J
  40.   uint8_t *W25QXX_BUF;) s3 U/ N) W2 o7 e4 A4 @2 u& }; L
  41.        
    9 x2 M; g  y) Q9 X9 J5 e! F$ d1 U
  42.   W25QXX_BUF = W25QXX_BUFFER;0 J7 _0 R/ c0 f, n- p+ U
  43.   secpos = WriteAddr/4096;        //扇区地址3 Z0 q8 ?6 R. g2 l/ ]
  44.   secpos = WriteAddr%4096;        //在扇区里的偏移0 P0 Y( q- d; O( |
  45.   secremain = 4096-secoff;        //扇区剩余空间大小6 p' i. P* R( e5 H8 b. W/ H
  46.   printf("WriteAddr:0x%X,NumByteToWrite:%d\r\n",WriteAddr,NumByteToWrite);! @4 T8 [: ~9 c3 x
  47.   if(NumByteToWrite <= secremain)  //不大于4K字节
    0 D) W8 V& \! \2 l, |2 \& g: p6 r
  48.     secremain = NumByteToWrite;
    / g1 O: I; |; I) ~, \2 |( L
  49.   while(1){, l% x$ u& }0 u
  50.     W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//读取整个扇区内容
    6 l  Y1 A7 c3 g! k, x4 [6 j2 H( L
  51.     for(i=0;i<secremain;i++){//校验数据" m' Z, V7 |1 N
  52.       if(W25QXX_BUF[secoff+i] != 0xff)//需要擦除
    ; h+ d2 S% Y/ e  u' `0 {; q/ L
  53.         break;
    . \* y$ W; }/ Q( N$ e9 I2 \
  54.     }/ s: l. s. r9 B: @
  55.                
    1 I/ l2 ]8 M- g) S& Y2 U" Z7 v8 ~6 Z
  56.     if(i < secremain){//需要擦除! L: M1 j( n4 q* O
  57.       W25QXX_Erase_Sector(secpos);//擦除扇区  X% ~% ]$ A3 D. R5 i9 X# Q
  58.       for(i=0;i<secremain;i++){
    " o$ e0 N  e3 |
  59.         W25QXX_BUF[i+secoff] = pBuffer[i];
    / r7 w3 j; U8 G8 Z8 V+ c8 G& k
  60.       }
    ! z8 ]( Z, U: G( W
  61.       W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区- f# B  f& j$ W  P' h2 n
  62.     }0 Y2 f+ |" i* V' b& q6 Q3 w
  63.     else{
    5 Z5 b5 `9 l( U" f% G- y
  64.       W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//写入扇区剩余空间
    : [& o5 H( a5 a; P
  65.     }
    2 \: ?+ r1 d( K, y3 j
  66.                 8 p" Q: R9 f$ K
  67.     if(NumByteToWrite == secremain){//写入结束了
    4 R1 ^7 ~* ?5 d& N
  68.       break;
      W! v4 ~3 Y8 ?' Y: C( D# a
  69.     }
    , q4 H5 g5 z/ W2 K% `( R
  70.     else{        //写入未结束
    4 a- j5 ~: f0 s  b* x
  71.       secpos++;        //扇区地址增1
    . L( P  \& N. v
  72.       secoff = 0;                //偏移位置为0               
    0 c  f* f6 o6 D% I6 ^/ Y
  73.       pBuffer += secremain;        //指针偏移5 X  q7 l9 w$ k$ {0 Y* H  l
  74.       WriteAddr += secremain;        //写地址偏移
    ! D2 u4 i) s8 H6 I) Q
  75.       NumByteToWrite -= secremain;//字节数递减8 S+ z9 G/ h% N: C: Z
  76.       if(NumByteToWrite > 4096)                7 w' ?0 H0 C! C. B5 [( r
  77.         secremain = 4096;        //下个扇区还没是写不完' K$ D/ K6 Z* E" R
  78.       else
    $ E- @% R; Y4 J
  79.         secremain = NumByteToWrite;//下个扇区可以写完了7 V. g; y- m5 a" r# _3 y) I( J
  80.     }
    " `# E$ H: Q; p( s
  81.   }
    $ K% S! w" Q6 c  ]$ [$ m$ F- P
  82. }
复制代码

7 S- a5 T( J2 r, l) \% {1 t
➡️ 在main.c文件下编写SPI测试代码
  1. /* USER CODE BEGIN PV */
    1 [1 A" t' ^: T: l; A" s: ^
  2. uint8_t wData[0x100];( V7 _- p- t( p$ a  N
  3. uint8_t rData[0x100];% M5 ?  B$ E* j0 ^7 _
  4. uint32_t i;9 X8 ~2 [( f- Z5 u" ^* p
  5. /* USER CODE END PV */2 A4 V5 B2 ]7 C1 {# S
  6. int main(void){! ~5 Q, t# V8 I; \# N9 }
  7.   /* USER CODE BEGIN 1 */& R! Z. k0 q+ t
  8.   uint8_t key;
    5 c' J  Q+ i4 j8 w* H6 ]4 J
  9.   /* USER CODE END 1 */  f# F/ e: z% ^
  10.   HAL_Init();
    & v/ U3 p! Z* G( M8 H8 O
  11.   SystemClock_Config();) y6 B- b& F  C( k8 `
  12.   MX_GPIO_Init();) l0 X* c0 d# f: Y7 O
  13.   MX_SPI2_Init();$ c- |: q1 e" t+ ^+ K
  14.   MX_USART1_UART_Init();7 I' L+ K/ G  ~3 N& m2 @( c3 @
  15.   /* USER CODE BEGIN 2 */3 ?  w* H8 Z2 R3 V/ ^, m' s6 i% i
  16.   W25QXX_Init();
    ( S$ ]& q7 x7 ~0 F- a) q4 J
  17.   for(i=0;i<0x100;i++){
    6 A( B! a# [' D( a2 j+ _) _
  18.     wData[i] = i;$ C% a+ J' X& D4 ]
  19.     rData[i] = 0;
    ! J! f$ h$ e$ U1 Q3 N; V  M$ }
  20.   }       
    7 Z4 z. m4 C9 ~+ o1 p" A8 |0 N# g
  21.   /* USER CODE END 2 */
    / h3 W6 R! O% q  i! h; u
  22.   while (1){
    3 q* Z' C2 I& |3 J; }5 o
  23.     key = KEY_Scan(0);
    1 V, {% G0 o9 S0 i/ ~  d7 @
  24.     if(key == KEY_UP_PRES){( ^, o4 Y- J+ i  D9 d! T
  25.       printf("KEY_UP_PRES write data...\r\n");" ?; H& Z8 g2 [$ q& v  Q$ b$ `
  26.       W25QXX_Erase_Sector(0);
    + Y6 j( W- j+ C* ?
  27.       W25QXX_Write(wData,0,256);                + X& D8 _% C- y
  28.     }
    5 ~% Z: V' u, D7 H; k
  29.                        
    : M6 ~) z6 U. h" ]" l, u. p+ p
  30.     if(key == KEY_DOWN_PRES){
    * ~$ n$ W7 H3 L+ j+ S0 {
  31.       printf("KEY_DOWN_PRES read data...\r\n");
    $ ~: L8 ^; s, t  ^6 x8 R
  32.       W25QXX_Read(rData,0,256);
    , T/ `( S, A  B: O0 c
  33.       for(i=0;i<256;i++){
    ; F  ]2 e% c! i2 W  ]
  34.         printf("0x%02X ",rData[i]);
    $ u$ j9 o4 {3 t& ]7 p; W  r
  35.       }& a9 t+ W4 \, ?
  36.     }
    6 @5 b6 Z( u4 u
  37.                
    * }; I- Z1 Q' q+ f5 \6 M. O
  38.     HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
    % T0 A: v; Z! U# W6 @
  39.     HAL_Delay(200);
    / ^$ F; a# y/ i' P0 ]2 k
  40.   }
    & s2 c5 Y4 B5 ]" H
  41. }
复制代码

" U# i& o/ o5 I
4.下载验证
编译无误下载到开发板后,可以看到D1指示灯不断闪烁,当按下K_UP按键后数据写入到W25Q64芯片内,当按下K_DOWN按键后读取W25Q64芯片的值,同时串口打印出相应信息
& a# ]4 D4 j$ S
微信图片_20230701185521.png 9 H' \0 L2 v; P" o

3 {; U5 ?% |  B- G  W6 }转载自: 嵌入式攻城狮/ @) T+ Z1 B! h+ J& D, H, w
如有侵权请联系删除
, |( X8 x2 m% U- \  \
) `1 I* n, n; s% m# D
( P2 S: f3 |5 l$ a3 ]. {- C
" Y1 U( L, X. M3 w2 t
赞 收藏 评论0 发布时间:2023-7-1 18:56

举报

0个回答

所属标签

相似技术帖

官网相关资源

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