3年嵌入式物联网学习资源整理分享:C语言、Linux开发、数据结构;软件开发,STM32单片机、ARM硬件开发、物联网通信开发、综合项目开发教程资料;笔试面试真题。点击下方插件免费领取↓↓↓https://s.pdb2.com/l/cnklSITCGo24eIn
因为24C02是一个2K Bit的串行EEPROM存储器(掉电不丢失),内部含有256个字节。也就是说有256个存储单元,一个字节就是一个存储单元,因为每个字节可以出存256个数,也就是说每个存储单元可以存0~255个数。我们可以这样理解,AT24C02是一栋教学楼,这个教学楼有256个房间(存储单元),没每个房间可以容纳256个学生(每个存储单元可以存储0 ~ 255个数)。而且这个芯片在断电的时候数据不会丢失,利用掉电不会丢失以及这款芯片容量不大的特性,可以大致判断它会在哪些地方可以用到。比如我们看电视得时候,正在看CCTV6电影频道,播放的声音比较大,那么这时候正好停电了。那么你下次来电时你打开电视机,电视机默认肯定是CCTV6电影频道,播放的声音也是很大。那么这些“频道”、“音量”这些数据就存在EEPROM里面,至于是不是ATC02就不一定了。
总结:
- 存储量少,用起来方便
- 可以任意访问地址数据,每一个存储单片可以独立访问,
- 写入前是不需要对写入的单片做独立的擦除
这三个特点对我们理解存储器的特性非常重要,因为接下来要说的FLASH芯片的特性就与它完全相反。
FLASH W25Q128存储器FLSAH字面意思就是闪现、一瞬间的意思,所以FLSAH存储器又称闪存,与 EEPROM都是掉电后数据不丢失的存储器,但FLASH存储器容量普遍大于 EPROM,现在基本取代了它的地位。生活中常用的 U 盘、SD卡、SSD 固态硬盘以及我们 STM32 芯片内部用于存储程序的设备,都是 FLASH 类型的存储器。在存储控制上,最主要的区别是 FLASH 芯片只能一大片一大片地擦写,而 EEPROM可以单个字节擦写。
FLASH 芯片的最小擦除单位为扇区(Sector),而一个块(Block)包含 16 个扇区,4Kbytes为一个Sector,16个扇区为1个Block。W25Q64 容量为8M字节(即 64M bit), 分为128块(Block),每一块的大小为64K字节,每块又分为16个扇区(Sector),那么每个扇区就是4K个字节。W25Q128 容量为16M字节(即 128M bit),分为256块(Block),每一块的大小为64K字节,每块又分为16个扇区(Sector),那么每个扇区就是4K个字节(4096个字节,也就是4096个存储单元)。
W25Qxx的最小擦除单位为一个扇区,也就是每一次必须擦除4K字节。所以必须给W25Qxx开辟至少4K的缓冲区,这样对单片机的RAM的要求比较高,要求芯片必须有4K以上的RAM才能很好的操作。所有的FLASH我们在写之前都要擦出对应的扇区,擦除后的数据是0XFF。我们可以这样理解。我们要改写FLASH芯片W25Q128的一个扇区中某一个数据,就必须在STM32芯片的内部RAM中开辟4K字节(4096字节)的缓冲区域。先把FLASH芯片W25Q128的一个扇区中数据全部读到STM32芯片的内部RAM中开辟4K字节(4096字节)的缓冲区域中去,把我们要改写的数据在缓冲区域改写好之后,再把FLASH芯片W25Q128的一个扇区中的数据全部擦除完毕,擦除完成之后再把数据写回去。这是写入数据的操作,在读数据的时候不需要以扇区为单位,想读哪个扇区就读哪个扇区的数据。
/*************************************************************************
* Function Name : SPI_Flash_Write
* Description : 在指定地址开始写入指定长度的数据,该函数带擦除操作!
* Input : *pBuffer:要写入数据的指针
WriteAddr:开始写入的地址(24bit)
NumByteToWrite:要写入的字节数(最大16 x 1024 x 1024)
* Output : None
* Return : None
****************************************************************************/
void SPI_Flash_Write(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
Addr = WriteAddr % 4096;//mod运算求余,若writeAddr是4096整数倍,运算结果Addr值为0
NumOfPage = NumByteToWrite / 4096;//计算出要写多少整数扇区
NumOfSingle = NumByteToWrite % 4096;//mod运算求余,计算出剩余不满一扇区的字节数
count = 4096 - Addr;//差count个数据值,刚好可以对齐到扇区地址
if (Addr == 0)//Addr=0,则WriteAddr刚好按扇区对齐或者说小于一个扇区
{
//NumByteToWrite < 4096,写入的字符串大小长度小于一个扇区(4096个字节)的大小,如22
if (NumOfPage == 0)
{
SPI_Flash_Write_Page(pBuffer, WriteAddr, NumByteToWrite);
}
else //NumByteToWrite > 4096,写入的字符串大小长度大与一个扇区(4096个字节)的大小,如4098
{
//先把整数扇区都写了
while (NumOfPage--)
{
SPI_Flash_Write_Page(pBuffer, WriteAddr, 4096);
WriteAddr = 4096;
pBuffer = 4096;
}
//若有多余的不满一扇区的数据,把它写完
SPI_Flash_Write_Page(pBuffer, WriteAddr, NumOfSingle);
}
}
//若地址与 4096 不对齐
else //Addr不等于0,则要写入的WriteAddr地址与4096不对齐
{
//NumByteToWrite < 4096
if (NumOfPage == 0)//大小不够一个扇区,如22
{
//当前页剩余的count个位置比NumOfSingle小,一扇区写不完
if (NumOfSingle > count)
{
temp = NumOfSingle - count;
//先写满当前扇区
SPI_Flash_Write_Page(pBuffer, WriteAddr, count);
WriteAddr = count;
pBuffer = count;
//再写剩余的数据
SPI_Flash_Write_Page(pBuffer, WriteAddr, temp);
}
else //当前扇区剩余的count个位置能写完NumOfSingle个数据
{
SPI_Flash_Write_Page(pBuffer, WriteAddr, NumByteToWrite);
}
}
else //NumByteToWrite > 4096 //大小够一个扇区,而且还超出一点点,如4098
{
//地址不对齐多出的count分开处理,不加入这个运算
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / 4096;
NumOfSingle = NumByteToWrite % 4096;
//先写完count个数据,为的是让下一次要写的地址对齐
SPI_Flash_Write_Page(pBuffer, WriteAddr, count);
//接下来就重复地址对齐的情况 */
WriteAddr = count;
pBuffer = count;
//把整数扇区都写了*/
while (NumOfPage--)
{
SPI_Flash_Write_Page(pBuffer, WriteAddr, 4096);
WriteAddr = 1096;
pBuffer = 4096;
}
//若有多余的不满一扇区的数据,把它写完
if (NumOfSingle != 0)
{
SPI_Flash_Write_Page(pBuffer, WriteAddr, NumOfSingle);
}
}
}
}总结:
/**********************************************************************
* Function Name : SPI_Flash_Read
* Description : 在指定地址开始读取指定长度的数据
* Input : *pBuffer:存储读出数据的指针
ReadAddr:开始读取的地址(24bit)
NumByteToRead:要读取的字节数(最大 16 x 1024 x 1024)
* Output : None
* Return : None
************************************************************************/
void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
{
u16 i;
SPI_FLASH_CS=0; //使能器件
SPI1_ReadWriteByte(CMD_W25X_ReadData); //发送读取命令
SPI1_ReadWriteByte((ReadAddr& 0xFF0000)>>16); //发送扇区地址的高8bit
SPI1_ReadWriteByte((ReadAddr& 0xFF00)>>8); //发送扇区地址的中间8bit
SPI1_ReadWriteByte( ReadAddr& 0xFF); //发送扇区地址的低8bit
for(i=0;i<NumByteToRead;i )
{
pBuffer[i]=SPI1_ReadWriteByte(0XFF); //循环读数
}
SPI_FLASH_CS=1; //取消片选
}
总结:
- 存储量大
- 不能任意访问字节地址数据,每一个存储单片不可以独立访问,最小读取单元是一个扇区
- 写入前是必须对写入的扇区做独立的擦除操作。擦除的目的是使存储单元的数据全为1
SD 卡(Secure Digital Memory Card)在我们生活中已经非常普遍了,控制器对 SD卡进行读写通信操作一般有两种通信接口可选,一种是 SPI接口,另外一种是 SDIO 接口。SDIO全称是安全数字输入/输出接口,多媒体卡(MMC)、SD卡、SD I/O 卡(专指使用SDIO 接口的一些输入输出设备)都可使用 SDIO 接口通讯。STM32F10x 系列控制器有一 个 SDIO 主机接口,它支持与上述使用 SDIO 接口的设备进行数据传输。