705 views
この記事は最終更新から 573日 が経過しています。
ブログ記事はまた後日書こう。
まずは Pico2に載せて動作確認出来たプログラムを置いておく。
【1】やりたいこと
家電製品を制御するための赤外線リモコンが発信する信号のパターンをモニタリングしたい。
ただし…
ブラックボックスな便利ライブラリを使うのではなく、生の信号データをそのまま見たい。
以下、3回のブログ投稿で完成を目指す。
(56)【連載2-1】リモコン作り:赤外線リモコンの信号パターンをキャプチャする。
(57)【連載2-2】リモコン作り:赤外線LEDで信号パターンを再生する。
(58)【連載2-3】リモコン作り:キャプチャ機能付きリモコンの完成!? ←今回
【2】回路の結線
後日追記


【3】使い方(操作仕様)
・赤ボタンを押下すると、記録を開始する。
基板上のLEDが点灯している2秒間だけ信号をキャプチャし、そのデータをファイル保存する。
・白ボタンを押下すると、赤外線信号を発信する。
先に記録したファイルをロードし、その情報に従って赤外線LEDを点灯制御する。
【4】プログラミング
main.py
from machine import Pin, PWM
import time
import os
#///////////////////////////////////////////////////////////////////////////////
# GPIO設定
btn_rec = Pin(17, Pin.IN, Pin.PULL_UP) # 記録ボタン
btn_tx = Pin(14, Pin.IN, Pin.PULL_UP) # 再生ボタン
rec_led = Pin(25, Pin.OUT) # 記録実行中表示LED
ir_pin = Pin(16, Pin.IN) # 赤外線受光モジュールの信号入力用ピン
ir_led = Pin(15, Pin.OUT) # 赤外線発光LEDの出力用ピン
pwm = PWM(ir_led) # PWMインスタンス作成
#///////////////////////////////////////////////////////////////////////////////
# 定数、変数定義
RECORDING_DURATION = 2 # 記録時間 [sec]
rec_signal_flag = False # 記録開始ボタン押下フラグ
play_signal_flag = False # 再生開始ボタン押下フラグ
last_press_time = 0 # 最後にボタンが押された時刻
DEBOUNCE_DELAY = 500 # チャタリング対策、デバウンス時間(ms)
# 赤外線受光信号の記録処理に使う変数
recorded_pattern = [] # 赤外線信号のパターンの保存用リスト
rec_last_time = 0 # 前回の信号変化検出時間
is_first_pulse = True # 初回のエッジを無視するフラグ
#///////////////////////////////////////////////////////////////////////////////
# 受信処理
#///////////////////////////////////////////////////////////////////////////////
#///////////////////////////////////////////////////////////////////////////////
# 赤外線受光信号エッジ検出割り込みハンドラ
def evh_record_pulse(pin):
global recorded_pattern
global rec_last_time
global is_first_pulse
#---------------------------------------------------------------------------
now = time.ticks_us() # 現在時刻を取得 [us]
#---------------------------------------------------------------------------
if is_first_pulse: # 初回の信号? → skip
is_first_pulse = False # 初回フラグをクリア
#---------------------------------------------------------------------------
else:
# パルス長を記録
pulse_length = time.ticks_diff(now, rec_last_time)
recorded_pattern.append(pulse_length)
#---------------------------------------------------------------------------
rec_last_time = now # 信号変化の検出時刻を更新
#///////////////////////////////////////////////////////////////////////////////
# 赤外線受光信号記録の開始処理
def record_ir_signal():
global recorded_pattern
global rec_last_time
global is_first_pulse
#---------------------------------------------------------------------------
print('now recording IR signal...')
recorded_pattern = [] # 信号パターン記録用リストを初期化
is_first_pulse = True # 初回フラグをセット
#---------------------------------------------------------------------------
rec_led.high() # 記録中LEDを点灯
ir_pin.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=evh_record_pulse) # 割り込み許可設定
time.sleep(RECORDING_DURATION) # 指定された期間だけ、信号を受信する。
ir_pin.irq(handler=None) # 割り込み解除
rec_led.low() # 記録中LEDを消灯
#---------------------------------------------------------------------------
print('Recording completed : ', recorded_pattern)
return recorded_pattern # 記録した信号パターンを返す。
#///////////////////////////////////////////////////////////////////////////////
# 記録ボタン押下時の割り込みハンドラ
def evh_btn_rec_pressed_handler(pin):
global rec_signal_flag, last_press_time
#---------------------------------------------------------------------------
current_time = time.ticks_ms() # 現在時刻を取得 [ms]
#---------------------------------------------------------------------------
# チャタリング対策のデバウンス処理: 最後の押下検出から指定時間が経過している場合のみ処理する。
if time.ticks_diff(current_time, last_press_time) > DEBOUNCE_DELAY:
print('Start recording')
rec_signal_flag = True # 記録開始ボタン押下フラグをセット → 記録開始
last_press_time = current_time # 最後の押下検出時刻を更新
################################################################################
# 再生処理
################################################################################
#///////////////////////////////////////////////////////////////////////////////
# PWM設定
def setup_pwm(frequency=38000, duty_cycle=33):
pwm.freq(frequency) # 38kHzに設定
pwm.duty_u16(int(65535 * duty_cycle / 100)) # Duty ratioを 33%に設定
#///////////////////////////////////////////////////////////////////////////////
# PWM ON
def enable_pwm():
pwm.init()
#///////////////////////////////////////////////////////////////////////////////
# PWM OFF
def disable_pwm():
pwm.deinit()
#///////////////////////////////////////////////////////////////////////////////
# IR点灯パターンファイルをロード
def load_ir_pattern(filename='ir_pattern.txt'):
#---------------------------------------------------------------------------
if not file_exists(filename): # ファイルが存在しない場合
return [] # 空リストを返す
#---------------------------------------------------------------------------
with open(filename, 'r') as f:
pattern = f.read().strip()
return list(map(int, pattern.split(','))) # 記録したパターンをリストとして返す。
#///////////////////////////////////////////////////////////////////////////////
# IR点灯実行
def play_ir_signal(pattern):
print('[BEGIN] Play IR Signal')
setup_pwm() # PWMを設定
#---------------------------------------------------------------------------
for i, pulse in enumerate(pattern):
if i % 2 == 0: # 偶数インデックスはON期間
enable_pwm() # PWMを有効化(赤外線信号送信)
else: # 奇数インデックスはOFF期間
disable_pwm() # PWMを無効化(信号を送らない)
#-----------------------------------------------------------------------
time.sleep_us(pulse) # 指定された期間待機
#---------------------------------------------------------------------------
# 再生終了後はPWMを無効化
disable_pwm()
print('[END] Play IR Signal')
#///////////////////////////////////////////////////////////////////////////////
# 再生ボタン押下時の割り込みハンドラ
def evh_btn_tx_pressed_handler(pin):
global play_signal_flag, last_press_time
#---------------------------------------------------------------------------
current_time = time.ticks_ms() # 現在時刻を取得 [ms]
#---------------------------------------------------------------------------
# チャタリング対策のデバウンス処理: 最後の押下検出から指定時間が経過している場合のみ処理する。
if time.ticks_diff(current_time, last_press_time) > DEBOUNCE_DELAY:
print('Start playing')
play_signal_flag = True # 再生開始ボタン押下フラグをセット → 再生開始
last_press_time = current_time # 最後の押下検出時刻を更新
################################################################################
# その他の処理
################################################################################
#///////////////////////////////////////////////////////////////////////////////
# ファイルの存在確認 ※MicroPythonでは os.path.exists()が使えない。
def file_exists(filename):
try:
os.stat(filename) # ファイル情報を取得
return True
except OSError:
return False
################################################################################
# メインループ
################################################################################
# ボタン押下割込みを許可設定
btn_rec.irq(trigger=Pin.IRQ_FALLING, handler=evh_btn_rec_pressed_handler)
btn_tx.irq( trigger=Pin.IRQ_FALLING, handler=evh_btn_tx_pressed_handler)
# 無限ループ
while True:
#---------------------------------------------------------------------------
# 記録処理
if rec_signal_flag:
rec_signal_flag = False # 記録開始フラグをリセット
recorded_pattern = record_ir_signal() # 記録実行
if len(recorded_pattern) > 0: # 要素数が0でない?
with open('ir_pattern.txt', 'w') as f: # 記録したパターンをファイルに保存
f.write(','.join(map(str, recorded_pattern)))
#---------------------------------------------------------------------------
# 再生処理
if play_signal_flag:
play_signal_flag = False # 再生開始フラグをリセット
recorded_pattern = load_ir_pattern() # 記録済みの信号パターンを読み込む
if len(recorded_pattern) > 0: # 要素数が0でない?
play_ir_signal(recorded_pattern) # 信号パターンを再生
#---------------------------------------------------------------------------
time.sleep(0.1) # メインループで軽く待機
アクセス数(直近7日): ※試験運用中、BOT除外簡易実装済2026-06-25: 0回 2026-06-24: 0回 2026-06-23: 0回 2026-06-22: 0回 2026-06-21: 4回 2026-06-20: 0回 2026-06-19: 0回