This shows you the differences between two versions of the page.
|
pm:prj2022:arosca:picomacropad [2022/05/06 22:32] pavel_vlad.mateescu |
pm:prj2022:arosca:picomacropad [2022/05/28 00:12] (current) pavel_vlad.mateescu [Download] |
||
|---|---|---|---|
| Line 11: | Line 11: | ||
| ===== Descriere generală ===== | ===== Descriere generală ===== | ||
| - | <note tip> | + | {{:pm:prj2022:arosca:block_diagram.png?nolink&500|}} |
| - | O schemă bloc cu toate modulele proiectului vostru, atât software cât şi hardware însoţită de o descriere a acestora precum şi a modului în care interacţionează. | + | |
| - | + | ||
| - | Exemplu de schemă bloc: http://www.robs-projects.com/mp3proj/newplayer.html | + | |
| - | </note> | + | |
| ===== Hardware Design ===== | ===== Hardware Design ===== | ||
| Lista componente: | Lista componente: | ||
| - | * Rasberry Py Pico | + | * Rasberry Pi Pico |
| * Display OLED 128x64 pixels | * Display OLED 128x64 pixels | ||
| * Rotary Encoder | * Rotary Encoder | ||
| * 10 Kailh Box Jade mechanical switches | * 10 Kailh Box Jade mechanical switches | ||
| * Hand made 2 layer copper etched pcb | * Hand made 2 layer copper etched pcb | ||
| + | * 10 12k SMD 1206 resistors | ||
| + | * 2 10k SMD 0805 resistors | ||
| + | * 1 10k Through Hole resistor | ||
| + | * 10 10nf SMD 0805 capacitors | ||
| + | * Pin headers and wires | ||
| + | |||
| + | {{:pm:prj2022:arosca:picomacropad1.jpeg?nolink&350|}}{{:pm:prj2022:arosca:picomacropad_pcb_pavel-vlad_mateescu.jpg?nolink&350|}} | ||
| + | |||
| + | {{:pm:prj2022:arosca:picomacropad_sch_pavel-vlad_mateescu.jpg?nolink&700|}} | ||
| - | <note tip> | ||
| - | Aici puneţi tot ce ţine de hardware design: | ||
| - | * listă de piese | ||
| - | * scheme electrice (se pot lua şi de pe Internet şi din datasheet-uri, e.g. http://www.captain.at/electronic-atmega16-mmc-schematic.png) | ||
| - | * diagrame de semnal | ||
| - | * rezultatele simulării | ||
| - | </note> | ||
| ===== 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> | ||