DS18B20温度采集并由lcd显示 - 图文

更新时间:2024-05-12 08:26:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

温度采集与显示系统

学院名称:光电与通信工程学院 专业名称:电子信息工程2班

组员信息:苏晓峰(1106012206)、郑元凯(1106012215)、梁斌(11060122) 指导老师:林峰 日期:2014年6月 15

目录

? 实验专题描述

—实验目的和实验功能 —系统硬件及软件 ——STC单片机介绍

? 实验原理与方法

— DS18C20简单原理介绍

— LCD1602简单原理介绍 — AT24C02简单原理介绍

? 实验结果与讨论

-专题制作过程中所遇到的困难与解決方法

? 心得与体会 ? 程序码

一、实验专题描述

单片机综合实验的目的是训练单片机应用系统的编程及调试能力,通过对一个单片机 应用系统进行系统的编程和调试,掌握单片机应用系统开发环境和仿真调试工具及仪器仪表的实用,掌握单片机应用程序代码的编写和编译,掌握利用单片机硬件仿真调试工具进行单片机程序的跟踪调试和排错方法,掌握示波器和万用表等杆塔工具在单片机系统调试中应用。

利用STC89C52、DS18B20、LCD1602、AT24C02等元器件设计温度采集与显示系统。系统具有以下功能: 1、能正确检测温度; 2、在1602上实时显示温度;

3、每隔10秒采集一次温度数据并保存到AT24C02 4、按键按下后,可逐个显示之前采集到的数据; 5、其他功能可根据系统上的资源自行设定。 扩展功能:

温度超过设定值,蜂鸣器报警;时间日期的显示;按键按下,重新开始采集温度等等

硬件组成:本系统所用的硬件有 如下图

序号 1 2 3 4 5 6 7 8 9 10 18 19 20 21 22 23 25 26 27 28 29 30 31 32 33 34 35 参数 STC89C52 DIP40针IC座 8针排针 MAX232E DIP16针IC座 DB9公头 0.1u瓷片电容 0.1u瓷片电容 DS18B20 3P圆孔座 5V有源蜂鸣器 100欧电阻 红色LED 1K排阻 8针排针 按键 1K欧电阻 11.0592M晶振 22p瓷片电容 10u瓷片电容 10K欧电阻 按键 直流电源插座 LM7805稳压芯片 0.33u瓷片电容 导线,杜邦线 数量 1 1 4 1 1 1 4 4 1 1 1 1 8 1 1 6 3 1 2 1 5 1 1 1 2 若干 存储电路 稳压电源 复位电路 中断电路 时钟电路 LED显示 蜂鸣器 温度传感器 串口下载 备注 单片机 AT24C02(DIP封装) 1 软件组成 软件有:keil软件、windows操作系统和串口调试助手等软件组成。

STC单片机介绍

单片机是随着大规模集成电路的出现极其发展,将计算机的CPU,RAM,ROM,定时/计数器和多种I/O接口集成在一片芯片上,形成了芯片级的计算机,因此单片机早期的含义称为单片微型计算机(single

chipmicrocomputer).它拥有优异的性价比、集成度高、体积小、可靠性高、控制功能强、低电压、低功耗的显著优点.主要应用于智能仪器仪表、工业检测控制、机电一体化等方面,并且取得了显著的成果.

图2-1单片机封装及引脚结构

DS18B20数字温度传感器介绍

DALLAS最新单线数字温度传感器DS18B20的“一线器件”体积更小、适用电压更宽、更经济 Dallas 半导体公司的数字化温度传感器DS1820是世界上第一片支持 “一线总线”接口的温度传感器。

表2-1DS18B20内部温度表示形式

DS18B20温度传感器的内部存储器包括一个高速暂存RAM和一个非易失性的可电擦除的E2PPRAM,后者存放高温度和低温度触发器TH、T和结构寄存器。暂存存储器包含了8个连续字节,前两个字节是测得的温度信息,第一个字节的内容是温度的低八位,第二个字节是温度的高八位。第三个和第四个字节是TH、TL的易失性拷贝,第五个字节是结构寄存器的易失性拷贝,这三个字节的内容在每一次上电复位时被刷新。第六、七、八个字节用于内部计算。第九个字节是冗余检验字节,见表2-3。

表2-3DS18B20暂存存储器的8个连续字节

寄存器内容 温度最低数字位 温度最高数字位 高温限值 低温限值 保留 字节地址 0 1 2 3 4 保留 计数剩余值 每度计数值 CTR校验 5 6 7 8

实验原理与方法

一、通过DS18B20采集温度数据,经I/O口传给单片机,单片机对接收到的数据进行实时在lcd上显示,并十秒采集通过I2C总线送到24c02进行储存,当按键按下时进入外部中断,并在外部中断中进行读取24c02所保存的值并在lcd上显示;拓展功能部分:在lcd的第二行显示时钟,并配有按键进行调时;温度报警电路,当温度上升到一定值时给蜂鸣器低信号,使其响起。

二、LCD顯示控制格式

实验结果与讨论

一、原理图

二、仿真结果

三、硬件结果

软件部分主要遇到的问题是温度采集保存到24c02模块,用一个字发送或者两个字节发送都会出问题,最后用八个字节发送就解决了此问题;关于显示部分,显示放在中断里执行会出现乱码,而放到主程序中则不会。 硬件部分主要是复位电路没焊好会使电路一直处于复位状态,反应出来结果就是无法显示任何内容。由于老师给的原理图是公头,而发下来的器件是母头,自己没有注意检查,到最后烧写程序的时候才发现,导致只能用开发板来烧写,给程序调试工作增加了很多工作量,并且单片机在拆卸过程中很容易损坏。

我们在调试过程一定要十分小心谨慎,因为有些芯片都是很容易烧坏的,稍有不慎就会导致某块芯片烧坏而导致实验结果出不来失败。其中我们在检查电路的时候一定要注意检查电路板的短路和虚焊的问题,要经过反复的用万用表不停的检测,由于电路连线比较复杂,所以在测试电路的问题上花了好多的时间。在本次实验中我们碰到的最大的问题就是LCD显示不能读取温度并显示,最终我们通过不断的检查电路和修改发现由于复位电路由一条线没有接地的原因,解决了就可以了啦。

心得与体会

在本次实验中,我们小组分工合作,首先要对所用的芯片进行了解和查找资料。在设计过程中protues仿真对设计来说也是很重要的,利用温

度传感器和时钟芯片进行对温度实践的检测,再将检测到的数据传送单片机经过程序的处理给LCD显示,在程序的调试过程中,主要注意的就是时间延迟函数和中断读取的设置。

通过这次对温度采集和显示的设计与制作,让我们了解了设计电路的程序,也让我们了解了关于单片机的原理与设计理念,要设计一个电路总要先用仿真仿真成功之后才实际接线的。但是最后的成品却不一定与仿真时完全一样,因为,再实际接线中有着各种各样的条件制约着。而且,在仿真中无法成功的电路接法,在实际中因为芯片本身的特性而能够成功。所以,在设计时应考虑两者的差异,从中找出最适合的设计方法。 通过这次学习,让我对各种电路都有了大概的了解,所以说,坐而言不如立而行,对于这些电路还是应该动手实际操作才会有深刻理解。从这次的课程设计中,我真真正正的意识到,在以后的学习中,要理论联系实际,把我们所学的理论知识用到实际当中,学习单机片机更是如此,程序只有在经常的写与读的过程中才能提高,这就是我在这次课程设计中的最大收获。

成员苏晓峰记——

在程序调试过程中,通过按键切换设置时间、当前温度和存储的温度一次显示在LCD上,在如何读取温度上的程序有些困惑,不知道用什么方法来写,自己上网查找各种资料,最后决定用中断来写,但调试过程而然碰

到了LCD显示出错了,而且并没有按照存储的数据顺序显示。通过几个晚上的思考和不断调试,不断的修改,总算是成功了。

成员郑元凯记——

在实验设计之前自己上网查找所用芯片的资料各种管脚接口和类似的一些这次实验作为参考,为设计过程中可能会产生的问题进行分析,尽可能的避免错误。但理论和实践还是有一定的差距的,不过在大家的努力下一一克服了。仿真后准备开始焊接电路前要进行电路的布局和线路的连接,最大化的减少交叉线和跑线,使电路板看上去简单明了。

成员梁斌记——

负责焊接的工作有点难度,不止考验焊接的功力还要有足够的耐心,根据已经布局好的电路进行焊接,省下了不少心力。每每焊接一部分,都要用万用表检查是否连接正确或者有存在虚焊的情况,尽可能的避免错误。完成后将程序烧录进去结果不能读取温度,大家都很着急,一起重新的检查,通过最后的补救总算是找到错误修改之后成功了。

程序码 主程序

#include #include

#define warn_35 350 #define warn_11 110 char miao,shi,fen,flag; uint s1num; uchar count,m,n; uint su,tt,mm; //uchar buff[4];

unsigned char pDat[7],pDat1[7]; sbit s1=P2^3; sbit s2=P2^4; sbit s3=P2^5;

sbit beep=P1^0;//蜂鸣器 void deal(uint tem) { }

void main() {

m=0; n=0; init(); EX0=1;

if((tem>warn_35)||(tem

else beep=1;

beep=0;

//init_com(); while(1) {

//包含了对定时器0的设定

tempchange(); tt=get_temp(); if(flag==1) {

EA=0; flag=0;

IRcvStr(0xa0,n,&pDat1[0],8);

mm=pDat1[0]*100+pDat1[1]*10+pDat1[2]; //pDat1[7]=0; n=n+0x08;

if(n==0xf8)

// }

} deal(tt);

write_sfm(12,miao); write_sfm(9,fen); write_sfm(6,shi);

dis_temp1(mm); n=0;

EA=1;

delay(5);

dis_temp(tt);

keyscan();

}

void int_0() interrupt 0

{

flag=1; }

void keyscan() {

if(s1==0) {

delay(5); if(s1==0) {

s1num++; while(!s1); if(s1num==1) { }

TR0=0;

write_com(0x80+0x40+12); //write_com(0x0f);

}

if(s1num==2) { }

if(s1num==3) {

write_com(0x80+0x40+9);

}

write_com(0x80+0x40+6);

if(s1num==4) { }

s1num=0; write_com(0x0c); TR0=1;

}

if(s1num!=0) {

if(s2==0) {

delay(5); if(s2==0) {

while(!s2); if(s1num==1) { }

if(s1num==2)

miao++; if(miao==60)

miao=0;

write_sfm(12,miao);

write_com(0x80+0x40+12);//指针回原位

}

}

{ }

if(s1num==3) { }

shi++; if(shi==24)

shi=0; fen++; if(fen==60)

fen=0;

write_sfm(9,fen);

write_com(0x80+0x40+9);//指针回原位

write_sfm(6,shi);

write_com(0x80+0x40+6);//指针回原位

if(s3==0) {

delay(5); if(s3==0) {

while(!s3); if(s1num==1) { /*

if(miao==0)

}

{ }*/ miao--; if(miao==-1)

miao=59; miao=59;

write_sfm(10,miao); write_com(0x80+0x40+10);

write_sfm(12,miao); write_com(0x80+0x40+12);

if(s1num==2) { }

if(s1num==3) {

shi--; if(shi==-1)

shi=23; fen--; if(fen==-1)

fen=59;

write_sfm(9,fen); write_com(0x80+0x40+9);

write_sfm(6,shi); write_com(0x80+0x40+6);

}

}

}

}

}

void timer0() interrupt 1 {

TH0=(65536-50000)/256; TL0=(65536-50000)%6; su++; if(su==100) { // } count++;

su=0;

pDat[0]=tt/100; pDat[1]=(tt0)/10; pDat[2]=tt;

ISendStr(0xa0,m,&pDat[0],8); //存温度 pDat[7]=0; m=m+0x08; if(m==0xf8) m=0;

if(count==20)

}

{ }

count=0; miao++; if(miao==60) { }

//write_sfm(10,miao);

miao=0; fen++; if(fen==60) { // }

//write_sfm(7,fen);

fen=0; shi++; if(shi==24) { }

write_sfm(4,shi);

shi=0;

温感部分

#include #include #include

sbit ds=P1^1; //温度传感器信号线 //sbit beep=P2^3; //蜂鸣器 uint temp; float f_temp;

void dsreset(void) //18B20复位,初始化函数 { uint i; ds=0; i=103; while(i>0)i--; ds=1; i=4; while(i>0)i--; }

bit tempreadbit(void) { uint i; bit dat;

ds=0;i++; ds=1;i++;i++; dat=ds; i=8;while(i>0)i--; return (dat); }

uchar tempread(void) {

//读1位函数 //i++ 起延时作用 //读1个字节 uchar i,j,dat; dat=0;

for(i=1;i<=8;i++) {

j=tempreadbit();

dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面,这样刚好一个字节在DAT里 }

return(dat); }

void tempwritebyte(uchar dat) //向18B20写一个字节数据 { uint i; uchar j; bit testb; for(j=1;j<=8;j++) {

testb=dat&0x01; dat=dat>>1; if(testb) //写 1 { ds=0; i++;i++; ds=1;

i=8;while(i>0)i--; } else

{

ds=0; //写 0 i=8;while(i>0)i--; ds=1; i++;i++; } } }

void tempchange(void) //DS18B20 开始获取温度并转换 {

dsreset(); delay(1);

tempwritebyte(0xcc); // 写跳过读ROM指令 tempwritebyte(0x44); // 写温度转换指令 }

uint get_temp() //读取寄存器中存储的温度数据 {

uchar a,b; dsreset(); delay(1);

tempwritebyte(0xcc); tempwritebyte(0xbe);

a=tempread(); //读低8位 b=tempread(); //读高8位 temp=b;

temp<<=8; //两个字节组合为1个字 temp=temp|a;

f_temp=temp*0.0625; //温度在寄存器中为12位 分辨率位0.0625° temp=f_temp*10+0.5; //乘以10表示小数点后面只取1位,加0.5是四舍五入 f_temp=f_temp+0.05;

return temp; //temp是整型 }

////////////////////显示程序调用lcd中的write_sfm1 十位地址写4 void dis_temp(uint t) { uint i; i=t/100; write_sfm1(0,i); i=(t0)/10; write_sfm1(1,i); i=t; write_sfm1(3,i); }

void dis_temp1(uint t) //显示储存的温度

{ uint i; i=t/100; write_sfm1(11,i); i=(t0)/10; write_sfm1(12,i); i=t;

个位为5 小数为7//////////////////////////

write_sfm1(14,i); }

/*void init_com(void) {

TMOD = 0x20; PCON = 0x00; SCON = 0x50; TH1 = 0xFd; TL1 = 0xFd; TR1 = 1; }

void comm(char *parr) { do {

SBUF = *parr++; 数据 while(!TI); 送完成标志为1 TI =0; 清零

}while(*parr); 环直到字符为'\\0' }

*/

//////////////////////////////////////////////

//发送

//等待发 //标志

//保持循

/*void warn(uint s,uchar led) //蜂鸣器报警声音 ,s控制音调 {

uchar i;i=s;

beep=0;

P1=~(led); while(i--) {

dis_temp(get_temp()); }

beep=1;

P1=0XFF; i=s; while(i--) {

dis_temp(get_temp()); } }

void deal(uint t) { uchar i;

if((t>warn_l2)&&(t<=warn_l1)) //大于25度小于27度

{

warn(40,0x01);

}

else if(t<=warn_l2) //小于25度

{

warn(10,0x03);

}

else if((t=warn_h1)) //小于32度大于30度 {

warn(40,0x04);

}

else if(t>=warn_h2)

{

warn(10,0x0c);

}

else { i=40; while(i--) {

dis_temp(get_temp()); } } }

*/

Lcd显示部分 #include sbit rs=P2^6; sbit lcden=P2^7; //sbit rw=P2^5;

uchar code tablenum[]= \

//大于32度 uchar code table[]= %uchar code table1[]=%uchar code table2[]=%uchar code table3[]=\ LIANGBIN \void delay(uint z) { }

void write_com(uchar com) { }

void write_date(uchar dat) {

rs=1; lcden=0; P0=dat; delay(5); rs=0; lcden=0; P0=com; delay(5); lcden=1; delay(5); lcden=0; uint x,y; for(x=z;x>0;x--)

for(y=110;y>0;y--);

}

lcden=1; delay(5); lcden=0;

void init() { // // //

uchar num; lcden=0; //rw=0; fen=59; miao=53; shi=23;

write_com(0x38); write_com(0x0c); write_com(0x06); write_com(0x01);

write_com(0x80);

for(num=0;num<16;num++)

{ }

write_com(0x80+0x40);

write_date(table2[num]); delay(5);

for(num=0;num<10;num++)

{

write_date(table3[num]);

}

}

delay(5);

delay(2000);

write_com(0x80);

for(num=0;num<16;num++)

{ }

write_date(table[num]); delay(5);

write_com(0x80+0x40); for(num=0;num<12;num++)

{ }

write_date(table1[num]); delay(5);

TMOD=0x01;

TH0=(65536-50000)/256; TL0=(65536-50000)%6; EA=1; ET0=1; TR0=1;

void write_sfm(uchar add,uchar dat)//写地址和自动显示两位数时间 {

uchar s,g; s=dat/10;

}

g=dat;

write_com(0x80+0x40+add); write_date(tablenum[s]); write_date(tablenum[g]);

void write_sfm1(uchar add,uchar dat) { } I2C部分

write_com(0x80+add); write_date(tablenum[dat]);

//写温度值十位地址写4 个位为5 小数为7

/*************************此部分为I2C总线的驱动程序*************************************/

#include #include #include

#define NOP() _nop_() /* 定义空指令 */ #define _Nop() _nop_() /*定义空指令*/ sbit SCL=P2^1; //I2C 时钟 sbit SDA=P2^0; //I2C 数据 bit ack; /*应答标志位*/

/******************************************************************* 起动总线函数 函数原型: void Start_I2c();

功能: 启动I2C总线,即发送I2C起始条件.

********************************************************************/ void Start_I2c() {

SDA=1; /*发送起始条件的数据信号*/ _Nop(); SCL=1;

_Nop(); /*起始条件建立时间大于4.7us,延时*/ _Nop(); _Nop(); _Nop(); _Nop();

SDA=0; /*发送起始信号*/

_Nop(); /* 起始条件锁定时间大于4μs*/ _Nop(); _Nop(); _Nop(); _Nop();

SCL=0; /*钳住I2C总线,准备发送或接收数据 */ _Nop(); _Nop(); }

/******************************************************************* 结束总线函数 函数原型: void Stop_I2c();

功能: 结束I2C总线,即发送I2C结束条件.

********************************************************************/

void Stop_I2c() {

SDA=0; /*发送结束条件的数据信号*/ _Nop(); /*发送结束条件的时钟信号*/ SCL=1; /*结束条件建立时间大于4μs*/ _Nop(); _Nop(); _Nop(); _Nop(); _Nop();

SDA=1; /*发送I2C总线结束信号*/ _Nop(); _Nop(); _Nop(); _Nop(); }

/******************************************************************* 字节数据发送函数 函数原型: void SendByte(UCHAR c);

功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对 此状态位进行操作.(不应答或非应答都使ack=0) 发送数据正常,ack=1; ack=0表示被控器无应答或损坏。 ********************************************************************/ void SendByte(unsigned char c) {

unsigned char BitCnt;

for(BitCnt=0;BitCnt<8;BitCnt++) /*要传送的数据长度为8位*/

{

if((c<

SDA=1; /*判断发送位*/

else

SDA=0;

_Nop();

SCL=1; _Nop();

_Nop(); _Nop(); _Nop();

_Nop(); SCL=0;

}

_Nop(); _Nop();

SDA=1; _Nop(); _Nop(); SCL=1; _Nop(); _Nop(); _Nop();

if(SDA==1)ack=0; else ack=1; SCL=0;

/*置时钟线为高,通知被控器开始接收数据位*/ /*保证时钟高电平周期大于4μs*/ /*8位发送完后释放数据线,准备接收应答位*/

/*判断是否接收到应答信号*/

_Nop(); _Nop(); }

/******************************************************************* 字节数据接收函数 函数原型: UCHAR RcvByte();

功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号), 发完后请用应答函数应答从机。

********************************************************************/ unsigned char RcvByte() {

unsigned char retc; unsigned char BitCnt; retc=0;

SDA=1; /*置数据线为输入方式*/ for(BitCnt=0;BitCnt<8;BitCnt++)

{

_Nop();

SCL=0; /*置时钟线为低,准备接收数据位*/ _Nop();

_Nop(); /*时钟低电平周期大于4.7μs*/ _Nop(); _Nop(); _Nop();

SCL=1; /*置时钟线为高使数据线上数据有效*/ _Nop();

_Nop(); retc=retc<<1; if(SDA==1)

retc=retc+1; /*读数据位,接收的数据位放入retc中 */

_Nop(); _Nop(); } }

/******************************************************************** 应答子函数 函数原型: void Ack_I2c(bit a);

功能: 主控器进行应答信号(可以是应答或非应答信号,由位参数a决定) ********************************************************************/ void Ack_I2c(bit a) {

if(a==0)

SDA=0; /*在此发出应答或非应答信号 */ SCL=0; _Nop(); _Nop(); return(retc);

else

SDA=1;

_Nop(); _Nop(); _Nop();

SCL=1; _Nop();

_Nop(); /*时钟低电平周期大于4μs*/ _Nop(); _Nop(); _Nop();

SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/ _Nop(); _Nop();

}

24c02部分

/*************************此部分为AT2402的驱动程序使用I2C总线连接*************************************/ #include //AT2402的功能函数

/******************************************************************* 向有子地址器件发送多字节数据函数 函数原型: bit ISendStr(UCHAR sla,UCHAR suba,ucahr *s,UCHAR no); 功能: 从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件 地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。 如果返回1表示操作成功,否则操作有误。 注意: 使用前必须已结束总线。

********************************************************************/

bit ISendStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char {

unsigned char i;

no) Start_I2c(); /*启动总线*/ SendByte(sla); /*发送器件地址*/ if(ack==0) return(0);

SendByte(suba); /*发送器件子地址*/ if(ack==0)return(0); for(i=0;i

SendByte(*s); /*发送数据*/ if(ack==0)return(0); s++; }

Stop_I2c(); /*结束总线*/ return(1); }

/******************************************************************* 向有子地址器件读取多字节数据函数 函数原型: bit RecndStr(UCHAR sla,UCHAR suba,ucahr *s,UCHAR no); 功能: 从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件 地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。 如果返回1表示操作成功,否则操作有误。 注意: 使用前必须已结束总线。

********************************************************************/

bit IRcvStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char {

unsigned char i;

Start_I2c(); /*启动总线*/

no) SendByte(sla); /*发送器件地址*/ if(ack==0)return(0);

SendByte(suba); /*发送器件子地址*/ if(ack==0)return(0);

Start_I2c(); /*重新启动总线*/ SendByte(sla+1); if(ack==0)return(0); for(i=0;i

*s=RcvByte(); /*发送数据*/ Ack_I2c(0); /*发送就答位*/ s++; }

*s=RcvByte();

Ack_I2c(1); /*发送非应位*/ Stop_I2c(); /*结束总线*/ return(1); }

Function.h部分

#define uchar unsigned char #define uint unsigned int

extern void write_sfm(uchar add,uchar dat); extern extern extern extern

void delay(uint z);

void dsreset(void); //18B20复位,初始化函数 bit tempreadbit(void); //读1位函数 uchar tempread(void); //读1个字节

本文来源:https://www.bwwdw.com/article/kc3g.html

Top