用51模拟SPI写FLASH,数据读出和写入不同。附上代码:
#include <reg52.h>
#include <intrins.h>
#include <stdio.h>
#define uchar unsigned char
unsigned char ID1,ID2;
unsigned char BUSY; //判忙碌
unsigned long Addre24; //24位的Flash地址
// ----W25X系统Flash读写---SUNYA注----
sbit CS = P3^7; //选通
sbit DIO = P3^6; //单片机输出
sbit DO = P3^5; //FLASH输出
sbit SCLK = P3^4; //时钟
#define W25X_ReadStatus 0x05 //读状态寄存器
#define W25X_WriteStatus 0x01 //写状态寄存器
#define W25X_ReadDATA8 0x03 //普读_数据
#define W25X_FastRead 0x0B //快读_数据
#define W25X_Write 0x02 //写_数据_0~255个字节
#define W25X_S_Erase 0x20 //扇区擦除4KB
#define W25X_B_Erase 0xD8 //块区擦除64KB
#define W25X_C_Erase 0xC7 //整片格式化
#define W25X_PowerDown 0xB9 //待机
#define W25X_PowerON_ID 0xAB //开机或是读ID
#define W25X_READ_ID 0x90 //读ID
#define W25X_JEDEC_ID 0x9F //十六位的JEDEC_ID
#define W25X_WriteEnable 0x06 //写充许
#define W25X_WriteDisable 0x04 //写禁止
#define W25X_BUSY 0x01 //FLASH忙
#define W25X_NotBUSY 0x00 //FLASH闲 这是自定义的
//*********************************************** OK
void Send_OneByte(unsigned char DATA8) //从SPI发8位数
{ //上升沿写入
unsigned char x;
SCLK=0;
for (x=0;x<8;x++)
{
// DATA8=DATA8<<1;
SCLK=0;
_nop_();
if(DATA8&0x80)
DIO=1;
else
DIO=0;
SCLK=1;
DATA8=DATA8<<1;
_nop_();
}
}
//*********************************************** OK
unsigned char Read_OneByte(void) //从SPI收8位数
{ //下降沿输出
unsigned char DATA8;
unsigned char x;
// DATA8=0;
// DO=0;
SCLK=1;
for (x=0;x<8;x++)
{
SCLK=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SCLK=0;
DATA8=(DATA8<<1)|DO;
}
return (DATA8);
}
//*************** 写允许 **************************** OK
void WriteEnable (void)
{
CS=0;
Send_OneByte(W25X_WriteEnable);
CS=1;
}
//*************** 写禁止 **************************** OK
void WriteDisable (void)
{
CS=0;
Send_OneByte(W25X_WriteDisable);
CS=1;
}
//***************判BUSY********************************
unsigned char W25X_BUSY_OrNot (void) //在读和写之前得先判断FLASH是否BUSY
{ //BUSY的原因是擦除,或是连续读写
unsigned char k; //如果没有以上方式,不必判定可以写读
// PCA0CPH2 = 0x00;
SCLK=1;
_nop_();
CS=0;
Send_OneByte(W25X_ReadStatus); //读状态寄存器
k=Read_OneByte(); //读一个字节
k=k&0x01;
CS=1;_nop_();
SCLK=1;
if(k)return (W25X_BUSY);
else return (W25X_NotBUSY);
} //end of check BUSY
//***********************************************
void W25X_Flash_Byte_Write(unsigned long Addre24,unsigned char dat)
{
uchar addr1,addr2,addr3;
addr3=Addre24>>16;
addr2=Addre24>>8;
addr1=Addre24;
while(W25X_BUSY_OrNot () ); //判BUSY 等到Flash闲才能操作
WriteEnable(); //写允许
//把地址拆开来
CS=0;
Send_OneByte(W25X_Write); //命令
Send_OneByte(addr3);
Send_OneByte(addr2);
Send_OneByte(addr1);
Send_OneByte(dat);
CS=1;
WriteDisable ();
} //写FLASH结束
//***********************************************
unsigned char W25X_Flash_Byte_Read (unsigned long Addre24) //从Flash里读出小于256字节数
{
unsigned char temp;
uchar addr1,addr2,addr3;
addr3=Addre24>>16;
addr2=Addre24>>8;
addr1=Addre24;
// while(W25X_BUSY_OrNot ()); //判BUSY
WriteEnable();
CS=0;
Send_OneByte(W25X_ReadDATA8);//命令读
Send_OneByte(addr3);
Send_OneByte(addr2);
Send_OneByte(addr1);
temp=Read_OneByte();
CS=1;
WriteDisable ();
return temp;
}
//**************片擦除 (MAX_80S)****************** OK
void W25X_ChipErase(void)
{
WriteEnable(); //写允许
SCLK=1;
CS=0;
Send_OneByte(W25X_C_Erase);//整片擦除命令
CS=1; //从CS=1时开始执行擦除
}
//*************** 4K扇擦除************************ OK
void W25X_SectorErase(unsigned long Addre24) //擦除资料图示的4KB空间
{
unsigned char Addre3;
unsigned char Addre2;
unsigned char Addre1;
WriteEnable(); //写允许
Addre1=Addre24;
Addre24=Addre24>>8;
Addre2=Addre24;
Addre24=Addre24>>8;
Addre3=Addre24; //把地址拆开来
SCLK=1;
CS=0;
Send_OneByte(W25X_S_Erase);//整扇擦除命令
Send_OneByte(Addre3);
Send_OneByte(Addre2);
Send_OneByte(Addre1);
CS=1;
}
//*************** 64K页/块擦除************************* OK
void W25X_BlockErase(unsigned long Addre24) //擦除资料图示的64KB空间
{
unsigned char Addre3;
unsigned char Addre2;
unsigned char Addre1;
WriteEnable(); //写允许
Addre1=Addre24;
Addre24=Addre24>>8;
Addre2=Addre24;
Addre24=Addre24>>8;
Addre3=Addre24; //把地址拆开来
SCLK=1;
CS=0;
Send_OneByte(W25X_B_Erase);//整扇擦除命令
Send_OneByte(Addre3);
Send_OneByte(Addre2);
Send_OneByte(Addre1);
CS=1;
}
//******************************************************** OK
void Delay_ms(unsigned int ms) //ms级延时
{
unsigned char i;
while(ms--)
for(i=0;i<110;i++);
}
void W25X_Flash_ID_Read ()
{
while(W25X_BUSY_OrNot ()); //判BUSY
CS=0;
Send_OneByte(W25X_READ_ID);
Send_OneByte(0x00);
Send_OneByte(0x00);
Send_OneByte(0x00);
ID1=Read_OneByte();
ID2=Read_OneByte();
CS=1;
}
unsigned char W25X_Status ()
{
unsigned char k;
SCLK=1;
_nop_();
CS=0;
Send_OneByte(W25X_ReadStatus); //读状态寄存器
k=Read_OneByte(); //读一个字节
CS=1;
return k;
}
void W25X_Flash_Status_Write()
{
while(W25X_BUSY_OrNot () ); //判BUSY 等到Flash闲才能操作
WriteEnable(); //写允许
SCLK=1;
CS=0;
Send_OneByte(W25X_WriteStatus); //命令
Send_OneByte(0x80);
CS=1;
}
void main()
{
TMOD=0X20;
TH1=0XFD;
TL1=0XFD;
TR1=1;
REN=1;
SM0=0;
SM1=1;
// W25X_ChipErase(); //片擦除
W25X_SectorErase(0); //4K擦除
//// W25X_BlockErase (Addre24); //64K块擦除
W25X_Flash_Byte_Write(0,0xaa); //存储数据
// while(W25X_BUSY_OrNot ());
while(1)
{
// W25X_Flash_Byte_Write(0xaaaaaa,0xaa);
Delay_ms(100);
// CS=0;
// Send_OneByte(0xaa);
// while(!RI);
// RI=0;
SBUF=W25X_Flash_Byte_Read (0);
while(!TI);
TI=0;
}
}
|