Comprei um DVR da marca Intelbras para gravar umas imagem e monitorar remotamente minha residencia dai tive a ideia de fazer uma placa que se conecte a este DVR e então acionar dispositivos ligados a rele desta placa de modo remoto.Para isto usei a saída RS-485 que controla a "Pan tilt"(aquelas câmeras que é possível movimentar sua posição).
A primeira coisa a fazer é saber qual é o protocolo utilizado! Então ao ver os tipos de comunicação utilizado achei muito material sobre o protocolo PELCO-D, uma vez com este protocolo montei o programa que será disponibilizado logo abaixo,no link para download que tem um manual e um software desenvolvido para configurar a placa depois de pronta:
https://drive.google.com/file/d/0Bx9JeN0dmzXxb1FPUm12MGxLQmc/edit?usp=sharing .
Coloquei também os arquivos gerber e um esquemático da placa além de ter um arquivo que foi feito no Kicad 2012 para gerar a placa, nesta pasta tem muita informação sobre o projeto.Para controlar os reles basta selecionar qual será a câmera configurada para utilizar a pan tilt e então pra cada comando da câmera irá acionar um rele(isso vai depender da configuração feita pelo software do projeto ),não testei em outros DVR´s que não seja o Intelbras.
Finalmente vou disponibilizar aqui o código completo do projeto, ficou gigante:
//*********************************************************************************************************** // acesso remoto com dvr // versão : 1.0 // descrição : acesso remoto usando protocolo pelco D // Autor : Aguivone // micropcontrolador : ATmega 328P // compilador : AVR-GCC / AtmelStudio 6.1 // Data do projeto : 10/12/2013 // finalizado : 20/12/2013 // EFUSE = 0XFF | LOCK BIT = 0XFF(sem cod. proteção) | FUSE HBIT = 0XDE | FUSE LBIT = 0XCF //************************************************************************************************************* #define F_CPU 16000000 // 16 MHz #include <avr/io.h> #include <avr/interrupt.h> #include <stdio.h> #include <util/delay.h> #include <string.h> #include <avr/eeprom.h> ///para usar a eeprom #define ALTERNA_PINO(x,y) x ^= _BV(y) #define LIGA_PINO(x,y) x |= _BV(y) #define DESLIGA_PINO(x,y) x &= ~(_BV(y)) #define LED PD3 #define CONTROL_RS485 PD2 #define RELE1 PB1 #define RELE2 PB2 #define RELE3 PB3 #define RELE4 PB4 #define RELE5 PB5 #define RELE6 PC0 #define RELE7 PC1 char gcRs232_caracter; long glTeste; int gbRs232_pacote_recebido = 0; int giRs232_pos=0; //variaveis dos reles char gcRele[7][6];//onde: byte 0=comando1_ligar,1=comando2_ligar,2=comando1_desligar,3=comando2_desligar,4=tempo,5='P' ou 'E'(pulso ou estado). char gcEnd_placa = 0x01;//endereço da placa char gcTemp_pulso[7];//tempo de pulso char gcRs232_buffer[20];//o tamanho do buffer é 20 caracteres char gcChecksum = 0; char v1,v2; //variaveis de retorno char convert_char[2];//variavels de retorno do tempo int tempo_pisca=0; int teste=0; ///////////////////////////////////////////////funçoes usadas pela usart//////////////////////////////////////////////// void RS485_inicializa(unsigned int BAUD) { unsigned int velocidade = F_CPU/16/BAUD-1; //veja que na simulação do proteus dá erros nas velocidade diferentes de 9600 mas na pratica funciona. UCSR0A = 0X20; /* habilita receiver and transmitter buffers */ UBRR0H = (unsigned char)(velocidade>>8); UBRR0L = (unsigned char)velocidade; UCSR0B = 0X98;//deve se habilitar somente a interrupção de recepção para não travar o microcontrolador /* 8 bits , 1 stop bit, assincrono , sem paridade,modo nornal */ UCSR0C = (1<<USBS0)|(3<<UCSZ00); DESLIGA_PINO(PORTD,CONTROL_RS485); } void escreve(unsigned char carac) { LIGA_PINO(PORTD,CONTROL_RS485);//pino de controle da RS-485 _delay_loop_1(1);//tempo para estabilizar tensão while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir para enviar um novo UDR0 = carac; while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir desabilita a transmissão _delay_loop_1(20);//tempo para garantir o envio DESLIGA_PINO(PORTD,CONTROL_RS485);//pino de controle da RS-485 } void imprime(const char frase[20],int taman) { unsigned int indice=0; while(indice<=taman)///veja que o programa pode travar se aqui não tiver as duas aspas { escreve(frase[indice]); indice++; } } ////////////////controla os reles////////////// void muda_rele(int rel,int estado) { switch(rel) { case 0: { if(estado == 1) { LIGA_PINO(PORTB,RELE1); } else { DESLIGA_PINO(PORTB,RELE1); } }break; case 1: { if(estado == 1) { LIGA_PINO(PORTB,RELE2); } else { DESLIGA_PINO(PORTB,RELE2); } }break; case 2: { if(estado == 1) { LIGA_PINO(PORTB,RELE3); } else { DESLIGA_PINO(PORTB,RELE3); } }break; case 3: { if(estado == 1) { LIGA_PINO(PORTB,RELE4); } else { DESLIGA_PINO(PORTB,RELE4); } }break; case 4: { if(estado == 1) { LIGA_PINO(PORTB,RELE5); } else { DESLIGA_PINO(PORTB,RELE5); } }break; case 5: { if(estado == 1) { LIGA_PINO(PORTC,RELE6); } else { DESLIGA_PINO(PORTC,RELE6); } }break; case 6: { if(estado == 1) { LIGA_PINO(PORTC,RELE7); } else { DESLIGA_PINO(PORTC,RELE7); } }break; } } void rotina_rs485() { char conta=0; while(conta < 7) { if(gcRele[conta][5]=='P')//esse rele é por pulso? { if((gcRele[conta][0] == gcRs232_buffer[2])&&(gcRele[conta][1] == gcRs232_buffer[3])) {//verifica se o comando é pra dar pulso muda_rele(conta,1);//liga o rele gcTemp_pulso[conta] = gcRele[conta][4]; conta = 20;//com isso sai do laço imediatamente } } else { if((gcRele[conta][0] == gcRs232_buffer[2])&&(gcRele[conta][1] == gcRs232_buffer[3])) {//verifica se o comando é pra ligar? muda_rele(conta,1); conta = 20;//com isso sai do laço imediatamente //escreve('L'); } else{ if((gcRele[conta][2] == gcRs232_buffer[2])&&(gcRele[conta][3] == gcRs232_buffer[3])) {//verifica se o comando é pra desligar? muda_rele(conta,0); conta = 20;//com isso sai do laço imediatamente //escreve('D'); } } } conta++; } } void limpa_buffer() { int conta = 0; while(conta<20) { gcRs232_buffer[conta]=0; conta++; } giRs232_pos=0; } long char_to_long(char val1,char val2,char val3,char val4) { long retorno=0; long gcValor3 = val4 -'0';//faz virar um long long gcValor2 = val3 -'0';//faz virar um long long gcValor1 = val2 -'0';//faz virar um long long gcValor0 = val1 -'0';//faz virar um long retorno = gcValor3+(gcValor2*10)+(gcValor1*100)+(gcValor0*1000); return(retorno); } //================================================= //funçao: _string_to_char //parametros: char val1 - centena,char val2 - dezenas,char val3 - unidades //retorno: //================================================= char string_to_char(char val2,char val3) { char retorno=0; char Valor2 = val3 -'0';//faz virar um long char Valor1 = val2 -'0';//faz virar um long retorno = Valor2+(Valor1*10); return(retorno); } char char_to_hex( char car) { char retorno; switch(car) { case '0': { retorno = 0; }break; case '1': { retorno = 1; }break; case '2': { retorno = 2; }break; case '3': { retorno = 3; }break; case '4': { retorno = 4; }break; case '5': { retorno = 5; }break; case '6': { retorno = 6; }break; case '7': { retorno = 7; }break; case '8': { retorno = 8; }break; case '9': { retorno = 9; }break; case 'A': { retorno = 10; }break; case 'B': { retorno = 11; }break; case 'C': { retorno = 12; }break; case 'D': { retorno = 13; }break; case 'E': { retorno = 14; }break; case 'F': { retorno = 15; }break; } return(retorno); } char hex_char( char car) { char retorno; switch(car) { case 0x00: { retorno = '0'; }break; case 0x01: { retorno = '1'; }break; case 0x02: { retorno = '2'; }break; case 0x03: { retorno = '3'; }break; case 0x04: { retorno = '4'; }break; case 0x05: { retorno = '5'; }break; case 0x06: { retorno = '6'; }break; case 0x07: { retorno = '7'; }break; case 0x08: { retorno = '8'; }break; case 0x09: { retorno = '9'; }break; case 0x0A: { retorno = 'A'; }break; case 0x0B: { retorno = 'B'; }break; case 0x0C: { retorno = 'C'; }break; case 0x0D: { retorno = 'D'; }break; case 0x0E: { retorno = 'E'; }break; case 0x0F: { retorno = 'F'; }break; } return(retorno); } char char_para_hexa(char vl1, char vl2) { char resultado = (char_to_hex(vl1)*16)+char_to_hex(vl2); return(resultado); } void hexa_to_char(char hexad) { if(hexad > 0x0F) { v2= hexad&0X0F; v2 = hex_char(v2); v1 = (hexad>>4); v1 = hex_char(v1); } else { v1='0'; v2=hex_char(hexad); } } void int_to_char(int quant) { convert_char[0]='0'; convert_char[1]='0'; //convert_char[2]='0'; /* while(quant>=100) { quant=quant-100; convert_char[0]++; }*/ while(quant>=10) { quant=quant-10; convert_char[0]++; } while(quant>=1) { quant=quant-1; convert_char[1]++; } } //////////////////////////interrupções requerida para usar a recepção serial/////////////////////////////////// ISR(USART_RX_vect) { gcRs232_caracter = (char)UDR0; // if(giRs232_pos == 0) if(((gcRs232_caracter == '<')||(gcRs232_caracter == 0XFF))&&(gbRs232_pacote_recebido == 0))//inicia a recepção se já tiver lido o buffer { //if(((gcRs232_caracter == '<')||(gcRs232_caracter == 0XFF))&&(gbRs232_pacote_recebido == 0))//inicia a recepção se já tiver lido o buffer //{ gcRs232_buffer[0]=gcRs232_caracter; gcChecksum=0; giRs232_pos=1; //} } else { if(giRs232_pos < 18) { if(gcRs232_buffer[0] == 0XFF) { if(giRs232_pos == 2) {//pos2 if(gcRs232_buffer[1]!= gcEnd_placa) {//já zera gbRs232_pacote_recebido = 0; limpa_buffer(); } else {//sim é igual gcRs232_buffer[giRs232_pos]=gcRs232_caracter; gcChecksum += gcRs232_caracter ; giRs232_pos++; // } } //} } else { gcRs232_buffer[giRs232_pos]=gcRs232_caracter; if(giRs232_pos == 6)//se chegou até aqui é porque o endereço confere { if(gcChecksum == gcRs232_caracter ) { gbRs232_pacote_recebido = 2;//sinaliza que tem dados } } else { gcChecksum += gcRs232_caracter ; } giRs232_pos++; } } else { if((gcRs232_caracter == '>')&&(gcRs232_buffer[0] == '<')) { gbRs232_pacote_recebido = 3;//sinaliza que tem dados } gcRs232_buffer[giRs232_pos]=gcRs232_caracter; giRs232_pos++; } } else {//já zera pois pacote é muito grande,é erro gbRs232_pacote_recebido = 0; limpa_buffer(); } } } //////////////////////////////////////ler e escreve um inteiro na eeprom////////////////////////// void escreve_memoria(int ende,char dados) { _EEPUT(ende,dados); } char ler_memoria(int ende) { char temp; _EEGET(temp,ende);//local a ser lido return(temp); } void ler_memo() { gcEnd_placa = ler_memoria(1); gcRele[0][4] = ler_memoria(2);//tempo gcRele[1][4] = ler_memoria(3); gcRele[2][4] = ler_memoria(4); gcRele[3][4] = ler_memoria(5); gcRele[4][4] = ler_memoria(6); gcRele[5][4] = ler_memoria(7); gcRele[6][4] = ler_memoria(8); gcRele[0][5] = ler_memoria(9);//estado gcRele[1][5] = ler_memoria(10); gcRele[2][5] = ler_memoria(11); gcRele[3][5] = ler_memoria(12); gcRele[4][5] = ler_memoria(13); gcRele[5][5] = ler_memoria(14); gcRele[6][5] = ler_memoria(15); gcRele[0][0] = ler_memoria(16);//comando1 ligar gcRele[1][0] = ler_memoria(17); gcRele[2][0] = ler_memoria(18); gcRele[3][0] = ler_memoria(19); gcRele[4][0] = ler_memoria(20); gcRele[5][0] = ler_memoria(21); gcRele[6][0] = ler_memoria(22); gcRele[0][1] = ler_memoria(23);//comando2 ligar gcRele[1][1] = ler_memoria(24); gcRele[2][1] = ler_memoria(25); gcRele[3][1] = ler_memoria(26); gcRele[4][1] = ler_memoria(27); gcRele[5][1] = ler_memoria(28); gcRele[6][1] = ler_memoria(29); gcRele[0][2] = ler_memoria(30);//comando1 desligar gcRele[1][2] = ler_memoria(31); gcRele[2][2] = ler_memoria(32); gcRele[3][2] = ler_memoria(33); gcRele[4][2] = ler_memoria(34); gcRele[5][2] = ler_memoria(35); gcRele[6][2] = ler_memoria(36); gcRele[0][3] = ler_memoria(37);//comando2 desligar gcRele[1][3] = ler_memoria(38); gcRele[2][3] = ler_memoria(39); gcRele[3][3] = ler_memoria(40); gcRele[4][3] = ler_memoria(41); gcRele[5][3] = ler_memoria(42); gcRele[6][3] = ler_memoria(43); } void gravar_memoria(void) { cli(); escreve_memoria(1,gcEnd_placa); escreve_memoria(16,gcRele[0][0]);//comando1 ligar escreve_memoria(17,gcRele[1][0]); escreve_memoria(18,gcRele[2][0]); escreve_memoria(19,gcRele[3][0]); escreve_memoria(20,gcRele[4][0]); escreve_memoria(21,gcRele[5][0]); escreve_memoria(22,gcRele[6][0]); escreve_memoria(23,gcRele[0][1]);//comando2 ligar escreve_memoria(24,gcRele[1][1]); escreve_memoria(25,gcRele[2][1]); escreve_memoria(26,gcRele[3][1]); escreve_memoria(27,gcRele[4][1]); escreve_memoria(28,gcRele[5][1]); escreve_memoria(29,gcRele[6][1]); escreve_memoria(30,gcRele[0][2]);//comando1 desligar escreve_memoria(31,gcRele[1][2]); escreve_memoria(32,gcRele[2][2]); escreve_memoria(33,gcRele[3][2]); escreve_memoria(34,gcRele[4][2]); escreve_memoria(35,gcRele[5][2]); escreve_memoria(36,gcRele[6][2]); escreve_memoria(37,gcRele[0][3]);//comando1 desligar escreve_memoria(38,gcRele[1][3]); escreve_memoria(39,gcRele[2][3]); escreve_memoria(40,gcRele[3][3]); escreve_memoria(41,gcRele[4][3]); escreve_memoria(42,gcRele[5][3]); escreve_memoria(43,gcRele[6][3]); escreve_memoria(2,gcRele[0][4]);//escreve tempo escreve_memoria(3,gcRele[1][4]);//escreve tempo escreve_memoria(4,gcRele[2][4]);//escreve tempo escreve_memoria(5,gcRele[3][4]);//escreve tempo escreve_memoria(6,gcRele[4][4]);//escreve tempo escreve_memoria(7,gcRele[5][4]);//escreve tempo escreve_memoria(8,gcRele[6][4]);//escreve tempo escreve_memoria(9,gcRele[0][5]);//tipo de acionamento escreve_memoria(10,gcRele[1][5]); escreve_memoria(11,gcRele[2][5]); escreve_memoria(12,gcRele[3][5]); escreve_memoria(13,gcRele[4][5]); escreve_memoria(14,gcRele[5][5]); escreve_memoria(15,gcRele[6][5]); escreve_memoria(50,'G');//indica que houve gravação sei(); } /////////////////////////////////config.padrao////////////////////////// void padrao(void) { int ende = 0; gcEnd_placa = 0x01;//endereço padrão é 01 while(ende < 7)//limpa registros { gcRele[ende][0]=0x00;//comando1 da pan ligar gcRele[ende][1]=0x00;//comando2 da pan ligar gcRele[ende][2]=0x00;//comando1 da pan desligar gcRele[ende][3]=0x00;//comando2 da pan desligar gcRele[ende][4]=0;//tempo gcRele[ende][5]='E';//tipo de acionamento por estado do rele*/ ende++; } // seta registros gcRele[0][1]=0x08;// sobe/comando2 da pan ligar gcRele[0][3]=0x10;// desce/comando2 da pan desligar gcRele[1][1]=0x04;// esquerda/comando2 da pan ligar gcRele[1][3]=0x02;// direita/comando2 da pan desligar gcRele[2][1]=0x20;// zoom+/comando2 da pan ligar gcRele[2][3]=0x40;// zoom-/comando2 da pan desligar gcRele[3][1]=0x80;// foco+/comando2 da pan ligar gcRele[3][2]=0x01;// foco-/comando1 da pan desligar gcRele[4][0]=0x02;// iris+/comando1 da pan ligar gcRele[4][2]=0x04;// iris-/comando1 da pan desligar gcRele[5][1]=0x0C;// ne/comando2 da pan ligar gcRele[5][3]=0x12;// so/comando2 da pan desligar gcRele[6][1]=0x0A;// no/comando2 da pan ligar gcRele[6][3]=0x14;// se/comando2 da pan desligar gravar_memoria(); } void rotina_configura() { int erro = 1; if((gcRs232_buffer[2]=='S')&&(giRs232_pos == 4))//envia todos os estados da placa { int cont=0; escreve('<'); escreve('S'); while(cont<7) { unsigned char temp[13]; temp[0]=(char)'1'+cont;//numero do rele - assim compensa a não existencia do rele 0 hexa_to_char(gcRele[cont][0]);//comando ligar os rele B1 temp[1]= v1; temp[2]= v2; hexa_to_char(gcRele[cont][1]);//comando ligar os rele B2 temp[3]= v1; temp[4]= v2; hexa_to_char(gcRele[cont][2]);//comando desligar os rele B1 temp[5]= v1; temp[6]= v2; hexa_to_char(gcRele[cont][3]);//comando desligar os rele B2 temp[7]= v1; temp[8]= v2; int_to_char(gcRele[cont][4]); // temp[9]= convert_char[0]; temp[9]= '0'; temp[10]= convert_char[0]; temp[11]= convert_char[1]; temp[12]= gcRele[cont][5]; temp[13]='>'; imprime(temp,13); cont++; } hexa_to_char(gcEnd_placa);//endereço escreve(v1); escreve(v2); escreve('>'); erro = 0; } if((gcRs232_buffer[2]=='P')&&(giRs232_pos == 4))//restaura todos os valores padrão { padrao(); imprime("<P>",2); erro = 0; } if((gcRs232_buffer[2]=='E')&&(giRs232_pos == 6))//muda endereço do equipamento { gcEnd_placa = char_para_hexa(gcRs232_buffer[3],gcRs232_buffer[4]);//string_to_char('0',gcRs232_buffer[3],gcRs232_buffer[4]); escreve_memoria(1,gcEnd_placa); escreve_memoria(50,'G'); imprime("<M>",2); erro = 0; } if((gcRs232_buffer[2]=='-')&&(giRs232_pos == 17))//comando de gravação { unsigned int ende = (int)gcRs232_buffer[3] - '0';//faz virar um long ende--;//assim não vai existir rele 0 if(ende < 7 ) { gcRele[ende][0]=char_para_hexa(gcRs232_buffer[4],gcRs232_buffer[5]); gcRele[ende][1]=char_para_hexa(gcRs232_buffer[6],gcRs232_buffer[7]); gcRele[ende][2]=char_para_hexa(gcRs232_buffer[8],gcRs232_buffer[9]); gcRele[ende][3]=char_para_hexa(gcRs232_buffer[10],gcRs232_buffer[11]); gcRele[ende][4]=string_to_char(gcRs232_buffer[13],gcRs232_buffer[14]);//tempo gcRele[ende][5]=gcRs232_buffer[15];//tipo de acionamento*/ imprime("<C>",2); erro = 0; gravar_memoria(); } else {//rele inexistente imprime("<E1>",3); erro = 0;//não precisa escrever erro pois já foi escrito } } if(erro > 0 ) { imprime("<E2>",3);//falha qualquer } } void led() { tempo_pisca = 0; ALTERNA_PINO(PORTD,LED); int contas=0; while(contas<7)//verifica se tem algum rele pra desligar { if(gcTemp_pulso[contas] > 0) { if(gcTemp_pulso[contas]== 0x01) { muda_rele(contas,0); //desliga rele } gcTemp_pulso[contas]--; } contas++; } } //////////////////////////////////////////////função principal/////////////////////////////////////////// int main(void) { DDRD = 0XFE; //inicializa portD como saida exceto pino D0(rx) DDRB = 0XFF; //inicializa portB como saida DDRC = 0XFF; //inicializa portC como saida RS485_inicializa(9600); if(ler_memoria(50)!= 'G')//testa se a memoria foi alterada alguma vez? {//não padrao(); escreve('P'); } else {//sim ler_memo();//busca valores escreve('G'); } sei();//habilita interrupções ////////////////////////// for(;;) { if(gbRs232_pacote_recebido > 0) {//tem dados pra ler cli(); //desabilita interrupções if(gbRs232_pacote_recebido == 3)//config { if(gcRs232_buffer[1]=='C')//comando de gravação { rotina_configura(); } } if(gbRs232_pacote_recebido == 2)//config {//dados da rs-485 rotina_rs485(); } gbRs232_pacote_recebido = 0;//reseta buffer limpa_buffer(); sei();//habilita interrupções } ///////////////////////////////// tempo_pisca++; if(tempo_pisca == 13000)//alterna led a cada 100ms { led(); } } }
Nenhum comentário :
Postar um comentário
olá,digite aqui seu comentário!