赤外線の受信・解析
STM32でテレビリモコンなどの赤外線信号を受信し、デコードするプログラムです。
本プログラムはNECフォーマットのみを対象としています。
使用部品
マイコン:STM32G031F6P6
赤外線受信モジュール:GP1UXC41QS
商品ページ:秋月電子 赤外線モジュール
データシートにあるCRフィルターは使用しています。
ロジックアナライザ:SparkFun USB Logic Analyzer (24MHz/8ch)
商品ページ:千石電商 ロジックアナライザ
ロジックアナライザは信号のhexデータの読み取り、信号の周期を測るのに利用しました。
hexデータはArduino&ライブラリ。周期はオシロスコープで測れば良いので必須ではないです。
赤外線信号の解析
ロジックアナライザで計測したデータが次の画像です。
アドレスコード
信号の種別を伝えるLeaderCodeの後にはリモコンのアドレスが続きます。
基本はAddress8ビット+反転8ビット。となりますが、このリモコンは反転していない事から16ビットアドレスと思われます。
データコード
リモコンのどのボタンが押されたかを伝える部分です。
こちらはどのリモコンにおいてもデータ8ビット+反転8ビットになります。
実際にデータを受信した後のエラーチェック用のようです。
リピートコード
長押しされているときに送信される信号です。
ただし上記のリモコンではリピートコードは送信されませんでした。
ですので別のリモコンでリピートコードが送信されたときの様子を載せます。
先ほどのデータ信号ではL-pulseとなっていましたが、こちらではShort pulseです。
AGC pulseは常に一定ですが、その後のHigh期間の長さで両者を区別できます。
データ信号のLong pulseは約4.5ms。リピートのShort pulseは約2.2msとなっています。
プログラムの概要
今回のプログラムは以下のような仕様となっています。
時間計測として汎用タイマ(TIM14)を使用
PLLクロックを64MHzとし、640で分周して10usでカウント。リロード値は62または110。
後述しますが、チャタリングのような動きが見られたので信号受信後に一定時間次の信号を無視するようにしています。
10usカウントとしたのはこの一定時間を確保する為です。
本来は1usカウントとしたいのですが、TIM14のリロードレジスタ(ARR)は16ビットであり、1usの場合最大で約65msしかカウントできない為、10usカウントになっています。
32ビットタイマ(G0xシリーズではTIM2が該当)を使用する場合は1usカウントでリロード値を10倍することでより直感的になるかと思います。
割り込みとポーリング
まずはシンプルで作りやすいポーリングのプログラムから作成し、その後割り込みを用いる形のものを作りました。
ですのでどちらも使えるようにしています。
信号受信後の処理
前述した通り、1回だけ押したつもりが2回分送信されてしまうチャタリングのような現象がまれに発生しました。
特に割り込みを使うプログラムでも確実にデータを取得する為に一定時間の割り込み禁止時間を設けています。
・リピート有りリモコンの無効時間
リピート信号同士の送信間隔が96msとなっているので、これより長い時間無効にすると正規のリピート信号すらも取りこぼすことになります。
よって(40+12)msより長く、96ms未満の無効時間として62ms無効にします。
・リピート無しリモコンの無効時間
送信間隔の42msと送信時間63msの合計である105msより長くする必要があります。
また105ms+42ms経つと次の正規データを取りこぼします。
よって105msより長く、147ms未満の110ms無効にします。
コード
ポーリング関数
赤外線モジュールからの出力が変化するまでRecieveIR()内で待機します。
赤外線信号はMSBで解釈します。
最初に載せたロジックアナライザでの測定結果を見てください。
アドレスコード0x80は0b1000 0000ですが実際のビット列は0b0000 0001となっています。
これをそのまま解釈すると当然0x01になりますので、受信の段階からビット順を並び変えています。
最後のビット0のとき、Binaryには1 << numBitsが実行されます。
この時numBitsは7となっているので、1 << 7、つまり0x80が代入されます。
このようにしてMSB形式でデータを受け取ります。
Binaryは32ビット変数で、これをBinarytoHex()に渡して構造体LSBに8ビットずつに分割して格納します。
ここではI2CのキャラクタLCDに上下2行で受信結果を示すようにしています。
割り込み関数
main.cで用意した配列Pulseにカウント値を入れ、DecodeIR()でビット列に変換。
さらにBinarytoHex()で構造体にパッキングします。
LeaderCodeの判定部分から配列に入れるだけの処理とすればさらにシンプルになるかもしれません。
ただしその場合はリピートコードの処理を改めて考える必要もあります。
ただしその場合はリピートコードの処理を改めて考える必要もあります。
まとめ
赤外線受信モジュールの種類について
当初使用していた赤外線受信モジュールはOSRB38C9AAというものでした。
ですがこのモジュールを使用していると、信号が無い状態でもノイズのようなパルスが発生していました。
1分間放置していた状態で4回ほど謎のパルスが発生しています。
一方でGP1UXC41QSの方ではさらに長い時間計測してもパルスは発生しませんでした。
周辺環境について
赤外線は太陽光にも含まれています。
受信モジュールによってはこの影響をかなり強く受けます。
先ほどの比較対象としてあげたOSRB38C9AAをあえて日光に当てた結果次のようになりました。
なおGP1UXC41QSで同様にテストをしたのですが、こちらはまったく影響を受けていませんでした。完璧すぎて逆に疑わしい
なおどちらも同じ値段です。
しかもGP1UXC41QSはシャープ製ですのでデータシートも日本語です。絶対こっち買ってください。
リンク
赤外線受信のプログラムは以前にも作成したものでしたが、改めて書き直すことで割り込みやタイマー関連の勉強になりました。
以前に作成したもの、今回紹介したものを合わせてGitHubに掲載しているので、気になった方は見てみてください。
0 件のコメント:
コメントを投稿