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