本ページはここからpdf形式での閲覧・保存ができます。

岡野ラボ 手作り研究装置 10 page 1
金欠ラボの節約術! 手作り研究装置:シリーズ10 磁気・気圧・温湿度・光環境ロガー 早稲田大学 先進理工学部 電気・情報生命工学科 岡野俊行 (2014.4.3) 【背景と経緯】 岡野研では、前項目の刺激装置等を用いて、光や電気や磁気などの刺激を動物に与え、
動物の行動を観察しています。このような実験では、実験は無人の状態でマイコンによる
制御で行いますが、正しく装置が作動しているか、どのような条件で実験が行われている
のか、などを無人実験中に記録しておく必要があります。そのため、刺激装置とは独立に、
磁気などの環境を記録しています。そのような目的のために、PICマイコンを用いた磁気記
録装置を作製しました。多目的に利用できるよう、磁気環境だけでなく、気圧や光、ある
いは温度の情報も長期に渡って記録できるものにしました。なお、ラボには、MTI社製、交
流・直流磁界両用、フラックスゲート式3軸磁界測定器(FM-3600、約250万円)が2台あり、
厳密な磁界測定を必要とする実験にはこれらを使用しています。 PIの岡野は普段、電子工作やプログラミングを行うまとまった時間をとることができな
いので、本装置は主として、2013年末-2014年始にかけてのお休みに作製・プログラミング
しました。また、岡野は電気関係学科の所属ですが、専門は生命科学なので、電子工作に
ついては素人で、プロのエンジニアやプログラマからみると、改善点も多いと思います。
あくまで、中学生〜大学学部生の入門の参考のための紹介と理解してください。 【仕様・構成】 本装置では、前項目で使用した8ビットマイコンPIC16F627A(120円)の上位機種にあたる
PIC16F1938(150円)を用いました。PIC16F627Aと比べると、PIC16F1938の最大速度は1.6倍
(32MHz/20MHz)、EEPROMは2倍(256bytes/128bytes)、RAMは約4.5倍(1024bytes/224bytes)、
フラッシュメモリは16倍(16K/1Kbytes)です。にもかかわらず、値段は30円しか変わりませ
ん。たとえば、PIC16F627A よりも性能が劣る古い設計のチップPIC16F84Aが250円するなど、
PICマイコンは、値段と性能が一致しません。古いものは材料費がかさむのかもしれません。
今回は、C言語でのプログラミングを行うため、メモリ容量が大きく、かつマイコンチップ
自体が大きすぎない28ピンのものを選びました。 本装置の材料費全体からみると、マイコンチップに比べて、センサーモジュールの方が
はるかに高額です。配線ミス等でセンサーモジュールを壊さないよう、注意して作製する
必要があります。とりわけ、デジタルコンパスモジュールは高価で、2種類合わせて2,500
円になります。装置構成は回路図の通りです。各モジュール・パーツの説明は後述します。 動作する時刻を正確に制御するために、マイコンとは独立した専用の時計(リアルタイ
ムクロックモジュール;RTCモジュール)を搭載しています。RTCモジュールとPICの間は、
I2C (アイスクエアシー)という通信機能を利用してデータをやりとりします。この通信機
能を使って、磁気方位センサ、3軸方位センサ、カラーセンサ、気圧センサ、温湿度セン
サ、それぞれのモジュールとデータをやりとりしています。 測定したデータは、液晶ディスプレイ(LCD)に表示すると同時に、SDカードに記録してい
ます。ここでは、測定時以外には別の用途にロガーを使用できるよう汎用性を考えて、付
け外しのできるSDロガー(データ・テクノ社, DT-MCK2-XC)を使用しました。RS232Cイン
岡野ラボ 手作り研究装置 10 page 2
ターフェースを介して9,600bps (bits per sec)で通信しています。SDロガーは、FAT16と
FAT32のいずれかを切り替えられるようになっていますが、現在は、従来型FAT16のファイ
ルシステムを使用しています。この場合はSDHCに対応していないため、2G以下のサイズの
SDカードを使用します。 電源は、SDロガーに電源を供給するため、9VのACアダプタを使用しています。ACアダプ
タを使用しない場合や停電時は、予備電池(Ni-MH)より電力が供給されます。9Vの定電圧電
源は、そのままSDロガーに供給されるほか、2つの3端子レギュレータにより、順次5V, 3.3V
に下げて、PIC(5V)、液晶ディスプレイ(5V)、その他モジュール(3.3V)に供給されています。
プログラムの書き込み更新は、PICをソケットに挿入したままで行うISCPを利用しています。 【設計】 仕様と大まかな構成(マイコンやモジ
ュール)が決まったら、次に、PIC16F1938
の各ピンの機能をみながら、どのピンを
どの用途に使用するのかを決めました
(PIN 割り付け表を参照)。この際には、電
源ピンのほか(pin8, 19, 20), I2C 通信
(pin14, 15), UART/RS232C 通信
(pin17,18), ISCP(pin1,27,28)のように、
機能が固定されているピンを先に決め、
続いて、基板上にそれぞれのモジュール
を並べながら、ピンを割り付けました。
RA, RB, RC, RE の各入出力ポートは、互
いに大きな機能的な違いはありませんが、
多少の違いがあります。たとえば、RB ポ
ートには内部プルアップが装備されてい
るので、スイッチ入力に便利です。その
ため、SW1-SW4 の入力ピンは、できれば
RB ポートを使いたかったのですが、残念
ながら配置の関係で今回は RA ポートになりました。液晶ディスプレイは主に RB ポートに、
液晶ディスプレイのバックライトと LED の明るさ調節は PWM 制御が使用できる CCP1-CCP5
のうちから 13 ピン(CCP1)と 12 ピン(CCP2)をそれぞれ選んでいます。ちなみに、PIC16F1938
は 5 つの PWM を装備しているので、そのうち 3 つをフルカラーLED の RGB にそれぞれ接続
することで容易に様々な色をつくることが出来ます。 【パーツ】 PICマイコン16F1938: PICには、機能や値段の異なるラインナップがあり、そのうち中
位に位置する8bitマイコンチップが16Fシリーズです。その中では最も機能的に上位にあた
るのが16F193Xシリーズ(16F1933,1934,1936-1939)です。ピン数が28pinのうち最上位が16F 1938,40pinだと16F1939です。これらは、IOポート数(16F1938は最大25チャネルの入力、
24チャネルの出力、16F1939は最大36チャネルの入力、35チャネルの出力、)以外はほぼ同
一で、基本機能としてプログラム格納用のフラッシュメモリが16Kバイト、各種レジスタや
岡野ラボ 手作り研究装置 10 page 3
変数格納領域が1024バイト、電源を切っても消去されないEEPROMが256バイトとなっていま
す。その他に、5つのタイマ、5つのPWM/コンパレータ、2系統の通信機能などがあります。 動作クロックの周波数は、内部発信器の使用で31kHz〜32MHzまで幅広いクロック周波数
が使用できますが、本機では、内蔵発振器を8MHzで使用しています。外部発信器をつける
ための8ピンソケットを基板上に用意してあり、SG-8002DC(エプソントヨコム)であれば、
ソケットに挿入して使用できます。同様に、ソケット上にミニモジュールを作成すること
でRC発信器やセラロック発信器を取り付けられますが、使用していません。 その他の詳細は16F193Xの日本語版説明書を参照してください。説明書には、各内蔵
モジュールの状態を記憶・制御するためのレジスタのメモリアドレスやメモリバンク(メ
モリのブロック番号)、ビットごとの機能など詳細が書かれています。アセンブラ言語でプ
ログラムを作成する場合には、詳細情報が不可欠ですが、C言語でプログラムする場合は、
メモリのアドレスはPICごとのヘッダファイルに書かれているため、アドレスは意識するこ
となく、レジスタ名と機能だけを参照すればほとんど問題ありません。 液晶ディスプレイSD1602HUOB: 16文字x2行の液晶ディスプレイで、定番のSC1602等と
似た仕様で、バックライトがオレンジのものです。バックライトがグリーンのもの
(SD1602HULB)もあります。SC1602とは少しピン配置が違うようです。万一壊れた時やバ
ックライトの色を変えたいときに、スムーズに交換できるように、基板に直接つけること
はせず、液晶モニタと基板のそれぞれにピンヘッダおよびソケットを取り付けて、自由に
外せるようにしてあります。このようにしておくことで、液晶ディスプレイの下の部品の
取り付けも簡単です。バックライトのLEDの駆動電流(順方向電流)が最大40mAなので、その
90%の36mAを流すことを考え、バックライトのVfが3.8Vであることを考慮して[(5V - 3.8V) / 36mA = 約33Ω]、バックライトのアノードには33Ωの抵抗を接続しています。 リアルタイムクロックモジュール(RTC8564NB): 水晶発信器が内蔵されていて、正確
な時間を計測します。モジュール基板(8ピン)に、8ピンの連結ソケットが付属しています。
これをモジュールにハンダ付けをした後、ソケットを8ピンのICソケットにはめています。
今回は使用していませんが、アラーム機能もついています。 大気圧センサモジュール(STマイクロ社、LPS331AP): モジュール基板(8ピン)に、付
属の4ピンピンヘッダを取り付け、8ピンのICソケットに挿しています。モジュール上にあ
る青色発光ダイオードは、光センサの計測の妨げになるため、外しています。データは、
23ビットありますが、下位の8ビットは使用していません。上位の15ビットは1hPaと対応、
中位の4ビットから小数点以下第一位を算出しています。圧力センサの校正のため、温度セ
ンサも内蔵しているので、温度データも取り出すことができます。センサだけでなく、圧
力センサおよび温度センサからのデータを元に、大気圧を計算するマイコンが内蔵されて
おり、校正済みの圧力数値データを送信してくれます。 温湿度センサモジュール(Aosong G uangzhou E lectronics、AM2321):丸ピンICソケ
ット(4穴分)を2つ準備し、片方にAM2321の足を広げて差し込んでハンダ付けし、もう一方
を基板に取り付けて両者を連結しています。上位8ビットと下位8ビットの組み合わせで、
岡野ラボ 手作り研究装置 10 page 4
湿度と温度の情報をそれぞれ少数以下1位までで返してくれます。センサ自体はマイナス
温度に対応していますが、プログラムは対応していません。 カラーセンサ(浜松ホトニクス、S11059): 赤、緑、青、赤外の4つの成分に分けて光
の強度を測定します。10ピンですが、1,5,6,10の4つのピン以外の6本は何も接続されてい
ないので折りとって、秋月電子通商の0.5mmピッチIC(8ピン)変換基板を裏返しにしたもの
にハンダ付けし、6ピン連結ソケットにのせています。 デジタルコンパスモジュール(ハネウェル、HMC6352): 内蔵する3軸磁気センサからの
情報を元に、磁気ベクトルを水平面上に投影した際の方位ベクトルを計算し、磁気的北を0
度として時計回りの方位角を計算してくれるモジュールです。ストロベリーリナックス社
で加工されたものを使用しました。 3軸ディジタルコンパスモジュールHMC5883L: 内蔵する3軸磁気センサからの情報を出
力するモジュールです。ストロベリーリナックス社で加工されたものを使用しました。秋
月電子からは、同じモジュールを搭載し電源レギュレータを内蔵した上級品(3000円)があ
りますが、こちらの方が割安(735円,2014/1現在)なのでこちらを使用しています。ただし、
電源レギュレータを内蔵しておらず、GNDピンと電源ピンが対角方向に位置しているため、
ソケットの抜き差しの際に、方向を誤ると素子を破壊してしまいます。また、上述のHMC6532
と並べてデータを取り込む際には、基板に対する取り付け方向を揃えておかないと、方位
角がずれてしまいます。本装置では、東西南北の4方位レベルにおいて、Y軸方向が磁気的
な北となるよう取り付け方向を揃えてありますが、測定時に装置の方向をHMC6532での値が
0度になるよう水平に配置しても、3軸のx軸の値はゼロにはなりません。正確に揃えたい場
合は、プログラム中の変数(mag_offset)の定数部分を書き換えて、HMC6352の値に回転補正
を行ってください。(0.1度=1として、-1800〜+3600のように設定可) 2SC2120-Y: 上述のように、バックライトの駆動電流を36mAとしているので、PICのI/Oピ
ンの1ピンあたりの入出力電流は最大25mAを越えており、そのまま駆動することはできませ
ん。そのため、汎用のNPN型トランジスタを使用して、CCP1からのPWM信号を増幅していま
す。ここで使用する2SC2120-Yは、最大コレクタ電流(Icmax) が 800mA, 最大コレクタ-エ
ミッタ間電圧Vceoが30V, 最大エミッタ-ベース間電圧Veboが5V,電流増幅率hfeが160-320
で、5VシグナルによるLEDやリレーの駆動に適しています。今回、ベース-エミッタ間の電
流は、36mA/160=0.225 mA以上は必要です。一方, ベース-エミッタ間電圧は0.6Vであるた
め、ベースに入力する信号(CCP1の電圧)が5Vの時に流れる電流を0.225mA とするには、
(5V-0.6V)/0.225mA = 19.5kΩ以下の抵抗を接続しておく必要があり、今回は抵抗値を15k
Ωにしました。2SC1815GR/Y(hfe=100)も使えますが、その場合はベース抵抗を12kΩくらい
にした方がよいと思います。 温度センサLM335Z: ナショナルセミコンダクタ社製の半導体温度センサです。10mV/°K
で電圧を発生します。バイアス抵抗を介して発生電圧を取り出し、AN0ピンに入力してPIC
の内蔵A-D変換により温度の値を算出しています。ADJピンは使用していません。 岡野ラボ 手作り研究装置 10 page 5
ショットキーバリアダイオード1S4: 順方向の電圧降下が小さい(約0.3V)特長がありま
す。そのため、電池駆動でも電圧があまり低下しません。このダイオードがないと、AC100V
が接続されている際に、電池が充電されてしまい危険です。電源電圧はACアダプター使用
の場合約9Vですが、NiMHバッテリー(1.2V x 7本)だと、充電直後は9.5V程度で次第に電圧
が低下してゆきます。 LED:LEDは順方向電圧(Vf)が1.7-2Vの赤色のLEDを使用し、10mA程度を流しています。色は
どの色でも構いませんが、Vfが大きな青色や白色のLEDを明るく点灯したい場合は、LED照
明の項目を参考に抵抗値を小さくしてください。ここでは秋月電子の「パーツ袋詰め」に
付属の赤色LEDを使用しました。CCP2のPWM機能を使用して調光しています。 抵抗:RA 3-6に接続の抵抗10KΩはSWが開いているときにHigh(+5V)にするためのプルアッ
プ用です。電圧・温度の計測に関わる抵抗は高精度の金属皮膜抵抗を使用しています。 コンデンサ:47μF以外のコンデンサは全て積層セラミックコンデンサです。 Vddに接続されている47μFと0.1μFのコンデンサは、それぞれ電源を安定化させるためと
ノイズを除去するためのものです。特に後者は、PICの電源ピンの近くに配置することが望
まれるため、PICの下側の28pinソケットの隙間に配置しています。 スイッチ:基板上の5つのSWはタクトスイッチを使用しています。SW0はマイコンをリセッ
トします。SW1-4はRA3-6に入力します。 電池:ケース内の基板下には予備電池電源として、単4のNi-MH電池が7本(3本+4本)入って
います。7本が直列となるよう基板のバッテリーA,Bにつなぎます。 D-sub9pinソケット:コネクタ(メス)をシェルに入れてSDロガー背面のRS232C端子に接続
します。 三端子レギュレータ:電源電圧を安定化させるために使用しています。7805は5V最大1A, NJU7223F33は3.3Vで最大500mAまでの余裕があります。7805は立てて取り付けると液晶ディ
スプレイとぶつかってしまうので、足を長めにとりつけて寝かせています。NJU7223F33は
頭が高すぎてアクリルケースとぶつかってしまうので、上部の放熱器取り付け部分をカッ
トしています。 【作り方:パーツの取り付け】 回路図どおりになるよう基板配線図や写真をみて配線します。トランジスタ、ダイオー
ド、LED、電解コンデンサは極性があるので注意してください。ピンク色はジャンパー線(ま
たは0Ω抵抗器)です。基板は、両面ホールスルーではなく片面のものを使用します。基板
の右側のモジュールが密集している場所は、I2Cのバス(SDA、SCL)と3.3Vの電源、GND線
が交錯しているので、ショートしないよう注意が必要です。また、取り付け位置を間違え
ると、モジュール同士がぶつかるのでその点も注意が必要です。基板中央のLEDの下のソケ
岡野ラボ 手作り研究装置 10 page 6
ットは、外部クロックを使用する際にクリスタルオシレータをつけるためのもので、プロ
グラムを変更しない限り使わないので、配線しなくても構いません。 基板上面写真: ICSP の書き込みは左側L型ピンヘッダに pickit3 を差し込んで行います。ピンヘッダは
斜めに折り曲げて、アクリルケースに入れたまま書き込みできるようにしました。 I
C
S
P
基板裏面: 1号機なので、試行錯誤の部分は痛々しい。 岡野ラボ 手作り研究装置 10 page 7
基板配線図:部品取り付け面からみた図(上)および配線面からみた図(下) +9V
NiMH Battery
+ – + –
A A B B
GND
RS232C
5 2 3 7 8
SD logger
1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
C1
3
–
J6
R 33
1S4
J5
SD1602HUOB LCD module
14 13 12 11
6
5
4
3
J3
2
1
16 15
+ –
2SC2120Y
E
28
PIC16F1938
–
J1.1
J2
6
–
AM
2321 +
SDA
R 1.2K
R 3.6K
8
R 2.4K
LM335Z
3
R 10K
C 0.1
5
5
4
2
+
5
J6
R 2.4K
8
4
4
7
8
J3
–
3
2
J2
1
+
–
1
HMC
5883L
6
S11059
ColSens
SG
8002
C 0.1
C 0.1
R 330
1
C 0.1
LPS
331AP
SCL
SCL
–
+
8
3
C 0.1
C 0.1 +
+
C 0.1
+
SCL
NJU7223F33
J1.2
+C 47–
RTC
8564NB
SCL
14
1
5
SDA +
1 2
R 15K
C 0.1
4
B
SDA
J4 J5
1
C
15
+ –
J4
R 2.4K
R 2.4K
2
R 3.9K
R 3.9K
1
7805
C1
ADM3202AN
おもて
1
2
3
4
5
6
7
8 J1.1
VPP 9
Vdd 0 +
Vss 1 –
DAT 2
CLK 3
4
5
6
7
8
9
J1.2
0
1
2
3
4
5
6
7
SCL
4
1
SDA
SW0
SW1
SW2
R 10K
SW4
SW3
R 10K
R 10K
+
3
HMC
6532
R 10K
SDA
+4
5
2
–1
8
+
NiMH Battery
– + – +
B B A A
RS232C
8 7 3 2 5
GND
+9V
SD logger
6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1
SD1602HUOB LCD module
RTC
8564NB
6
3
8
C 0.1
J3
R 2.4K
R 2.4K
うら
SDA
SDA
SCL
SCL
AM
+ 2321
SDA
5
4
4
5
2
– +
3
4
5
6
C1
3
11 12 13 14
E
– +
J5 J4
PIC16F1938 C 0.1
–
14
1
C 0.1
SCL
J2
J1.1
– C 47
R 330
–
3
2
J2
5
C
–
C 0.1 NJU7223F33
+
+ C 0.1
LPS
331AP
1
J3
B
–
C 0.1
15 16
HMC
5883L
4
+
6
7
SCL
+
R 1.2K
R 3.6K
8
5
SG
8002
S11059
ColSens
8
1
1
–
4
6J
R 2.4K
1
1
SDA
4
3
2
1–
2
3
5
HMC
6532
SW4
8
SW3
R 10K
R 10K
+
SW2
R 10K
SW1
SW0
R 10K
+
R 10K
4
R 3.9K
1
R 15K
C 0.1
7805
ADM3202AN
C 0.1
2
1S4
J5
C1
1
J6
R 33
J4
1
2
3
4
5
6
7
J1.1
8
9
0
– 1
2
3
4
5
6
7
8
9
2.1J
0
1
2
3
4
5
6
7
R 2.4K
–
VPP
Vdd
Vss
DAT
CLK
岡野ラボ 手作り研究装置 10 page 8
回路図: Experimental condition logger Ver.1.0
5V 1A
Regulator
7805
LED1
SW0
PIC16F1938
SD1602
HUOB
LCD
SW1-4
ADM3202AN
RS232C
LM
I C
335Z
Realtime
Magneto
Color
Humidity
Pressure
Magneto
3.3V 500mA
Clock module
Sensor
Sensor
Sensor
Sensor
Sensor
Regulator
RTC8564NB
HMC5883L
S11059
AM2321
LPS331
HMC6532
NJU7223F33
0xA2,A3
0x3C,3D
0x54,55
0xB8,B9
0xBA,BB
0x42,43
Ver.1.0 by Dr. Toshiyuki Okano
(WASEDA Univ., Tokyo, JAPAN; JAN, 2014)
【ケースへの収納】 ケースは磁気をシールドしないよう金属製は避ける必要があります。ここでは、ラボに
余っていたプラスチック製のピペットチップ立てを利用したチップケースバージョン(装
置外観参照)と、ドン・キホーテで購入した市販のアクリル多目的ボックス(M1609, フォー
リビ社)を使用したバージョンの写真を掲載します。チップケースバージョンはかっこいい
のですが、フタに色がついており、色の計測が正しく行われないため、光計測用にアクリ
ルケースに移しました。どちらのケースも基板のサイズがケースの内法とぴったり一致し
ているので、スペーサをつけた基板をなかに置いているだけで、固定はしていません。 チップケースバージョン アクリルケースバージョン 節分にはこんな使い方も? Vcc
(+9V, 1A)
3,OUT
+
CCP2/RC1
2.4KΩ
ICSP
1μF
20 Vdd
10KΩ
MCLR/Vpp
27 ICSP/CLK
28
ICSP/DAT
8,19
RB5
RB4
RB3
RB2
RB1
RB0
0.1μF
RC5
10KΩx4
5,6,7,10
0.1μF
2
0.1μF
0.1μF
R2
3.6KΩ
13 DB6
24
12 DB5
23
11 DB4
22
6
21
5
16
4
2
15
Vdd A
1.2KΩ
ENBL
R/W
Vo
3
RS
DACOUT/RA2 4
K
Vss
1
16
2.4KΩ
2.4KΩ
10
17
9
18
Vdd(+5V)
3
4
TX/RC6
2
5
15
CCP1/RC2
2SC2120Y
AN0/RA0
3
15KΩ
13
RX/RC7
2.4KΩ
6
14 DB7
25
16
T2
8
1
RA3-6
26
Bat 1.2Vx7
8.4-9.6V
1μF
2,GND
47μF
33Ω
1
Vss
7
0.1μF
12 330Ω
SD logger
DT-MCK2-XC
1S4
1,IN
2
2
AN1/RA1
Vdd(+5V)
3.9KΩ
14
3
11
0.1μF
RC0
SDA/RC4
3.9KΩ
SCL
SCL/RC3
0.1μF
15
SDA
8
6
5
3
2
Piezo SP
PKM17EPP
7
6
6
10
4
2
2
3
2,IN
1,OUT
4
1
4
4
8
5
1
3
1
8
1,4,5
0.1μF
3,GND
岡野ラボ 手作り研究装置 10 page 9
【使用マニュアル】 ボタンの説明:基板上の5つのタクトスイッチ(左からSW0-4:色は抵抗のカラーコードに
対応)を使用して操作します。SW0はリセットスイッチなので、スタートからやり直したい
とき以外は押さないようにします。SW1は入力、SW2はカウントアップ、SW3はカウントダウ
ン、SW4はオプション操作に使用します。カウントアップとカウントダウンは押し続けると
続けてカウントします。設定の途中で間違えた場合は、一つ戻ることはできないので、SW0
を押してスタートからやり直します。 ファイル名の決定:はじめにSDカードに記録するファイルの名称を決定します。ファイ
ル名は、英文字2文字+数字4桁からなります。頭の1文字から順にA-Zの中から選ぶこと
ができます。SW2とSW3で選択したらSW1を押して決定します。2文字目も同じようにして決
定します。続いて、4桁の初期番号を決定します。カウントアップ、カウントダウンの際に
SW4を同時に押すとカウントする速度が早くなります。 測定中は、一定回数のデータを測定するとファイル名が更新されて新しいファイルを自
動作成します。たとえば、はじめのファイルがAA0000だと, AA0001が次のファイルになり
ます。1つのファイルに書き込まれるデータは、プログラムの冒頭(120-130行)で決めてあ
り、現行では8640にしています。この場合、10秒間隔で記録すると24時間ごとに新しいフ
ァイルが作られることになります。ただし、記録しはじめてはじめに午前0時をまたぐ際に
は、時間のきりを良くするために、新しいファイルが作られるようにしています。つまり、
夜の9時すぎから測定を開始すると、開始から23:59:50までがはじめのファイルになり、0
時からは次のファイルに記録されます。また、停電等により電源の電圧が低下しバックア
ップ電源に切り替わった場合には、データの保存性を上げるために、初期には4時間ごと、
さらに電圧が下がると1時間ごとにファイルを更新するようになっています。 日時の入力:データを保存するファイルの名称が決まったら、次に日時を入力します。こ
れも、SW1が決定、SW2,SW3がアップダウンとなっていて、年号->月日->時刻の順に入力し
ます。測定開始するまで、時刻のカウントははじまりません。また、2100年以降には対応
していません。 測定間隔の決定: 測定間隔は、SW1-3を使い、10秒、1分、10分のいずれかより選んでく
ださい。測定間隔は、前回の設定を機械は覚えていないので、必ず選んでください。 バックライトの設定:測定中にバックライトを点灯するかどうかを選ぶことができます。
ONにすると、測定中にバックライトと赤色LEDが点灯します。待機中はバックライトを減光
します。バックライトの明るさとコントラストは、周囲の明るさによって変化します。バ
ックライトONの状態では、各測定の開始直前に一瞬バックライトとLEDが消灯します。これ
は、周囲の光環境を正確に測定するために、光センサに迷光が入らないようにするためで
す。OFFにすると測定開始直後の1回目を除き、待機中も測定中もバックライトは点灯しま
せん。なお、バックライトのON/OFF設定に関わらず、電源電圧が8.95Vを切った段階でバッ
クライトは消灯します。LEDはバックライトがOFFの場合は消灯、ONの場合は最低の明るさ
に固定されます。バッテリー電圧が8Vを切ると、Low Batteryの表示が出ます。8V以下では、
SDロガーの仕様によりSDカードへの記録はできなくなります。 岡野ラボ 手作り研究装置 10 page 10
SDカードのセット:SDカードへ記録する場合は、SDカードロガーの電源およびRS232Cケ
ーブルを接続し、電源スイッチを入れておきます。カードは、SDHCは使えないので、2GB
の低容量のものを用意しておきます。SDロガーの後ろのディップスイッチは3番のみON(下
側)でそれ以外はOFF(上側)にセットしておきます。 測定開始:SW4を押すと、押したタイミングが0秒として、表示されている時刻から時計が
スタートします。10分間隔の測定にした場合は、まず1回目の測定を行い、次の0, 10, 20, 30, 40, 50分のいずれかの時点から10分間隔で測定を行います。 SDカードのデータの取り出しと測定終了:測定中にデータを回収したい場合は、待機中
にロガーの電源を一端OFFにし、カードを抜いて内容を別のPCにコピーした後、ロガーに戻
せば、その後のデータは記録できます。つまり、カードを抜いている間は記録できません
が、同じファイルに追加で書き込まれます。ただし、データを追加書き込み中のファイル
をSDカードから消去してしまうと翌日からしか記録されません。また、万一、午前0時の
1度の新しいファイルが作られるタイミングをまたいでカードを抜き差しすると、その翌
日のファイル作成時までデータが記録されないので要注意です。 SDロガーは、電源をOFFにすると必ずファイルを一度クローズするようになっています。
測定中に、リセットボタンを押すと、次のファイルが正しく作成されず、次の測定がうま
く行かない場合があるので注意が必要です。測定中にリセットが必要な場合は、測定待機
中にロガーの電源をOFFにしてから行ってください。 記録されたデータ:ファイルをMicrosoft Excelでひらいたところを下に示します。測定
間隔10秒で測定した際の最初の9回の測定データのみをここでは表示しています。実際には
8640個のデータがあります。測定開始から10秒後から30秒にかけて磁気の方向が大きく変
わっているのは装置を回転させたためです。磁気ベクトルの単位はμT(マイクロテスラ)
で記録しています。MacのExcel2011では、そのままtxtを開くことはできますが、グラフを
作成しようとするとエラーになることがあります。データをコピーして別のシートにペー
ストすると問題なくグラフを作成することができます。 Tips1: SDカードに書き込むべきファイルがあるかどうかの確認は、装置本体側で行って
いません。なので、測定開始時・ファイル作成時にロガーの電源がOFFになっていると、フ
ァイルが作成されず、次のファイル作成時まで全く記録されないので注意が必要です。 Tips2: データをSDカードに記録しない場合は、ロガーを接続する必要はありません。接
続して電源をOFFにしていても問題ありません。 岡野ラボ 手作り研究装置 10 page 11
Tips3:ファイル番号は、ファイル名の頭文字やSDカードの残量とは関係なく、9999番目の
ファイルへの記録が終了すると、プログラムを終了します。 Tips4:ファイル名は、一度リセットすると、次回はこれまでに作製されたファイルの次の
番号をデフォルトとして表示するようになっています。測定を中断して、再度測定を開始
する場合は、SW1を続けておせば大丈夫です。また、測定開始日時も記憶しています。 ファイルのサイズと記録できるデータ量:1観測点あたり 約100バイトを使用するので、
10秒間隔で記録した場合、24時間ごとに1Mbytes弱のファイルが作成されます。SDロガーで
は512個のファイルまでしか作成できないので、2GのSDカード1枚あたり、500MByte程度ま
で記録されます。その場合でも、512日分のデータを1枚のカードに記録できます。 【プログラミングとプログラムの書き込み】 開発環境:Microchip社の専用ソフトMPLAB-X IDE(無料)を使用しました。 書き込み装置:Pickit3がおすすめです。ICSPという仕組みを利用すると、ICチップを基
板に取り付けたまま、プログラムの書き込みと書き換えができます。ICSPを使用するため
に、基板の隅に6pinのL型コネクタを付けてあります。 プログラム: プログラムは、統合開発環境MPLAB-X for Macを使用しMicrochip社が無料で
公開しているHitech-PICC(Lite)で記述しています。 SDロガーへの出力の確認:RS232Cへの通信シグナルが正しく出力されないと、SDロガー
への書き込みがうまくゆきません。通信に関わる部分はシリアル-USB変換ケーブルを利用
してPCでモニタしながら作りました。Windowsの場合はハイパーターミナルが使えるようで
すが、Mac(Macbook Air)のため、手持ちのシリアル-USB変換ケーブル(UC-SGT, Elecom)を
繋いで、ターミナル(Terminal.app)でモニタしまし
た。Elecomよりドライバが提供されていないため、
Prolific社のドライバをインストールした後、
Xcodeをインストールしてドライバを書き換える必
要があり少々面倒です。方法の詳細は、Dr.RayCobb
氏とs15silvia氏の記事を参考にしました。ただし、
Dr.RayCobb氏の方法だとInfo.plistの編集がうま
くできなかったので、その部分はrootユーザアカウ
ントでログインして編集しました。 【今後の課題】 ハードウェアに関して:今回使用したSDカードロガーは、1台が23,000円と割高なので、
たとえマイクロテクニカ社のSDカードモジュール(リアルタイムクロック内蔵SD対応シリ
アル簡単アクセスボードMSC-MOD60, 5,820円)を使用すると、安くできると思います。そ
の場合は、一部プログラムの変更が必要です。 岡野ラボ 手作り研究装置 10 page 12
今回のハードウェアでは、せっかく各モジュールが低電力仕様になっているのに、液晶
ディスプレイとSDロガーのために、総電力の半分近くをレギュレータで損失しているので、
電力的にちょっと残念です。上記のSDカードアクセス用のMSC-MOD60ボードは3.3V仕様で、
PICマイコンおよびリアルタイムクロックモジュールは3.3Vで動くことから、LCDモジュー
ルをSC1602BBWB-XA-LB-Gのように3.3V仕様のものに変更すれば、低電圧の電源のみで使え
るように設計変更できます。 また、停電しているかどうかの判断に電圧の値を利用しているので、充電池が満タンの
時には、電池を節約してくれません。ACアダプタからの入力にも1S4ダイオードを入れてお
き、その手前の電圧を、入力ポートで検出することで、アダプタからの電源がなくなった
ことを直接検知するようにしてもよかったと思います。 ソフトウェアに関して:関数名等もあまり統一せずに適当にしたので、随所におかしな
部分があると思います。日付や時刻情報の管理は、構造体や共用体をもっと使いこなせれ
ば遥かにスマートなプログラムになりそうですが、とりあえず動くことが目的として作成
したのでご容赦ください。画面上に日時が表示されて、カーソル移動で変更できると本当
は便利ですが、スイッチの数が少ないため、日付の入力も一手間かかります。プログラム
メモリはまだ余裕があるので、たとえば連続的に磁場だけ、あるいは気圧だけを測定する
モードなどあっても便利な気がします。今回の装置では、全てのセンサーの測定感度は固
定にしましたが、実際には、光センサーや磁気センサーは感度を変えることが可能なので、
必要に応じて、プログラムを書き加えて感度設定を変えることが可能です。たとえば、変
数を16倍するような演算には本来、ビットシフト命令を使うべきですが、本プログラムは
実行速度を要求しないので、読み易さを優先してなるべくかけ算を使うようにしました。 装置全体に関して:今回は磁気の記録が目的でしたが、周囲の電流等の影響を受けるの
か、磁気センサが思ったより実際の地磁気の方位とずれがあるようです。温度は、
LM335Z,AM2321,LPS331の3つのセンサーでの値を記録していますが、3つがほぼ同じ数値を
出す場合とLM335Zのみ1.7-2度程度離れた値を出す場合があるようです。これが、センサー
の性能によるものか、基板上の配置によるものかは、わかりませんが、装置にあたる風に
よっても値のばらつきが変化するので、基板上での熱の伝導や放熱の具合が影響している
ようです。一方、あくまで印象ですが、光センサーによる光分布と大気圧はある程度正確
に測定できている印象です。温度センサーは氷点下も測定できますが、結露するとSDロガ
ー他のモジュールに悪影響がでると考えられるので、室温で使用することを前提としてプ
ログラミングしました。なので、マイナスの温度は、正しく表示・記録はされません。 【参考資料】 開発環境とプログラミング方法の解説は後閑哲也氏や鈴木哲哉氏の各種の本やホームペ
ージ(picfun.com, きむ茶工房氏、AirVariable氏、エレキジャック氏、PICで遊ぶ電子工
作ページ、etc.)が勉強になります。Microchip社MPLABの使用説明書(和文あり)、マイ
コンチップごとの使用説明書が参考になります。16F193Xの説明書(pdf) は日本語版があ
り便利です。C言語に関しては、中尾真治著「C言語ではじめるPICマイコン―フリーのCコ
ンパイラではじめよう」オーム社を参考にしました。その他、Webで公開されているものを
岡野ラボ 手作り研究装置 10 page 13
一部参考にしましたが、転載不可のものや、独自性の高いコードはコピーしていないつも
りです。16Kバイトのメモリのうち、10Kバイト弱を使用しています。 【PI のつぶやき】 電子工作のはじまりは小学生のころ。父親に大阪の日本橋に連れて行かれ、トランスや
ダイオードを買い込んだ。父親が電源装置を作っているのを眺めていたら、おもしろがっ
ていると思われたようで、「工作でもやってみるか」と。間もなく NHK 出版のホビーテク
ニックシリーズの「電子オモチャの作り方」という本を買ってきた。初めに作ったのは確
か、無安定マルチ回路。2SC458,TLR103,あとはコンデンサと抵抗,,,材料はこんなところだ
ったような。シリコンハウス共立もまだ無く、恵比須町出口横の東海電気という店で購入
した。その後は、同出版の「デジタル IC のいたずら」等を見ながらの電子工作と、定番の
電子ブロック。しばらく間があいて、学部生のころには、大学の情報センターで
Fortran/unix を使ってみたり、どこからか手に入れた Lattice C をかじってはみたものの、
当時は NEC 系の N88BASIC が全盛で、他の言語は使いたくても入手できず。はじめて手に入
れた PC は展示品処分の PC6001mkII。テレビにつないで使うというマイコンに毛が生えた
ような代物。それでも、N-BASIC と Z80 アセンブラを組み合わせ、8255AP-5 インターフェ
ースボードを作成してから装置を動かしたり、N-BASIC で Z80 アセンブラのコンパイラを
作ったりして遊んだ。学部時代の経験が大学院時代には多少役に立ち、NEC の PC9801 から
GPIB インターフェースで島津の MPS2000 型分光器と通信、8255AP-5 インターフェースボー
ドから電磁シャッターを制御、はじめて趣味以外に役立つ。生命系大学院に入ってからは、
めっきり情報系のニーズもなくなり、忙しさもあってプログラミングの機会は消滅。mac
が、bsd unix ベースの osx になってから、フリー言語を使ってみたいとは思うものの、時
間的余裕がなく手をつけられず。研究で動物行動の解析を始めてから、必要に迫られて行
動記録データを perl で周期解析するプログラムを作成したくらい。間があいて、昨年久し
ぶりに、懐かしいアセンブラを PIC で使えることを知り、動物実験の装置を作製で PIC デ
ビュー(前項目)。今回、PIC は 2 作目で、はじめて C 言語を使用しました。 【ソースコード】 約 2000 行あります。大した内容ではないのに大げさですが、一応コピーライトに関して
は、BSD ライセンスに準じたいと考えています。営利・非営利を問わず、一定の条件の下
にコピー・2次利用・改変・頒布等は自由とします。 /*
* File:
MG_TMP_CLK_SD.c
* Copyright © 2014, Toshiyuki Okano, Ph.D.
* All rights reserved.
* Department of Electrical Engineering and Bioscience,
* Graduate School of Advanced Science and Engineering,
* TWIns, WASEDA University, Japan
*
* Created on 2013/12/30, 13:09
*/
#include <htc.h>
#include <pic.h>
#include "pic16f1938.h"
#define _XTAL_FREQ 8000000
//I/O port list
#define lcd_E RB1
#define lcd_RW RB0
#define lcd_RS RC5
岡野ラボ 手作り研究装置 10 page 14
#define PORT_B PORTB
#define SW1 RA3
#define SW2 RA4
#define SW3 RA5
#define SW4 RA6
#define SP RC0
#define lcd_backlight CCPR1L
#define LED CCPR2L
static void pic_init(void);
static void lcd_send4(unsigned char cmd1);
static void lcd_cmd(unsigned char);
static void lcd_data(unsigned char);
static void lcd_init(void);
static void lcd_locate(unsigned char x, unsigned char y);
static void lcd_2chars(unsigned char x, unsigned char y, unsigned char z);
static void lcd_print( const char *c );
static void lcd_clr(void);
static void lcd_contrast(unsigned char);
void i2c_enable(void);
void i2c_disable(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_wait(void);
void i2c_write(const unsigned char data);
unsigned char i2c_read(const char ack);
static void send_RS232C_char(unsigned char i);
static void send_RS232C_CR(void);
static void send_RS232C_LF(void);
static void send_RS232C_TAB(void);
static void send_RS232C_word(const char *c);
void __delay_1s(void);
static unsigned int temp_LM335Z_read(void);
static void temphumid_chdata4chars(unsigned int data, unsigned char c[]);
static void temp_LM335Z_print(unsigned int temp);
static void buz(void);
static void buz_low(void);
static unsigned int mag_read(void);
static void mag_chdata5chars(unsigned int data, unsigned char c[]);
static void mag_print(unsigned int mag);
static void mag3D_init(void);
static void mag3D_pointx(void);
static void mag3D_pointy(void);
static void mag3D_pointz(void);
static unsigned int mag3D_read(void);
static void mag3D_calc_and_chdata4chars(unsigned int data, unsigned char c[]);
static void mag3D_print(unsigned int magx,unsigned int magy,unsigned int magz);
static unsigned char ch_bcd(unsigned char x);
static void rtc_init(void);
static void chdata2chars(char data, unsigned char c[]);
static void push_wait(void);
static void datetime_setting(void);
static char rtc_read(unsigned char);
static unsigned int voltage_read(void);
static void voltage_check(unsigned int vdd_voltage);
static void chdata4chars1(unsigned int data, unsigned char c[]);
static void voltage_print(unsigned int vdd);
static void humid_am2321_read(void);
static void humid_am2321_print(void);
static void chdata5chars(unsigned int data, unsigned char c[]);
岡野ラボ 手作り研究装置 10 page 15
static void color_read(void);
static void color_print(void);
static void chdata4chars2(unsigned int data, unsigned char c[]);
static void lps331_write(unsigned char register_address, unsigned char command);
static unsigned char lps331_read(unsigned char register_address);
static void pressure_read(void);
static void sd_write_header(void);
// static void lcd_printval(unsigned int value);
// static void look(unsigned int value);
// grobal variables
unsigned char year, month, day, hour, min, sec = 0;
// unsigned char cent, week;
unsigned char sec_bcd, min_bcd, hour_bcd, day_bcd, week_bcd, cent_bcd, month_bcd, year_bcd;
unsigned char sec_upper, min_upper, hour_upper, day_upper, week_upper, month_upper, year_upper;
unsigned char sec_lower, min_lower, hour_lower, day_lower, week_lower, month_lower, year_lower;
unsigned char name1, name2, backlight = 1; // header of filename, backlight on/off
unsigned int filenumber, endnum; // file number, number of data end;
unsigned int vdd_voltage, light_intensity = 128;
unsigned int vdd_threshold_high = 8950; // higher threshold
unsigned int vdd_threshold_low = 8000;
// lower threshold
unsigned char pushflag, interval;
static unsigned char buf[16];
unsigned int humid_int, temp2_int;
unsigned char red_upper, red_lower, green_upper, green_lower;
unsigned char blue_upper, blue_lower, ir_upper, ir_lower;
unsigned int red_int, green_int, blue_int, ir_int;
signed int mag_offset = 0; // for adjustment with 3D compass module
// Data number per file:
interval
10sec.
1min.
10min.
// unsigned int data_endnumber =
10; // for test;
// unsigned int data_endnumber =
60; // for 10min or
1hr or
10hr
// unsigned int data_endnumber =
72; // for 12min or 72min or
12hr
// unsigned int data_endnumber = 360; // for
1hr or
6hr or
60hr
// unsigned int data_endnumber = 1440; // for
4hr or
1day or 10days
// unsigned int data_endnumber = 4320; // for 12hr or 3days or 30days
unsigned int data_endnumber = 8640; // for 1days or 6days or 60days
// unsigned int data_endnumber = 25920; // for 3days or 18days or 180days
// unsigned int data_endnumber = 43200;// for 5days or 30days or 300days
__CONFIG(FOSC_INTOSC & WDTE_OFF & PWRTE_ON & MCLRE_OFF & CP_OFF &
BOREN_ON & CLKOUTEN_OFF & WRT_OFF & PLLEN_OFF & IESO_OFF &
STVREN_ON & LVP_OFF & FCMEN_ON);
// EEPROM for 2014/1/1, 0:00:00, year, month, day, hour, min, null, name1, name2
__EEPROM_DATA(14,1,1,0,0,0,'A','A');
// EEPROM for nextfilenum_upper, nextfilenum_lower
__EEPROM_DATA(0,0,0,0,0,0,0,0);
// ==================== PIC initialization ===========================
static void pic_init(void)
{
OSCCON = 0b01110010;
// INTERNAL 8MHz x 1
APFCON = 0X00;
CM1CON0 = 0x00;
CM2CON0 = 0x00;
TRISA = 0b01111111; //0x43; RA0, RA1 & RA3-6 for inputs
TRISB = 0b11000000; //0xC0; RB6 & RB7 for inputs
TRISC = 0b11011000; //0xD8; RC0-2,RC5 for outputs
TRISE = 0b000; //0x06; RE3 for outputs
ANSELA = 0b00000111; // RA0 & RA1 for analog inputs
ANSELB = 0b00000001; // RB for digital io
PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
FVRCON = 0b10000011; //Vref = 4.096 V
T2CON = 0;
PR2 = 0xFF;
TMR2 = 0;
DACCON0 = 0b11100000;
TXSTA = 0b00100100 ;
// Asynchronous 8bit non-parity, SYNC = 0; BRGH = 1;
岡野ラボ 手作り研究装置 10 page 16
RCSTA = 0b10010000 ;
SPBRG = 51 ;
CCP1CON = 0x0C;
PWM1CON = 0x80;
CCP1AS = 1;
CCP2SEL = 0;
CCP2CON = 0x0C;
PWM2CON = 0x80;
CCP2AS = 1;
CCPTMRS0 = 0;
TMR2ON = 1;
LED = 255;
//
// high speed BR=9600
// CCP1 for backlight of LCD
// CCP2 assigned at RC1
// CCP2 for LED
// PWM start
__delay_ms(100);
}
// =============== send 4bit-data to LCD module ======================
static void lcd_send4(unsigned char cmd1)
{
lcd_RS = 0;
cmd1 <<= 2;
PORT_B = (PORT_B & 0xC3) | cmd1;
lcd_E = 1;
lcd_E = 0;
NOP();
NOP();
}
// ================ send 1byte-command to LCD module =================
static void lcd_cmd(unsigned char cmd1)
{
// write upper 4bits
lcd_RS = 0;
unsigned char cmd2 = cmd1;
cmd2 &= 0xF0;
cmd2 >>= 2;
PORT_B = (PORT_B & 0xC3) | cmd2;
cmd2 = PORT_B;
lcd_E = 1;
// write upper 4bits
NOP();
NOP();
lcd_E = 0;
NOP();
NOP();
// write lower 4bits
cmd2 = cmd1 & 0x0F;
cmd2 <<= 2;
PORT_B = (PORT_B & 0xC3) | cmd2;
cmd2 = PORT_B;
lcd_E = 1;
NOP();
NOP();
lcd_E = 0;
__delay_ms(7);
}
// =================== send 1byte-data to LCD ========================
static void lcd_data(unsigned char cmd1)
{
lcd_RS = 1;
unsigned char cmd2 = cmd1;
cmd2 &= 0xF0;
cmd2 >>= 2;
PORT_B = (PORT_B & 0xC3) | cmd2;
cmd2 = PORT_B;
lcd_E = 1;
// write upper 4bits
NOP();
NOP();
lcd_E = 0;
NOP();
NOP();
岡野ラボ 手作り研究装置 10 page 17
cmd2 = cmd1 & 0x0F;
cmd2 <<= 2;
PORT_B = (PORT_B & 0xC3) | cmd2;
cmd2 = PORT_B;
lcd_E = 1;
// write lower 4bits
NOP();
NOP();
lcd_E = 0;
__delay_ms(4);
}
// =================== LCD contrast setting ==========================
static void lcd_contrast(unsigned char x)
{
if (x>32){
x = 32;
}
DACCON1 = 32 - x; // LCD contrast High 0-31 Low
}
// ==================== LCD initialization ===========================
/*
*
LCD
*
RB2:lcd_DB4
*
RB3:lcd_DB5
*
RB4:lcd_DB6
*
RB5:lcd_DB7
*
RC5:lcd_RS
*
RB1:lcd_E
*
RB0:lcd_R/W
*
DACOUT/RA2:lcd_Vo
*
CCP1/RC2:lcd_K
*/
static void lcd_init(void)
{
lcd_RW = 0;
lcd_RS = 0;
lcd_E = 0;
__delay_ms(70);
lcd_send4(0x03);
__delay_ms(30);
lcd_send4(0x03);
__delay_ms(13);
lcd_send4(0x03);
__delay_ms(3);
lcd_send4(0x02);
__delay_ms(2);
// 4bit mode
lcd_cmd(0x28);
__delay_ms(3);
lcd_cmd(0x08);
lcd_cmd(0x01);
lcd_cmd(0x0C);
lcd_cmd(0x06);
lcd_cmd(0x01);
__delay_ms(100);
if (backlight) {
lcd_backlight = 80;// LCD backlight 0-255
lcd_contrast(20);
}
}
// ==================== location function ============================
static void lcd_locate(unsigned char x, unsigned char y)
{
unsigned char cmd1;
cmd1 = 3 - x;
cmd1 *= 0x40;
cmd1 += y;
cmd1 --;
cmd1 |= 0x80;
岡野ラボ 手作り研究装置 10 page 18
lcd_cmd(cmd1);
}
// ==================== lcd print 2 char number ======================
static void lcd_2chars(unsigned char x, unsigned char y, unsigned char z)
{
lcd_locate(x,y);
chdata2chars(z, buf);
lcd_print(buf);
lcd_locate(x,y + 1);
}
// ======================= word outputs ==============================
static void lcd_print(const char *c)
{
while(*c != 0){
lcd_data(*c);
c ++;
}
}
// ======================== LCD clear ================================
static void lcd_clr(void)
{
lcd_cmd(1);
__delay_ms(3);
}
// ================== I2C interface commands =========================
// ====================== I2C initialize =============================
void i2c_enable(void)
{
SSPSTAT = 0b10000000;
// I2C 100kHz
SSPADD = 79;
// I2C Baud rate, 4MHz/((SSPADD + 1)*4) = 100kHz
SSPCON1 = 0b00101000;
// I2C, Master Mode
}
// ======================== I2C disable ==============================
void i2c_disable(void)
{
SSPCON1 = 0b00001000;
// I2C, Master Mode
}
// ========================= I2C start ===============================
void i2c_start(void)
{
SSPCON2bits.SEN = 1;
// Start Condition Enabled bit
i2c_wait();
}
// ========================= I2C stop ================================
void i2c_stop(void)
{
SSPCON2bits.PEN = 1;
// Stop Condition Enable bit
i2c_wait();
}
// ========================= I2C wait ================================
void i2c_wait(void)
{
while ( ( SSPCON2 & 0x1F ) || ( SSPSTATbits.R_nW ) );
}
// ========================= I2C write ===============================
void i2c_write(const unsigned char data)
{
SSPBUF = data;
i2c_wait();
}
// ========================= I2C receive =============================
unsigned char i2c_read(const char ack)
{
SSPCON2bits.RCEN = 1;
岡野ラボ 手作り研究装置 10 page 19
i2c_wait();
unsigned char data = SSPBUF;
i2c_wait();
if(ack) SSPCON2bits.ACKDT = 0;
else SSPCON2bits.ACKDT = 1;
// ACK
// NO_ACK
SSPCON2bits.ACKEN = 1;
i2c_wait();
return data;
}
// ====================== USART commands =============================
// ================== send one byte for RS232C =======================
static void send_RS232C_char(char i)
{
while(TXIF == 0);
// wait
TXREG = i;
// send
}
// ================== send CR for RS232C =============================
static void send_RS232C_CR(void)
{
send_RS232C_char(0x0D); //CR
}
// ================== send LF for RS232C =============================
static void send_RS232C_LF(void)
{
send_RS232C_char(0x0A); //LF
}
// ================== send TAB for RS232C ============================
static void send_RS232C_TAB(void)
{
send_RS232C_char(0x09);
}
// ================== word outputs for RS232C ========================
static void send_RS232C_word( const char *i )
{
while(*i != 0)
{
send_RS232C_char(*i);
i++;
}
}
// ======================== delay times ==============================
void __delay_1s(void)
{
for (unsigned int n = 0; n < 10; n++) __delay_ms(100);
}
// =========== temperature measurement 1 (LM335Z) ===================
static unsigned int temp_LM335Z_read(void)
{
int temp;
ADCON0 = 0b00000111; // AN1 on, ADC on
ADCON1 = 0b00100011; // AD clock = Fosc/32
while(ADCON0 & 0b00000010); // wait for A-D conversion
temp = ADRESH;
temp *= 4;
temp += (ADRESL >> 6);
temp *= 4;// 1 step = 4mV ( = Vref / 1024)
temp -= 2732;
return temp;
}
static void temphumid_chdata4chars(unsigned int data, unsigned char c[]) // 4 bytes
{
*c++ = ' ';
岡野ラボ 手作り研究装置 10 page 20
*c++ = '0';
*c++ = '.';
*c++ = '0';
*c = 0x00;
*--c = '0' + (data % 10);
data /= 10;
*--c;
while(data){
*--c = '0' + (data % 10);
data /= 10;
}
}
static void temp_LM335Z_print(unsigned int temp)
{
temp = temp_LM335Z_read();
lcd_locate(2,1);
lcd_print("Temp1 = ");
temphumid_chdata4chars(temp, buf);
lcd_print(buf);
send_RS232C_word(buf); // sending 4 bytes
lcd_locate(2,14);
lcd_print(" C ");
__delay_ms(100);
}
// ========================== buzzer 1 ===============================
static void buz(void)
{
for(unsigned char bz=0;bz<50;bz++){
SP = 0;
__delay_ms(1);
SP = 1;
__delay_ms(1);
}
}
// ========================== buzzer 2 ===============================
static void buz_low(void)
{
for(unsigned char bz=0;bz<25;bz++){
SP = 0;
__delay_ms(2);
SP = 1;
__delay_ms(2);
}
}
// ======== measurement of total geomagnetic field ===================
// ======== by using digital compass module HMC6532 ==================
static unsigned int mag_read(void)
{
unsigned char mag_upper = 0;
unsigned char mag_lower = 0;
signed int mag = 0;
unsigned char add = 0x42;
i2c_enable();
__delay_ms(100);
__delay_ms(10);
i2c_start();
i2c_write(add);
i2c_write('A');
i2c_stop();
i2c_start();
i2c_write(add | 0x01);
mag_upper = i2c_read(1);
mag_lower = i2c_read(0);
i2c_stop();
岡野ラボ 手作り研究装置 10 page 21
mag = (mag_upper << 8) + mag_lower;
mag += mag_offset;
mag += 3600;
mag %= 3600;
return mag;
}
static void mag_chdata5chars(unsigned int data, unsigned char c[]) // 5 bytes
{
*c++ = ' ';
*c++ = ' ';
*c++ = '0';
*c++ = '.';
*c++ = '0';
*c = 0x00;
*--c = '0' + (data % 10);
data /= 10;
*--c;
while(data){
*--c = '0' + (data % 10);
data /= 10;
}
}
static void mag_print(unsigned int mag)
{
lcd_clr();
lcd_locate(1,1);
lcd_print("Mag =
deg");
lcd_locate(1,8);
mag_chdata5chars(mag, buf);
lcd_print(buf);
send_RS232C_word(buf);
// sending 5 bytes
}
// ======== measurement of geomagnetic field vectors =================
// ======== by using 3D digital compass module HMC5883L ==============
static void mag3D_init(void)
{
unsigned char add = 0x3C;
i2c_enable();
__delay_ms(100);
i2c_start();
i2c_write(add);
i2c_write(0x02);
i2c_write(0x00);
i2c_stop();
i2c_start();
i2c_write(add);
i2c_write(0x01);
i2c_write(0x20);// sensitivity set
i2c_stop();
}
static void mag3D_pointx(void)
{
i2c_enable();
unsigned char add = 0x3C;
i2c_start();
i2c_write(add);
i2c_write(0x03);
i2c_stop();
}
static void mag3D_pointy(void)
{
i2c_enable();
unsigned char add = 0x3C;
i2c_start();
i2c_write(add);
岡野ラボ 手作り研究装置 10 page 22
i2c_write(0x07);
i2c_stop();
}
static void mag3D_pointz(void)
{
i2c_enable();
unsigned char add = 0x3C;
i2c_start();
i2c_write(add);
i2c_write(0x05);
i2c_stop();
}
static unsigned int mag3D_read(void)
{
unsigned char add = 0x3C;
unsigned char mag_upper = 0;
unsigned char mag_lower = 0;
unsigned int mag = 0;
i2c_enable();
i2c_start();
i2c_write(add | 0x01);
mag_upper = i2c_read(1);
mag_lower = i2c_read(1);
i2c_read(0);
i2c_stop();
mag = (mag_upper << 8) + mag_lower;
return mag;
}
static void mag3D_calc_and_chdata4chars(unsigned int data, unsigned char c[])
{
// 5 bytes
if (data < 2048){
*c++ = ' ';
}
else if (data > 63488){
data = ~data;
*c++ = '-';
}
else{
*c++ = ' ';
*c++ = 'O';
*c++ = 'F';
*c++ = '!';
*c++ = ' ';
*c = 0x00;
return;
}
*c++ = ' ';
*c++ = ' ';
*c++ = '0';
*c++ = '.';
*c++ = '0';
*c = 0x00;
unsigned long mag_value = data * 100 + 54; // 100 micro T = 1090 counts
mag_value /= 109;
data = (int) mag_value;
*--c = '0' + (data % 10);
data /= 10;
*--c;
while(data){
*--c = '0' + (data % 10);
data /= 10;
}
}
static void mag3D_print(unsigned int magx,unsigned int magy,unsigned int magz)
{
// totally sending 17 bytes
lcd_locate(2,1);
lcd_print("Magx =
uT");
岡野ラボ 手作り研究装置 10 page 23
lcd_locate(2,8);
mag3D_calc_and_chdata4chars(magx, buf);
lcd_print(buf);
send_RS232C_word(buf); // sending 5 bytes
send_RS232C_TAB();
// sending 1 bytes
__delay_ms(600);
lcd_locate(2,1);
lcd_print("Magy =
uT");
lcd_locate(2,8);
mag3D_calc_and_chdata4chars(magy, buf);
lcd_print(buf);
send_RS232C_word(buf); // sending 5 bytes
send_RS232C_TAB();
// sending 1 bytes
__delay_ms(600);
lcd_locate(2,1);
lcd_print("Magz =
uT");
lcd_locate(2,8);
mag3D_calc_and_chdata4chars(magz, buf);
lcd_print(buf);
send_RS232C_word(buf); // sending 5 bytes
__delay_ms(600);
}
// ========= change binary coded number to real number ===============
// ========= used in the real time clock routines ====================
static unsigned char ch_bcd(unsigned char x)
{
unsigned char y = x / 10;
x -= (y * 10);
x += (y * 16);
return x;
}
// ================== realtime clock using RTC8564NB =================
static void rtc_init(void)
{
i2c_enable();
__delay_1s();
unsigned char add = 0xA2;
i2c_start();
i2c_write(add); // set write mode
i2c_write(0x00); // address of control
i2c_write(0x00); // test=0
i2c_write(0x00); //AIE=TIE=0
i2c_stop();
}
static void chdata2chars(unsigned char data, unsigned char c[]) // 2 bytes
{
*c++ = '0';
*c++ = '0';
*c = 0x00;
while(data){
*--c = '0' + (data % 10);
data /= 10;
}
}
static void push_wait(void)
{
if (pushflag == 0) __delay_ms(500);
pushflag = 1;
__delay_ms(60);
}
岡野ラボ 手作り研究装置 10 page 24
static void datetime_setting(void)
{
year = eeprom_read(0x00);
month = eeprom_read(0x01);
day = eeprom_read(0x02);
hour = eeprom_read(0x03);
min = eeprom_read(0x04);
i2c_enable();
__delay_ms(100);
//
cent = 0x80;
lcd_cmd(0x0C); // blink off
while(SW1 == 0);
__delay_ms(100);
lcd_clr();
lcd_locate(1,1);
lcd_print("year = 20");
lcd_locate(2,1);
lcd_print("1:go 2:up 3:down");
pushflag = 0;
while(SW1)
{
lcd_2chars(1,10, year);
if (SW2 == 0){
year ++;
if (year == 100) year = 0;
lcd_2chars(1,10, year);
push_wait();
}
if (SW3 == 0){
year --;
if (year == 255) year = 99;
lcd_2chars(1,10, year);
push_wait();
}
if (SW2 * SW3) pushflag = 0;
}
eeprom_write(0x00, year);
while(WR);
while(SW1 == 0);
__delay_ms(100);
lcd_locate(1,1);
lcd_print("month =
");
pushflag = 0;
while(SW1)
{
lcd_2chars(1,9, month);
if (SW2 == 0){
month ++;
if (month == 13) month = 1;
lcd_2chars(1,9, month);
push_wait();
__delay_ms(60);
}
if (SW3 == 0){
month --;
if (month == 0) month = 12;
lcd_2chars(1,9, month);
push_wait();
__delay_ms(40);
}
if (SW2 * SW3) pushflag = 0;
}
eeprom_write(0x01, month);
岡野ラボ 手作り研究装置 10 page 25
while(WR);
while(SW1 == 0);
__delay_ms(100);
lcd_locate(1,1);
lcd_print("day =
");
pushflag = 0;
while(SW1)
{
lcd_2chars(1,7, day);
if (SW2 == 0){
day ++;
if (day == 32 & month == 1) day = 1;
if (day == 29 & month == 2 & (year % 4 != 0)) day = 1;
if (day == 30 & month == 2 & (year % 4 == 0)) day = 1;
if (day == 32 & month == 3) day = 1;
if (day == 31 & month == 4) day = 1;
if (day == 32 & month == 5) day = 1;
if (day == 31 & month == 6) day = 1;
if (day == 32 & month == 7) day = 1;
if (day == 32 & month == 8) day = 1;
if (day == 31 & month == 9) day = 1;
if (day == 32 & month == 10) day = 1;
if (day == 31 & month == 11) day = 1;
if (day == 32 & month == 12) day = 1;
lcd_2chars(1,7, day);
push_wait();
}
if (SW3 == 0){
day --;
if (day == 0 & month == 1) day = 31;
if (day == 0 & month == 2 & (year % 4 == 0)) day = 29;
if (day == 0 & month == 2 & (year % 4 != 0)) day = 28;
if (day == 0 & month == 3) day = 31;
if (day == 0 & month == 4) day = 30;
if (day == 0 & month == 5) day = 31;
if (day == 0 & month == 6) day = 30;
if (day == 0 & month == 7) day = 31;
if (day == 0 & month == 8) day = 31;
if (day == 0 & month == 9) day = 30;
if (day == 0 & month == 10) day = 31;
if (day == 0 & month == 11) day = 30;
if (day == 0 & month == 12) day = 31;
lcd_2chars(1,7, day);
push_wait();
}
if (SW2 * SW3) pushflag = 0;
}
eeprom_write(0x02, day);
while(WR);
while(SW1 == 0);
__delay_ms(100);
lcd_locate(1,1);
lcd_print("hour =
");
pushflag = 0;
while(SW1)
{
lcd_2chars(1,8, hour);
if (SW2 == 0){
hour ++;
if (hour == 24) hour = 0;
lcd_2chars(1,8, hour);
push_wait();
岡野ラボ 手作り研究装置 10 page 26
}
if (SW3 == 0){
hour --;
if (hour == 255) hour = 23;
lcd_2chars(1,8, hour);
push_wait();
}
if (SW2 * SW3) pushflag = 0;
}
eeprom_write(0x03, hour);
while(WR);
while(SW1 == 0);
__delay_ms(100);
pushflag = 0;
lcd_locate(1,1);
lcd_print("min =
");
while(SW1)
{
lcd_2chars(1,7, min);
if (SW2 == 0)
{
min ++;
if (min == 60) min = 0;
lcd_2chars(1,7, min);
push_wait();
}
if (SW3 == 0)
{
min --;
if (min == 255) min = 59;
lcd_2chars(1,7, min);
push_wait();
}
if (SW2 * SW3) pushflag = 0;
}
eeprom_write(0x04, min);
while(WR);
}
static char rtc_read(unsigned char mode)
{
i2c_enable();
__delay_ms(20);
unsigned char add = 0xA2;
i2c_start();
i2c_write(add); // set read mode
i2c_write(0x02); // set pointer to second data address
add = 0xA3;
i2c_start();
i2c_write(add); // set read mode
sec_bcd = i2c_read(1); // read data for second 0-59 in <6:4><3:0>
min_bcd= i2c_read(1); // read data for min 0-59 in <6:4><3:0>
hour_bcd = i2c_read(1); // read data for hour 0-23 in <5:4><3:0>
day_bcd = i2c_read(1); // read data for date 1-31 in <6:4><3:0>
week_bcd = i2c_read(1); // read data week sun 0123456 sat in <2:0>
month_bcd =i2c_read(1); // read data for cent,month 1-12 in <4><3:0>, set <7> if 21th cent
year_bcd = i2c_read(0); // read data year 00-99 in <7:4><3:0>
i2c_stop();
sec_upper = (sec_bcd & 0b01110000) >> 4;
sec_lower = sec_bcd & 0b00001111;
sec = 10 * sec_upper + sec_lower;
min_upper = (min_bcd & 0b01110000) >> 4;
min_lower = min_bcd & 0b00001111;
min = 10 * min_upper + min_lower;
岡野ラボ 手作り研究装置 10 page 27
hour_upper = (hour_bcd & 0b00110000) >> 4;
hour_lower = hour_bcd & 0b00001111;
hour = 10 * hour_upper + hour_lower;
day_upper = (day_bcd & 0b00110000) >> 4;
day_lower = day_bcd & 0b00001111;
day = 10 * day_upper + day_lower;
//
//
week_upper = 0x00;
week_lower = week & 0b00001111;
month_upper = (month_bcd & 0b00010000) >> 4;
month_lower = month_bcd & 0b00001111;
month = 10 * month_upper + month_lower;
year_upper = (year_bcd & 0b11110000) >> 4;
year_lower = year_bcd & 0b00001111;
year = 10 * year_upper + year_lower;
// convert decimal to ASCII
sec_upper | = 0x30;
sec_lower | = 0x30;
min_upper | = 0x30;
min_lower | = 0x30;
hour_upper | = 0x30;
hour_lower | = 0x30;
day_upper | = 0x30;
day_lower | = 0x30;
month_upper | = 0x30;
month_lower | = 0x30;
year_upper | = 0x30;
year_lower | = 0x30;
//Display date & time on LCD
if (mode){
lcd_clr();
lcd_locate(1,1);
lcd_print("20 / /
lcd_locate(1,3);
lcd_data(year_upper);
lcd_locate(1,4);
lcd_data(year_lower);
lcd_locate(1,6);
lcd_data(month_upper);
lcd_locate(1,7);
lcd_data(month_lower);
lcd_locate(1,9);
lcd_data(day_upper);
lcd_locate(1,10);
lcd_data(day_lower);
lcd_locate(2,1);
lcd_print(" : :
}
");
");
lcd_locate(2,1);
lcd_data(hour_upper);
lcd_locate(2,2);
lcd_data(hour_lower);
lcd_locate(2,4);
lcd_data(min_upper);
lcd_locate(2,5);
lcd_data(min_lower);
lcd_locate(2,7);
lcd_data(sec_upper);
lcd_locate(2,8);
lcd_data(sec_lower);
if (mode){
send_RS232C_word("20");
send_RS232C_char(year_upper);
send_RS232C_char(year_lower);
岡野ラボ 手作り研究装置 10 page 28
send_RS232C_word("/");
send_RS232C_char(month_upper);
send_RS232C_char(month_lower);
send_RS232C_word("/");
send_RS232C_char(day_upper);
send_RS232C_char(day_lower);
send_RS232C_TAB();
// sending 10 bytes
send_RS232C_char(hour_upper);
send_RS232C_char(hour_lower);
send_RS232C_word(":");
send_RS232C_char(min_upper);
send_RS232C_char(min_lower);
send_RS232C_word(":");
send_RS232C_char(sec_upper);
send_RS232C_char(sec_lower); // sending 8 bytes
}
__delay_ms(50);
unsigned char interval_degit;
if (interval == 1)interval_degit = sec_upper; // when interval = 10sec.
if (interval == 2)interval_degit = min_lower; // when interval = 1min.
if (interval == 3)interval_degit = min_upper; // when interval = 10min.
return interval_degit;
}
// ======== measurement of power supply voltage ======================
// ======== by using A-D converter to save battery ==================
static unsigned int voltage_read(void)
{
int vdd;
ADCON0 = 0b00000011; // AN0 on, ADC on
ADCON1 = 0b00100011; // AD clock = Fosc/32
while(ADCON0 & 0b00000010); // wait for A-D conversion
vdd = ADRESH;
vdd *= 4;
vdd += (ADRESL >> 6);
vdd *= 16;
return vdd;
}
static void voltage_check(unsigned int vdd_voltage)
{
if (vdd_voltage < vdd_threshold_low){
lcd_backlight = 0;
lcd_contrast(10);
if (backlight) CCP2CON = 0x1C;
else CCP2CON = 0x0C;
LED = 0;
buz_low();
lcd_clr();
lcd_locate(1,1);
lcd_print(" LOW BATTERY!");
if (interval) endnum = 360;
if (interval == 2) endnum = 60;
if (interval == 3) endnum = 6;
// Low Battery
// minimum light for LED
__delay_1s();
}
if (vdd_voltage < vdd_threshold_high){
// Battery
lcd_backlight = 0;
lcd_contrast(32);
if (backlight) CCP2CON = 0x1C;
// minimum light for LED
else CCP2CON = 0x0C;
LED = 0;
if (interval) endnum = data_endnumber / 6;
if (interval == 2) endnum = data_endnumber / 36;
if (interval == 3) endnum = data_endnumber / 360;
}
else if (backlight) {
// AC adaptor
岡野ラボ 手作り研究装置 10 page 29
if (light_intensity > 767) lcd_backlight = 255;
else {
light_intensity += 256;
lcd_backlight = light_intensity >> 2;
}
CCP2CON = 0x0C;
// mode return for LED
LED = lcd_backlight;
unsigned char contrast_value = light_intensity;
contrast_value /= 16;
contrast_value += 16;
lcd_contrast(contrast_value);
endnum = data_endnumber;
}
else {
CCP2CON = 0x0C;
LED = 0;
lcd_backlight = 0;
// LED off
}
}
static void chdata4chars1(unsigned int data, unsigned char c[]) // 4 bytes
{
*c++ = '0';
*c++ = '0';
*c++ = '0';
*c++ = '0';
*c = 0x00; // c ="0000¥n"
while(data){
*--c = '0' + (data % 10);
data /= 10;
}
}
static void voltage_print(unsigned int vdd)
{
lcd_clr();
lcd_locate(1,1);
lcd_print("Vdd = ");
__delay_ms(100);
chdata4chars1(vdd, buf);
lcd_print(buf);
send_RS232C_word(buf); // sending 4 bytes
__delay_ms(80);
lcd_locate(1,14);
lcd_print(" mV");
__delay_ms(200);
}
// ==========
humidity & temp measurement (am2321)
=================
static void humid_am2321_read(void)
{
unsigned char humid_upper, humid_lower, humidchar;
unsigned char temp_upper, temp_lower, tempchar;
unsigned char crc_upper, crc_lower;
unsigned int crc_int;
unsigned char add = 0xB8;
i2c_enable();
__delay_ms(200);
i2c_start();
i2c_write(add); // set
__delay_ms(5);
i2c_stop();
__delay_ms(100);
write mode
岡野ラボ 手作り研究装置 10 page 30
i2c_start();
i2c_write(add); // set write mode
i2c_write(0x03); // set read command
i2c_write(0x00); // set pointer to data start address
i2c_write(0x04);
i2c_stop();
__delay_ms(20);
i2c_start();
i2c_write(add+1); //
i2c_read(1);
i2c_read(1);
humid_upper = i2c_read(1); //
humid_lower = i2c_read(1); //
temp_upper = i2c_read(1); //
temp_lower = i2c_read(1); //
crc_lower = i2c_read(1); //
crc_upper = i2c_read(0); //
i2c_stop();
humid_int = (humid_upper << 8) | humid_lower;
temp2_int = (temp_upper << 8) | temp_lower;
}
static void humid_am2321_print(void)
{
temphumid_chdata4chars(humid_int, buf);
lcd_clr();
lcd_locate(1,1);
lcd_print("Humid = ");
lcd_print(buf);
lcd_locate(1,14);
lcd_print(" % ");
send_RS232C_word(buf);
send_RS232C_TAB();
temphumid_chdata4chars(temp2_int, buf);
lcd_locate(2,1);
lcd_print("Temp2 = ");
lcd_print(buf);
lcd_locate(2,14);
lcd_print(" C ");
send_RS232C_word(buf);
}
static void chdata5chars(unsigned int data, unsigned char c[]) // 5 bytes
{
*c++ = ' ';
*c++ = ' ';
*c++ = ' ';
*c++ = ' ';
*c++ = '0';
*c = 0x00;
while(data){
*--c = '0' + (data % 10);
data /= 10;
}
}
// ================ light condition measurement =====================
// ================ by using S11059 color sensor ====================
static void color_read(void)
{
unsigned char add = 0x54; // 0xC8 -> 0x08
unsigned char i;
for (i=0;i<4;i++){
lcd_backlight >>= 1;
__delay_ms(50);
岡野ラボ 手作り研究装置 10 page 31
}
lcd_backlight = 0;
CCP2CON = 0x0C;
LED = 0;
i2c_enable();
// LED off
i2c_start();
i2c_write(add);
i2c_write(0);
i2c_write(0x8A);// ADC reset, start measurement, gain=high; 22.4msec/ch
i2c_stop();
i2c_start();
i2c_write(add);
i2c_write(0);
i2c_write(0x0A);
i2c_stop();
__delay_ms(100);// wait for measurement
i2c_start();
i2c_write(add);
i2c_write(0x03);
i2c_stop();
i2c_start();
i2c_write(add+1);
red_upper = i2c_read(1);
red_lower = i2c_read(1);
green_upper = i2c_read(1);
green_lower = i2c_read(1);
blue_upper = i2c_read(1);
blue_lower = i2c_read(1);
ir_upper = i2c_read(1);
ir_lower = i2c_read(0);
i2c_stop();
red_int = (red_upper << 8) | red_lower;
green_int = (green_upper << 8) | green_lower;
blue_int = (blue_upper << 8) | blue_lower;
ir_int = (ir_upper << 8) | ir_lower;
light_intensity = 0;
light_intensity += red_int / 3;
light_intensity += green_int / 3;
light_intensity += blue_int / 3;
}
static void color_print(void)
{
unsigned char add = 0x54; // 0xC8 -> 0x08
lcd_clr();
chdata5chars (red_int, buf);
lcd_locate(1,1);
lcd_print("R:");
lcd_print(buf);
send_RS232C_word(buf);
send_RS232C_TAB();
// sending totally 24 bytes
chdata5chars (green_int, buf);
lcd_locate(2,1);
lcd_print("G:");
lcd_print(buf);
send_RS232C_word(buf);
send_RS232C_TAB();
chdata5chars (blue_int, buf);
lcd_locate(1,10);
lcd_print("B:");
lcd_print(buf);
send_RS232C_word(buf);
send_RS232C_TAB();
chdata5chars (ir_int, buf);
岡野ラボ 手作り研究装置 10 page 32
lcd_locate(2,10);
lcd_print("I:");
lcd_print(buf);
send_RS232C_word(buf);
send_RS232C_TAB();
__delay_ms(700);
}
// ======== measurement of atmospheric pressure and temperature ======
// ============== by using lps331 pressure sensor ====================
static void chdata4chars2(unsigned int data, unsigned char c[]) // 4 bytes
{
*c++ = ' ';
*c++ = ' ';
*c++ = ' ';
*c++ = '0';
*c = 0x00; // c ="
0¥n"
while(data){
*--c = '0' + (data % 10);
data /= 10;
}
}
static void lps331_write(unsigned char register_address, unsigned char command)
{
i2c_start();
i2c_write(0xBA);
i2c_write(register_address);
i2c_write(command);
i2c_stop();
}
static unsigned char lps331_read(unsigned char register_address)
{
unsigned char value;
i2c_start();
i2c_write(0xBA);
i2c_write(register_address);
i2c_stop();
i2c_start();
i2c_write(0xBB);
value = i2c_read(0);
i2c_stop();
return value;
}
static void pressure_read(void)
{
unsigned char pressout_h, pressout_l, pressout_xl;
unsigned char tempout_h, tempout_l, ctrl2;
unsigned char add = 0xBA;
unsigned int press_int, press_sub;
signed int temp_int;
i2c_enable();
//
//
//
RES_CONF
lps331_write(0x10, 0x7A);
//
CTRL1-3 default setting
lps331_write(0x20, 0x80);
// CTRL1
one-shot measurement start
lps331_write(0x20, 0x88); // CTRL1
lps331_write(0x21, 0x01); // CTRL2
ctrl2 = 1;
while(ctrl2)
{
ctrl2 = lps331_read(0x21);
ctrl2 &= 0x01;
}
岡野ラボ 手作り研究装置 10 page 33
//
readout pressure data
pressout_xl = lps331_read(0x28);
pressout_l = lps331_read(0x29);
pressout_h = lps331_read(0x2A);
//
readout temperature data
tempout_l = lps331_read(0x2B);
tempout_h = lps331_read(0x2C);
//
calculate pressure
press_int = pressout_h;
press_int *= 16;
press_int |= (pressout_l & 0xF0) >> 4;
press_sub = pressout_l & 0x0F;
press_sub *= 625;
press_sub += 500;
press_sub /= 1000;
temp_int = tempout_h << 8;
temp_int |= tempout_l;
temp_int ^ 0xFFFF;
temp_int /= 48;
temp_int += 425;
chdata4chars2(press_int, buf); // sending totally 6 bytes
lcd_clr();
lcd_locate(1,1);
lcd_print("Press= ");
lcd_print(buf);
send_RS232C_word(buf);
lcd_data('.');
send_RS232C_char('.');
lcd_data('0' + press_sub);
lcd_locate(1,14);
lcd_print("hPa");
send_RS232C_char('0' + press_sub);
send_RS232C_TAB();
// sending 1 byte
temphumid_chdata4chars(temp_int, buf);
lcd_locate(2,1);
lcd_print("Temp3 = ");
lcd_print(buf);
lcd_locate(2,14);
lcd_print(" C ");
send_RS232C_word(buf); // sending 4 bytes
__delay_ms(500);
}
// ============== write header on sd card via RS232C =================
static void sd_write_header(void)
{
send_RS232C_word("P:09B"); // 155 characters
send_RS232C_CR();
send_RS232C_word("Date");
// 4 bytes
send_RS232C_TAB();
// 1 byte
send_RS232C_word("Time");
// 4 bytes
send_RS232C_TAB();
// 1 byte, totally 10 bytes
send_RS232C_word("Vdd(mV)");
// 7 bytes
send_RS232C_TAB();
// 1 byte
send_RS232C_word("Temp1(degC)");
// 11 bytes, totally 29 bytes
send_RS232C_TAB();
// 1 byte
send_RS232C_word("Humidity(%)");
// 11 bytes
send_RS232C_TAB();
// 1 byte
send_RS232C_word("Temp2(degC)");
// 11 bytes
send_RS232C_TAB();
// 1 byte
send_RS232C_word("Press(hPa)");
// 10 bytes
send_RS232C_TAB();
// 1 byte
send_RS232C_word("Temp3(degC)");
// 11 bytes, totally 76 bytes
send_RS232C_TAB();
// 1 byte
send_RS232C_word("totalMag(deg)"); // 13 bytes
send_RS232C_TAB();
// 1 byte, totally 91 bytes
岡野ラボ 手作り研究装置 10 page 34
send_RS232C_word("MagX(microT)");
send_RS232C_TAB();
send_RS232C_word("MagY(microT)");
send_RS232C_TAB();
send_RS232C_word("MagZ(microT)");
send_RS232C_TAB();
send_RS232C_word("Red");
send_RS232C_TAB();
send_RS232C_word("Green");
send_RS232C_TAB();
send_RS232C_word("Blue");
send_RS232C_TAB();
send_RS232C_word("InfraRed");
send_RS232C_CR();
send_RS232C_LF();
send_RS232C_CR();
// 12 bytes
// 1 byte
// 12 bytes
// 1 byte
// 12 bytes
// 1 byte
// 3 bytes
// 1 byte
// 5 bytes, totally 139 bytes
// 1 byte
// 4 bytes
// 1 byte
// 8 bytes
// 1 byte
// 1 byte, totally 154 bytes
// sending 1 byte for termination
}
//
for debugging
/*static void lcd_printval(unsigned int data)
{
chdata4chars1(data, buf);
lcd_print(buf);
}
static void look(unsigned int value)
{
lcd_clr();
lcd_locate(1,1);
lcd_print("Value = ");
lcd_printval(value);
__delay_1s();
}
*/
// ======================= main program ==============================
main(void)
{
// initialization of PIC and peripherals
pic_init();
lcd_init();
lcd_clr();
unsigned int mag = mag_read();
// PIC initialization
// LCD initialization
lcd_RW = 0;
buz();
voltage_read();
mag_read();
vdd_voltage = voltage_read();
voltage_check(vdd_voltage);
rtc_init();
// rtc initialization
// read the head two characters and number of starting file from eeprom memory
name1 = eeprom_read(0x06);
// header for filename
name2 = eeprom_read(0x07);
// header for filename
filenumber = 0;
filenumber = eeprom_read(0x08);
filenumber <<= 8;
filenumber += eeprom_read(0x09);
// setting of start filename
lcd_cmd(0x0D);
lcd_cmd(0x18);
lcd_clr();
lcd_locate(1,1);
lcd_print("StartFile: ");
chdata4chars1(filenumber, buf);
lcd_print(buf);
岡野ラボ 手作り研究装置 10 page 35
lcd_locate(1,11);
lcd_data(name1);
lcd_data(name2);
lcd_locate(2,1);
lcd_print("1:go 2:up 3:down");
// setting of the first character of starting file
pushflag = 0;
while(SW1)
{
lcd_locate(1,11);
lcd_data(name1);
lcd_locate(1,11);
if (SW2 == 0){
name1 ++;
if (name1 > 0x5A) name1 = 0x41;
lcd_locate(1,11);
lcd_data(name1);
lcd_locate(1,11);
push_wait();
}
if (SW3 == 0){
name1 --;
if (name1 < 0x41) name1 = 0x5A;
lcd_locate(1,11);
lcd_data(name1);
lcd_locate(1,11);
push_wait();
}
if (SW2 * SW3) pushflag = 0;
}
// save the first character of starting file to eeprom memory
eeprom_write(0x06, name1);
while(WR);
// setting of the second character of starting file
while(SW1 == 0);
__delay_ms(100);
pushflag = 0;
while(SW1)
{
lcd_locate(1,12);
lcd_data(name2);
lcd_locate(1,12);
if (SW2 == 0){
name2 ++;
if (name2 > 0x5A) name2 = 0x41;
lcd_locate(1,12);
lcd_data(name2);
lcd_locate(1,12);
push_wait();
}
if (SW3 == 0){
name2 --;
if (name2 < 0x41) name2 = 0x5A;
lcd_locate(1,12);
lcd_data(name2);
lcd_locate(1,12);
push_wait();
}
if (SW2 * SW3) pushflag = 0;
}
// save the second character of starting file to eeprom memory
eeprom_write(0x07, name2);
while(WR);
岡野ラボ 手作り研究装置 10 page 36
while(SW1 == 0);
__delay_ms(100);
// setting of the number of starting file
while(SW1 * SW2 * SW3)
{
lcd_locate(1,13);
chdata4chars1(filenumber, buf);
lcd_print(buf);
lcd_locate(1,16);
__delay_ms(150);
}
pushflag = 0;
while(SW1)
{
lcd_locate(1,13);
chdata4chars1(filenumber, buf);
lcd_print(buf);
if (SW2 == 0)
{
lcd_locate(2,1);
lcd_print("+SW4: high speed");
filenumber ++;
if (SW4) __delay_ms(20); else filenumber += 19;
if (filenumber > 9999) filenumber = 0;
lcd_locate(1,13);
chdata4chars1(filenumber, buf);
lcd_print(buf);
if (pushflag == 0)__delay_ms(500);
pushflag = 1;
}
if (SW3 == 0)
{
lcd_locate(2,1);
lcd_print("+SW4: high speed");
filenumber --;
if (SW4) __delay_ms(20); else filenumber -= 19;
if (filenumber > 9999) filenumber = 9999;
lcd_locate(1,13);
chdata4chars1(filenumber, buf);
lcd_print(buf);
if (pushflag == 0)__delay_ms(500);
pushflag = 1;
}
if (SW2 * SW3){
lcd_locate(2,1);
lcd_print("1:go 2:up 3:down");
pushflag = 0;
}
}
// save the number of starting file to eeprom memory
unsigned char filenumber_lower = filenumber & 0xFF;
unsigned char filenumber_upper = filenumber >> 8;
eeprom_write(0x08, filenumber_upper);
while(WR);
eeprom_write(0x09, filenumber_lower);
while(WR);
// setting of the interval of every measurement
while(SW1 == 0);
__delay_ms(100);
lcd_clr();
lcd_locate(1,1);
lcd_print("Select Interval");
lcd_locate(2,1);
lcd_print("1:10s 2:1m 3:10m");
interval = 1;
while(1)
{
__delay_ms(150);
岡野ラボ 手作り研究装置 10 page 37
if (SW1 == 0)break;
if (SW2 == 0){
interval = 2;
break;
}
if (SW3 == 0){
interval = 3;
break;
}
}
// setting of mode of backlight during measurements:
// High power supply voltage and backlight ON;
//
backlight and LCD contrast changes accoring to environmental light condition
// Low power supply voltage or backlight OFF;
//
backlight is always turned off during measurements
lcd_clr();
lcd_locate(1,1);
lcd_print("Backlight on/off");
lcd_locate(2,1);
lcd_print("1:on 2:off
");
while(1)
{
__delay_ms(150);
if (SW1 == 0) break;
if (SW2 == 0){
backlight = 0;
break;
}
}
// setting of date and time variables
datetime_setting();
while (SW1 == 0);
// rtc write
// confirmation of setting of SD logger
lcd_cmd(0x0C); // blink off
lcd_clr();
lcd_locate(1,1);
lcd_print("Confirm SD");
lcd_locate(2,1);
lcd_print("0:restart 1:go");
while (SW1 == 1);
// start of measurements
lcd_clr();
lcd_locate(1,1);
chdata2chars(hour, buf);
lcd_print(buf);
lcd_print(":");
chdata2chars(min, buf);
lcd_print(buf);
lcd_print(":");
chdata2chars(sec, buf);
lcd_print(buf);
lcd_locate(2,1);
lcd_print("4:logging start");
while(SW4 == 1);
buz();
lcd_clr();
lcd_locate(1,1);
lcd_print("Now Starting ...");
// send data of date and time variables to realtime clock module
year_bcd = ch_bcd(year);
month_bcd = ch_bcd(month);
day_bcd = ch_bcd(day);
hour_bcd = ch_bcd(hour);
min_bcd = ch_bcd(min);
sec_bcd = ch_bcd(sec);
unsigned char add = 0xA2;
岡野ラボ 手作り研究装置 10 page 38
i2c_start();
i2c_write(add); // set write mode
i2c_write(0x02); // set pointer to second data address
i2c_write(sec_bcd); // write data for second 0-59 in <6:4><3:0>
i2c_write(min_bcd); // write data for min 0-59 in <6:4><3:0>
i2c_write(hour_bcd); // write data for hour 0-23 in <5:4><3:0>
i2c_write(day_bcd); // write data for date 1-31 in <6:4><3:0>
i2c_write(week_bcd); // write data for week sun 0123456 sat in <2:0>
i2c_write(month_bcd);// write data for cent,month 1-12 in <4><3:0>, set <7> if 21th cent
i2c_write(year_bcd); // write data for year 00-99 in <7:4><3:0>
i2c_stop();
// measurement cycles (outer loop)
unsigned char current_date;
while (filenumber < 10000)
{
// creation of a new file
current_date = day;
send_RS232C_word("W:");
lcd_clr();
lcd_locate(1,1);
lcd_print("Create file ");
lcd_locate(2,1);
lcd_data(name1);
send_RS232C_char(name1);
lcd_data(name2);
send_RS232C_char(name2);
chdata4chars1(filenumber, buf);
lcd_print(buf);
send_RS232C_word(buf);
lcd_print(".TXT");
send_RS232C_word(".TXT");
send_RS232C_CR();
__delay_ms(100);
sd_write_header();
// close the new file
send_RS232C_word("C:W");
send_RS232C_CR();
// save the number of nextfile to eeprom memory
unsigned int nextfile = filenumber + 1;
if (nextfile == 10000) nextfile = 0;
unsigned char nextfilenumber_lower = nextfile & 0xFF;
unsigned char nextfilenumber_upper = nextfile >> 8;
eeprom_write(0x08, nextfilenumber_upper);
while(WR);
eeprom_write(0x09, nextfilenumber_lower);
while(WR);
__delay_ms(10);
unsigned int datanum = 0;
endnum = data_endnumber;
// measurement cycles (inner loop)
while (datanum < endnum)
{
// open the current file as append mode
send_RS232C_word("A:");
send_RS232C_char(name1);
send_RS232C_char(name2);
chdata4chars1(filenumber, buf);
send_RS232C_word(buf);
send_RS232C_word(".TXT");
岡野ラボ 手作り研究装置 10 page 39
send_RS232C_CR();
__delay_ms(20);
// send the data number to SD logger
send_RS232C_word("P:069"); // 105 bytes / line
send_RS232C_CR();
// get environmental light condition and read voltage
mag_read();
color_read();
vdd_voltage = voltage_read();
voltage_check(vdd_voltage);
humid_am2321_read();
// get date/time from realtime clock module to display and send the data to SD logger
rtc_read(1);
// rtc read 19 bytes
send_RS232C_TAB();
// 1 byte
__delay_ms(200);
// get power supply voltage to display and send the data to SD logger
voltage_print(vdd_voltage); // 4 bytes
send_RS232C_TAB();
// 1 byte
__delay_ms(100);
// get temperature data (1) to display and send the data to SD logger
int temp = temp_LM335Z_read();
temp_LM335Z_print(temp);
// 4 bytes
send_RS232C_TAB();
// 1 byte
__delay_ms(100);
// get humidity and temperature data (2) to display and send the data to SD logger
humid_am2321_read();
humid_am2321_print();
// 9 bytes
send_RS232C_TAB();
// 1 byte
__delay_ms(700);
// get atmospheric pressure and temperature data (3) to display and send the data to SD logger
pressure_read();
// 11 bytes
send_RS232C_TAB();
// 1 byte
// get direction of geomagnetic field to display and send the data to SD logger
mag = mag_read();
// 5 bytes
__delay_ms(100);
mag_print(mag);
send_RS232C_TAB();
__delay_ms(100);
// 1 byte
// get 3D vectors of geomagnetic field to display and send the data to SD logger
unsigned int magx, magy, magz;
mag3D_init();
__delay_ms(100);
mag3D_pointx();
__delay_ms(10);
magx = mag3D_read();
mag3D_pointy();
__delay_ms(10);
magy = mag3D_read();
mag3D_pointz();
__delay_ms(10);
magz = mag3D_read();
mag3D_print(magx,magy,magz);// 20 bytes
send_RS232C_TAB();
// 1 byte
// print environmental light condition to display and send the data to SD logger
// R: red, G: green, B: blue, I: infrared
color_print();
// 24 bytes
__delay_ms(100);
send_RS232C_CR();
// 1 byte
send_RS232C_LF();
// 1 byte
send_RS232C_CR();
// + 1 byte
send_RS232C_word("C:W");
send_RS232C_CR();
岡野ラボ 手作り研究装置 10 page 40
// waiting for the next measurement and
// LCD backlight diminishing during waiting period
if ((vdd_voltage >= vdd_threshold_high) * backlight) {
unsigned char i,j;
i = lcd_backlight;
for (j=0;j<8;j++){
i >>= 1;
lcd_backlight = 10 + i;
__delay_ms(50);
}
}
else lcd_backlight = 0;
lcd_clr();
lcd_locate(1,1);
lcd_print("Waiting ...
lcd_locate(2,1);
lcd_print(" : :
");
");
unsigned char t, u;
t = rtc_read(0);
do{
u = rtc_read(0);
}while (t == u);
// loop out to proceed the next file when the date changes
if (current_date != day) break;
datanum ++;
}
filenumber ++;
}
// loop out to end the measurements when the filenumber exceeds 9999
lcd_clr();
lcd_locate(1,1);
lcd_print("Filenumber ended");
buz();
__delay_1s();
buz();
__delay_1s();
}
// program end
Copyright (c) 2014, Toshiyuki Okano All rights reserved.
ソースコード形式かバイナリ形式か、変更するかしないかを問わず、以下の条件を満たす場合に限り、再頒布および使用が許可され
ます。
• ソースコードを再頒布する場合、上記の著作権表示、本条件一覧、および下記免責条項を含めること。
• バイナリ形式で再頒布する場合、頒布物に付属のドキュメント等の資料に、上記の著作権表示、本条件一覧、および下記免責条項を
含めること。
• 書面による特別の許可なしに、本ソフトウェアから派生した製品の宣伝または販売促進に、早稲田大学の名前または岡野俊行の名前
を使用してはならない。
本ソフトウェアは、著作権者によって「現状のまま」提供されており、明示黙示を問わず、商業的な使用可能性、および特定の目的
に対する適合性に関する暗黙の保証も含め、またそれに限定されない、いかなる保証もありません。著作権者も、事由のいかんを問
わず、 損害発生の原因いかんを問わず、かつ責任の根拠が契約であるか厳格責任であるか(過失その他の)不法行為であるかを問
わず、仮にそのような損害が発生する可能性を知らされていたとしても、本ソフトウェアの使用によって発生した(代替品または代
用サービスの調達、使用の喪失、データの喪失、利益の喪失、業務の中断も含め、またそれに限定されない)直接損害、間接損害、
偶発的な損害、特別損害、懲罰的損害、または結果損害について、一切責任を負わないものとします。