├── examples.py ├── .gitignore ├── LICENSE ├── inputs.py └── README.md /examples.py: -------------------------------------------------------------------------------- 1 | # Example of using the "inputs" library with the Micro Python pyboard. 2 | 3 | import time 4 | from inputs import Manager, Digital, Counter, Analog 5 | 6 | # List the desired inputs and pass them to a Manager object. 7 | mgr = Manager([Digital('Y1:button1'), 8 | Counter('Y2'), 9 | Analog('X1:sensor1_volts', convert_func=lambda x: x / 4095 * 3.3)]) 10 | 11 | # The manager object immediately starts polling the inputs after instantiation. 12 | 13 | # wait until the Analog input reading buffer before reading all the inputs the 14 | # first time. 15 | time.sleep(0.4) 16 | 17 | while True: 18 | # get a snapshot of all the current input values 19 | vals = mgr.values() 20 | 21 | print(vals) # prints the entire dictionary of readings 22 | 23 | # prints two individual readings, using normal dictionary access and also 24 | # attribute access. 25 | print(vals['button1'], vals.sensor1_volts, '\n') 26 | 27 | time.sleep(1) 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # My special files 2 | copy_to_pyboard_HP.bat 3 | main.py 4 | 5 | # Byte-compiled / optimized / DLL files 6 | __pycache__/ 7 | *.py[cod] 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | env/ 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *,cover 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | 57 | # Sphinx documentation 58 | docs/_build/ 59 | 60 | # PyBuilder 61 | target/ 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Alan Mitchell 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 | -------------------------------------------------------------------------------- /inputs.py: -------------------------------------------------------------------------------- 1 | # inputs.py 2 | # Author: Alan Mitchell, tabb99@gmail.com 3 | # Provides counters, debounced digital inputs, analog inputs with 4 | # moving averages. 5 | 6 | import pyb 7 | import array 8 | import math 9 | 10 | 11 | # -------------------------- Classes to Manage All Inputs ---------------------------- 12 | 13 | class Manager: 14 | '''Class to manage and service a number of inputs. 15 | ''' 16 | 17 | def __init__(self, inputs, timer_num=1, poll_freq=480): 18 | '''Arguments are: 19 | inputs: a list or tuple of Inputs objects that derive from InputBase. 20 | timer_num: the number of the microcontroller Timer that will be used to 21 | periodically poll the inputs. If None is passed, no Timer will be 22 | set up automatically and you will need to periodically call 23 | the 'service_inputs()` method from your own timer. 24 | poll_freq: the frequency in Hz to read the inputs. The default value 25 | of 480 Hz means each input will be read every 2.08 ms (1000 ms / 480). 26 | Be careful about setting this too high as the time required to read 27 | each input will consume substantial CPU cycles. Roughly, each input 28 | takes 80 usec to read. Therefore, reading 20 inputs would require 29 | 80 usec x 20 = 1600 usec or 1.6 ms. If inputs are being read every 2.08 ms, 30 | the process of reading inputs consumes 1.6 / 2.08 or 77% of the CPU cycles. 31 | ''' 32 | self.inputs = inputs 33 | if timer_num is not None: 34 | self._tim = pyb.Timer(timer_num, freq=poll_freq) 35 | self._tim.callback(self.service_inputs) 36 | 37 | def service_inputs(self, t): 38 | '''This method is called by the timer interrupt and runs the 'service_input' 39 | routine on each input. That routine reads the input and does any required 40 | processing. 41 | ''' 42 | for i in range(len(self.inputs)): 43 | self.inputs[i].service_input() 44 | 45 | def values(self): 46 | '''Returns the current values of all inputs as a MyDict object 47 | (basically a Python dictionary that also allows value access through 48 | attributes). 49 | The keys in the dictionary are the 'key_name' for the input (see 50 | InputBase class) and the dictionary values are the fully processed 51 | input values (e.g. debounced digital input values, counter values, moving 52 | average analog values). 53 | ''' 54 | return MyDict([(inp.key_name(), inp.value()) for inp in self.inputs]) 55 | 56 | def __getattr__(self, input_key): 57 | '''Returns a particular input with the key_name of 'input_key'. This 58 | method is accessed by the obj.input_key sytax. 59 | ''' 60 | for inp in self.inputs: 61 | if inp.key_name() == input_key: 62 | return inp 63 | raise KeyError 64 | 65 | 66 | class MyDict(dict): 67 | '''A normal Python dictionary that also allows access to the value 68 | of each item as an attribute of the object. For example, 69 | if 'd' is a MyDict object and has a key of 'abc', the value associated 70 | with 'abc' can be accessed via d['abc'] or via d.abc . 71 | ''' 72 | 73 | def __getattr__(self, key_name): 74 | return self[key_name] 75 | 76 | 77 | # ---------------------- The Base Input Class and all Dervied Input Classes 78 | 79 | 80 | class InputBase(object): 81 | '''Base Class for all input types (digital and analog). The input classes 82 | that are used inherit from this one. 83 | ''' 84 | 85 | def __init__(self, pin_name, pull=pyb.Pin.PULL_NONE, convert_func=None): 86 | '''Arguments are: 87 | pin_name: The Pyboard pin name, such as X1 or Y2, as string. Optionally, 88 | a more descriptive name can be added after a colon, e.g. 'X1:outside_temp'. 89 | If the descriptive name is present, it will be used as the key for accessing 90 | the input's value. 91 | pull: can be used to enable a pull-up or pull-down on the input line. Must be 92 | one of the pyb.Pin.PULL_ constants and defaults to no pull on the input line. 93 | convert_func: If a function is provided here, it will be applied to the input's 94 | value before being returned. The function can be used to convert the value 95 | into engineering units or even a text string. 96 | ''' 97 | name_parts = pin_name.split(':') 98 | self._pin_name = name_parts[0].strip() 99 | self._pin = pyb.Pin(self._pin_name, pyb.Pin.IN, pull) 100 | self.input_name = name_parts[1].strip() if len(name_parts) > 1 else None 101 | self.convert_func = convert_func 102 | 103 | def key_name(self): 104 | '''Returns the the descriptive input name, if present, otherwise the pin 105 | name is returned. This value is used as the identifying name for 106 | the input. 107 | ''' 108 | return self.input_name if self.input_name else self._pin_name 109 | 110 | def service_input(self): 111 | '''Override this method to read the input and do any required processing. 112 | This method is called every timer interrupt by the Manager class. 113 | ''' 114 | pass 115 | 116 | def _compute_value(self): 117 | '''Override this method to return the input value, prior to applying any 118 | convert_func provided in the constructor. 119 | ''' 120 | return None 121 | 122 | def value(self): 123 | '''Returns the final value of this input. Interrupts are disabled so that 124 | the value isn't altered during retrieval. The conversion function, if supplied, 125 | in the constructor is applied before returning. 126 | ''' 127 | irq_state = pyb.disable_irq() 128 | val = self._compute_value() 129 | pyb.enable_irq(irq_state) 130 | return self.convert_func(val) if self.convert_func else val 131 | 132 | 133 | class DigitalBase(InputBase): 134 | '''The base class for digital inputs. 135 | ''' 136 | 137 | def __init__(self, pin_name, pull=pyb.Pin.PULL_UP, stable_read_count=12, **kwargs): 138 | '''New arguments not in the inheritance chain are: 139 | stable_read_count: The number of consistent readings of the pin in order to 140 | declare that the pin has changed state. If sampling occurs at 480 Hz, 141 | reads of the pin will occur every 2.1 ms. A 'stable_read_count' of 12 142 | means that the same value has to be read 12 times to be considered solid. 143 | Those 12 reads will span 2.1 ms x 12 = 25.2 ms. 144 | ''' 145 | InputBase.__init__(self, pin_name, pull=pull, **kwargs) 146 | # create a bit mask that will spans 'stable_read_count' bits. 147 | self._mask = 2 ** stable_read_count - 1 148 | # start the variables in a state consistent with the PULL_UP. 149 | # the self._reads variable holds the digital readings, each reading 150 | # occupying one bit position; the most recent read is in the LSB 151 | # position. 152 | if pull == pyb.Pin.PULL_UP: 153 | self._reads = self._mask 154 | self._cur_val = 1 155 | else: 156 | self._reads = 0 157 | self._cur_val = 0 158 | 159 | 160 | class Digital(DigitalBase): 161 | '''A class to provide a debounced digital value from a pin. 162 | ''' 163 | 164 | def __init__(self, pin_name, hl_func=None, lh_func=None, **kwargs): 165 | '''Arguments not in the inheritance chain: 166 | hl_func: if a function is provided, it is called when the pin 167 | transitions from a high state (1) to a low state (0). This 168 | function call occurs during the Timer interrupt, so do not 169 | consume much time within the function. 170 | lh_func: if a function is provided, it is called when the pin 171 | transitions from a low state (0) to a high state(1). The 172 | call occurs during the timer iterrupt. 173 | ''' 174 | DigitalBase.__init__(self, pin_name, **kwargs) 175 | self.hl_func = hl_func 176 | self.lh_func = lh_func 177 | 178 | def service_input(self): 179 | # shift the prior readings over one bit, and put the new reading 180 | # in the LSb position. 181 | self._reads = ((self._reads << 1) | self._pin.value()) & self._mask 182 | if self._reads != 0 and self._reads != self._mask: 183 | # The prior set of readings have alternated between ones and zeroes 184 | # so a bouncy state is occurring. Just return w/o changing value. 185 | return 186 | # there is a stable set of readings. Get the stable value (either a 187 | # 1 or a 0) 188 | self._new_val = self._reads & 0x01 189 | if self._new_val == self._cur_val: 190 | # no change in value 191 | return 192 | if self._new_val > self._cur_val: 193 | # transition from low to high occurred. 194 | if self.lh_func: 195 | self.lh_func() 196 | else: 197 | # transition from high to low occurred. 198 | if self.hl_func: 199 | self.hl_func() 200 | self._cur_val = self._new_val 201 | 202 | def _compute_value(self): 203 | return self._cur_val 204 | 205 | 206 | class Counter(DigitalBase): 207 | '''A class used to count pulses on a digital input pin. The counter 208 | can count one or both edge transitions of the pulse. Pin transitions 209 | are debounced. 210 | ''' 211 | 212 | # Constants signifying whether one or both transition edges are counted. 213 | ONE_EDGE = 1 214 | BOTH_EDGES = 2 215 | 216 | def __init__(self, pin_name, stable_read_count=4, edges=ONE_EDGE, reset_on_read=False, 217 | rollover=1073741823, **kwargs): 218 | '''Arguments not in the inheritance chain: 219 | edges: Either ONE_EDGE or BOTH_EDGES indicating which transitions of the pulse to 220 | count. 221 | reset_on_read: if True, the counter value will be reset to 0 after the count 222 | is read via a call to the value() method. 223 | rollover: count will roll to 0 when it hits this value. 224 | Note that the default 'stable_read_count' value is set to 4 reads. With the 225 | default 2.1 ms read interval, this requires stability for 8.4 ms. Counters are 226 | often reed switches or electronic pulse trains, both of which have little to no 227 | bounce. Using a low value for 'stable_read_count' increases the pulse frequency 228 | that can be read by the counter. 229 | ''' 230 | DigitalBase.__init__(self, pin_name, stable_read_count=stable_read_count, **kwargs) 231 | self.edges = edges 232 | self.reset_on_read = reset_on_read 233 | self._rollover = rollover 234 | self._count = 0 235 | self._new_val = None # need to allocate memory here, not in interrupt routine 236 | 237 | def service_input(self): 238 | # shift the prior readings over one bit, and put the new reading 239 | # in the LSb position. 240 | self._reads = ((self._reads << 1) | self._pin.value()) & self._mask 241 | if self._reads != 0 and self._reads != self._mask: 242 | # The prior set of readings have alternated between ones and zeroes 243 | # so a bouncy state is occurring. Just return w/o changing value. 244 | return 245 | self._new_val = self._reads & 0x01 246 | if self._new_val == self._cur_val: 247 | # no change in value 248 | return 249 | if self._new_val < self._cur_val: 250 | # transition from high to low occurred. Always count these 251 | # transitions. 252 | self._count = (self._count + 1) % self._rollover 253 | elif self.edges == Counter.BOTH_EDGES: 254 | # A low to high transition occurred and counting both edges 255 | # was requested, so increment counter. 256 | self._count = (self._count + 1) % self._rollover 257 | self._cur_val = self._new_val 258 | 259 | def _compute_value(self): 260 | ct = self._count 261 | if self.reset_on_read: 262 | self._count = 0 263 | return ct 264 | 265 | def reset_count(self): 266 | '''Resets the counts and protects the processs form being 267 | interrupted. 268 | ''' 269 | irq_state = pyb.disable_irq() 270 | self._count = 0 271 | pyb.enable_irq(irq_state) 272 | 273 | 274 | class AnalogBase(InputBase): 275 | '''Base class for analog input pins. 276 | ''' 277 | 278 | def __init__(self, pin_name, buffer_size=144, **kwargs): 279 | '''Arguments not in inheritance chain: 280 | buffer_size: the number readings to include in the moving 281 | average. If the sampling frequency is 480 Hz and 144 282 | readings are included in the moving average, the average 283 | spans 144 / 480 = 0.3 seconds. For cancellation of 60 Hz 284 | noise, it is good to have this time be an exact number of 285 | 60 Hz cycles. 0.3 seconds is exactly 18 full 60 Hz cycles. 286 | ''' 287 | InputBase.__init__(self, pin_name, **kwargs) 288 | self._adc = pyb.ADC(self._pin) 289 | self._buflen = buffer_size 290 | # create a ring array with 2 byte elements, sufficient to 291 | # store the 12-bit ADC readings. 292 | self._buf = array.array('H', [0] * buffer_size) 293 | self._ix = 0 # ring array index 294 | 295 | def service_input(self): 296 | self._buf[self._ix] = self._adc.read() 297 | self._ix = (self._ix + 1) % self._buflen 298 | 299 | 300 | class Analog(AnalogBase): 301 | '''Analog input that returns a moving average of the input pin. 302 | ''' 303 | 304 | def _compute_value(self): 305 | # return the average value in the ring buffer. 306 | return sum(self._buf)/self._buflen 307 | 308 | 309 | class AnalogDeviation(AnalogBase): 310 | '''Analog input that returns the standard deviation of the readings 311 | in the ring buffer. 312 | ''' 313 | 314 | def _compute_value(self): 315 | # returns standard deviation of values in the ring buffer. 316 | n = self._buflen 317 | mean = sum(self._buf) / n 318 | dev_sq = 0.0 319 | for v in self._buf: 320 | dev = v - mean 321 | dev_sq += dev * dev 322 | return math.sqrt(dev_sq/(n-1)) 323 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # micropython-inputs 2 | This Micro Python library facilitates reading digital and analog inputs on the pyboard or other microcontrollers running [Micro Python](http://micropython.org/), a variant of the Python 3 programming language. These library routines were tested on a [pyboard, available here](https://micropython.org/store/#/store). Some of the notable features of this library are: 3 | 4 | * Digital input pins are debounced so transitions are detected cleanly. Debouncing parameters are controllable by the user. 5 | * Digital input pins can be configured as counters for counting pulse trains. Either one or both edges of the pulses can be counted, and debouncing is present to clean up reed switch closures. 6 | * Analog readings are averaged across a user-selectable number of recent readings spaced at 2.1 ms (user configurable) intervals. Noise on the analog line can be significantly suppressed with this averaging technique. 7 | * Current values from the pins are easily accessible through a Python dictionary, keyed by either the Pin name or a more descriptive name you can assign to the pin. 8 | 9 | ## Quickstart 10 | 11 | The entire library resides in one file, `inputs.py`. Suppose we need to set up an input to detect button presses, a counter to count the pulses from a water meter utilizing a reed switch, and an Analog input to measure a sensor voltage. Here is the setup code: 12 | 13 | ```Python 14 | from inputs import Manager, Digital, Counter, Analog 15 | 16 | # We create this function that will be called when there is a 17 | # High-to-Low transition on a Digital pin we set up below. 18 | def hl_occurred(): 19 | print('High to Low transition occurred!') 20 | 21 | 22 | # the Manager class holds the input objects and polls them at a regular 23 | # interval from a Timer interrupt. We pass a list of the three needed 24 | # input objects to the constructor. 25 | mgr = Manager([Digital('Y1: button1', hl_func=hl_occurred), 26 | Counter('Y2'), 27 | Analog('X1: sensor1_volts', convert_func=lambda x: x / 4095 * 3.3)]) 28 | ``` 29 | The first argument passed to constructor of each Input object is the name of the pin to use for the input. For example, the Counter input uses the Y2 pin. Optionally, a more descriptive name can be added after a colon. The Digital input uses Pin Y1 and is labeled `button1`. If a descriptive name is provided, it will be used for all labeling and accessing of the input. 30 | 31 | Each Input object type has a number of configuration options, all with default values except for the required `pin_name` argument. Some of the configuration options are shown in the example. For the Digital input in this example, a function is passed that will be called when the input makes a clean transition from High (1) to Low (0). For the Analog input, a conversion function is passed that takes the raw 0 - 4095 reading from the Analog pin and converts it to a voltage value. Either a lambda function, as shown here, or a normal multi-line `def` function name can be passed. 32 | 33 | After the Manager object is created, it automatically starts polling the input objects at the default rate of 480 Hz (a 2x or greater multiple of 60 Hz will help filter 60 Hz noise on Analog lines). Each input is read and processed according to the type of input it is. 34 | 35 | At any time, the current values of all the inputs can be read by executing the `values()` method on the Manager object. The return object is a Python dictionary with the added feature that values can be read as attributes of the object: 36 | 37 | ```Python 38 | # get all of the current input values 39 | vals = mgr.values() 40 | 41 | # two different ways of accessing the current counter value on pin Y2. 42 | print(vals['Y2']) 43 | print(vals.Y2) 44 | 45 | # for pins with descriptive names, you must use the descriptive name to access 46 | # the input value. Note that if the descriptive name contains spaces, 47 | # attribute access will not work, and instead, standard dictionary access 48 | # should be used: vals['descriptive name'] 49 | print(vals.button1) 50 | ``` 51 | 52 | I will be using the pyboard as a data acquistion peripheral for the Raspberry Pi. A simple way to transfer the input values to the Pi is to print the `vals` dictionary. When the Pi receives the string representation of the dictionary, a call to `eval()` will convert the string back into a dictionary. Here is a complete pyboard program for printing three input values out the USB port every second: 53 | 54 | ```Python 55 | import time 56 | from inputs import Manager, Digital, Counter, Analog 57 | 58 | mgr = Manager([Digital('Y1: button1'), 59 | Counter('Y2'), 60 | Analog('X1: sensor1_volts', convert_func=lambda x: x / 4095 * 3.3)]) 61 | 62 | # wait to fill the Analog buffer with readings before reading the first time. 63 | time.sleep(0.4) 64 | while True: 65 | vals = mgr.values() 66 | print(vals) 67 | time.sleep(1) 68 | ``` 69 | 70 | And here is a sample of the output from the program: 71 | 72 | ``` 73 | {'Y2': 0, 'button1': 1, 'sensor1_volts': 1.64033} 74 | {'Y2': 1, 'button1': 0, 'sensor1_volts': 1.639513} 75 | {'Y2': 2, 'button1': 0, 'sensor1_volts': 1.639983} 76 | {'Y2': 2, 'button1': 1, 'sensor1_volts': 1.639995} 77 | ``` 78 | 79 | If you want to access one individual input object, perhaps to read its value alone or change its descriptive name, you can do that through attribute access on the Manager object: 80 | 81 | ```Python 82 | # counter_obj will contain the full Counter object, not just its current value. 83 | counter_obj = mgr.Y2 84 | 85 | # print the counter's current value 86 | print(counter_obj.value()) 87 | ``` 88 | 89 | ## CPU Resources 90 | 91 | If you are setting up many input objects, you need to consider the amount of load you will put on the CPU. Each input takes roughly 80 usec to poll. If you have 20 inputs, total time consumed in the Timer interrupt routine polling the inputs will be 20 x 80 usec = 1600 usec, or 1.6 ms. The default polling rate is 2.1 ms, so the polling process will consumer 76% of your CPU resources. This may or may not be acceptable, depending on your application. 92 | 93 | ## Documentation of Classes 94 | 95 | This section documents the public interface to classes in the micropython-inputs library. 96 | 97 | ### Manager class 98 | 99 | This class holds the configured Input objects, periodically polls each input to update the input's value, and provides convenient ways to return the current value of inputs. 100 | 101 | **Manager**(inputs, timer_num=1, poll_freq=480) 102 | Arguments for instantiating a Manager object include: 103 | 104 | `inputs`: This is the list of input objects that the Manager will periodically poll and manage. 105 | 106 | `timer_num`: The number of the microcontroller Timer that will be used to generate an interrupt for polling the inputs. If `None` is passed, no automatic polling of inputs will occur, and you will need to periodically call the `service_inputs()` method of this object, perhaps from your own Timer interrupt routine. 107 | 108 | `poll_freq`: The frequency that will be used to poll the inputs in Hz. The default of 480 Hz will poll each sensor every 2.08 ms, which is a convenient value for debounce routines discussed later and analog averaging routines that sample across an exact number of 60 Hz cycles. 109 | 110 | **Manager.values**() 111 | This returns a snapshot of all of the current inputs. The return object is a Python dictionary with the added feature of being able to use an attribute to access a value as well as standard dictionary syntax. If `vals` is the object returned by this method, these two read access means are equivalent: `vals['X1']` and `vals.X1`. 112 | 113 | **Manager.service_inputs**() 114 | This routine reads and services all of the inputs and does not normally need to be used; it is generally called from a Timer interrupt internally set up by the Manager object. However, if this internal Timer is disabled by passing `None` to the `timer_num` constructor argument, a user can use their own Timer interrupt to periodically call this `service_inputs()` method. 115 | 116 | --- 117 | 118 | ### Methods Common to All Input Classes 119 | 120 | A number of methods are present on all the Input classes below, including: 121 | 122 | InputClass.**value**() 123 | This returns the current value for the input, including all processing that occurs for that input, e.g. debouncing, averaging. 124 | 125 | InputClass.**key_name**() 126 | This returns the pin name, e.g. 'X1', or, if a descriptive name for the input was provided, the descriptive name is returned instead. 127 | 128 | InputClass.**service_input**() 129 | If you are using one of the Input objects without use of the Manager object, this is the method that must be periodically called to update and process new input values. 130 | 131 | --- 132 | 133 | ### Digital class 134 | This class handles a digital input pin, providing debouncing and the ability to have callback functions that run when the pin changes state. 135 | 136 | **Digital**(pin_name, pull=pyb.Pin.PULL_UP, convert_func=None, 137 | stable_read_count=12, hl_func=None, lh_func=None) 138 | Arguments for instantiating a Digital object include: 139 | 140 | `pin_name`: The microcontroller pin name, such as 'X1' or 'Y2'. Optionally a descriptive name can be provided after a separating colon, e.g. 'X1: button1'. If the descriptive name is provided, it will be used instead of the pin name for accessing the input. 141 | 142 | `pull`: A pull up or pull down resistor can be enabled on the pin by setting this argument to one of the `pyb.Pin.PULL_` constants. 143 | 144 | `convert_func`: A Digital input normally reads a 0 or a 1 value. If you want these two values translated to something else (even a string), provide the name of a conversion function here, or enter a Python lambda function. 145 | 146 | `stable_read_count`: The digital input pin is read repeatedly at a rate determined by the `poll_freq` value passed to the Manager class. To debounce the input, a changed input value must remain the same for `stable_read_count` readings. If so, a state changed is deemed to occur. The default value is 12 readings in a row, and with the default polling frequency of 480 Hz (2.08 ms spacing), the reading must remain stable for about 25 ms to be considered valid. This argument must be set to a value of 30 stable readings or less. 147 | 148 | `hl_func`: A callback function that will be run when the input stably transitions from a 1 value to a 0 value. This callback function is run 149 | from inside a Timer interrupt routine, so do not consume much time in 150 | the function you provide, as it will block future interrupts. 151 | 152 | `lh_func`: A callback function that will be run when the input stably transitions from a 0 value to a 1 value. This callback function is run 153 | from inside a Timer interrupt routine, so do not consume much time in 154 | the function you provide, as it will block future interrupts. 155 | 156 | --- 157 | 158 | ### Counter class 159 | This class uses a digital input pin to count pulses. Transitions on the pin are debounced before counting. 160 | 161 | **Counter**(pin_name, pull=pyb.Pin.PULL_UP, convert_func=None, 162 | stable_read_count=4, edges=Counter.ONE_EDGE, reset_on_read=False, 163 | rollover=1073741823) 164 | 165 | Arguments for instantiating a Digital object include: 166 | 167 | `pin_name`: The microcontroller pin name, such as 'X1' or 'Y2'. Optionally a descriptive name can be provided after a separating colon, e.g. 'X1: button1'. If the descriptive name is provided, it will be used instead of the pin name for accessing the input. 168 | 169 | `pull`: A pull up or pull down resistor can be enabled on the pin by setting this argument to one of the `pyb.Pin.PULL_` constants. 170 | 171 | `convert_func`: The value returned by the Counter object is the count that has accumulated. If you want this count value translated to something else, provide the name of a conversion function here, or enter a Python lambda function. 172 | 173 | `stable_read_count`: The digital input pin is read repeatedly at a rate determined by the `poll_freq` value passed to the Manager class. To debounce the input, a changed input value must remain the same for `stable_read_count` readings. If so, a state changed is deemed to occur. The default value is 4 readings in a row, and with the default polling frequency of 480 Hz (2.08 ms spacing), the reading must remain stable for about 8.3 ms to be considered valid. Electronic generated pulses and reed switch pulses have little or no bounce, so a small stable read count can be used to increase the maximum pulse rate that can be read. This argument must be set to a value of 30 stable readings or less. 174 | 175 | `edges`: This argument determines whether the falling edge alone of the pulse is counted, or whether both the falling and rising edges are counted. It must be either the constant `Counter.ONE_EDGE` or the constant `Counter.BOTH_EDGES`. 176 | 177 | `reset_on_read`: If True, the count is reset to 0 every time the count value is read through use of the `value()` method. 178 | 179 | `rollover`: If the count reaches this value it will reset to 0. The default rollover value of 1073741823 is the largest that is possible. 180 | 181 | **Counter.reset_count**() 182 | This method will reset the count to zero. 183 | 184 | --- 185 | 186 | ### Analog class 187 | This class is used to read analog values on an analog input pin. A moving average of prior reads is calculated to help reduce the impacts of noise on the pin. The value() returned by the class is the 12 bit ADC count, ranging from 0 - 4095. 188 | 189 | **Analog**(pin_name, pull=pyb.Pin.PULL_NONE, convert_func=None, 190 | buffer_size=144,) 191 | The arguments for instantiating an Analog input object are: 192 | 193 | `pin_name`: The microcontroller pin name, such as 'X1' or 'Y2'. Optionally a descriptive name can be provided after a separating colon, e.g. 'X1: button1'. If the descriptive name is provided, it will be used instead of the pin name for accessing the input. 194 | 195 | `pull`: While not normally used with an analog channel, a pull up or pull down resistor can be enabled on the pin by setting this argument to one of the `pyb.Pin.PULL_` constants. 196 | 197 | `convert_func`: The value returned by the Analog object is the 12 bit ADC value, ranging from 0 - 4095. If you want this value translated to something else, provide the name of a conversion function here, or enter a Python lambda function. For example, to convert the ADC value into measured voltage, use `convert_func=lambda x: x / 4095 * 3.3`. 198 | 199 | `buffer_size`: This is the number of recent readings that you want averaged together to determine the final value returned by the `value()` method. At the default sampling rate of 480 Hz, 144 reading values take 0.3 seconds to complete and span 16 complete 60 Hz cycles. 200 | 201 | --- 202 | 203 | ### AnalogDeviation class 204 | The AnalogDeviation class measures the standard deviation of the signal on an analog input pin. The standard deviation is expressed in terms of the ADC units, which range from 0 to 4095 for the 12-bit converter. 205 | 206 | The instantiation arguments and methods are identical for this class and the `Analog` class. The only difference is that this class returns the standard deviation of the signal instead of the average value of the signal. 207 | --------------------------------------------------------------------------------