您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 公司方案 > 基于mega16和M45PE16的SPI存储扩展与Proteus仿真
基于mega16和M45PE16的SPI存储扩展与Proteus仿真对mega16进行外部存储扩展,用M45PE16作为flash存储的扩展,两设备通过SPI接口进行通信。用proteus进行仿真,结果如图:在SPIDebug-Monitormode窗口我们看到这个程序执行的过程。大概分为3部分:1,激活M45PE162,把数据写入M45PE163,从M45PE16中读出上步写入的数据源代码如下,M45PE16简称为M了:/*m45pe16.h头文件,定义了一些常用的东西,在datasheet里都有。前面一堆是对M进行操作的指令,后面的DL,drivenlow,把ss拉低。DH,drivenhigh,把ss拉高。WAIT,等,等SPI口的传输完毕(每传一个byte就要加个WAIT)。*/#ifndefM45PE16_H_#defineM45PE16_H_#defineWREN0X06#defineWRDI0X04#defineRDID0X9F#defineRDSR0X05#defineREAD0X03#defineFAST_READ0X0B#definePW0X0A#definePP0X02#definePE0XDB#defineSE0XD8#defineDP0XB9#defineRDP0XAB#defineDHPORTB|=(14)#defineDLPORTB&=~(14)#defineWAITwhile(!(SPSR&(1SPIF)))#endif/*M45PE16_H_*//*memoryspi.c主程序文件。具体的操作的含义注释里有。*/#includeavr/io.h#includeavr/interrupt.h#includeavr/delay.h#includem45pe16.h#definebyteunsignedchar#definewordunsignedintbytei;byteinit_m45pe16(void){//上电后的初始化M,这个是必须的,在datasheet里有一句话,在开始任何操作之前要有一个fallingedge。DL;DH;return0;}voidinit_spimaster(void){//初始化SPI接口的master设备DDRB|=(14)|(15)|(17);//除了MISO都设为输出SPCR|=(1SPE)|(1MSTR)|(1SPR0);//使能spi,作为master,分频SPSR=0x00;}bytespi_mtxd(bytedata){//在一个操作周期里传一个byte。一个操作周期,意思是spi接口的ss从拉低,传输,到拉高的一个过程。我们知道在ss为低时是可以传很多byte的DL;//拉低,可以传数据了SPDR=data;//对SPDR赋值,自动启动传输WAIT;//等待传输完成DH;//拉高,不能再传了returndata;}voidspi_wait(void){WAIT;}//这个没啥用了,调用这个函数和写个WAIT在功能上一样。byteflash_pw(byte*data,byten){//pagewrite,写入一页。过程就是:1,writeenable,注意这个小过程,是要拉低,wren,拉高,最后必须要拉高才行;2,拉低,pagewrite,3byte的地址,数据,拉高。那个数据只要多于0个字节就行。bytei;//DL;SPDR=RDSR;WAIT;SPDR=0x00;WAIT;PORTA=SPDR;DH;return1;spi_mtxd(WREN);//writeenable_delay_ms(10);DL;SPDR=PW;WAIT;//pagewriteSPDR=0x1f;WAIT;//address是由下面的3个byte连起来构成的。直接传就是,M可以理解,虽然mega16不知道它自己在说些什么。SPDR=0x00;WAIT;SPDR=0x00;WAIT;for(i=0;in;i++){//这就是那堆数据了。连着传就是了,就是,ss一直为低SPDR=data[i];WAIT;}DH;//传输完毕,把ss拉高以示结束。必须要的这个。return0;}byteflash_read(byte*data,byten){//读取。这个还好说些。先拉低,1,给M一个读指令。2,3byte的地址,3,读数据,最后拉高。bytei;DL;//拉低SPDR=READ;WAIT;//传由3个byte构成的地址SPDR=0x1f;WAIT;SPDR=0x00;WAIT;SPDR=0x00;WAIT;for(i=0;in;i++){//读数据。注意spi中,从机不能主动给主机传数据,只能主机提供时钟,在代码上,就是:主机随便给从机一个byte,交换回从从机那边过来的数据。从机对过来的那个垃圾byte置之不理。SPDR=0xf0;WAIT;//主机送过一个0xf0,来和从机交换data[i]=SPDR;//交换完成,现在SPDR里装的就是从从机那边过来的数据了!}DH;//拉高,结束传输。return0;}intmain(void){DDRA=0XFF;bytearrled[10];//等着传过去bytearrget[10];//用来接收//bytedatatemp;bytei;for(i=0;i10;i++){arrled[i]=i;}init_spimaster();//初始化spiinit_m45pe16();//初始化Msei();//没用_delay_ms(1000);//嗯。。。有时候我们要等所有的设备都初始化完毕flash_pw(arrled,10);//把数组指针传过去,告诉函数从这个指针指的东西里传10个字节_delay_ms(1000);//等都写好了再读,其实应该读那个M里的状态,是RDSR?里面有个“正忙着写入”的标志。留读者自己去玩玩了。flash_read(arrget,10);//读,读10个。放到指针指的东西里面for(i=0;i10;i++){//反应到io口,看自己弄得对不对了?PORTA=arrget[i];_delay_ms(500);}while(1){//TODO::Pleasewriteyourapplicationcode}}看运行结果吧:竖线的右边是数据的“来龙去脉”,深蓝的箭头是主机到从机的,浅蓝的箭头是从机到主机的。单线的是指令,双线的是地址,没线的是数据。上半部分是写入过程,下半部分是读取过程。大概就这些了。没什么纠错啊什么的,那个读出写入的也没给地址,还有很多可以做的更地道的地方其实。可以在读出写入的函数里加上个小数组,存着想要放在那个地址里,的地址。可以返回个小数组,存着现在末尾的地址。可以弄个全局变量等等了。自己对自己要干的事情必定是最清楚的啦~byPurepromise
本文标题:基于mega16和M45PE16的SPI存储扩展与Proteus仿真
链接地址:https://www.777doc.com/doc-2570853 .html