ようこそNICのホームページへ(なが〜い試運転中)    あなたは2001/5/12以来 人目の来訪者です。
HP パソコン 健康 落語 海外 思うまま 電子工作


ブラウザー経由でシリアルポートからデータを読み取る

Last update:2008/12/07    Build:2008/09/02

データーロガーを作り、アナログデーターを取り込めるようになった。
windows経由、エクセルにはデーターが取り込める。
24時間動いている、freebsdベースのサーバーがある。
これを使って継続的に温度観測ができないだろうか??

ということで、やってみることにした。
結果、何とか読み込めるようになった。
現在、30分間隔でデータを取り込んでいる。できれば1年継続してみたい。


別途、ブラウザー経由で任意に温度データを取り込めるようにした。
ここです。


読み出しているデータは、日付、時刻、アナログデーターのAD変換値4つ

1つめ:アナログ値1、基準電圧(1023になるはずなのに??)
2つめ:アナログ値2、アース電圧 0です
3つめ:温度センサー(LM35DZ)の出力値(AD変換値)
4つめ:温度センサー(S−8100B)の出力値(AD変換値)


それと温度センサーの出力値を温度に換算したもの

2つのセンサーは5cm程度しか離れていないので、もっと近い値を示していいはずですが
キャリブレーションがうまく行っていないのでしょうか。
それとも温度換算がうまく行っていないのでしょうか。
基準電圧の影響があるのでしょうか。
すこし、様子を見ながら、考えます

(2008/09/05)追記
デジタル温度計を温度センサーのそばに置くと、S−8100Bの値とほぼ同じです。
LM−35DZセンサーの値が小さめのようです。もう一個LM−35DZセンサーがあるので
5ボルト電源を与えて、テスターで直読してみました。ほぼ、S−8100Bセンサーの示す温度と同じです。
データーロガーのLM−35DZセンサーをもう一個のLM−35DZセンサーに付け替えましたが、結果は変わらず。
AD変換がおかしいのか、配線上の何か抵抗があるのか?現時点で不明。(2008/09/05)追記



(2008/09/06)追記
接触抵抗など、センサー(LM35DZ)からPICの足まで抵抗があるのかもしれないと考え、
ブレッドボードにLM35DZと10kΩ可変抵抗を乗せ、LM35DZのアウトプットに
可変抵抗を繋ぎ、テスターで出力電圧を直読しました。
0kΩから10kΩまで可変させても出力値は約300mVで変化しませんでした。
なぜ、センサー直読すると300mVなのにPICでAD変換すると260mV程度なのだろう
(2008/09/06)追記




(2008/12/07)追記
PIC(12F683)とAMD3202の直前のVssとGNDの間に0.1μFのコンデンサーをそれぞれいれることで
プルアップした値が「1023」となりました。
温度センサーLM−35DZの値も正しく表示されるようになりました。
ただ、もう一つの温度センサーS−8100Bの値が揺れ動くようになりました。
2つのセンサーの値は近い値になりました。
この経緯は2台目のデータロガーを作るを参照
(2008/12/07)追記




ここからは試行錯誤の結果です。

まず、freebsdのシリアルポートが使えるかのチェック
シリアルポートが認識されていることは
$ dmesg | grep sio
sio0 at port 0x3f8-0x3ff irq 4 flags 0x10 on isa0
sio0: type 16550A
sio1: configured irq 3 not in bitmap of probed irqs 0
sio1: port may not be enabled
で確認済み

そこでKermitというターミナルソフトをインストールして、
直接シリアルポートをさわってみました。




待ち受けではないので、/dev/cuad0というディバイスでアクセス可能です。
(待ち受けの場合は/dev/ttyd0を使うようです)
ただし、ユーザはダイアルアップと同じことをするようで、
'dialer'グループに属する必要がありました。→/etc/groupのdialerグループにユーザーを追加。

次にperlでこれらのデータを読み込み、ファイルに書き出す作業です
このようなプログラムを作りました

#!/usr/bin/perl -w  
#               -w ワーニングを出す
#           データロガーから読み取るプログラム
#           /home/USER/datalgr.pl mod 700
#           2008/08/27
#
use strict; # 宣言した変数以外を使えなくする

$| = 1;   # ゼロ以外が代入されると出力をバッファリングしなくなる。

my $file="/home/USER/log-data.txt";
my $sec;
my $min;
my $hour;
my $mday;
my $mon;
my $year;
my $wday;
my $yday;
my $isdst;
my $tt;
my $null="";


# 読み込み書き込みファイルオープン
#                読み取り 書き込み 追加 新規作成 上書き 
#   <   filename ○         ×      ×     ×      × 
#   >   filename ×         ○      ×     ○      ○ 
#   >>  filename ×         ○      ○     ○      × 
#   +<  filename ○         ○      ×     ×      × 
#   +>  filename ○         ○      ×     ○      ○ 
#   +>> filename ○         ○      ○     ○      × 


open (COM1, "+</dev/cuad0") or die "ERROR /dev/caud0 not open$!\n" ; # シリアルポートを入出力可能でオープン
#system("stty </dev/cuad0 cs8 -parenb  -cstopb speed 9600") ;


#print "open serial port COM1 ok\n" ;



#  #########################  シリアルポートCOM1からデータを取得
#
print COM1 "0\n"; # アナログポート0
my $data0 = <COM1>
$data0 =~s/\n//;    # 後ろ\nを除去

print COM1 "1\n"; # アナログポート1
my $data1 = <COM1>
$data1 =~s/\n//;    # 後ろ\nを除去

print COM1 "2\n"; # アナログポート2
my $data2 = <COM1>
$data2 =~s/\n//;    # 後ろ\nを除去

print COM1 "3\n"; # アナログポート3
my $data3 = <COM1>

close COM1 ;

# ########################### 時刻とデータの印字(ファイルへの出力)
$tt=time();
($sec, $min, $hour, $mday, $mon, $year,
    $wday, $yday, $isdst) = localtime($tt);
$year=$year+1900;
$mon=$mon+1;

open (LOGFILE,">>$file") or die "ERROR output file not open$!\n" ; # 出力ファイルをオープン
print LOGFILE  $year,"/",$mon,"/",$mday,"   ",$hour,":",$min,":",$sec,"  ",$data0,$data1,$data2,$data3 ;

close LOGFILE ;



このようにして、継続的にデーターを取り込むことができるようになりました。
現在はcronを使って30分ごとにデータを読み込んでいます

シリアルポートCOM1からデータを取得したあとで’¥n’を除去しているのは
横一列でデータを出力したかったのに、改行されてしまうからです
最後は改行しても良いので、’¥n’を除去しませんでした



次に、このperlを利用し、ブラウザーを経由して任意にデータを採取するためのcgiを作った

#!/usr/bin/perl -w  
#               -w ワーニングを出す
#           データロガーから読み取るプログラム
#           /home/USER/datalgr.cgi mod 755
#           2008/08/27
#
use strict; # 宣言した変数以外を使えなくする

$| = 1;   # ゼロ以外が代入されると出力をバッファリングしなくなる。

my $file="/home/USER/log-data.txt";
my $sec;
my $min;
my $hour;
my $mday;
my $mon;
my $year;
my $wday;
my $yday;
my $isdst;
my $tt;
my $null="";


# 読み込み書き込みファイルオープン
#                読み取り 書き込み 追加 新規作成 上書き 
#   <   filename ○         ×      ×     ×      × 
#   >   filename ×         ○      ×     ○      ○ 
#   >>  filename ×         ○      ○     ○      × 
#   +<  filename ○         ○      ×     ×      × 
#   +>  filename ○         ○      ×     ○      ○ 
#   +>> filename ○         ○      ○     ○      × 


open (COM1, "+</dev/cuad0") or die "ERROR /dev/cuad0 not open\n" ; # シリアルポートを入出力可能でオープン
#system("stty </dev/cuad0 cs8 -parenb  -cstopb speed 9600") ;


#print "open serial port COM1 ok\n" ;



#  #########################  シリアルポートCOM1からデータを取得
#
print COM1 "0\n"; # アナログポート0
my $data0 = <COM1>
$data0 =~s/\0\n//;    # 後ろ\0\nを除去

print COM1 "1\n"; # アナログポート1
my $data1 = <COM1>
$data1 =~s/\0\n//;    # 後ろ\0\nを除去

print COM1 "2\n"; # アナログポート2
my $data2 = <COM1>
$data2 =~s/\0\n//;    # 後ろ\0\nを除去

print COM1 "3\n"; # アナログポート3
my $data3 = <COM1>
$data3 =~s/\0\n//;    # 後ろ\0\nを除去

close COM1 ;

my $lm35 =0 ;
my $s8100=0 ;
my $lm35f=1 ; # TEST
my $s8100f=1 ;# TEST

$lm35 =$data2/$data0*5.1/0.01 ;#  LM35DZの温度換算
$s8100=(1.908-$data3/$data0*5.1)/0.008-20 ; # S-8100Bの温度換算

#printf "%5.1f",$lm35  > $lm35f ; # 書式の指定 うまくいかなかった。
#printf "%5.1f",$s8100 > $s8100f; # 書式の指定 うまくいかなかった。

$lm35f  = round($lm35 , 1);  # 小数点以下1桁まで求める subroutine 使用
$s8100f = round($s8100, 1);  # 小数点以下1桁まで求める subroutine 使用






# ########################### 時刻とデータの印字(ファイルへの出力)
$tt=time();
($sec, $min, $hour, $mday, $mon, $year,
    $wday, $yday, $isdst) = localtime($tt);
$year=$year+1900;
$mon=$mon+1;

#open (LOGFILE,">>$file") or die "ERROR output file not open$!\n" ; # 出力ファイルをオープン
#print LOGFILE  $year,"/",$mon,"/",$mday,"   ",$hour,":",$min,":",$sec,"  ",$data0,$data1,$data2,$data3 ;

#close LOGFILE ;


# ############### ここからhtml出力へ

print "Content-type: text/html\n\n";
print <<EOM;


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
	<title>計測中の温度を表示</title>
</head>
<body>

計測中の温度<br>

$year/$mon/$mday   $hour:$min:$sec  $data0  $data1  $data2  $data3 

温度    <br>


<table>
	<tr>
		<td>LM35DZ</td>
		<td>$lm35f ℃</td>
	</tr>
	<tr>
		<td>S−8100B</td>
		<td>$s8100f ℃</td>
	</tr>
</table>

<a href="../test.html" target="MAIN">Test画面へ戻る</a>

</body>
</html>

EOM


# ######################  sub routine  ######################
# $num を四捨五入して小数点以下 $decimals桁にする

sub round {
  my ($num, $decimals) = @_;
  my ($format, $magic);
  $format = '%.' . $decimals . 'f';
  $magic = ($num > 0) ? 0.5 : -0.5;
  sprintf($format, int(($num * (10 ** $decimals)) + $magic) /
                   (10 ** $decimals));
}




ただし、/dev/cuad0 を使うので、ここでpermissionエラーがでた
apacheがnobodyユーザーで動いており、cgiの起動もnobodyユーザーで行われる
このため、シリアルポートディバイス/dev/cuad0 へのアクセスもnobodyが行うため、
エラーとなった。仕方がないので、
chmod 766 /dev/cuad0
とした。セキュリティ上もっと良い方法がないのだろうか?


とりあえず、ブラウザー経由で温度データの取り出しが可能になった

パソコンのことへ     HomePage     このページのトップ