/*******************************************************************************
FileName: main.c
Dependencies: Veja a secao de includes
Processor: Raspberry Pico
Compiler: SDK 1.5.1
Company: FATEC Santo Andre
Author: *
* ALMIR *
* CARLOS SILVA *
* WILLIAN
Date: 15/11/2024
*******************************************************************************
File Description: Teste Leitura de Mapas ,MASSA E PRESSÃO DE AR
*
Change History:
1.0 09/11/2024 Versao inicial
*******************************************************************************/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
#include "hardware/gpio.h"
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include "hardware/timer.h"
#include "ssd1306.h"
//====================================================================
// Área de Prototipos de Funções
void gpio_callback(uint gpio, uint32_t events);
bool timer_callback(repeating_timer_t *rt);
int BuscaPressao(int frequencia_map);
int BuscaTemp(int resistencia_temp);
int CalculaMassaAr(int pressao_map, int t_ar);
//====================================================================
// Definicoes do Projeto
//====================================================================
#define oscilador 14 //GPIO14
#define botao_B1 22 //GPIO22
#define bico_Injetor 8 //GPIO08
#define resetar_tempo 16 //GPIO16
#define PIP 7 //GPIO07
//Definição para controle do portenciometro
#define GPIO_SENSOR_MAP 27
#define ADC_INPUT_MAP 1
#define GPIO_SENSOR_TEMP 28
#define ADC_INPUT_TEMP 2
// Definições para escalonamento de tempo em µs
#define TIME_0_1_MS 100 // 0,1 ms em microssegundos
#define TIME_1_MS 1000 // 1,0 ms em microssegundos
#define TIME_10_MS 10000 // 10 ms em microssegundos
#define TIME_100_MS 100000 // 100 ms em microssegundos
// Definições de constantes
#define R_CONSTANTE 8314 // Constante dos gases ideais
#define MASSA_MOLAR 28960 // Massa molar do ar em mg/mol (28,96 g/mol)
#define V_MOTOR 1000 // Volume total do motor em cm³ (ajuste conforme necessário)
#define TAMANHO_TABELA 7 // Tamanho dos arrays de frequência e pressão
#define TAMANHO_TABELA_TEMP 7 // Tamanho dos arrays de volts e ohm
// Arrays de frequência e pressão correspondentes (em mbar) - já em ordem decrescente de frequência
int tabela_frequencia [TAMANHO_TABELA] = {150, 136, 130, 125, 105, 97, 95}; // Frequências
int tabela_pressao [TAMANHO_TABELA] = {0, -133, -266, -399, -533, -666, -799}; // Pressões em mbar
// Arrays de ohm e temp correspondentes (em mbar) - já em ordem decrescente de sinal
int tabela_resistencia [TAMANHO_TABELA_TEMP] = { 3730, 1620, 770, 380, 280, 210, 0}; // Resistencia
int tabela_temperatura [TAMANHO_TABELA_TEMP] = {20, 40, 60, 80, 90, 100, 110}; // Temp
//===================================================================
// Variáveis Globais
//===================================================================
uint32_t ultima_borda[3] = {0, 0, 0};
uint32_t tempo_pulso[3] = {0, 0, 0};
volatile bool primeiro_pulso[3] = {false, false, false};
volatile bool status_bico = false;
volatile bool status_oscilador = false;
bool status_resetar = true;
// Contadores para os intervalos de tempo
uint32_t counter_1_ms = 0;
uint32_t counter_10_ms = 0;
uint32_t counter_100_ms = 0;
uint8_t tinj = 20;
uint8_t tinj_display = 1;
// Buffer de RAM de tela
uint8_t display_buffer[128 * SSD1306_HEIGHT / 8] = {0};
// Converter a escala de trabalho do sensor MAP de 0 - 4095 para 150 - 95,9
const float valor_inicial_map = 150.0f;
const float valor_final_map = 95.9f;
const int max_sensor_map = 4095;
void converter_sensor_map(int valor_map, float *resultado_map)
{
*resultado_map = valor_inicial_map + ((float)valor_map / max_sensor_map) * (valor_final_map - valor_inicial_map);
}
// Converter a escala de trabalho do sensor TEMP de 0 - 4095 para 0 - 5870
const float valor_inicial_temp = 0.0f;
const float valor_final_temp = 5870.0f;
const int max_sensor_temp = 4095;
/*
const float valor_inicial_temp = 0.5f;
const float valor_final_temp = 3.5f;
const int max_sensor_temp = 4095;
*/
void converter_sensor_temp(int valor_temp, float *resultado_temp)
{
*resultado_temp = valor_inicial_temp + ((float)valor_temp / max_sensor_temp) * (valor_final_temp - valor_inicial_temp);
}
//===============================================================================================
int main()
{
// Define variáveis do programa principal
bool status_botao = true;
uint32_t RPM = 0;
// Define variáveis da leitura dos sensores MAP/TEMP
float MAP_read = 0.0f;
float TEMP_read = 0.0f;
uint16_t adc_reading = 0;
// Inicializa a UART com baud rate de 115200
stdio_init_all();
// Declaração da variável do temporizador repetitivo
repeating_timer_t timer;
// Configura o temporizador para disparar a cada 0,1 ms (100 µs)
if (!add_repeating_timer_us(-TIME_0_1_MS, timer_callback, NULL, &timer)) {
printf("Falha ao iniciar o temporizador!\n");
return 1;
}
// Inicializa a interface I2C e o display
SSD1306_init();
// Limpa o buffer
ssd1306_clear_buffer(display_buffer);
ssd1306_send_data(display_buffer, 128 * SSD1306_HEIGHT / 8);
sleep_ms(2000);
// Escreve texto no buffer
ssd1306_write_text(display_buffer, 0, 0, "FATEC - 2024");
ssd1306_write_text(display_buffer, 0, 8, "TESTE DE MAP");
ssd1306_write_text(display_buffer, 0, 16, "---------------");
ssd1306_write_text(display_buffer, 0, 24, "TINJ= ");
ssd1306_write_text(display_buffer, 0, 32, "RPM = ");
//ssd1306_write_text(display_buffer, 0, 40, "B1 ajusta Tinj");
ssd1306_write_text(display_buffer, 0, 40, "MAP = ");
ssd1306_write_text(display_buffer, 0, 48, "TEMP= ");
ssd1306_write_text(display_buffer, 0, 56, "MASS= ");
ssd1306_send_data(display_buffer, 128 * SSD1306_HEIGHT / 8);
sleep_ms(2000);
//===============================================================================================
// Configura os pinos GPIO 5, 6 e 7 para interrupção externa
gpio_init(5); // Interrupção para PIP
gpio_init(6); // Interrupção para MAP
gpio_init(7); // Interrupção para BAT
gpio_set_dir(5, GPIO_IN); // Configura o pino 16 como entrada
gpio_set_dir(6, GPIO_IN); // Configura o pino 17 como entrada
gpio_set_dir(7, GPIO_IN); // Configura o pino 18 como entrada
// Habilita interrupção na borda de subida
gpio_set_irq_enabled_with_callback(5, GPIO_IRQ_EDGE_RISE, true, &gpio_callback);
gpio_set_irq_enabled_with_callback(6, GPIO_IRQ_EDGE_RISE, true, &gpio_callback);
gpio_set_irq_enabled_with_callback(7, GPIO_IRQ_EDGE_RISE, true, &gpio_callback);
// Define os GPIOs do Botão e do Bico Injetor
gpio_init(botao_B1);
gpio_init(bico_Injetor);
gpio_set_dir(botao_B1, GPIO_IN);
gpio_set_dir(bico_Injetor, GPIO_OUT);
// Define pino para monitorar Timer
gpio_init(oscilador);
gpio_set_dir(oscilador, GPIO_OUT);
// Define pino para resetar o valor do tempo de injeção
gpio_init(resetar_tempo);
gpio_set_dir(resetar_tempo, GPIO_IN);
gpio_pull_up(resetar_tempo);
// Define pino para monitorar o sensor MAP e sensor TEMP
adc_init();
adc_gpio_init(GPIO_SENSOR_MAP);
adc_gpio_init(GPIO_SENSOR_TEMP);
//===============================================================================================
while (true)
{
ssd1306_write_text(display_buffer, 55, 24, " x0,1MS"); //Limpa local do buffer
ssd1306_int_number(display_buffer, 55, 24, tinj_display, 6); // Mostra o valor do tempo de pulso do PIP em us.
RPM = 30000000 / tempo_pulso[2];
ssd1306_write_text(display_buffer, 56, 32, " "); //Limpa local do buffer
ssd1306_int_number(display_buffer, 56, 32, RPM, 6); // Mostra o valor da rotação em RPM.
// Atualiza o display com o conteúdo do buffer
ssd1306_send_data(display_buffer, 128 * SSD1306_HEIGHT / 8);
status_botao = gpio_get(botao_B1);
if(!status_botao)
{
tinj_display++; // Incrementa o tempo de injeção
if(tinj_display>150) // Limite de 15,0 ms.'
{
tinj_display = 1;
}
}
status_resetar = gpio_get(resetar_tempo);
if(!status_resetar)
{
tinj_display = 1;
}
sleep_ms(100);
//Leitura e tratamento do sinal recebido do potenciomentro simulando MAP
// Seleção entrada do ADC e leitura do MAP
adc_select_input(ADC_INPUT_MAP);
adc_read();
adc_reading = adc_read();
// Converter o valor do MAP guardado para escala de trabalho do nosso sensor
MAP_read = adc_reading;// * fator_conversao;
int valor_map = MAP_read;
float valor_convertido_map;
converter_sensor_map(valor_map, &valor_convertido_map);
float frequencia_map = valor_convertido_map;
// Busca da pressão com base na frequência
int pressao_map = BuscaPressao(frequencia_map); // Pressão em mbar
//Imprimindo valor da pressao do absoluta
ssd1306_write_text(display_buffer, 55, 40, " Bar ");
ssd1306_int_number(display_buffer, 55, 40, pressao_map, 6);
//Leitura e tratamento do sinal recebido do potenciomentro simulando TEMP
// Seleção entrada do ADC e leitura do TEMP
adc_select_input(ADC_INPUT_TEMP);
adc_read();
adc_reading = adc_read();
// Converter o valor do MAP guardado para escala de trabalho do nosso sensor
TEMP_read = adc_reading;
int valor_temp = TEMP_read;
float valor_convertido_temp;
converter_sensor_temp(valor_temp, &valor_convertido_temp);
float resistencia_temp = valor_convertido_temp;
// Busca da pressão com base na frequência
int temp_ar = BuscaTemp(resistencia_temp); // Pressão em mbar
//Imprimindo valor da temperatura do ar
ssd1306_write_text(display_buffer, 55, 48, " C ");
ssd1306_int_number(display_buffer, 55, 48, temp_ar, 6);
// Cálculo da massa de ar
int massa_ar = CalculaMassaAr(pressao_map, temp_ar);
//Imprimindo valor da massa do ar
ssd1306_write_text(display_buffer, 55, 56, " Mg");
ssd1306_int_number(display_buffer, 55, 56, massa_ar, 6);
}
return 0;
}
//===========================================================================================================================
// ISR: Código que será executado quando uma interrupção externa ocorrer
void gpio_callback(uint gpio, uint32_t events)
{
uint32_t tempo_atual = time_us_32();
if(gpio == 5) // Detectou borda de subida
{
if(primeiro_pulso[0])
{
tempo_pulso[0] = tempo_atual - ultima_borda[0];
}
primeiro_pulso[0] = true;
ultima_borda[0] = tempo_atual;
}
if(gpio == 6)
{
if(primeiro_pulso[1])
{
tempo_pulso[1] = tempo_atual - ultima_borda[1];
}
primeiro_pulso[1] = true;
ultima_borda[1] = tempo_atual;
}
if(gpio == 7)
{
if(primeiro_pulso[2])
{
tempo_pulso[2] = tempo_atual - ultima_borda[2];
}
primeiro_pulso[2] = true;
ultima_borda[2] = tempo_atual;
status_bico = false; // Aciona o bico injetor (A saída está invertida no Drive)
tinj = tinj_display;
}
}
//===========================================================================================================================
// ISR: Código que será executado quando a interrupção de tempo ocorrer
// Função chamada a cada 100 µs (0,1 ms)
bool timer_callback(repeating_timer_t *rt)
{
// Executa a tarefa de 0,1 ms
tinj--; // Decrementa o tempo de injeção
if(!tinj)
{
status_bico = true;
gpio_put(bico_Injetor, status_bico);
tinj=20;
}
gpio_put(bico_Injetor, status_bico); // Liga saída do bico injetor
status_oscilador = !status_oscilador;
gpio_put(oscilador, status_oscilador);
// Incrementa o contador de 1,0 ms
counter_1_ms++;
if (counter_1_ms >= 10)
{ // 10 * 0,1 ms = 1 ms
// Executa a tarefa de 1,0 ms
counter_1_ms = 0; // Reinicia o contador de 1,0 ms
// Incrementa o contador de 10 ms
counter_10_ms++;
if (counter_10_ms >= 100) { // 10 * 1 ms = 10 ms
// Executa a tarefa de 10 ms
counter_10_ms = 0; // Reinicia o contador de 10 ms
// Incrementa o contador de 100 ms
counter_100_ms++;
if (counter_100_ms >= 1000) { // 10 * 10 ms = 100 ms
// Executa a tarefa de 100 ms
counter_100_ms = 0; // Reinicia o contador de 100 ms
status_bico = false; // Aciona o bico injetor (A saída está invertida no Drive)
gpio_put(bico_Injetor, status_bico); // Liga saída do bico
}
}
}
return true; // Retorna "true" para manter o temporizador ativo
}
//=========================================================================================================================
// FUNÇÕES DO PROGRAMA
//=========================================================================================================================
// Função para realizar uma busca binária para encontrar a pressão correspondente
int BuscaPressao(int frequencia_map)
{
int valor_esq_map = 0;
int valor_dir_map = TAMANHO_TABELA - 1;
while (valor_esq_map <= valor_dir_map)
{
int valor_meio_map = valor_esq_map + (valor_dir_map - valor_esq_map) / 2;
if (tabela_frequencia[valor_meio_map] == frequencia_map)
{
return tabela_pressao[valor_meio_map]; // Encontra a pressão exata
}
else if (tabela_frequencia[valor_meio_map] < frequencia_map)
{
valor_dir_map = valor_meio_map - 1;
}
else
{
valor_esq_map = valor_meio_map + 1;
}
}
// Se não encontrar a frequência exata, retorna a pressão do índice mais próximo
if (valor_esq_map >= TAMANHO_TABELA)
{
return tabela_pressao[TAMANHO_TABELA - 1];
}
else if (valor_dir_map < 0)
{
return tabela_pressao[0];
}
else
{
return tabela_pressao[valor_esq_map];
}
}
// Função para realizar uma busca binária para encontrar a temperatura correspondente
int BuscaTemp(int resistencia_temp)
{
int valor_esq_temp = 0;
int valor_dir_temp = TAMANHO_TABELA_TEMP - 1;
while (valor_esq_temp <= valor_dir_temp)
{
int valor_meio_temp = valor_esq_temp + (valor_dir_temp - valor_esq_temp) / 2;
if (tabela_resistencia[valor_meio_temp] == resistencia_temp)
{
return tabela_temperatura[valor_meio_temp]; // Encontra a pressão exata
}
else if (tabela_resistencia[valor_meio_temp] < resistencia_temp)
{
valor_dir_temp = valor_meio_temp - 1;
}
else
{
valor_esq_temp = valor_meio_temp + 1;
}
}
// Se não encontrar a frequência exata, retorna a pressão do índice mais próximo
if (valor_esq_temp >= TAMANHO_TABELA_TEMP)
{
return tabela_temperatura[TAMANHO_TABELA_TEMP - 1];
}
else if (valor_dir_temp < 0)
{
return tabela_temperatura[0];
}
else
{
return tabela_temperatura[valor_esq_temp];
}
}
// Função para calcular a massa de ar admitida usando a expressão fornecida, utilizando a pressão e a temperatura encontrada
int CalculaMassaAr(int pressao_map, int temp_ar)
{
// Convertendo pressão para Pa (1 mbar = 100 Pa)
int pressao_map_pa = (1000 + pressao_map) * 100;
// Massa de ar = (V_motor / 4) * (p_Map / (R * T_air)) * 28,96
int massa_ar = (V_MOTOR / 4) * pressao_map_pa * MASSA_MOLAR / (R_CONSTANTE * temp_ar);
return massa_ar; // Massa de ar em mg
}