PICでマイコン製作
【序章】
アラーム装置を作ってみよう!・・・から大変な事になってきた・・・・。
とにかくマイコンでコントロールする以外に方法は無い!と思ってしまったんだから仕方が無い・・・・。
ま、これも性分として諦めるしかないわな・・・・。
しっかし、遂に手を出してしまったかぁ・・・・マイコン・・・・(ため息)。
四半世紀前にあの有名なTK−80が世に出てから4年後、
あたしが大学3年の時に初めて世に出たNECのPCシリーズ。
卒業時に買った東芝のパソピアは163,000円と、あたしの初任給より高かったわい。
中学生の頃からアキバに抵抗買いには行っていたが、
40年の歴史を誇る秋月電子のAKI−80キットを、
横目で見ながら知らぬフリをする事20数年。
だってROMライター高いし!
アセンブラだし!
使うとこ無いし!・・・・使うとこ無いし!・・・・使うとこ無いし!?
・・・・なんでこの歳になって「使うとこ」出てきちゃったんだろう・・・・。
傾斜センサーで制御したい!・・・・までは道を外れていなかったつもりなのに、キャリブレーションが必要な場合はその初期値を保持する命令が必要じゃん!
命令=プログラム=マイコンチップ・・・・・ってか・・・・。
で、もう大人だから何気に小銭は持ってる訳で、何っ!?電源供給がUSBのROMライターが6800円!?
えっ!?ROMが80円〜!?(〜350円程度)
うっ!?アセンブルソフトと書き込みソフトがフリーソフト!!!???
【情報収集】
だめだ・・悪いムシが・・・・・。
ついに手にしてしまった・・・・秋月電子のAKI−PIC2プログラマボード(PICkit2互換)
とはいえ、大前提ではあるが、
・ICの事全く知らないし!
・アセンブラ知らないし!
・電子回路作れないし!
の3大要素が見事に欠落している訳で。
なのに何だろう・・・この興奮は・・・何か嬉しい・・・・・。
新たに目標が出来た喜びだろうか?・・・・それとも新たな新天地に接する喜びだろうか?
ともかく何も知らないで買ってしまったんだから、どの程度のオモチャに出来上がるか?やってみよう!である。
昔と違ってHPがある現在では、ものの数分でウンザリする程の情報が手に入る。
当然のように、
・PICとは?
・アセンブラの書き方
・コンパイルの方法
・チップへの書き込み方
などが出てくる出てくる・・・。
ただ、ICに対応する「電子回路の作り方」については、死ぬほど情報はあるものの全く判らない訳で、早々に断念。
お手本となる回路が山ほどHPにあるので、それらを参照する事としよう。
さて、AKI−PIC2プログラマボードを買う時点でいろいろ調べていた事。
・ICの足はそれぞれ意味があって、電源用、I/O用、タイマー用など使い分けるらしい。
・ICを起動させるには発振子というパーツでクロックを発振して動かすらしい。バイクのセルのようなものか?
・発振子は水晶やコンデンサ一体型などあるらしい。
・同時に電解コンもセットで使うらしい。
・「基板にハンダ」する前に「ブレッドボード」なるテスト基板に差す事でテストが容易に出来るらしい。
ってな事で、
PICマイコン | PIC16F84A | 1個 | 250円 |
発振子 | セラロック10MHz セラロック20MHz | 1個 | 30円 40円 |
電解コンデンサー | 220uF | 1本 | 30円 |
積層セラミックコンデンサ | 0.1μF | 10個 | 100円 |
LED | 赤 緑 黄色 | 1本 | 各20円 |
抵抗 | 470Ω | 1袋 (100本) | 100円 |
ICソケット | 18ピン | 1個 | 50円 |
ブレッドボード | 102B | 1セット | 700円 |
ACアダプター | 5V用 | 1個 | 600円 |
アダプターソケット | 2.1mm | 1個 | 40円 |
などHP上にあったパーツも一緒に(&適当に)買い込んでみる。
【準備@コンパイルツール】
先ずは「とりあえず(よく判らんが)動いたぞ!?」までを実践してみよう。
「マイクロチップ」という会社が無償で配布しているコンパイラーソフト「MPLAB IDE V8.33」の最新版をダウンロードしてインストール。
同時に「PICKIT2プログラマー V2.61」というライターソフトもダウンロード(上記と同じURL)。
あっ!こいつ!「.NETフレームワーク」を強制しやがる!
チックショー!!やっぱり時代には逆らえないのか・・・涙を呑んでインストールする。
MPLAB IDE V8.33の使い方
@インストール後、起動したら「Project Wizard」を選択。
AStepOneで使うチップを選択する。
今回はPIC16F84Aを使う。
選択後「次へ」
BStepTwo
何も触らず「次へ」
CStepThree
新たなプロジェクトを作るのでそのプロジェクト名を指定する。
「Browse」ボタンでディレクトリを指定してファイル名の欄に任意のプロジェクト名(ここでは"test01")を入力する。
「次へ」
DStepFour
何も触らず「次へ」
ESummary
「完了」で終了。
FDebbger⇒Select Tool⇒MPLAB SIM
を選択する。
GFile⇒Add New File to Project
を選択する。
Gプロジェクト名と同じ名前のファイルに「.ASM」を付け加えて「保存」
Hエディタが出現し、
これでソースを記述する事が出来るようになった!
I訳も判らず先生のソースをコピペしてみる。
(ソースの出典はここ)
JProject⇒Build Allを選択するとコンパイルが始まる。
Kコンパイルに成功するとOutPut画面の最後に
BUILD SUCCEEDED
と出る。
このメッセージと異なる場合はソースが間違ってるので、
自力で直せる力が付くまで別のソースを用意しよう!
成功した場合、プロジェクトフォルダに、HEXファイルが追加されている。(この場合はtest01.HEX)
このファイルをチップに書き込む訳だ。
この場合は84バイトの容量のファイルを書き込む事になる。
これでMPLAB IDE V8.33の操作は終了!
【準備Aライティングツール】
PICKIT2プログラマー V2.61の使い方
@「AKI−PIC2プログラマボード」に「PIC16F84A」をセットする。
どこに差してもいっか?と適当に差してもソフトが認識してくれないので注意!
きちんと指示通りにソケットの@にピンを合わせてセットする事。
PICを差してからUSB接続するとレディ状態を示す緑LEDが点灯。
A「PICKIT2プログラマー」を起動すると「PIC16F84A」が自動認識されている。
B先に完成したHEXファイルをインポートする。
CWriteボタンを押下するとチップに書き込みを開始する。
書き込み中はボードの赤LEDが点灯して2秒ほどで書き込み終了。
早っ!
昔のEP−ROMは書き込みに数分、消すのに(お日様に当てて)2時間・・・とか記憶があるんだけどなぁ・・・。
D書き込みが完了すると”Successful”のメッセージが表示されるので確認する。
これで完了!自分のプログラムがチップに書かれた!事になる。
(今はまだ人の作ったプログラムだけど!)
【準備Bチップテスト】
オリジナル・チップのテスト方法
ブレッドボードを眺めて思案する。
「中はどういう配線なのよ?」それが判んなきゃ接続のしようがない。
ひっくり返してみたが中は見えない。
ググッてみるとあった。
要はこういう事らしい・・・⇒
ブレッドボードに回路図通りにジャンパーして見る。
この付属のジャンパー線よいね。
もうすこし太い方が使い勝手は良いが高くなるか。
なんか小学生の時分に父親に買ってもらった「電子ブロック」を思い出したよ。
あの時分にもう少し電子回路に興味を持っていたら、今苦労しなくて済んだかもなぁ・・・。
配線後、5V電源を接続してみると見事にLEDが点灯!
ここまでは全く問題なく終了・・・・って、見本通だから当たり前だ。
しかもソースはコピペだし。
その後も簡単なソースをコピペして実験&成功。
・・・・・・・だんだんつまらなくなってきた。
そりゃそうだ!人のソースだもの。
やっぱ「訳判んねぇ〜」ってつまらない。
と言う訳で、ここからICとアセンブラの解析に入る。
【準備Cファームウェアを理解する】
ICとアセンブラの相互関係
いろいろ調べて判った事。
実は(後々の為に)教科書ライクに書き連ねようと思ったのだが、
・現状で自分のスキルが追いついていない!
・ならば説明を誤魔化そうとして散々参考HPを読んでも全く意味が判らん!
・なんか面倒臭くなってきた・・・・
の事態に陥ってきた為、取り敢えず、
@ICのピン配置と意味
AICのプログラムメモリの意味
BICのデータメモリとレジスタの意味
CICのEPROMの意味
の4項目+アセンブラ命令と引数の意味(次章)の概要だけを列挙して、後はテストをしながら順次覚えていく事に決めた。
上記5項目は別々のカテゴリのようで、実は全て相互関係が成り立っている。
だから別々に記述したのでは、自分のように「ICもアセンブラも初心者」にしてみたら全く意味不明になってしまう事が判明。
常に一緒に照らし合わせながら理解していかないとまるで判らん!になってしまう。
まぁ、考えて見れば「1つのチップにプログラムを埋め込む」のだから、専用のチップ知識と専用のプログラム知識が必要なのは当たり前の事だ。
尤も1つを完全に把握してしまえばその知識応用は広いと思うが。
@「PIC16F84A」のピン配置と意味
先ずはこのチップの詳細を覚えてしまう事から。(先生のHPに全部書いてある事だけど自分で理解出来るか?トレースしてみた)
ピン番号 | 意味と使い方 |
1 |
ポートAとBの入出力用ピン。
全てのピンが入力と出力の両方が可能。
ポート?⇒合計で13個の入出力のピンがある訳だが、これが2つのグループに別れている。
何故か?というと1回では8ビット(FFh)=8ピンまでしかアクセス出来ないから。
RA0〜RA4がAグループでこれをポートAという。
RB0〜RB7がBグループでこれをポートBという。
例えば12ピンを制御したい場合は「12番目のピン」ではなくて「ポートBの6番ピン」となる。
各ピンの耐電流は20mA。
但しポートAの合計電流は50mA、ポートBの合計電流は100mAを超えてはいけないらしい。
3ピンだけは出力する場合はプルアップが必要。
プルアップ?⇒先ずICはONかOFFがハッキリしていないと誤動作を起こすものらしい。
で、ハッキリと電圧が掛かっているONの時は良いとして、回路がOFFの時は今何ボルトなの?ってな感じで不安定な状態らしい。 で、回路がOFFの時は抵抗をアースした回路にして「完全にOFF状態」にしてやる事らしい。(判り易い解説はここ) |
2 |
3 |
17 |
18 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
4 | 無条件で+5Vに接続 |
15 | 発振子(水晶クロックやセラロック)に接続。 方向はどちらでもよい。 ちなみに発振子の真ん中の足はGND。 |
16 |
5 | Vssと覚えよう。無条件でアース(GND)に接続 |
14 | Vddと覚えよう。無条件で+5Vに接続 |
A「PIC16F84A」のプログラムメモリの意味
チップ内のメモリ領域には3つの種類がある。
プログラムメモリ領域、データメモリ領域、EEPROM領域だ。
先ず、プログラムメモリ領域は作ったプログラムを格納する場所。
フラッシュメモリで電源OFFでも記憶し続ける。
容量は1KW(キロワード)。
1W(ワード)=14bit(ビット)だから、14*1024^2/8=1792B(バイト)までのプログラムの搭載が可能って事だ。
WindowsでC++をコンパイルしようもんならすぐに1MB程度のファイルになる訳で、そんな感覚でいるとぶっ飛ぶ数字だね。
でも先の「Test01.HEX」の容量は84バイトだから、この20倍ものプログラムが作れる計算になる。
ちなみにプログラム中のコメントはコンパイル時に省かれるので、幾らコメントしても容量が増える心配はない。
上記は自分で判り易くバイト表現したけど、バイト変換する意味は全くありません。
何故なら「1命令=1ワード」で1024箇所(ループもあるので回ではない)しか命令出来ないからで「その容量範囲ならいくらでも命令可能」ではないからです。
さて、プログラムを埋め込む先頭のアドレスが0(ゼロ)番地である事は理解できる。先頭だからね。
この0番地の事を「リセットベクタ」と呼ぶらしい。まぁ、そういう呼び名だと覚えよう。
そこから次の命令が格納されるのが+1番地と進んでいく訳だが、4番目の番地を「割り込みベクタ」と呼んで、割り込み時にここにジャンプするらしい。
これが判らん・・・・・400番地(16進数でいう190hとか)なら何となく理解できそうだが、4番地って「じゃぁ、4つ目の命令はどこに書かれるの?」が疑問。
まぁ、今の自分はそんなレベルという事で次に進んでみる。
もう一つプログラムメモリには「コンフィグレーションワード」という領域がって8199番地(2007h)に有るそうな。
えぇ〜!?さっき1024番地(400h)まで!って言ったじゃん!!
そうなんです・・・・それ以降にも用意してあるらしいのですが「未実装領域」とかいって使えない領域のようです。
ただその中の8199番地だけは使うようで。
ここには基本情報を書き込む場所だそうで、プログラムの最初に記述する、
a)コードプロテクションの指定(CP)
b)パワーアップタイマーの指定(PWRTE)
c)ウォッチドッグタイマーの指定(WDT)
d)クロック発振器タイプの指定(OSC)
が書き込まれる場所なんだそうで。
a)コードプロテクション
チップメモリの内容が読み出し禁止にするフラグで、
ON: プロテクトしない
OFF:プロテクトする
b)パワーアップタイマー
電源投入後約72ms間、リセットし続けるためのタイマーだそうで通常は使用するんだそうです。
ON:使用する
OFF:使用しない
c)ウォッチドッグタイマー
わかりません
ON:使用する
OFF:使用しない
d)クロック発振器タイプ
・Resistor/Capacitor 1MHz以下
・High Speed Crystal/Resonator 4MHz〜20MHz
・Crystal/Resonator 4MHz以下
・Low Power Crystal 200KHz以下
の選択だそうですが、その選択方法が不明・・・・。
この設定の記述は後述のプログラム編で。
しかしこれは「おまじない」の領域なので、あまり真剣に悩む必要はないと思う・・・。
プログラムメモリ領域の書き替え回数は1万回が限度らしい・・・そんなに酷使しないよ・・・250円だし・・・。
B「PIC16F84A」のデータメモリとレジスタの意味
プログラムが生成したデータを格納する場所。電源OFFで情報は消失します。
下図の様に、データメモリ領域は「バンク0」と「バンク1」に別れています。
Q:何故1つじゃないんだ!
A:データ領域の任意の番地を指定するレジスタはSFRも指定する関係で7ビット=128個しか無い。
それでは余りに少なくね?って事で「後から追加した考え方」としてバンクという概念が出来たそうな。
ただ84Aの場合は容量が元々68バイトしか無い訳で関係ない様な気もするが違うのかな?(まだ意味不明でいいか・・・)
水色:取り敢えず使用するレジスタ
灰色:未使用で考えなくてよい領域
バンク0 | バンク1 |
SFR (Special Function Registers)00h〜0Bh | 00h | INDF | 間接アドレス(方式)使用時のレジスタ内容 (現在不使用) | SFR 80h〜8Bh | 00h | INDF | (バンク0と同じ=未使用) |
01h | TMR0 | タイマーカウンター(現在不使用) | 81h | OPTION | プルアップが必要な時に使うらしい。 あとはよく判りません(現在不使用) |
02h | PCL | プログラムカウンター1 プログラムをトレースする為の番地を格納 (これって勝手に使用するんじゃないのかな?) | 82h | PCL | (バンク0と同じ=未使用) |
03h | STATUS | バンク0とバンク1の切り替え (表1) | 83h | STATUS | (バンク0と同じ=未使用) |
04h | FSR | 間接アドレス(方式)用レジスタ テーブルを一度に読みたい時などの用いる? (現在不使用) | 84h | FSR | (バンク0と同じ=未使用) |
05h | PORTA | ポートAのピンのON/OFF (表4) | 85h | TRISA | ポートAのピンの入出力決定 (表2) |
06h | PORTB | ポートBのピンのON/OFF (表5) | 86h | TRISB | ポートBのピンの入出力決定 (表3) |
07h | (未使用) | 87h | (未使用) |
08h | EEDATA | EPROM用データ(現在不使用) | 88h | EECON1 | EPROM用制御レジスタ(現在不使用) |
09h | EEADR | EPROM用アドレス(現在不使用) | 89h | EECON2 | EPROM用書き込み制御レジスタ (現在不使用) |
0Ah | PCLATH | プログラムカウンター2 プログラムをトレースする為の番地を格納 (これって勝手に使用するんじゃないのかな?) | 8Ah | PCLATH | (バンク0と同じ=未使用) |
0Bh | INTCON | 割り込み制御用(現在不使用) | 8Bh | INTCON | (バンク0と同じ=未使用) |
GPR 0Ch〜4Fh | 68バイトの汎用RAM。 いわゆるフリー領域でプログラムで使う変数等を自由に格納出来る。 先頭番地は0Ch。 | GPR 8Ch〜CFh | (バンク0と同じ=未使用) |
取り敢えず動作させる為の手順としては、
a)SFRのSTATUSでバンクを1に切り替える
b)SFRのTRISA(TRISB)で使用するポートの入出力を決定する
c)SFRのSTATUSでバンクを0に戻す
ここまでがイニシャライズ処理。
d)プログラムで使用するデータをGPRに記憶させる。
e)その値に従ってSFRのPORTA(PORTB)のON/OFF処理を行う
といった手順だ。よしよし、少しづつ判ってきたぞ!
次に、ではこれを具体的に実現するにはどうすればいいか?
で、それぞれのレジスタの構造が必要になってくる。
a)SFRのSTATUSでバンクを1に切り替える
(表1)STATUSレジスタは下記の配列となっている。
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
IRP | RP1 | PR0 | TO | PD | Z | DC | C |
未使用 | 未使用 | バンク切り替え 0:バンク0 1:バンク1 | よく判りません (現在不使用) | よく判りません (現在不使用) | よく判りません (現在不使用) | よく判りません (現在不使用) | よく判りません (現在不使用) |
これより、”STATUS”の”RP0”を”1”にすればよい事になる。
これ以降、バンク1の操作が可能になる訳だ。
b)SFRのTRISA(TRISB)で使用するポートの入出力を決定する
TRISA、TRISB共に、
0:出力
1:入力
となる。
(表2)TRISAレジスタは下記の配列となっている。
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
--- | --- | --- | TRIS A4 | TRIS A3 | TRIS A2 | TRIS A1 | TRIS A0 |
未使用 | 未使用 | 未使用 | 3番ピン | 2番ピン | 1番ピン | 18番ピン | 17番ピン |
(表3)TRISBレジスタは下記の配列となっている。
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
TRIS B7 | TRIS B6 | TRIS B5 | TRIS B4 | TRIS B3 | TRIS B2 | TRIS B1 | TRIS B0 |
13番ピン | 12番ピン | 11番ピン | 10番ピン | 9番ピン | 8番ピン | 7番ピン | 6番ピン |
これより、”TRISA(TRISB)”の全てを0にすれば、全てのピンが出力用になる事が分かる。(今はまだ個別設定はしない)
c)SFRのSTATUSでバンクを0に戻す
a)同様に”STATUS”の”RP0”を”0”にする。
これ以降、バンク0の操作が可能になる。
d)プログラムで使用するデータをGPRに記憶させる。
開始アドレスは0Chから。詳細は「アセンブラ命令と引数の意味」で。
e)その値に従ってSFRのPORTA(PORTB)のON/OFF処理を行う
PORTA、PORTB共に、
0:OFF
1:ON
となる。
(表4)PORTAレジスタは下記の配列となっている。
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
--- | --- | --- | RA4 | RA3 | RA2 | RA1 | RA0 |
未使用 | 未使用 | 未使用 | 3番ピン | 2番ピン | 1番ピン | 18番ピン | 17番ピン |
(表5)PORTBレジスタは下記の配列となっている。
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
RB7 | RB6 | RB5 | RB4 | RB3 | RB2 | RB1 | RB0 |
13番ピン | 12番ピン | 11番ピン | 10番ピン | 9番ピン | 8番ピン | 7番ピン | 6番ピン |
これより、”PORTA(PORTB)”のRA0〜RA4(RB0〜RB7)を1にすれば、そのピンから出力ONになる事が分かる。
8ビットあるので全部を載せる訳にはいかないが、例えば、
17番ピンのみONさせたい場合 | 1h | 1=1h |
17番&18番ピンのみONさせたい場合 | 3h | 1+1*2^1=3=3h |
13番ピンのみONさせたい場合 | 80h | 1*2^7=128=80h |
6番〜13番ピンをONさせたい場合 | FFh | 1+1*2^1+1*2^2+1*2^3+1*2^4+1*2^5+1*2^6+1*2^7=1+2+4+8+16+32+64+128=255=FFh |
となる。これは進数の考え方なので、別途2進数と16進数の理解が必要。
C「PIC16F84A」のEPROMの意味
いわゆる不揮発性メモリ。
容量は64バイトでプログラムで書き換えが可能。
書き換え回数上限は100万回だが、ワーク変数などに用いてしまうと一瞬で上限に達してしまうらしい。
よって固定数値など保存が必要な場合のみ使用した方がよさそうだ。
今はまだ使わないからこれ以上はあまり探求しない!
【準備Dアセンブラ命令と引数の意味】
アセンブラの基本命令は全部で35種類!
なんて嬉しい仕様なんでしょう!
しかしそれは上記パラメータを理解した上で初めて成り立つものなので、まだまだ油断は出来ません。
んで、いろいろなHPに掲載されている「電子工作のためのPIC活用ガイドブック(技術評論社)」の一覧があるが、たった35種類でも混乱してくる。
だから取り敢えず、今使う命令だけを列挙して少しずつ増やしていこっと!
またこの他に「擬似命令」なるものが幾つかあって、主にプログラムを構成する「宣言命令」に相当するらしい。
これも出てきたものから順次覚えていく事にしよう。
取り敢えず下記はシンプルなソースに基づいてソースのアップダウン順に掲載してみた。
またこの中に出てこないキーワードで「ワーク領域W」の存在がある。
他言語ではワーク領域も変数定義するのだが、この「W」というワーク領域だけは「勝手にどこかに作られたただ1つの指定領域」らしい。
ただの「ワーク変数」かと思っていたがどうやら「チップに書き込む橋渡しをする特別な変数」らしい。
だから以下の説明文中でもそのまま「ワークW」と呼ぶ事にする。
擬似命令 | 意味 |
LIST | 使用するチップの種類を宣言する。コンパイル時に必要なおまじない。 |
INCLUDE | 使用するチップの情報を外部ファイルで取り込む。コンパイル時に必要なおまじない。 |
__CONFIG | プログラムメモリ上のコンフィギュレーションワードの設定。プログラム起動時に必要なおまじない。 |
EQU | 番地を変数名に置き換えて判り易くする為の初期宣言。 |
SET | 初期宣言した変数の番地を変更する場合に使用。(今回は使用しないけど) |
ORG | プログラムの先頭番地を指定する命令。通常は0を設定。 |
MAIN | 固定の名前ではないが通常プログラムを開始する時のスタート宣言として用いる。 |
(この間に下表の命令を使ってプログラムを作る感じ!) |
END | プログラムの終了宣言。他の言語と違う点はサブルーチンもこの間に含めてしまう事。 |
命令 | 引数1 | 引数2 | 意味 | 使い方例 | 使い方例の説明 |
BSF | レジスタ名 | ビット位置 | 指定レジスタの指定ビットを1にする | BFS STATUS,RP0 | STATUSレジスタの5ビット目を1にしてバンクを1にした |
CLRF | レジスタ名 | (なし) | 指定レジスタを0クリアする | CLRF TRISB | TRISBをゼロクリアして全て出力モードにした |
BCF | レジスタ名 | ビット位置 | 指定レジスタの指定ビットを0にする | BCF STATUS,RP0 | STATUSレジスタの5ビット目を0にしてバンクを0に戻した |
MOVLW | 数値 | (なし) | 数値をワークWへ代入する | MOVLW 80h | 128(10)という数値をワークWへ代入する。 数値の意味は「ただの数字」でよい。 |
MOVWF | レジスタ名 | (なし) | ワークWの数値を指定レジスタへ代入する | MOVLW PORTB | ワークWの数値をPORTBへ代入してPORTBのON/OFF設定を行う。 数値の意味はビット毎の値変更。 例えば80hなら10000000だからRB7だけがONになる。 |
CALL | ジャンプ先ラベル名 | (なし) | 他の言語ではメイン処理からサブルーチンを呼び出す意味で「指定ルーチンを呼ぶ」になるのだが、ルーチン内なので「指定場所にジャンプする」になる | CALL Timer | Timerというラベルにジャンプする |
GOTO | ジャンプ先ラベル名 | (なし) | 指定ラベルに飛ぶ。主にループ処理で使用。CALLで呼び出した場合は必ずRETURNで戻り、GOTOしてはいけない。 まぁ、プログラムの基礎という事で。 | GOTO LOOP1 | 処理をLOOP1へ強制送還する |
RETURN | (なし) | (なし) | CALLで呼ばれた次のステップへ進む | | |
NOP | (なし) | (なし) | 何もしないで1サイクル使う。タイマーカウンター等で使う | | |
DECFSZ | レジスタ名 | 格納先 | 指定レジスタの値を−1して、その値を格納先に代入する。 格納先は、 0:ワークWに代入する 1:指定レジスタに戻す 但し−1した値が0ならば次の命令(通常はループに戻るGOTOなど)を飛ばしてその次の命令を実行する | DECFSZ GPR2,1 | GPR2という変数名を持った番地に代入されている値から−1して、またGPR2番地に戻してやって次の命令へ。 但しその値が0だったら次の次の命令へ |
実際にプログラムを作ってみる
上記を参考にしながら実際にプログラムを作ってきます。
ソースは例によって先生のHPにあるものです。
****************************
ソースはこちら
****************************
さぁ、テストです。
ちなみに電源を毎回接続するのが面倒になってきたので、ジャックをブレッドボードへ接着しちゃいました。
そのうちにスイッチを付けようとは思いますが、取り敢えず+端子を長めにして・・・
完成!
このタイマーの計算を何度も読み返してみたんですが、サイクルの算出が命令単位なので難しくて・・・・。
だから完全に理解はしていないままです。
【実践的テスト開始!】
さてさて、大枠が理解できたところで、もう8月。
来月の京都ツーリングに向けて早く盗難アラームを作らないと何の意味もない!
だからこれ以上の応用編は全部省略して、いきなり本番に向けて製作を始めちゃいます!
T.抵抗分圧のテスト
またなんやかんやと買い込む。
金属皮膜抵抗1W | 1.8kΩ 1.2kΩ | 1個 | 20円 |
ACアダプター | 12V用 | 1個 | 700円 |
3端子レギュレータ | TA4805S | 1個 | 100円 |
液晶モジュール | SC1602BSLB | 1個 | 700円 |
昇圧コンバータ | MAX662DIPモジュール | 1個 | 400円 |
ブレッドボード用 ジャンパーワイヤー | 白 赤 黒 緑 青 | 各1袋 (10本) | 各300円 |
本番に向けて、先ずは電源供給ルートの確保から。
電源は出来ればバッテリーから直で取りたい。理由は「面倒だから」の一言。
しかしPICは5V。
12Vから5Vのステップダウンは相当キツイのでは?
5/12=41.6%とギリギリセーフ?・・・・・う〜ん・・・ま、やってみよう!
先ずは抵抗だけでステップダウン。
机上なのでAC12Vアダプターを買ってきてテスト。
抵抗も当然発熱対策で1Wの金属皮膜抵抗を用いる。
このまま電圧を掛けると(ストップランプの時の様に)ボンッ!ってLEDが破裂するぞ!
オームの法則(懐かし!)より、
V=IR
従って、V1=IR1+IR2+・・・・より、
V2=V1R2/(R1+R2))
となる。
この場合は、
5=12(R2/(R1+R2)
1.8kΩを持っているからE24に当てはめてみると、
R1=1800Ω
R2=1300Ω
となる。
取り敢えず1.3kΩが無かったので1.2kΩでテストしてみる。
計算上では4.8Vになる。
ピッタリ!
これでAC12Vアダプターを使って実験が出来るようになったぞ!
暫く電圧を掛けてテストしてみる。
尤も、殆ど電流を流してないので意味は無いのであるが、
少なくとも熱くなる事はなかった。
0.2V落ちてもけっこうLEDが暗くなるもんだなぁ・・・・。
電圧管理はシビアにやらないとダメなのね。
それよりもさぁ・・・何の為に3端子レギュレータ買ってきたのよ!?
真面目にやろうとしてるのに・・・・・。
ってな訳で、折角買ってきた「TA4805S」を使ってみる。
ステップダウンの代償で熱変換するのは当然の事だけど、
それは1つより2つ、2つより3つに分散した方がよくね?
って考えに基づいて、
抵抗分圧:12V⇒7V
3端子レギュレータ:7V⇒5V
だったら、なんか均等に発熱してくれて壊れにくくね?
って思ったの・・・・んで、やってみる。
なんと偶然にも、さっきの
R1=1800Ω
R2=1200Ω
を、
R1=1200Ω
R2=1800Ω
に引っくり返せば7Vの出来上がり。
ラッキー!
んで、レギュレータを通してみると、5.01V!
嬉しっ!
これで分圧・・・・というかステップダウンの目処が付いた。
実は買い物をする時点で、マイコン処理後に復帰する電圧について考えてみた。
1:マイコン通過後に自力で12Vに復帰、つまりステップアップする。
2:リレーを使って無関係のままにしておく。
2:の方が簡単だが、面白そうなので、12V昇圧DC−DCコンバータ・モジュール「MAX662A」を買ってみた。
そのうちに使ってみよう。
U.ADコンバートのテスト
@どうやってコンバートすればいいのか?判らない。
Aどうやって検証すればいいのか?判らない。
のAが気になって、お買い物時に「液晶LCDモジュール」なんぞも買ってみた。(もう・・・ハマりまくりか・・・・)
どうやって使うのか?はもちろん!全く判らん!!
とってもワクワク状態です・・・・先ずは、
A)LCDで「CB1300イチサンCLUB」を表示するプログラムの作成
B)アナログ入力が可能なチップの選定と内部クロック化
C)アナログセンサーを使ってLCDに測定値を出力してみる
までが完成したら、いよいよ「3軸加速度センサー」にお出まし頂こうと思っている。
尚、チップの選定に関しては、
・電圧5V
・84Aコンパチ
・ADコンバータ内蔵
・コンパレータ内蔵でヒステリシス管理が出来る
などを基に探してみる。
A)LCDで「CB1300イチサンCLUB」を表示するプログラムの作成
取り敢えず、何も判らずググッてみると、ものの数秒で該当サイトにヒット!
そこには「16F84」で作ったLCD操作のサンプルがあった。
全く便利な世の中になったよ・・・ってか、こんな世の中じゃなきゃ、こんな事には手は出さないけどね・・・。
取り敢えず回路図通りにジャンパーしてみる。
このサイトの図がとても判り易かったので、
自分でも資料として保管する意味で描いて残しておこうと思います。
(とても判りやすい図をありがとうです!)
線が14本になると揺れただけで接触不良になるみたい。
慎重に慎重に・・・・。
んで、ソースは例によってコピペ。
「16F84A」と何が違うのか?
幾つかエラーが出たが、ラベル名変えたり入力し直したりしているうちにエラーが消えた。
よく判らん。
で、電源を入れてみるとアッサリと・・・・⇒
本当はバックライトを付けて写真を撮りたかったんだけど、揺らすと消えちゃったり文字化けしちゃうので諦めました。フラッシュが当たっちゃったけど、
--------------------------
CBイチサンCLUB
1300sf
--------------------------
って書いてます!
ちなみにコンパイル時に出る”Message[302] ”は、バンク0以外で実行する命令の全てに対して出るメッセージだそうで、
逆に言えば、このメッセージが出ているステップ番号を追う事で、ちゃんとバンク1に切り替わっているか?のチェックが出来る。
とにかく「16F84A」で正常に表示できる事が判ったので、この配線をLCDに付属していたピン・ソケットで固定してからソースの解析といきましょうか!
8月15日
LCDに付属のコネクターピンを眺めていて気がついた。
大きい方を逆さにしてハンダ付けすればジャンパーワイヤーピンがダイレクトに刺せる。
それをボンドで固めたらいいんでないかい!?
しかし肝心のジャンパー線が足りなくて作業中断。
赤・黒・緑・青(合計40本)を買い足して続行。んで、こうなった⇒
大成功!
赤:Vdd
黒:Vss、V0
緑:RS、R/W、E
白:データ
白のデータ線は8本あるので、DB0〜DB7まで、マジックで線を1本ずつ増やしてみた。
バックライトは4.2Vなので降圧が必要だが、既存のパターンと穴を使いたかったので、
抵抗を通す為に不要なパターンをカッターでカットする。
抵抗は62Ωしか持ってなかったので、そのまま付けたらチト暗い。
で、並列に2個使う事にした。31Ωにしたら満足の明るさ!
ボンドが乾いた処でピンを刺してみる。
こりゃいいぞ!!
バックライトが点くと、とっても見やすい!!(↓)
LCDのファームウェアを理解する
さて、ウソっこ完成を見届けたところで、ファームウェアとプログラムの解析に入ろう。
SC1602BSLBのピン配置と意味 |
ピン番号 | 記号 | 意味 |
1 | VDD | 電源5Vへ |
2 | VSS | GNDへ |
3 | V0 | GNDへ |
4 | RS | 0:コマンドモード 1:データモード ストローブする際にはコマンドモードにする必要あり。 LCDにデータを表示させる場合はデータモードにする。 |
5 | R/W | 0:書き込みモード 1:読み込みモード LCDに表示させる場合は書き込みモード。 LCDからビジー情報などを得る時は読み込みモード。 |
6 | E | 0:イネーブル 1:ストローブ ストローブとはストロボの事で「その一瞬を切り取る」という意味。 書き込みモードの場合は「その瞬間にワークWの内容を書く」となる。 読み込みモードの場合は「その瞬間のLCDの値を読み取る」となる。 |
7 | DB0 | データの下位4ビット 要はアスキーコードの左の16進値。 さすがに制御コード域は使えない。 逆にE0〜FFにも何か入ってるぞ! それ以外はアスキーコードと同じで、数字は30h〜、アルファベットは41h〜と馴染みやすい。 |
8 | DB1 |
9 | DB2 |
10 | DB3 |
11 | DB0 | データの上位4ビット 要はアスキーコードの上の16進値 |
12 | DB5 |
13 | DB6 |
14 | DB7 |
文字コード表
| 上位 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
下 位 | 0 | | | SPACE | 0 | @ | P | ` | p | | | | − | タ | ミ | α | Ρ |
1 | | | ! | 1 | A | Q | a | q | | | 。 | ア | チ | ム | | |
2 | | | ” | 2 | B | R | b | r | | | 「 | イ | ツ | メ | β | θ |
3 | | | # | 3 | C | S | c | s | | | 」 | ウ | テ | モ | ε | ∞ |
4 | | | $ | 4 | D | T | d | t | | | 、 | エ | ト | ヤ | μ | Ω |
5 | | | % | 5 | E | U | e | u | | | . | オ | ナ | ユ | σ | |
6 | | | & | 6 | F | V | f | v | | | ヲ | カ | ニ | ヨ | ρ | Σ |
7 | | | ’ | 7 | G | W | g | w | | | ァ | キ | ヌ | ラ | | |
8 | | | ( | 8 | H | X | h | x | | | ィ | ク | ネ | リ | √ | |
9 | | | ) | 9 | I | Y | i | y | | | ゥ | ケ | ノ | ル | | |
A | | | * | : | J | Z | j | z | | | ェ | コ | ハ | レ | | 千 |
B | | | + | ; | K | [ | k | { | | | ォ | サ | ヒ | ロ | | 万 |
C | | | , | < | L | ¥ | l | | | | | ャ | シ | フ | ワ | φ | 円 |
D | | | − | = | M | ] | m | } | | | ュ | ス | ヘ | ン | | ÷ |
E | | | . | > | N | ^ | n | → | | | ョ | セ | ホ | ゛ | | |
F | | | / | ? | O | _ | o | ← | | | ッ | ソ | マ | ゜ | | ■ |
灰色:未使用
ピンク:キーボードの入力が判りません!!(LCD付属のキャラクターパターンシートを参照下さい!)
LCD表示行桁の各番地
| 桁 |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
行 | 1 | 00h | 01h | 02h | 03h | 04h | 05h | 06h | 07h | 08h | 09h | 0Ah | 0Bh | 0Ch | 0Dh | 0Eh | 0Fh |
2 | 40h | 41h | 42h | 43h | 44h | 45h | 46h | 47h | 48h | 49h | 4Ah | 4Bh | 4Ch | 4Dh | 4Eh | 4Fh |
いろいろ読み進めてみると、何だかLCDの初期化ってとっても面倒臭い。
もう余り考えずに「おまじない」にしておこうと思う。
初期化@:ファンクションをセットする(固定)
RS | R/W | DB7 | DB6 | DB5 | DB4 | DB3 | DB2 | DB1 | DB0 |
0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 |
出来る限り固定値で覚えたいのでファンクションは全て固定とした。一応設定箇所としては、
DB4:1=8ビット使用時
0=4ビット使用時
DB3:1=1/16デューティー
0=1/8デューティー
「デューティー」が「デュティー比」の事だとするならば、LCDが点灯している時間と消灯している時間の割合だと思うのだが。
1/16ならば点灯時間を1とするならば、消灯している時間が16って事なんだけど、実際にはそんなに消灯しているとは思えないなぁ・・・。
逆だとしたら97%の点灯?・・・この辺の説明がどこにも見当たらないのよ・・・判りません!
DB2:1=文字フォント5*10
0=5*7
初期化A:表示クリア(固定)
RS | R/W | DB7 | DB6 | DB5 | DB4 | DB3 | DB2 | DB1 | DB0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
全表示クリア後、カーソルを00h番地へ戻す。
初期化B:エントリーモードの設定(可変)
RS | R/W | DB7 | DB6 | DB5 | DB4 | DB3 | DB2 | DB1 | DB0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | X | Y |
カーソルの進む方向と表示をシフトさせるか否かの設定。
X:1=アドレス+1でカーソルを右へ動かす。
0=アドレス−1でカーソルを左へ動かす。
Y:1(且つX=1の時)=左へシフトする。
1(且つX=0の時)=右へシフトする。
0=表示はシフトしない。
初期化C:表示のON/OFF(固定)
RS | R/W | DB7 | DB6 | DB5 | DB4 | DB3 | DB2 | DB1 | DB0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 |
DB2:1=表示オン
0=表示オフ
DB1:1=カーソル表示
0=カーソル非表示
DB0:1=文字ブリンク(その文字がブリンクするだけ。しかも塗り潰しのブリンクなので正確には意味ない気がする)
0=文字ブリンクしない
その他のインストラクション@:ビジー監視
RS | R/W | DB7 | DB6 | DB5 | DB4 | DB3 | DB2 | DB1 | DB0 |
0 | 1 | X | data | data | data | data | data | data | data |
リードモードで使います。書き込みを行う前に、書き込みが可能か?のチェック。
書き込みがOKの場合hは「DB7=0」になるので、それを確認&待つ(LOOP)。
X:1=書き込み不可
0=書き込み可
その他のインストラクションA:カーソルホーム
RS | R/W | DB7 | DB6 | DB5 | DB4 | DB3 | DB2 | DB1 | DB0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
表示をクリアしないで上書きしたい時に用いるようだ。
DB1:1=表示はそのままにカーソル位置を00h番地へ
その他のインストラクションB
・CGRAMアドレスセット
・DDRAMアドレスセット
・CGRAM/DDRAMへの書き込み
・CGRAM/DDRAMからの読み込み
があるが、使い方が全く判らん!ので放置です。(^^;
LCDのプログラムを理解する
ここで気がついた事。
プログラミングは昔からテキストエディターを使用してます。
尤も、DOSしか無い時代からだから、VZとかREDとか随分お世話になりました。
んで、やっぱり背景が黒の方が落ち着くので、現在愛用してるQXでプログラミングをしたのね。
それを全選択のコピペしようと、MPLABをアクティブにしたらナント!
「ファイルが変更されているけどリロードする?」
って聞いてくるじゃありませんか!!スゴイ!&エライ!これでプログラミングが随分と楽になりました。
****************************
ソースはこちら
****************************
なんかエディタのソースをコピペするとひどいなぁ〜・・・・・。
HYOUJIのコメントの部分は「エントリーモード」を替えて「左に流れる文字」にした例。(→)
流れて消えたまんま暫く帰ってこない・・・・。
調べてみたら表示は16桁なのに内部座標は40桁まであるらしい。
LCDは本来キャラクタパターンなど持っていなく、
LCDコントローラドライバというチップが担っているらしい。
SC1602BSLBには沖データのMSM6562B-01というコントローラドライバが使われているそうな。
で、沖データはSC1602BSLB専用に開発した訳では無く汎用的に作ったのだそうだ。
なるほどね。世の中には詳しい人が一杯いますなぁ〜・・・・。
B)アナログ入力が可能なチップの選定と内部クロック化
さらにちょっと買い込む。
PICマイコン | PIC12F683−I/P | 1個 | 150円 |
PICマイコン | PIC12F675−I/P | 1個 | 120円 |
PICマイコン | PIC16F88−I/P | 1個 | 200円 |
PICマイコン | PIC16F819−I/P | 1個 | 180円 |
さて、ここまできて「84A」で出来ない事をやらなければならない。アナログ変換である。
いろいろなサイトを参考に、
・「84A」コンパチで
・A/Dコンバータ内蔵で
・コンパレータ内臓(意味と使い方がおぼろげなんだけどきっと使う気がするので)
の結果から、
・PIC16F88
・PIC16F819
・PIC12F683
を購入してみた。
最終的に電圧変化の感知がキモなので先生のHPにある「84A」の簡易A/Dコンバートでは辛いのでは?との考えからだ。
ところがこの先生、ちゃんと別のチップでもA/D変換の記事を載せている。
しかも上記の3チップのうち「16F88」と「12F683」のA/Dコンバートについてアップしていた。全くすげ〜よ。
ちょっとこの辺で先生にメールして挨拶しておこ。あまりにも盗作続きなものだかさ・・・・(^_^;
と言いながらも「16F88」との比較表がもう便利で!便利で!(この表には「16F819」も載っている!)・・・・自分の手元に置いておきたくて頂いちゃいました。
| PIC16F84A | PIC16F88 | PIC16F819 |
命令数 | 35 |
プログラムメモリサイズ(ワード) | 1024 | 4096 | 2048 |
1ワードのビット数 | 14 |
データメモリサイズ(バイト) | 68 | 368 | 256 |
EEPROMメモリサイズ(バイト) | 64 | 256 |
I/O数 | 13 PORTA:5 PORTB:8 | 16 PORTA:8 PORTB:8 |
最大クロック | 20MHz |
内部クロック | − | 〜8MHz |
タイマー | TMR0:8bit WDT:8bit | TMR1:16bit TMR2:8bit WDT:8bit |
A/D変換チャネル数 | − | 7 | 5 |
A/D変換精度 | − | 10bit |
コンパレータ数 | − | 2 | − |
ECCP/CCP数 | − | 0/1 |
PWMチャネル数 | − | 1 |
PWM精度 | − | 10bit |
ハードウェア乗算命令 | − |
BOR | なし | あり |
省電力対応 | なし | あり |
電源電圧 | 4.5〜5.5V | 4.0〜5.5V |
価格 | 250円 | 200円 | 180円 |
んで、具体的な違いは何だろう?って思う間もなく、次の項目で先生がしっかり書いている!恐れ入りました・・・・。
やっぱりこの先生のサイトへのリンク切れが生じたら、このHP自身がスカスカになってしまう・・・・やっぱり手元に置かせて下さいな!
変更・修正箇所は4点。
@宣言文の変更1:ソースのLISTとINCLUDEの型番を変更(これは当たり前の事か)
LIST P=PIC16F88
INCLUDE P16F88.INC
A宣言文の変更2:__CONFIGへの追加。機能が増えている分だけ宣言も多くなっているようだ。
詳細はまだ読んでないので判りませんが、おまじないなのでこのまま使います。
__CONFIG _CONFIG1, _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _HS_OSC & _LVP_OFF & _CPD_OFF & _DEBUG_OFF
B初期設定がアナログになってる
アナログ入出力を持つチップは電源投入時にはアナログになっているそうな。
だから必要に応じてデジタルに設定しておく必要があるとの事。
BSF STATUS,RP0 ;バンク1に切替え
CLRF ANSEL ;A/D未使用
BCF STATUS,RP0 ;バンク0に切替え
Cデータメモリ領域の先頭番地が違う!
これが大きい。これを間違えると全く動かないのでリソースが大変。だから頭で変数宣言しておくんだな!よく判りました。
先頭番地は0Chではなく20hだそうだ。
あくまでもデータ領域の事なのでプログラム領域と間違えないように!>自分
ってな訳で、これからはPIC16F88を使用する事にした。
ここで「84A」と比較しながらピン配置を眺めてみる。
ポートA、ポートB、Vss、Vddは変わらないようで安心!
ピン配置だけでなく名称も同じなので、本当に上記の命令箇所を変えればよいだけのようだ。
オシレータの2箇所(15ピン、16ピン)が「RA6/RA7」として使える。
「88」は内部クロックを持っているので、これを使えば、「RA3/RA6/RA7」の3つを3軸で使えそうだ!(なんか先が見えてきたよ!)
取り敢えず現行から移植してみる
取り敢えず、現在のLCD一式をそのまま「88」に移植してみる。
上記変更を終えてPickit2で呼び出してみると「Worning:Some configuration words not in hex file」のメッセージが。
気にせず書き込んでみたものの動作せず。HPでいろいろ調べてみたら、コンフィグの記述がおかしいらしい。
そこでまたいろいろなサイトから「88」用のソースを参照して片っ端から入れ替えてみる。数回目でやっと動くコンフィグを発見!(↓)
__CONFIG _CONFIG1, _HS_OSC & _MCLR_OFF & _LVP_OFF & _WDT_OFF & _PWRTE_ON & _BODEN_OFF & _CPD_OFF & _CP_OFF & _WRT_PROTECT_OFF
__CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF
内部クロックへの切り替え
12F683用のソースを参照しながら、
MOVLW 070h ;8MHzを
MOVWF OSCCON ;で指定する。
をバンク1で設定すれよいと気がつく。それだけ?
ワクワクしながら接続。
ん?作動しない。
そっか!オシレータ入れたままだった。配線とともに外してみる。
あれ?動かない。
やっぱ「それだけ?」が気になっていろいろ調べてみる。
気が遠くなる程の資料の中から「_INTRC_IO:オシレータは内部クロック使用」を見つけた。
なんだ!やっぱり加筆が必要なんじゃん!・・・・と、その出典を辿ったら・・・・・先生の「汎用PWMコントローラ」のページだった!
やっぱり戻ってくるのね・・・・・改めて・・・・スゲ〜ッ!!
__CONFIG _CONFIG1, _WDT_OFF & _BODEN_ON & _PWRTE_ON & _LVP_OFF & _INTRC_IO ;_INTRC_IO=内部クロックを使用!
__CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF
と、こうすればいい事が判った。
結局先生のコンフィグに「_CONFIG2」の部分と追加してやれば良いのだが、その理由がまだ判らん・・・・。
ついでにその検索途中で「内部オシレータの微調整」ってなコンフィグレーションについて書かれたサイトもあったので、
MOVLW 1Fh
MOVWF OSCTUNE
なんぞも加えてスイッチON!
バックライトが点いた!・・・・消えた?・・・・点いた!・・・消えた?・・・・・????
接触不良みたいな感じで点いたり消えたり・・・・。
ふ〜む・・・・よく見るとコンデンサに電気が溜まっている時だけ動作する感じ・・・・・。
う〜ん・・・・一番最初のLED点滅まで戻って配線を見てみる。
あっ!
さっきオシレータ用の配線を外した時にMCRの配線も外したわよね!?
と配線してみると見事に安定して動き始めた。
なるほど。よく判らんがそういう事らしい・・・・・。
ついでに10MHzから8MHzになったので、タイマーのループ回数も減らさにゃいかん。
例によって計算式が理解できないので、そのまま変更する。
よし!これで内部クロック化終了!
これで外部クロックで使っていた15ピンと16ピンがポートとして使えるようになったぞ!
やっぱり「88」のレジスタ表が必要!
って探したが解説しているサイトは無し。
仕方ないのでデータシートを確保する。
見たって判らないよ・・・・。
C)アナログセンサーを使ってLCDに測定値を出力してみる
さて、実験の最後は実際にアナログ機器と接続してみよう!
何故(!)なのかと言うと、ここまでは全てデジタルの世界だったから。
尤も機器といってもここではサーミスタ=温度センサーであるが。
ロジックとしては、
@:アナログ機器の接続ピンを入力に設定する。
A:あるタイミングで入力ピンをストローブする。
B:その値をLCDに出力する。
だけだと思っている。実際にはその入力電圧バンドの調整が必要なのだと思うが。
早速買ってきた「LM35DZ」を取り出す。例によって英語の説明書なので図だけ見る。
なるほど。平らの左が+5Vだな・・・と差してみる・・・・・数秒後に焦げ臭いにおいが・・・・慌ててLM35を摘む。熱っ!
何でや?説明書の図を見る。下に小さく「BOTTEM VIEW」と書いてあった・・・・わはは・・・思いっきり素人がバレちまったぜぃ!!
空いた15ピンと16ピンをアナログ設定しようとピン配置を確認して気がついた。
あれ?このピンってアナログにならないじゃん!
仕方が無いので、現在LCDで使っている17ピンと18ピンをソース上で15ピンと16ピンに変更。
やっぱり単独で光ってくれるLEDって回路のデバックに必要かも?
って事で、3ピン(RA4)をLEDとした。
これで2ピン(RA3=AN3)と17ピン(RA0=AN0)と18ピン(RA1=AN1)の3ピンがフリーになった。
で、現在の配線図はこうなる。(→)
****************ちょっと休憩******************
やっと気付いたよ。
ソケットからICを外す時に、耳掻きが大いに役立っていたのだが、
ちょっとした気分で最後のピンが曲がってしまうのよ。
毎回注意しながら外すのが面倒で面倒で・・・・・。
そっか!
ゼロプレッシャーソケット付ければいいんじゃん!
Pickit2の小さいほうと全く同じものだ。
グッと押し込むと結構しっかり入る。
だがレバーの力の方が強く、ラフにレバーを上げると抜けてしまう。
これはもう接着剤で固定してしまった方がいいのかもしれない。
ま、ピンソケットに比べれば全然楽だが・・・・・。
*****************休憩おわり!*****************
A/D変換のレジスタ
88内蔵のADコンバータは10ビットで構成されている。
つまり2ビット分の1バイトと8ビット分の1バイトの合計2バイトで、”バンク0”にある「ADRESH」レジスタと”バンク1”にある「ADRESL」レジスタだ。
そのレジスタにアナログデータを代入する手順は、
@入力ポートの設定
Aアナログポートの設定
B基準電圧の設定
CA/D入力チャンネルの設定
DA/D変換クロックの設定
E結果配置の設定
Fアナログ使用宣言
G計測開始
H計測終了を監視(アクイジョンタイム込み)
I表示
となる。
@入力ポートの設定
入力ポートを設定するには”バンク1”の「TRIS*」レジスタを操作する。
TRISAレジスタは下記の配列となっている。
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
TRIS A7 | TRIS A6 | TRIS A5 | TRIS A4 | TRIS A3 | TRIS A2 | TRIS A1 | TRIS A0 |
16番ピン | 15番ピン | 4番ピン | 3番ピン | 2番ピン | 1番ピン | 18番ピン | 17番ピン |
TRISBレジスタは下記の配列となっている。
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
TRIS B7 | TRIS B6 | TRIS B5 | TRIS B4 | TRIS B3 | TRIS B2 | TRIS B1 | TRIS B0 |
13番ピン | 12番ピン | 11番ピン | 10番ピン | 9番ピン | 8番ピン | 7番ピン | 6番ピン |
0=出力として使用する。
1=入力として使用する。
今回はRA1(TRIS A1=18ピン)だけを入力に使いたいので、TRISAは「0000010」とする。
ちなみにTRISBは「00000000」となる。
Aアナログポートの設定
アナログポートを設定するには”バンク1”の「ANSEL」レジスタを操作する。
ANSELレジスタは下記の配列となっている。
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
- | RB7 | RB6 | RA4 | RA3 | RA2 | RA1 | RA0 |
未使用 | RB6 | ANS5 | ANS4 | ANS3 | ANS2 | ANS1 | ANS0 |
0=デジタルとして使用する。
1=アナログとして使用する。
今回はANS1(RA1=18ピン)だけをアナログ用に使いたいので「0000010」とする。
B基準電圧の設定
アナログ入力用基準電圧の設定を行う。
通常はVddとVssを使うが、より精度を高めるなら、自由に電圧設定ができるらしい。
その設定は”バンク1”の「ADCON0」レジスタと「ADCON1」レジスタを操作する。
ADCON0レジスタは下記の配列となっている。
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
ADCS1 | ADCS0 | CHS2 | CHS1 | CHS0 | GO/DONE | 未使用 | ADON |
ADCON1レジスタは下記の配列となっている。
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
ADFM | ADCS2 | VCFG1 | VCFG0 | 未使用 | 未使用 | 未使用 | 未使用 |
基準電圧の設定値
VCFG1 | VCFG0 | +電圧 | −電圧 |
0 | 0 | Vdd | Vss |
0 | 1 | Vdd | Vref- |
1 | 0 | Vref+ | Vss |
1 | 1 | Vref+ | Vref- |
「Vref−」は1ピン、「Vref+」は2ピンを使用する事で設定が可能らしい。
取り敢えずは既存のVddとVss、つまり「00」を使用する。
CA/D入力チャンネルの設定
最初に入力ポートの設定を「TRIS*」で行ったが、そこに向けて「チャンネルを開放する」という作業が必要らしい。
その設定は”バンク1”の「ADCON0」レジスタの「CHS2〜0」を操作する。
チャンネルの設定値
CHS2 | CHS1 | CHS0 | アナログポート |
0 | 0 | 0 | AN0 |
0 | 0 | 1 | AN1 |
0 | 1 | 0 | AN2 |
0 | 1 | 1 | AN3 |
1 | 0 | 0 | AN4 |
1 | 0 | 1 | AN5 |
1 | 1 | 0 | AN6 |
今回はAN1をアナログ入力ポートにしているので「001」となる。
DA/D変換クロックの設定
A/D変換を行うクロック数を設定する。
その設定は”バンク1”の「ADCON0」レジスタの「ADCS2〜1」と「ADCON1」レジスタの「ADCS0」を操作する。
何故3ビット指定なのに「ADCON0」と「ADCON1」に別れているか?と言うと「ADCS2が後から追加されたから」らしい。
ADCSの設定値
PICの周波数 | ADCS2 | ADCS1 | ADCS0 |
00.00MHz〜01.25MHz | 0 | 0 | 0 |
01.25MHz〜02.50MHz | 1 | 0 | 0 |
02.50MHz〜05.00MHz | 0 | 0 | 1 |
05.00MHz〜10.00MHz | 1 | 0 | 1 |
10.00MHz〜20.00MHz | 0 | 1 | 0 |
20.00MHz〜40.00MHz | 1 | 1 | 0 |
今回は内部クロックの8MHzだから「101」となる。
E結果配置の設定
これで計測を開始すれば「ADRESH」レジスタと「ADRESL」レジスタに値が収まる事になる訳だ。
そこで、2バイト=16ビットのどこに10ビットを収めるの?を設定する。
余り精度を必要としない場合は、右図の「ADFM=0」様に左詰めにして下位2ビットを捨てて、
ADRESHだけを使う事も可能。(もちろんこれで10ビット使う事も可能だが)
その設定は”バンク1”の「ADCON0」レジスタの「ADFM」を操作する。
今回は10ビット使いたいので右詰めの「1」とする。
Fアナログ使用宣言
上記まででやっとアナログ使用に関する初期設定が終了した。(すげ〜な!この面倒臭さ!)
ここまでやったにも関わらす、最後に「その開始宣言」が必要だそうだ。
その設定は”バンク1”の「ADCON0」レジスタの「ADON」を操作する。
0=アナログ未使用
1=アナログ使用
GH計測開始と終了
計測開始は”バンク1”の「ADCON0」レジスタの「GO」を操作する。
尚、計測が終了すると自動的に0になるので初期化は必要ない。
1=計測開始
I表示
@2進数表示してみる
さて、繋いでみた・・・・・って、やっぱ表示が無いと何だか判んね〜じゃん!
ってな訳で「ADRESH」と「ADRESL」の中身を知るべく「そのまま2進表示」してみる事にした。
理屈は簡単。
イ)各ビットをそのビットだけでマスクする。(他を0にする)
ロ)1ビット目まで右シフトさせる。
ハ)その値をアスキーコードにする為に+30hする。
ニ)それらを変数に入れておいて纏めて表示する。
注)自分のスキルが上がった一ヵ月後の手法
イ)各ビットをそのビットだけでマスクする。(他を0にする)
ロ)そのビットを減算してステータスを見る。
ハ)その結果で30hか31hかを判断する。
ニ)それを変数に入れておいて纏めて表示する。
となった。
A16進数表示
これ見てもよく判らないので、次に16進数で表示してみる。
これも理屈は簡単。
イ)ADRESHは2ビットだけなので、その2ビット以外をマスクする。(他を0にする)
ロ)その値が10進数の9未満なら+30hする。
ハ)10以上(A〜F)なら+37hする。
ニ)ADRESLは8ビットだから上位4ビットと下位4ビットに分離する。
ホ)それぞれに対してロ)とハ)を実行。(上位4ビットは4ビット目まで右シフトする事)
チ)それらを変数に入れておいて纏めて表示する。
B1.023Vの取得
早速その16進表示を計算してみる。
5.2℃!?・・・・・確かに8月の部屋のクーラーは効いているが・・・・んな訳ねぇ〜じゃん!
まさかLM35DZが壊れてる?
ここでまた先生のサイトを熟読する事数時間・・・・「基準電圧の作り方」が目に付いた。
そういえばさっき”基準電圧の設定”って項目があったな・・・判らないから飛ばしたけど・・・・。
「今回必要な基準電圧は1.023Vです」
えっ?何それ?・・・と読み続ける・・・・・・・!!!!
ここで判った事。
10ビットは10進数で1024まで分解可能(0〜1023)。
で、LM35DZの出力の最大が1Vだから、
基準電圧を1.023VにすればA/D変換結果をちょうど1mV単位で分解出来る・・・・って訳だ。
つまり、
0mV=0℃
1mV=0.1℃
10mV=1℃
100mV=10℃
1V=100℃
となる訳だ!すごいぞ!>先生!
って事は、今5Vが掛かっているハズだから5/1.023倍してやれば正しい値になるって事か?
5.2*5=26.0℃・・・・!!!・・・なんか合ってそう・・・♪
じゃぁ、このまま5倍すればいいだけじゃん!・・・・・を更に読み進めると、
「Vddは不安定で変動する。だから精度を高めたければVref+を使うべき」とあった。
ふむ・・・・で?・・・Vref+って?・・・・・あっ!「c)基準電圧の設定」の事か!
で、PIC16F88のピン配置図まで戻る。
RA2=Vref−
RA3=Vref+
とある。なるほど。この事だったのか!
つまり電圧を自在に入出力する、特に+入力を使いたい時は、RA3を使えばいいんだ。
つまりは、温度センサーのアナログ処理用にRA3を5V⇒1.023Vに降圧して接続すればいい事になる。
当然、入力モードに変更する必要がある訳だ。
ところで、1.023Vって、どうやって実現するの?
これも調査の結果、
・単純な回路にしないと不安定さが増すだけ。
・しっかりとレギュレートできている事。
・微調整は半固定抵抗で。
から、こんな回路となった。(→)
5Vから1.2Vまで降圧できる可変レギュレータLM350を経由して、
100Ω*2の抵抗で分圧を取る。
この時点で1.24Vだったので100Ωの半固定抵抗で調整する。
最初は1個20円の半固定を買ってきたのだが、チャチすぎ!
ちょっと指で触るとすぐに+−0.2Vくらい変動してしまう。
だから真面目な(?)1個130円のモノと取り替える。
この時点で回路図はこう変更している。(→)
なぜ表示の段階になって?
しかも16進数表示と10進数表示の間に。
実は16進表示した時点でちょっと高めの表示されている気がしたのね。
それが「電圧不安定」か?と思ってみたんだけど、
実際1.023Vにしても16進表示では余り変わらなかった。
ま、気にせず進めますか。
C10進数表示
さて、ここで再びアセンブラの習得に1週間を費やす事になった。
何故なら・・・・10ビットのBCD変換(バイナリ−デシマル変換)ってば・・・・・・・超難関!!
大概のソースは眺めればフローチャートは浮かんでくるものだが、このルーチンに関しては、さっぱり判らなかった。
しかもC言語なら数分もあればプログラミングできる
if( i > 0 ){
処理1
}else{
処理2
}
といったフローに四苦八苦なのである。
で、いろいろ見ているうちに、先に用意した命令一覧はそもそも情報が欠落している事が解って来た。
前回はただ命令内容だけを書いて後の付属は無視したが、それでは辛くなってきたのだ。
特に分岐ルーチンなどは35個の命令以外にステータスのフラグを監視する必要があったのだ!
しかも「リテラル」とか「レジストリファイル」だとかの意味も判ってくると余計にキッチリとした記述が必要になる。
” f ”はレジストリファイル=変数の事で、変数以外は受け付けない。だから、
MOVF 80h,W
とやっても反応してくれないのだ。(これに気付くのに1週間掛かったよ・・・・)
逆に” k ”はリテラル=数値の事で、数値以外は受け付けない。だから
MOVLW WORK
などとやっても反応しない。
やっかいなのはこれらを記述してもコンパイルエラーにならない事。
MPLABのデバックで追いかけてやっと気が付くのだ。
アセンブラ初心者は知らないでor気づかずに記述ミスをしてしばらく悩む事になる。
やっとこれらが理解出来てきたよ。
だからしっかりと命令一覧を作らなければならないんだ!
これまでに増えた命令に加えて、とっ払った付属を理解しながら改めて表にしてみる。
(しかし意地でも書き写しはしない!しかも自分が判る言葉しか使わない!)
よっしゃ!全35命令表完成!
群 |
命令 |
引数1 |
引数2 |
意味 |
例 |
変化するステータス |
変数 単体の 操作 (14個) |
初期化 (2個) |
CLRF |
レジスタ名 変数名 |
なし |
レジスタ(変数)を0クリアする |
CLRF TRISB CLRF WORK |
必ずZ=1 |
CLRW |
なし |
なし |
Wを0クリアする |
CLRW |
必ずZ=1 |
演算 (4個) |
DECF |
レジスタ名 変数名 |
格納先 0 or W ⇒Wに代入 1 or F ⇒そのレジスタ または変数に戻す |
レジスタ(変数)−1の結果を格納先へ代入 |
DECF WORK,W |
変数-1 = 0
ならZ=1
それ以外
ならZ=0
|
DECFSZ |
レジスタ名 変数名 |
格納先 0 or W ⇒Wに代入 1 or F ⇒そのレジスタ または変数に戻す |
レジスタ(変数)の値−1を格納先に代入して、その結果が0ならば次の命令をジャンプする |
DECFSZ DMY,W DECFSZ DMY,F |
なし |
INCF |
レジスタ名 変数名 |
格納先 0 or W ⇒Wに代入 1 or F ⇒そのレジスタ または変数に戻す |
レジスタ(変数)+1の結果を格納先へ代入 |
INCF WORK,W |
変数+1 = 0
ならZ=1
それ以外
ならZ=0
|
INCFSZ |
レジスタ名 変数名 |
格納先 0 or W ⇒Wに代入 1 or F ⇒そのレジスタ または変数に戻す |
レジスタ(変数)の値+1を格納先に代入して、その結果が0ならば次の命令をジャンプする |
INCFSZ DMY,W |
なし |
判断 (2個) |
BTFSC |
レジスタ名 変数名 |
ビット位置 |
レジスタ(変数)の指定 ビット目が0だったら次命令をスキップする |
BTFSC WORK,1 |
なし |
BTFSS |
レジスタ名 変数名 |
ビット位置 |
レジスタ(変数)の指定 ビット目が1だったら次命令をスキップする |
BTFSS WORK,1 |
なし |
シフト 操作 (2個) |
RLF |
レジスタ名 変数名 |
格納先 0 or W ⇒Wに代入 1 or F ⇒そのレジスタ または変数に戻す |
1ビット左へシフトする。 1ビット目には現在ステータスのCに入っている内容が補充される |
RLF WORK,W |
C=シフトで 押し出された 8ビット目 |
RRF |
レジスタ名 変数名 |
格納先 0 or W ⇒Wに代入 1 or F ⇒そのレジスタ または変数に戻す |
1ビット右へシフトする。 8ビット目には現在ステータスのCに入っている内容が補充される |
RRF WORK,W |
C=シフトで 押し出された 1ビット目 |
ビット 操作 (4個) |
BCF |
レジスタ名 変数名 |
ビット位置 |
レジスタ(変数)の指定ビットを0にする |
BCF STATUS,DMY BCF WORK,0 |
なし |
BSF |
レジスタ名 変数名 |
ビット位置 |
レジスタ(変数)の指定ビットを1にする |
BFS STATUS,DMY BFS WORK,1 |
なし |
COMF |
レジスタ名 変数名 |
格納先 0 or W ⇒Wに代入 1 or F ⇒そのレジスタ または変数に戻す |
レジスタ(変数)の全ビットを反転する。 使い方がよくわからん! |
COMF WORK,W |
反転結果 = 0
ならZ=1
それ以外
ならZ=0
|
SWAPF |
レジスタ名 変数名 |
格納先 0 or W ⇒Wに代入 1 or F ⇒そのレジスタ または変数に戻す |
上位4ビットと下位4ビットを入れ替える。
使い方がよくわからん! よくわかりました・・・ステータスクリア+シフトを4回やるのは辛いです・・・。 |
SWAPF WORK,W |
なし |
変数 とW の関係 (7個) |
代入 (2個) |
MOVF |
レジスタ名 変数名 |
格納先 0 or W ⇒Wに代入 1 or F ⇒そのレジスタ または変数に戻す |
レジスタ(変数)から格納先へ代入 本来は単体操作だが、 主にWへの代入で使用する為ここに分類 | MOVF WORK,W |
格納先の値 = 0
ならZ=1
それ以外
ならZ=0
|
MOVWF |
レジスタ名 変数名 |
なし |
Wの値を指定レジスタ(変数)へ代入 |
MOVWF PORTB MOVWF WORK |
なし |
演算 (2個) |
ADDWF |
レジスタ名 変数名 |
格納先 0 or W ⇒Wに代入 1 or F ⇒そのレジスタ または変数に戻す |
レジスタ(変数)+Wを格納先へ代入 | ADDWF DMY,W |
変数+W = 0 ならZ=1
8bitをOverFlow
したらC=1
下位4bitがOverFlow
したらDC=1
上記以外なら
C=0,DC=0,Z=0
|
SUBWF |
レジスタ名 変数名 |
格納先 0 or W ⇒Wに代入 1 or F ⇒そのレジスタ または変数に戻す |
レジスタ(変数)−Wを格納先へ代入 (W−レジスタではない) |
SUBWF DMY,W |
変数−W = 0
ならC=1,Z=1
変数−W < 0
ならC=0,Z=0
変数−W > 0
ならC=1,Z=0
つまり、
変数 >= 0
ならC=1
|
論理 (3個) |
ANDWF |
レジスタ名 変数名 |
格納先 0 or W ⇒Wに代入 1 or F ⇒そのレジスタ または変数に戻す |
レジスタ(変数)とWをANDして格納先へ代入。
ANDはマスクしたい時に使う。
0+0=0 1+0=0
1+1=1 となる |
ANDWF DMY,W |
変数 AND W = 0
ならZ=1
それ以外
ならZ=0
|
IORWF |
レジスタ名 変数名 |
格納先 0 or W ⇒Wに代入 1 or F ⇒そのレジスタ または変数に戻す |
レジスタ(変数)とWをORして格納先へ代入。
ORは有効な全てのビットが欲しい時に使う。
0+0=0 1+0=1
1+1=1 となる
|
IORWF DMY,W |
変数 OR W = 0
ならZ=1
それ以外
ならZ=0
|
XORWF |
レジスタ名 変数名 |
格納先 0 or W ⇒Wに代入 1 or F ⇒そのレジスタ または変数に戻す |
レジスタ(変数)とWをXORして格納先へ代入。 排他的論理和の事だが使い方はよく解からん!
0+0=0
1+0=1
1+1=0 となる
|
XORWF DMY,W |
変数 XOR W = 0
ならZ=1
それ以外
ならZ=0
|
数値 とW の関係 (6個) |
代入 (1個) |
MOVLW |
数値 |
なし |
数値をWへ代入 |
MOVLW 80h |
なし |
演算 (2個) |
ADDLW |
数値 |
なし |
数値+WをWへ代入する |
ADDLW 80h |
変数+W = 0 ならZ=1
8bitをOverFlow
したらC=1
下位4bitがOverFlow
したらDC=1
上記以外なら
C=0,DC=0,Z=0
|
SUBLW |
数値 |
なし |
数値−WをWへ代入 (W−数値ではない) |
SUBLW WORK |
数値−W = 0
ならC=1,Z=1
数値−W < 0
ならC=0,Z=0
数値−W > 0
ならC=1,Z=0
つまり、
数値 >= 0
ならC=1
|
論理 (3個) |
ANDLW |
数値 |
なし |
数値とWをANDしてWへ代入。
ANDはマスクしたい時に使う。
0+0=0 1+0=0
1+1=1 となる
|
ANDLW 80h |
数値 AND W = 0
ならZ=1
それ以外
ならZ=0
|
IORLW |
数値 |
なし |
数値とWをORしてWへ代入。
ORは有効な全てのビットが欲しい時に使う。
0+0=0 1+0=1
1+1=1 となる
|
IORLW 80h |
数値 OR W = 0
ならZ=1
それ以外
ならZ=0
|
XORLF |
数値 |
なし |
数値とWをXORしてWへ代入。 排他的論理和の事だが使い方はよく解からん!
0+0=0
1+0=1
1+1=0 となる
|
XORLW 80h |
数値 XOR W = 0
ならZ=1
それ以外
ならZ=0
|
その他 (8個) |
再帰 (2個) |
CALL |
呼び出し ラベル名 |
なし |
指定ラベルを呼び出す |
CALL WORK | なし |
RETURN |
なし |
なし |
呼び出した指定ラベルから戻る |
RETURN |
なし |
JUMP (1個) |
GOTO |
ジャンプ先 ラベル名 |
なし |
指定ラベルにジャンプ |
GOTO LOOP1 |
なし |
タイマ (2個) |
CLRWDT |
なし |
なし |
ウォッチドックタイマをクリアする。 使い方がよく判らん! |
CLRWDT |
STASUSの TO=1 PD=1 |
SLEEP |
なし |
なし |
クロック発振器を停止してプロセッサをスリープモードにする。
プリスケーラをウォッチドッグタイマーに使用している場合はプリスケーラもリセットする。 使い方が全く判らん! |
SLEEP |
なし |
その他 (3個) |
NOP |
なし |
なし |
何もしない。 時間調整や単純ループなどで使用する。 |
NOP |
なし |
RETFIE |
なし |
なし |
割り込み処理からの復帰 使い方がよく判らん! |
RETFIE |
なし |
RETLW |
なし |
なし |
リテラルデータをWレジスタにセットしてサブルーチンから戻る 使い方が全く判らん! |
RETLW |
なし |
やっぱりな・・・・巷にある表と同じになってきちゃったよ・・・・。
それから”自己ルーチンを作っておく”なんて20代のプログラマー時代(四半世紀前!)に夢中になってヘッダーファイル群を在庫していった頃を思い出してワクワクする。
考えてみれば当然だよね!
今回、自然にタイマールーチンとかお手本を基に在庫してる訳だけど、とにかく命令が少ない!って事がココヘ来て苦痛になってきたのよ。
「え〜い!C言語なら一瞬で終わるじゃん!」ってなイラつきがフラストレーションになっていく。
しかし仕事じゃない分だけ「習得してやろうじゃね〜の!」って気持ちの方が大きいんで諦めませんがな。
だからコツコツと「自分ルーチン」を作っていく事にした。
それも信じられないくらい単純な「A=Bなら」「A>Bなら」などのルーチンを。
それでもパズルが解けなくて悩む時間の方が多かったりするが・・・・。
さて・・・だ。
10ビットの値を8ビットの器に入れなきゃイカン。
いや、正確には10ビットの値を10進表示の4バイトにせにゃイカン。
エクセルでいろんなパターンを試してみる。
()が10個連続しても計算してくれるソフトはエクセル以外に無いし、VBで作るより簡単だから。
・・・・ダメだ・・・やっぱり一気に計算しないと繰り上げや桁溢れに対処できない。
ふむ・・・・ここはベタの計算通り、
10ビット目を4バイトに代入+9バイト目を代数4バイトにして加算計算+8バイト目を同様+・・・・+1
のプログラムを作ってみるか?(なんかすげ〜煩雑なPGになりそうだな・・・)
とりあえず、ADRESHの2ビットを計算してみる。
1繰り上がる事はあっても2繰り上がる事は絶対に無いのだから、都度計算で大丈夫だと思う・・・・。
上位2ビットが512(10)+256(10)で計算するルーチンの完成に2日。
ステータスフラグを表にしてなかったら5倍は掛かってたな・・・・。
え〜?あと8回分も作るの〜?・・・・ゲッソリ・・・・・で、ここで気がついた!
あれ?待てよ?残りの8ビットは1バイトなんだから一気に行けるんじゃね?
だからその値+上位2ビットの加算で終了じゃね?
なるほど。
ADREDLの値を「100で割った商+余りを10で割った商+余り」でOKじゃん!
ラッキー〜!(なのか?)
ってな訳で完成しました!
****************************
ソースはこちら
注)オリジナル記述が増えてきましたが、
まだ初心者なのでロジックが安定していません。
真似しない方がいいです。
****************************
ここまでの設備費やら材料費やら参考文献やら・・・・で、
1万円の温度計!(泣)
ここまでのノウハウとしては、
・チップ全般の知識
・クロック発振の手法
・アナログ処理の手法
・電圧管理手法
・LCD表示手法
・アセンブラ記述スキル
・デバッグスキル
を習得した訳だ。
まぁ、自己投資としちゃぁ〜高くねぇ〜・・・・か?
V.3軸加速度センサーの実装
なんか・・・・記事が膨大になってきたな・・・・見出し番号の振り方もグジャグジャになってきてるし・・・。
自分で整理が付かなくなってきたよ・・・・加速度センサーの話ってもうしたんだっけ?
何故「加速度センサー」なのか?の話は大元の記事「アラーム装置を作ってみよう!」でするとして、とにかく実装してみる。
ここにくるまでにすでに一ヶ月が経過。
つまりマイコンに手を染めてからもう一ヶ月過ぎた訳だ。
なんか感慨深いよ。
しかしそんな事言ってられない。
まだ課題は山積したままだし、第一、もう京都ツーまで1ヶ月切っちゃったよ。
急がないと・・・・。
LM35DZとその周辺を取っ払うと随分とすっきりとした。
一番の要因はVref+へ接続する電圧が不要になった事。
Vdd(5V)から直接取れるので煩雑にならない。
今回の用途は「何度傾斜したか?」が問題ではなく、
傾斜値が変化したのか?が重要なので、値に関してのガイドラインは設けない。
よって、これから行うべき事は、
@プログラムの完成と作動確認。
A起動時に3軸の値の各々の平均値を取得し、ゼロ・キャリブレーションとして記憶させる。
B約0.5秒毎に各々の新しい値を取得し、ゼロ基準値と比較する。
C上限・下限値を越えた場合に、取り敢えず12V接続のブザーを鳴らしてみる。
Dアラーム作動中に再び上限・下限値を越えた場合(実地では車両移動等の動きが激しい時)は次のアラームも発令する。
E2つのアラームが作動中に再び上限・下限値を越えた場合は全解放で時間無制の3つのアラームを鳴らしっぱなしにする。
になる。
@プログラムの完成と作動確認。
先ずはプログラムの制作。
温度計の製作まででまだ未修得なのが「オペアンプ」なのだが今回は特に必要なさそう。
取り敢えず、温度計プログラムでそのまま動かしてみる。
おっ!何か動いてるぞ!
そりゃそうだ。
・アナログ入力
・A/Dコンバート
・電圧表示
ってだけなんだから、温度も加速度も同じようなものだ。
さて、それでは制作していこう。
先ず最初に初期化から。
・VCFGをVref+からVddへ
・入力ポートを3つへ
・アナログポートを3つへ
・入力チャンネルを3つへ・・・・・・???・・・・無いじゃん!!
あれ?どうすんだ?
あっ!そうか!一回の入力では1チャンネルしか使えないんだ!きっと。
つまり、3測定する場合は、2回チャンネルを切り替えないといけないんだな!?
つまりは、入力チャンネルの操作は初期化時ではなくてメインプログラム内で行う必要があるんだ。
という訳で、初期化から抜き取り、メインルーチンへ。
メイン処理はX,Y,Zの3処理を組み込む。
デシマル計算は未だに難関で完成していない。(頭悪り〜な〜・・・・おれ・・・・落ち込み・・・)
ただ理屈が判らないまま組み込むよりも、多少ゴミPGになっても自分が理解している方が良いので、
上位2ビットは0〜3の4パターンを固定でBCD化し、(それ以外はエラーとする)それに下位8ビットを加算して終了とした。
最後にLCD表示をX,Y,Z表示に変えて終了。
その結果がこれ(→)
仕様書には、5Vの場合、0G(静止状態)では、Vdd/2(V)とあるので、250前後の値かと思ったんだけど何でだろう?
Vref+供給に比べれば、単純すぎるくらいの回路なので、どこかに間違いがあるとも思えないし。
念の為にいろんなサイトの回路見てみたけど、抵抗やパスコンも使ってないようだ。
(もともとセンサー回路に内臓してあるから必要ないとはあるけど)
で、再度センサー道場を読み返してみる。
アナログポートへの配線を外してみると1V〜2V圧力が掛かっている。
「何も接続しなければ電圧は決まらない」
が電子回路である事はここを読んで理解はしていたが、
プルアップを気にして100KΩの抵抗を入力ピンに差してみる。
見事0Vで安定した。
また全体の数値も1.2V程度下がった様だ。
XYZでこれだけバラ付きが出ているのは愛嬌なのだろうか?
ま、今回の趣旨に沿えば、絶対値は関係ないので気にしないが。
またこれを見る限り、Z軸は使う必要がなさそうだ。
今回はベクトル計算も重力加速度も考慮しないので関係ないと言えば関係ない訳だ。
ちょっと考慮中。
電子回路としてこれでいいのか?
を判断できるスキルが無いのが悔しいが、
壊れない限りこれでやってみよう。
ハッと気がつく。
もはやシステム屋の机ではないわな・・・。
完全にデバイス屋になってる・・・。
A起動時に3軸の値の各々の平均値を取得し、ゼロ・キャリブレーションとして記憶させる。
さて、ここまできて初めてバイクが登場する。
回路を離れて考慮すべき事は「キャリブレーション」の回数。
例えば倉庫ならセンサー起動時に一回すればOK。
だけどバイクは、外に駐輪してサイド(センター)スタンドを立てて翌日まで放置する事を想定している。
・下のアスファルトが柔らかくて時間経過と共に沈下したら?
・スタンド時に偶然石を挟んでしまい、何かの拍子にそれが抜けたら?
・そもそも土だったら?
・なんらかの原因で一度姿勢を崩したら?
・地震だったら?
など。(さすがに地震は諦めるか・・・・)
先ず、一回のキャリブレーションをする為のメモリ領域確認から。
ここまでで、020h〜04Bhまでを使っている。
改めてデータシートを読んでみると、
020h〜07Fh=96バイト(バンク0)
0A0h〜0EFh=80バイト(バンク1)
110h〜11Fh=16バイト(バンク3)
120h〜16Fh=80バイト(バンク3)
190h〜19Fh=16バイト(バンク4)
1A0h〜1EFh=80バイト(バンク4)
の合計368バイトとなっている。
なぁ〜んだ・・・・余裕じゃん!・・・・って思ったけど、出来るだけバンク切り替えはしたくない。
だから実質96バイトの中で何とかしたいものだ。
ちなみにプログラム領域の上限は4096ワード。
このプログラム領域の意味がイマイチ理解出来てないのだが、一応HEXファイルの大きさという事で・・・・。
そうするとすでに2785バイト消費している。もしかしてこっちの方がヤバいかも?。
そこで先ほど考慮したZ軸に関する記述を削除したら2433バイトに減少した。
という事で、一回のキャリブレーション用採取回数を10回とする。
10回の理由は所要時間。余り長いとその間にセンサーが作動した場合に割り込み処理が必要になるから。
一回の処理に時間を掛けるなら「短く多く」の方が効率がよい。
次にその採取タイミングは約300秒とする。特に理由はない・・・。
300秒≒600回として、600回に一回の割合でキャリブレートしよう。
(2週間後・・・・・)
でぇ〜っ!!
疲れた〜・・・・・!!!
キャリブレーションロジックなんざ数時間で片付ける予定だったのに、2週間も掛かってる・・・・・!!
何故!?の答えは簡単。
a)「10ビットを足して割って・・・・どうやんのよ!?」
b)偏差とトリムはどうするのよ?
a)の解決策
自分用に作ったんだけど、これを見て判るかしらん?攻め何処は2バイト目が2ビットしか使ってないって事。
@2バイト目を合算(絶対にオーバーフローしない)
A1バイト目の上位4ビットを下位に移動して1バイトとして合算(最大00111100で絶対にオーバーフローしない)
Bその5ビット目以上を2バイト目に合算(最大00001111で絶対にオーバーフローしない)
C1バイト目の下位4ビットを仮想の−1バイト目として合算(最大00111100で絶対にオーバーフローしない)
Dその5ビット目以上を1バイト目に合算(最大00001111で絶対にオーバーフローしない)
E仮想の−1バイト目も最大で00001100となる。
F1バイト目と仮想の−1バイト目を左シフトして合算(最大11111100で絶対にオーバーフローしない)
G1バイト目を1回目右シフトして上位1ビットを空け、押し出された値はワーク1へ。
H1バイト目を2回目右シフトして上位2ビットを空け、押し出された値はワーク2へ。
I押し出された合算がオーバーフローしたら1バイト目に合算(合算しても1バイト目は絶対にオーバーフローしない)
J2バイト目を1回目右シフトして溢れた値を1バイト目の7ビット目に合算する。
K2バイト目を2回目右シフトして溢れた値を1バイト目の8ビット目に合算する。
で平均値の完成。これをX軸とY軸行う訳だ。
1バイト目を2回シフトした桁溢れ分の合算がオーバーフローしなければ無視する。
そうそう、キャリブレーション用採取回数は10回ではなく4回としました。
だって2のn乗で割り切れないじゃん!・・・・この辺が2進数慣れしてないところなのよね。
2の3乗=8回にしようとも思ったんだけど、もうバンク0の変数定義用のアドレス残量が少なくなってきている!!
だから4回にしました。
1桁目がキャリブレート数値。
2行目がリアルタイム数値。
この写真は、わざと傾けてキャリブレートさせてから、
水平に戻してリアル値を表示しているところ。
ここまで、考えが纏まれば案外簡単な理屈なのだが、
しかしここに辿り着くまでに悩む悩む・・・・。
20数年ぶりに夢でデバックしてしまったよ。
現役時代に仕事で苦悩していた頃を懐かしんで涙が滲みます・・・・なんて楽しいオモチャなんでしょ!!
しかしb)の偏差とトリム化は断念しました。
理由は「単純だが想像を絶する面倒臭ささ!!だから」
このプログラムが完成したら実装後にC言語に移行しようと思います。
アセンブラでは単純なロジックすらも頭を抱える事になるのですよ。
特に”配列”と”ループ”及び”判定”に関してはもう最低な言語です・・・・。
トリム平均なんて
・全ての値を配列に入れる
・ループで最大値と最小値を判定する
・その配列を削除して平均化処理に移行する
ってなだけで、C言語だったら20ステップくらいで済みますがな・・・・も〜イヤ!!
しかし数十年ぶりにビットに浸ると感動するのも確かだしなぁ・・・・・アセンブラの魔力恐るべし!!・・・・・です。
B約0.5秒毎に各々の新しい値を取得し、ゼロ基準値と比較する。
さて、比較してその結果どうする? ⇒ 取り敢えずLED発光・・・・・もうポートが無い!!
なんて事だ!PICの18ピンの全てを使い切ってしまっている為にLEDを差す余裕が無い!!
実はもうLCDに限界を感じていて、RS232−Cでパソコン通信しようかと考えている。
特にアナログ入力システムに関してはデバックする際にどうにも不便だからだ。
しかしこれを実現する為には、RS232−Cモジュールが必要になる。
ちょうど明日アキバに行くからついでに買ってこよう。
ってな訳で、また回り道を余儀なくされる。
取り敢えずリアルタイム確認で使っている4番ピンを使うとするか。
先の資料の「比較の考え方」に則ってプログラミング。
で、完成がこれ。(→)
赤がキャリブレートで緑がアラームの状態。
ちょっとケーブルに被ってしまったけど、キャリブレート後に移動するとアラームが光り、
キャリブレート同期と共に消えるのが判る。
よし!よし!ここまで順当に成功してるぞ!!
(順当?死ぬ思いなんですけど!>俺)
BとCの間に・・・・・
なんと!タイミング良く先生のHPにRS232Cでパソコンと通信(PIC16F88)がUPされてる!(しかも先週!!)うれしっ!!
で、早速買ってきましたよ。
「RS232ライン・ドライバ/レシーバ」(ADM3202AN)
配線は簡単。
図の通り組み付ければいいだけ。
違う点は、潔く(!?)LCDを取っ払っちまいました!!
PICとPCをハンドシェイクする為の通信速度は一般的な、
9600/8/1/NON
とする。
なんか懐かしいなぁ〜・・・・。
コンピュータの仕事をするようになったばかりの20代では、
まだTCP/IPが確立出来ていなくて、ペリフェラルと言えば、
・シリアル
・パラレル
しかなかったものだから、シリアルのクロスケーブルなんて
全て自作で納品していたよなぁ・・・だから「クンロクハチイチノン」
なんて呪文のように染み付いていたもんなぁ・・・(しばし回顧)
さて、プログラム。
やっぱりRS232モジュールだって、それなりの仕様がある訳で、
それを覚えにゃぁ〜プログラム出来ん!
先ずは理屈から。
a)送信
・TRMTでレディー状態を確認する。
・ビジーでなければデータをTXREGにセットする。
・セット直後に自動でTXIFがビジーになる。
・TXREGの内容がTSRに自動でセットされる。
・TSRから自動でシリアル変換されてTXピンに出力される。
・出力直後にTXIFが自動でレディとなる。
b)受信
・RXピンを常時監視する。
・スタートだったら、その後ろのデータをRSRへスタックする。
・ストップだったら、RSRの内容をRXREGへセットする。
・セット直後にRCIFが自動でレディとなる。
・レディだったらRXREGから内容を読み出す。
注)RXREGは2つの領域があり、次のデータをバッファリング出来る。
従って、現在の次の次のデータが受診完了してしまう前に、
現在のデータを取得してしまえば連続受信が可能になる訳だ。
それでは具体的にレジスタを見ていく。
SPBRGの設定値
| クロック数別SPBRGの設定値 |
ボーレート | 20MHz | 10MHz | 8MHz(内部) |
9,600 | 32 | 15 | 12 |
19,200 | 15 | 7 | 5 |
今回は、9600ボー/内部クロック(8MHz)を使用するので「SPBR=12」となる。
TXSTAレジスタ(バンク1)の設定
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
CSRC | TX9 | TXEN | SYNC | - | BRGH | TRMT | TX9D |
クロック選択 0:外部 1:内部 非同期の場合は無視 | ビットモード 0:8bit 1:9bit | 送信許可 0:禁止 1:許可 | 同期モード 0:非同期 1:同期 | (未使用) | サンプリング 0:低速 1:高速 | 送信ステータス 0:まだダメ 1:OK | 9bit目パリティ |
今回は一般的な設定で、”00100000”とする。
クロックを外部のままにしてるのは非同期で無視されるから。
RCSTAレジスタの設定
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
SPEN | RX9 | SREN | CREN | - | FERR | OERR | RX9D |
シリアルピン 0:汎用 1:シリアル | ビットモード 0:8bit 1:9bit | シングル受信許可 0:禁止 1:許可 | 継続受信許可 0:禁止 1:許可 | (未使用) | フレーミングエラー 0:正常 1:エラー | オーバーランエラー 0:正常 1:エラー | 9bit目パリティ |
今回は一般的な設定で、”10010000”とする。
上記の3つのレジスタを設定するには、
BSF | STATUS,RP0 | バンク1へ切替えて |
MOVLW | 20h | |
MOVWF | TXSTA | 送信有効,非同期,8bit,高速 |
MOVLW | 0Ch | |
MOVWF | SPBRG | 8MHz,9600bps |
BCF | STATUS,RP0 | バンク0に戻す |
MOVLW | 090h | |
MOVWF | RCSTA | シリアルポート有効,8bit,連続受信可 |
****************************
ソースはこちら
****************************
【PICが死んだ!!】
a)12Vだっつ〜の!!
気がつくと深夜でボ〜っとしてるのがわかる。
何故か12Vのピンを引き抜いて3端子レギュレータを通さずに直接(+)に差してる自分がいた。
レギュレート後の電源ピンとレギュレート前の電源ピンを間違えて差してしまったのだ。
慌てて引き抜くも後の祭り。
PICが死んでしまった・・・・・ライターで書き換えはOKなのにプログラムが走らない。
どうやら作業メモリ領域のどこかを破壊してしまったようだ。
全く・・・・寄り道するよ・・・・・在庫の88と交換して書き込む。
何事も無くプログラムが走り出す・・・・やっぱりな・・・・・また在庫を買ってこよう・・・・。
b)_MCLR_OFF の脅威!!
PCとの送受信をモニタしたくてLEDを足そうとしたが、もうポートAに空きがない。
ん?違うじゃん。RA5が空いてるじゃん。
と、Vddに接続してあるピンを抜く・・・・あれ?落ちた・・・・?
そっか!_MCLRが有効になってるから電源として必要なんだ。
だったら”_MCLR_OFF”で切断しよう。
でコンパイル後に作動してみるとOK!
さて次・・・・とまたデバッグして、ライターに置いたら・・・・認識しない・・・・・!?
何度やっても「No Detecte Deviced」と出てきてしまう。
わっ!また死んだか?何でや!?
と何回もやり直すが直らない・・・・・汗・・・・だって今、新品にしたばかりじゃん!
ググッってみると、あった!
--------------------------------------------------------------------------
注意することはMCLRをOFFにしないこと。
もしNOMCLRにして書き込みをしてしまった場合は、それ以降の書き込みが出来なくなります。
(書き込み不能になった場合は、このページの最後を見てください)
--------------------------------------------------------------------------
なんだよ!それ!?バグか!?
んで訳も判らずに「このページの最後」を実行してみる。
ア)PICkit2(V2.61)を立ち上げて、電圧を3.0Vに設定する。
イ)「Read」でPICの中身を読み込む。
ウ)読み込みが成功したら「program memory」の先頭アドレスだけを「2800」に変更する。
もし読み込みが失敗したら残念ながらそのPICは使えません。
エ)「Write」で書き込む。この時色々エラーが出るが一切無視する。
オ)終わったら電圧を5.0Vに設定してから「Erase」で消去する。
カ)これで「Complete」が表示されたら復活成功!ダメでも何回かやってみよう!
PICが復活したところで”_MCLR_OFF”を削除して再コンパイル。
あ〜ビックリした・・・・このサイトが無かったらここで手詰まりだったよ・・・・感謝!!
で、気を取り直して再びRS232の世界へ。
Windowsのハイパーターミナルを立ち上げて設定する。
ア)自分のPCのRS232-Cのポート番号を設定する。
イ)ボーレートを「9600」にする。
ウ)フロー制御を「なし」にする。
以上で即実行状態になっている。
プログラムが上手く動いていればこうなる(→)
ここで先生のプログラムをじっくり見ていて、
言語一覧の最後の「RETLW」の使い方が良く判った。
「リテラルデータをWレジスタにセットしてサブルーチンから戻る」
ならばRETURNで戻ればいいじゃん!?
の考え方が間違っていた事を!
その1:連続してWに読み込んで処理をしたい場合、いちいちリターンするんかい!
その2:そもそもリターンじゃ次の指定が出来ないじゃん!
つまり・・・・だ。
ある配列があってその配列に文字列が1バイトづつ入っていたとする。
それを連続して読み込めば文字列として表示出来る。
でもアセンブラには配列は無いからそのアドレスを順番に呼び出せば配列と同じ事が出来る・・・・って事だ。
で、配列に相当するのが連続したRETLWであり、その呼び出しを行うのがPCLって事なんだ。
なるほどね。
って、ここまできて気がつく訳だ・・・・・リテラル(固定)じゃないじゃん!
変数(ラベル)じゃん!・・・・どうするのよ?
結局、LCDと同じく、一文字取り出しちゃぁ〜「TXREG」へ書き出す・・・・。
ま、あくまでもモニタリングだけだし・・・いいっか!
で、ダラダラと出されても読めないからこうした(→)
シリアル/パラレルの制御なんざ、その昔の15インチ・ドット・インパクト・プリンタの制御で、
死ぬほどやったから体が覚えてるわい・・・。
AVE:アベレージ(平均)化した数値
このX、Yの数値と現在の数値(以下、実測値と呼ぶ)を比較してアラームに流す。
NOW:現在の実測値
LCDを取っ払ったら速くなっちゃったよ。約0.1秒で更新してる。
MAX:上限値
傾きに呼応した電圧変化を10進数で表した場合の上限値の設定。
現在は「50(10)」のマージンを取っているが、これは実車に実装した時に変更する。
最終的には実装後に赤外線リモコンで設定値変更が出来るようにしたいと思っている。
MIN:下限値
上限値と同様。
@正常な状態
アベレージと実測値の差が上限も下限も超えていないのでアラーム処理へ飛ばない。
AY方向に傾斜が生じてY軸の実測値が下限値を超えたところ。
この時点でアラーム処理に入っている。
Bそのままキャリブレーションさせた想定で、Y軸のアベレージ&上限値&下限値が設定されたところ。
実際にはこんな激しい差異は出ないが、夜中に(?)スタンドが地面にめり込んだ場合の補正の実験。
C同様にX方向に傾斜が生じて上限値を超えたところ。
D同様にそのままキャリブレーションしてみる。
C上限・下限値を越えた場合に、取り敢えず12V接続のブザーを鳴らしてみる。
ようやく帰ってこられた・・・・・シリアル制御だけで一週間掛かってる・・・・。
ところで何気にHEXファイルを見てみたら4401バイトになってる。
あれ?4096が限界じゃなかったんかい!?と調べてみたら、
どうやらプログラムメモリとは「コンパイル時にスタックするプログラム容量」の意味らしく、
MPLABの「View」→「Memory Usage Gauge」の「Program Memory」の事らしい。
現在「771/4096」という事は、この5倍のプログラミングが出来るという事!?
まぁ、監視ながら開発を続けよう・・・・。
さて、実験値だがPCで視覚的にモニタ出来るようになったので、ケジメが楽になった。
つまり、「ここまでOK」「ここではすでにNG」などの切り分けが視覚的に出来るので作業が進むのだ。
早速、ブザーを鳴らしてみよう。
ここへ来てやっと聴覚に訴えるテストが出来るのだから気の長い話だよ・・・・。
しかしその前にラッチング・リレーの解説をしておく必要がある。
最終的にバイクのホーンやブザーを鳴らすのは12Vだからリレーが必要になる。
そのリレーはマイコン内で制御するのでコイルは5V動作である事が必須。
制限値を超えた時にスイッチが入るのはOKとして、すぐに制限値内に戻す=元の位置に戻したらOFFになっていいの?
だとしたらすぐに元に戻して静かになった処で破壊工作に入るよね・・・・普通。
つまり、単純なリレーのON/OFFだけだったら、そうなってしまうという事。
Q:それを阻止するには?
A:一度スイッチが入ったら、電子回路が遮断(OFF)になっても、設定時間だけリレーのスイッチは入りっぱなしであればよい。
Q:どうすればいいの?
A:ラッチングを使えばいいのさ!
ラッチング・リレーの動作
このリレーは電磁石のみによって接点が変わる方式ではないので、スタート時に必ずa接点から始まるといった規則はない。
つまり一度電気的に接点が繋がると、その後で電気が切断されても永久磁石によって、その接点が保持される。
a接点のコイルを「セットコイル」、b接点のコイルを「リセットコイル」と呼ぶ。
例えば、現在a接点が接続されているとすると、セットコイルが作動した後で永久磁石によってa接点が接続しっぱなしになっている。
次にリセットコイルに規定電圧が掛かるとa接点からb接点に切り替わる。
そしてリセットコイルへの電圧がゼロになっても今度は永久磁石によってb接点が接続しっぱなしになるという訳だ。
これにより、プログラムでその時間を指定してやれば、好きな時間だけ好きな接点を繋いでおく事が可能になる訳だ。
良いでしょ!?
で、今回使用するのが、OMRONのG6CK−2117C−US。
2極、つまりb接点も動作出来るので解除&解除LEDモニタとして使う予定。
最終的にはこのリレーを3つ使って3段階アラームにしたいので、PORTBの0番、1番、3番を使う。
2番も使えばいいのだが、シリアル通信は最後までモニタリングしたいので除外する。
また動作リセット用に3つのb接点を共通で使いたいので、その制御にPORTBの4番を使う事にするが、
今はまだテストだから1個をON/OFFで使ってみる。
ブレッドボードに使っている12Vをダイレクトに5Vに切り替えて、2枚目のブレッドボードに12Vを接続する。
これをバイクに見立てる訳だ。
ACアダプターの微妙な接続が面倒なので、
プラグを切断してピンコードを半田付けした。
5Vと12Vを間違えると無駄な労力を要するので
デッカいシールを貼って・・・・と。
これで接触不良とはおさらばだ。
そこにブザー(エーモンNo.1868:音圧90db)を接続する。
マイナス側にリレーのa接点
(3ピンと4ピン)を割り込ませる。
下のボードが12V(バイク)のつもり。
右下に見えるのがエーモンのブザー。
IC等の配線を左右で別けるには、
ボードの真ん中を使うしかないので、
なんか一直線に並んでしまう。
これで今回の制作シリーズの原型の完成だ!(→)
早速テストしてみる。
予めブザーの動作テストを行ったが、余りに五月蝿い!=甲高くて耳障りな音!なので、
圧力排出口をテープで塞いである。
それでもこれだけの音がするのだ。(→)
今はラッチングリレーの解除をキャリブレーションに連動させているので、すぐに止んでしまうが、
姿勢を元に戻しても鳴り止まない効果が判るだろうか?
リレーを組み込んだ回路図はこうなる。(↓)
実際にはまだ1個だが、配線はこんな感じ。
Dアラーム作動中に再び上限・下限値を越えた場合(実地では車両移動等の動きが激しい時)は次のアラームも発令する。
上図の2個目のアラームを鳴らすプログラムに入る。
しかしその前にここで後回しにしていた処理をロジックから組み上げる必要がある。
それは、3つのアラームの
・アラーム解除時間のカウント方法の決定
・その割り込み処理方法
がまだ未解決なのだ。
現在は単純にキャリブレーションのタイミングで解除しているだけなので、このままだとキャリブレーションカウンタの状態によっては、1秒後に解除されるかもしれないし、5分後?(設定値による)に解除されるかもしれないからだ。
理想としては、
@1つ目のアラームは警告も含めて「間欠音を30秒間」鳴らす。
A1つ目のアラームを鳴している間に、再び制限値を超えたら、2つ目のアラームを「連続音で1分間」鳴らす。
この時、1つ目のアラームも連動して同じ「連続音を1分間」鳴らす。(出来れば抵抗などで微妙に周波数をずらしたい)
B2つ目のアラームを鳴らしている間に、再び制限値を超えたら、3つ目のアラーム(ホーン)を「連続音で時間無制限」で鳴らす。
この時、1つ目と2つ目のアラームも連動して同じ「連続音で時間無制限」で鳴らす。
Cアラーム1〜2が鳴っている間はキャリブレーションへは飛ばさずに、解除後にキャリブレーションに飛ばす。
Dアラーム3はプログラムの暴走状態を作るだけなので、無限ループに入れて、後は知らん!
E将来的にはリモコンで解除(電源リセットor切断)出来るようにしたい
となる。
Eはプログラムでリレーを切り替えれば警告音は鳴り止むが、
それ以外の場合は時間解除を待つかトグルスイッチを用意して12V側の電圧を切断するしかない。
また@〜Dの状態で制御基盤(このシステム)を破壊したとすると、その時点で逆に制御不能になり、
やはりトグルスイッチで12V電圧を切断するしか鳴り止む方法は無いのだ!
(いづれにしても大音量の重奏が響く中で、スイッチを探して切るか、バッテリー付近の配線をやみくもに切断するしかないのだよ)
これらを実現する為には、これまで扱ってこなかった「タイマー割り込み」が必須になってくる。
何故ならば、時間を調整する必要がある項目は全部で5つ。
・実測値取得
・リレー接点切り替え
・キャリブレート
・アラーム1間隔
・アラーム2間隔
「実測値取得/リレー接点切り替え/キャリブレート」の3つは、その時間を無駄に潰す事が主目的なので、
今までのクロックカウントでOKなのだが、「アラーム1間隔/アラーム2間隔」に関しては、
アラーム処理をしている間に次のアクションが取れないと現状認識が出来ない為に、
細かいカウンターを使ってカウントダウンを管理するか、タイマー管理するかのどちらかになるが、
プログラム的にはタイマー発行するだけで後は結果を受け取るだけのほうが簡素化出来るからだ。
それではタイマー管理の方法を見ていく。
使用するレジスタは3つ。
@TMR0を求める
AOPTIONの設定
BINTCONの設定
@TMR0を求める
カウント数の最大値は8ビットだから256(10)。
これでは如何にも少な!って事で「プリスケーラ」という概念が取り入れられている。
これはTMR0を8ビットで管理する事を目的としている。
つまり256*256=65535までカウントが可能という事だ。
これを上限として「ある判り易い単位時間」を求めるとすると、内部クロック8MHzだから、
65565*4*0.08/1000=20.9172≒20(msec)
から、20m秒を1つの目安にすると、20ナノ秒/(クロック周波数*1命令当たりの時間)より、
20*1000/(0.08*4)=50000
50000/256≒195=C3h
TMR0はFFhまでのカウントアップなので、
FFh−C3h=3Chとなり、
TMR0=3Ch
となる。
AOPTIONの設定
OPTIONレジスタの内容
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
^RBPU | INTEDG | T0CS | T0SE | PSA | PS2 | PS1 | PS0 |
PORTBプルアップ 0:使用する 1:使用しない | 割り込みエッジ 0:RB0/INT立ち下りエッジによる 1:RB0/INT立ち上がりエッジによる (よくわかりません) | クロック選択 0:内部クロック 1:RA4/T0CKI | TMR0ソースエッジ選択 0:RA4/T0CKIがLowからHigh 1:RA4/T0CKIがHighからLow (全く判りません) | プリスケーラ 0:TMR0 1:WDT |
000 | → | *2 |
001 | → | *4 |
010 | → | *8 |
011 | → | *16 |
100 | → | *32 |
101 | → | *64 |
110 | → | *128 |
111 | → | *256 |
|
ポートBは出力なのでプルアップしない。^RBPU=1
内部クロックを使用するので、T0CS=0
プリスケーラも使うので、PSA=0
最大値を使いたいので、PS2-PS0=111
よって、OPTION='10000111'となる。
BINTCONの設定
INTCONレジスタの内容
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
GIE | PEIE | TMR0IE | INT0IE | RBIE | TMR0IF | INT0IF | RBIF |
全ての 割り込み許可を 0:禁止 1:許可 | EEPROM 書き込み完了 割り込みを 0:禁止 1:許可 | TRM0の 割り込みを 0:禁止 1:許可 | RB0/INTの 割り込みを 0:禁止 1:許可 | RBポートの 変化割り込みを 0:禁止 1:許可 | TMR0 割り込み発生 0:してない 1:した | RB0/INT 割り込み発生 0:してない 1:した | RBポート 変更割り込み発生 0:してない 1:した |
割り込みを使用するので、GIE=1
TMR0を使用するので、TMR0IE=1
よって、INTCON='10100000'となる。
という事で、20m秒のルーチンの完成。
これを50回ループすると1秒、さらにそれを30回ループすれば30秒の完成だ。
ここでRETFIE命令の具体的な使い方が初めて登場する。
割り込みに飛ばす時にCALLを使うのか?GOTOを使うのか?でいろいろ試行錯誤してみた結果、
1:タイマーをセットした時点でカウントを始め、カウンターがFF+1になったら無条件でORG4へ飛ぶ。
2:直下でタイマーセットルーチンへ飛ばす。
3:ルーチン内で再びタイマーセットをしてやる。
4:このルーチンからの戻りでRETFIEを指定すると「ORG4へ飛ぶ時のアドレスに復帰する」
事が判明した。よってタイマーセットルーチンへはGOTOで飛ばすのが正しいと理解した。
OPTION_REGとINTCONを設定してからTMR0へ値を入れると、その瞬間からカウントアップが始まる。
アラームが上がってからタイマーを掛けたいので停止させようと試みたがデバッグでTMR0を監視するも、どうやっても止まらない。
実はここでも1週間が経過していて、さすがに飽きはじめていた。
いろいろなサイトを何度も見ながら悩んでいたが、ある晴れた日中、昼飯を食べようとした時に、
「あれ?!・・・もしかして・・・・”許可”って・・・・飛ばすか?飛ばさないか?・・・・って事だけなんじゃね?」
とハッ!とする。
すでにこの頃になると、PIC製作がすっかり生活に溶け込み、生活の一部として機能しているものだから、日常で普通に思い返すのだ。
「つまり・・・だ。カウンターのカウントと許可とは全く別もので、カウントがどうであろうと単に割り込ませないだけの事なのでは?」
これまでデバッグでTMR0がカウントアップされると「ちっ・・・また(違うの)かよ・・・」とウンザリしていたので、
実際に割り込みが発生するか否かまでは確認していなかったのだ。
なんかルンルンで帰宅後にタイマー間隔を縮めてテスト。
それまでサイトで確認していた、INTCONのGIE(GeneralInterruptEnable)=0(禁止)にして、
FD、FE、FF、00・・・・・飛ばない!!!!
飛ばないで何事もなく次ステップを実行しているよ!!
つまりつまり・・・だ。「割り込み」とはカウントを停止させる事ではなくて「処理に飛ぶ」ってだけの事だったんだ!
そういう事だったのかぁ・・・・もう100近いサイトを閲覧したが、その辺を解説してくれているサイトはどこにもなかったよ・・・・。
(もしかして誰でも普通に知ってる事だったのかぁ?)
なんかちょっと感動したので長めに書いてみた・・・・。
とにかくタイマーは発振子を基準に確実に刻むので、時間経過に関しては信頼できる訳で、セットするタイミングさえ間違わなければ後は放置でよい訳だ。
という訳で、ルーチンは、
@アラーム・ルーチンに入った時に「CALL〜RETURN」で「BSF INTCON,GIE」を実行してタイマー(割り込み)を起動する。
A割り込みが入ったルーチンで継続or終了処理を行う。
・継続の場合は、ループカウンター−1後に、TMR0値を再セットして「BSF INTCON,GIE」を実行する。
・終了の場合は、ループカウンターとリレーを戻して後に、「BCF INTCON,GIE」を実行してタイマー(割り込み)を停止する。
と、まぁ、もう少しで完成なのだが、残念ながらここでタイムアウト。
京都ツーに向けて、
・回路の製作
・動作確認
を行う時間を考えると、もうこれ以上開発に時間は裂けない。
取り敢えず、どこで今回持ち込む為の妥協をするか?が問題なのだが、やっぱりTMR0は外そう。つまり、
@センサーは単独で1個とする
Aセンサー作動と直結してアラームを鳴らす。
B鳴り止むタイミングはタイマーではなくて、キャリブレーションとする。
で妥協しよう。
な〜に、京都ツーが終われば、またたっぷりと時間が取れるってもんさ。
さて、ここまで何やかんやと理屈を覚えながら試作を続けてきたが、ある日、振動工学と熱力学の専門家と会話する機会があり、実際に車載するにあたっては、
@出来るだけシンプルなプログラムで単純動作がMTBFを延ばしますぞ!
A出来るだけシンプルな部品構成がMTBFを延ばしますぞ!
と至極尤もなご意見を頂いた・・・・・まぁ、そりゃそうだけど・・・・・。
んで、実装に当たり幾つか変更を試みる事にした。
@10ビット処理を止めて8ビットで対応してみる。(これで大幅なステップ数を削れる)
A12Vからレギュレータ1個で5Vに降圧する。(部品点数が3点減らせる)
B取り敢えずリレー1個で動作させてみる。
上位2ビットを削る事により1024階調から256階調になってしまうが、今回は数値はどうでもよく、その差異のみを取得する事が目的であるから「まぁ・・・いいっか・・・」と妥協してみる。
7Vの降圧に関しては常用する訳ではない事と「TA4805S」の最大入力電圧が16Vまで可能である事から「まぁ・・・いいっか・・・・」と納得する。
上記よりその構成を図面に起こしてみた。
シルバーウィークに突入する金曜日。
アキバで今回用の最後の買い物をする。
・ICピンソケット(1P/8P/16P/18P)
・整流ダイオード
・ケース
・グロメット
・配線
・カプラー
・スイッチ
完成途中だからICは基板に半田付けすると勿体無い。
だからピンソケットにICを装着して京都ツーが終わったらICだけ外して基板は処分という事になる。
当然、ICだけでなくリレーやレギュレータもそうだ。
抵抗/コンデンサ/ダイオードは諦めよう。
配線は事前にPHOTOSHOPのレイヤーを使って構想していたので、収まる大きさは判っている。
リレーが1個だけだから小さくて済む。
ケースは漏電を考慮してプラスチックケース。
よし!完成だ!
さっそく実装テストだ!
(盗難アラームの製作に戻る)
|