⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spi_flash_driver.c

📁 基于SPI接口的Flash读写程序集(flash型号 AT45DB041B)
💻 C
字号:
/*==================================================================
// 文件名: SPI_Flash_Driver.c
// 作  者: 三生石
// 日  期: 2008/06/05
// 描  述: SPI串口Flash烧写读取操作程序集
//
// 参  考: 1.flash型号;AT45DB041B
		   2.晶振:11.0592MHZ
		   3.指令周期:≈1us
		   4.SPI MODE:0; 在此模式下:SCK=0为空闲;时钟上升沿读取,下降沿写
		   5.除中间函数,完整功能函数出口处SCK都为低
		   
// 版  本:
//      2008/06/05      First version    
=====================================================================*/

#include <reg52.h>
#include <intrins.h>

typedef unsigned char uchar;
typedef unsigned int  uint;

/*=======接口配置文件=====*/
sbit _CS = P1^2; //Chip select pin
sbit SCK = P2^5; //Serial Data Clock (SCK)
sbit SI  = P2^6; //Serial Data Input (SI)
sbit SO  = P2^7; //Serial Data Output
/*=======命令宏===================*/
#define R_PAGE 0xD2	    //按指定页读取 spi mode 0
#define R_BUSY 0xD7		//读状态命令

#define W_BUF1 0X84		//写BUF1
#define W_BUF2 0x87		//写BUF2
#define W_BUF1_MEM 0x83	//Buffer to Main Memory page program with built-in Erase
#define W_BUF2_MEM 0x86


uchar xdata Buffer[32]={/*--  文字:  徐  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
0x10,0x88,0xC4,0x73,0x22,0x20,0x10,0x28,0x24,0xE3,0x24,0x28,0x18,0x30,0x10,0x00,
0x01,0x00,0xFF,0x00,0x20,0x11,0x0D,0x49,0x81,0x7F,0x01,0x05,0x09,0x39,0x10,0x00};
/*========================================================================
// 函数: void SendByte(uchar cmd)
// 描述: 发送1字节8位的命令,或者地址
// 参数: 要发送的字节数据 
// 返回: 无
// 备注: 
// 版本:
//      2008/06/05      First version
		2008/06/10		Ver1.1 使用掩码来得到数据从高位到低位的bit值,
								使程序清晰简洁,提高了可读性和运行效率
//======================================================================*/
void SendByte(uchar Data)
{
	uchar i;
	uchar mask = 0x80; /*判断Data某位为1或0的掩码*/

	for(i=8;i>0;i--)
	{
		SI  = (bit)(Data&mask);	/*在时钟上升沿到来前将数据发出*/
		SCK = 0;
		SCK = 1;
		mask>>= 1;
	}
}
/*========================================================================
// 函数: void ReceiveByte(uint *SaveAdd)
// 描述: 接收1字节8位的数据
// 参数: 要发送的字节数据 
// 返回: 无
// 备注: 
// 版本:
//      2008/06/05      First version
//======================================================================*/

/*========================================================================
// 函数: void SendPageAdd(uint PageAdd)
// 描述: 发送11位的目标页地址
// 参数: PageAdd:目标页地址 
// 返回: 无
// 备注: 
// 版本:
//      2008/06/05      First version

//======================================================================*/
void SendPageAdd(uint PageAdd)
{
	uchar i;
	uint mask = 0x0400; /*判断PageAdd某位为1或0的掩码*/	
	for(i=11;i>0;i--)
	{
		
		SI = (bit)(PageAdd&mask); /*在时钟上升沿到来前将数据发出*/		
		SCK=0;
		SCK=1;
		mask>>= 1;
	}
}
/*========================================================================
// 函数: void SendBFAdd(uchar PageAdd)
// 描述: 发送9位目标buffer或页中起始字节地址
// 参数: PageAdd:目标地址 
// 返回: 无
// 备注: 因为buffer和页中只用到前面256字节,所以地址最高位都为:0 
// 版本:
//      2008/06/05      First version
	
//======================================================================*/
void SendBFAdd(uchar BFAdd)
{
	uchar i;
	uchar mask = 0x80; /*判断Data某位为1或0的掩码*/

	SI  = 0;
	SCK = 0;
	SCK = 1;

	for(i=8;i>0;i--)
	{
		SI  = (bit)(BFAdd&mask);	/*在时钟上升沿到来前将数据发出*/
		SCK = 0;
		SCK = 1;
		mask>>= 1;
	}
}

/*========================================================================
// 函数: void PageRead(uint PageAdd,uchar BA)

// 描述: 读取指定页中指定起始字节的数据指令

// 参数: PageAdd:要读目标页地址;BA:目标页中要读的字节地址;
 
// 返回: 无

// 备注: 1.PageAdd为10位;BA这里被设置为8位(只用到前面256字节);
		 2.在SPI Mode 0下的读;
// 版本:
//      2008/06/05      First version
//======================================================================*/
void PageRead(uint PageAdd,uchar BA)
{
	uchar i,j;
	uchar RecData=0;

	
	SCK = 0; //模式0下,在片选信号有效前,时钟应为低
	_CS = 0; 

	/*发送页读命令*/
	SendByte(R_PAGE);

	/*发送4位保留位*/
	for(i=0;i<4;i++)
	{
		SCK = 0;_nop_();
		SI  = 0;//应该可以去掉,时序满足要求,数据无关!资料上说推荐写0;
		SCK = 1;_nop_();
	}
	/*发送10位页地址*/
	SendPageAdd(PageAdd);

	/*发送9位字节地址*/
	SCK = 0;
	_nop_();
	SI  = 0;//BA最高位为0;
	SCK = 1;//准备好数据后,上升沿跳变,使flash可以接收
	_nop_();
	SendByte(BA);

	/*发送32位无关位*/
	for(i=0;i<32;i++)
	{
		SCK = 0;
		_nop_();
		SI  = 0;
		SCK = 1;
		_nop_();
	}
/*=============指令发送完毕,开始接受数据============*/
	SO = 1;//初始化接收端口
	for(i=0;i<32;i++)
	{
		for(j=0;j<8;j++)
		{
			SCK = 0;//数据在SCK从1到0跳变后已经准备好了,下面开始接收
			_nop_();
			RecData=(RecData<<1)|SO;//把SO上的数据位移位到接受数据的相应位;
			SCK = 1;//拉高,等待下次跳变
			_nop_();
		}
		Buffer[i]=RecData;//接收到的数据放到缓冲区
		RecData = 0;
	}
	/*读写操作结束*/
	SCK = 0;
	_CS = 1;
}
/*========================================================================
// 函数: void WaitFlashReady(void)
// 描述: 等待存储器就绪状态
// 参数: 无
// 返回: 无
// 备注: The user can continuously poll bit 7 of the status register 
		 by stopping SCK at a low level once bit 7 has been output. 
		 The status of bit 7 will continue to be output on the SO pin, 
		 and once the device is no longer busy, the state of SO will 
		 change from 0 to 1.
// 版本:
//      2008/06/05      First version
//======================================================================*/
void WaitFlashReady(void)
{
	SCK = 0;
	_CS = 0;
		
	SendByte(R_BUSY);

	SCK = 0; 		//把时钟信号线拉低,然后一直查询D7位
	while(SO!=1);	//直到bit 7变为ready,否则一直等待

	_CS = 1;
}
/*========================================================================
// 函数: void BufferWrite(uchar cmd,uchar BuffAdd,uchar* DataAdd)
// 描述: 写buffer
// 参数: cmd:对那个buffer写,BuffAdd:flash缓冲开始地址,DataAdd:传输数据的起始地址// 返回: 无
// 备注: 
// 版本:
//      2008/06/06      First version
//======================================================================*/
void BufferWrite(uchar cmd,uchar BuffAdd,uchar* DataAdd)
{
	uchar i;

	SCK = 0;
	_CS = 0;

	SendByte(cmd);
	for(i=0;i<15;i++)
	{
		SCK = 0;
		_nop_();
		SI  = 0;
		SCK = 1;
		_nop_();
	}
	SendBFAdd(BuffAdd);

	/*开始发送数据*/
	for(i=0;i<32;i++)		//i不能为255,溢出后判断无效
	{
		SendByte(*DataAdd++);
	}

	/*SendByte(*DataAdd);		//最后一字节单独发送  */

	SCK = 0;
	_CS = 1;
}
/*========================================================================
// 函数: void Buffer_To_Mem(uchar cmd,uint PageAdd)
// 描述: 写buffer
// 参数: cmd:从哪个buffer写,PageAdd:目标页地址
// 返回: 无
// 备注: 
// 版本:
//      2008/06/06      First version
//======================================================================*/
void Buffer_To_Mem(uchar cmd,uint PageAdd)
{
 	uchar i;

	SCK = 0;
	_CS = 0;
	/*发送命令*/
	SendByte(cmd);
	/*4个保留位*/
	for(i=0;i<4;i++)
	{
		SCK = 0;_nop_();
		SI  = 0;
		SCK = 1;_nop_();
	}
	/*发送目标页地址*/
	SendPageAdd(PageAdd);
	/*9个无关位*/
	for(i=0;i<9;i++)
	{
		SCK = 0;_nop_();
		SI  = 0;
		SCK = 1;_nop_();
	}
	/*启动写命令*/
	SCK = 0;
	_CS = 1;
}
/*========================================================================
// 函数: void ProgramFlash(uint PageNum)
// 描述: 烧字库
// 参数: PageNum:需要编程的页数
// 返回: 无
// 备注: 
// 版本:
//      2008/06/06      First version
//======================================================================*/
extern DelayMs(uchar n);
extern uchar code Buffer2[32];

void TestFlash(void)
{
	uchar i;
	uchar* p;

	p = Buffer;

	BufferWrite(W_BUF1,0,Buffer2);
	Buffer_To_Mem(W_BUF1_MEM,0);

	for(i=0;i<32;i++)
	{
		*p=0x00;
		p++;
	}

	/*WaitFlashReady();*/
	DelayMs(22);
			
	PageRead(0,0);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -