找回密码
 立即注册

QQ登录

只需一步,快速开始

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

AT89C51单片机DS18B20温度检测应用设计 Proteus仿真

[复制链接]
跳转到指定楼层
楼主
ID:623141 发表于 2020-6-23 16:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、设计目的
1、学习并掌握One-Wire总线的工作原理
2、学习并掌握DS18B20温度传感器工作原理;
3、学习并掌握温度采集程序设计方法;
4、学习并掌握串行通信程序设计;
二、实验设备
1、计算机;
2、单片机开发板;
3、Keil C51编程软件;
4、Proteus仿真软件;
三、设计内容
1、完成功能
(1)检测温度并显示一位小数(XX.X),
(2)将温度值通过串口发送到上位机串口调试助手,
(3)上位机串口调试助手显示(文本形式显示):“T:XX.X”回车(XX.X是温度值,逐行显示)
2、硬件电路原理图
3、设计程序(5号、宋体、单倍行距、分两栏,要求程序设计规范化,添加必要的说明和注释)


/****************************************************************
* 实 验 名 :DS18B20温度实验
* 实验说明 :数码管显示当前温度
* 连接方式 :将DS18B20插到数字温度检测模块的U5上(注意方向),DS_RD接P2.2
*****************************************************************/
//包含文件
#include<reg52.h>
#include<intrins.h>
//宏定义
#defineBAUD 9600        //波特率设置,bps
#defineFOSC 11059200L //晶振设置,默认使用11.0592MHz
//#defineFOSC 12000000L //晶振设置,使用12M Hz
//#defineFOSC 24000000L //晶振设置,使用24M Hz
//IO接口定义
#defineLED_PORT P0
sbitwela_1 = P2^4;
sbitwela_2 = P2^5;
sbitwela_3 = P2^6;
sbitwela_4 = P2^7;
sbitDQ = P2^2;              //定义DS18B20端口DQ
//全局变量定义
unsignedchar temperature;
unsignedchar temperature_dec;
unsignedchar qian,bai,shi,ge;
//LED显示字模 0-F 共阳模式
unsignedcode table[]={0Xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
unsignedchar RomCode[8];   //DS18B20中的RomCode
/*******************************************************************************
* 函 数 名 :Delayms
* 函数功能 :实现 ms级的延时
* 输    入:ms
* 输    出:无
*******************************************************************************/
voidDelayms(unsigned int ms)
{
    unsigned int i,j;
    for(i=0;i<ms;i++)
    #if FOSC == 11059200L
       for(j=0;j<114;j++);
    #elif FOSC == 12000000L
     for(j=0;j<123;j++);
    #elif FOSC == 24000000L
       for(j=0;j<249;j++);
    #else
       for(j=0;j<114;j++);
    #endif
}
/*******************************************************************************
* 函 数 名 :LEDdisplay
* 函数功能 :循环显示各个位上的数据
* 输    入:num要显示的数据
* 输    出:无
*******************************************************************************/
voidLEDdisplay()
{   
    wela_1 = 1;   //关闭所有数码管
    wela_2 = 1;
    wela_3 = 1;
    wela_4 = 1;
    wela_4=0; //显示千位
    LED_PORT=table[qian];
    Delayms(1);
    LED_PORT = 0xff;
    wela_4=1;
   
    wela_3=0; //显示百位
    LED_PORT=table[bai];
    Delayms(1);
    LED_PORT = 0xff;
    wela_3=1;
   
    wela_2=0; //显示十位
    LED_PORT=table[shi] & 0x7F;
    Delayms(1);
    LED_PORT = 0xff;
    wela_2=1;
   
    wela_1=0; //显示个位
    LED_PORT=table[ge];
    Delayms(1);
    LED_PORT = 0xff;
}
/*******************************************************************/
/*us级延时函数  执行一次US--所需6.5us进入一次函数需要11.95us                                    */
/*******************************************************************/
voidDelay(unsigned int num)
{
    while( --num ) ;
}
/*******************************************************************/
/*初始化ds1820                                                    */
/*******************************************************************/
bitInit_DS18B20(void)
{
    bit presence;
    DQ = 1;     //DQ复位
    Delay(8);   //稍做延时
    DQ = 0;     //单片机将DQ拉低
    Delay(90);  //精确延时 大于 480us
    DQ = 1;     //拉高总线
    Delay(4);   //稍做延时   
    presence = DQ; //如果=0则初始化成功 =1则初始化失败
    Delay(20); //稍做延时
    DQ = 1;
    return(presence); //返信号,0=presence,1= no presence
}
/*******************************************************************/
/* 读一个字节                                                     */
/*******************************************************************/
unsignedchar ReadOneChar(void)
{
    unsigned char i = 0;
    unsigned char dat = 0;
    for (i = 8; i > 0; i--)//循环8次,通过dat变量的依次右移装入8位数据
    {
       DQ = 0;        //单片机将DQ拉低
       dat >>= 1;     //dat右移1位,准备读取1位数据
       DQ = 1;        //单片机将DQ拉高      
       if(DQ)        //判断DQ状态,DQ=1则dat的最高位为1,DQ=0则dat的最高位为0
           dat |= 0x80;//dat或10000000,控制dat的最高位:DQ=1则为1,DQ=0则为0
       //proteus仿真设置为Delay(40)
       Delay(40);     //延时
       //Delay(4);
    }
    return (dat);      //返回值dat即为读到的一字节数据
}
/*******************************************************************/
/* 写一个字节                                                     */
/*******************************************************************/
void  WriteOneChar(unsigned char dat)
{
    unsigned char i = 0;
    for (i = 8; i > 0; i--)//循环8次,通过dat变量的依次右移发出8位数据
    {
       DQ = 0;        //单片机将DQ拉低
       DQ = dat&0x01; //DQ=dat与00000001,则DQ=dat的最低位(0或1)
       Delay(5);      //延时     
       DQ = 1;        //单片机将DQ拉高
       dat>>=1;       //dat右移1位,准备取下一位数据
    }
}
/*******************************************************************/
/* 温度报警值写入DS18B20                                           */
/*******************************************************************/
voidWrite_Temperature_alarm(unsigned char Temp_h , unsigned char Temp_l)
{
    Init_DS18B20();           //初始化
    WriteOneChar(0xCC);       //跳过读序列号的操作
    WriteOneChar(0x4e);       //将设定的温度报警值写入DS18B20
    WriteOneChar(Temp_h);      //写TH
    WriteOneChar(Temp_l);      //写TL
    WriteOneChar(0x7f);       //12位精确度
    Init_DS18B20();           //初始化
    WriteOneChar(0xCC);       //跳过读序号列号的操作
    WriteOneChar(0x48);       //把暂存器里的温度报警值拷贝到EEROM
}
/*******************************************************************/
/* 读取64位序列码                                                 */
/*******************************************************************/
voidRead_RomCord(void)
{
    unsigned char j;
    Init_DS18B20();           //初始化
    WriteOneChar(0x33);       // 读序列码的操作命令
    for (j = 0; j < 8; j++)
    {
       RomCode[j] = ReadOneChar() ;
    }
}
/*******************************************************************/
/*DS18B20的CRC8校验程序                                            */
/*******************************************************************/
unsignedchar CRC8()
{
    unsigned char i,x;
    unsigned char crcbuff,crc;
    crc=0;
    for(x = 0; x <8; x++)
    {
       crcbuff=RomCode[x];
       for(i = 0; i < 8; i++)
       {
           if(((crc ^ crcbuff)&0x01)==0)
              crc >>= 1;
           else
           {
              crc ^= 0x18;   //CRC=X8+X5+X4+1
              crc >>= 1;
              crc |= 0x80;
           }         
           crcbuff >>= 1;      
       }
    }
    return crc;
}   
/*******************************************************************/
/* 读取温度                                                       */
/*******************************************************************/
unsignedchar* Read_Temperature(void)
{
    //unsigned char  i;
    unsigned char temp_comp[2];
    unsigned char temp_data[2];
    unsigned char temp_alarm[2];   
    //unsigned int t;
    Init_DS18B20();           //初始化   
    WriteOneChar(0xCC);       //跳过读序列号的操作
    WriteOneChar(0x44);       //启动温度转换
    Init_DS18B20();           //初始化
    //实际器件:匹配ROM或跳过序列号均可   
    //WriteOneChar(0x55);         //匹配ROM命令
    //for(i=0;i<8;i++)
    //  WriteOneChar(RomCode);
    //proteus仿真:跳过序列号
    WriteOneChar(0xCC);           //跳过读序列号的操作   
    WriteOneChar(0xBE);           //读取温度寄存器
      
    temp_data[0] = ReadOneChar();   //温度低8位
    temp_data[1] = ReadOneChar();   //温度高8位
    temp_alarm[0] = ReadOneChar();  //温度报警TH
    temp_alarm[1] = ReadOneChar();  //温度报警TL  
    temp_comp[0]=((temp_data[0]&0xf0)>>4)|((temp_data[1]&0x0f)<<4);//取温度整数值
    temp_comp[1] = temp_data[0]&0x0f;//读取小数
    //课件程序:
    //t=temp_data[1];
    //t<<=8;
    //t=t|temp_data[0];
    //temp_comp=t*0.0625;  
    return &temp_comp;                                                   
}
/*******************************************************************************
* 函 数 名 :UsartConfiguration
* 函数功能 :串口设置
* 输    入:无
* 输    出:无
*******************************************************************************/
voidUsartConfiguration()
{
    SCON = 0X50;   //设置为工作方式1:10位异步收发器
    TMOD |= 0x20;  //设置计数器工作方式2:8位自动重装计数器  
    PCON = 0X80;   //波特率加倍:SMOD = 1
    TH1 = 256 -(FOSC/12/32/(BAUD/2)); //计算定时器1初值
    TL1 = 256 -(FOSC/12/32/(BAUD/2));
    TR1 = 1;//启动定时器T1
    ES=1;  //开串口中断
    EA = 1; //开总中断
}
/*******************************************************************************
* 函 数 名 :UsartSendTemper
* 函数功能 :串口发送温度
* 输    入:无
* 输    出:无
*******************************************************************************/
voidUsartSendTemper()
{
    //发送 T
       TI = 0;          //清除发送中断标志位TI
       SBUF='T';      //收到的数据放入到发送SBUF,启动串口发送
       while(!TI);      //等待发送数据完成   
    //发送 :
       TI = 0;          //清除发送中断标志位TI
       SBUF=':';      //收到的数据放入到发送SBUF,启动串口发送
       while(!TI);      //等待发送数据完成
    //发送温度十位
       TI = 0;          //清除发送中断标志位TI
       SBUF=temperature/10+'0';//收到的数据放入到发送SBUF,启动串口发送
       while(!TI);      //等待发送数据完成
    //发送温度个位
       TI = 0;          //清除发送中断标志位TI
       SBUF=temperature%10+'0';//收到的数据放入到发送SBUF,启动串口发送
       while(!TI);      //等待发送数据完成
    //发送小数点
       TI = 0;          //清除发送中断标志位TI
       SBUF='.';//收到的数据放入到发送SBUF,启动串口发送
       while(!TI);      //等待发送数据完成
   
    //发送温度小数位
       TI = 0;          //清除发送中断标志位TI
       SBUF=temperature_dec+'0';//收到的数据放入到发送SBUF,启动串口发送
       while(!TI);      //等待发送数据完成
      
    //发送换行符
       TI = 0;          //清除发送中断标志位TI
       SBUF='\n'; //收到的数据放入到发送SBUF,启动串口发送
       while(!TI);      //等待发送数据完成
       TI=0;   
           
}
/*******************************************************************/
/* 主函数                                                         */
/*******************************************************************/
voidmain(void)
{
    unsigned char* temp;
    int count = 0;
    temperature = 0;
    //proteus仿真:不读取64位序列码   
    //Read_RomCord();   //读取64位序列码
    UsartConfiguration();//串口配置
    while(1)
    {
       if(count >= 200)//采集周期1s
       {
           temp = Read_Temperature();  //读取温度
           temperature = temp[0];
           temperature_dec = temp[1]*0.625;
           count= 0;
           UsartSendTemper();//串口发送温度      
       }
       qian=temperature/100;
       bai=temperature%100/10;
       shi=temperature%10;
       ge=temperature_dec;           
       LEDdisplay();//显示温度
      
       count++;
    }
}


四、本任务中的几个功能如何实现?(说明设计思路)
设计思路:
1.       温度读取和数码管显示套用DS18B20温度读取例程改写,
2.       串口发送程序采用查询法。
功能实现:
温度读取:
核心为OneWire总线的使用,严格对应时序图编程,实现初始化、读、写一个字节,要注意延时函数的控制。
显示小数:
将原来的读函数改为usigned char*类型,返回一个长度为2的数组,分别存储温度的整数值和小数值。
将原来的数码管显示函数前三个显示整数、最后一个数码管显示小数。小数处理和整数取完对应位之后的下一步处理有区别(小数需要乘0.625)
发送温度:
发送时候要一字节一字节地发送。温度处理之后,还要加‘0’将数字转化为对应ASCII值。

DS18B20温度检测应用设计.rar

5.14 MB, 下载次数: 91, 下载积分: 黑币 -5

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

使用道具 举报

沙发
ID:843576 发表于 2020-11-16 20:44 | 只看该作者
我想请问一下,如果吧AC89C51换成STC89C51程序可以照样使用吗?
回复

使用道具 举报

板凳
ID:839551 发表于 2020-12-29 00:32 | 只看该作者
不对啊 负数
回复

使用道具 举报

地板
ID:800086 发表于 2020-12-29 08:59 | 只看该作者
这个简单也,实用。刚入门的可以学习一下
回复

使用道具 举报

5#
ID:863465 发表于 2020-12-31 10:29 来自手机 | 只看该作者
你好,我想问一下我接收不到数据,是怎么回事?
回复

使用道具 举报

6#
ID:863465 发表于 2020-12-31 10:29 来自手机 | 只看该作者
不显示小数
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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