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