sexta-feira, 29 de agosto de 2014

Usando display de LCD no modo 4 bits com o XC8


Aqui vou demonstrar como usar um display de 2 linhas 16 caracteres usando o Mplab XC8, para colocar a frase na linha 1 basta inserir o carácter "\n" ena linha dois o carácter "\r" antes da mensagem desejada.Uma vantagem desta configuração é a possibilidade de escolher qualquer port e pino do microcontrolador por meio do"#define" dos bits, livrando a necessidade de ter um port especifico pra isso.


O Código fonte:


/*
 *                          USANDO DISPLAY DE LCD NO MODO 4BITS
 *
 * Compilador :      MPlabXC8
 * Microcontrolador: 18F13K22
 * Autor:            Aguivone
 * Versão:           1
 * Data de criação:  29 de agosto de 2014.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <xc.h>
#define _XTAL_FREQ 16000000//usado para rotinas de  delays
/*******************************configuraçôes do pic ****************************************************/

// CONFIG1H
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config PLLEN = OFF      // 4 X PLL Enable bit (PLL is under software control)
#pragma config PCLKEN = ON      // Primary Clock Enable bit (Primary clock enabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRTEN = OFF     // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config BORV = 19        // Brown Out Reset Voltage bits (VBOR set to 1.9 V nominal)

// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config HFOFST = ON      // HFINTOSC Fast Start-up bit (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
#pragma config MCLRE = OFF      // MCLR Pin Enable bit (RA3 input pin enabled; MCLR disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config BBSIZ = OFF      // Boot Block Size Select bit (512W boot block size)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block not protected from table reads executed in other blocks)


//************************************************************************************/
//VARIAVEIS GLOBAIS
//************************************************************************************/
char gcCaracter;
bit  gbFlag_interrupcao = 0;


//o pino R/W é conectado ao terra pois não é feita nenhuma leitura no display
//configuração:
//
// pino da porta selecionada / pino display
//
// C4 = pino de D4 do display
// C5 = pino de D5 do display
// C6 = pino de D6 do display
// C7 = pino de D7 do display
//
// C1 = pino de RS do display
// C2 = pino de EN do display
//
/*************************** configuração dos pinos **************************************************/
 #define BIT_0  LATCbits.LATC4
 #define BIT_1  LATCbits.LATC5
 #define BIT_2  LATCbits.LATC6
 #define BIT_3  LATCbits.LATC7

 #define RS     LATCbits.LATC0
 #define EN     LATCbits.LATC1

#define _XTAL_FREQ 16000000//usado para rotinas de  delays


unsigned char valor_bit(char cDa,char cBit)
{
    unsigned char retorna = 0;
    if((cDa & cBit)>= 1)
    {
     retorna = 1;
    }
    return(retorna);
}

void porta_lcd(char cDado)//byte a ser enviado
{
       //envia os bytes mais altos
       BIT_0 = valor_bit(cDado,0X10);
       BIT_1 = valor_bit(cDado,0X20);
       BIT_2 = valor_bit(cDado,0X40);
       BIT_3 = valor_bit(cDado,0X80);
       EN = 1;
       __delay_ms(10);
       EN = 0;
       __delay_ms(15);
       //envia os bytes mais baixos
       RS = 0; //habilita comandos
       BIT_0 = valor_bit(cDado,0X01);
       BIT_1 = valor_bit(cDado,0X02);
       BIT_2 = valor_bit(cDado,0X04);
       BIT_3 = valor_bit(cDado,0X08);
       EN = 1;
       __delay_ms(10);
       EN = 0;
       __delay_ms(15);
}
void escreve_LCD(char cDado,int iVlr)//byte a ser enviado ,escreve caracter(0) ou comando(1)
{
    if(iVlr == 0)
       {
         RS = 0; //habilita comandos
       }
       else
       {
        RS = 1; //habilita dados
       }
       //envia os bytes mais altos
       BIT_0 = valor_bit(cDado,0X10);
       BIT_1 = valor_bit(cDado,0X20);
       BIT_2 = valor_bit(cDado,0X40);
       BIT_3 = valor_bit(cDado,0X80);
       EN = 1;
       __delay_us(30);//tempo estabilizar o pino
       EN = 0;
       __delay_us(30);//tempo estabilizar o pino
       //envia os bytes mais baixos
       BIT_0 = valor_bit(cDado,0X01);
       BIT_1 = valor_bit(cDado,0X02);
       BIT_2 = valor_bit(cDado,0X04);
       BIT_3 = valor_bit(cDado,0X08);
       EN = 1;
       __delay_us(30);//tempo estabilizar o pino
       EN = 0;
       __delay_us(30);
}

void inicializa_display(void)
{
       EN = 0;
       __delay_ms(15);//tempo para estabilizar a tensão e preparar o display
       porta_lcd(0X02);//nesse momento o display ainda está em modo 8bits solicita modo de 4 bits
       porta_lcd(0X28);//configura para usar modo 4bits,manda usar 2 linhas e matriza de caracter de 5X7.
       porta_lcd(0X01);//limpa display
       porta_lcd(0X06);//deslocamento do cursor para direita ,sem deslocamento de caracter automaticamente.
       porta_lcd(0X0C);//liga display ,cursor desligado e

}
void impri_lcd(const unsigned char *ucFrase)//  [17])
{
      unsigned int indice=0;
      unsigned int tamanho = strlen(ucFrase);
      while(indice<tamanho)
       {
            if(ucFrase[indice]=='\n')//linha 1
            {
              escreve_LCD(0X80,0);
                        }
            if(ucFrase[indice]=='\r')//linha2
            {
                          escreve_LCD(0XC0,0);
            }
            if((ucFrase[indice]!='\r') && (ucFrase[indice]!='\n') && (indice<18))//dados
                        {
                          escreve_LCD(ucFrase[indice],1);
            }
       indice++;
       }
}

//*******************************Rotina principal*********************************************/

void main(void)
{
    TRISC = 0x00;    
    inicializa_display();
    impri_lcd("\n__Teste de lcd  ");
    impri_lcd("\rTamanho max.16__");
for(;;)
    {}//loop infinito
}

A simulação:


quinta-feira, 7 de agosto de 2014

Voltímetro com ATmega328P

Olá, hoje vou postar este exemplo de como usar o conversor analógico digital do ATmega328P. 


O código fonte:

//***********************************************************************************************************
//                               Usando o conversor analogico/digital
//
// no gravador configurar os fuses assim:
//  EXTENDED 0XFF 
//  HIGH     0XD8 - neste modo funciona com qualquer valor de cristal usei um de 16Mhz  
//  LOW      0XC7
//  LOKBITS  0XFF  - sem proteção
//
//
//  versão                        : 1
//  descrição                   : Voltimetro
//  Autor                      : Aguivone
//  microcontrolador           : ATmega328P
//  compilador                   : AVR-GCC / Atmel AVR Studio 6.1
//  Data do projeto            : 07/08/2014 
//*************************************************************************************************************
#include <avr/io.h>
#include <string.h>
#include <stdio.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>// AVRJazz Mega328 SPI I/O

////////////////////////funçoes auxiliares/////////////////////////////
#define alterna_pino(x,y) x ^= _BV(y) 
#define   LED    PD2
#define  TENSAO           PC2

 char caracter;
 
void RS232_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);
}
void escreve_caracter(unsigned char carac)
{  
            _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(1);//tempo para garantir o envio
}
void impri_serial(const char frase[80])
{
      unsigned int indice=0;
      unsigned int tamanho = strlen(frase);    
       while(indice<=tamanho)///veja que o programa pode travar se aqui não tiver as duas aspas
       {
            escreve_caracter(frase[indice]);
            indice++;
       }

}
//////////////////////////interrupções requerida para usar a recepção serial///////////////////////////////////
ISR(USART_RX_vect)
{
 caracter = (char)UDR0;
 escreve_caracter(caracter);
}

///long para char
void long_to_char(unsigned int quant)
{
        char texto[6];
        texto[1] = '0';
        texto[2] = '0';
        texto[3] = ',';
        texto[4] = '0';
        texto[5] = '0';
        if(quant>9999)//||(quant<10))
        {
        texto[1] = 'F';
        texto[2] = 'A';
        texto[3] = 'L';
        texto[4] = 'H';
        texto[5] = 'A';
        }
        else
        {
              while(quant>=1000)
                {
                 quant=quant-1000;
                 texto[1]++;
                 }
              while(quant>=100)
                {
                 quant=quant-100;
                 texto[2]++;
                 }
               while(quant>=10)
                {
                 quant=quant-10;
                 texto[4]++;
                 }
               while(quant>=1)
                {
                 quant=quant-1;
                 texto[5]++;
                 }
         }
         escreve_caracter(texto[1]);
         escreve_caracter(texto[2]);
         escreve_caracter(texto[3]);
         escreve_caracter(texto[4]);
         escreve_caracter(texto[5]);

      
}

////////////rotina de leitura de tensão /////////////////////////////////
void ler_adc() {
    ADCSRA |= _BV(ADSC);//inicia conversão analogico/digital
    while ( (ADCSRA & _BV(ADSC)) );//espera terminar leitura
    float valor = ADC*5/10.23;
    long_to_char(valor);
    return;
}
void inicializa_adc()
{
    ADMUX    = 0X02;// vai usar o pino PC2 como entrada, justificado a direita
//    ADMUX    = 0X08;// sensor de temperatura, justificado a direita
    ADCSRA = 0XA0;//habilita o conversor adc clock dividido por 2 e trigger
    ADCSRB = 0X41;//habilita o comparador e o trigger usará a saida dele
    DIDR0 = 0XFB;////desabilita entrada analogico(reduz consumo), deixa apenas PC2 como analogico
 } 

////////////////////função principal/////////////////////////////////////
int main(void)
 {
  
  //////////////////inicializa port D /////////////////////////////////////////////////////////////////////
    DDRD = 0XFE;  //inicializa portD,4 a 7 entrada
    DDRC = 0x18;//configura port C como entradas exceto C3 e C4
    PORTD = 0x00;//desabilita pull ups
    DDRB = 0x2F;//configura port B
    PORTB = 0x02;//inicia com o pino de reset e desliga wiznet em nivel alto
    RS232_inicializa(9600);
    inicializa_adc();
    sei();//habilita interrupções
    impri_serial("Voltimetro serial ... \n\r");
    
///////////////////////////////////////////////////////
 for(;;)
    {  
            impri_serial("->");
            ler_adc();    
            impri_serial(".\n\r");       
            _delay_ms(1000);
            alterna_pino(PORTD,LED);//led
   }//chave do laço infinito (for)
}//chave de main

A simulação do proteus, veja no detalhe o valor lido na serial e no multímetro do programa:


terça-feira, 5 de agosto de 2014

Controle de acesso via DVR Intelbras


              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();
        }
    }
}