I2C協(xié)議在項(xiàng)目開發(fā)中使用很常見,很多存儲(chǔ)芯片使用I2C接口。由于51單片機(jī)沒有I2C接口,這里使用IO口模擬I2C通訊協(xié)議,來完成I2C芯片驅(qū)動(dòng)。使用的I2C芯片為AT24C02。 原理圖如下:
本文引用地址:http://butianyuan.cn/article/201611/321316.htm
代碼如下:
//程序功能:計(jì)時(shí)器每一秒向AT24C02保持?jǐn)?shù)據(jù),同時(shí)數(shù)碼管顯示,重啟之后讀取出數(shù)據(jù)接著計(jì)時(shí),100S循環(huán)
//程序問題:無法寫入
#include
#define uint unsigned int
#define uchar unsigned char
//變量定義
uint timer_flag; //用于判斷定時(shí)器T0方式一是否計(jì)滿1s
uchar shiwei,gewei; //數(shù)碼管顯示的十位與個(gè)位
uint number;
uchar time_date; //當(dāng)前時(shí)間數(shù)據(jù)
//控制端口聲明
sbit duanxuan=P2^6; //數(shù)碼管段選端
sbit weixuan=P2^7; //數(shù)碼管位選端
sbit AT24C02_SDA=P2^0; //AT24C02串行數(shù)據(jù)輸入輸出端口
sbit AT24C02_SCLK=P2^1; //時(shí)鐘信號(hào)端口
//數(shù)碼管顯示數(shù)字段碼定義
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
//相關(guān)函數(shù)聲明
void delay_minute(); //延時(shí)us級(jí)函數(shù)聲明
void delay_xs(uint); //延時(shí)s級(jí)函數(shù)聲明
void timer_init(); //定時(shí)器T0方式一初始化函數(shù)聲明
void AT24C02_init(); //I^2C通訊總線初始化函數(shù)聲明
void star(); //I^2C通訊啟動(dòng)函數(shù)聲明
void stop(); //I^2C通訊停止函數(shù)聲明
void response(); //應(yīng)答函數(shù)聲明
void write_in_byte(uchar); //寫入一個(gè)字節(jié)函數(shù)聲明
uchar read_out_byte(); //讀出一個(gè)字節(jié)函數(shù)聲明,函數(shù)放回到讀出的值
//注意寫入一個(gè)字節(jié)與寫入數(shù)據(jù)的區(qū)別,前者是后者的一個(gè)子過程,讀取同
void saveing(uchar,uchar); //向AT24C02保存數(shù)據(jù)函數(shù)聲明
uchar load(uchar); //從AT24C02載入掉電之前的數(shù)據(jù),函數(shù)放回到讀出的值
void quwei(uchar); //顯示數(shù)字取出各位與十位
void display(uchar); //數(shù)碼管顯示函數(shù)聲明
//主函數(shù)
void main()
{
AT24C02_init(); //AT24C02初始化
time_date=load(3); //開機(jī)首先載入AT24C02中的數(shù)據(jù),這里讀取的是第三位址的數(shù)據(jù)
if(time_date>100) //防止上一次保存的數(shù)據(jù)是100,這里計(jì)時(shí)是100循環(huán)的
{
time_date=1;
}
timer_init(); //計(jì)時(shí)器T0方式一初始化
while(1)
{
display(time_date); //顯示時(shí)間
if(timer_flag==1) //如果計(jì)滿一秒,就保存時(shí)間數(shù)據(jù)
{
timer_flag=0;
saveing(3,time_date); //保存時(shí)間數(shù)據(jù)
}
}
}
//延時(shí)us級(jí)函數(shù)主體
void delay_minute()
{;;}
//延時(shí)s級(jí)函數(shù)主體
void delay_xs(uint s)
{
uint i,j;
for(i=s;i>0;i--)
{
for(j=110;j>0;j--)
{
}
}
}
//定時(shí)器T0方式一初始化函數(shù)主體
void timer_init()
{
//方式選擇
TMOD=0x01;
//預(yù)裝初值
TH0=(65536-46080)/256;
TL0=(65536-46080)%6;
//開中斷
EA=1;
ET0=1;
//啟動(dòng)定時(shí)器
TR0=1;
}
//I^2C通訊總線初始化函數(shù)主體
void AT24C02_init() //兩線均寫1 AT24C02數(shù)據(jù)有效規(guī)則,sclk為高電平且sda數(shù)據(jù)穩(wěn)定,當(dāng)sda發(fā)生有效數(shù)據(jù)變化時(shí),sclk必須要是0
{
AT24C02_SDA=1;
delay_minute();
AT24C02_SCLK=1;
delay_minute();
}
//I^2C通訊啟動(dòng)函數(shù)主體
void star() //啟動(dòng)規(guī)則:SCLK-1,SDA下降沿
{
AT24C02_SDA=1; //一定要SDA首先為1,再是SCLK為1,否則會(huì)出現(xiàn)一個(gè)停止信號(hào)
delay_minute();
AT24C02_SCLK=1;
delay_minute();
AT24C02_SDA=0;
delay_minute();
}
//I^2C通訊停止函數(shù)主體
void stop() //停止規(guī)則:SCLK-1,SDA上升沿
{
AT24C02_SDA=0; //一定要SDA首先為0,再是SCLK為1,否則會(huì)出現(xiàn)一個(gè)啟動(dòng)信號(hào)
delay_minute();
AT24C02_SCLK=1;
delay_minute();
AT24C02_SDA=1;
delay_minute();
}
//應(yīng)答函數(shù)主體
void response() //應(yīng)答規(guī)則:SCLK-1,等待從機(jī)把SDA拉低
{
uint i;
AT24C02_SCLK=1;
delay_minute();
while(AT24C02_SDA==1&&i<255)//等待從機(jī)把SDA拉低,且超過一定時(shí)間沒有應(yīng)答,默認(rèn)已經(jīng)應(yīng)答
{
i++;
}
AT24C02_SCLK=0; //應(yīng)答之后,SCLK-0.防止數(shù)據(jù)誤操作,因?yàn)镾CLK-1,數(shù)據(jù)就是有效地
delay_minute();
}
//寫入一個(gè)字節(jié)函數(shù)主體
void write_in_byte(uchar date)
{
uint i,buffer; //i用于循環(huán)發(fā)送每一位,buffer緩沖數(shù)據(jù)
buffer=date;
for(i=0;i<8;i++)
{
buffer=buffer<<1; //buffer左旋,高位就放入CY
AT24C02_SCLK=0; //有效發(fā)送規(guī)則:sclk-0變化數(shù)據(jù),sclk-1數(shù)據(jù)穩(wěn)定后有效
delay_minute();
AT24C02_SDA=CY;
delay_minute();
AT24C02_SCLK=1;
delay_minute();
}
AT24C02_SCLK=0; //不發(fā)送,一定是SCLK-0,SDA-1
delay_minute();
AT24C02_SDA=1;
delay_minute();
}
//讀出一個(gè)字節(jié)函數(shù)主體
uchar read_out_byte() //讀出規(guī)則:啟動(dòng)-控制字片選+寫(為了寫入要讀取的地址)-應(yīng)答-寫入存儲(chǔ)地址-應(yīng)答-讀取數(shù)據(jù)-應(yīng)答-停止
{
uchar i,buffer_writting;
//--------------------------------------------------
//不能少的
AT24C02_SCLK=0; //方便SDA數(shù)據(jù)發(fā)生有效變化
delay_minute();
AT24C02_SDA=1;
delay_minute();
//--------------------------------------------------
for(i=0;i<8;i++)
{
AT24C02_SCLK=1;
delay_minute();
buffer_writting=(buffer_writting<<1)|AT24C02_SDA;//buffer_writting左旋之后與AT24C02_SDA的數(shù)據(jù)線與
delay_minute();
AT24C02_SCLK=0;
delay_minute();
}
return buffer_writting;
}
//向AT24C02保存數(shù)據(jù)函數(shù)主體
void saveing(uchar address,uchar time_date0) //寫入字節(jié)規(guī)則:啟動(dòng)-控制字片選+寫-應(yīng)答-寫入存儲(chǔ)地址-應(yīng)答-寫入數(shù)據(jù)-應(yīng)答-停止
{
star(); //啟動(dòng)信號(hào)
write_in_byte(0xa0);
response();
write_in_byte(address);
response();
write_in_byte(time_date0);
response();
stop();
}
//從AT24C02載入掉電之前的數(shù)據(jù)函數(shù)主體
uchar load(uchar address) //讀出規(guī)則:啟動(dòng)-控制字片選+寫(為了寫入要讀取的地址)-應(yīng)答-寫入存儲(chǔ)地址-應(yīng)答-讀取數(shù)據(jù)-應(yīng)答-停止
{
uchar time_date_former;
star();
write_in_byte(0xa0);
response();
write_in_byte(address);
response();
time_date_former=read_out_byte();
stop();
return time_date_former;
}
//顯示數(shù)字取出各位與十位函數(shù)主體
void quwei(uchar quwei_date)
{
shiwei=quwei_date/10;
gewei=quwei_date;
}
//數(shù)碼管顯示函數(shù)函數(shù)主體
void display(uchar display_date)
{
quwei(display_date);
//顯示第一個(gè)數(shù)碼管
duanxuan=1;
P0=table[shiwei];
duanxuan=0;
P0=0xff;
weixuan=1;
P0=0xfe;
weixuan=0;
delay_xs(2);
//顯示第二的數(shù)碼管
duanxuan=1;
P0=table[gewei];
duanxuan=0;
P0=0xff;
weixuan=1;
P0=0xfd;
weixuan=0;
delay_xs(2);
}
//T0定時(shí)器方式一中斷服務(wù)程序
void T0_timer_no1() interrupt 1
{
//預(yù)裝初值
TH0=(65536-46080)/256;
TL0=(65536-46080)%6;
number++;
if(number==20) //20次計(jì)滿就是1s
{
number=0;
time_date++; //時(shí)間累加
timer_flag=1; //計(jì)滿一次就保存數(shù)據(jù)
if(time_date==100) //100s循環(huán)計(jì)時(shí)
{
time_date=0;
}
}
}
以上,結(jié)束。
評(píng)論