void w_dat(uint8 dat) {
wait(); EN = 0; P0 = dat; RS = 1; RW = 0; EN = 1; EN = 0; }
写命令
void w_cmd(uint8 cmd) {
wait(); EN = 0; P0 = cmd; RS = 0; RW = 0; EN = 1; EN = 0; }
发送字符串到LCD
void w_string(uint8 addr_start, uint8 *p) {
w_cmd(addr_start); while (*p != '\\0') { w_dat(*p++); } }
初始化1602
void Init_LCD1602(void) {
w_cmd(0x38); // 16*2显示,5*7点阵,8位数据接口 w_cmd(0x0c); // 显示器开、光标开、光标允许闪烁 w_cmd(0x06); // 文字不动,光标自动右移 w_cmd(0x01); // 清屏 }
uchar Reset()//完成单总线的复位操作。 {
uchar d;
DQ = 0; // 将 DQ 线拉低
Delayus(29); // 保持 480μs .复位时间为480μs,因此延时时间为(480-24)/16 = 28.5,取29μs。
DQ = 1; // DQ返回高电平
Delayus(3); // 等待存在脉冲.经过70μs之后检测存在脉冲,因此延时时间为(70-24)/16 = 2.875,取3μs。 d = DQ; // 获得存在信号 Delayus(25); // 等待时间隙结束
return(d); // 返回存在信号,0 = 器件存在, 1 = 无器件 }
void write_bit(uchar bitval)//向单总线写入1位值:bitval {
DQ = 0; // 将DQ 拉低开始写时间隙 if(bitval==1)
DQ =1; // 如果写1,DQ 返回高电平 Delayus(5);// 在时间隙内保持电平值,
DQ = 1; // Delayus函数每次循环延时16μs,因此Delayus(5)=5*16+24=104μs }
void ds18write_byte(char val)//向单总线写入一个字节值:val {
uchar i; uchar temp;
for (i=0; i<8; i++)// 写入字节, 每次写入一位 {
temp = val>>i; temp &= 0x01; write_bit(temp); }
Delayus(5); }
uchar read_bit()//从单总线上读取一位信号,所需延时时间为15μs,因此无法调用前面定义 { //的Delayus()函数,而采用一个for()循环来实现延时。 uchar i;
DQ = 0; //将DQ 拉低开始读时间隙 DQ = 1; // 然后返回高电平 for (i=0; i<3; i++); // 延时15μs return(DQ); // 返回 DQ 线上的电平值 }
uchar ds18read_byte()//从单总线读取一个字节的值 {
uchar i;
uchar value = 0; for (i=0;i<8;i++) { // 读取字节,每次读取一个字节
if(read_bit())
value|=0x01<
return(value); }
int Readtemperature()//如果单总线节点上只有一个器件则可以直接掉用本函数。如果节点上有多个器 { //件,为了避免数据冲突,应使用Match ROM函数来选中特定器件。
uchar temp_d,temp_g,k,get[2],temp; Reset();
ds18write_byte(0xcc); // 跳过 ROM ds18write_byte(0x44); // 启动温度转换 Delayus(5); Reset();
ds18write_byte(0xcc); // 跳过 ROM ds18write_byte(0xbe); // 读暂存器 for (k=0;k<2;k++) {
get[k]=ds18read_byte(); }
temp_d = get[0];//低位 temp_g = get[1];//高位
if((temp_g&0xf0)==0xf0) //正负号判断 {
temp_d=~temp_d;
if(temp_d==0xff) //保证-48(1111110100000000)、-32和-16显示正常 {
temp_d=temp_d+0x01;//00000000 temp_g=~temp_g;//00000010 temp_g=temp_g+0x01;//00000011 } else {
temp_d=temp_d+0x01;
temp_g=~temp_g; } w_cmd(0xc5);
w_dat(Xsw[temp_d&0x0f]); //查表得小数位的值 temp=((temp_d&0xf0)>>4)|((temp_g&0x0f)<<4); w_cmd(0xc1); w_dat(0x2d);//负号 }
else //正数 {
w_cmd(0xc5);
w_dat(Xsw[temp_d&0x0f]);//查表得小数位的值 temp=((temp_d&0xf0)>>4)|((temp_g&0x0f)<<4); w_cmd(0xc1);
w_dat(Bw[temp/100]); }
return temp; } main() {
Init_LCD1602();
w_string(0x80,word1); while (1) {
wendu=Readtemperature();
temp_g=wendu0/10+'0';//这里要特别注意啊少了0就差很多 temp_d=wendu+'0'; w_cmd(0xc2); delay(2);
w_dat(temp_g); delay(2);
w_dat(temp_d); delay(2);
w_cmd(0xc4); delay(2);
w_dat(0x2e);//小数点 delay(2);
w_cmd(0xc6); delay(2);
w_dat(0xdf);//温度符号 delay(2); w_dat(0x43); } }
六、设计体会
通过这次基于DS18B20传感器测量温度的设计,我学到了不少新的知识。首先,这次设计让我把书本上学到的理论知识转化成为现实生活中有价值的实物。如果没有这次设计为我 搭建的平台,我就不能对书本上的知识进行很好的理解,也不能熟练的把它们应用到现实生活中。还有,我们学会不能手高眼低,要踏踏实实,从基础学起、做起。但是,具体到设计时,我遇到了很多麻烦,比如如何将传感器得到的温度转换成为对应的电信号,如何将电信号输送到单片机进行控制,如何把测得的温度用数字显示出来等等。这就要求我们学习要一步一
个脚印,掌握扎实的理论基础了。最重要的一点是,我在这次设计中培养了自己的学习能力。由于好多知识超出了我们的课本范围,这就要求我们自己通过资料来增加我们的知识,解决遇到的一些问题。在短时间内从书本资料中筛选出我们所需要的知识,对我们的自主学习能力有很大的帮助。就拿DS18B20来说,我们书本上没有介绍到这种温度传感器,所以我们就通过学习DS18B20的说明书,了解它工作的原理以及特性,清楚在实际应用时要注意的事项,对DS18B20进行初始化、编程的要求和规定等。培养了自主学习的能力,无论以后我要做什么样的设计,我都能够通过查阅资料来实现。最后,本次设计能够顺利完成。 七、参考文献
【1】 梁森,欧阳三泰,王侃夫. 自动检测技术及应用【M】.北京:机械工业出版社.
【2】 万隆.单片机原理及应用技术教程 清华大学出版社.
【3】 李朝青.单片机原理及接口技术(简明修订版).杭州:北京航空航天大学出版社,
【4】 李广弟.单片机基础[M].北京:北京航空航天大学出版社. 【5】 康华光.数字电子技术基础(第四版). 北京:高等教育出版社.