Leer Echo de Sensor HC-SR04 con PIC16F84A mediante ASM

Agradecido por la ayuda, navegando encontré este proyecto que muestra en un pantalla LED 16x2 lo adquirido por un sensor HC-SR04 ultrasónico:

http://ccspicc.blogspot.com.ar/2016/11/pic16f84a-hc-sr04-ultrasonic-sensor.html

El proyecto es excelente, y funciona muy bien, sin embargo está escrito en CCS C, y mi proyecto es convertirlo en ASM.

Código:
//LCD module connections
#define LCD_RS_PIN PIN_B0
#define LCD_RW_PIN PIN_B1
#define LCD_ENABLE_PIN PIN_B2
#define LCD_DATA4 PIN_B3
#define LCD_DATA5 PIN_B4
#define LCD_DATA6 PIN_B5
#define LCD_DATA7 PIN_B6
//End LCD module connections

#include <16F84A.h>
#fuses HS,NOWDT,PUT,NOPROTECT
#use delay(clock = 8000000)
#include <lcd.c>
#use fast_io(A)

unsigned int8 count;
unsigned int16 i, distance;
#INT_TIMER0
void timer0_isr(){
  count++;
  clear_interrupt(INT_TIMER0);
}
int1 wait_sensor(){
  i = 0;
  set_timer0(0);
  count = 0;                             // Reset Timer0
  while(!input(PIN_A1) && (i < 1000))
    i = count * 256 + get_timer0();
  if(i > 990)
    return 0;
  else
    return 1;
}
unsigned int16 get_distance(){
  i = 0;
  set_timer0(0);
  count = 0;
  while(input(PIN_A1) && (i < 25000))
    i = count * 256 + get_timer0();
  return i;
}
void main(){
  output_a(0);
  set_tris_a(2);                                      // Configure RA1 as input
  lcd_init();                                         // Initialize LCD module
  lcd_putc('\f');                                     // LCD clear
  clear_interrupt(INT_TIMER0);
  enable_interrupts(GLOBAL);
  enable_interrupts(INT_TIMER0);
  setup_timer_0 (T0_INTERNAL | T0_DIV_2);             // Configure Timer0 module
  lcd_gotoxy(4, 1);                                   // Go to column 4 row 1
  lcd_putc("Distance:");
  while(TRUE){
    // Send 10us pulse to HC-SR04 Trigger pin
    output_high(PIN_A0);
    delay_us(10);
    output_low(PIN_A0);
    // Read pulse comes from HC-SR04 Echo pin
    if(wait_sensor()) {
      distance = get_distance();
      if(distance > 24990) {
        lcd_gotoxy(3, 2);                             // Go to column 3 row 2
        lcd_putc("Out Of Range");
      }
      else {
        distance = i/58;                              // Calculate the distance
        lcd_gotoxy(3, 2);                             // Go to column 3 row 2
        lcd_putc("       cm   ");
        lcd_gotoxy(6, 2);                             // Go to column 6 row 2
        printf(lcd_putc,"%3Lu",distance);
      }
    }
    else {
      lcd_gotoxy(3, 2);                               // Go to column 3 row 2
      lcd_putc("  Time Out  ");
    }
  delay_ms(100);
  }
}

Usando las librerías del libro de palacios y haciendo un pequeño cambio en la librería LCD_4BIT.INC para los pines del LED, he obtenido lo siguiente:

Código:
	LIST 	P=16F84A
	INCLUDE <P16F84A.INC>

	#DEFINE Sensor_Trigger PORTA,0
	#DEFINE Sensor_Echo PORTA,1


	CBLOCK	0x0C
	ENDC
	ORG 	0


Bucle
	BSF		Sensor_Trigger			; Envio un pulso de 10us 
	CALL	Retardo_10micros
	BCF		Sensor_Trigger
	
	BSF		Sensor_Echo				; Recibo por el PORTA,1
	
	CALL	LCD_Inicializa			; Inicializa LCD
	MOVLW	PORTA					; Muevo el valor recibido del Puerto A a W
	CALL	LCD_ByteCompleto		; Muestro el valor

	CALL	Retardo_100ms
	GOTO	Bucle


	INCLUDE <LCD_4BIT.INC>
	INCLUDE <RETARDOS.INC>


	END

Me quedé estancado en la parte donde se lee el Echo del Sensor, que se recibe en RA1, y si pueden sugerirme algo más, ya que mi programación es básica. Sin embargo pude hacer funcionar la simulación en Proteus y armar el circuito físico.

Dejo el diagrama, Agradecido de antemano
 

Adjuntos

  • hc-sr04-ultrasonic-sensor-distance-pic16f84a-circuit.jpg
    hc-sr04-ultrasonic-sensor-distance-pic16f84a-circuit.jpg
    65.8 KB · Visitas: 66
Última edición por un moderador:
Hola salvacoloco francamente es mucho las sencillo hacer el programa en C pero para recordar viejos tiempos aquí un ejemplo.
Código:
   #include <P16F84a.inc>
   list p=16F84a
;***********************************************************
#define	lcd_en	PORTA,3         ;pin de enable  
#define lcd_rs  PORTA,2         ;pin de selección de comando o caracter
#define lcd_bus	PORTB
#define	nible_bajo		;nible bajo - nible_alto

#define disparo	PORTA,0		
#define eco	PORTB,7
;***********************************************************
cblock 0x20
   nibble_lcd
   temp_lcd
   
   PDel0
   PDel1
   PDel2
   
   ptr_const
   char_temp
   
   digito0
   digito1
   digito2
   
   contador
   cont_timer
   bandera_error
   bandera_eco_listo
   
   W_TEMP
   STATUS_TEMP
endc
;***********************************************************
   org 0x00
   goto	inicio
;***********************************************************
   org 0xf0
mensaje1
   addwf	PCL,f
   dt "Distancia[cm]:",0
;***********************************************************
   org 0x04
PUSH
   MOVWF W_TEMP ; Copy W to TEMP register,
   SWAPF STATUS, W ; Swap status to be saved into W
   MOVWF STATUS_TEMP ; Save status to STATUS_TEMP register

   btfsc	INTCON,T0IF
   goto		interrupcion_timer0
   btfsc	INTCON,RBIF
interrupcion_portb
      movf	PORTB,f
      bcf	INTCON,RBIF
      btfss	eco
      goto 	detener_timer
      movlw	.154		;carga al timer 0 para 
      movwf	TMR0		;una interrupción de 58us
      bsf	STATUS,RP0
      bcf	OPTION_REG,T0CS	;inicia al timer0
      bcf	STATUS,RP0
      clrf	digito0
      clrf	digito1
      clrf	digito2
      clrf	bandera_error
      goto	POP
detener_timer
      bsf	STATUS,RP0
      bsf	OPTION_REG,T0CS	;detiene al timer0
      bcf	STATUS,RP0
      incf	bandera_eco_listo
      goto	POP
interrupcion_timer0
   bcf		INTCON,T0IF
   movlw	.154		;carga al timer 0 para 
   movwf	TMR0		;una inetrrupcion de 58us
   incf		digito0
   movfw	digito0
   xorlw	.10
   btfss	STATUS,Z
   goto		POP
   clrf		digito0
   incf		digito1
   movfw	digito1
   xorlw	.10
   btfss	STATUS,Z
   goto		POP
   clrf		digito1
   incf		digito2
   movfw	digito2
   xorlw	.3
   btfsc	STATUS,Z
   incf		bandera_error
POP
   SWAPF STATUS_TEMP,W
   MOVWF STATUS
   SWAPF W_TEMP, F
   SWAPF W_TEMP, W 
   retfie
;***********************************************************
inicio
   clrf		PORTB
   ;movf		PORTB,F
   ;bcf	INTCON,RBIF		
   clrf		PORTA
   clrf		digito0
   clrf		digito1
   clrf		digito2
   clrf		bandera_error
   
   bsf		STATUS,RP0
   bcf		disparo
   movlw	b'01111111'
   movwf	OPTION_REG
   bcf		STATUS,RP0
   movf		PORTB,F
   bcf		INTCON,RBIF
   bsf		STATUS,RP0
   bsf		INTCON,GIE	;habilita las interrupciones
   bsf		INTCON,T0IE	;interrupcion del timer 0 activada
   bsf		INTCON,RBIE	;interrupcion de cambio de estado del puerto B habilitado
   bcf		STATUS,RP0

   call	   	lcd_init	;inicializa el LCD
   
   clrf		ptr_const	;****************************
   movfw	ptr_const	;muestra el mensaje 1
   call		mensaje1	;en el LCD
   movwf	char_temp	;
   xorlw	0		;
   btfsc	STATUS,Z	;
   goto		leer_sensor	;
   movfw	char_temp	;
   call  	lcd_char	;
   incf		ptr_const	;
   goto		$-.9		;****************************
leer_sensor
   clrf		bandera_eco_listo
   movlw	.6		;****************************
   movwf	contador	;disparo del sensor
   bsf		disparo		;
   decfsz	contador	;
   goto		$-.1		;
   bcf		disparo		;****************************
   
   movlw 	b'11000000'	;********************************
   call		lcd_com		;lcd fila2 columna1
   
   movfw	bandera_eco_listo
   xorlw	.1
   btfss	STATUS,Z
   goto		$-3
   
   movfw	bandera_error
   xorlw	.1
   btfsc	STATUS,Z
   goto		mensaje_error
   movlw	0x30
   iorwf	digito0
   iorwf	digito1
   iorwf	digito2
   movfw	digito2
   call		lcd_char
   movfw	digito1
   call		lcd_char
   movfw	digito0
   call		lcd_char
   goto		retardo
mensaje_error
   movlw	'X'
   call		lcd_char
   movlw	'X'
   call		lcd_char
   movlw	'X'
   call		lcd_char
retardo
   call		DEMORA
   goto		leer_sensor
;******************************************************
DEMORA				;500ms 8MHz
	    movlw     .14       ; 1 set numero de repeticion  (C)
	    movwf     PDel0     ; 1 |
PLoop000    movlw     .72       ; 1 set numero de repeticion  (B)
	    movwf     PDel1     ; 1 |
PLoop111    movlw     .247      ; 1 set numero de repeticion  (A)
	    movwf     PDel2     ; 1 |
PLoop222    clrwdt              ; 1 clear watchdog
	    decfsz    PDel2, 1  ; 1 + (1) es el tiempo 0  ? (A)
	    goto      PLoop222    ; 2 no, loop
	    decfsz    PDel1,  1 ; 1 + (1) es el tiempo 0  ? (B)
	    goto      PLoop111    ; 2 no, loop
	    decfsz    PDel0,  1 ; 1 + (1) es el tiempo 0  ? (C)
	    goto      PLoop000    ; 2 no, loop
PDelL111    goto      PDelL222         ; 2 ciclos delay
PDelL222    clrwdt              ; 1 ciclo delay
            return              ; 2+2 Fin.
;**************************************************
;Rutinas para el LCD 4 bits
;**************************************************
lcd_init
   bsf	   STATUS,RP0
   bcf     lcd_rs  
   bcf     lcd_en
   movfw   lcd_bus
   #ifdef  nible_bajo
   andlw   0xf0
   #else
   andlw   0x0f
   #endif
   movwf   lcd_bus
   bcf	   STATUS,RP0
   bcf     lcd_rs  
   bcf     lcd_en
   call    Delay
   movlw   b'00000011'     ;se envia 4 veces configuracion para 8 bits
   call    lcd_com         ;EnvLcd envia solo el nibble bajo.
   movlw   b'00000011'
   call    lcd_com
   movlw   b'00000011'
   call    lcd_com
   movlw   b'00000010'     ;LCD en modo 4 bits
   call    EnvLcd
   movlw   b'00101000'     ;4 bits y dos lineas
   call    lcd_com         ;Lcd_com envia 8 bits en 2 paquetes de 4 bits
   movlw   b'00000110'     ;LCD: Informacion no se desplaza, incremento del cursor
   call    lcd_com
   movlw   b'00001111'     ;Cursor visible e intermitente
   call    lcd_com
   movlw   b'00000001'     ;Borra pantalla y va home
   call    lcd_com
   return
;***********************************************************
lcd_char
   bsf     lcd_rs          ;RS = 1 caracter
lcd_com
   movwf   nibble_lcd
   swapf   nibble_lcd,w                ;intercambia nibbles y guarda en w
   andlw   0x0f
   call    EnvLcd
   movf    nibble_lcd,w
   andlw   0x0f
   call    EnvLcd
   bcf     lcd_rs
   return
;***********************************************************
EnvLcd
   clrwdt
   movwf   temp_lcd
   movfw   lcd_bus
   #ifdef  nible_bajo
   andlw   0xf0
   #else
   swapf   temp,f
   andlw   0x0f
   #endif
   iorwf   temp_lcd,w
   movwf   lcd_bus
   bsf     lcd_en
   call    Del_40us
   bcf     lcd_en
   btfss   lcd_rs
   call    Delay           ;si es comando-> 5 mS
   return
;***********************************************************
Delay			    ;5ms 8MHz
        movlw     .8        ; 1 set numero de repeticion  (B)
        movwf     PDel0     ; 1 |
PLoop1  movlw     .249      ; 1 set numero de repeticion  (A)
        movwf     PDel1     ; 1 |
PLoop2  clrwdt              ; 1 clear watchdog
        clrwdt              ; 1 ciclo delay
        decfsz    PDel1, 1  ; 1 + (1) es el tiempo 0  ? (A)
        goto      PLoop2    ; 2 no, loop
        decfsz    PDel0,  1 ; 1 + (1) es el tiempo 0  ? (B)
        goto      PLoop1    ; 2 no, loop
PDelL1  goto      PDelL2    ; 2 ciclos delay
PDelL2  clrwdt              ; 1 ciclo delay
        return              ; 2+2 Fin.
;***********************************************************
Del_40us		     ;40us 8MHz
         movlw     .18       ; 1 set numero de repeticion 
         movwf     PDel0     ; 1 |
PLoop00  clrwdt              ; 1 clear watchdog
         decfsz    PDel0, 1  ; 1 + (1) es el tiempo 0  ?
         goto      PLoop00   ; 2 no, loop
PDelL11  goto      PDelL22   ; 2 ciclos delay
PDelL22  clrwdt              ; 1 ciclo delay
         return              ; 2+2 Fin.
;***********************************************************
   end
Sin título.jpg
 
Atrás
Arriba