找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2047|回复: 2
打印 上一主题 下一主题
收起左侧

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

[复制链接]
跳转到指定楼层
楼主
ID:212343 发表于 2017-7-30 15:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
DS1624基本原理  (仿真实验中用DS1621)
   DS1624是美国DALLAS公司生产的集成了测量系统和存储器于一体的芯片。数字接口电路简单,与I2C总线兼容,且可以使用一片控制器控制多达8片的DS1624。其数字温度输出达13位,精度为0.03125DS1624可工作在最低2.7V电压下,适用于低功耗应用系统。
(1).   DS1624基本特性
  ◆ 无需外围元件即可测量温度
◆      测量范围为-55℃~+125℃,精度为0.03125℃
file:///C:/Users/DELL/AppData/Local/Temp/msohtmlclip1/01/clip_image001.jpg◆      测量温度的结果以13位数字量(两字节传输)给出
◆      测量温度的典型转换时间为1秒        
◆      集成了256字节的E2PROM非易性存储器
◆      数据的读出和写入通过一个2-线(I2C)串行接口完成
◆      采用8脚DIP或SOIC封装,如图2.34.1  
                              图2.34.1
(2).   引脚描述及功能方框图
其引脚描述如表1所示:
file:///C:/Users/DELL/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg
DS1624的功能结构图如图4.34.2所示:
file:///C:/Users/DELL/AppData/Local/Temp/msohtmlclip1/01/clip_image003.jpg
图4.34.2
(3).   DS1624工作原理
温度测量
图4.34.3是温度测量的原理结构图
file:///C:/Users/DELL/AppData/Local/Temp/msohtmlclip1/01/clip_image005.jpg
           4.34.3 温度测量的原理结构图
DS1624在测量温度时使用了独有的在线温度测量技术。它通过在一个由对温度高度敏感的振荡器决定的计数周期内对温度低敏感的振荡器时钟脉冲的计数值的计算来测量温度。DS1624在计数器中预置了一个初值,它相当于-55℃。如果计数周期结束之前计数器达到0,已预置了此初值的温度寄存器中的数字就会增加,从而表明温度高于-55℃。
与此同时,计数器斜坡累加电路被重新预置一个值,然后计数器重新对时钟计数,直到计数值为0。
通过改变增加的每1℃内的计数器的计数,斜坡累加电路可以补偿振荡器的非线性误差,以提高精度,任意温度下计数器的值和每一斜坡累加电路的值对应的计数次数须为已知。
  DS1624通过这些计算可以得到0.03125℃的精度,温度输出为13位,在发出读温度值请求后还会输出两位补偿值。表2给出了所测的温度和输出数据的关系。这些数据可通过2线制串行口连续输出,MSB在前,LSB在后。
2 温度与输出数据关系表
  
温度
  
数字量输出(二进制)
数字量输出(十六进制)
125
0111110100000000
7D00H
25.0625
0001100100010000
1910H
0.5
0000000010000000
0080H
0
0000000000000000
0000H
-0.5
1111111110000000
FF80H
-25.0625
1110011011110000
E6F0H
-55
1100100100000000
C900H
由于数据在总线上传输时MSB在前,所以DS1624读出的数据可以是一个字节(分辨率为1℃),也可以是两个字节,第二个字节包含的最低位为0.03125℃。
213位温度寄存器中存储温度值的数据格式
file:///C:/Users/DELL/AppData/Local/Temp/msohtmlclip1/01/clip_image006.giffile:///C:/Users/DELL/AppData/Local/Temp/msohtmlclip1/01/clip_image007.giffile:///C:/Users/DELL/AppData/Local/Temp/msohtmlclip1/01/clip_image008.giffile:///C:/Users/DELL/AppData/Local/Temp/msohtmlclip1/01/clip_image009.giffile:///C:/Users/DELL/AppData/Local/Temp/msohtmlclip1/01/clip_image010.giffile:///C:/Users/DELL/AppData/Local/Temp/msohtmlclip1/01/clip_image010.giffile:///C:/Users/DELL/AppData/Local/Temp/msohtmlclip1/01/clip_image010.giffile:///C:/Users/DELL/AppData/Local/Temp/msohtmlclip1/01/clip_image010.gif高八位字节                   低八位字节
  
S
  
B14
B13
B12
B11
B10
B9
B8
  
B7
B6
B5
B4
B3
0
0
0
         3 温度值的数据存储格式
其中 S-为符号位,当S0时,表示当前的测量的温度为正的温度;当S1时,表示当前的测量的温度为负的温度。B14B3为当前测量的温度值。最低三位被设置为0
DS1624工作方式
DS1621的工作方式是由片上的配置/状态寄存器来决定的,如表4,该寄存器的定义如下:
        表4 配置/状态寄存器格式
  
DONE
  
1
0
0
1
0
1
1SHOT
其中DONE为转换完成位,温度转换结束时置1,正在进行转换时为0;1SHOT温度转换模式选择。1SHOT为1时为单次转换模式,DS1624在收到启动温度转换命令EEH后进行一次温度转换。1SHOT为0时为连续转换模式,此时DS1624将连续进行温度转换,并将最近一次的结果保存在温度寄存器中。该位为非易失性的。
片内256字节存储器操作
控制器对DS1624的存储器编程有两种模式:一种是字节编程模式,另一种是页编程模式。
在字节编程模式中,主控制器发送地址和一个字节的数据到DS1624。
在主器件发出开始(START)信号以后,主器件发送写控制字节即1001A2A1A00(其中R/W控制位为低电平“0”)。指示从接收器被寻址,DS1624接收后应答,再由主器件发送访问存储器指令(17H)后,DS1624接收后应答,接着由主器件发送的下一个字节字地址将被写入到DS1624的地址指针。主器件接收到来自DS1624的另一个确认信号以后,发送数据字节,并写入到寻址的存储地址。DS1624再次发出确认信号,同时主器件产生停止条件STOP,启动内部写周期。在内部写周期DS1624将不产生确认信号。
在页编程模式中,如同字节写方式,先将控制字节、访问存储器指令(17H)、字地址发送到DS1624,接着发N个数据字节,其中以8个字节为一个页面。主器件发送不多于一个页面字节的数据字节到DS1624,这些数据字节暂存在片内页面缓存器中,在主器件发送停止信号以后写入到存储器。接收每一个字节以后,低位顺序地址指针在内部加1。高位顺序字地址保持为常数。如果主器件在产生停止条件以前要发送多于一页字的数据,地址计数器将会循环,并且先接收到的数据将被覆盖。像字节写操作一样,一旦停止条件被接收到,则内部写周期将开始。
存储器的读操作
  在这种模式下,主器件可以从DS1624的EEPROM中读取数据。主器件在发送开始信号之后,主器件首先发送写控制字节1001A2A1A00,主器件接收到DS1624应答之后,发送访问存储器的指令(17H),收到DS1624的应答之后,接着发送字地址将被被写入到DS1624的地址指针。这时DS1624发送应答信号之后,主器件并没有发送停止信号,而是重新发送START开始信号,接着又发送读控制字节1001A2A1A01,主器件接收到DS1624应答之后,开始接收DS1624送出来的数据,主器件每接收完一个字节的数据之后,都要发送一个应答信号给DS1624,直到主器件发送一个非应答信号或停止条件来结束DS1624的数据发送过程。
DS1624的指令集
数据和控制信息的写入读出是以表5和表6所示的方式进行的。在写入信息时,主器件输出从器件(即DS1624)的地址,同时R/W位置0。接收到响应位后,总线上的主器件发出一个命令地址,DS1624接收此地址后,产生响应位,主器件就向它发送数据。如果要对它进行读操作,主器件除了发出命令地址外,还要产生一个重复的启动条件和命令字节,此时R/W位为1,读操作开始。下面对它们的命令进行说明。
  访问存储器指令[17H]:该指令是对DS1624的EEPROM进行访问,发送该指令之后,下一个字节就是被访问存储器的字地址数据。
  访问设置寄存器指令[ACH]:如果R/W位置0,将写入数据到设置寄存器。发出请求后,接下来的一个字节被写入。 如果R/W位置1,将读出存在寄存器中的值。
读温度值指令[AAH]:即读出最后一个测温结果。DS1624产生两个字节,即为寄存器内的结果。
开始测温指令[EEH]:此命令将开始一次温度的测量,不需再输入数据。在单次测量模式下,可在进行转换的同时使DS1624保持闲置状态。在连续模式下,将启动连续测温。
停止测温指令[22H]:该命令将停止温度的测量,不需再输入数据。此命令可用来停止连续测温模式。发出请求后,当前温度测量结束,然后DS1624保持闲置状态。直到下一个开始测温的请求发出才继续进行连续测量。
5 主机对DS1624写操作通信格式
  
I2C通信开始
  
主器件发送控制字节(DS1624地址和写操作)
DS1624应答
主器件发送访问DS1624的指令
DS1624应答
主器件发送的数据字节
DS1624应答
I2C通信停止
6 主机对DS1624读操作通信格式
  
I2C通信开始
  
主器件发送控制字节(DS1624地址和写操作)
DS1624应答
主器件发送访问DS1624的指令
DS1624应答
I2C通信开始
主器件发送控制字节(DS1624地址和读操作)
DS1624应答
数据字节0
主机应答
数据字节1
主机非应答
I2C通信停止
2      实验任务
用一片DS1624完成本地数字温度的测量,并通过8位数码管显示出测量的温度值。其硬件电路图如图4.34.4所示
3      电路原理图
file:///C:/Users/DELL/AppData/Local/Temp/msohtmlclip1/01/clip_image012.jpg
图4.34.4
  
4      系统板上硬件连线
(1).   把“单片机系统”区域中的P0.0-P0.7用8芯排线连接到“动态数码显示”区域中的ABCDEFGH端子上。
(2).   把“单片机系统”区域中的P2.0-P2.7用8芯排线连接到“动态数码显示”区域中的S1S2S3S4S5S6S7S8端子上。
(3).   把DS1624芯片插入到“二线总线模块”区域中的8脚集成座上,注意芯片不插反。
(4).   把“二线总线模块”区域中的PIN1 PIN2分别用导线连接到“单片机系统”区域中的P1.6和P1.7端子上。
(5).   把“二线总线模块”区域中的PIN4 PIN5 PIN6分别用导线连接到“电源模块”区域中的GND端子上。
5       程序设计内容
(1).   由于DS1624是I2C总线结构的串行数据传送,它只需要SDA和SCL两根线完成数据的传送过程。因此,我们在进行程序设计的时候,也得按着I2C协议来对DS1624芯片数据访问。有关I2C协议参看有关资料,这里不详述。对于AT89S51单片机本身没有I2C硬件资源,所以必须用软件来模拟I2C协议过程。
(2).   要从DS1624中读取温度值,首先启动DS1624的内部温度A/D开始转换,对应着有相应的命令用来启动开始温度转换,有关DS1624的指令集参考前面的叙述。一般情况下,DS1624经过一次温度的变换,需要经过1秒钟左右的时间,所以等待1秒钟后,即可读取内部的温度值,对于读取的温度值,仍然通过DS1624的指令集来完成温度的读取。但所有有数据的传送过程必须遵循I2C协议。
6       C语言源程序
#include <AT89X52.H>
#include<INTRINS.H>      //c51中的intrins.h库函数.txt
  
unsigned char codedisplaybit[]={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 codedotcode[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)
{
  bitsample;
  
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;
      P2=0xff;
     if (displaycount==5)
       {
         P0=(displaycode[displaybuffer[7-displaycount]]| 0x80); //在该位同时还要显示小数点
       }
       else
         {
           P0=displaycode[displaybuffer[7-displaycount]];
         }
     P2=displaybit[displaycount];
     displaycount++;
     if(displaycount==8)
       {
         displaycount=0;
       }
    }
}

评分

参与人数 2黑币 +12 收起 理由
愤怒电容 + 10 很给力!
wuli韬韬 + 2 赞一个!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:372774 发表于 2018-7-16 21:01 | 只看该作者
本帖最后由 Engineer. 于 2018-7-24 21:04 编辑

学习一下,谢谢
回复

使用道具 举报

板凳
ID:372774 发表于 2018-7-16 21:03 | 只看该作者
学习一下,谢谢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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