delay1ms();
}
//函数功能:
判断液晶模块的忙碌状态
bitBusyTest(void)
{
bitresult;RS=0;RW=1;E=1;_nop_();_nop_();
_nop_();_nop_();
result=BF;//将忙碌标志电平赋给result
E=0;
returnresult;
}
//函数功能:
将模式设置指令或显示地址写入液晶模块
voidWriteInstruction(unsignedchardictate)
{
while(BusyTest()==1);//如果忙就等待
RS=0;RW=0;E=0;_nop_();_nop_();
P0=dictate;_nop_();_nop_();_nop_();_nop_();
E=1;_nop_();_nop_();_nop_();_nop_();E=0;
}
//函数功能:
指定字符显示的实际地址
voidWriteAddress(unsignedcharx)
{
WriteInstruction(x|0x80);//显示位置的确定方法规定为"80H+地址码x"
}
///函数功能:
将数据(字符的标准ASCII码)写入液晶模块
voidWriteData(unsignedchary)
{
while(BusyTest()==1);RS=1;RW=0;E=0;P0=y;
_nop_();_nop_();_nop_();_nop_();E=1;_nop_();_nop_();
_nop_();_nop_();E=0;
}
//函数功能:
对LCD的显示模式进行初始化设置
voidLcdInitiate(void)
{
delaynms(15);//延时15ms,首次写指令时应给LCD一段较长的反应时间
WriteInstruction(0x38);//显示模式设置:
16×2显示,5×7点阵,8位数据接口
delaynms(5);
WriteInstruction(0x38);
delaynms(5);
WriteInstruction(0x38);//连续三次,确保初始化成功
delaynms(5);
WriteInstruction(0x0c);//显示模式设置:
显示开,无光标,光标不闪烁
delaynms(5);
WriteInstruction(0x06);//显示模式设置:
光标右移,字符不移
delaynms(5);
WriteInstruction(0x01);//清屏幕指令,将以前的显示内容清除
delaynms(5);
}
sbitDQ=P3^3;
unsignedchartime;//设置全局变量,专门用于严格延时
//函数功能:
将DS18B20传感器初始化,读取应答信号
bitInit_DS18B20(void)
{
bitflag;//储存DS18B20是否存在的标志,flag=0,表示存在;flag=1,表示不存在
DQ=1;
for(time=0;time<2;time++);
DQ=0;
for(time=0;time<200;time++);
DQ=1;
for(time=0;time<10;time++);
flag=DQ;
for(time=0;time<200;time++);
return(flag);//返回检测成功标志
}
//函数功能:
从DS18B20读取一个字节数据
unsignedcharReadOneChar(void)
{
unsignedchari=0;
unsignedchardat;//储存读出的一个字节数据
for(i=0;i<8;i++)
{
DQ=1;
_nop_();
DQ=0;
dat>>=1;
_nop_();
DQ=1;
for(time=0;time<2;time++);
if(DQ==1)
dat|=0x80;//如果读到的数据是1,则将1存入dat
else
dat|=0x00;//如果读到的数据是0,则将0存入dat
for(time=0;time<8;time++);//延时3us,两个读时序之间必须有大于1us的恢复期
}
return(dat);//返回读出的十进制数据
}
///函数功能:
向DS18B20写入一个字节数据
WriteOneChar(unsignedchardat)
{
unsignedchari=0;
for(i=0;i<8;i++)
{
DQ=1;
_nop_();
DQ=0;
DQ=dat&0x01;//利用与运算取出要写的某位二进制数据,
//并将其送到数据线上等待DS18B20采样
for(time=0;time<10;time++);//延时约30us,DS18B20在拉低后的约15~60us期间从数据线上采样
DQ=1;
for(time=0;time<1;time++);//延时3us,两个写时序间至少需要1us的恢复期
dat>>=1;//将dat中的各二进制位数据右移1位
}
for(time=0;time<4;time++);
}
///函数功能:
显示没有检测到DS18B20
voiddisplay_error(void)
{
unsignedchari;
WriteAddress(0x00);//写显示地址,将在第1行第1列开始显示
i=0;
while(Error[i]!
='\0')//只要没有写到结束标志,就继续写
{
WriteData(Error[i]);
i++;
delaynms(100);
}
while
(1);//进入死循环,等待查明原因
}
//函数功能:
显示说明信息
voiddisplay_explain(void)
{
unsignedchari;
WriteAddress(0x00);//写显示地址,将在第1行第1列开始显示
i=0;
while(Str[i]!
='\0')
{
WriteData(Str[i]);
i++;
delaynms(100);
}
}
//函数功能:
显示温度符号
voiddisplay_symbol(void)
{
unsignedchari;
WriteAddress(0x40);//写显示地址,将在第2行第1列开始显示
i=0;
while(Temp[i]!
='\0')//只要没有写到结束标志,就继续写
{
WriteData(Temp[i]);
i++;
delaynms(50);
}
}
//函数功能:
显示温度的小数点
voiddisplay_dot(void)
{
WriteAddress(0x45);//写显示地址,将在第2行第6列开始显示
WriteData('.');//将小数点的字符常量写入LCD
delaynms(50);
}
//函数功能:
显示温度的单位(Cent)
voiddisplay_cent(void)
{
unsignedchari;
WriteAddress(0x48);//写显示地址,将在第2行第8列开始显示
i=0;
while(Cent[i]!
='\0')
{
WriteData(Cent[i]);
i++;
delaynms(50);
}
}
//函数功能:
显示温度的整数部分
voiddisplay_temp1(unsignedcharx)
{
unsignedcharj,k,l;//j,k,l分别储存温度的百位、十位和个位
j=x/100;//取百位
k=(x%100)/10;//取十位
l=x%10;//取个位
WriteAddress(0x42);//写显示地址,将在第2行第3列开始显示
WriteData(digit[j]);//将百位数字的字符常量写入LCD
WriteData(digit[k]);//将十位数字的字符常量写入LCD
WriteData(digit[l]);//将个位数字的字符常量写入LCD
delaynms(50);
}
//函数功能:
显示温度的小数数部分
voiddisplay_temp2(unsignedcharx)
{
WriteAddress(0x46);//写显示地址,将在第2行第7列开始显示
WriteData(digit[x]);//将小数部分的第一位数字字符常量写入LCD
delaynms(50);
}
//函数功能:
做好读温度的准备
voidReadyReadTemp(void)
{
Init_DS18B20();
WriteOneChar(0xCC);//跳过读序号列号的操作
WriteOneChar(0x44);//启动温度转换
for(time=0;time<100;time++);
Init_DS18B20();
WriteOneChar(0xCC);//跳过读序号列号的操作
WriteOneChar(0xBE);//读取温度寄存器,前两个分别是温度的低位和高位
}
//函数功能:
主函数
voidmain(void)
{
unsignedcharTL;//储存暂存器的温度低位
unsignedcharTH;//储存暂存器的温度高位
unsignedcharTN;//储存温度的整数部分
unsignedcharTD;//储存温度的小数部分
LcdInitiate();//将液晶初始化
delaynms(5);
feng=1;
if(Init_DS18B20()==1)
display_error();
display_explain();
display_symbol();//显示温度说明
display_dot();//显示温度的小数点
display_cent();//显示温度的单位
while
(1)//不断检测并显示温度
{
ReadyReadTemp();//读温度准备
TL=ReadOneChar();//先读的是温度值低位
TH=ReadOneChar();//接着读的是温度值高位
TN=TH*16+TL/16;//实际温度值=(TH*256+TL)/16,即:
TH*16+TL/16
//这样得出的是温度的整数部分,小数部分被丢弃了
TD=(TL%16)*10/16;//计算温度的小数部分,将余数乘以10再除以16取整,
//这样得到的是温度小数部分的第一位数字(保留1位小数)
display_temp1(TN);//显示温度的整数部分
display_temp2(TD);//显示温度的小数部分
delaynms(10);
if(TN>=33||TN<=20)//温度大于33,小于20时报警
feng=!
feng;
elsefeng=1;
delaynms(10);
}
}
7:
设计小结
本次试验是基于DS18B20的可报警温度传感器,DS18B20外形像一个小三极管,硬件连接非常简单,它不仅能测量温度,而且也是一个ADC转换器,它能将测得的温度信号直接转换成数字信号输入到单片机。
硬件设计相对简单一些,但DS18B20软件编程比较复杂,不过可以把复位、读和写3个基本操作的子程序看成是3个固定的基本模块。
在软件编程时特别要注意时序问题,比如DS18b20对数据的采集和数据的转换,单片机检测输出脉冲和显示温度等,注意读写时序。
从这次的课程设计中,我意识到在以后的学习中,要理论联系实际,把我们所学的理论知识用到实际当中,课外自己动手做一些感兴趣和有意义的东西,对于程序只有在经常写与读的过程中才能提高,这样收获才会更大。
8:
附录
硬件仿真图