|
一、设计目的
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值。
|
|