思路
天冷了,房间里的暖气感觉一直不是很暖和。最近在搞cacti,对时序数据库rrd做了一些了解。在cacti里面根据历史数据可以根据刻/时/日/周/月/年的粒度来绘制历史图表。由于将数据进行了压缩,可以用很小的文件存储数年的历史趋势数据。所以就想用rrdtool来给室内温度做个曲线,来看下这个室温的历史曲线。
二关于数据采集方面,前一段买了一个51单片机,里面刚好带了一个温度传感器。这样就解决了数据采集和呈现的部分。另外51上带了led发光管,同时可以将温度显示出来。
二处理方面,因为电脑不可能一直开机,所以理所当然的用功耗更低的RaspPI了,至此概念上没什么问题,就差实现了。
获取温度传感器数据
了解了一下51mcu的硬件结构将传感器连接到51,将以下的c代码编译生成bin,下载到单片机上。
1#include <reg52.h>
2#include <stdlib.h>
3#define uchar unsigned char
4#define uint unsigned int
5unsigned char flag,a,i;
6
7uchar code tablet[]="";
8
9unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
10 0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
11unsigned char code table1[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,
12 0x87,0xff,0xef};
13
14sbit DS=P2^2; //define interface
15uint temp; // variable of temperature
16sbit dula=P2^6;
17sbit wela=P2^7;
18sbit beep=P2^3;
19
20void init()
21{
22TMOD=0X20;
23TH1=0xfd;
24TL1=0xfd;
25TR1=1;
26REN=1;
27SM0=;
28SM1=1;
29EA=1;
30ES=1;
31}
32
33// Temprature functions
34void delay(uint count) //delay
35{
36 uint i;
37 while(count)
38 {
39 i=200;
40 while(i>)
41 i--;
42 count--;
43 }
44}
45void dsreset(void) //send reset and initialization command
46{
47 uint i;
48 DS=;
49 i=103;
50 while(i>)i--;
51 DS=1;
52 i=4;
53 while(i>)i--;
54}
55
56bit tmpreadbit(void) //read a bit
57{
58 uint i;
59 bit dat;
60 DS=;i++; //i++ for delay
61 DS=1;i++;i++;
62 dat=DS;
63 i=8;while(i>)i--;
64 return (dat);
65}
66
67uchar tmpread(void) //read a byte date
68{
69 uchar i,j,dat;
70 dat=;
71 for(i=1;i<=8;i++)
72 {
73 j=tmpreadbit();
74 dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面,这样刚好一个字节在DAT里
75 }
76 return(dat);
77}
78
79void tmpwritebyte(uchar dat) //write a byte to ds18b20
80{
81 uint i;
82 uchar j;
83 bit testb;
84 for(j=1;j<=8;j++)
85 {
86 testb=dat&0x01;
87 dat=dat>>1;
88 if(testb) //write 1
89 {
90 DS=;
91 i++;i++;
92 DS=1;
93 i=8;while(i>)i--;
94 }
95 else
96 {
97 DS=; //write 0
98 i=8;while(i>)i--;
99 DS=1;
100 i++;i++;
101 }
102
103 }
104}
105
106void tmpchange(void) //DS18B20 begin change
107{
108 dsreset();
109 delay(1);
110 tmpwritebyte(0xcc); // address all drivers on bus
111 tmpwritebyte(0x44); // initiates a single temperature conversion
112}
113
114uint tmp() //get the temperature
115{
116 float tt;
117 uchar a,b;
118 dsreset();
119 delay(1);
120 tmpwritebyte(0xcc);
121 tmpwritebyte(0xbe);
122 a=tmpread();
123 b=tmpread();
124 temp=b;
125 temp<<=8; //two byte compose a int variable
126 temp=temp|a;
127 tt=temp*0.0625;
128 temp=tt*10+0.5;
129 return temp;
130}
131
132void display(uint temp) //显示程序
133{
134 uchar A1,A2,A2t,A3;
135 A1=temp/100;
136 A2t=temp%100;
137 A2=A2t/10;
138 A3=A2t%10;
139 dula=;
140 P0=table[A1]; //显示百位
141 dula=1;
142 dula=;
143
144 wela=;
145 P0=0x7e;
146 wela=1;
147 wela=;
148 delay(1);
149
150 dula=;
151 P0=table1[A2]; //显示十位
152 dula=1;
153 dula=;
154
155 wela=;
156 P0=0x7d;
157 wela=1;
158 wela=;
159 delay(1);
160
161 P0=table[A3]; //显示个位
162 dula=1;
163 dula=;
164
165 P0=0x7b;
166 wela=1;
167 wela=;
168 delay(1);
169}
170// end temp functions
171
172void main()
173{
174 init();
175 while(1)
176 {
177 tmpchange();
178 for(a=10;a>;a--)
179 {
180 display(tmp());
181 }
182
183 if(flag==1)
184 {
185 ES=;
186 // SBUF=hex2dec(tmp());
187 SBUF=tmp();
188 while(!TI);
189 TI=;
190 SBUF=a;
191 while(!TI);
192 TI=;
193 ES=1;
194 flag=;
195 }
196
197 }
198
199}
200
201void ser() interrupt 4
202{
203RI=;
204a=SBUF;
205flag=1;
206}
在RaspPI上用python读取温度
由于c51上输出的温度是不带小数点的十六进制整型量,所以需要进行一个数值转换。 注意的是由于默认的PI上的usb转串口芯片自动识别后会被设置root和dailout组,并且是750的权限,因此需要修改
1/lib/udev/rules.d/91-permissions.rules
2#SUBSYSTEM==”tty”, GROUP=”dialout”
3SUBSYSTEM==”tty”, GROUP=”sudo”
4
5crw-rw—T 1 root sudo 188, 0 Dec 23 11:44 /dev/ttyUSB0
这样就可以被sudo组的用户使用了。 PI可以直接识别无需驱动。
1[ 239.349670] usb 1-1.2.2: new full-speed USB device number 9 using dwc_otg
2[ 239.471543] usb 1-1.2.2: New USB device found, idVendor=1a86, idProduct=7523
3[ 239.471574] usb 1-1.2.2: New USB device strings: Mfr=0, Product=2, SerialNumber=0
4[ 239.471592] usb 1-1.2.2: Product: USB2.0-Serial
5[ 239.475632] ch341 1-1.2.2:1.0: ch341-uart converter detected
6[ 239.479287] usb 1-1.2.2: ch341-uart converter now attached to ttyUSB0
gettmp.py
1#!/usr/bin/python
2import serial
3import os
4if os.path.exists('/dev/ttyUSB0'):
5 port='/dev/ttyUSB0'
6elif os.path.exists('/dev/ttyUSB1'):
7 port='/dev/ttyUSB1'
8else:
9 print"No comm port found"
10 os._exit(1)
11 ser=serial.Serial(port,9600,timeout=2)
12 ser.write('0')
13 x=ser.readline()
14 #return hex format
15 with integerprintfloat(ord(x[]))/10
16 ser.close()
用rddtool绘图
rrdtool非常方便,直接用shell就可以处理数据的收集和绘图。
1#!/bin/sh
2
3rrdtool=/usr/bin
4gettmp=/home/cli/lab/gettmp.py
5
6RRD_DB_DIR=/home/cli/lab/
7RRD_DB_FILE=/home/cli/lab/temp.rrd
8RRD_DB_PIC=/home/cli/lab/
9NOW=`date +%s`
10MONTH_IN_SEC=2629743
11MONTH_AGO=$(($NOW-$MONTH_IN_SEC))
12
13ONE_QUARTER_AGO=$(($NOW-900))
14ONE_HOUR_AGO=$(($NOW-3600))
15ONE_DAY_AGO=$(($NOW-86400))
16ONE_WEEK_AGO=$(($NOW-604800))
17ONE_MONTH_AGO=$(($NOW-2629743))
18ONE_YEAR_AGO=$(($NOW-31556926))
19
20do_rrdgraph(){
21
22if [ $2 = "quarter" ]
23 then
24 echo quarter
25 flag=MINUTE:1:MINUTE:3:MINUTE:3::"%H:%M"
26elif [ $2 = "hour" ]
27 then
28 echo hour
29 flag=MINUTE:3:MINUTE:6:MINUTE:6::"%H:%M"
30elif [ $2 = "day" ]
31 then
32 echo day
33 flag=MINUTE:30:HOUR:1:HOUR:2::"%H:%M"
34elif [ $2 = "week" ]
35 then
36 echo week
37 flag=DAY:1:DAY:2:DAY:1::"%m/%d"
38elif [ $2 = "month" ]
39 then
40 echo month
41 flag=DAY:1:DAY:3:DAY:3::"%m/%d"
42elif [ $2 = "year" ]
43 then
44 echo year
45 flag=MONTH:1:MONTH:2:MONTH:2::"%Y/%m"
46fi
47
48if [ !$3 = "" ]
49then
50 echo "resolution=$3"
51 resolution="-S $3"
52else
53 echo "resolution=300"
54 resolution="-S 300"
55fi
56
57$rrdtool/rrdtool graph "${RRD_DB_PIC}temp_$2.png" -s $1 -h 120 -w 500 -a PNG ${resolution} -t "Temperature C (last $2)" \
58-v bytes \
59-R light \
60-G mono \
61-u 40 \
62-l \
63--color BACK#000000 \
64--color FRAME#00FF00 \
65--color CANVAS#000000 \
66--color GRID#000000 \
67--color MGRID#003300 \
68--color FONT#00FF00 \
69--lower-limit= \
70--units-exponent \
71--rigid \
72--x-grid ${flag} \
73DEF:a="$RRD_DB_FILE":temp:AVERAGE \
74DEF:b="$RRD_DB_FILE":temp:MAX \
75DEF:c="$RRD_DB_FILE":temp:MIN \
76AREA:a#00EE00:"Temp. \: " \
77GPRINT:a:AVERAGE:"%sAvg %.2lf" \
78GPRINT:b:MAX:"%sMax %.2lf" \
79GPRINT:c:MIN:"%sMin %.2lf"
80
81}
82
83if [ -e "$RRD_DB_FILE" ]
84then
85 echo "file exits: $RRD_DB_FILE"
86 VALUE=$($gettmp)
87echo $VALUE
88 $rrdtool/rrdtool updatev $RRD_DB_FILE N:${VALUE}
89
90 do_rrdgraph $ONE_QUARTER_AGO quarter
91 do_rrdgraph $ONE_HOUR_AGO hour
92 do_rrdgraph $ONE_DAY_AGO day 600
93 do_rrdgraph $ONE_WEEK_AGO week 600
94 do_rrdgraph $ONE_MONTH_AGO month 600
95 do_rrdgraph $ONE_YEAR_AGO year 1800
96
97else
98
99$rrdtool/rrdtool create $RRD_DB_FILE --step 300 \
100DS:temp:GAUGE:600::40 \
101RRA:AVERAGE:.5:1:1200 \
102RRA:MIN:.5:12:2400 \
103RRA:MAX:.5:12:2400 \
104RRA:AVERAGE:.5:12:2400
105echo "file created:$RRD_DB_FILE"
106
107fi
最终这样的
- 硬件是这样的
- 跑了一段时间后从浏览器里打开可以看到这个图。从里面可以看到供暖后温度上升的趋势。