pic-rtc

last updata : 2013/06/06

pic-clock 【PIC12F1822-I/PとSP521Pを使ったLCD時計】

ついでに電源電圧や温度も測る。最終的にはpic-RTCにして使おう。

桜
2011年の桜

季節の風景を取るの忘れたので前回のままで

実験途中の物 (2011/06/26)

pic-clock

ロガー単体で記録していく為には、ある程度正確な時計機能が必要になります。

簡単に済ますには、リアルタイムクロック(RTC)ICを使うのが簡単です。 エプソンデバイスのRTC-8564NBが秋月で簡単に購入できるので使われていると思います。

RTC-8564NBは、価格の安い標準仕様です。 全温度範囲/全電圧範囲で精度は、月差±1分ほど有ります。 高い製品では、月差±15秒程度物もあります。凄く高いけど。

PICにもTimer1のサブクロックを使用たリアルタイムクロックを構成することができます。 そこで、精度月差±1分以下のリアルタイムクロックが可能かテストしてみます。

PIC12F1822-I/Pにしたのは、8pinでI2Cが付いている最新のPICという事で使ってみました。 最終的には、pic-rtcを作ってみたいですね。

PIC12F1822-I/Pには、内蔵に基準電源や温度センサが有り外付け無しに電源電圧を測ったり温度を測ったりできます。 ここら辺もテストしてみます。

構 想

水晶振動子の発振精度を確認するだけなら、分周したクロックを出力して周波数カウンタで測る手も有ります。 でもそれでは面白くないので時計を作ってみました。 実際温度変化等で水晶振動子の精度が変わるので長時間測った方が良いのかも。

表示器とスイッチ×2個あと肝心の時計用水晶振動子です。

表示器

手持ちで余っていたLCD SP521Pを使って表示します。 長時間電池駆動できれば、ロガー用表示に使えるかと考えてです。

74HC595が見える

LCDドライバ?

LCDのSP521Pは、スタティック駆動(commonが1つ)ですので、CMOS-ICの出力で有れば特に問題なく 駆動できます。 ピン数の多いPICで駆動しても良いのですが、今回は74HC595と言うロジックICを使いました。 出力ポートが足りないときに、拡張用で良く使うICで手持ちが有りました。

タクトスイッチ

これも、手持ちに有るものを使ってます。

回路図

回路図

右の回路図を見れば判る通り、8ピンPICにロジックICが付いて表示しているだけの回路です。

特殊な部品は使っていませんから、1,000円以下でできるでしょう。 私は全て他で使った部品の余りでできてしまいました。

LCD SP521P

秋月で売っているLCD SP-521と同等品です。 入手先は、覚えていませんが製造元はSIIらしいです。

SP521P ピン配列

ピン配は、SII仕様で描きました。 ネット上のSP-521を使ったピン配の書き方と違ったようです。 接続は、同じになるので気にしないでください。(無理かな?)

ロジックIC 74HC595

各社からでていて一般的なシリアル-パラレル変換ICです。 今回は、PICのピン数少ないので、2線式のシフトレジスタ的な使い方になっています。

本来このICは、データをシフトして行き、最後にラッチさせて出力します。 すると、データ、シフトクロック、ラッチクロックの最低3本の制御線が必要になります。 しかし、シフトレジスタの様にデータが次々に出力されても良い場合には、シフトクロックと ラッチクロックを纏めて駆動することができます。 これで、2本にしています。 LCDの反応速度が遅いので細かいパルス状の間違ったデータが出ても表示には影響しません。

LCDの駆動方法

前に書いた様にSP521Pは、スタティック駆動ですので2値しか取りません。 ただし、LCDですので直流は掛けられません。 直流ですと電極の劣化が早く使い物にならないようです。

交流で2値という事は、

  • B.P(COMMON)が 0V で SEGMENTが 5V 点灯 … ①
  • B.P(COMMON)が 0V で SEGMENTが 0V 消灯 … ②
  • B.P(COMMON)が 5V で SEGMENTが 0V 点灯 … ③
  • B.P(COMMON)が 5V で SEGMENTが 5V 消灯 … ④

の4値を持つ事になります。具体的には、下図の様になります。

スタティックLCD駆動
LCD スタティック駆動

LCDの駆動調べると良く出てくる波形だと思います。

プログラム的に言えば、

  • COMMONがLowの時は、SEGMENTデータをビット反転しないで出力する。
  • COMMONがHighの時は、SEGMENTデータをビット反転してから出力する。

これだけで、事足りるわけです。

タクトスイッチ

手持ちに有った一度使った跡が有る物ですが、ぜんぜん問題なく動きます。 台湾製で、チャタも結構有るのですが普通のチャタリング防止のプログラムでOKでした。

電解コンデンサを回路図では描いていますが、実際には付けていません。 電流が少ないので、それほど問題でありません。

製作上の注意点

74HC595とSP521Pを直付けしたので、静電気に注意するぐらいです。

配線量が少し多いので、確認しながら進めるのが良いです。 後から、間違えに気付くと外して直さないといけなくなることが多々有ります。 (今回は、半田ブリッジが1カ所だけで済みました。)

ソフトウェア

ダウンロード HI-TECH C版

PIC12F1822 用 ファームウェア Version 0.81 (hexファイル&ソースファイル) pic-clock081.zip

HI-TECH Cでプログラムを記述しています。 この程度ならアセンプラでと思ったのですが・・・ PIC12F1822ってバンクレジスタが32に増えて スタックも8から16へと増えています。 (FSRを使えば何処にでもアクセス可と言うのも。) どうもC言語を主体にするような構造になっているようです。

アセンブラでも書いてみていますが、バンクアクセスやっぱり面倒かも。

それと、HI-TECH C Ver9.81では、バグが有るようで上手く動作しません。 Ver9.82以降を使用してください。

Ver0.80に数カ所バグが有ったので修正しました。(2011/06/30)

ダウンロード MPASM版

PIC12F1822 用 ファームウェア Version 1.06 (hexファイル&ソースファイル) pic_rtc106.zip

Ver 1.06 では、リアルタイムの進み/遅れ補正を正式追加(2013/06/06)

Ver 1.05 では、リアルタイムの進み/遅れ補正をテスト追加(2013/06/03)

Ver 1.03 では、リアルタイム処理の年処理を修正しました。

Ver 1.02 では、リアルタイム処理の日,月,年のバグを修正しました。

Ver 1.01 では、日付表示とVDD処理を変えました。

Ver 0.91 では、表示処理を少し変更して小数点付きの表示を改善しました。

Ver 0.90 では、温度表示処理を入れました。 一点補正タイプを入れています。二点補正は、精度からしても余り意味がなさそうです。

HI-TECH C Liteでは大きくなり過ぎているのでMPAS版に切り換えました。 0.85になって、電源電圧の表示/温度のADCデータを表示できるようにしました。

温度精度は、補正後の補正温度位置で±1℃それから外ずれていけば±20℃位ずれそうです。

Ver 0.87 では、演算を16bitから32bitへ変更して温度処理を少し入れています。 温度表示から-40すると温度ですが補正していないのでずれまくりです。

Ver 0.85 には多少バグ(割り込み中にグローバルメモリを操作するとか数値とか)有ります。 必ずスリープ中に割り込むので問題はでませんが、気持ち悪いのでVer 0.87で修正しました。

使用ファイル

pic_rtc.asm / pic-clock.c

今回のメインファイルです。 起動したら、内部16MHzに変更します。 32MHzも有りますが電池電圧は、3.3V~2.0V位ですので16MHzにしています。

あと、単純なスイッチ入力(チャタリング防止)を記述しています。

Timer1RTC.asm, Timer1RTC.inc /

timer1rtc.c, timer1rtc.h

今回メイン処理になる リアルタイムクロック処理部です。 Timer1にて32.768kHzのサブクロック発振とカウント処理をします。

割り込み処理も有ります。 今回は、LCDの表示処理有りますので1秒間に64回(15.625mS)割り込みます。

表示処理や電圧監視処理は、100uSも掛かりません。 後は、スリープして割り込みが掛かるのを待ちます。 スリープ中は、50uA以下になります。(計測してないので予想ですが)

時刻と日付と分けられるようにしています。 LCD表示のプログラム量が大きいので、今回は時刻のみの処理をしています。 (HI-TECH C)

SP521P.asm, SP521P.inc / sp521p.c, sp521p.h

今回のLCD表示ファイルです。 割り込み毎にセグメントデータをシリアル転送して表示しています。 16MHzで転送するので、誤表示は見えません。

Ver 0.85で 時計表示以外に電源電圧表示/温度ADCデータ表示ができるようになりました。

InternalTemp.asm, InternalTemp.inc / lowbattery.c, lowbattery.h

電源電圧を測る方法は、内部基準電圧を電源電圧リファレンスで測定すると判ります。 絶対精度は、±10%前後になりますがローバッテリ検出には十分です。

Ver 0.81までは LOBAT 測定のみでしたが、Ver 0.85以降では、電圧値変換を行っています。

Ver 0.85から内部の温度を計っています。 Ver 0.90で、温度表示ができるようにしました。 16bit演算では桁が足りないため、32bit演算に変更しました。

演算方法は、マイクロチップのアプリケーションマニュアルのAN1333を参照してください。

-- / GenericTypeDefs.h

元々Microchip Solutionsに入っていたGeneric Type Definitions ファイルです。 HI-TECH Cにも対応しているので、そのまま使っています。

良く使う BOOL や BYTE(unsigned char)やWROD(unsigned short)が有ります。

calc16.asm, calc16.inc / --

16bit演算処理用です。 PIC12F1822では、命令が拡張されていて16bit演算がし易くなっています。 C言語だとこの辺がライブラリで楽なのですが…

calc32.asm, calc32.inc / --

32bit演算処理用です。 Ver 0.87以降 16bit演算を32bit演算に変更しました。

pic_eeprom.asm, pic_eeprom.inc / --

PIC内蔵EEPROMの読み書き用です。 一応Byte(8bit)とWord(16bit)とLong(32bit)でアクセスできます。

12f1822.lkr / --

リンカーファイルです。 C言語用にリニアメモリ設定も有るのですが使いづらいので変更しています。 後デバック関係の部分とか。

アセンブラのリロケータブルについて

各ファイルは、リロケータブル(再配置可能)になっています。 多分、拡張PIC16なら.incを修正するだけで使えるはずですがまっ判りません。

動作について

Ver 1.06 (2013/06/06)

  • 時刻表示の時、SW1の長押しで、時刻の設定モードに入ります。
  • 日付表示の時、SW1の長押しで、日付の設定モードに入ります。
  • 電圧表示の時、SW1の長押しで、進み/遅れ補正モードに入ります。(Ver 1.06)
  • 温度表示の時、SW1の長押しで、温度補正モードに入ります。
  • SW1の短押しで、時刻→日付→電源電圧→温度 と切り換えます。
  • 時刻表示の時にSW2を押すと秒を表示します。
  • 日付表示の時にSW2を押すと年を表示します。

時刻の調整モード時、ボタンは下記のように動きます。

  • SW1を押すと 時→分→秒の調整を切り換えます。
  • 秒から時刻表示に戻るときRTCに設定値が書き込まれます。

  • SW2を押すと「時」、「分」、「秒」を進めます。

日付の調整モード時、ボタンは下記のように動きます。

  • SW1を押すと 日→月→年の調整を切り換えます。
  • 年から日付表示に戻るときRTCに設定値が書き込まれます。

  • SW2を押すと「日」、「月」、「年」を進めます。

進み/遅れ補正モードは、1ステップで1日に0.03秒進めたり/遅れさせたりします。 0で補正無し 1から99までが進めます。-1~-99が遅らせます。 (2013/06/03現在テスト中です。)

進み/遅れ補正モード時、ボタンは下記のように動きます。

  • SW1を押すと 進み補正(遅らせる) → 遅れ補正(進ませる) と切り換えます。
  • 表示に「-」「+」がでます。

  • SW2を押すと 進み補正の時は時計は遅れて 遅れ補正の時は時計は進みます。

温度補正モード時、ボタンは下記のように動きます。

  • SW1を押すと +補正 → -補正 と切り換えます。
  • 表示に「+」「-」がでます。

  • SW2を押すと +補正の時は温度値が上がり -補正の時は温度値が下がります。

温度補正は、電源を入れてから数分おいてPIC内部の温度が安定してから調整すると良いようです。

ここ数日動かしているのですが、一日に1秒弱遅れているかなと言う程度です。 一カ月で30秒遅れる程度ならRTC-8564NBと同じぐらい?

ハードウェアで調整する場合は、水晶振動子に付いている22pFのコンデンサを変更します。 遅れているって事は、20pか18pにすれば良いのか?(テストしてません。)

水晶振動子の推奨コンデンサは12pFの様です。 今のは少し大きいみたいです。(2011/07/21)

追伸 (2011/06/28)

約5日で約3秒遅れです。 一日の温度差(部屋)が約10℃ほど有る中で、無調整でこの精度なら良いと思います。

また、PIC12F1822なら内部温度が測れるから、遅れ補正をする様にプログラムすれば 月差±15秒以下できるかもしれません。

電源 (2011/06/28)

二日前から単三アルカリ電池の電圧も計っています。 測定初期値は、2.917V 24時間後2.911V 48時間後 2.907Vと言うところです。 一日で0.005V前後落ちていきます。 この調子なら、3.6V~2.0V迄使えたとして、320日ですか……

一秒間に64回もカウンタを32+1回分動かす部分で電気を食っている様ですね。

追伸2 電源 (2011/06/29)

電圧を計って三日目ですが、2.908Vに電圧を戻して維持しています。 電池特性や2本の電池の電圧差で、この程度の現象は出るでしょうが… もう少しデータを取ってみましょう。 電池二本で、8年位動作なら合格ですけど。

結果 (2011/07/21)

下記の電源表示や温度表示が増え(活動時間が3倍近く増えている)にもかかわらず、 約20日後で2.898Vを維持しています。一日当たり約0.0005V落ちていく計算になります。

電池二本で、8年の動作はクリアできそうです。

結果2 (2011/08/09)

時間のずれですが20日で16秒の遅れです。 通常のRTCに比べても遜色は無いようです。 コンデンサを22pFから10pF~18pFに替えればもう少し良くなりそうです。

結果3 (2013/06/02)

約2年動作させています。2.5Vまで落ちました。 途中で色々作業しているので、少し早い落ち方かなと思いますが、あと2年は動作すると思います。 あと時間のずれですが、補正掛けて時刻合わせを減らせないかなとテスト開始しました。

追伸 進み/遅れ補正(2013/06/06)

32.768kHzで発振していますので、32768カウントで1秒になります。 1日に960回、90秒毎にカウント数を変更して補正します。 最大99カウント減らして(増やして)960回補正すると、

1/32768 * 99 * 960 ≒ 2.9(秒)

で1日最大2.9秒進める(遅らせる)ことができます。 実際は32.768kHzがずれているのでそれを合わせるのですが…。

電源電圧表示 (2011/07/04)

VDD表示

電源電圧表示 (VDDを表示する)

先ずは、VDDを測ります。 温度の値を得るにはVDDを知る必要が有るので先ずこちらを測定します。

測定方法は……

  • FVRの設定を 1.024Vに設定する。
  • ADCの設定を VREF+:VDD VREF-:GND AN:FVR にする。
  • ADCの結果を得る。
  • 1047.552をADCの結果で割る。答えが電圧値

これで、数値が2.93…となります。 実数が扱えるなら簡単なのですが、如何せん今は16bit整数演算しか積んでいないので工夫しています。

  • ADCの結果を得る。迄は同じです。
  • 1047*50をADCの結果で割る。答えと余りが得られます。
  • 答えを左シフトして2倍にします。
  • ADCの結果を右シフトして1/2にします。
  • 余りとADCの結果を比較して余りが大きければ答えの最下位ビットを1にします。
  • これで答えは、電圧値*100 の値(293)になります。 あとは、適当に小数点付けて表示します。

    追伸 (2011/07/10)

    電圧変換の値を間違えていました。1023では無くて1047.552です。 最初に計算していたのにプログラムするときにすっかり忘れていました。
    VDD = (FVR * (210 - 1)) / ADC ですので
    1.024V * 1023 = 1047.552 です。

    32bits整数演算を積んだので上の演算は、
    (1047552/ADCの結果)/10 = 電圧値*100 の値
    と簡単にできるようになりました。(多分時間は掛かるけど。)

    どの程度の精度だったか書くのを忘れてました。
    DMMで3.65Vを表示している時に3.63の値を返しています。
    DMMで2.903Vを表示している時に2.90の値を返しています。
    DMMで2.599Vを表示している時に2.58の値を返しています。

    誤差として多く見ても2%以下です。 FVR:1024Vの絶対精度が±8%前後なのを考えるとかなり良いですね。

    PIC18F14K50-I/PでもFVRを基準電圧として使いましたが、 絶対精度が少し市販の電圧基準ICより劣る程度で十分に使えます。 あと精度はソフトウェアで補正できますしね。

    追伸 (2011/07/21)

    電圧やローバッテリ表示だけなら10bitADCで十分ですが、 次の温度表示に使うとなると少し精度が悪いみたいです。

    Ver 1.01では、12bit相当ADC化して様子を見ています。

    温度表示 全面改訂(2011/07/13)

    温度表示

    温度を表示する

    ファームウェア Ver 0.90にて、マイクロチップのアプリケーションマニュアルの AN1333 Use and Calibration of the Internal Temperature Indicator に基づいて温度取得及び表示ができました。

    まだ疑問点も有ります。 FVRCON レジスタの bit 4 温度インジケーターレンジですが…

    どうもビットが 逆のような感じです。

    bit 4 TSRNG: Temperature Indicator Range Selection bit
        0 = VOUT = VDD - 4VT (High Range) ←これと
        1 = VOUT = VDD - 2VT (Low Range)  ←これ
    

    そのまま計算すると、値が吹っ飛んで悩みましたが、逆にして見ると補正範囲内かなと...

    電源が電池二本ですので、Low Range でしょう。 データシートの15.2にも 1.8Vは TSRNG = 0と書いて有るので逆だと思います。

    同じ系列のPIC16F1939のデータシートを確認しましたら、やっぱり逆でした。 (2011/07/14)

    ADC 10bitでは足りない?

    AN1333のFigure 4(図4)を見ると-40℃~+85℃の範囲をADC値120~156で表しています。 8bitADCの様ですので、10bitADCに換算すると480~624程度になると思います。 温度差125℃を144ステップで表すので何とか1℃単位で表示できそうです。

    もう少し精度を上げたいのでオーバーサンプリング処理にて、13bitADC相当にしてから温度換算します。

    10bitADC→13bit相当ADCにするには、『1回サンプルする所を、64回サンプル加算して3bit右シフトする。』 だけです。

    1回加算すると1/2bitほど改善されるので、

    • 4回加算して1bit右シフトすると 10bit → 11bit相当
    • 16回加算して2bit右シフトすると 10bit → 12bit相当
    • 64回加算して3bit右シフトすると 10bit → 13bit相当

    ただし、万能では有りません。 ADCの量子化ノイズに依存しますが、今回のように入力信号の変化が少ない温度等には有効と思います。 (pic-loggerでも12bit相当ADC化を行っています。)

    温度へ換算

    換算式は下記のようになります。

    温度(℃) = ((0.659-(VDD/mode)*(1-(ADC値/(2n-1))))/0.00132)-40
    High-Range mode = 4
    Low-Range  mode = 2
    

    C言語なら、floatで処理したいところですが、アセンブラですので32bit整数演算で処理します。

    先ずは"(1-(ADC値/(2n-1)))"ここから 小数点以下を処理するため10,000倍してから処理します。

     A = ADC値 × 10000     --- ADC値を10000倍をAに入れる
     A = A ÷ 8191          --- Aを213-1=8191 で割る
     A = 10000 - A          --- 10000 - A 
    

    次は、上記の結果に(VDD/mode)を掛けます。 modeは2です。 電圧を1/2にするのは、温度測定用ダイオードが2つ有るためです。

     A = A ×VDD値          --- VDD値はVDD*1000です。
     A = A × 5             --- 計算上 ((VDD/2)*10000) * A になります。
    

    次は、0.659から上記結果を引きます。 0.659Vは、-40℃の時の温度測定用ダイオードのVfになります。 また、引く数が10,000*10,000倍しているので0.659*10000*10000から引きます。

     A = 65900000 - A       --- 温度の変化の値
    

    次に 上記結果を0.00132で割ります。 0.00132Vは、1℃当たりの温度測定用ダイオードのVfの変化値です。 この値も10,000*10,000倍したいところですが、温度*10の値にするために0.00132*10000*1000で割ります。

     A = A ÷ 132000         --- (温度+40)*10
    

    換算処理は、此処で終わっています。 温度表示をする時、上記の値から400を引いてプラスかマイナスを判断して3桁表示しています。 そして適宜な位置に小数点を付けます。 (0.1℃とかの表示が変だって所は有ります。…修正しました (2011/07/17))

    温度の補正

    AN1333のFigure 5(図5)を見ると温度変化率はまあまあ揃っていますが、 温度誤差は50℃以上有りそうです。 この誤差を補正しなければ使い物になりません。

    温度変化率はまあまあ揃っているので、一点補正(SINGLE-POINT CALIBRATION)を行います。

    AN1333では、ADC値そのものに補正を掛ける方法をとっています。 これだと、計算手順が増えるのでやめました。

    そこで、-40℃の時の温度測定用ダイオードのVf値の0.659V(65900000)に補正を加える事で対処しました。

    詳細は、ソースを見てください。

    温度の精度

    補正掛け どの程度正確に表示するかというと、 今年の暑い夏の室温で28℃から35℃ですが… 手元の温度計と比較して1℃前後の誤差です。

    -40℃とか+85℃とかになれば10℃~20℃はずれるんじゃないかな?

    AN1333のFigure 8を見れば判りますが二点補正でも5℃~10℃誤差になっていますしね。

    追伸 (2011/07/21)

    温度表示を見ていると1~2℃程度一気にふらつく事が気になって調べてみました。

    原因は100%とは言えませんが、VDDの精度不足の感じです。 Ver 1.01で、VDD処理の12bit相当ADC化して様子を見ています。

    残りのシリアル通信は (2011/08/09)

    I2Cのスレーブを実装するには、LCDとスイッチ一個を外して通信を行わないといけません。 そこで、新しく同じ系統のPIC16F1937でLCD直接駆動の回路を組みますのでそこで行いたいと思います。

    免 責

    情報は出来るだけ正確に書くつもりです。ただこの記事を見て作ると思ったときは、 個人の責任において作業を行なってください。 データの喪失や機器の損傷が有っても、一切の責任は取れません。