Fork me on GitHub

02/09/13

PIC: HC-SR04 - Sensor Ultrassonico

PIC: HC-SR04 - Sensor Ultrassônico



O sensor ultrasônico HC-SR04 funciona como um detector de objetos e permite medir distancias mínimas de 2 centímetros podendo chegar a distancias máximas de até 4 metros com uma precisão de 3 milímetros. Estes sensores emitem um sinal ultrassônico (40 kHz) que ao atingir um objeto, retorna ao sensor. O sinal de retorno é captado, permitindo-se calcular a distância do objeto ao sensor, medindo o tempo de ida e volta do sinal emitido.

Usando a seguinte fórmula, é possível calcular a distância, sendo que v (velocidade do som) é ~350m/s.

d[m] = ( v[m/s] * t[s] ) / 2

Para a contagem do tempo, foi utilizado o Timer1, configurado de modo que incremente a cada 1us.


CÓDIGO DA BIBLIOTECA
MikroC PRO PIC
sbit HCSR04_Trigger at RB0_Bit;
sbit HCSR04_Echo at RB1_Bit;
sbit HCSR04_Trigger_Direction at TRISB0_Bit;
sbit HCSR04_Echo_Direction at TRISB1_Bit;

//No teste utilizei um cristal de (20MHz + PLL) = 48MHz e configurei
//o prescaler do TIMER1 para 1:8 ( mode = 3 )
//fator = 1 / ( ( 4 * Prescaler ) / Clock )
//fator = 1 / ( ( 4 * 8 ) / 48 ) 
#define fator 1.5

//mode = 0, prescaler 1:1
//mode = 1, prescaler 1:2
//mode = 2, prescaler 1:4
//mode = 3, prescaler 1:8
void HCSR04_Init( char mode )
{
 HCSR04_Trigger_Direction = 0;
 HCSR04_Echo_Direction = 1;
 TMR1L = 0;
 TMR1H = 0;
 T1CON = 0b00000000; //Clock 4Mhz / Prescaler 1:1
 //T1CON = 0b00010000; //Clock 8 Mhz / Prescaler 1:2
 //T1CON = 0b00100000; //Clock 16 Mhz / Prescaler 1:4
 //T1CON = 0b01100000; //Clock 32 Mhz / Prescaler 1:8
 T1CON.B4 = mode.B0;
 T1CON.B5 = mode.B1;
}

unsigned HCSR04_Read()
{
float distance;
unsigned time;
unsigned i;
   
   HCSR04_Trigger = 0;
   Delay_us( 2 );
   HCSR04_Trigger = 1;
   Delay_us( 10 );
   HCSR04_Trigger = 0;
   
   i = 0xFFFF;
   while( !HCSR04_Echo && i-- );
   
   TMR1H = 0;
   TMR1L = 0;
   TMR1ON_Bit = 1;
   
   i = 0xFFFF;
   while( HCSR04_Echo && i-- );
   
   TMR1ON_Bit = 0;
   
   time = *(unsigned*)&TMR1L;
   distance = (0.175 * time / fator); //distancia em mm
   
   return (unsigned)distance;
}



EXEMPLO:
// LCD module connections
sbit LCD_RS at RB6_bit;
sbit LCD_EN at RB7_bit;
sbit LCD_D4 at RB2_bit;
sbit LCD_D5 at RB3_bit;
sbit LCD_D6 at RB4_bit;
sbit LCD_D7 at RB5_bit;

sbit LCD_RS_Direction at TRISB6_bit;
sbit LCD_EN_Direction at TRISB7_bit;
sbit LCD_D4_Direction at TRISB2_bit;
sbit LCD_D5_Direction at TRISB3_bit;
sbit LCD_D6_Direction at TRISB4_bit;
sbit LCD_D7_Direction at TRISB5_bit;
// End LCD module connections


//Insira o código da biblioteca aqui!!!


char txt[12];
unsigned distancia;

void main()
{
   ADCON1 = 0x0F;  //Desligar o canal analógico da PORTB
   HCSR04_Init(3); //Prescaler 1:8
   Lcd_Init();
   Lcd_Cmd( _LCD_CURSOR_OFF );
   
   while(1)
   {
    distancia = HCSR04_Read(); //mm
    WordToStr(distancia, txt);
    Lcd_Out(1,1,"Distancia: ");
    Lcd_Out_CP(txt);
    Lcd_Out_CP(" mm");
    Delay_ms(1000);
   }
}

31 comentários:

  1. tem algum link pra baixar assim como nos outros arquivos do blog?

    ResponderExcluir
  2. Como faço para baixar a biblioteca para o proteus??

    ResponderExcluir
  3. FIZ UM TESTE, E FUNCIONOU.
    FIZ ATÉ UM VIDEO.
    http://www.youtube.com/watch?v=UR6Q9G8GX9A&feature=youtu.be

    ResponderExcluir
  4. Ola a todos, desde já um muito obrigado pelo post, já agora preciso de uma ajuda só para perceber uma linha do código:

    distance = (0.175 * time * fator); //distancia em mm

    Como chegaram ao valor 0.175???
    Só me falta compreender isso porque o resto percebo.
    Obrigado!

    ResponderExcluir
    Respostas
    1. Transformando metros pra milimetros e tempo de segundos para microsegundos, e v sendo 350/2 m/s:
      a formula fica : 10E+3*v[mm/s] * 10E-6* t[us];
      entao = (10E+3 * 10E-6) * 175 * t;
      = 10E-3 * 175 * t
      = 0.175 * t
      considerando o fator
      =0.175 * t * fator

      Excluir
    2. Eu pensei nessa fórmula mas por algum motivo dava valores
      diferentes durante os cálculos mas devia ser distração ( no valor das unidades ) !!!
      Muito obrigado pelo esclarecimento e desde já um MUITO OBRIGADO pelo trabalho realizado no blog. Abraço

      Excluir
    3. não consigo ter os valores correctos de medida com o pic 16F877A a 20mhz
      mas a 8mhz tenho tudo certo! seria de esperar que o codigo que usam a 20mhz funcione da mesma forma na pic 16F877A a 20mhz não?

      Excluir
  5. Estou tendo o mesmo problema! copiando o codigo pra 16f877a a 20mhz ele dá errado...

    ResponderExcluir
    Respostas
    1. no código tinha um pequeno erro, mas já arrumei. Tenta fazer o teste novamente.

      Excluir
  6. boa noite,
    Tiago, estou tendo o mesmo problema dos colegas acima.
    poderia dizer onde encontra a falha do codigo?
    obrigado.

    ResponderExcluir
    Respostas
    1. Eu ja arrumei o codigo. E tah funcionando perfeitamente. Fiz o teste com o pic rodando a 48MHz.
      Tente ajustar o fator de acordo com o clock desejado.

      Excluir
  7. o que seria o T1CON.B4 = mode.B0; ??????
    T1CON.B5 = mode.B1;

    ResponderExcluir
    Respostas
    1. os bits B4 e B5 do registro T1CON são usados pra configurar o prescaler. No caso estou definindo seus valores com o valor dos bits B0 e B1 da variavel "mode".

      Excluir
  8. Olá bacana seu post, eu citei ele, também fiz uma aplicação com o HC e para isso eu emulei o módulo com um PIC12F629. Segue o post, se alguem ta querendo experimentar fazer um code e apenas simular acho que isso pode ajudar: http://robsoneletronico.wordpress.com/2014/05/18/sensor-de-distancia-por-ultrasom-modulo-hc-sr04-emulador-do-modulo/

    ResponderExcluir
  9. Oi,
    O seu blog é demais... muito tenho aprendido com exemplos práticos do seu blog.

    Só que eu queria simular o HC-SR04 como voçê tem na imagem, mas eu não encontro na minha libraria do PROTEUS. Eu tinha a versão 7.8, mas ontem saquei a versão 8.1 do seu blog e algumas livrarias que voçê aqui tem, mas não encontro esta"HC-SR04", não me aparece no PROTEUS.

    Pode me arranjar, pondo aqui a libraria do HC-SR04 ou o exemplo deste mesmo projecto????
    Desde já muito obrigado pela sua atenção.

    ResponderExcluir
  10. Se eu usar o Oscilador interno do PIC16F628A, O Fator ficará igual a 1? Mais uma coisa, eu adicionei esse codigo:

    sbit HCSR04_Saida at RB2_Bit;
    sbit HCSR04_Saida2 at TRISB2_Bit;
    .
    .
    HCSR04_Saida2 = 0;
    .
    .
    while(1)
    {
    distancia = HCSR04_Read(); //mm
    if(distancia < 100){
    HCSR04_Saida2 = 1;
    }
    else{
    HCSR04_Saida2 = 0;
    }
    Delay_ms(1000);
    }

    Para que quando o objeto estiver em uma distancia de até 30cm a saída "HCSR04_Saida2" fique em nível alto. Está certo esse código?

    ResponderExcluir
    Respostas
    1. Corrigindo: Distancia de até 10 cm a saída fique em nível alto.

      Excluir
    2. Arrume isso aqui:
      if(distancia < 100){
      HCSR04_Saida2 = 1;
      }
      else{
      HCSR04_Saida2 = 0;
      }

      Troque HCSR04_Saida2 por HCSR04_Saida

      Excluir
  11. Seria possível usar o PIC 12F675 com clock interno para identificar se a distância estiver menor que 1 metro usando este software?
    Precisaria modificar o que?
    Obrigado.

    ResponderExcluir
  12. Olá, estou projetando um robo que irá utilizar um módulo deste.
    utilizarei um PIC16F877A.

    Seria possível disponibilizar o código para utilizar no source?

    ResponderExcluir
  13. A função WordToStr é de que Biblioteca, estou enfrentando muitos problemas para converter Float para Char no compilador XC8 usando a IDE Mplab.

    ResponderExcluir
  14. Olá Thiago,

    Primeiramente parabéns pelo site.
    Gostaria de saber se no seguidor de linha, posso colocar este sensor, sendo que ao avistar um obstaculo terá que parar por 10 segundo e depois retornar ao percurso normal. Como faço isso.
    Preciso de uma força aí.
    Obrigado
    Carlos

    ResponderExcluir
  15. seria possivel ao inves de mostrar a distancia, mostrar litros de agua?

    ResponderExcluir
  16. Boa noite. Estou com o seguinte problema: Calculei o "factor" para Cristal de 20MHz, configurei o Timer1 para 1us, código exatamente igual ao publicado, apenas essas alterações para ajustar ao meu projeto. Porém, até 2m funciona muito bem. Mais que isso já não dá certo. Achei que pudesse ser o sensor mas já testei dois e estão do mesmo jeito. Alguém sabe o que poderia ser??? Pelo que sei esse sensor mede até 4m certo? Qualquer ajuda é bem vinda... Grato desde já!!!

    ResponderExcluir
    Respostas
    1. Resolvido! Não sei pq mas o problema era com o Clock. Tirei o cristal de 20MHz e rodei com o oscilador interno (4MHz), alterei os valores do "factor" e do Timer1 pra obter 1us e funcionou. Se alguém souber pq não funciona com o Cristal de 20MHz seria uma informação importante... Até mais! Parabéns pelo blog.

      Excluir
  17. Estou adaptando ao meu projeto com o 16f887 ja tive resultado positivos mas n consigo compreender essa trecho o que faz ?



    i = 0xFFFF;
    while( !HCSR04_Echo && i-- );
    TMR1H = 0;
    TMR1L = 0;
    TMR1ON_Bit = 1;

    i = 0xFFFF;
    while( HCSR04_Echo && i-- );

    TMR1ON_Bit = 0;

    time = *(unsigned*)&TMR1L;
    distance = (0.175 * time / fator); //distancia em mm

    ResponderExcluir

Postagens Relacionadas!!