C51_将按键次数写入AT24C02,再读出送LCD显示

//C51_将按键次数写入AT24C02,再读出送LCD显示
//这篇文章较为详细介绍了AT24C02,感谢!
//开发版在连接AT24C02千万别连错,视力不好的近视的连好了仔细检查
//思路:1.利用以前编写的LCD显示函数(直接copy)
2.消抖程序确认按键按下(电平改变,直接copy)
3.计数程序
4.AT24C02的相关程序
#code

#include<reg51.h>       
#include<intrins.h>     //包含_nop_()函数的头文件
/*LCD模块与单片机引脚连接确定*/
sbit RS=P1^0;//RS为寄存选择位,引脚根据自己的电路图定义
sbit RW=P1^1;//读写选择位
sbit E=P1^2;//LCD模块使能端
sbit BF=P0^7;//1602字符型LCD设置的忙碌标志位BF连接在8位双向数据线的D7位上根据单片机原理图我对应于P0^7引脚
sbit S=P1^4;            //开关
#define	OP_READ	0xa1	// 宏 全局定义
#define	OP_WRITE 0xa0	
sbit SDA=P3^4;          //SDA根据原理图设置引脚
sbit SCL=P3^3;         
unsigned char code digit[ ]={"0123456789"}; //
/*LCD设置*/
/***************************************************
延时基函数:设置目的为根据所需时间随意改变谁让这是1ms
***************************************************/
void delay1ms()
{
   unsigned char i,j;	
	 for(i=0;i<10;i++)
	  for(j=0;j<33;j++)//time~=3*(i*j)
	   ;		 
 }
/*****************************************************
延时自定义函数:根据基变量1ms来自定义定延迟时间函数
***************************************************/
 void delaynms(unsigned char n)
 {
   unsigned char i;
	for(i=0;i<n;i++)
	   delay1ms();
 }
/*****************************************************
LCD模块状态检测>>>LCD模块是慢显示器>>>在写每一条指令前需要检测
忙碌状态,忙等,不忙在执行。
***************************************************/
 unsigned char BusyTest(void)
  {
    bit result;
	RS=0;       
//RS是寄存器选择,RS=0为选择了指令寄存器>>>检查是否忙碌跟指令相关
    RW=1;
//RW为读写选择,RW=1为读LCD的忙碌状况>>>检查是要去读状态
    E=1;        
//E是模块使能端,负跳变时E=1,LCD模块开始执行命令
    _nop_();   //一个空的机器周期(记住就OK啦!)
    _nop_();
    _nop_(); 
    _nop_();   //4个机器周期,让硬件有充足反应时间>>>LCD是一个慢显示器
    result=BF;  //把BF的状态给result返回传达忙碌状态
   E=0;         //不得进行读/写操作
   return result;//result=1 busy;result=0 rest
  }
/*****************************************************
写入指令:将模式设置指令或显示地址写入LCD模块
写指令RS=0;RW=0;E=0>>>E=1>>>E=0(高脉冲,过程才能写入dictate)
***************************************************/
void WriteInstruction (unsigned char dictate)
{   
    while(BusyTest()==1);   //检查LCD是否忙碌是则空操作等待至位0
	 RS=0;                  //选择指令寄存器
	 RW=0;                  //选择进行写入操作
	 E=0;                   //脉冲开始
	 _nop_();
	 _nop_();               //老年人多体谅给点反应时间
	 P0=dictate;            
//把dictate(指令或地址)送入P0口即写入指令或地址        	 
	 _nop_();
	 _nop_();
	 _nop_();
	 _nop_();               //4个机器周期用于硬件处理
	 E=1;                   //高电平,产生跳变>>>进行读写操作
	 _nop_();
	 _nop_();
	 _nop_();
	 _nop_();               //就是如此无语的慢
	  E=0;                  
//负跳变完成一个脉冲。LCD模块开始执行dictate。
 }
/*****************************************************
指定字符显示地址:跟据1602字符型LCD
确定位置的方法80H+地址码知道输出实际地址
***************************************************/
 void WriteAddress(unsigned char x)
 {
     WriteInstruction(x|0x80); 
 //通过WriteInstruction函数将指令写入
 }
/*****************************************************
写数据:将数据(想在LCD上输出的字符标准ASCII码/电脑会将A等自动转为ASCII码/)写入LCD模块
***************************************************/
 void WriteData(unsigned char y)
 {
    while(BusyTest()==1);  
	  RS=1;           //选择数据寄存器
	  RW=0;           //写数据
	  E=0;            //高脉冲
	  P0=y;           //将数据送入P0口,将数据写入液晶模块
	  _nop_();
	  _nop_();
 	  _nop_();
      _nop_();       
	  E=1;          
	  _nop_();
	  _nop_();
	  _nop_();
	  _nop_();       
	  E=0;          
 }
/*****************************************************
LCD初始化
***************************************************/
void LcdInitiate(void)
{
    delaynms(15);               //首次写指令延时>>>充足反应时间
    WriteInstruction(0x38);     
    //显示模式:16*2显示,5*7点阵,8位数据接口
	delaynms(5);                
    WriteInstruction(0x38);
	delaynms(5);
	WriteInstruction(0x38);     //确保成功
	delaynms(5);
	WriteInstruction(0x0c);     //显示模式:显示开,有光标,光标闪烁
	delaynms(5);
	WriteInstruction(0x06);     //显示模式:光标移动,字符不动
	delaynms(5);
	WriteInstruction(0x01);     //清屏指令
	delaynms(5);
 }
/***************************************************
             
***************************************************/
void Display(unsigned char x)
{
   unsigned char i,j;
	i=x/10;                  
	j=x%10;                 
    WriteAddress(0x44);      
	WriteData(digit[i]);     
	WriteData(digit[j]);     
     
 }
/******************AT24C02的操作******************/
/***************************************************
AT24C02开始信号
***************************************************/
void start()
// 开始传输数据
{
	SDA = 1;    //串行数据/地址线高电平
	SCL = 1;    //串行时钟线高电平
	_nop_();    //机器周期>>>反应时间
	_nop_(); 
	SDA = 0;    //开始传输数据标志SDA负跳变,SCL尚处于高电平
	_nop_();    
	_nop_();    
	_nop_();    
	_nop_();   
	SCL = 0;    //SCL为低电平时,SDA上的数据才允许变化即允许以后数据传输
}
/***************************************************
AT24C02停止信号
***************************************************/
void stop()
// 停止传输数据
{
	SDA = 0;     //结束出初期SDA为低电平
	_nop_();     
	_nop_();    
	SCL = 1;     //高电平,不允许数据传输
	_nop_();     
	_nop_();    
	_nop_();     
	_nop_();    
	SDA = 1;    //最终SDA变为高电平
}
/*以上两步的图解可以参考度娘上的便于理解*/
/***************************************************
从AT24C02读取数据
***************************************************/
unsigned char ReadData()
//将AT24C02数据给MCU
{
	unsigned char i;
	unsigned char x;   //存储从AT24C02中读出的数据
	for(i = 0; i < 8; i++)
	{
		SCL = 1;                //SCL置为高电平
		x<<=1;                  //将x中二进制向左移动一位
		x|=(unsigned char)SDA; 
		 //将SDA中的数据通过按位或运算存入x中
		SCL = 0;                        //在SCL下降时读出数据
	}
	return(x);               
}
/***************************************************
向AT24C02当前地址写入数据
***************************************************/
//因为要用到start函数,so SCL=0
bit WriteCurrent(unsigned char y)
{
	unsigned char i;
	bit ack_bit;               //存储应答位
	for(i = 0; i < 8; i++)		//循环移入8个位
	{
    	SDA = (bit)(y&0x80);   //按位与运算将最高位数据送到S
    	                       //传递时高位在前低位在后
		_nop_();           
	    SCL = 1;            //上升时将数据写入AT24C02      
   	    _nop_();            
	    _nop_();             
	  	SCL = 0;            //置零为为循环准备
		y <<= 1;           
	}
	SDA = 1;			  // 主机在时钟脉冲的高电平期间释放SDA
	                //ÒÔÈÃSDAÏßתÓɽÓÊÕÉ豸(AT24Cxx)¿ØÖÆ
	_nop_();        
	_nop_();        
	SCL = 1;      
	_nop_();      
	_nop_();       
	_nop_();      
	_nop_();       
	ack_bit = SDA; //表示AT24C02向SDA输送低电平表示已经接收到了第一个字节
	               //若为高电平则异常
	SCL = 0;       //SCL位低电平SDA才允许数据变化即允许后续数据传输
	return  ack_bit;			//返回AT24C02的应答位
}
/***************************************************
向AT24C02中指定地址写入数据
add为存储指定地址,dat为存储待写入数据
***************************************************/
void WriteSet(unsigned char add, unsigned char dat)
// 在指定地址addr处写入数据WriteCurrent
{
	start();               //开始传递
	WriteCurrent(OP_WRITE); //选择要操作的芯片,并告知要对其写入数据
	WriteCurrent(add);       //写入指定地址
	WriteCurrent(dat);       //向上面指定地址写入数据
	stop();                //停止数据传递
	delaynms(4);	      
}
/***************************************************
从当前地址读取数据
***************************************************/
unsigned char ReadCurrent()
{
	unsigned char x;
	start();               
	WriteCurrent(OP_READ);  //选择要操作的芯片,并告知要对其写入数据
	x=ReadData();         
	stop();               
	return x;             
}
/***************************************************
在指定地址读取数据
***************************************************/
unsigned char ReadSet(unsigned char set_add)
// 在指定地址读取
{
	start();                     
	WriteCurrent(OP_WRITE);       
	WriteCurrent(set_add);       
	return(ReadCurrent());        //从指定地址读出数据并返回
}
 void main(void)
 {
    unsigned char sum;    
	 unsigned char x;      //存储从AT24C02读出数值
    LcdInitiate();      
 	 sum=0;               
    while(1)            
      {
		  if(S==0)        
		   {
		    delaynms(80);  
			 if(S==0)        
			  sum++;         
			 if(sum==99)     
			  sum=0;        
			}
       WriteSet(0x01,sum); 
		 x=ReadSet(0x01);   
		 Display(x);	    
	  }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章