找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9574|回复: 9
打印 上一主题 下一主题
收起左侧

FLASH写入和读出的数据不一样,求助

[复制链接]
跳转到指定楼层
楼主
ID:87842 发表于 2015-8-7 14:47 | 显示全部楼层 回帖奖励 |倒序浏览 |阅读模式
用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;
}
      
}
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:87842 发表于 2015-8-10 10:10 | 显示全部楼层
我做了一部分测试,
输入        输出
0xa0        0x81
0xb0        0xa1
0xc0        0xc0
0xd0        0xc1
0x20        0x01
0x0a        0x03
0x0b        0x07
0x0c        0x09
0x0d        0x0b
0x0e        0x0d
还有就是输入0xf0~0xf9 ,0xfb~0xff,0x0f~0x09,0x0b~0x0f,,,输出都对
现象就是这样
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表