打印

pic16f877a_18b20 采回的温度不对总是显示99.9有没有哪位朋友遇到相同的问题

[复制链接]
1035|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
LFD0776|  楼主 | 2017-8-8 17:36 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

#include <pic.h>
__CONFIG(0x3B31);
#define uchar unsigned char
#define uint  unsigned int

#define rs RD5           //命令/数据选择
#define rw RD4           //读写口
#define e  RD3           //锁存控制
#define Dataport PORTB   //数据口定义

unsigned char temp1;
unsigned char temp2;

//转换后的温度值小数点部分查表
const unsigned char table[16]={0,0,1,2,2,3,4,4,5,6,6,7,8,8,9,9};

uchar  dis0[16]={'T','h','e',' ','t','e','m','p',' ','n','o','w',' ','i','s',':',};//LCD第1行
uchar  dis[10]={' ',' ',' ',' ',0x00,0x00,'.',0x00,0xeb,'C'};                     //LCD第2行

//***********************************************************************************
//延时
//***********************************************************************************
void delay1(uint time)
{
uint i,j;
for(i = 0;i < time; i++)
{
   for(j = 0;j < 30; j++);
    }
}
//**************************************************************************************************
//向LCD写一命令
//**************************************************************************************************
wcode(uchar t)
{
  rs=0;           // 写的是命令
  rw=0;           // 写状态
  e=1;            //使能
  Dataport=t;     //写入命令
  delay1(20);     //等待写入,如果时间太短,会导致液晶无法显示
  e=0;            //数据的锁定
}
//**************************************************************************************************
//向LCD写一数据
//**************************************************************************************************
wdata(uchar t)
{
  rs=1;          // 写的是数据
  rw=0;          // 写状态
  e=1;           //使能
  Dataport=t;    //写入数据
  delay1(20);    //等待写入,如果时间太短,会导致液晶无法显示
  e=0;           //数据的锁定
}
//**************************************************************************************************
//LCD显示
//**************************************************************************************************
show()
{
  uchar i;
  wcode(0x80);          //设置第一行显示地址
  for(i=0;i<16;i++)     //循环16次,写完1行
    {
      wdata(dis0[i]);   //写入该行数据
    }

  wcode(0xc6);          //设置第一行显示地址
  for(i=0;i<10;i++)     //循环16次,写完1行
    {
      wdata(dis[i]);    //写入该行数据
    }
}
//**************************************************************************************************
//LCD 初始化
//**************************************************************************************************
InitLCD()
   {           
   wcode(0x01);          //清屏
   wcode(0x06);   //输入方式控制,增量光标不移位
   wcode(0x0e);   //显示开关控制
   wcode(0x38);   //功能设定:设置16x2显示,5x7显示,8位数据接口            
   }
//---------------------------------------
//名称:复位DS18B20函数
//---------------------------------------
unsigned char Reset(void)
{
                unsigned int i;   
                unsigned char k;       
                TRISD7=1;//先设置为输入
                NOP();NOP();
                TRISD7=0;                 //设置输出口
                NOP();NOP();
                RD7=0;                      //拉低DQ总线开始复位       
                   i=67;while(i>0)i--;  //保持DQ低大约870uS,符合不低于480US的要求                                      
            TRISD7=1;            //设置为输入口,以释放总线等电阻拉高总线
                    i=6;while(i>0)i--;  //大约78uS后,判断是否复位成功
                      
        if(RD7==0)                   //读出数据并保存
                   k=0;   
        else
                k=1;
                   i=31;while(i>0)i--; //维持约400US,符合总读时隙不低于480US的要求                             
                   return k;           //k=0为复位成功,k=1为复位失败
}

//---------------------------------------
//名称:写字节函数
//---------------------------------------
void WriteByte(unsigned char dat)
{
        unsigned int i;
           unsigned char j;
           for(j=0;j<8;j++)
           {            
                if(dat&0x01)        //如果写1
                      {      
                                TRISD7=0;        //设置RA4位输出口
                                   //NOP();
                                RD7=0;         //拉低      
                         NOP();NOP();NOP();NOP();NOP();NOP();//维持6US,符合大于1US小于15US的规范                                         
                         TRISD7=1;             //设置RA4为输入口,以释放总线等电阻拉高总线        
                         i=14;while(i>0)i--;   //维持约63US,符合不低于60US的要求
                         
                        }
              else        //如果写0
                      {         
                                TRISD7=0;        //设置R位输出口   
                                //NOP();
                                RD7=0;         //拉低                 
                         i=14;while(i>0)i--;        //维持约63US,符合不低于60US的要求                              
                         TRISD7=1;           //设置为输入口,以释放总线等电阻拉高总线                
                         NOP();//NOP();               //维持2US,符合大于1US的规范                                                 
                      }
        dat=dat>>1;        //写入字节右移1位
        }
}
//---------------------------------------
//名称:读字节函数
//---------------------------------------
unsigned char ReadByte(void)
{
        unsigned int i;
           unsigned char j,buf=0;
           for(j=1;j<=8;j++)        //接收8次还原一个字节数据
           {
                buf=buf>>1;          //接收前,先将接收缓冲区右移
                TRISD7=0;        //设置位输出口   
                RD7=0;         //拉低      
              NOP();NOP();NOP();NOP();NOP();NOP();//维持2US,符合大于1US小于15US的规范                    
              TRISD7=1;               //设置为输入口,以释放总线等电阻拉高总线 准备读       
                NOP();NOP(); //维持6US,符合大于1US小于15US的规范                              
                if(RD7==1) buf|=0x80;          //读出1位数据保存于buf中最高位
                i=3;while(i>0)i--;          //维持约52US,符合总读时隙不低于60US的要求                
}
                   return buf;                     //退出的同时将接收缓冲区参数返回       
}
//---------------------------------------
//名称:启动读温度函数
//---------------------------------------
unsigned char Convert(void)
{
        unsigned int i;
    if(Reset()==0)                    //如果复位成功
        {  
                i=77;                 //延时约1000US
              while(i>0)         //延时约1000US
              i--;            //延时约1000US
        WriteByte(0xCC);             // 跳过多器件识别
        WriteByte(0x44);             // 启动温度转换
                return 1;
    }
else
        {
return 0;
        }
}
//---------------------------------------
//名称:读温度函数
//---------------------------------------
void ReadFlash(void)
{
        unsigned int i;
    unsigned char Lsb,Msb;            
    if(Reset()==0)
{  
                i=77;while(i>0)i--;                 //延时约1000US                                       
        WriteByte(0xCC);              // 跳过多器件识别
        WriteByte(0xBE);              // 读暂存器
        
                Lsb=ReadByte();               // 低字节
        Msb=ReadByte();                     // 高字节
                temp2=Lsb&0x0f;                //LSB的低4位为小数部分
                temp1=(Lsb>>4)|(Msb<<4);//LSB的高4位和MSB拼成整数部分
    }   
else
        {
                temp1=0;
                temp2=0;
        }
}
//**************************************************************************************************
//主函数
//**************************************************************************************************
main()
{
        TRISB=0x00;       //RB设置为输出
        PORTB=0xff;       //初始化为高
    TRISA=0xff;
        PORTA=0x00;
        TRISD=0x80;     
        PORTD=0x80;   
          InitLCD();                 //液晶初始化
  while(1)                  
          {  
                    if(Convert()==1)                 //启动转换
                        {                    
                            ReadFlash();                       //读取温度                   
                         if(temp1>99) temp1=99;         
                         if(temp2>15) temp2=0;         
                            dis[4]=temp1/10+0x30;                
                            dis[5]=temp1%10+0x30;       
                            dis[7]=table[temp2&0x0f]+0x30;
                        }         
    show();                  //显示温度值
    delay1(500);             //延时
          }
}
沙发
LFD0776|  楼主 | 2017-8-8 17:41 | 只看该作者
之前温度低于33.6就会显示99.9,时序也修改过多次也不行,IO口也修改过也不行

使用特权

评论回复
板凳
LFD0776|  楼主 | 2017-8-9 10:43 | 只看该作者
刚刚又试了一下,试出来了!!这个程序没有问题,是我用的电脑软件有问题!!

使用特权

评论回复
地板
石婷婷| | 2017-9-1 16:36 | 只看该作者
你说的电脑软件有问题是MPLAB有问题吗

使用特权

评论回复
5
LFD0776|  楼主 | 2017-9-4 10:31 | 只看该作者
是的!!!编译软件版本不一样。需要修改时序才行!!!

使用特权

评论回复
6
石婷婷| | 2017-9-5 13:48 | 只看该作者
LFD0776 发表于 2017-9-4 10:31
是的!!!编译软件版本不一样。需要修改时序才行!!!

能帮我看下吗?我用的是PIC18F4431,晶振8Mhz,MPLAB+XC8,现在是只能读出FF,时序按着说明书也对了,就是不行。

#define DQ0        PORTEbits.RE0   //定义水箱出口温度数据端口   
#define DQ0_DIR    TRISEbits.TRISE0 //定义水箱出口温度方向寄存器


//*************** 水箱出口温度18B20******************//
//*************** 初始化******************//
bit  DS18B20_Init0(void)                //初始化18B20
{
    static bit presence;      //定义一个应答信号   
    DQ0_DIR=1;
    Nop();
    Nop();
    //Nop();
   
    DQ0_DIR =0;      //设置为输出      
    DQ0 = 0;
    Delay(80);                 //置总线为低电平并保持526us
     
    DQ0_DIR=1;              //等电阻拉高总线并保持15-60us
    Delay(10);               //延时约71us
   
    presence=DQ0;              //接受应答信号
    Delay(70);                 //延时约460us
   
    return(presence);         //返回应答信号
}

//---------------------------------------
//名称:写字节函数
//---------------------------------------
void WriteByte0(unsigned char dat)
{
   uchar i;
   for(i=0;i<8;i++)
      {            
        if(dat&0x01)        //如果写1
          {      
             DQ0_DIR =0;      //设置为输出   
             DQ0 = 0;      
             Nop();
             Nop();  
             Nop();
             Nop();     
             Nop();
             Nop(); //维持3US,符合大于1US小于15US的规范                                          
            
             DQ0_DIR =1; //设置RE0为输入口,以释放总线等电阻拉高总线
             Delay(10); //维持约75US,符合不低于60US的要求               
          }
        else        //如果写0
          {         
             DQ0_DIR =0;      //设置为输出        
             DQ0 = 0;            //设置输出口.拉低
             Delay(10);  //维持约75US,符合不低于60US的要求
            
             DQ0_DIR =1; //设置RE0为输入口,以释放总线等电阻拉高总线               
             Nop();
             Nop();
             Nop();
             Nop();
             Nop();
             Nop();//维持3US,符合大于1US的规范                                                  
           }
            dat>>=1;        //写入字节右移1位
      }
}
//---------------------------------------
//名称:读字节函数
//---------------------------------------
uchar ReadByte0(void)
  {
    uchar i,buf=0;
    for(i=1;i<=8;i++)        //接收8次还原一个字节数据
        {
         
          DQ0_DIR =1;
          Nop();Nop();Nop();Nop();
         
          DQ0_DIR =0;      //设置为输出      
          DQ0 = 0;            //设置输出口.拉低
          Nop();Nop();
          Nop();Nop();
          Nop();Nop();
         
          //维持3US,符合大于1US的规范                       
          buf>>=1;          //接收前,先将接收缓冲区右移
         
          DQ0_DIR =1;   //设置为输入口,以释放总线等电阻拉高总线 准备读   
          Nop();Nop();Nop();Nop();
          Nop();Nop();Nop();Nop();
          Nop(); Nop();   
          //维持5US,符合大于1US小于15US的规范  
         
          if(DQ0==1)
            {
               buf|=0x80;
            }//读1 /// 读0右移处理
          else
          {
              buf|=0x00;
          }
            Delay(10);////>60us
        }
    return buf;                     //退出的同时将接收缓冲区参数返回        
   }

//---------------------------------------
//名称:读温度函数
//---------------------------------------
unsigned int Readtemp0(void)
{
    unsigned char Lsb0,Msb0;            
    unsigned int temp0;   
    if(DS18B20_Init0()==0)
    {  
       Delay(160);      //延时约1000US
       WriteByte0(0xCC);             // 跳过多器件识别
       WriteByte0(0x44);             // 启动温度转换   
      
     }
        
    if(DS18B20_Init0()==0)
    {                                          
        Delay(160);      //延时约1000US  
        WriteByte0(0xCC);              // 跳过多器件识别
        WriteByte0(0xBE);              // 读暂存器
      
      
        Lsb0=ReadByte0();               // 低字节
        Msb0=ReadByte0();               // 高字节
      
       // Lsb0&=0X0F;
       // tempx0=Lsb0;                //LSB的低4位为小数部分
        Lsb0>>=4;
        Msb0<<=4;
        Lsb0|=Msb0;
        temp0=Lsb0;      //LSB的高4位和MSB拼成整数部分
    }
    else
    {
       // tempx0=0;
        temp0=0;
    }
    return(temp0);
}

使用特权

评论回复
7
LFD0776|  楼主 | 2017-9-21 09:36 | 只看该作者
你最好用软件防真一下你的时序!!!每一个软件版本不一样时序有差别的!!这个时序要求比较高!!还要系统用到中断也会出错!!

使用特权

评论回复
8
LFD0776|  楼主 | 2017-9-21 10:01 | 只看该作者
我看了这个好像一点乱!!!这里来了两个判断,,,,还有几个return!!


if(DS18B20_Init0()==0)
    {  
       Delay(160);      //延时约1000US
       WriteByte0(0xCC);             // 跳过多器件识别
       WriteByte0(0x44);             // 启动温度转换   
      
     }
        
    if(DS18B20_Init0()==0)
    {                                          
        Delay(160);      //延时约1000US  
        WriteByte0(0xCC);              // 跳过多器件识别
        WriteByte0(0xBE);              // 读暂存器
      
      
        Lsb0=ReadByte0();               // 低字节
        Msb0=ReadByte0();               // 高字节
      
       // Lsb0&=0X0F;
       // tempx0=Lsb0;                //LSB的低4位为小数部分
        Lsb0>>=4;
        Msb0<<=4;
        Lsb0|=Msb0;
        temp0=Lsb0;      //LSB的高4位和MSB拼成整数部分

使用特权

评论回复
9
石婷婷| | 2017-9-26 16:38 | 只看该作者
LFD0776 发表于 2017-9-21 10:01
我看了这个好像一点乱!!!这里来了两个判断,,,,还有几个return!!

谢谢!已经解决了,还是时序的问题

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

16

帖子

1

粉丝