思路

天冷了,房间里的暖气感觉一直不是很暖和。最近在搞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

最终这样的