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!
Ei cara, coloca este projeto no github para poder dar sugestões no código e aprimorá-lo
ResponderExcluirmeu user: williamtorres1