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

terça-feira, 15 de dezembro de 2015

Medindo tensão AC com o sensor AMF-16

Olá,
       hoje meu exemplo será diferente, apenas vou mostrar como funciona o sensor AC AMF16, é um sensor desenvolvido para quem não quer correr riscos tomando choques ou queimando seu hardware por conta de altas tensões a serem mensuradas.
       Este sensor é um produto que foi desenvolvido a nível de testes . Este sensor pode medir tensão senoidal,dente de serra,triangular e onda quadrada.
      A interface é algo simples bastando para isto uma porta serial do microcontrolador ou ligado a uma hardware especifico pra isso(tipo max 232 ou módulos bluetooth, confome já foi abordado em outras postagens aqui).Os dados recebidos pela porta serial estão no formato XXXX- onde "X" representa um numero de 0 a 9, o valor máximo lido é 1024(devido ao conversor de 10 bits).A porta serial deve ser configurada para Baud rate de 9600 ,8 bits de dados ,sem paridade e 1 stop bit.
     O sensor é na verdade uma placa de desenvolvimento com os conectores para fazer a integração com o hardware da sua aplicação(pode ser usado para Arduíno, pic ou qualquer outro dispositivo que tenha a porta serial integrada).Para mais informações consulte o pequeno  manual que montei e está disponível em : https://drive.google.com/file/d/0Bx9JeN0dmzXxNjhucVFIelA1MW8/view?usp=sharing .
       Para baixar o aplicativo para usar com Smartphone android acesse : https://drive.google.com/file/d/0Bx9JeN0dmzXxLTZJSHE1NHVCREU/view?usp=sharing .
       Para baixar o aplicativo para usar com o windows acesse : https://drive.google.com/file/d/0Bx9JeN0dmzXxTUpsU2xfZ1VKWDQ/view?usp=sharing.
          A seguir vou colocar os videos de demonstração, mas antes vejam a foto abaixo para saber o que é cada módulo que foi colocado na proto-o-board. O transformador é usado para alimentar a placa(sensor AMF16) ,este transformador pode ser trocado por um de 12V /100mA ou 9V/100mA(pra ficar menor e com baixo custo),os fios do secundário do transformador faz a  alimentação que passa por uma ponte de diodos(retificando a tensão) e então é ligada a alimentação da placa(veja os detalhes no manual).
         Como foi feito dois tipos de demostração tem se um modulo bluetooth(para comunicar com o android) e um circuito montado com o max 232 para comunicar com o windows.O sensor estava na configuração de uso até 1000V.  
     
         Em alguns momentos voces vão ver uma pequena divergencia de tensão isso se deve a precisão do ciruito que considero ser melhor do que a do multimetro pois ele tem mais casas decimais e devido a erros que todo multimetro tem quando se mede tensões fora de sua escala. Por exemplo meça uma tensão de 110V na escala de "x200V" e denovo numa escala de "x1000V" do multímetro e veja o quanto ele varia.Posso assegurar que o circuito funciona na escala de 1000V com tensões que vão de 30VAC a 1000VAC sem problemas de leitura, mas para melhor precisão use ele na escala de 40V para tensões de 8VAC a 40VAC, muito cuidado para não configurar errado e queimar o chip da placa veja no manual como fazer.
         Veja que a forma como os cálculos são feitos no celular e no PC dão uma diferença sutil por, exemplo no PC posso usar a divisão por raiz de 2 no Smartfone eu pego um valor aproximado de raiz de 2 e coloco pra dividir logo ocorre pequenas divergências, quanto menos arredondamentos tiver mais próximo do valor real fica.

Sensor AMF16 com o windows:


Sensor AMF16 com o Android:



Envie um email para : microcontroladores.c@gmail.com