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);	    
	  }
}

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