# ========= Multicore + OLED SSD1306 + Salida Binaria (RP2040) =========
# Core 1: genera contador y lo saca en binario por GP2..GP11 (10 bits)
# Core 0: muestra el contador en el OLED SSD1306 por I2C0 (GP0=SDA, GP1=SCL)
import _thread
import time
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
import framebuf
# ===================== Configuración =====================
# I2C del OLED: usar I2C0 en GP0= SDA, GP1= SCL (evita conflicto con GP2..GP11)
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=200000)
oled = SSD1306_I2C(128, 64, i2c)
# Pines de salida binaria (10 bits): GP2..GP11
gpio_pins = [2,3,4,5,6,7,8,9,10,11]
BIN_PINS = [Pin(p, Pin.OUT) for p in gpio_pins]
# Parámetros del contador
COUNT_MAX = 1023 # 10 bits -> 0..1023
STEP = 1 # incremento
PERIOD_MS = 150 # periodo del contador (ajusta velocidad)
# Estado compartido
lock = _thread.allocate_lock()
counter = 0
# ===================== Funciones utilitarias =====================
def to_binary_string(value, bits=10):
"""Convierte un número entero en cadena binaria de longitud fija (MicroPython-compatible)."""
s = ""
for i in range(bits - 1, -1, -1): # desde MSB hasta LSB
s += "1" if (value >> i) & 1 else "0"
return s
def write_binary_to_pins(value):
# LSB en GP2, MSB en GP11
for i, pin in enumerate(BIN_PINS): # i=0..9
pin.value((value >> i) & 1)
def draw_centered_text(oled, text, y, scale=1):
# Renderizado simple: texto escalado x2/x3 manualmente
# Para números grandes combinaremos escalado simple de texto
x = (oled.width - len(text) * 8 * scale) // 2
if x < 0: x = 0
for idx, ch in enumerate(text):
# usar text normal y escalar con múltiples writes
if scale == 1:
oled.text(ch, x + idx*8, y)
else:
# “pobre-man’s scale”: escribir varias veces desplazado
bx = x + idx*8*scale
for dy in range(scale):
for dx in range(scale):
oled.text(ch, bx + dx, y + dy)
return
def draw_screen(value):
oled.fill(0)
# Línea superior con título
oled.text("MULTICORE RP2040", 0, 0)
# Valor decimal grande (centrado)
dec = str(value)
# Para decimal “grande” usamos el truco de duplicar 2x
draw_centered_text(oled, dec, 18, scale=2)
# Valor binario de 10 bits en dos líneas (5+5) o entero si cabe
bstr = to_binary_string(value, 10)
oled.text("BIN:", 0, 50)
oled.text(bstr, 28, 50)
oled.show()
# ===================== Tareas por núcleo =====================
def core1_task():
global counter
while True:
# Actualiza contador
with lock:
counter = (counter + STEP) & COUNT_MAX
out = counter
# Saca a pines en binario
write_binary_to_pins(out)
time.sleep_ms(PERIOD_MS)
def core0_task():
# Refresca OLED sin bloquear al core1
last = -1
while True:
with lock:
current = counter
if current != last:
draw_screen(current)
last = current
time.sleep_ms(50) # tasa de refresco de pantalla
# ===================== Inicio =====================
def main():
# Mensaje inicial
oled.fill(0)
oled.text("Iniciando...", 0, 0)
oled.text("Core1: GPIO bin", 0, 16)
oled.text("Core0: OLED", 0, 26)
oled.text("GP0/GP1 = I2C0", 0, 46)
oled.show()
time.sleep_ms(800)
# Lanzar Core 1
_thread.start_new_thread(core1_task, ())
# Core 0 se queda en la UI
try:
core0_task()
except KeyboardInterrupt:
# Apaga salidas y limpia OLED si se interrumpe
for p in BIN_PINS:
p.value(0)
oled.fill(0)
oled.text("Detenido", 0, 0)
oled.show()
main()