sexta-feira, 21 de julho de 2017

Sistema de irrigação com pic 16F628

Olá, já algum tempo comprei umas válvulas para controlar um sistema de irrigação, dai coloquei três válvulas para decidir qual mangueira acionar (com pequenos pivôs(ou aspersores de irrigação)), o primeiro problema a ser resolvido era tentar umidecer ao máximo todo o jardim com esses aspersores, porém como eu não posso controlar a pressão da água que vem da rua, resolvi montar um circuito que   pudesse acionar fazendo combinações de modo a ter pelo menos 3 níveis de alcance(o alcance depende da pressão da água e esta depende do numero de micropivô).veja abaixo o esquemático do projeto,observe que terá um botão para ligar e outro para desligar(se necessário pois quando o programa for finalizado ele já desliga toda energia).

        Com a combinação consegui um resultado satisfatório; então depois de fazer toda a parte hidráulica era hora de colocar em pratica este circuito que montei, apesar de ter 2 reles para garantir que não existiria energia nos contatos das válvulas(para eliminar risco de choques quando o sistema não estiver acionado, ou caso um vazamento molhasse os contatos elétricos) resolvi separar a parte elétrica da hidráulica e acabei tendo que usar uma caixa de alarme(de uma sucata que eu tinha aqui em casa) para colocar todo o circuito, veja abaixo as fotos da placa e da montagem final:


Vamos agora ver como ficou o código fonte, ele é separado em 2 partes,o modo configuração usado pra gravar os tempos em que o sistema ficará em cada estagio(são 7)  e o modo de funcionamento onde rodará o programa uma vez e logo em seguida desliga tudo.Veja que será usado a comunicação serial pra configurar e guardar os dados na memoria.

O código fonte:

  /* projeto irrigador simples XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F628A
 * Autor: aguivone
 * Versão: 1
 * Data :  06 de julho de 2017
 * 
 * intruções:
 *  a programação deve ser feita usado #SXX* ; onde S=o ciclo que se quer alterar(1 a 7) e XX é um valor de 00 a 99
 *  note que a programação será por multiplos de 10s
 * 
 * 
 * mapa de endereços
 * posição de memoria - descrição.
 * 
 * 0 - posição de memoria rom que indica se houve gravação
 * 1 a 7 - relativo ao modo de funcionamento 1 a 7.
 * 
 */

#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
#define _XTAL_FREQ 4000000    // vou usar o oscilador interno
#include <xc.h>

/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////

//#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config FOSC = HS  ///se for de 20mhz deve ser HS
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

#define BOT_CONFIG   RA4

#define RL_GERAL RB7

#define RL_1 RB4
#define RL_2 RB5
#define RL_3 RB6

#define LED_STATUS RB0


////////////////////////////////////////////////variaveis globais///////////////////////////////////////////////////////////
int modo=0;//modo de funcionamento
int tempo[7];//para guardar os tempos
int pos_prog=6;//posição inicial

//usadas na serial
char rs232[6];//guarda pacote recebido
char caracter;
int pos_serial=0;
bit flag_interrupcao = 0;

/////////////////////////////////funçoes usadas pela uart //////////////////////////////////////////////////////
//void inicializa_RS232(long velocidade,int modo)
void inicializa_RS232()
{////por padrão é usado o modo 8 bits e sem paridade, mas se necessario ajuste aqui a configuração desejada.
    //verifique datasheet para ver a porcentagem de erro e se a velocidade é possivel para o cristal utilizado.
    RCSTA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono.  
    TXSTA = 0X24;//modo assincrono,trasmissao 8 bits./alta velocidade
    SPBRG = 25;//9600
    RCIE = 1;//habilita interrupção de recepção
    TXIE = 0;//deixa interrupção de transmissão desligado(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo)
}
void escreve(char valor)
{
    TXIF = 0;//limpa flag que sinaliza envio completo.
    TXREG = valor;
    while(TRMT==0);//resolvi usar este flag em vez de TXIF
   // while(TXIF ==0);//espera enviar caracter//alterei para 1 para testar 18/07/17
   // __delay_us(20); 
}
void imprime(const char frase[])
{
     char indice = 0;
     char tamanho = strlen(frase);
      while(indice < tamanho ) ///veja que o programa pode travar se aqui não tiver as duas aspas
       {
           escreve(frase[indice]);
           indice++;
       }
}
void int_to_char(int quant)
{//converte para inteiro e imprime
     unsigned char ucDez='0', ucUn='0';
     while(quant>=10)
    {
      quant -= 10;  
      ucDez++;  
    }
    while(quant>=1)
    {
       quant -= 1; 
       ucUn++;  
    }
     escreve(ucDez);
     escreve(ucUn);
}
void delay_ms(long valor)//resolve um erro do conmpilador
{
    while(valor>0)
    {
     __delay_ms(1);   
     valor--;
    }        
}
void delay_seg(long valor)//rotina de 1s
{
    while(valor>0)
    {
     __delay_ms(1000); 
     //__delay_ms(100); //pra simular
     LED_STATUS = ~LED_STATUS;
     valor--;
    } 
    //para simular pode reduzir o tempo
}
void ler_dados()
{
    imprime(" \n\r tempos=");
    int var_auxi=0;
    while(var_auxi<7)
    {              
      tempo[var_auxi] = eeprom_read(var_auxi+1);
      int_to_char(tempo[var_auxi]); 
      escreve('0');
      escreve('|');
      var_auxi++;
    }
}


///////////////////////////////////////////////////interrupção//////////////////////////////////////////////////////////////
void interrupt RS232(void)//vetor de interrupção
 {
    if(RCIF)
    {//se pacote for de tamanho diferente ele descarta o pacote. formato #XXX*
     caracter = RCREG;
     if(flag_interrupcao == 0)
     {//verifica se está liberado para ler dados
     if(pos_serial>0)
     {               
            if(caracter == '*')
            {//pacote aceito
                if(pos_serial == 4)
                {
                 flag_interrupcao = 1;
                 rs232[pos_serial]=caracter; 
                 pos_serial = 0;//pra evitar que escreva antes de ler
                }
                else
                {//descarta pois é menor que o esperado
                    pos_serial = 10;//faz zerar tudo
                }
                 
            }
            else
            {
               rs232[pos_serial]=caracter; 
               pos_serial++;
            }            
        }
     if(pos_serial>4)
        {
            //erro no tamanho zera tudo
             rs232[0]='0';
             rs232[1]='0';
             rs232[2]='0';
             rs232[3]='0';
             rs232[4]='0';
             pos_serial = 0; 
        }
     if(caracter == '#')
     {
        pos_serial = 1;
        rs232[0]='#';
     }  
    }
     RCIF = 0;//  limpa flag de interrupção de recepção
    }    

 }


//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////

void main(void)
{
    TRISB = 0X02;//configura portB como saida, B1 (pino RX) como entrada
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    TRISA = 0XFF;//configura portA   como entrada
    inicializa_RS232();//modo de alta velocidade
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit
    __delay_ms(200);
    imprime("Sistema de irrigação V.1.0.0 \n\r"); 
    //pega valores da memoria
    if(eeprom_read(0) != 'G')
    {//nunca foi gravada, então coloca valor padrão
        eeprom_write(0X00,0);
        eeprom_write(0X01,1);//endereço/valor
        eeprom_write(0X02,1);
        eeprom_write(0X03,1);
        eeprom_write(0X04,1);
        eeprom_write(0X05,1);
        eeprom_write(0X06,1);
        eeprom_write(0X07,1);
    }
    ////leitura 
    modo=1;
    if(BOT_CONFIG == 0)
    {   delay_ms(1000);
        if(BOT_CONFIG == 0)
        {
         imprime("Modo configuração \n\r");        
         modo=0;
       // eeprom_write(0X00,'G');//indica que houve gravação na memoria
         LED_STATUS =1;
        }        
    } 
    if(modo == 1)
        {
          RCIE = 0;//desabilita interrupção de recepção
          TXIE = 0;//desabilita interrupção de transmissao 
          ler_dados(); 
          LED_STATUS =0;
        }
   
    
//////////////
    for(;;)
    {   
        if(modo==0)
        {
            if(flag_interrupcao ==  1)
            {//tem dados para ler
             LED_STATUS =0;
             escreve(rs232[0]);
             escreve(rs232[1]);
             escreve(rs232[2]);//retorna o valor lido
             escreve(rs232[3]);
             escreve(rs232[4]);
             //////processa dados/////
             if((rs232[2]>0X2F)&&(rs232[2]<0X40)&&(rs232[3]>0X2F)&&(rs232[3]<0X40))//indica que foi recebido um numero valido
             {//trata pacote                 
                 if((rs232[1]>0X30)&&(rs232[1]<0X38))//indica que foi recebido um modo valido(entre 1 e 7)
                 {//verifica se o modo de programação tem caracter valido
                    int valor = (((rs232[2] - 0X30)*10)+(rs232[3] - 0X30));//converte pra int
                    int posicao = (rs232[1] - 0X30);//converte pra int 
                    eeprom_write(posicao,valor);//altera o valor na de memoria;                    
                    imprime("\n\r Alterado:\n\r");
                    for(int i=1;i<8;i++)
                    {//imprime valores da memoria
                     int_to_char(eeprom_read(i));
                     escreve('|');
                    }
                    eeprom_write(0X00,'G');//indica que houve gravação na memoria;
                 }
             }
             pos_serial = 0; 
             flag_interrupcao = 0;//libera pra pegar outro pacote 
             LED_STATUS =1;
            }  
            
        }
        else
        {   //a sequencia foi pensada de forma que cada valvula tenha pelo menos 1 ciclo de descanso a cada 2 ciclos(execto se o tempo for zero para uma das posicoes)          
              switch(pos_prog)
              {
                  case 0:
                  { //fim de programa
                     RL_1=0;
                     RL_2=0;
                     RL_3=0;
                     delay_ms(500);
                     RL_GERAL=0;
                  }break;
                  case 1:
                  {
                     if(tempo[0]>0)
                     {
                        RL_1=1;
                        RL_2=0;
                        RL_3=0;
                     } 
                     pos_prog=3;//vai para proxima posição
                     delay_seg(tempo[0]*10);
                  }break;
                  case 2:
                  {
                     if(tempo[1]>0)
                     {
                        RL_1=0;
                        RL_2=1;
                        RL_3=0;
                     } 
                     pos_prog=7;//vai para proxima posição
                     delay_seg(tempo[1]*10);
                  }break;
                  case 3:
                  {
                     if(tempo[2]>0)
                     {
                        RL_1=1;
                        RL_2=1;
                        RL_3=0;
                     } 
                     pos_prog=4;//vai para proxima posição
                     delay_seg(tempo[2]*10);
                  }break;
                  case 4:
                  {
                     if(tempo[3]>0)
                     {
                        RL_1=0;
                        RL_2=0;
                        RL_3=1;
                     } 
                     pos_prog=5;//vai para proxima posição
                     delay_seg(tempo[3]*10);
                  }break;
                  case 5:
                  {
                     if(tempo[4]>0)
                     {
                        RL_1=1;
                        RL_2=0;
                        RL_3=1;
                     } 
                     pos_prog=2;//vai para proxima posição
                     delay_seg(tempo[4]*10);
                  }break;
                  case 6:
                  {//como o programa inicia aqui é preciso ter uma atenção diferente neste ponto
                     RL_GERAL=1; //rele principal, mantem a placa energizada 
                     if(tempo[5]>0)
                     {
                        RL_1=0;
                        RL_2=1;
                        RL_3=1;
                     }
                     else
                     {
                        RL_1=0;
                        RL_2=0;
                        RL_3=0;
                     } 
                     pos_prog=1;//vai para proxima posição
                     delay_seg(tempo[5]*10);
                  }break;                  
                  case 7:
                  {
                     if(tempo[6]>0)
                     {
                        RL_1=1;
                        RL_2=1;
                        RL_3=1;
                     } 
                     pos_prog=0;//vai para proxima posição
                     delay_seg(tempo[6]*10);
                  }break;
              }
        }             
     }//loop infinito 

}

O esquemático de simulação no proteus ficou:


O vídeo de demonstração :



Até a próxima pessoal!







Um comentário :

  1. Ei cara, coloca este projeto no github para poder dar sugestões no código e aprimorá-lo
    meu user: williamtorres1

    ResponderExcluir

olá,digite aqui seu comentário!