044 - MicroPython TechNotes: Infrared Receiver
Introduction
In this article, I will tackle how you can use an Infrared receiver module with ESP32 using MicroPython. GorillaCell Infrared Receiver module from GorillaCell ESP32 development kits uses a VS1838 photodiode infrared receiver. It is low cost and easy to use.
Bill Of Materials
- ESP32 development board.
- Gorillacell ESP32 shield.
- 3-pin female-female dupont wires.
- Gorillacell Infrared Receiver module.
Pinout
It has 3 pins namely:
- G – for the ground pin.
- V – for the supply voltage.
- S – for the infrared receive signal pin.
Hardware Instruction
- First, attach the ESP32 development board on top of the ESP32 shield and make sure that both the USB port are on the same side.
- Next, attach the dupont wires to the Infrared Receiver module by following the color coding that is black for the ground, red for the VCC, and yellow for the signal pin.
- Next, attach the other end of the dupont wires to the ESP32 shield by matching the colors of the wires to the colors of the pin headers that is black is to black, red is to red, and yellow is to yellow pin headers. For this lesson, I choose GPIO 23 to serve as the input pin from the Infrared Receiver module.
- Next, power the ESP32 shield with an external power supply with a type-C USB connector and make sure that the power switch is set to ON state.
- Lastly, connect the ESP32 to the computer using a micro-USB connector cable.
Software Instruction
- Copy the ir_rx.py from the SOURCE CODE section and paste it to Thonny IDE.
- Save it to MicroPython root directory by clicking the File menu and select Save As.
- Select MicroPython Device.
- And save it as ir_rx.py.
- Copy other examples to Thonny IDE and run it accordingly.
- Feel free to modify and adapt according to your needs.
Video Demonstration
Call To Action
If you have any concern regarding this video, please write your question in the comment box.
You might also liked to support my journey on Youtube by subscribing on my channel, TechToTinker. Click this to Subscribe.
Thank you and have a good days ahead.
– George Bantique | tech.to.tinker@gmail.com
Source Code
1. Example # 1, decode and display the receive infrared data to the REPL:
1# More details can be found in TechToTinker.blogspot.com
2# George Bantique | tech.to.tinker@gmail.com
3
4import time
5from machine import Pin
6from ir_rx import NEC_16
7
8def callback(data, addr, ctrl):
9 if data > 0: # NEC protocol sends repeat codes.
10 print('Data {:02x} Addr {:04x}'.format(data, addr))
11
12ir = NEC_16(Pin(23, Pin.IN), callback)
2. Example # 2, display actual buttons key in the REPL:
1# More details can be found in TechToTinker.blogspot.com
2# George Bantique | tech.to.tinker@gmail.com
3
4from machine import Pin
5from ir_rx import NEC_16
6
7ir_key = {
8 0x45: 'POWER',
9 0x46: 'MODE',
10 0x47: 'MUTE',
11 0x44: 'PLAY',
12 0x40: 'PREV',
13 0x43: 'NEXT',
14 0x07: 'EQ',
15 0x15: 'MINUS',
16 0x09: 'PLUS',
17 0x16: '0',
18 0x19: 'REPEAT',
19 0x0D: 'USD',
20 0x0C: '1',
21 0x18: '2',
22 0x5E: '3',
23 0x08: '4',
24 0x1C: '5',
25 0x5A: '6',
26 0x42: '7',
27 0x52: '8',
28 0x4A: '9'
29 }
30
31def callback(data, addr, ctrl):
32 if data > 0: # NEC protocol sends repeat codes.
33 #print('Data {:02x} Addr {:04x}'.format(data, addr))
34 print(ir_key[data])
35
36ir = NEC_16(Pin(23, Pin.IN), callback)
3. Example # 3, application, controlling the on-board LED. Pressing 2 will blinks the LED every 500ms, pressing 0 will turn OFF the LED:
1# More details can be found in TechToTinker.blogspot.com
2# George Bantique | tech.to.tinker@gmail.com
3
4from machine import Pin
5from machine import Timer
6from ir_rx import NEC_16
7
8
9def ir_callback(data, addr, ctrl):
10 global ir_data
11 global ir_addr
12 if data > 0:
13 ir_data = data
14 ir_addr = addr
15 print('Data {:02x} Addr {:04x}'.format(data, addr))
16
17def timer_callback(timer):
18 led.value( not led.value() )
19
20ir = NEC_16(Pin(23, Pin.IN), ir_callback)
21led = Pin(2, Pin.OUT)
22tim0 = Timer(0)
23isLedBlinking = False
24ir_data = 0
25ir_addr = 0
26
27while True:
28 if ir_data > 0:
29 if ir_data == 0x16: # 0
30 led.value(0)
31 if isLedBlinking==True:
32 tim0.deinit()
33 isLedBlinking = False
34 elif ir_data == 0x0C: # 1
35 led.value(1)
36 if isLedBlinking==True:
37 tim0.deinit()
38 isLedBlinking = False
39 elif ir_data == 0x18: # 2
40 isLedBlinking = True
41 tim0.init(period=500,
42 mode=Timer.PERIODIC,
43 callback=timer_callback)
44 ir_data = 0
4. micropython_ir.py driver library:
1# MIT License
2#
3# Copyright (c) 2020 Peter Hinch
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21# SOFTWARE.
22
23# Author: Peter Hinch
24# Copyright Peter Hinch 2020-2021 Released under the MIT license
25# http://github.com/peterhinch/micropython_ir
26
27from machine import Pin
28from machine import Timer
29from array import array
30from utime import ticks_us
31from utime import ticks_diff
32
33# Save RAM
34# from micropython import alloc_emergency_exception_buf
35# alloc_emergency_exception_buf(100)
36
37
38# On 1st edge start a block timer. While the timer is running, record the time
39# of each edge. When the timer times out decode the data. Duration must exceed
40# the worst case block transmission time, but be less than the interval between
41# a block start and a repeat code start (~108ms depending on protocol)
42
43class IR_RX():
44 # Result/error codes
45 # Repeat button code
46 REPEAT = -1
47 # Error codes
48 BADSTART = -2
49 BADBLOCK = -3
50 BADREP = -4
51 OVERRUN = -5
52 BADDATA = -6
53 BADADDR = -7
54
55 def __init__(self, pin, nedges, tblock, callback, *args): # Optional args for callback
56 self._pin = pin
57 self._nedges = nedges
58 self._tblock = tblock
59 self.callback = callback
60 self.args = args
61 self._errf = lambda _ : None
62 self.verbose = False
63
64 self._times = array('i', (0 for _ in range(nedges + 1))) # +1 for overrun
65 pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING))
66 self.edge = 0
67 self.tim = Timer(-1) # Sofware timer
68 self.cb = self.decode
69
70 # Pin interrupt. Save time of each edge for later decode.
71 def _cb_pin(self, line):
72 t = ticks_us()
73 # On overrun ignore pulses until software timer times out
74 if self.edge <= self._nedges: # Allow 1 extra pulse to record overrun
75 if not self.edge: # First edge received
76 self.tim.init(period=self._tblock , mode=Timer.ONE_SHOT, callback=self.cb)
77 self._times[self.edge] = t
78 self.edge += 1
79
80 def do_callback(self, cmd, addr, ext, thresh=0):
81 self.edge = 0
82 if cmd >= thresh:
83 self.callback(cmd, addr, ext, *self.args)
84 else:
85 self._errf(cmd)
86
87 def error_function(self, func):
88 self._errf = func
89
90 def close(self):
91 self._pin.irq(handler = None)
92 self.tim.deinit()
93
94
95class NEC_ABC(IR_RX):
96 def __init__(self, pin, extended, callback, *args):
97 # Block lasts <= 80ms (extended mode) and has 68 edges
98 super().__init__(pin, 68, 80, callback, *args)
99 self._extended = extended
100 self._addr = 0
101
102 def decode(self, _):
103 try:
104 if self.edge > 68:
105 raise RuntimeError(self.OVERRUN)
106 width = ticks_diff(self._times[1], self._times[0])
107 if width < 4000: # 9ms leading mark for all valid data
108 raise RuntimeError(self.BADSTART)
109 width = ticks_diff(self._times[2], self._times[1])
110 if width > 3000: # 4.5ms space for normal data
111 if self.edge < 68: # Haven't received the correct number of edges
112 raise RuntimeError(self.BADBLOCK)
113 # Time spaces only (marks are always 562.5µs)
114 # Space is 1.6875ms (1) or 562.5µs (0)
115 # Skip last bit which is always 1
116 val = 0
117 for edge in range(3, 68 - 2, 2):
118 val >>= 1
119 if ticks_diff(self._times[edge + 1], self._times[edge]) > 1120:
120 val |= 0x80000000
121 elif width > 1700: # 2.5ms space for a repeat code. Should have exactly 4 edges.
122 raise RuntimeError(self.REPEAT if self.edge == 4 else self.BADREP) # Treat REPEAT as error.
123 else:
124 raise RuntimeError(self.BADSTART)
125 addr = val & 0xff # 8 bit addr
126 cmd = (val >> 16) & 0xff
127 if cmd != (val >> 24) ^ 0xff:
128 raise RuntimeError(self.BADDATA)
129 if addr != ((val >> 8) ^ 0xff) & 0xff: # 8 bit addr doesn't match check
130 if not self._extended:
131 raise RuntimeError(self.BADADDR)
132 addr |= val & 0xff00 # pass assumed 16 bit address to callback
133 self._addr = addr
134 except RuntimeError as e:
135 cmd = e.args[0]
136 addr = self._addr if cmd == self.REPEAT else 0 # REPEAT uses last address
137 # Set up for new data burst and run user callback
138 self.do_callback(cmd, addr, 0, self.REPEAT)
139
140class NEC_8(NEC_ABC):
141 def __init__(self, pin, callback, *args):
142 super().__init__(pin, False, callback, *args)
143
144class NEC_16(NEC_ABC):
145 def __init__(self, pin, callback, *args):
146 super().__init__(pin, True, callback, *args)
References And Credits
-
Purchase your Gorillacell ESP32 development kits from: https://gorillacell.kr/
-
Peter Hinch micropython IR library: http://github.com/peterhinch/micropython_ir
Posts in this series
- 049 - MicroPython TechNotes: MP3 Player
- 048 - MicroPython TechNotes: Analog Touch Sensor
- 047 - MicroPython TechNotes: E108 GPS
- 046 - MicroPython TechNotes: RF433 Transceivers
- 045 - MicroPython TechNotes: Infrared Transmitter
- 043 - MicroPython TechNotes: ESP12E WiFi | External WiFi module
- 042 - MicroPython TechNotes: JDY-32 | Bluetooth Low Energy BLE
- 041 - MicroPython TechNotes: Bluetooth HC-06
- 040 - MicroPython TechNotes: Relay
- 039 - MicroPython TechNotes: Electromagnet
- 038 - MicroPython TechNotes: Buzzer
- 037 - MicroPython TechNotes: Servo Motor
- 036 - MicroPython TechNotes: Stepper Motor
- 035 - MicroPython TechNotes: Dual Motor Driver
- 034 - MicroPython TechNotes: DC Motors | Gear Motor and Fan Motor
- 033 - MicroPython TechNotes: TCS34725 RGB Color Sensor
- 032 - MicroPython TechNotes: BMP280 Sensor
- 031 - MicroPython TechNotes: TOF Distance Sensor
- 030 - MicroPython TechNotes: DS3231 RTC
- 029 - MicroPython TechNotes: HC-SR04 Ultrasonic Sensor
- 028 - MicroPython TechNotes: DHT11 Temperature and Humidity Sensor
- 027 - MicroPython TechNotes: Rotary Encoder
- 026 - MicroPython TechNotes: Light Dependent Resistor (LDR)
- 025 - MicroPython TechNotes: Joystick
- 024 - MicroPython TechNotes: Slider Switch
- 023 - MicroPython TechNotes: Continuous Rotation Potentiometer
- 022 - MicroPython TechNotes: Potentiometer | Reading an Analog Input
- 021 - MicroPython TechNotes: Color Touch Sensor
- 020 - MicroPython TechNotes: Touch Sensor
- 019 - MicroPython TechNotes: Switch Module
- 018 - MicroPython TechNotes: Button | Reading an Input
- 017 - MicroPython TechNotes: LASER Module
- 016 - MicroPython TechNotes: RGB LED Matrix
- 015 - MicroPython TechNotes: Neopixel 16
- 014 - MicroPython TechNotes: 8x8 Dot Matrix Display (I2C)
- 013 - MicroPython TechNotes: 8x16 Dot Matrix Display (SPI)
- 012 - MicroPython TechNotes: 8x8 Dot Matrix Display (SPI)
- 011 - MicroPython TechNotes: 1.3 OLED Display
- 010 - MicroPython TechNotes: 0.96 OLED Display
- 009 - MicroPython TechNotes: 7 Segment Display
- 008 - MicroPython TechNotes: 16x2 LCD
- 007 - MicroPython TechNotes: RGB LED
- 006 - MicroPython TechNotes: Traffic Light LED Module
- 005 - MicroPython TechNotes: Gorilla Cell LED | MicroPython Hello World
- 004 - MicroPython TechNotes: Gorilla Cell I/O Devices
- 003 - MicroPython TechNotes: Gorillacell ESP32 Shield
- 002 - MicroPython TechNotes: Introduction for Gorillacell ESP32 Dev Kit
- 001 - MicroPython TechNotes: Get Started with MicroPython
- 000 - MicroPython TechNotes: Unboxing Gorillacell ESP32 Development Kit
No comments yet!