使用 STM32 的 SPI 来读取外部 SPI FLASH 芯片(W25Qxx)
SPI简介
SPI 是英语 Serial Peripheral interface 的缩写,顾名思义就是串行外围设备接口。是 Motorola 首先在其 MC68HCXX 系列处理器上定义的。SPI 接口主要应用在 EEPROM,FLASH,实时时 钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工, 同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局 上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信 协议,STM32 也有 SPI 接口。SPI 的内部简明图。
SPI 接口一般使用 4 条线通信: MISO 主设备数据输入,从设备数据输出。 MOSI 主设备数据输出,从设备数据输入。 SCLK 时钟信号,由主设备产生。 CS 从设备片选信号,由主设备控制。 SPI 主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可 编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。 SPI 总线四种工作方式 SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串 行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果 CPOL=0,串行同步时钟的空闲状态为低电平;如果 CPOL=1,串行同步时钟的空闲状态为高电 平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果 CPHA=0, 在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果 CPHA=1,在串行同步时钟 的第二个跳变沿(上升或下降)数据被采样。SPI 主模块和与之通信的外设备时钟相位和极性 应该一致。
不同时钟相位下的总线传输时序(CPHA=0/1)。
硬件电路
软件设计
spi.h
ifndef __SPI_H #define __SPI_H #include "sys.h"void SPI1_Init(void); //初始化SPI口 void SPI1_SetSpeed(u8 SpeedSet); //设置SPI速度 u8 SPI1_ReadWriteByte(u8 TxData);//SPI总线读写一个字节#endif
spi.c
#include "spi.h"//以下是SPI模块的初始化代码,配置成主机模式,访问SD Card/W25Q64/NRF24L01 //SPI口初始化 //这里针是对SPI1的初始化SPI_InitTypeDef SPI_InitStructure;void SPI1_Init(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA ,ENABLE );//PORTA时钟使能 RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE );//SPI1时钟使能 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PA5/6/7复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOAGPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); //PA5/6/7上拉SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPISPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为高电平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_256; //定义波特率预分频的值:波特率预分频值为256SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式SPI_Init(SPI1, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器SPI_Cmd(SPI1, ENABLE); //使能SPI外设SPI1_ReadWriteByte(0xff);//启动传输 } //SPI 速度设置函数 //SpeedSet: //SPI_BaudRatePrescaler_2 2分频 //SPI_BaudRatePrescaler_8 8分频 //SPI_BaudRatePrescaler_16 16分频 //SPI_BaudRatePrescaler_256 256分频 void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler) {assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));SPI1->CR1&=0XFFC7;SPI1->CR1|=SPI_BaudRatePrescaler; //设置SPI2速度 SPI_Cmd(SPI1,ENABLE); } //SPIx 读写一个字节 //TxData:要写入的字节 //返回值:读取到的字节 u8 SPI1_ReadWriteByte(u8 TxData) { u8 retry=0; while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位{retry++;if(retry>200)return 0;} SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个数据retry=0;while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)//检查指定的SPI标志位设置与否:接受缓存非空标志位{retry++;if(retry>200)return 0;} return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据 }
flash.h
#ifndef __FLASH_H #define __FLASH_H #include "sys.h" #define W25Q80 0XEF13 #define W25Q16 0XEF14 #define W25Q32 0XEF15 #define W25Q64 0XEF16extern u16 SPI_FLASH_TYPE; //定义我们使用的flash芯片型号 #define SPI_FLASH_CS PAout(4) //选中FLASH extern u8 SPI_FLASH_BUF[4096]; //W25X16读写 #define FLASH_ID 0XEF14 //指令表 #define W25X_WriteEnable 0x06 #define W25X_WriteDisable 0x04 #define W25X_ReadStatusReg 0x05 #define W25X_WriteStatusReg 0x01 #define W25X_ReadData 0x03 #define W25X_FastReadData 0x0B #define W25X_FastReadDual 0x3B #define W25X_PageProgram 0x02 #define W25X_BlockErase 0xD8 #define W25X_SectorErase 0x20 #define W25X_ChipErase 0xC7 #define W25X_PowerDown 0xB9 #define W25X_ReleasePowerDown 0xAB #define W25X_DeviceID 0xAB #define W25X_ManufactDeviceID 0x90 #define W25X_JedecDeviceID 0x9F void SPI_Flash_Init(void); u16 SPI_Flash_ReadID(void); //读取FLASH ID u8 SPI_Flash_ReadSR(void); //读取状态寄存器 void SPI_FLASH_Write_SR(u8 sr); //写状态寄存器 void SPI_FLASH_Write_Enable(void); //写使能 void SPI_FLASH_Write_Disable(void); //写保护 void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead); //读取flash void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);//写入flash void SPI_Flash_Erase_Chip(void); //整片擦除 void SPI_Flash_Erase_Sector(u32 Dst_Addr);//扇区擦除 void SPI_Flash_Wait_Busy(void); //等待空闲 void SPI_Flash_PowerDown(void); //进入掉电模式 void SPI_Flash_WAKEUP(void); //唤醒 #endif
flash.c
#include "flash.h" #include "spi.h" #include "delay.h" u16 SPI_FLASH_TYPE=W25Q64;//默认就是25Q64;若使用W25Q128将其改成W25Q128; //4Kbytes为一个Sector //16个扇区为1个Block //W25X16 //容量为2M字节,共有32个Block,512个Sector //初始化SPI FLASH的IO口 void SPI_Flash_Init(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4; //SPI CSGPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //复用推挽输出GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4);SPI1_Init(); //初始化SPISPI1_SetSpeed(SPI_BaudRatePrescaler_4); //设置为18M时钟,高速模式SPI_FLASH_TYPE=SPI_Flash_ReadID();//读取FLASH ID. } //读取SPI_FLASH的状态寄存器 //BIT7 6 5 4 3 2 1 0 //SPR RV TB BP2 BP1 BP0 WEL BUSY //SPR:默认0,状态寄存器保护位,配合WP使用 //TB,BP2,BP1,BP0:FLASH区域写保护设置 //WEL:写使能锁定 //BUSY:忙标记位(1,忙;0,空闲) //默认:0x00 u8 SPI_Flash_ReadSR(void) { u8 byte=0; SPI_FLASH_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_ReadStatusReg); //发送读取状态寄存器命令 byte=SPI1_ReadWriteByte(0Xff); //读取一个字节 SPI_FLASH_CS=1; //取消片选 return byte; } //写SPI_FLASH状态寄存器 //只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!! void SPI_FLASH_Write_SR(u8 sr) { SPI_FLASH_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_WriteStatusReg); //发送写取状态寄存器命令 SPI1_ReadWriteByte(sr); //写入一个字节 SPI_FLASH_CS=1; //取消片选 } //SPI_FLASH写使能 //将WEL置位 void SPI_FLASH_Write_Enable(void) {SPI_FLASH_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_WriteEnable); //发送写使能 SPI_FLASH_CS=1; //取消片选 } //SPI_FLASH写禁止 //将WEL清零 void SPI_FLASH_Write_Disable(void) { SPI_FLASH_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_WriteDisable); //发送写禁止指令 SPI_FLASH_CS=1; //取消片选 } //读取芯片ID W25X16的ID:0XEF14 u16 SPI_Flash_ReadID(void) {u16 Temp = 0; SPI_FLASH_CS=0; SPI1_ReadWriteByte(0x90);//发送读取ID命令 SPI1_ReadWriteByte(0x00); SPI1_ReadWriteByte(0x00); SPI1_ReadWriteByte(0x00); Temp|=SPI1_ReadWriteByte(0xFF)<<8; Temp|=SPI1_ReadWriteByte(0xFF); SPI_FLASH_CS=1; return Temp; } //读取SPI FLASH //在指定地址开始读取指定长度的数据 //pBuffer:数据存储区 //ReadAddr:开始读取的地址(24bit) //NumByteToRead:要读取的字节数(最大65535) void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead) { u16 i; SPI_FLASH_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_ReadData); //发送读取命令 SPI1_ReadWriteByte((u8)((ReadAddr)>>16)); //发送24bit地址 SPI1_ReadWriteByte((u8)((ReadAddr)>>8)); SPI1_ReadWriteByte((u8)ReadAddr); for(i=0;i<NumByteToRead;i++){ pBuffer[i]=SPI1_ReadWriteByte(0XFF); //循环读数 }SPI_FLASH_CS=1; //取消片选 } //SPI在一页(0~65535)内写入少于256个字节的数据 //在指定地址开始写入最大256字节的数据 //pBuffer:数据存储区 //WriteAddr:开始写入的地址(24bit) //NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!! void SPI_Flash_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite) {u16 i; SPI_FLASH_Write_Enable(); //SET WEL SPI_FLASH_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_PageProgram); //发送写页命令 SPI1_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址 SPI1_ReadWriteByte((u8)((WriteAddr)>>8)); SPI1_ReadWriteByte((u8)WriteAddr); for(i=0;i<NumByteToWrite;i++)SPI1_ReadWriteByte(pBuffer[i]);//循环写数 SPI_FLASH_CS=1; //取消片选 SPI_Flash_Wait_Busy(); //等待写入结束 } //无检验写SPI FLASH //必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败! //具有自动换页功能 //在指定地址开始写入指定长度的数据,但是要确保地址不越界! //pBuffer:数据存储区 //WriteAddr:开始写入的地址(24bit) //NumByteToWrite:要写入的字节数(最大65535) //CHECK OK void SPI_Flash_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite) { u16 pageremain; pageremain=256-WriteAddr%256; //单页剩余的字节数 if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节while(1){ SPI_Flash_Write_Page(pBuffer,WriteAddr,pageremain);if(NumByteToWrite==pageremain)break;//写入结束了else //NumByteToWrite>pageremain{pBuffer+=pageremain;WriteAddr+=pageremain; NumByteToWrite-=pageremain; //减去已经写入了的字节数if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节else pageremain=NumByteToWrite; //不够256个字节了}}; } //写SPI FLASH //在指定地址开始写入指定长度的数据 //该函数带擦除操作! //pBuffer:数据存储区 //WriteAddr:开始写入的地址(24bit) //NumByteToWrite:要写入的字节数(最大65535) u8 SPI_FLASH_BUF[4096]; void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite) { u32 secpos;u16 secoff;u16 secremain; u16 i; secpos=WriteAddr/4096;//扇区地址 0~511 for w25x16secoff=WriteAddr%4096;//在扇区内的偏移secremain=4096-secoff;//扇区剩余空间大小 if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节while(1) { SPI_Flash_Read(SPI_FLASH_BUF,secpos*4096,4096);//读出整个扇区的内容for(i=0;i<secremain;i++)//校验数据{if(SPI_FLASH_BUF[secoff+i]!=0XFF)break;//需要擦除 }if(i<secremain)//需要擦除{SPI_Flash_Erase_Sector(secpos);//擦除这个扇区for(i=0;i<secremain;i++) //复制{SPI_FLASH_BUF[i+secoff]=pBuffer[i]; }SPI_Flash_Write_NoCheck(SPI_FLASH_BUF,secpos*4096,4096);//写入整个扇区 }else SPI_Flash_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间. if(NumByteToWrite==secremain)break;//写入结束了else//写入未结束{secpos++;//扇区地址增1secoff=0;//偏移位置为0 pBuffer+=secremain; //指针偏移WriteAddr+=secremain;//写地址偏移 NumByteToWrite-=secremain; //字节数递减if(NumByteToWrite>4096)secremain=4096; //下一个扇区还是写不完else secremain=NumByteToWrite; //下一个扇区可以写完了} }; } //擦除整个芯片 //整片擦除时间: //W25X16:25s //W25X32:40s //W25X64:40s //等待时间超长... void SPI_Flash_Erase_Chip(void) { SPI_FLASH_Write_Enable(); //SET WEL SPI_Flash_Wait_Busy(); SPI_FLASH_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_ChipErase); //发送片擦除命令 SPI_FLASH_CS=1; //取消片选 SPI_Flash_Wait_Busy(); //等待芯片擦除结束 } //擦除一个扇区 //Dst_Addr:扇区地址 0~511 for w25x16 //擦除一个山区的最少时间:150ms void SPI_Flash_Erase_Sector(u32 Dst_Addr) { Dst_Addr*=4096;SPI_FLASH_Write_Enable(); //SET WEL SPI_Flash_Wait_Busy(); SPI_FLASH_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_SectorErase); //发送扇区擦除指令 SPI1_ReadWriteByte((u8)((Dst_Addr)>>16)); //发送24bit地址 SPI1_ReadWriteByte((u8)((Dst_Addr)>>8)); SPI1_ReadWriteByte((u8)Dst_Addr); SPI_FLASH_CS=1; //取消片选 SPI_Flash_Wait_Busy(); //等待擦除完成 } //等待空闲 void SPI_Flash_Wait_Busy(void) { while ((SPI_Flash_ReadSR()&0x01)==0x01); // 等待BUSY位清空 } //进入掉电模式 void SPI_Flash_PowerDown(void) { SPI_FLASH_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_PowerDown); //发送掉电命令 SPI_FLASH_CS=1; //取消片选 delay_us(3); //等待TPD } //唤醒 void SPI_Flash_WAKEUP(void) { SPI_FLASH_CS=0; //使能器件 SPI1_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB SPI_FLASH_CS=1; //取消片选 delay_us(3); //等待TRES1 }
main.c
#include "led.h" #include "delay.h" #include "sys.h" #include "usart.h" #include "lcd.h" #include "key.h" #include "spi.h" #include "flash.h"//要写入到W25Q64的字符串数组 const u8 TEXT_Buffer[]={" SPI TEST"}; #define SIZE sizeof(TEXT_Buffer) int main(void){ u8 key;u16 i=0;u8 datatemp[SIZE];u32 FLASH_SIZE;delay_init(); //延时函数初始化 uart_init(9600); //串口初始化为9600LED_Init(); //初始化与LED连接的硬件接口ILI9341_Init ();KEY_Init(); //按键初始化 SPI_Flash_Init(); //SPI FLASH 初始化 LCD_SetFont(&Font8x16); //设置英文字体类型 Font24x32;:Font16x24;:Font8x16;ILI9341_DispStringLine_EN(LINE(0)," STM32"); ILI9341_DispStringLine_EN(LINE(1),"SPI TEST"); ILI9341_DispStringLine_EN(LINE(2),"2014/3/9"); ILI9341_DispStringLine_EN(LINE(3),"KEY1:Write KEY2:Read"); //显示提示信息 LED1=0;while(SPI_Flash_ReadID()!=W25Q64)//检测不到W25Q64;默认W25Q64;若使用W25Q128,改为W25Q64{ILI9341_DispStringLine_EN(LINE(4),"25Q64 Check Failed!");delay_ms(500);ILI9341_DispStringLine_EN(LINE(5),"Please Check! ");delay_ms(500);LED1=!LED1;//DS0闪烁}ILI9341_DispStringLine_EN(LINE(6),"25Q64 Ready!");FLASH_SIZE=8*1024*1024; //FLASH 大小为8M字节LCD_SetColors(RED,BLACK);while(1){key=KEY_Scan(0);if(key==KEY1_PRES) //WK_UP 按下,写入W25Q64{ILI9341_Clear( 0, 110, 240, 320 );ILI9341_DispStringLine_EN(LINE(7),"Start Write W25Q64....");SPI_Flash_Write((u8*)TEXT_Buffer,FLASH_SIZE-100,SIZE); //从倒数第100个地址处开始,写入SIZE长度的数据ILI9341_DispStringLine_EN(LINE(8),"W25Q64 Write Finished!"); //提示传送完成}if(key==KEY2_PRES) //KEY0 按下,读取字符串并显示{ILI9341_Clear( 0, 150, 240, 320 ); ILI9341_DispStringLine_EN(LINE(9),"Start Read W25Q64.... ");SPI_Flash_Read(datatemp,FLASH_SIZE-100,SIZE); //从倒数第100个地址处开始,读出SIZE个字节ILI9341_DispStringLine_EN(LINE(10),"The Data Readed Is: "); //提示传送完成ILI9341_DispStringLine_EN(LINE(11),datatemp); //显示读到的字符串}i++;delay_ms(10);if(i==20){LED1=!LED1;//提示系统正在运行 i=0;} } }
使用 STM32 的 SPI 来读取外部 SPI FLASH 芯片(W25Qxx)相关推荐
- CC2530(SPI)驱动FLASH芯片W25Qxx
由于之前用的存储芯片价格涨得离谱,需要寻找新的存储芯片,综合考虑找到了W25Qxx来测试替代的可行性.不用DMA的具体代码经过测试可用,但DMA收发测试不成功,仍在测试修改阶段. 所用芯片:cc253 ...
- Openwrt读取spi-nand协议Flash芯片UniqueID(华邦为例)
Flash芯片一般都有一个出厂时由制造商设定的Unique ID,唯一ID.获取到可以用来进行各类加密识别认证,作为设备唯一ID的一种. 本文以华邦品牌的flash芯片为例(W25N01GV.W25M ...
- 基于线性序列机的SPI协议读写winbond公司flash芯片25Q16
基于小梅哥所提的线性序列机思想设计读写该芯片的SPI协议,线性序列机简单来说就是用一个计数器对时钟计数,对于每一个计数值,按照时序要求对信号做出相应操作.简单写了一下 Read Manufacture ...
- STM32F103ZE单片机FSMC接口读取NAND Flash芯片K9F1G08U0E的数据时出现数据丢失的解决办法
[问题] STM32单片机使用FSMC读取K9F1G08U0E NAND Flash时,出现部分字节丢失的情况.例如:Flash存储器中存储有连续的0xff字节,则在进行连续读(Page Read)操 ...
- STM32笔记(十二)---SPI读写FLASH
SPI读写FLASH 文章目录 SPI读写FLASH 一.SPI协议简介 1.1 SPI 物理层 1.2 协议层 1.2.1 SPI 基本通讯过程 1.2.2 通讯的起始和停止信号 1.2.3 数据有 ...
- STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片
STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片 STM32基础工程生成 首先使用STM32CUBEMX生成STM32的基础工程,配置时钟到7 ...
- 《STM32从零开始学习历程》——SPI物理层及FLASH芯片介绍
<STM32从零开始学习历程>@EnzoReventon SPI物理层及FLASH芯片介绍 相关链接: SPI协议层 SPI特性及架构 SPI固件库 参考资料: [野火EmbedFire] ...
- stm32中常见的通信协议之SPI
目录 1.SPI总线 2.SPI的寻址方式 3.SPI的工作原理总结 4.SPI的通讯过程 5.SPI的极性和相位 6.IIC和SPI的异同 7.stm32中SPI配置中常用的寄存器 8.stm32中 ...
- stm32中spi可以随便接吗_STM32的SPI模式读写FLASH芯片全面讲解
例程完整代码: SPI协议简介 SPI协议,即串行外围设备接口,是一种告诉全双工的通信总线,它被广泛地使用在ADC,LCD等设备与MCU间通信的场合. SPI信号线 SPI包含4条总线,分别为SS,S ...
最新文章
- java方法未定义类型_java - 方法未定义为类 - SO中文参考 - www.soinside.com
- aop简介-基于jdk的动态代理
- 3PAR推InServ-T级存储 EMC们紧张了?
- 使用DbContextPool提高EfCore查询性能
- 使用 C# 代码实现拓扑排序
- Esp8266(4)
- “领跑者”计划倒逼光伏产业升级效果显现
- VB编程操作AutoCAD线型
- LibreCAD的基本使用
- Matlab:求出n边凹多边形内角
- 第二届亚太应用经济学会博硕士论文研讨会长沙落幕
- 普通型母函数和指数型母函数
- 实战—深圳链家租房数据分析
- pathon的基本语法
- 从冰雪盛会的幕后赛场,看数字建设者如何保障大型赛事
- windows下使用route添加路由
- Prometheus入门实践
- 蓝湖类似的软件_一款产品设计团队必备的协作工具——蓝湖
- MATLAB离散卷积的实现_代码编写_实现两列数的卷积
- rsync+sersync实时同步数据
热门文章
- 免费的高效视频会议系统 你也可以拥有
- sourceTree git 空目录从远程仓库克隆代码出现warning: templates not found
- matlab打开笔记本摄像头_matlab-调用摄像头人脸识别
- npm 安装报错 code EPERM syscall mkdir
- 计算机毕设Python+Vue药店管理系统(程序+LW+部署)
- 执行查询提示目录名称无效
- 融合transformer和对抗学习的多变量时间序列异常检测算法TranAD论文和代码解读...
- JAVA计算机毕业设计家居体验平台的设计与实现Mybatis+系统+数据库+调试部署
- 2023 年五个最佳被动收入来源
- [矩阵树定理 容斥 meet in middle] Topcoder SRM 551 DIV1 Hard. SweetFruits