找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6018|回复: 10
打印 上一主题 下一主题
收起左侧

18b20+1602制作数字温度计的C51程序

  [复制链接]
跳转到指定楼层
楼主
闲来无事,用18b20温度传感器和1602液晶做了一个温度计,学习一下有关传感器的时序和操作,以及1602液晶显示程序.
效果如下:

[分享]18b20+1602制作数字温度计的C51程序硬件连接:
1、18b201脚接GND,3脚接5V电源,2脚接P2.7,并将2脚与电源间串一4.7K电阻;
2、1602 VDD接5V电源,VSS接GND;A接5V电源,K接GND;
3、VO串一1K电阻接5V电源;
4、RS接P1.0,RW接P1.1;
5、使能信号端E接P1.2;
6、D0-D7分别接P0.0-P0.7.

程序如下(些段程序是用很多别人的程序拼凑的,功能能实现,但肯定不是最优化的代码):
#include
#include

typedef unsigned char uint8;
typedef unsigned int uint16;
typedef char int8;
typedef int int16;

sbit DQ  = P2^7;                  //温度输入口
sbit RS = P1^0 ;
sbit RW = P1^1 ;
sbit EN = P1^2 ;
sbit BUSY = P0^7;
#define nops();  {_nop_(); _nop_(); _nop_(); _nop_();} //定义空指令

   uint8 i;
         uint16 temp,temp2;
         unsigned char xiaoshu1,xiaoshu2,xiaoshu;
void wait(void)
{
         P0 = 0xFF;
                   do
         {
                   RS = 0;
                   RW = 1;
                   EN = 0;
                   EN = 1;
         }while (BUSY == 1);
         EN = 0;
}

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;
}

void w_string(uint8 addr_start, uint8 *p)
{
         w_cmd(addr_start);
         while (*p != '\0')
         {
                   w_dat(*p++);
         }
}

void Init_LCD1602(void)
{
         w_cmd(0x38);  // 16*2显示,5*7点阵,8位数据接口
         w_cmd(0x0C);  // 显示器开、光标开、光标允许闪烁
         w_cmd(0x06);  // 文字不动,光标自动右移
         w_cmd(0x01);  // 清屏
}

void delay(uint16 n)
{
         while (n--);
}

void delay_ms(uint16 n)
{
         uint8 m=120;
         while (n--)
                   while (m--);
}

void DS18b20_reset(void)
{
         bit flag=1;
         while (flag)
         {
                   while (flag)
                 {
                           DQ = 1;
                            delay(1);
                           DQ = 0;
                           delay(50); // 550us
                           DQ = 1;
                           delay(6);  // 66us
                           flag = DQ;
               }
                   delay(45);    //延时500us
                   flag = ~DQ;
         }
         DQ=1;
}

void write_byte(uint8 val)
{
         uint8 i;
         for (i=0; i<8; i++)
         {
                   DQ = 1;
                   _nop_();
                   DQ = 0;
                   nops(); //4us
                   DQ = val & 0x01;      //最低位移出
                   delay(6);           //66us
                   val >>= 1;          //右移一位
         }
         DQ = 1;
         delay(1);
}

uint8 read_byte(void)
{
         uint8 i, value=0;
         for (i=0; i<8; i++)
         {
                   DQ=1;
                   _nop_();
                   value >>= 1;
                   DQ = 0;
                   nops();   //4us
                   DQ = 1;
                   nops();   //4us
                   if (DQ)
                            value|=0x80;
                   delay(6);           //66us
         }
         DQ=1;
         return(value);
}

void start_temp_sensor(void)
{
         DS18b20_reset();
         write_byte(0xCC); // 发Skip ROM命令
         write_byte(0x44); // 发转换命令
}

int16 read_temp(void)
{
         uint8 temp_data[2]; // 读出温度暂放
         DS18b20_reset();  // 复位
         write_byte(0xCC); // 发Skip ROM命令
         write_byte(0xBE); // 发读命令
         temp_data[0]=read_byte();  //温度低8位
         temp_data[1]=read_byte();  //温度高8位
         temp = temp_data[1];
         temp2=temp_data[1];
         temp <<= 8;
         temp |= temp_data[0];
         temp >>= 4;
         xiaoshu1 = (temp_data[0]&0x0f)*10/16; //小数第一位
         xiaoshu2 = (temp_data[0]&0x0f)*100/16;//小数
         xiaoshu=xiaoshu1*10+xiaoshu2; //小数
         //return temp;
}
unsigned char code word1[]={"Temperature:"};
uint8  table1[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};  //自定义字符数据地址
unsigned char table[]={0x10,0x06,0x09,0x08,0x08,0x09,0x06,0x00};//字符℃
uint16 a,j,k,n;

main()
{
         while (1)
         {
                   start_temp_sensor();
                   delay_ms (100); // 延时0.1秒
                   read_temp();
         a=temp/100;
         j=temp/10;
         k=temp-100*a-10*j;
         Init_LCD1602();
                                     w_cmd(0x40);
             for(n=0;n<8;n++)//写入温度符号代码
              {
               w_dat(table[n]);
               delay(1);
              }
         w_string(0x80,word1);
   w_cmd(0xC4);
         if(temp2>0x7f){
                   w_dat(45);       }//如果温度为负,显示负号
         if(a!=0){
        w_dat(a+48);}//如果百位是零则不显示
   w_dat(j+48);//十位
         w_dat(k+48);//个位
    w_dat(46);
         w_dat(xiaoshu1+48);
         w_dat(xiaoshu2+48);
   w_dat(table1[0]);//温度符号
}
}

在编写程序中,有很多感慨,毕竟自己不是电子专业,纯属业余爱好而已,所以编写程序中遇到了一些意想不到的麻烦.
1、在写延时程序时,这是在编写数码管显示程序时遇到的,当时想改编一下别人的程序:
void led_delay(void)
{
   unsigned char i,j;
         for(i=0;i<250;i++)
           for(j=0;j<250;j++)
             ;
}
程序中有一嵌套.我想加长延时的时间,所以就想将i或j改大一些,改成300或以上,但烧录后,却不成功,当时百思不得其解啊.后来才恍然大悟,char最大取值是255!所以就又加了一层嵌套.
2、在用1602显示温度时,显示简单汉字和英文均正常,但读取18b20的温度数值,显示到1602时,一直是乱码.当时想了各种办法,怎么也不成功,从变量到显示函数都认真研究了一遍,就是找不到问题.偶然机会,在网上看到,向1602发送的数字,1602当ASCII码!一语惊醒梦中人啊,将温度数字加上48后,一切正常!

    发生了这么两件简单的事情后,我发现,不是专业出身,没有经过系统学习是不行的!所以我从网上找了一套单片机学习教程,系统的学习了一遍,虽然没有达到精通的程度,但确实有了很大程度的进步!
这套教程由浅入深,循序渐进,有大量资料和说明,并配有教程中的所有程序,学习起来非常方便.

现在只传了一部分,其余部分陆续上传

评分

参与人数 1威望 +20 黑币 +20 收起 理由
admin + 20 + 20 很给力!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表