现在的位置: 首页 > 综合 > 正文

Philips P89LPC917单片机对温度芯片DS1820的取温度笔记

2013年09月05日 ⁄ 综合 ⁄ 共 4181字 ⁄ 字号 评论关闭

硬件环境:  P89LPC917, DS1820温度芯片, VDD=3.3V, 调试串口;
软件环境:  Keil uVision2, 串口通讯控制器(用来接收串口数据)

过程:
看了资料, 其有着许多C51单片机操作DS1820的实例,但是其晶振频率都是参照标准的51芯片的,为11.059MHz. 而P89LPC917的晶振是7372800Hz.由于单总线对时序十分的严谨,而且十分的短暂,所以其延时都是用的循环代码来延时的,这关键就是在7372800Hz晶振下的延时程序应该如何做?

看书了解了什么时钟周期,机器周期,指令周期以后打算算出一个精确的延时程序来,可是偶用C语言来写的,这实在是不好算. 最后,偶打算用示波器来测量延时的时间. 一番折腾后偶得到了下面的结论:

延时代码为:
// DELAY - with an 7.3728MHz crystal
// Calling the routine takes about 4μs, and then
// each count takes another 3.2μs
void delay( uint16 us )
{
    volatile uint16 s;
    for ( s = 0; s < us; s++ );
}
结论:
调用一次循环函数所用的时间  4us
没增加一次循环增加的时间    3.2us
一条赋值代码所需要的时间    280ns

之后参照其数据手册,严格按照其读写的时序来操作,最终正确取到了温度值(请注意,其温度是以0.5度为递增的,取道的值转换为十进制以后要除以2才是真正的温度值)

现把代码公布于下:
 /*
*********************************************************************************************************
*                                           ######有限公司
*                                             技术研发部
*
*                                  (c) Copyright 2005-2006, kmajian
*                                        All Rights Reserved
*
*                                  通过单总线协议从DS1820获取温度程序
*
* File : GETTMP.H
* By   : kmajian
* Date : 2006-5-15
*********************************************************************************************************
*/
#include "config.h"

sbit DQ = P0^1;

void GetTempInit( void )
{
    P0M1 = 0x00;                        // 将P0.1设置为准双向口
    P0M2 = 0x00;
}

// DELAY - with an 7.3728MHz crystal
// Calling the routine takes about 4μs, and then
// each count takes another 3.2μs
void delay( uint16 us )
{
    volatile uint16 s;
    for ( s = 0; s < us; s++ );
}
// 复位
uint8 ow_reset( void )
{
    unsigned char presence;
    DQ = 0;                               // pull DQ line low
    delay( 141 );                          // leave it low for 480μs
    DQ = 1;                               // allow line to return high
    delay( 14 );                           // wait for presence
    presence = DQ;                        // get presence signal
    delay( 110 );                          // wait for end of timeslot
    return( presence );                   // presence signal returned
}                                         // presence = 0, no part = 1

// 读位
uint8 read_bit( void )
{
    DQ = 0;                               // pull DQ low to start timeslot
    DQ = 0;                     
    DQ = 0;
    DQ = 0;
    DQ = 1;                               // then return high
    delay( 3 );                           // delay 15μs from start of timeslot
    return( DQ );                         // return value of DQ line
}

// 写位
void write_bit( int8 bitval )
{
    DQ = 0;                               // pull DQ low to start timeslot
    DQ = 0;                               // 至少保持1us
    DQ = 0;
    DQ = 0;
    if( bitval == 1 )
     DQ = 1;                             // return DQ high if write 1
    delay( 18 );                         // hold value for remainder of timeslot,60us
    DQ = 1;
}                                        

// 读字节
uint8 read_byte( void )
{
    uint8 i;
    uint8 value = 0;
    for ( i = 0; i < 8; i++ )
    {
        if( read_bit() )
      value |= 0x01<<i;                  // reads byte in, one byte at a time and then
                                         // shifts it left
        delay( 18 );                     // wait for rest of timeslot
    }
    return( value );
}

// 写字节
void write_byte( int8 val)
{
    uint8 i;
    uint8 temp;
    for (i = 0; i < 8; i++)             // writes byte, one bit at a time
    {
        temp = val>>i;                  // shifts val right ‘i’ spaces
        temp &= 0x01;                   // copy that bit to temp
        write_bit( temp );              // write bit in temp into
    }
    delay( 18 );
}

// 读取温度
uint8 GetTmp( uint8 *sym )
{
    uint8 val1 = 0, val2 = 0;

    ow_reset();                        // 复位
    write_byte( 0xCC );                // 跳过 ROM 命令
    write_byte( 0x44 );                // Convert T 命令
    TDelay( 100 );                     // 延时一秒, 转换需要足够的时间
    ow_reset();                        // 复位
    write_byte( 0xCC );                // 跳过 ROM 命令
    write_byte( 0xBE );                // 发送读取命令
    val1 = read_byte();                // 读取低字节
    val2 = read_byte();                // 读取高字节
    if( val2 > 0 )                     // 温度为负值则做处理
    {
        *sym = 1;                      // 标示为负数
        val1 = ~val1 + 1;              // 取其补码
    }
    else
    {
        *sym = 0;
    }

    return val1;
}

/*                                                
**********************************************************************************************************
*                                             END 
*********************************************************************************************************
*/

抱歉!评论已关闭.