用C#在树莓派温度实时温度采集上通过ADS怎样读取温度传感器的数据?

因为项目需要,要在上位机界面实时显示室内温度,上位机采用QT5.5编写,采用DS18B20采集数据,显示在控件lcdNumber上。DS18B20是一个比较常用的温度传感器,采用单总线控制,在linux中,一切都是文件,所以数据采集也是文件的读取。一、修改配置文件在/boot/config.txt文件后面添加下面这一句sudo vi /boot/config.txt
dtoverlay=w1-gpio
这一句就是树莓派添加Device Tree设备,dtoverlay=w1-gpio表示添加单总线设备,也可以写成dtoverlay=w1-gpio,gpioin=4默认管脚为BCM编号4,如果DS18B20接到其他管脚则需要修改这个值,在微雪电子的树莓派扩展板上Pioneer 600扩展板DS18B20默认接到4,故不用修改。二、查看模块是否启动重启树莓派使设置生效,运行lsmod命令,如果发现红色方框的两个模块说明模块已启动。如果没有发现,也可以运行如下命令加载模块sudo modprobe w1_gpio
sudo modprobe w1_therm
三、 读取温度如果没有问题,在/sys/bus/w1/devices中发现一个28-XXXX开头的文件夹,这个就是DS18B20的ROM,每个DS18B20都一样,连接多个18B20就会有多个这样的文件,在这个文件夹中再读取w1_slave文件则会返回当前温度值。这里我们先进去打印一下,看看有哪些数值: sudo modprobe w1-gpio
sudo modprobe w1-therm
cd
/sys/bus/w1/devices
cd 28-00000xxx
cat w1_slave
在返回数据中,第一行最后的YRS表示CRC校验成功,数据有效。第二行最后t=30500表示当前温度为30.5摄氏度。按照此逻辑,只要反复读取这个文件中的t值即可显示温度。四:QT界面显示温度在QT中ui界面拖选一个lcdNumber,然后使用定时器定时去读取数值,显示在这个控件上即可;参照一个大佬的程序:QT+树莓派读取温度,在实际使用中有一点问题,一是显示在lcdNumber上,必须是个字符串,而我想要的是带小数点的温度值。二是涉及到一些数值类型装换,如读到的值是30500,实际要显示为30.5。三是树莓派直接接DS18B20是找不到上面所说的文件的,必须要在DS18B20的VCC和数据引脚之间接一个4.7K的上拉电阻才可以。五:源程序.h文件只是添加一些要用到的包,再声明一个信号函数private slots:void cj();#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QString>
#include <QDir>
#include <QStringList>
#include <QMessageBox>
#include <QTextStream>
#include <QDebug>
#include <QTimer>
#include <QTime>
#inclede <QTextCodec>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void cj();
private:
Ui::MainWindow *ui;
QDebug *Debug;
};
#endif // MAINWINDOW_H
.cpp文件
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::cj()
{
system("sudo modprobe w1-gpio");
system("sudo modprobe w1-therm");
QString tempFile="/sys/bus/w1/devices/";
qDebug() << tempFile;
QString tempData;
//设置ds18b20的文件所在位置
QDir tempPath("/sys/bus/w1/devices/");
//得到所有的文件列表
QStringList fileList=tempPath.entryList();
//遍历所有文件,找到关于ds18b20的文件
int i=0;
while(i<fileList.size())
{
if(fileList.at(i).contains("28-"))
{
tempFile.append(fileList.at(i));
//已经找到了文件
break;
}
i++;
}
tempFile.append("/w1_slave");
qDebug() << tempFile;
QFile file(tempFile);
if(!file.open(QIODevice::ReadOnly|QFile::Text))
{
QMessageBox::information(this,tr("fgbdfgds"),tr("hjggnfghn"));
return;
}
QTextStream in(&file);
//根据存储的文件找到需要的数据
QString str=in.readAll(); //读出所有内容
//
qDebug() << str;
tempData=str.mid(str.indexOf('t')+2,3); //定位数据的位置,找到所需要的数据,精度可以达到小数点后三位,本程序只
需一位
float temp = tempData.toFloat();
// 将字符类型转换为float
float temp2 = temp/10;
// 将float进行运算得到小数点
QString temp3 = QString::number(temp2,'f',2);
// 再将float转换为字符型,2代表小数点后几位
ui->lcdNumber->display(temp3);
file.close();
}
1 DS18B20简介(1) ds18b20介绍DS18B20是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点,是通过一线协议来配置的传感器,刚好拿实验室的树莓派来做一下获取温度的小项目。(2) DS18B20连接树莓派配置内核启动后自动加载一线协议驱动 连接引脚
输入命令进行配置 pi@raspberrypi:~ $ sudo raspi-config
//打开配置选项
按Enter选中继续按Enter选中打开内核文件pi@raspberrypi:~ $ vim /boot/config.txt
在最后添加连接的引脚,我们连接了22(BCM编码)dtoverlay=w1-gpio-pullup,gpiopin=22
重启树莓派pi@raspberrypi:~ $ sudo reboot
重启系统后,确认系统有自动加载一线协议的驱动模块pi@raspberrypi:~/ds18b20 $ lsmod
grep w1
当树莓派配置好DS18B20数字温度传感器后,该温度信息通常保存在下面路径中,我们只需要读取文件中的温度即可:/sys/bus/w1/devices/28-XXXXXXXX/w1_slave
查看路径文件下温度数据:(3) 流程简述1 调用opendir()和readdir()来打开读取文件路径(默认文件路径“/sys/bus/w1/devices/”)在这里我们注意到为什么不是全部路径 (/sys/bus/w1/devices/28-XXXXXXXX/w1_slave) 而是只截取到 (/sys/bus/w1/devices/),这是因为“28-XXXXX”是产品序列号,如果我们换了一个DS18B20进行获取温度,产品序列号XXXXX改变,那此路径就不能用了,而这一产品序列号XXXXX目录无论变成什么永远在(/sys/bus/w1/devices/)路径下,所以我们只打开读取路径到这里2 寻找“28-”开头的文件,将其存入缓冲区接下来在(默认文件路径“/sys/bus/w1/devices/”)下通过strstr()函数找到“28-”打头的文件,并且存入缓冲区,方便更改3 调用closedir()关闭文件**4 通过strncat链接文件路径调用strncat将(默认文件路径“/sys/bus/w1/devices/”)和存入缓冲区的(“28-XXXXX”)连接起来,然后再调用strncat()将“/w1_slave”路径连接起来,此时需要读取数据的路径就完整了,进行实时获取产品序列号的文件目录,以便实时读取温度5 调用open()和read()来打开文件,读取文件,找到温度(t=)打头的数据利用strstr()再匹配(“t=”)打头的数据6 调用close()关闭文件7 将数据进行处理然后打印即可将获得的字符类型数据转换成单精度类型数据,只打印数据,不打印“t=”2 项目代码介绍(1)文件I/O的API函数open() int open(const char *path, int oflag, ... /*mode_t mode*/);
open()系统调用用来打开一个文件,并且返回一个文件描述符(fd),并且该文件描述符是当前进程最小,并未使用的文件描述符数值,即3,因为0是标准输入,1是标准输出,2是标准出错。参数: path: 要打开的文件、设备的路径oflag: 由多个选项进行“或”运算构造oflag参数 。必选: O_RDONLY (只读)、 O_WRONLY(只写)、 O_RDWR(读写)可选: O_APPEND 每次写时都追加到文件的尾端。O_CREAT 文件不存在则创建它,使用该选项需要第三个参数modeO_TRUNC 如果文件存在,而且为只写或读写成功打开,则将其长度截取为0;O_NONBLOCK 如果path是一个FIFO、块设备、字符特殊文件则此 选项为文件的本次打开和后续的I/O操作设置非阻塞模式方式:O_EXEC、O_SEARCH、O_CLOEXEC、O_NOCTTY…mode: oflag带O_CREAT选项时可以用来创建文件,这时必须带该参数用来指定创建文件的权限模式,如066。 否则不需要。使用示例代码:int fd;fd = open(“text.txt”, O_RDWR|O_CREAT|O_TRUNC, 0666);fd = open(“text.txt”, O_WRONLY|O_APPEND);read()ssize_t read(int fd, void*buf, size_t nbytes);
read()函数是用来打开文件描述符对应的文件中读取数据放到buf指向的内存空间中去,最多不要超过nbytes个字节,这里的nbytes一般指的是buf剩余空间的大小。如果read成功,则返回实际读到的字节数(由nbtyes或读懂到文件尾决定,其中EOF宏用来判断是否到了文件尾),如果返回值小于0则表示出错,如哦尝试读取一个没有权限读取的文件时就会抛错。close()int close(int fd);
该函数用来关闭一个打开的文件描述符,关闭一个文件时还会释放该进程加载该文件上的所有记录锁。当一个进程终止时,内核将会自动关闭它所打开的文件。opendir()DIR *opendir(const char *pathname)
opendir()是用来打开指定的目录文件,并返回DIR *形态的目录流,和open()类似,接下来对目录的搜索和读取都要使用此返回值,该返回值是指向DIR结构体的指针,失败返回 NULL。readdir()struct dirent *readdir(DIR *dirp)
readdir()函数的参数是opendir()返回的DIR *结构体指针也就是dirp,通过这个结构体,我们可以读取文件夹的相关信息(文件名,长度等),并返回一个direntp的指针,该结构体就用来存放这些信息,失败时返回NULLstruct dirent
{
long d_ino; /* inode number 索引节点号 */
off_t d_off; /* offset to this dirent 在目录文件中的偏移 */
unsigned short d_reclen; /* length of this d_name 文件名长 */
unsigned char d_type; /* the type of d_name 文件类型 */
char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符*/
}
closedir()关闭目录路流(2)项目代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
char
path[100] = "/sys/bus/w1/devices/";
//局部变量存储大概路径
char
buf1[1024];
char
buf2[100];
char
*ptr = NULL;
int
fd = -1;
int
rv = -1;
int
flag = 0;
float
temp;
DIR
*dirp;
struct dirent
*direntp;
if((dirp = opendir(path)) == NULL)
{
printf("Opendir %s error: %s\n",path,strerror(errno));
return -1;
}
while((direntp = readdir(dirp)) != NULL)
{
if(strstr(direntp->d_name, "28-"))
{
strncpy(buf2, direntp->d_name, sizeof(buf2));
flag = 1;
}
}
closedir(dirp);
if(!flag)
{
printf("Can not find 28- in the path\n");
return -2;
}
strncat(path, buf2, sizeof(path)-strlen(path));
strncat(path, "/w1_slave",sizeof(path)-strlen(path));
if((fd = open(path,O_RDONLY)) < 0)
{
printf("Open %s failure: %s\n",path,strerror(errno));
return -3;
}
if((rv = read(fd,buf1,sizeof(buf1))) < 0)
{
printf("Read %s failure;%s\n",path,strerror(errno));
return -4;
}
close(fd);
if((ptr = strstr(buf1,"t=")) != NULL)
{
temp = atof(ptr+2)/1000;
printf("The current temperature: %.2f℃\n",temp);
}
else
{
printf("Can not get the current temperture\n");
return
-5;
}
return 0;
}
· 运行结果获取到了我们想要的温度!!!
设备树莓派3b+温湿度传感器DHT11接线VCC - 电源3.3v或者5vdata - 数据读取GND - 接地这个的接线方式和上次的接线很像,其实其他的也都差不多,电源正负和数据读取写入读取在上面的接线中,我把DHT11放在了22号针脚上,所以下面的针脚号都是22,如果你接在了其他部分,注意修改~使用官方库官方的安装方式和上次用显示屏的方式一样,都是clone,安装,执行git clone git://github.com/adafruit/Adafruit_Python_DHT.git
cd Adafruit_Python_DHT/
sudo python setup.py install
cd examples/
python AdafruitDHT.py 11 22
最终的结果是Temp=25.0*
Humidity=22.0%
如果是用python3,就把上面的python改成python3即可。sudo python3 setup.py install
python3 AdafruitDHT.py 11 22
也是可以执行的。AdafruitDHT.py文件内容如下#!/usr/bin/python
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import sys
import Adafruit_DHT
# Parse command line parameters.
sensor_args = { '11': Adafruit_DHT.DHT11,
'22': Adafruit_DHT.DHT22,
'2302': Adafruit_DHT.AM2302 }
if len(sys.argv) == 3 and sys.argv[1] in sensor_args:
sensor = sensor_args[sys.argv[1]]
pin = sys.argv[2]
else:
print('Usage: sudo ./Adafruit_DHT.py [11|22|2302] <GPIO pin number>')
print('Example: sudo ./Adafruit_DHT.py 2302 4 - Read from an AM2302 connected to GPIO pin #4')
sys.exit(1)
# Try to grab a sensor reading.
Use the read_retry method which will retry up
# to 15 times to get a sensor reading (waiting 2 seconds between each retry).
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
# Un-comment the line below to convert the temperature to Fahrenheit.
# temperature = temperature * 9/5.0 + 32
# Note that sometimes you won't get a reading and
# the results will be null (because Linux can't
# guarantee the timing of calls to read the sensor).
# If this happens try again!
if humidity is not None and temperature is not None:
print('Temp={0:0.1f}*
Humidity={1:0.1f}%'.format(temperature, humidity))
else:
print('Failed to get reading. Try again!')
sys.exit(1)
使用GPIO读取我们也可以直接通过python直接读取GPIO针脚的数据
import RPi.GPIO as GPIO
import time
channel = 22
#引脚号
data = []
#温湿度值
j = 0
#计数器
GPIO.setmode(GPIO.BCM)
#以BCM编码格式
time.sleep(1)
#时延一秒
GPIO.setup(channel, GPIO.OUT)
GPIO.output(channel, GPIO.LOW)
time.sleep(0.02)
#给信号提示传感器开始工作
GPIO.output(channel, GPIO.HIGH)
GPIO.setup(channel, GPIO.IN)
while GPIO.input(channel) == GPIO.LOW:
continue
while GPIO.input(channel) == GPIO.HIGH:
continue
while j < 40:
k = 0
while GPIO.input(channel) == GPIO.LOW:
continue
while GPIO.input(channel) == GPIO.HIGH:
k += 1
if k > 100:
break
if k < 8:
data.append(0)
else:
data.append(1)
j += 1
print("sensor is working.")
print(data)
#输出初始数据高低电平
humidity_bit = data[0:8]
#分组
humidity_point_bit = data[8:16]
temperature_bit = data[16:24]
temperature_point_bit = data[24:32]
check_bit = data[32:40]
humidity = 0
humidity_point = 0
temperature = 0
temperature_point = 0
check = 0
for i in range(8):
humidity += humidity_bit[i] * 2 ** (7 - i)
#转换成十进制数据
humidity_point += humidity_point_bit[i] * 2 ** (7 - i)
temperature += temperature_bit[i] * 2 ** (7 - i)
temperature_point += temperature_point_bit[i] * 2 ** (7 - i)
check += check_bit[i] * 2 ** (7 - i)
tmp = humidity + humidity_point + temperature + temperature_point
#十进制的数据相加
if check == tmp:
#数据校验,相等则输出
print ("temperature : ", temperature, ", humidity : " , humidity)
else:
#错误输出错误信息,和校验数据
print ("wrong")
print ("temperature : ", temperature, ", humidity : " , humidity, " check : ", check, " tmp : ", tmp)
GPIO.cleanup()
执行之后也可以得到传感器结果pi@xiaoyupi:~/RaspberryPiScript $ python3 DHT11.py
sensor is working.
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1]
temperature :
25 , humidity :
16
使用0.96寸oled屏展示温湿度代码如下#!/usr/bin/python
import time
import Adafruit_GPIO.SPI as SPI
import Adafruit_SSD1306
import Adafruit_DHT
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import subprocess
# Raspberry Pi pin configuration:
RST = None
# on the PiOLED this pin isnt used
# Note the following are only used with SPI:
DC = 23
SPI_PORT = 0
SPI_DEVICE = 0
disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST)
# Initialize library.
disp.begin()
# Clear display.
disp.clear()
disp.display()
# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
width = disp.width
height = disp.height
image = Image.new('1', (width, height))
# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)
# Draw a black filled box to clear the image.
draw.rectangle((0,0,width,height), outline=0, fill=0)
# Draw some shapes.
# First define some constants to allow easy resizing of shapes.
padding = -2
top = padding
bottom = height-padding
# Move left to right keeping track of the current x position for drawing shapes.
x = 0
# Load default font.
font = ImageFont.load_default()
# Alternatively load a TTF font.
Make sure the .ttf font file is in the same directory as the python script!
# Some other nice fonts to try: http://www.dafont.com/bitmap.php
# font = ImageFont.truetype('Minecraftia.ttf', 8)
while True:
# Draw a black filled box to clear the image.
draw.rectangle((0,0,width,height), outline=0, fill=0)
sensor
= 11 # 传感器型号
pin = 22 # 针脚
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
if humidity is not None and temperature is not None:
Temp = 'Temp={0:0.1f}*'.format(temperature)
H = 'Humidity={0:0.1f}%'.format(humidity)
now = time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime())
draw.text((x, top),
str(now),
font=font, fill=255)
draw.text((x, top+8),
str(Temp), font=font, fill=255)
draw.text((x, top+16),
str(H), font=font, fill=255)
# Display image.
disp.image(image)
disp.display()
time.sleep(1)
最终实现效果如图

我要回帖

更多关于 树莓派温度实时温度采集 的文章

 

随机推荐