導航:首頁 > 數據處理 > ds1307時鍾讀出來的數據怎麼處理

ds1307時鍾讀出來的數據怎麼處理

發布時間:2022-09-11 23:41:58

㈠ DS1307時鍾變慢要怎麼解決

更換精度更高的晶體,DS1307走時快慢只和晶體的頻率有關系

㈡ 如何讀出DS1302裡面的時鍾數據

#include <REG51.H>
#include <intrins.h>
//#include "LCD1602.h"
//#include "DS1302.h"
#define uint unsigned int
#define uchar unsigned char
sbit DS1302_CLK = P1^7; //實時時鍾時鍾線引腳
sbit DS1302_IO = P1^6; //實時時鍾數據線引腳
sbit DS1302_RST = P1^5; //實時時鍾復位線引腳
sbit wireless_1 = P3^0;
sbit wireless_2 = P3^1;
sbit wireless_3 = P3^2;
sbit wireless_4 = P3^3;
sbit ACC0 = ACC^0;
sbit ACC7 = ACC^7;
char hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year; //秒,分,時到日,月,年位閃的計數
sbit Set = P2^0; //模式切換鍵
sbit Up = P2^1; //加法按鈕
sbit Down = P2^2; //減法按鈕
sbit out = P2^3; //立刻跳出調整模式按鈕
char done,count,temp,flag,up_flag,down_flag;
uchar TempBuffer[5],week_value[2];

/***********DS1302時鍾部分子程序******************/
typedef struct __SYSTEMTIME__
{
unsigned char Second;
unsigned char Minute;
unsigned char Hour;
unsigned char Week;
unsigned char Day;
unsigned char Month;
unsigned char Year;
unsigned char DateString[11];
unsigned char TimeString[9];
}SYSTEMTIME; //定義的時間類型
SYSTEMTIME CurrentTime;

#define AM(X) X
#define PM(X) (X+12) // 轉成24小時制
#define DS1302_SECOND 0x80 //時鍾晶元的寄存器位置,存放時間
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_WEEK 0x8A
#define DS1302_DAY 0x86
#define DS1302_MONTH 0x88
#define DS1302_YEAR 0x8C

void DS1302InputByte(unsigned char d) //實時時鍾寫入一位元組(內部函數)
{
unsigned char i;
ACC = d;
for(i=8; i>0; i--)
{
DS1302_IO = ACC0; //相當於匯編中的 RRC
DS1302_CLK = 1;
DS1302_CLK = 0;
ACC = ACC >> 1;
}
}

unsigned char DS1302OutputByte(void) //實時時鍾讀取一位元組(內部函數)
{
unsigned char i;
for(i=8; i>0; i--)
{
ACC = ACC >>1; //相當於匯編中的 RRC
ACC7 = DS1302_IO;
DS1302_CLK = 1;
DS1302_CLK = 0;
}
return(ACC);
}

void Write1302(unsigned char ucAddr, unsigned char ucDa) //ucAddr: DS1302地址, ucData: 要寫的數據
{
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr); // 地址,命令
DS1302InputByte(ucDa); // 寫1Byte數據
DS1302_CLK = 1;
DS1302_RST = 0;
}

unsigned char Read1302(unsigned char ucAddr) //讀取DS1302某地址的數據
{
unsigned char ucData;
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr|0x01); // 地址,命令
ucData = DS1302OutputByte(); // 讀1Byte數據
DS1302_CLK = 1;
DS1302_RST = 0;
return(ucData);
}

void DS1302_GetTime(SYSTEMTIME *Time) //獲取時鍾晶元的時鍾數據到自定義的結構型數組
{
unsigned char ReadValue;
ReadValue = Read1302(DS1302_SECOND);
Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_MINUTE);
Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_HOUR);
Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_DAY);
Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_WEEK);
Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_MONTH);
Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_YEAR);
Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
}

void DateToStr(SYSTEMTIME *Time) //將時間年,月,日,星期數據轉換成液晶顯示字元串,放到數組里DateString[]
{ if(hide_year<2) //這里的if,else語句都是判斷位閃爍,<2顯示數據,>2就不顯示,輸出字元串為 2007/07/22
{
Time->DateString[0] = '2';
Time->DateString[1] = '0';
Time->DateString[2] = Time->Year/10 + '0';
Time->DateString[3] = Time->Year%10 + '0';
}
else
{
Time->DateString[0] = ' ';
Time->DateString[1] = ' ';
Time->DateString[2] = ' ';
Time->DateString[3] = ' ';
}
Time->DateString[4] = '/';
if(hide_month<2)
{
Time->DateString[5] = Time->Month/10 + '0';
Time->DateString[6] = Time->Month%10 + '0';
}
else
{
Time->DateString[5] = ' ';
Time->DateString[6] = ' ';
}
Time->DateString[7] = '/';
if(hide_day<2)
{
Time->DateString[8] = Time->Day/10 + '0';
Time->DateString[9] = Time->Day%10 + '0';
}
else
{
Time->DateString[8] = ' ';
Time->DateString[9] = ' ';
}
if(hide_week<2)
{
week_value[0] = Time->Week%10 + '0'; //星期的數據另外放到 week_value[]數組里,跟年,月,日的分開存放,因為等一下要在最後顯示
}
else
{
week_value[0] = ' ';
}
week_value[1] = '\0';

Time->DateString[10] = '\0'; //字元串末尾加 '\0' ,判斷結束字元
}

void TimeToStr(SYSTEMTIME *Time) //將時,分,秒數據轉換成液晶顯示字元放到數組 TimeString[];
{ if(hide_hour<2)
{
Time->TimeString[0] = Time->Hour/10 + '0';
Time->TimeString[1] = Time->Hour%10 + '0';
}
else
{
Time->TimeString[0] = ' ';
Time->TimeString[1] = ' ';
}
Time->TimeString[2] = ':';
if(hide_min<2)
{
Time->TimeString[3] = Time->Minute/10 + '0';
Time->TimeString[4] = Time->Minute%10 + '0';
}
else
{
Time->TimeString[3] = ' ';
Time->TimeString[4] = ' ';
}
Time->TimeString[5] = ':';
if(hide_sec<2)
{
Time->TimeString[6] = Time->Second/10 + '0';
Time->TimeString[7] = Time->Second%10 + '0';
}
else
{
Time->TimeString[6] = ' ';
Time->TimeString[7] = ' ';
}
Time->DateString[8] = '\0';
}

void Initial_DS1302(void) //時鍾晶元初始化
{
unsigned char Second="Read1302"(DS1302_SECOND);
if(Second&0x80) //判斷時鍾晶元是否關閉
{
Write1302(0x8e,0x00); //寫入允許
Write1302(0x8c,0x07); //以下寫入初始化時間 日期:07/07/25.星期: 3. 時間: 23:59:55
Write1302(0x88,0x07);
Write1302(0x86,0x25);
Write1302(0x8a,0x07);
Write1302(0x84,0x23);
Write1302(0x82,0x59);
Write1302(0x80,0x55);
Write1302(0x8e,0x80); //禁止寫入
}

}

void Upkey()//升序按鍵
{
Up=1;
if(Up==0||wireless_2==1)
{
mdelay(8);
switch(count)
{case 1:
temp="Read1302"(DS1302_SECOND); //讀取秒數
temp="temp"+1; //秒數加1
up_flag=1; //數據調整後更新標志
if((temp&0x7f)>0x59) //超過59秒,清零
temp="0";
break;
case 2:
temp="Read1302"(DS1302_MINUTE); //讀取分數
temp="temp"+1; //分數加1
up_flag=1;
if(temp>0x59) //超過59分,清零
temp="0";
break;
case 3:
temp="Read1302"(DS1302_HOUR); //讀取小時數
temp="temp"+1; //小時數加1
up_flag=1;
if(temp>0x23) //超過23小時,清零
temp="0";
break;
case 4:
temp="Read1302"(DS1302_WEEK); //讀取星期數
temp="temp"+1; //星期數加1
up_flag=1;
if(temp>0x7)
temp="1";
break;
case 5:
temp="Read1302"(DS1302_DAY); //讀取日數
temp="temp"+1; //日數加1
up_flag=1;
if(temp>0x31)
temp="1";
break;
case 6:
temp="Read1302"(DS1302_MONTH); //讀取月數
temp="temp"+1; //月數加1
up_flag=1;
if(temp>0x12)
temp="1";
break;
case 7:
temp="Read1302"(DS1302_YEAR); //讀取年數
temp="temp"+1; //年數加1
up_flag=1;
if(temp>0x85)
temp="0";
break;
default:break;
}

while(Up==0);
while(wireless_2==1);
}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Downkey()//降序按鍵
{
Down=1;
if(Down==0||wireless_3==1)
{
mdelay(8);
switch(count)
{case 1:
temp="Read1302"(DS1302_SECOND); //讀取秒數
temp="temp-1"; //秒數減1
down_flag=1; //數據調整後更新標志
if(temp==0x7f) //小於0秒,返回59秒
temp="0x59";
break;
case 2:
temp="Read1302"(DS1302_MINUTE); //讀取分數
temp="temp-1"; //分數減1
down_flag=1;
if(temp==-1)
temp="0x59"; //小於0秒,返回59秒
break;
case 3:
temp="Read1302"(DS1302_HOUR); //讀取小時數
temp="temp-1"; //小時數減1
down_flag=1;
if(temp==-1)
temp="0x23";
break;
case 4:
temp="Read1302"(DS1302_WEEK); //讀取星期數
temp="temp-1"; //星期數減1
down_flag=1;
if(temp==0)
temp="0x7";;
break;
case 5:
temp="Read1302"(DS1302_DAY); //讀取日數
temp="temp-1"; //日數減1
down_flag=1;
if(temp==0)
temp="31";
break;
case 6:
temp="Read1302"(DS1302_MONTH); //讀取月數
temp="temp-1"; //月數減1
down_flag=1;
if(temp==0)
temp="12";
break;
case 7:
temp="Read1302"(DS1302_YEAR); //讀取年數
temp="temp-1"; //年數減1
down_flag=1;
if(temp==-1)
temp="0x85";
break;
default:break;
}

while(Down==0);
while(wireless_3==1);
}
}

void Setkey()//模式選擇按鍵
{
Set=1;
if(Set==0||wireless_4==1)
{
mdelay(8);
count="count"+1; //Setkey按一次,count就加1
done="1"; //進入調整模式
while(Set==0);
while(wireless_4==1);
}

}

void keydone()//按鍵功能執行
{ uchar Second;
if(flag==0) //關閉時鍾,停止計時
{ Write1302(0x8e,0x00); //寫入允許
temp="Read1302"(0x80);
Write1302(0x80,temp|0x80);
Write1302(0x8e,0x80); //禁止寫入
flag="1";
}
Setkey(); //掃描模式切換按鍵
switch(count)
{case 1:do //count=1,調整秒
{
outkey(); //掃描跳出按鈕
Upkey(); //掃描加按鈕
Downkey(); //掃描減按鈕
if(up_flag==1||down_flag==1) //數據更新,重新寫入新的數據
{
Write1302(0x8e,0x00); //寫入允許
Write1302(0x80,temp|0x80); //寫入新的秒數
Write1302(0x8e,0x80); //禁止寫入
up_flag=0;
down_flag=0;
}

hide_sec++; //位閃計數
if(hide_sec>3)
hide_sec=0;
show_time(); //液晶顯示數據
}while(count==2);break;
case 2:do //count=2,調整分
{
hide_sec=0;
outkey();
Upkey();
Downkey();
if(temp>0x60)
temp="0";
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //寫入允許
Write1302(0x82,temp); //寫入新的分數
Write1302(0x8e,0x80); //禁止寫入
up_flag=0;
down_flag=0;
}
hide_min++;
if(hide_min>3)
hide_min=0;
show_time();
}while(count==3);break;
case 3:do //count=3,調整小時
{
hide_min=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //寫入允許
Write1302(0x84,temp); //寫入新的小時數
Write1302(0x8e,0x80); //禁止寫入
up_flag=0;
down_flag=0;
}
hide_hour++;
if(hide_hour>3)
hide_hour=0;
show_time();
}while(count==4);break;
case 4:do //count=4,調整星期
{
hide_hour=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //寫入允許
Write1302(0x8a,temp); //寫入新的星期數
Write1302(0x8e,0x80); //禁止寫入
up_flag=0;
down_flag=0;
}
hide_week++;
if(hide_week>3)
hide_week=0;
show_time();
}while(count==5);break;
case 5:do //count=5,調整日
{
hide_week=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //寫入允許
Write1302(0x86,temp); //寫入新的日數
Write1302(0x8e,0x80); //禁止寫入
up_flag=0;
down_flag=0;
}
hide_day++;
if(hide_day>3)
hide_day=0;
show_time();
}while(count==6);break;
case 6:do //count=6,調整月
{
hide_day=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //寫入允許
Write1302(0x88,temp); //寫入新的月數
Write1302(0x8e,0x80); //禁止寫入
up_flag=0;
down_flag=0;
}
hide_month++;
if(hide_month>3)
hide_month=0;
show_time();
}while(count==7);break;
case 7:do //count=7,調整年
{
hide_month=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //寫入允許
Write1302(0x8c,temp); //寫入新的年數
Write1302(0x8e,0x80); //禁止寫入
up_flag=0;
down_flag=0;
}
hide_year++;
if(hide_year>3)
hide_year=0;
show_time();
}while(count==8);break;
case 8: count="0";hide_year=0; //count8, 跳出調整模式,返回默認顯示狀態
Second="Read1302"(DS1302_SECOND);
Write1302(0x8e,0x00); //寫入允許
Write1302(0x80,Second&0x7f);
Write1302(0x8E,0x80); //禁止寫入
done="0";
break; //count=7,開啟中斷,標志位置0並退出
default:break;

}

}

㈢ 誰會讀寫DS1307,並顯示到1602上

/******************************************************************************************************************************/
/* smally 2008.5.20 南陽師范學院*/

#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit lcdrs=P2^7;
sbit lcden=P2^6;
sbit rtscl=P2^1;
sbit rtsda=P2^2;
sbit da_18b20=P2^0;
uchar code table[]="0123456789";
uchar table1[8];
uchar convert_begin;
uint t_click,tp;
//*****************************************/
//1602操作相關函數
//*****************************************/
void wait() //上電後延時操作,等待各晶元准備好 //avoid error
{
uint i=60000;
while(i>0)i--;
}
void delay() // 操作之間的時間間隔
{
uchar i=200;
while(i>0)i--;
}
void write_com(uchar com) //寫命令到1602
{
lcdrs=0;
P0=com;
lcden=1;
delay();
lcden=0;
}
void write_dat(uchar dat) //寫數據到1602
{
lcdrs=1;
P0=dat;
lcden=1;
delay();
lcden=0;
}

void init_1602() //初始化1602
{
lcden=0;
write_com(0x01);delay();
write_com(0x80);delay();
write_com(0x38);delay();
write_com(0x0c);delay();
write_com(0x06);delay();
}
//**********************************************
//over
//**********************************************

//********************************************/
//ds1307相關操作函數//傳送與接收數據都是先高位
//********************************************/
void rt_delay() //操作延時,等待信號穩定
{
uchar i=10;
while(i>0)i--;
}
void init_1307() //初始化1307
{
rtscl = 1; rt_delay(); rtsda = 1; rt_delay();
}
void start_1307() // 開始信號
{
rtsda = 1; rtscl = 1; rt_delay(); rtsda = 0; rt_delay();
}
void stop_1307() // 結束信號
{
rtsda = 0; rtscl = 1; rt_delay(); rtsda = 1; rt_delay();
}
void write_1307(uchar d ) //寫1307
{
uchar i,j; rtscl = 0;
for(i = 0;i < 8; i++)
{
rtsda = (d >> 7);
rtscl = 1;
rt_delay();
d = d << 1;
rtscl = 0;
}
rtsda = 1;
rtscl = 1;
while((rtsda == 1) && (j < 255))j++;
rtscl=0;
}
uchar read_1307(uchar b) //讀1307
{
uchar d ,i;
rtsda = 1; rtscl = 0;
for(i = 0; i < 8; i++)
{
rtscl = 1;
rt_delay();
d = d << 1;
d = d | rtsda;
rtscl=0;
}
rtsda = b;
rt_delay();
rtscl = 0;
rtscl = 1;
return d;
}
read_8byte_1307()
{
uchar i;
start_1307( );
write_1307( 0xd0 );
write_1307( 0x00 );
stop_1307( );
for(i = 0;i < 8; i++)
{
start_1307();
write_1307(0xd1);
table1[i]=read_1307(1);
stop_1307();
}
}
//**********************************************
//over
//**********************************************

//**********************************************
//18b20操作相關函數
//**********************************************
void reset_time_18b20() //延時640us
{
uint i;
i=80;
while(i>0)i--;
}

void wrbyte(uchar b) //寫一個位元組
{
uchar i,j;
bit btmp;
for(j=1;j<=8;j++)
{
btmp=b&0x01;
b=b>>1;
if(btmp)
{
da_18b20=0;
i++;i++;
da_18b20=1;
i=40; //寫1時,15us內拉高數據線,總時間時隙不低於60us
while(i>0)i--;
}
else
{
da_18b20=0;
i=40; //寫0時,拉低至少60us
while(i>0)i--;
da_18b20=1;
}
}
}

bit rdbit() //讀取18b20的一位
{
uchar i;
uchar b;
da_18b20=0;
i++;i++;i++;i++;i++;
da_18b20=1;
i=10; //上升沿15us後讀有效
while(i>0)i--;
b=da_18b20;
i=30;
while(i>0)i--; ///總時間不低於60us
return(b);
}

uchar rdbyte() //讀取18b20的一位元組
{
uchar i,j,byte;

for(i=1;i<=8;i++)
{
j=rdbit();
byte=(j<<7)|(byte>>1);
}

return(byte);
}

uchar init_18b20() //初始化18b20
{
uint j=0;
da_18b20=0;
reset_time_18b20();
da_18b20=1;
while((da_18b20==1)&&(j<250))j++;
if(da_18b20) return 0;
else
{
while(!da_18b20);
return 1;
}
}

void restore()
{
if(t_click==0)
{
if(init_18b20())
{
ET0=0;
while(ET0); //////////操作命令時關閉中斷,以免影響時序
wrbyte(0xcc);//////////skip rom命令
wrbyte(0x44);//////////convert 命令
ET0=1; //////////操作命令後再打開中斷
convert_begin=1;
}
}
}

void read_18b20()
{
uchar tplsb,tpmsb;
if(t_click>100)
{
convert_begin=0;t_click=0;
if(init_18b20())
{
ET0=0;
while(ET0); //////////操作命令時關閉中斷,以免影響時序
wrbyte(0xcc);//////////skip rom命令
wrbyte(0xbe);//////////讀暫存器
tplsb=rdbyte();
tpmsb=rdbyte();
ET0=1; //////////操作命令後再打開中斷
tp=tpmsb*256+tplsb;
}
}
}
//**********************************************
//over
//**********************************************

//**********************************************
//1602顯示函數
//**********************************************

void display()
{
uint nian;
write_com(0x80);delay();
write_dat('D');delay();write_dat('a');delay();
write_dat('t');delay();write_dat(':');delay();
//顯示日期信息
nian=table1[7]/16*10+table1[7]%16;
write_dat('2');delay();
write_dat(table[(table1[6]/100)]);delay();
write_dat(table[(table1[6]%100/10)]);delay();
write_dat(table[(table1[6]%10)]);delay();
//間隔符號'-'
write_dat('-');delay();
//顯示月份
write_dat(table[table1[5]/16%2]);delay();
write_dat(table[table1[5]%16]);delay();
//間隔符號'-'
write_dat('-');delay();
//顯示日期
write_dat(table[table1[4]/16%4]);delay();
write_dat(table[table1[4]%16]);delay();
//星期
write_dat(' ');delay();
write_dat(table[table1[3]%16]);delay();
//LCD第二行
write_com(0x80+0x40);delay();
write_dat('T');delay();write_dat('i');delay();
write_dat('m');delay();write_dat(':');delay();
//顯示小時
write_dat(table[table1[2]/16%4]);delay();
write_dat(table[table1[2]%16]);delay();
//間隔符號'-'
write_dat('-');delay();
//顯示分鍾
write_dat(table[table1[1]/16%8]);delay();
write_dat(table[table1[1]%16]);delay();
//間隔符號'-'
write_dat('-');delay();
//顯示秒
write_dat(table[table1[0]/16%8]);delay();
write_dat(table[table1[0]%16]);delay();
//顯示溫度
write_dat(' ');delay();
if((tp>>11)==0)
{write_dat('+');delay();
write_dat(table[(tp>>4)/10]);delay();
write_dat(table[(tp>>4)%10]);delay();
}
else
{write_dat('-');delay();
write_dat(table[((~(tp-1))>>4)/10]);delay();
write_dat(table[((~(tp-1))>>4)%10]);delay();
}

}

//**********************************************
//over
//**********************************************

//**********************************************

//main主函數

//**********************************************
void main()
{
TMOD=0x01;
TH0=(65536-1000)/256;
TL0=(65536-1000)%256; //定時器初始化
EA=1;
ET0=1;
TR0=1;

wait(); //上電前預熱
init_1602();
init_1307();
if(init_18b20())
{
ET0=0;
while(ET0); //////////操作命令時關閉中斷,以免影響時序
wrbyte(0xcc);//////////skip rom命令
wrbyte(0x4E);//////////寫暫存器命令
wrbyte(0x01);//////////設置上限溫度
wrbyte(0x00);//////////設置下限溫度
wrbyte(0x1f);//////////設置解析度TM/R1/R0/1/1/1/1/1
wrbyte(0x43);//////////復制暫存器
ET0=1; //////////操作命令後再打開中斷

}
start_1307();
write_1307(0xd0);
write_1307(0x00);
write_1307(0x00);
write_1307(0x59);
write_1307(0x12);
write_1307(0x05);
write_1307(0x03);
write_1307(0x07);
write_1307(0x09);
stop_1307();
while(1)
{
restore();
read_18b20();
read_8byte_1307();
display();
}
}

//****************************************************************

//over

//***************************************************************

//***************************************************************

//中斷服務子程序

//***************************************************************

void time0() interrupt 1 using 1
{
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
if(convert_begin)t_click++;
}
//****************************************************************

//over

//****************************************************************

//**********************************************that's alll*******************************************************************//

㈣ 單片機 DS1302時鍾讀寫問題

uchar read_Byte()
{
uchar i;
for(i = 8;i > 0;i--)
{
ACC = ACC >> 1;
ACC7 = ds1302_IO;
ds1302_SCLK = 1;
ds1302_SCLK = 0;
}
return(ACC);
}

是的,你要相信自己,然後多實踐,網上的東西只做一個參考,對不對還要由你自己來驗證。

㈤ 樹莓派基礎實驗32:DS1302實時時鍾模塊實驗

  現在有很多流行的串列時鍾晶元,如DS1302,DS1307,PCF8485等,由於簡單的介面,低成本和易用性,他們被廣泛應用於電話、傳真、攜帶型儀器等產品領域。在本實驗中,我們將使用DS1302實時時鍾(RTC)模塊獲取當前日期和時間。

  DS1302可以用於數據記錄,特別是對某些具有特殊意義的數據點的記錄,能實現數據與出現該數據的時間同時記錄。這種記錄對長時間的連續測控系統結果的分析,及對異常數據出現的原因的查找具有重要意義。

  傳統的數據記錄方式是隔時采樣或定時采樣,沒有具體的時間記錄,因此,只能記錄數據而無法准確記錄其出現的時間;若採用單片機計時,一方面需要採用計數器,佔用硬體資源,另一方面需要設置中斷、查詢等,同樣耗費單片機的資源,而且,某些測控系統可能不允許。但是,如果在系統中採用時鍾晶元DS1302,則能很好地解決這個問題。

★Raspberry Pi 3主板*1

★樹莓派電源*1

★40P軟排線*1

★DS1302實時時鍾模塊*1

★麵包板*1

★跳線若干

  DS1302是DALLAS(達拉斯)公司出的一款涓流充電時鍾晶元,2001年DALLAS被MAXIM(美信)收購。
  DS1302實時時鍾晶元廣泛應用於電話、傳真、攜帶型儀器等產品領域,他的主要性能指標如下:
  1、DS1302是一個實時時鍾晶元,可以提供秒、分、小時、日期、月、年等信息,並且還有軟年自動調整的能力,可以通過配置AM/PM來決定採用24小時格式還是12小時格式。
  2、擁有31位元組數據存儲RAM。
  3、串列I/O通信方式,相對並行來說比較節省IO口的使用。
  4、DS1302的工作電壓比較寬,大概是2.0V~5.5V都可以正常工作。
  5、DS1302這種時鍾晶元功耗一般都很低,它在工作電壓2.0V的時候,工作電流小於300nA。
  6、DS1302共有8個引腳,有兩種封裝形式,一種是DIP-8封裝,晶元寬度(不含引腳)是300mil,一種是SOP-8封裝,有兩 種寬度,一種是150mil,一種是208mil。我們看一下DS1302的引腳封裝圖:

  7、當供電電壓是5V的時候,兼容標準的TTL電平標准,這里的意思是,可以完美的和單片機進行通信。
   8、由於DS1302是DS1202的升級版本,所以所有的功能都兼容DS1202。此外DS1302有兩個電源輸入,一個是主電源, 另外一個是備用電源,比如可以用電池或者大電容,這樣是為了保證系統掉電的情況下,我們的時鍾還會繼續走。如果使用的是充電電池,還可以在正常工作時,設置充電功能,給我們的備用電池進行充電。

  DS1302的特點第二條「擁有31位元組數據存儲RAM」,這是DS1302額外存在的資源。這31位元組的RAM相當於一個存儲器一樣,我們編寫單片機程序的時候,可以把我們想存儲的數據存儲在DS1302里邊,需要的時候讀出來,這塊功能和EEPROM有點類似,相當於一個掉電丟失數據的「EEPROM」,如果我們的時鍾電路加上備用電池,那麼這31個位元組的RAM就可以替代EEPROM的功能了。

  DS1302一共有8個引腳,下邊要根據引腳分布圖和典型電路圖來介紹一下每個引腳的功能:

  DS1302的電路一個重點就是時鍾電路,它所使用的晶振是一個32.768k的晶振,晶振外部也不需要額外添加其他的電容或者電阻電路了。時鍾的精度,首先取決於晶振的精度以及晶振的引腳負載電容。如果晶振不準或者負載電容過大過小,都會導致時鍾誤差過大。在這一切都搞定後,最終一個考慮因素是晶振的溫漂。隨著溫度的變化,晶振往往精度會發生變化,因此,在實際的系統中,其中一種方法就是經常校對。比如我們所用的電腦的時鍾,通常我們會設置一個選項「將計算機設置於internet時間同步」。選中這個選項後,一般可以過一段時間,我們的計算機就會和internet時間校準同步一次。

  對DS1302的操作就是對其內部寄存器的操作,DS1302內部共有12個寄存器,其中有7個寄存器與日歷、時鍾相關,存放的數據位為BCD碼形式。此外,DS1302還有年份寄存器、控制寄存器、充電寄存器、時鍾突發寄存器及與RAM相關的寄存器等。時鍾突發寄存器可一次性順序讀/寫除充電寄存器以外的寄存器。

  DS1302的一條指令一個位元組8位,其中第7位(即最高位)是固定1,這一位如果是0的話,那寫進去是無效的。第6位是選擇RAM還是CLOCK的,這里主要講CLOCK時鍾的使用,它的RAM功能我們不用,所以如果選擇CLOCK功能,第6位是0,如果要用RAM,那第6位就是1。從第5到第1位,決定了寄存器的5位地址,而第0位是讀寫位,如果要寫,這一位就是0,如果要讀,這一位就是1。

  DS1302時鍾的寄存器,其中8個和時鍾有關的,5位地址分別是00000一直到00111這8個地址,還有一個寄存器的地址是01000,這是涓流充電所用的寄存器,我們這里不講。在DS1302的數據手冊里的地址,直接把第7位、第6位和第0位值給出來了,所以指令就成了80H、81H那些了,最低位是1,那麼表示讀,最低位是0表示寫。

  寄存器一:最高位CH是一個時鍾停止標志位。如果我們的時鍾電路有備用電源部分,上電後,我們要先檢測一下這一位,如果這一位是0,那說明我們的時鍾在系統掉電後,由於備用電源的供給,時鍾是持續正常運行的;如果這一位是1,那麼說明我們的時鍾在系統掉電後,時鍾部分不工作了。若我們的Vcc1懸空或者是電池沒電了,當我們下次重新上電時,讀取這一位,那這一位就是1,我們可以通過這一位判斷時鍾在單片機系統掉電後是否持續運行。剩下的7位高3位是秒的十位,低4位是秒的個位,這里注意再提一次,DS1302內部是BCD碼,而秒的十位最大是5,所以3個二進制位就夠了。
  寄存器二:bit7沒意義,剩下的7位高3位是分鍾的十位,低4位是分鍾的個位。
  寄存器三:bit7是1的話代表是12小時制,是0的話代表是24小時制,bit6固定是0,bit5在12小時制下0代表的是上午,1代表的是下午,在24小時制下和bit4一起代表了小時的十位,低4位代表的是小時的個位。
  寄存器四:高2位固定是0,bit5和bit4是日期的十位,低4位是日期的個位。
  寄存器五:高3位固定是0,bit4是月的十位,低4位是月的個位。
  寄存器六:高5位固定是0,低3位代表了星期。
  寄存器七:高4位代表了年的十位,低4位代表了年的個位。這里特別注意,這里的00到99年指的是2000年到2099年。
  寄存器八:bit7是一個保護位,如果這一位是1,那麼是禁止給任何其他的寄存器或者那31個位元組的RAM寫數據的。因此在寫數據之前,這一位必須先寫成0。

   物理上,DS1302的通信介面由3個口線組成,即RST,SCLK,I/O。其中RST從低電平變成高電平啟動一次數據傳輸過程,SCLK是時鍾線,I/O是數據線。這個DS1302的通信線定義和SPI很像,事實上,DS1302的通信是SPI的變異種類,它用了SPI的通信時序,但是通信的時候沒有完全按照SPI的規則來,下面我們介紹DS1302的變異SPI通信方式。

  請注意數據是對時鍾信號敏感的,而且一般數據是在下降沿寫入,上升沿讀出。平時SCLK保持低電平,當需要寫命令或者寫數據時,在時鍾輸出變為高電平之前先輸出數據;當需要讀數據時,在時鍾輸出變為高電平之前采樣讀取數據。

   第1步: 連接電路。

   第2步: DS1302的Python程序比較復雜,我們先編寫一個模塊ds1302.py,在裡面創建一個類DS1302(),在裡面編寫讀取時鍾信息等方法。

   第3步: 編寫實際控製程序,導入上面的模塊ds1302。運行本文件,不斷循環讀取並列印時鍾信息。

  實驗結果示例:

㈥ DS1307讀取時間出問題了,幫忙看看錯哪了

gfu

㈦ c語言編的DS1302怎麼讀出和寫入數據

這是匯編版的dS1302驅動程序,你可以參考一下。
PUBLIC D1302_INIT,SET1302,GET1302,WRITE,READ
CODE_DS1302 SEGMENT CODE
T_CLK BIT P1.0
T_IO BIT P1.1
T_RST BIT P1.2
SECOND EQU 30H
MINUTE EQU 31H
HOUR EQU 32H
DAY EQU 33H
MONTH EQU 34H
WEEK EQU 35H
YEAR EQU 36H

RSEG CODE_DS1302 ;使用當前段
;以下是DS1302初始化子程序
D1302_INIT: CLR T_RST ;DS1302復位
CLR T_CLK
NOP
NOP
SETB T_RST
MOV R1,#80H
MOV R0,#00H
LCALL WRITE
MOV R1,#90H
MOV R0,#0ABH
LCALL WRITE
RET
;以下是 讀 日期時間數據子程序
GET1302: MOV R1,#81H
LCALL READ
MOV SECOND,R0
MOV R1,#83H
LCALL READ
MOV MINUTE,R0
MOV R1,#85H
LCALL READ
MOV HOUR,R0
MOV R1,#87H
LCALL READ
MOV DAY,R0
MOV R1,#89H
LCALL READ
MOV MONTH,R0
MOV R1,#8BH
LCALL READ
MOV WEEK,R0
MOV R1,#8DH
LCALL READ
MOV YEAR,R0
RET
;以下是時鍾日歷寫操作子程序(單片機向DS1302寫入初始時間)
SET1302: MOV R1,#80H ;寫 秒
LCALL WRITE
MOV SECOND,R0
MOV R1,#82H ;寫 分
LCALL WRITE
MOV MINUTE,R0
MOV R1,#84H ;寫 時
LCALL WRITE
MOV HOUR,R0
MOV R1,#86H ;寫 天
LCALL WRITE
MOV DAY,R0
MOV R1,#88H ;寫 月
LCALL WRITE
MOV MONTH,R0
MOV R1,#8AH ;寫 周
LCALL WRITE
MOV WEEK,R0
MOV R1,#8CH ;寫 年
LCALL WRITE
MOV YEAR,R0
RET
;以下是 寫 一個位元組地址和數據的子程序
WRITE: CLR T_CLK
NOP
NOP
SETB T_RST
NOP
MOV A,R1
MOV R2,#08H
WRI_01: RRC A
NOP
NOP
CLR T_CLK
NOP
NOP
MOV T_IO,C
NOP
NOP
SETB T_CLK
NOP
NOP
DJNZ R2,WRI_01
CLR T_CLK
NOP
NOP
MOV A,R0
MOV R2,#08H
WRI_02: RRC A
NOP
CLR T_CLK
NOP
NOP
MOV T_IO,C
NOP
NOP
SETB T_CLK
NOP
NOP
DJNZ R2,WRI_02
CLR T_CLK
NOP
NOP
CLR T_RST
NOP
NOP
RET

;以下是從DS1302讀取一位元組地址中數據子程序
READ: CLR T_CLK
NOP
NOP
SETB T_RST
NOP
NOP
MOV A,R1
MOV R2,#08H
READ_01: RRC A
NOP
MOV T_IO,C
NOP
NOP
SETB T_CLK
NOP
NOP
CLR T_CLK
NOP
NOP
DJNZ R2,READ_01
NOP
NOP
SETB T_IO
CLR A
CLR C
MOV R2,#08H
READ_02: CLR T_CLK
NOP
NOP
MOV C,T_IO
NOP
NOP
RRC A
NOP
NOP
SETB T_CLK
NOP
NOP
DJNZ R2,READ_02
MOV R0,A
CLR T_RST
RET
END

㈧ ds1302是怎麼個工作過程,怎麼把當前時間賦給它,又是怎樣通過控制段選、位選來顯示ds1302寫入的時間

首先、你要寫一個讀位元組函數(根據1302的讀寫時序);其次、你要知道時、分、秒等寄存器的地址,給它們宏定義了;然後、你就可以根據原先定義好的讀函數來讀取當前時間寄存器中的數據了(也就是把時、分、秒等讀取出來);最後、做數據處理就可以拿來顯示了。不知樓主是否可以給分了……

㈨ Tiny RTC I2C模塊的DS1307連續讀取時間時,有時會死掉,這是什麼問題

IIC匯流排的時序有問題,看看匯流排的時鍾頻率和應答位那裡處理的不合適

㈩ 單片機問題:單片機從ds1302時鍾晶元io口讀出來的數據是什麼進制的,那怎麼送到1602液晶顯示呢

BCD碼(16進制數)。參考下面的程序(取數後送1602顯示)
//向LCM中填寫 年 數據
void lcm_w_yy(void){
//if(read_clock(0x8d) != yy){
yy = read_clock(0x8d);
lcm_w_test(0,0x83);
lcm_w_word("20");
lcm_w_test(0,0x84);
lcm_w_test(1,(yy/16)+0x30);
lcm_w_test(1,yy%16+0x30);
} //}
/*****************************************************************************/
//向LCM中填寫 月 數據
void lcm_w_mo(void){
//if(read_clock(0x89) != mo){
mo = read_clock(0x89);
lcm_w_test(0,0x90);
if(mo/16 != 0){lcm_w_test(1,(mo/16)+0x30);} //十位消隱
else{lcm_w_test(1,0x20);}//同上
lcm_w_test(1,mo%16+0x30);
lcm_w_test(0,0x91);
lcm_w_word("月");
} //}
/*****************************************************************************/
//星期處理並送入LCM的指定區域
void lcm_w_xq(void){
unsigned char sel;
//if(read_clock(0x8b) != xq){
xq = read_clock(0x8b);
sel = (read_clock(0x8b))%16; //位元組低4位的BCD碼放入sel
lcm_w_test(0,0x97);//寫入指定區域(97H 第二行第8個字)
if(sel==7) {lcm_w_word("日");} //
if(sel==6) {lcm_w_word("六");} //
if(sel==5) {lcm_w_word("五");} //
if(sel==4) {lcm_w_word("四");} //
if(sel==3) {lcm_w_test(1,0xc8);lcm_w_test(1,0xfd);} //此指令等於lcm_w_word("三"); 因為「三」的內碼失效。
if(sel==2) {lcm_w_word("二");} //
if(sel==1) {lcm_w_word("一");} //星期一
lcm_w_test(0,0x95);
lcm_w_word("星期");
} //}
/*****************************************************************************/
//向LCM中填寫 日 數據
void lcm_w_dd(void){
// if(read_clock(0x87) != dd){
dd = read_clock(0x87);
lcm_w_test(0,0x92);
if(dd/16 != 0){lcm_w_test(1,(dd/16)+0x30);} //十位消隱
else{lcm_w_test(1,0x20);}//同上
lcm_w_test(1,dd%16+0x30);
lcm_w_test(0,0x93);
lcm_w_word("日 ");

} //}
/*****************************************************************************/
//向LCM中填寫 小時 數據
void lcm_w_hh(void){
if(read_clock(0x85) != hh){
hh = read_clock(0x85);
if (hh > 0x07 && hh < 0x22 && w == 0){
Beep();//整點報時音
}
}
lcm_w_test(0,0x88);
lcm_w_test(1,(hh/16)+0x30);
lcm_w_test(1,hh%16+0x30);

}
/*****************************************************************************/
//向LCM中填寫 分鍾 數據
void lcm_w_mm(void){
if(read_clock(0x83) != mm){
mm = read_clock(0x83);
}
if(w == 0){
days();//節日顯示
}
lcm_w_test(0,0x89);
lcm_w_test(1,0x3a); //":"
lcm_w_test(1,(mm/16)+0x30);
lcm_w_test(1,mm%16+0x30);
lcm_w_test(1,0x2e); //"."
}
/*****************************************************************************/
//刷新數據
void updata (void){
lcm_w_mm();//刷新 分
lcm_w_hh();//刷新 小時
lcm_w_dd();//刷新 日
lcm_w_xq();//更新星期值
lcm_w_mo();//刷新 月
lcm_w_yy();//刷新 年
}
/*****************************************************************************/
//向LCM中填寫 秒 數據
void lcm_w_ss(void){
unsigned int i=0;
unsigned char a=0,b=0,c=0;
if(read_clock(0x81) != ss){ //判斷是否需要更新
ss = read_clock(0x81); //更新數據
lcm_w_test(0,0x8b); //秒值在LCM上的寫入位置
lcm_w_test(1,(ss/16)+0x30); //寫十位
lcm_w_test(1,ss%16+0x30); //寫個位
lcm_w_word(" ");
led_b = ~led_b; //LED閃爍
updata (); //刷新數據
lcm_w_test(0,0x8d); //溫度在LCM上的寫入位置
i=ReadTemperature();//讀溫度並送顯
a=i/100;
lcm_w_test(1,a+0x30); //顯示溫度十位
b=i/10-a*10;
lcm_w_test(1,b+0x30); //個位
lcm_w_test(1,0x2e); //"."
c=i-a*100-b*10;
lcm_w_test(1,c+0x30); //小位1位
lcm_w_word("℃"); //度C
} }

閱讀全文

與ds1307時鍾讀出來的數據怎麼處理相關的資料

熱點內容
如何在微信小程序辦理冀時辦 瀏覽:863
蘇醒之路怎麼修改數據 瀏覽:964
信息如何找回前一天刪除的 瀏覽:123
廣東2018中博會哪些產品 瀏覽:437
造船企業技術部怎麼樣 瀏覽:98
程序員都要學什麼技能 瀏覽:777
為什麼說銀行理財產品單一 瀏覽:412
路邊停車能採集哪些數據 瀏覽:572
哪些企業可以獲得碳交易配額 瀏覽:292
怎麼和情人聊天讓她不發信息 瀏覽:773
如何確定技術轉讓費 瀏覽:477
生態崗位交易是什麼意思 瀏覽:687
產品經理如何出頭 瀏覽:263
女中專學什麼技術好 瀏覽:609
有脾氣天團小程序怎麼注冊 瀏覽:184
怎麼發起小程序項目 瀏覽:255
運營式系統核心階段技術是什麼 瀏覽:241
瑪莎拉蒂鑰匙怎麼走平台交易 瀏覽:229
電腦核心技術有哪些 瀏覽:584
怎麼把信息錄入大腦系統 瀏覽:7