- 打卡等级:以坛为家II
- 打卡总天数:493
- 最近打卡:2025-05-01 08:31:58
荣誉版主
- 积分
- 3476
|
本帖最后由 浦江一水 于 2024-6-30 21:57 编辑
基于STC32G12K128实验箱V9.62_实验之片外部Flash存储器读写
W25Qxx芯片Flash存储器,存储容量大,接口简单,在单片机项目中被广泛使用。
STC32G12K128实验箱V9.62,搭载了一片W25Q40的外部Flash存储器芯片,容量为512K字节,扇区大小为256字节。
学习和掌握此芯片的读写,无疑是必备的基本功了。
然而此类存储器与STC内部EEPROM的读写有一个共同特点,那就是可以将1写成0,而不能将0写成1,也就是只能通过擦除,将0变成1,且擦除必须是按整扇区进行。
因此,读写时要倍加小心注意了,要避免后写入数据时,将前写入的同扇区数据清除掉。
本实验尝试优化算法,以实现在芯片地址范围内,任意地址和长度的写入和读出,自动判空和识别是否需要擦除扇区,以确保写入数据不被无意擦除。
本实验依然采用官方例程的对话方式, 用实验箱串口2与上位机通讯(不使用实验箱的显示设备),实际对话操作如截图所示:
主程序如下:
//********************************************************************************
// 名称: Main.C 通过串口2 STC32G12K128 读写外部Flash存储器
// 基于: STC32G12K128 V9.62 实验箱
// 实验: .../STC-USB-Link1D仿真器调试...
// 编程: 浦晓明(浦江一水) 2023-12-14
//********************************************************************************
#include "STC32G_SYS.H"
#include "STC32G_UART.H"
#include "W25Q40.H"
/** 全局变量说明 设为全局,便于调试观察... **************/
u16 W25Q40_ID; //设备ID
u32 T_Addr; //目标地址
u8 R_Buf[256]; //读取数据缓存
extern u8 F_Buf[256]; //扇区缓存
//========================================================================
// 函数: void delay_ms(unsigned int ms)
// 描述: 毫秒级延时函数。 @22.1184MHz
// 参数: ms,要延时的ms数,自动适应主时钟.
//=====================================================================
void delay_ms(unsigned int ms)
{ unsigned int i;
do{ i = MAIN_Fosc / 6000;
while(--i);
} while(--ms);
}
/**** 主函数入口 ************************/
void main(void)
{ u8 ch,n,ts=1;
u16 i,len;
SYS_Init(); //系统初始化
UART2_Init(1,1,115200); //IO切换1,模式1,波特率115200
W25Q40_Init();
W25Q40_ID=W25Q40_ReadID(); //读取ID(验证设备是否存在)
// printf("STC32G UART2 Test Printf(x)...\r\n"); //测试 printf 发送一个字符串
// UART2_SendStr("UART2_SendStr(x)...OK!\r\n"); //测试字符串发送函数:UART2_SendStr()...
//主循环...
while(1)
{ if(ts)
{ //实验操作提示...
printf("\r\n** STC32G单片机对外部Flash_W25Q40读写实验 **\r\n");
printf("- 实验箱_USART2(RS232)串口连接PC机串口.波特率115200,8,1,N\r\n");
printf("- PC机使用串口助手,串口命令例\xfd举如下:(无需回车换行)\r\n");
printf("E 0x000020 --> 删除\xfd字节地址0x000020所在扇区.\r\n");
printf("W 0x000020 ABCDE12345 --> 写入地址0x000020字符串ABCDE12345\r\n");
printf("R 0x000020 10 --> 读出地址0x000020指定长度字节.\r\n");
printf("读写地址范围: 0x000000 -- 0x07FFFF (512K)\r\n\r\n");
ts=0;
}
delay_ms(10);
if(RX2_Cnt>=10) //串口2收到指令信息...
{ for(i=0;i<8;i++)
{ if((RX2_Buf >= 'a') && (RX2_Buf <= 'z'))RX2_Buf -= 0x20; } //小写转大写
if(((RX2_Buf[0]=='E')||(RX2_Buf[0]=='W')||(RX2_Buf[0]=='R'))&&(RX2_Buf[1]==' '))
{ //解析地址...
ch=RX2_Buf[4]-0x30; if(ch>9)ch=ch-0x07; T_Addr=(u32)ch;
ch=RX2_Buf[5]-0x30; if(ch>9)ch=ch-0x07; T_Addr=16*T_Addr+(u32)ch;
ch=RX2_Buf[6]-0x30; if(ch>9)ch=ch-0x07; T_Addr=16*T_Addr+(u32)ch;
ch=RX2_Buf[7]-0x30; if(ch>9)ch=ch-0x07; T_Addr=16*T_Addr+(u32)ch;
ch=RX2_Buf[8]-0x30; if(ch>9)ch=ch-0x07; T_Addr=16*T_Addr+(u32)ch;
ch=RX2_Buf[9]-0x30; if(ch>9)ch=ch-0x07; T_Addr=16*T_Addr+(u32)ch;
//解析指令
switch(RX2_Buf[0])
{ case 'E': W25Q40_SectorErase(T_Addr);
printf("OK! Sector Erase.\r\n");
break;
case 'W': n=RX2_Cnt-11; //取指令数据长度
W25Q40_Write(T_Addr,RX2_Buf+11,n);
printf("OK! Write %2d Byte.\r\n",n);
break;
case 'R': n=RX2_Cnt-11; len=0; //取指令数据长度
for(i=0;i<n;i++) //取需要读取的数据长度
{ ch=RX2_Buf[11+i];
if((ch>='0')&&(ch<='9'))len=10*len+RX2_Buf[11+i]-'0';
else break;
}
if(len>256)len=256;
W25Q40_Read(T_Addr,R_Buf,len);
printf("OK! Read out %3d Bytes:\r\n",len);
for(i=0;i<len;i++)UART2_SendChar(R_Buf);
UART2_SendChar(0x0D); UART2_SendChar(0x0A);
break;
}
} else { printf("指令错误!!\r\n"); ts=1; }
RX2_Cnt=0;RX2_Buf[0]=0; //计数清零
}
}
}
相关存储器读写算法的W25Q40.C/H文件, 包含于工程包中,供有兴趣的爱好者参考。
07-TestW25Q40.rar
(45.76 KB, 下载次数: 99)
|
|