完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
这里讲的是两块STM32F407板子的互相通讯,折腾了3天,终于比较清楚了,特此记录。
两块板子互相通讯,除了SPI的接线,肯定还有其他信号线,必须注意这些信号线的上拉下拉,输出口,最好配置为上拉,输入口,直接不拉。 我遇到,一边输入口,一边输出口,2边都配成下拉,接口当输出口输出时,电压只有2.01V,然后通信通不起,把我整了很久。其实想想原因很简单,当输出时,内部电路给电,然后两边的下拉电阻相当于并联对地(下拉电阻相当于减小一般),然后STM32内部向上驱动力不足,导致对方检测不到输入。所以看来STM32,能用上拉电阻就用上拉,使用时向下的驱动强些。 下面进入正题,直接上代码,都是在用的。 首先,硬件连接方式, ----- 主机 --------------------------------------从机 NSS(PB12) --------------------------NSS(PB12) SPI_SCK ---------------------------------SPI_SCK SPI_MISO--------------------------------SPI_MISO SPI_MOSI---------------------------------SPI_MOSI PDin(6)-------------------<-----------PCout(0) //含义 1 = 从机初始化完成了,开始吧。 PDout(10)-------------->--------------PCin(4) //含义 1 = 主机要发送主机了 //NSS引脚,其实可以不用。我已经测试,在用的时候和不用的时候,实际没有区别。 先上从机代码 //从机SPI初始化 void SPI2_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);//使能SPI2时钟 //GPIOFB13,14,15初始化设置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14|GPIO_Pin_15;//PB3~5复用功能输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉 GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;//PB3~5复用功能输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;// GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化 //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 ;//PB12复用NSS //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能 //GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出 //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz //GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;// //GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化 //GPIO_PinAFConfig(GPIOB,GPIO_PinSource12,GPIO_AF_SPI2); //PB13复用为 SPI2 (这里是注释点了的,注释过后,其实NSS引脚也就没用了) GPIO_PinAFConfig(GPIOB,GPIO_PinSource13,GPIO_AF_SPI2); //PB13复用为 SPI2 GPIO_PinAFConfig(GPIOB,GPIO_PinSource14,GPIO_AF_SPI2); //PB14复用为 SPI2 GPIO_PinAFConfig(GPIOB,GPIO_PinSource15,GPIO_AF_SPI2); //PB15复用为 SPI2 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工 SPI_InitStructure.SPI_Mode = SPI_Mode_Slave ; //设置SPI工作模式:设置为主SPI SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; //设置SPI的数据大小:SPI发送接收16位帧结构 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //串行同步时钟的空闲状态为低电平,这个高低电平,必须配合时钟线来,我这里时钟线是PB13,是采用的下拉 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样,这个跳变沿,和主机一样。 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制,这个选为软件,硬件,似乎,没有什么影响。网上有人说,还是选为硬件,他的解释是,要通信的时候,主机先发送片选命令,就是NSS引脚置低(当为从机时,NSS引脚拉低就表示选中了这个芯片,当为主机时,NSS引脚拉高就表示选中了这个芯片),这样让从机提前一点点知道要发送数据了,SPI外设就自动提前准备好,表面上一看比较有道理。我的理解是,如果设置为NSS软件管理,那么这个芯片是否被片选,就由SPI_InitStructure.SPI_Mode = SPI_Mode_Slave 这个来决定的,那么说白了,芯片只要一初始化,SPI外设就随时都初始化好了,只要在至收发数据期间,没有干扰,就没为题。所以,这个选为硬件,不是那么必要。 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; //定义波特率预分频的值:波特率预分频值为4 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式 SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器 SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx ,ENABLE); //使能SPI2 DMA功能 SPI_Cmd(SPI2, ENABLE); //使能SPI外设 } //从机SPI读写函数 //SPI2 读写一个字节 //TxData:要写入的字节 //返回值:读取到的字节 u8 SPI2_ReadWriteByte(u8 TxData) { while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET){}//等待发送区空 SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个byte 数据 while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET){} //等待接收完一个byte return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据 } // 从机 DMAx的各通道配置 //这里的传输形式是固定的,这点要根据不同的情况来修改 //从存储器->外设模式/8位数据宽度/存储器增量模式 //DMA_Streamx:DMA数据流,DMA1_Stream07/DMA2_Stream07 //chx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7 //par:外设地址 //mar:存储器地址 //ndtr:数据传输量 //Ddtd:存储器到外设模式DMA_DIR_MemoryToPeripheral ,外设到存储器DMA_DIR_PeripheralToMemory, // DMA_DIR_MemoryToMemory 内存到内存 void MYDMA_Config(DMA_Stream_TypeDef DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr,u32 Ddtd)(这是个通用函数,主机也是这个函数,只是参数不一样) { DMA_InitTypeDef DMA_InitStructure; if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1 { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能 }else { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能 } DMA_DeInit(DMA_Streamx); while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}//等待DMA可配置 / 配置 DMA Stream */ DMA_InitStructure.DMA_Channel = chx; //通道选择 DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMA外设地址 DMA_InitStructure.DMA_Memory0BaseAddr = mar;//DMA 存储器0地址 DMA_InitStructure.DMA_DIR = Ddtd;//存储器到外设模式DMA_DIR_MemoryToPeripheral ,外设到存储器DMA_DIR_PeripheralToMemory DMA_InitStructure.DMA_BufferSize = ndtr;//数据传输量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据长度:16位 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//存储器数据长度:16位 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输 DMA_Init(DMA_Streamx, &DMA_InitStructure);//初始化DMA Stream } // 从机 开启一次DMA传输 //DMA_Streamx:DMA数据流,DMA1_Stream07/DMA2_Stream07 //ndtr:数据传输量 void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)(这是个通用函数,主机也是这个函数,只是参数不一样) {undefined DMA_Cmd(DMA_Streamx, DISABLE); //关闭DMA传输 while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){} //确保DMA可以被设置 DMA_SetCurrDataCounter(DMA_Streamx,ndtr); //数据传输量 DMA_Cmd(DMA_Streamx, ENABLE); //开启DMA传输 } //从机 接收数据的函数,主函数调用就行 u32 DataDranInit_Check(void) {undefined u16 l; SPI2_Init(); //第一步,SPI初始化,SPI已使能 MYDMA_Config(DMA1_Stream3,DMA_Channel_0,(u32)&SPI2->DR,(u32)test_8,10,DMA_DIR_PeripheralToMemory); //Delay_ms(500); l = SPI2->DR;//第三步,这一步相当重要,我们这个是从机的函数。 //从机的SPI设置为了从站模式,并且上面第一步已经使能,然后由于可能主机还在初始化,在其初始化过程中,有可能SPI时钟线会产生震荡,导致从机SPI->SP寄存器之RXNE位置1,最终导致下面DMA开启的时候发生错位。 //作为从机来讲,SPI外设与DMA外设的通信工作过程就是,SPI收到信号,产生RXNE标志位,DMA收到该标志位,就进行一次数据传输。 //第三部的操作,就是读SPI数据寄存器的值,将自动复位RXNE标志。相当于有些人说的对SPI->DR的清零。 ReData: DMA_ClearFlag(DMA1_Stream3, DMA_FLAG_TCIF3 | DMA_FLAG_HTIF3 | DMA_FLAG_TEIF3 | DMA_FLAG_DMEIF3 | DMA_FLAG_FEIF3 );//清除DMA的标志位,必须要清除这些标志位,才能重新对DMA进行使能,DMA才会重启。光关闭DMA使能,再开DMA使能,DMA是不会重启的。 PDout(0)=0; //告诉对方初始化完成 while(PDin(4)==1){} //等待对方的信号 MYDMA_Enable(DMA1_Stream3,10); //检测到响应数据,转SPI DMA,接收数据 while(DMA1_Stream3->NDTR){} //等待传输完成 PDout(0)=1; //复位初始化信号 for(i=0; i<10; i++) { printf("n–%d—%d----%d—n",i,test_8,DMA1_Stream3->NDTR);} Delay_ms(30); goto ReData; }//循环采集数据。这个只是测试程序,所以这样做的,个人根据实际情况修改 下面是主机的函数 //主机 SPI初始化 void SPI2_Tx_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);//使能SPI2时钟 //GPIOFB13,14,15初始化设置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14|GPIO_Pin_15;//PB3~5复用功能输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉 GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;//PB3~5复用功能输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//上拉 GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化 //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 ;// //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT ;// //GPIO_InitStructure.GPIO_OType = GPIO_OType_PP ;//推挽输出 //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz ;//100MHz //GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;//上拉 //GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化 GPIO_PinAFConfig(GPIOB,GPIO_PinSource13,GPIO_AF_SPI2); //PB13复用为 SPI2 GPIO_PinAFConfig(GPIOB,GPIO_PinSource14,GPIO_AF_SPI2); //PB14复用为 SPI2 GPIO_PinAFConfig(GPIOB,GPIO_PinSource15,GPIO_AF_SPI2); //PB15复用为 SPI2 //这里只针对SPI口初始化 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master ; //设置SPI工作模式:设置为从SPI SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; //设置SPI的数据大小:SPI发送接收16位帧结构 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //串行同步时钟的空闲状态为高电平 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; //定义波特率预分频的值:波特率预分频值为4 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式 SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器 SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Tx,ENABLE); //使能SPI2 DMA功能 SPI_Cmd(SPI2, ENABLE); //使能SPI外设 } //主机 SPI2 读写一个字节(和从机是一样的) //TxData:要写入的字节 //返回值:读取到的字节 u8 SPI2_ReadWriteByte(u8 TxData) { while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET){}//等待发送区空 SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个byte 数据 while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET){} //等待接收完一个byte return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据 } //主机 DMAx的各通道配置 (和从机一样的) //这里的传输形式是固定的,这点要根据不同的情况来修改 //从存储器->外设模式/8位数据宽度/存储器增量模式 //DMA_Streamx:DMA数据流,DMA1_Stream07/DMA2_Stream07 //chx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7 //par:外设地址 //mar:存储器地址 //ndtr:数据传输量 //Ddtd:存储器到外设模式DMA_DIR_MemoryToPeripheral ,外设到存储器DMA_DIR_PeripheralToMemory, // DMA_DIR_MemoryToMemory 内存到内存 void MYDMA_Config(DMA_Stream_TypeDef DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr,u32 Ddtd) { DMA_InitTypeDef DMA_InitStructure; if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1 { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能 }else { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能 } DMA_DeInit(DMA_Streamx); while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}//等待DMA可配置 / 配置 DMA Stream */ DMA_InitStructure.DMA_Channel = chx; //通道选择 DMA_InitStructure.DMA_PeripheralBaseAddr = par; //DMA外设地址 DMA_InitStructure.DMA_Memory0BaseAddr = mar; //DMA 存储器0地址 DMA_InitStructure.DMA_DIR = Ddtd; //存储器到外设模式DMA_DIR_MemoryToPeripheral , //外设到存储器DMA_DIR_PeripheralToMemory DMA_InitStructure.DMA_BufferSize = ndtr; //数据传输量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设非增量模式 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器增量模式 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据长度:16位 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //存储器数据长度:16位 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 使用普通模式 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //中等优先级 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输 DMA_Init(DMA_Streamx, &DMA_InitStructure); //初始化DMA Stream } //(主机)开启一次DMA传输(和从机一样的) //DMA_Streamx:DMA数据流,DMA1_Stream07/DMA2_Stream07 //ndtr:数据传输量 void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr) {undefined DMA_Cmd(DMA_Streamx, DISABLE); //关闭DMA传输 while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){} //确保DMA可以被设置 DMA_SetCurrDataCounter(DMA_Streamx,ndtr); //数据传输量 DMA_Cmd(DMA_Streamx, ENABLE); //开启DMA传输 } u16 test_8[37]={40960,53,46,288,72,6,97,8,91,130,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37}; //主机的 输入参数 //主机,SPI DMA发送数据的程序 void DataDranInit_Check(void) {undefined SPI2_Tx_Init(); //使能SPI为从,开启SPI2发送数据的DMA,等待发送数据 //配置DMA为发送数据模式 MYDMA_Config(DMA1_Stream4,DMA_Channel_0,(u32)&SPI2->DR,(u32)test_8,10,DMA_DIR_MemoryToPeripheral); //Delay_ms(200); PBout(12)= 1 ; PCout(10)=1; //告诉对方,可以读取了。 sendData: if ( PCin(6) == 0 ) //等待对方初始化完成的信号 { //Delay_us(10); //合理延时,等待对方响应 //这个延时可以不要,只是做测试时加在这的,我不删,是如果不行,给你提供的思路。。。 if(test_8[1]>32767) test_8[1]=1; test_8[1]++;//这只是让发送的数据变化,测试时,好知道传输没断,是一直在传而已。 DMA_ClearFlag(DMA1_Stream4, DMA_FLAG_TCIF4 | DMA_FLAG_HTIF4 | DMA_FLAG_TEIF4 | DMA_FLAG_DMEIF4 | DMA_FLAG_FEIF4 ); //必须清数据位,否则DMA根本不会重启。 PCout(10)=0; //告诉对方,主机准备好了,要发送开始数据了。 Delay_us(4); //这个延时很随意,酌情。。。 PBout(12)= 0 ; //使能NSS,片选从机,从机如果是Soft就不用这个了。 Delay_us(1); //这个延时很随意,酌情。。。 MYDMA_Enable(DMA1_Stream4,10); //使能发送数据 while(DMA_GetCurrDataCounter(DMA1_Stream4)){} PCout(10)=1; //发送完毕,复位。 Delay_ms(1); //这个延时很随意,酌情。。。 PBout(12)= 1 ; //恢复片选 aafd = DMA_GetCurrDataCounter(DMA1_Stream4); Delay_ms(1); } goto sendData; // } STM32 的SPI DMA通讯,也不算坑吧,用着还好。 另外,所谓的 CPOL CHPA,就是SPI的四种模式,建议用逻辑分析仪看下,根据清空设置就行了,我这的话,反正主从设置为一样,我觉得应该都是一样就行了。 |
|
|
|
只有小组成员才能发言,加入小组>>
3262 浏览 9 评论
2943 浏览 16 评论
3442 浏览 1 评论
8950 浏览 16 评论
4036 浏览 18 评论
1078浏览 3评论
558浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
551浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2286浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1846浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-9 04:30 , Processed in 0.957021 second(s), Total 51, Slave 41 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号