原创 AVR(Mega8)的study:9、IO口模拟SPI,读写FLASH

2008-3-12 20:16 4143 5 6 分类: MCU/ 嵌入式

       现在串行SPI接口的FLASH,许多厂商都在生产,一般用于扩展储存程序,读写的速度一般可达30多M,快的有50多M。本例讲一个使用Mega8的IO口模拟SPI读写Spansion生产的串行FLASH芯片(s25fl004a),大小为4Mbit,即是512K字节。想要PDFDATASHEET的朋友可以去21IC下。


程序如下:


/***************************************************


flash.h


***************************************************/


#ifndef _flash_
#define _flassh_


#define SI 4
#define SO 3
#define SCLK 5
#define CS 2
#define WP 1
#define PORT1 PORTB
#define PIN1 PINB
#define DDR1 DDRB
#define SO_0 PORT1&=~(1<#define SO_1 PORT1|=(1<#define SCLK_0 PORT1&=~(1<#define SCLK_1 PORT1|=(1<#define CS_0 PORT1&=~(1<#define CS_1 PORT1|=(1<#define WP_0 PORT1&=~(1<#define WP_1 PORT1|=(1<#define in_SI ((1<

uint8 Read_abyte(uint32 address);
void Write_adata(uint32 address,uint8 write_data);
void WriteEN(void);
uint8 Read_RDSR(void);
void WriteDisable(void);
void Sector_Erase(uint32 address);
void Write_string(uint8 *string,uint32 address,uint8 n);
void Bulk_Erase(void);
void DelayX100ms(uint32 x);


#endif


/*********************************************


flash.c


***********************************************/


#include
#include "mytype.h"
#include "flash.h"


/***************************************************************************************
读取一个字节  
*****************************************************************************************/
uint8 Read_abyte(uint32 address)
{
uint8 i;
uint8 read_data;
uint8 command;
command=0x03;//读取数据命令。
while((Read_RDSR())&0x01);//等待空闲。
CS_1;
SCLK_1;
CS_0;
SCLK_0;
for(i=0;i<8;i++)//写入命令。
{
SCLK_0;
if(0x80&command)//高位优先。
SO_1;
else
SO_0;
SCLK_1;
command<<=1;
}
for(i=0;i<24;i++)//写入24位读取地址值。
{
SCLK_0;
if(0x00800000&address)
SO_1;
else
SO_0;
SCLK_1;
address<<=1;
}
SO_0;
for(i=0;i<8;i++)//读取数据值。
{
SCLK_0;
;;
SCLK_1;
read_data<<=1;
if(in_SI)
read_data++;
}
SCLK_0;
CS_1;
return(read_data);
}


/***************************************************************************************
写入一个字节  
*****************************************************************************************/
void Write_adata(uint32 address,uint8 write_data)
{
uint8 i;
uint8 command;
while((Read_RDSR())&0x01);
WriteEN();
command=0x02;
CS_1;
SCLK_1;
CS_0;
SCLK_0;
for(i=0;i<8;i++)
{
SCLK_0;
if(0x80&command)
SO_1;
else
SO_0;
SCLK_1;
command<<=1;
}
for(i=0;i<24;i++)
{
SCLK_0;
if(0x00800000&address)
SO_1;
else
SO_0;
SCLK_1;
address<<=1;
}


for(i=0;i<8;i++)
{
SCLK_0;
if(0x80&write_data)
SO_1;
else
SO_0;
SCLK_1;
write_data<<=1;
}
SCLK_0;
CS_1;
}


/***************************************************************************************
写入写使能命令
*****************************************************************************************/
void WriteEN(void)
{
uint8 i;
uint8 command;
command=0x06;//使能命令。
CS_1;
SCLK_1;
CS_0;
for(i=0;i<8;i++)//写入命令。
{
SCLK_0;
if(0x80&command)
SO_1;
else
SO_0;
SCLK_1;
command<<=1;
}
SCLK_0;
CS_1;
}



/***************************************************************************************
写入写禁止命令
*****************************************************************************************/
void WriteDisable(void)
{
uint8 i;
uint8 command;
command=0x04;//写入禁止命令。
CS_1;
SCLK_1;
CS_0;
SCLK_0;
for(i=0;i<8;i++)//写入命令。
{
SCLK_0;
if(0x80&command)
SO_1;
else
SO_0;
SCLK_1;
command<<=1;
}
SCLK_0;
CS_1;
}
/***************************************************************************************
写入段擦除使能命令
*****************************************************************************************/
void Sector_Erase(uint32 address)
{
uint8 i;
uint8 command;
WriteEN();
while((Read_RDSR())&0x01);
command=0xd8;//段擦除命令。
CS_1;
SCLK_1;
CS_0;
SCLK_0;
for(i=0;i<8;i++)
{
SCLK_0;
if(0x80&command)
SO_1;
else
SO_0;
SCLK_1;
command<<=1;
}
for(i=0;i<24;i++)
{
SCLK_0;
if(0x00800000&address)
SO_1;
else
SO_0;
SCLK_1;
address<<=1;
}
SCLK_0;
CS_1;
}


/***************************************************************************************
写入片擦除使能命令
*****************************************************************************************/
void Bulk_Erase(void)
{
uint8 i;
uint8 command;
command=0xc7;//片擦除命令。
while((Read_RDSR())&0x01);
WriteEN();
CS_1;
SCLK_1;
CS_0;
for(i=0;i<8;i++)
{
SCLK_0;
if(0x80&command)
SO_1;
else
SO_0;
SCLK_1;
command<<=1;
}
SO_0;
SCLK_0;
CS_1;
}


/***************************************************************************************
 延时X/100ms
*****************************************************************************************/
void DelayX100ms(uint32 x)
{
 uint32 i;
 while(x--)
  {
   i="1275";
   while(i--);
  }
}


/***************************************************************************************
读取状态寄存器。
*****************************************************************************************/
uint8 Read_RDSR(void)
{
uint8 i,j;
uint8 read_data;
uint8 command;
command=0x05;
j=3;
CS_1;
SCLK_1;
CS_0;
SCLK_0;
for(i=0;i<8;i++)
{
SCLK_0;
if(0x80&command)
SO_1;
else
SO_0;
SCLK_1;
command<<=1;
}
SO_0;
for(i=0;i<8;i++)
{
SCLK_0;
j=0;
SCLK_1;
read_data<<=1;
if(in_SI)
read_data++;
}
SCLK_0;
CS_1;
return(read_data);
}
/**************************************************************
写入一串字节,芯片最多支持写入256个字节。
****************************************************************/
void Write_string(uint8 *string,uint32 address,uint8 n)
{
uint8 i;
uint8 command;
while((Read_RDSR())&0x01);
WriteEN();
command=0x02;
CS_1;
SCLK_1;
CS_0;
SCLK_0;
for(i=0;i<8;i++)
{
SCLK_0;
if(0x80&command)
SO_1;
else
SO_0;
SCLK_1;
command<<=1;
}
for(i=0;i<24;i++)
{
SCLK_0;
if(0x00800000&address)
SO_1;
else
SO_0;
SCLK_1;
address<<=1;
}
while(n--)
{
for(i=0;i<8;i++)
{
SCLK_0;
if(0x80&(*string))
SO_1;
else
SO_0;
SCLK_1;
(*string)<<=1;
}
string++;
}
SCLK_0;
CS_1;
}
/**************************************************************
写保护
****************************************************************/
void Write_Protect()
{
uint8 i;
uint8 command;
uint8 write_data;
while((Read_RDSR())&0x01);
WriteEN();
command=0x01;
write_data=0x9c;
CS_1;
SCLK_1;
CS_0;
SCLK_0;
for(i=0;i<8;i++)
{
SCLK_0;
if(0x80&command)
SO_1;
else
SO_0;
SCLK_1;
command<<=1;
}
for(i=0;i<8;i++)
{
SCLK_0;
if(0x80&write_data)
SO_1;
else
SO_0;
SCLK_1;
write_data<<=1;
}
SCLK_0;
CS_1;
}


/****************************************************


main.c


********************************************************/


#include
#include "mytype.h"
#include "uart.h"
#include "flash.h"


uint8 table[16]={"0123456789abcdef"};
void DelayXms(unsigned int x)//延迟xms
{
unsigned int m;
 while(x--)
  {
   m="1275";
   while(m--);
  }
}



void main(void)
{
uint8 i;
uint8 j;
uint8 string[25]={0};
DDR1=((1<Uart_init();//串口初始化。
WP_1;//屏蔽写保护。
Sector_Erase(0x00000005);//擦除第一段。
Write_adata(0x00000000,0xaa);//向地址0x000000写入0xaa
Write_adata(0x0000000f,0xbb);//向地址0x00000f写入0xaa
for(i=0;i<16;i++)//读取地址0x000000~0x00000f上的值,并发到串口。
{
j=Read_abyte(i);
Send_abyte(table[j/16]);
Send_abyte(table[j%16]);
Send_abyte(' ');
}
}


由于没有带硬件回家,无法给出调试图片,有了再发。


程序包:点击下载

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户1116930 2009-10-28 13:12

模拟SPI的最基本的一个过程应该写成子函数,其他函数都调用它,而不用每个函数重复的模拟SPI的传输过程
相关推荐阅读
用户131149 2008-06-29 19:55
080629写了个按键的程序(扫描方式)
        刚刚写了个5个按键,扫描方式检测的。烧写进实验板后发现按起来不够灵敏,常常是按N多次才响应一次,高手帮忙看看什么问题。程序包在下面附件里,打算再用中断方式写一个看看。         ...
用户131149 2008-06-28 14:37
080628我的开发板,有PP
          得空拍了张图,大家可以看看!        ...
用户131149 2008-06-28 11:38
080628我的第一个ARM2410程序(2)
             昨天说了一下工程建立、编译链接及得到BIN文件,现在只要烧写到SDRAM里面就可以跑起来看看现象了。烧写前准备工作要做好。                1.先将板的串口线、...
用户131149 2008-06-28 01:34
080627成功的烧写到板上,跑了我的第一个程序(1)
              今天晚上花了点时间将昨天写好的程序,成功的下到了板上,跑了起来,迈出了实验的第一步。其中用USB下载花了我点时间来装驱动。现在将我跑的第一个程序过程给大家分享下。     ...
用户131149 2008-06-27 00:10
关于IO口模拟SPI
               最近有朋友问到IO口模拟SPI的问题,其实光模拟来说,就时序问题,读取和写入一个字节的时序。                   首先选4个IO口,作模拟用,分别模拟CS...
用户131149 2008-06-26 22:51
080626Make成第一个实验程序
        经过近两天对ADS和2410用户手册的学习,终于搞定了一个可以烧到板上的实验程序。由于板现在不在宿舍,所以还无法搞定。明天看能不能烧到板上跑起来。程序是从网上淘的一个,做了小小修改,以...
EE直播间
更多
我要评论
1
5
关闭 站长推荐上一条 /3 下一条