エントリー

カテゴリー「make:」の検索結果は以下のとおりです。

AVRtiny13Aでつくるシリーズ6 気圧センサとI2Cのリード

  • 2016/04/05 09:44
  • カテゴリー:make:


 そろそろ面倒くさくなってきたtiny13を使った工作ですが,今回で一応一区切りです。I2Cについては,よく考えるとライトはやっていますが,リードはやっていません。センサなどを繋いだ場合はリードがメインになるだけに,これをやっていないというのは少々物足りません。

 なにかないかなとジャンク箱を漁っていたら,随分昔に秋月で購入した気圧センサ,フリースケールのMPL115A2が出てきました。600円。今,同じ物が400円で売られているんですね。

 I2Cで繋がる気圧センサとしては数年前からよく知られたメジャーなものです。デジタルで情報が飛んできますが,残念ながら値を結構複雑な計算で求めねばなりませんし,チップごとに校正された補正値を読み込んで,その係数を使う必要があったりとなかなか面倒です。

 そのわりには,今ひとつ精度も良くないという事らしく,人気の方は今ひとつという感じです。

 ですが,ちょうどI2Cのリードを試すにはちょうどいいですし,600円もしたんですから使ってみたいと思いました。しかし,この気圧センサはLGAというピンのないパッケージに入っており,小型である事もあいまって,実装が大変です。

 変換基板などもありませんので細いワイヤーで信号を引っ張り出すことにしますが,電源とGNDとI2Cの信号線だけですから,4本だけです。それならなんとかなるでしょう。

 ということで,信号線を引っ張り作業を始めたのですが,これがなかなか難しい。すぐに熱が回ってしまうので,一度付けたハンダがポロッと外れてしまうこともしばしばです。

 そうこうしているうちに,なんと電源のランドがハンダゴテの熱で剥がれてしまいました。万事休す。もうダメだ。俺は寝る。

 しかし,虫眼鏡でよく見ると,剥がれたランドのそばに,電源のパターンが走っています。ここにワイヤーをハンダ付けすればなんとかなるかも知れません。

 慎重に他の信号も引っ張り出して,とにかく外部にピンを出す事に成功しました。

 でも,これで動く保証はありません。というか,ほぼ壊れていると考えていいでしょう。そこで,mbedで動作を確認します。サンプルコードを探すと,あったあったありました。

 さくっと実行すると,気圧と温度と高度がLCDに表示されます。それなりに意味のある数字が出ているようですので,とりあえずこの気圧センサは生きているようです。

 で,あとはtiny13Aです。

 I2Cのライブラリの中に,リードを行う関数が用意されてはいるのですが,これをコールすればそれでいいというような簡単な話ではありません。

 MPL115A2の仕様書を読んでいると,リードの際にはまずコマンドを発行して読みたいレジスタを指定するとあります。それが済んだらリードをするという事です。

 ここで注意すべきは,ホストがリードを行う場合には,アドレスに+1しないといけないということです。この+1は,R/Wビットといって,ホストがライトするときには0,リードするときには1を書きます。

 これを0ビット目とし,あとはアドレスを1から7ビット目まで置いた合計8ビットを,スタートコンディションの次に送ります。

 MPL115A2のI2Cアドレスは0x60なのですが,ライトの時には0xc0を,リードの時には0xc1を送る必要があるということですね。

 ところが,スタートコンディションに続いてアドレスを送り,コマンドを送った後,どうやってR/Wビットを1にしてリードモードにすればいいのでしょう。

 仕様書によると,ここはリピートスタートコンディションを送るとのこと。

 べた書きすると,こんな感じになります。

    I2C_Start();
    I2C_write(0xc0);    //    addr + R/W bit = 0
    I2C_write(0x04);    //    command 0x04(read add = 0x04)

    I2C_Start();    // Repeat start condition(W/O Stop condition)
    I2C_write(0xc1);    //    addr + R/W bit = 1

    a0m = I2C_Read();
    a0l = I2C_Read();
    b1m = I2C_Read();
    b1l = I2C_Read();
    b2m = I2C_Read();
    b2l = I2C_Read();
    c12m = I2C_Read();
    c12l = I2C_Read();
    I2C_Stop();

 これは8つの補正値を読み出すコードなのですが,I2Cではストップコンディションを発行する前にスタートコンディションを発行すると,それはリピートスタートコンディションと見なされて,バスが解放されないまま,アドレスを再送出来るのです。

 ところが,変換開始から変換後の値を読み出すところは,またちょっと違うんです。これも仕様書によると,以下のようになります。

    I2C_Start();
    I2C_write(0xc0);    // addr + R/Wbit = 0
    I2C_write(0x12);    // command = 0x12, 0x01(convert start)
    I2C_write(0x01);   
    I2C_Stop();

    _delay_ms(5);

    I2C_Start();
    I2C_write(0xc0);    // addr + R/Wbit = 0
    I2C_write(0x00);    // command 0x00(read add=0x00)

    I2C_Start();        // Repeat start condition
    I2C_write(0xc1);    // addr + R/Wbit = 1

    bm = I2C_Read();
    bl = I2C_Read();
    tm = I2C_Read();
    tl = I2C_Read();
    I2C_Stop();

 0x12というのは変換開始のコマンド,次の0x01はダミーです。ここで一度ストップコンディションを発行してバスを解放しています。そして数ms待った後で,改めてスタートコンディションを出しているんです。

 あとはどこを読みたいか書き込んで,リピートスタートコンディションを出してから読むという流れなのですが,変換開始のコマンドのあと,わざわざバスを解放しないといけない理由がよく分かりません。

 まあ,普通に考えたら5msも待つんですから,その間にバスを明け渡して他が使えるようにしないといけないわけですが,今回のようにバスを占有しても問題がない場合は,別にいいんじゃないかと思ったのです。

 しかし,試してみたらダメでした。

 やはり仕様書の通りに書かないとダメのようです。

 で,あとは気圧と温度の表示なのですが,これがとても面倒くさい。とても1kバイトのメモリに入りそうにないと悟った私は,とりあえず気温だけ表示することにしました。

    t = tm<<2 | tl>>6;
    t = 250-(t-498)*1000/535;
    lcd_cmd(0xc0);   
    lcd_data(t/100 + 0x30);
    lcd_data(t/10%10 + 0x30);
    lcd_data('.');
    lcd_data(t%10 + 0x30);
    lcd_data('C');

 tはint型で,tmとtlはchar型です。tmを2ビットずらし,tlを6ビットずらして,トータル10ビットの値として,int型に格納します。出来るだけ小数点を使わないようにするために,補正式をちょっと修正しました。本当は,25-(t-498)/5.35で計算するんだそうです。でもおかしいんですよ。472で25度になるという話なのに,この式だと25度にならないですよね・・・まあいいか。

 一応これで温度の表示は出来たのですが,値がとにかく数度単位でばらつくんです。それでももうやる気を失って,やめました。

 ということで,なんとなくだらけたところで,このシリーズはちょっと休憩。小さい小さいマイコンを気軽に使いたいという話から,なぜか限界ギリギリを責める話になってしまったわけですが,これはこれでパズルを解くような面白さがあって,とても楽しかったです。

 たまにはこういうこともやってみるものです。

AVRtiny13Aでつくるシリーズ5 温度と時刻を同時に表示

  • 2016/04/04 12:02
  • カテゴリー:make:

 さてさて,お次はTCXOの時計と,LMT01の温度計を組み合わせたものです。LCDにはAQM0802を使って,1ライン目には温度を,2ライン目には時計を表示します。写真が好きな割にはうまく撮れずに恥ずかしいです。

20160404221135.JPG

 右側にあるのがLCDのAQM0802,その左下に8ピンDIPのATtiny13A,その上にはLMT01を寝かせておいてあります。

 LMT01の左側にはTCXOの出力(0.8Vp-pのなんちゃって正弦波)をCMOSレベルに変換するトランジスタ(2SC1815)があり,トランジスタの足下には10MHzのTCXOであるTG-5021があります。

 さらにその左側には2.85VのLDOがあって,すべてに電源を供給しています。LCDの電源としてはかなり低めで動作が心配されましたが,コントラストが低くなってしまったのでそこを調整した以外に,今のところ不具合はありません。

 左下の白い四角いものは押しボタンスイッチです。左が時を,右が分を進めます。両方押すと秒がゼロにリセットされ,離すとカウントを始めます。

 なんでもない時計ですが,実力で時計は1ppm以内の精度,温度計は0.5度以内というもので,これを8ピンの50円マイコンで作ってみようというのですから,なかなか面白そうだと思いませんか。

 ソフトとしては,これまで紹介した時計と温度計を組み合わせるだけです。割り込みは2種類から発生しますので,ここがうまく動くか,ちょっと心配な所です。また,それなりに処理が重いので,割り込み処理が間に合うか,また割り込み以外の処理が次の割り込みに間に合うか,そのあたりも気がかりなところです。

 メモリサイズは,あまり心配していませんでした。というのも,それぞれLCD駆動部分をいれて80%程でしたので,ここを共通化すれば収まるだろうと思っていたのです。

 ですが,やっぱりそうは問屋が卸しません。問題が噴出です。

 まず処理の問題。割り込み処理が間に合わないらしく,LMT01のパルスを正しくカウントしていないようです。これは処理順番を変更して対策。

 次に,割り込みの外の処理が重すぎて,時々変な数字を表示します。これも順番を変更して対策。

 そしてやっぱりダメだったメモリ。出来たバイナリは,1.2kBになっていました。2割もオーバーしているというのは,もう絶望的です。ちょっとやそっとで入る大きさではないですよ。しかも,温度のマイナス表示は外してあります。

 この,メモリを削って行く作業というのは実に地道な作業なのですが,もともと1kバイトしかありませんし,豊富な機能があるわけではないので,削る機能もありません。

 手始めに,LCDとI2Cのウェイトを削って行きます。すると,みるみる減っていきます。AVRのdelayというのは,実は結構なステップ数になると聞いたことがあるのですが,あっという間に100バイトほど減りました。

 もともと必要で入れてあったウェイトですから,外していい物はないはずなのですが,そういうきれい事を言っているわけにはいきません。1つずつ外して,動くかどうかを見て,また外して・・・を繰り返し,とにかく実力依存で動くところまで,削り取りました。

 なにかあったら,速攻でコケるだろうなあ。

 それでもまだオーバーしています。次はLMT01です。以前,摂氏に変換するのにカウント数*10/16-500をする,と書いたことがあるのですが,ここを減らします。

 カウント数が1234だとしましょう。この計算式に従うと,271となります。つまり27.1度ですね。

 これを書き直します。カウント数を10倍するのはあきらめます。これを右に4ビットシフトします。これで1/16されて,値は771となります。

 さて,よくよく見てみると,オフセットである500を減算して影響があるのは,100の位だけです。あとの10の位と1の位はなにも変化しません。それなら,この771を表示する際に,100の位の7から5を引き算し,あとはそのまま表示することにします。

 こうすると,演算が8ビットで済むので,少し減ります。シフトとの合わせ技で数バイト減りました。もちろん,マイナス表示は割り切ります。氷点下になるような場所にいたら体に悪いです。

 キーのチャタリング対策のウェイトも全部外しました。LCDの初期化も,本当に最低限必要な物だけにしました。そして,表示部分も,キャラクターコードのオフセット分0x30を,表示関数の中で加算するようにして,毎回加算することをやめました。

 これで,なんと1018バイト。ギリギリ入りました。かろうじて動いている感じです。

 さて,ここまで来て安心した私は,クロックの設定をデバッグ用の内蔵9.6MHzから,外部10MHzに書き換えることにしました。クロックの設定を9600000から10000000にして,ビルドします。

 すると,あろうことか,1030バイトになりました。オーバーしたため書き込みが出来ないと怒られて気が付いたんですが,せっかくの苦労が水の泡です。クロックを変えるだけで,なんでこんなに増えるのかと泣きたくなりましたが,これはおそらく,コードサイズに影響が大きい,delayで回るループの回数が変わったからでしょう。クロックが速くなると,それだけループもたくさん回すことになります。

 ということで,わずか400KHzの差だというなら,もうそのままでいいじゃないかということで,クロックは9600000にしました。

 これで最終的に1018バイト。これで書き込み,動作を確認しました。メモリもほぼ使い切り,機能的にもこれが限界でしょう。精度はTCXOですので申し分なく,温度計もとりあえずおかしな値を表示してはいません。

 文字化けや表示の乱れもなく,安定して動いてくれているのはいいのですが,消費電流が結構大きいのです。TCXOの電源を安定化したいので2.85VのLDOを通してすべての電源を供給していますが,LDOの入力で5.3mA流れています。

 5.4mAですから,仮に2000mAの単三電池を2本使ったとすると,単純計算で370時間。およそ2週間で電池切れです。これはかなり厳しいです。

 深夜にLCDを消すというのはどうかと考えたのですが,それでも減るのは1mA弱。3日ほど伸びるだけです。電池を4本にすれば1ヶ月,6000mAクラスのリチウム電池を使えば1.5ヶ月です。

 中途半端ですよね。10mA以下ですからACアダプタを出してくるのはもったいないですが,かといって電池ではすぐに切れてしまいます。こうなってくると消費電力を下げる工夫を考えたいのですが,これがなかなか難しいです。

 まず考えつくのはtiny13Aのクロックを下げる事ですが,10MHzで時計を作っている以上は,1/8の分周器しか使えません。でも,1.25MHzでは処理が追いつかないのは明白ですから,これはあきらめます。

 1秒ごとに表示を更新するだけだから,それ以外はスリープに入れればいいとも思うのですが,残念ながら1秒間に625回入る割り込みと,温度センサのパルスのカウント,そしてI2Cの通信でほぼずっと全速力で回っているCPUを止められません。

 それと,実はTCXOが2mAほど消費しています。tiny13Aが2mA,LCDが1mAとして合計で5mAですから,TCXOだけを動かすことにしても,2mA以下にはならないのです。仮に2mAになったとして約40日です。これで電池が切れてしまうというのは,程度の問題とは言え,面倒な事には変わりがないでしょう。

 なので,もうあきらめます。電池で動かすことを最初に目標に置いて,そのために必要な対策を最初から盛り込んでいかないといけなかったと思います。例えばクロックは明らかに周波数が高すぎますから,最大でも32.768kHz,可能であればここはリアルタイムクロックで閉じてしまい,tiny13AはRTCからの割り込みで1秒ごとにデータをもらう仕事に徹します。

 そして夜中はLCDを消します。これでおそらく24時間平均で1.2mA,だいたい3.5ヶ月動く計算です。3ヶ月持てば充電式の電池を使うなら,なんとか許せるでしょうか。

 そう考えると,市販されている時計の,なんと低消費電力なことでしょうか。腕時計なんか,小さな電池1つで,何年も動きます。専用のLSIに専用のディスプレイ,専用の水晶発振子でトータルの精度を維持するという,強烈な技術の集大成です。

 どういうわけだか,私は時計を作るのが好きなのですが,ことこの分野においては,消費電力においても,あるいは精度においても,プロが作る製品に,アマチュアの工作は全く追いつかないことを思い知らされます。

 そうそう,ところで,Si5351Aを使ったTCXO時計を作ったとここに書きましたが,壊れてしまいました。

 どういう訳だかわからないのですが,どうもaitendoの特価LCDが壊れてしまったらしく,手にとって他の人に紹介した直後から表示が消えてしまったことを考えると,どうも静電気で破壊したんじゃないかと思います。LCDの消費電流がゼロのまま,まったく変化しません。

 I2Cで動くセグメントLCDってなかなか貴重で,交換しようにも手頃な物がないのです。残念ですがこの時計はあきらめるしかありません。10日ほど動かしましたが,目視で分かるようなズレが出なかったことを,ここに書いておきたいと思います。

AVRtiny13Aでつくるシリーズ4 I2CでキャラクタLCDを

  • 2016/04/01 08:26
  • カテゴリー:make:


 今回は,tiny13AでI2CのキャラクタLCDを動かすという話です。

 またまた秋月ですが,AQM0802という320円のキャラクタLCDがあります。8文字x2行で,大きさは2.5cm x 1cm程度と小型,3.3Vで動作し消費電流も最大1mAとなかなかのものです。

 I2Cですから,電源2本と信号線2本の合計4本を配線するだけです。これがtiny13Aに繋がってくれると,随分出来る事が増えそうです。

 同じI2Cで叩くSi5351AやaitendoのLCDが動いているんですから,なにも心配などありません。アドレスを変更し,コマンドとデータを送ってやれば,すぐに文字が出てくるさ,と思って軽い気持ちで始めたのです。

 ところが,これが悪夢の始まりでした。

 いくらやっても動きません。文字も出ません。初期化も出来ていないようです。おかしい,とにかくおかしい。

 いろいろいじっても,全然動く気配がありません。配線ミスも疑いましたが,それもなし。このLCDはハンドシェイクをせず,ウェイトで制御しますので,十分なウェイトをあちこちにいれましたが,それでもダメ。

 関数を作らず,ベタでデータを流し込んでもダメ。とにかくダメなのです。

 いろいろいじっているうちに,初期化だけは出来るようになりました。スタートコンディションに続けてアドレスを送り,コマンドをだだだと流し込むと,とりあえずLCDがぼやーっと動き始めます。

 そこからさらにデータを書き込むと,なにやら文字が出るようになりました。でも,化けていたり,出なくなったりと,散々です。

 いろいろ試していると,ストップコンディションから次のスタートコンディション,そしてアドレス送信という一連の流れを繰り返さず,続けてデータを送り込めば動く事がわかりました。

 この段階で胃に穴が3つほどあいていた私は,向かい風に立ち向かえなくなっていました。もうこれでいい,とにかくデータを流し込もう・・・

 しかし無残に,表示は途中で途切れ,そこからはバケバケになってしまいました。

 万策尽きた。もうダメだ。俺はもう疲れた。寝る。

 悪いことに,オシロスコープが使えない環境で検討をしていたのですが,それはすでにSi5351AでI2Cが動いていたので,I2Cで問題が出るとは思っていなかったからです。

 AQM0802特有の問題,もっと言うとLCDコントローラであるST7032の相性問題と考えて,もうこのLCDはあきらめようと思っていたのですが,最後に波形だけ見て終わりにしようとおもったのでした。

 自宅にある,使い慣れたバグファインダー,HP54645D。

 Si5351AのI2Cにプローブをあて,設定完了までの約1秒間,波形を丸取りです。

 そして拡大して波形の詳細を見ていきます。

 私はここで,戦慄しました。

 まず。I2Cの基本的な概念が実装されていません。I2Cは,SDAの取り込みをSCLのエッジでは行いません。SCLがHighの時に取り込む,レベルトリガです。ゆえに,SDAはSCLがLowの間にしか,動かしてはなりません。

 波形を見ると,SDAとSCLが同時に変化しています。これでもなんとか動いているのは,Si5351Aのマージンのおかげでしょう。

 スタートコンディションを見ていきます。うん,これはまあ正常です。

 次,ACKです。一説によると,ST7032はACKを返す際に,レベルを下げきれないことがあり,これが誤動作に繋がるという話です。しかし,今回はプルアップ抵抗を大きめにしてある(10kΩ)ので,ちゃんとACKが下がっています。問題ありません。

 そして次,ストップコンディションです。

 ・・・え,ストップコンディションが出てないじゃないか。

 一応それらしい動きをしていると思われる場所は,最後の部分にありました。しかし,SDAがHighのままになっていて,その状態でSCLがLowからHighになっているのです。

 本来なら,SDAは一度Lowになってなくてはならず,そこからHighにならないといけないのですが,ストップコンディションになり損ねています。

 どうやら,ストップコンディションを発生させる関数の先頭にSDAとSCLの両方をLowにする記述を忘れているようです。

 自宅ではコンパイラもライタもないので,修正はできません。おそらくこうだろうとコードをざざっと書いて,翌日修正をして書き込んで見ると,何事もなかったように文字が出ました。

 うれしいと言うよりも,なんだかバカバカしいと思いました。

 というのも,このコード,google先生に聞いて出てきた,ある人のコードをそのままコピペしたものだったのです。一応内容は理解したつもりでしたし,なにより動作しているわけですから,ここを疑うことはしませんでした。

 そもそも,この方も,海外のあるサイトから持ってきた物だとおっしゃっていて,内容を理解した上でウェイトを調整したと書かれていました。

 でもね,内容を理解されたという割には,波形を見たら5分で分かるようなミス,それもストップコンディションというI2Cの基本中の基本シーケンスが動いていないんですから・・・

 いえいえ,信じた私が一番悪いのです。

 他人を信用せず,全部自分で書こうかと,途中までソフトウェアI2Cを書いていた途中のことでしたが,原因が分かり,修正ができたのですから,もうこのまま使います。

 この修正をaitendoのLCDで作った時計にも入れてみましたが,当然問題はありませんでした。これで検証終了。修正版を正式にリリースです。

 まとめるとこうです。ストップコンディションが出ていない状態ですので,バスは生きています。しかしホストはスタートコンディションとアドレスを発行します。スレーブはこれがデータかコマンドと解釈するので,意味のある数字なら動くし,ダメなら動かないわけです。

 なら,Si5351Aではなぜ動いたのか。これはやっぱり,ストップコンディションが出ていなくても動くようになっていたから,ということでしょう。もしかしたら,SDAもSCLも両方ともが,ある時間以上Highになっているとタイムアウトでバスを解放するようになっているのかも知れません。

 aitendoのLCDも修正前状態で動いていましたので,こちらもストップコンディションを無視しているんでしょうね。3つのデバイスのうち,2つが動けば,申し訳ないけど正しく動いていると信じてしまいます。

 ということで,なんとかAQM0802を動かす事に成功しました。I2Cの動作も詳細に理解しましたので,決して無駄ではなかったと思うのですが,それでもどかっと疲れが出ましたし,釈然としない物もあります。

 今回もはっきりわかったのは,やっぱり波形を見るとすぐに解決するということ,そしてオシロスコープはやはり最強ツールだということでした。

 波形を見ずに試行錯誤をしていては,20時間経っても30時間経っても問題が見つかりません。問題が見つからないと対策も打てません。

 でも,波形を見れば,本当に5分で問題が発覚,対策も打てます。

 そして波形を取るのも,簡単にできると作業が捗ります。I2Cを解析する機能を持ったオシロスコープもありますが,私はそこまではいりません。ただ,見たい部分を確実に取り込める事が大事です。

 これはつまり,多彩な条件を設定出来る,キレのいいトリガがオシロスコープの性能を決めるといっていいのですが,それ以外に,長時間丸取りし,あとで詳細を拡大して見ることが出来る機能が,私には必須です。

 今のオシロスコープでこの機能がどのくらい装備されているのかわかりませんが,HP54000シリーズはこの機能の走りだったと記憶していて,幸い私が使い始めた54645Dがもつこの機能に,思わずため息が出たことを覚えています。

 拡大すると取り直しになるオシロスコープがまだ多く,見たい部分の位置が,先頭からのバラバラの時間になってしまうようなケースだと,もうお手上げだったりします。

 少ないチャンスを確実にものにするのが,キレのいいトリガ。そしてそのチャンスを生かし切るのが,MegaZoomです。

 最近,安価なオシロスコープが当たり前になってきており,電子工作を嗜む人達の間でオシロスコープを持っていることが珍しくなくなりました。

 それはそれでいい時代になったと思うのですが,それらが本当に良いものかどうか,私にはわかりません。良い道具を使えば,良い仕事ができます。それを強く感じた,一連の騒動でした。

GPSで周波数を追い込む

  • 2016/03/31 15:57
  • カテゴリー:make:

 周波数カウンタにTCXOを搭載し,2ppm以下の周波数精度を手に入れた私ではありますが,2ppmといえば,1MHzに対して2Hzですから,8桁の周波数カウンタの精度としては,ちょっと心許ないのも事実です。

 フルスケール10MHzを測定するとすれば,1ppmなら10Hzです。ちょうど3桁目が10Hzの桁ですので,8桁のカウンタなら下2桁が信用出来ないという事になります。せっかくの8桁カウンタなのに,寂しいですよね。

 温度変化や経年変化はやむを得ないとして,今出ている周波数が一体どれくらい正確なのか知りたいと思っても,そういうチャンスはなかなかありません。ルビジウム発振器に手を出すとか,校正済みのOCXOを買うとか,そういうことは費用の問題もそうですし,維持の問題もあるので,素人には厳しいです。

 ちょっとまった,手軽に高精度な「絶対値」が手に入る方法があります。GPSです。かつてはJJYの10MHzをつかまえるとか,カラーテレビの内部からカラーバースト信号を引きずり出すという方法がありましたが,JJYの短波は停波して久しく,カラーバーストも地デジになった現在では無い物ねだりに過ぎません。中国政府が威信をかけて出している標準電波もありますが,それこそ知る人ぞ知るでしょう。

 GPSではすべての衛星で位相まで揃った高精度な周波数が手に入り,これを元に測位を行います。周波数の精度が高くないと測距精度が上がりませんので,GPSの衛星には10E-13という精度の原子時計が搭載されて,しかも精度は地上で管理されています。

 GPSの受信機はこの周波数と位相まで一致させて測位を行います。ですから,理屈の上では10E-13の精度が手元にくるはずですが,なにせ宇宙から飛んでくる電波ですから,空気の揺らぎもあって,そこまでの精度は出ません。
 
 調べて見るとGPSモジュールが出力する1秒パルス(1PPS)の精度は10nsくらいとのことです。1nsは10E-9秒ですから,1PPSの精度は10E-8ということになります。

 ここで重要な事は,この1秒で10nsのズレという精度は,常に補正され続けているので,10秒だろうが100秒だろうが1000秒だろうが,トータルのズレはやっぱり10nsということです。ということは,長いスパンで見れば見るほど,精度は上がっていくのだという事です。

 また,正確なパルスは1秒に一度しか出ませんから,パルスが出ていないときは,GPSとは別の時計を持っていないといけません。ここに変動の大きな発振器を使うと,1秒ごとに正確な時間に補正されるとは言え,1秒未満の時間は全くあてにならないということになってしまいます。

 よく,GPSを使ったタイムベースにOCXOを使う例を見るわけですが,1秒未満の時間はOCXOを使い,これを1秒ごとにGPSで補正して使っているわけです。

 GPSの1秒ごとの精度は10E-8から10E-9くらいですが,これが1000秒になると10E-12くらいに精度があがります。こうして長い時間かけてOCXOの補正を続けて,最終的に10E-12という原子時計に迫る精度を手元に作り上げるのです。

 まあ,ここまでやると結構大変です。そこでふと見方を変えてみたのですが,10E-8でよければ,1秒でいいのです。なら,面倒な仕組みも必要なく,GPSモジュールから出てくる1PPSだけでいいですよね。

 もちろん,周波数も異なるので,この1PPSをそのまま,周波数カウンタのタイムベースにすることはできません。しかし,タイムベースを校正するための基準クロックとしてなら,十分です。

 そう,GPSの1PPSのパルスが,正確に1Hzになるよう,周波数カウンタのタイムベースを調整するのです。

 とはいえ,この方法では1秒に一度しかパルスが出ませんので,ゲートタイムが10秒程度の普通の周波数カウンタでは10個のパルスしか数える事が出来ません。10MHzがGPSから出てくればいいんだけどなあ・・・

 そんなことを数年前から考えていたんですが,周波数は周期の逆数ですので,周期を計ればいいんじゃないかと気が付きました。

 周波数カウンタのモードを周期を測定するモードに切り替えます。正確な1秒を入力に突っ込むのですから,この1秒の間にタイムベースのパルスがいくつあったかを数えれば,校正できそうです。

 例えば10MHzのタイムベースを数えることにすると,カウントされた数字は10000000となり,1000000.0us,すなわち1秒という測定結果を得られることでしょう。

 とまあ,そんな風に妄想していたところ,ふと最近のGPSモジュールのタイムパルス出力が,1PPSではなく10kHzや1MHz,はては10MHzまで設定可能であることを知りました。

 なんと,GPSから10MHzが直接出てくるなんて,夢のようです。

 しかし残念ながら,それは夢でした。というのも,ジッタが大きすぎて使い物にならないんだそうです。理由はどうやら,GPSモジュールの内部クロックが48MHzで,ここから10MHzを作っている関係で,どうしてもジッタが大きめに出るのだとか。だから,1MHzや8MHzといった整数比であれば,ジッタは少ないものが手に入ります。

 さて,話を整理します。

 うちの周波数カウンタは,TCXOを使って安定度を2ppm程度にしてあります。これは10MHzフルスケール(8桁フルカウント)で,20Hz程度の測定誤差が出ることを意味しています。

 ただし安定度ですから,初期値に対する変動が2ppmというだけで,初期値がいくつかはデータシートを信用するしかありません。VM39S5Gという秋月のTCXOは1ppm以内に合わせてあるということですが,以前ここに書いたように電源電圧で大きく変動し,0.1Vで40Hzも動きます。0.03Vずれると1ppm変動するというのですから,これはかなり大きいです。

 一応,高精度な電圧計で電源電圧を5Vぴったりに追い込んでいますし,秋月の話を信じるなら5Vで1ppm以内に調整されているということですので,そんなにずれているわけではないと思いますが,それでも初期値は現在不明なままです。

 そしてその初期値は,絶対精度がはっきりしている,GPSから生成された周波数との比較で手に入ります。本来GPSでは1PPSしか出てきませんし,これも長期的に平均を取らないと10E-12レベルにはなりませんが,1秒でも10E-8程度の精度は持っているという話です。

 そこで,GPSで1PPSを元にしたもっと高い周波数を作り,これを周波数カウンタに突っ込み,その周波数になるように周波数カウンタのタイムベースを調整します。タイムベースの調整は,TCXOに供給する電源電圧の微調整で行います。

 よし,あとはどうやって行くかを考えましょう。

 GPSといえば,aitendoです。aitendoのGPSの取り扱い品種は多く,でもあまり詳しい説明がないので,正直敷居は高いです。ですが,先人達の苦労のおかげで,なにを買えばいいのか,調べることができます。

 今回私が買ったのは2種類,u-bloxのNEO-6Mが搭載された基板とアンテナのセットでNEO6M-ANT-4Pです。数ヶ月前のトラ技にも出ていたんですが,値段が上がったようで1980円ではなく2780円で買いました。

 もう1つは最新のNEO-M8Tが搭載された,GM-8013Tです。最新だけにちょっと高くて,3980円でした。最新のものが欲しいのは,別のいろんな衛星をつかまえたいわけではなく,少しでも感度を稼ぎたいと思ったからです。

 そうと決まれば,在庫があるうちに注文です。迅速な対応で,翌日には届きました。ありがたいですね。

 さて,届いたGPSですが,いずれもシリアルポートで繋ぎます。RS-232Cではないので,レベル変換はいらないのですが,この時手元に,USB-シリアル変換基板が1つもありませんでした。

 しかも,u-bloxのツールである,u-centerはWindows Vista以降しか動かないという事なので,古いPCではダメ。USB-RS-232C変換ケーブルも新しいOS用のドライバがなくて動かず,結局買い直す羽目になりました。

 Windows8.1でu-centerが動くようになって,ようやくこの2つのモジュールに火を入れます。PCとの通信は問題がないのですが,室内なのでなかなか衛星をつかまえてくれません。特にGM-8013Tは全然だめです。壊れたのか?

 そのうちつかまえるだろうと,u-centerで先に設定をいじってみます。configuration viewからTP5の設定をあれこれいじって,8MHzを出してみました。衛星をつかまえていないので,あくまでこのモジュールの内部クロックです。

 周波数カウンタで調べると,7Hzほど高いです。なるほど。

 ・・・さて,そのうちつかまえるだろうと思っていた衛星は,なかなかつかまりません。やっぱり壊れたのか?

 ふと気が付くと,一緒に電源を入れたNEO6M-ANT-4Pは結構しっかりつかまえているようです。

 こっちにシリアルポートをつなぎ替えて,設定をします。衛星をつかまえていないときには1MHzを,衛星をつかまえてロックしたら8MHzになるようにしました。こうすれば,いちいちPCを立ち上げなくても状態が出力される周波数でわかります。

 衛星をつかまえない状態では1MHz,つかまえたら8MHzに鳴っていることを確認して,これを10MHzに設定してみると,値がパラパラとばらつきます。オシロで見れば,それはそれはひどいジッタで,これは全然使い物にならないです。

 1MHzや4MHz,8MHzや規格外ですが12MHzにすると,ジッタが目視できないくらいの綺麗な波形が出てきます。周波数カウンタでも値は動きません。

 とりあえず,この8MHzを校正用基準周波数として,周波数カウンタのタイムベースの電源電圧を調整し,8MHzになるようにあわせます。最初はゲートタイムを1秒にして大まかにあわせ,次にゲートタイムを10秒にして追い込んで行きます。

 10秒に一度しか値が更新されませんので調整は難しいのですが,ちょっとずつちょっとずつあわせます。

 8000000.0Hzになるように根気よく合わせるのですが,5Vを作っている可変電圧LDOの可変抵抗が,いかに多回転型を使ったとはいえ,時間と共に変動があるのです。TCXOで温度変化を相殺しても,電源電圧に温度依存があったり経年変化があったらなんか意味がないです。

 最終的に,0.1Hzの桁まであわせ込みました。

 8桁の周波数カウンタは,ゲートタイム10秒で0.1Hz以下をカウント出来ません。最大0.1Hzの測定誤差を起こすわけですから,これは0.0125ppm,すなわちこの段階では1.25ppb以内の精度になっているということになります。

 もちろん安定度が2ppm以下ですので,こんなものはすぐに変動してしまうでしょう。そんなに意味はありません。けど,やっぱり限界ギリギリまでせめた,という気持ちよさはありますね。

 一応,このまま二晩通電して周波数を測定し続けました。周波数カウンタは最終桁が2ほど動く事はありますが,なんとか追い込めたようです。ゲートタイムが10秒で精一杯ですので,1PPSから作る8MHzの精度も10E-8くらいがいいところでしょう。あるいはGPSモジュール内蔵のPLLから生成する8MHzなので,もっと悪いかも知れません。

 仮に10E-8出ていれば,この周波数カウンタの精度としてはまずまずでしょう。
 
 ところで,GM-8013Tも同時に調べていたのですが,翌日の朝になるとちゃんとつかまえるようになりました。窓際に置いておくとたくさんの衛星をつかまえるようになり,ロックした瞬間に7Hzのズレがあった8MHzも,ピタッと8MHzになりました。

 ということで,周波数カウンタの校正は終わりました。TCXOの安定度が気になる場合は,GPSで校正をしてから測定をすればいいわけで,TCXOとGPSの手軽さが生きてきます。

 この状態で,手元のOCXOも調整をしましたし,TCXOも可能な物は確認して調整をしました。優秀だったのは以前鈴商の店頭で買ったNECの15MHzで,これはもともと1ppm以下のズレしかない上に,電源電圧の変動に対しても安定でした。優秀です。

 TG-5021も電源の変動には強かったです。これがトヨコムの9.98MHzのものだとバンバン動きます。VM39S5Gもそうです。こういう観点で評価をしないと,このあたりの発振器は難しいですね。


AVRtiny13Aでつくるシリーズ3 TCXOを使って時計を作る

  • 2016/03/31 12:04
  • カテゴリー:make:


 さて,今回はCPUのクロックに外部のTCXOで作った10MHzを突っ込み,これをもとに時計を作るという話です。少し前に,わざわざSi5351で32.678kHzを生成して時計を作ったという話を書きましたが,そんなことをしなくてもTCXOの時計を作る事は出来るんじゃないかという発想を,実際にやってみたという話です。

 そのTCXOの周波数ですが,別に10MHzでなくてもいいんじゃないのと思われると思いますが,そうは問屋が卸しません。

 なにせtiny13Aです,最終的に1秒を作る事の出来る外部クロックは,限られます。ここでは手持ちの関係もあり,10MHzのTCXOを使う事にします。

 原理は簡単で,以前の32.768kHzの時計と全く同じです。ただ,CPUクロックを使いますので,プリスケーラを通せます。

 まず10MHzをプリスケーラで1/64します。そうすると156250Hzになるのですが,これをカウンタで数えます。一定の数になったら割り込みを発生させますが,割り込みの発生が整数回数でなければ,1秒を作れません。

 そこで,数える数を250とします。すると1秒間に625回の割り込みが発生します。割り込み処理で変数をインクリメントし,625になったら1秒です。あとは普通に作ればいいだけです。

 変数はint型になりますし,16ビットの加算になるのでコードも大きくなりますが,処理時間としてはこのくらいの内容なら,まあ大丈夫でしょう。

 LCDは,引き続きデジットの8桁14セグのものです。

 

続きを読む

ページ移動

ユーティリティ

2020年05月

- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31 - - - - - -

検索

エントリー検索フォーム
キーワード

ユーザー

新着画像

新着エントリー

過去ログ

Feed