找回密码
 注册会员
img_loading
智能检测中
更新自动建库工具PCB Footprint Expert 2024.04 Pro / Library Expert 破解版

DS1302和DS18B20简单易懂程序

[复制链接]
admin 发表于 2012-9-2 04:29:22 | 显示全部楼层 |阅读模式

本文包含原理图、PCB、源代码、封装库、中英文PDF等资源

您需要 登录 才可以下载或查看,没有账号?注册会员

×
/*采用同步串行的通信(单字节的读写)
ds1302芯片内部有可编程的日历时钟和31个字节的静态RAM,工作电压宽,晶振接32.768khz(实时时钟都接这个大小)
单片机 与芯片连接采用3线连接串行通信方式sclk为串行数据位同步脉冲信号,单电源供电时候结VCC1双电源时候主电源接
VCC2备份电池接VCC1,备份电池也可使用1uf以上的电容代替。

命令字节是最低位在前(注意!!!)
在传输之前RST=1;单字节的读……

每个寄存器(年、月、星期……)都有一个地址,每个数据都是两位!!!
WP,第七位(write protect)往里面写数据时候必须是零!!!

使用范围在-40-85^C
*/

#include<reg52.h>
#include<intrins.h>

#define uchar unsigned char
#define uint unsigned int

uchar time_data[7]={12,7,4,1,22,59,20};//year,week,month,day,hour,minute,second
uchar Write_add[7]={0x8c,0x8a,0x88,0x86,0x84,0x82,0x80}; //address of writing
uchar Read_add[7]={0x8d,0x8b,0x89,0x87,0x85,0x83,0x81}; //address of reading
uchar code Tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};
uchar disp[8];

sbit SCLK=P1^0;
sbit IO=P1^1;
sbit RST=P1^2; //片选端
sbit key1=P1^4;
sbit key2=P1^5;

void Delay_nus(uchar us)
{
uchar a;
while(us--)
{
for(a=0;a<25;a++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}

void Write_ds1302_byte(uchar dat) //single byte read
{
uchar i;
for(i=0;i<8;i++)
{
SCLK=0;
IO=dat&0x01; //准备好数据,低位在前,高电平(上升沿)写入数据
dat>>=1;
SCLK=1;
}
}

void Write_ds1302(uchar add,uchar dat) //先写地址后写数据
{
RST=0;
_nop_(); // 2000ns
SCLK=0;
_nop_();
RST=1;
_nop_();
Write_ds1302_byte(add); //两个时序是连着的不能间隔
Write_ds1302_byte(dat);
RST=0;
_nop_();

IO=1; //释放总线
SCLK=1;

}

uchar Read_ds1302(uchar add)
{
uchar i,value;
RST=0;
_nop_();
SCLK=0;
_nop_();
RST=1;
_nop_();
Write_ds1302_byte(add);
for(i=0;i<8;i++)
{
value>>=1; //判断八次移位七次
SCLK=0; //写完后sclk=1根据时序图应将sclk=0;形成第一个下降沿送出数据到IO,接下来进行判断即可
if(IO)
{
value|=0x80;//线读出来低位,故必须右移
}
SCLK=1; //释放总线
}
RST=0;
_nop_();
SCLK=0;
_nop_();

SCLK=1;
_nop_();
IO=1;
return value;
}

void Set_rtc()
{
uchar i,j;
for(i=0;i<7;i++)//年,月,星期,日,秒……
{
j=time_data[i]/10; //取出高位
time_data[i]=time_data[i]%10; //取出低位
time_data[i]=time_data[i]+j*16; //转化为BCD(4为二进制数表示1位十进制数)码 其实是:time_data[i]*16^0+j*16^1,故得到左边的式子
}
Write_ds1302(0x8e,0x00); //去出写保护
for(i=0;i<7;i++)
{
Write_ds1302(Write_add[i],time_data[i]);
}
Write_ds1302(0x8e,0x80); //开启写保护
}

void Read_rtc()
{
uchar j;
for(j=0;j<7;j++)
{
time_data[j]=Read_ds1302(Read_add[j]);
}
}

void Time_pros()
{
disp[0]=time_data[6]/16; //去BCD码的高位送数码管显示
disp[1]=time_data[6]%16;
disp[2]=17;
disp[3]=time_data[5]/16;
disp[4]=time_data[5]%16;
disp[5]=17;
disp[6]=time_data[4]/16;
disp[7]=time_data[4]%16;
}

void Display()
{
P0=Tab[disp[6]];
P2=0xfe;
Delay_nus(6);

P0=Tab[disp[7]];
P2=0xfd;
Delay_nus(6);

P0=Tab[10];
P2=0xfb;
Delay_nus(6);

P0=Tab[disp[3]];
P2=0xf7;
Delay_nus(6);

P0=Tab[disp[4]];
P2=0xef;
Delay_nus(6);

P0=Tab[10];
P2=0xdf;
Delay_nus(6);

P0=Tab[disp[0]];
P2=0xbf;
Delay_nus(6);

P0=Tab[disp[1]];
P2=0x7f;
Delay_nus(6);
}

void main()
{
Set_rtc(); //芯片在第一次使用用来对时,再后来的使用中将此条语句去掉
while(1)
{
Read_rtc();
Time_pros();
Display();
}
}
/* 单总线温度传感器,每个都有意个唯一的ROM序列号,可将多只DS18B20连在同一根单总线上
进行简单的多点分布应用,
DS18B20内部有三个主要的数字部件,64位ROM温度传感器,非易失性报警触发器TH和TL

可采用寄生电源的工作方式:从单总线山汲取能量,在信号线处于高电平期间把能量存在
内部电容里,

ROM操作指令:
(1)读出ROM,33H,用于读取序列号
(2)匹配ROM,55H
(3)搜索ROM,F0H,
(4)跳过ROM,CCH,命令发出后系统对所有DS18B20进行操作,通常用在启动所有DS18B20
转换之前,或系统中只有一个DS18B20
(5)报警搜索,ECH

存储器操作命令:
(1)温度转换,44H
(2)读暂存器,BEH
(3)写寄存器,4EH
(4)读电源,B4H
*/
#include<reg52.h>
#include<intrins.h>

#define uchar unsigned char
#define uint unsigned int
uchar code Tab[ ]={0xc0,0xf9,0xa4,
0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

uchar code Tab1[ ]={0x40,0x79,0x24,
0x30,0x19,0x12,0x02,0x78,0x00,0x10};

sbit DQ=P3^3;
sbit Louder=P3^6;
uchar temp,temp1;

void delay(uint t)
{
while(t--);
}

void delay1(unsigned char ms)
{ while(ms--)
{ unsigned char i;
for(i = 0; i< 25; i++)
{
_nop_(); //执行一条_nop_()指令为一个机器周期
_nop_();
_nop_();
_nop_();
}
}
}

uchar init_ds18b20()
{
uchar n;
DQ=1; //默认状态为高电平
delay(8);
DQ=0;
delay(80); //12MHZ 600uszuoyou(低电平在480—960us期间)
DQ=1;
delay(8);
n=DQ; //主机采样DS18B20是否有低电平,看是否有器件相应
delay(4);
return n;
}

void write_byte(uchar dat) //写数据时低位在前,数据时“一位一位”写的
{
uchar i;
for(i=0;i<8;i++)
{
DQ=0;
DQ=dat&0x01; //准备好数据
delay(4); //40-50us
DQ=1; //传完数据拉高总线,高电平期采样
dat=dat>>1;

}
delay(4); //让数据稳定
}

uchar read_byte()
{
uchar i,value;
for(i=0;i<8;i++)
{
DQ=0;
value>>=1; //判断8次移位7次,同时延时几个微妙
DQ=1; //释放总线 后开始采样

if(DQ) //采得的数据为1
{
value|=0x80;
}
delay(4);

}
return value;
}

uchar readtemperature()
{
uchar a,b; //读取高八位和低八位
init_ds18b20();
write_byte(0xcc); //跳过ROM
write_byte(0x44); //启动温度转换
delay(300);
/*温度值已经存入寄存器,接下来读取温度*/
init_ds18b20();
write_byte(0xcc);
write_byte(0xbe); //读取命令
a=read_byte(); //低8位
b=read_byte(); //高8位
b<<=4; //不管小数点(0.0625) 注意这种操作方式
b+=(a&0xf0)>>4;
return b;
/*t1=(a&0x0f)*0.0625; //小数
t=(b<<4)|(a>>4); //整数
if(t>128)
{
t=~t+1;
}
t=t+t1;
return t; */

}

uchar readtemperature_xiaoshu()
{
uchar a,t1; //读取高八位和低八位
init_ds18b20();
write_byte(0xcc); //跳过ROM
write_byte(0x44); //启动温度转换
delay(300);
/*温度值已经存入寄存器,接下来读取温度*/
init_ds18b20();
write_byte(0xcc);
write_byte(0xbe); //读取命令
a=read_byte(); //低8位
t1=(a&0x0f)*0.625; //小数
return t1;

}

void display(uchar aa,uchar bb)
{
P0=Tab[aa/10];
P2=0xfe;
delay1(4);

P0=Tab1[aa%10];
P2=0xfd;
delay1(4);

P0=Tab[bb];
P2=0xfb;
delay1(4);

/* P0=Tab[aa%10];
P2=0xf7;
delay1(6);*/

}
void main()
{
while(1)
{
temp=readtemperature();
//temp=temp*100;
temp1=readtemperature_xiaoshu();
display(temp,temp1);
}
}
您需要登录后才可以回帖 登录 | 注册会员

*滑块验证:
img_loading
智能检测中
本版积分规则

QQ|手机版|MCU资讯论坛 ( 京ICP备18035221号-2 )|网站地图

GMT+8, 2025-7-24 23:48 , Processed in 0.051859 second(s), 10 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表