Código Funcionando teto solar- aceito críticas

Boa tarde e bom final de semana galera do Arduino.cc venho aqui mostrar meu código fonte completo funcionando sem erros, testado, aprovado por eu, por mim e pelo arduino mesmo. quem quiser pegar o código para utilizar para o mesmo propósito ou para um projeto parecido ou idéia mesmo sei lá. só quero que pelo menos coloquem meu nome Rafael Drimel Costandrade, é a única coisa que peço, na verdade peço outra aprimoramento deste código ou idéias. Afinal estamos aqui para melhorarmos e evoluirmos (pelo menos é o que eu acho)

este projeto eu utilizei no meu teto solar do meu carro (um Kadett) com motor do teto solar e botões pego de um Omega Suprema. Sai na manivelinha para abrir e fechar e instalei o motor elétrico, mas ficar segurando o botão ou trancar o carro e ver que o teto estava levantado ou totalmente aberto me incomodava.

Então eu fiz este projeto por 3 motivos, 1º queria um teto com one touch (clicou e pronto faz o resto sozinho), com fechamento e abertura inteligente no alarme. 2º não achei em canto algum na internet e loja que vende-se um módulo one-touch para este teto solar. (achava uns vídeos mas sem explicação de qual foi o módulo utilizado e como foi instalado). 3º tenho o arduino fazendo nada, olhei para ele e ele olhou pra mim, peguei ele e joguei em cima do teto e disse faça o teto funionar do meu jeito, e pronto o arduino fez. :D XD

sem delongas o código completo e atual que está no meu carro

            //////////////////////////////////////
                       // DEFININDO AS PINAGENS DO ARDUINO //
                      //////////////////////////////////////
                      
//pino 12 ativa módulo 1 ativa o relé principal de energia do teto solar
//pino 11 ativa módulo 2 ativa os 2 relés secundários para acionar o teto solar
//pino 9 recebe sinal botão 1 fecha teto e levanta o teto
//pino 8 recebe sinal botão 2 abre o teto e abaixa o teto
//pino 7 recebe sinal alarme trava fecha o teto e desliga o arduino mesmo sinal que vem do som.
//pino 6 recebe sinal alarme destrava abre o teto e liga o arduino sinal que vem do módulo do teto solar
//pino 5 recebe sinal do botão para resetar o teto

int rele_principal = 6; //ativa o relé principal que envia 12V + para um dos relés secundários e ativa o motor do teto solar
int rele_secundario = 5; //ativa os 2 relés secundários para inverter a polaridade do motor do teto solar
int botao_abre_abaixa = 8; //recebe o sinal do botão do teto solar 
int botao_fecha_levanta = 4; //recebe o sinal do botão do teto solar
int alarme_trava = 7; //recebe sinal para travar (fechar o teto ou abaixar o teto, deixando travado o módulo dentro de um loop eterno até o arduino ser desligado pelo temporizador)
int alarme_destrava = 3;  //recebe sinal para abrir o teto totalmente quando acionado o botão auxiliar do alarme
int reseta_teto = 9; //botão de emergência para resetar a posição do teto caso de algum travamento do sistema ou dos módulos.

//declarando os loops externos do sistema
void teto_reseta(); //função de resetamento do teto solar, ele no final retornará para o loop do teto fechado.
void teto_fecha(); //função de fechamento do teto solar
void teto_fechado(); //função loop interno 
void teto_levanta(); // função de levantamento do teto solar
void teto_abre(); //função de abertura total do teto solar
void teto_aberto(); //função do teto solar aberto
void teto_abaixa(); //função do teto solar abaixando
void teto_desliga(); //função para que o arduino fique preso dentro até o relé temporizador desliga-lo, assim tornando mais seguro o sistema do teto solar. 

                  ///////////
                 // SETUP //
                 ///////////


void setup() 
{
  //ATIVANDO E DECLARANDO OS PINOS E SEU ATRIBUTO E SUA FUNCIONALIDADE 
  pinMode (botao_abre_abaixa, INPUT_PULLUP); //botão do teto com função de abrir e abaixar configurado para entrada de energia e com resistência interna do arduino
  pinMode (botao_fecha_levanta, INPUT_PULLUP);  //botão do teto com função de fechar e levantar configurado para entrada de energia e com resistência interna do arduino
  pinMode (reseta_teto, INPUT_PULLUP); //botão extra para acionar o teto em caso de problemas de código ou remover bateria com o teto aberto ou levantado
  pinMode (alarme_trava, INPUT); //entrada de energia quando o alarme positron é acionado para trancar o carro
  pinMode (alarme_destrava, INPUT); //entrada de energia quando o alarme está desligado e quando é acionado o botão auxiliar do controle
  pinMode (rele_secundario, OUTPUT); //saída de energia do arduino para acionar o relé principal.
  pinMode (rele_principal, OUTPUT); //saída de energia do arduino para acionar os 2 relés secundários, para fazer a troca de polaridade do teto solar. (inversão dos pólos)
  delay (3000);   ///temporizamento do código só para não sobrecarregar demais o carro.
}

////////////
//  LOOP  //
//////////// 

void loop(){
  //Inciando com o teto fechado - posição 0
  //ler sinal dos botões e alarme 
  // Este loop funciona normal, porém ele não volta mais caso o botão auxiliar ou qualquer outro botão seja acionado, o loop será feito na função Teto_Fechado();
  //Tive que criar esta função teto_fechado(), porque quando eu acionava o botão auxiliar do alarme e depois eu fechava o 
  //teto ele voltava a abrir o teto novamente porque o pino  alarme_trava() estava constantemente energizado e isso me gerou um problema, mas agora foi resolvido com uma função a mais no código
  if (digitalRead (botao_fecha_levanta) == HIGH){ //Se acionar o botão 1
    teto_levanta();
  }
  else  if (digitalRead (botao_abre_abaixa) == HIGH){ //Se acionar o botão 2
    teto_abre();
  }
  else if (digitalRead (alarme_destrava) == HIGH){ //Se acionar o botão auxiliar do controle do alarme
    teto_abre();
  }
  else if (digitalRead (alarme_trava) == LOW){ //Se acionar o alarme para trancar o carro
    delay(5000);
    teto_desliga();
  }
  else if (digitalRead (reseta_teto) == HIGH){ //Se caso de algum problema do teto estar fora da posição quando liga o arduino
    teto_reseta();  
  }
  else{
    delay(100); //Se não for feito nada ele retornará o loop inicial.
  }      
}
                  
                        //////////////////////
                       // FUNÇÕES EXTERNAS //
                      //////////////////////

void teto_abre(){ //botão 2 acionado ou o auxiliar do teto acionado.
  digitalWrite(rele_secundario, HIGH); //envia energia para ativar os relés de inverão de polaridade
  digitalWrite(rele_principal, HIGH); // envia energia para ativar o relé que envia carga para 1 dos reles secundários.
  delay(8000); // 8 segundos para o teto abrir a primeira parte
  digitalWrite(rele_principal, LOW); // desativa o relé para destravar o teto
  delay(100); // 0,1 segundos só para o motor do teto destravar
  digitalWrite(rele_principal, HIGH); // re-ativa o relé para continuar a abertura completa do teto
  delay(3000); // 3 segundos para finalizar a abertura total do teto solar.
  digitalWrite(rele_principal, LOW); //desliga primeiro o principal
  digitalWrite(rele_secundario, LOW); // depois desliga os 2 reles secundarios.
  delay(200); // 0,2 só para dar um tempo para destravar o motor do teto solar mesmo.
  teto_aberto(); // agora vai para a próxima função
}

void teto_aberto(){
  if (digitalRead(botao_fecha_levanta) == HIGH){ //Se acionar o botão 1 o teto fechará
    teto_fecha();
  }
  else if (digitalRead(alarme_trava) == LOW){ //Se acionar o alarme do carro o teto fechará
    delay(5000);
    teto_fecha();
  }
  else if (digitalRead (reseta_teto) == HIGH){ //Se acionar o botão de resetar o teto ele resetará o teto deixando na posição fechado independente onde o teto esteja.
    teto_reseta();
  }
  else{
    delay(100);
    teto_aberto(); //caso nada seja feito retornará neste evento mesmo. (loop interno)
  }
}

void teto_fecha(){ //fechamento do teto - teto solar se encontra totalmente aberto
  digitalWrite(rele_principal, HIGH); //Aciona o relé principal
  delay(10000); //10 segundos para fechar o teto
  digitalWrite(rele_principal, LOW); //desativa o relé 
  delay(200); //tempo para dar uma relaxada no sistema hehehehe
  teto_fechado(); //vai para a função 
}

void teto_fechado(){ // Esta função é o Loop principal do sistema, aqui eu ignoro a varredura do botão auxiliar do alarme.
  if (digitalRead (botao_fecha_levanta) == HIGH){  //Se acionar o botão 1 o teto irá levantar
    teto_levanta();
  }
  else  if (digitalRead (botao_abre_abaixa) == HIGH){ //Se acionar o botão 2 o teto irá abrir
    teto_abre();
  }
  else if (digitalRead (alarme_trava) == LOW){ //Se trancar o carro o teto irá para a função desligar
    delay(5000);
    teto_desliga();  
  }
  else if (digitalRead (reseta_teto) == HIGH){ //Se acionar o botão de resetar teto
    teto_reseta();
  }
  else{
    delay(100);
    teto_fechado(); //aqui ele retorna pro início desta função.
  }
}

void teto_levanta(){ 
  digitalWrite(rele_principal, HIGH);
  delay(3000);
  digitalWrite(rele_principal, LOW);
  delay(200);
  teto_levantado();
}

void teto_levantado(){
  if (digitalRead (botao_abre_abaixa) == HIGH){
    teto_abaixa(); 
  }
  else if (digitalRead(alarme_trava) == LOW){
    delay(5000);
    teto_abaixa();
  }
  else if (digitalRead (reseta_teto) == HIGH){
    teto_reseta();
  }
  else{
    delay(100);
    teto_levantado();
  }
}

void teto_abaixa(){
  digitalWrite(rele_secundario, HIGH);
  digitalWrite(rele_principal, HIGH);
  delay(3000);
  digitalWrite(rele_principal, LOW);
  digitalWrite(rele_secundario, LOW);
  delay(200);
  teto_fechado();
}

void teto_reseta(){ //esta função só serve para caso de remoção da bateria com teto aberto, ou queima de fusível e deixe o teto na metade do caminho.
//ele simplesmente vai ignorar a posição atual do teto solar, vai fechar o teto 2 vezes como se estivesse aberto totalmente e vai abaixar o teto. deixando na posição fechado.
  delay(5000);
  digitalWrite(rele_principal, HIGH);
  delay(10000);
  digitalWrite(rele_principal, LOW);
  delay(200);
  digitalWrite(rele_principal, HIGH);
  delay(4000);
  digitalWrite(rele_principal, LOW);
  delay(200);
  digitalWrite(rele_secundario, HIGH);
  digitalWrite(rele_principal, HIGH);
  delay(4000);
  digitalWrite(rele_principal, LOW);
  digitalWrite(rele_secundario, LOW);
  delay(3000);
  teto_fechado();
}

void teto_desliga(){ //Função de segurança, aqui o alarme acionado tranca o carro e o arduino ficará preso neste loop até o relé temporizador desligar o arduino.
  delay(50000); //50 segundos, prefiro deixar um delay mais pequeno para não dar alguma pala (bug)
  teto_desliga(); // função retorna para o início desta função.
}

Se perceberem o código é bem bobo e sem muita inteligência, afinal foram só 2 horas digitando isso, criei no papel os esqueminhas e upei no arduino e pronto.

teria jeito de encurtar o código, ou aprimorar as verificações dos botões. sei lá. como eu já falei antes só aprimorar, o arduino está funcionando perfeito, estou satisfeito com este código mas quero ver outras possibilidades para o mesmo funcionamento.

minha esposa me veio com uma idéia de fazer uma função de interromper o teto solar em qualquer momento, pensei na possibilidade de colocar um contador com um delay de 10 e verificar os botões do teto. Ainda não fiz e nem testei mas é uma idéia boa.

Tens coisas a melhorar... uma delas e o facto do teu programa estar feito com delays...

Se a meio da abertura, decidires que queres na realidade fechar, ardeu... tens de esperar pela sequencia completa para o fazeres. Se tivesses realizado isto sem delays era mais simples.

Fazer uma funcao que e chamada uma unica vez vai um pouco contra o conceito de funcao. Uma maneira melhor e ter uma funcao que dependendo dos parametros de entrada faz uma coisa ou outra. Por exemplo, para que uma funcao para abrir e fechar o tecto?

Nao podia ser uma funcao tecto com o parametro a dizer se era para abrir ou fechar?

A funcao de delay devia ser apagada de tudo o que esta relacionado com o Arduino. Faz mais mal que bem.

delay faz mal no arduino porque? como assim? sério?

e como eu faria então para ele desligar um relé depois de 8 ou 10 segundos já que o arduino trabalha linha por linha? e como seria esta função de parametros? Obrigado pelo post [u]bubulindo[/u]

Olá!

Fuja do delay usando millis(). Veja se isto ajuda.

/* Blink without Delay

 Turns on and off a light emitting diode(LED) connected to a digital  
 pin, without using the delay() function.  This means that other code
 can run at the same time without being interrupted by the LED code.

 The circuit:
 * LED attached from pin 13 to ground.
 * Note: on most Arduinos, there is already an LED on the board
 that's attached to pin 13, so no hardware is needed for this example.


 created 2005
 by David A. Mellis
 modified 8 Feb 2010
 by Paul Stoffregen

 This example code is in the public domain.


 http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
 */

// constants won't change. Used here to 
// set pin numbers:
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);      
}

void loop()
{
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the 
  // difference between the current time and last time you blinked 
  // the LED is bigger than the interval at which you want to 
  // blink the LED.
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

A função que o amigo se refere é deste tipo:

void teto_abre_fecha(byte tarefa)
{
  if(tarefa == 1)
   {
     // Abre teto
    }
   else
    {
      // Fecha teto
    }

}

Quando for chamar a função usa uma destas opções.

teto_abre_fecha(0);
teto_abre_fecha(1);

Abraço. Fernando Garcia

Nunca trabalhei com motores e tenho pouco ideia de como é o funcionamento do teto solar, mas gostaria de, pelo menos, deixar uma observações sobre a utilização de tempo (seja delay ou millis) na abertura ou fechamento do teto solar. Utilizar tempo não me agrada muito, pois como aberturas e fechamentos utilizam engrenagens e mecanismos, que sofrem desgastes, o tempo pode variar para abrir ou fechar. Acho que o ideal é utilizar aquelas chaves de contato. Quanto o teto fechasse ou abrisse completamente, haveria uma chavinha fazendo o contato, indicando que isso aconteceu. Acho que isso resolveria os problemas como querer abrir ou fechar o teto a qualquer momento e problemas de possíveis desgaste nas engrenagens. Abraços

Aproveitando para aprender um pouco.

Qual a razão para se fazer este tipo de declaração?

//declarando os loops externos do sistema
void teto_reseta(); 
void teto_fecha(); 
void teto_fechado(); 
void teto_levanta(); 
void teto_abre(); 
void teto_aberto();
void teto_abaixa(); 
void teto_desliga();

FernandoGarcia: ``` void teto_abre_fecha(byte tarefa) {   if(tarefa == 1)   {     // Abre teto     }   else     {       // Fecha teto     }

}




Quando for chamar a função usa uma destas opções.



teto_abre_fecha(0); teto_abre_fecha(1); ```

Abraço. Fernando Garcia

Obrigado [u]Fernando Garcia[/u] Mas uma dúvida e se eu não apertar nada o loop será reniciado normalmente sem fazer nada também? ou ficará indo para uma função de teto fechar? outra dúvida e como ficaria mais mais de 1 função e mais 1 parametro?

porque tenho 4 botões ao total abre, fecha, tranca alarme e abre alarme.

FernandoGarcia: Aproveitando para aprender um pouco.

Qual a razão para se fazer este tipo de declaração?

//declarando os loops externos do sistema
void teto_reseta(); 
void teto_fecha(); 
void teto_fechado(); 
void teto_levanta(); 
void teto_abre(); 
void teto_aberto();
void teto_abaixa(); 
void teto_desliga();

Estava com problema no arduino ao compilar e também as vezes não sei direito estava pulando os loops externos, depois que fiz uma declaração dos voids no setup os erros sumiram.

[u]Filantropic[/u], tudo bom. O problema é que o espaço interno do teto é muito pequeno e não teria como fazer este sistema de botões, um colega meu fez e acabou tendo problema com chuvas, goteiras apareceram dentro do carro por causa dos botões atrapalhando na vedação. Eu coloquei um tempo extra no tetopara fechar com 7 segundos e coloquei no código 10 segundos. assim como fiz com a abertura, abertura para cima e fechamento para baixo com tempos acima do normal dele. independente se eu fico segurando o botão o teto (o motor tem um sistema interno de auto desligamento de energia), porém ele não tem retorno para me avisar isso. Não tem aviso de queda de tensão,ou resistência ele simplesmente desliga, mesmo eu mandando carga (bem analógico o sistema do motor). então independente do delay que eu colocar no código não afetará o motor (só não pode ser abaixo ou igual ao tempo que ele leva para fazer o movimento se não ficará pela metade do percurso completo entende). espero que tenho tirado sua dúvida.

Não importa se tem tarefa ou não, o programa sempre vai retornar para o início do loop.

Você pode fazer qualquer coisa deste tipo.

void teto_abre_fecha(byte tarefa, int maisTarefa, float outraTarefa, boolean chega)
{
  if(tarefa == 1)
   {
    if(maisTarefa == x)
     {
     // Abre teto
     }
    }
   else if((tarefa == 0)  &&  (outraTarefa < 1.5)
    {
      // Fecha teto
    }
   else if((tarefa == 2) || (chega == false))
    {
      // Aciona alarme
    }
}

Depois passa os 4 parâmetros:

teto_abre_fecha(tarefa, maisTarefa, outraTarefa, chega);

Show Fernando, vou refazer o código e testa-lo. depois eu coloco ele completo aqui para mais aprimoramentos.

O que eu ia falar também é dos delays. Também se pode fazer debounce dos botões (não gosto muito dessa forma mais básica de ler botões). Lendo os botões de forma diferente, poderia diminuir-se o número destes, fazendo por exemplo uma acção para um premir curto do botão e outra acção quando se prime o botão durante mais tempo.

No entanto, não quero com isto dizer que pense que o programa está mal, antes pelo contrário, se é a primeira vez que trabalha com este tipo de coisas, penso que está bastante bom. Parabéns.

[u]luisilva[/u], Muito Obrigado pelo seu post. Sou leigo ainda com Arduino eu adquiri o Mega a pouco tempo e comprei o Nano para este projeto. A única programação que fiz além desta foi ligar um LCD e enviar mensagens para ele, e informar a leitura de um sensor de temperatura.

Ainda irei aperfeiçoar este código, o código e o projeto está funcionando perfeitamente e está me satisfazendo, não tem erros e muito menos falhas. O que quero é o que está acontecendo aqui, vocês dando pitacos (críticas) muito bem elaboradas e isso aperfeiçoa não o código deixando mais limpo, mais leve e menos tralhas de escritas repetitivas.

Obrigado a todos e continuem a me criticar neste meu projeto