STC89C52读写存储模块W25Q备忘

接线

        电源模块输出3.3v电源  W25Q32接P0口上拉3.3V  用4个1k电阻限流

/*模式0*/
sbit CS=P0^0;//SS
sbit MISO=P0^1;//从机DO
sbit CLK=P0^2;
sbit MOSI=P0^3;//..DI

      LCD1602用i2c转接板接P1^6(SCL) P1^7(SDA)

注意:电源需要首先接到最小系统板给51和1602供电再接到电源模块5v插针给电源模块供电(没错 这样也行。。) 开始先接电源模块再通过插针给最小系统和1602供电不知道为啥1602不显示

乱糟糟的图:

代码备忘

main.c

#include "regx52.h"
#include "intrins.h"
#include "delayms.h"
//#include "stdio.h"
#include "lcd1602i2c.h"
#include "W25Q32.h"

#define uchar unsigned char
#define uint unsigned int

void main()
{
	uchar Writes[]="rexsam111",Read[10];
	lcd_init();
	W25Q_init();

	W25Q_SectorErase(0,0xf0);			//注释掉这两行测试掉电不丢失
	W25Q_PageProgram(0,0xf0,Writes,9);
	
	W25Q_Read(0,0xf0,Read,9);

	lcdstr(1,1,Read);

	while(1)
	{
	}
}
SPI.c
#include <REGX52.H>

#define uchar unsigned char

/*模式0*/
sbit CS=P0^0;//SS
sbit MISO=P0^1;//从机DO
sbit CLK=P0^2;
sbit MOSI=P0^3;//..DI

void spi_init()
{
	CS=1;
	CLK=0;
}
void spi_start(){	CS=0;	}
void spi_stop(){	CS=1;	}
uchar spi_(uchar Send)
{
	uchar Data=0x00,i;

	for(i=0;i<8;i++)
	{
//		MOSI=( Send & (0x80>>i) );
//		MOSI=Send&0x80;//上升沿要给从机的数据要提前放好
		Send<<=1;
		MOSI=CY;
		CLK=1;//上升沿主从机读入数据
//		if(MISO==1)
//			Data|=(0x80>>i);
		Data<<=1;
		Data|=MISO;
//		if(i<7) Data<<=1;
		CLK=0;//下降沿从机把数据放上线 主机下个循环头放数据上线
	}
	return Data;
}
W25Q32.c 草率了 因为不知道可以定义long变量就是32位 就把24位地址分成了高8位和低16位来发
#include <REGX52.H>
#include "SPI.h"
#define uchar unsigned char
#define uint unsigned int
	
#define W25Q64_WRITE_ENABLE							0x06
#define W25Q64_WRITE_DISABLE						0x04
#define W25Q64_READ_STATUS_REGISTER_1				0x05
#define W25Q64_READ_STATUS_REGISTER_2				0x35
#define W25Q64_WRITE_STATUS_REGISTER				0x01
#define W25Q64_PAGE_PROGRAM							0x02
#define W25Q64_QUAD_PAGE_PROGRAM					0x32
#define W25Q64_BLOCK_ERASE_64KB						0xD8
#define W25Q64_BLOCK_ERASE_32KB						0x52
#define W25Q64_SECTOR_ERASE_4KB						0x20
#define W25Q64_CHIP_ERASE							0xC7
#define W25Q64_ERASE_SUSPEND						0x75
#define W25Q64_ERASE_RESUME							0x7A
#define W25Q64_POWER_DOWN							0xB9
#define W25Q64_HIGH_PERFORMANCE_MODE				0xA3
#define W25Q64_CONTINUOUS_READ_MODE_RESET			0xFF
#define W25Q64_RELEASE_POWER_DOWN_HPM_DEVICE_ID		0xAB
#define W25Q64_MANUFACTURER_DEVICE_ID				0x90
#define W25Q64_READ_UNIQUE_ID						0x4B
#define W25Q64_JEDEC_ID								0x9F
#define W25Q64_READ_DATA							0x03
#define W25Q64_FAST_READ							0x0B
#define W25Q64_FAST_READ_DUAL_OUTPUT				0x3B
#define W25Q64_FAST_READ_DUAL_IO					0xBB
#define W25Q64_FAST_READ_QUAD_OUTPUT				0x6B
#define W25Q64_FAST_READ_QUAD_IO					0xEB
#define W25Q64_OCTAL_WORD_READ_QUAD_IO				0xE3
#define W25Q64_DUMMY_BYTE							0xFF


void W25Q_init()
{
	spi_init();
}

void W25Q_readID(uchar *MID,uint *DID)
{
	spi_start();
	spi_(W25Q64_JEDEC_ID);//发完指令 下一次!!!才能收到结果
	*MID=spi_(W25Q64_DUMMY_BYTE);
	*DID=spi_(W25Q64_DUMMY_BYTE);
	*DID<<=8;
	*DID|=spi_(W25Q64_DUMMY_BYTE);
	spi_stop();
}
void W25Q_WriteEnable()
{
	spi_start();
	spi_(W25Q64_WRITE_ENABLE);
	spi_stop();
}
void W25Q_WaitBusy()
{
	uchar R1,busy;
	uchar timeout=100;//不要太长 否则写入失败
	spi_start();
	do
		{
			spi_(W25Q64_READ_STATUS_REGISTER_1);
			R1=spi_(W25Q64_DUMMY_BYTE); 
			busy=R1&0x01;
			timeout--;
			if(!timeout)
			{
				break;
			}
		}
	while(busy);
	
	spi_stop();
}
//i为数据数组角标
void W25Q_PageProgram(uchar addr23_16,uint addr15_0,uchar *DataArray,uchar i)
{
	uchar j;
	
	W25Q_WriteEnable();//写使能
	
	spi_start();
	spi_(W25Q64_PAGE_PROGRAM);
	spi_(addr23_16);
	spi_(addr15_0&0xf0);
	spi_(addr15_0&0x0f);
	for(j=0;j<=i;++j)
	{
		spi_(DataArray[j]);
	}
	spi_stop();
	
	W25Q_WaitBusy();//只有写和擦除造成忙 所以只在写和擦除后加busy就够了
}
void W25Q_Read(uchar addr23_16,uint addr15_0,uchar *DataArray,uint i)
{
	uchar j;
	spi_start();
	spi_(W25Q64_READ_DATA);
	spi_(addr23_16);
	spi_(addr15_0&0xf0);
	spi_(addr15_0&0x0f);
	for(j=0;j<=i;j++)
	{
		DataArray[j]=spi_(0xff);
	}
	spi_stop();
}
void W25Q_SectorErase(uchar addr23_16,uint addr15_0)
{
	
	W25Q_WriteEnable();
	
	spi_start();
	spi_(W25Q64_SECTOR_ERASE_4KB);
	spi_(addr23_16);
	spi_(addr15_0&0xf0);
	spi_(addr15_0&0x0f);
	spi_stop();
	
	W25Q_WaitBusy();
}

lcd1602i2c.c
#include <REGX52.H>



sbit sda=P1^7;
sbit scl=P1^6;

#define uchar unsigned char
#define ADDR 0x4e // 0x27<<! | 0x00(i2c write)

void delay()
{		} 

void i2c_init() //scl sda都拉高初始化总线
{
	scl=1;
	delay();
	sda=1;
	delay();
}

void i2c_start()
{
	sda=1;
	delay();
	scl=1;
	delay();
	sda=0;
	delay();
}

void i2c_stop()
{
	sda=0;
	delay();
	scl=1;
	delay();
	sda=1;
	delay();
}
	
void i2c_re() //等待接收应答的程序
{
	unsigned char i=0;
	scl=1;
	delay();
	while((sda==1)&&(i<250))
		i++;
	scl=0;
	delay();
}

void i2c_writebyte(uchar d )
{
	uchar i,temp;
	temp=d;
	for(i=0;i<8;i++)
	{
		temp=temp<<1;
		scl=0;
		delay();
		sda=CY;
		delay();
		scl=1;
		delay();
	}
	scl=0;//释放总线?
	delay();
	sda=1;
	delay();
}

uchar i2c_readbyte()
{
	uchar i,temp;
	scl=0;
	delay();
	sda=1;//释放数据总线
	delay();
	for(i=0;i<8;i++)
	{
		scl=1;
		delay();
		temp=(temp<<1)|sda;
		scl=0;
		delay();
	}
	return temp;
}
	
void write_com(uchar aa)
{
	uchar H=0x00,L=0x00;
	H=aa&0xf0;	
	L=(aa&0x0f)<<4;
	i2c_writebyte(0x08+H);//1(BACKLIGHT),0(EN),0(RW),0(RS)
	i2c_re();
	i2c_writebyte(0x0c+H);//1(BACKLIGHT),1(EN),0(RW),0(RS)
	i2c_re();
	i2c_writebyte(0x08+H);//1(BACKLIGHT),0(EN),0(RW),0(RS)
	i2c_re();
	delay();
	i2c_writebyte(0x08+L);
	i2c_re();
	i2c_writebyte(0x0c+L);
	i2c_re();
	i2c_writebyte(0x08+L);
	i2c_re();
	delay();
}


void write_data(uchar aa)
{
	uchar H=0x00,L=0x00;
	H=aa&0xf0;	
	L=(aa&0x0f)<<4;
	i2c_writebyte(0x09+H);//1(BACKLIGHT),0(EN),0(RW),1(RS)
	i2c_re();
	i2c_writebyte(0x0d+H);//1(BACKLIGHT),1(EN),0(RW),1(RS)
	i2c_re();
	i2c_writebyte(0x09+H);//1(BACKLIGHT),0(EN),0(RW),1(RS)
	i2c_re();
	delay();
	i2c_writebyte(0x09+L);
	i2c_re();
	i2c_writebyte(0x0d+L);
	i2c_re();
	i2c_writebyte(0x09+L);
	i2c_re();
	delay();
}

void lcd_init()
{
	i2c_init();
	i2c_start();
	i2c_writebyte(ADDR);
	i2c_re();
	write_com(0x02);//设置四线发送数据
	write_com(0x08);//因为writcom只发四位 0X28需要分两次发才行

	write_com(0x0c);
	write_com(0x06);
	write_com(0x01);
}

void lcdgoto(unsigned char x,unsigned char y)//x行 y列
{
	if(x==1)
		write_com(0x80+y-1);
	else
		write_com(0x80+0x40+y-1);
}

void lcdstring(uchar *str)
{
	uchar i=0;
	while(str[i]) write_data(str[i++]);
}

void lcdstr(uchar x,uchar y,uchar *str)
{
	lcdgoto(x,y);
	lcdstring(str);
}

void lcdchar(uchar x,uchar y,uchar c)
{
	lcdgoto(x,y);
	write_data(c);
}

int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}
void lcdnum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	lcdgoto(Line,Column);
	for(i=Length;i>0;i--)
	{
		write_data(Number/LCD_Pow(10,i-1)%10+'0');
	}
}
void lcdhex(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	lcdgoto(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			write_data(SingleNumber+'0');
		}
		else
		{
			write_data(SingleNumber-10+'A');
		}
	}
}
void lcdsignednum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	lcdgoto(Line,Column);
	if(Number>=0)
	{
		write_data('+');
		Number1=Number;
	}
	else
	{
		write_data('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		write_data(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

无关紧要碎碎念

第一天因为用的89c52 应该是0口的Vcc断了导致P0口输出不稳影响通讯搞得我困惑了一晚上(我就不明白我自己的写法有什么问题得不出正确ID 事实上也没问题),那个单片机也弹翻新提示框了,应该是到寿了也不稳定。不合理设计的最小系统板上的DIP40插座真是断脚神器(前面没空间翘单片机只能一边翘),本来没事一插一把断脚了我还傻傻的没当回事万用表一量有输出继续用了,换了个新的一插一拔好几个脚差点断了,最后虚虚的搭着用了不敢插进去了。

看着32的教程用51驱动成还是挺开心的,本废物也能做点简单的事。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值