Manejar varios hc-srf04 en mikrobasic ?

Explico, realizo la secuencia de trigger escuchar el eco, trigger escuchar el eco, trigger escuchar el eco, y trigger escuchar el eco, y cuando lo ejecuto en algun momento se cuelga o se queda bloqueado.....

El programa:
program sensor

Código:
'TRIGGER Y ECHO DE CADA SENSOR
symbol        TDI         =   porta.0        ''TRIGGER
symbol        EDI         =   porta.1        ''ECHO

symbol        TDD         =   porta.2         ''   _______________________________
symbol        EDD         =   porta.3         ''  [         - E T 5V    DI        ]
                                              ''  [         - E T 5V    DD        ]
symbol        TLI         =   porta.4         ''  [         - E T 5V    LI        ]
symbol        ELI         =   porta.5         ''  [         - E T 5V    LD        ]
                                              ''  [         - E T 5V    ATRAS     ]
symbol        TLD         =   portc.0         ''  [                               ]
symbol        ELD         =   portc.1         ''  [                               ]
                                              ''  [                               ]
symbol        TA         =   portc.2          ''  [                               ]
symbol        EA         =   portc.3          ''

'LED DE INDICACION
symbol        DI          =   portb.0
symbol        DD          =   portb.1
symbol        LI          =   portb.2
symbol        LD          =   portb.3
symbol        TRASERO          =   portb.4

symbol        ALCANCE     =   8000
symbol        ALCANCE_useg    =   5024

'DECLARACIONES DE VARIABLES
dim            duration_us as word
               distance as word
               length_mm as char[4]

'SETUP DEL PIC
sub procedure InitMain()
              OPTION_REG =   0x80              ' Pull-up disabled PORTB
              INTCON     =   0x00              ' Disable interrupts
              adcon1 = $06                     'ESTO ES PARA EL 16F873A
              ''ansel=0
              ''anselh=0
              porta = 0
              trisa = %00101010          ''     - - E T E T E T
              portb = 0
              trisb = %00000000
              portc=0
              trisc=  %10001010          ''     RX TX - - E T E T
end sub



'MAIN
main:

aaa:
        InitMain()
        duration_us = 0
        distance   = 0
        DI          = 1
        DD          = 1
        LI          = 1
        LD          = 1
        TRASERO      =1
        DELAY_MS(1000)
        DI          = 0
        DD          = 0
        LI          = 0
        LD          = 0
        TRASERO      =0
        DELAY_MS(1000)
        
    ''    goto aaa
volver: 

''********************************************************************
        TDI = 1                    ' Trigger the module for 10usec
        delay_us(10)
        TDI = 0
        while EDI = 0              ' Waiting for the echo
              ''Si no anda cuando desconectamos el sensor cambiamos trigger con echo en todos los sensores!!! y agregamos la resis de pulldown
              nop
        wend
        TMR1L    = 0                   ' Clear the TMR1L value
        TMR1H    = 0                   ' Clear the TMR1H value
        T1CON    = 0x01                ' Enable TMR1
        while EDI = 1              ' While echo received, let the TMR1 count
              ''Lo meto aca dentro para poder terminar antes si no anda el sensor!!!!
              ''duration_us = TMR1H<<8 + TMR1L ' Retain TMR1 value = ON pulse
              nop
        wend
        T1CON    = 0
        duration_us = TMR1H<<8 + TMR1L ' Retain TMR1 value = ON pulse
        distance   = duration_us * 1.716 * 0.927856  ''useg /58 = centimetros
        '' Me parece que son 5024useg los 80cm    ALCANCE_useg
        '' 343.2 m/seg o 34,32cm/seg es la velocidad del sonido, y la distancia sensada es el doble!!!
        IF   (distance > ALCANCE) THEN
        ''IF   (duration_us > ALCANCE_useg) THEN
                DI=0
        ELSE
                DI=1
        END IF
        delay_ms(10)
''********************************************************************

''********************************************************************
        TDD = 1                    ' Trigger the module for 10usec
        delay_us(10)
        TDD = 0
        while EDD = 0              ' Waiting for the echo
              nop
        wend
        TMR1L    = 0                   ' Clear the TMR1L value
        TMR1H    = 0                   ' Clear the TMR1H value
        T1CON    = 0x01                ' Enable TMR1
        while EDD = 1              ' While echo received, let the TMR1 count
              nop
        wend
        T1CON    = 0
        duration_us = TMR1H<<8 + TMR1L ' Retain TMR1 value = ON pulse
        distance   = duration_us * 1.716 * 0.927856
        IF   (distance > ALCANCE) THEN
       '' IF   (duration_us > ALCANCE_useg) THEN
                DD=0
        ELSE
                DD=1
        END IF
        delay_ms(10)
''********************************************************************




         GOTO volver
         
end.

Si manejo uno solo de los sensores anda bien , pero si pongo dos de vez en cuando se queda colgado, intuyo que es dentro de alguno de los whiles!!!!
 
Última edición por un moderador:
supongo que si tienes un error de este tipo...

y yo no le veo ningun sentido que ejecutes la subrutina init main, declarar los registros al inicio es suficiente y yo crearia una subrutina para manejar ambos sensores con el mismo codigo, solo cambiaria el puerto que se este utilizando.

no tengo proton (creo que es ese) sino te pondria en codigo de lo que te sugiero.
 
Última edición:
He pasado el código a mi lenguaje (que prácticamente es el mismo) y en la simulación no se me cuelga.

Lo que si he observado es que declaras "distance" como un Word, que en mi lenguaje es un entero de 16bit sin signo, así que lo he tenido que declarar como "Single" que es equivalente al tipo Float; real de 4bytes, porque mi compilador es más estricto y no permite ese tipo de operación.

Dim distance as Single 'Float de 4bytes.
distance = duration_us * 1.716 * 0.927856 ''useg /58 = centímetros
 
Última edición:
Si en la simulacion anda barbaro, pero se ve que tiene que haber algun problema por que se queda bloqueado......., me juego a que en los while pregunto antes que se de la condicion. Quisiera hacer una funcion que maneje un sensor y salga por timeout. Osea una funcion asi

que devuelva un word ULTRA( y le de como parametros los pines de triger y echo, mas el timeout).

Se entiende?

Muchas gracias
 
Pasar a una función los pin a utilizar no es tan fácil.

Código:
'TRIGGER Y ECHO DE CADA SENSOR
Define SIMULATION_WAITMS_VALUE = 0
Symbol tli = PORTA.4  ''  [         - E T 5V    LI        ]
Symbol eli = PORTA.5  ''  [         - E T 5V    LD        ]
''  [         - E T 5V    ATRAS     ]
Symbol tld = PORTC.0  ''  [                               ]
Symbol eld = PORTC.1  ''  [                               ]
''  [                               ]
Symbol ta = PORTC.2  ''  [                               ]
Symbol ea = PORTC.3  ''

'LED DE INDICACION
Symbol trasero = PORTB.4

Const alcance = 8000
Const alcance_useg = 5024

'DECLARACIONES DE VARIABLES
Dim duration_us As Word
Dim distance As Single  'word
Dim length_mm(4) As Byte
Const sensor1 = 1
Const sensor2 = 2

'MAIN
main:

	aaa:
		Call initmain()
		duration_us = 0
		distance = 0
		di = 1
		dd = 1
		li = 1
		ld = 1
		trasero = 1
		WaitMs 1000
		di = 0
		dd = 0
		li = 0
		ld = 0
		trasero = 0
		WaitMs 1000

	''    goto aaa
volver:
''********************************************************************
	distance = _read(alcance, sensor1)
	Call _led_delantero(distance, alcance)
	distance = _read(alcance, sensor2)
	Call _led_trasero(distance, alcance)
	
Goto volver
End                                               
''********************************************************************
''********************************************************************
'Control sensor
Symbol tdi = PORTA.0  ''TRIGGER
Symbol edi = PORTA.1  ''ECHO
Symbol tdd = PORTA.2  ''   _______________________________
Symbol edd = PORTA.3  ''  [         - E T 5V    DI
Function _read(_alcance As Word, _mod As Byte) As Single
	ConfigPin tdi = Output
	ConfigPin edi = Input
	ConfigPin tdd = Output
	ConfigPin edd = Input

	If _mod = 1 Then
		tdi = 1  'Trigger the module for 10usec
		WaitMs 10
		tdi = 0
		While edi = 0  'Waiting for the echo
			ASM:        nop
		Wend
	Endif
	If _mod = 2 Then
		tdd = 1  'Trigger the module for 10usec
		WaitMs 10
		tdd = 0
		While edd = 0  'Waiting for the echo
			ASM:        nop
		Wend
	Endif
	TMR1L = 0  'Clear the TMR1L value
	TMR1H = 0  'Clear the TMR1H value
	T1CON = 0x01  'Enable TMR1
	If _mod = 1 Then
		While edi = 1  'While echo received, let the TMR1 count
			ASM:        nop
		Wend
	Endif
	If _mod = 2 Then
		While edd = 1  'While echo received, let the TMR1 count
			ASM:        nop
		Wend
	Endif
	T1CON = 0
	duration_us = ShiftLeft(TMR1H, 8)  '+ TMR1L  'Retain TMR1 value = ON pulse
	duration_us = duration_us + TMR1L
	distance = duration_us * 1.716 * 0.927856
	WaitMs 10
	_read = distance
End Function                                      
'*********************************************
'Control led
Symbol di = PORTB.0
Symbol dd = PORTB.1
Proc _led_delantero(_distance As Single, _alcance As Word)
	ConfigPin di = Output
	ConfigPin dd = Output
	If _distance > _alcance Then
		'' IF   (duration_us > ALCANCE_useg) THEN
		di = 0
	Else
		dd = 1
	Endif
	WaitMs 10
End Proc                                          
Symbol li = PORTB.2
Symbol ld = PORTB.3
Proc _led_trasero(_distance As Single, _alcance As Word)
	ConfigPin li = Output
	ConfigPin ld = Output
	If _distance > _alcance Then
		'' IF   (duration_us > ALCANCE_useg) THEN
		li = 0
	Else
		ld = 1
	Endif
	WaitMs 10
End Proc                                          
'SETUP DEL PIC
Proc initmain()
	OPTION_REG = 0x80  'Pull-up disabled PORTB
	INTCON = 0x00  'Disable interrupts
	ADCON1 = $06  'ESTO ES PARA EL 16F873A
	''ansel=0
	''anselh=0
	PORTA = 0
	TRISA = %00101010  ''     - - E T E T E T
	PORTB = 0
	TRISB = %00000000
	PORTC = 0
	TRISC = %10001010  ''     RX TX - - E T E T
End Proc
 
Última edición:
Si, se me esta complicando demasiado... pero el problema mas grave es que se queda dentro de alguno de los while, esperando que llegue el cero o el uno y de ahi no sale...... Por eso quiero que este un tiempo y se valla.......
 
Este código tiene Timer out:

Código:
'**********************************************************************************
'Funciones para la medición de distancia con el sensor HC-SR04 con TMR1
'Placa PicEBasic, By COS, 11/2013
'Basic Pic Simulator IDE (PSI), v6.95_6, Pic16F88
'**********************************************************************************
'----------------------------------------------------------------------------------
Define CONF_WORD = 0x2f50
Define CONF_WORD_2 = 0x3ffc
Define CLOCK_FREQUENCY = 8
'Define SIMULATION_WAITMS_VALUE = 1  'Activar para simulación
'-----------------------------------------
Call _setupebasic()
Hseropen 38400  'Inicializa puerto RS232 por hardware a 4800Baudios
Lcdinit  'Inicializa el LCD sin cursor
WaitMs 100  'Pausa de 100 mSeg.
Lcdout "Test P. HC-SR04"  'Imprime el texto en el LCD
WaitMs 2000  'Pausa de 2 Seg.
'-----------------------------------------
void_main:

	Call _setup_hcsr04(8, 15, 0)  'Reloj, compensación positiva, compensación negativa
	Symbol _ledsr04 = RA4  'Se asigna pin del LED placa adaptadora
	ConfigPin _ledsr04 = Output  'Led, salida
	Dim distancia_mm As Word
	Dim main As Byte

	While main = main
		'Muestra lecturas
		_ledsr04 = True  'Led a On
		distancia_mm = _gethcsr04()  'Lee sensor
		WaitMs 50  'Pausa para que se vea el led iluminado
		_ledsr04 = False  'Led a Off
		Lcdcmdout LcdLine2Home  'Cursor al principio de la linea2
		Lcdout "HC-SR04: ", #distancia_mm, "mm    "  'Salida de datos por el LCD
		Hserout "HC-SR04: ", #distancia_mm, "mm", CrLf  'Salida de datos por Usart
'WaitMs 100
	Wend

End                                               
Include "_ProcSetUpEBasic.bas"
Include "_FuncionesGeneralLibrary.bas"
Include "_FuncionesPic16F88.bas"
'-------------------------------------------------
'Funciones para el control del sensor HC-SR04
'********************************************************************
'Funcion para la configuración de la función
'_clk = Mhz del reloj del sistema
'_mas = factor de correción positivo, incrementa la lectura final
'_menos = factor de correción negativo, decrementa la lectura final
'Call _setup_hcsr04(Mhz reloj, incremento, decremento)
Proc _setup_hcsr04(_clk As Byte, _mas As Byte, _menos As Byte)
	Call _hcsr04(_clk, _mas, _menos, 0)
End Proc                                          
'Función para la lectura del sensor
'Retorna una lectura en mm del sensor HC-SR04
'_GetHCSR04 = retorna la lectura en mm del sensor
'Lectura = _GetHCSR04()
Function _gethcsr04() As Word
	_gethcsr04 = _hcsr04(0, 0, 0, 1)
End Function                                      
'Función principal de lectura y control del sensor HC-SR04
'Funcion de lectura y control del sensor HC-SR04, devuelve valor
'_clk = Mhz del reloj del sistema
'_mas = factor de correción positivo, incrementa la lectura final
'_menos = factor de correción negativo, decrementa la lectura final
'_ctrl = configración
'Call _gethcsr04(Mhz reloj, incremento, decremento, control)
'_gethcsr04 > de 0 lectura en mm, = 0 error de lectura
Symbol _echosr04 = RB4  'Se asigna pin del ECHO
Symbol _trigersr04 = RB1  'Se asigna pin del TRIGER
Function _hcsr04(_mhz As Byte, _mas As Byte, _menos As Byte, _ctrl As Byte) As Word
	Dim _auxw As Word
	Dim _auxl As Long
	Dim _aux_mhz As Byte
	Dim _aux_mas As Byte
	Dim _aux_menos As Byte
	_hcsr04 = 0  'Se marca error de lectura por defecto
	'Inicializa la función
	If _ctrl = 0 Then
		ConfigPin _echosr04 = Input  'Echo, entrada
		ConfigPin _trigersr04 = Output  'Triger, salida
		_trigersr04 = False  'Inicializa el Triger
		_ledsr04 = False  'Inicializa el Led
		_aux_mhz = (_mhz * 2) / 8  'Factor corrección a uSeg.
		_aux_mas = _mas  'Calibrado positivo
		_aux_menos = _menos  'Calibrado negativo
		Call _setup_timer1(_tmr1_internal, _tmr1_div1)  'Configura el timer1
		Call _timer1(_on)
		'Call _disable_interrupts(_int_timer1)  'Desactiva las interrupciones del Timer1
		Exit  'Fuerza la salida de la función
	Endif
	'Solicitud de una lectura al sensor -------------------------------------
	'Se demanda lectura
	_trigersr04 = True  'Inicia pulso del Triger
	WaitUs 15  'Ancho del pulso del Triger en uSeg., minimo 10uSeg.
	_trigersr04 = False  'Fin del pulso del Triger
	Call _clear_timer1()  'Se borra el contador del Timer
	While _echosr04 = False  'Se espera hasta que el sensor inicie una lectura
		If _tmr1if = True Then Exit  'Fin si desbordo el Timer
	Wend
	Call _clear_timer1()  'Se borra el contador del Timer
	While _echosr04 = True  'Se espera hasta que el sensor inicie fin de lectura
		If _tmr1if = True Then Exit  'Fin si desbordo el Timer
	Wend
	_auxw = _get_timer1()  'Asigna la lectura del Timer
	_auxw = ((_auxw / _aux_mhz) + _aux_mas) - _aux_menos  'Calibrado
	_auxl = ((_auxw * 340) / 2) / 1000  'Milimetros
	_hcsr04 = _auxl  'Pasa valor
End Function                                      
'**************************************************************************
 
Si tu lenguaje te permite trabajar directamente con bit, existe una forma cómoda para pasar pin (in/out) a una función:

Código:
'Ejemplo_02
'07/09/2015, Basic PSI, By COS
'Función que permite trabajar 2Pin como entradas
'y 2Pin como salidas.
'Puertos de los pin configurables dos a dos.
'Se puede trabajar sobre el mismo puerto
'o un puerto para las entradas y otro para las salidas
AllDigital
main:
	Const pin0 = 0
	Const pin1 = 1
	Const pin2 = 2
	Const pin3 = 3
	Const pin4 = 4

	Call _fun(pin0, pin1, pin0, pin4)

Goto main
End                                               
'***************************************
'Selet Port input
Symbol _port_in = PORTA
Symbol _input = TRISA
'Selet Port output
Symbol _port_out = PORTB
Symbol _output = TRISB
Function _fun(_in1 As Byte, _in2 As Byte, _out1 As Byte, _out2 As Byte) As Byte
	'Setup TRIS
	_input._in1 = 1
	_input._in2 = 1
	_output._out1 = 0
	_output._out2 = 0
	
	If _port_in._in1 = 1 Then
		_port_out._out1 = 1
	Else
		_port_out._out1 = 0
	Endif
	
	If _port_in._in2 = 1 Then
		_port_out._out2 = 1
	Else
		_port_out._out2 = 0
	Endif

End Function
 
Última edición:
Que tal si le da un vistazo a este codigo a lo mejor algo le pueda ser de utilidad:

Código:
program sensor_ultrasonico_12f629
' Declarations section              well im trying with a 12f615

dim     duration_us as word
        distance1, distance2 as word
        length_mm as char[4]         ' i supose this is for the LCD but i won´t erase it just in case

sub procedure InitMain()
    OPTION_REG =   0x80              ' this said "Pull-up disabled" i guess it doesnt matter
    INTCON     =   0x00              ' Disable interrupts
    CMCON      =   0x00              ' No COMP

    T1CON      =   0x00

    TRISIO      =  %00011000              ' RA4,3 inputs, rest of them outputs         00000100

    GPIO      =   0x00              ' Clear gpio                       gp.5 = trigger   gp.4 = echo

end sub

main:
'   Main program
InitMain()

duration_us = 0
  distance1   = 0
  distance2   = 0
  

Measure:
  GPIO.5 = 1                    ' Trigger the module for 10usec
  delay_us(10)
  GPIO.5 = 0

  while GPIO.4 = 0              ' Waiting for the echo
        nop
  wend

  TMR1L    = 0                   ' Clear the TMR1L value     (i don´t know what is doing  XD)
  TMR1H    = 0                   ' Clear the TMR1H value     (i don´t know what is doing  XD)
  T1CON    = 0x01                ' Enable TMR1               (i don´t know what is doing  XD)

  while GPIO.4 = 1              ' While echo received, let the TMR1 count       (i don´t know what is doing  XD)
        GPIO.0 = 1               '    especially i dont understand this part, why to gp.0?
  wend

  duration_us = TMR1H<<8 + TMR1L ' Retain TMR1 value = ON pulse
  distance1   = duration_us * 1.716 * 0.927856
  distance2   = distance1 - 10 'Substract 10mm as this is the distance between the sensor (inside the aluminium tube) and the edge of the tube itself.


                   WordToStr(distance2, length_mm)             ' i supose this is for the LCD but i won´t erase it just in case

                   if distance2 < 1000 then               ' after all operations, i supose my output will be on distance2
                   gpio.2=1                              ' ¿am i right?
                   delay_ms(10)                          ' if its right, i should be able to link a led on gp.2
                   gpio.2=0
                   delay_ms(5)
                   end if


goto measure
 
end.
 
Última edición:
Por si el código que puse antes es muy complicado; solo tienes que añadir el control de desborde del TMR1 en los Whiles, y esto se hace controlando el bit PIR1.TMR1IF. Este flag se pone a 1 cuando el registro del Tmr1 se desborda, no vuelve solo a valor 0, por lo que hay que borrarlo antes de volver a comprobarlo.

TMR1L = 0 'Clear the TMR1L value
TMR1H = 0 'Clear the TMR1H value
T1CON = 0x01 'Enable TMR1
PIR1.TMR1IF = 0 'Clear desborde TMR1

While _port_in._echo = 0 And PIR1.TMR1IF = 0 'Waiting for the echo y desborde Tmr1
ASM: nop
Wend

TMR1L = 0 'Clear the TMR1L value
TMR1H = 0 'Clear the TMR1H value
T1CON = 0x01 'Enable TMR1
PIR1.TMR1IF = 0 'Clear desborde TMR1

While _port_in._echo = 1 And PIR1.TMR1IF = 0 'While echo received y desborde Tmr1
ASM: nop
Wend
 
Atrás
Arriba