X-Git-Url: https://vault307.fbx.one/gitweb/micorpython_ir.git/blobdiff_plain/d2a0c49467a3a7832d5d350ea00a50c59359722b..3b6cfaf15ad930c34b0d7f87c6a841ea651ccccb:/ir_tx.py?ds=inline diff --git a/ir_tx.py b/ir_tx.py index 9757840..4a91336 100644 --- a/ir_tx.py +++ b/ir_tx.py @@ -6,7 +6,6 @@ # Copyright (c) 2020 Peter Hinch from pyb import Pin, Timer -from time import sleep_us, sleep from micropython import const from array import array import micropython @@ -26,39 +25,39 @@ _T_RC6 = const(444) _T2_RC6 = const(889) # IR abstract base class. Array holds periods in μs between toggling 36/38KHz -# carrier on or off. -# Subclass is responsible for populating .arr and initiating transmission. -# Operation is in two phases: .transmit populates .arr with times in μs, then -# calls .start to initiate physical transmission. +# carrier on or off. Physical transmission occurs in an ISR context controlled +# by timer 2 and timer 5. See README.md for details of operation. class IR: - def __init__(self, pin, freq, asize, duty): - tim = Timer(2, freq=freq) + def __init__(self, pin, freq, asize, duty, verbose): + tim = Timer(2, freq=freq) # Timer 2/pin produces 36/38KHz carrier self._ch = tim.channel(1, Timer.PWM, pin=pin) - self._ch.pulse_width_percent(_SPACE) - self.duty = duty - self.arr = array('H', 0 for _ in range(asize)) - self._tim = Timer(5) - self._tcb = self._cb - self.pretrans() + self._ch.pulse_width_percent(_SPACE) # Turn off IR LED + self._duty = duty if not _SPACE else (100 - duty) + self._tim = Timer(5) # Timer 5 controls carrier on/off times + self._tcb = self.cb # Pre-allocate + self.verbose = verbose + self.arr = array('H', 0 for _ in range(asize)) # on/off times (μs) + self.carrier = False # Notional carrier state while encoding biphase + self.aptr = 0 # Index into array # Before populating array, zero pointer, set notional carrier state (off). - def pretrans(self): - self.aptr = 0 # Index into array + def transmit(self, addr, data, toggle=0): # NEC: toggle is unused + self.aptr = 0 # Inital conditions for tx: index into array self.carrier = False + self.tx(addr, data, toggle) + self.append(_STOP) + self.aptr = 0 # Reset pointer + self.cb(self._tim) # Initiate physical transmission. - def start(self): - self.aptr = 0 # Reset pointer and initiate TX. - self._cb(self._tim) - - def _cb(self, t): + def cb(self, t): # T5 callback, generate a carrier mark or space t.deinit() p = self.aptr v = self.arr[p] if v == _STOP: self._ch.pulse_width_percent(_SPACE) # Turn off IR LED. return - self._ch.pulse_width_percent(_SPACE if p & 1 else self.duty) + self._ch.pulse_width_percent(_SPACE if p & 1 else self._duty) self._tim.init(prescaler=84, period=v, callback=self._tcb) self.aptr += 1 @@ -67,51 +66,74 @@ class IR: self.arr[self.aptr] = t self.aptr += 1 self.carrier = not self.carrier # Keep track of carrier state - print('append', t, 'carrier', self.carrier) + self.verbose and print('append', t, 'carrier', self.carrier) def add(self, t): # Increase last time value - print('add', t) + self.verbose and print('add', t) self.arr[self.aptr - 1] += t # Carrier unaffected # NEC protocol class NEC(IR): - def __init__(self, pin, freq=38000): # NEC specifies 38KHz - super().__init__(pin, freq, 68, 50) + def __init__(self, pin, freq=38000, verbose=False): # NEC specifies 38KHz + super().__init__(pin, freq, 68, 50, verbose) def _bit(self, b): self.append(_TBURST, _T_ONE if b else _TBURST) - def transmit(self, addr, data, _=0): # Ignore toggle if passed - self.pretrans() # Set initial conditions + def tx(self, addr, data, _): # Ignore toggle self.append(9000, 4500) if addr < 256: # Short address: append complement addr |= ((addr ^ 0xff) << 8) - for x in range(16): + for _ in range(16): self._bit(addr & 1) addr >>= 1 data |= ((data ^ 0xff) << 8) - for x in range(16): + for _ in range(16): self._bit(data & 1) data >>= 1 - self.append(_TBURST, _STOP) - self.start() + self.append(_TBURST) def repeat(self): self.aptr = 0 self.append(9000, 2250, _TBURST, _STOP) + self.aptr = 0 # Reset pointer + self.cb(self._tim) # Initiate physical transmission. + +# NEC protocol +class SONY(IR): + + def __init__(self, pin, bits=12, freq=40000, verbose=False): # Sony specifies 40KHz + super().__init__(pin, freq, 3 + bits * 2, 30, verbose) + if bits not in (12, 15, 20): + raise ValueError('bits must be 12, 15 or 20.') + self.bits = bits + + def tx(self, addr, data, ext): + self.append(2400, 600) + bits = self.bits + v = data & 0x7f + if bits == 12: + v |= (addr & 0x1f) << 7 + elif bits == 15: + v |= (addr & 0xff) << 7 + else: + v |= (addr & 0x1f) << 7 + v |= (ext & 0xff) << 12 + for _ in range(bits): + self.append(1200 if v & 1 else 600, 600) + v >>= 1 # Philips RC5 protocol class RC5(IR): - def __init__(self, pin, freq=36000): - super().__init__(pin, freq, 28, 30) + def __init__(self, pin, freq=36000, verbose=False): + super().__init__(pin, freq, 28, 30, verbose) - def transmit(self, addr, data, toggle): - self.pretrans() # Set initial conditions + def tx(self, addr, data, toggle): d = (data & 0x3f) | ((addr & 0x1f) << 6) | ((data & 0x40) << 6) | ((toggle & 1) << 11) - print(bin(d)) + self.verbose and print(bin(d)) mask = 0x2000 while mask: if mask == 0x2000: @@ -124,17 +146,14 @@ class RC5(IR): else: self.append(_T_RC5, _T_RC5) mask >>= 1 - self.append(_STOP) - self.start() # Philips RC6 mode 0 protocol class RC6_M0(IR): - def __init__(self, pin, freq=36000): - super().__init__(pin, freq, 44, 30) + def __init__(self, pin, freq=36000, verbose=False): + super().__init__(pin, freq, 44, 30, verbose) - def transmit(self, addr, data, toggle): - self.pretrans() # Set initial conditions + def tx(self, addr, data, toggle): # leader, 1, 0, 0, 0 self.append(2666, _T2_RC6, _T_RC6, _T2_RC6, _T_RC6, _T_RC6, _T_RC6, _T_RC6, _T_RC6) # Append a single bit of twice duration @@ -145,7 +164,7 @@ class RC6_M0(IR): self.append(_T2_RC6, _T2_RC6) d = (data & 0xff) | ((addr & 0xff) << 8) mask = 0x8000 - print('toggle', toggle, self.carrier, bool(d & mask)) + self.verbose and print('toggle', toggle, self.carrier, bool(d & mask)) while mask: bit = bool(d & mask) if bit ^ self.carrier: @@ -154,5 +173,3 @@ class RC6_M0(IR): self.add(_T_RC6) self.append(_T_RC6) mask >>= 1 - self.append(_STOP) - self.start()