STM32 赤外線受信プログラム

2025年2月14日金曜日

【STM32】 LL プログラム

t f B! P L

 赤外線の受信・解析

STM32でテレビリモコンなどの赤外線信号を受信し、デコードするプログラムです。
本プログラムはNECフォーマットのみを対象としています。

使用部品

マイコン:STM32G031F6P6
赤外線受信モジュール:GP1UXC41QS
    データシートにあるCRフィルターは使用しています。
ロジックアナライザ:SparkFun USB Logic Analyzer (24MHz/8ch)

ロジックアナライザは信号のhexデータの読み取り、信号の周期を測るのに利用しました。
hexデータはArduino&ライブラリ。周期はオシロスコープで測れば良いので必須ではないです。

赤外線信号の解析

ロジックアナライザで計測したデータが次の画像です。

アドレスコード

信号の種別を伝えるLeaderCodeの後にはリモコンのアドレスが続きます。
基本はAddress8ビット+反転8ビット。となりますが、このリモコンは反転していない事から16ビットアドレスと思われます。

データコード

リモコンのどのボタンが押されたかを伝える部分です。
こちらはどのリモコンにおいてもデータ8ビット+反転8ビットになります。
実際にデータを受信した後のエラーチェック用のようです。

リピートコード

長押しされているときに送信される信号です。
ただし上記のリモコンではリピートコードは送信されませんでした。
ですので別のリモコンでリピートコードが送信されたときの様子を載せます。

AGC pulseの後に注目してください。
先ほどのデータ信号では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回分送信されてしまうチャタリングのような現象がまれに発生しました。
特に割り込みを使うプログラムでも確実にデータを取得する為に一定時間の割り込み禁止時間を設けています。

リピート有りリピート無し
送信間隔40ms42ms
送信時間12ms
(リピート)
63ms
(データ)

送信間隔はデータ信号の末尾から次のデータ(リピート)先頭までの時間
送信時間はデータorリピート信号全体の時間です。

上記の表から次のように無効時間を決めました。

・リピート有りリモコンの無効時間
リピート信号同士の送信間隔が96msとなっているので、これより長い時間無効にすると正規のリピート信号すらも取りこぼすことになります。

よって(40+12)msより長く、96ms未満の無効時間として62ms無効にします。

・リピート無しリモコンの無効時間
送信間隔の42msと送信時間63msの合計である105msより長くする必要があります。
また105ms+42ms経つと次の正規データを取りこぼします。

よって105msより長く、147ms未満の110ms無効にします。

コード

ポーリング関数


IR_REPEAT_VALIDは前述した無効時間の設定用です。
赤外線モジュールからの出力が変化するまでRecieveIR()内で待機します。
赤外線信号はMSBで解釈します。
最初に載せたロジックアナライザでの測定結果を見てください。
アドレスコード0x80は0b1000 0000ですが実際のビット列は0b0000 0001となっています。

これをそのまま解釈すると当然0x01になりますので、受信の段階からビット順を並び変えています。

先ほどのビット列0b0000 0001であればまずビット7~ビット1まではnumBits++のみが行われます。
最後のビット0のとき、Binaryには1 << numBitsが実行されます。
この時numBitsは7となっているので、1 << 7、つまり0x80が代入されます。

このようにしてMSB形式でデータを受け取ります。
Binaryは32ビット変数で、これをBinarytoHex()に渡して構造体LSBに8ビットずつに分割して格納します。
名前がLSBってよくない気がしてきた

ここではI2CのキャラクタLCDに上下2行で受信結果を示すようにしています。

割り込み関数


割り込み関数を用いる方ではLeaderCodeの判定を行った後、単純にタイマーのカウント値のみを取得します。
main.cで用意した配列Pulseにカウント値を入れ、DecodeIR()でビット列に変換。
さらにBinarytoHex()で構造体にパッキングします。


割り込み関数の処理はシンプルであるべきだと思うですが、その点で見るとあまり良い関数ではないかもしれません。
LeaderCodeの判定部分から配列に入れるだけの処理とすればさらにシンプルになるかもしれません。
ただしその場合はリピートコードの処理を改めて考える必要もあります。

まとめ

赤外線受信モジュールの種類について

当初使用していた赤外線受信モジュールはOSRB38C9AAというものでした。
ですがこのモジュールを使用していると、信号が無い状態でもノイズのようなパルスが発生していました。

ロジックアナライザでのパルス計測結果です。
1分間放置していた状態で4回ほど謎のパルスが発生しています。

一方でGP1UXC41QSの方ではさらに長い時間計測してもパルスは発生しませんでした。

赤外線受信モジュールにはノイズ耐性としてシールド付きのものがあるようですが、その効果はかなり大きいものかと思います。

周辺環境について

赤外線は太陽光にも含まれています。
受信モジュールによってはこの影響をかなり強く受けます。
先ほどの比較対象としてあげたOSRB38C9AAをあえて日光に当てた結果次のようになりました。


このように強烈な影響を受けていることがわかります。
なおGP1UXC41QSで同様にテストをしたのですが、こちらはまったく影響を受けていませんでした。完璧すぎて逆に疑わしい

なおどちらも同じ値段です。
しかもGP1UXC41QSはシャープ製ですのでデータシートも日本語です。絶対こっち買ってください。

リンク

赤外線受信のプログラムは以前にも作成したものでしたが、改めて書き直すことで割り込みやタイマー関連の勉強になりました。
以前に作成したもの、今回紹介したものを合わせてGitHubに掲載しているので、気になった方は見てみてください。


Translate

検索

QooQ