製作モジュール一覧

ラベル デバッグ の投稿を表示しています。 すべての投稿を表示
ラベル デバッグ の投稿を表示しています。 すべての投稿を表示

2014年9月11日木曜日

ATtiny13のゆるゆる万歩計デバッグ(その2)

万歩計デバッグの続きです。
①ADコンバーターの入力ピンにボリュームからの電圧を投入。
②この電圧を監視し、変動があれば万歩計に出力する 
この実例です。

今回のサンプルソースでは、tiny13の3番ピンADC2から電圧を拾い、5番ピンPB0に万歩計を接続して上位8ビットの値を表示しようとしています。
(入力電圧を変えるために使ってるボリュームは一部で有名なセリアの100円アンプのもの、単に手元に適当なボリュームがなかったからなのですが。昨今100円ショップに依存しておりまする)

tiny13の動きは以下のようになっています。 
①ADC2より電圧のAD変換値を取得。
②現在保持している値よりADC2の値が大きければ1パルス入れカウントアップ。
③逆に小さければ、万歩計をリセット。
④最初に戻る。

こう組む事によって、メインループの中で、ボリュームの手操作に健気に万歩計がついてくるという動作となりました。(映像暗くてすんません)
うまく使えば完成品の表示装置として使えるんじゃないかな…とも。



ソースコードは以下のとおりです。
例によってコンパイルにはavr-gccを使っています。
自分はMacOSXでビルドしております。

#include <avr/io.h>
#include <util/delay.h>

#define cbi(addr,bit)     addr &= ~(1<<bit)
#define sbi(addr,bit)     addr |=  (1<<bit)


void delayms(int ms) {
    int n;
    for(n = 0 ; n<ms ; n++)
        _delay_ms(1);
}

void pulseOut(int ms,int wait) {
    cbi(PORTB,0);
    //指定ミリ秒間出力0を維持
    delayms(ms);
    sbi(PORTB,0);
    delayms(wait);
}

//指定チャネルからADC値を8ビット取得
uint8_t getADC(uint8_t ch)
{
    ADCSRA |= _BV(ADEN);
    ADCSRA |= _BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0);
    sbi(ADMUX,ADLAR);//上位8bit
    ADMUX |= ch;//ADCchセット
    sbi(ADCSRA,ADIF);
    sbi(ADCSRA,ADSC);
    loop_until_bit_is_set(ADCSRA,ADIF);
    return ADCH;
}


int main(void)
{
    int rstwait = 500;//resetパルス幅
    int clkwidth = 2;//Sigパルス幅
    int clkwait = 10;//パルスの待ち時間
    uint8_t outvalue = 0;//万歩計への出力数値
    int innervalue;
  
    //AD変換可能なポートを入力に設定
    DDRB = ~0b00111100;
    PORTB = 0b00111100;
    //ポートB0を出力に設定
    sbi(DDRB,0);
    //万歩計に0.5秒間0を入れて初期リセット
    pulseOut(rstwait,clkwait);
    innervalue = 0 ;
  
    //メインループ
    while(1){
        //①ADC2より電圧のAD変換値を取得。
        outvalue = getADC(2);
      
        if ( outvalue == innervalue ) {
            _delay_ms(200);
        } else if ( outvalue > innervalue ) {
            //②現在保持している値よりADC2の値が大きければ
            //1パルス入れカウントアップ
            pulseOut(clkwidth,clkwait);
            innervalue++ ;
        } else if ( outvalue < innervalue) {
            //③逆に小さければ、万歩計をリセット。
            pulseOut(rstwait,clkwait);
            innervalue = 0 ;
        }
    }
    return 0;
}

2014年9月10日水曜日

ATtiny13のゆるゆる万歩計デバッグ。

 ゲストの冨塚電磁です。 よろしくおねがいいたします。
 
 えー、常々ATtiny13はたいした奴だと思っております。たかだか8ピンのパッケージ。
 電源GNDを取ったら6ピンしかないが全部双方向に使える。
 LEDくらいなら楽々駆動できる。
 ATtiny2313にはついていない、10ビットADコンバータを4つも持っている。

 そして秋月で一個50円(笑)

 でもね、デバッグどうしようかいつも悩むわけですよ。
 単純に温度センサーからの入力が、どんな範囲でAD変換されるのかチェックしたい。
 それだけなのに、なーんかめんどい。
 
 だいたいデータ取り出しのためだけに何本もピンをとられたら本末転倒。
 メモリ空間もたかだか1kバイトしかないので複雑なプロトコルも組みたくない。
 そこで、手軽に実行時の数値取り出しを行える手段を考えてみました。

 この方式の便利なのは、

1、表示装置が108円で済む。
2、表示装置側のプログラミングは一切不要。
3、tiny13側のプログラムがアホみたいに軽い。
4、tiny13側はポート1ピンしか食われない。
  (残り5ピンはそのガジェットにフルに供することができる。)

 最大のデメリットは 表 示 が 遅 い  コレにつきます。

※アイディアの元は、2011年にいろいろやってた、ガイガーカウンタ 。
 実験回路ではGM管が放射線を検知した際に発するパルスを万歩計に入れてカウントし、それを単位時間あたりに換算して、放射線量を測定するという実験をやっていたのです。

 手軽に入手できる、ダイソー万歩計(スタイリッシュ歩数計)。税込み108円。
1.55Vの電池もついています。
バラすと、シンプルの極地です。ボタン電池の実装方法は真似したい。

 右下のスイッチはリセットスイッチです。
 0.5秒程度長押しするとカウンターがリセットされます。リセットスイッチ左ピンの信号線(Rstと呼称)を右ピンGNDと同じレベルに落とすとスイッチを押したことになります。

 さて、歩数カウンタのほうですが、左側のなにやら怪しげな錘とバネのついた機械的機構で振動を電気的なパルスに変えます。
 バネとGND信号線が共通である本田宗一郎的思想に感動します。
 こちらも赤いラインの信号線(Sigと呼称)を黒いラインのGNDに落とすことでパルスがはいります。


 液晶とのツナギの構造とかまあいろいろおもろいとこはあったのですが、いろいろすっとばして、このよう ↑ にピンヘッドつけて改造し3線でブレッドボードに差せるようにします。
 実のところ回路図など書くまでもありません。
 写真のピンヘッド左側から[Vcc] [Sig/Rst] [GND]です。[Sig/Rst] [GND]のピンヘッドは基板上のスイッチのランドに直づけしています。
 カウントアップの信号線Sigとリセット信号Rstはめんどいのでまとめてしまいました。
(こちらからは見えませんが赤いSigラインはRstの基板上ランドにハンダづけされております。 )
 [Vcc] 省いて外部電源供給なしで付属のボタン電池駆動でも問題ありません。2−3時間ほったらかしでグルグル放置で寝てても健気に動いてました。

 tiny13のプログラム側は

①0.5秒以上の幅の0パルスをRstに送り長押しを再現、万歩計のカウンターをリセット
②確認したい変数の値分、0.1秒以下の幅でSigにパルスを送る。
 (同一ピンに改造されていますが、短いパルスではRstは反応しません)

 そんだけです。プロトコルもへったくれもなく全く以て原始的です。
 鐘や太鼓で時間を知らせるとか、狼煙を何本上げるとか、そんなかんじ(笑)

☆問題は万歩計がそれほど高周波のパルスを受け付けてくれない(せいぜい秒間十数パルス)ことで、速すぎるととりこぼします。
 (サンプルソースの例では、クロック周期を司るclkwaitの値が10以下になると取りこぼし始めます)
 我慢できるレスポンスが数秒程度と考えるならば、実用になるのは、5-6ビット幅までのレジスタ値かと。
 測定結果の気温とか、電圧とかならいいのかもしれません。値が変化したときだけ表示を書き換えるようにすると良さそう。
 もし10ビット幅(最大1024)などチェックしようものなら2分くらいかかります。

 512という数字を出そうとするだけで、こんなに ↓ かかったりします。
 (下のサンプルを実行した結果です。)
 しかし、1ピンのみの占有でLEDなら1bitしか出せないのを時間さえかければ数ビット分引きずりだせるわけです。

 …10ビット幅もデバッグのみに使うなら5ビットづつ2回に分けてあとは手計算という手があるか。


 サンプルの例ではoutvalという変数に入れた数値の数分、tiny13の3番ピンPort4で万歩計の[Sig/Rst]を叩いて値を出しています。
 実用的には各種センサのAD変換値や計算結果などをoutvalに入れて表示という流れになるかとおもわれます。
 サンプルソースコード(avr-gcc)はこれだけ ↓ です。

                       文責  冨塚電磁

#include <avr/io.h>
#include <util/delay.h>

void delayms(int ms) {
    int n;
    for(n = 0 ; n<ms ; n++)
        _delay_ms(1);
}

void portGnd(int ms,int wait) {
    PORTB = 0b00000000;
    //指定ミリ秒間出力0を維持
    //※なぜか_delay_ms(ms)としてパラメータに変数を使うと
    //   極端にhexファイルがでかくなる
    delayms(ms);
    PORTB = 0b00010000;
    delayms(wait);
}

int main(void)
{
    int rstwait = 500;//resetパルス幅
    int clkwidth = 2;//Sigパルス幅
    int clkwait = 15;//パルスの待ち時間
   
    int outval = 512;//万歩計への出力数値
    int n1;
   
    //ポートB4を出力に設定
    DDRB  = 0b00010000;
    //万歩計に0.5秒間0を入れて初期リセット
    portGnd(rstwait,clkwait);
    n1 = 0 ;

    //グルグル
    while(1){
        //万歩計に0パルスを送る
        portGnd(clkwidth,clkwait);
        n1++ ;

        if ( outval == n1 ) {//カウンタが出力値に到達
            n1 = 0;
            //2秒待って表示を確定
            delayms(2000); 
            //万歩計に0.5秒間0を入れてリセットしグルグルに戻る
            portGnd(rstwait,clkwait); 
        }
    }
    return 0;
}