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

📄 5045_spi_c.c

📁 对x5045的c语言读写操作
💻 C
字号:
/*用C语言编的5045程序
K1键:加一键。实验板上闪烁的字符加一,前两位是地址值,后两位是数据值。
K2键:减一键。实验板上闪烁的字符减一,前两位是地址值,后两位是数据值。
K3键:读写交换键。P1^0亮,表示读指示;P1^1亮,表示写指示。
K4键:多功能键。按一下,控制P^4的点亮或熄灭,亮,表示K1和K2改写的是地址,同时地址值闪烁;
      连按两下控制P1^5的点亮,表示执行(K1,K2,K3或K4任意键按一下,P1^5都会熄灭)。
*/
#include<reg51.h>
#include<intrins.h>

void initial(void);			//函数声明
void kscan(void);
void SPISendByte(unsigned char ch);
unsigned char SPIreceiveByte();
void ChangeAdr(unsigned char Adr);
void ChangeData(unsigned char Data);
void Display(void);
void mDelay(unsigned char Delay);
unsigned char ReadStatus(void);
void WriteStatus(void);
unsigned char ReadEEP(void);
void WriteEEP(void);
//bit CheakWrite(void);

#define T0INIT_H (65536-2000)/16
#define T0INIT_L (65536-2000)%16
#define uchar unsigned char
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
//5045命令定义
#define WREN 0x06        //读允许命令,Enable Write Operation
#define WRDI 0x04        //读禁止命令,Disable Write Operation
#define RDSR 0x05        //读状态寄存器,Read Status Register
#define WRSR 0x01        //写状态寄存器,Write Status Register
#define READ_L 0x03       //读低256字节EEProm
#define READ_H 0x0b       //读高256字节EEProm
#define WRITE_L 0x02      //写低256字节EEProm
#define WRITE_H 0x0a      //写高256字节EEProm

uchar bdata flag;
sbit flag_k=flag^0;	     //有键按下标志
sbit flag_k12_first=flag^1;	//键1和键2第一次按下标志
sbit flag_k3_first=flag^2;	//K3第一次按键标志
sbit flag_k_enter=flag^3;	//有键按下标志,为的是减少硬件是用次数
sbit flag_addr_data=flag^4;	//地址或数据加减标志
sbit K4_func1=flag^5;	 //k4功能键标志
sbit K4_func2=flag^6;
sbit DorW=flag^7;
sbit P1_0=P1^0;
sbit P1_1=P1^1;

sbit P1_2=P1^2;    //K1键显示
sbit P1_3=P1^3;    //K2键显示
sbit P1_4=P1^4;    //K4功能1显示,亮,地址调节;灭,数据调节
sbit P1_5=P1^5;    //K4功能2显示
//bit bdata P12=1,P13=1,P14=1,P15=1;    //写这一句的时候代码是380多,不加的话是250左右
uchar bdata dictation;
sbit P12=dictation^0;sbit P13=dictation^1;sbit P14=dictation^2;sbit P15=dictation^3;
sbit flag_k4_first=dictation^4;   //作为k4键的第一次设置标志
uchar Addr,Data,QdorYsh,K4_Delay,K4_Count;	   //用到的字节定义
uchar ds;    //显示位选择
uchar code GYshjzh[16]={0xC0,0xF9,0xA4,0xB0,	 //共阳十进制值,十位数字转换字节存放区0---F
                          0x99,0x92,0x82,0xF8,
						  0x80,0x90,0x88,0x83,
						  0xC6,0xA1,0x86,0x8E};
uchar  code DisBit[6]={0x7F,0xBF,0xDF,0xEF,0xF7,0xFB};   //显示位字节存放区,中间两个是消隐码
uchar  idata DisData[12]={0xc0,0xc0,0xff,0xff,0xc0,0xc0,
                          0xff,0xff,0xff,0xff,0xc0,0xc0};   //显示数据字节存放区,0xff是消隐码,地址消隐
//uchar  AdrH,AdrL,Hidden,Hidden,DataH,DataL;
//uchar  idata *DisPoi[6];  //定义指针数组,指示显示的每位的数字
//-----------------------函数声明,变量定义--------------------------------------------------------
sbit SCK=P3^6;                           // 将p3.6口模拟时钟输出
sbit MOSI=P3^7;                          // 将p3.7口模拟主机输出
sbit MISO=P3^7;                          // 将p3.7口模拟主机输入
sbit CS=P2^1;                           // 将p2.1口模拟片选
sbit WP=P2^0;							//写保护
/**********主函数***************************/
void main()
{
    initial();
    while(1)
	{ Display();
	  if(K4_func1==1)
	    { 
		  P14=~P14;
		  P1_4=P14;
		  flag_addr_data=~flag_addr_data;
		  if(flag_addr_data==1)	  //数据闪烁,表明修改的内容是数据
		  {
		    DisData[6]=DisData[0];
			DisData[7]=DisData[1];
			DisData[10]=0xff;
			DisData[11]=0xff;
		  }
		  else                      //地址闪烁,表明修改的内容是地址
		  {
		    DisData[6]=0xff;
			DisData[7]=0xff;
			DisData[10]=DisData[4];
			DisData[11]=DisData[5];
		  }
		  K4_func1=0;
		}
	  if(K4_func2==1)
	    { //P1_5=0;       //P1_5LED点亮,表示读写执行
//		  P15=~P15;
//		  P1_5=P15;
		  if(DorW==1)     //读命令
		   {Data=ReadEEP();
		   	ChangeData(Data);
			if(flag_addr_data==1)	  //数据闪烁,表明修改的内容是数据
		      {
		       DisData[6]=DisData[0];
			   DisData[7]=DisData[1];
			   DisData[10]=0xff;
			   DisData[11]=0xff;
		      }
		    else                      //地址闪烁,表明修改的内容是地址
		     {
		       DisData[6]=0xff;
			   DisData[7]=0xff;
			   DisData[10]=DisData[4];
			   DisData[11]=DisData[5];
		     }
		   }
		  else
		   {
		   	WriteEEP();
//          CheakWrite(void); 			//5045状态检查操作
		   } 
		  K4_func2=0;
		  P1_5=0;       //P1_5LED点亮,表示读写执行
		 // P1_5=1;       //P1_5LED熄灭
		}
	}
}
void initial(void)
{
   TMOD=0x01;     //定时器0工作于方式1
   TH0=T0INIT_H;
   TL0=T0INIT_L;
   TR0=1;         //定时器0开始运行
   EA=1;
   ET0=1;
   DorW=1;        //设置为读显示
   P1_0=0;		  //读显示灯亮
   P12=1;
   P13=1;
   P14=1;
   P15=1;
   WriteStatus();
}
/*************T0中断程序*********************
	键盘扫描程序
******************/
void T0int(void) interrupt 1 using 1
{  //P1_0=0;
   TH0=T0INIT_H;
   TL0=T0INIT_L;
   if(K4_Delay!=0)
      {
	    K4_Delay--;
		if(K4_Delay==0)
		 {if(K4_Count!=1)
		   {
		    K4_func2=1;
		    K4_Count=0;    //计数器复位
		   }
		 else
		   { 
		     K4_func1=1;
		     K4_Count=0;   //计数器复位
			 P1_5=1;       //再一次有键按下,P1_5LED熄灭
		   }
		   flag_k4_first=0;    //取消标志位,可以下次再用
		 }
      }
//	else
//	  ;
   if(flag_k==1)
    {	QdorYsh--;
	  if(QdorYsh!=0)
//	     QdorYsh--;
		   ;
	  else
	    kscan();
    }
   else
     kscan();
}
/*****************键盘扫描程序*****************/
void kscan(void)
{		 uchar j;
        j=P3&0x3c;
      if(j!=0x3c)    //我加上括号就是259个code,不加的话是132个code
		{
		  if(flag_k==1)
		    {
			  switch(P3&0x3c)
			   { 
			     case 0x38:	//K1键处理程序
//				    P12=~P12;
//				    P1_2=P12;
              P1_5=1;       //再一次有键按下,P1_5LED熄灭
			  if(flag_addr_data==0)
				   {if(flag_k12_first==1)
				     {
					   Addr++;
					   ChangeAdr(Addr);
					   QdorYsh=20;
					 }
				   else
				     {
					   Addr++;
					   ChangeAdr(Addr);
					   flag_k12_first=1;
					   QdorYsh=200;
					 }
					}
			      else
				  {if(flag_k12_first==1)
				     {
					   Data++;
					   ChangeData(Data);
					   QdorYsh=20;
					 }
				   else
				     {
					   Data++;
					   ChangeData(Data);
					   flag_k12_first=1;
					   QdorYsh=200;
					 }
					}
					   flag_k=0;
					  break;
				  case 0x34: //K2键处理程序
//				   P13=~P13;
//				   P1_3=P13;
                   P1_5=1;       //再一次有键按下,P1_5LED熄灭
				   if(flag_addr_data==0)
				   {if(flag_k12_first==1)
				       {
					     Addr--;
						 ChangeAdr(Addr);
					     QdorYsh=20;
					   }
				     else
				       {
					     Addr--;
					     ChangeAdr(Addr);
						 flag_k12_first=1;
					     QdorYsh=200;
					   }
					 }
					else
					 {if(flag_k12_first==1)
				       {
					     Data--;
						 ChangeData(Data);
					     QdorYsh=20;
					   }
				      else
				       {
					     Data--;
						 ChangeData(Data);
					     flag_k12_first=1;
					     QdorYsh=200;
					   }
					  }
						flag_k=0;
					   break;
	     		   case 0x2c: //K3键处理程序
				   P1_5=1;       //再一次有键按下,P1_5LED熄灭
				    if(flag_k3_first==1)
					     ;
					else
					  flag_k3_first=1;
					  DorW=~DorW;      //读或写位取反,显示也取反
					  P1_0=~DorW;
					  P1_1=DorW;
					  flag_k=0;       //键盘处理完
					    break;
				   case 0x1c: //K4键处理程序
				      if(flag_k4_first==1)
					    { 
						  K4_Count++;
//						  flag_k=0;
						}
					  else
					    { 
						  flag_k4_first=1;
				          K4_Delay=25;    //延时判断功能的设置,根据具体的实验板实验而得
					      K4_Count=0x01;}
//					      flag_addr_data=~flag_addr_data;
                          flag_k=0;
					     break;
				   default:
				         break;
			   }
			}
		  else 
		   {
		     flag_k=1;
			 flag_k_enter=1;	   //设置有键按下标志
			 QdorYsh=2;            //延时去抖设计时间
		   }
		}
		else
		{
		  if(flag_k_enter==1)
		    {
			  flag_k=0;
			  flag_k12_first=0;
			  flag_k3_first=0;
//			  flag_k4_first=0;
			  flag_k_enter=0;
			}
//			else
//			  ;
		}
}
/***************地址字节变换***********/
void ChangeAdr(unsigned char Adr)
  {
      uchar i,j;
	  i=Adr/16;
	  j=Adr%16;
	  DisData[0]=GYshjzh[i];		  //将要显示字符的地址送给指针
	  DisData[1]=GYshjzh[j];
  }
/***************数据字节变换***********/
void ChangeData(unsigned char Data)
  {
      uchar i,j;
	  i=Data/16;
	  j=Data%16;
	  DisData[4]=GYshjzh[i];		  //将要显示字符的地址送给指针
	  DisData[5]=GYshjzh[j];
  }
/******************显示子程序********************/
void Display(void)
{  if(ds>6)
   {
   	 P2=DisBit[ds-6];
   }
   else{
   P2=DisBit[ds];}
   P0=DisData[ds];
   mDelay(10);
     ds++;
   if(ds==0x0c)     //显示位超出LED显示范围
     ds=0;
}
/**************************************************
 函数名称: SPISendByte
 入口参数: ch
 函数功能: 发送一个字节
****************************************************/
void SPISendByte(unsigned char ch)
{ 
unsigned char idata n=8;      // 向SDA上发送一位数据字节,共八位      
         SCK = 1 ;                   //时钟置高
         CS  = 0 ;                   //选择从机

while(n--)
{ 
             delayNOP();
             SCK = 0 ;                   //时钟置低
           if((ch&0x80) == 0x80)     // 若要发送的数据最高位为1则发送位1
   {       
                   MOSI = 1;     // 传送位1
   }
   else
   {  
    MOSI = 0;     // 否则传送位0
   }
                 delayNOP();
   ch = ch<<1;         // 数据左移一位
              SCK = 1 ;                   //时钟置高 
}
}
/**************************************************
 函数名称: SPIreceiveByte
 返回接收的数据
 函数功能: 接收一字节子程序
***************************************************/
unsigned char SPIreceiveByte()
{
unsigned char idata n=8;     // 从MISO线上读取一上数据字节,共八位
unsigned char tdata;
         SCK = 1;                    //时钟为高
         CS  = 0;                    //选择从机
while(n--)
{       
                 delayNOP();
                 SCK = 0;                    //时钟为低
   delayNOP();
   tdata = tdata<<1;     // 左移一位,或_crol_(temp,1)
   if(MISO == 1)
    tdata = tdata|0x01;     // 若接收到的位为1,则数据的最后一位置1
   else 
    tdata = tdata&0xfe;     // 否则数据的最后一位置0
   SCK=1;
}
return(tdata);
}
/************延时子程序***********/
void mDelay(unsigned char Delay)
{
    unsigned char  i;
	for(;Delay>0;Delay--)
	 {
	   for(i=0;i<124;i++)
	      {;}
	 }
}
/**************读状态寄存器*******************
unsigned char ReadStatus(void)
{	
   unsigned char i;
  SPISendByte(RDSR);
  i=SPIreceiveByte();
   CS=1;
   delayNOP();
   return(i);
}
***********写状态寄存器*******************/
void WriteStatus(void)
{
  SPISendByte(WREN);
    CS=1;
	delayNOP();			     //如果CS不变高,下面的写WRSR操作会被忽略
  SPISendByte(WRSR);
  SPISendByte(0x33);     //写状态寄存器,不保护写地址,不设置看门狗
    CS=1;				 //解除对5045的选择
	delayNOP();
}
/**************从EEProm中读取数据************************/
unsigned char ReadEEP(void)
{  unsigned char i;
   SPISendByte(READ_L);
   SPISendByte(Addr);
   i=SPIreceiveByte();
    CS=1;			   //解除对5045的选择
	delayNOP();
   return(i);
}
/**************向EEProm写入数据***************************/
void WriteEEP(void)
{
   SPISendByte(WREN);
    CS=1;
	delayNOP();                 //理由同写状态寄存器
   SPISendByte(WRITE_L);
   SPISendByte(Addr);
   SPISendByte(Data);
    CS=1;				  //解除对5045的操作
	delayNOP();
}
/************检测写操作**********************************
bit CheakWrite(void)
{
   unsigned char j;
   j=ReadStatus();
    CS=1;			      //解除对5045的选择
	delayNOP();
   if((j&0x01)==0)
     return(0);                 //表示闲,可以写入数据,写数据前需检查其闲或忙的状态
   else
     return(1);					//表示忙,须等待
} */

⌨️ 快捷键说明

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