from machine import Pin, I2C, ADC, PWM
from ssd1306 import SSD1306_I2C
import sys
import time
import random
import math
from lexer import Lexer
from parser import Parser
from evaluator import Evaluator
# Configuración I2C para la pantalla OLED
# === Inicialización de pantalla y hardware ===
i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000)
oled = SSD1306_I2C(128, 64, i2c)
buffer = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x10\x8a\n0\x10$\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\xfe\xff?\xfe\xfd|\xfb\xf8\xfc\xff|\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\xc0@\xe0\xe0\xe0\xc0\xc1c\x9f\xff\x0f\xce\xff\xff\xcf\xe3\xf0pp\xa0\xe0\xe0\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xff\xfb\xe7\xdf\x8e\x9e\xfd\x95"$%\x00\xfe\xff\xff\xed\xdd\xce\xce\xff\xe7\xe7\xf7\xfb\xf9\xfep\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@6\x9bg7\xcfo\x9d\xdb?\xbbws\xf7\xfa\xfa\xf9\xf4\xfd\xf7\xf3\xf1\xfdsy\xbd;\xd9\x9do\xcc6g\x9b6@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x02\x01\x04\x03\t\x06\x13\x0c&\x19\r\x1b\x1b\r\x19&\x0c\x13\x06\t\x03\x04\x01\x02\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
fb = framebuf.FrameBuffer(buffer, 48, 48, framebuf.MVLSB)
def clear_screen():
oled.fill(0)
oled.show()
def draw_axes(x_min=-10, x_max=10, y_min=-5, y_max=5):
oled.fill(0)
# Calcular escalas
x_scale = 128 / (x_max - x_min)
y_scale = 64 / (y_max - y_min)
# Origen (donde x=0, y=0)
origin_x = int(-x_min * x_scale)
origin_y = int(y_max * y_scale)
# Dibujar ejes
oled.hline(0, origin_y, 128, 1) # Eje X
oled.vline(origin_x, 0, 64, 1) # Eje Y
# Pequeñas marcas en los ejes
for x in range(int(x_min), int(x_max)+1):
if x != 0:
pos_x = int((x - x_min) * x_scale)
oled.vline(pos_x, origin_y-2, 5, 1)
for y in range(int(y_min), int(y_max)+1):
if y != 0:
pos_y = int((y_max - y) * y_scale)
oled.hline(origin_x-2, pos_y, 5, 1)
oled.show()
return x_scale, y_scale, origin_x, origin_y
def plot_function(expr, x_min=-10, x_max=10, y_min=-5, y_max=5):
try:
# Procesar la expresión
lexer = Lexer(expr)
tokens = lexer.tokenize()
parser = Parser(tokens)
ast = parser.parse()
evaluator = Evaluator()
# Dibujar ejes
x_scale, y_scale, origin_x, origin_y = draw_axes(x_min, x_max, y_min, y_max)
# Evaluar y graficar la función
prev_pixel_y = None
for pixel_x in range(128):
# Convertir coordenada de pantalla a valor x matemático
x = x_min + (pixel_x / x_scale)
try:
y = evaluator.evaluate(ast, x)
# Limitar y al rango visible
y = max(min(y, y_max), y_min)
# Convertir valor y a coordenada de pantalla
pixel_y = int((y_max - y) * y_scale)
# Dibujar punto
oled.pixel(pixel_x, pixel_y, 1)
# Conectar con el punto anterior (para línea continua)
if prev_pixel_y is not None:
# Dibujar línea entre puntos consecutivos
oled.line(pixel_x-1, prev_pixel_y, pixel_x, pixel_y, 1)
prev_pixel_y = pixel_y
except:
# Si hay error (división por cero, etc.), no conectamos los puntos
prev_pixel_y = None
oled.show()
return True
except Exception as e:
print("Error al graficar:", e)
clear_screen()
oled.text("Error en", 0, 20)
oled.text("la funcion", 0, 30)
oled.show()
utime.sleep(2)
return False
def main():
print("Graficando un BMP")
oled.fill(0)
oled.blit(fb, 8, 0)
oled.show()
time.sleep(2)
#oled.fill(0)
print("Mensaje")
oled.text("Pi Pico W", 45, 0)
oled.text("SSD1306", 50, 10)
oled.text("Dr.Pereira", 39, 45)
oled.show()
time.sleep(4)
oled.fill(0)
clear_screen()
draw_axes()
print("Calculadora Grafica")
print("Ingrese funcion (ej. '3*x + sin(x)') o 'quit' para salir")
while True:
expr = input("f(x) = ").strip()
if expr.lower() == 'quit':
break
if plot_function(expr):
print("Funcion graficada correctamente")
if __name__ == "__main__":
main()