//=============================================================================<br />//=============================================================================<br />//=============================================================================<br />// 原创 18B20 读写程序,欢迎拍砖<br />// www.21ic.com 之 E007<br />//=============================================================================<br />//=============================================================================<br />//=============================================================================<br /><br /><br />//=============================================================================<br />//=============================================================================<br />//=============================================================================<br />// 以下为 F_18B20.h 文件<br />//=============================================================================<br />//=============================================================================<br />//=============================================================================<br /><br />#ifndef __F_18B20_H__<br />#define __F_18B20_H__<br />//-----------------------------------------------------------------------------<br /><br />void DS18B20_Init(void);<br />int DS18B20_ReadTemp();<br /><br />//-----------------------------------------------------------------------------<br />#endif // #ifndef __F_18B20_H__<br />// End of this file<br /><br />//=============================================================================<br />//=============================================================================<br />//=============================================================================<br />// 以下为 F_18B20.c 文件<br />//=============================================================================<br />//=============================================================================<br />//=============================================================================<br /><br />#include "F_18B20.h"<br /><br />// 常用数据类型定义,这部分我是放在 main.h 中的,这里一起贴出来<br />#ifndef __UU_DEF__<br />#define __UU_DEF__<br /><br />typedef unsigned char U8;<br />typedef unsigned int U16;<br />typedef unsigned long U32;<br /><br />typedef signed char S8;<br />typedef signed int S16;<br />typedef signed long S32;<br /><br />typedef union UU16<br />{<br /> U16 u16;<br /> S16 s16;<br /> U8 u8[2];<br /> S8 s8[2];<br />} UU16;<br />// used with UU16<br /># define LSB 1<br /># define MSB 0<br /><br />typedef union UU32<br />{<br /> U32 u32;<br /> S32 s32;<br /> UU16 uu16[2];<br /> U16 u16[2];<br /> S16 s16[2];<br /> U8 u8[4];<br /> S8 s8[4];<br />} UU32;<br />// used with UU32 (b0 is least-significant byte)<br /># define b0 3<br /># define b1 2<br /># define b2 1<br /># define b3 0<br /><br />typedef unsigned char BYTE;<br />typedef unsigned char UCHAR;<br />typedef union {unsigned short i; unsigned char c[2];} WORD;<br />// 这些定义包容了大部分人习惯的写法<br />#endif // #ifndef __UU_DEF__<br /><br /><br />//-----------------------------------------------------------------------------<br />// 以下定义 1-Wire 时隙<br />// 这些值用于调用 Delay 函数时的参数,应根据具体情况而定,关系到 1-Wire 成功读写<br />// 的关键,故一定要精确设置<br />// 此例中使用 C8051F340 MCU,时钟48MHz,根据测试后计算而得公式 n(us)*4 - 2<br /><br />#define wV_30us 118<br /><br />// 高速和低速时各个时隙值,本例中使用的是低速值<br />// 使用高速模式时定义一个 OWHIGHSPEED 即可<br />// #define OWHIGHSPEED<br />#ifdef OWHIGHSPEED // high speed<br /><br />#define wOW_A ( 1.5 * 4 - 2 )<br />#define wOW_B ( 7.5 * 4 - 2 )<br />#define wOW_C ( 7.5 * 4 - 2 )<br />#define wOW_D ( 2.5 * 4 - 2 )<br />#define wOW_E ( 0.75 * 4 - 2 )<br />#define wOW_F ( 7 * 4 - 2 )<br />#define wOW_G ( 2.5 * 4 - 2 )<br />#define wOW_H ( 70 * 4 - 2 )<br />#define wOW_I ( 8.5 * 4 - 2 )<br />#define wOW_J ( 40 * 4 - 2 )<br /><br />#else // standard speed<br /><br />#define wOW_A ( 6 * 4 - 2 )<br />#define wOW_B ( 64 * 4 - 2 )<br />#define wOW_C ( 60 * 4 - 2 )<br />#define wOW_D ( 10 * 4 - 2 )<br />#define wOW_E ( 9 * 4 - 2 )<br />#define wOW_F ( 55 * 4 - 2 )<br />#define wOW_G ( 0 )<br />#define wOW_H ( 480 * 4 - 2 )<br />#define wOW_I ( 70 * 4 - 2 )<br />#define wOW_J ( 410 * 4 - 2 )<br /><br />#endif<br /><br />sbit OWDO =P0^4; // 1-Wire DO Line 根据实际使用的口线定义<br /><br />// #define EINT() { EA = 1; }<br />// #define DINT() { EA = 0; }<br />// 开/关中断的宏,根据MCU来定<br /><br />//-----------------------------------------------------------------------------<br />// 循环延时程序,每一次循环消耗12个时钟周期,另外固定有25个时钟周期消耗在调用及返<br />// 回的过程中,故得出延时 n us 计算公式 c = (n*48-25)/12 或 c=n*4-2<br />// 实际延时值设置应根据实际情况来定<br />void Delay( unsigned int c )<br />{<br /> while( c-- ); // 用"c--",而不是"--c",在Keil下编译,测试是正确的<br /> // 先判断而后减,必须先判断再减,因为有个 0 值<br /> // 这样的写法我很少敢用,这里测试过没问题才用的<br />}<br />//-----------------------------------------------------------------------------<br />// 以下为总线复位,写字节,读字节函数,因为时隙要求严格,故在函数中关闭中断<br />//-----------------------------------------------------------------------------<br />// 复位 1 wire<br />// 设备无响应返回非0,有响应返回0<br />// 函数名字前的 "OW" means One Wire( 1-Wire ),此类函数可用于其它 1-Wire 设备<br />U8 OWReset()<br />{<br /> U8 rv = 0;<br /> DINT();<br /> Delay( wOW_G );<br /> OWDO=0; // 复位<br /> Delay( wOW_H ); // 480us<br /> OWDO=1; // 释放总线<br /> Delay( wOW_I ); // 70us<br /> rv = OWDO; // 读器件响应<br /> Delay( wOW_J ); // 410us<br /> EINT();<br /> return rv;<br />}<br />//-----------------------------------------------------------------------------<br />// 向 1 Wire 写一个字节.x是要写的内容<br />// w : 预写字节<br />void OWWriteByte(unsigned char w)<br />{<br /> unsigned char i;<br /> DINT();<br /> for(i=0;i<8;i++)<br /> {<br /> if(0x01&w)<br /> { // 写1<br /> OWDO=0;<br /> Delay( wOW_A ); // 6us<br /> OWDO=1;<br /> Delay( wOW_B ); // 64us<br /> }<br /> else<br /> { // 写0<br /> OWDO=0;<br /> Delay( wOW_C ); // 60us<br /> OWDO=1;<br /> Delay( wOW_D ); // 10us<br /> }<br /> w>>=1;<br /> }<br /> EINT();<br />}<br />//-----------------------------------------------------------------------------<br />// 从 1 Wire 读一个字节.返回读到的内容<br />// 返回读取的内容<br />unsigned char OWReadByte(void)<br />{<br /> unsigned char bLoop,rv;<br /> rv=0;<br /> DINT();<br /> for(bLoop=0;bLoop<8;bLoop++)<br /> {<br /> rv>>=1;<br /> OWDO=0;<br /> Delay( wOW_A ); // 6us<br /> OWDO=1;<br /> Delay( wOW_E ); // 9us<br /> if( OWDO )<br /> rv|=0x80;<br /> Delay( wOW_F ); // 55us<br /> }<br /> EINT();<br /> return rv;<br />}<br />//-----------------------------------------------------------------------------<br />// 以下为 18B20 专用函数<br />//-----------------------------------------------------------------------------<br />// 每次上电都检查设置值,如果与要求的参数一致则跳过,否则重新设置<br />#define CONFIG18B20 0x7F // 将18b20设为12位,精度就是0.0625度<br />void DS18B20_Init(void) <br />{<br /> if( !OWReset() )<br /> {<br /> OWWriteByte( 0xCC ); // 发送Skip ROM命令<br /> // 本例中线上只有一片18B20<br /> // 所以跳过选择器件的过程<br /> OWWriteByte( 0xBE ); // 发送"读"暂存RAM命令<br /> OWReadByte(); // 复位温度值低字节,弃之<br /> OWReadByte(); // 复位温度值高字节,弃之<br /> // 然后读取报警上限/下限温度值及配置值,该值保存是内部EEPROM中,<br /> // 在初次上电和更改设置时才需要重写<br /> // 先判断后写的方式,可以保证器件有更长的寿命,并不需要每次都写<br /> // 这里报警温度值均为 0 度<br /> if( 0x00!=OWReadByte() || 0x00!=OWReadByte() || CONFIG18B20!=OWReadByte() )<br /> {<br /> OWReset();<br /> OWWriteByte( 0xCC ); // 发送Skip ROM命令<br /> OWWriteByte( 0x4E ); // 发送"写"暂存RAM命令<br /> OWWriteByte( 0x00 ); // 温度报警上限设为0<br /> OWWriteByte( 0x00 ); // 温度报警下限设为0<br /> OWWriteByte( CONFIG18B20 ); // 写配置值<br /> }<br /> OWReset();<br /> }<br />}<br />//-----------------------------------------------------------------------------<br />int DS18B20_ReadTemp(void) // 读18b20温度值,此函数为 18B20 专用<br />{<br /> UU16 tmp;<br /> tmp.u16=0x8000; // 初始化一不可能值,无器件时时返回此值<br /><br /> if( !OWReset() ) // 如果复位没发现设备则返回无效值 0x8000<br /> {<br /> OWWriteByte( 0xCC ); // 发送Skip ROM命令<br /> OWWriteByte( 0x44 ); // 发送温度转换命令<br /><br />#ifdef POWERONDO<br /> POWERDOON(); // 在 DO 线上使能强上拉,<br /> // 如果由DO线供电,则采用延时的方式等待转换结束<br /> // 此方式的延时程序依个人风格来写<br /> //<br /> DELAYNMS( n ); // 9 位精度,等待>93.74ms<br /> // 10 位精度,等待>187.5ms<br /> // 11 位精度,等待>375ms<br /> // 12 位精度,等待>750ms<br /> POWERDOOFF(); // 撤消 DO 强上拉<br /> // 自己定义这两个 DO 线上的强上拉方式<br /> // 的开与关的宏<br />#else<br /> // 单独的电源供给线,采用等待转换结束信号的方式<br /> // 发送开始转换命令后10us,18B20开始转换<br /> // 开始转换后,从DO读位数据,读出0时表示转换未结束<br /> // 读出1时表示转换结束<br /> Delay( wV_30us );<br /> do<br /> {<br /> DINT(); // 关中断<br /><br /> OWDO=0;<br /> Delay( wOW_A ); // 6us<br /> OWDO=1; <br /> Delay( wOW_E ); // 9us<br /> if( OWDO )<br /> tmp.u8[0] = 0x80; // 此时 tmp 空闲,暂时借用一下,可少定义变量<br /> else<br /> tmp.u8[0] = 0;<br /> Delay( wOW_F ); // 55us<br /> EINT(); // 开中断<br /> }<br /> while( tmp.u8[0]==0 );<br /> Delay( wV_30us );<br />#endif<br /><br /> OWReset(); // 总线复位<br /> OWWriteByte( 0xCC ); // 发送Skip ROM命令<br /> OWWriteByte( 0xBE ); // 发送"读"暂存RAM命令<br /><br /> tmp.u8[1]=OWReadByte(); // 读温度低字节<br /> tmp.u8[0]=OWReadByte(); // 读温度高字节<br /> // 51的整型数字高字节在前,NND,我好烦这个<br /> // 18B20 的温度值是一个标准的有符号数,此值乘上 0.0625 即是实际温度值<br /> // 注意,当选择非12bit精度时,要把未使用的低位抹平,复位成0<br /><br /> OWReset();<br /> }<br /> return tmp.u16;<br />}<br />//-----------------------------------------------------------------------------<br />// End of this file<br /><br />//=============================================================================<br />//=============================================================================<br />//=============================================================================<br />// 以下为 main.c 文件<br />//=============================================================================<br />//=============================================================================<br />//=============================================================================<br /><br /><br />//#include <C8051F340.h><br />#include "main.h"<br />#include "F_18B20.h"<br /><br /><br />//-----------------------------------------------------------------------------<br />void main()<br />{<br /> int temp;<br /> Init_Device(); // 全部 MCU 初始化工作<br /> EA = 1;<br /><br /> DS18B20_Init(); // 初始化 18B20<br /><br /> while( 1)<br /> {<br /> temp = DS18B20_ReadTemp();<br /> // 对温度值做进一步处理<br /> // 还有其它需要的工作<br /> }<br />}<br /><br />//-----------------------------------------------------------------------------<br />//-----------------------------------------------------------------------------<br />// End of this file<br />//-----------------------------------------------------------------------------<br /> |
|