from machine import Pin, I2C, ADC
import ssd1306
import time
import json
# =========================================================
# CONFIGURACAO
# =========================================================
# True = usa as chaves/botoes de teste do Wokwi
# False = preparado para usar as entradas reais do carro
MODO_TESTE = True
# =========================================================
# ENTRADAS REAIS
# =========================================================
#
# GPIO26 = velocidade atraves do PC817
# GPIO35 = pulso do bico atraves do PC817
# GPIO34 = temperatura do motor - sensor original Gol G3
# GPIO36 = temperatura externa - sensor original Golf Mk4
#
# GPIO34, GPIO35 e GPIO36 sao entradas somente-leitura.
# =========================================================
GPIO_VELOCIDADE_REAL = 26
GPIO_BICO_REAL = 35
GPIO_TEMPERATURA_MOTOR_REAL = 34
GPIO_TEMPERATURA_EXTERNA_REAL = 36
# =========================================================
# OLED
# =========================================================
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
# =========================================================
# BOTOES
# =========================================================
zero = Pin(14, Pin.IN, Pin.PULL_UP)
res = Pin(32, Pin.IN, Pin.PULL_UP)
set_btn = Pin(25, Pin.IN, Pin.PULL_UP)
# =========================================================
# BOTAO DE TESTE DE AQUECIMENTO - SOMENTE WOKWI
# =========================================================
teste_aquecimento = Pin(33, Pin.IN, Pin.PULL_UP)
# =========================================================
# SELETOR ON/OFF
# =========================================================
sw_mode = Pin(18, Pin.IN, Pin.PULL_UP)
# =========================================================
# SELETOR MFA
# =========================================================
mfa1 = Pin(12, Pin.IN, Pin.PULL_UP)
mfa2 = Pin(13, Pin.IN, Pin.PULL_UP)
# =========================================================
# SENSOR DE NIVEL DO RESERVATORIO
# =========================================================
sensor_arrefecimento = Pin(27, Pin.IN, Pin.PULL_UP)
# =========================================================
# BUZZER
# =========================================================
buzzer = Pin(19, Pin.OUT)
buzzer.value(0)
# =========================================================
# LED FISICO DE ALERTA
# =========================================================
led_arrefecimento = Pin(23, Pin.OUT)
led_arrefecimento.value(0)
# =========================================================
# VELOCIDADE - PC817
# =========================================================
speed_input = Pin(
GPIO_VELOCIDADE_REAL,
Pin.IN,
Pin.PULL_UP
)
USAR_VELOCIDADE_REAL = not MODO_TESTE
# =========================================================
# BICO - PC817
# =========================================================
bico_input = Pin(
GPIO_BICO_REAL,
Pin.IN,
Pin.PULL_UP
)
USAR_BICO_REAL = not MODO_TESTE
# =========================================================
# TEMPERATURA DO MOTOR - SENSOR ORIGINAL GOL G3
# =========================================================
#
# O sinal do sensor original do Gol G3 e lido pelo GPIO34.
#
# Valores de referencia utilizados:
#
# 25 C = aproximadamente 2,85 a 3,15 kOhm
# 40 C = aproximadamente 1,51 a 1,67 kOhm
# 80 C = aproximadamente 0,35 a 0,38 kOhm
# 100 C = aproximadamente 0,19 a 0,21 kOhm
#
# Na aplicacao original da injecao:
#
# 25 C -> aproximadamente 3,0 V
# 40 C -> aproximadamente 2,2 V
# 80 C -> aproximadamente 0,8 V
# 100 C -> aproximadamente 0,5 V
#
# O GPIO34 recebe o sinal devidamente protegido.
# =========================================================
temperatura_motor_input = ADC(
GPIO_TEMPERATURA_MOTOR_REAL
)
temperatura_motor_input.atten(
ADC.ATTN_11DB
)
temperatura_motor_input.width(
ADC.WIDTH_12BIT
)
USAR_TEMPERATURA_MOTOR_REAL = not MODO_TESTE
# =========================================================
# TEMPERATURA EXTERNA - SENSOR ORIGINAL GOLF MK4
# =========================================================
#
# Sensor G17 original do Golf Mk4.
#
# Resistencia aproximada:
#
# -30 C = 18,1 kOhm
# 0 C = 3,28 kOhm
# 10 C = 1,99 kOhm
# 20 C = 1,25 kOhm
# 25 C = 1,00 kOhm
# 30 C = 0,80 kOhm
# 40 C = 0,53 kOhm
# 50 C = 0,36 kOhm
# 60 C = 0,25 kOhm
#
# Para a leitura direta pelo ESP32, o sensor sera usado
# em divisor resistivo.
#
# GPIO36 = ponto de leitura do divisor.
# =========================================================
temperatura_externa_input = ADC(
GPIO_TEMPERATURA_EXTERNA_REAL
)
temperatura_externa_input.atten(
ADC.ATTN_11DB
)
temperatura_externa_input.width(
ADC.WIDTH_12BIT
)
USAR_TEMPERATURA_EXTERNA_REAL = not MODO_TESTE
# Resistor fixo do divisor da temperatura externa.
#
# Ligacao prevista:
#
# 3V3 ---- 1.2k ---- GPIO36 ---- SENSOR GOLF MK4 ---- GND
#
RESISTOR_DIVISOR_EXTERNO = 1200.0
# =========================================================
# MEMORIA
# =========================================================
ARQUIVO_ODO = "odometro.json"
ARQUIVO_ESTADO = "estado_mfa.json"
def carregar_odometro():
try:
with open(ARQUIVO_ODO, "r") as arquivo:
dados = json.load(arquivo)
return float(dados["odometro"])
except:
return 168420.0
def salvar_odometro():
try:
with open(ARQUIVO_ODO, "w") as arquivo:
json.dump({"odometro": odometro}, arquivo)
except:
pass
def carregar_estado():
try:
with open(ARQUIVO_ESTADO, "r") as arquivo:
dados = json.load(arquivo)
return (
int(dados.get("pagina", 0)),
int(dados.get("modo_relogio", 0)),
int(dados.get("mode", sw_mode.value())),
int(
dados.get(
"mfa",
1 if mfa1.value() == 0 else 2
)
)
)
except:
return (
0,
0,
sw_mode.value(),
1 if mfa1.value() == 0 else 2
)
def salvar_estado():
try:
with open(ARQUIVO_ESTADO, "w") as arquivo:
json.dump(
{
"pagina": pagina,
"modo_relogio": modo_relogio,
"mode": sw_mode.value(),
"mfa": 1 if mfa1.value() == 0 else 2
},
arquivo
)
except:
pass
# =========================================================
# DADOS
# =========================================================
pagina_salva, modo_relogio, modo_salvo, mfa_salvo = carregar_estado()
modo_atual = sw_mode.value()
mfa_atual = 1 if mfa1.value() == 0 else 2
if modo_salvo == modo_atual and mfa_salvo == mfa_atual:
pagina = pagina_salva
else:
pagina = 0
if pagina < 0:
pagina = 0
if modo_relogio not in (0, 1):
modo_relogio = 0
CAPACIDADE_TANQUE = 51.0
combustivel = CAPACIDADE_TANQUE
combustivel_consumido = 0.0
consumo_inst = 12.4
consumo_medio = 11.2
tempo_motor = 0
trip = 42.8
tempo_viagem = 0
km_rodado = 428.6
media_velocidade = 72.4
velocidade_max = 128
odometro = carregar_odometro()
litros_total = 0.0
autonomia = CAPACIDADE_TANQUE * consumo_medio
# =========================================================
# CORRECAO DE VELOCIDADE
# =========================================================
FATOR_VELOCIDADE = 1.68
# =========================================================
# VELOCIDADE SIMULADA
# =========================================================
velocidade = 65
ultima_velocidade = time.ticks_ms()
direcao_velocidade = 1
velocidade_real = 0.0
# =========================================================
# TEMPERATURA DO MOTOR
# =========================================================
temperatura_motor = 82.0
TEMPERATURA_LIMITE = 95.0
temperatura_superaquecimento = False
# =========================================================
# TEMPERATURA EXTERNA
# =========================================================
temperatura_externa = 24.5
# =========================================================
# CONTROLE DO ALERTA DE TEMPERATURA
# =========================================================
temp_alerta_ativo = False
temp_alerta_inicio = 0
temp_proximo_alerta = 0
temp_bip_numero = 0
temp_bip_ativo = False
temp_bip_inicio = 0
# =========================================================
# RELOGIO
# =========================================================
hora = 14
minuto = 15
segundo = 0
ultimo_segundo = time.ticks_ms()
# =========================================================
# CONTADORES
# =========================================================
ultimo_tempo_motor = time.ticks_ms()
ultimo_tempo_viagem = time.ticks_ms()
ultimo_km = time.ticks_ms()
distancia_media = 0.0
ultimo_media = time.ticks_ms()
ultimo_consumo = time.ticks_ms()
ultimo_salvamento_odo = time.ticks_ms()
# =========================================================
# SENSOR / ALERTA
# =========================================================
arrefecimento_baixo = False
# =========================================================
# CONTROLE DO BUZZER DO NIVEL
# =========================================================
buzzer_ativo = False
buzzer_inicio = 0
bip_1_feito = False
bip_2_feito = False
bip_3_feito = False
proximo_bip = 0
# =========================================================
# CONTROLE DO ALERTA VISUAL DO NIVEL
# =========================================================
alerta_visual_ativo = False
alerta_visual_ate = 0
# =========================================================
# FONTE GRANDE DO RELOGIO
# =========================================================
FONTE_GRANDE = {
"0": [
"01110",
"10001",
"10011",
"10101",
"11001",
"10001",
"01110"
],
"1": [
"00100",
"01100",
"00100",
"00100",
"00100",
"00100",
"01110"
],
"2": [
"01110",
"10001",
"00001",
"00010",
"00100",
"01000",
"11111"
],
"3": [
"11110",
"00001",
"00001",
"01110",
"00001",
"00001",
"11110"
],
"4": [
"00010",
"00110",
"01010",
"10010",
"11111",
"00010",
"00010"
],
"5": [
"11111",
"10000",
"10000",
"11110",
"00001",
"00001",
"11110"
],
"6": [
"01110",
"10000",
"10000",
"11110",
"10001",
"10001",
"01110"
],
"7": [
"11111",
"00001",
"00010",
"00100",
"01000",
"01000",
"01000"
],
"8": [
"01110",
"10001",
"10001",
"01110",
"10001",
"10001",
"01110"
],
"9": [
"01110",
"10001",
"10001",
"01111",
"00001",
"00001",
"01110"
],
":": [
"00000",
"00100",
"00100",
"00000",
"00100",
"00100",
"00000"
]
}
# =========================================================
# FONTE MINI
# =========================================================
FONTE_MINI = {
"0": ["111", "101", "101", "101", "111"],
"1": ["010", "110", "010", "010", "111"],
"2": ["110", "001", "010", "100", "111"],
"3": ["110", "001", "010", "001", "110"],
"4": ["101", "101", "111", "001", "001"],
"5": ["111", "100", "110", "001", "110"],
"6": ["011", "100", "111", "101", "111"],
"7": ["111", "001", "010", "010", "010"],
"8": ["111", "101", "111", "101", "111"],
"9": ["111", "101", "111", "001", "110"],
"/": ["001", "001", "010", "100", "100"],
"-": ["000", "000", "111", "000", "000"],
" ": ["000", "000", "000", "000", "000"],
"S": ["111", "100", "111", "001", "111"],
"E": ["111", "100", "110", "100", "111"],
"T": ["111", "010", "010", "010", "010"],
"A": ["010", "101", "111", "101", "101"],
"I": ["111", "010", "010", "010", "111"],
"R": ["110", "101", "110", "101", "101"]
}
def desenhar_texto_grande(texto, escala, y):
largura_total = 0
for caractere in texto:
largura_total += 5 * escala
if caractere != texto[-1]:
largura_total += escala
x = (128 - largura_total) // 2
for caractere in texto:
desenho = FONTE_GRANDE.get(
caractere,
FONTE_GRANDE["0"]
)
for linha in range(7):
for coluna in range(5):
if desenho[linha][coluna] == "1":
for dx in range(escala):
for dy in range(escala):
oled.pixel(
x + coluna * escala + dx,
y + linha * escala + dy,
1
)
x += (5 * escala) + escala
def desenhar_texto_mini(texto, y):
escala = 1
espaco = 1
largura_total = (
len(texto) * 3
+
(len(texto) - 1) * espaco
)
x = (128 - largura_total) // 2
for caractere in texto:
desenho = FONTE_MINI.get(
caractere,
FONTE_MINI[" "]
)
for linha in range(5):
for coluna in range(3):
if desenho[linha][coluna] == "1":
oled.pixel(
x + coluna,
y + linha,
1
)
x += 3 + espaco
# =========================================================
# LEITURA DO SENSOR
# =========================================================
def atualizar_sensor_arrefecimento():
global arrefecimento_baixo
if sensor_arrefecimento.value() == 0:
arrefecimento_baixo = True
led_arrefecimento.value(1)
else:
arrefecimento_baixo = False
led_arrefecimento.value(0)
# =========================================================
# TEMPERATURA DO MOTOR - GOL G3
# =========================================================
def converter_temperatura_motor_tensao(tensao):
# Pontos de referencia do sensor original do Gol G3.
#
# A conversao e feita por interpolacao linear entre
# os pontos conhecidos.
pontos = [
(0.50, 100.0),
(0.80, 80.0),
(2.20, 40.0),
(3.00, 25.0)
]
if tensao >= pontos[-1][0]:
return 25.0
if tensao <= pontos[0][0]:
return 100.0
for i in range(len(pontos) - 1):
v1, t1 = pontos[i]
v2, t2 = pontos[i + 1]
if v1 <= tensao <= v2:
temperatura = (
t1
+
(
(tensao - v1)
*
(t2 - t1)
/
(v2 - v1)
)
)
return temperatura
return 82.0
def atualizar_temperatura_motor():
global temperatura_motor
if not USAR_TEMPERATURA_MOTOR_REAL:
return
valor_adc = temperatura_motor_input.read()
tensao = (
valor_adc *
3.3 /
4095.0
)
temperatura_motor = converter_temperatura_motor_tensao(
tensao
)
# =========================================================
# TEMPERATURA DO MOTOR - TESTE WOKWI
# =========================================================
def atualizar_temperatura_teste():
global temperatura_motor
if not MODO_TESTE:
return
if teste_aquecimento.value() == 1:
temperatura_motor = 82.0
else:
temperatura_motor = 100.0
# =========================================================
# TEMPERATURA EXTERNA - GOLF MK4
# =========================================================
def converter_temperatura_externa_resistencia(resistencia):
# Curva aproximada do sensor G17 do Golf Mk4.
pontos = [
(18100.0, -30.0),
(9950.0, -20.0),
(5590.0, -10.0),
(3280.0, 0.0),
(2540.0, 5.0),
(1990.0, 10.0),
(1570.0, 15.0),
(1250.0, 20.0),
(1000.0, 25.0),
(800.0, 30.0),
(650.0, 35.0),
(530.0, 40.0),
(360.0, 50.0),
(250.0, 60.0)
]
if resistencia >= pontos[0][0]:
return -30.0
if resistencia <= pontos[-1][0]:
return 60.0
for i in range(len(pontos) - 1):
r1, t1 = pontos[i]
r2, t2 = pontos[i + 1]
if r2 <= resistencia <= r1:
temperatura = (
t1
+
(
(resistencia - r1)
*
(t2 - t1)
/
(r2 - r1)
)
)
return temperatura
return 24.5
def atualizar_temperatura_externa():
global temperatura_externa
if not USAR_TEMPERATURA_EXTERNA_REAL:
temperatura_externa = 24.5
return
valor_adc = temperatura_externa_input.read()
if valor_adc <= 0:
return
if valor_adc >= 4094:
return
tensao = (
valor_adc *
3.3 /
4095.0
)
if tensao <= 0.01:
return
if tensao >= 3.29:
return
# Divisor:
#
# 3V3 -> resistor fixo -> ADC -> sensor -> GND
#
# R_sensor = R_fixo * Vadc / (3.3 - Vadc)
resistencia = (
RESISTOR_DIVISOR_EXTERNO *
tensao
/
(3.3 - tensao)
)
temperatura_externa = (
converter_temperatura_externa_resistencia(
resistencia
)
)
# =========================================================
# ALERTA DE TEMPERATURA
# =========================================================
def atualizar_alerta_temperatura():
global temperatura_superaquecimento
global temp_alerta_ativo
global temp_alerta_inicio
global temp_proximo_alerta
global temp_bip_numero
global temp_bip_ativo
global temp_bip_inicio
agora = time.ticks_ms()
if temperatura_motor <= TEMPERATURA_LIMITE:
temperatura_superaquecimento = False
temp_alerta_ativo = False
temp_alerta_inicio = 0
temp_proximo_alerta = 0
temp_bip_numero = 0
temp_bip_ativo = False
temp_bip_inicio = 0
return
if not temperatura_superaquecimento:
temperatura_superaquecimento = True
temp_alerta_ativo = True
temp_alerta_inicio = agora
temp_proximo_alerta = agora + 4000
temp_bip_numero = 1
temp_bip_ativo = True
temp_bip_inicio = agora
buzzer.value(1)
return
if temp_bip_ativo:
tempo_bip = time.ticks_diff(
agora,
temp_bip_inicio
)
if tempo_bip >= 150:
buzzer.value(0)
temp_bip_ativo = False
temp_bip_inicio = agora
return
if temp_bip_numero < 3:
tempo_entre_bips = time.ticks_diff(
agora,
temp_bip_inicio
)
if tempo_entre_bips >= 100:
temp_bip_numero += 1
temp_bip_ativo = True
temp_bip_inicio = agora
buzzer.value(1)
return
if temp_alerta_ativo:
tempo_alerta = time.ticks_diff(
agora,
temp_alerta_inicio
)
if tempo_alerta >= 3000:
temp_alerta_ativo = False
if time.ticks_diff(
agora,
temp_proximo_alerta
) >= 0:
temp_alerta_ativo = True
temp_alerta_inicio = agora
temp_proximo_alerta = agora + 4000
temp_bip_numero = 1
temp_bip_ativo = True
temp_bip_inicio = agora
buzzer.value(1)
# =========================================================
# INICIAR BIP DO NIVEL
# =========================================================
def iniciar_bip():
global buzzer_ativo
global buzzer_inicio
global alerta_visual_ativo
global alerta_visual_ate
agora = time.ticks_ms()
buzzer.value(1)
buzzer_ativo = True
buzzer_inicio = agora
alerta_visual_ativo = True
alerta_visual_ate = agora + 3000
# =========================================================
# ATUALIZAR BUZZER DO NIVEL
# =========================================================
def atualizar_buzzer():
global buzzer_ativo
global buzzer_inicio
global bip_1_feito
global bip_2_feito
global bip_3_feito
global proximo_bip
global alerta_visual_ativo
global alerta_visual_ate
agora = time.ticks_ms()
if temperatura_superaquecimento:
return
if not arrefecimento_baixo:
buzzer.value(0)
buzzer_ativo = False
bip_1_feito = False
bip_2_feito = False
bip_3_feito = False
proximo_bip = 0
alerta_visual_ativo = False
alerta_visual_ate = 0
return
if buzzer_ativo:
if time.ticks_diff(
agora,
buzzer_inicio
) >= 600:
buzzer.value(0)
buzzer_ativo = False
if alerta_visual_ativo:
if time.ticks_diff(
agora,
alerta_visual_ate
) >= 0:
alerta_visual_ativo = False
if not bip_1_feito:
iniciar_bip()
bip_1_feito = True
proximo_bip = agora + 5000
return
if obter_velocidade() <= 0:
return
if not bip_2_feito:
if time.ticks_diff(
agora,
proximo_bip
) >= 0:
iniciar_bip()
bip_2_feito = True
proximo_bip = agora + 5000
return
if not bip_3_feito:
if time.ticks_diff(
agora,
proximo_bip
) >= 0:
iniciar_bip()
bip_3_feito = True
proximo_bip = agora + 30000
return
if bip_3_feito:
if time.ticks_diff(
agora,
proximo_bip
) >= 0:
iniciar_bip()
proximo_bip = agora + 30000
# =========================================================
# MOSTRAR ALERTA DE NIVEL
# =========================================================
def mostrar_alerta_arrefecimento():
oled.fill(0)
oled.text("!", 60, 5)
oled.text(
"ARREFECIMENTO",
10,
25
)
oled.text(
"BAIXO",
46,
40
)
oled.show()
# =========================================================
# MOSTRAR ALERTA DE TEMPERATURA
# =========================================================
def mostrar_alerta_temperatura():
oled.fill(0)
oled.text(
"!",
60,
5
)
oled.text(
"AQUECIMENTO",
16,
25
)
oled.text(
"MOTOR",
44,
40
)
oled.show()
# =========================================================
# RELOGIO
# =========================================================
def atualizar_relogio():
global hora
global minuto
global segundo
global ultimo_segundo
agora = time.ticks_ms()
if time.ticks_diff(
agora,
ultimo_segundo
) >= 1000:
ultimo_segundo += 1000
segundo += 1
if segundo >= 60:
segundo = 0
minuto += 1
if minuto >= 60:
minuto = 0
hora += 1
if hora >= 24:
hora = 0
# =========================================================
# VELOCIDADE SIMULADA
# =========================================================
def atualizar_velocidade_simulada():
global velocidade
global ultima_velocidade
global direcao_velocidade
agora = time.ticks_ms()
if time.ticks_diff(
agora,
ultima_velocidade
) >= 500:
ultima_velocidade += 500
velocidade += direcao_velocidade * 5
if velocidade >= 120:
velocidade = 120
direcao_velocidade = -1
if velocidade <= 0:
velocidade = 0
direcao_velocidade = 1
# =========================================================
# VELOCIDADE UTILIZADA PELO MFA
# =========================================================
def obter_velocidade():
if USAR_VELOCIDADE_REAL:
return velocidade_real
return velocidade * FATOR_VELOCIDADE
# =========================================================
# LEITURA DO BICO
# =========================================================
def ler_pulso_bico():
if USAR_BICO_REAL:
return bico_input.value()
return 0
# =========================================================
# VELOCIDADE REAL - PC817
# =========================================================
def atualizar_velocidade_real():
global velocidade_real
if not USAR_VELOCIDADE_REAL:
return
# Leitura da entrada real do PC817.
#
# O calculo definitivo km/h por frequencia sera calibrado
# conforme o sinal real do sensor de velocidade do Gol G3.
#
# Por enquanto mantem a ultima velocidade calculada.
estado = speed_input.value()
_ = estado
# =========================================================
# CORTE DE COMBUSTIVEL
# =========================================================
def corte_combustivel():
if (
not USAR_VELOCIDADE_REAL
and
velocidade > 60
and
direcao_velocidade == -1
):
return True
return False
# =========================================================
# VELOCIDADE MAXIMA
# =========================================================
def atualizar_velocidade_maxima():
global velocidade_max
velocidade_atual = obter_velocidade()
if velocidade_atual > velocidade_max:
velocidade_max = velocidade_atual
# =========================================================
# TEMPOS
# =========================================================
def atualizar_tempos():
global tempo_motor
global tempo_viagem
global ultimo_tempo_motor
global ultimo_tempo_viagem
agora = time.ticks_ms()
velocidade_atual = obter_velocidade()
if velocidade_atual > 0:
if time.ticks_diff(
agora,
ultimo_tempo_motor
) >= 1000:
ultimo_tempo_motor += 1000
tempo_motor += 1
else:
ultimo_tempo_motor = agora
if velocidade_atual > 0:
if time.ticks_diff(
agora,
ultimo_tempo_viagem
) >= 1000:
ultimo_tempo_viagem += 1000
tempo_viagem += 1
else:
ultimo_tempo_viagem = agora
# =========================================================
# DISTANCIAS
# =========================================================
def atualizar_distancias():
global trip
global km_rodado
global odometro
global ultimo_km
global distancia_media
global ultimo_media
agora = time.ticks_ms()
velocidade_atual = obter_velocidade()
if velocidade_atual > 0:
tempo_passado = time.ticks_diff(
agora,
ultimo_km
)
if tempo_passado >= 1000:
segundos = tempo_passado / 1000.0
distancia = (
velocidade_atual / 3600.0
) * segundos
trip += distancia
km_rodado += distancia
odometro += distancia
ultimo_km = agora
tempo_media_passado = time.ticks_diff(
agora,
ultimo_media
)
if tempo_media_passado >= 1000:
segundos_media = (
tempo_media_passado / 1000.0
)
distancia_media += (
velocidade_atual / 3600.0
) * segundos_media
ultimo_media = agora
else:
ultimo_km = agora
ultimo_media = agora
# =========================================================
# SALVAR ODOMETRO
# =========================================================
def atualizar_memoria_odometro():
global ultimo_salvamento_odo
agora = time.ticks_ms()
if time.ticks_diff(
agora,
ultimo_salvamento_odo
) >= 10000:
salvar_odometro()
ultimo_salvamento_odo = agora
# =========================================================
# MEDIA DE VELOCIDADE
# =========================================================
def atualizar_media_velocidade():
global media_velocidade
if tempo_viagem > 0:
media_velocidade = (
distancia_media /
(tempo_viagem / 3600.0)
)
# =========================================================
# CONSUMO E AUTONOMIA
# =========================================================
def atualizar_consumo():
global consumo_inst
global consumo_medio
global combustivel
global combustivel_consumido
global litros_total
global autonomia
global ultimo_consumo
agora = time.ticks_ms()
velocidade_atual = obter_velocidade()
if corte_combustivel():
consumo_inst = 0.0
elif velocidade_atual > 0:
consumo_inst = (
16.0 -
(velocidade_atual * 0.06)
)
if consumo_inst < 7.0:
consumo_inst = 7.0
else:
consumo_inst = 1.2
if time.ticks_diff(
agora,
ultimo_consumo
) >= 1000:
segundos = time.ticks_diff(
agora,
ultimo_consumo
) / 1000.0
ultimo_consumo = agora
if corte_combustivel():
litros = 0.0
elif velocidade_atual > 0:
distancia = (
velocidade_atual / 3600.0
) * segundos
litros = (
distancia /
consumo_inst
)
else:
litros = (
1.2 *
(segundos / 3600.0)
)
combustivel_consumido += litros
if combustivel_consumido > CAPACIDADE_TANQUE:
combustivel_consumido = CAPACIDADE_TANQUE
litros_total = combustivel_consumido
combustivel = (
CAPACIDADE_TANQUE -
combustivel_consumido
)
if trip > 0 and combustivel_consumido > 0:
consumo_medio = (
trip /
combustivel_consumido
)
if combustivel > 0 and consumo_medio > 0:
autonomia = (
combustivel *
consumo_medio
)
else:
autonomia = 0
# =========================================================
# TEMPERATURA EXTERNA
# =========================================================
def mostrar_temperatura_externa():
texto = "{:.1f}C".format(
temperatura_externa
)
largura = len(texto) * 8
x = (128 - largura) // 2
oled.text(
texto,
x,
0
)
# =========================================================
# DISPLAY
# =========================================================
def mostrar():
if temp_alerta_ativo:
mostrar_alerta_temperatura()
return
if alerta_visual_ativo:
mostrar_alerta_arrefecimento()
return
# =====================================================
# RELOGIO DE MESA
# =====================================================
if modo_relogio == 1:
oled.fill(0)
mostrar_temperatura_externa()
desenhar_texto_grande(
"{:02d}:{:02d}".format(
hora,
minuto
),
3,
10
)
desenhar_texto_mini(
"03/10/2026",
40
)
desenhar_texto_mini(
"SET - SAIR",
57
)
oled.show()
return
oled.fill(0)
if mfa1.value() == 0:
posicao = 1
else:
posicao = 2
velocidade_atual = obter_velocidade()
# =====================================================
# MODO SIMPLES
# =====================================================
if sw_mode.value() == 1:
if posicao == 1:
if pagina == 0:
oled.text(
"{:.1f}".format(consumo_medio),
42,
10
)
oled.text(
"med km/L",
37,
41
)
else:
oled.text(
str(int(velocidade_atual)),
52,
10
)
oled.text(
"km/h",
50,
41
)
else:
if pagina == 0:
oled.text(
"{:.1f}".format(trip),
45,
10
)
oled.text(
"trip 1",
46,
41
)
else:
minutos = tempo_viagem // 60
segundos_tv = tempo_viagem % 60
texto = "{:02d}:{:02d}".format(
minutos,
segundos_tv
)
oled.text(
texto,
44,
10
)
oled.text(
"tempo viag",
31,
41
)
# =====================================================
# MODO AVANCADO
# =====================================================
else:
if posicao == 1:
if pagina == 0:
if corte_combustivel():
oled.text(
"---",
52,
10
)
oled.text(
"km/L inst",
35,
41
)
elif velocidade_atual > 0:
oled.text(
"{:.1f}".format(consumo_inst),
42,
10
)
oled.text(
"km/L inst",
35,
41
)
else:
oled.text(
"{:.1f}".format(consumo_inst),
42,
10
)
oled.text(
"L/h inst",
39,
41
)
elif pagina == 1:
oled.text(
"{:.1f}".format(consumo_medio),
42,
10
)
oled.text(
"med km/L",
37,
41
)
elif pagina == 2:
minutos = tempo_motor // 60
segundos_tm = tempo_motor % 60
texto = "{:02d}:{:02d}".format(
minutos,
segundos_tm
)
oled.text(
texto,
44,
10
)
oled.text(
"motor lig",
38,
41
)
else:
oled.text(
"TEMP. MOTOR:",
0,
25
)
oled.text(
"{:.0f} C".format(
temperatura_motor
),
82,
25
)
oled.text(
"BATERIA :",
0,
40
)
oled.text(
"14.2 V",
82,
40
)
else:
if pagina == 0:
oled.text(
"{:.1f}".format(km_rodado),
38,
10
)
oled.text(
"km rodado",
36,
41
)
elif pagina == 1:
oled.text(
"{:.1f}".format(media_velocidade),
42,
10
)
oled.text(
"med km/h",
37,
41
)
elif pagina == 2:
oled.text(
str(int(velocidade_max)),
48,
10
)
oled.text(
"max km/h",
37,
41
)
elif pagina == 3:
oled.text(
"{:.1f}".format(odometro),
34,
10
)
oled.text(
"odo total",
39,
41
)
elif pagina == 4:
oled.text(
"{:.1f}".format(litros_total),
42,
10
)
oled.text(
"litros tot",
34,
41
)
else:
oled.text(
"{:.0f}".format(autonomia),
44,
10
)
oled.text(
"auton km",
39,
41
)
# =====================================================
# RELOGIO
# =====================================================
relogio = "{:02d}:{:02d}".format(
hora,
minuto
)
oled.text(
relogio,
0,
0
)
# =====================================================
# ON/OFF
# =====================================================
if sw_mode.value() == 0:
oled.text("ON", 110, 0)
else:
oled.text("OFF", 104, 0)
# =====================================================
# MFA
# =====================================================
if mfa1.value() == 0:
oled.text("M1", 110, 54)
else:
oled.text("M2", 110, 54)
# =====================================================
# DATA
# =====================================================
oled.text(
"03/10/26",
0,
54
)
# =====================================================
# TEMPERATURA EXTERNA
# =====================================================
texto_temp = "{:.1f}C".format(
temperatura_externa
)
oled.text(
texto_temp,
82,
54
)
oled.show()
# =========================================================
# RESET DA FUNCAO
# =========================================================
def resetar_funcao():
global consumo_inst
global consumo_medio
global tempo_motor
global trip
global tempo_viagem
global km_rodado
global media_velocidade
global velocidade_max
global litros_total
global autonomia
global distancia_media
global combustivel_consumido
global combustivel
if mfa1.value() == 0:
if pagina == 0:
consumo_inst = 0.0
elif pagina == 1:
consumo_medio = 0.0
combustivel_consumido = 0.0
litros_total = 0.0
combustivel = CAPACIDADE_TANQUE
elif pagina == 2:
tempo_motor = 0
else:
if pagina == 0:
km_rodado = 0.0
distancia_media = 0.0
elif pagina == 1:
media_velocidade = 0.0
distancia_media = 0.0
elif pagina == 2:
velocidade_max = 0
elif pagina == 4:
litros_total = 0.0
combustivel_consumido = 0.0
combustivel = CAPACIDADE_TANQUE
elif pagina == 5:
autonomia = (
combustivel *
consumo_medio
)
mostrar()
# =========================================================
# MASTER RESET
# =========================================================
def master_reset():
global consumo_inst
global consumo_medio
global tempo_motor
global trip
global tempo_viagem
global km_rodado
global media_velocidade
global velocidade_max
global litros_total
global autonomia
global distancia_media
global combustivel_consumido
global combustivel
consumo_inst = 0.0
consumo_medio = 0.0
tempo_motor = 0
trip = 0.0
tempo_viagem = 0
km_rodado = 0.0
distancia_media = 0.0
media_velocidade = 0.0
velocidade_max = 0
litros_total = 0.0
combustivel_consumido = 0.0
combustivel = CAPACIDADE_TANQUE
autonomia = (
CAPACIDADE_TANQUE *
consumo_medio
)
mostrar()
# =========================================================
# ABASTECIMENTO
# =========================================================
def abastecer():
global combustivel
global combustivel_consumido
global litros_total
global autonomia
if obter_velocidade() > 0:
return
combustivel = CAPACIDADE_TANQUE
combustivel_consumido = 0.0
litros_total = 0.0
autonomia = (
CAPACIDADE_TANQUE *
consumo_medio
)
mostrar()
# =========================================================
# INICIALIZACAO
# =========================================================
atualizar_sensor_arrefecimento()
atualizar_temperatura_teste()
atualizar_temperatura_motor()
atualizar_temperatura_externa()
atualizar_alerta_temperatura()
atualizar_buzzer()
mostrar()
anterior_zero = zero.value()
anterior_res = res.value()
anterior_set = set_btn.value()
anterior_mode = sw_mode.value()
anterior_mfa1 = mfa1.value()
anterior_mfa2 = mfa2.value()
res_pressionado = False
inicio_res = 0
reset_2s_executado = False
reset_5s_executado = False
# =========================================================
# SET - CONTROLE POR PULSO
# =========================================================
set_pressionado = False
inicio_set = 0
set_5s_executado = False
ultimo_display = time.ticks_ms()
# =========================================================
# LOOP PRINCIPAL
# =========================================================
while True:
atualizar_relogio()
atualizar_sensor_arrefecimento()
if not USAR_VELOCIDADE_REAL:
atualizar_velocidade_simulada()
else:
atualizar_velocidade_real()
atualizar_temperatura_teste()
atualizar_temperatura_motor()
atualizar_temperatura_externa()
atualizar_alerta_temperatura()
atualizar_velocidade_maxima()
atualizar_tempos()
atualizar_distancias()
atualizar_media_velocidade()
atualizar_consumo()
atualizar_memoria_odometro()
atualizar_buzzer()
atual_zero = zero.value()
atual_res = res.value()
atual_set = set_btn.value()
atual_mode = sw_mode.value()
atual_mfa1 = mfa1.value()
atual_mfa2 = mfa2.value()
# =====================================================
# ALERTA DE TEMPERATURA
# =====================================================
if temp_alerta_ativo:
mostrar_alerta_temperatura()
anterior_zero = atual_zero
anterior_res = atual_res
anterior_set = atual_set
anterior_mode = atual_mode
anterior_mfa1 = atual_mfa1
anterior_mfa2 = atual_mfa2
time.sleep_ms(50)
continue
# =====================================================
# ALERTA VISUAL DO NIVEL
# =====================================================
if alerta_visual_ativo:
mostrar_alerta_arrefecimento()
anterior_zero = atual_zero
anterior_res = atual_res
anterior_set = atual_set
anterior_mode = atual_mode
anterior_mfa1 = atual_mfa1
anterior_mfa2 = atual_mfa2
time.sleep_ms(50)
continue
# =====================================================
# PAGINAS
# =====================================================
if atual_mfa1 == 0:
if atual_mode == 0:
max_pagina = 3
else:
max_pagina = 1
else:
if atual_mode == 0:
max_pagina = 1
else:
max_pagina = 5
# =====================================================
# ZERO
# =====================================================
if anterior_zero == 1 and atual_zero == 0:
pagina += 1
if pagina > max_pagina:
pagina = 0
salvar_estado()
mostrar()
time.sleep_ms(300)
anterior_zero = zero.value()
# =====================================================
# RES - INICIO
# =====================================================
if anterior_res == 1 and atual_res == 0:
res_pressionado = True
inicio_res = time.ticks_ms()
reset_2s_executado = False
reset_5s_executado = False
# =====================================================
# RES - PRESSAO
# =====================================================
if res_pressionado and atual_res == 0:
tempo_pressao = time.ticks_diff(
time.ticks_ms(),
inicio_res
)
if tempo_pressao >= 2000:
if not reset_2s_executado:
resetar_funcao()
reset_2s_executado = True
if tempo_pressao >= 5000:
if not reset_5s_executado:
master_reset()
reset_5s_executado = True
# =====================================================
# RES - SOLTO
# =====================================================
if res_pressionado and atual_res == 1:
if not reset_2s_executado:
pagina -= 1
if pagina < 0:
pagina = max_pagina
salvar_estado()
mostrar()
res_pressionado = False
# =====================================================
# SET - DETECTA PULSO / PRESSIONAR
# IGUAL AO ZERO
# =====================================================
if anterior_set == 1 and atual_set == 0:
set_pressionado = True
inicio_set = time.ticks_ms()
set_5s_executado = False
# =====================================================
# SET - SEGURANDO
# =====================================================
if set_pressionado and atual_set == 0:
tempo_set = time.ticks_diff(
time.ticks_ms(),
inicio_set
)
if tempo_set >= 5000:
if not set_5s_executado:
set_5s_executado = True
if obter_velocidade() <= 0:
abastecer()
# =====================================================
# SET - SOLTO
# =====================================================
if set_pressionado and anterior_set == 0 and atual_set == 1:
tempo_total_set = time.ticks_diff(
time.ticks_ms(),
inicio_set
)
# TOQUE CURTO
if (
tempo_total_set < 5000
and not set_5s_executado
):
if modo_relogio == 0:
modo_relogio = 1
else:
modo_relogio = 0
salvar_estado()
mostrar()
set_pressionado = False
set_5s_executado = False
# =====================================================
# ON/OFF
# =====================================================
if atual_mode != anterior_mode:
pagina = 0
salvar_estado()
mostrar()
# =====================================================
# MFA
# =====================================================
if (
atual_mfa1 != anterior_mfa1
or
atual_mfa2 != anterior_mfa2
):
pagina = 0
salvar_estado()
mostrar()
# =====================================================
# DISPLAY
# =====================================================
agora_display = time.ticks_ms()
if time.ticks_diff(
agora_display,
ultimo_display
) >= 200:
ultimo_display = agora_display
mostrar()
# =====================================================
# ESTADOS ANTERIORES
# =====================================================
anterior_zero = atual_zero
anterior_res = atual_res
anterior_set = atual_set
anterior_mode = atual_mode
anterior_mfa1 = atual_mfa1
anterior_mfa2 = atual_mfa2
time.sleep_ms(20)