/*
O botão verde é o seletor de função, existem 6 opções.
Os botões vermelho e azul, servem para aumentar e diminuir, respectivamente, valores de configuração.
Opção i=1, mostra valores atuais de temperatura e ph
Opção i=2, muda configurações de luminosidade
Opção i=3, muda o valor minimo de temperatura
Opção i=4, muda o valor maximo de temperatura
Opção i=5, muda o valor minimo de ph
Opção i=6, muda o valor maximo de ph
Temos um sensor de temperatura, e um potenciometro para o ph
LED no PWM 13, PB7 liga se ph fora do desejado
LED no PWM 12, PB6 liga se temperatura fora do desejado
LED no PWM 8 e 7, PH5 e PH4 ligam para demostrar diferentes niveis de luminosidade
Na USART,
- não usar digitos singulares para configurar temperatura ou ph, por exemplo '1' ou '3' ou '9'. Usar '01', '02', '03'...
na hora de modificar valores de configuração, o código foi implementado de tal forma a aceitar apenas numeros com 2 digitos
- não use valores com sinal de negativo
Caso o usuário fique inativo por 10 segundos o sistema volta para a tela inicial
*/
#define AVR_ATmega2560 // programa compilado para o micrcontrolador ATmega 2560
#include <avr/io.h> // definições das entradas e saídas
#include <stdint.h> /* usamos o tipo uint8_t */
#include <avr/pgmspace.h> // usamos PROGMEM e PSTR
#ifndef F_CPU // se não foi definida a frequência de relógio
#define F_CPU 16000000UL // a frequência de relógio é 16 MHz
#endif
#include <avr/interrupt.h> /* usamos interrupções no programa */
#include <util/delay.h> /* usamos o procedimento _delay_ms(double) */
#include <inttypes.h> /* usamos os tipos uint8_t e uint16_t */
#include <stdlib.h>
#define ATmega2560 /* programa para o microcontrolador ATmega2560 */
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
// ALGUMAS VARIÁVEIS
volatile uint8_t i = 1; // variavel usada para o botão seletor de funções
const uint8_t numero_de_funcoes = 6;
volatile uint16_t tick; // variável para o timer e para marcar tempo
const uint16_t tempo_inativo = 10000; // 10000ms = 10 segundos
volatile uint8_t opcao_escolhida = 0; // Para a USART, variável usada no Switch Case para determinar a seleção de funções
// VARIÁVEIS PARA FAZER O DEBOUNCE DAS CHAVES
volatile uint8_t estado_atual_chave; // o estado da chave: valor da chave sem debounce
volatile uint8_t estado_anterior_chave; // armazena o estado anterior da chave
volatile uint8_t leitura_atual_chave; // a leitura atual do valor da chave
volatile uint8_t leitura_anterior_chave; // a leitura anterior do valor da chave
volatile uint8_t chave_pressionada; // 1 se é reconhecida uma borda de descida
float temp_min = 10; // Valor default inicial
float ph_min = 5; // Valor default inicial
float temp_max = 35; // Valor default inicial
float ph_max = 10; // Valor default inicial
float temp_sensor; // Para receber o valor do sensor, em Celsius
float ph_sensor; // Para receber o valor do sensor, em Ph (0~14)
char buffer1[15]; // Para usar o display lcd
char buffer3[15];
const int beta = 3950; // Constante para calculo da temperatura
uint16_t leitura_temperatura; // variável usada para armazenar valor lido pelo adc
uint16_t leitura_ph; // variável usada para armazenar valor lido pelo adc
volatile uint8_t ch; // variável para ser usada na parte do usart, ajuda na mudança dos valores designados pelo usuário para temp, ph e iluminação
float volatile media_temp; // para a temperatura
float volatile soma = 0; // para a temperatura
uint8_t num_de_amostras = 0; //
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
#define TAMANHO_BUFFER 16 // valor padrão do tamanho do buffer
uint8_t buffer[TAMANHO_BUFFER]; // Array com os dados do buffer circular
uint8_t writeIndx; // Índice de escrita (próxima posição para inserir)
uint8_t readIndx; // Índice de leitura (próxima posição para recuperar)
uint8_t buffer_status_read; // 0 se o buffer está vazio, 1 se houver elementos
uint8_t buffer_status_write; // 0 se o buffer está cheio, 1 se está livre para escritas
#define RS PB5 /* Defimos o terminal RS */
#define EN PB4 /* Definimos o terminal EN */
#define COMANDO 0 /* O dado enviado é um comando */
#define DADO 1 /* Enviamos um dado */
ISR(TIMER0_COMPA_vect) // interrupções do OCR0A a cada 1ms
{
tick++;
}
int chave_foi_pressionada(uint8_t porta) { // função de debounce
tick = 0;
leitura_anterior_chave = leitura_atual_chave; // atualizamos a leitura anterior da chave
leitura_atual_chave = ((PIND & (1 << porta)) == 0x00); // realizamos a leitura de PB0
estado_anterior_chave = estado_atual_chave; // atualiza o estado anterior da chave
if (leitura_atual_chave == leitura_anterior_chave) // se o sinal da chave permanece estável no intervalo
{
estado_atual_chave = leitura_atual_chave; // o estado da chave é igual ao valor da chave
}
// verificamos se a chave foi pressionada
if ((estado_anterior_chave == 0x01) && (estado_atual_chave == 0x00)) {
_delay_ms(50); // debounce delay
if ((PIND & (1 << porta)) == 0x00) {
return 1;
}
}
return 0;
}
ISR(USART0_RX_vect) {
tick = 0;
uint8_t data = UDR0; // leia o dado recebido pela USART0
uint8_t WriteNextIndx = (writeIndx + 1) % TAMANHO_BUFFER; //
if ((WriteNextIndx == readIndx)) { //
buffer_status_write = 0; // sinaliza que o buffer circular está cheio
} else { // se o buffer não está cheio
buffer[writeIndx] = data; // escreve o dado
writeIndx = WriteNextIndx; // aponta para a próxima posição no buffer circular para ser escrito
buffer_status_write = 1; // sucesso na operação de escrita no buffer circular
}
}
// INTERRUPÇÕES PARA USO DOS BOTÕES
/**
@brief Sub-rotina de interrupção para tratar as solicitações das interrupções
INT0 VERDE
*/
ISR(INT0_vect) // SLC 21 | VERDE | BOTÃO SELETOR DE FUNÇÃO
{
if (chave_foi_pressionada(PIND0)) // função de debounce
{
i++; // variável seletor de funções
if (i > numero_de_funcoes) i = 1; // se chegar na 'ultima' função, volta pra primeira
}
}
/**
@brief Sub-rotina de interrupção para tratar as solicitações das interrupções INT1
*/
ISR(INT1_vect) // BOTÃO DE MAIS || VERMELHO
{
if (chave_foi_pressionada(PIND1)) // função de debounce
{
if (i == 2) // opção de iluminação
{
if (PORTH != 0b00110000) PORTH = PORTH << 1;
} // Se iluminação não estiver no máximo, 0011.0000, aumenta a luminosidade
if (i == 3) temp_min++; // opção de aumento da temp_min
if (i == 4) temp_max++; // opção de aumento da temp_max
if (i == 5) {
if ( ph_min != 14 ) ph_min++; // ph_min só aumenta até 14
}
if (i == 6) {
if ( ph_max != 14 ) ph_max++; // ph_max só aumenta até 14
}
}
}
/**
@brief Sub-rotina de interrupção para tratar as solicitações das interrupções INT2
*/
ISR(INT2_vect) // BOTÃO DE MENOS || AZUL
{
if (chave_foi_pressionada(PIND2))
{
if (i == 2) // opção de iluminação
{
if (PORTH != 0b00001100) PORTH = PORTH >> 1;
} // Se iluminação não estiver no minimo, 0000.1100, diminui a luminosidade
if (i == 3) temp_min--; // opção de diminuir da temp_min
if (i == 4) temp_max--; // opção de diminuir da temp_min
if (i == 5) {
if ( ph_min != 0 ) ph_min--; // ph_min só diminui até 0
}
if (i == 6) {
if ( ph_max != 0 ) ph_max--; // ph_max só diminui até 0
}
}
}
void ADC_configura_disparo_simples_ADC5(void) {
ADCSRA = 0x87; // ADEN=1 ADSC=0 ADATE=0 ADIE=0 ADIF=0 ADPS[2:0]=111
ADCSRB = 0x00; // bit[7]=reservado=0 ACME=0 bits[5:4]=reservado=0 MUX[5]=0 ADTS[2:0]=000
}
uint16_t ADC_medida(void) {
ADCSRA |= (1 << ADSC); // fazendo ADSC=1 em ADCSRA, iniciamos uma nova conversão
while (ADCSRA & (1 << ADSC)) // enquanto ADSC=1, a conversão está em andamento
; //
return ADC; // retorna o valor do canal convertido
}
void LCD_pulso_EN(void)
{
PORTB |= (1 << EN);
_delay_us(1);
PORTB &= ~(1 << EN);
}
void LCD_Init(void)
{
_delay_ms(20);
LCD_escreve(COMANDO, 0x02); /* mostrador LCD modo de 4 bits */
LCD_escreve(COMANDO, 0x28); /* DL=0 modo de 4 bits, N=1 2 linhas e F=0 tamanho da de fonte 5*8 */
LCD_escreve(COMANDO, 0x0C); /* D=1 mostrador ligado, C=0 cursor desligado e B=0 caractere piscando desligado */
LCD_escreve(COMANDO, 0x06); /* desloca o cursor para a direita na escrita de um dado */
LCD_escreve(COMANDO, 0x01); /* apaga o mostrador */
}
void LCD_escreve(uint8_t rs, uint8_t valor)
{
PORTB = (PORTB & 0xF0) | (valor >> 4);
PORTB = (rs == 0) ? PORTB & ~(1 << RS) : PORTB | (1 << RS);
LCD_pulso_EN();
_delay_us(1);
PORTB = (PORTB & 0xF0) | (valor & 0x0F);
LCD_pulso_EN();
/* ver https://www.electronicwings.com/avr-atmega/lcd16x2-interfacing-with-atmega16-32 */
if (rs == DADO)
{
_delay_ms(1);
}
else
{
_delay_ms(3);
}
}
void LCD_string(const char *str)
{
uint8_t ch; // armazena temporariamente um carcatere da string str
/* enquanto o caractere da string não é NULL = fim da string carregamos em ch
o caractere atual e apontamos para o próximo caractere de str */
while (ch = *str++)
{
LCD_escreve(DADO, ch); // escreve no mostrador o carcatere ch
}
}
void LCD_string_flash(const char *str)
{
uint8_t ch; // armazena temporariamente um carcatere da string str
/* enquanto o caractere da string não é NULL = fim da string carregamos em ch
o caractere atual e apontamos para o próximo caractere de str */
while (ch = pgm_read_byte(str++))
{
LCD_escreve(DADO, ch); // escreve no mostrador o carcatere ch
}
}
void LCD_gotoxy(uint8_t linha, uint8_t coluna)
{
uint8_t lc_addr; /* endereço do cursor no mostrador LCD*/
lc_addr = coluna + linha * 0x40; /* calculamos o endereço do cursor */
LCD_escreve(COMANDO, 0x80 | lc_addr); /* atualizamos o endereço do cursor */
}
void LCD_Clear(void)
{
LCD_escreve(COMANDO, 0x01); /* Clear display */
_delay_ms(2);
LCD_escreve(COMANDO, 0x80); /* Cursor at home position (0,0) */
}
void USART0_configura(void) {
UBRR0 = 0x022; // UBRR=----0000 0010 0010
UCSR0A = 0x02; // RXC0=0, TXC0=0, UDRE0=0, FE0=0, DOR0=0, UPE0=0, U2X0=1 e MPCM0=0
UCSR0B = 0x18; // RXCIE0=0, TXCIE0=0, UDRIE0=0, RXEN0=1, TXEN0=1, UCSZ0[2]=0, RXB80=0 e TXB80=0
UCSR0C = 0x06; // UMSEL[1:0]=00, UPM0[1:0]=00, USBS0=0, UCSZ0[1:0]=11 e UCPOL0=0
UCSR0B |= (1 << RXCIE0); // habilitamos as interrupções para a leitura da USART0
}
void USART0_transmite(uint8_t dado) {
while (!(UCSR0A & (1 << UDRE0))) // esperamos o buffer de transmissão ficar vazio
; //
//
UDR0 = dado; // colocamos o dado a ser transmitido no buffer de transmissão
}
uint8_t USART0_recebe(void) {
uint8_t value = 0; // armazenamos o dado recebido pela USART0. Retornamos 0 se não há dados
//
if (writeIndx == readIndx) { // se todos os dados escritos foram lidos
buffer_status_read = 0; // sinaliza que o buffer circular está vazio
} else { // se há dados no buffer
value = buffer[readIndx]; // leia um byte
readIndx = (readIndx + 1) % TAMANHO_BUFFER; // aponta para o próximo byte a ser lido no buffer circular
buffer_status_read = 1; // sucesso na leitura do buffer
}
return value; // retorna o dado recebido no buffer de recepção
}
void USART0_transmite_string_RAM(uint8_t* str) {
uint8_t ch; // variável que armazena o caractere que será transmitido pela USART0
while ((ch = *str++)) { // leia um caractere da string str da RAM, até o delimitador /0, indicando o fim da string
USART0_transmite(ch); // transmite o caractere
}
}
void USART0_transmite_string_FLASH(uint8_t* str) {
uint8_t ch; // variável para armazenar o caractere que será transmitido pela USART0
while ((ch = pgm_read_byte(str++))) { // leia um caractere da string str da FLASH, até o delimitador /0.
USART0_transmite(ch); // transmite o caractere
}
}
void INTERRUPCOES_EXTERNAS_configura(void) // Todas interrupções acontecem na borda de descida dos botões
{
EICRA = 0xff; // ISC1[1:0]=11 int0 VERMELHO ISC0[1:0]=11 VERDE int0
EICRB = 0xff; // ISC2[1:0]=11 int2 AZUL // tudo borda de descida
EIMSK = 0x07; // INT2=1 INT1=1 INT0=1 // máscara
sei(); // habilita as interrupções globalmente
} // 11 = borda de descida
void TIMER_configura(void) {
TCCR0A = 0x02; // saídas OC0A e OC0B como portas normais. COM0A[1:0]=00 COM0B[1:0]=00 WGM0[2:0]=010
TCCR0B = 0x03; // dividimos a frequência de relógio por 64. FOC0A = 0 FOC0B = 0 WGM0[2:0]=010 CS0[2:0] = 011
TIMSK0 = 0x02; // interrupções ocorrem no overflow do contador. OCIE0B = 0 OCIE0A = 1 TOIE0 = 0
OCR0A = 249; // valor de TOP = 249
TCNT0 = 0x00; // zeramos o contador
}
/*
@brief Configuramos as portas
PB[3:0] : saídas. Ligamos o LCD a estes termimais.
PB[7] : saída. ligamos um LED que indica ph fora do normal
PB[6] : saída. ligamos um LED que indica temp fora do normal
PH[5] : saída. ligamos um LED que indica o nível de luminosidade
PH[4] : saída. ligamos um LED que indica o nível de luminosidade
PD[2:0] : Entradas com resistor de pull-up interno. Ligamos a cada um destes terminais uma chave tipo push-buttom.
*/
void PORTAS_configura(void)
{
// PB3 a PB0 e PB7 e PB6 são configuradas como saídas | PB7=PWM13 | PB6=PWM12 | PB0=53 | PB1=52 | PB2=51 | PB3=50 |
DDRB |= ((1 << DDB7) | (1 << DDB6) | (1 << DDB5) | (1 << DDB4) | (1 << DDB3) | (1 << DDB2) | (1 << DDB1) | (1 << DDB0));
// PH4 e PH5 são configuradas saídas para os LEDs de iluminação
DDRH |= ((1 << DDH5) | (1 << DDH4));
// PD2, PD1 e PD0 são configuradas como entradas para usar como habilitação de interrupções int0, int1 e int2
DDRD &= ~((1 << DDD2) | (1 << DDD1) | (1 << DDD0)); // PD2=RX119 AZUL | PD1=SDA20 VERMELHO | PD0=SCL21 VERDE
// Usamos o resistor de pull-up interno de PD1, PD0 e PD2
PORTD |= ((1 << DDD2) | (1 << DDD1) | (1 << DDD0));
}
void exibir_opcoes(void)
{
USART0_transmite_string_RAM("\n\nEscolha a opção de ajuste:\n\n");
USART0_transmite_string_RAM("1- Iluminação.\n");
USART0_transmite_string_RAM("2- Temperatura minima.\t\t");
USART0_transmite_string_RAM("4- Ph minimo.\n");
USART0_transmite_string_RAM("3- Temperatura maxima.\t\t");
USART0_transmite_string_RAM("5- Ph maximo.\n");
USART0_transmite_string_RAM("Temp:");
dtostrf(media_temp, 6, 2, buffer3); // função "double to string". buffer = string com o float de ADC
//dtostrf(temp_sensor, 6, 2, buffer3); // função "double to string". buffer = string com o float de ADC
USART0_transmite_string_RAM(buffer3); // transmite a string com o valor da tensão em decimal.
USART0_transmite_string_RAM("\tpH:");
dtostrf(ph_sensor, 6, 2, buffer1); // função "double to string". buffer = string com o float de ADC
USART0_transmite_string_RAM(buffer1); // transmite a string com o valor da tensão em decimal.
}
void configura(void) {
PORTAS_configura(); // Configura as portas
INTERRUPCOES_EXTERNAS_configura(); // Configuramos o sistema para aceitar interrupções
ADC_configura_disparo_simples_ADC5(); // Configuramos para fazer conversão
USART0_configura(); // Configuramos a USART
LCD_Init(); // Inicialização do LCD
TIMER_configura();
// PORTH = 0b00011000; // liga LED iluminação, somente 1 inicia ligado
PORTH |= ((1 << PORTH4) | (1 << PORTH3)); // liga LED iluminação, somente 1 inicia ligado
}
void leitura_e_tratamento_dos_sensores(void) {
num_de_amostras++;
ADMUX = 0x46; // Configuramos leitura do conversor conectado em A6
leitura_temperatura = ADC_medida(); // Realizamos a leitura do conversor A6 TEMPERATURA
// Converte a leitura do ADC para temperatura em graus Celsius
//temp_sensor = (leitura_temperatura * 0.448759); // Convertendo para temperatura
temp_sensor = 1 / ((log(1 / ((1023.0 / leitura_temperatura) - 1)) / beta) + (1.0 / 298.5)) - 273.5; // tratamento do valor obtido
soma = soma + temp_sensor;
if (num_de_amostras == 25) {
media_temp = soma / 25;
soma = 0;
num_de_amostras = 0;
}
ADMUX = 0x45; // Configuramos leitura do conversor conectado em A5
leitura_ph = ADC_medida(); // Realizamos a leitura do conversor A5 PH
ph_sensor = leitura_ph * (14.0 / 1023.0); // tratamento do valor obtido
if (ph_sensor < ph_min || ph_sensor > ph_max)
PORTB = PORTB | (1 << PORTB7); // liga LED PWM13 se ph fora do normal estabelecido
else
PORTB = PORTB & ~(1 << PORTB7); // senão desliga LED PWM13
if (media_temp < temp_min || media_temp > temp_max)
PORTB = PORTB | (1 << PORTB6); // liga LED PWM12 se temp fora do normal estabelecido
else
PORTB = PORTB & ~(1 << PORTB6); // senão desliga LED PWM12
}
void interatividade_com_LCD() {
if (i == 1) // função 1 do aquário || mostra valores atuais de temperatura e ph
{
LCD_gotoxy(0, 0);
LCD_string_flash(PSTR("Ph atual: "));
LCD_gotoxy(0, 10);
dtostrf(ph_sensor, 0, 1, buffer1); // ph_sensor deve ser tipo float
LCD_string(buffer1); // mostra o valor do ph
LCD_gotoxy(0, 10 + strlen(buffer1));
LCD_string_flash(PSTR(" ")); // limpar uma área específica do display com espaços
LCD_gotoxy(1, 0);
LCD_string_flash(PSTR("Temp atual: "));
LCD_gotoxy(1, 12);
dtostrf(media_temp, 0, 1, buffer3); // media_temp deve ser tipo float
LCD_string(buffer3); // mostra o valor da temperatura
LCD_gotoxy(1, 12 + strlen(buffer3));
LCD_string_flash(PSTR(" ")); // limpar uma área específica do display com espaços
}
else if (i == 2) // função 2 do aquário || muda a luminosidade
{
LCD_gotoxy(0, 0);
LCD_string_flash(PSTR("Configure a "));
LCD_gotoxy(1, 0);
LCD_string_flash(PSTR("luminosidade... "));
}
else if (i == 3) // função 3 do aquário || muda valor mínimo da temperatura
{
LCD_gotoxy(0, 0);
LCD_string_flash(PSTR("Configure a temp "));
LCD_gotoxy(1, 0);
LCD_string_flash(PSTR("minima..."));
LCD_gotoxy(1, 9);
dtostrf(temp_min, 0, 0, buffer1); // deve ser tipo float
LCD_string(buffer1); // mostra temp_min desejada
LCD_gotoxy(1, 9 + strlen(buffer1));
LCD_string_flash(PSTR(" ")); // limpar uma área específica do display com espaços
}
else if (i == 4) // função 4 do aquário || muda valor máximo da temperatura
{
LCD_gotoxy(0, 0);
LCD_string_flash(PSTR("Configure a temp "));
LCD_gotoxy(1, 0);
LCD_string_flash(PSTR("maxima..."));
LCD_gotoxy(1, 9);
dtostrf(temp_max, 0, 0, buffer1); // deve ser tipo float
LCD_string(buffer1); // mostra temp_max desejada
LCD_gotoxy(1, 9 + strlen(buffer1));
LCD_string_flash(PSTR(" ")); // limpar uma área específica do display com espaços
}
else if (i == 5) // função 5 do aquário || muda valor mínimo do ph
{
LCD_gotoxy(0, 0);
LCD_string_flash(PSTR("Configure o ph "));
LCD_gotoxy(1, 0);
LCD_string_flash(PSTR("minimo..."));
LCD_gotoxy(1, 9);
dtostrf(ph_min, 0, 0, buffer1); // deve ser tipo float
LCD_string(buffer1); // mostra ph_min desejado
LCD_gotoxy(1, 9 + strlen(buffer1));
LCD_string_flash(PSTR(" ")); // limpar uma área específica do display com espaços
}
else if (i == 6) // função 6 do aquário || muda valor máximo do ph
{
LCD_gotoxy(0, 0);
LCD_string_flash(PSTR("Configure o ph "));
LCD_gotoxy(1, 0);
LCD_string_flash(PSTR("maximo..."));
LCD_gotoxy(1, 9);
dtostrf(ph_max, 0, 0, buffer1); // deve ser tipo float
LCD_string(buffer1); // mostra ph_max desejado
LCD_gotoxy(1, 9 + strlen(buffer1));
LCD_string_flash(PSTR(" ")); // limpar uma área específica do display com espaços
}
else
{
LCD_gotoxy(0, 0); // Este procedimento não deve executar
LCD_string_flash(PSTR(" else ")); // Este procedimento não deve executar
LCD_gotoxy(1, 0); // Este procedimento não deve executar
LCD_string_flash(PSTR(" else ")); // Este procedimento não deve executar
}
}
float modifica_temp_e_ph(float ph_ou_temp) {
uint8_t resultado_final = 0;
do {
interatividade_com_LCD(); // a interatividade com o LCD
leitura_e_tratamento_dos_sensores(); // faz a leitura dos sensores
if (inatividade(tempo_inativo)) {
i = 1;
tick = 0;
exibir_opcoes();
break;
}
ch = USART0_recebe();
if (buffer_status_read == 1) {
char resultado_str[8]; // Para mostrar na USART
uint8_t dezena = (ch - '0') * 10; // Convertendo ch para inteiro e multiplicando para ser dezena
while (1) {
ch = USART0_recebe();
uint8_t unidade = ch - '0'; // Convertendo ch para inteiro
if (buffer_status_read == 0) break;
resultado_final = dezena + unidade; // Faz a soma da dezena e da unidade, para montar o número
ph_ou_temp = resultado_final * 1.0;
if (((ph_ou_temp > 10) || (ph_ou_temp < 5 )) && (i == 5 || i == 6)) { // Verifica valores aceitáveis de configuração de pH
USART0_transmite_string_RAM("\n\nValor escolhido de pH inválido. pH = 7.");
ph_ou_temp = 7;
break;
}
if (((ph_ou_temp > 35) || (ph_ou_temp < 10 )) && (i == 4 || i == 3)) { // Verifica valores aceitáveis de configuração de temperatura
USART0_transmite_string_RAM("\n\nValor escolhido de temperatura inválido. Temperatura = 25°C.");
ph_ou_temp = 25;
break;
}
itoa(resultado_final, resultado_str, 10);
USART0_transmite_string_RAM("\n\n");
if (i == 3 ) USART0_transmite_string_RAM("\nTemperatura minima escolhida:");
if (i == 4 ) USART0_transmite_string_RAM("\nTemperatura maxima escolhida:");
if (i == 5 ) USART0_transmite_string_RAM("\nPH minimo escolhido:");
if (i == 6 ) USART0_transmite_string_RAM("\nPh maximo escolhido:");
USART0_transmite_string_RAM(resultado_str);
break;
}
}
} while (resultado_final == 0); // fica nesse loop até receber um valor diferente de 0, por ser um aquário
return ph_ou_temp; // nenhum comando sério terá valores de ph=0 e temp=0
} // retorna um valor float para ser usado por temp_min, temp_max, ph_min ou ph_max
int inatividade(uint16_t tempo_inativo)
{
if (tick > tempo_inativo) { // Ação automática de inatividade do usuário, se 10seg sem atividade
tick = 0;
return 1;
}
return 0;
}
int main(void)
{
configura();
USART0_transmite_string_RAM("Inicializando...\n");
exibir_opcoes();
while (1) // laço infinito principal do codigo
{
interatividade_com_LCD(); // a interatividade com o LCD e
leitura_e_tratamento_dos_sensores(); // faz a leitura dos sensores
opcao_escolhida = USART0_recebe(); // recebe a opção desejada pelo usuário
if (inatividade(tempo_inativo))
{
i = 1;
exibir_opcoes();
}
switch (opcao_escolhida) {
case '1':
i = 2; // LCD para a tela da luminosidade
USART0_transmite_string_RAM("\n\n\n\n\n\nConfigure o nivel de luminosidade:\n");
USART0_transmite_string_RAM("1- Para aumentar.\t2- Para diminuir.\t0- Para sair.");
do {
ch = USART0_recebe(); // recebe valor de aumentar ou diminuir
interatividade_com_LCD(); // a interatividade com o LCD
leitura_e_tratamento_dos_sensores(); // faz a leitura dos sensores
if (ch == '1') { // se apertou 1 aumenta luminosidade
if (PORTH != 0b00110000) PORTH = PORTH << 1; // Se iluminação não estiver no máximo, 0011.0000, aumenta a luminosidade
}
if (ch == '2') { // se apertou 2 diminui luminosidade
if (PORTH != 0b00001100) PORTH = PORTH >> 1; // Se iluminação não estiver no minimo, 0000.1100, diminui a luminosidade
}
if (inatividade(tempo_inativo))
{
i = 1;
exibir_opcoes();
break;
}
} while (ch != '0'); // aperta 0 para sair
i = 1; // LCD volta para tela inicial
USART0_transmite_string_RAM("\n\n");
exibir_opcoes();
break;
case '2':
USART0_transmite_string_RAM("\n\n\n\n\n\n\nDigite valores positivos.\nPara valores com 1 digito, ou seja menores que 10, acrescente na frente '0':");
USART0_transmite_string_RAM("\n\nConfigure a temperatura minima:");
i = 3; // LCD mostra a tela da opcao
temp_min = modifica_temp_e_ph(temp_min); // recebe o valor de configuração do usuário pela USART
exibir_opcoes();
i = 1; // LCD volta para tela inicial
break;
case '3':
USART0_transmite_string_RAM("\n\n\n\n\n\n\nDigite valores positivos.\nPara valores com 1 digito, ou seja menores que 10, acrescente na frente '0':");
USART0_transmite_string_RAM("\n\nConfigure a temperatura maxima:");
i = 4; // LCD mostra a tela da opcao
temp_max = modifica_temp_e_ph(temp_max); // recebe o valor de configuração do usuário pela USART
exibir_opcoes();
i = 1; // LCD volta para tela inicial
break;
case '4':
USART0_transmite_string_RAM("\n\n\n\n\n\n\nDigite valores positivos.\nPara valores com 1 digito, ou seja menores que 10, acrescente na frente '0':");
USART0_transmite_string_RAM("\n\nConfigure o ph minimo:");
i = 5; // LCD mostra a tela da opcao
ph_min = modifica_temp_e_ph(ph_min); // recebe o valor de configuração do usuário pela USART
exibir_opcoes();
i = 1; // LCD volta para tela inicial
break;
case '5':
USART0_transmite_string_RAM("\n\n\n\n\n\n\nDigite valores positivos.\nPara valores com 1 digito, ou seja menores que 10, acrescente na frente '0':");
USART0_transmite_string_RAM("\n\nConfigure o ph maximo:");
i = 6; // LCD mostra a tela da opcao
ph_max = modifica_temp_e_ph(ph_max); // recebe o valor de configuração do usuário pela USART
exibir_opcoes();
i = 1; // LCD volta para tela inicial
break;
default:
// tick = 0; // Demonstra interatividade do usuário
;
}
}
return 0; // Este procedimento não deve executar
}