单片机教程网

电脑版
提示:原网页已由神马搜索转码, 内容由www.51hei.com提供.
查看:2813|回复: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, 下载次数: 92, 下载积分: 黑币 -5

ID:843576发表于 2020-11-16 20:44|显示全部楼层
我想请问一下,如果吧AC89C51换成STC89C51程序可以照样使用吗?
ID:839551发表于 2020-12-29 00:32|显示全部楼层
不对啊 负数
ID:800086发表于 2020-12-29 08:59|显示全部楼层
这个简单也,实用。刚入门的可以学习一下
ID:863465发表于 2020-12-31 10:29来自手机|显示全部楼层
你好,我想问一下我接收不到数据,是怎么回事?
ID:863465发表于 2020-12-31 10:29来自手机|显示全部楼层
不显示小数

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

Powered by 单片机教程网