打印

原创 18B20 读写程序 ------ 收砖

[复制链接]
3017|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
E007|  楼主 | 2009-2-15 22:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
//=============================================================================
//=============================================================================
//=============================================================================
// 原创 18B20 读写程序,欢迎拍砖
// www.21ic.com 之 E007
//=============================================================================
//=============================================================================
//=============================================================================


//=============================================================================
//=============================================================================
//=============================================================================
// 以下为 F_18B20.h 文件
//=============================================================================
//=============================================================================
//=============================================================================

#ifndef __F_18B20_H__
#define __F_18B20_H__
//-----------------------------------------------------------------------------

void DS18B20_Init(void);
int  DS18B20_ReadTemp();

//-----------------------------------------------------------------------------
#endif                          // #ifndef __F_18B20_H__
// End of this file

//=============================================================================
//=============================================================================
//=============================================================================
// 以下为 F_18B20.c 文件
//=============================================================================
//=============================================================================
//=============================================================================

#include "F_18B20.h"

// 常用数据类型定义,这部分我是放在 main.h 中的,这里一起贴出来
#ifndef __UU_DEF__
#define __UU_DEF__

typedef unsigned char   U8;
typedef unsigned int    U16;
typedef unsigned long   U32;

typedef signed char     S8;
typedef signed int      S16;
typedef signed long     S32;

typedef union UU16
{
   U16  u16;
   S16  s16;
   U8   u8[2];
   S8   s8[2];
} UU16;
// used with UU16
# define LSB 1
# define MSB 0

typedef union UU32
{
   U32  u32;
   S32  s32;
   UU16 uu16[2];
   U16  u16[2];
   S16  s16[2];
   U8   u8[4];
   S8   s8[4];
} UU32;
// used with UU32 (b0 is least-significant byte)
# define b0 3
# define b1 2
# define b2 1
# define b3 0

typedef unsigned char BYTE;
typedef unsigned char UCHAR;
typedef union {unsigned short i; unsigned char c[2];} WORD;
// 这些定义包容了大部分人习惯的写法
#endif          // #ifndef __UU_DEF__


//-----------------------------------------------------------------------------
// 以下定义 1-Wire 时隙
// 这些值用于调用 Delay 函数时的参数,应根据具体情况而定,关系到 1-Wire 成功读写
// 的关键,故一定要精确设置
// 此例中使用 C8051F340 MCU,时钟48MHz,根据测试后计算而得公式 n(us)*4 - 2

#define wV_30us     118

// 高速和低速时各个时隙值,本例中使用的是低速值
// 使用高速模式时定义一个 OWHIGHSPEED 即可
// #define OWHIGHSPEED
#ifdef OWHIGHSPEED      // high speed

#define wOW_A   ( 1.5  * 4 - 2 )
#define wOW_B   ( 7.5  * 4 - 2 )
#define wOW_C   ( 7.5  * 4 - 2 )
#define wOW_D   ( 2.5  * 4 - 2 )
#define wOW_E   ( 0.75 * 4 - 2 )
#define wOW_F   ( 7    * 4 - 2 )
#define wOW_G   ( 2.5  * 4 - 2 )
#define wOW_H   ( 70   * 4 - 2 )
#define wOW_I   ( 8.5  * 4 - 2 )
#define wOW_J   ( 40   * 4 - 2 )

#else                   // standard speed

#define wOW_A   ( 6   * 4 - 2 )
#define wOW_B   ( 64  * 4 - 2 )
#define wOW_C   ( 60  * 4 - 2 )
#define wOW_D   ( 10  * 4 - 2 )
#define wOW_E   ( 9   * 4 - 2 )
#define wOW_F   ( 55  * 4 - 2 )
#define wOW_G   ( 0 )
#define wOW_H   ( 480 * 4 - 2 )
#define wOW_I   ( 70  * 4 - 2 )
#define wOW_J   ( 410 * 4 - 2 )

#endif

sbit OWDO =P0^4;                    // 1-Wire DO Line 根据实际使用的口线定义

// #define EINT()  { EA = 1; }
// #define DINT()  { EA = 0; }
// 开/关中断的宏,根据MCU来定

//-----------------------------------------------------------------------------
// 循环延时程序,每一次循环消耗12个时钟周期,另外固定有25个时钟周期消耗在调用及返
// 回的过程中,故得出延时 n us 计算公式 c = (n*48-25)/12  或 c=n*4-2
// 实际延时值设置应根据实际情况来定
void Delay( unsigned int c )
{
    while( c-- );                   // 用"c--",而不是"--c",在Keil下编译,测试是正确的
                                    // 先判断而后减,必须先判断再减,因为有个 0 值
                                    // 这样的写法我很少敢用,这里测试过没问题才用的
}
//-----------------------------------------------------------------------------
// 以下为总线复位,写字节,读字节函数,因为时隙要求严格,故在函数中关闭中断
//-----------------------------------------------------------------------------
// 复位 1 wire
// 设备无响应返回非0,有响应返回0
// 函数名字前的 "OW" means One Wire( 1-Wire ),此类函数可用于其它 1-Wire 设备
U8 OWReset()
{
    U8 rv = 0;
    DINT();
    Delay( wOW_G );
    OWDO=0;                                     // 复位
    Delay( wOW_H );                             // 480us
    OWDO=1;                                     // 释放总线
    Delay( wOW_I );                             // 70us
    rv = OWDO;                                  // 读器件响应
    Delay( wOW_J );                             // 410us
    EINT();
    return rv;
}
//-----------------------------------------------------------------------------
// 向 1 Wire 写一个字节.x是要写的内容
// w : 预写字节
void OWWriteByte(unsigned char w)
{
    unsigned char i;
    DINT();
    for(i=0;i<8;i++)
    {
        if(0x01&w)
        {                                       // 写1
            OWDO=0;
            Delay( wOW_A );                     // 6us
            OWDO=1;
            Delay( wOW_B );                     // 64us
        }
        else
        {                                       // 写0
            OWDO=0;
            Delay( wOW_C );                     // 60us
            OWDO=1;
            Delay( wOW_D );                     // 10us
        }
        w>>=1;
    }
    EINT();
}
//-----------------------------------------------------------------------------
// 从 1 Wire 读一个字节.返回读到的内容
// 返回读取的内容
unsigned char OWReadByte(void)
{
    unsigned char bLoop,rv;
    rv=0;
    DINT();
    for(bLoop=0;bLoop<8;bLoop++)
    {
        rv>>=1;
        OWDO=0;
        Delay( wOW_A );                         // 6us
        OWDO=1;
        Delay( wOW_E );                         // 9us
        if( OWDO )
            rv|=0x80;
        Delay( wOW_F );                         // 55us
    }
    EINT();
    return rv;
}
//-----------------------------------------------------------------------------
// 以下为 18B20 专用函数
//-----------------------------------------------------------------------------
// 每次上电都检查设置值,如果与要求的参数一致则跳过,否则重新设置
#define CONFIG18B20 0x7F                        // 将18b20设为12位,精度就是0.0625度
void DS18B20_Init(void)                         
{
    if( !OWReset() )
    {
        OWWriteByte( 0xCC );                    // 发送Skip ROM命令
                                                // 本例中线上只有一片18B20
                                                // 所以跳过选择器件的过程
        OWWriteByte( 0xBE );                    // 发送"读"暂存RAM命令
        OWReadByte();                           // 复位温度值低字节,弃之
        OWReadByte();                           // 复位温度值高字节,弃之
        // 然后读取报警上限/下限温度值及配置值,该值保存是内部EEPROM中,
        // 在初次上电和更改设置时才需要重写
        // 先判断后写的方式,可以保证器件有更长的寿命,并不需要每次都写
        // 这里报警温度值均为 0 度
        if( 0x00!=OWReadByte() || 0x00!=OWReadByte() || CONFIG18B20!=OWReadByte() )
        {
            OWReset();
            OWWriteByte( 0xCC );                // 发送Skip ROM命令
            OWWriteByte( 0x4E );                // 发送"写"暂存RAM命令
            OWWriteByte( 0x00 );                // 温度报警上限设为0
            OWWriteByte( 0x00 );                // 温度报警下限设为0
            OWWriteByte( CONFIG18B20 );         // 写配置值
        }
        OWReset();
    }
}
//-----------------------------------------------------------------------------
int DS18B20_ReadTemp(void)                      // 读18b20温度值,此函数为 18B20 专用
{
    UU16 tmp;
    tmp.u16=0x8000;                             // 初始化一不可能值,无器件时时返回此值

    if( !OWReset() )                            // 如果复位没发现设备则返回无效值 0x8000
    {
        OWWriteByte( 0xCC );                    // 发送Skip ROM命令
        OWWriteByte( 0x44 );                    // 发送温度转换命令

#ifdef POWERONDO
        POWERDOON();                            // 在 DO 线上使能强上拉,
        // 如果由DO线供电,则采用延时的方式等待转换结束
        // 此方式的延时程序依个人风格来写
        //
        DELAYNMS( n );                          // 9  位精度,等待>93.74ms
                                                // 10 位精度,等待>187.5ms
                                                // 11 位精度,等待>375ms
                                                // 12 位精度,等待>750ms
        POWERDOOFF();                           // 撤消 DO 强上拉
                                                // 自己定义这两个 DO 线上的强上拉方式
                                                // 的开与关的宏
#else
        // 单独的电源供给线,采用等待转换结束信号的方式
        // 发送开始转换命令后10us,18B20开始转换
        // 开始转换后,从DO读位数据,读出0时表示转换未结束
        // 读出1时表示转换结束
        Delay( wV_30us );
        do
        {
            DINT();                             // 关中断

            OWDO=0;
            Delay( wOW_A );                     // 6us
            OWDO=1;                             
            Delay( wOW_E );                     // 9us
            if( OWDO )
                tmp.u8[0] = 0x80;               // 此时 tmp 空闲,暂时借用一下,可少定义变量
            else
                tmp.u8[0] = 0;
            Delay( wOW_F );                     // 55us
            EINT();                             // 开中断
        }
        while( tmp.u8[0]==0 );
        Delay( wV_30us );
#endif

        OWReset();                              // 总线复位
        OWWriteByte( 0xCC );                    // 发送Skip ROM命令
        OWWriteByte( 0xBE );                    // 发送"读"暂存RAM命令

        tmp.u8[1]=OWReadByte();                 // 读温度低字节
        tmp.u8[0]=OWReadByte();                 // 读温度高字节
        // 51的整型数字高字节在前,NND,我好烦这个
        // 18B20 的温度值是一个标准的有符号数,此值乘上 0.0625 即是实际温度值
        // 注意,当选择非12bit精度时,要把未使用的低位抹平,复位成0

        OWReset();
    }
    return tmp.u16;
}
//-----------------------------------------------------------------------------
// End of this file

//=============================================================================
//=============================================================================
//=============================================================================
// 以下为 main.c 文件
//=============================================================================
//=============================================================================
//=============================================================================


//#include <C8051F340.h>
#include "main.h"
#include "F_18B20.h"


//-----------------------------------------------------------------------------
void main()
{
    int temp;
    Init_Device();  // 全部 MCU 初始化工作
    EA = 1;

    DS18B20_Init(); // 初始化 18B20

    while( 1)
    {
        temp = DS18B20_ReadTemp();
        // 对温度值做进一步处理
        // 还有其它需要的工作
    }
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// End of this file
//-----------------------------------------------------------------------------

相关帖子

沙发
E007|  楼主 | 2009-2-15 22:33 | 只看该作者

沙发自己坐,挨砖时有缓冲,哈......

使用特权

评论回复
板凳
E007|  楼主 | 2009-2-15 22:33 | 只看该作者

板凳也抢一个,准备反击~~~

使用特权

评论回复
地板
E007|  楼主 | 2009-2-16 13:08 | 只看该作者

坐地板上抽根烟,准备删贴~~~

BS那些光复制不留脚印的~~~

使用特权

评论回复
5
dream110| | 2009-2-26 14:04 | 只看该作者

呵呵,正需要哪,参考一下

使用特权

评论回复
6
E007|  楼主 | 2009-3-9 19:47 | 只看该作者

有人用我就没白贴,呵呵......

使用特权

评论回复
7
王紫豪| | 2009-3-9 22:27 | 只看该作者

没有 crc?

使用特权

评论回复
8
E007|  楼主 | 2009-3-16 21:52 | 只看该作者

CRC 程序满天飞,自己找个用吧,呵呵......

使用特权

评论回复
9
hotpower| | 2009-3-16 21:56 | 只看该作者

晕~~~1-wire没有X8+X5+X4+X0还叫程序

使用特权

评论回复
10
E007|  楼主 | 2009-3-17 13:13 | 只看该作者

那就当我这个是来捣乱的吧,呵呵......

使用特权

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

本版积分规则

5

主题

207

帖子

1

粉丝