# Sensor de distancia HC-SR04



## syryus (Jun 25, 2012)

Hola a todos. Tengo un problema con la programación de un sensor de distancia por ultrasonidos con un ATmega128 y Mikroc.

Lo que hago es mandar un pulso de 15µs al Trigger y esperar a recibir por el Echo el pulso correspondiente que mas tarde mediré y será lo que me de la distancia.

El VCC del sensor está conectado al puerto PA7 que siempre se mantiene en estado alto para mantener la tensión del sensor.

```
/*Defino donde va a estar conectado el sensor*/

#define ECHO PORTA.B3
#define TRIG PORTA.B5
#define VCC  PORTA.B7
int i,r,distancia;

// Conexiones LCD
sbit LCD_RS at PORTC2_bit;
sbit LCD_EN at PORTC3_bit;
sbit LCD_D4 at PORTC4_bit;
sbit LCD_D5 at PORTC5_bit;
sbit LCD_D6 at PORTC6_bit;
sbit LCD_D7 at PORTC7_bit;

sbit LCD_RS_Direction at DDC2_bit;
sbit LCD_EN_Direction at DDC3_bit;
sbit LCD_D4_Direction at DDC4_bit;
sbit LCD_D5_Direction at DDC5_bit;
sbit LCD_D6_Direction at DDC6_bit;
sbit LCD_D7_Direction at DDC7_bit;
// Fin conexiones LCD

//Función para leer pulso
  int ancho_pulso ()
{
//Espero flanco de subida en ECHO, me mantengo en el bucle hasta que detecte tensión

        for(i=0;i<600000;i++)
          {
          if (!ECHO) continue; else break;
          }
//Si supera esos ciclos es que no hay ningún objeto
          if(i==600000)
          return 0xFFFF;
//Voy a configurar el timer
           TCCR0=0x02; //preescaler 8
           TCNT0=0x00; //empieza a contar
           
                  for(i=0;i<600000;i++)
       {
          if(ECHO)
          {
             if(TCNT0 > 60000) break; else continue;
          }
          else
             break;
       }
       if(i==600000)
          return 0xffff;
          
          distancia=TCNT0;
          
                 if(distancia > 60000)
         return 0xfffe;
       else
          return distancia;
}

void main (){
/*
Configuración previa de los puertos
-Dejo solo como entrada PA3
-Dejo el puerto de VCC como salida para alimentar
-Dejo el trigger a 0 al principio
*/

     DDRA=0xF7;
     PORTA=0xD7;
     delay_ms(1000);

       

 while (1) {
 TRIG=0xFF;
 Delay_ms(15);
 TRIG=0x00;
   
   r=ancho_pulso();
//Inicio LCD
  Lcd_Init();                        // Inicio
  Lcd_Cmd(_LCD_CLEAR);               // Limpio
  Lcd_Cmd(_LCD_CURSOR_OFF);          // Apago cursor
   
   if (r==0xFFF)
   {
    Lcd_Out(1,1,"ERROR");
   }
   else
            {

            int d;

            d=(r/58); //Paso a cm

            LCD_out (1,1,d);

         }
}
}
```

La verdad es que ando algo perdido espero que alguien pueda orientarme


----------



## syryus (Jun 25, 2012)

He corregido algo y parece ser que ya manda y recibe a traves de Trigger y Echo respectivamente algo. Pero aun no consigo nada en el LCD...


```
/*Defino donde va a estar conectado el sensor*/

#define ECHO PORTA.B3
#define TRIG PORTA.B5
#define VCC  PORTA.B7
int i,r,distancia;
char texto[7];


// Conexiones LCD
sbit LCD_RS at PORTC2_bit;
sbit LCD_EN at PORTC3_bit;
sbit LCD_D4 at PORTC4_bit;
sbit LCD_D5 at PORTC5_bit;
sbit LCD_D6 at PORTC6_bit;
sbit LCD_D7 at PORTC7_bit;

sbit LCD_RS_Direction at DDC2_bit;
sbit LCD_EN_Direction at DDC3_bit;
sbit LCD_D4_Direction at DDC4_bit;
sbit LCD_D5_Direction at DDC5_bit;
sbit LCD_D6_Direction at DDC6_bit;
sbit LCD_D7_Direction at DDC7_bit;
// Fin conexiones LCD

//Función para leer pulso
  int ancho_pulso ()
{
//Espero flanco de subida en ECHO, me mantengo en el bucle hasta que detecte tensión

        for(i=0;i<600;i++)
          {
          if (!ECHO) continue; else break;
          }
//Si supera esos ciclos es que no hay ningún objeto
          if(i==600)
          return 0xFFFF;
//Voy a configurar el timer
           TCCR0=0x02; //preescaler 8
           TCNT0=0x00; //empieza a contar
           
                  for(i=0;i<600;i++)
       {
          if(ECHO)
          {
             if(TCNT0 > 600) break; else continue;
          }
          else
             break;
       }
       if(i==600)
          return 0xffff;
          
          distancia=TCNT0;
          TCCR1B=0x00;
          
                 if(distancia > 600)
         return 0xfffe;
       else
          return distancia;
}

void main (){
/*
Configuración previa de los puertos
-Dejo solo como entrada PA3
-Dejo el puerto de VCC como salida para alimentar
-Dejo el trigger a 0 al principio
*/

     DDRA=0xF7;
     PORTA=0xD7;
     DDRB=0xFF;
     PORTB=0x00;
     //Inicio LCD
  Lcd_Init();                        // Inicio
  Lcd_Cmd(_LCD_CLEAR);               // Limpio
  Lcd_Cmd(_LCD_CURSOR_OFF);          // Apago cursor
     delay_ms(1000);
  LCD_out (1,6,"PRUEBA");
  LCD_out (2,2,"Sensor HC-SR04");
  Delay_ms(2000);

       

 while (1) {
  delay_ms(100);
 TRIG=0xFF;
 Delay_ms(15);
 TRIG=0x00;

   
   r=ancho_pulso();

   if (r==0xFFF)
   {
    Lcd_Out(1,1,"ERROR");
   }
   else
            {

            int d;

            d=(r/58); //Paso a cm

            IntToStr (d,texto);
            Lcd_Cmd(_LCD_CLEAR);
            LCD_out (1,1,texto);

         }
}
}
```


----------



## Gudino Roberto duberlin (Jun 25, 2012)

Amigo, 1ro. arma un simple algoritmo para probar unicamente el display LCD.


----------



## andbrs (May 14, 2013)

Hola que tal, tengo un proyecto de programas un carro que evada obstáculos,
y pues el primer paso fue comprar el sensor que es un hc-sr04 pero no lo puedo probar por que no entiendo mucho de la implementación de los pulso echo y trigger.
Mi pregunta es, si tienen un programa para probarlo, o algo para decir si funciona o no ???
gracias 
Es picc o ccs el compilador gracias y si esta simulado en proteus
aunque me ayudarían si me explicaran para armar el código 

yo ya hice parte del código, me podrían ayudar por que solo me mide 001cm.
Pareciera de que no cuenta bien, y está bien conectado y todo (aclaro la idea la saque de un ejemplo de programa que encontré) Gracias





```
#include "C:\Users\User\Desktop\sensor prueba 1\pic c 3\main.h"
#define trig pin_b0
#define echo input(pin_b1)
#include "flex_lcd.c"
#include "kbd_lib.c"



int16 mide_distancia(void)
{
int16 centimetros=0; 
output_high(trig); // pulso de disparo
delay_us(50);
output_low(trig);

while(echo==0); 

while(echo==1)
{
centimetros++;
delay_us(58);

delay_ms(50);
return(centimetros);
}
}


void main()
{
int16 distancia;
int8 i;
lcd_init(); 


while (true)
{
distancia=mide_distancia(); 

lcd_gotoxy(1,1);
if(distancia>100)
{ // si lectura > 500cm entonces no es valida, osea no hay objeto
lcd_putc('\f'); // Borra LCD
printf(lcd_putc,"no objeto");
output_low(pin_c0);
}

else
{

printf(lcd_putc,"%03lucm ",distancia);
output_high(pin_c0);

}
}
}
```


----------



## komisario (May 19, 2013)

Hola amigos del Foro!...les cuento que soy estudiante de ingenieria electrónica. Actualmente estoy cursando una materia llamada Procesadores II, en la que aprendemos la estructura, funcionamiento y programacion de microcontroladores pic.

Estoy en por empezar un proyecto, el cual es un detector de distancia para vehículo. La idea es determinar la distancia entre dos vehículos para estacionar. El problema es que aun no vemos (y al parecer no nos enseñaran en esta materia) el uso de sensores de proximidad. He leído sobre algunos de ultrasonido, pero aun no logro entender bien como es su funcionamiento. 

El motivo de este tema, es pedirles ayuda sobre el uso de sensores de este tipo, y si pueden facilitarme en lo posible material para estudiarlos y ver como funcionan, asi llevo adelante dicho proyecto. Aclaro que estuve buscando en google sobre sensores, pero no encontre hasta el momento información profundizada sobre esto. 

Desde ya muchas gracias por tomarse su tiempo en leer mi inquietud.

Saludos a todos!


----------



## Gerson strauss (May 20, 2013)

komisario dijo:


> Hola amigos del Foro!...les cuento que soy estudiante de ingenieria electrónica. Actualmente estoy cursando una materia llamada Procesadores II, en la que aprendemos la estructura, funcionamiento y programacion de microcontroladores pic.
> 
> Estoy en por empezar un proyecto, el cual es un detector de distancia para vehículo. La idea es determinar la distancia entre dos vehículos para estacionar. El problema es que aun no vemos (y al parecer no nos enseñaran en esta materia) el uso de sensores de proximidad. He leído sobre algunos de ultrasonido, pero aun no logro entender bien como es su funcionamiento.
> 
> ...



Mira en este enlace, a ver si te sirve algo. ULTRASONIDO


----------



## andbrs (May 20, 2013)

bueno como nadie pudo responder mi pregunta yo te la respondo a ti entre mas sensillo es la cosa es mejor yo tuve que comprar un sensor ultrasonico hc sr04 el cual me costo en colombia unos 30 dolares o 60000 pesos colombianos este es talvez el mas sencillo y cumple bien su tarea el manda un pulso cada cierto tiempo (lo indica el programa yo por ejemplo utilizo lenguajes c en pcw o pic c) el cual activa un contador tambien en el pic y calcula la distancias en el pic si compilas en pcw y decides comprarlos me dices para enviarte el codigo de prueba


----------



## komisario (May 22, 2013)

Muchisimas gracias Andres y Gerson por sus respuestas y ayuda!!...voy a implementarlo en C con el Ccs Compiler y luego vere como funciona la cosa...en proteus no hay forma de simular dicho sensor??...aca dejo un link que me pareció muy interesante con respecto al uso del sensor, con pic, por si le sirve a alguien ...http://campos-inventronica.blogspot.com.ar/2012/04/como-usar-sensor-ultrasonico-hc-sr04.html


----------



## andbrs (May 22, 2013)

bueno si vas a utilizar el ccs que creo que es el mismo pcw ese código de ejemplo no te funcionara o al menos a mi no me sirvio te paso uno que si me funciono solo hay que cuadrarle los centímetros pero te dice si tu sensor funciona o no


```
#include "main.h"
#use delay(clock=20000000) 
#include "flex_lcd.c"                        


int16 distancia, tiempo;
#define trig pin_B0
#define echo pin_B1

void main() 
{ 
output_low(PIN_C1);
lcd_init();                              
printf(LCD_PUTC, "\f Iniciando...");
delay_ms(1000);
printf(LCD_PUTC, "\fProbando Sensor\nUltrasonico"); 
delay_ms(1000);                              
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); 

while(true)
{ 
output_high(trig);                     
delay_us(20);                         
output_low(trig); 
while(!input(ECHO))                      
{} 
set_timer1(0);                           
while(input(ECHO))                       
{} 
tiempo=get_timer1();                       
distancia=tiempo*0.028 + 1.093 ;                                   
printf(LCD_PUTC, "\fTiempo :%Lu \nDistancia = %Lu",tiempo,distancia); 
delay_ms(100); 

if (distancia>5)
{

      output_high(PIN_C1);
      


}
else
{
output_low(PIN_C1);
}

} 
}
```
las librería flex_lcd son modificadas por que yo utilizo un cristal de 20Mh me dices para subirlas librerías que luego las pegas en donde te compila tu proyecto 

aaa y el sensor no se puede simular en proteus te toca estar quemando el pic (quemar es grabar por si acaso) e ir probando


----------



## locodelafonola (May 22, 2013)

hola aca en el link http://www.sharatronica.com/ultrasonido.html tenes explicado como funciona el ultra sonido y algunos calculos de como medir la distancia y basicamente tendras que realizar uncontador de tiempo y traducirlo a representacin en metros...juan


----------



## juanpp (May 30, 2013)

hola que tal estoy haciendo un proyecto de un sensor ultrasonico que me detecte un objeto a una distancia pero pues la verdad es que no se como hacerlo ni tampoco programar el pic estoy utilizando un pic 16f887 y sensor hc sr04 me gustaria que me ayudaran con esto y me dieran una idea de como arrancar


----------



## andbrs (May 30, 2013)

Mi pregunta es, ¿sabes programar? si es así, ¿que lenguaje manejas? si utilizas pic c este código te servirá.
Sólo mira que salidas cambian en tu pic, te servirá para probar si tu sensor funciona.


```
include "main.h"
#use delay(clock=20000000) 
#include "flex_lcd.c"                        


int16 distancia, tiempo;
#define trig pin_B0
#define echo pin_B1

void main() 
{ 
output_low(PIN_C1);
lcd_init();                              
printf(LCD_PUTC, "\f Iniciando...");
delay_ms(1000);
printf(LCD_PUTC, "\fProbando Sensor\nUltrasonico"); 
delay_ms(1000);                              
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); 

while(true)
{ 
output_high(trig);                     
delay_us(20);                         
output_low(trig); 
while(!input(ECHO))                      
{} 
set_timer1(0);                           
while(input(ECHO))                       
{} 
tiempo=get_timer1();                       
distancia=tiempo*0.028 + 1.093 ;                                   
printf(LCD_PUTC, "\fTiempo :%Lu \nDistancia = %Lu",tiempo,distancia); 
delay_ms(100); 

if (distancia>5)
{

      output_high(PIN_C1);
      


}
else
{
output_low(PIN_C1);
}

} 
}
```


----------



## Majuliet (May 27, 2014)

andres1594 dijo:


> Mi pregunta es, ¿sabes programar? si es así, ¿que lenguaje manejas? si utilizas pic c este código te servirá.
> Sólo mira que salidas cambian en tu pic, te servirá para probar si tu sensor funciona.
> 
> 
> ...





Hola que tal! estoy usando tu codigo y acomodandolo para mi pic, pero que pic usaste con este programa? el 16F877A?


----------



## D@rkbytes (May 27, 2014)

*andres1594 *no ha regresado al Foro desde 02/08/201, puede ser que no te conteste.

A tu consulta, puedes usar cualquier PIC que tenga Timer1, y también puedes usar la librería lcd.c de CCS en vez de la librería flex_lcd.c.

Al parecer si utilizó el PIC16F877/A u otro mediano como el PIC16F873/A que cuenta con el pin RC1
Si usas otro PIC más pequeño, cambia ese pin por otro y podrás usar ese código.

PD:
Esto también lo tienes que tomar en cuenta al usar otro PIC y la configuración de pines para la pantalla.
#define trig pin_B0
#define echo pin_B1

Suerte.


----------



## Majuliet (May 28, 2014)

Estoy usando el 16F877A pero no me funciona nada. Existe alguna manera de comprobar si el sensor esta funcionando?? 

Tambien tengo una duda con respecto a: 
#define trig pin_B0
#define echo pin_B1

El ayudante de la materia me dijo que colocara el Trigger en ccp1 y el echo en RA2 que se me haria mas facil ya que necesito una salida digital para que pueda conectar el sensor directamente al controlador de servo ( este: pololu . com / product / 1351) hice lo que me dijo pero ni siquiera compila por los errores  si puedes ayudarme con esto te lo agradeceria mucho.


----------



## D@rkbytes (May 28, 2014)

Infortunadamente no tengo ese sensor ni tampoco ese servo, pero prueba con ese mismo código.
Los pines que quieras usar para el echo y el trigger no tienen mucha importancia, puedes usar cualquier otro pin.
Por la configuración de los pines con ADC no te preocupes, el compilador configura ADCON1 = b'00000111'
O sea, con la configuración para que todos los pines con entradas análogas, funcionen como digitales.
Tampoco se está haciendo uso de interrupciones ni capturas, tan solo se está midiendo el tiempo de retorno.
El pin que no te recomiendo usar es RA4, porque es con drenador abierto.

Tal vez los errores de compilación que tienes se deban a que no se incluyó el archivo main.h
Pero prueba con el mismo código ahora con el agregado de la configuración de fuses y usando la librería LCD.C de CCS.

```
#include  <16f877a.h>
#fuses   nobrownout
#use     delay(crystal = 20MHz) 
#include <lcd.c>                       


int16 distancia, tiempo;
#define trig pin_B0
#define echo pin_B1

void main() 
{ 
output_low(PIN_C1);
lcd_init();                              
printf(LCD_PUTC, "\f Iniciando...");
delay_ms(1000);
printf(LCD_PUTC, "\fProbando Sensor\nUltrasonico"); 
delay_ms(1000);                              
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); 

while(true)
{ 
   output_high(trig);                     
   delay_us(20);                         
   output_low(trig); 
   while(!input(ECHO)){} 
   
   set_timer1(0);                           
   while(input(ECHO)){} 
   
   tiempo=get_timer1();                       
   distancia=tiempo*0.028 + 1.093 ;                                   
   printf(LCD_PUTC, "\fTiempo :%Lu \nDistancia = %Lu",tiempo,distancia); 
   delay_ms(100); 

   if (distancia>5)
   {

   output_high(PIN_C1);
      
   }
   else
   {
   output_low(PIN_C1);
   }

   } 
}
```
Este programa ahora te debe compilar sin errores.
Para las conexiones de la pantalla, sigue el esquema adjunto y utiliza los pines que quieras para el sensor.

Suerte.


----------



## yesvari85 (Oct 19, 2015)

Está súper bueno este proyecto, D@rkbytes.
Me gustaría implementarlo para un trabajo en la universidad y explicarles las aplicaciones del ultrasonido.
Te pregunto. ¿Si deseo usar el PIC16F887, qué cambios debo hacer?

Muchas gracias, amigo.

Saludos.



*Como no cumplo las Políticas del Foro, me editaron el mensaje.*​


----------



## D@rkbytes (Oct 20, 2015)

Puedes usar casi cualquier tipo de PIC.
Los únicos cambios los expliqué anteriormente, así que no debes tener problemas.


----------



## julian403 (May 24, 2016)

Buenas, estoy realizando una simple detección de movimiento con el módulo HCRS04 y el pic16f84. El problema es que no detecta la diferencia de la señal del eco inicial y las variaciones de las distancias. El código es el siguiente: 

Los disparos para el HCRS04 (trigger) son en el pin RA0, y el eco retorna por el pin RB4 

Como verán la función que se encarga de detectar la distancia es int cuenta(), la cual retorna la distancia. Ahora bien, cuando se envía el pulso (trigger) comienza la cuenta de la distancia hasta que el eco produce la interrupción por cambio descendente en el pueto RB4, el cambio descendente es cuando termina el pulso


```
#include <xc.h>

// CONFIG
#pragma config FOSC = XT        // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF       // Watchdog Timer (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (Power-up Timer is disabled)
#pragma config CP = OFF         // Code Protection bit (Code protection disabled

#define _XTAL_FREQ 3582056
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/3582056)))  
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/3582.056)))  

#define SALIDA PORTBbits.RB2

int variable=0;

#INT_RB
void interrupt isr(void) 
{ 
   INTCONbits.GIE=0;
if(INTCONbits.RBIE) 
{	
    variable=variable+1;
    
}
 INTCONbits.GIE=1;
 INTCONbits.RBIE=0;
 return;
}

int cuenta (void)
{ 
    int i=0; 
    int c=1;
     __delay_us(15); 
     PORTA=0xFF; 
     __delay_us(15); 
     PORTA=0x00; 
    
      while(c)
        {
              i++;      
             __delay_us(500);
             if(variable>0) 
             { 
                c=0;   
             }   
        } 
    
     return (i);
}

void main(void) {
    

        TRISB=0b111110001; 
        TRISA=0x00; 
        INTCON=0x98;
        OPTION_REG=0x98;
        int d1=0;
        int l1=0;
         
        d1=cuenta();
        l1=d1;
         variable=0;
             while(1)
             {
              l1=cuenta();   
               variable=0;
             if(l1!=d1) 
             {
                 SALIDA=1; 
        __delay_ms(1000); 
              d1=cuenta();  
              variable=0;
             }
             
             }
}
```


----------



## D@rkbytes (May 25, 2016)

Tienes muy mal el código de ese programa.

Vamos a empezar por las dos redefiniciones; __delay_us(x) y __delay_ms(x)
El compilador muestra las siguientes advertencias:
warning: (111) redefining preprocessor macro "__delay_us" (C:\Program Files\Microchip\xc8\v1.37\include\pic.h)
warning: (111) redefining preprocessor macro "__delay_ms" (C:\Program Files\Microchip\xc8\v1.37\include\pic.h)

Como ya están declaradas en el archivo "pic.h", ya no es necesario que las incluyas.

Después estás mezclando directivas de PIC C Compiler en XC8:
*#INT_RB *No es reconocido por el compilador XC8
Y la información de compilación lo indica con otra advertencia:
warning: (107) illegal # directive "INT_RB"

Y en la configuración del registro TRISB, te sobra un bit: (Podría ser el de la izquierda o el de la derecha)
TRISB=0b111110001;
El registro TRISB al igual que el registro TRISA, son de 8 bits.
(Aunque en el 16F84A, el puerto A únicamente tenga 5 bits activos. <RA4:RA0>)
warning: (751) arithmetic overflow in constant expression

Ahora vamos al problema principal.
Dices que el eco lo recibes por cambio de estado en RB4, pero la configuración de registros en la rutina de servicio de interrupción, no es correcta.
El bit RBIE del registro INTCON, habilita o deshabilita la interrupción por cambio de estado en el los bits <RB7:RB4>
Pero tú lo estás usando para determinar si se incrementa la variable "variable" (Redundante, pero así la nombraste) 
En C, es más simple escribir; variable ++; que variable = variable + 1; 

Posteriormente desactivas la interrupción por cambio de estado, pero activando las interrupciones globales.
Entonces, al ya no tener un control sobre las interrupciones, se producirá un desborde o "Stack Overflow"
Y ya con eso tienes para que todos los procesos mueran. 

Corrige esos detalles y principalmente la rutina del servicio de interrupción.
Tal vez después de eso, el código restante funcione.


----------



## julian403 (May 25, 2016)

Uf tremendo gracias pero hay ciertas cosas que no entiendo todabía. No sé si podrías hacerme el favor de responderlas.



> Después estás mezclando directivas de PIC C Compiler en XC8:
> #INT_RB No es reconocido por el compilador XC8
> Y la información de compilación lo indica con otra advertencia:
> warning: (107) illegal # directive "INT_RB"



Si yo no poní la directiva #INT_RB luego de la variable global "variable" y antes de la función de interrupción no me tomaba la variable como global, es decir, el cambio que se producía en la función interrupción no era posible visualizarla en el main o en la función cuenta(). Como puedo hacer eso? es decir modificar el valor de la variable y mantener esa modificación externamente, ya que al parecer MPLAB no permite trabaajar con punteros y tampoco no sé como pasarselo a esa función. 



> Ahora vamos al problema principal.
> Dices que el eco lo recibes por cambio de estado en RB4, pero la configuración de registros en la rutina de servicio de interrupción, no es correcta.
> El bit RBIE del registro INTCON, habilita o deshabilita la interrupción por cambio de estado en el los bits <RB7:RB4>
> Pero tú lo estás usando para determinar si se incrementa la variable "variable" (Redundante, pero así la nombraste)
> En C, es más simple escribir; variable ++; que variable = variable + 1;


Claro es RBIF, lo que pasa es que he cambiado tanto el código que ya no pensaba y decidí pedir ayuda.

Ahora el código quedó de la siguiente manera: 

```
#include <xc.h>

// CONFIG
#pragma config FOSC = XT        // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF       // Watchdog Timer (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (Power-up Timer is disabled)
#pragma config CP = OFF         // Code Protection bit (Code protection disabled

#define _XTAL_FREQ 3582056


#define SALIDA PORTBbits.RB2

volatile int variable=0;


void interrupt isr(void) 
{ 
   INTCONbits.GIE=0;
if(INTCONbits.RBIF) 
{	
    variable++;
    
}
 INTCONbits.GIE=1;
 INTCONbits.RBIF=0;
 return;
}

int cuenta (void)
{ 
    int i=0; 
    int c=1;
     __delay_us(15); 
     PORTA=0xFF; 
     __delay_us(15); 
     PORTA=0x00; 
    
      while(c)
        {
              i++;      
             __delay_us(50);
             if(variable>0) 
             { 
                c=0;   
             }   
        } 
     variable=0;
     return (i);
}

void main(void) {
    

        TRISB=0b11110000; 
        TRISA=0x00; 
        INTCON=0x98;
        OPTION_REG=0x98;
        int d1=0;
        int l1=0;
         
        d1=cuenta();
           l1=d1;
             while(1)
             {
              l1=cuenta();   
              
             if(l1!=d1) 
             {
                 SALIDA=1; 
        __delay_ms(1000); 
      
             }
               variable=0;
             }
}
```

Pero sigo teniendo el mismo problema, es raro ya que cuando entra al while(1) asigna las distancias a l1 y a d1 con los valores obtenidos de la espera del eco pero hay veces que se prende el led y queda prendido, de manera que detecta distancias diferentes pero nada se interpone.


----------



## Gerson strauss (May 25, 2016)

julian403 dijo:


> Uf tremendo gracias pero hay ciertas cosas que no entiendo todabía. No sé si podrías hacerme el favor de responderlas.
> 
> 
> 
> ...



Pues si quieres mira este código que esta bien explicado; esta en Proton pero el objetivo es el mismo. CODIGO HC-SR04.

Por cierto, se dice: yo puse, no, yo poní.


----------



## julian403 (May 25, 2016)

He leido la explicación pero eso mismo he implementado, al parecer mi error es de código y la verdad que el mplab es bastante caprichoso. 

Si observan mi código, luego de las configuraciones el algoritmo es este. Se llama a la función cuenta que envía un pulso al trigger y cuenta hasta que llega el flanco descendente del eco (a mi no me interesa medir distancia sino detección o cambio de distancia), una vez obtenido el valor de la cuenta, almacenado en la variable d1, entra al while donde se observa nuevamente la distancia y se almacena en l1 y se compara con d1 (que es la distancia anterior), si es diferente prende led sino nada y dicho hecho se vuelve a repetir indefinidamente.

El problema es que el led siempre está prendido y tendría que prender solamente cuando algo se interponga entre el sensor.


----------



## Gerson strauss (May 25, 2016)

julian403 dijo:


> He leido la explicación pero eso mismo he implementado, al parecer mi error es de código y la verdad que el mplab es bastante caprichoso.
> 
> Si observan mi código, luego de las configuraciones el algoritmo es este. Se llama a la función cuenta que envía un pulso al trigger y cuenta hasta que llega el flanco descendente del eco (a mi no me interesa medir distancia sino detección o cambio de distancia), una vez obtenido el valor de la cuenta, almacenado en la variable d1, entra al while donde se observa nuevamente la distancia y se almacena en l1 y se compara con d1 (que es la distancia anterior), si es diferente prende led sino nada y dicho hecho se vuelve a repetir indefinidamente.
> 
> El problema es que el led siempre está prendido y tendría que prender solamente cuando algo se interponga entre el sensor.



El lenguaje C no me gusta; con Proton el programa que quieres, lo haces en 3 minutos.


----------



## julian403 (May 25, 2016)

Pues creo que el problema puede estar en variable. Fijensen que cuando ocurre la primera vez la interrupción, para setear d1, variable es modificada aumentando en una unidad. Y cuando sucede eso, sale del while dentro de la función cuenta, quedando seteada la cuenta en la variable c. Luego pongo a cero la  variable "variable" pero no sé si se mantiene globalmente ese cero luego de que sale de cuenta() o no. 


```
#include <xc.h>
#include <stdint.h>

// CONFIG
#pragma config FOSC = XT        // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF       // Watchdog Timer (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (Power-up Timer is disabled)
#pragma config CP = OFF         // Code Protection bit (Code protection disabled

#define _XTAL_FREQ 3582056


#define SALIDA PORTBbits.RB2

volatile char variable=0;


void interrupt isr(void) 
{ 
    if(PORTBbits.RB4==0) 
    {
    variable++;
    } 
    INTCONbits.RBIF = 0;    //clear interrupt request flag
}


char cuenta (void)
{ 
   
    char c=0;
     __delay_us(15); 
     PORTA=0xFF; 
     __delay_us(15); 
     PORTA=0x00; 
    
     while(!(variable))
     {
         c++;
         __delay_us(100);
     }
     variable=0;
     return c;
}

void main(void) {
    

        TRISB=0b11110000; 
        TRISA=0x00; 
        INTCON=0x98;
        OPTION_REG=0x98;
        char d1=0;
        char l1=0;
         
        d1=cuenta();
        l1=d1;
        while(1)
        {
            l1=cuenta();   
              
            if(l1!=d1) 
            {
                SALIDA=1; 
                __delay_ms(1000); 
      
             }
            d1=cuenta();
           
        }
}
```

No sé si me doy a entender lo que quiero decir. En sí, tampoco entiendo la parte de que en la interrupción tengo que leer el puerto.


----------



## D@rkbytes (May 25, 2016)

Te iba a mencionar sobre el servicio de interrupción, pero veo que ya lo modificaste.
Ahora prueba de ésta forma:

```
void interrupt isr (void) 
{ 
    if(INTCONbits.RBIF) 
    {    
        if(!PORTBbits.RB4)
        {
            variable++;
        }
        INTCONbits.RBIF = 0;
        PORTB = (PORTB & 0xF0);
    }
}
```
En la subrutina "cuenta" debes poner un "break;" cuando quieras salir.
Por ejemplo, en esta parte:

```
if(variable > 0) 
             { 
                c = 0;
                break;
             }
```
De otra forma el ciclo seguirá y no retornará de ahí.

Recomendaciones:
Activa las resistencias pull-up del puerto B en el registro OPTION_REG.
Puedes hacer uso de Proteus para entrar en modo de depuración y ver la ejecución del programa paso a paso.
Cuando entras al modo de depuración, podrás ver el valor de las variables y el estado de los registros.


----------



## julian403 (May 25, 2016)

Excelente al parecer ha mejorado el funcionamiento, debo seguir puliéndolo . Es decir ahora puse que muestre por el puerto RB1 cuando no halla cambio y por el RB2 cuando hay un cambio y de vez en cuando me tira que hay un cambio cuando no lo hay. Por cierto veo que con 

  PORTB = (PORTB & 0xF0);
guardas los valores de la parte alta del puerto B ¿por qué? 



> En la subrutina "cuenta" debes poner un "brake;" cuando quieras salir.
> Por ejemplo, en esta parte:



ahi no entiendo lo que decis ya que la subrutina cuenta tiene la siguiente forma: 


```
int cuenta (void)
{ 
   
    int c=0;
     __delay_us(15); 
     PORTA=0xFF; 
     __delay_us(15); 
     PORTA=0x00; 
    
     while(!(variable))
     {
         c++;
         __delay_ms(1);
     }
     variable=0;
     return c;
}
```

¿donde dice que debo poner el break? yo pensaba que el break era solo para salir por un imprevisto o condición pero en este caso se sale del while cuando la variable pasa a tener el valor 1.

¿Es muy importante que ponga los capacitores de 27pF entre el cristal?


----------



## D@rkbytes (May 25, 2016)

julian403 dijo:


> Por cierto, veo que con
> 
> PORTB = (PORTB & 0xF0);
> guardas los valores de la parte alta del puerto B ¿por qué?


Es para restablecer un valor al puerto B, bits <RB7:RB4> para un nuevo cambio de estado en esos bits.
Suele pasar que si no se hace eso, no se logra salir del servicio de interrupción.




julian403 dijo:


> No entiendo lo que decís, ya que la subrutina cuenta tiene la siguiente forma:
> 
> 
> ```
> ...


El break sirve precisamente para romper una condición, pero lo mencioné al ver el código anterior.
Este nuevo código no lo he analizado y eso era para el código anterior.


julian403 dijo:


> ¿Es muy importante que ponga los capacitores de 27pF entre el cristal?


Si, pero depende del tipo de cristal, ya que existen unos que los tienen internos y ya no hacen falta.
Pero sirven para mantener una oscilación estable y también para ajustar la frecuencia.
Colocalos de todas formas. (Con un frecuencímetro puedes encontrar el valor correcto)


----------



## julian403 (May 25, 2016)

> Es para restablecer un valor al puerto B, bits <RB7:RB4> para un nuevo cambio de estado en esos bits.
> Suele pasar que si no se hace eso, no se logra salir del servicio de interrupción



Claro eso es lo que no entiendo, según lo que he visto de la hoja de datos hay que leer el puerto para que se produzca la interrupción. Eso me han dicho en el foro de microchip y en el datasheet dice esto: 

The inputs pins (of RB7:RB4) are compared with the old value latched on the last read of PORTB. 

El traductor me dice: 
Los pines de entradas ( de RB7 : RB4 ) se comparan con el valor antiguo enclavado en la última lectura del PORTB. 

Lo que pasa es que el RB4 hay un pulso y la interrupción según el OPTION_REG se producen en el flanco descendente, así que la última lectura sería un valor positivo. O sería el último valor del flanco descendente?


----------



## D@rkbytes (May 26, 2016)

julian403 dijo:


> Claro eso es lo que no entiendo, según lo que he visto de la hoja de datos hay que leer el puerto para que se produzca la interrupción. Eso me han dicho en el foro de microchip y en el datasheet dice esto:
> 
> The inputs pins (of RB7:RB4) are compared with the old value latched on the last read of PORTB.
> 
> ...


Así es, pero por ser una interrupción por cambio de estado, se puede producir en cualquier condición.
O sea que el flanco de interrupción no se establece en ningún registro.
Es decir, no es como la interrupción por RB0 en donde si se puede elegir si se dará por flanco ascendente o por flanco descendente.
En este caso la interrupción se ejecutará cuando cualquier pin <RB7:RB4> cambie de estado.
Y se puede ejecutar cuando se lee el puerto B.
Por eso no es recomendable usar lecturas del puerto cuando se usa esta interrupción.
Por lo tanto, la configuración del registro OPTION_REG para establecer un flanco de interrupción, no tiene ningún efecto en esta interrupción.



julian403 dijo:


> Lo que pasa es que el RB4 hay un pulso y la interrupción según el OPTION_REG se producen en el flanco descendente, así que la última lectura sería un valor positivo.
> ¿O sería el último valor del flanco descendente?


Por lo explicado anteriormente, durante el servicio de interrupción se debe leer el puerto B y así determinar cuál fue el pin que cambió de estado, y esto se determina por la lógica de estados basados en resistencias pull-up o pull-down en <RB7:RB4> y conforme al estado lógico ingresado a cada pin.

Una comparación sobre el estado esperado es suficiente para tomar decisiones y posteriormente salir de la rutina, ya que desde que se inicia el programa se dará la interrupción por cambio de estado.

Sobre lo expuesto, agrego lo siguiente:
El bit INTEDG del registro OPTION_REG, es únicamente para establecer el flanco de interrupción del bit 0 del puerto B (RB0)
Por lo cual, su configuración no tiene efecto sobre los pines <RB7:RB4>


----------



## julian403 (May 27, 2016)

Lo que me parece raro es como se observa en la siguiente imágen, en la posición de memoria de programa 0x04 (donde va al interrupción) NO HAY UN SALTO (goto a alguna parte) y eso está mal según lo que entiendo porque el pic16f84 solo recerva solo una posición ahi, así que si se usa la interrupción hay que hacer un salto a otra parte para implementar la rutina de la interrupción. 

Con razón no me funciona, eso debe ser pero es el compilador el que genera eso. ¿Qué puedo hacer?


----------



## D@rkbytes (May 27, 2016)

Es más fácil que uses el Timer 1 para contar el tiempo que tarda el eco y posteriormente lo conviertas a distancia.


----------



## julian403 (May 27, 2016)

¿Y cómo lo podría implementar en C? Pienso en lo siguiente, como ya debes saber la distancia es proporcional al ancho del pulso por lo tanto:

```
void interrupt isr(void) 
{ 
    
  if(INTCONbits.RBIF) 
  {
      if(PORTBbits.RB4) 
      {
          //acá iría una función que maneja el timer pero desconozco que lo inicialice
      }
       if (!PORTBbits.RB4) 
        {
          //acá daría fin al timer y lo guardaría en la variable variable
         }
  }
    INTCONbits.RBIF = 0;   
     PORTB = (PORTB & 0xF0);//clear interrupt request flag
}
```


----------



## D@rkbytes (May 27, 2016)

Buscando un poquito, encontré algo sobre lo que te mencioné:
*Interfacing HC-SR04 Ultrasonic Sensor with PIC Microcontroller*

Ahí encontrarás un programa para XC8.


----------



## julian403 (May 28, 2016)

Ok buenisimo, pero en el pic16f84 ¿cómo enciendo el timer? ¿poniendo a 1 TOIE? y lo apago poniendo a cero TOIE. Quedando guardada la cuenta en TMR0

Porque veo que en el pic16f877 en el programa lo enciende con: TMR1ON = 1;


----------



## D@rkbytes (May 28, 2016)

Ahí hay un detalle. El 16F84 no tiene Timer 1, sólo Timer 0, y eso si es un problema porque no se obtendrá la misma respuesta usando el Timer 0, porque el Timer 1 es de 16 bits y el Timer 0 es de 8 bits.


----------



## julian403 (May 28, 2016)

Si me parecía, no tengo el 16f877 pero tengo el 18f2550 pero el problema que tengo ahí es la configuración de los fusibles. Si me pasas la configuración de los fusible para dicho pic, no molestaré más. Enserio, la configuración para usarlo como un pic de la linea 16f, con cristal externo y sin preescaler, sin usb. bien básico.


----------



## D@rkbytes (May 28, 2016)

Esta sería la palabra de configuración para el PIC18F2550:

```
#pragma config CONFIG1L CPUDIV = OSC1_PLL2, PLLDIV = 1, USBDIV = 1
#pragma config CONFIG1H FCMEN = OFF, IESO = OFF, FOSC = XT_XT
#pragma config CONFIG2L PWRT = ON, VREGEN = OFF, BORV = 3, BOR = ON 
#pragma config CONFIG2H WDTPS = 32768, WDT = OFF
#pragma config CONFIG3H CCP2MX = ON, PBADEN = OFF, MCLRE = ON, LPT1OSC = ON
#pragma config CONFIG4L STVREN = ON, DEBUG = OFF, LVP = OFF, XINST = OFF
#pragma config CONFIG5L CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF
#pragma config CONFIG5H CPB = OFF, CPD = OFF
#pragma config CONFIG6L WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF
#pragma config CONFIG6H WRTB = OFF, WRTC = OFF, WRTD = OFF
#pragma config CONFIG7L EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF
#pragma config CONFIG7H EBTRB = OFF

#define _XTAL_FREQ 3582056
```
Coloqué todos los fuses por si necesitas cambiar alguno, pero la palabra de configuración se puede acortar permitiendo que el compilador use los que tiene por defecto.
Así como está, es la configuración que requieres. (XT: Cristal menor a 4 MHz.)

Los fuses y la descripción de cada uno, la puedes encontrar en el archivo "18f2550.html"
Esa documentación se encuentra en la carpeta "C:/Program Files/Microchip/xc8/v1.37/docs/chips/"
En mi caso en la "v.137" pero eso depende de la versión XC8 que tengas.


----------



## Ardogan (May 30, 2016)

D@rkbytes dijo:


> ...



D@rkbytes, te merecés un monumento a la paciencia .

@julian403: tratá de no empezar desde 0 con muchas cosas a la vez. Parecía que tu duda era específicamente con el HC-SR04 pero después tenías problemas con el compilador y sus directivas, después con las interrupciones y finalmente con el timer 0.
Empezá de a poco, resolvé de a 1 cosa a la vez, no todo al mismo tiempo.

Primero: estás pasando del compilador CCS al compilador XC8 (aparentemente) -->fijate las diferencias entre uno y otro, como se configura micro (pragma), como se declara una rutina de interrupción etc.
Si ya tuviste experiencia con el CCS probá "traducir" un programa que sabés que funciona al XC8.

Luego, manejo del HC-SR04: requiere manejar 1 salida, 1 entrada y medir tiempo.


Tu primer programa podría ser prender y apagar un led (aprendemos a manejar 1 salida). 
No puedo dejar de enfatizar lo importante que es este primer paso, ¿por que?, porque con esto ya estás comprobando que tenés tu proyecto bien configurado, que el compilador genera bien el programa y/o el .hex, que el reloj está bien configurado, que el micro está bien alimentado, que el programador/depurador funciona, que configuraste bien el pin usando los registros correctos, que no falto conectar ningún pin imprescindible del pic, etc.
El segundo programa que el led se encienda y apague cada x milisegundos.
El 3ro que el led se prenda y se apague al apretar un botón (un tact switch por ejemplo), acá incorporas el manejo de 1 entrada).
Luego (si querés, podría no hacer falta) el manejo de una interrupción--> mismo ejemplo del botón pero que el apagado y encendido se haga a través de la rutina de interrupción del pic.
No quiero alargar demasiado, pero la idea es: avanzar de a poco, un pasito atrás del otro, ir de menor a mayor. Cada cosita nueva que hacés ya sabés que lo que hiciste anteriormente funciona (ya lo probaste, esta testeado!!!).
Si hay un problema tenés que buscarlo en lo último que hiciste, nada más, no hace falta revisar el proyecto completo. 
Si ponés 3 o 4 cosas juntas y enchufaste algo nuevo, no sabés si el error es en hardware (algo mal conectado), en software, en configuración, si lo que funciona mal es la rutina de interrupción o el programa del while(1), etc.

Es algo que siempre pasa en el foro, pero bueno, me puse en viejo renegón. No pasa nada, yo al principio también quería tener un programa completo funcionando (hey!!!, la simulación anda, por qué no va a andar en la placa física?  ) y después al querer programarlo no funcionaba nada.

Buena suerte!!!!.

--------------------------------------
Addendum:
Ojo!!!, eso no significa que siempre hay que diseñar bottom-up y nunca top-down (filosofía de diseño). Hay un lugar para trabajar de arriba para abajo, y de abajo hacia arriba. Pero si se tiene el hardware a mano es mejor aprender a manejar el hardware y conocer mejor las capacidades básicas (eso es bottom-up) y después pasar al esquema top-down, ver que necesitamos realmente e implementarlo.
Si uno hace bottom-up solamente vas a terminar con un montón de funciones que no vas a usar nunca, sobre-diseñando y haciendo el código mucho más complicado; cuando lo que se busca es tener algo lo más sencillo posible que cumpla con nuestras necesidades.


----------



## HectorMuse17 (Sep 27, 2016)

Realicé el programa con el compilador MikroC, con el pic 16f887 y utilicé el timer 1.
Lo compilé y no hubo errores, pero al momento de probarlo, no realiza la condición, como si no hiciera la detección.

Mi circuito físico está bien conectado en sus respectivos pines, pero necesito saber en qué falla.
Uso el módulo ultrasónico HC-SR04 y no descubro el problema. 

Menciono que RA1_bit es el pin echo y RB1_bit es el trigger

```
// prueba del sensor ultrasónico con PIC 16F887

unsigned int ConteoH;
unsigned char ConteoL;
unsigned int ConteoF;
int Distancia;


void main() {

Ansel=0;
Anselh=0;
TrisA=1;
TrisB=0;
Portb=0;
Porta=0;


T1CON.T1OSCEN=0; // Deshabilitar oscilador externo
T1CON.TMR1CS=0;

while (1){

TMR1H=0X8E; // VALOR INICIAL 0X8EB7=36535 CONTEO
TMR1L=0XB7;

Delay_us(5);
RB1_bit=1;     //Pulso inicial al sensor
Delay_us(10);
RB1_bit=0;

while(!RA1_bit); // Mientras no haya respuesta del sensor no se hará nada

RB3_bit=0;
T1CON.TMR1ON=1; // Encender Timer

while(RA1_bit && !T1CON.TMR0IF); // Espera de regreso de finalizado del pulso del sensor
// TMR1IF es el conteo máximo o desborde, indicando que no se detectó un objeto
// Mientras RA1 siga alto y el timer no desborde no se hará nada

T1CON.TMR1ON=0; // Desactivar Timer
T1CON.TMR0IF=0; // Eliminar desborde(conteo máximo)

ConteoH= TMR1H; // Leer máximo conteo de TMR1H
ConteoL= TMR1L; // Leer máximo conteo de TMR1L

ConteoH= ConteoH <<8; // Dezplazar posiciones para poder juntar con el otro registro
ConteoF= ConteoH + ConteoL; // ConteoF= Conteo final
// Sumar los 2 registros

Distancia= ((ConteoF-0x8eb7)/29)/2; // Operación para obtener la distancia en cm según la detección del sensor

// Condiciones

if(Distancia<=20){
RB2_bit=1; //encender LED
Delay_ms(2000);
RB2_bit=0;
}
}
}
```
Por favor, ¿Alguien podría resolver mi duda?


----------



## D@rkbytes (Sep 27, 2016)

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?


----------



## HectorMuse17 (Sep 27, 2016)

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


----------



## D@rkbytes (Sep 27, 2016)

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.


----------



## HectorMuse17 (Sep 27, 2016)

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


----------



## D@rkbytes (Sep 28, 2016)

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.


----------



## HectorMuse17 (Sep 28, 2016)

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


----------



## D@rkbytes (Sep 28, 2016)

HectorMuse17 dijo:


> 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



HectorMuse17 dijo:


> 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.


HectorMuse17 dijo:


> 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:

```
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?


----------



## dosekk (Oct 6, 2016)

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


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


----------



## D@rkbytes (Oct 6, 2016)

¿Por qué no tomas como referencia el código del post _#34_?
Ahí hay un enlace con un programa escrito en MikroC.


dosekk dijo:


> 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.


----------



## dosekk (Oct 7, 2016)

D@rkbytes dijo:


> ¿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 

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


```
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


----------



## dosekk (Oct 9, 2016)

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 


```
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??


----------



## D@rkbytes (Oct 9, 2016)

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.


----------



## dosekk (Oct 9, 2016)

mira aca esta el codigo


```
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


----------



## D@rkbytes (Oct 10, 2016)

dosekk dijo:


> 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.


dosekk dijo:


> ¿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>


----------



## miglo (Abr 15, 2020)

Hola buena gente, tengo un problemilla y no se donde esta mi error al hacer el codigo.


```
#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.


----------



## argi (Abr 15, 2020)

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]


----------



## 1024 (Abr 15, 2020)

miglo dijo:


> 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.


----------



## miglo (Abr 15, 2020)

Hola, igual no me explicado bien, lo que quiero es sacar la media de las 5 lecturas.


----------



## D@rkbytes (Abr 15, 2020)

miglo dijo:


> lo que quiero es sacar la media de las 5 lecturas.


Para eso debes realizar un promedio de las lecturas.


----------



## miglo (Abr 15, 2020)

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.


```
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:

```
void medir(void) {
  for(i=0;i<5;i++) {
    total+=Longitud();
    delay_ms(1500);
    }
 distancia=total/5.0; 
 }
```


----------

