打印
[AVR单片机]

DS18B20 AVR 写时序有问题,不能显示温度,望高手指教

[复制链接]
1863|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
aifang|  楼主 | 2012-12-6 10:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#ifndef DS18B20_H_INCLUDED
#define DS18B20_H_INCLUDED

#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>

#define DS18B20_DDR DDRD
#define DS18B20_PORT PORTD
#define DS18B20_PIN PIND

#define DQ 7

#define DS18B20_DQ_DDR_0 (DS18B20_DDR &= ~(1 << DQ))
#define DS18B20_DQ_DDR_1 (DS18B20_DDR |= (1 << DQ))
#define DS18B20_DQ_0 (DS18B20_PORT &= ~(1 << DQ))
#define DS18B20_DQ_1 (DS18B20_PORT |= (1 << DQ))
#define DS18B20_DQ_PIN (DS18B20_PIN & (1 << DQ))==(1 << DQ)

char DS18B20_Init(void);
void DS18B20_Write_Com(unsigned char Data);
char DS18B20_Read_Data(void);
void DS18B20_Read_Temperature(void);
void DS18B20_Read_Temperature(void);
void DS18B20_Convert_Temp(char *sign,char *Temperature);

///设置全局变量用于存储从DS18B20读取的温度值
char Temp_Value[2];

#endif // DS18B20_H_INCLUDED

#include "DS18B20.h"

/// DS18B20初始化子程序
char DS18B20_Init(void)
{
    DS18B20_DQ_DDR_1;
    DS18B20_DQ_0;               ///拉低总线,持续480us左右,初始化、复位器件
    _delay_us(500);
    DS18B20_DQ_DDR_0;
    _delay_us(60);
    return (DS18B20_DQ_PIN);    ///用于判断复位是否成功,若成功则返回的值为0,否则为1
    DS18B20_DQ_DDR_1;
    DS18B20_DQ_1;               ///释放总线,持续300us,等待器件发出存在脉冲
    _delay_us(300);
}
///向DS18B20写1字节子程序
void DS18B20_Write_Com(unsigned char Data)
{
    unsigned char i = 0;
    DS18B20_DQ_DDR_1;
    for(i = 0;i < 8;i++)
    {
        DS18B20_DQ_0;      ///拉低总线,产生些时间片
        _delay_us(45);     ///I/O线有高电平变为低电平后,DS18B20在15us至60us之间对I/O口采样,为高写1,为低写0
        if((Data & (1 << i)) == (1 << i))
            DS18B20_DQ_1;   ///写1
        else
            DS18B20_DQ_0;   ///写0
        _delay_us(20);     ///所有写时间片最短持续期限为60us,各周期之间必须有最短为1us的恢复时间
    }
    DS18B20_DQ_1;      ///释放总线
}
///从DS18B20读1字节子程序
char DS18B20_Read_Data(void)
{
     unsigned char i,Data=0;
     for(i = 0;i < 8;i++)
     {
         Data >>= 1;        ///数据位右移,先读出的为低位,后读出的为高位
         DS18B20_DQ_DDR_1;  ///设置总线为输出
         DS18B20_DQ_0;      ///拉低总线,产生读时间片
         _delay_us(5);
         //DS18B20_DQ_1;      ///因DS18B20输出数据在主机下降沿15秒之内有效,延时后需释放总线
         DS18B20_DQ_DDR_0;  ///设置总线为读功能,读出DS18B20内的数据
         if(DS18B20_DQ_PIN)
            Data |= 0x80;   ///先读出的为低位,所以或0x80,然后右移
         _delay_us(60);     ///所有读时间片最短持续期限为60us
     }
     DS18B20_DQ_DDR_1;      ///总线设为输出
     return Data;
}
///读取温度值
void DS18B20_Read_Temperature(void)
{
    DS18B20_Init();
    DS18B20_Write_Com(0xCC);     ///跳过序列号
    DS18B20_Write_Com(0x44);     ///启动温度转换
    _delay_ms(10);
    DS18B20_Init();
    DS18B20_Write_Com(0xCC);     ///跳过序列号
    DS18B20_Write_Com(0xBE);     ///读取温度寄存器
    Temp_Value[0]=DS18B20_Read_Data();///读取当前温度低8位
    Temp_Value[1]=DS18B20_Read_Data();///读取当前温度高8位
}
///转换温度数据,返回温度符号sign,整数部分Temprature
void DS18B20_Convert_Temp(char *sign,char *Temperature)
{
    *sign=1;                        ///温度符号先设为正
    if((Temp_Value[1]&0xF8)==0xF8)  ///如果为负数则读取值取反加1转换为温度值,并设置负号标识
    {
        Temp_Value[1]=~Temp_Value[1];
        Temp_Value[0]=~Temp_Value[0]+1;
        if(Temp_Value[0]==0x00)
            Temp_Value[1]++;
        *sign=-1;
    }
    *Temperature=(Temp_Value[0]>>4)|(Temp_Value[1]<<4);///获取温度值
}

相关帖子

沙发
aifang|  楼主 | 2012-12-6 10:54 | 只看该作者
初始化没有问题,写时序有问题,高手指教

使用特权

评论回复
板凳
blessdxp| | 2012-12-6 12:29 | 只看该作者
肯定是时时序问题,对照18B20的时序表格在看程序,应该是没有问题的,我用过

使用特权

评论回复
地板
blessdxp| | 2012-12-6 12:31 | 只看该作者
#include   <ADuC7026.h>
#include   "constant.h"
#include   "variable.h"
#include   <math.h>
#define DQ_OUT_1 { GP2DAT = GP2DAT|0x04000000; GP2SET=0x00040000;}  //P2.2输出1
#define DQ_OUT_0 { GP2DAT = GP2DAT|0x04000000; GP2CLR=0x00040000;}  //P2.2输出0
#define DQ_IN { GP2DAT = GP2DAT&0xFBFFFFFF;read = GP2DAT;}

int DS18B20_ini(void);

int DS18B20_read(void);

void DS18B20_write(int);

void DS18B20_delay(int);

int read = 0xFF;
/*******************************************************************/
int DS18B20_ini(void)
{
        int j_ini;
        int  DS18B20_FLAG;
        DQ_OUT_1;
        DS18B20_delay(150);
        DQ_OUT_0;                             //发送复位脉冲
        DS18B20_delay(2600);
        DQ_OUT_1;
        DS18B20_delay(220);
        j_ini = 240;                        //设置采样总线周期个数
        DS18B20_FLAG = 1;            //是否收到存在脉冲标志,DS18B20_FLAG=1表示收到,DS18B20_FLAG=0表示失败
        DQ_IN;                             
        while (read & 0x04!=0)
        {
                j_ini--;                                                          
                if( j_ini == 0 )
                {
                        DS18B20_FLAG = 0;
                        break;
                }
                DS18B20_delay(80);
                DQ_IN;
        }
        DQ_OUT_1;
        DS18B20_delay(80);
        DQ_IN;       
        while (read & 0x04 == 0)
        {                         
                DS18B20_delay(160);
                DQ_IN;
        }
        return DS18B20_FLAG;
}

/********************************************************************
        *********************写函数*********************************
********************************************************************/
void DS18B20_write(int buf)
{
        int j_write;
        DQ_IN;
        while ((read & 0x04) == 0)
        {
                DS18B20_delay(80);
                DQ_IN;
        }
        GP2DAT = GP2DAT|0x04000000;
        for( j_write = 0;j_write<8;j_write++)
        {
                GP2CLR = 0x00040000;
                DS18B20_delay(35);

                if((buf & 0x0001) == 1)
                {
                        GP2SET = 0x00040000;
                }
                else
                {
                        GP2CLR = 0x00040000;
                }
                DS18B20_delay(450);
                buf = buf >> 1;
                GP2SET = 0x00040000;
                DS18B20_delay(35);
        }
}

/********************************************************************
        ****************************读函数**************************
********************************************************************/
int DS18B20_read(void)
{
        int j_read,buf = 0;
        GP2DAT = GP2DAT&0xFBFFFFFF;
        DQ_IN;
        while ((read & 0x04) == 0)
        {
                DS18B20_delay(80);
                read = GP2DAT;
        }
        for( j_read = 0;j_read<16;j_read++)
        {
                DQ_OUT_1;
                DS18B20_delay(35);

                DQ_OUT_0;
                DS18B20_delay(5);

                DQ_IN;
                read = read >> 2;
                buf |= (read & 0x0001) << j_read;
                DS18B20_delay(310);
        }
        DQ_OUT_1;
        return buf;

}

/*******************************************************************/
float Temper_Test(void)
{
        char j_test = 0;
        int temp1;
        float i_test,tempt;          
        while((DS18B20_ini() == 0)&&(j_test < 10 ))
        {       
                j_test++;
                DS18B20_delay(400);
        }
        if ( j_test == 10 )
        {
                tempt = 0xAAAA;        //表示总线上没有可工作的DS18b20
                return tempt;
        }
        else
        {
                DS18B20_ini();
                DS18B20_write(0xCC);//跳过ROM
                DS18B20_write(0x44);//温度开始转换
                DQ_IN;
                while ((read & 0x0004) == 0)
                {
                        DS18B20_delay(400);
                        DQ_IN;
                }
                DS18B20_ini();
                DS18B20_write(0xCC); //跳过ROM
                DS18B20_write(0xBE); //发送读温度值命令
                DS18B20_delay(400);                        ///;
                temp1 = DS18B20_read();//将温度值读入内存
                DS18B20_ini();         
               
                for(i_test = 0.0625,j_test = 0;j_test < 11;j_test++) //温度十六进制转十进制
                {
                       
                        tempt += (temp1 & 0x0001) * i_test;
                        i_test *= 2;
                        temp1 >>= 1;
                }
                if(temp1 & 0x0001)        //判断温度是正还是负
                {
                        tempt = -tempt;
                }         
        }

               return tempt;
}

void DS18B20_delay(int length)   //延时
{
    while(length>=0)       
        length--;       
}

使用特权

评论回复
5
aifang|  楼主 | 2012-12-8 09:56 | 只看该作者
找到问题了,是写时序里void DS18B20_Write_Com(unsigned char Data)
{
    unsigned char i = 0;
    DS18B20_DQ_DDR_1;
    for(i = 0;i < 8;i++)
    {
        DS18B20_DQ_0;      ///拉低总线,产生些时间片
        _delay_us(45);     ///I/O线有高电平变为低电平后,DS18B20在15us至60us之间对I/O口采样,为高写1,为低写0



//此处延时较长,改为十几微秒就好用了
        if((Data & (1 << i)) == (1 << i))
            DS18B20_DQ_1;   ///写1
        else
            DS18B20_DQ_0;   ///写0
        _delay_us(20);     ///所有写时间片最短持续期限为60us,各周期之间必须有最短为1us的恢复时间
    }
    DS18B20_DQ_1;      ///释放总线
}


多谢指教

使用特权

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

本版积分规则

2

主题

35

帖子

0

粉丝