# =========================================================
# LABORATORIO DE MICROPROCESADORES Y MICROCONTROLADORES
# BLOQUE 6 - VOLTIMETRO + OHMETRO + AMPERIMETRO + DHT22
# Raspberry Pi Pico W
# =========================================================
# =========================================================
# IMPORTS
# =========================================================
from machine import Pin, I2C, Timer, ADC
from ssd1306 import SSD1306_I2C
import utime
import dht
# =========================================================
# CONFIGURACION DE HARDWARE
# =========================================================
# ---------------- OLED SSD1306 ----------------
# SDA -> GP0
# SCL -> GP1
ANCHO_OLED = 128
ALTO_OLED = 64
i2c = I2C(
0,
scl=Pin(1),
sda=Pin(0),
freq=400000
)
oled = SSD1306_I2C(
ANCHO_OLED,
ALTO_OLED,
i2c
)
# ---------------- BOTON ----------------
# GP15 con pull-up interno
boton = Pin(
15,
Pin.IN,
Pin.PULL_UP
)
# ---------------- DHT22 ----------------
# DATA -> GP16
sensor_dht = dht.DHT22(Pin(16))
# ---------------- ADC VOLTIMETRO ----------------
# GP28 -> ADC2
adc_voltimetro = ADC(28)
# ---------------- ADC OHMETRO ----------------
# GP27 -> ADC1
adc_ohmetro = ADC(27)
# ---------------- ADC AMPERIMETRO ----------------
# GP26 -> ADC0
adc_amperimetro = ADC(26)
# =========================================================
# VARIABLES GLOBALES DEL SISTEMA
# =========================================================
# ---------------- MAQUINA DE ESTADOS ----------------
MODOS = [
"DSP",
"VOLTIMETRO",
"OHMETRO",
"AMPERIMETRO",
"DHT22"
]
modo_actual = 0
# ---------------- RTC SOFTWARE ----------------
horas = 14
minutos = 25
segundos = 0
# ---------------- FLAGS ----------------
flag_actualizar_status = False
flag_cambio_modo = True
# ---------------- DEBOUNCE ----------------
ultimo_boton = 0
DEBOUNCE_MS = 200
# ---------------- BATERIA ----------------
bateria = 100
# ---------------- OHMETRO ----------------
R_REFERENCIA = 10000 # 10k ohms
VIN = 3.3
# ---------------- AMPERIMETRO ----------------
R_SHUNT = 10 # ohms
# =========================================================
# FUNCIONES OLED
# =========================================================
def dibujar_barra_estado():
"""
Dibuja la barra superior:
- reloj
- bateria
"""
oled.fill_rect(0, 0, 128, 16, 0)
reloj = "{:02d}:{:02d}:{:02d}".format(
horas,
minutos,
segundos
)
oled.text(reloj, 0, 4)
texto_bateria = "{}%".format(bateria)
oled.text(texto_bateria, 88, 4)
oled.hline(0, 15, 128, 1)
def limpiar_area_trabajo():
"""
Limpia SOLO el area de trabajo:
filas 16 -> 64
"""
oled.fill_rect(0, 16, 128, 48, 0)
def dibujar_modo_actual():
"""
Muestra el modo seleccionado
"""
limpiar_area_trabajo()
oled.text("MODO:", 0, 25)
oled.text(
MODOS[modo_actual],
0,
40
)
# =========================================================
# MODO VOLTIMETRO
# =========================================================
def modo_voltimetro():
"""
Funcion principal del voltimetro digital.
"""
lectura_adc = adc_voltimetro.read_u16()
voltaje = (lectura_adc * 3.3) / 65535
limpiar_area_trabajo()
oled.text("VOLTIMETRO", 0, 20)
oled.text(
"ADC: {}".format(lectura_adc),
0,
35
)
oled.text(
"V: {:.2f} V".format(voltaje),
0,
50
)
# =========================================================
# MODO OHMETRO
# =========================================================
def modo_ohmetro():
"""
Funcion principal del ohmetro digital.
"""
lectura_adc = adc_ohmetro.read_u16()
voltaje = (lectura_adc * VIN) / 65535
# Evitar division por cero
if voltaje >= VIN:
resistencia = 999999
else:
resistencia = (
R_REFERENCIA * voltaje
) / (VIN - voltaje)
limpiar_area_trabajo()
oled.text("OHMETRO", 0, 18)
oled.text(
"ADC: {}".format(lectura_adc),
0,
32
)
oled.text(
"V: {:.2f} V".format(voltaje),
0,
44
)
resistencia_k = resistencia / 1000
oled.text(
"R: {:.2f}k".format(resistencia_k),
0,
56
)
# =========================================================
# MODO AMPERIMETRO
# =========================================================
def modo_amperimetro():
"""
Funcion principal del amperimetro digital.
"""
lectura_adc = adc_amperimetro.read_u16()
# Conversion ADC -> Voltaje
voltaje_shunt = (
lectura_adc * 3.3
) / 65535
# Ley de Ohm
corriente = voltaje_shunt / R_SHUNT
limpiar_area_trabajo()
oled.text("AMPERIMETRO", 0, 18)
oled.text(
"ADC: {}".format(lectura_adc),
0,
32
)
oled.text(
"V: {:.2f} V".format(voltaje_shunt),
0,
44
)
oled.text(
"I: {:.3f} A".format(corriente),
0,
56
)
# =========================================================
# MODO DHT22
# =========================================================
def modo_dht22():
"""
Funcion principal del sensor DHT22.
"""
try:
# Leer sensor
sensor_dht.measure()
temperatura = sensor_dht.temperature()
humedad = sensor_dht.humidity()
limpiar_area_trabajo()
oled.text("DHT22", 0, 18)
oled.text(
"Temp:",
0,
34
)
oled.text(
"{:.1f} C".format(temperatura),
48,
34
)
oled.text(
"Hum:",
0,
50
)
oled.text(
"{:.1f} %".format(humedad),
48,
50
)
except:
limpiar_area_trabajo()
oled.text("DHT22 ERROR", 0, 30)
# =========================================================
# FUNCIONES ISR
# =========================================================
def timer_callback(timer):
"""
ISR del timer periodico.
SOLO:
- actualiza RTC
- activa flags
NO:
- display.show()
- print()
- delays
"""
global segundos
global minutos
global horas
global flag_actualizar_status
segundos += 1
if segundos >= 60:
segundos = 0
minutos += 1
if minutos >= 60:
minutos = 0
horas += 1
if horas >= 24:
horas = 0
flag_actualizar_status = True
def boton_irq(pin):
"""
ISR del boton.
Implementa:
- debounce
- cambio de modo
SOLO modifica variables globales.
"""
global ultimo_boton
global modo_actual
global flag_cambio_modo
tiempo_actual = utime.ticks_ms()
if utime.ticks_diff(
tiempo_actual,
ultimo_boton
) > DEBOUNCE_MS:
modo_actual += 1
if modo_actual >= len(MODOS):
modo_actual = 0
flag_cambio_modo = True
ultimo_boton = tiempo_actual
# =========================================================
# FUNCIONES DEL SISTEMA
# =========================================================
def inicializar_pantalla():
"""
Inicializa la interfaz grafica
"""
oled.fill(0)
dibujar_barra_estado()
dibujar_modo_actual()
oled.show()
# =========================================================
# CONFIGURACION DE INTERRUPCIONES
# =========================================================
timer_reloj = Timer()
timer_reloj.init(
period=1000,
mode=Timer.PERIODIC,
callback=timer_callback
)
boton.irq(
trigger=Pin.IRQ_FALLING,
handler=boton_irq
)
# =========================================================
# INICIALIZACION
# =========================================================
inicializar_pantalla()
# =========================================================
# MAIN LOOP
# =========================================================
while True:
# ---------------------------------------------
# ACTUALIZAR BARRA SUPERIOR
# ---------------------------------------------
if flag_actualizar_status:
flag_actualizar_status = False
dibujar_barra_estado()
oled.show()
# ---------------------------------------------
# CAMBIO DE MODO
# ---------------------------------------------
if flag_cambio_modo:
flag_cambio_modo = False
dibujar_modo_actual()
oled.show()
# ---------------------------------------------
# MODOS
# ---------------------------------------------
# VOLTIMETRO
if MODOS[modo_actual] == "VOLTIMETRO":
modo_voltimetro()
oled.show()
# OHMETRO
elif MODOS[modo_actual] == "OHMETRO":
modo_ohmetro()
oled.show()
# AMPERIMETRO
elif MODOS[modo_actual] == "AMPERIMETRO":
modo_amperimetro()
oled.show()
# DHT22
elif MODOS[modo_actual] == "DHT22":
modo_dht22()
oled.show()
# ---------------------------------------------
# PEQUEÑO RETARDO DE ESTABILIDAD
# ---------------------------------------------
utime.sleep_ms(200)