这是我学习单片机制作的,设计参数主要有: 1.温度传感器采用DS18B20芯片;
2.LCD1602液晶模块作为显示器;
3.能够实现按键调整温度上下限; 4.能够显示年月日。
里面有电路仿真图,c程序等,希望能够帮助到大家。
- #include<reg51.h> //将AT89X52.h头文件包含到主程序
- #include<intrins.h> //将intrins.h头文件包含到主程序(调用其中的_nop_()空操作函数延时)
- #define uint unsigned int //变量类型宏定义,用uint表示无符号整形(16位)
- #define uchar unsigned char //变量类型宏定义,用uchar表示无符号字符型(8位)
- sbit lcdrs=P2^4;
- sbit lcdrw=P2^5;
- sbit lcden=P2^6;
- sbit ds=P1^3;
- sbit k1=P3^0;//设置按键
- sbit k2=P3^1;//加1按键
- sbit k3=P3^2;//减1按键
- //sbit k4=P3^3;//关蜂鸣器按键
- sbit D1=P1^0;
- sbit D2=P1^1;
- uchar flag,num;
- uint aa,bb;
- uchar miao,fen,shi,ri=3,month=7,year=18,num11;
- long uint temp,biaozhi; //参数temp一定要声明为 int 型
- //延时函数
- void Tempdelay11(uchar us) //经验表明,这里us=1时约等于6.9us
- {
- while(us--);
- }
- void delay11(uint count) //延时子函数,当count=1是,延时大概2ms
- {
- uint i;
- while(count)
- {
- i=200;
- while(i>0)
- i--;
- count--;
- }
- }
- void delay(uint z)
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=110;y>0;y--);
- }
- /******************lcd液晶程序部分**************************/
- void write_com(uchar com) //lcd写指令
- {
- lcdrs=0;
- lcdrw=0;
- P0=com;
- lcden=1;
- delay(5);
- lcden=0;
- }
- void write_date(uchar date) //lcd写数据
- {
- lcdrs=1;
- lcdrw=0;
- P0=date;
- lcden=1;
- delay(5);
- lcden=0;
- }
- void init() //lcd初始化
- {
- lcdrw=0;
- write_com(0x38); //lcd液晶 显示模式设置
- write_com(0x0c); //lcd液晶 开显示 关光标 关闪烁
- write_com(0x06); //读一个字节 光标指针加一 不整屏移动
- write_com(0x01); //清屏
- write_com(0x80); //设置数据指针
- }
- void key()
- {
- if(k1==0)//判断k1按键是否按下
- {
- delay(10);//延时,消抖
- if(k1==0)//再次判断k1按键是否按下
- {
- while(k1==0);//按键松手检测
- num++;
- if(num==1)
- {
- write_com(0x80+9);
- write_com(15);
- }
- if(num==2)
- {
- write_com(0x80+15);
- }
- if(num==3)
- {
- num=0;
- write_com(12);
- }
- }
- }
- if(num!=0)
- {
- if(k2==0)//判断k1按键是否按下
- {
- delay(10);//延时,消抖
- if(k2==0)//再次判断k1按键是否按下
- {
- while(k2==0);//按键松手检测
- if(num==1)
- {
- aa++;
- if(aa==1000)
- aa=0;
- write_com(0x80+6);
- write_date(48+aa/100);
- write_com(0x80+7);
- write_date(48+aa/10%10);
- write_com(0x80+9);
- write_date(48+aa%10);
- write_com(0x80+8);
- write_date('.');
- }
- if(num==2)
- {
- if(bb<aa)
- bb++;
- if(bb==1000)
- bb=0;
- write_com(0x80+12);
- write_date(48+bb/100);
- write_date(48+bb/10%10);
- write_com(0x80+15);
- write_date(48+bb%10);
- write_com(0x80+14);
- write_date('.');
- }
- }
- }
- if(k3==0)//判断k1按键是否按下
- {
- delay(10);//延时,消抖
- if(k3==0)//再次判断k1按键是否按下
- {
- while(k3==0);//按键松手检测
- if(num==1)
- {
- if(aa>0)
- aa--;
- if(aa==-1)
- aa=999;
- write_com(0x80+6);
- write_date(48+aa/100);
- write_date(48+aa/10%10);
- write_com(0x80+9);
- write_date(48+aa%10);
- write_com(0x80+8);
- write_date('.');
- }
- if(num==2)
- {
- if(bb>0)
- bb--;
- if(bb==-1)
- bb=999;
- write_com(0x80+12);
- write_date(48+bb/100);
- write_date(48+bb/10%10);
- write_com(0x80+15);
- write_date(48+bb%10);
- write_com(0x80+14);
- write_date('.');
- }
- }
- }
- }
- }
- //LCD1602液晶的显示
- void display(uint temp)
- {
- uchar bai,shi,ge;
- bai=temp/100;
- shi=temp/10%10;
- ge=temp%10;
- if(num==0)
- {
- if(biaozhi==1)
- {
- biaozhi=0;
- }
- write_com(0x80);
- write_date(48+bai);
- write_date(48+shi);
- write_date('.');
- write_date(48+ge);
- write_date(' ');
- write_date('H');
- write_date(48+aa/100);
- write_date(48+aa/10%10);
- write_date('.');
- write_date(48+aa%10);
- write_date(' ');
- write_date('L');
- write_date(48+bb/100);
- write_date(48+bb/10%10);
- write_date('.');
- write_date(48+bb%10);
- if(temp>aa)
- {
- D1=0;
- }
- else
- D1=1;
- if(temp<bb)
- D2=0;
- else
- D2=1;
- }
- write_com(0xc0+3);
- write_date('2');
- write_date('0');
- write_date(48+year/10);
- write_date(48+year%10);
- write_date('-');
- write_date(48+month/10);
- write_date(48+month%10);
- write_date('-');
- write_date(48+ri/10);
- write_date(48+ri%10);
- }
- /*****************************************
- 时序:初始化时序、读时序、写时序。
- 所有时序都是将主机(单片机)作为主设备,单总
- 线器件作为从设备。而每一次命令和数据的传输
- 都是从主机主动启动写时序开始,如果要求单总
- 线器件回送数据,在进行写命令后,主机需启动
- 读时序完成数据接收。数据和命令的传输都是低
- 位在先。
- 初始化时序:复位脉冲 存在脉冲
- 读;1 或 0时序
- 写;1 或 0时序
- 只有存在脉冲信号是从18b20(从机)发出的,其
- 它信号都是由主机发出的。
- 存在脉冲:让主机(总线)知道从机(18b20)已
- 经做好了准备。
- ******************************************/
- /*--------------------------------------------------------------------------------------------------------------------
- 初始化:检测总线控制器发出的复位脉冲
- 和ds18b20的任何通讯都要从初始化开始
- 初始化序列包括一个由总线控制器发出的复位脉冲
- 和跟在其后由从机发出的存在脉冲。
- 初始化:复位脉冲+存在脉冲
- 具体操作:
- 总线控制器发出(TX)一个复位脉冲 (一个最少保持480μs 的低电平信号),然后释放总线,
- 进入接收状态(RX)。单线总线由5K 上拉电阻拉到高电平。探测到I/O 引脚上的上升沿后
- DS1820 等待15~60μs,然后发出存在脉冲(一个60~240μs 的低电平信号)。
- 具体看18b20 单线复位脉冲时序和1-wire presence detect "的时序图
- -------------------------------------------------------------------------------------------------------------------*/
- void ds_reset()
- {
- ds=1;
- _nop_(); //1us
- ds=0;
- Tempdelay11(80); //当总线停留在低电平超过480us,总线上所以器件都将被复位,这里
- //延时约530us总 线停留在低电平超过480μs,总线上的所有器件都将被复位。
- _nop_();
- ds=1; //产生复位脉冲后,微处理器释放总线,让总线处于空闲状态,原因查
- //18b20中文资料
- Tempdelay11(5); //释放总线后,以便从机18b20通过拉低总线来指示其是否在线,
- //存在检测高电平时间:15~60us, 所以延时44us,进行1-wire presence //detect(单线存在检测)
- _nop_();
- _nop_();
- _nop_();
- if(ds==0)
- flag=1; //detect 18b20 success
- else
- flag=0; //detect 18b20 fail
- Tempdelay11(20); //存在检测低电平时间:60~240us,所以延时约140us
- _nop_();
- _nop_();
- ds=1; //再次拉高总线,让总线处于空闲状态
- }
- /*----------------------------------------
- 读/写时间隙:
- DS1820 的数据读写是通过时间隙处理
- 位和命令字来确认信息交换。
- ------------------------------------------*/
- bit ds_read_bit() //读一位
- {
- bit dat;
- ds=0; //单片机(微处理器)将总线拉低
- _nop_(); //读时隙起始于微处理器将总线拉低至少1us
- ds=1; //拉低总线后接着释放总线,让从机18b20能够接管总线,输出有效数据
- _nop_();
- _nop_(); //小延时一下,读取18b20上的数据 ,因为从ds18b20上输出的数据
- //在读"时间隙"下降沿出现15us内有效
- dat=ds; //主机读从机18b20输出的数据,这些数据在读时隙的下降沿出现15us内有效
- Tempdelay11(10); //所有读"时间隙"必须60~120us,这里77us
- return(dat); //返回有效数据
- }
- uchar ds_read_byte() //读一字节
- {
- uchar value,i,j;
- value=0; //一定别忘了给初值
- for(i=0;i<8;i++)
- {
- j=ds_read_bit();
- value=(j<<7)|(value>>1); //这一步的说明在一个word文档里面
- }
- return(value); //返回一个字节的数据
- }
- void ds_write_byte(uchar dat) //写一个字节
- {
- uchar i;
- bit onebit; //一定不要忘了,onebit是一位
- for(i=1;i<=8;i++)
- {
- onebit=dat&0x01;
- dat=dat>>1;
- if(onebit) //写 1
- {
- ds=0;
- _nop_();
- _nop_(); //看时序图,至少延时1us,才产生写"时间隙"
- ds=1; //写时间隙开始后的15μs内允许数据线拉到高电平
- Tempdelay11(5); //所有写时间隙必须最少持续60us
- }
- else //写 0
- {
- ds=0;
- Tempdelay11(8); //主机要生成一个写0 时间隙,必须把数据线拉到低电平并保持至少60μs,这里64us
- ds=1;
- _nop_();
- _nop_();
- }
- }
- }
- /*****************************************
- 主机(单片机)控制18B20完成温度转换要经过三个步骤:
- 每一次读写之前都要18B20进行复位操作,复位成功后发送
- 一条ROM指令,最后发送RAM指令,这样才能对DS18b20进行
- 预定的操作。
- 复位要求主CPU将数据线下拉500us,然后释放,当ds18B20
- 受到信号后等待16~60us,后发出60~240us的存在低脉冲,
- 主CPU收到此信号表示复位成功
- ******************************************/
- /*----------------------------------------
- 进行温度转换:
- 先初始化
- 然后跳过ROM:跳过64位ROM地址,直接向ds18B20发温度转换命令,适合单片工作
- 发送温度转换命令
- ------------------------------------------*/
- void tem_change()
- {
- ds_reset();
- delay11(1); //约2ms
- ds_write_byte(0xcc);
- ds_write_byte(0x44);
- }
- /*----------------------------------------
- 获得温度:
- ------------------------------------------*/
- uint get_temperature()
- {
- float wendu;
- uchar a,b;
- ds_reset();
- delay11(1); //约2ms
- ds_write_byte(0xcc);
- ds_write_byte(0xbe);
- a=ds_read_byte();
- b=ds_read_byte();
- temp=b;
- temp<<=8;
- temp=temp|a;
- /*if((b&0x80)==0x80)
- {
- biaozhi=1;//设置温度正负的标志
- temp=0xffff-temp;
- temp=temp+1;
- }*/
- wendu=temp*0.0625; //得到真实十进制温度值,因为DS18B20
- //可以精确到0.0625度,所以读回数据的最低位代表的是0.0625度
- temp=wendu*10.0+0.5; //放大十倍,这样做的目的将小数点后第一位
- //也转换为可显示数字,同时进行一个四舍五入操作。
- return temp;
- }
- void main()
- {
- aa=500;
- bb=50;
- EA=1;
- ET0=1;
- TMOD=0x01;
- TH0=(65536-50000)/256;
- TL0=(65536-50000)%256;
- TR0=1;
- init();
- while(1)
- {
- key();
- if(num==0)
- {
- tem_change(); //开始转换12位转换时间最大为750ms
- get_temperature();//000000000000
- }
- display(temp);
- }
- }
- //定时器0中断子函数
- void t0() interrupt 1
- {
- TH0=(65536-50000)/256;
- TL0=(65536-50000)%256;
- num11++;
- if(num11==20)
- {
- num11=0;
- miao++;
- if(miao==60)
- {
- miao=0;
- fen++;
- if(fen==60)
- {
- fen=0;
- shi++;
- if(shi==24)
- {
- shi=0;
- fen=0;
- miao=0;
- ri++;
- if(ri==29)
- if((year%4!=0)&&(month==2))
- {
- ri=1;
- month++;
- if(month==13)
- {
- month=1;
- year++;
- }
- }
- if(ri==30)
- if((year%4==0)&&(month==2))
- {
- ri=1;
- month++;
- if(month==13)
- {
- month=1;
- year++;
- }
- }
- if(ri==31)
- if((month==4)||(month==6)||(month==9)||(month==11))
- {
- ri=1;
- month++;
- if(month==13)
- {
- month=1;
- year++;
- }
- }
- if(ri==32)
- if((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12))
- {
- ri=1;
- month++;
- if(month==13)
- {
- month=1;
- year++;
- }
- }
- }
- }
- }
- }
- }
复制代码全部资料51hei下载地址:
基于DS18B20的温度计.zip
(79.31 KB, 下载次数: 132)
|