带有存储器功能的数字温度计

DS1624基本原理

DS1624是美国DALLAS公司生产的一款集成了测量系统和存储器功能的芯片,数字接口电路简单且兼容I2C总线。一片控制器最多可控制8片DS1624。该芯片的数字温度输出精度为0.03125℃,达到13位,能在最低2.7V电压下工作,适用于低功耗系统。

DS1624基本特性

1.无需外围元件即可测量温度

2.测量范围为-55℃~+125℃,精度为0.03125℃

3.测量温度的结果以13位数字量(两字节传输)给出

4.测量温度的典型转换时间为1秒        

5.集成了256字节的E2PROM非易性存储器

6.数据的读出和写入通过一个2-线(I2C)串行接口完成

7.采用8脚DIP或SOIC封装

引脚描述及功能方框图

DS1624工作原理

温度测量

DS1624采用独特的在线温度测量技术来测量温度。它利用对温度敏感振荡器和对温度不敏感振荡器时钟脉冲计数值的比较来计算温度。初始时,计数器值相当于-55℃,如果在计数周期结束前计数器归零,则温度寄存器中的数字会增加,表示温度高于-55℃。

同时,计数器会重新预置一个值,并开始新的计数,直到再次归零。

通过调整每1℃内计数器的计数,斜坡累加电路可以补偿振荡器的非线性误差,提高精度。为了实现0.03125℃的精度,DS1624会输出13位的温度数据,以及发出读取请求后的两位补偿值。这些数据可以通过2线制串行口按顺序输出,最高位在前,最低位在后。

​ 温度与输出数据关系表

温度 数字量输出(二进制) 数字量输出(十六进制)
+125℃ 0111,1101,0000,0000 7D00H
+25.0625℃ 0001,1001,0001,0000 1910H
+0.5℃ 0000,0000,1000,0000 0080H
+0℃ 0000,0000,0000,0000 0000H
-0.5℃ 1111,1111,1000,0000 FF80H
-25.0625℃ 1110,0110,1111,0000 E6F0H
-55℃ 1100,1001,0000,0000 C900H

由于数据在总线上传输时MSB在前,所以DS1624读出的数据可以是一个字节(分辨率为1℃),也可以是两个字节,第二个字节包含的最低位为0.03125℃。

DS1624工作方式

DS1621的工作方式是由片上的配置/状态寄存器来决定的,如表,该寄存器的定义如下:

DONE 1 0 0 1 0 1 1SHOT

DS1624芯片有两个重要的控制位:DONE和1SHOT。DONE用于指示转换是否完成,当温度转换结束时,DONE置1;在转换进行中,DONE为0。1SHOT用于选择温度转换模式。当1SHOT为1时,为单次转换模式,即在接收到启动温度转换命令后,DS1624进行一次温度转换。当1SHOT为0时,为连续转换模式,DS1624将持续进行温度转换,并将最近一次的结果保存在温度寄存器中。这两个控制位都是非易失性的,能够保持设置的状态。

片内256字节存储器操作

DS1624的存储器编程有两种模式:字节编程模式和页编程模式。

在字节编程模式下,主控制器向DS1624发送地址和一个字节的数据。通过发送开始信号(START)后,主器件发送写控制字节(1001A2A1A00,其中R/W控制位为低电平“0”)来寻址接收器,DS1624收到后进行应答。接着主器件发送访问存储器指令(17H),DS1624再次应答。接下来,主器件发送下一个字节的字地址,该字地址将被写入DS1624的地址指针。在DS1624再次应答后,主器件发送数据字节并写入目标存储地址。DS1624再次应答后,主器件产生停止条件(STOP),触发内部写周期。在内部写周期中,DS1624不会产生应答信号。

在页编程模式中,与字节编程方式类似,首先发送控制字节、访问存储器指令(17H)和字地址给DS1624。然后,连续发送N个数据字节,其中每8个字节为一页。主器件将不超过一页字节的数据字节发送到DS1624,并暂存在片内页面缓存器中。在发送停止信号后,数据字节将被写入存储器。每接收到一个字节后,低位顺序地址指针在内部递增。高位顺序字地址保持不变。如果主器件在发送多于一页字节的数据之前产生停止条件,地址计数器将循环,并且先接收到的数据将被覆盖。与字节编程操作类似,一旦接收到停止条件,内部写周期将开始。

存储器的读操作

在这种模式下,主控制器可以从DS1624的EEPROM中读取数据。首先发送开始信号(START)后,主器件发送写控制字节(1001A2A1A00),DS1624收到后进行应答。然后主器件发送访问存储器指令(17H),DS1624再次应答。接下来,主器件发送字地址,并将其写入DS1624的地址指针。DS1624再次应答后,主器件不发送停止条件,而是重新发送开始信号(START),接着发送读控制字节(1001A2A1A01)。主器件接收到DS1624的应答之后,开始接收DS1624送出的数据。每接收到一个字节的数据后,主器件都要发送一个应答信号给DS1624。直到主器件发送非应答信号或停止条件,DS1624的数据发送过程才结束。

DS1624的指令集

  1. 访问存储器指令[17H]:该指令用于访问DS1624的EEPROM存储器,发送该指令后,下一个字节就是要访问的存储器的字地址数据。
  2. 访问设置寄存器指令[ACH]:当R/W位置0时,该指令用于向设置寄存器写入数据。发送该指令后,接下来的一个字节将被写入设置寄存器。当R/W位置1时,该指令用于从设置寄存器中读取数据。
  3. 读温度值指令[AAH]:该指令用于读取最后一次测温的结果。DS1624会产生两个字节的数据,即为寄存器内的结果。
  4. 开始测温指令[EEH]:该命令将启动一次温度测量,不需要再输入数据。在单次测量模式下,可在进行转换的同时使DS1624保持闲置状态。在连续模式下,将启动连续测量。
  5. 停止测温指令[22H]:该命令用于停止温度测量,不需要再输入数据。这个命令可以用来停止连续测温模式。发出请求后,当前温度测量结束,DS1624将保持闲置状态,直到下一个开始测温的请求发出才会继续进行连续测量。

​ 主机对DS1624写操作通信格式

I2C通信开始 主器件发送控制字节(DS1624地址和写操作) DS1624应答 主器件发送访问DS1624的指令 DS1624应答 主器件发送的数据字节 DS1624应答 I2C通信停止

​ 主机对DS1624读操作通信格式

I2C通信开始 主器件发送控制字节(DS1624地址和写操作) DS1624应答 主器件发送访问DS1624的指令 DS1624应答 I2C通信开始 主器件发送控制字节(DS1624地址和读操作) DS1624应答 数据字节0 主机应答 数据字节1 主机非应答 I2C通信停止

实验任务

用一片DS1624完成本地数字温度的测量,并通过8位数码管显示出测量的温度值。

电路原理图

程序设计内容

(1)由于DS1624是I2C总线结构的串行数据传送,它只需要SDA和SCL两根线完成数据的传送过程。因此,我们在进行程序设计的时候,也得按着I2C协议来对DS1624芯片数据访问。有关I2C协议参看有关资料,这里不详述。对于AT89S51单片机本身没有I2C硬件资源,所以必须用软件来模拟I2C协议过程。

(2)要从DS1624中读取温度值,首先启动DS1624的内部温度A/D开始转换,对应着有相应的命令用来启动开始温度转换,有关DS1624的指令集参考前面的叙述。一般情况下,DS1624经过一次温度的变换,需要经过1秒钟左右的时间,所以等待1秒钟后,即可读取内部的温度值,对于读取的温度值,仍然通过DS1624的指令集来完成温度的读取。但所有有数据的传送过程必须遵循I2C协议。

C语言源程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#include <AT89X52.H>
#include <INTRINS.H>
unsigned char code displaybit[]={0xfe,0xfd,0xfb,0xf7,
0xef,0xdf,0xbf,0x7f};
unsigned char code displaycode[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,0x00};
 
unsigned char code dotcode[32]={0,3,6,9,12,16,19,22,
25,28,31,34,38,41,44,48,
50,53,56,59,63,66,69,72,
75,78,81,84,88,91,94,97};
sbit SDA=P1^6;
sbit SCL=P1^7;
 
unsigned char displaybuffer[8]={0,1,2,3,4,5,6,7};
unsigned char eepromdata[8];
unsigned char temperdata[2];
 
unsigned char timecount;
unsigned char displaycount;
 
bit secondflag=0;
unsigned char secondcount=0;
unsigned char retn;
unsigned int result;
unsigned char x;
unsigned int k;
unsigned int ks;
 
void delay(void);
void delay10ms(void);
void i_start(void);
void i_stop(void);
void i_init(void);
void i_ack(void);
bit i_clock(void);
bit i_send(unsigned char i_data);
unsigned char i_receive(void);
bit start_temperature_T(void);
bit read_temperature_T(unsigned char *p);
void delay(void)
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
 
void delay10ms(void)
{
unsigned int i;
for(i=0;i<1000;i++)
{
delay();
}
}
 
void i_start(void)
{
SCL=1;
delay();
SDA=0;
delay();
SCL=0;
delay();
}
 
void i_stop(void)
{
SDA=0;
delay();
SCL=1;
delay();
SDA=1;
delay();
SCL=0;
delay();
}
void i_init(void)
{
SCL=0;
i_stop();
}
 
void i_ack(void)
{
SDA=0;
i_clock();
SDA=1;
}
 
bit i_clock(void)
{
bit sample;
 
SCL=1;
delay();
sample=SDA;
_nop_();
_nop_();
SCL=0;
delay();
return(sample);
}
 
bit i_send(unsigned char i_data)
{
unsigned char i;
 
for(i=0;i<8;i++)
{
SDA=(bit)(i_data & 0x80);
i_data=i_data<<1;
i_clock();
}
SDA=1;
return(~i_clock());
}
unsigned char i_receive(void)
{
unsigned char i_data=0;
unsigned char i;
 
for(i=0;i<8;i++)
{
i_data*=2;
if(i_clock()) i_data++;
}
return(i_data);
}
 
bit start_temperature_T(void)
{
i_start();
if(i_send(0x90))
{
if(i_send(0xee))
{
i_stop();
delay();
return(1);
}
else
{
i_stop();
delay();
return(0);
}
}
else
{
i_stop();
delay();
return(0);
}
}
 
bit read_temperature_T(unsigned char *p)
{
i_start();
if(i_send(0x90))
{
if(i_send(0xaa))
{
i_start();
if(i_send(0x91))
{
*(p+1)=i_receive();
i_ack();
*p=i_receive();
i_stop();
delay();
return(1);
}
else
{
i_stop();
delay();
return(0);
}
}
else
{
i_stop();
delay();
return(0);
}
}
else
{
i_stop();
delay();
return(0);
}
}
 
void main(void)
{
P1=0xff;
timecount=0;
displaycount=0;
TMOD=0x21;
TH1=0x06;
TL1=0x06;
TR1=1;
ET1=1;
ET0=1;
EA=1;
 
if(start_temperature_T()) //向DS1624发送启动A/D温度转换命令,成功则启动T0定时1s。
{
secondflag=0;
secondcount=0;
TH0=55536/256;
TL0=55536%256;
TR0=1;
}
while(1)
{
if(secondflag==1)
{
secondflag=0;
TR0=0;
if(read_temperature_T(temperdata)) //T0定时1s时间到,读取DS1624的温度值
{
for(x=0;x<8;x++)
{
displaybuffer[x]=16;
}
x=2;
result=temperdata[1]; //将读取的温度值进行数据处理,并送到显示缓冲区
while(result/10)
{
displaybuffer[x]=result%10;
result=result/10;
x++;
}
displaybuffer[x]=result;
result=temperdata[0];
result=result>>3;
displaybuffer[0]=(dotcode[result])%10;
displaybuffer[1]=(dotcode[result])/10;
if(start_temperature_T()) //温度值数据处理完毕,重新启动DS1624开始温度转换
{
secondflag=0;
secondcount=0;
TH0=55536/256;
TL0=55536%256;
TR0=1;
}
}
}
}
}
void t0(void) interrupt 1 using 0 //T0用于定时1s时间到
{
secondcount++;
if(secondcount==100)
{
secondcount=0;
secondflag=1;
}
TH0=55536/256;
TL0=55536%256;
}
void t1(void) interrupt 3 using 0 //T1定时1ms用数码管的动态刷新
{
timecount++;
if(timecount==4) //T1定时1ms到
{
timecount=0;
if (displaycount==5)
{
P0=(displaycode[displaybuffer[7-displaycount]] | 0x80); //在该位同时还要显示小数点
}
else
{
P0=displaycode[displaybuffer[7-displaycount]];
}
P2=displaybit[displaycount];
displaycount++;
if(displaycount==8)
{
displaycount=0;
}
}
}