ラベル PIC16F18326 の投稿を表示しています。 すべての投稿を表示
ラベル PIC16F18326 の投稿を表示しています。 すべての投稿を表示

2026年7月18日土曜日

LiDARを使った相対速度計(その9)

 PICを16F18326に変えることで、LiDARとの間の通信はI2Cに限定された。しかし新品のLiDARのインターフェイスはデフォルトでUART(460,800bps)に設定されているのでこの矛盾を何とか整合させたい。以前、ポートを直接ソフトウェアでON/OFFしてUART信号を作り、460,800bpsを9600bpsに落とすことが出来たが、その応用として9600bpsのソフトウェアUARTを作りたい。とりあえず送信だけ出来れば何とかなるので作ってみた。そのコア部分は、

#define TX_OUT      LATAbits.LATA4 

static void send_byte_9600(byte data){

    TX_OUT      = 0;   __delay_us(100);  // Start bit
    byte cnt = 8;
    while(cnt-- > 0){
        TX_OUT  = data & 0x01;
        __delay_us(100);                // Bit width shall be 104us
        data >>= 1;
    }
    TX_OUT      = 1;   __delay_us(200);  // Stop bit    
}

void u2raw_send_cmd(byte *data, byte len){
    for(byte n=0; n<len; n++){
        send_byte_9600(*data++);
    }
}

である(同期ずれを防ぐため2StopBitsとしている)。なおこのプログラムを呼び出す前段階として出力ポートの設定や、同期ずれを防ぐための割り込み禁止措置が必要である。受信はサポートしていないので正確にはUAT(Universal Asynchronous Transmitter)だ。

これを使えばUARTでLiDARの一通りのコマンドを実行できる。完全なソフトウェアUARTを作る事もできるが、それは後回しにしよう。

とりあえず、ドライバーの立ち上がり時のLiDARの制御は、

  1. ソフトウェアUARTで460,800bpsを9600bpsへ落とす。
  2.  ソフトウェアUARTでインターフェイスをI2Cへ変更。
  3. 以降I2CインターフェイスでLiDARと通信。 

とする。2.のI2Cインターフェイスへの切り替えは次のようなコマンドをソフトウェアUARTで生成している。


LiDARは一旦I2Cへ切り替えると以降はUARTへ戻すコマンドをを実行しない限り一旦電源を切ってもI2Cのまま保留されるが、I2C通信時にUART信号を送っても無視されるので実用上はこれで特に問題はない。

 (続く)

 

 

2026年7月14日火曜日

LiDARを使った相対速度計(その8)

 さて、PIC上で動かすI2Cのドライバー(プログラム)であるが、以前、見様見真似で納得しないまま作ったものを再利用してみたが上手く行かない。最初は何とか動いたように見えたが、ソフトを弄っているうちにLiDARが全く応答しなくなり、不正なデータを送って内部状態が異常になったか壊れたと思ってLiDARをもう1個買い足したりしたが結果は変わらなかった。

仕方が無いので改めてI2Cドライバーを作り直した。今回はハード/ソフトに関する理解が進んだのか意外とすんなりと動き、LiDARも正常な応答を返すようになった。

I2CでLiDARを扱う場合は先ずIDを読んでみて、IDを正しく読めているかを確認する。 I2Cの場合、データの書き込みより読み出しの方が少しややこしいのいで、読み出しが成功すれば一安心だ。実際のI2Cのトレースを取得してみると、

LiDARのIDの取得、 

 測距データの取得、

ソフトウェアバージョンの取得、
シリアル番号の取得、

レーザーON、

なおTSD20でレーザーをOFFにすると測距データは20,000mmに固定される。

 (続く)

 

2026年7月13日月曜日

LiDARを使った相対速度計(その7)

 TSD20は思いのほか小さかった。コネクタも小さいので抜き差しすると壊しそうだ。接続線も簡単に切れそうに細い。

TSD20では測定頻度を毎秒50回を含む他の頻度に変更するのも上手く行った。

 TSD20を空に向けると測定値は20000mmとなり、マニュアルにあるような50000mmでは無い。これはTSD50のマニュアル記述の使い回しで修正を失念したのかな。

LiDARにUARTでSTOPコマンドを送ると1秒1回程度の頻度で次のデータを自発的に送ってくる(6番目の0xf0はチェックサムだ)。 

5a 0f 02 ff ff f0

 これが何を意味しているのかマニュアルに記述が無く、ネット情報も無く皆目分からない。たぶん Keep Alive 的な性格を持っているものと推察する。

 

さて、TSD10やTSD20ではUARTインターフェイスで上手く行ったが、一方TSD50では毎秒500回という固定した測定頻度の関係で9600bpsではデータを送りきれない。そこでI2Cインターフェイスに挑戦する事にした。併せてPICを容量の大きいPIC16F18326に変えるが、このPICには2個目のUARTが搭載されていないのでI2C専用、或いはソフトでUARTを実現する必要がある。

PICとのインターフェイスでLiDARでデフォルトのUARTを選んだ場合、UARTは全二重通信なのでデータはLiDAR主導で測定頻度に従って勝手に送られてくる。またLiDARへのコマンドの送信とレスポンスの受信も送信側の勝手なタイミングで行われる。一方、I2Cの場合はポーリング方式なのでマスター(PIC)側主導でデータを転送する必要がある。

従ってUARTではPICはLiDARから勝手に送られてくるデータを受信し処理すればよいが、一方I2Cを使う場合はPIC主導で定期的にデータを取得し、その結果を処理する必要がある。つまりUARTとI2Cではソフトの造りが違ってくる。

I2Cを使ったデータ転送は具体的にはLiDARの内部レジスタのデータの読み出し/書込みという操作である。I2Cを使う場合は、LiDARの内部レジスタの書き換えは500Hzの測定毎に行われると思われるが、それとデータ取得の関係(タイミング)についてデータシートには何も説明が無く、やってみないと結果は分からない。

LiDARのI2Cアドレスについてもマニュアルの説明では0x52と書いてあるが説明図では0x54(0b010101xx)みたいに見える。これも試してみないと分らないが、後のチェックで0x52が正解であることが分った。

(続く)

  

2026年5月23日土曜日

LiDARを使った相対速度計(その4)

 とりあえず基板を百均のクリアトレー(ミニ)を加工した箱に入れた。


LiDAR(TSD10)は反射物までの距離の測定を毎秒50回行う。前出のセンサー部はこの10回分を平均して、即ち0.2秒毎に距離をcm単位で報告してくる。

相対速度はこの0.2妙毎の距離の変化(差分)から算出すればよい。具体的には差分(m/0.2sec)を18000倍(=5×60×60)して100000で割ることで時速(Km/h)に変換できる。

7セグLEDの表示はこの相対速度(Km/h)と距離(cm)をスイッチで切り替えられるようにした。 またセンサー部からの入力が無い場合は全桁ドット(.)を、センサーの探知範囲外は全桁ダッシュ(-)を表示する。

左端の緑、黄、赤のLEDは次の様に点灯させる。緑は相対速度が正の場合に点灯、 赤は相対速度が負の場合に点灯、赤と緑の点灯には閾値を設定している。黄色は相対速度が0の状態が3秒以上続いた場合に静止状態と判断し点灯する。黄色から緑へ点灯が変化する場合、即ち信号待ちで停車中に前車が発射した場合にブザーをピッと鳴動させる。ブザーは当初は市販の小型電子ブザーを使ったが音がプアーだったのでタイマーで作った約2KHzの方形波でスピーカを鳴らすようにした。


次の写真で赤丸は 追加した相対速度と距離の切り替えスイッチ、橙丸は追加したダイナミックスピーカ。スピーカはPICの出力からコンデンサーで直流分を切って直接駆動している。


これで予定した基本的な機能は実装できたはずである。

(続く) 

 

2026年5月19日火曜日

LiDARを使った相対速度計(その3)

 ソフトの制作と並行して基板を組み立てた。

そしてPICにソフトを書き込んでデータを表示させてみた。
実際にはTM-I2Cの実装とテストに思いのほか手間がかかった。しかし動き始めればこっちのものである。
あとは上位アプリをどう作って行こうか?
 
(続く) 
 
 

2026年5月12日火曜日

LiDARを使った相対速度計(その2)

 今回の速度計で一番問題となるのはTM1637のI2Cモドキの2線インターフェイスだ(以降「TM-I2C」インターフェイスとする)。最初はPICのI2Cインターフェイスが流用できるかもしれないと考えたが仕様を検討して諦めた。TM-I2CもI2Cのようにクロックとデータの2線構成だが転送する最初のバイトがI2Cのアドレス+R/WではなくTM-I2Cはコマンドだ。またビットの並びも逆になっている(これはソフト的に解決可能だが)。従ってTM-I2Cはソフト的に実装する事とした。TM-I2Cの通信速度に下限規定は無いので実装は楽だろう。

TM-I2Cでデータ線は双方向通信を行う必要があるが、これはWired-OR接続で解決できる(注1)。Wired-OR接続の設定は例えばC1ポートでは次の様に設定した。 

    // 15: RC1 - DSPDAT
        LATCbits.LATC1   = 1;       // normal H
        TRISCbits.TRISC1 = 0;       // Output Enable
        ANSELCbits.ANSC1 = 0;       // Digital
        ODCONCbits.ODCC1 = 1;       // Open Drain
        WPUCbits.WPUC1   = 1;       // Weak Pull-Up

プログラム中ではデータ線、クロック線については次の様にマクロ定義している。また適当に遅延を入れてタイミングを調整している。

    #define CLK_OUT     LATCbits.LATC0
    #define CLK_IN      PORTCbits.RC0
    #define DAT_OUT     LATCbits.LATC1
    #define DAT_IN      PORTCbits.RC1

    #define DLY_4US     __delay_us(4)
    #define DLY_10US    __delay_us(10)
    #define DLY_50US    __delay_us(50)


 クロックが1の間データ線は変化してはならない(スタート・ストップ時を除く)から、1ビットの送信は、

    static void tm_send_bit(boolean d){
        DAT_OUT     = d;
        DLY_10US;
        CLK_OUT     = 1;
        DLY_50US;
        CLK_OUT     = 0;
        DLY_50US;
    }
で良いだろう。逆に1ビットの受信は、

    static boolean tm_rcv_bit(){
        boolean dat;
        DAT_OUT     = 1;
        DLY_50US;
        CLK_OUT     = 1;
        dat     = DAT_IN;
        DLY_50US;
        return dat;
    }
 スタートビット、ストップビットについては、

    static void tm_start_bit(){
        DAT_OUT     = 0;
        DLY_50US;
        CLK_OUT     = 0;
        DLY_50US;
    }

    static void tm_stop_bit(){
        DAT_OUT     = 0;
        DLY_10US;
        CLK_OUT     = 1;
        DLY_50US;
        DAT_OUT     = 1;
        DLY_50US;
        DLY_50US;
    }


としている。そして出来上がったTM-I2Cの波形をpulseviewで見ると、例えば次の様になった。ちなみにデコーダにはI2Cの物を使っているのでデコード結果は不正確だがデバッグには十分である。

(続く)

  〔注1〕この接続法はWikipediaを見るとWired-AND接続と書かれているが、初期の8ビットのコンピュータ時代、カードエッジコネクタを通して負論理バスで接続していた頃はWired-OR接続と呼んでいた。今回は信号は正論理だが動作はOR的なのでどちらの呼称が適切だろうか?これはIC-R6のCI-Vバスでも同じ事が言えるのだが。

2026年4月30日木曜日

LiDARを使った相対速度計(その1)

 以前米国を走っているトラック野郎USAの動画を見ていたら、自車の車速に加えて前車の車速を測る機械が付いていて、あれは便利そうだなと思った。またAquaを運転し赤信号で止まっている時、前車が発車した後自車が発車せずにいるとピッと警告で知らせてくれる。これも便利だ。

そこで同じ様な機能が作れないかと考えてみた。超音波センサーは車外に出すセンサー部の防水が面倒なので除外する。前車の速度を測るにはミリ波レーダが良さそうだが距離を安価に測れるものは秋月では売ってない。 一方PONO社のLiDARは最大50mまで計れるし安全基準はCLASS1となっているのでこれを使うのが良かろう。とりあえず前に使っていた10mまで計れるTSD10を使ってみる事にする。上手く行ったら50mまで計れるTSD50も試してみよう。なおTSD20は電圧仕様が異なるため今回は除外する。

TSD10は10mまで、TSD50は50mまで計れるから4桁の表示器が欲しい。秋月で色々物色した結果4桁の緑色の7セグLEDを使う事とした(当初は4桁2色の7セグLEDを使うことも考えたが全幅が3cmと思いのほか小さかったため諦めた)。ドライバーには TM1637というアノードコモン用のドライバーを使う事とする。TM1637は外付け部品無しで直接6桁までの7セグLEDを扱うことが出来る(このICがある事は超音波距離計を作っている時は気付かなかった。知ってたらもっとコンパクトに出来たかもしれない)。またTM1637はI2Cに似た仕様の2線インターフェイスで接続するのでPICの足を無駄に消費せず便利だ。

以上を踏まえて早速基板を設計・発注した。回路図上はPICに20ピンの16F18346を使うように書いているが実際はそれとほぼ同じ内容で14ピンの16F18326を使うつもりだ。J5は汎用入出力用としており特に役目は決めていない。

 

ケースの高さを抑えるため基板は2つにカットし、L型に仕上げて使うようにしている。

(続く)

2025年9月9日火曜日

2色 8×8 マトリクスLEDを使う(その7)

 これまで、買った15個のマトリクスLEDのうち5個を使って基板を作成しテストをしていたが、残り10個分の基板も発注し作成した。14個を連結して表示させてみたが特に問題なく動く。次の動画は10個連結した例である。

  

製作の過程で経験したのは、ハンダペースト+ヒートガンでSMD(表面実装部品)をハンダ付けする場合、ハンダ付け後急に冷やすと基板と部品の熱膨張率の違いによりハンダにクラックが生じて著しく信頼性が低下する事である。

せっかく効率的にハンダ付けが出来ても後で細かく補修する羽目になる。 これが老眼の目にはきつい。USB顕微鏡が欲しい所である。 あと、注射器タイプのペーストハンダを直接基板に付けたが斑になり均一な量を塗布できなかった(概ね多すぎた)。基板と同時にステンシル(ハンダマスク)も発注したほうが均一に塗布できハンダ付けは上手く行くだろう。但しその場合は基板作成の値段が跳ね上がる覚悟が必要だ。

最後に、定電流LEDドライバーのTB62706BFは意外と異常電圧に弱い。最近のIC、LSI類は設計が良いのか多少手荒く扱っても、一瞬逆電圧をかけても滅多に壊れないが、TB62706BFは簡単に壊れ数個をダメにした。具体的にはENA端子が絶縁破壊されGNDとの間の抵抗値が170Ω程度に下がり(正常なICは十数MΩある)動作が不安定になった。注意が必要である。

 秋月のアウトレットで安く入手した2色8X8マトリクスLED15個を使い終わったので、このシリーズは終わりとする。

(終わり) 

 ----------------(追記)------------------

その後、依頼によりデモ表示内容を一定時間ごとに切り替えるような機能を追加した。デモは6種類まで設定できる。またデモ中にUARTからテキスト入力があればそれを一定時間表示した後デモに戻る。このとき超音波測距のデータについては特別に処理を加え距離の範囲に応じて色を変えて表示するようにしている。 

 -------------(追記終り)--------------- 

2025年6月20日金曜日

2色 8×8 マトリクスLEDを使う(その6)

 LEDの明るさはTB62706BFに付ける外部抵抗(R-EXT)で決まるが、この抵抗は桁毎に固定抵抗をハンダ付けしているため容易に明るさを変更できない。 一方設置の自由度を増すため明るさは可変にしたい。

そこで(その4)で述べたようにイネーブル信号をパルス幅変調(PWM)して明るさを可変にする事とした。 当初は2ms毎のラスタースキャンを起動しているTMR2をトリガーにTMR1とCLCを組み合わせてPWMを作る事を考えたが、やってみるとどうも上手く行かない。理由は不明だがTMR1にクロック(Fosc)が供給されないのだ。そこでCCPを使う事とした。CCPは元々TMR2と組み合わせてPWMを作る事が出来るようになっている。

この回路の動作の中心はクロック(Fosc/4)でカウントUPされる8ビットのTMR2である。TMR2の値がPR2と同じになると、 次のクロックでTMR2は0にリセットされる。すなわちPR2+1の周期のカウンタとなる。またこの時R-S・FFがSETされPWMのパルスがスタートする。さらにこのタイミングで割り込みを発生させることが出来る。

CCPでは10ビットのCCPRと10ビットに拡張されたTMR2とが比較され(10ビットのTMR2がFoscで駆動されていると考えると分かり易い)、一致するとR-S・FFがリセットされPWMのパルスが終了する。この動作が成り立つためには 0< CCPR <(PR2*4)の関係が成立している必要がある。

最初からCCPを使えばよかったように思われるが、そうしなかったのには理由がある。TMR2による2ms毎の割込み処理の中では先ず1行分のデータを作成し、次にSPIインターフェイスでデータをLEDの各桁まで届け、最後にラッチさせることでその行データがLEDを光らせる。つまり割り込みから実際の表示(ラッチ)迄の処理である程度の時間を取られる。一方明るさを制御するPWM信号はラッチを起点としたいが、実際は割り込みがカウント開始の起点となり処理に時間を取られるので望む結果が得られない。そこで処理の順番を変更し、割込みと同時にラッチを行うことでPWMの起点と整合させる事とした。その後次の割込みに向けて行データを用意し各桁へ届けて割込み処理を終える。このデータのラッチ(表示)は次の割込みの頭で行う。

 この方法でPWMパルスのデユーティ比は概ねCCPR/(PR2*4)である。この式から分かるがPR2が小さい場合にはPWMの細かい制御は出来ない。具体的には行スキャンレートを2msとするためのPR2の値は7なので明るさは3~4%単位での制御となる。

なお、R-EXTの値はテスト段階では室内用に10KΩを使ったがPWMを実装した後は1KΩにした。これでけっこう明るくでき、直射日光下でなければ昼間の屋外でも見えるだろうし、R-EXTを小さくすればもっと明るく出来る。LED1個当たりの最大平均電流は25mAなのでR-EXTは約800Ωまで下げることが出来る(ピークを考えるともっと下げられる)。一方それが最大16個並列になるので、ソースドライバは400mAのドライブ能力が必要だがTD62783は最大500mAのドライブ能力がある(推奨条件とは異なる)ので通常の動作は大丈夫だろう。

 (続く)

2025年6月8日日曜日

2色 8×8 マトリクスLEDを使う(その5)

 出すのが遅れたが制御部は次のような簡単な回路である。J101が外部インターフェイス用のRS-232Cコネクタ、J102とJ104はドライバー部との接続コネクタである。配置の自由度を増すため2個設けている。2つのジャンパーはソフト的にチェックして立ち上げモードを変更できるようにするためのものであり、またこの端子をデバッグ用信号の出力にも使っている。その2で見せた割り込み中を表すトレース波形はここから取り出した。

このユニットを作って驚いたのは、PICが極めて低消費電力なのは言うに及ばず、J101にRS-232cのケーブル経由でPCが接続されていれば電源を切っても動き続ける事である。回路的には何処からも電源が供給されていなくても、UARTのRX 端子(U-RX)に加わるHの信号電圧だけで機能している事になる。つまり入力ポートからの漏れ電流だけで動いていることになる。さらに5桁のマトリクスLEDを接続した状態でもこの動作は継続される。このとき暗闇で見るとLEDが薄く点灯して動作している。これには感動した。

(続く) 

 

2025年6月6日金曜日

2色 8×8 マトリクスLEDを使う(その4)

 5桁のLEDマトリクスを裏側から見るとこうなる。制御部は一番左の二階部分。全体を見るとコネクタが多くの経費を食っているようだ。

 

 使っているCコンパイラのバグに悩まされて手間取ったが(Cコンパイラのバージョンが古いままだったため原因不明の異常動作に悩まされたが最新のバージョンに上げたら安定した)、その後表示内容をスクロールさせる機能を追加することが出来た(以下はデータ量を減らすため動作が分かる程度のショート動画にしている)。


 

スクロールの基本的な構造は、表・裏2つの画面バッファを持ち(それらを瞬時に切り替えることも可能)、2つのバッファを(縦または横に)ループ状に繋げて連続的にシフトする事でスクロールさせている。左・上スクロールを組み合わせて斜め上スクロールも出来て、見てると浮遊感があるが見続けていると酔った感じになって気分が悪くなった。

機能は一通り出そろったので、これrらをユーザインターフェイスにどう纏めるかが課題となった。あと、LEDの明るさを抵抗で決めているがソフト的に変更できるようにしたい。そのためには現在BLINKの機能に使っているイネーブル端子をパルス幅変調する必要がある。このときパルスの周期を表示と同期させないとエイリアシングが発生して周期的に明滅するので一工夫する必要がある。とりあえずTimer1とCLCを使えば何とかなるだろう。

現在、前作の超音波測距センサーと組み合わせて反射物までの距離を表示させている。

(続く)


 

 

 

2025年5月18日日曜日

2色 8×8 マトリクスLEDを使う(その2)

 ソフトを組むうえで改めて構成を考えてみた。色々数値を試算してみて、CPUクロック(Fosc)を4MHz(インストラクションサイクル(Fosc/4)は1MHz)、SPIクロックを500KHzとした(その後、場合によっては処理が間に合わない事が分かったのでCPUクロックを4倍の16MHzにした。以下のトレースはCPUクロックが4MHzの時点の写真である)。

LEDは8行(row)で構成されるが、各行を同じ明るさで表示するため、タイマーを使って行毎の表示時間を一定にする。タイマーの割込み間隔を2msにすると1秒間の表示回数は約62回(=1/(0.002*8))となる。行データは1桁に3バイトなのでLEDを5桁並べると15バイト、つまり120ビットである。これを500Kbpsで転送すると240μsかかり2msより充分短いのでソフトのオーバーヘッドを考慮しても問題ないだろう。次トレースは上が行ラッチのストローブ(2ms周期)、下がSPIクロックである。

これを拡大すると15個のSPIクロックの塊が見え1行15バイトのデータを(240μsではなく)800μsかかって転送していることが分かる。この処理を割り込み処理ルーチンの中で実行しているのでその間割込み禁止となっており、残り1200μsの中でアプリケーションを動かす事になる。
これをさらに拡大すると次の様に2μs周期(500KHz)のSPIクロックが見える。

ホストとの通信レートは9600bpsとするので最短でも1ms/バイト程度であり十分表示の合間に処理できるだろう。

ソフトもテストパターンを出せる所まで作った。


行表示タイマーの割込み間隔を色々設定できるようにしているが、2msより大きくするとチラつきが目立つようになる。さらに200ms程度に大きくするとスキャンの動作が見えてデバッグに役立った(配線の誤りを発見できた)。

その後CPUクロックを16MHzに上げた。その状態を表す次のトレースで上が2ms毎のラッチ信号、下がHで割込み処理中を表しており、割込み(表示)に500μsかかり、その他の処理に1.5msの余裕が出来たことがわかる。



 マトリクスに表示させる文字パターンはAscii文字を対象にし、著作権フリーのフォントデータを使い、そのほか任意のパターンを設定できるようにする予定である。

その前に誤っていたPCBのパターンを修正する必要がある(コネクタを裏面に取り付けた事でピン番号の偶奇が逆になっていた。今はソフト的にビットを入れ替える事で修正している)。

 (続く)

 

2025年5月5日月曜日

2色 8×8 マトリクスLEDを使う(その1)

 先日、秋月へ行ったら2色の8×8マトリクスLED15個入りのレールが300円で売っていたので思わず買ってしまった。


家に帰って改めて調べるとLITE-ONのLTP-12188Mというモデルで大きさは32mm×32mm、1個140円で売っているものが20円で買えたので1/7の値段だ。

内部は次のような結線で8×8×2色、アノード・コモンになっており足は24本ある。

さぁて、これをどう料理しようかと調べ始めた。

こういう場合は8行(ROW)を順にスキャンさせ、16列(COL)にデータを与える。出来ればドライバーを32mm×32mmに収め、水平方向にドッキングさせると横長に広がるようにしたいがどんな回路にしたら良いか。列に接続する電流制限のシリーズ抵抗だけで16本必要であり、8行(ROW)16列(COL)構成の駆動をするだけで8ビットのシフトレジスタが3個必要で、安易に作ると部品が基板からはみ出す。

ネットで色々調べると、74TC595AFという8ビットシフトレジスタ+ラッチと、TB62708BFという16ビットシフトレジスタ+ラッチ+定電流ドライバを使うと上手く行きそうな事が分かり、早速ドライブ部の設計を始めた。

これでロジック的には動きそうなのでPCB基板を考えた。
 
ちなみに、この回路のインターフェイスにはSPIを使い、3バイトで1行のデータを表示する。これを8回繰り返す事で8x8ドットを表示することが出来る。表示のリフレッシュレートを30回/秒とするとデータレートは最低5760bps(=3*8*30*8)必要となる。これを5個直列接続する場合は5倍の29Kbps必要である。実際にはソフトのオーバーヘッドを考慮してクロックを100Kbps以上にすれば良いだろう。1点注意が必要なのはTB62708BFのラッチが負論理のエッジトリガーなのに対し74TC595AFのラッチは正論理のエッジトリガーと逆になっている点である。間にインバータを1個入れれば問題ないが余計な部品を追加せずシンプルに済ませたい。そこで両者を同じトリガー信号で駆動する事とし、短いトリガーパルスを使うことで両者をほぼ同時にラッチさせる事とした。このトリガーパルスは負極性でも正極性でも問題なさそうであるが、実際には負極性だと上手く行かず消灯すべきLEDが暗く点灯する現象が発生した。
 

実装密度を上げ基板の面積を抑えるために表面実装部品(SMD)を積極的に使うようにした。PCBの設計で問題だったのはICチップのフットプリントである。ICの型番は分かって外形もSOP-16などと記述されているが実際の大きさが曖昧である。昔のDIPならソケットで規格化されていて簡単だがSOPには様々な大きさのパッケージがあり、どれを選べばよいか。幸い秋月では定規にあてたチップの写真を掲載してくれているので非常に助かった。あと、TB62708BFは足のピッチがインチ(1.27mm)ではなく1mmと変則的なので自分でフットプリントを作らざるを得なかった。

結局、出来上がった基板は32mm×32mmには収めきれなかった。

ここまで来て、改めて電流値を計算してみた。LEDの向きからTB62708BFを定電流シンクとして使う。1列の中で同時に光るLEDのは1個なのでドライブ能力は十分ある。一方74TC595AFを電流ソースとして使うことになるが1行最大16個のLEDを同時に駆動する必要がある。TTLの場合は電流ソースとしてのドライブ能力はとても低かったが今回のC-MOSでは改善され25mAある。しかし行ドライバーとして16個のLEDを同時駆動するには数百mAの電流が必要であり、全く足りない。この基板は未発注のままお蔵入りとなった。

やはり別途電流ドライバーが必要である。ここにNPNトランジスタのエミッタフォロワーが使えないか等と調べていたらTD62783という8チャネル500mAのソースドライバーを売っていたのでこれを使う事にし、次の回路を作った。

この回路は上の大きさの基板に収まりそうもないし、これ以上面積を大きくすると例え完成したとしても見栄えが悪すぎる。

 そこで基板を2枚に分けて直交させ、前面からはLEDのみが見え、不足する面積は奥行で解決する事とした。2枚の基板間はコネクタ接続としている。さらにPIC(16F18326)による制御部を追加して3枚の基板に仕上げた。

基板にVカットを入れた1枚の基板として発注したかったが規定以下のサイズと形状のため不可であり、そこでエッジカットを入れて1枚の基板として誤魔化して発注してみたが3枚とカウントされ追加料を支払うはめに・・・まあ、安いから良いけど。

 基板が届いて組み立てた。

背面の2段重ねの基板のうち上がPICを使った制御部で、下がLEDのドライバー部だ。制御部を外すとドライバー部はこうなる。

ドライバー部は横に連結して広げる事ができるようになってている。制御部1つで複数のドライバー部を制御する。何個連結できるかは主に電源容量とPICのドライブ能力に依存するが少ない数ではないだろう。

TB62708BFのR-EXT端子に接続する抵抗Rの値でLEDに流す電流を設定することが出来る。

とりあえずテストのために10KΩを入れた。 試しに330Ωを入れてみたが物凄く明るく直視できない。これでも発光時間は1/8だから平均電流に直したらLED1個当たり7mA程度の筈である。色々な場所で使えるようにするためにはENABLE端子をPWM信号で駆動して明るさを可変にするのが良いのかもしれない。

(続く)

 

 

2025年2月27日木曜日

出入り検知器をPCB化する(その23)・超音波測距3

 インテグレーションを目指して実際に超音波測距センサーを使ってみると、特に室内では反射物が多く場所を少し変えるごとに状況が変わり閾値の設定がものすごく面倒で、容易に置き場所や周囲の状況を変更できない。そこで新たにトレーニング・モードを設けた。立ち上げ時に周囲を何回かスキャンし、各方向のセンサー毎にエコーの最近値からマージン(とりあえず5cm)を引いて閾値(最大探知距離)として自動的に設定する。

*** Start Training.
*** Trained Max Range R:178 F:98 L:50
  US Sensing parameters:
        Mode = Range Data with Zero Suppress.
        Ch-R: ON : 010 - 173
        Ch-F: ON : 010 - 093
        Ch-L: ON : 010 - 045

この効果は絶大で、何処でも簡単に設置でき、トレーニングが終われば人などが前を通過したときちゃんと反応する。 

_10,0,0
_10,20,0
_0,20,0
_0,20,0
_0,23,0
_0,0,21
_0,0,23
_0,0,0
 

エコーが無くなった事を表すため最後には 0,0,0 を出力させている。

さらに状況が変化した時はいつでも再度トレーニングを実行できるようボタンを追加した。

これでいつでも再トレーニングできるようになり、室内でも使い勝手が随分良くなった。

超音波センサーモジュール込みの消費電流を測ってみたが、電源電圧5Vで約7mA、3.3Vで5mAであった。

 (続く)

 

2025年1月13日月曜日

出入り検知器をPCB化する(その21)・超音波測距2

 年末年始で手を付けていなかった超音波測距だが、ソフトを作って実際に動かしてみた。PICは14ピンのPIC16F18326を使った。


Timer1に入力するクロック(LFINTOSC=31KHz)をプリスケーラで2分周する事で、計測値1カウント当たり1.1cmの測距距離とした。これで1カウント当たりほぼ1cmと考える事ができる。音波の反射や回り込みによる相互干渉を避けるため Right, Front, Left の3つのセンサーを(同時でなく)100ms毎に順番に起動し測距する。これを連続で行うと3回/秒程度の頻度の測定になる。次図で上のトレースは右(R)のセンサーのトリガーであり、100msずつ遅れて起動する他のセンサーのトリガーは見えていない。下のトレースはTimer1のゲート信号で、順に3つのセンサー(R,F,L)のエコーに対応している。
各エコーのパルス幅が測距距離に対応しており、毛布で覆ってエコーが無いと思われる場合は次のような波形になった。

中央の幅広のパルスを生成しているセンサーがUS-015であり、それ以外はHC-SR04である。それぞれUS-015で75ms、HC-SR04で50ms程度あり最大探知距離相当時間の2倍以上は確保されている。

 測定結果はシリアルインターフェイスを通じてホストへ送信する。

測定したデータの処理には次の3つのモードを設けた。

  1. 生データ表示モード
  2. 測定結果表示モード
  3. 最接近表示モード

1.生データ表示モードはデバッグ用で、測定した3方向の生データを16進表示する。

#0049:0021:001e
#0049:0022:001f
#0049:0022:001f
#0049:0021:001e
#004a:0023:001e

2.測定結果表示モードでは測定した3方向のデータを10進表示するが、この時測定したい距離の閾値(最大距離、最小距離)を適用し、その範囲外のデータは0とする。これは近くにある固定された反射物を避けるとともに、とくに最大探知距離より大きな値(無エコー、誤データ)を排除する為である。

> R:144 F:63 L:32
> R:144 F:63 L:31
> R:73 F:33 L:31
> R:73 F:34 L:32
> R:73 F:32 L:31
> R:144 F:64 L:32
> R:144 F:63 L:31

3.最接近表示モードでは、3方向のうち最も距離の近い対象までの向きとデータ(≒距離)を表示する。3方向とも範囲内に対象物が検知されなかった場合は何も表示しない。

=L23
=L30
=F51
=F53
=F48
=F52
=R71
=R71

基板上の3つのLEDは夫々のセンサーが対象範囲(閾値)内にエコーを捉えていると点灯する。 

3つのセンサーのデータをAI(機械学習)で学習すれば前を通る人の動きを認識出来るかも知れないが、今回はそこまでやらない。

このセンサーユニットを、これまで作った回路と組み合わせることで纏まった動作をさせるよう今後インテグレーションしたい。


(続く)

 

 

2024年12月25日水曜日

出入り検知器をPCB化する(その21)・超音波測距1

 出入り検知器は元々20cm離れた2本の赤外線を人が横切る事を検知するよう考えていた。これは狭いゲートを通過する人を検知するような使い方を前提としていた。一方、目前の歩道を通り過ぎるような人の動きを検知して働くような機能の方がより汎用的に使えるだろうと、そのようなセンシングを考える事とした。

このような動きを捉えるには画像認識以外には次のような幾つかの方法が考えられる。それぞれ対象物との絶対的な距離を測れるものと、距離の変化を捉えるものがある。

  1. 焦電センサー
  2. 赤外測距センサー
  3. 超音波測距センサー
  4. ミリ波センサー 

これらのうち秋月で入手が容易な(比較的安価な)センサーについて特性を調べた。1.焦電センサーは人体から放射される赤外線を捉え、その量の変化が閾値を超えた場合に反応するが屋外では太陽光やその反射光、風が吹いても反応する事があり屋外での特に昼間の利用には不向きである。2.は自ら赤外線を発射し、その反射光を受信するまでの時間から対象物迄の距離を測定する。その例として秋月で売っているVL53L0X使用 レーザー測距モジュールを買ってみた。これは Arduino ではライブラリが使えるようだがモジュール自体の仕様は公開されておらずPICからは容易に使えないので今回は扱わない。3.は超音波を使って2と同様な事を行う。4.はミリ波を使って同様な事を行う。最近は車の人感センサーに応用され比較的入手が容易である。ただ電波法で規制されるため認証されたものを使う必要がある。秋月で売っている手頃なものはドップラー効果を応用しているのか人が近づいたり離れたりする動きのみ取り出せるので焦電センサーと変わりない。


取り合えず安価で最も使い易そうな超音波センサーを使ってみる事とした。秋月では手頃な値段のUS-015とHC-SR04という見かけの似た2つの超音波センサーモジュールを販売している。

値段もあまり違わない。インターフェイスも同じGPIOで4ピンの信号割り当ても同じ。但し(マニュアルは中国語で分かり辛いが)HC-SR04はジャンパーを切り替える事でGPIO(PWM)のほかI2CまたはUARTインターフェイスを選ぶ事が出来るようである。汎用性を考え、とりあえずGPIOインターフェイスで使ってみる事にした。次図はGPIOのタイミングチャートである。


GPIOでは Trig端子に10μsのパルスを加えることで測距がスタートする。先ず40KHzの超音波パルスが8回発射され、それが対象物で反射されて帰ってきたエコーを受けてEcho端子に往復時間に対応する時間幅のパルスが出力される。もしエコーが検知されなかった場合は80msのパルスが出力されるとUS-015のマニュアルにあるが、HC-SR04にはそれに相当する記述はない(実際に測定したところでは50ms強であった)。Trig端子に与えるパルスの繰り返し周期は仕様上はUS-015で85ms程度、HC-SR04では200ms以上必要である。

音速を340m/sとし、最大測距距離4mとして試算すると往復時間(Echo端子への出力パルス幅)は23.5msである。厳密には大気中の音速の温度勾配が0.6m/s/T程度あるようであるが、今回の目的には補正は必要ないだろう。もし補正したいならPICに内蔵の温度センサーを使うと簡易な補正はできる。

測定にPIC16F18326を使う場合、カウンタをゲート制御できるTimer1を使うのが適当である。Echo端子の信号をカウンタのゲートに加える。カウンタに加えるクロックにLFINTOSC(31KHz)を使うと距離を(理論的には)約1.1cm単位で測定する事が出来る(往復だと0.55cm)。また無エコー時の80msパルスのカウント値は24,80カウントでありTimer1の16ビットの範囲に収まる。

・・・てな事を考えながら回路を考え基板を発注した(この回路では将来の拡張を考えてPIC16F18346を使っている)。


この基板では3方向の超音波センサーを使う事を想定している。センサーの指向性は±15度なので各センサーは角度の30度離して取り付けるのが良いと思われるが3つ併せても探知範囲は90度しかない。広い範囲を見るためにあと2個追加して探知範囲を150度としたいものである。

(続く)

 

2024年11月21日木曜日

PIC16F18xxxのA5ポートが使えなかった件に関する情報

 PIC16F18313、PIC16F18326、PIC16F18346 など PIC16F18xxx シリーズのPICを使ってみたが A5 ポートが入力にも出力にも全く使えなかった。色々調べてみたが全く原因が分からない。チップの系統的な欠陥か、まがい物を掴まされたかとも考えたが秋月でまがい物を売っているとも思えない。

この事から、これまでA5端子(ポート)は使えないという前提で、使わないよう設計してきた。

これは何かおかしいと最近再度調べたら、マイクロチップ社のホームページのフォーラムの中に同様の投稿を探り当て、答えが分かった。

https://forum.microchip.com/s/topic/a5CV400000015P3MAI/t395592

原因はPICのコンフィグレーション情報のFEXTOSCがOFFになっていなかったのだ。

次の記述を見て、内部発信器を使うのでFEXTOSCは関係しないと無視してきたが、
 
FEXTOSCがOFFでないとA5ポートはクロック発信器関係の端子として強制的に割り当てられ通常の入出力には使えないようだ。ただ、この情報はPICのマニュアルを探しても明確な記述が見つからず、幾つかの記述から類推するしかない。

A5端子が使えない事で何度かTRY&FAIL⇒設計変更したが、答えがこんな事だったとは・・・。

 

2024年10月15日火曜日

出入り検知器をPCB化する(その12)

 これまで作った歴代作品を並べてみた。残念ながら汎用基板を2段重ねした第1.5世代は部品を使い回ししたため残っていない。

当初は人の動きを捉えて喋るだけで良かったものが、それに加えてリアルタイムクロック(RTC)や気圧センサーを加え気圧変化を喋り、さらにメロディを奏でるまでになった。C言語で書いたプログラムもメロディ生成に2千行、本体は1万行程度になった。そして開発は今後も続く。本バージョンの締めとして若干の修正を加えた第4.2版を赤色のレジストで発注した。

これで終わりかと思ったが、更なるリクエストがあり、 開発は続く。

(続く)


 



 


2024年7月31日水曜日

出入り検知器をPCB化する(その11)

メロディ生成をPIC16F18326に変えたので、それに合わせて第4版のPCBを発注した。版を追うごとに基板の密度が上がっている。秋月で買える安い部品だけで作っているのでICのパッケージも様々である。これまでと同じ大きさの基板に収めるのはボチボチ限界かな。

1週間ほどで基板が出来上がってきたので早速秋月に走り部品を調達して組み立てた。

ソフトに幾つかの修正を加えてメロディIC(PIC16F18326)を接続できた。

RS-Kager2 Ver0.23 for RH-Kager2 Rev 0.40 2024/07/30-1
 StateMachine: 3.1 SpeakMessage: 0.4
 Copyright(C)2023,2024 by MYcrosLip. (DEBUG MODE)
... Checking Melody Player - Tone326-197:103
--- Melody Player is ready.

... Checking Voice Synthesizer -VF1a
--- Voice Synthesizer is ready.
--- I2C_INIT: I2C Bus is Ready.
--- Extend EEPROM OK.
... EEPROM-ID = RS-Kager2 Ver0.23 2024/07/30-1
... RTC RAW10: 02 80 08 22 23 09 31 03  07 24
--- RTC is active.
--- RTC: 24/07/31(WED) 09:23:22
--- Barom is active.
!!! Barom: FIFO is not full; Wait a dozen seconds.
--- Air Pressure: 996.0 hPa (Offset 9.2 hPa).
--- Power Supply : 5.09 V
--- Environment : OFFICE mode.
--- Speak air pressure 1 time(s) in an hour.
--- Speak the time before speak the pressure is ON
--- Speak random at S3 is : ON
--- Speak Battery Low is ON.
--- Current LED Brightness is 30 %
--- Start Interrupt Handling.
 

メロディが時々ハングアップしたが、これは暫定的に作っていたインターフェイスの中の待ち行列(QUE)がCでお決まりのNULLポインタを起こしていた。複数の曲をキューイングして演奏する状況は考えられないのでQUEの使用は止め、逆に曲の途中で別の曲を強制的に割り込ませる機能を追加した。これにはメロディICとPIC18F27Q43の間の連携が必要であるが、メロディICに予め演奏の強制停止コマンドを組み込んでおいたおかげですんなりと実現できた。

(その後)

第4版のPCBに若干の修正を加えて第4.1版を作った。変更点はPICのバグ回避のための変更1件と利用上の都合に伴う2件である。

 出来ればこれを最終版にし、あとはソフトに任せたい。

 (続く)

 

2024年7月18日木曜日

出入り検知器をPCB化する(その10)メロディ生成4

 次はテンポの処理である。

単音の場合は適当に遅延を挟むことでメロディを演奏することが出来たが和音の場合は各音符の長さが同一ではないため単純な遅延では処理できない。 そこで32分音符の長さを基準とした割り込みとソフトのカウンタで処理する事とした。

実際にはスタッカートやテヌートも処理したいので音符の長さを12分割した間隔で割り込みをかけ発音を制御する。最高のレートだとBPM=200の場合は約3ms毎に割り込む事になる。

割込みにはTimer6(TMR2)を使った。250KHzのクロックをプリスケーラで16分周するとポストスケーラを使わなくても丁度良い具合になる。 BPM=40で244分周、BPM=200で49分周と、8ビットの分周器に丁度収まるスケールだ。

ここまで出来たら、あとは譜面の記法を決めればよい。TeraTermで操作できるよう譜面は全て文字で表記するようにした。前に書いたように音の高さはMIDIの音階と同じコードを使うがメモリーを節約するため16進数で表記する。音の長さは次の様にした。

音符は音の高さ2文字と長さ1文字の3文字で表す(休符は音階=0とする)。更にチャネル指定を「:c:」で、BPMを「%hh」、音階のオフセットを「$±h」で表す。1音を3文字で表すよう数値は16進標記とした。3文字の間にはスペースや幾つかの区切り記号を挿入することが出来る。

譜面は改行で終わる1行の文字列である。譜面を最後まで読み込んだら内部でチャネル(音源)ごとの楽譜に変換し、32分音符の1/12の時間間隔の割込みに従って同時進行で演奏(音をON/OFF)する。

次のような4和音の譜面を1オクターブ上げてBPM=100で演奏してみた(この譜面はプログラム中にデータとして記述して分かり易いよう改行を入れている部分であるが、実際は「"」や改行を外し1行にする必要がある)。

       "%64$+c"
    ":1:43E 41E 46E 48G 4dG 4aE_48G 4dG 4aE 46E 48E 43E 413"
    ":3:3EE 3cE 3eE 45E     45E_45E     46E 43E 43E 3cE 3c3"
    ":2:3aE 39E 3aE 3cE     41E_3cE     41E 3eE 40E 37E 393"
    ":4:37E 35E 37E 35E     32E_35E     3aE 37E 30E 34E 353"


 これを解釈し内部で使う音源ごとの楽譜に変換したものは次のようなものである(各音源の最初の16バイトの16進ダンプ)。

  --1-- 54 43 54 41 54 46 74 48  74 4d 54 4a 74 48 74 4d
  --2-- 54 3a 54 39 54 3a 54 3c  54 41 54 3c 54 41 54 3e
  --3-- 54 3e 54 3c 54 3e 54 45  54 45 54 45 54 46 54 43
  --4-- 54 37 54 35 54 37 54 35  54 32 54 35 54 3a 54 37

これを演奏するとこのような音になる。

(その後)

3連符を表現したくて割込み頻度を3倍にして、32分音符の間に3×12回割り込むようにした。これで音符の長さを表すパラメータが3倍となり3で割り切れるようになる。表記も改訂した。

この機能を使って3連符のあるこんな演奏ができる。我ながら上出来である。 

(さらにその後)

音源3,4はパルス幅変調ができるので、試してみた。パルス幅を50%、25%、12.5%、…と半分ずつにしていくと、50%~6.25%までは音質が変わり、それを超えると音量が低下する。これは主旋律を目立たせる技として使えそうである。

(さらにその後)

オシロスコープを使って割り込み処理にどの程度時間を取られているか観測してみたところ約2msかかっていた。一方200BPMの時32分音符に費やされる時間は約37ms。実際にはそれを12分割して管理していたが、さらに3連符処理のためその1/3倍としている。つまり割込み処理を1ms以下で終える必要がある。一方実際には処理にその倍の時間がかかっており100BPM以上の演奏には追従できない事が分かる。 これを解決するためCPUクロック(Fosc)を4倍に引き上げて4MHzとした。これで1回の割込み処理が500μs程度で終わり時間に余裕が生まれた(実際には36回(或いはその倍数)に1回起こる音符の切り替え処理時にもっと多くの時間がかかるが聞いていても分からない)。またクロックの変更に伴って影響を受けるUARTの通信速度や音の高さに関係するパラメータを変更した。幸いにも音符の高さを表すパラメータはクロックを細工する事で再計算せずに当初の音域をカバーする事が出来た。詳しくは後述する。

(つづく)