This shows you the differences between two versions of the page.
pm:prj2022:arosca:picomacropad [2022/05/27 23:40] pavel_vlad.mateescu [Hardware Design] |
pm:prj2022:arosca:picomacropad [2022/05/28 00:12] (current) pavel_vlad.mateescu [Download] |
||
---|---|---|---|
Line 34: | Line 34: | ||
===== Software Design ===== | ===== Software Design ===== | ||
- | <note tip> | + | Codul a fost dezvoltat folosind limbajul CircuitPython in Thonny. |
- | Descrierea codului aplicaţiei (firmware): | + | Biblioteci externe: |
- | * mediu de dezvoltare (if any) (e.g. AVR Studio, CodeVisionAVR) | + | * Adafruit Framebuf |
- | * librării şi surse 3rd-party (e.g. Procyon AVRlib) | + | * Adafruit SSD1306 |
- | * algoritmi şi structuri pe care plănuiţi să le implementaţi | + | * Adafruit HID |
- | * (etapa 3) surse şi funcţii implementate | + | * Adafruit ImageLoader |
- | </note> | + | |
- | ===== Rezultate Obţinute ===== | + | Codul citeste semnale de la cele 10 butoane si de la codorul rotativ, inclusiv butonul acestuia |
- | <note tip> | + | Pentru a programa functionalitatea celor 10 butoane, trebuie definita o matrice de 5x2 cu functionalitatea pentru foecare butoane. Functionalitatea butoanelor este preluata din biblioteca Adafruit HID. |
- | Care au fost rezultatele obţinute în urma realizării proiectului vostru. | + | |
- | </note> | + | |
+ | Pentru controlul OLED-ului se foloseste biblioteca Adafruit SSD1306 si Adafruit ImageLoader. Se pot scrie mesaje caracter cu caracter, se pot incarca imagini sau se pot seta pixeli arbitrar pe o matrice de 128x64 pixeli. | ||
+ | |||
+ | <code python> | ||
+ | import rotaryio | ||
+ | import board | ||
+ | import digitalio | ||
+ | import displayio | ||
+ | import adafruit_imageload | ||
+ | import usb_hid | ||
+ | from adafruit_hid.consumer_control import ConsumerControl | ||
+ | from adafruit_hid.consumer_control_code import ConsumerControlCode | ||
+ | import time | ||
+ | from digitalio import DigitalInOut, Direction, Pull | ||
+ | from adafruit_hid.keyboard import Keyboard | ||
+ | from adafruit_hid.keycode import Keycode | ||
+ | import busio | ||
+ | import adafruit_ssd1306 | ||
+ | |||
+ | #display | ||
+ | i2c = busio.I2C(board.GP27, board.GP26) | ||
+ | display = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c) | ||
+ | |||
+ | |||
+ | # left encoder | ||
+ | buttonL = digitalio.DigitalInOut(board.GP6) | ||
+ | buttonL.direction = digitalio.Direction.INPUT | ||
+ | buttonL.pull = digitalio.Pull.UP | ||
+ | |||
+ | encoderL = rotaryio.IncrementalEncoder(board.GP7, board.GP8) | ||
+ | |||
+ | cc = ConsumerControl(usb_hid.devices) | ||
+ | |||
+ | button_stateL = None | ||
+ | last_positionL = encoderL.position | ||
+ | |||
+ | # keyboard | ||
+ | |||
+ | led = DigitalInOut(board.LED) | ||
+ | led.direction = Direction.OUTPUT | ||
+ | led.value = True | ||
+ | |||
+ | kbd = Keyboard(usb_hid.devices) | ||
+ | cck = ConsumerControl(usb_hid.devices) | ||
+ | |||
+ | |||
+ | pins = [ | ||
+ | board.GP13, | ||
+ | board.GP12, | ||
+ | board.GP11, | ||
+ | board.GP10, | ||
+ | board.GP16, | ||
+ | board.GP17, | ||
+ | board.GP18, | ||
+ | board.GP19, | ||
+ | board.GP20, | ||
+ | board.GP21, | ||
+ | ] | ||
+ | |||
+ | MEDIA = 1 | ||
+ | KEY = 2 | ||
+ | META = 3 | ||
+ | |||
+ | # functionality of each layer | ||
+ | keymap_layers = [{ | ||
+ | (0): (KEY, [Keycode.ONE]), | ||
+ | (1): (KEY, [Keycode.TWO]), | ||
+ | (2): (KEY, [Keycode.THREE]), | ||
+ | (3): (KEY, [Keycode.FOUR]), | ||
+ | (4): (META, [Keycode.CAPS_LOCK]), | ||
+ | (5): (KEY, (Keycode.SHIFT, Keycode.GUI, Keycode.M)), | ||
+ | (6): (KEY, [Keycode.FIVE]), | ||
+ | (7): (KEY, [Keycode.SIX]), | ||
+ | (8): (KEY, [Keycode.SEVEN]), | ||
+ | (9): (KEY, [Keycode.EIGHT]), | ||
+ | }, | ||
+ | { | ||
+ | (0): (KEY, [Keycode.NINE]), | ||
+ | (1): (KEY, [Keycode.ZERO]), | ||
+ | (2): (KEY, (Keycode.SHIFT, Keycode.NINE)), | ||
+ | (3): (KEY, (Keycode.SHIFT, Keycode.ZERO)), | ||
+ | (4): (META, [Keycode.CAPS_LOCK]), | ||
+ | (5): (KEY, (Keycode.SHIFT, Keycode.GUI, Keycode.M)), | ||
+ | (6): (KEY, (Keycode.SHIFT, Keycode.THREE)), | ||
+ | (7): (KEY, (Keycode.SHIFT, Keycode.FOUR)), | ||
+ | (8): (KEY, (Keycode.SHIFT, Keycode.SEVEN)), | ||
+ | (9): (KEY, (Keycode.SHIFT, Keycode.EIGHT)), | ||
+ | }] | ||
+ | |||
+ | keymap = keymap_layers[0] | ||
+ | |||
+ | layer = True | ||
+ | mute = False | ||
+ | |||
+ | # display layers based on keyboard layer | ||
+ | def change_layer(mute): | ||
+ | global keymap | ||
+ | if layer: | ||
+ | display.fill(0) | ||
+ | keymap = keymap_layers[not layer] | ||
+ | display.text("layer 1 2 3 4", 0, 0, 1) | ||
+ | if mute == True: | ||
+ | display.text("unmute 5 6 7 8", 0, 32, 1) | ||
+ | else: | ||
+ | display.text("mute 5 6 7 8", 0, 32, 1) | ||
+ | display.show() | ||
+ | else: | ||
+ | display.fill(0) | ||
+ | keymap = keymap_layers[not layer] | ||
+ | display.text("layer 9 0 ( )", 0, 0, 1) | ||
+ | if mute == True: | ||
+ | display.text("unmute # $ & *", 0, 32, 1) | ||
+ | else: | ||
+ | display.text("mute # $ & *", 0, 32, 1) | ||
+ | display.show() | ||
+ | |||
+ | switches = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | ||
+ | |||
+ | for i in range(10): | ||
+ | switches[i] = DigitalInOut(pins[i]) | ||
+ | switches[i].direction = Direction.INPUT | ||
+ | switches[i].pull = Pull.UP | ||
+ | |||
+ | switch_state = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] | ||
+ | |||
+ | # init | ||
+ | change_layer(mute) | ||
+ | |||
+ | while True: | ||
+ | # left encoder | ||
+ | current_positionL = encoderL.position | ||
+ | position_changeL = current_positionL - last_positionL | ||
+ | if position_changeL > 0: | ||
+ | for _ in range(position_changeL): | ||
+ | cc.send(ConsumerControlCode.VOLUME_DECREMENT) | ||
+ | #print(current_positionL) | ||
+ | elif position_changeL < 0: | ||
+ | for _ in range(-position_changeL): | ||
+ | cc.send(ConsumerControlCode.VOLUME_INCREMENT) | ||
+ | #print(current_positionL) | ||
+ | last_positionL = current_positionL | ||
+ | if not buttonL.value and button_stateL is None: | ||
+ | button_stateL = "pressed" | ||
+ | if buttonL.value and button_stateL == "pressed": | ||
+ | cc.send(ConsumerControlCode.MUTE) | ||
+ | button_stateL = None | ||
+ | |||
+ | # keyboard | ||
+ | for button in range(10): | ||
+ | if switch_state[button] == 0: | ||
+ | if not switches[button].value: | ||
+ | try: | ||
+ | if keymap[button][0] == KEY: | ||
+ | if button == 5: | ||
+ | mute = not mute | ||
+ | change_layer(mute) | ||
+ | kbd.press(*keymap[button][1]) | ||
+ | else: | ||
+ | if button == 4: | ||
+ | layer = not layer | ||
+ | change_layer(mute) | ||
+ | else: | ||
+ | cck.send(keymap[button][1]) | ||
+ | except ValueError: # deals w six key limit | ||
+ | pass | ||
+ | switch_state[button] = 1 | ||
+ | |||
+ | if switch_state[button] == 1: | ||
+ | if switches[button].value: | ||
+ | try: | ||
+ | if keymap[button][0] == KEY: | ||
+ | kbd.release(*keymap[button][1]) | ||
+ | |||
+ | except ValueError: | ||
+ | pass | ||
+ | switch_state[button] = 0 | ||
+ | |||
+ | time.sleep(0.01) # debounce | ||
+ | </code> | ||
+ | ===== Rezultate Obţinute ===== | ||
+ | |||
+ | Am dobandit skill-ul de a face un PCB de mana. | ||
+ | Am produs un tool pe care il voi folosi in timpul lucrului de zi cu zi | ||
===== Concluzii ===== | ===== Concluzii ===== | ||
+ | Rezultatul proiectului este un punct bun de inceput prototiparea unui produs care poate fi adus pe piata | ||
===== Download ===== | ===== Download ===== | ||
- | <note warning> | + | {{:pm:prj2022:arosca:picomacropad_surse_pavel-vlad_mateescu.zip|}} |
- | O arhivă (sau mai multe dacă este cazul) cu fişierele obţinute în urma realizării proiectului: surse, scheme, etc. Un fişier README, un ChangeLog, un script de compilare şi copiere automată pe uC crează întotdeauna o impresie bună ;-). | + | |
- | Fişierele se încarcă pe wiki folosind facilitatea **Add Images or other files**. Namespace-ul în care se încarcă fişierele este de tipul **:pm:prj20??:c?** sau **:pm:prj20??:c?:nume_student** (dacă este cazul). **Exemplu:** Dumitru Alin, 331CC -> **:pm:prj2009:cc:dumitru_alin**. | ||
- | </note> | ||
- | ===== Jurnal ===== | + | ===== Bibliografie/Resurse ===== |
- | <note tip> | + | **Resurse Software** |
- | Puteți avea și o secțiune de jurnal în care să poată urmări asistentul de proiect progresul proiectului. | + | |
- | </note> | + | |
- | ===== Bibliografie/Resurse ===== | + | * Adafruit's CircuitPython docs: https://docs.circuitpython.org/en/latest/shared-bindings/index.html |
+ | * Adafruit's CircuitPython libraries catalog: https://learn.adafruit.com/welcome-to-circuitpython/circuitpython-libraries | ||
+ | * I2C OLED tutorial: https://lastminuteengineers.com/oled-display-arduino-tutorial/ | ||
+ | |||
+ | **Resurse Hardware**. | ||
+ | |||
+ | * Raspberry Pi Pico datasheet: https://datasheets.raspberrypi.com/pico/pico-datasheet.pdf | ||
+ | * Generic I2C OLED datasheet: https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf | ||
+ | * Generic Rotary Encoder description page: https://components101.com/modules/KY-04-rotary-encoder-pinout-features-datasheet-working-application-alternative | ||
- | <note> | ||
- | Listă cu documente, datasheet-uri, resurse Internet folosite, eventual grupate pe **Resurse Software** şi **Resurse Hardware**. | ||
- | </note> | ||
<html><a class="media mediafile mf_pdf" href="?do=export_pdf">Export to PDF</a></html> | <html><a class="media mediafile mf_pdf" href="?do=export_pdf">Export to PDF</a></html> | ||