Sensor de distancia HC-SR04

No entiendo por qué configuras el pin RA0 como entrada, cuando usas RA1 para la detección, y está configurado cómo salida.
¿No te sirvió nada de lo expuesto en los temas anteriores?
 
Todo mi puerto A está configurado como entrada, por el "TrisA=1"
y solo use el bit RA1, ya que es mi unica entrada, la del sensor
 
No. TRISA = 1 es tener únicamente RA0 cómo entrada y el resto salidas.
Recuerda: Un 1 pone el bit cómo entrada, y un 0 lo pone cómo salida.
Entonces TRISA = 1 = 0b00000001 // RA0 será entrada.

Si lo dejaras sin configurar si quedaría todo el puerto A cómo entradas.
Por defecto ese es el estado inicial de todos los puertos.
Que sería: TRISA = 0xFF pero escribir ésto, es redundante.
 
Pero se supone que TrisA=1 señala como si fuera 0b11111111
Al igual que si se pone TrisA=0, sería 0b00000000,
Así se declara por puerto completo.
Si fuera por bit... Sería TrisA=0b00000010
Pero en mi caso paraa evitarme de todo yo puse todo el puerto
 
No, señor. Aquí ya estás muy mal.
Un 1 es un 1, y en binario de 8 bits es 0b00000001
Si fuera 0xFF (Hexadecimal) o 255 (Decimal), entonces si sería 0b11111111 (Binario)
Piensa en binario, que es como el microcontrolador toma los números.
RA7 es el bit más significativo, y RA0 es el bit menos significativo del puerto A.

Entonces, vamos a verlo de la siguiente manera:
RA7, RA6, RA5, RA4, RA3, RA2, RA1, RA0
Bit 7, Bit 6, Bit 5, Bit 4, Bit 3, Bit 2, Bit 1, y Bit 0 = 8 bits del puerto A
Si escribes TRISA = 1, en binario de 8 bits será: 00000001
Los ceros a la izquierda no cuentan, pero lo ejemplifico con los 8 bits para que lo comprendas.
¿Qué pasa?
Que para el microcontrolador será un 1 o 0b00000001.
O sea, pondrá un 1 en el bit 0 del registro TRISA, y esto lo hace entrada, quedando los demás cómo salidas por estar en 0.

Me parece que debes estudiar el sistema numérico binario. :rolleyes:
 
Muchas gracias y disculpe si no me di a entender bien... Okay
Sé bien como usar y conozco el sistema binario
Conozco sus valores de decimal a binario´, así como 2 en decimal es en binario 10
3 es 11
4 es 100... etc,.

Ahora, no se si su duda surja por el compilador que uso... Uso el compilador MikroC, lo he estudiado y he aprendido a programar en ese compilador, y principalmente esas instrucciones principales, son las escenciales de aprender para la programación en MikroC, ahora pues no me queda más que justificarle mi respuesta con esta captura que realicé de un ejemplo de un programa hecho por la misma empresa que creo el compilador, disculpe pero si esto no es suficiente justificar pues.... Gracias
 

Adjuntos

  • fig4-30.gif
    fig4-30.gif
    29.5 KB · Visitas: 17
Muchas gracias y disculpe si no me di a entender bien... Okay
Sé bien como usar y conozco el sistema binario
Conozco sus valores de decimal a binario´, así como 2 en decimal es en binario 10
3 es 11
4 es 100... etc.
Entonces me sorprende que digas que TRISA = 1 coloca todo el registro en 0b11111111

Ahora, no sé si su duda surja por el compilador que uso... Uso el compilador MikroC, lo he estudiado y he aprendido a programar en ese compilador, y principalmente esas instrucciones principales, son las esenciales de aprender para la programación en MikroC.
Yo no tengo dudas.
El sistema binario es el mismo para cualquier tipo de compilador.
Ahora pues no me queda más que justificarle mi respuesta con esta captura que realicé de un ejemplo de un programa hecho por la misma empresa que creo el compilador, disculpe pero si esto no es suficiente justificar pues.... Gracias
El código de esa imagen tiene lo siguiente:
Código:
ANSEL = 0 ; // = 0b00000000 (Todo el registro en 0)
ANSELH = 0; // = 0b00000000 (Todo el registro en 0)
PORTB = 0b01010101; // RB7 = 0, RB6 = 1, RB5 = 0, RB4 = 1, RB3 = 0, RB2 = 1, RB1 = 0, RB0 = 1
TRISB = 0; // = 0b00000000 // Todo el puerto B cómo salidas.
Entonces esa imagen no justifica nada.
No es lo mismo TRISB = 0 que TRISB = 1.
Aquí volvemos a lo mismo:
0 en binario de 8 bits = 0b00000000
1 en binario de 8 bits = 0b00000001

Y si sabemos que los ceros a la izquierda no cuentan, será lo mismo escribir un 1 que un 0.
Repito, los 8 bits en 1 equivale a 255 en decimal, 0xFF hexadecimal y 0b11111111 en binario.

Si dices que conoces bien el sistema binario, ¿Entonces qué te hace pensar que un 1 pondrá los 8 bits en 1?
 
hola que tal a todos, estoy tratando de hacer funcionar un sensor ultrasonico el que tengo es el HC-SR04 pero hasta ahora no eh podido hacerlo, mas abajo les dejo mi código por si alguien me puede decir el error que estoy cometiendo....el pic16f887 es el que estoy utilizando y estoy programando en MikroC

Código:
sbit LCD_RS at RD4_bit;
sbit LCD_EN at RD5_bit;
sbit LCD_D4 at RD0_bit;
sbit LCD_D5 at RD1_bit;
sbit LCD_D6 at RD2_bit;
sbit LCD_D7 at RD3_bit;
sbit LCD_RS_Direction at TRISD4_bit;
sbit LCD_EN_Direction at TRISD5_bit;
sbit LCD_D4_Direction at TRISD0_bit;
sbit LCD_D5_Direction at TRISD1_bit;
sbit LCD_D6_Direction at TRISD2_bit;
sbit LCD_D7_Direction at TRISD3_bit;

char txt1[]="Distancia:";
int time_us;
int distance;
char length_cm[4];

void main() {
ADCON1 = 0X06;            //confg an as digital
ANSEL  = 0x00;            // Configure
ANSELH = 0x00;            // Configure other AN pins as digital I/O
C1ON_bit =  0;            // Deshabilitar comparadores
C2ON_bit =  0;
TRISE.RE0 = 0;
TRISE.RE1 = 1;
INTCON = 0x00;            //Disable interrupts
T1CON = 0x00;
Lcd_Init(); // Inicialización del visualizador LCD
Lcd_Cmd(_LCD_CURSOR_OFF); // Comando LCD (apagar el cursor)
Lcd_Cmd(_LCD_CLEAR); // Comando LCD (borrar el LCD)
Lcd_Out(1,2,txt1);

while(1)
{
PORTE.RE0=0;//initialize trig to inactive level
delay_ms(1000);
PORTE.RE0=1; //ping the sonar
delay_us(10); //sending 10us pulse
PORTE.RE0=0;

while (PORTE.RE1 =0); //wait for high state of echo pin
{}
TMR1L = 0; //Clear the TMR1L value
TMR1H = 0 ; //Clear the TMR1H value
T1CON = 0x21; //Enable TMR1

while (PORTE.RE1=1); //While echo received, let the TMR1 count
{}
T1CON=0;
time_us = TMR1H + TMR1L; //Retain TMR1 value = ON pulse
distance = ((time_us/58)*34000/2); //distance in cm


intTostr(distance, length_cm) ;

Lcd_Out(2,3,length_cm); //Write text in 2nd row
Lcd_Out(2,7,"cm"); // Write text in 2nd row

delay_ms(500);
}
}
 
Última edición:
¿Por qué no tomas como referencia el código del post #34?
Ahí hay un enlace con un programa escrito en MikroC.
el pic16f877 es el que estoy utilizando y estoy programando en MikoC
¿Seguro que estás usando un PIC16F877?
Porque los registros ANSEL, ANSELH, C1ON y C2ON, no son registros de ese PIC.
 
Última edición:
¿Por qué no tomas como referencia el código del post #34?
Ahí hay un enlace con un programa escrito en MikroC.

¿Seguro que estás usando un PIC16F877?
Porque los registros ANSEL, ANSELH, C1ON y C2ON, no son registros de ese PIC.

Cierto me equivoque estoy utilizando el pic16f887 error de dedo :LOL:

Ya probé el código que dices pero no me mide bien, le pongo un obstáculo cerca y me aparece Out Of Range y la única modificación que hice fue cambie de puerto el trigger y echo, mira abajo dejo el codigo

Código:
sbit LCD_RS at RD4_bit;
sbit LCD_EN at RD5_bit;
sbit LCD_D4 at RD0_bit;
sbit LCD_D5 at RD1_bit;
sbit LCD_D6 at RD2_bit;
sbit LCD_D7 at RD3_bit;
sbit LCD_RS_Direction at TRISD4_bit;
sbit LCD_EN_Direction at TRISD5_bit;
sbit LCD_D4_Direction at TRISD0_bit;
sbit LCD_D5_Direction at TRISD1_bit;
sbit LCD_D6_Direction at TRISD2_bit;
sbit LCD_D7_Direction at TRISD3_bit;

void main()
{
  int a;
  char txt[7];
  OSCCON=0b0110110;
  ADCON1 = 0X06;            //confg an as digital
  ANSEL  = 0x00;            // Configure
  ANSELH = 0x00;            // Configure other AN pins as digital I/O
  C1ON_bit =  0;            // Deshabilitar comparadores
  C2ON_bit =  0;
  TRISE.RE0 = 0;            //Trigger
  TRISE.RE1 = 1;            //RE1 as Input PIN (ECHO)
  Lcd_Init();               // Inicialización del visualizador LCD
  Lcd_Cmd(_LCD_CURSOR_OFF); // Comando LCD (apagar el cursor)
  Lcd_Cmd(_LCD_CLEAR);      // Comando LCD (borrar el LCD)

  Lcd_Out(1,1,"Developed By");
  Lcd_Out(2,1,"electroSome");

  Delay_ms(3000);
  Lcd_Cmd(_LCD_CLEAR);

  T1CON = 0x10;                 //Initialize Timer Module

  while(1)
  {
    TMR1H = 0;                  //Sets the Initial Value of Timer
    TMR1L = 0;                  //Sets the Initial Value of Timer

    PORTE.F0 = 1;               //TRIGGER HIGH
    Delay_us(10);               //10uS Delay
    PORTE.F0 = 0;               //TRIGGER LOW

    while(!PORTE.F1);           //Waiting for Echo
    T1CON.F0 = 1;               //Timer Starts
    while(PORTE.F1);            //Waiting for Echo goes LOW
    T1CON.F0 = 0;               //Timer Stops

    a = (TMR1L | (TMR1H<<8));   //Reads Timer Value
    a = a/58.82;                //Converts Time to Distance
    a = a + 1;                  //Distance Calibration
    if(a>=2 && a<=400)          //Check whether the result is valid or not
    {
      IntToStr(a,txt);
      Ltrim(txt);
      Lcd_Cmd(_LCD_CLEAR);
      Lcd_Out(1,1,"Distance = ");
      Lcd_Out(1,12,txt);
      Lcd_Out(1,15,"cm");
    }
    else
    {
      Lcd_Cmd(_LCD_CLEAR);
      Lcd_Out(1,1,"Out of Range");
    }
    Delay_ms(400);
  }
}



creo que ya se que estaba mal, lo que pasa es que estaba utilizando el oscilador interno pero creo que lo configure mal así que mejor puse un externo y ya las mediciones van un poco mejor pero solo a distancias pequeñas como 7 cm porque si alejo el objeto la distancia empieza a variar y aveces se va hasta 374 cm :unsure: :confused:
 
Última edición:
estoy tratando de meterle condiciones para que cuando detecte una cierta distancia muestre en la pantalla LCD nivel bajo, nivel medio,..etc pero no pasa nada

Código:
if (a>7){
      Lcd_Cmd(_LCD_CLEAR);            // Comando LCD (borrar el LCD)
      Lcd_Out(2,1,"Nivel Bajo");
      Lcd_Out(1,1,"Distance = ");
      Lcd_Out(1,12,txt);
      Lcd_Out(1,15,"cm");
      UART1_Write_Text("Nivel Bajo");
      UART1_Write(0x0D);              // ASCII - Retorno de Carro
      UART1_Write(0x0A);              // ASCII - Avance de Linea
      Delay_ms(400);
      }
      if (a>=4 && a<=7){
      Lcd_Cmd(_LCD_CLEAR);        // Comando LCD (borrar el LCD)
      Lcd_Out(2,1,"Nivel Medio");
      Lcd_Out(1,1,"Distance = ");
      Lcd_Out(1,12,txt);
      Lcd_Out(1,15,"cm");
      UART1_Write_Text("Nivel Medio");
      UART1_Write(0x0D);              // ASCII - Retorno de Carro
      UART1_Write(0x0A);              // ASCII - Avance de Linea
      Delay_ms(400);
      }
      if (a>=0 && a<4){
      Lcd_Cmd(_LCD_CLEAR);        // Comando LCD (borrar el LCD)
      Lcd_Out(2,1,"Nivel Alto");
      Lcd_Out(1,1,"Distance = ");
      Lcd_Out(1,12,txt);
      Lcd_Out(1,15,"cm");
      UART1_Write_Text("Nivel Alto");
      UART1_Write(0x0D);              // ASCII - Retorno de Carro
      UART1_Write(0x0A);              // ASCII - Avance de Linea
      Delay_ms(400);
      }

alguien me puede decir que estoy haciendo mal??
 
Deberías subir el código completo que estás usando actualmente.
Si uno arma el programa con lo que has subido, los resultados pueden ser muy diferentes.
 
mira aca esta el codigo

Código:
int a;
  char txt[7];
  void medir(void);

void main()
{
  ADCON1 = 0X06;            //confg an as digital
  ANSEL  = 0x00;            // Configure
  ANSELH = 0x00;            // Configure other AN pins as digital I/O
  C1ON_bit =  0;            // Deshabilitar comparadores
  C2ON_bit =  0;
  TRISE = 0b00000010;
  PORTE = 0;
  Lcd_Init();                 // Inicialización del visualizador LCD
  Lcd_Cmd(_LCD_CURSOR_OFF);   // Comando LCD (apagar el cursor)
  Lcd_Cmd(_LCD_CLEAR);        // Comando LCD (borrar el LCD)
  Lcd_Out(1,1,"Sensando");
  UART1_Init(9600);           // Iniciar comunicacion Serial
  Delay_us(100);              // Retardo para estabilizar el ADC
  T1CON = 0x10;                 //Initialize Timer Module
  
  while (1) {
  void medir();
  
  if (a>=7){
      Lcd_Cmd(_LCD_CLEAR);            // Comando LCD (borrar el LCD)
      Lcd_Out(2,1,"Nivel Bajo");
      Lcd_Out(1,1,"Distance = ");
      Lcd_Out(1,12,txt);
      Lcd_Out(1,15,"cm");
      UART1_Write_Text("Nivel Bajo");
      UART1_Write(0x0D);              // ASCII - Retorno de Carro
      UART1_Write(0x0A);              // ASCII - Avance de Linea
      Delay_ms(400);
      }
      if (4<=a<=7){
      Lcd_Cmd(_LCD_CLEAR);        // Comando LCD (borrar el LCD)
      Lcd_Out(2,1,"Nivel Medio");
      Lcd_Out(1,1,"Distance = ");
      Lcd_Out(1,12,txt);
      Lcd_Out(1,15,"cm");
      UART1_Write_Text("Nivel Medio");
      UART1_Write(0x0D);              // ASCII - Retorno de Carro
      UART1_Write(0x0A);              // ASCII - Avance de Linea
      Delay_ms(400);
      }
      if (0<=a<=4){
      Lcd_Cmd(_LCD_CLEAR);        // Comando LCD (borrar el LCD)
      Lcd_Out(2,1,"Nivel Alto");
      Lcd_Out(1,1,"Distance = ");
      Lcd_Out(1,12,txt);
      Lcd_Out(1,15,"cm");
      UART1_Write_Text("Nivel Alto");
      UART1_Write(0x0D);              // ASCII - Retorno de Carro
      UART1_Write(0x0A);              // ASCII - Avance de Linea
      Delay_ms(400);
      }
      }

}

void medir(void)
  {
    TMR1H = 0;                  //Sets the Initial Value of Timer
    TMR1L = 0;                  //Sets the Initial Value of Timer

    PORTE.F0 = 1;               //TRIGGER HIGH
    Delay_us(10);               //10uS Delay
    PORTE.F0 = 0;               //TRIGGER LOW

    while(!PORTE.F1);           //Waiting for Echo
    T1CON.F0 = 1;               //Timer Starts
    while(PORTE.F1);            //Waiting for Echo goes LOW
    T1CON.F0 = 0;               //Timer Stops

    a = (TMR1L | (TMR1H<<8));   //Reads Timer Value
    a = a/58.82;                //Converts Time to Distance
    a = a + 1;                  //Distance Calibration

      IntToStr(a,txt);
      Ltrim(txt);
  }

ya me di cuenta del problema, es que estaba declarando mal los void(funciones) y como no me marcaba el error al compilar, no me daba cuenta de mi enorme error jejeje una disculpa.... pero ya que solucione esto, me puedes dar una idea de como hacer que cuando presione una tecla en especial del teclado matricial me active una salida para un pequeño motor, necesariamente tengo que utilizar interrupciones o lo puedo hacer sin utilizarla?.....lo que quiero hacer es que cuando presione un botón se active el motor y se detenga hasta que llegue al nivel deseado
 
Última edición:
Ya me dí cuenta del problema, es que estaba declarando mal los void(funciones) y como no me marcaba el error al compilar, no me daba cuenta de mi enorme error.
OK. Es lo que te iba a mencionar acerca del "void medir();" dentro del bucle.
¿Me puedes dar una idea de cómo hacer que cuando presione una tecla en especial del teclado matricial, me active una salida para un pequeño motor?
Necesariamente tengo que utilizar interrupciones. ¿O lo puedo hacer sin utilizarlas?
Lo que quiero hacer, es que cuando presione un botón, se active el motor y se detenga hasta que llegue al nivel deseado.
Se me ocurre que puedes usar la interrupción por cambio de estado en el puerto B. <RB7:RB4>
 
Hola buena gente, tengo un problemilla y no se donde esta mi error al hacer el codigo.

Código:
#include<16F876A.h>
#fuses XT,NOPUT,NOBROWNOUT,NOPROTECT
#use delay(clock=4Mhz)

#include "flex_lcd 4x20.c"
#define trig      pin_C0  // Disparo  HC-SR04
#define echo    pin_C1  // Receptor HC-SR04
#define motor  pin_C2  // Pin de Motor

#use fast_io(B)
#use fast_io(C)

int16 toma[5];
float distancia=0;

int16 Longitud(void) {
 int16 centimetros=0;         
  output_high(trig);         
  delay_us(10);               
  output_low(trig);           
 while(!input(echo)){}       
 while(input(echo)) {         
  centimetros++;             
   delay_us(52);             
    }
delay_ms(50);             
return(centimetros);
  }
 
void main( void ) {
  set_tris_B(0X00);
  set_tris_C(0X02);
   output_B(0);
   output_C(0);

 lcd_init();

  lcd_putc('\f');
  lcd_gotoxy(1,1);
  lcd_putc("  DISTANCIA MEDIDA  ");
  lcd_gotoxy(1,2);
  printf(lcd_putc,"  MEDIDA: %03.1f cmts ",distancia);
 
 while (true) {
 
 toma[0]= Longitud();
 delay_ms(3000);
 toma[1]= Longitud();
 delay_ms(3000);
 toma[2]= Longitud();
 delay_ms(3000);
 toma[3]= Longitud();
 delay_ms(3000);
 toma[4]= Longitud();
 distancia=(toma[0]+toma[1]+toma[2]+toma[3]+toma[4])/5.0;   // instruccion que funciona
 
 // distancia=toma[5]/5.0;                                // instruccion que no funciona
 
  if(distancia>15) {                    // Si la distancia es mayor de 10cm
     lcd_gotoxy(1,2);
     printf(lcd_putc,"%3lu%3lu%3lu%3lu%3lu %3.2f",toma[0],toma[1],toma[2],toma[3],toma[4],distancia);
      output_high(motor);           // El Motor esta encendido
      }   
  if(distancia<=15) {                 // si la distancia es menor de 10cm
     lcd_gotoxy(1,2);
     printf(lcd_putc,"%3lu%3lu%3lu%3lu%3lu %3.2f",toma[0],toma[1],toma[2],toma[3],toma[4],distancia);
      output_low(motor);            // El Motor esta apagado
       }
   delay_ms(500);     
     }     
  }

el tema es que si la instruccion pongo "distancia=(toma[0]+toma[1]+toma[2]+toma[3]+toma[4])/5.0; " funciona bien,
si la hago "distancia=toma[5]/5.0;" entonces ya no funciona, esto lo hago asi por que pense que ahorraba tener que poner todas las tomas.

Esta es mi pregunta: como debo poner la instruccion para evitar que sea tan larga?.

Lo de los delays de 3000 ms solo es para las practicas en proteus.
 
Hola.
No entiendo que es exactamente lo que quieres hacer con toma[5]. Si quieres hacer la media de las 5 lecturas vas bien.
Si quieres usar toma[5] la tienes que declarar con: int16 toma[6];
y has puesto: int16 toma[5]; que va de toma[0] a toma[4]
 
Esta es mi pregunta: como debo poner la instruccion para evitar que sea tan larga?
Hola, si lo que buscas es la suma de todos los elementos puedes crear una funcion que realice esta accion, la instruccion "distancia=toma[5]/5.0" no es de ningun modo valida, aqui estas dividiendo el elemento 5 del vector entre cinco, elemento que por cierto no existe.
 
Eso es lo que intento hacer darkbytes, ahora he creado una funcion como dice 1024, cosa que no habia pensado, pero aun me falta poder sacar en pantalla los datos de las 5 tomas, eso es para poder comprobar si funciona bien el programa.

La funcion que creado es la siguiente, creo que esta bien por que estoy probandola en proteus y saca el resultado bien, lo que me falta es poder sacar los datos de las 5 tomas que no se como hacerlo.

Código:
void medir(void) {
for(i=0;i<5;i++) {
  toma=Longitud();
  total+=toma;
  delay_ms(1500);
   }
distancia=total/5.0;
}

Bueno pues ya lo tengo como deseaba mas-menos pero queda bien, he modificado un poco la funcion y a la vez saco en pantalla la variable total con la que se cual es la suma de las tomas y por otro lado saco, con la variable distancia, la media.
Lo que me gustaria es poder sacar en pantalla las 5 tomas pero esto ya se me complica un poco, de todas formas gracias a todos.
La funcion la he dejado como sigue:
Código:
void medir(void) {
  for(i=0;i<5;i++) {
    total+=Longitud();
    delay_ms(1500);
    }
 distancia=total/5.0; 
 }
 
Última edición:
Atrás
Arriba