PIC12F509ちっさいけれど,ピリリ
PIC16F88+SC1602S*Bを使った陸上タイム計測器の時報(スタート音)に使う正弦波発信器モドキをPIC12F509で作ってみよか,と思いつき,考えてみた.Excelで試算した内容を冷静にも一度見てみた.
プリスケーラを2とか1に設定すれば,TMR0を使って何とか1KHz前後までは何とか発生できる見込み.でもPIC12F509って,割り込みが無いんだよな.すると,ソフトウエアでTMR0の計数値を見張り,例えばFF→00になった瞬間をSTATUS-Zフラグで検出すれば出来るのだけれど,これにはbtfs?命令とGOTOディレクティブでループを構成しなければならない.でも待てよ?プリスケーラが1ということは,TMR0のカウントクロックとCPUの動作するインストラクションクロックが全く同一ってコトだな.そうすると,TMR0のオーバフローを検出するループが仮に3マシンサイクル(btfs?(=1サイクル)+goto(2サイクル))になってしまうので,タイミングが0~3サイクルは狂ってしまうことになる.うーん,残念だけれどTMR0は使わないほうが良いね.このクラスのPICで組まれる一般的な方法として,nopやLoopで時間待ちをしたほうが良さそうだ. nopやloopで時間待ちをする場合,ソフトウエアの正確なコードが決まらないとどんな時間待ちをどのような定数でやれば良いかも決まらない.卵鶏状態でなにも決まらない.
そこで,コードを書き始めることにする.
何ちゃって正弦波発信器は,PIC12F509のGPIOをVVVF(Variable Voltage & Variable Frequency))っぽく制御すれば制限波っぽい波形を生成できるんじゃないか,という幼稚な発想で始めた遊びだ.発生させたい正弦波の8倍の周波数で,VVVF的パルスを生成する為の指令(1ビット)を出力する.これをトランジスタで受け,オープンコレクタ出力にして指令に対応した電圧が生成されるように負荷抵抗をセットしてやれば良い.オープンコレクタにするのは,複数の指令パルスを受けた電圧をワイヤードORで結線することでして連続波形にする為だ.(ほんとうはOPアンプの加算回路で合成するべきなのかもしれないが,遊びだから面倒くさいことはなるべくやりたくないのだ.後は交流カップリングとアッテネータを介してで386(1WオーディオアンプIC)へ送れば良いんじゃないか.
さてと,ソフトを作るには...MPLAB のIDEの環境を整えて,っと.MicroChipのサンプルソースを変更してソフトを書けば良いね.サンプルソフトを見てみた.すると,
ORG 0x3FF ; processor reset vector
; Internal RC calibration value is placed at location 0x3FF by Microchip
; as a movlw k, where the k is a literal value.
ORG 0x000 ; coding begins here
movwf OSCCAL ; update register with factory cal value
とある.え?リセット割り込みベクタが03ffH??? しかも何のソースコードも書いていないし.その後すぐにorg000Hがあるし.
データシートを斜め読みしてみると,12F509はPricisionな内蔵RC発振器を有しており,かつそのキャリブレーション値が工場出荷時に書かれているというのだ.上記のサンプルソースと併せて解釈すると,キャリブレーション値はプログラムメモリの03ffHにmovlw kの形式で保持されているという.(kがキャリブレーション値)なおかつ,03ffHはリセットベクタだというから,電源リセット時にはここからCPUは動作を始める.PIC12F509の場合,03ffHのこの命令の次にPC(プログラムカウンタ)が向かうところはオ-バーフローして000Hだ.ここにはmovwf OSCCAL命令があり,Wレジスタに保持された,工場で書き込まれた内蔵RCオシレータのキャリブレーション値がキャリブレーションレジスタに目出たく書かれ,とてもリーズナブルな仕組みで4MHz(誤差1%)のPricisionなCPU動作クロックが供給されるということになる.こんな仕組みが60円のCPUに入っているなんて,にくいねぇ.4MHzの発振器から供給されたクロックは,4分周されてTMR0のカウントアップ用クロックソースとして供給される.だからこの場合,カウントクロックは1MHzだ.また,CPUのマシンサイクルは4クロックで供給されるので,1マシンサイクルは1MHzとなる.かくして,ユーザはTMR0で1μSecで刻むなり,1命令で1μSecを消費するなりということで,単純だが精度の良く計算のしやすいクロックを用いてアプリケーションを作成することができる.
さて,PIC12F509は8pinのIC.内蔵クロックで駆動するとなると,電源+,Gndに2pinを消費するが,残りの6品は全てI/Oとして使える.但し,GPIO3だけは入力としてしか使えないそうだ.ちょっと不満.何でbit3なんだ.MCLR*との関係なんだろうけれど...ま,こういう割り切りがPICの魅力でもあるんだけれどね.
かくして,趣味で.
Bit0(出力)角度 -1π/16~3π/16, 5π/16~7π/16の時の出力指令
Bit1(出力)角度 3π/16~5π/16, 15π/16~17π/16の時の出力指令
Bit2(出力)角度 7π/16~9π/16,13π/16~15π/16の時の出力指令
Bit3(入力)低音:ブッ(440Hz)の発振指令
Bit4(出力)角度 11π/16~13π/16の時の出力指令
Bit5(入力)高音:ピー(880Hz)の発振指令
というピンアサインとした.
入力のビットパターンが変わらない限りは,所定のサイクルで上記Bit0,1,2,4をサイクリックにON/OFFさせれば良い.
一つのパルスを発生させるソフトはおおよそ次のようになるだろう
ModeL_1_8_PI ; 1/8PI Out PitPatern=0x04
movf GPIO,W ←1Clock
andlw CommandMaskBitPattern ←1Clock
xorwf mode,W ←1Clock
btfsc STATUS,Z ←1Clock
goto setMode
;;; Wait xxx Instruction Clock
movlw LowToneWaitFactor <<<- ここまで
call wait_8_Plus_4_by_n_Clocks LowToneWaitFactor×4+8 ->>>
nop ←(補正)1Clock
nop ←(補正)1Clock
;;; Out Signal to GPIO
movlw 0x04 ←1Clock
movwf GPIO ←1Clock
goto ModeL_3_8_PI ←2Clock
ここで,共通の時間待ちサブルーチンを以下とした
wait_8_Plus_4_by_n_Clocks
wait_8P4n000 movwf wait_8P4nCounter0
wait_8P4n001 decf wait_8P4nCounter0,F
btfsc STATUS,Z
return
goto wait_8P4n001
この条件で消費クロックを数え,excelから時間待ちFactorと調整用のNOPを入れて正しく440Hz,または880Hzの正弦波っぽくなるように調整した.
コンパイルは通ったぞ.とりあえず.
「PIC12F509FakeOfSinWave.asm」をダウンロード
「P12C509.INC」をダウンロード
「ms509.inc」をダウンロード
大きな勘違いは無いと思うけれど.ビールの見ながらExcelシートと作ったし.計算間違ってなければいいなあ.取り合えず,今度の休みにでも動作確認してみよう.
それにしても,60円のPIC12F509もやるもんだ.がんばっているなぁ.


コメント