A. 51单片机和ds1302之间使用什么协议通信,是怎么通信的
51和DS1302之间是串行通讯,具体通讯协议和时序,请参看附件的DataSheet文档(英文)。
B. 基于51单片机的数字时钟为什么用DS1302
因为DS1302比较精准,而且价钱又便宜比DS12C887便宜好多,而且又可以接备用电源电池
C. 51单片机 DS1302时钟程序求助
void DS1302_WriteData(uchar cmd , uchar dat)//写数据指令,参数是命令和数据
{
uchar j,k=1;
RST=0;
SCLK=0;
RST=1;
for(j=0;j<=7;j++) //写控制字
{
if(cmd&k) //取cmd的第j位,并写到数据线上
DATA=1;
else
DATA=0;
SCLK=1; // 时钟高
k<<=1;// 取第J位
SCLK=0; //SCLK低
}
k=1;// 从低位开始
for(j=0;j<=7;j++) //写数据
{
if(dat&k)
DATA=1;
else
DATA=0;
SCLK=1;
k<<=1;
SCLK=0;
}
SCLK=1;
RST=0;
}
D. 51单片机中DS1302芯片的引脚配置原理是什么
CE和SCLK是DS1302芯片的信号线,但也是与单片机的PIO口连接的;
因此初始化CE和SCLK,也就是初始化单片机的PIO口了;
在代码中,你可以去看看 DS1302_CE、DS1302_SCLK 的定义就明白了;
E. 我用DS1302时钟芯片用51单片机怎么时间越走越快应该怎样调整谢谢各位大神帮忙
DS1302时钟的快慢与外接的晶振频率有关,如果越走越快的话,可能是输入的频率发生了变化。
F. 51单片机 外接DS1302
一个是单片机外接晶体,提供单片机工作频率用,多是4M-20M的频率。
一个专门的时钟芯片DS1302专用外接晶体,这种晶体都比较准确稳定,来减少时钟误差。。
DS1302专用晶体频率是32.768kHz,无法和单片机晶体通用。
G. 51单片机控制DS1302,时间显示在数码管上。
1302.c
#include<DS1302.h>
#include<key.h>
ucharbit_ser[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf};
ucharseven_seg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
/***********************时间显示*****************/
voidtimer0_init(void) //T0初始化函数,用于时间的动态显示
{
TMOD=0x21;
TL0=(65536-5000)%256;
TH0=(65536-5000)/256;
EA=1;
ET0=1;
TR0=1;
}
voidtimer0_isr(void)interrupt1 //T0中断处理函数
{
charflag; //flag用于表示调整时闪烁的亮或灭
TR0=0;
TL0=(65536-5000)%256;
TH0=(65536-5000)/256;
TR0=1;
flag=x/100*0xff; //设置闪烁标志,如果x大于100则flag为0xff,小于100则为0x00
x++;
if(x>200)
x=0;
switch(i)
{
case0:
P2=bit_ser[0];
if(setflag==3) //根据setflag的值判断当前位是否需要闪烁
P0=flag|seven_seg[dis_buffer[0]];
else
P0=seven_seg[dis_buffer[0]];
break;
case1:
P2=bit_ser[1];
if(setflag==3)
P0=flag|seven_seg[dis_buffer[1]];
else
P0=seven_seg[dis_buffer[1]];
break;
case2:
P2=bit_ser[2];
if(setflag==2)
P0=flag|seven_seg[dis_buffer[2]];
else
P0=seven_seg[dis_buffer[2]];
break;
case3:
P2=bit_ser[3];
if(setflag==2)
P0=flag|seven_seg[dis_buffer[3]];
else
P0=seven_seg[dis_buffer[3]];
break;
case4:
P2=bit_ser[4];
if(setflag==1)
P0=flag|seven_seg[dis_buffer[4]];
else
P0=seven_seg[dis_buffer[4]];
break;
case5:
P2=bit_ser[5];
if(setflag==1)
P0=flag|seven_seg[dis_buffer[5]];
else
P0=seven_seg[dis_buffer[5]];
break;
}
i++;
if(i>=6)
{
i=0;
if(j==10)
{
j=0;
if(setflag==0)
DS1302_GetTime(&Time); //如果setflag是0,就从1302中读出时间,因为setflag不是0时,说明处于调整状态,不需要读时间
dis_buffer[5]=Time.Second%10; //把当前时间放入显示缓冲区
dis_buffer[4]=Time.Second/10;
dis_buffer[3]=Time.Minute%10;
dis_buffer[2]=Time.Minute/10;
dis_buffer[1]=Time.Hour%10;
dis_buffer[0]=Time.Hour/10;
}
j++;
}
}
voidmain()
{
Initial_DS1302(Time);
timer0_init();
while(1)
{
set_down();
timer_down();
up_down();
down_down();
beepflag_down();
if(setflag==0&&Time.Hour==romhour&&Time.Minute==romminute&&Beepflag==1) //判断蜂鸣器是否要响
Beep=!Beep;
}
}
//key.c
#include<reg51.h>
#defineucharunsignedchar
#defineuintunsignedint
uchari=0,j=0,x=0,setflag,flag_set,flag_timer;//setflag用来表示调整的位置,flag_set和flag_timer分别表示当前处于调整状态还是定时状态
SYSTEMTIMETime={0,20,15,3,30,6,10}; //系统时间的初始值2010年6月30日星期三,15时20分0秒
chardis_buffer[6]; //存放显示数据的缓冲区
sbitBeep_flag=P3^2; //蜂鸣器的接口
sbitkey_timer=P3^4; //定时按钮
sbitkey_set=P3^5; //调整按钮
sbitkey_up=P3^6; //增加按钮
sbitkey_down=P3^7; //减小按钮
charromhour,romminute,romsec; //分别存放定时的时,分,秒
bitBeepflag; //标记闹钟是否开启
//延时函数
voiddelays(ucharx)
{
while(x)x--;
}
//设置键的处理函数
voidset()
{
setflag++;
flag_set=1;
if(setflag>=4)
{
setflag=0;
flag_set=0;
Initial_DS1302(Time);
}
}
//定时间的处理函数
voidtimer()
{
setflag++;
flag_timer=1;
if(setflag==1)
{
Time.Hour=romhour;
Time.Minute=romminute;
Time.Second=romsec;
}
elseif(setflag>=4)
{
setflag=0;
flag_timer=0;
romhour=Time.Hour;
romminute=Time.Minute;
romsec=Time.Second;
}
}
//增加键的处理函数
voip()
{
switch(setflag)
{
case0:
break;
case1:
Time.Second++;
if(Time.Second>=60)
Time.Second=0;
break;
case2:
Time.Minute++;
if(Time.Minute>=60)
Time.Minute=0;
break;
case3:
Time.Hour++;
if(Time.Hour>=24)
Time.Hour=0;
break;
}
}
//减小键的处理函数
voiddown()
{
switch(setflag)
{
case0:
break;
case1:
Time.Second--;
if(Time.Second<0)
Time.Second=59;
break;
case2:
Time.Minute--;
if(Time.Minute<0)
Time.Minute=59;
break;
case3:
Time.Hour--;
if(Time.Hour<0)
Time.Hour=23;
break;
}
}
//设置键的扫描函数
voidset_down()
{
if(key_set==0&&flag_timer==0)
{
delays(100);
if(key_set==0)
{
set();
}
while(!key_set);
}
}
//定时键的扫描函数
voidtimer_down()
{
if(key_timer==0&&flag_set==0)
{
delays(100);
if(key_timer==0)
{
timer();
}
while(!key_timer);
}
}
//增加键的扫描函数
voip_down()
{
if(key_up==0&&setflag!=0)
{
delays(100);
if(key_up==0)
{
up();
while(!key_up);
}
}
}
//减少键的处理函数
voiddown_down()
{
if(key_down==0&&setflag!=0)
{
delays(100);
if(key_down==0)
{
down();
while(!key_down);
}
}
}
//定时开关的扫描处理函数
voidbeepflag_down()
{
if(Beep_flag==0)
{
delays(100);
{
Beepflag=!Beepflag;
while(!Beep_flag);
}
}
}
//ds1302.h
#ifndef_REAL_TIMER_DS1302
#define_REAL_TIMER_DS1302
#include<REG51.h>
sbitDS1302_CLK=P1^1;//实时时钟时钟线引脚
sbitDS1302_IO=P1^2;//实时时钟数据线引脚
sbitDS1302_RST=P1^3;//实时时钟复位线引脚
sbitACC0=ACC^0;
sbitACC7=ACC^7;
sbitBeep=P2^7;
typedefstruct__SYSTEMTIME__
{ charSecond;
charMinute;
charHour;
charWeek;
charDay;
charMonth;
charYear;
}SYSTEMTIME; //定义的时间类型
#defineAM(X) X
#definePM(X) (X+12) //转成24小时制
#defineDS1302_SECOND 0x80//秒寄存器
#defineDS1302_MINUTE 0x82//分寄存器
#defineDS1302_HOUR 0x84
#defineDS1302_WEEK 0x8A
#defineDS1302_DAY 0x86
#defineDS1302_MONTH 0x88
#defineDS1302_YEAR 0x8C
#defineDS1302_RAM(X) (0xC0+(X)*2) //用于计算DS1302_RAM地址的宏
voidDS1302InputByte(unsignedchard) //实时时钟写入一字节(内部函数)
{unsignedchari;
ACC=d;
for(i=8;i>0;i--)
{ DS1302_IO=ACC0; //相当于汇编中的RRC
DS1302_CLK=1;
DS1302_CLK=0;//发一个高跳变到低的脉冲
ACC=ACC>>1;
}
}
unsignedcharDS1302OutputByte(void) //实时时钟读取一字节(内部函数)
{ unsignedchari;
for(i=8;i>0;i--)
{ ACC=ACC>>1; //相当于汇编中的RRC
ACC7=DS1302_IO;
DS1302_CLK=1;
DS1302_CLK=0;//发一个高跳变到低的脉冲
}
return(ACC);
}
voidWrite1302(unsignedcharucAddr,unsignedcharucDa)//ucAddr:DS1302地址,ucData:要写的数据
{ DS1302_RST=0;
DS1302_CLK=0;
DS1302_RST=1;
DS1302InputByte(ucAddr); //地址,命令
DS1302InputByte(ucDa); //写1Byte数据
DS1302_CLK=1;
DS1302_RST=0;//RST0->1->0,CLK0->1
}
unsignedcharRead1302(unsignedcharucAddr) //读取DS1302某地址的数据
{ unsignedcharucData;
DS1302_RST=0;
DS1302_CLK=0;
DS1302_RST=1;//enable
DS1302InputByte(ucAddr|0x01);//地址,命令
ucData=DS1302OutputByte();//读1Byte数据
DS1302_CLK=1;//RST0->1->0,CLK0->1
DS1302_RST=0;
return(ucData);
}
voidDS1302_SetProtect(bitflag)//是否写保护
{ if(flag)
Write1302(0x8E,0x80);//WP=1,不能写入
else
Write1302(0x8E,0x00);//WP=0,可以写入
}
voidDS1302_SetTime(unsignedcharAddress,unsignedcharValue)//设置时间函数
{ DS1302_SetProtect(0);
Write1302(Address,((Value/10)<<4|(Value%10)));//高4位为十位,低4位为个位
DS1302_SetProtect(1);
}
//获取时间函数,从DS1302内读取时间然后存入Time内
voidDS1302_GetTime(SYSTEMTIME*Time)
{ unsignedcharReadValue;
ReadValue=Read1302(DS1302_SECOND);
Time->Second=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);//转换成10进制的秒
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);
}
//利用STime初始化DS1302
voidInitial_DS1302(SYSTEMTIMESTime)
{ unsignedcharSecond=Read1302(DS1302_SECOND);
if(Second&0x80) DS1302_SetTime(DS1302_SECOND,0);//如果第七为1(表明没有启动),则启动时钟
DS1302_SetTime(DS1302_SECOND,STime.Second); //设定起始时间
DS1302_SetTime(DS1302_MINUTE,STime.Minute);
DS1302_SetTime(DS1302_HOUR,STime.Hour);
DS1302_SetTime(DS1302_DAY,STime.Day);
DS1302_SetTime(DS1302_MONTH,STime.Month);
DS1302_SetTime(DS1302_YEAR,STime.Year);
DS1302_SetTime(DS1302_WEEK,STime.Week);
}
#endif
H. 基于51单片机的数字时钟为什么用DS1302
你使用这样的电路可以,前提是不掉电的情况下,而且精确度有待商榷,如果使用DS1302,内置时间寄存器,并可对时间进行校正,同时,如果对其加电池,那么时间不会停止,一直走动,否则,按您的电路,你一关电,所有的时间你得重新设置。希望您明白我的意思。
I. 51单片机DS1302程序
void v_RTInputByte(uchar ucDa)
{
uchar i;
ACC = ucDa;
for(i=8; i>0; i--)
{
T_IO = ACC0; //相当于汇编中的 RRC
T_CLK = 1;
T_CLK = 0;
ACC = ACC >> 1;
}
}
/********************************************************************
*
* 名称: uchar uc_RTOutputByte
* 说明:
* 功能: 从DS1302读取1Byte数据
* 调用:
* 输入:
* 返回值: ACC
***********************************************************************/
uchar uc_RTOutputByte(void)
{
uchar i;
for(i=8; i>0; i--)
{
ACC = ACC >>1; //相当于汇编中的 RRC
ACC7 = T_IO;
T_CLK = 1;
T_CLK = 0;
}
return(ACC);
}
/********************************************************************
*
* 名称: v_W1302
* 说明: 先写地址,后写命令/数据
* 功能: 往DS1302写入数据
* 调用: v_RTInputByte()
* 输入: ucAddr: DS1302地址, ucDa: 要写的数据
* 返回值: 无
***********************************************************************/
void v_W1302(uchar ucAddr, uchar ucDa)
{
T_RST = 0;
T_CLK = 0;
T_RST = 1;
v_RTInputByte(ucAddr); //地址,命令
v_RTInputByte(ucDa); //写1Byte数据
T_CLK = 1;
T_RST =0;
}
/********************************************************************
*
* 名称: uc_R1302
* 说明: 先写地址,后读命令/数据
* 功能: 读取DS1302某地址的数据
* 调用: v_RTInputByte() , uc_RTOutputByte()
* 输入: ucAddr: DS1302地址
* 返回值: ucDa :读取的数据
***********************************************************************/
uchar uc_R1302(uchar ucAddr)
{
uchar ucDa;
T_RST = 0;
T_CLK = 0;
T_RST = 1;
v_RTInputByte(ucAddr); //地址,命令
ucDa = uc_RTOutputByte(); //读1Byte数据
T_CLK = 1;
T_RST =0;
return(ucDa);
}
/********************************************************************
*
* 名称: v_BurstW1302T
* 说明: 先写地址,后写数据(时钟多字节方式)
* 功能: 往DS1302写入时钟数据(多字节方式)
* 调用: v_RTInputByte()
* 输入: pSecDa: 时钟数据地址 格式为: 秒 分 时 日 月 星期 年 控制
* 8Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B 1B
* 返回值: 无
***********************************************************************/
void v_BurstW1302T(uchar *pSecDa)
{
uchar i;
v_W1302(0x8e,0x00); //控制命令,WP=0,写操作?
T_RST = 0;
T_CLK = 0;
T_RST = 1;
v_RTInputByte(0xbe); //0xbe:时钟多字节写命令
for (i=8;i>0;i--) //8Byte = 7Byte 时钟数据 + 1Byte 控制
{
v_RTInputByte(*pSecDa); //写1Byte数据
pSecDa++;
}
T_CLK = 1;
T_RST =0;
}
/********************************************************************
*
* 名称: v_BurstR1302T
* 说明: 先写地址,后读命令/数据(时钟多字节方式)
* 功能: 读取DS1302时钟数据
* 调用: v_RTInputByte() , uc_RTOutputByte()
* 输入: pSecDa: 时钟数据地址 格式为: 秒 分 时 日 月 星期 年
* 7Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B
* 返回值: ucDa :读取的数据
***********************************************************************/
void v_BurstR1302T(uchar *pSecDa)
{
uchar i;
T_RST = 0;
T_CLK = 0;
T_RST = 1;
v_RTInputByte(0xbf); //0xbf:时钟多字节读命令
for (i=8; i>0; i--)
{
*pSecDa = uc_RTOutputByte(); //读1Byte数据
pSecDa++;
}
T_CLK = 1;
T_RST =0;
}
/********************************************************************
*
* 名称: v_BurstW1302R
* 说明: 先写地址,后写数据(寄存器多字节方式)
* 功能: 往DS1302寄存器数写入数据(多字节方式)
* 调用: v_RTInputByte()
* 输入: pReDa: 寄存器数据地址
* 返回值: 无
***********************************************************************/
void v_BurstW1302R(uchar *pReDa)
{
uchar i;
v_W1302(0x8e,0x00); //控制命令,WP=0,写操作?
T_RST = 0;
T_CLK = 0;
T_RST = 1;
v_RTInputByte(0xfe); //0xbe:时钟多字节写命令
for (i=31;i>0;i--) //31Byte 寄存器数据
{
v_RTInputByte(*pReDa); //写1Byte数据
pReDa++;
}
T_CLK = 1;
T_RST =0;
}
/********************************************************************
*
* 名称: uc_BurstR1302R
* 说明: 先写地址,后读命令/数据(寄存器多字节方式)
* 功能: 读取DS1302寄存器数据
* 调用: v_RTInputByte() , uc_RTOutputByte()
* 输入: pReDa: 寄存器数据地址
* 返回值: 无
***********************************************************************/
void v_BurstR1302R(uchar *pReDa)
{
uchar i;
T_RST = 0;
T_CLK = 0;
T_RST = 1;
v_RTInputByte(0xff); //0xbf:时钟多字节读命令
for (i=31; i>0; i--) //31Byte 寄存器数据
{
*pReDa = uc_RTOutputByte(); //读1Byte数据
pReDa++;
}
T_CLK = 1;
T_RST =0;
}
/********************************************************************
*
* 名称: v_Set1302
* 说明:
* 功能: 设置初始时间
* 调用: v_W1302()
* 输入: pSecDa: 初始时间地址。初始时间格式为: 秒 分 时 日 月 星期 年
* 7Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B
* 返回值: 无
***********************************************************************/
void v_Set1302(uchar *pSecDa)
{
uchar i;
uchar ucAddr = 0x80;
v_W1302(0x8e,0x00); //控制命令,WP=0,写操作?
for(i =7;i>0;i--)
{
v_W1302(ucAddr,*pSecDa); //秒 分 时 日 月 星期 年
pSecDa++;
ucAddr +=2;
}
v_W1302(0x8e,0x80); //控制命令,WP=1,写保护?
}
/********************************************************************
*
* 名称: v_Get1302
* 说明:
* 功能: 读取DS1302当前时间
* 调用: uc_R1302()
* 输入: ucCurtime: 保存当前时间地址。当前时间格式为: 秒 分 时 日 月 星期 年
* 7Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B
* 返回值: 无
***********************************************************************/
void v_Get1302(uchar ucCurtime[])
{
uchar i;
uchar ucAddr = 0x81;
for (i=0;i<7;i++)
{
ucCurtime[i] = uc_R1302(ucAddr); //格式为: 秒 分 时 日 月 星期 年
ucAddr += 2;
}
}
J. 求助用51单片机加DS1302编写定时器程序的问题
亲,DS1302是实时时钟芯片,定时器可以直接用单片机的内部定时器写就可以了,没必要用DS1302了,用它做个时钟那还可以。DIY电子时钟,我做过教程,有问题可以联系。