/ adafruit_touchscreen.py
adafruit_touchscreen.py
1 # The MIT License (MIT) 2 # 3 # Copyright (c) 2019 ladyada for Adafruit 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 13 # all 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 21 # THE SOFTWARE. 22 """ 23 `adafruit_touchscreen` 24 ================================================================================ 25 26 CircuitPython library for 4-wire resistive touchscreens 27 28 29 * Author(s): ladyada 30 31 Implementation Notes 32 -------------------- 33 34 **Hardware:** 35 36 37 **Software and Dependencies:** 38 39 * Adafruit CircuitPython firmware for the supported boards: 40 https://github.com/adafruit/circuitpython/releases 41 """ 42 43 __version__ = "0.0.0-auto.0" 44 __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Touchscreen.git" 45 46 from digitalio import DigitalInOut 47 from analogio import AnalogIn 48 49 50 def map_range(x, in_min, in_max, out_min, out_max): 51 """ 52 Maps a number from one range to another. 53 Note: This implementation handles values < in_min differently than arduino's map function does. 54 :return: Returns value mapped to new range 55 :rtype: float 56 """ 57 mapped = (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min 58 if out_min <= out_max: 59 return max(min(mapped, out_max), out_min) 60 return min(max(mapped, out_max), out_min) 61 62 63 class Touchscreen: 64 """A driver for common and inexpensive resistive touchscreens. Analog input 65 capable pins are required to read the intrinsic potentiometers""" 66 67 def __init__( 68 self, 69 x1_pin, 70 x2_pin, 71 y1_pin, 72 y2_pin, 73 *, 74 x_resistance=None, 75 samples=4, 76 z_threshhold=10000, 77 calibration=None, 78 size=None 79 ): 80 """Create the Touchscreen object. At a minimum you need the 4 pins 81 that will connect to the 4 contacts on a screen. X and Y are just our 82 names, you can rotate and flip the data if you like. All pins must be 83 capable of becoming DigitalInOut pins. 'y2_pin', 'x1_pin' and 'x2_pin' 84 must also be capable of becoming AnalogIn pins. 85 If you know the resistance across the x1 and x2 pins when not touched, 86 pass that in as 'x_resistance'. 87 By default we oversample 4 times, change by adjusting 'samples' arg. 88 We can also detect the 'z' threshold, how much its prssed. We don't 89 register a touch unless its higher than 'z_threshold' 90 'calibration' is a tuple of two tuples, the default is 91 ((0, 65535), (0, 65535)). The numbers are the min/max readings for the 92 X and Y coordinate planes, respectively. To figure these out, pass in 93 no calibration value and read the raw values out while touching the 94 panel. 95 'size' is a tuple that gives the X and Y pixel size of the underlying 96 screen. If passed in, we will automatically scale/rotate so touches 97 correspond to the graphical coordinate system. 98 """ 99 self._xm_pin = x1_pin 100 self._xp_pin = x2_pin 101 self._ym_pin = y1_pin 102 self._yp_pin = y2_pin 103 self._rx_plate = x_resistance 104 self._xsamples = [0] * samples 105 self._ysamples = [0] * samples 106 if not calibration: 107 calibration = ((0, 65535), (0, 65535)) 108 self._calib = calibration 109 self._size = size 110 self._zthresh = z_threshhold 111 112 @property 113 def touch_point(self): # pylint: disable=too-many-locals 114 """A tuple that represents the x, y and z (touch pressure) coordinates 115 of a touch. Or, None if no touch is detected""" 116 with DigitalInOut(self._yp_pin) as y_p: 117 with DigitalInOut(self._ym_pin) as y_m: 118 with AnalogIn(self._xp_pin) as x_p: 119 y_p.switch_to_output(True) 120 y_m.switch_to_output(False) 121 for i in range(len(self._xsamples)): 122 self._xsamples[i] = x_p.value 123 x = sum(self._xsamples) / len(self._xsamples) 124 x_size = 65535 125 if self._size: 126 x_size = self._size[0] 127 x = int(map_range(x, self._calib[0][0], self._calib[0][1], 0, x_size)) 128 129 with DigitalInOut(self._xp_pin) as x_p: 130 with DigitalInOut(self._xm_pin) as x_m: 131 with AnalogIn(self._yp_pin) as y_p: 132 x_p.switch_to_output(True) 133 x_m.switch_to_output(False) 134 for i in range(len(self._ysamples)): 135 self._ysamples[i] = y_p.value 136 y = sum(self._ysamples) / len(self._ysamples) 137 y_size = 65535 138 if self._size: 139 y_size = self._size[1] 140 y = int(map_range(y, self._calib[1][0], self._calib[1][1], 0, y_size)) 141 142 z_1 = z_2 = z = None 143 with DigitalInOut(self._xp_pin) as x_p: 144 x_p.switch_to_output(False) 145 with DigitalInOut(self._ym_pin) as y_m: 146 y_m.switch_to_output(True) 147 with AnalogIn(self._xm_pin) as x_m: 148 z_1 = x_m.value 149 with AnalogIn(self._yp_pin) as y_p: 150 z_2 = y_p.value 151 # print(z_1, z_2) 152 z = 65535 - (z_2 - z_1) 153 if z > self._zthresh: 154 return (x, y, z) 155 return None