在树莓派中有一种自带的查看DS18B20温度信息,已经写好DS18B20时序,对外设设备进行读取信息然后保存的值在/sys/bus/w1/devices/28-xxxxxxxxxxx/w1_slave文件中,将DS18B20的DQ数据线直接连接在树莓派的GPIO4上就可以使用cat命令进行查看温度值。连接方式如图1,读取温度如图2。读取到温度为 t / 1000,图2的温度为23.187。
图1.使用w1-gpio进行温度读取
图2.使用cat读取温度信息
使用C语言打开w1_slave文件进行读取转换就行,代码如下
#include
#include
#include
#include
#include
#include
#include
#include
#define BUFSIZE 128
char* addr = "/sys/bus/w1/devices/28-02161682f4ee/w1_slave";
int main(void)
{
float temp;
int i, j;
int fd;
int ret;
char buf[BUFSIZE];
char tempBuf[5];
while (1){
fd = open(addr, O_RDONLY);
if(-1 == fd){
perror("open device file error");
return 1;
}
while(1){
ret = read(fd, buf, BUFSIZE);
if(0 == ret){
break;
}
if(-1 == ret){
if(errno == EINTR){
continue;
}
perror("read()");
close(fd);
return 1;
}
}
for(i=0;i
DS18B20通过使用DQ数据线对ROM进行写数操作读写来控制操作模式及读取数值,调用wiringPi库。
每次操作完成后写1为释放总线。
根据时序表先写入1进入检测状态,然后写0进入总线检测应答,检测应答时间为480~960us,如果应答成功则需要下一个拉高(需要人为写1)进行应答脉冲,芯片应答成功将总线拉低,表示复位成功。
void Init_DS18B20(void)
{
unsigned int var = 0;
digitalWrite(DQ_OUT, HIGH); //开
delayMicroseconds(1); // 微秒
digitalWrite(DQ_OUT, LOW); //关
delayMicroseconds(500);
digitalWrite(DQ_OUT, HIGH); //开
delayMicroseconds(60);
var = digitalRead(DQ_IN);
if (0 == var)
{
ds_flag = 1;
delayMicroseconds(250);
}
else
{
ds_flag = 0;
}
digitalWrite(DQ_OUT, HIGH); //开
}
ROM 功能命令
Read Rom[33h] 读取DS18B20中ROM的内容
该命令允许总线主机读取DS18B20的8位c产品家族码,唯一的48位序列号和8位CRC。 只有在总线上有一个DS18B20时才能使用此命令。 如果总线上存在多个从机,当所有从机同时尝试往主机发送时,将发生数据冲突时(会产生线与结果)。
Match Rom[55h] ROM匹配
匹配ROM命令后跟64位ROM地址,允许总线主机在多点总线上寻址特定的DS18B20。 只有与64位ROM地址完全匹配的DS18B20才响应总线主机的命令。 所有与64位ROM序列不匹配的从器件将等待复位脉冲。 此命令可用于总线上的单个或多个从机。
Skip Rom[CCh] 跳过ROM
该命令允许总线主机可以不提供64位ROM序列也能访问存储器,从而可以节省单个总线系统中的时间。如果总线上存在多个从机并且主机在发出Skip ROM命令之后发出读命令,则当多个从机同时发送时,总线上将发生数据冲突(会产生线与结果)。
Search Rom[F0h] 搜索ROM
当系统刚启动时,总线上的主机可能不知道单总线上的从机数量和它们的64位ROM序列号。搜寻ROM命令使总线主机识别总线上所有从机的64位ROM序列号。
Alarm Search[ECh] 警报搜索
该命令的流程图与Search ROM命令相同,但是,只有在最后一次温度测量中遇到报警条件时,DS18B20才会响应这个命令。
存储功能命令
Write Scratchpad[4Eh] 写暂存器
发出数据向内部RAM的第2,3,4字节写,内容是上限温度数据命令、下限温度数据命令。
Read Scratchpad [BEh] 读暂存器
读内部RMA中的9字节的内容
Copy Scratchpad [48h] 复制暂存器
将RAM中的第2,3,4字节的内容复制到EEPROM中
Convert T [44h] 温度转换
启动DS18B20进行温度转换,转换时间最长为500ms(典型为200ms),结果存入内部9字节RAM中
Recall E2 [B8h] 重调EEPROM
EEPROM中的内容恢复到RAM中的第2,3,4字节
Read Power Supply [B4h] 读供电方式
读DS18B20的供电模式,寄生供电时DS12B20发送“0”,外接电源供电时DS12B20发送“1”
ROM会有64位的ROM序列号如果不使用0xCC跳过则需要进行ROM匹配,一把都进行跳过;
0x44为温度转换,转换一般需要100ms~1s的时间延时,转换为数值为模拟量值,还需要进行16位的分辨率转换,即得到的值除以16。
0xBE为读取ROM类的数值。
写操作分为写1和写0但两者的总时序都在60us完成。
void WriteOneChar(unsigned char data)
{
unsigned char i = 0, j = 0;
unsigned int temp = 0;
digitalWrite(DQ_OUT, HIGH); //开 // Write 1
delayMicroseconds(61);
for (j = 1;j <= 8;j++)
{
digitalWrite(DQ_OUT, LOW); //关 // Write 0
delayMicroseconds(15);
temp = data & 0x01;
data = data >> 1;
digitalWrite(DQ_OUT, temp); //写值
delayMicroseconds(45);
digitalWrite(DQ_OUT, HIGH); //释放总线 // Write 1
delayMicroseconds(2);
}
digitalWrite(DQ_OUT, HIGH); //释放总线 // Write 1
}
读模式在得到总线资源的15us内读到数据,读取后等待40us得到下一包数据,而我的做法是空一拍数据这样做的好处是可以更加准确的得到总线资源
unsigned char ReadOneChar(void)
{
unsigned char i = 0;
unsigned char var = 0;
unsigned char vara = 0;
digitalWrite(DQ_OUT, HIGH); //开 // Write 1
delayMicroseconds(2);
digitalWrite(DQ_OUT, LOW); //关
delayMicroseconds(3);
digitalWrite(DQ_OUT, HIGH); //开 // Write 1
delayMicroseconds(3);
var = digitalRead(DQ_IN);
delayMicroseconds(60); // 微秒
return var;
}
读取一个温度值
unsigned char DS18B20_Read_Byte(void)
{
unsigned char i, j, data;
data = 0;
for (i = 1;i <= 8;i++)
{
j = ReadOneChar();
data = (j << 7) | (data >> 1);
}
return data;
}
unsigned int ReadTempetature(void)
{
unsigned int data[3] = { 0,0,0 };
unsigned char i = 0;
Init_DS18B20();
while (0 == ds_flag)
{
Init_DS18B20();
}
WriteOneChar(0xCC);
WriteOneChar(0x44);
delay(500); // 毫秒
Init_DS18B20();
WriteOneChar(0xCC);
WriteOneChar(0xBE);
data[0] = DS18B20_Read_Byte();
data[1] = DS18B20_Read_Byte();
data[2] = data[1] << 8 | data[0];
return data[2];
}
最后main函数调用
int main(void)
{
unsigned int a = 0;
wiringPiSetupSys();
pinMode(DQ_OUT, OUTPUT);
pinMode(DQ_IN, INPUT);
while (true)
{
a = ReadTempetature();
a = a / 16;
printf("temp=%d\n", a);
}
return 0;
}