├── Code ├── i2c_lcd.py ├── i2c_lcd_test.py ├── lib │ ├── imu.py │ ├── lcd_api.py │ ├── pico_i2c_lcd.py │ ├── picozero.py │ └── vector3d.py ├── pico_74hc595.py ├── pico_BLE_LED.py ├── pico_BLE_recieve.py ├── pico_BLE_send.py ├── pico_LED_blink.py ├── pico_LED_blink1.py ├── pico_LED_brightness.py ├── pico_LED_toggle.py ├── pico_LM35.py ├── pico_MPU-6050.py ├── pico_OLED.py ├── pico_RTC.py ├── pico_buzzer.py ├── pico_gasSensor.py ├── pico_i2c_scanner.py ├── pico_inbuilt_tempSensor.py ├── pico_joystick.py ├── pico_keypad.py ├── pico_ldr.py ├── pico_ledPWM.py ├── pico_multithreading.py ├── pico_potentiometer.py ├── pico_pushButton.py ├── pico_rgbLED.py ├── pico_seven_segment_display.py ├── pico_thermistor.py ├── pico_tilt_sensor.py └── pico_ultrasonic_sensor.py └── README.md /Code/i2c_lcd.py: -------------------------------------------------------------------------------- 1 | from machine import I2C, Pin 2 | from time import sleep 3 | from pico_i2c_lcd import I2cLcd 4 | i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000) 5 | 6 | I2C_ADDR = i2c.scan()[0] 7 | lcd = I2cLcd(i2c, I2C_ADDR, 2, 16) 8 | 9 | # -------------- Test Area ------------------- # 10 | 11 | 12 | #lcd.backlight_off() 13 | #while True: 14 | msrg = 3 15 | 16 | lcd.putstr("Message: "+str(msrg)) 17 | #lcd.putstr("Placidlearn") 18 | 19 | #lcd.blink_cursor_on() 20 | #lcd.move_to(2,0) 21 | #lcd.putstr("Follow for more"+"\n") 22 | #lcd.putstr("") 23 | 24 | 25 | -------------------------------------------------------------------------------- /Code/i2c_lcd_test.py: -------------------------------------------------------------------------------- 1 | from machine import I2C, Pin 2 | from time import sleep 3 | from pico_i2c_lcd import I2cLcd 4 | i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000) 5 | 6 | I2C_ADDR = i2c.scan()[0] 7 | lcd = I2cLcd(i2c, I2C_ADDR, 2, 16) 8 | while True: 9 | print(I2C_ADDR) 10 | lcd.blink_cursor_on() 11 | lcd.putstr("I2C Address:"+str(I2C_ADDR)+"\n") 12 | lcd.putstr("Placidlearn") 13 | sleep(2) 14 | lcd.clear() 15 | lcd.putstr("I2C Address:"+str(hex(I2C_ADDR))+"\n") 16 | lcd.putstr("Placidlearn") 17 | sleep(2) 18 | lcd.blink_cursor_off() 19 | lcd.clear() 20 | lcd.putstr("Backlight Test") 21 | for i in range(10): 22 | lcd.backlight_on() 23 | sleep(0.2) 24 | lcd.backlight_off() 25 | sleep(0.2) 26 | lcd.backlight_on() 27 | lcd.hide_cursor() 28 | for i in range(20): 29 | lcd.putstr(str(i)) 30 | sleep(0.4) 31 | lcd.clear() 32 | -------------------------------------------------------------------------------- /Code/lib/imu.py: -------------------------------------------------------------------------------- 1 | # imu.py MicroPython driver for the InvenSense inertial measurement units 2 | # This is the base class 3 | # Adapted from Sebastian Plamauer's MPU9150 driver: 4 | # https://github.com/micropython-IMU/micropython-mpu9150.git 5 | # Authors Peter Hinch, Sebastian Plamauer 6 | # V0.2 17th May 2017 Platform independent: utime and machine replace pyb 7 | 8 | ''' 9 | mpu9250 is a micropython module for the InvenSense MPU9250 sensor. 10 | It measures acceleration, turn rate and the magnetic field in three axis. 11 | mpu9150 driver modified for the MPU9250 by Peter Hinch 12 | 13 | The MIT License (MIT) 14 | Copyright (c) 2014 Sebastian Plamauer, oeplse@gmail.com, Peter Hinch 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the "Software"), to deal 17 | in the Software without restriction, including without limitation the rights 18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | The above copyright notice and this permission notice shall be included in 22 | all copies or substantial portions of the Software. 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | THE SOFTWARE. 30 | ''' 31 | 32 | # User access is now by properties e.g. 33 | # myimu = MPU9250('X') 34 | # magx = myimu.mag.x 35 | # accelxyz = myimu.accel.xyz 36 | # Error handling: on code used for initialisation, abort with message 37 | # At runtime try to continue returning last good data value. We don't want aircraft 38 | # crashing. However if the I2C has crashed we're probably stuffed. 39 | 40 | from utime import sleep_ms 41 | from machine import I2C 42 | from vector3d import Vector3d 43 | 44 | 45 | class MPUException(OSError): 46 | ''' 47 | Exception for MPU devices 48 | ''' 49 | pass 50 | 51 | 52 | def bytes_toint(msb, lsb): 53 | ''' 54 | Convert two bytes to signed integer (big endian) 55 | for little endian reverse msb, lsb arguments 56 | Can be used in an interrupt handler 57 | ''' 58 | if not msb & 0x80: 59 | return msb << 8 | lsb # +ve 60 | return - (((msb ^ 255) << 8) | (lsb ^ 255) + 1) 61 | 62 | 63 | class MPU6050(object): 64 | ''' 65 | Module for InvenSense IMUs. Base class implements MPU6050 6DOF sensor, with 66 | features common to MPU9150 and MPU9250 9DOF sensors. 67 | ''' 68 | 69 | _I2Cerror = "I2C failure when communicating with IMU" 70 | _mpu_addr = (104, 105) # addresses of MPU9150/MPU6050. There can be two devices 71 | _chip_id = 104 72 | 73 | def __init__(self, side_str, device_addr=None, transposition=(0, 1, 2), scaling=(1, 1, 1)): 74 | 75 | self._accel = Vector3d(transposition, scaling, self._accel_callback) 76 | self._gyro = Vector3d(transposition, scaling, self._gyro_callback) 77 | self.buf1 = bytearray(1) # Pre-allocated buffers for reads: allows reads to 78 | self.buf2 = bytearray(2) # be done in interrupt handlers 79 | self.buf3 = bytearray(3) 80 | self.buf6 = bytearray(6) 81 | 82 | sleep_ms(200) # Ensure PSU and device have settled 83 | if isinstance(side_str, str): # Non-pyb targets may use other than X or Y 84 | self._mpu_i2c = I2C(side_str) 85 | elif hasattr(side_str, 'readfrom'): # Soft or hard I2C instance. See issue #3097 86 | self._mpu_i2c = side_str 87 | else: 88 | raise ValueError("Invalid I2C instance") 89 | 90 | if device_addr is None: 91 | devices = set(self._mpu_i2c.scan()) 92 | mpus = devices.intersection(set(self._mpu_addr)) 93 | number_of_mpus = len(mpus) 94 | if number_of_mpus == 0: 95 | raise MPUException("No MPU's detected") 96 | elif number_of_mpus == 1: 97 | self.mpu_addr = mpus.pop() 98 | else: 99 | raise ValueError("Two MPU's detected: must specify a device address") 100 | else: 101 | if device_addr not in (0, 1): 102 | raise ValueError('Device address must be 0 or 1') 103 | self.mpu_addr = self._mpu_addr[device_addr] 104 | 105 | self.chip_id # Test communication by reading chip_id: throws exception on error 106 | # Can communicate with chip. Set it up. 107 | self.wake() # wake it up 108 | self.passthrough = True # Enable mag access from main I2C bus 109 | self.accel_range = 0 # default to highest sensitivity 110 | self.gyro_range = 0 # Likewise for gyro 111 | 112 | # read from device 113 | def _read(self, buf, memaddr, addr): # addr = I2C device address, memaddr = memory location within the I2C device 114 | ''' 115 | Read bytes to pre-allocated buffer Caller traps OSError. 116 | ''' 117 | self._mpu_i2c.readfrom_mem_into(addr, memaddr, buf) 118 | 119 | # write to device 120 | def _write(self, data, memaddr, addr): 121 | ''' 122 | Perform a memory write. Caller should trap OSError. 123 | ''' 124 | self.buf1[0] = data 125 | self._mpu_i2c.writeto_mem(addr, memaddr, self.buf1) 126 | 127 | # wake 128 | def wake(self): 129 | ''' 130 | Wakes the device. 131 | ''' 132 | try: 133 | self._write(0x01, 0x6B, self.mpu_addr) # Use best clock source 134 | except OSError: 135 | raise MPUException(self._I2Cerror) 136 | return 'awake' 137 | 138 | # mode 139 | def sleep(self): 140 | ''' 141 | Sets the device to sleep mode. 142 | ''' 143 | try: 144 | self._write(0x40, 0x6B, self.mpu_addr) 145 | except OSError: 146 | raise MPUException(self._I2Cerror) 147 | return 'asleep' 148 | 149 | # chip_id 150 | @property 151 | def chip_id(self): 152 | ''' 153 | Returns Chip ID 154 | ''' 155 | try: 156 | self._read(self.buf1, 0x75, self.mpu_addr) 157 | except OSError: 158 | raise MPUException(self._I2Cerror) 159 | chip_id = int(self.buf1[0]) 160 | if chip_id != self._chip_id: 161 | raise ValueError('Bad chip ID retrieved: MPU communication failure') 162 | return chip_id 163 | 164 | @property 165 | def sensors(self): 166 | ''' 167 | returns sensor objects accel, gyro 168 | ''' 169 | return self._accel, self._gyro 170 | 171 | # get temperature 172 | @property 173 | def temperature(self): 174 | ''' 175 | Returns the temperature in degree C. 176 | ''' 177 | try: 178 | self._read(self.buf2, 0x41, self.mpu_addr) 179 | except OSError: 180 | raise MPUException(self._I2Cerror) 181 | return bytes_toint(self.buf2[0], self.buf2[1])/340 + 35 # I think 182 | 183 | # passthrough 184 | @property 185 | def passthrough(self): 186 | ''' 187 | Returns passthrough mode True or False 188 | ''' 189 | try: 190 | self._read(self.buf1, 0x37, self.mpu_addr) 191 | return self.buf1[0] & 0x02 > 0 192 | except OSError: 193 | raise MPUException(self._I2Cerror) 194 | 195 | @passthrough.setter 196 | def passthrough(self, mode): 197 | ''' 198 | Sets passthrough mode True or False 199 | ''' 200 | if type(mode) is bool: 201 | val = 2 if mode else 0 202 | try: 203 | self._write(val, 0x37, self.mpu_addr) # I think this is right. 204 | self._write(0x00, 0x6A, self.mpu_addr) 205 | except OSError: 206 | raise MPUException(self._I2Cerror) 207 | else: 208 | raise ValueError('pass either True or False') 209 | 210 | # sample rate. Not sure why you'd ever want to reduce this from the default. 211 | @property 212 | def sample_rate(self): 213 | ''' 214 | Get sample rate as per Register Map document section 4.4 215 | SAMPLE_RATE= Internal_Sample_Rate / (1 + rate) 216 | default rate is zero i.e. sample at internal rate. 217 | ''' 218 | try: 219 | self._read(self.buf1, 0x19, self.mpu_addr) 220 | return self.buf1[0] 221 | except OSError: 222 | raise MPUException(self._I2Cerror) 223 | 224 | @sample_rate.setter 225 | def sample_rate(self, rate): 226 | ''' 227 | Set sample rate as per Register Map document section 4.4 228 | ''' 229 | if rate < 0 or rate > 255: 230 | raise ValueError("Rate must be in range 0-255") 231 | try: 232 | self._write(rate, 0x19, self.mpu_addr) 233 | except OSError: 234 | raise MPUException(self._I2Cerror) 235 | 236 | # Low pass filters. Using the filter_range property of the MPU9250 is 237 | # harmless but gyro_filter_range is preferred and offers an extra setting. 238 | @property 239 | def filter_range(self): 240 | ''' 241 | Returns the gyro and temperature sensor low pass filter cutoff frequency 242 | Pass: 0 1 2 3 4 5 6 243 | Cutoff (Hz): 250 184 92 41 20 10 5 244 | Sample rate (KHz): 8 1 1 1 1 1 1 245 | ''' 246 | try: 247 | self._read(self.buf1, 0x1A, self.mpu_addr) 248 | res = self.buf1[0] & 7 249 | except OSError: 250 | raise MPUException(self._I2Cerror) 251 | return res 252 | 253 | @filter_range.setter 254 | def filter_range(self, filt): 255 | ''' 256 | Sets the gyro and temperature sensor low pass filter cutoff frequency 257 | Pass: 0 1 2 3 4 5 6 258 | Cutoff (Hz): 250 184 92 41 20 10 5 259 | Sample rate (KHz): 8 1 1 1 1 1 1 260 | ''' 261 | # set range 262 | if filt in range(7): 263 | try: 264 | self._write(filt, 0x1A, self.mpu_addr) 265 | except OSError: 266 | raise MPUException(self._I2Cerror) 267 | else: 268 | raise ValueError('Filter coefficient must be between 0 and 6') 269 | 270 | # accelerometer range 271 | @property 272 | def accel_range(self): 273 | ''' 274 | Accelerometer range 275 | Value: 0 1 2 3 276 | for range +/-: 2 4 8 16 g 277 | ''' 278 | try: 279 | self._read(self.buf1, 0x1C, self.mpu_addr) 280 | ari = self.buf1[0]//8 281 | except OSError: 282 | raise MPUException(self._I2Cerror) 283 | return ari 284 | 285 | @accel_range.setter 286 | def accel_range(self, accel_range): 287 | ''' 288 | Set accelerometer range 289 | Pass: 0 1 2 3 290 | for range +/-: 2 4 8 16 g 291 | ''' 292 | ar_bytes = (0x00, 0x08, 0x10, 0x18) 293 | if accel_range in range(len(ar_bytes)): 294 | try: 295 | self._write(ar_bytes[accel_range], 0x1C, self.mpu_addr) 296 | except OSError: 297 | raise MPUException(self._I2Cerror) 298 | else: 299 | raise ValueError('accel_range can only be 0, 1, 2 or 3') 300 | 301 | # gyroscope range 302 | @property 303 | def gyro_range(self): 304 | ''' 305 | Gyroscope range 306 | Value: 0 1 2 3 307 | for range +/-: 250 500 1000 2000 degrees/second 308 | ''' 309 | # set range 310 | try: 311 | self._read(self.buf1, 0x1B, self.mpu_addr) 312 | gri = self.buf1[0]//8 313 | except OSError: 314 | raise MPUException(self._I2Cerror) 315 | return gri 316 | 317 | @gyro_range.setter 318 | def gyro_range(self, gyro_range): 319 | ''' 320 | Set gyroscope range 321 | Pass: 0 1 2 3 322 | for range +/-: 250 500 1000 2000 degrees/second 323 | ''' 324 | gr_bytes = (0x00, 0x08, 0x10, 0x18) 325 | if gyro_range in range(len(gr_bytes)): 326 | try: 327 | self._write(gr_bytes[gyro_range], 0x1B, self.mpu_addr) # Sets fchoice = b11 which enables filter 328 | except OSError: 329 | raise MPUException(self._I2Cerror) 330 | else: 331 | raise ValueError('gyro_range can only be 0, 1, 2 or 3') 332 | 333 | # Accelerometer 334 | @property 335 | def accel(self): 336 | ''' 337 | Acceleremoter object 338 | ''' 339 | return self._accel 340 | 341 | def _accel_callback(self): 342 | ''' 343 | Update accelerometer Vector3d object 344 | ''' 345 | try: 346 | self._read(self.buf6, 0x3B, self.mpu_addr) 347 | except OSError: 348 | raise MPUException(self._I2Cerror) 349 | self._accel._ivector[0] = bytes_toint(self.buf6[0], self.buf6[1]) 350 | self._accel._ivector[1] = bytes_toint(self.buf6[2], self.buf6[3]) 351 | self._accel._ivector[2] = bytes_toint(self.buf6[4], self.buf6[5]) 352 | scale = (16384, 8192, 4096, 2048) 353 | self._accel._vector[0] = self._accel._ivector[0]/scale[self.accel_range] 354 | self._accel._vector[1] = self._accel._ivector[1]/scale[self.accel_range] 355 | self._accel._vector[2] = self._accel._ivector[2]/scale[self.accel_range] 356 | 357 | def get_accel_irq(self): 358 | ''' 359 | For use in interrupt handlers. Sets self._accel._ivector[] to signed 360 | unscaled integer accelerometer values 361 | ''' 362 | self._read(self.buf6, 0x3B, self.mpu_addr) 363 | self._accel._ivector[0] = bytes_toint(self.buf6[0], self.buf6[1]) 364 | self._accel._ivector[1] = bytes_toint(self.buf6[2], self.buf6[3]) 365 | self._accel._ivector[2] = bytes_toint(self.buf6[4], self.buf6[5]) 366 | 367 | # Gyro 368 | @property 369 | def gyro(self): 370 | ''' 371 | Gyroscope object 372 | ''' 373 | return self._gyro 374 | 375 | def _gyro_callback(self): 376 | ''' 377 | Update gyroscope Vector3d object 378 | ''' 379 | try: 380 | self._read(self.buf6, 0x43, self.mpu_addr) 381 | except OSError: 382 | raise MPUException(self._I2Cerror) 383 | self._gyro._ivector[0] = bytes_toint(self.buf6[0], self.buf6[1]) 384 | self._gyro._ivector[1] = bytes_toint(self.buf6[2], self.buf6[3]) 385 | self._gyro._ivector[2] = bytes_toint(self.buf6[4], self.buf6[5]) 386 | scale = (131, 65.5, 32.8, 16.4) 387 | self._gyro._vector[0] = self._gyro._ivector[0]/scale[self.gyro_range] 388 | self._gyro._vector[1] = self._gyro._ivector[1]/scale[self.gyro_range] 389 | self._gyro._vector[2] = self._gyro._ivector[2]/scale[self.gyro_range] 390 | 391 | def get_gyro_irq(self): 392 | ''' 393 | For use in interrupt handlers. Sets self._gyro._ivector[] to signed 394 | unscaled integer gyro values. Error trapping disallowed. 395 | ''' 396 | self._read(self.buf6, 0x43, self.mpu_addr) 397 | self._gyro._ivector[0] = bytes_toint(self.buf6[0], self.buf6[1]) 398 | self._gyro._ivector[1] = bytes_toint(self.buf6[2], self.buf6[3]) 399 | self._gyro._ivector[2] = bytes_toint(self.buf6[4], self.buf6[5]) -------------------------------------------------------------------------------- /Code/lib/lcd_api.py: -------------------------------------------------------------------------------- 1 | """Provides an API for talking to HD44780 compatible character LCDs.""" 2 | 3 | import time 4 | 5 | class LcdApi: 6 | """Implements the API for talking with HD44780 compatible character LCDs. 7 | This class only knows what commands to send to the LCD, and not how to get 8 | them to the LCD. 9 | 10 | It is expected that a derived class will implement the hal_xxx functions. 11 | """ 12 | 13 | # The following constant names were lifted from the avrlib lcd.h 14 | # header file, however, I changed the definitions from bit numbers 15 | # to bit masks. 16 | # 17 | # HD44780 LCD controller command set 18 | 19 | LCD_CLR = 0x01 # DB0: clear display 20 | LCD_HOME = 0x02 # DB1: return to home position 21 | 22 | LCD_ENTRY_MODE = 0x04 # DB2: set entry mode 23 | LCD_ENTRY_INC = 0x02 # --DB1: increment 24 | LCD_ENTRY_SHIFT = 0x01 # --DB0: shift 25 | 26 | LCD_ON_CTRL = 0x08 # DB3: turn lcd/cursor on 27 | LCD_ON_DISPLAY = 0x04 # --DB2: turn display on 28 | LCD_ON_CURSOR = 0x02 # --DB1: turn cursor on 29 | LCD_ON_BLINK = 0x01 # --DB0: blinking cursor 30 | 31 | LCD_MOVE = 0x10 # DB4: move cursor/display 32 | LCD_MOVE_DISP = 0x08 # --DB3: move display (0-> move cursor) 33 | LCD_MOVE_RIGHT = 0x04 # --DB2: move right (0-> left) 34 | 35 | LCD_FUNCTION = 0x20 # DB5: function set 36 | LCD_FUNCTION_8BIT = 0x10 # --DB4: set 8BIT mode (0->4BIT mode) 37 | LCD_FUNCTION_2LINES = 0x08 # --DB3: two lines (0->one line) 38 | LCD_FUNCTION_10DOTS = 0x04 # --DB2: 5x10 font (0->5x7 font) 39 | LCD_FUNCTION_RESET = 0x30 # See "Initializing by Instruction" section 40 | 41 | LCD_CGRAM = 0x40 # DB6: set CG RAM address 42 | LCD_DDRAM = 0x80 # DB7: set DD RAM address 43 | 44 | LCD_RS_CMD = 0 45 | LCD_RS_DATA = 1 46 | 47 | LCD_RW_WRITE = 0 48 | LCD_RW_READ = 1 49 | 50 | def __init__(self, num_lines, num_columns): 51 | self.num_lines = num_lines 52 | if self.num_lines > 4: 53 | self.num_lines = 4 54 | self.num_columns = num_columns 55 | if self.num_columns > 40: 56 | self.num_columns = 40 57 | self.cursor_x = 0 58 | self.cursor_y = 0 59 | self.implied_newline = False 60 | self.backlight = True 61 | self.display_off() 62 | self.backlight_on() 63 | self.clear() 64 | self.hal_write_command(self.LCD_ENTRY_MODE | self.LCD_ENTRY_INC) 65 | self.hide_cursor() 66 | self.display_on() 67 | 68 | def clear(self): 69 | """Clears the LCD display and moves the cursor to the top left 70 | corner. 71 | """ 72 | self.hal_write_command(self.LCD_CLR) 73 | self.hal_write_command(self.LCD_HOME) 74 | self.cursor_x = 0 75 | self.cursor_y = 0 76 | 77 | def show_cursor(self): 78 | """Causes the cursor to be made visible.""" 79 | self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY | 80 | self.LCD_ON_CURSOR) 81 | 82 | def hide_cursor(self): 83 | """Causes the cursor to be hidden.""" 84 | self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY) 85 | 86 | def blink_cursor_on(self): 87 | """Turns on the cursor, and makes it blink.""" 88 | self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY | 89 | self.LCD_ON_CURSOR | self.LCD_ON_BLINK) 90 | 91 | def blink_cursor_off(self): 92 | """Turns on the cursor, and makes it no blink (i.e. be solid).""" 93 | self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY | 94 | self.LCD_ON_CURSOR) 95 | 96 | def display_on(self): 97 | """Turns on (i.e. unblanks) the LCD.""" 98 | self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY) 99 | 100 | def display_off(self): 101 | """Turns off (i.e. blanks) the LCD.""" 102 | self.hal_write_command(self.LCD_ON_CTRL) 103 | 104 | def backlight_on(self): 105 | """Turns the backlight on. 106 | 107 | This isn't really an LCD command, but some modules have backlight 108 | controls, so this allows the hal to pass through the command. 109 | """ 110 | self.backlight = True 111 | self.hal_backlight_on() 112 | 113 | def backlight_off(self): 114 | """Turns the backlight off. 115 | 116 | This isn't really an LCD command, but some modules have backlight 117 | controls, so this allows the hal to pass through the command. 118 | """ 119 | self.backlight = False 120 | self.hal_backlight_off() 121 | 122 | def move_to(self, cursor_x, cursor_y): 123 | """Moves the cursor position to the indicated position. The cursor 124 | position is zero based (i.e. cursor_x == 0 indicates first column). 125 | """ 126 | self.cursor_x = cursor_x 127 | self.cursor_y = cursor_y 128 | addr = cursor_x & 0x3f 129 | if cursor_y & 1: 130 | addr += 0x40 # Lines 1 & 3 add 0x40 131 | if cursor_y & 2: # Lines 2 & 3 add number of columns 132 | addr += self.num_columns 133 | self.hal_write_command(self.LCD_DDRAM | addr) 134 | 135 | def putchar(self, char): 136 | """Writes the indicated character to the LCD at the current cursor 137 | position, and advances the cursor by one position. 138 | """ 139 | if char == '\n': 140 | if self.implied_newline: 141 | # self.implied_newline means we advanced due to a wraparound, 142 | # so if we get a newline right after that we ignore it. 143 | self.implied_newline = False 144 | else: 145 | self.cursor_x = self.num_columns 146 | else: 147 | self.hal_write_data(ord(char)) 148 | self.cursor_x += 1 149 | if self.cursor_x >= self.num_columns: 150 | self.cursor_x = 0 151 | self.cursor_y += 1 152 | self.implied_newline = (char != '\n') 153 | if self.cursor_y >= self.num_lines: 154 | self.cursor_y = 0 155 | self.move_to(self.cursor_x, self.cursor_y) 156 | 157 | def putstr(self, string): 158 | """Write the indicated string to the LCD at the current cursor 159 | position and advances the cursor position appropriately. 160 | """ 161 | for char in string: 162 | self.putchar(char) 163 | 164 | def custom_char(self, location, charmap): 165 | """Write a character to one of the 8 CGRAM locations, available 166 | as chr(0) through chr(7). 167 | """ 168 | location &= 0x7 169 | self.hal_write_command(self.LCD_CGRAM | (location << 3)) 170 | self.hal_sleep_us(40) 171 | for i in range(8): 172 | self.hal_write_data(charmap[i]) 173 | self.hal_sleep_us(40) 174 | self.move_to(self.cursor_x, self.cursor_y) 175 | 176 | def hal_backlight_on(self): 177 | """Allows the hal layer to turn the backlight on. 178 | 179 | If desired, a derived HAL class will implement this function. 180 | """ 181 | pass 182 | 183 | def hal_backlight_off(self): 184 | """Allows the hal layer to turn the backlight off. 185 | 186 | If desired, a derived HAL class will implement this function. 187 | """ 188 | pass 189 | 190 | def hal_write_command(self, cmd): 191 | """Write a command to the LCD. 192 | 193 | It is expected that a derived HAL class will implement this 194 | function. 195 | """ 196 | raise NotImplementedError 197 | 198 | def hal_write_data(self, data): 199 | """Write data to the LCD. 200 | 201 | It is expected that a derived HAL class will implement this 202 | function. 203 | """ 204 | raise NotImplementedError 205 | 206 | # This is a default implementation of hal_sleep_us which is suitable 207 | # for most micropython implementations. For platforms which don't 208 | # support `time.sleep_us()` they should provide their own implementation 209 | # of hal_sleep_us in their hal layer and it will be used instead. 210 | def hal_sleep_us(self, usecs): 211 | """Sleep for some time (given in microseconds).""" 212 | time.sleep_us(usecs) # NOTE this is not part of Standard Python library, specific hal layers will need to override this -------------------------------------------------------------------------------- /Code/lib/pico_i2c_lcd.py: -------------------------------------------------------------------------------- 1 | import utime 2 | import gc 3 | 4 | from lcd_api import LcdApi 5 | from machine import I2C 6 | 7 | # PCF8574 pin definitions 8 | MASK_RS = 0x01 # P0 9 | MASK_RW = 0x02 # P1 10 | MASK_E = 0x04 # P2 11 | 12 | SHIFT_BACKLIGHT = 3 # P3 13 | SHIFT_DATA = 4 # P4-P7 14 | 15 | class I2cLcd(LcdApi): 16 | 17 | #Implements a HD44780 character LCD connected via PCF8574 on I2C 18 | 19 | def __init__(self, i2c, i2c_addr, num_lines, num_columns): 20 | self.i2c = i2c 21 | self.i2c_addr = i2c_addr 22 | self.i2c.writeto(self.i2c_addr, bytes([0])) 23 | utime.sleep_ms(20) # Allow LCD time to powerup 24 | # Send reset 3 times 25 | self.hal_write_init_nibble(self.LCD_FUNCTION_RESET) 26 | utime.sleep_ms(5) # Need to delay at least 4.1 msec 27 | self.hal_write_init_nibble(self.LCD_FUNCTION_RESET) 28 | utime.sleep_ms(1) 29 | self.hal_write_init_nibble(self.LCD_FUNCTION_RESET) 30 | utime.sleep_ms(1) 31 | # Put LCD into 4-bit mode 32 | self.hal_write_init_nibble(self.LCD_FUNCTION) 33 | utime.sleep_ms(1) 34 | LcdApi.__init__(self, num_lines, num_columns) 35 | cmd = self.LCD_FUNCTION 36 | if num_lines > 1: 37 | cmd |= self.LCD_FUNCTION_2LINES 38 | self.hal_write_command(cmd) 39 | gc.collect() 40 | 41 | def hal_write_init_nibble(self, nibble): 42 | # Writes an initialization nibble to the LCD. 43 | # This particular function is only used during initialization. 44 | byte = ((nibble >> 4) & 0x0f) << SHIFT_DATA 45 | self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) 46 | self.i2c.writeto(self.i2c_addr, bytes([byte])) 47 | gc.collect() 48 | 49 | def hal_backlight_on(self): 50 | # Allows the hal layer to turn the backlight on 51 | self.i2c.writeto(self.i2c_addr, bytes([1 << SHIFT_BACKLIGHT])) 52 | gc.collect() 53 | 54 | def hal_backlight_off(self): 55 | #Allows the hal layer to turn the backlight off 56 | self.i2c.writeto(self.i2c_addr, bytes([0])) 57 | gc.collect() 58 | 59 | def hal_write_command(self, cmd): 60 | # Write a command to the LCD. Data is latched on the falling edge of E. 61 | byte = ((self.backlight << SHIFT_BACKLIGHT) | 62 | (((cmd >> 4) & 0x0f) << SHIFT_DATA)) 63 | self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) 64 | self.i2c.writeto(self.i2c_addr, bytes([byte])) 65 | byte = ((self.backlight << SHIFT_BACKLIGHT) | 66 | ((cmd & 0x0f) << SHIFT_DATA)) 67 | self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) 68 | self.i2c.writeto(self.i2c_addr, bytes([byte])) 69 | if cmd <= 3: 70 | # The home and clear commands require a worst case delay of 4.1 msec 71 | utime.sleep_ms(5) 72 | gc.collect() 73 | 74 | def hal_write_data(self, data): 75 | # Write data to the LCD. Data is latched on the falling edge of E. 76 | byte = (MASK_RS | 77 | (self.backlight << SHIFT_BACKLIGHT) | 78 | (((data >> 4) & 0x0f) << SHIFT_DATA)) 79 | self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) 80 | self.i2c.writeto(self.i2c_addr, bytes([byte])) 81 | byte = (MASK_RS | 82 | (self.backlight << SHIFT_BACKLIGHT) | 83 | ((data & 0x0f) << SHIFT_DATA)) 84 | self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) 85 | self.i2c.writeto(self.i2c_addr, bytes([byte])) 86 | gc.collect() -------------------------------------------------------------------------------- /Code/lib/picozero.py: -------------------------------------------------------------------------------- 1 | from machine import Pin, PWM, Timer, ADC 2 | from micropython import schedule 3 | from time import ticks_ms, ticks_us, sleep 4 | 5 | ############################################################################### 6 | # EXCEPTIONS 7 | ############################################################################### 8 | 9 | class PWMChannelAlreadyInUse(Exception): 10 | pass 11 | 12 | class EventFailedScheduleQueueFull(Exception): 13 | pass 14 | 15 | ############################################################################### 16 | # SUPPORTING CLASSES 17 | ############################################################################### 18 | 19 | def clamp(n, low, high): return max(low, min(n, high)) 20 | 21 | def pinout(output=True): 22 | """ 23 | Returns a textual representation of the Raspberry Pi pico pins and functions. 24 | 25 | :param bool output: 26 | If :data:`True` (the default) the pinout will be "printed". 27 | 28 | """ 29 | pins = """ ---usb--- 30 | GP0 1 |o o| -1 VBUS 31 | GP1 2 |o o| -2 VSYS 32 | GND 3 |o o| -3 GND 33 | GP2 4 |o o| -4 3V3_EN 34 | GP3 5 |o o| -5 3V3(OUT) 35 | GP4 6 |o o| -6 ADC_VREF 36 | GP5 7 |o o| -7 GP28 ADC2 37 | GND 8 |o o| -8 GND AGND 38 | GP6 9 |o o| -9 GP27 ADC1 39 | GP7 10 |o o| -10 GP26 ADC0 40 | GP8 11 |o o| -11 RUN 41 | GP9 12 |o o| -12 GP22 42 | GND 13 |o o| -13 GND 43 | GP10 14 |o o| -14 GP21 44 | GP11 15 |o o| -15 GP20 45 | GP12 16 |o o| -16 GP19 46 | GP13 17 |o o| -17 GP18 47 | GND 18 |o o| -18 GND 48 | GP14 19 |o o| -19 GP17 49 | GP15 20 |o o| -20 GP16 50 | ---------""" 51 | 52 | if output: 53 | print(pins) 54 | return pins 55 | 56 | class PinMixin: 57 | """ 58 | Mixin used by devices that have a single pin number. 59 | """ 60 | 61 | @property 62 | def pin(self): 63 | """ 64 | Returns the pin number used by the device. 65 | """ 66 | return self._pin_num 67 | 68 | def __str__(self): 69 | return "{} (pin {})".format(self.__class__.__name__, self._pin_num) 70 | 71 | class PinsMixin: 72 | """ 73 | Mixin used by devices that use multiple pins. 74 | """ 75 | 76 | @property 77 | def pins(self): 78 | """ 79 | Returns a tuple of pins used by the device. 80 | """ 81 | return self._pin_nums 82 | 83 | def __str__(self): 84 | return "{} (pins - {})".format(self.__class__.__name__, self._pin_nums) 85 | 86 | class ValueChange: 87 | """ 88 | Internal class to control the value of an output device. 89 | 90 | :param OutputDevice output_device: 91 | The OutputDevice object you wish to change the value of. 92 | 93 | :param generator: 94 | A generator function that yields a 2d list of 95 | ((value, seconds), *). 96 | 97 | The output_device's value will be set for the number of 98 | seconds. 99 | 100 | :param int n: 101 | The number of times to repeat the sequence. If None, the 102 | sequence will repeat forever. 103 | 104 | :param bool wait: 105 | If True the ValueChange object will block (wait) until 106 | the sequence has completed. 107 | """ 108 | def __init__(self, output_device, generator, n, wait): 109 | self._output_device = output_device 110 | self._generator = generator 111 | self._n = n 112 | 113 | self._gen = self._generator() 114 | 115 | self._timer = Timer() 116 | self._running = True 117 | self._wait = wait 118 | 119 | self._set_value() 120 | 121 | def _set_value(self, timer_obj=None): 122 | if self._wait: 123 | # wait for the exection to end 124 | next_seq = self._get_value() 125 | while next_seq is not None: 126 | value, seconds = next_seq 127 | 128 | self._output_device._write(value) 129 | sleep(seconds) 130 | 131 | next_seq = self._get_value() 132 | 133 | else: 134 | # run the timer 135 | next_seq = self._get_value() 136 | if next_seq is not None: 137 | value, seconds = next_seq 138 | 139 | self._output_device._write(value) 140 | self._timer.init(period=int(seconds * 1000), mode=Timer.ONE_SHOT, callback=self._set_value) 141 | 142 | if next_seq is None: 143 | # the sequence has finished, turn the device off 144 | self._output_device.off() 145 | self._running = False 146 | 147 | def _get_value(self): 148 | try: 149 | return next(self._gen) 150 | 151 | except StopIteration: 152 | 153 | self._n = self._n - 1 if self._n is not None else None 154 | if self._n == 0: 155 | # it's the end, return None 156 | return None 157 | else: 158 | # recreate the generator and start again 159 | self._gen = self._generator() 160 | return next(self._gen) 161 | 162 | def stop(self): 163 | """ 164 | Stops the ValueChange object running. 165 | """ 166 | self._running = False 167 | self._timer.deinit() 168 | 169 | ############################################################################### 170 | # OUTPUT DEVICES 171 | ############################################################################### 172 | 173 | class OutputDevice: 174 | """ 175 | Base class for output devices. 176 | """ 177 | def __init__(self, active_high=True, initial_value=False): 178 | self.active_high = active_high 179 | if initial_value is not None: 180 | self._write(initial_value) 181 | self._value_changer = None 182 | 183 | @property 184 | def active_high(self): 185 | """ 186 | Sets or returns the active_high property. If :data:`True`, the 187 | :meth:`on` method will set the Pin to HIGH. If :data:`False`, 188 | the :meth:`on` method will set the Pin to LOW (the :meth:`off` method 189 | always does the opposite). 190 | """ 191 | return self._active_state 192 | 193 | @active_high.setter 194 | def active_high(self, value): 195 | self._active_state = True if value else False 196 | self._inactive_state = False if value else True 197 | 198 | @property 199 | def value(self): 200 | """ 201 | Sets or returns a value representing the state of the device: 1 is on, 0 is off. 202 | """ 203 | return self._read() 204 | 205 | @value.setter 206 | def value(self, value): 207 | self._stop_change() 208 | self._write(value) 209 | 210 | def on(self, value=1, t=None, wait=False): 211 | """ 212 | Turns the device on. 213 | 214 | :param float value: 215 | The value to set when turning on. Defaults to 1. 216 | 217 | :param float t: 218 | The time in seconds that the device should be on. If None is 219 | specified, the device will stay on. The default is None. 220 | 221 | :param bool wait: 222 | If True, the method will block until the time `t` has expired. 223 | If False, the method will return and the device will turn on in 224 | the background. Defaults to False. Only effective if `t` is not 225 | None. 226 | """ 227 | if t is None: 228 | self.value = value 229 | else: 230 | self._start_change(lambda : iter([(value, t), ]), 1, wait) 231 | 232 | def off(self): 233 | """ 234 | Turns the device off. 235 | """ 236 | self.value = 0 237 | 238 | @property 239 | def is_active(self): 240 | """ 241 | Returns :data:`True` if the device is on. 242 | """ 243 | return bool(self.value) 244 | 245 | def toggle(self): 246 | """ 247 | If the device is off, turn it on. If it is on, turn it off. 248 | """ 249 | if self.is_active: 250 | self.off() 251 | else: 252 | self.on() 253 | 254 | def blink(self, on_time=1, off_time=None, n=None, wait=False): 255 | """ 256 | Makes the device turn on and off repeatedly. 257 | 258 | :param float on_time: 259 | The length of time in seconds that the device will be on. Defaults to 1. 260 | 261 | :param float off_time: 262 | The length of time in seconds that the device will be off. If `None`, 263 | it will be the same as ``on_time``. Defaults to `None`. 264 | 265 | :param int n: 266 | The number of times to repeat the blink operation. If None is 267 | specified, the device will continue blinking forever. The default 268 | is None. 269 | 270 | :param bool wait: 271 | If True, the method will block until the device stops turning on and off. 272 | If False, the method will return and the device will turn on and off in 273 | the background. Defaults to False. 274 | """ 275 | off_time = on_time if off_time is None else off_time 276 | 277 | self.off() 278 | 279 | # is there anything to change? 280 | if on_time > 0 or off_time > 0: 281 | self._start_change(lambda : iter([(1,on_time), (0,off_time)]), n, wait) 282 | 283 | def _start_change(self, generator, n, wait): 284 | self._value_changer = ValueChange(self, generator, n, wait) 285 | 286 | def _stop_change(self): 287 | if self._value_changer is not None: 288 | self._value_changer.stop() 289 | self._value_changer = None 290 | 291 | def close(self): 292 | """ 293 | Turns the device off. 294 | """ 295 | self.value = 0 296 | 297 | class DigitalOutputDevice(OutputDevice, PinMixin): 298 | """ 299 | Represents a device driven by a digital pin. 300 | 301 | :param int pin: 302 | The pin that the device is connected to. 303 | 304 | :param bool active_high: 305 | If :data:`True` (the default), the :meth:`on` method will set the Pin 306 | to HIGH. If :data:`False`, the :meth:`on` method will set the Pin to 307 | LOW (the :meth:`off` method always does the opposite). 308 | 309 | :param bool initial_value: 310 | If :data:`False` (the default), the LED will be off initially. If 311 | :data:`True`, the LED will be switched on initially. 312 | """ 313 | def __init__(self, pin, active_high=True, initial_value=False): 314 | self._pin_num = pin 315 | self._pin = Pin(pin, Pin.OUT) 316 | super().__init__(active_high, initial_value) 317 | 318 | def _value_to_state(self, value): 319 | return int(self._active_state if value else self._inactive_state) 320 | 321 | def _state_to_value(self, state): 322 | return int(bool(state) == self._active_state) 323 | 324 | def _read(self): 325 | return self._state_to_value(self._pin.value()) 326 | 327 | def _write(self, value): 328 | self._pin.value(self._value_to_state(value)) 329 | 330 | def close(self): 331 | """ 332 | Closes the device and turns the device off. Once closed, the device 333 | can no longer be used. 334 | """ 335 | super().close() 336 | self._pin = None 337 | 338 | class DigitalLED(DigitalOutputDevice): 339 | """ 340 | Represents a simple LED, which can be switched on and off. 341 | 342 | :param int pin: 343 | The pin that the device is connected to. 344 | 345 | :param bool active_high: 346 | If :data:`True` (the default), the :meth:`on` method will set the Pin 347 | to HIGH. If :data:`False`, the :meth:`on` method will set the Pin to 348 | LOW (the :meth:`off` method always does the opposite). 349 | 350 | :param bool initial_value: 351 | If :data:`False` (the default), the LED will be off initially. If 352 | :data:`True`, the LED will be switched on initially. 353 | """ 354 | pass 355 | 356 | DigitalLED.is_lit = DigitalLED.is_active 357 | 358 | class Buzzer(DigitalOutputDevice): 359 | """ 360 | Represents an active or passive buzzer, which can be turned on or off. 361 | 362 | :param int pin: 363 | The pin that the device is connected to. 364 | 365 | :param bool active_high: 366 | If :data:`True` (the default), the :meth:`on` method will set the Pin 367 | to HIGH. If :data:`False`, the :meth:`on` method will set the Pin to 368 | LOW (the :meth:`off` method always does the opposite). 369 | 370 | :param bool initial_value: 371 | If :data:`False` (the default), the Buzzer will be off initially. If 372 | :data:`True`, the Buzzer will be switched on initially. 373 | """ 374 | pass 375 | 376 | Buzzer.beep = Buzzer.blink 377 | 378 | class PWMOutputDevice(OutputDevice, PinMixin): 379 | """ 380 | Represents a device driven by a PWM pin. 381 | 382 | :param int pin: 383 | The pin that the device is connected to. 384 | 385 | :param int freq: 386 | The frequency of the PWM signal in hertz. Defaults to 100. 387 | 388 | :param int duty_factor: 389 | The duty factor of the PWM signal. This is a value between 0 and 65535. 390 | Defaults to 65535. 391 | 392 | :param bool active_high: 393 | If :data:`True` (the default), the :meth:`on` method will set the Pin 394 | to HIGH. If :data:`False`, the :meth:`on` method will set the Pin to 395 | LOW (the :meth:`off` method always does the opposite). 396 | 397 | :param bool initial_value: 398 | If :data:`False` (the default), the LED will be off initially. If 399 | :data:`True`, the LED will be switched on initially. 400 | """ 401 | 402 | PIN_TO_PWM_CHANNEL = ["0A","0B","1A","1B","2A","2B","3A","3B","4A","4B","5A","5B","6A","6B","7A","7B","0A","0B","1A","1B","2A","2B","3A","3B","4A","4B","5A","5B","6A","6B"] 403 | _channels_used = {} 404 | 405 | def __init__(self, pin, freq=100, duty_factor=65535, active_high=True, initial_value=False): 406 | self._check_pwm_channel(pin) 407 | self._pin_num = pin 408 | self._duty_factor = duty_factor 409 | self._pwm = PWM(Pin(pin)) 410 | self._pwm.freq(freq) 411 | super().__init__(active_high, initial_value) 412 | 413 | def _check_pwm_channel(self, pin_num): 414 | channel = PWMOutputDevice.PIN_TO_PWM_CHANNEL[pin_num] 415 | if channel in PWMOutputDevice._channels_used.keys(): 416 | raise PWMChannelAlreadyInUse( 417 | "PWM channel {} is already in use by {}. Use a different pin".format( 418 | channel, 419 | str(PWMOutputDevice._channels_used[channel]) 420 | ) 421 | ) 422 | else: 423 | PWMOutputDevice._channels_used[channel] = self 424 | 425 | def _state_to_value(self, state): 426 | return (state if self.active_high else self._duty_factor - state) / self._duty_factor 427 | 428 | def _value_to_state(self, value): 429 | return int(self._duty_factor * (value if self.active_high else 1 - value)) 430 | 431 | def _read(self): 432 | return self._state_to_value(self._pwm.duty_u16()) 433 | 434 | def _write(self, value): 435 | self._pwm.duty_u16(self._value_to_state(value)) 436 | 437 | @property 438 | def is_active(self): 439 | """ 440 | Returns :data:`True` if the device is on. 441 | """ 442 | return self.value != 0 443 | 444 | @property 445 | def freq(self): 446 | """ 447 | Returns the current frequency of the device. 448 | """ 449 | return self._pwm.freq() 450 | 451 | @freq.setter 452 | def freq(self, freq): 453 | """ 454 | Sets the frequency of the device. 455 | """ 456 | self._pwm.freq(freq) 457 | 458 | def blink(self, on_time=1, off_time=None, n=None, wait=False, fade_in_time=0, fade_out_time=None, fps=25): 459 | """ 460 | Makes the device turn on and off repeatedly. 461 | 462 | :param float on_time: 463 | The length of time in seconds the device will be on. Defaults to 1. 464 | 465 | :param float off_time: 466 | The length of time in seconds the device will be off. If `None`, 467 | it will be the same as ``on_time``. Defaults to `None`. 468 | 469 | :param int n: 470 | The number of times to repeat the blink operation. If `None`, the 471 | device will continue blinking forever. The default is `None`. 472 | 473 | :param bool wait: 474 | If True, the method will block until the LED stops blinking. If False, 475 | the method will return and the LED will blink in the background. 476 | Defaults to False. 477 | 478 | :param float fade_in_time: 479 | The length of time in seconds to spend fading in. Defaults to 0. 480 | 481 | :param float fade_out_time: 482 | The length of time in seconds to spend fading out. If `None`, 483 | it will be the same as ``fade_in_time``. Defaults to `None`. 484 | 485 | :param int fps: 486 | The frames per second that will be used to calculate the number of 487 | steps between off/on states when fading. Defaults to 25. 488 | """ 489 | self.off() 490 | 491 | off_time = on_time if off_time is None else off_time 492 | fade_out_time = fade_in_time if fade_out_time is None else fade_out_time 493 | 494 | def blink_generator(): 495 | if fade_in_time > 0: 496 | for s in [ 497 | (i * (1 / fps) / fade_in_time, 1 / fps) 498 | for i in range(int(fps * fade_in_time)) 499 | ]: 500 | yield s 501 | 502 | if on_time > 0: 503 | yield (1, on_time) 504 | 505 | if fade_out_time > 0: 506 | for s in [ 507 | (1 - (i * (1 / fps) / fade_out_time), 1 / fps) 508 | for i in range(int(fps * fade_out_time)) 509 | ]: 510 | yield s 511 | 512 | if off_time > 0: 513 | yield (0, off_time) 514 | 515 | # is there anything to change? 516 | if on_time > 0 or off_time > 0 or fade_in_time > 0 or fade_out_time > 0: 517 | self._start_change(blink_generator, n, wait) 518 | 519 | def pulse(self, fade_in_time=1, fade_out_time=None, n=None, wait=False, fps=25): 520 | """ 521 | Makes the device pulse on and off repeatedly. 522 | 523 | :param float fade_in_time: 524 | The length of time in seconds that the device will take to turn on. 525 | Defaults to 1. 526 | 527 | :param float fade_out_time: 528 | The length of time in seconds that the device will take to turn off. 529 | Defaults to 1. 530 | 531 | :param int fps: 532 | The frames per second that will be used to calculate the number of 533 | steps between off/on states. Defaults to 25. 534 | 535 | :param int n: 536 | The number of times to pulse the LED. If None, the LED will pulse 537 | forever. Defaults to None. 538 | 539 | :param bool wait: 540 | If True, the method will block until the LED stops pulsing. If False, 541 | the method will return and the LED will pulse in the background. 542 | Defaults to False. 543 | """ 544 | self.blink(on_time=0, off_time=0, fade_in_time=fade_in_time, fade_out_time=fade_out_time, n=n, wait=wait, fps=fps) 545 | 546 | def close(self): 547 | """ 548 | Closes the device and turns the device off. Once closed, the device 549 | can no longer be used. 550 | """ 551 | super().close() 552 | del PWMOutputDevice._channels_used[ 553 | PWMOutputDevice.PIN_TO_PWM_CHANNEL[self._pin_num] 554 | ] 555 | self._pwm.deinit() 556 | self._pwm = None 557 | 558 | class PWMLED(PWMOutputDevice): 559 | """ 560 | Represents an LED driven by a PWM pin; the brightness of the LED can be changed. 561 | 562 | :param int pin: 563 | The pin that the device is connected to. 564 | 565 | :param int freq: 566 | The frequency of the PWM signal in hertz. Defaults to 100. 567 | 568 | :param int duty_factor: 569 | The duty factor of the PWM signal. This is a value between 0 and 65535. 570 | Defaults to 65535. 571 | 572 | :param bool active_high: 573 | If :data:`True` (the default), the :meth:`on` method will set the Pin 574 | to HIGH. If :data:`False`, the :meth:`on` method will set the Pin to 575 | LOW (the :meth:`off` method always does the opposite). 576 | 577 | :param bool initial_value: 578 | If :data:`False` (the default), the LED will be off initially. If 579 | :data:`True`, the LED will be switched on initially. 580 | """ 581 | PWMLED.brightness = PWMLED.value 582 | 583 | def LED(pin, pwm=True, active_high=True, initial_value=False): 584 | """ 585 | Returns an instance of :class:`DigitalLED` or :class:`PWMLED` depending on 586 | the value of the `pwm` parameter. 587 | 588 | :: 589 | 590 | from picozero import LED 591 | 592 | my_pwm_led = LED(1) 593 | 594 | my_digital_led = LED(2, pwm=False) 595 | 596 | :param int pin: 597 | The pin that the device is connected to. 598 | 599 | :param int pin: 600 | If `pwm` is :data:`True` (the default), a :class:`PWMLED` will be 601 | returned. If `pwm` is :data:`False`, a :class:`DigitalLED` will be 602 | returned. A :class:`PWMLED` can control the brightness of the LED but 603 | uses 1 PWM channel. 604 | 605 | :param bool active_high: 606 | If :data:`True` (the default), the :meth:`on` method will set the Pin 607 | to HIGH. If :data:`False`, the :meth:`on` method will set the Pin to 608 | LOW (the :meth:`off` method always does the opposite). 609 | 610 | :param bool initial_value: 611 | If :data:`False` (the default), the device will be off initially. If 612 | :data:`True`, the device will be switched on initially. 613 | """ 614 | if pwm: 615 | return PWMLED( 616 | pin=pin, 617 | active_high=active_high, 618 | initial_value=initial_value) 619 | else: 620 | return DigitalLED( 621 | pin=pin, 622 | active_high=active_high, 623 | initial_value=initial_value) 624 | 625 | try: 626 | pico_led = LED("LED", pwm=False) 627 | except TypeError: 628 | # older version of micropython before "LED" was supported 629 | pico_led = LED(25, pwm=False) 630 | 631 | class PWMBuzzer(PWMOutputDevice): 632 | """ 633 | Represents a passive buzzer driven by a PWM pin; the volume of the buzzer can be changed. 634 | 635 | :param int pin: 636 | The pin that the buzzer is connected to. 637 | 638 | :param int freq: 639 | The frequency of the PWM signal in hertz. Defaults to 440. 640 | 641 | :param int duty_factor: 642 | The duty factor of the PWM signal. This is a value between 0 and 65535. 643 | Defaults to 1023. 644 | 645 | :param bool active_high: 646 | If :data:`True` (the default), the :meth:`on` method will set the Pin 647 | to HIGH. If :data:`False`, the :meth:`on` method will set the Pin to 648 | LOW (the :meth:`off` method always does the opposite). 649 | 650 | :param bool initial_value: 651 | If :data:`False` (the default), the buzzer will be off initially. If 652 | :data:`True`, the buzzer will be switched on initially. 653 | """ 654 | def __init__(self, pin, freq=440, duty_factor=1023, active_high=True, initial_value=False): 655 | super().__init__(pin, freq, duty_factor, active_high, initial_value) 656 | 657 | PWMBuzzer.volume = PWMBuzzer.value 658 | PWMBuzzer.beep = PWMBuzzer.blink 659 | 660 | class Speaker(OutputDevice, PinMixin): 661 | """ 662 | Represents a speaker driven by a PWM pin. 663 | 664 | :param int pin: 665 | The pin that the speaker is connected to. 666 | 667 | :param int initial_freq: 668 | The initial frequency of the PWM signal in hertz. Defaults to 440. 669 | 670 | :param int initial_volume: 671 | The initial volume of the PWM signal. This is a value between 0 and 672 | 1. Defaults to 0. 673 | 674 | :param int duty_factor: 675 | The duty factor of the PWM signal. This is a value between 0 and 65535. 676 | Defaults to 1023. 677 | 678 | :param bool active_high: 679 | If :data:`True` (the default), the :meth:`on` method will set the Pin 680 | to HIGH. If :data:`False`, the :meth:`on` method will set the Pin to 681 | LOW (the :meth:`off` method always does the opposite). 682 | """ 683 | NOTES = { 684 | 'b0': 31, 'c1': 33, 'c#1': 35, 'd1': 37, 'd#1': 39, 'e1': 41, 'f1': 44, 'f#1': 46, 'g1': 49,'g#1': 52, 'a1': 55, 685 | 'a#1': 58, 'b1': 62, 'c2': 65, 'c#2': 69, 'd2': 73, 'd#2': 78, 686 | 'e2': 82, 'f2': 87, 'f#2': 93, 'g2': 98, 'g#2': 104, 'a2': 110, 'a#2': 117, 'b2': 123, 687 | 'c3': 131, 'c#3': 139, 'd3': 147, 'd#3': 156, 'e3': 165, 'f3': 175, 'f#3': 185, 'g3': 196, 'g#3': 208, 'a3': 220, 'a#3': 233, 'b3': 247, 688 | 'c4': 262, 'c#4': 277, 'd4': 294, 'd#4': 311, 'e4': 330, 'f4': 349, 'f#4': 370, 'g4': 392, 'g#4': 415, 'a4': 440, 'a#4': 466, 'b4': 494, 689 | 'c5': 523, 'c#5': 554, 'd5': 587, 'd#5': 622, 'e5': 659, 'f5': 698, 'f#5': 740, 'g5': 784, 'g#5': 831, 'a5': 880, 'a#5': 932, 'b5': 988, 690 | 'c6': 1047, 'c#6': 1109, 'd6': 1175, 'd#6': 1245, 'e6': 1319, 'f6': 1397, 'f#6': 1480, 'g6': 1568, 'g#6': 1661, 'a6': 1760, 'a#6': 1865, 'b6': 1976, 691 | 'c7': 2093, 'c#7': 2217, 'd7': 2349, 'd#7': 2489, 692 | 'e7': 2637, 'f7': 2794, 'f#7': 2960, 'g7': 3136, 'g#7': 3322, 'a7': 3520, 'a#7': 3729, 'b7': 3951, 693 | 'c8': 4186, 'c#8': 4435, 'd8': 4699, 'd#8': 4978 694 | } 695 | 696 | def __init__(self, pin, initial_freq=440, initial_volume=0, duty_factor=1023, active_high=True): 697 | 698 | self._pin_num = pin 699 | self._pwm_buzzer = PWMBuzzer( 700 | pin, 701 | freq=initial_freq, 702 | duty_factor=duty_factor, 703 | active_high=active_high, 704 | initial_value=None, 705 | ) 706 | 707 | super().__init__(active_high, None) 708 | self.volume = initial_volume 709 | 710 | def on(self, volume=1): 711 | self.volume = volume 712 | 713 | def off(self): 714 | self.volume = 0 715 | 716 | @property 717 | def value(self): 718 | """ 719 | Sets or returns the value of the speaker. The value is a tuple of (freq, volume). 720 | """ 721 | return tuple(self.freq, self.volume) 722 | 723 | @value.setter 724 | def value(self, value): 725 | self._stop_change() 726 | self._write(value) 727 | 728 | @property 729 | def volume(self): 730 | """ 731 | Sets or returns the volume of the speaker: 1 for maximum volume, 0 for off. 732 | """ 733 | return self._volume 734 | 735 | @volume.setter 736 | def volume(self, value): 737 | self._volume = value 738 | self.value = (self.freq, self.volume) 739 | 740 | @property 741 | def freq(self): 742 | """ 743 | Sets or returns the current frequency of the speaker. 744 | """ 745 | return self._pwm_buzzer.freq 746 | 747 | @freq.setter 748 | def freq(self, freq): 749 | self.value = (freq, self.volume) 750 | 751 | def _write(self, value): 752 | # set the frequency 753 | if value[0] is not None: 754 | self._pwm_buzzer.freq = value[0] 755 | 756 | # write the volume value 757 | if value[1] is not None: 758 | self._pwm_buzzer.volume = value[1] 759 | 760 | def _to_freq(self, freq): 761 | if freq is not None and freq != '' and freq != 0: 762 | if type(freq) is str: 763 | return int(self.NOTES[freq]) 764 | elif freq <= 128 and freq > 0: # MIDI 765 | midi_factor = 2**(1/12) 766 | return int(440 * midi_factor ** (freq - 69)) 767 | else: 768 | return freq 769 | else: 770 | return None 771 | 772 | def beep(self, on_time=1, off_time=None, n=None, wait=False, fade_in_time=0, fade_out_time=None, fps=25): 773 | """ 774 | Makes the buzzer turn on and off repeatedly. 775 | 776 | :param float on_time: 777 | The length of time in seconds that the device will be on. Defaults to 1. 778 | 779 | :param float off_time: 780 | The length of time in seconds that the device will be off. If `None`, 781 | it will be the same as ``on_time``. Defaults to `None`. 782 | 783 | :param int n: 784 | The number of times to repeat the beep operation. If `None`, the 785 | device will continue beeping forever. The default is `None`. 786 | 787 | :param bool wait: 788 | If True, the method will block until the buzzer stops beeping. If False, 789 | the method will return and the buzzer will beep in the background. 790 | Defaults to False. 791 | 792 | :param float fade_in_time: 793 | The length of time in seconds to spend fading in. Defaults to 0. 794 | 795 | :param float fade_out_time: 796 | The length of time in seconds to spend fading out. If `None`, 797 | it will be the same as ``fade_in_time``. Defaults to `None`. 798 | 799 | :param int fps: 800 | The frames per second that will be used to calculate the number of 801 | steps between off/on states when fading. Defaults to 25. 802 | """ 803 | self._pwm_buzzer.blink(on_time, off_time, n, wait, fade_in_time, fade_out_time, fps) 804 | 805 | def play(self, tune=440, duration=1, volume=1, n=1, wait=True): 806 | """ 807 | Plays a tune for a given duration. 808 | 809 | :param int tune: 810 | 811 | The tune to play can be specified as: 812 | 813 | + a single "note", represented as: 814 | + a frequency in Hz e.g. `440` 815 | + a midi note e.g. `60` 816 | + a note name as a string e.g. `"E4"` 817 | + a list of notes and duration e.g. `[440, 1]` or `["E4", 2]` 818 | + a list of two value tuples of (note, duration) e.g. `[(440,1), (60, 2), ("e4", 3)]` 819 | 820 | Defaults to `440`. 821 | 822 | :param int volume: 823 | The volume of the tune; 1 is maximum volume, 0 is mute. Defaults to 1. 824 | 825 | :param float duration: 826 | The duration of each note in seconds. Defaults to 1. 827 | 828 | :param int n: 829 | The number of times to play the tune. If None, the tune will play 830 | forever. Defaults to 1. 831 | 832 | :param bool wait: 833 | If True, the method will block until the tune has finished. If False, 834 | the method will return and the tune will play in the background. 835 | Defaults to True. 836 | """ 837 | 838 | self.off() 839 | 840 | # tune isn't a list, so it must be a single frequency or note 841 | if not isinstance(tune, (list, tuple)): 842 | tune = [(tune, duration)] 843 | # if the first element isn't a list, then it must be list of a single note and duration 844 | elif not isinstance(tune[0], (list, tuple)): 845 | tune = [tune] 846 | 847 | def tune_generator(): 848 | for note in tune: 849 | 850 | # note isn't a list or tuple, it must be a single frequency or note 851 | if not isinstance(note, (list, tuple)): 852 | # make it into a tuple 853 | note = (note, duration) 854 | 855 | # turn the notes into frequencies 856 | freq = self._to_freq(note[0]) 857 | freq_duration = note[1] 858 | freq_volume = volume if freq is not None else 0 859 | 860 | # if this is a tune of greater than 1 note, add gaps between notes 861 | if len(tune) == 1: 862 | yield ((freq, freq_volume), freq_duration) 863 | else: 864 | yield ((freq, freq_volume), freq_duration * 0.9) 865 | yield ((freq, 0), freq_duration * 0.1) 866 | 867 | self._start_change(tune_generator, n, wait) 868 | 869 | def close(self): 870 | self._pwm_buzzer.close() 871 | 872 | class RGBLED(OutputDevice, PinsMixin): 873 | """ 874 | Extends :class:`OutputDevice` and represents a full colour LED component (composed 875 | of red, green, and blue LEDs). 876 | Connect the common cathode (longest leg) to a ground pin; connect each of 877 | the other legs (representing the red, green, and blue anodes) to any GP 878 | pins. You should use three limiting resistors (one per anode). 879 | The following code will make the LED yellow:: 880 | 881 | from picozero import RGBLED 882 | rgb = RGBLED(1, 2, 3) 883 | rgb.color = (1, 1, 0) 884 | 885 | 0–255 colours are also supported:: 886 | 887 | rgb.color = (255, 255, 0) 888 | 889 | :type red: int 890 | :param red: 891 | The GP pin that controls the red component of the RGB LED. 892 | :type green: int 893 | :param green: 894 | The GP pin that controls the green component of the RGB LED. 895 | :type blue: int 896 | :param blue: 897 | The GP pin that controls the blue component of the RGB LED. 898 | :param bool active_high: 899 | Set to :data:`True` (the default) for common cathode RGB LEDs. If you 900 | are using a common anode RGB LED, set this to :data:`False`. 901 | :type initial_value: ~colorzero.Color or tuple 902 | :param initial_value: 903 | The initial color for the RGB LED. Defaults to black ``(0, 0, 0)``. 904 | :param bool pwm: 905 | If :data:`True` (the default), construct :class:`PWMLED` instances for 906 | each component of the RGBLED. If :data:`False`, construct 907 | :class:`DigitalLED` instances. 908 | 909 | """ 910 | def __init__(self, red=None, green=None, blue=None, active_high=True, 911 | initial_value=(0, 0, 0), pwm=True): 912 | self._pin_nums = (red, green, blue) 913 | self._leds = () 914 | self._last = initial_value 915 | LEDClass = PWMLED if pwm else DigitalLED 916 | self._leds = tuple( 917 | LEDClass(pin, active_high=active_high) 918 | for pin in (red, green, blue)) 919 | super().__init__(active_high, initial_value) 920 | 921 | def _write(self, value): 922 | if type(value) is not tuple: 923 | value = (value, ) * 3 924 | for led, v in zip(self._leds, value): 925 | led.value = v 926 | 927 | @property 928 | def value(self): 929 | """ 930 | Represents the colour of the LED as an RGB 3-tuple of ``(red, green, 931 | blue)`` where each value is between 0 and 1 if *pwm* was :data:`True` 932 | when the class was constructed (but only takes values of 0 or 1 otherwise). 933 | For example, red would be ``(1, 0, 0)`` and yellow would be ``(1, 1, 934 | 0)``, whereas orange would be ``(1, 0.5, 0)``. 935 | """ 936 | return tuple(led.value for led in self._leds) 937 | 938 | @value.setter 939 | def value(self, value): 940 | self._stop_change() 941 | self._write(value) 942 | 943 | @property 944 | def is_active(self): 945 | """ 946 | Returns :data:`True` if the LED is currently active (not black) and 947 | :data:`False` otherwise. 948 | """ 949 | return self.value != (0, 0, 0) 950 | 951 | is_lit = is_active 952 | 953 | def _to_255(self, value): 954 | return round(value * 255) 955 | 956 | def _from_255(self, value): 957 | return 0 if value == 0 else value / 255 958 | 959 | @property 960 | def color(self): 961 | """ 962 | Represents the colour of the LED as an RGB 3-tuple of ``(red, green, 963 | blue)`` where each value is between 0 and 255 if *pwm* was :data:`True` 964 | when the class was constructed (but only takes values of 0 or 255 otherwise). 965 | For example, red would be ``(255, 0, 0)`` and yellow would be ``(255, 255, 966 | 0)``, whereas orange would be ``(255, 127, 0)``. 967 | """ 968 | return tuple(self._to_255(v) for v in self.value) 969 | 970 | @color.setter 971 | def color(self, value): 972 | self.value = tuple(self._from_255(v) for v in value) 973 | 974 | @property 975 | def red(self): 976 | """ 977 | Represents the red component of the LED as a value between 0 and 255 if *pwm* was :data:`True` 978 | when the class was constructed (but only takes values of 0 or 255 otherwise). 979 | """ 980 | return self._to_255(self.value[0]) 981 | 982 | @red.setter 983 | def red(self, value): 984 | r, g, b = self.value 985 | self.value = self._from_255(value), g, b 986 | 987 | @property 988 | def green(self): 989 | """ 990 | Represents the green component of the LED as a value between 0 and 255 if *pwm* was :data:`True` 991 | when the class was constructed (but only takes values of 0 or 255 otherwise). 992 | """ 993 | return self._to_255(self.value[1]) 994 | 995 | @green.setter 996 | def green(self, value): 997 | r, g, b = self.value 998 | self.value = r, self._from_255(value), b 999 | 1000 | @property 1001 | def blue(self): 1002 | """ 1003 | Represents the blue component of the LED as a value between 0 and 255 if *pwm* was :data:`True` 1004 | when the class was constructed (but only takes values of 0 or 255 otherwise). 1005 | """ 1006 | return self._to_255(self.value[2]) 1007 | 1008 | @blue.setter 1009 | def blue(self, value): 1010 | r, g, b = self.value 1011 | self.value = r, g, self._from_255(value) 1012 | 1013 | def on(self): 1014 | """ 1015 | Turns the LED on. This is equivalent to setting the LED color to white, e.g. 1016 | ``(1, 1, 1)``. 1017 | """ 1018 | self.value = (1, 1, 1) 1019 | 1020 | def invert(self): 1021 | """ 1022 | Inverts the state of the device. If the device is currently off 1023 | (:attr:`value` is ``(0, 0, 0)``), this changes it to "fully" on 1024 | (:attr:`value` is ``(1, 1, 1)``). If the device has a specific colour, 1025 | this method inverts the colour. 1026 | """ 1027 | r, g, b = self.value 1028 | self.value = (1 - r, 1 - g, 1 - b) 1029 | 1030 | def toggle(self): 1031 | """ 1032 | Toggles the state of the device. If the device has a specific colour, then that colour is saved and the device is turned off. 1033 | If the device is off, it will be changed to the last colour it had when it was on or, if none, to fully on (:attr:`value` is ``(1, 1, 1)``). 1034 | """ 1035 | if self.value == (0, 0, 0): 1036 | self.value = self._last or (1, 1, 1) 1037 | else: 1038 | self._last = self.value 1039 | self.value = (0, 0, 0) 1040 | 1041 | def blink(self, on_times=1, fade_times=0, colors=((1, 0, 0), (0, 1, 0), (0, 0, 1)), n=None, wait=False, fps=25): 1042 | """ 1043 | Makes the device blink between colours repeatedly. 1044 | 1045 | :param float on_times: 1046 | Single value or tuple of numbers of seconds to stay on each colour. Defaults to 1 second. 1047 | :param float fade_times: 1048 | Single value or tuple of times to fade between each colour. Must be 0 if 1049 | *pwm* was :data:`False` when the class was constructed. 1050 | :type colors: tuple 1051 | Tuple of colours to blink between, use ``(0, 0, 0)`` for off. 1052 | :param colors: 1053 | The colours to blink between. Defaults to red, green, blue. 1054 | :type n: int or None 1055 | :param n: 1056 | Number of times to blink; :data:`None` (the default) means forever. 1057 | :param bool wait: 1058 | If :data:`False` (the default), use a Timer to manage blinking, 1059 | continue blinking, and return immediately. If :data:`False`, only 1060 | return when the blinking is finished (warning: the default value of 1061 | *n* will result in this method never returning). 1062 | """ 1063 | self.off() 1064 | 1065 | if type(on_times) is not tuple: 1066 | on_times = (on_times, ) * len(colors) 1067 | if type(fade_times) is not tuple: 1068 | fade_times = (fade_times, ) * len(colors) 1069 | # If any value is above zero then treat all as 0-255 values 1070 | if any(v > 1 for v in sum(colors, ())): 1071 | colors = tuple(tuple(self._from_255(v) for v in t) for t in colors) 1072 | 1073 | def blink_generator(): 1074 | 1075 | # Define a linear interpolation between 1076 | # off_color and on_color 1077 | 1078 | lerp = lambda t, fade_in, color1, color2: tuple( 1079 | (1 - t) * off + t * on 1080 | if fade_in else 1081 | (1 - t) * on + t * off 1082 | for off, on in zip(color2, color1) 1083 | ) 1084 | 1085 | for c in range(len(colors)): 1086 | if on_times[c] > 0: 1087 | yield (colors[c], on_times[c]) 1088 | 1089 | if fade_times[c] > 0: 1090 | for i in range(int(fps * fade_times[c])): 1091 | v = lerp(i * (1 / fps) / fade_times[c], True, colors[(c + 1) % len(colors)], colors[c]) 1092 | t = 1 / fps 1093 | yield (v, t) 1094 | 1095 | self._start_change(blink_generator, n, wait) 1096 | 1097 | def pulse(self, fade_times=1, colors=((0, 0, 0), (1, 0, 0), (0, 0, 0), (0, 1, 0), (0, 0, 0), (0, 0, 1)), n=None, wait=False, fps=25): 1098 | """ 1099 | Makes the device fade between colours repeatedly. 1100 | 1101 | :param float fade_times: 1102 | Single value or tuple of numbers of seconds to spend fading. Defaults to 1. 1103 | :param float fade_out_time: 1104 | Number of seconds to spend fading out. Defaults to 1. 1105 | :type colors: tuple 1106 | :param on_color: 1107 | Tuple of colours to pulse between in order. Defaults to red, off, green, off, blue, off. 1108 | :type off_color: ~colorzero.Color or tuple 1109 | :type n: int or None 1110 | :param n: 1111 | Number of times to pulse; :data:`None` (the default) means forever. 1112 | """ 1113 | on_times = 0 1114 | self.blink(on_times, fade_times, colors, n, wait, fps) 1115 | 1116 | def cycle(self, fade_times=1, colors=((1, 0, 0), (0, 1, 0), (0, 0, 1)), n=None, wait=False, fps=25): 1117 | """ 1118 | Makes the device fade in and out repeatedly. 1119 | 1120 | :param float fade_times: 1121 | Single value or tuple of numbers of seconds to spend fading between colours. Defaults to 1. 1122 | :param float fade_times: 1123 | Number of seconds to spend fading out. Defaults to 1. 1124 | :type colors: tuple 1125 | :param on_color: 1126 | Tuple of colours to cycle between. Defaults to red, green, blue. 1127 | :type n: int or None 1128 | :param n: 1129 | Number of times to cycle; :data:`None` (the default) means forever. 1130 | """ 1131 | on_times = 0 1132 | self.blink(on_times, fade_times, colors, n, wait, fps) 1133 | 1134 | def close(self): 1135 | super().close() 1136 | for led in self._leds: 1137 | led.close() 1138 | self._leds = None 1139 | 1140 | RGBLED.colour = RGBLED.color 1141 | 1142 | class Motor(PinsMixin): 1143 | """ 1144 | Represents a motor connected to a motor controller that has a two-pin 1145 | input. One pin drives the motor "forward", the other drives the motor 1146 | "backward". 1147 | 1148 | :type forward: int 1149 | :param forward: 1150 | The GP pin that controls the "forward" motion of the motor. 1151 | 1152 | :type backward: int 1153 | :param backward: 1154 | The GP pin that controls the "backward" motion of the motor. 1155 | 1156 | :param bool pwm: 1157 | If :data:`True` (the default), PWM pins are used to drive the motor. 1158 | When using PWM pins, values between 0 and 1 can be used to set the 1159 | speed. 1160 | 1161 | """ 1162 | def __init__(self, forward, backward, pwm=True): 1163 | self._pin_nums = (forward, backward) 1164 | self._forward = PWMOutputDevice(forward) if pwm else DigitalOutputDevice(forward) 1165 | self._backward = PWMOutputDevice(backward) if pwm else DigitalOutputDevice(backward) 1166 | 1167 | def on(self, speed=1, t=None, wait=False): 1168 | """ 1169 | Turns the motor on and makes it turn. 1170 | 1171 | :param float speed: 1172 | The speed as a value between -1 and 1: 1 turns the motor at 1173 | full speed in one direction, -1 turns the motor at full speed in 1174 | the opposite direction. Defaults to 1. 1175 | 1176 | :param float t: 1177 | The time in seconds that the motor should run for. If None is 1178 | specified, the motor will stay on. The default is None. 1179 | 1180 | :param bool wait: 1181 | If True, the method will block until the time `t` has expired. 1182 | If False, the method will return and the motor will turn on in 1183 | the background. Defaults to False. Only effective if `t` is not 1184 | None. 1185 | """ 1186 | if speed > 0: 1187 | self._backward.off() 1188 | self._forward.on(speed, t, wait) 1189 | 1190 | elif speed < 0: 1191 | self._forward.off() 1192 | self._backward.on(-speed, t, wait) 1193 | 1194 | else: 1195 | self.off() 1196 | 1197 | def off(self): 1198 | """ 1199 | Stops the motor turning. 1200 | """ 1201 | self._backward.off() 1202 | self._forward.off() 1203 | 1204 | @property 1205 | def value(self): 1206 | """ 1207 | Sets or returns the motor speed as a value between -1 and 1: -1 is full 1208 | speed "backward", 1 is full speed "forward", 0 is stopped. 1209 | """ 1210 | return self._forward.value + (-self._backward.value) 1211 | 1212 | @value.setter 1213 | def value(self, value): 1214 | if value != 0: 1215 | self.on(value) 1216 | else: 1217 | self.stop() 1218 | 1219 | def forward(self, speed=1, t=None, wait=False): 1220 | """ 1221 | Makes the motor turn "forward". 1222 | 1223 | :param float speed: 1224 | The speed as a value between 0 and 1: 1 is full speed, 0 is stop. Defaults to 1. 1225 | 1226 | :param float t: 1227 | The time in seconds that the motor should turn for. If None is 1228 | specified, the motor will stay on. The default is None. 1229 | 1230 | :param bool wait: 1231 | If True, the method will block until the time `t` has expired. 1232 | If False, the method will return and the motor will turn on in 1233 | the background. Defaults to False. Only effective if `t` is not 1234 | None. 1235 | """ 1236 | self.on(speed, t, wait) 1237 | 1238 | def backward(self, speed=1, t=None, wait=False): 1239 | """ 1240 | Makes the motor turn "backward". 1241 | 1242 | :param float speed: 1243 | The speed as a value between 0 and 1: 1 is full speed, 0 is stop. Defaults to 1. 1244 | 1245 | :param float t: 1246 | The time in seconds that the motor should turn for. If None is 1247 | specified, the motor will stay on. The default is None. 1248 | 1249 | :param bool wait: 1250 | If True, the method will block until the time `t` has expired. 1251 | If False, the method will return and the motor will turn on in 1252 | the background. Defaults to False. Only effective if `t` is not 1253 | None. 1254 | """ 1255 | self.on(-speed, t, wait) 1256 | 1257 | def close(self): 1258 | """ 1259 | Closes the device and releases any resources. Once closed, the device 1260 | can no longer be used. 1261 | """ 1262 | self._forward.close() 1263 | self._backward.close() 1264 | 1265 | Motor.start = Motor.on 1266 | Motor.stop = Motor.off 1267 | 1268 | class Robot: 1269 | """ 1270 | Represents a generic dual-motor robot / rover / buggy. 1271 | 1272 | Alias for :class:`Rover`. 1273 | 1274 | This class is constructed with two tuples representing the forward and 1275 | backward pins of the left and right controllers. For example, 1276 | if the left motor's controller is connected to pins 12 and 13, while the 1277 | right motor's controller is connected to pins 14 and 15, then the following 1278 | example will drive the robot forward:: 1279 | 1280 | from picozero import Robot 1281 | 1282 | robot = Robot(left=(12, 13), right=(14, 15)) 1283 | robot.forward() 1284 | 1285 | :param tuple left: 1286 | A tuple of two pins representing the forward and backward inputs of the 1287 | left motor's controller. 1288 | 1289 | :param tuple right: 1290 | A tuple of two pins representing the forward and backward inputs of the 1291 | right motor's controller. 1292 | 1293 | :param bool pwm: 1294 | If :data:`True` (the default), pwm pins will be used, allowing variable 1295 | speed control. 1296 | 1297 | """ 1298 | def __init__(self, left, right, pwm=True): 1299 | self._left = Motor(left[0], left[1], pwm) 1300 | self._right = Motor(right[0], right[1], pwm) 1301 | 1302 | @property 1303 | def left_motor(self): 1304 | """ 1305 | Returns the left :class:`Motor`. 1306 | """ 1307 | return self._left 1308 | 1309 | @property 1310 | def right_motor(self): 1311 | """ 1312 | Returns the right :class:`Motor`. 1313 | """ 1314 | return self._right 1315 | 1316 | @property 1317 | def value(self): 1318 | """ 1319 | Represents the motion of the robot as a tuple of (left_motor_speed, 1320 | right_motor_speed) with ``(-1, -1)`` representing full speed backwards, 1321 | ``(1, 1)`` representing full speed forwards, and ``(0, 0)`` 1322 | representing stopped. 1323 | """ 1324 | return (self._left.value, self._right.value) 1325 | 1326 | @value.setter 1327 | def value(self, value): 1328 | self._left.value, self._right.value = value 1329 | 1330 | def forward(self, speed=1, t=None, wait=False): 1331 | """ 1332 | Makes the robot move "forward". 1333 | 1334 | :param float speed: 1335 | The speed as a value between 0 and 1: 1 is full speed, 0 is stop. Defaults to 1. 1336 | 1337 | :param float t: 1338 | The time in seconds that the robot should move for. If None is 1339 | specified, the robot will continue to move until stopped. The default 1340 | is None. 1341 | 1342 | :param bool wait: 1343 | If True, the method will block until the time `t` has expired. 1344 | If False, the method will return and the motor will turn on in 1345 | the background. Defaults to False. Only effective if `t` is not 1346 | None. 1347 | """ 1348 | self._left.forward(speed, t, False) 1349 | self._right.forward(speed, t, wait) 1350 | 1351 | def backward(self, speed=1, t=None, wait=False): 1352 | """ 1353 | Makes the robot move "backward". 1354 | 1355 | :param float speed: 1356 | The speed as a value between 0 and 1: 1 is full speed, 0 is stop. Defaults to 1. 1357 | 1358 | :param float t: 1359 | The time in seconds that the robot should move for. If None is 1360 | specified, the robot will continue to move until stopped. The default 1361 | is None. 1362 | 1363 | :param bool wait: 1364 | If True, the method will block until the time `t` has expired. 1365 | If False, the method will return and the motor will turn on in 1366 | the background. Defaults to False. Only effective if `t` is not 1367 | None. 1368 | """ 1369 | self._left.backward(speed, t, False) 1370 | self._right.backward(speed, t, wait) 1371 | 1372 | def left(self, speed=1, t=None, wait=False): 1373 | """ 1374 | Makes the robot turn "left" by turning the left motor backward and the 1375 | right motor forward. 1376 | 1377 | :param float speed: 1378 | The speed as a value between 0 and 1: 1 is full speed, 0 is stop. Defaults to 1. 1379 | 1380 | :param float t: 1381 | The time in seconds that the robot should turn for. If None is 1382 | specified, the robot will continue to turn until stopped. The default 1383 | is None. 1384 | 1385 | :param bool wait: 1386 | If True, the method will block until the time `t` has expired. 1387 | If False, the method will return and the motor will turn on in 1388 | the background. Defaults to False. Only effective if `t` is not 1389 | None. 1390 | """ 1391 | self._left.backward(speed, t, False) 1392 | self._right.forward(speed, t, wait) 1393 | 1394 | def right(self, speed=1, t=None, wait=False): 1395 | """ 1396 | Makes the robot turn "right" by turning the left motor forward and the 1397 | right motor backward. 1398 | 1399 | :param float speed: 1400 | The speed as a value between 0 and 1: 1 is full speed, 0 is stop. Defaults to 1. 1401 | 1402 | :param float t: 1403 | The time in seconds that the robot should turn for. If None is 1404 | specified, the robot will continue to turn until stopped. The default 1405 | is None. 1406 | 1407 | :param bool wait: 1408 | If True, the method will block until the time `t` has expired. 1409 | If False, the method will return and the motor will turn on in 1410 | the background. Defaults to False. Only effective if `t` is not 1411 | None. 1412 | """ 1413 | self._left.forward(speed, t, False) 1414 | self._right.backward(speed, t, wait) 1415 | 1416 | def stop(self): 1417 | """ 1418 | Stops the robot. 1419 | """ 1420 | self._left.stop() 1421 | self._right.stop() 1422 | 1423 | def close(self): 1424 | """ 1425 | Closes the device and releases any resources. Once closed, the device 1426 | can no longer be used. 1427 | """ 1428 | self._left.close() 1429 | self._right.close() 1430 | 1431 | Rover = Robot 1432 | 1433 | class Servo(PWMOutputDevice): 1434 | """ 1435 | Represents a PWM-controlled servo motor. 1436 | 1437 | Setting the `value` to 0 will move the servo to its minimum position, 1438 | 1 will move the servo to its maximum position. Setting the `value` to 1439 | :data:`None` will turn the servo "off" (i.e. no signal is sent). 1440 | 1441 | :type pin: int 1442 | :param pin: 1443 | The pin the servo motor is connected to. 1444 | 1445 | :param bool initial_value: 1446 | If :data:`0`, the servo will be set to its minimum position. If 1447 | :data:`1`, the servo will set to its maximum position. If :data:`None` 1448 | (the default), the position of the servo will not change. 1449 | 1450 | :param float min_pulse_width: 1451 | The pulse width corresponding to the servo's minimum position. This 1452 | defaults to 1ms. 1453 | 1454 | :param float max_pulse_width: 1455 | The pulse width corresponding to the servo's maximum position. This 1456 | defaults to 2ms. 1457 | 1458 | :param float frame_width: 1459 | The length of time between servo control pulses measured in seconds. 1460 | This defaults to 20ms which is a common value for servos. 1461 | 1462 | :param int duty_factor: 1463 | The duty factor of the PWM signal. This is a value between 0 and 65535. 1464 | Defaults to 65535. 1465 | """ 1466 | def __init__(self, pin, initial_value=None, min_pulse_width=1/1000, max_pulse_width=2/1000, frame_width=20/1000, duty_factor=65535): 1467 | self._min_duty = int((min_pulse_width / frame_width) * duty_factor) 1468 | self._max_duty = int((max_pulse_width / frame_width) * duty_factor) 1469 | 1470 | super().__init__(pin, freq=int(1 / frame_width), duty_factor=duty_factor, initial_value=initial_value) 1471 | 1472 | def _state_to_value(self, state): 1473 | return None if state == 0 else clamp((state - self._min_duty) / (self._max_duty - self._min_duty), 0, 1) 1474 | 1475 | def _value_to_state(self, value): 1476 | return 0 if value is None else int(self._min_duty + ((self._max_duty - self._min_duty) * value)) 1477 | 1478 | def min(self): 1479 | """ 1480 | Set the servo to its minimum position. 1481 | """ 1482 | self.value = 0 1483 | 1484 | def mid(self): 1485 | """ 1486 | Set the servo to its mid-point position. 1487 | """ 1488 | self.value = 0.5 1489 | 1490 | def max(self): 1491 | """ 1492 | Set the servo to its maximum position. 1493 | """ 1494 | self.value = 1 1495 | 1496 | def off(self): 1497 | """ 1498 | Turn the servo "off" by setting the value to `None`. 1499 | """ 1500 | self.value = None 1501 | 1502 | ############################################################################### 1503 | # INPUT DEVICES 1504 | ############################################################################### 1505 | 1506 | class InputDevice: 1507 | """ 1508 | Base class for input devices. 1509 | """ 1510 | def __init__(self, active_state=None): 1511 | self._active_state = active_state 1512 | 1513 | @property 1514 | def active_state(self): 1515 | """ 1516 | Sets or returns the active state of the device. If :data:`None` (the default), 1517 | the device will return the value that the pin is set to. If 1518 | :data:`True`, the device will return :data:`True` if the pin is 1519 | HIGH. If :data:`False`, the device will return :data:`False` if the 1520 | pin is LOW. 1521 | """ 1522 | return self._active_state 1523 | 1524 | @active_state.setter 1525 | def active_state(self, value): 1526 | self._active_state = True if value else False 1527 | self._inactive_state = False if value else True 1528 | 1529 | @property 1530 | def value(self): 1531 | """ 1532 | Returns the current value of the device. This is either :data:`True` 1533 | or :data:`False` depending on the value of :attr:`active_state`. 1534 | """ 1535 | return self._read() 1536 | 1537 | class DigitalInputDevice(InputDevice, PinMixin): 1538 | """ 1539 | Represents a generic input device with digital functionality e.g. buttons 1540 | that can be either active or inactive. 1541 | 1542 | :param int pin: 1543 | The pin that the device is connected to. 1544 | 1545 | :param bool pull_up: 1546 | If :data:`True`, the device will be pulled up to HIGH. If 1547 | :data:`False` (the default), the device will be pulled down to LOW. 1548 | 1549 | :param bool active_state: 1550 | If :data:`True` (the default), the device will return :data:`True` 1551 | if the pin is HIGH. If :data:`False`, the device will return 1552 | :data:`False` if the pin is LOW. 1553 | 1554 | :param float bounce_time: 1555 | The bounce time for the device. If set, the device will ignore 1556 | any button presses that happen within the bounce time after a 1557 | button release. This is useful to prevent accidental button 1558 | presses from registering as multiple presses. The default is 1559 | :data:`None`. 1560 | """ 1561 | def __init__(self, pin, pull_up=False, active_state=None, bounce_time=None): 1562 | super().__init__(active_state) 1563 | self._pin_num = pin 1564 | self._pin = Pin( 1565 | pin, 1566 | mode=Pin.IN, 1567 | pull=Pin.PULL_UP if pull_up else Pin.PULL_DOWN) 1568 | self._bounce_time = bounce_time 1569 | 1570 | if active_state is None: 1571 | self._active_state = False if pull_up else True 1572 | else: 1573 | self._active_state = active_state 1574 | 1575 | self._state = self._pin.value() 1576 | 1577 | self._when_activated = None 1578 | self._when_deactivated = None 1579 | 1580 | # setup interupt 1581 | self._pin.irq(self._pin_change, Pin.IRQ_RISING | Pin.IRQ_FALLING) 1582 | 1583 | def _state_to_value(self, state): 1584 | return int(bool(state) == self._active_state) 1585 | 1586 | def _read(self): 1587 | return self._state_to_value(self._state) 1588 | 1589 | def _pin_change(self, p): 1590 | # turn off the interupt 1591 | p.irq(handler=None) 1592 | 1593 | last_state = p.value() 1594 | 1595 | if self._bounce_time is not None: 1596 | # wait for stability 1597 | stop = ticks_ms() + (self._bounce_time * 1000) 1598 | while ticks_ms() < stop: 1599 | # keep checking, reset the stop if the value changes 1600 | if p.value() != last_state: 1601 | stop = ticks_ms() + self._bounce_time 1602 | last_state = p.value() 1603 | 1604 | # re-enable the interupt 1605 | p.irq(self._pin_change, Pin.IRQ_RISING | Pin.IRQ_FALLING) 1606 | 1607 | # did the value actually change? 1608 | if self._state != last_state: 1609 | # set the state 1610 | self._state = self._pin.value() 1611 | 1612 | # manage call backs 1613 | callback_to_run = None 1614 | if self.value and self._when_activated is not None: 1615 | callback_to_run = self._when_activated 1616 | 1617 | elif not self.value and self._when_deactivated is not None: 1618 | callback_to_run = self._when_deactivated 1619 | 1620 | if callback_to_run is not None: 1621 | 1622 | def schedule_callback(callback): 1623 | callback() 1624 | 1625 | try: 1626 | schedule(schedule_callback, callback_to_run) 1627 | 1628 | except RuntimeError as e: 1629 | if str(e) == "schedule queue full": 1630 | raise EventFailedScheduleQueueFull( 1631 | "{} - {} not run due to the micropython schedule being full".format( 1632 | str(self), callback_to_run.__name__)) 1633 | else: 1634 | raise e 1635 | 1636 | @property 1637 | def is_active(self): 1638 | """ 1639 | Returns :data:`True` if the device is active. 1640 | """ 1641 | return bool(self.value) 1642 | 1643 | @property 1644 | def is_inactive(self): 1645 | """ 1646 | Returns :data:`True` if the device is inactive. 1647 | """ 1648 | return not bool(self.value) 1649 | 1650 | @property 1651 | def when_activated(self): 1652 | """ 1653 | Returns a :samp:`callback` that will be called when the device is activated. 1654 | """ 1655 | return self._when_activated 1656 | 1657 | @when_activated.setter 1658 | def when_activated(self, value): 1659 | self._when_activated = value 1660 | 1661 | @property 1662 | def when_deactivated(self): 1663 | """ 1664 | Returns a :samp:`callback` that will be called when the device is deactivated. 1665 | """ 1666 | return self._when_deactivated 1667 | 1668 | @when_deactivated.setter 1669 | def when_deactivated(self, value): 1670 | self._when_deactivated = value 1671 | 1672 | def close(self): 1673 | """ 1674 | Closes the device and releases any resources. Once closed, the device 1675 | can no longer be used. 1676 | """ 1677 | self._pin.irq(handler=None) 1678 | self._pin = None 1679 | 1680 | class Switch(DigitalInputDevice): 1681 | """ 1682 | Represents a toggle switch, which is either open or closed. 1683 | 1684 | :param int pin: 1685 | The pin that the device is connected to. 1686 | 1687 | :param bool pull_up: 1688 | If :data:`True` (the default), the device will be pulled up to 1689 | HIGH. If :data:`False`, the device will be pulled down to LOW. 1690 | 1691 | :param float bounce_time: 1692 | The bounce time for the device. If set, the device will ignore 1693 | any button presses that happen within the bounce time after a 1694 | button release. This is useful to prevent accidental button 1695 | presses from registering as multiple presses. Defaults to 0.02 1696 | seconds. 1697 | """ 1698 | def __init__(self, pin, pull_up=True, bounce_time=0.02): 1699 | super().__init__(pin=pin, pull_up=pull_up, bounce_time=bounce_time) 1700 | 1701 | Switch.is_closed = Switch.is_active 1702 | Switch.is_open = Switch.is_inactive 1703 | Switch.when_closed = Switch.when_activated 1704 | Switch.when_opened = Switch.when_deactivated 1705 | 1706 | class Button(Switch): 1707 | """ 1708 | Represents a push button, which can be either pressed or released. 1709 | 1710 | :param int pin: 1711 | The pin that the device is connected to. 1712 | 1713 | :param bool pull_up: 1714 | If :data:`True` (the default), the device will be pulled up to 1715 | HIGH. If :data:`False`, the device will be pulled down to LOW. 1716 | 1717 | :param float bounce_time: 1718 | The bounce time for the device. If set, the device will ignore 1719 | any button presses that happen within the bounce time after a 1720 | button release. This is useful to prevent accidental button 1721 | presses from registering as multiple presses. Defaults to 0.02 1722 | seconds. 1723 | """ 1724 | pass 1725 | 1726 | Button.is_pressed = Button.is_active 1727 | Button.is_released = Button.is_inactive 1728 | Button.when_pressed = Button.when_activated 1729 | Button.when_released = Button.when_deactivated 1730 | 1731 | class AnalogInputDevice(InputDevice, PinMixin): 1732 | """ 1733 | Represents a generic input device with analogue functionality, e.g. 1734 | a potentiometer. 1735 | 1736 | :param int pin: 1737 | The pin that the device is connected to. 1738 | 1739 | :param active_state: 1740 | The active state of the device. If :data:`True` (the default), 1741 | the :class:`AnalogInputDevice` will assume that the device is 1742 | active when the pin is high and above the threshold. If 1743 | ``active_state`` is ``False``, the device will be active when 1744 | the pin is low and below the threshold. 1745 | 1746 | :param float threshold: 1747 | The threshold that the device must be above or below to be 1748 | considered active. The default is 0.5. 1749 | 1750 | """ 1751 | def __init__(self, pin, active_state=True, threshold=0.5): 1752 | self._pin_num = pin 1753 | super().__init__(active_state) 1754 | self._adc = ADC(pin) 1755 | self._threshold = float(threshold) 1756 | 1757 | def _state_to_value(self, state): 1758 | return (state if self.active_state else 65535 - state) / 65535 1759 | 1760 | def _value_to_state(self, value): 1761 | return int(65535 * (value if self.active_state else 1 - value)) 1762 | 1763 | def _read(self): 1764 | return self._state_to_value(self._adc.read_u16()) 1765 | 1766 | @property 1767 | def threshold(self): 1768 | """ 1769 | The threshold that the device must be above or below to be 1770 | considered active. The default is 0.5. 1771 | """ 1772 | return self._threshold 1773 | 1774 | @threshold.setter 1775 | def threshold(self, value): 1776 | self._threshold = float(value) 1777 | 1778 | @property 1779 | def is_active(self): 1780 | """ 1781 | Returns :data:`True` if the device is active. 1782 | """ 1783 | return self.value > self.threshold 1784 | 1785 | @property 1786 | def voltage(self): 1787 | """ 1788 | Returns the voltage of the analogue device. 1789 | """ 1790 | return self.value * 3.3 1791 | 1792 | def close(self): 1793 | self._adc = None 1794 | 1795 | class Potentiometer(AnalogInputDevice): 1796 | """ 1797 | Represents a potentiometer, which outputs a variable voltage 1798 | between 0 and 3.3V. 1799 | 1800 | Alias for :class:`Pot`. 1801 | 1802 | :param int pin: 1803 | The pin that the device is connected to. 1804 | 1805 | :param active_state: 1806 | The active state of the device. If :data:`True` (the default), 1807 | the :class:`AnalogInputDevice` will assume that the device is 1808 | active when the pin is high and above the threshold. If 1809 | ``active_state`` is ``False``, the device will be active when 1810 | the pin is low and below the threshold. 1811 | 1812 | :param float threshold: 1813 | The threshold that the device must be above or below to be 1814 | considered active. The default is 0.5. 1815 | 1816 | """ 1817 | pass 1818 | 1819 | Pot = Potentiometer 1820 | 1821 | def pico_temp_conversion(voltage): 1822 | # Formula for calculating temp from voltage for the onboard temperature sensor 1823 | return 27 - (voltage - 0.706)/0.001721 1824 | 1825 | class TemperatureSensor(AnalogInputDevice): 1826 | """ 1827 | Represents a TemperatureSensor, which outputs a variable voltage. The voltage 1828 | can be converted to a temperature using a `conversion` function passed as a 1829 | parameter. 1830 | 1831 | Alias for :class:`Thermistor` and :class:`TempSensor`. 1832 | 1833 | :param int pin: 1834 | The pin that the device is connected to. 1835 | 1836 | :param active_state: 1837 | The active state of the device. If :data:`True` (the default), 1838 | the :class:`AnalogInputDevice` will assume that the device is 1839 | active when the pin is high and above the threshold. If 1840 | ``active_state`` is ``False``, the device will be active when 1841 | the pin is low and below the threshold. 1842 | 1843 | :param float threshold: 1844 | The threshold that the device must be above or below to be 1845 | considered active. The default is 0.5. 1846 | 1847 | :param float conversion: 1848 | A function that takes a voltage and returns a temperature. 1849 | 1850 | e.g. The internal temperature sensor has a voltage range of 0.706V to 0.716V 1851 | and would use the follow conversion function:: 1852 | 1853 | def temp_conversion(voltage): 1854 | return 27 - (voltage - 0.706)/0.001721 1855 | 1856 | temp_sensor = TemperatureSensor(pin, conversion=temp_conversion) 1857 | 1858 | If :data:`None` (the default), the ``temp`` property will return :data:`None`. 1859 | 1860 | """ 1861 | def __init__(self, pin, active_state=True, threshold=0.5, conversion=None): 1862 | self._conversion = conversion 1863 | super().__init__(pin, active_state, threshold) 1864 | 1865 | @property 1866 | def temp(self): 1867 | """ 1868 | Returns the temperature of the device. If the conversion function is not 1869 | set, this will return :data:`None`. 1870 | """ 1871 | if self._conversion is not None: 1872 | return self._conversion(self.voltage) 1873 | else: 1874 | return None 1875 | 1876 | @property 1877 | def conversion(self): 1878 | """ 1879 | Sets or returns the conversion function for the device. 1880 | """ 1881 | return self._conversion 1882 | 1883 | @conversion.setter 1884 | def conversion(self, value): 1885 | self._conversion = value 1886 | 1887 | pico_temp_sensor = TemperatureSensor(4, True, 0.5, pico_temp_conversion) 1888 | TempSensor = TemperatureSensor 1889 | Thermistor = TemperatureSensor 1890 | 1891 | class DistanceSensor(PinsMixin): 1892 | """ 1893 | Represents a HC-SR04 ultrasonic distance sensor. 1894 | 1895 | :param int echo: 1896 | The pin that the ECHO pin is connected to. 1897 | 1898 | :param int trigger: 1899 | The pin that the TRIG pin is connected to. 1900 | 1901 | :param float max_distance: 1902 | The :attr:`value` attribute reports a normalized value between 0 (too 1903 | close to measure) and 1 (maximum distance). This parameter specifies 1904 | the maximum distance expected in meters. This defaults to 1. 1905 | """ 1906 | def __init__(self, echo, trigger, max_distance=1): 1907 | self._pin_nums = (echo, trigger) 1908 | self._max_distance = max_distance 1909 | self._echo = Pin(echo, mode=Pin.IN, pull=Pin.PULL_DOWN) 1910 | self._trigger = Pin(trigger, mode=Pin.OUT, value=0) 1911 | 1912 | def _read(self): 1913 | echo_on = None 1914 | echo_off = None 1915 | timed_out = False 1916 | 1917 | self._trigger.off() 1918 | sleep(0.000005) 1919 | self._trigger.on() 1920 | sleep(0.00001) 1921 | self._trigger.off() 1922 | 1923 | # If an echo isn't measured in 100 milliseconds, it should 1924 | # be considered out of range. The maximum length of the 1925 | # echo is 38 milliseconds but it's not known how long the 1926 | # transmission takes after the trigger 1927 | stop = ticks_ms() + 100 1928 | while echo_off is None and not timed_out: 1929 | if self._echo.value() == 1 and echo_on is None: 1930 | echo_on = ticks_us() 1931 | if echo_on is not None and self._echo.value() == 0: 1932 | echo_off = ticks_us() 1933 | if ticks_ms() > stop: 1934 | timed_out = True 1935 | 1936 | if echo_off is None or timed_out: 1937 | return None 1938 | else: 1939 | distance = ((echo_off - echo_on) * 0.000343) / 2 1940 | distance = min(distance, self._max_distance) 1941 | return distance 1942 | 1943 | @property 1944 | def value(self): 1945 | """ 1946 | Returns a value between 0, indicating the reflector is either touching 1947 | the sensor or is sufficiently near that the sensor can’t tell the 1948 | difference, and 1, indicating the reflector is at or beyond the 1949 | specified max_distance. A return value of None indicates that the 1950 | echo was not received before the timeout. 1951 | """ 1952 | distance = self.distance 1953 | return distance / self._max_distance if distance is not None else None 1954 | 1955 | @property 1956 | def distance(self): 1957 | """ 1958 | Returns the current distance measured by the sensor in meters. Note 1959 | that this property will have a value between 0 and max_distance. 1960 | """ 1961 | return self._read() 1962 | 1963 | @property 1964 | def max_distance(self): 1965 | """ 1966 | Returns the maximum distance that the sensor will measure in metres. 1967 | """ 1968 | return self._max_distance 1969 | 1970 | -------------------------------------------------------------------------------- /Code/lib/vector3d.py: -------------------------------------------------------------------------------- 1 | # vector3d.py 3D vector class for use in inertial measurement unit drivers 2 | # Authors Peter Hinch, Sebastian Plamauer 3 | 4 | # V0.7 17th May 2017 pyb replaced with utime 5 | # V0.6 18th June 2015 6 | 7 | ''' 8 | The MIT License (MIT) 9 | Copyright (c) 2014 Sebastian Plamauer, oeplse@gmail.com, Peter Hinch 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | ''' 26 | 27 | from utime import sleep_ms 28 | from math import sqrt, degrees, acos, atan2 29 | 30 | 31 | def default_wait(): 32 | ''' 33 | delay of 50 ms 34 | ''' 35 | sleep_ms(50) 36 | 37 | 38 | class Vector3d(object): 39 | ''' 40 | Represents a vector in a 3D space using Cartesian coordinates. 41 | Internally uses sensor relative coordinates. 42 | Returns vehicle-relative x, y and z values. 43 | ''' 44 | def __init__(self, transposition, scaling, update_function): 45 | self._vector = [0, 0, 0] 46 | self._ivector = [0, 0, 0] 47 | self.cal = (0, 0, 0) 48 | self.argcheck(transposition, "Transposition") 49 | self.argcheck(scaling, "Scaling") 50 | if set(transposition) != {0, 1, 2}: 51 | raise ValueError('Transpose indices must be unique and in range 0-2') 52 | self._scale = scaling 53 | self._transpose = transposition 54 | self.update = update_function 55 | 56 | def argcheck(self, arg, name): 57 | ''' 58 | checks if arguments are of correct length 59 | ''' 60 | if len(arg) != 3 or not (type(arg) is list or type(arg) is tuple): 61 | raise ValueError(name + ' must be a 3 element list or tuple') 62 | 63 | def calibrate(self, stopfunc, waitfunc=default_wait): 64 | ''' 65 | calibration routine, sets cal 66 | ''' 67 | self.update() 68 | maxvec = self._vector[:] # Initialise max and min lists with current values 69 | minvec = self._vector[:] 70 | while not stopfunc(): 71 | waitfunc() 72 | self.update() 73 | maxvec = list(map(max, maxvec, self._vector)) 74 | minvec = list(map(min, minvec, self._vector)) 75 | self.cal = tuple(map(lambda a, b: (a + b)/2, maxvec, minvec)) 76 | 77 | @property 78 | def _calvector(self): 79 | ''' 80 | Vector adjusted for calibration offsets 81 | ''' 82 | return list(map(lambda val, offset: val - offset, self._vector, self.cal)) 83 | 84 | @property 85 | def x(self): # Corrected, vehicle relative floating point values 86 | self.update() 87 | return self._calvector[self._transpose[0]] * self._scale[0] 88 | 89 | @property 90 | def y(self): 91 | self.update() 92 | return self._calvector[self._transpose[1]] * self._scale[1] 93 | 94 | @property 95 | def z(self): 96 | self.update() 97 | return self._calvector[self._transpose[2]] * self._scale[2] 98 | 99 | @property 100 | def xyz(self): 101 | self.update() 102 | return (self._calvector[self._transpose[0]] * self._scale[0], 103 | self._calvector[self._transpose[1]] * self._scale[1], 104 | self._calvector[self._transpose[2]] * self._scale[2]) 105 | 106 | @property 107 | def magnitude(self): 108 | x, y, z = self.xyz # All measurements must correspond to the same instant 109 | return sqrt(x**2 + y**2 + z**2) 110 | 111 | @property 112 | def inclination(self): 113 | x, y, z = self.xyz 114 | return degrees(acos(z / sqrt(x**2 + y**2 + z**2))) 115 | 116 | @property 117 | def elevation(self): 118 | return 90 - self.inclination 119 | 120 | @property 121 | def azimuth(self): 122 | x, y, z = self.xyz 123 | return degrees(atan2(y, x)) 124 | 125 | # Raw uncorrected integer values from sensor 126 | @property 127 | def ix(self): 128 | return self._ivector[0] 129 | 130 | @property 131 | def iy(self): 132 | return self._ivector[1] 133 | 134 | @property 135 | def iz(self): 136 | return self._ivector[2] 137 | 138 | @property 139 | def ixyz(self): 140 | return self._ivector 141 | 142 | @property 143 | def transpose(self): 144 | return tuple(self._transpose) 145 | 146 | @property 147 | def scale(self): 148 | return tuple(self._scale) -------------------------------------------------------------------------------- /Code/pico_74hc595.py: -------------------------------------------------------------------------------- 1 | from machine import Pin 2 | import utime 3 | import random 4 | 5 | dataPIN = 13 6 | latchPIN = 15 7 | clockPIN = 14 8 | 9 | dataPIN=Pin(dataPIN, Pin.OUT) 10 | latchPIN=Pin(latchPIN, Pin.OUT) 11 | clockPIN=Pin(clockPIN, Pin.OUT) 12 | 13 | def shift_update(input,data,clock,latch): 14 | #put latch down to start data sending 15 | clock.value(0) 16 | latch.value(0) 17 | clock.value(1) 18 | 19 | #load data in reverse order 20 | for i in range(7, -1, -1): 21 | clock.value(0) 22 | data.value(int(input[i])) 23 | clock.value(1) 24 | 25 | #put latch up to store data on register 26 | clock.value(0) 27 | latch.value(1) 28 | clock.value(1) 29 | 30 | shift_update("00000000",dataPIN,clockPIN,latchPIN) 31 | 32 | bit_string="00000000" 33 | 34 | while True: 35 | shift_update(bit_string,dataPIN,clockPIN,latchPIN) 36 | bit_string = str(random.randint(0, 1))+bit_string[:-1] 37 | #bit_string = str(1)+bit_string[:-1] 38 | utime.sleep(0.1) 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Code/pico_BLE_LED.py: -------------------------------------------------------------------------------- 1 | # Import necessary modules 2 | from machine import Pin 3 | import bluetooth 4 | from ble_simple_peripheral import BLESimplePeripheral 5 | 6 | # Create a Bluetooth Low Energy (BLE) object 7 | ble = bluetooth.BLE() 8 | 9 | # Create an instance of the BLESimplePeripheral class with the BLE object 10 | sp = BLESimplePeripheral(ble) 11 | 12 | # Create a Pin object for the onboard LED, configure it as an output 13 | led = Pin("LED", Pin.OUT) 14 | 15 | 16 | # Define a callback function to handle received data 17 | def on_rx(data): 18 | print("Data received: ", data) # Print the received data 19 | #global led_state # Access the global variable led_state 20 | if data == b'H\r\n': 21 | led.on() 22 | elif data == b'L\r\n': 23 | led.off() 24 | 25 | # Start an infinite loop 26 | while True: 27 | if sp.is_connected(): # Check if a BLE connection is established 28 | sp.on_write(on_rx) # Set the callback function for data reception -------------------------------------------------------------------------------- /Code/pico_BLE_recieve.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/judenkereuwem/Raspberry_Pi_Pico_MicroPython/bcedf05c163e0e6f3f5ab1153234624fbffb6abf/Code/pico_BLE_recieve.py -------------------------------------------------------------------------------- /Code/pico_BLE_send.py: -------------------------------------------------------------------------------- 1 | from machine import Pin 2 | from time import sleep 3 | 4 | led = Pin(25, Pin.OUT) 5 | 6 | while True: 7 | led.value(1) 8 | sleep(1) 9 | led.value(0) 10 | sleep(1) -------------------------------------------------------------------------------- /Code/pico_LED_blink.py: -------------------------------------------------------------------------------- 1 | from machine import Pin, Timer 2 | led = Pin(25, Pin.OUT) 3 | timer = Timer() 4 | 5 | def blink(timer): 6 | led.toggle() 7 | 8 | timer.init(freq=2.5, mode=Timer.PERIODIC, callback=blink) -------------------------------------------------------------------------------- /Code/pico_LED_blink1.py: -------------------------------------------------------------------------------- 1 | from machine import Pin 2 | from time import sleep 3 | 4 | led = Pin(17, Pin.OUT) 5 | 6 | while True: 7 | led.value(1) 8 | sleep(1) 9 | led.value(0) 10 | sleep(1) -------------------------------------------------------------------------------- /Code/pico_LED_brightness.py: -------------------------------------------------------------------------------- 1 | from machine import ADC, Pin, PWM 2 | import time 3 | 4 | pwm = PWM(Pin(15)) 5 | adc = ADC(Pin(26)) 6 | 7 | pwm.freq(1000) 8 | 9 | while True: 10 | duty = adc.read_u16() 11 | pwm.duty_u16(duty) 12 | -------------------------------------------------------------------------------- /Code/pico_LED_toggle.py: -------------------------------------------------------------------------------- 1 | from machine import Pin 2 | led = Pin(25, Pin.OUT) 3 | 4 | #led.value(1) #led on 5 | #led.value(0) #led off 6 | led.toggle() #led on/off when Run is pressed -------------------------------------------------------------------------------- /Code/pico_LM35.py: -------------------------------------------------------------------------------- 1 | from machine import ADC, Pin 2 | from time import sleep 3 | 4 | LM35 = ADC(Pin(26)) 5 | 6 | while True: 7 | reading = LM35.read_u16() 8 | voltage = (reading / 65535) * 3.3 9 | tempC = voltage*100 10 | tempF = (tempC*9.0/3.3)+32.0 11 | 12 | print("tempC", "%.2f" % tempC, "\xB0C") 13 | print("tempC", "%.2f" % tempF, "\xB0F") 14 | print("") 15 | sleep(0.5) -------------------------------------------------------------------------------- /Code/pico_MPU-6050.py: -------------------------------------------------------------------------------- 1 | from imu import MPU6050 2 | from time import sleep 3 | from machine import Pin, I2C 4 | 5 | i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000) 6 | imu = MPU6050(i2c) 7 | 8 | while True: 9 | ax=round(imu.accel.x,2) 10 | ay=round(imu.accel.y,2) 11 | az=round(imu.accel.z,2) 12 | gx=round(imu.gyro.x) 13 | gy=round(imu.gyro.y) 14 | gz=round(imu.gyro.z) 15 | tem=round(imu.temperature,2) 16 | #print("ax",ax,"\t","ay",ay,"\t","az",az,"\t","gx",gx,"\t","gy",gy,"\t","gz",gz,"\t","Temperature",tem," ",end="\r") 17 | print("Accel_X: ", ax) 18 | print("Accel_Y: ", ay) 19 | print("Accel_Z: ", az) 20 | 21 | print("Gyro_X: ", gx) 22 | print("Gyro_Y: ", gy) 23 | print("Gyro_Z: ", gz) 24 | 25 | print("Temperature: ", tem) 26 | print("") 27 | sleep(0.2) -------------------------------------------------------------------------------- /Code/pico_OLED.py: -------------------------------------------------------------------------------- 1 | #install "micropython-ssd1306" library 2 | 3 | from machine import Pin, I2C 4 | from ssd1306 import SSD1306_I2C 5 | 6 | i2c = I2C(0, sda=Pin(16), scl=Pin(17), freq=400000) 7 | oled = SSD1306_I2C(128, 64, i2c) 8 | 9 | oled.text(" Welcome to", 0, 16) 10 | oled.text(" Placidlearn", 0, 30) 11 | oled.show() 12 | -------------------------------------------------------------------------------- /Code/pico_RTC.py: -------------------------------------------------------------------------------- 1 | 2 | from machine import Pin, I2C 3 | from ssd1306 import SSD1306_I2C 4 | from machine import RTC 5 | 6 | #Initialize I2C and OLED 7 | i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000) 8 | oled = SSD1306_I2C(128, 64, i2c) 9 | 10 | #Initialize RTC 11 | rtc = RTC() 12 | date = rtc.datetime()[0:3] 13 | time = rtc.datetime()[4:6] 14 | 15 | #print(rtc.datetime()) 16 | #print("Date: ", *date) 17 | #print("Time: ", *time) 18 | 19 | print("Date: ", '-'.join(str(x) for x in date)) 20 | print("Time: ", ':'.join(str(x) for x in time)) 21 | 22 | 23 | oled.text("Date: ", 0, 16) 24 | oled.text(':'.join(str(x) for x in date), 48, 16) 25 | oled.text("Time: ", 0, 30) 26 | oled.text(':'.join(str(x) for x in time), 48, 30) 27 | oled.show() 28 | 29 | -------------------------------------------------------------------------------- /Code/pico_buzzer.py: -------------------------------------------------------------------------------- 1 | from machine import Pin, PWM 2 | from utime import sleep 3 | 4 | buzzer = PWM(Pin(13)) 5 | buzzer.freq(500) 6 | 7 | while True: 8 | buzzer.duty_u16(1000) 9 | sleep(0.5) 10 | buzzer.duty_u16(0) 11 | sleep(0.5) 12 | 13 | 14 | -------------------------------------------------------------------------------- /Code/pico_gasSensor.py: -------------------------------------------------------------------------------- 1 | # from machine import Pin 2 | # import utime 3 | # 4 | # gasSensor = Pin(16, Pin.IN, Pin.PULL_UP) 5 | # 6 | # while True: 7 | # print(gasSensor.value()) 8 | # if gasSensor.value() == 1: 9 | # print("gas not detected") 10 | # utime.sleep(0.2) 11 | # else: 12 | # print("gas detected") 13 | # utime.sleep(0.2) 14 | 15 | 16 | 17 | #------- Analog Gas Sensor reading ----------# 18 | from machine import ADC, Pin 19 | import utime 20 | 21 | adc = ADC(Pin(26)) 22 | 23 | while True: 24 | print(adc.read_u16()) 25 | utime.sleep(0.5) -------------------------------------------------------------------------------- /Code/pico_i2c_scanner.py: -------------------------------------------------------------------------------- 1 | # I2C Scanner MicroPython 2 | from machine import Pin, SoftI2C 3 | 4 | # You can choose any other combination of I2C pins 5 | i2c = SoftI2C(scl=Pin(1), sda=Pin(0)) 6 | 7 | print('I2C SCANNER') 8 | devices = i2c.scan() 9 | 10 | if len(devices) == 0: 11 | print("No i2c device !") 12 | else: 13 | print('i2c devices found:', len(devices)) 14 | 15 | for device in devices: 16 | print("I2C hexadecimal address: ", hex(device)) -------------------------------------------------------------------------------- /Code/pico_inbuilt_tempSensor.py: -------------------------------------------------------------------------------- 1 | import machine 2 | import utime 3 | from machine import Pin, I2C 4 | from ssd1306 import SSD1306_I2C 5 | 6 | i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000) 7 | oled = SSD1306_I2C(128, 64, i2c) 8 | 9 | sensor_temp = machine.ADC(4) 10 | conversion_factor = 3.3/(65535) 11 | 12 | while True: 13 | reading = sensor_temp.read_u16()*conversion_factor 14 | temperature = 27 - (reading - 0.706)/0.001721 15 | print(temperature) 16 | 17 | oled.fill(0) 18 | oled.text("Temp: ", 0, 16) 19 | oled.text(str(round(temperature, 2)), 48, 16) 20 | oled.text("*C", 96, 16) 21 | utime.sleep(0.5) 22 | oled.show() -------------------------------------------------------------------------------- /Code/pico_joystick.py: -------------------------------------------------------------------------------- 1 | from machine import Pin, ADC 2 | import utime 3 | 4 | xAxis = ADC(Pin(27)) 5 | yAxis = ADC(Pin(26)) 6 | button = Pin(16,Pin.IN, Pin.PULL_UP) 7 | currentStatus = "" 8 | 9 | while True: 10 | xValue = xAxis.read_u16() 11 | yValue = yAxis.read_u16() 12 | buttonValue = button.value() 13 | xStatus = "middle" 14 | yStatus = "middle" 15 | buttonStatus = "not pressed" 16 | 17 | #print("X: ", xValue) 18 | #print("Y: ", yValue) 19 | #print("") 20 | 21 | if yValue <= 30000: 22 | xStatus = "left" 23 | elif yValue >= 60000: 24 | xStatus = "right" 25 | if xValue >= 60000: 26 | yStatus = "up" 27 | elif xValue <= 30000: 28 | yStatus = "down" 29 | if buttonValue == 0: 30 | buttonStatus = "pressed" 31 | #print("X: " + xStatus + ", Y: " + yStatus + " -- button " + buttonStatus) 32 | 33 | 34 | if xStatus is not "middle" and yStatus == "middle" and buttonStatus == "not pressed": 35 | currentStatus = xStatus 36 | elif yStatus is not "middle" and xStatus == "middle" and buttonStatus == "not pressed": 37 | currentStatus = yStatus 38 | elif xStatus == "middle" and yStatus == "middle" and buttonStatus == "pressed": 39 | currentStatus = buttonStatus 40 | elif xStatus == "middle" and yStatus == "middle" and buttonStatus == "not pressed": 41 | currentStatus = "nothing" 42 | 43 | print(currentStatus) 44 | 45 | utime.sleep(0.1) 46 | 47 | -------------------------------------------------------------------------------- /Code/pico_keypad.py: -------------------------------------------------------------------------------- 1 | from machine import Pin 2 | import utime 3 | 4 | led = Pin(15, Pin.OUT) 5 | 6 | col_list = [1,2,3,4] 7 | row_list = [5,6,7,8,9] 8 | 9 | for x in range(0, 5): 10 | row_list[x] = Pin(row_list[x], Pin.OUT) 11 | row_list[x].value(1) 12 | 13 | for x in range(0, 4): 14 | col_list[x] = Pin(col_list[x], Pin.IN, Pin.PULL_UP) 15 | 16 | key_map = [["LEFT","0","RIGHT","ENT"],\ 17 | ["7","8","9","ESC"],\ 18 | ["4","5","6","DOWN"],\ 19 | ["1","2","3","UP"],\ 20 | ["F1","F2","#","*"]] 21 | 22 | def Keypad4x5Read(cols, rows): 23 | for r in rows: 24 | r.value(0) 25 | result = [cols[0].value(),cols[1].value(),cols[2].value(),cols[3].value()] 26 | if min(result)==0: 27 | key=key_map[int(rows.index(r))][int(result.index(0))] 28 | r.value(1) #manages key kept pressed 29 | return(key) 30 | r.value(1) 31 | 32 | print("----Ready for user inputs-------") 33 | while True: 34 | key=Keypad4x5Read(col_list, row_list) 35 | if key != None: 36 | print("Input: "+key) 37 | led.value(1) 38 | utime.sleep(0.3) 39 | led.value(0) -------------------------------------------------------------------------------- /Code/pico_ldr.py: -------------------------------------------------------------------------------- 1 | from machine import ADC, Pin 2 | from time import sleep 3 | 4 | LDR = ADC(Pin(26)) 5 | 6 | while True: 7 | light = LDR.read_u16() 8 | light = int(light/65535*100) 9 | print(light) 10 | sleep(0.5) 11 | 12 | -------------------------------------------------------------------------------- /Code/pico_ledPWM.py: -------------------------------------------------------------------------------- 1 | from machine import Pin, PWM 2 | from time import sleep 3 | 4 | pwm = PWM(Pin(15)) 5 | 6 | pwm.freq(1000) 7 | 8 | while True: 9 | for duty in range(65025): 10 | pwm.duty_u16(duty) 11 | sleep(0.0001) 12 | for duty in range(65025, 0, -1): 13 | pwm.duty_u16(duty) 14 | sleep(0.0001) -------------------------------------------------------------------------------- /Code/pico_multithreading.py: -------------------------------------------------------------------------------- 1 | 2 | from machine import Pin 3 | import utime 4 | import _thread 5 | 6 | led1 = Pin(2, machine.Pin.OUT) 7 | led2 = Pin(3, machine.Pin.OUT) 8 | sLock = _thread.allocate_lock() 9 | 10 | def second_thread(): 11 | while True: 12 | sLock.acquire() 13 | led2.toggle() 14 | print("Second thread") 15 | utime.sleep(1) 16 | sLock.release() 17 | _thread.start_new_thread(second_thread, ()) 18 | 19 | while True: 20 | # We acquire the semaphore lock 21 | sLock.acquire() 22 | led1.toggle() 23 | print("First thread") 24 | utime.sleep(1) 25 | # We release the semaphore lock 26 | sLock.release() -------------------------------------------------------------------------------- /Code/pico_potentiometer.py: -------------------------------------------------------------------------------- 1 | 2 | from machine import ADC, Pin 3 | import time 4 | 5 | adc = ADC(Pin(26)) 6 | 7 | while True: 8 | print(adc.read_u16()) 9 | time.sleep(1) 10 | -------------------------------------------------------------------------------- /Code/pico_pushButton.py: -------------------------------------------------------------------------------- 1 | from picozero import Button 2 | from time import sleep 3 | 4 | button = Button(16) 5 | 6 | while True: 7 | if button.is_pressed: 8 | print("Button is pressed") 9 | else: 10 | print("Button is not pressed") 11 | sleep(0.1) -------------------------------------------------------------------------------- /Code/pico_rgbLED.py: -------------------------------------------------------------------------------- 1 | from picozero import RGBLED 2 | from time import sleep 3 | 4 | rgb = RGBLED(red = 16, green = 17, blue = 18) 5 | 6 | while True: 7 | rgb.color = (255, 0, 0) 8 | sleep(0.5) 9 | rgb.color = (0, 255, 0) 10 | sleep(0.5) 11 | rgb.color = (0, 0, 255) 12 | sleep(0.5) 13 | rgb.color = (0, 0, 0) 14 | sleep(0.5) 15 | 16 | # blink purple 2 seconds, off 0.5 seconds 17 | #rgb.blink((0.5, 0.5, 0.5), colors=((255, 0, 0), (0, 255, 0), (0, 0, 255)), wait=True, n=3) 18 | #print("Finished blinking") # Runs after 3 repeats 19 | 20 | # Colour cycle slower in the opposite direction 21 | #rgb.cycle(fade_times=3, colors=((0, 0, 255), (0, 255, 0), (255, 0, 0)), wait=True, n=2) 22 | 23 | # 2 second to fade from purple to off, 0.5 seconds to change from off to purple 24 | #rgb.pulse(fade_times=(2, 0.5), colors=((0, 0, 255), (255, 0, 0)), wait=True, n=2) 25 | #print("Finished pulsing") # Runs after 3 pulses 26 | 27 | #rgb.off() -------------------------------------------------------------------------------- /Code/pico_seven_segment_display.py: -------------------------------------------------------------------------------- 1 | from machine import Pin 2 | from time import sleep 3 | 4 | a = Pin(10, Pin.OUT) 5 | b = Pin(11, Pin.OUT) 6 | c = Pin(12, Pin.OUT) 7 | d = Pin(13, Pin.OUT) 8 | e = Pin(14, Pin.OUT) 9 | f = Pin(15, Pin.OUT) 10 | g = Pin(16, Pin.OUT) 11 | 12 | while True: 13 | # number 0 14 | a.value(1) 15 | b.value(1) 16 | c.value(1) 17 | d.value(1) 18 | e.value(1) 19 | f.value(1) 20 | g.value(0) 21 | sleep(1) 22 | 23 | # number 1 24 | a.value(0) 25 | b.value(1) 26 | c.value(1) 27 | d.value(0) 28 | e.value(0) 29 | f.value(0) 30 | g.value(0) 31 | sleep(1) 32 | 33 | # number 2 34 | a.value(1) 35 | b.value(1) 36 | c.value(0) 37 | d.value(1) 38 | e.value(1) 39 | f.value(0) 40 | g.value(1) 41 | sleep(1) 42 | 43 | # number 3 44 | a.value(1) 45 | b.value(1) 46 | c.value(1) 47 | d.value(1) 48 | e.value(0) 49 | f.value(0) 50 | g.value(1) 51 | sleep(1) 52 | 53 | # number 4 54 | a.value(0) 55 | b.value(1) 56 | c.value(1) 57 | d.value(0) 58 | e.value(0) 59 | f.value(1) 60 | g.value(1) 61 | sleep(1) 62 | 63 | # number 5 64 | a.value(1) 65 | b.value(0) 66 | c.value(1) 67 | d.value(1) 68 | e.value(0) 69 | f.value(1) 70 | g.value(1) 71 | sleep(1) 72 | 73 | # number 6 74 | a.value(1) 75 | b.value(0) 76 | c.value(1) 77 | d.value(1) 78 | e.value(1) 79 | f.value(1) 80 | g.value(1) 81 | sleep(1) 82 | 83 | # number 7 84 | a.value(1) 85 | b.value(1) 86 | c.value(1) 87 | d.value(0) 88 | e.value(0) 89 | f.value(0) 90 | g.value(0) 91 | sleep(1) 92 | 93 | # number 8 94 | a.value(1) 95 | b.value(1) 96 | c.value(1) 97 | d.value(1) 98 | e.value(1) 99 | f.value(1) 100 | g.value(1) 101 | sleep(1) 102 | 103 | # number 9 104 | a.value(1) 105 | b.value(1) 106 | c.value(1) 107 | d.value(1) 108 | e.value(0) 109 | f.value(1) 110 | g.value(1) 111 | sleep(1) 112 | -------------------------------------------------------------------------------- /Code/pico_thermistor.py: -------------------------------------------------------------------------------- 1 | from machine import ADC, Pin 2 | import utime 3 | import math 4 | 5 | #Variable declaration 6 | logR2 = None 7 | R2 = None 8 | T = None 9 | Tc = None 10 | Tf = None 11 | 12 | R1 = 10000 13 | c1 = 1.009249522e-03 14 | c2 = 2.378405444e-04 15 | c3 = 2.019202697e-07 16 | 17 | thermistorPin = machine.ADC(27) 18 | 19 | while True: 20 | reading = thermistorPin.read_u16() 21 | 22 | R2 = R1 * (65535 / reading - 1.0); 23 | logR2 = math.log(R2); 24 | T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2)); 25 | Tc = T - 273.15; 26 | Tf = (Tc * 9.0)/ 5.0 + 32.0; 27 | 28 | print("Temperature: ", Tc) 29 | print("Temperature: ", Tf) 30 | print(" ") 31 | utime.sleep(0.5) 32 | -------------------------------------------------------------------------------- /Code/pico_tilt_sensor.py: -------------------------------------------------------------------------------- 1 | from machine import Pin, I2C 2 | from ssd1306 import SSD1306_I2C 3 | import time 4 | 5 | # OLED display 6 | i2c = I2C(0, sda=Pin(16), scl=Pin(17), freq=400000) 7 | oled = SSD1306_I2C(128, 64, i2c) 8 | 9 | # Tilt sensor: first pin to VCC and the other to GP2 10 | tilt = Pin(2, Pin.IN, Pin.PULL_DOWN) 11 | 12 | while True: 13 | oled.fill(0) 14 | if tilt.value() == 1: 15 | oled.text("Flat", 50, 20) 16 | elif tilt.value() == 0: 17 | oled.text("Vertical", 30, 20) 18 | oled.show() -------------------------------------------------------------------------------- /Code/pico_ultrasonic_sensor.py: -------------------------------------------------------------------------------- 1 | from machine import Pin 2 | import utime 3 | 4 | trigger = Pin(3, Pin.OUT) 5 | echo = Pin(2, Pin.IN) 6 | 7 | def ultrasonic(): 8 | trigger.low() 9 | utime.sleep_us(2) 10 | trigger.high() 11 | utime.sleep_us(5) 12 | trigger.low() 13 | while echo.value() == 0: 14 | signaloff = utime.ticks_us() 15 | while echo.value() == 1: 16 | signalon = utime.ticks_us() 17 | timepassed = signalon - signaloff 18 | distance = (timepassed * 0.0343) / 2 19 | distance = round(distance, 2) 20 | print("Distance: ", distance, "cm") 21 | 22 | while True: 23 | ultrasonic() 24 | utime.sleep(1) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raspberry_Pi_Pico 2 | 3 | Full Tutorial: https://judeok.wixsite.com/placidlearn/raspberry-pi-pico 4 | --------------------------------------------------------------------------------