紅外線遙控接收-micropython
tags: esp32
vs1838
micropython
紅外線遙控
**紅外接收器模塊使用 VS1838 光電二極管紅外接收器。它成本低且易於使用。
引腳:
它有 3 個引腳,即:
G - 接地引腳。
V - 電源電壓。
S - 為紅外接收信號引腳。**
上傳micropython_ir Library of Peter Hinch函式庫:
# MIT License
#
# Copyright (c) 2020 Peter Hinch
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# Author: Peter Hinch
# Copyright Peter Hinch 2020-2021 Released under the MIT license
# http://github.com/peterhinch/micropython_ir
from machine import Pin
from machine import Timer
from array import array
from utime import ticks_us
from utime import ticks_diff
# Save RAM
# from micropython import alloc\_emergency\_exception_buf
# alloc\_emergency\_exception_buf(100)
# On 1st edge start a block timer. While the timer is running, record the time
# of each edge. When the timer times out decode the data. Duration must exceed
# the worst case block transmission time, but be less than the interval between
# a block start and a repeat code start (~108ms depending on protocol)
class IR_RX():
# Result/error codes
# Repeat button code
REPEAT = -1
# Error codes
BADSTART = -2
BADBLOCK = -3
BADREP = -4
OVERRUN = -5
BADDATA = -6
BADADDR = -7
def __init__(self, pin, nedges, tblock, callback, *args): # Optional args for callback
self._pin = pin
self._nedges = nedges
self._tblock = tblock
self.callback = callback
self.args = args
self._errf = lambda _ : None
self.verbose = False
self._times = array('i', (0 for _ in range(nedges + 1))) # +1 for overrun
pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING))
self.edge = 0
self.tim = Timer(-1) # Sofware timer
self.cb = self.decode
# Pin interrupt. Save time of each edge for later decode.
def _cb_pin(self, line):
t = ticks_us()
# On overrun ignore pulses until software timer times out
if self.edge <= self._nedges: # Allow 1 extra pulse to record overrun
if not self.edge: # First edge received
self.tim.init(period=self._tblock , mode=Timer.ONE_SHOT, callback=self.cb)
self._times[self.edge] = t
self.edge += 1
def do_callback(self, cmd, addr, ext, thresh=0):
self.edge = 0
if cmd >= thresh:
self.callback(cmd, addr, ext, *self.args)
else:
self._errf(cmd)
def error_function(self, func):
self._errf = func
def close(self):
self._pin.irq(handler = None)
self.tim.deinit()
class NEC_ABC(IR_RX):
def __init__(self, pin, extended, callback, *args):
# Block lasts <= 80ms (extended mode) and has 68 edges
super().__init__(pin, 68, 80, callback, *args)
self._extended = extended
self._addr = 0
def decode(self, _):
try:
if self.edge > 68:
raise RuntimeError(self.OVERRUN)
width = ticks_diff(self._times[1], self._times[0])
if width < 4000: # 9ms leading mark for all valid data
raise RuntimeError(self.BADSTART)
width = ticks_diff(self._times[2], self._times[1])
if width > 3000: # 4.5ms space for normal data
if self.edge < 68: # Haven't received the correct number of edges
raise RuntimeError(self.BADBLOCK)
# Time spaces only (marks are always 562.5µs)
# Space is 1.6875ms (1) or 562.5µs (0)
# Skip last bit which is always 1
val = 0
for edge in range(3, 68 - 2, 2):
val >>= 1
if ticks_diff(self._times[edge + 1], self._times[edge]) > 1120:
val = 0x80000000
elif width > 1700: # 2.5ms space for a repeat code. Should have exactly 4 edges.
raise RuntimeError(self.REPEAT if self.edge == 4 else self.BADREP) # Treat REPEAT as error.
else:
raise RuntimeError(self.BADSTART)
addr = val & 0xff # 8 bit addr
cmd = (val >> 16) & 0xff
if cmd != (val >> 24) ^ 0xff:
raise RuntimeError(self.BADDATA)
if addr != ((val >> 8) ^ 0xff) & 0xff: # 8 bit addr doesn't match check
if not self._extended:
raise RuntimeError(self.BADADDR)
addr |= val & 0xff00 # pass assumed 16 bit address to callback
self._addr = addr
except RuntimeError as e:
cmd = e.args[0]
addr = self._addr if cmd == self.REPEAT else 0 # REPEAT uses last address
# Set up for new data burst and run user callback
self.do_callback(cmd, addr, 0, self.REPEAT)
class NEC_8(NEC_ABC):
def __init__(self, pin, callback, *args):
super().__init__(pin, False, callback, *args)
class NEC_16(NEC_ABC):
def __init__(self, pin, callback, *args):
super().__init__(pin, True, callback, *args)
範例1
套用以下範例並記下遙控器按鍵的data
from ir_rx import NEC_16
from machine import Timer
from machine import Pin
def callBack(data, addr, ctrl):
if data > 0:
print("data: {:02x} addr: {:04x}".format(data, addr))
ir = NEC_16(Pin(26, Pin.IN), callBack)
範例2:
有了對應鍵的16進制,並存放在dist裡,就可以把它套用在callBack()去作比對
from ir_rx import NEC_16
from machine import Timer
from machine import Pin
def callBack(data, addr, ctrl):
if data > 0:
# print("data: {:02x} addr: {:04x}".format(data, addr))
print(ir_key[data])
ir = NEC_16(Pin(26, Pin.IN), callBack)
ir_key = {
0x16 : '0',
0x0c : '1',
0x18 : '2',
0x5e : '3',
0x08 : '4',
0x1c : '5',
0x5a : '6',
0x42 : '7',
0x52 : '8',
0x4a : '9',
0x15 : 'ok',
0x40 : 'up',
0x19 : 'down',
0x07 : 'left',
0x09 : 'right',
0x44 : 'power',
}
範例3:
現在有了精確的數字,可以運用在控制某些例如燈具…等等的物品這裡使用一個簡單的例子,當按下”1”的鍵時,打開esp32的內鍵燈,當按下”2”時,關閉內鍵燈。
from ir_rx import NEC_16
from machine import Timer
from machine import Pin
led = Pin(2, Pin.OUT)
def callBack(data, addr, ctrl):
global _data, _addr
_data = ir_key[data]
_addr = addr
if data > 0:
# print("data: {:02x} addr: {:04x}".format(data, addr))
print(_data)
ir = NEC_16(Pin(26, Pin.IN), callBack)
ir_key = {
0x16 : '0',
0x0c : '1',
0x18 : '2',
0x5e : '3',
0x08 : '4',
0x1c : '5',
0x5a : '6',
0x42 : '7',
0x52 : '8',
0x4a : '9',
0x15 : 'ok',
0x40 : 'up',
0x19 : 'down',
0x07 : 'left',
0x09 : 'right',
0x44 : 'power',
}
_data = 0
if _data == "1":
led.on()
elif _data == "2":
led.off()