PIC時計を作る(1)

October 25, 2015

しばらく日記をサボっていましたが、最近また趣味の電子工作を再開したので久々に書きます。

前回は単純な自律走行するカーロボットを作成しましたが、次はオリジナル目覚まし時計を作ることにしました。当初サーボモータを使ってロボットを作る予定でしたが、大変そうだったので方針変更です。でも、もしかしたら今回作成する時計にサーボモータを使うかもしれません。あと、おしゃべり機能も入れてみたいです。

まずは、どうやって時計を実現するための時間計測を行うか、を検討したのですが、精度と処理速度を両立するため、PICの発振回路と、時計用の発振回路は別々にすることにしました。具体的には、PICはセラロック+PIC内蔵回路(発振回路の設定はHS)、時計は水晶振動子(周波数32.768kHz)による発振回路を用いることにしました。水晶の回路で発振した出力信号は、PICのTMR0ピンに入力し、TMR0割り込みでカウントすることにしました。

簡単にいくかなと思ったのですが、水晶の発振がなかなかうまくいかず、結局2週間くらいかかってしまいました。最初はユニバーサル基板に部品を半田付けしていましたが、何度も回路を見直すたびにハンダを吸い取ったりするのがめんどくさくなって、初めてブレッドボードを使うことにしました。ブレッドボードだとジャンパーコードをつけ間違えてもピンの抜き差しだけで済むので、本当に楽です。試作をする時にもってこいですね。

今回一番難しかったのが水晶発振回路の回路定数(使用するコンデンサ、抵抗の容量)をどうやって決めれば良いのかがよくわからなかったので試行錯誤せざるをえなかったことと、発振しているかどうかを確認する方法が最初わからなかったので動作しなかった時に原因の特定が困難だったことです。波形を直接見るためにソフトオシロスコープを試してみたりしましたがうまくいかず、結局手持ちのテスターにたまたま周波数測定機能があったことを発見し、これで発振していることが確認できるようになりました。ただし、この機能を使うとテスター側にたくさんの電流が流れるらしく(入力抵抗約2kオーム)、PIC回路側への動作に影響を及ぼしてしまうようです(実際、周波数測定中は、PIC側のカウントが不安定になり、本来よりも早くカウントアップが進んでいました)。

今回の工作での反省は下記の通りです。

  • PICのオシレーターコンフィグレーションはPIC側で使用する発振回路にあうように、正しく設定すること(セラミック振動子を使っているのに、HSではなくてLPに設定していたため、かなりカウンタのカウントアップが遅くなっていた。参考URL
  • 水晶発振回路に使用する部品の選定は適当に行わないこと(ちなみに、今回調べた文献の中ではトランジスタ技術の2011年9月号の発振回路の記事や、エプソンの技術解説ページが参考になりました)
  • 動かなかったら、使用している部品が適切か、壊れていないか、配線は正しいか、極性はあっているか、ノイズ対策を怠っていないか、など様々な原因を考えてみること
  • テスターで測定中は回路の動作に影響を及ぼす可能性がある(特に発振回路)ので測定する方法には十分配慮すること(参考URL)
  • ブレッドボードを電気器具の上に置いて使用しない(電気スタンドの台に直接ブレッドボードを置いて動作させると正常に発振しなくなったことがあった)

ようやく基本的なクロック回路ができたので、次回は時計を音声でお知らせするための仕組みを作っていく予定です。

今回作成した回路をアップしておきます。

clock

下記はこの回路をテストするために作ったコードです。TMR0のパルスを65536回カウントアップするごとにLEDのON,OFFを切り替えるだけです。正常に発振すれば周波数は32.768kHzですので、ぴったり2s毎にOn,Offが切り替わります。


#INCLUDE "P16F84A.INC"

 __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_ON & _CP_OFF

save_st EQU 0EH
save_w EQU 0FH

RES_VECT CODE 0x0000 ; processor reset vector
 GOTO START ; go to beginning of program

ISR CODE 0x0004 ; interrupt vector location
 MOVWF save_w ;Wレジスタの保存
 SWAPF STATUS,W
 MOVWF save_st ;ステータスレジスタの保存

 ; 各割り込みの処理
 BTFSC INTCON,T0IF ; TIMER0割り込み判定
 CALL TM0LISTEN

ISRFINISH
 SWAPF save_st,W
 MOVWF STATUS
 SWAPF save_w,F
 SWAPF save_w,W

 RETFIE ; 割り込み復帰

TM0LISTEN
 BCF INTCON,T0IF ; 割り込みフラグをクリアする
 CLRF TMR0 ; カウンタを0に初期化する
 ; LED(RA1ピン)を反転させる
 BTFSC PORTA,1 ; RA1がON?
 GOTO LEDOFF
LEDON
 BSF PORTA,1 ; LED ON
 GOTO TM0LISTEN_FINISH
LEDOFF
 BCF PORTA,1 ; LED OFF
TM0LISTEN_FINISH
 RETURN

;*******************************************************************************
; MAIN PROGRAM
;*******************************************************************************

MAIN_PROG CODE ; let linker place main program

START

 BSF STATUS,RP0 ; バンク1に切り替え
 ; PORTAはRA4のみ入力
 MOVLW 0x10
 MOVWF TRISA
 ; PORTBは全部出力
 CLRF TRISB
 ; TMR0を外部クロックにする
 ; RBPU 1 : PORTBのPullUp = なし
 ; INTEDGE 1 : INT割り込み信号のエッジ=立ち上がり
 ; T0CS 1 : 入力の選択 = RA4ピン指定
 ; T0SE 1 : インクリメントするタイミング = RA4の入力がHからL
 ; PSA 0 : プリスケーラ有無 = 有り
 ; PS1~3 111 : プリスケーラ値 = 256
 MOVLW 0xF7
 MOVWF OPTION_REG
 BCF STATUS,RP0 ; バンク0に切り替え
 ; TMR0割り込みを許可
 MOVLW 0xA0
 MOVWF INTCON
 CLRF TMR0

LOOP
 GOTO $ ; loop forever

 END