DS1302時鐘芯片簡單操作及BCD相關(guān)注意事項
ds1302是具有時鐘功能的芯片,一旦啟動,可以自動計時,內(nèi)部含有年月日時分秒寄存器等。
先說下我這幾天遇到的問題,其實(shí)歸結(jié)起來滿簡單的一個問題,針對ds1302芯片的讀寫字節(jié)操作滿簡單的,見附表的datasheet,但這里要強(qiáng)調(diào)的是往ds1302芯片寫數(shù)據(jù)或者是讀數(shù)據(jù),在程序執(zhí)行上一般會分別調(diào)用先后調(diào)用往ds1302寫一個字節(jié)或者讀一個字節(jié)的方法(當(dāng)然這兩個方法得自己寫)。不過記得在調(diào)用這兩個方法的過程中要保持CE(即芯片的置位端)持續(xù)為高電平,切不可寫完一個字節(jié)就將置位端拉低,接著要寫下一個字節(jié)又把置位端拉高?,F(xiàn)在看看下面的代碼:
sbit clk = P3^6;//時鐘
sbit io = P3^4; //數(shù)據(jù)
sbit reset = P3^5;// DS1302復(fù)位
/寫一字節(jié)到ds1302
void write_byte(uchar dat)
{
uchar i = 0;
reset = 1; //置位端高電平允許寫
for(i=0; i<8; i++)
{
clk = 0;
io = dat&0x01; //從最低位開始寫
clk = 1; //時鐘信號上升沿接收數(shù)據(jù)
dat = dat >> 1; //數(shù)據(jù)右移
}
reset = 0;
}
//從ds1302讀一個字節(jié)
uchar read_byte()
{
uchar rev = 0x00;
uchar i = 0;
reset = 1; //置位端高電平允許讀
for(i=0; i<8; i++)
{
clk = 0;
if(io)
{
rev |= 0x80; //讀取的數(shù)據(jù)放在高位端
}
rev >>= 1; //數(shù)據(jù)右移
clk = 1; //時鐘信號上升沿接收數(shù)據(jù)
}
return rev;
}
void write_data_ds1302(uchar address, uchar dat)
{
reset=0;
_nop_();
clk=0;
_nop_();
reset = 1;
_nop_(); //啟動
write_byte(address); //發(fā)送地址
write_byte(dat); //發(fā)送數(shù)據(jù)
clk = 1;
reset = 0; //恢復(fù)
}
在主函數(shù)里
write_data_ds1302(0x82, 0x36); //在分鐘寄存器里寫入數(shù)據(jù)
minute = read_data_ds1302(0x83); //讀出分鐘寄存器里的數(shù)據(jù)
write_data(minute);
得到的minute卻是0x7e,或者0x00這樣明顯錯誤的答案!!
原因在于write_byte(uchar dat)中最后一行代碼reset = 0;相當(dāng)于拉低置位端,數(shù)據(jù)后續(xù)的傳輸被破壞了。
真正的函數(shù)方法只要這樣寫就可以了
sbit SCK = P3^6;//時鐘
sbit SDA = P3^4; //數(shù)據(jù)
sbit RST = P3^5;// DS1302復(fù)位
//寫一字節(jié)到ds1302
void write_byte(uchar dat)
{
uchar i = 0;
SCK = 0;
RST = 1; //置位端高電平允許寫
for(i=0; i<8; i++)
{
SCK = 0;
delay(1);
SDA = dat&0x01; //從最低位開始寫
dat >>= 1; //數(shù)據(jù)右移
SCK = 1; //時鐘信號上升沿接收數(shù)據(jù)
}
}
//從ds1302讀一個字節(jié)
uchar read_byte()
{
uchar rev = 0x00;
uchar i = 0;
for(i=0; i<8; i++)
{
if(SDA)
{
rev |= 0x80; //讀取的數(shù)據(jù)放在高位端
}
SCK = 0;
rev >>= 1; //數(shù)據(jù)右移
SCK = 1;
}
return rev;
}
void write_data_ds1302(uchar address, uchar dat)
{
RST = 0;
SCK = 0;
RST = 1;
write_byte(address);//發(fā)送地址
write_byte(dat);//發(fā)送數(shù)據(jù)
RST = 0; //恢復(fù)
}
uchar read_data_ds1302(uchar address)
{
uchar rev = 0x00;
RST = 0;
SCK = 0;
delay(4);
RST = 1;
write_byte(address);
rev = read_byte();
return rev;
}
這里的write_data_ds1032(uchar address, uchar dat)指的是寫入地址后接著寫入一個字節(jié)的數(shù)據(jù),如果還要寫第二個字節(jié)數(shù)據(jù),應(yīng)當(dāng)把末行的RST = 0; 去掉,同時調(diào)用write_byte(uchar dat)方法。
在這里談下ds1302 數(shù)據(jù)的注意事項,比如write_data_ds1302(0x84, 18); //在分鐘寄存器里寫入數(shù)據(jù) 這里將18無論以十進(jìn)制的方法或者十六進(jìn)制0x12的方法存到寄存器中,在讀取出來是0x18,因?yàn)榇嫒氲郊拇嫫骼锏陌宋粩?shù)據(jù),在寄存器的八位中,寄存器的前四位存放十位,后四位存放個位。(因?yàn)榉昼娂拇嫫鞔娣诺臄?shù)據(jù)最大也就59即0x59).所以minute = read_data_ds1302(0x85); //讀出分鐘寄存器里的數(shù)據(jù) 將得到0x18.