一、樹莓派自帶W1-GPIO讀取
在樹莓派中有一種自帶的查看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 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#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<sizeof(buf);i++){
if(buf[i] == 't'){
for(j=0;j<sizeof(tempBuf);j++){
tempBuf[j] = buf[i+2+j];
}
}
}
temp = (float)atoi(tempBuf) / 1000;
printf("%.3f C\n",temp);
close(fd);
}
return 0;
}
二、使用GPIO17和GPIO18進行時序配置實現數據讀取
參考文獻
溫度傳感器DS18B20應用
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操作模式有以下功能
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;
}