Mostrando postagens com marcador microcontroladores AVR. Mostrar todas as postagens
Mostrando postagens com marcador microcontroladores AVR. Mostrar todas as postagens

quinta-feira, 17 de dezembro de 2015

Lendo tensão(0 a 55V) e temperatura(sensor interno) com o ATmega328P

Olá,
       Vamos trabalhar com medição de tensão e corrente usando o ATmega328P, como ele possui um sensor de temperatura interno a gente já mata dois coelhos com um tiro só.
        A primeira coisa que se deve fazer é configurar o hardware pra isso, é preciso estar atento a entrada Aref(referência analógica), para não ter problemas na configuração faça assim: coloque o pino Avcc ligado ao +5V,o pino Aref ligado um capacitor de 100nf que estará com o outro teminal ligado ao terra(dessa forma ele funciona como um filtro, o que reduz e muito ruídos),nunca ligue este pino ao GND pois pode inutilizar este chip para a função de leitura de tensão. Para este exemplo vou usar um cristal de 16Mhz e um circuito com o max232 para enviar os dados a um PC.
       Para fazer a leitura de tensão de 0 a 55V usei um divisor resistivo igual o da figura abaixo:
      Ou seja a razão de saída é 11:1(se entra 55V sai 5V na saída), no código deixei uma linha comentada para o caso de alguém querer usar para medir de 0 a 5V.Na simulação do proteus não deu certo colocar o divisor resistivo então optei por usar 2 potenciômetro para conseguir um resultado aproximado.Outro detalhe é que na simulação o sensor interno não é simulador então lá ele assume valor 0 o que acaba resultado em -65°C.
        A equação para medir a temperatura foi retirada deste site  http://www.embarcados.com.br/arduino-uno-sensor-de-temperatura/ .

O código fonte:

//***********************************************************************************************************
//                               Usando o conversor analógico/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.1
//  descrição                   : Voltimetro e leitor de temperatura
//  Autor                      : Aguivone
//  microcontrolador           : ATmega328P
//  compilador                   : AVR-GCC / Atmel AVR Studio 6.1
//  Data do projeto            : 07/08/2014 
//  Data de atualização        : 07/08/2015 - adicionado leitura de temperatura e melhoria para ler tensão
//*************************************************************************************************************
#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(2);//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, int inicio)
{
        char texto[6];
        texto[1] = '0';
        texto[2] = '0';
        texto[3] = ',';
        texto[4] = '0';
        texto[5] = '0';
        if(quant>9999)//valor maior que 100V
        {
        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]++;
                 }
         }
         int cont = inicio;
         while(cont<=5)
         {
             escreve_caracter(texto[cont]);
             cont++;
         }  
}

////////////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;
    //valor = ((ADC*50)/102);//mede de 0 a 5V
    valor = ((ADC*50)/102)*11;//mede de 0 a 55V  - colocando um resitor de 10K e outro de 1K(entre o pino de entrada e gnd) 
    long_to_char(valor,1);
    return;
}
void ler_temperatura() {
    ADCSRA |= _BV(ADSC);//inicia conversão analogico/digital
    while ( (ADCSRA & _BV(ADSC)) );//espera terminar leitura
    float valor = ADC;
    // a formula é  temperatura = (ADC - 324,31)/1,22 , mas vou arrendondar para 324
    if(valor < 324)
    {
        //temperatura negativa
        valor = (324.31-valor)/1.22;;
        escreve_caracter('-');
    }
    else
    {    //temperatura positiva
        valor = (valor-324.31)/1.22;;
        escreve_caracter('+');
    }    
    long_to_char(valor,4);
    return;
}
void inicializa_adc(int valor)
{
    if(valor == 0)///Modo ler tensão
    {
        ADMUX    = 0X42;// vai usar o pino PC2 como entrada, justificado a direita e com capacitor externo no pino de referencia(estabiliza leitura)
        ADCSRA = 0XA7;//habilita o conversor adc clock dividido por 128(para 16MHZ - pois o range deve ser de 50-200khz) e trigger
        ADCSRB = 0X41;//habilita o comparador e o trigger usará a saida dele
        DIDR0 = 0XFB;////desabilita entrada analógica(reduz consumo), deixa apenas PC2 como analógica
    }
    if(valor == 1)///Modo ler temperatura
    {
        //deve ser alterado somente esses dois registradores pois 
        ADMUX    = 0XC8;// sensor de temperatura, justificado a direita e capacitor externo no pino de referencia
        //ADCSRA = 0XA7;//habilita o trigger e o conversor adc clock dividido por 128(para 16MHZ - pois o range deve ser de 50-200khz) 
        ADCSRB = 0X41;//habilita o comparador e o trigger usará a saida dele
        //DIDR0 = 0XFF;////desabilita entrada analógica(reduz consumo)
    }

 } 

////////////////////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(0);
    sei();//habilita interrupções
    impri_serial("Lendo tensão e temperatura ... \n\r");
///////////////////////////////////////////////////////
 for(;;)
    {  
            impri_serial("Tensão = ");
            ler_adc();
            inicializa_adc(1);//ler temp
            _delay_ms(50);//estabilizar tensão
            impri_serial("  Temp = ");
            ler_temperatura();
            impri_serial(". \n\r ");
            inicializa_adc(0);//volta a ler tensão 
            //não sei por que em alguns terminais seriais o valor não é impresso,
            //mas na simulação e em um aplicativo que fiz mostra normalmente     
            _delay_ms(500);
            alterna_pino(PORTD,LED);//led
   }//chave do laço infinito (for)
}//chave de main

A Simulação:
Saída no terminal serial:

link para baixar o terminal serial: https://drive.google.com/file/d/0Bx9JeN0dmzXxNFhxMVFLQ2NPWHc/view?usp=sharing

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







quarta-feira, 25 de junho de 2014

Controlando 3 motores de passo de forma simultânea com o Atmega328P.

Projeto de controle de 3 motores de passos. 

         Olá, hoje vou demonstrar como controlar 3 motores de forma simultânea e ao mesmo tempo você pode mudar o comportamento de cada um de forma independentes,para isto criei um aplicativo serial para monitorar e testar o funcionamento deste projeto, embora esse programa pode ser usado para outras finalidades.
         Vamos começar exemplificando como funciona o software do projeto(por ser mais simples) e logo em seguida vamos ao projeto do firmware.

O software do projeto:

         O aplicativo de controle do motor de passo é descrito na figura a seguir:

         Na figura pode ser visualizado 2 botões de envio de dados, sendo possível enviar o comando de velocidade e de giro de forma alternada sem ter que ficar reescrevendo na caixa de texto, sempre que uma porta serial virtual(geralmente quando se usa um emulador usb/serial) for conectada não é necessário reiniciar o aplicativo pois ao clicar para ver as portas de comunicação disponível o aplicativo já busca no windows quais estão ativas.Para que ele rode perfeitamente no seu computador você deve estar com o framework(a partir da versão 3.5) da microsoft atualizado.

link para download do aplicativo:
https://drive.google.com/file/d/0Bx9JeN0dmzXxN192eEUzaW1iRUk/edit?usp=sharing


O projeto:
       
        Quando fiz este projeto eu tinha em mente fazer algo que pudesse ser usado em uma CNC qualquer(pois A CNC pode ser de furação,deposição(impressora 3D) ou fresagem) logo os comando enviados devem controlar os três motores de forma independente e ao mesmo tempo ter a possibilidade de mudar a velocidade,mas para que os motores não extrapolem o limite físico da CNC, já previ a utilização de seis chaves fim de curso para sinalizar os limites de cada eixo(inicio e fim).
        O comando são enviados por pacotes com a seguinte formatação <XAAYAAZAA> a cada envio de dados o hardware irá devolver um '*' para indica que o comando foi recebido pelo microcontrolador, o carácter 'X' corresponde ao comando a ser efetuado pelo eixo X, o carácter 'Y' corresponde ao comando a ser efetuado pelo eixo Y e o carácter 'Z' corresponde ao comando a ser efetuado pelo eixo Z, já os caracteres 'AA' correspondem ao valor referente ao comandos.A lista de comandos é:
N ->Este comando não faz nada, somente para fechar o pacote.
P ->Este comando manda parar o motor imediatamente.
I ->Este comando manda o motor ir até o inicio do eixo,gira até chegar na chave fim de curso.
F ->Este comando manda o motor ir até o fim do eixo,gira até chegar na chave fim de curso.
H ->Gira um numero de pulsos ('AA' ) no sentido horário, varia de 00 a 99.
A ->Gira um numero de pulsos ('AA' ) no sentido anti-horário, varia de 00 a 99.
V ->Configura a velocidade do motor para um valor qualquer('AA'), varia de 00 a 99.
        Por exemplo vamos supor que eu queira a velocidade  motor no eixo 'X' igual a 10 do eixo 'Y' igual a 50 e do eixo 'Z' igual a 1, então basta enviar o comando "<V10V50V01>" , vamos supor agora que eu queira que o motor do eixo 'X' dê 10 passos no sentido horário, do eixo 'Y' dê 90 passos no sentido horário e do eixo 'Z' dê 50 passos no sentido anti-horário, então é só enviar o comando "<H10H90A50>", se por ventura eu decidir parar o motor do eixo 'Y' enquanto o comando anterior é executado basta enviar "<N00P00N00>" . Para melhor ilustrar isso veja o vídeo:


 

O Código fonte:

///************************************************************************/
//                             Placa de controle de uma CNC com 3 eixos
// EFUSE = 0XFF | LOCK BIT = 0XFF(sem cod. proteção) | FUSE HBIT = 0XD8 | FUSE LBIT = 0XC7

//  Version    : 1.0
//  microcontrolador : AVR ATMega328P
//  Autor        : Aguivone
//  descrição  : CNC via porta serial.
//  data : 25/05/2014.

////AVISOS:
// DESABILITAR OTIMIZAÇOES - 01, Se não dasabilitar pode fazer o programa travar ou rodar de modo errado.
// Atenção ao pino de reset sempre deve estar ligado ao +5V. 
//************************************************************************/

#define F_CPU 16000000UL  // 16 MHz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <util/delay.h>
#include <string.h>
#include <avr/eeprom.h>//usado para acessar memoria
// definições auxiliaries
#define liga_pino(x,y) x |= _BV(y)
#define desliga_pino(x,y) x &= ~(_BV(y))
#define alterna_pino(x,y) x ^= _BV(y)
#define estado_pino(x,y) ((x & _BV(y)) == _BV(y)) //o pino deve estar como entrada ,testa se está em nivel logico 1
// definições dos pinos de entrada
#define SI_X   PC0//sensor de inicio da posição no eixo X
#define SF_X   PC1//sensor de fim da posição no eixo X
#define SI_Y   PC2//sensor de inicio da posição no eixo Y
#define SF_Y   PC3//sensor de fim da posição no eixo Y
#define SI_Z   PC4//sensor de inicio da posição no eixo Z
#define SF_Z   PC5//sensor de fim da posição no eixo Z
// definições dos pinos de saidas(motores)
#define MX_D   PB2//motor de delocamento no eixo X
#define MX_C   PB3
#define MX_B   PB4
#define MX_A   PB5

#define MY_A   PD6//motor de delocamento no eixo Y
#define MY_B   PD7
#define MY_C   PB0
#define MY_D   PB1

#define MZ_D   PD2//motor de delocamento no eixo Z
#define MZ_C   PD3
#define MZ_B   PD4
#define MZ_A   PD5




///variaveis usadas na comunicação serial

unsigned char caracter;//
unsigned int  tam_buffer;//usado para contar o tamanho do buffer de recepção
unsigned char buffer_serial[12];//buffer da serial
volatile char rec_buffer ='S';//usado para ler o buffer de recepção (volatile para funcionar pois sempre ira retornar mesmo valor)


//variaveis dos motores

unsigned char comandos[]={'P','P','P'};
unsigned int  num_passo[]={0,0,0};
unsigned int  pos_motor[]={0,0,0};
unsigned char sent_giro[]={'A','A','A'};//sentido da ultima rotação


//variaveis de tempo
unsigned int tempo[]={0,0,0};//tempo de comparação
unsigned int vel_motor[]={50,50,50};

//variaveis dos sensores
unsigned char status_sensor[]={0,0,0};//sensores de 0 a 2.
// I- inicio,F- fim,C- em area de deslocamento

///////////////////////////////////////////////funçoes usadas pela usart////////////////////////////////////////////////

void serial_inicializa(int BAUD)
{
    int valor = ((F_CPU/16)/BAUD)-1; //verifique se na simulação não está habilitado pra divir por oito o clock do microcontrolador
    /* baud rate */
    UCSR0A = 0X20;
    /* habilita receiver and transmitter buffers */
    UBRR0H = (unsigned char)(valor>>8);
    UBRR0L = (unsigned char)valor;
    /* habilita receiver and transmitter buffers */
    UCSR0B = 0X98;//deve se habilitar somente a interrupção de recepção para não travar o microcontrolador
    /* modo assicrono,8 bits , 1 stop bit, assincrono , sem paridade */
    UCSR0C = 0X06;
    //UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}

void impri_serial(const char frase[20])//já tem caracter null embutido
{
    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
    {
        while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir para enviar um novo
        UDR0 =frase[indice];
        indice++;
        while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir desabilita a transmissão
    }
}

void escreve_caracter(const char carac)
{
    while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir para enviar um novo
    UDR0 =carac;
    while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir desabilita a transmissão
}

void inicializa_timer0(void)
{
    TCCR0A = 0X00;//não tem uso para o timer,configura para modo normal
    // TCCR0B = 0x01; //pre escaler dividido por 1
    //  TCCR0B = 0x02; //pre escaler dividido por 8
    //  TCCR0B = 0x03; //pre escaler dividido por 64
    TCCR0B = 0x04; //pre escaler dividido por 256
    //  TCCR0B = 0x05; //pre escaler dividido por 1024
    //uma interrupção a cada 64ms
    TIMSK0 = 0x01; //habilita interrupção do timer 0(estouro do contador)
}
void parar_timer(void)
{
    TIMSK0 = 0x00; //desabilita interrupção do timer 0(estouro do contador)
}
void reiniciar_timer(void)
{
    TIMSK0 = 0x01; //habilita interrupção do timer 0(estouro do contador)
}

//////////////////////////interrupção requerida para usar a serial///////////////////////////////////
ISR(USART_RX_vect)
{
    caracter = (char)UDR0;
    if(caracter == '>')
    {
        if((tam_buffer<12)&&(tam_buffer>9))//max do display
        {
            
            rec_buffer ='F';//dados
            
        }
        else
        {
            rec_buffer = 'S';//pede pra ignorar vetor - zera
        }
    }
    if((caracter != '>')&&(rec_buffer == 'I'))
    {
        buffer_serial[tam_buffer]=caracter;
        tam_buffer++;
    }
    if(caracter == '<')
    {
        rec_buffer ='I';
        buffer_serial[0]='<';
        tam_buffer=1;
    }
}
void parar_motor(int eixo)
{
    if(eixo == 0)
    {//eixo X
        desliga_pino(PORTB,MX_A);
        desliga_pino(PORTB,MX_B);
        desliga_pino(PORTB,MX_C);
        desliga_pino(PORTB,MX_D);
    }
    else
    {
        if(eixo == 1)
        {// eixo Y
            desliga_pino(PORTD,MY_A);
            desliga_pino(PORTD,MY_B);
            desliga_pino(PORTB,MY_C);
            desliga_pino(PORTB,MY_D);
        }
        else
        {//eixo Z (2)
            desliga_pino(PORTD,MZ_A);
            desliga_pino(PORTD,MZ_B);
            desliga_pino(PORTD,MZ_C);
            desliga_pino(PORTD,MZ_D);
        }
    }
   if((comandos[eixo]=='A')||(comandos[eixo]=='F'))
      //isso compensa o ultimo decremento que não foi usado
 {
  if(pos_motor[eixo]== 3)
  {
     pos_motor[eixo]= 0 ;
  }
  else
  {
   pos_motor[eixo]++;
  }
 }
     if((comandos[eixo]=='I')||(comandos[eixo]=='H'))
       //isso compensa o ultimo incremento que não foi usado
 {
  if(pos_motor[eixo]== 0)
  {
   pos_motor[eixo]= 3 ;
  }
  else
  {
   pos_motor[eixo]--;
  } 
 }
    num_passo[eixo]=0;
    tempo[eixo]=0;//zera tempo
} void atualiza_sensores() { if((estado_pino(PINC,SI_X)==1)&&(estado_pino(PINC,SF_X)==1)) { status_sensor[0] = 'C';//indica que está no curso do eixo } else { if(estado_pino(PINC,SI_X)==1) { status_sensor[0] = 'I';//indica que está no inicio do eixo } else { status_sensor[0] = 'F';//indica que está no fim do eixo } } if((estado_pino(PINC,SI_Y))&&(estado_pino(PINC,SF_Y))) { status_sensor[1] = 'C';//indica que está no curso do eixo } else { if(estado_pino(PINC,SI_Y)) { status_sensor[1] = 'I';//indica que está no inicio do eixo } else { status_sensor[1] = 'F';//indica que está no fim do eixo } } if((estado_pino(PINC,SI_Z))&&(estado_pino(PINC,SF_Z))) { status_sensor[2] = 'C';//indica que está no curso do eixo } else { if(estado_pino(PINC,SI_Z)) { status_sensor[2] = 'I';//indica que está no inicio do eixo } else { status_sensor[2] = 'F';//indica que está no fim do eixo } } } void giro_anti_horario(int eixo) { switch(pos_motor[eixo]) { case 0: {//passo 1 if(eixo == 0) {//eixo X liga_pino(PORTB,MX_A); desliga_pino(PORTB,MX_B); desliga_pino(PORTB,MX_C); desliga_pino(PORTB,MX_D); } else { if(eixo == 1) {// eixo Y liga_pino(PORTD,MY_A); desliga_pino(PORTD,MY_B); desliga_pino(PORTB,MY_C); desliga_pino(PORTB,MY_D); } else {//eixo Z (2) liga_pino(PORTD,MZ_A); desliga_pino(PORTD,MZ_B); desliga_pino(PORTD,MZ_C); desliga_pino(PORTD,MZ_D); } } pos_motor[eixo]=3; }break; case 1: {//passo 2 if(eixo == 0) {//eixo X liga_pino(PORTB,MX_B); desliga_pino(PORTB,MX_A); desliga_pino(PORTB,MX_C); desliga_pino(PORTB,MX_D); } else { if(eixo == 1) {// eixo Y liga_pino(PORTD,MY_B); desliga_pino(PORTD,MY_A); desliga_pino(PORTB,MY_C); desliga_pino(PORTB,MY_D); } else {//eixo Z (2) liga_pino(PORTD,MZ_B); desliga_pino(PORTD,MZ_A); desliga_pino(PORTD,MZ_C); desliga_pino(PORTD,MZ_D); } } pos_motor[eixo]=0; }break; case 2: {//passo 3 if(eixo == 0) {//eixo X liga_pino(PORTB,MX_C); desliga_pino(PORTB,MX_B); desliga_pino(PORTB,MX_A); desliga_pino(PORTB,MX_D); } else { if(eixo == 1) {// eixo Y liga_pino(PORTB,MY_C); desliga_pino(PORTD,MY_B); desliga_pino(PORTD,MY_A); desliga_pino(PORTB,MY_D); } else {//eixo Z (2) liga_pino(PORTD,MZ_C); desliga_pino(PORTD,MZ_B); desliga_pino(PORTD,MZ_A); desliga_pino(PORTD,MZ_D); } } pos_motor[eixo]=1; }break; case 3: {//passo 4 if(eixo == 0) {//eixo X liga_pino(PORTB,MX_D); desliga_pino(PORTB,MX_B); desliga_pino(PORTB,MX_C); desliga_pino(PORTB,MX_A); } else { if(eixo == 1) {// eixo Y liga_pino(PORTB,MY_D); desliga_pino(PORTD,MY_B); desliga_pino(PORTB,MY_C); desliga_pino(PORTD,MY_A); } else {//eixo Z (2) liga_pino(PORTD,MZ_D); desliga_pino(PORTD,MZ_B); desliga_pino(PORTD,MZ_C); desliga_pino(PORTD,MZ_A); } } pos_motor[eixo]= 2; }break; } } void giro_horario(int eixo) { switch(pos_motor[eixo]) { case 0: {//passo 1 if(eixo == 0) {//eixo X liga_pino(PORTB,MX_A); desliga_pino(PORTB,MX_B); desliga_pino(PORTB,MX_C); desliga_pino(PORTB,MX_D); } else { if(eixo == 1) {// eixo Y liga_pino(PORTD,MY_A); desliga_pino(PORTD,MY_B); desliga_pino(PORTB,MY_C); desliga_pino(PORTB,MY_D); } else {//eixo Z (2) liga_pino(PORTD,MZ_A); desliga_pino(PORTD,MZ_B); desliga_pino(PORTD,MZ_C); desliga_pino(PORTD,MZ_D); } } pos_motor[eixo]=1; }break; case 1: {//passo 2 if(eixo == 0) {//eixo X liga_pino(PORTB,MX_B); desliga_pino(PORTB,MX_A); desliga_pino(PORTB,MX_C); desliga_pino(PORTB,MX_D); } else { if(eixo == 1) {// eixo Y liga_pino(PORTD,MY_B); desliga_pino(PORTD,MY_A); desliga_pino(PORTB,MY_C); desliga_pino(PORTB,MY_D); } else {//eixo Z (2) liga_pino(PORTD,MZ_B); desliga_pino(PORTD,MZ_A); desliga_pino(PORTD,MZ_C); desliga_pino(PORTD,MZ_D); } } pos_motor[eixo]=2; }break; case 2: {//passo 3 if(eixo == 0) {//eixo X liga_pino(PORTB,MX_C); desliga_pino(PORTB,MX_B); desliga_pino(PORTB,MX_A); desliga_pino(PORTB,MX_D); } else { if(eixo == 1) {// eixo Y liga_pino(PORTB,MY_C); desliga_pino(PORTD,MY_B); desliga_pino(PORTD,MY_A); desliga_pino(PORTB,MY_D); } else {//eixo Z (2) liga_pino(PORTD,MZ_C); desliga_pino(PORTD,MZ_B); desliga_pino(PORTD,MZ_A); desliga_pino(PORTD,MZ_D); } } pos_motor[eixo]=3; }break; case 3: {//passo 4 if(eixo == 0) {//eixo X liga_pino(PORTB,MX_D); desliga_pino(PORTB,MX_B); desliga_pino(PORTB,MX_C); desliga_pino(PORTB,MX_A); } else { if(eixo == 1) {// eixo Y liga_pino(PORTB,MY_D); desliga_pino(PORTD,MY_B); desliga_pino(PORTB,MY_C); desliga_pino(PORTD,MY_A); } else {//eixo Z (2) liga_pino(PORTD,MZ_D); desliga_pino(PORTD,MZ_B); desliga_pino(PORTD,MZ_C); desliga_pino(PORTD,MZ_A); } } pos_motor[eixo]= 0; }break; } } int valor_decimal(char dezena,char unidade) { int retorno=0; dezena = dezena - 0X30;//converte para int unidade = unidade - 0X30; if(dezena == 0X00) { retorno = unidade; } else { retorno = (dezena*10)+unidade; } return(retorno); } void compensa_giro(int passo) { //como o valor que está na variavel seria a prox posição, mas o giro foi invertdo //logo deve voltar a posição atual e então colocar o proxima posição conforme a seguir: switch(pos_motor[passo]) { case 0: { pos_motor[passo]=2; }break; case 1: { pos_motor[passo]=3; }break; case 2: { pos_motor[passo]=0; }break; case 3: { pos_motor[passo]=1; }break; } } void ger_motor(int rodar) { switch(comandos[rodar]) { case'N': {//não altera o estado atual do motor mas evita a perda de tempo checando as proximas possibilidades }break; case'P': {//manda o motor parar if(num_passo > 0)//testa se motor está energizado? { parar_motor(rodar); } }break; case'I': {//manda motor voltar a origem do eixo if(status_sensor[rodar] != 'I')//ainda não chegou na origem do eixo { if(sent_giro[rodar]=='H')//verifica de qual lado foi o ultimo giro {//isso indica que o giro deve ser invertido logo a proxima posição deve ser compensada compensa_giro(rodar); giro_anti_horario(rodar); }else { giro_anti_horario(rodar); } sent_giro[rodar]='A'; } else {//se já estiver na origem não movimenta mais parar_motor(rodar); num_passo[rodar]=0; comandos[rodar]='P';//troca o comando para não ficar executando essa rotina } }break; case'F': {//manda motor ir para o fim do eixo if(status_sensor[rodar] != 'F')//ainda não chegou no fim do eixo { if(sent_giro[rodar]=='H') { giro_horario(rodar); }else {//compensa inversão de giro compensa_giro(rodar); giro_horario(rodar); } sent_giro[rodar]='H'; } else {//chegou ao fim do eixo. parar_motor(rodar); num_passo[rodar]=0; comandos[rodar]='P';//troca o comando para não ficar executando essa rotina } }break; case'A': {//manda motor girar em sentido anti-horario,rumo ao inicio de deslocamento if(status_sensor[rodar] != 'I')//ainda não chegou na origem do eixo { if(sent_giro[rodar]=='H')//verifica de qual lado foi o ultimo giro {//isso indica que o giro deve ser invertido logo a proxima posição deve ser compensada compensa_giro(rodar); giro_anti_horario(rodar); }else { giro_anti_horario(rodar); } sent_giro[rodar]='A'; if(num_passo[rodar] <= 0) { parar_motor(rodar); num_passo[rodar]=0; comandos[rodar]='P';//troca o comando para não ficar executando essa rotina } else { num_passo[rodar]--; } } else {//se já estiver na origem não movimenta mais parar_motor(rodar); num_passo[rodar]=0; comandos[rodar]='P';//troca o comando para não ficar executando essa rotina } }break; case'H': {//manda motor girar em sentido horario, rumo ao fim do deslocamento. if(status_sensor[rodar] != 'F')//ainda não chegou no fim do eixo { if(sent_giro[rodar]=='H') { giro_horario(rodar); }else {//compensa inversão de giro compensa_giro(rodar); giro_horario(rodar); } sent_giro[rodar]='H'; if(num_passo[rodar] <= 0) { parar_motor(rodar); num_passo[rodar]=0; comandos[rodar]='P';//troca o comando para não ficar executando essa rotina } else { num_passo[rodar]--; } } else {//chegou ao fim do eixo. parar_motor(rodar); num_passo[rodar]=0; comandos[rodar]='P';//troca o comando para não ficar executando essa rotina } }break; } } ISR(TIMER0_OVF_vect) {//interrupção overflow // divisão: tempo de cada interrupção: // 1 -> 16s ; // 8 -> 128us ; // 64 -> 1,024ms // 256 -> 4,096ms // 1024 -> 16,38ms. int xis=0; while(xis<3) { tempo[xis]++; if(tempo[xis] >= vel_motor[xis])//compara tempo de acionar saida { atualiza_sensores();//checa o estado das chaves de inicio e fim de curso. ger_motor(xis); tempo[xis]=0;//zera tempo } xis++; } } int main(void) { DDRB = 0XFF; //são saidas PORTB = 0X00;//zera saidas DDRC = 0X00; // configurado como entrada (sensores) DDRD = 0XFE; //pinos como saida exceto D0(RX da serial) PORTD = 0X00;//zera saidas DIDR0 = 0X00;////desabilita entrada analogico(reduz consumo).evita problemas quando esse pino é usado como I/O serial_inicializa(9600);// verifique se o clock não está dividido por 8! inicializa_timer0(); //parar_timer(); reiniciar_timer(); sei(); //habilita interrupções parar_timer(); impri_serial(" CNC - 3 Eixos."); reiniciar_timer(); /*for(;;) { //impri_serial("teste \n\r "); //_delay_ms(500); }*/ for(;;) { if(rec_buffer =='F')//tem dados pra ler { int temp=1; int com=0; parar_timer(); while(temp<9) { if(buffer_serial[temp]=='V') {//altera velocidade vel_motor[com]=valor_decimal(buffer_serial[temp +1],buffer_serial[temp +2]); } else { comandos[com]=buffer_serial[temp]; num_passo[com]=valor_decimal(buffer_serial[temp +1],buffer_serial[temp +2]); } com++; temp=temp+3; } escreve_caracter('*'); reiniciar_timer(); rec_buffer ='S';//fim de processamento de dados } } }