打印

拟了一个LM75驱动,不知是否可行?

[复制链接]
4279|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
天雨粟|  楼主 | 2008-12-4 21:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    关于测温,常用热敏电阻及专用测温芯片两种办法。热敏电阻法:用555形成振荡,测脉宽得温度;用电压比较器控制充放电,测充电时间得温度;采取电阻比率法,借助标准电阻,通过充放电时间之比,测电阻得温度。以上均须借助热敏电阻。我验收过几批热敏电阻,军级,成本是天价,姑无论也,准确度是多少呢?±10%,民用级或更而下之云。这几批热敏电阻仅用在要求不高的控温场合,总之,用热敏电阻测温,准确度不能令人满意。
    18B20准确度是很好的,但它对时序要求极严。如是系统测温是首要任务,其它任务可暂时屏蔽,亦不失为一种办法,但如系统有不可屏蔽中断,18B20便高才不第,落落寡合了。
    综合比较,LM75是较好的。精度0.5℃,准确度一般应有1℃(指标是2℃)。
   工程师们似不太喜欢75,比起18B20的盛名,75就要黯然得多,资料也不易求得。我在网上下了一点资料,手中暂无芯片,根据资料先拟了一个驱动,(也借用了一些I2C的常用编程办法),不知是否行得通,贴出来向大家讨教。

/* 全局符号定义 */
#include <reg52.h>
#include <intrins.h>

#define HIGH 1
#define LOW 0
#define FALSE 0
#define TRUE ~FALSE
#define Uchar unsigned char
#define Uint unsigned int
#define WRITE 0x90  /* 定义LM75的器件地址SLA和方向位W ,A2 A1 A0接地*/
#define READ 0x91   /* 定义LM75的器件地址SLA和方向位R ,A2 A1 A0接地*/

Uchar EAROMImage[2];    /* 在RAM中定义存储映象单元 */
bit s_flag;
Uchar temp;
sbit SCL = 0x96 ;
sbit SDA = 0x97 ;


/********************************************************************
*    函数原型: void delay(void);
*    功    能: 本函数实际上只有一条返回指令, 在具体应用中可视具体
*              要求增加延时指令。
********************************************************************/
void delay( void ) {
    ;
}

/********************************************************************
*    函数原型: void I_start(void);
*    功    能: 提供I2C总线工作时序中的起始位。                       
********************************************************************/
void I_start( void ) {
    SCL = HIGH ;
    delay() ;
    SDA = LOW ;
    delay() ;
    SCL = LOW ;
    delay() ;
     }

/********************************************************************
*    函数原型: void I_stop(void);
*    功    能: 提供I2C总线工作时序中的停止位。
********************************************************************/
void I_stop( void ) {
    SDA = LOW ;
    delay() ;
    SCL = HIGH ;
    delay() ;
    SDA = HIGH ;
    delay() ;
    SCL = LOW ;
    delay() ;
     }

/********************************************************************
*    函数原型: void I_init(void);
*    功    能: I2C总线初始化。在main()函数中应首先调用本函数, 然后再
*              调用其它函数。
********************************************************************/
void I_init( void ) {
    SCL = LOW ;
    I_stop() ;
}

/********************************************************************
*    函数原型: bit I_clock(void);
*    功    能: 提供I2C总线的时钟信号, 并返回在时钟电平为高期间SDA 信
*              号线上状态。本函数可用于数据发送, 也可用于数据接收。
********************************************************************/
bit I_clock( void ) {
    bit sample ;
    SCL = HIGH ;
    delay() ;
    sample = SDA ;
    SCL = LOW ;
    delay() ;
    return ( sample ) ;
 }

/********************************************************************
*    函数原型: bit I_send(Uchar I_data);
*    功    能: 向I2C总线发送8位数据, 并请求一个应答信号ACK。如果收到*              ACK应答则返回1(TRUE), 否则返回0(FALSE)。
********************************************************************/
bit I_send( Uchar I_data ) {
    Uchar i ;
    /* 发送8位数据 */
    for ( i=0 ; i<8 ; i++ ) {
        SDA = (bit)( I_data & 0x80 ) ;
        I_data = I_data << 1 ;
        I_clock() ;
    }
    /* 请求应答信号ACK */
    SDA = HIGH ;
    return ( ~I_clock() );
  }

/********************************************************************
*    函数原型: Uchar I_receive(void);
*    功    能: 从I2C总线上接收8位数据信号, 并将接收到8位数据作为一个
*              字节返回, 不回送应答信号ACK。主函数在调用本函数之前应
*              保证SDA信号线处于浮置状态, 即使8051的P1.7脚置1。
********************************************************************/
Uchar I_receive( void ) {
    Uchar I_data = 0 ;
    register Uchar i ;
    for ( i=0 ; i<8 ; i++ ) {
        I_data *= 2 ;
        if (I_clock()) I_data++ ;
    }
    return ( I_data ) ;
}

/********************************************************************
*    函数原型: void I_Ack(void);
*    功    能: 向I2C总线发送一个应答信号ACK, 一般用于连续数据读取时。
********************************************************************/
void I_Ack( void ) {
    SDA = LOW ;
    I_clock() ;
    SDA = HIGH ;
}


/********************************************************************
*    函数原型: bit E_address(Uchar Address);
*    功    能: 向LM75写入器件地址和一个指定的字节地址。
********************************************************************/
bit E_address( Uchar Address ) {
    I_start() ;
    if ( I_send( WRITE ) )
        return ( I_send( Address ) ) ;
    else
        return ( FALSE ) ;
}

/********************************************************************
*    函数原型: bit E_read(Uchar Address);
*    功    能: 从LM75中读取两个字节的数据并转存于RAM存储映象单元, 采
*              用序列读操作方式从片内指定地址开始连续读取数据。如果
*              LM75不接受指定的地址则返回0(FALSE)。
********************************************************************/
bit E_read( Uchar Address ) {
    if ( E_address( Address ) ) {  
                    //如果从机地址及片内地址都写入成功
        I_start() ;    //发重复起始信号
        if ( I_send( READ ) ) {       //发读命令
            EAROMImage[0] = ( I_receive() ) ;
            I_Ack() ;//主机应答,通知从机继续发出数据
            EAROMImage[1] = ( I_receive() ) ;
            I_clock() ;
            I_stop() ;    //主机不再应答并停止总线
            return ( TRUE ) ;
            }
        else {
            I_stop() ;
            return ( FALSE ) ;
            }
        }
    else
        I_stop() ;
        return ( FALSE ) ;
    }

/********************************************************************
*    函数原型: void wait_5ms(void);
*    功    能: 提供5ms延时(时钟频率为12MHz)。
********************************************************************/
void wait_5ms( void ) {
    int i ;
    for ( i=0 ; i<1000 ; i++ ) {
        ;
    }
}

/********************************************************************
*    函数原型: bit E_write(Uchar Address);
*    功    能: 将RAM存储映象单元中的两个数据写入到LM75的指定地址单
*              元。采用字节写操作方式。如果LM75不接受指定的地址或某个*              传送的字节未收到应答信号ACK, 则返回0(FALSE)。
********************************************************************/
bit E_write(Uchar Address) {
    if ( E_address(Address) && I_send( EAROMImage[0])) { 
//如果从机地址及片内地址都写入正确且成功发送了一个数据
        if(I_send(EAROMImage[1])){                //则继续发送下一个数据
            I_stop() ;
            wait_5ms();
            return (TRUE);
            }
        else{
            I_stop();
            return ( FALSE ) ;
          }
        }
    else{
        I_stop();
        return (FALSE);
        }
     }

void  main() {
    I_init();          /* I2C 总线初始化 */
    E_read(0x00);    //读温度寄存器的内容
    if(EAROMImage[0]&0x80)
        s_flag=1;
    else    s_flag=0;                      //符号判断
    temp=EAROMImage[0]<<1|EAROMImage[1]>>7;  //数据拼装
    if(s_flag)
        temp=~temp+1;       //如果是负温度则取其绝对值
    while(1);
}
        

相关帖子

沙发
ayb_ice| | 2008-12-4 21:54 | 只看该作者

单总线命中注定

只能是简单的应用.

使用特权

评论回复
板凳
天雨粟|  楼主 | 2008-12-4 22:08 | 只看该作者

18B20确实很奇怪!

不知道外国人发明它干什么?
据说,也挂不了几个,75理论上也可以挂八个。

多个18B20的编程极难。商品化的多路温度巡回检测仪也不是用的它!

使用特权

评论回复
地板
ljm810010| | 2008-12-4 22:22 | 只看该作者

最要命的是抗干扰极差

受干扰后读出温度值为85度,CRC验证却正确。

使用特权

评论回复
5
awey| | 2008-12-4 22:30 | 只看该作者

热敏电阻没楼主说得那么差

俺比较穷,都用1毛多钱的NTC电阻测温,不调校误差做到3%没问题。
要准确就加调校,精度±0.2C的体温计也是拿它做的。

使用特权

评论回复
6
天雨粟|  楼主 | 2008-12-4 22:32 | 只看该作者

单总线,一个概念炒作?

商业运作?总之,不敢领教。
我手上有两片,看了几天资料,想尽办法,安排不好其时序,只得告罢!

想讨教75的用法,网上资料难求。

哪位有用过的驱动,能否慨以见惠?

无芯片空谈!政治家空谈误国,工程师空谈误事啊!

使用特权

评论回复
7
天雨粟|  楼主 | 2008-12-4 22:51 | 只看该作者

回五楼

我测试过上万只的热敏电阻,10%的确属少数,3%的多见。但根据计量学的观点,从可靠性、一致性的角度考虑,我只能当其准确度为10%。考虑其它误差,用热敏电阻测环境温度,我只能同意正负3度的准确度。

自然,我讲的热敏电阻不是指四百元一只铂电阻。

使用特权

评论回复
8
ljm810010| | 2008-12-4 23:10 | 只看该作者

5楼说要 校准 后才能达到0.2度的误差

使用特权

评论回复
9
天雨粟|  楼主 | 2008-12-4 23:26 | 只看该作者

LS

体温计属强制计量的计量器具。既然能达到国家强制标准,当非虚言,但实现手段或者也属独家之秘,在下不敏,不得其法,亦不敢妄求。只想讨教大路常见的75的用法!

使用特权

评论回复
10
xhtxzxw| | 2008-12-4 23:29 | 只看该作者

嘿嘿


单总线,没那么不好用吧???? 不能直接测高温,这个倒是它比较不太好的地方.

使用特权

评论回复
11
天雨粟|  楼主 | 2008-12-4 23:42 | 只看该作者

楼上

如是有这样一个系统,怎样安排18B20的时序?
TIMER0,不可屏蔽的高先级中断,运行时间60微秒
TIMER1,10ms定时中断,不可连续屏蔽2ms以上;
INT0,不可屏蔽5ms以上
按键扫描,20ms必须扫描一下

使用特权

评论回复
12
awey| | 2008-12-4 23:53 | 只看该作者

不知楼主用过什么NTC电阻这么差?

我用的是SEMITEC公司生产的103KT1608 NTC电阻
Resistance Tolerance ±1 %
B Value Tolerance ± 1 %

我说误差做到3%没问题是对整机的,比较保守,实际可以做得更高。
参数是它说明书上写的,不符可以退货。

使用特权

评论回复
13
天雨粟|  楼主 | 2008-12-5 17:45 | 只看该作者

楼上

MF111,25度标称阻值允许误差10%,50度标称阻值允许误差12%。
B值3650。

感谢您提供的资料,可以一试!

使用特权

评论回复
14
耕在此行| | 2008-12-5 18:18 | 只看该作者

楼主做什么产品的哦

上次问时钟 这次问温度 
呵呵 是根据温度补偿时间吧.
LM75做起来不难的,我这有现成的程序 不过不是我自己写的.
要的话我发给你. 
xuehongren@126.com

使用特权

评论回复
15
xhtxzxw| | 2008-12-5 20:57 | 只看该作者

嘿嘿

回11楼:
不加别的措施,18B20肯定,绝对不行!呵呵

I2C的LM75,行不行呢?

使用特权

评论回复
16
zq1987731| | 2008-12-6 20:06 | 只看该作者

我认为

可以用一片CPLD来读多个18B20,再用单片机读CPLD,这样时序相当准确的,而且还能补充IO脚数量,况且现在CPLD都便宜了,我之前的一个小方案用的Altera的EPM240,才10元...

使用特权

评论回复
17
xhtxzxw| | 2008-12-6 20:21 | 只看该作者

嘿嘿

嘿嘿 我也和LS一个想法

使用特权

评论回复
18
天雨粟|  楼主 | 2008-12-8 13:07 | 只看该作者

感谢楼上几位给予的帮助。

回耕在此行网友:不敢说做产品,现在才刚学步呢!计划把单片机的几个主要系统都弄通,现在初步掌握了“剑法”(键法),汇编及C的一些典型算法,数码动态显示、液晶显示、串行通讯等。只有实时时钟,例程很多,以为不难,实际上最麻烦。弄75,确实是按您的提示,准备用来对晶振进行温补。等下给您发个邮件,求驱动。
回15、16、17楼:
个人认为,I2C与单片机串行通讯原理一样,既串行通讯不惧中断,则I2C通讯亦当不惧。

还有一个想法,用NTC及用芯片,根本原理是相同的,考虑国外器件的工艺,个人认为,用芯片要更靠谱一些!

使用特权

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

本版积分规则

16

主题

168

帖子

0

粉丝