背景:使用系统的红外遥控软件没有反应,然后以为自己接线错误,反复测试,结果烧坏了一个红外接收器,信号主板没有问题。所以自己开发了一个红外接收器的python驱动。接线参见https://my.oschina.net/mengyoufengyu/blog/2966992
源码如下:
import time
import RPi.GPIO as GPIO
import queue
import threading
class IRRemoteController:
def __init__(self, pin_num: int = 18):
self.pin_num = pin_num
GPIO.setmode(GPIO.BCM)
GPIO.setup(self.pin_num, GPIO.IN, GPIO.PUD_UP)
self.key_queue = queue.Queue(100)
self.thread = self.myThread(1, "key_detect", 1, self.pin_num, self.key_queue)
def release(self):
GPIO.remove_event_detect(self.pin_num)
GPIO.cleanup()
def start(self):
self.thread.start()
pass
def stop(self):
self.thread.stop()
self.release()
pass
def get_key(self):
if self.key_queue.empty():
return None
else:
return self.key_queue.get()
def get_msg(self):
return self.thread.msg
def add_event(self, key_value, func):
self.thread.add_event(key_value, func)
def remove_event(self, key_value):
self.thread.remove_event(key_value)
class myThread(threading.Thread):
def __init__(self, threadID, name, counter, pin_num, key_queue):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
self.pin_num = pin_num
self.key_queue = key_queue
self.key_event = {}
self.__pause_flag = threading.Event() # 用于暂停线程的标识
self.__pause_flag.set() # 设置为True
self.__running_flag = threading.Event() # 用于停止线程的标识
self.__running_flag.set() # 将running设置为True
self.msg = []
def add_event(self, key_value, func):
self.key_event[key_value] = func
def remove_event(self, key_value):
del self.key_event[key_value]
def get_low_meaning(self, diff_time):
low_pulse_type = 0
if 0.0004 < diff_time < 0.0009:
low_pulse_type = 1 # 一个0.560ms的脉冲
elif 0.008 < diff_time < 0.015:
low_pulse_type = 2 # 一个9mS的脉冲
else:
low_pulse_type = 0
return low_pulse_type
def get_high_meaning(self, diff_time):
high_pulse_type = 0
if 0.0004 < diff_time < 0.0009:
high_pulse_type = 1 # 0.560ms的高电平
elif 0.0009 < diff_time < 0.0018:
high_pulse_type = 2 # 1.13ms的高电平
elif 0.0018 < diff_time < 0.003:
high_pulse_type = 4 # 2.25ms的高电平
elif 0.004 < diff_time < 0.006:
high_pulse_type = 8 # 4.5ms的高电平
elif 0.02 < diff_time < 0.2:
high_pulse_type = 16 # 39ms或95ms的高电平
else:
high_pulse_type = 0
return high_pulse_type
def get_high_low_meaning(self, high_pulse_type, low_pulse_type):
# 根据高低电平意义的出这个脉冲的意思
key_char = ""
if low_pulse_type == 2 and high_pulse_type == 8:
key_char = "Z" # 引导码: 0的时间(ms):9.067 1的时间(ms):4.517
elif low_pulse_type == 2 and high_pulse_type == 4:
key_char = "Y" # 重复码: 0的时间(ms):9.093 1的时间(ms):2.265
elif low_pulse_type == 1 and high_pulse_type == 16:
key_char = "X" # 时间对齐码: 0的时间(ms):0.550 1的时间(ms):39.362 0的时间(ms):0.550 1的时间(ms):95.722
elif low_pulse_type == 1 and high_pulse_type == 1:
key_char = "0" # 逻辑0: 0的时间(ms):0.553 1的时间(ms):0.632
elif low_pulse_type == 1 and high_pulse_type == 2:
key_char = "1" # 逻辑1: 0的时间(ms):0.535 1的时间(ms):1.684
return key_char
def get_high_low_char_process(self, last_key_char, key_char, high_pulse_type, low_pulse_type):
new_key_char = self.get_high_low_meaning(high_pulse_type, low_pulse_type)
if new_key_char == "Z" or new_key_char == "Y":
key_char = new_key_char
else:
key_char += new_key_char
# key_char += self.get_high_low_meaning(high_pulse_type, low_pulse_type)
if key_char.endswith("X"):
if key_char.startswith("Z"):
last_key_char = key_char
# 重复码处理
elif key_char.startswith("Y"):
last_key_char = last_key_char
else:
last_key_char = ""
# 对键值进行处理
key_value = last_key_char[1:-1]
# print(last_key_char, key_value)
if key_value:
key_value = hex(int(key_value, base=2))
if self.key_queue.full():
self.key_queue.get()
self.key_queue.put(key_value)
if key_value in self.key_event: # 实时触发事件
self.key_event[key_value]()
# 恢复key_char
key_char = ""
return last_key_char, key_char
def run(self):
last_signal = GPIO.HIGH
start_time = time.time()
low_pulse_type = 0 # 0表示无用 1表示9mS的脉冲 2 表示0.565ms的脉冲
high_pulse_type = 0 # 0表示无用 1表示9mS的脉冲 2 表示0.565ms的脉冲
last_key_char = key_char = ""
while self.__running_flag.isSet():
self.__pause_flag.wait() # 为True时立即返回, 为False时阻塞直到内部的标识位为True后返回 buffer = []
new_signal = GPIO.input(self.pin_num)
now_time = time.time()
if new_signal == last_signal == GPIO.HIGH and key_char and now_time - start_time > 0.095:
new_signal = GPIO.LOW
if new_signal != last_signal: # 进入接受信号开始
end_time = now_time
diff_time = end_time - start_time
start_time = end_time
# 上一个信号是低电平,根据时间解析其意义
if last_signal == GPIO.LOW:
low_pulse_type = self.get_low_meaning(diff_time)
else: # 上一个信号是高电平,根据时间解析其意义
high_pulse_type = self.get_high_meaning(diff_time)
self.msg.append([last_signal, new_signal, diff_time, low_pulse_type, high_pulse_type,key_char])
if (last_signal == GPIO.HIGH and new_signal == GPIO.LOW) : # 高变低,这时候完成一个高低电平信号,要进行处理
# 根据高低电平意义的出这个脉冲的意思
last_key_char, key_char = self.get_high_low_char_process(
last_key_char, key_char, high_pulse_type, low_pulse_type)
low_pulse_type = 0
high_pulse_type = 0
last_signal = new_signal
time.sleep(0.00001)
def pause(self):
self.__pause_flag.clear() # 设置为False, 让线程阻塞
def resume(self):
self.__pause_flag.set() # 设置为True, 让线程停止阻塞
def stop(self):
self.__pause_flag.set() # 将线程从暂停状态恢复, 如何已经暂停的话
self.__running_flag.clear() # 设置为False
@staticmethod
def example():
irrc = IRRemoteController()
print("开始采集数据:")
def left():
print("[0xffa25d CH-] 前进Forward")
def mid():
print("[0xff629d CH] 停止 Stop")
def right():
print("[0xffe21d CH+] 后退 Back off")
def main_exit():
print("[0xff906f EQ] 主线程退出")
irrc.add_event('0xffa25d', left)
irrc.add_event('0xff629d', mid)
irrc.add_event('0xffe21d', right)
irrc.add_event('0xff906f', main_exit)
irrc.start()
now_time = time.time()
while time.time() - now_time < 50:
key = irrc.get_key()
if key is None:
time.sleep(0.01)
continue
if key == "0xff906f":
break
# else:
# print(key)
print("结束采集数据:")
irrc.stop()
# for item in irrc.get_msg():
# print(item)
if __name__ == "__main__":
IRRemoteController.example()