Ayuda con proyecto (simulador de ap)

Hola necesito ayuda con un proyecto que inicie hace un tiempo y estoy casi terminando, se trata de un dispositivo de entrada/salida que emula el piloto automático de un avión pequeño. Por lo cual no se trata de un simple joystick sino que además este dispositivo recibe algunos datos provenientes del PC (del simulador de vuelo) como ser la altitud, el rumbo, la velocidad vertical, etc. y las muestra en un LCD de 16x2.
Para dicho proyecto utilice un 18F4550 por sus prestaciones y su cantidad de patas, cabe aclarar que este dispositivo cuenta con la entrada de 7 botones encargados de la activación-desactivación de los comandos del AP, así como 4 botones mas encargados de subir o bajar el numero y de cambiar el selector.
Paso a enseñarles el diagrama del dispositivo para que aclaren un poco las cosas:



En tamaño real:
http://img830.imageshack.us/img830/4663/fsap10.jpg

Bueno el dispositivo funciona perfectamente, todas sus funciones estas activas y el LCD muestra lo correcto enviado desde el PC pero el problema es el siguiente:
TODO MARCHA BIEN HASTA LUEGO DE PRESIONAR 8 VECES LOS BOTONES, ES DECIR FUNCIONA PERFECTO PERO A LA OCTAVA VEZ QUE SE A PRESIONADO CUALQUIER BOTON SE REINICIA EL PIC.
Presione cualquier botón, a cualquier velocidad, da igual si lo mantengo presionado como si se presiona una hora después, luego de 8 veces se reinicia el pic y al segundo reinicio se vuelve inestable e inoperable.
Bueno les envio el código del PIC realizado en PROTON y con la ayuda del EasyHID, no les doy el código fuente del software ya que este no es el del problema (el PIC se reinicia este conectado o no al software).
Ojala puedan ayudarme, prometo compartir el proyecto una vez funcione, tanto diagramas pcb códigos etc. Un saludo grande a toda la comunidad, Gaston.

PHP:
' select MCU and clock speed
Device = 18F4550
XTAL = 48	

' descriptor file, located in \inc\usb_18 - a copy
' is located in the same folder as this file	
USB_DESCRIPTOR = "FSXAP2010DESC.inc"

' USB Buffer...
Symbol USBBufferSizeMax = 32
Symbol USBBufferSizeTX  = 32
Symbol USBBufferSizeRX  = 32
Dim    USBBuffer[USBBufferSizeMax] As Byte

'REMINDERS = 1                                               ' Mostrar todos los avisos al compilar.
'********************************    
'*    CONFIGURACION DE FUSES    *
'********************************
        
        @CONFIG_REQ
        @PLL_REQ
        @__config config1l, PLLDIV_1_1 & CPUDIV_1_1 & USBDIV_2_1
        @__config config1h, FOSC_XTPLL_XT_1
        @WATCHDOG_REQ
        @__config config2h, WDT_OFF_2 & WDTPS_128_2
        @DEBUG_REQ        
        @__config config4l, LVP_OFF_4 & ICPRT_OFF_4 & XINST_OFF_4 & DEBUG_OFF_4
        @__config config3h, PBADEN_OFF_3

        ALL_DIGITAL = true
        


'********************************
'*   CONFIGURACION DE PUERTOS   *
'********************************

TRISA = 0                                                   ' El puerto A como salida 
TRISB = 0                                                   ' El puerto B como salida (Panel LCD)
TRISC.0 = 1                                                 ' El puerto C como entrada (Selector y subir bajar numero)
TRISC.1 = 1
TRISC.2 = 1
TRISC.6 = 1
TRISC.7 = 1
TRISD = 255                                                 ' El puerto D como entrada (Botones AP)
TRISE.0 = 1                                                 ' El puerto E como entrada (Auxiliares)
TRISE.1 = 1


'SETEO EL LCD 16X2 PARA 4 CABLES

LCD_DTPIN = PORTB.4         
LCD_RSPIN = PORTB.3
LCD_ENPIN = PORTB.2
LCD_INTERFACE = 4    
LCD_LINES = 2
LCD_TYPE = 0



'VARIABLES 

Dim SELECTOR_UP As Bit                                       ' "SELECTOR_UP" se utiliza para establecer un incremento en el numero
Dim SELECTOR_DOWN As Bit                                     ' "SELECTOR_DOWN" se utiliza para establecer un decremento en el numero
Dim ARRAY[2] As Byte                                         ' Array para el pasaje de los estados
Dim NUMERO As Word                                           ' Variable para el numero recibido del buffer
Dim DIVISOR As Word                                          ' Variable para el multiplicador del numero recibido del buffer
Dim RESTO As Word                                            ' Variable para el resto recibido del buffer
Dim NUMERO_VS As Word                                        ' Variable para el numero del la Vs recibido del buffer
Dim DIVISOR_VS As Word                                       ' Variable para el multiplicador del numero_Vs recibido del buffer
Dim NUMERO_STR As String * 6                                 ' String para imprimir el numero
Dim NUMERO2_STR As String * 5                                ' String para imprimir el numero de la Vs
Dim NUMERO_HDG As String * 3                                 ' String para imprimir el numero de rumbo HDG

'VARIABLES DE LOS ESTADOS DE LOS PUERTOS
Dim ESTADO_SELECTOR As Byte                                  ' Variable del estado del selector
Dim ESTADO_GRAL_STR As String * 3                            ' String para el pasaje de los estados
Dim ESTADO_GRAL As Byte                                      ' Variable para enviar los estados al buffer
Dim ESTADO_BOTONES As Byte                                   ' Variable del estado de los botones
Dim ESTADO_ATP As Byte                                       ' Variable del estado ATP para los LEDs
Dim SELECTOR_ANT As Byte                                     ' Variable para guardar el estado del selector antes de presionar el boton
Dim ESTADO_NUMERO As Byte                                    ' Variable del estado de los botones de subir/bajar
Dim A As Word                                                ' Variable multifuncion
             
'REGISTROS Y BANDERAS
Dim PP0 As Byte SYSTEM                                       ' Registro dentro del PIC USBPOLL STATUS
Symbol CARRY_FLAG = STATUS.0                                 ' En estado alto si el PIC no tiene el control sobre el buffer
Symbol ATTACHED_STATE = 6                                    ' Si el USB está conectado


Cls                                                          ' Borrar el LCD al iniciar
Clear                                                        ' Limpiar la memoria al iniciar
A= 0                                                         ' Inicializo las variables
ESTADO_SELECTOR = 1
SELECTOR_ANT = 1
ESTADO_NUMERO = 0
ESTADO_BOTONES = PORTD

Print At 1,1,"Conectando      "                           
Print At 2,1,"al USB.         " 
DelayMS 500
Cls
Print At 1,1,"Conectando      "                           
Print At 2,1,"al USB...       " 

GoSub AttachToUSB                                             ' Comprueba si esta conectado a USB 
DelayMS 500
Print Cls,At 1,1,"   Conectado!   "                           ' Escribe que la conexion funciona
DelayMS 500


  
' *****************************************************************
' * LAZO PRINCIPAL DEL PROGRAMA MIENTRAS SE ESTÁ CONECTADO A USB  *
' *****************************************************************
INICIO:

                           
                                               
     Print Cls, At 1,1, "Esperando al    "                     
     Print At 2,1,      "Software...     "                    
     

PRINCIPAL:
     
     If A = 0 Then GoSub ESPERAR_DATO
     DelayMS 200                                             ' Demora para establecer los botones
     SELECTOR_ANT = ESTADO_SELECTOR                          ' El selector anterior sera ahora el selector actual
     
'RUTINA DEl ENVIO DE DATOS AL USB   
ENVIAR:       
     
     USBBuffer[0] = 0                                         ' El primer byte es de reporte de conexion
     USBBuffer[1] = SELECTOR_ANT                              ' El segundo sera el estado del selector 
     USBBuffer[3] = ESTADO_BOTONES                            ' El tercer sera el estado del PORTD (botones del AP)
     USBBuffer[4] = ESTADO_NUMERO                            ' El estado del numero (subir/bajar) 0 no hace nada 1 sube 2 baja

     GoSub DoUSBOut                                           ' Transmite lo almacenado en el buffer
     DelayMS 50                                               ' Se da un tiempo de demora
     ESTADO_NUMERO = 0   
'RUTINA DE LA RECEPCION DE DATOS DEL USB   
    GoSub ESPERAR_DATO                                       ' Lee el buffer de entrada

RECIBIDO:    
    A = 1  
    ESTADO_ATP = USBBuffer[5]                                 ' recibe el estado de los botones del AP
    NUMERO = USBBuffer[6]                                     ' recibe el numero sin multiplicar (para no ecceder los 256 del byte)
    DIVISOR = USBBuffer[7]                                    ' recibe el numero para multiplicar al anterior
    RESTO = USBBuffer[8]                                      ' recibe el resto de la cuenta, para lograr el numero exacto
    NUMERO_VS = USBBuffer[9]                                  ' reciben los numeros para formar el
    DIVISOR_VS = USBBuffer[10]                                ' Numero de la Velocidad vertical (Vs) que utilizaremos para mostrar en caso de que el 
                                                              ' Selector se encuentre en "Alt"
    ESTADO_SELECTOR = USBBuffer[11]                           ' El ultimo Byte recibe el estado actual del selector
    
'RUTINA PARA ESTABLECER LOS DATOS RECIBIDOS
    
    
    Select ESTADO_SELECTOR                                    ' Comprueba el estado del selector actual y lo muestra
'                                                               En el LCD, se coloca en la rutina de recibo de datos      
     Case 1:                                                  ' Porque si desde el juego se cambia el estado del selector
       Print Cls, At 1,2, "Alt          "                     ' Y se cambia el numero, el hardware debe mostrar el dato 
       Print At 2,1,      "   Vs        "                     ' En el LCD que ha cambiado.
     Case 2:
       Print Cls, At 1,2, "Vs           "
     Case 4:
       Print Cls, At 1,2, "HDG          "
     Case 8:
       Print Cls, At 1,2, "IAS          "
      
     End Select
     DelayMS 10
     SELECTOR_ANT = ESTADO_SELECTOR
     NUMERO = NUMERO * DIVISOR + RESTO                        ' En las siguientes lineas se establecen los numeros
     NUMERO_VS = NUMERO_VS * DIVISOR_VS                       ' Recibidos, se multiplica con sus respectivos "divisores" y se
     NUMERO_STR =  Str$ (DEC5 NUMERO)                         ' Les suma el resto, luego se los pasa a las variables de tipo
     NUMERO2_STR =  Str$ (DEC4 NUMERO_VS)                     ' String para poder imprimir como cadena de texto (esto se puede evitar) pero
     NUMERO_HDG =  Str$ (DEC3 NUMERO)                         ' El autor prefiere utilizar este metodo.
 
    If SELECTOR_ANT = 1 Then                                  ' Si el selector es "Alt" entonces imprime tambien el numero de la velocidad vertical
       Print At 2,12, NUMERO2_STR
    End If   
 
    If SELECTOR_ANT = 4 Then                                  ' Si el selector es "HDG" (rumbo) entonces imprime solo los tres numeros del rumbo si los
       Print  At 1,12, NUMERO_HDG                             ' Ceros de la izquierda
    Else                                                      ' Si no es asi imprime de forma normal
       Print  At 1,11, NUMERO_STR
    End If
 
    GoSub ESPERAR_CAMBIO                                      ' Se cierra la rutina llamando a la subrutina DoUSBIn para recibir datos del USB, o en caso
                                                              ' se presionarse un boton, volver a la rutina principal
  
  
' ************************************************************
' *    RUTINA DE RECEPCIÓN DE DATOS Y CAMBIO DE ESTADO       *
' ************************************************************
ESPERAR_CAMBIO:
   
   If PORTC.6 = 0 Then                                        ' Si se presiona el boton de SUBIR el selector, sale de la
      DelayMS 50                                              ' Rutina actual y va a ANALISIS para establecer el nuevo
      SELECTOR_UP = 1                                         ' Estado
      GoTo ANALISIS
   End If
   If PORTC.7 = 0 Then                                        ' Si se presiona el boton de BAJAR el selector, sale de la
      DelayMS 50                                              ' Rutina actual y va a ANALISIS para establecer el nuevo
      SELECTOR_DOWN = 1                                       ' Estado
      GoTo ANALISIS
   End If
   
   If PORTC.1 = 0 Then                                       ' Si se presiona el boton de SUBIR numero, sale de la
      DelayMS 50                                              ' Rutina actual y va a principal para ENVIAR el nuevo
      ESTADO_NUMERO = 1                                       ' Numero
      GoTo PRINCIPAL
   End If
  
   If PORTC.2 = 0 Then                                        ' Si se presiona el boton de BAJAR el numero, sale de la
      DelayMS 50                                              ' Rutina actual y va a principal para ENVIAR el nuevo
      ESTADO_NUMERO = 2                                       ' Numero
      GoTo PRINCIPAL
   End If
   
   ESTADO_BOTONES = PORTD                                     ' El estado del PORTB lo asigna a "ESTADO_BOTONES" para almacenar el estado
                                                              ' y que no se pierda luego de soltar el boton
   
   If ESTADO_BOTONES > 0 Then GoTo PRINCIPAL                  ' Si se presiono alguno de los botones el estado sera distinto de cero, por los cual sale
                                                              
ESPERAR_DATO:                                                 ' Inmediatamente de esta rutina y va a PRINCIPAL a enviar los nuevos datos.
   USBIn 1, USBBuffer, USBBufferSizeRX, ESPERAR_CAMBIO         ' Si no recibe nada del USB vuelve a empezar la rutina, en caso contrario
   GoSub RECIBIDO                                              ' Sale y va a la rutina "RECIBIDO"
   
' ************************************************************
' *              RUTINA DE TRANSMISIÓN DE DATOS              *
' ************************************************************

DoUSBOut:   
   USBOut 1, USBBuffer, USBBufferSizeTX, DoUSBOut
   Return

' ************************************************************
' *           ESPERA HASTA QUE EL USB SE CONECTE             *
' ************************************************************

AttachToUSB:
   Repeat								
      USBPoll		
   Until PP0 = ATTACHED_STATE
   Return


' ************************************************************
' *           ANALIZA EL ESTADO DEL SELECTOR                 *
' ************************************************************


ANALISIS:
   
   DelayMS 50                                                 ' Da una pequeña demora 
   If SELECTOR_UP = 1  Then GoSub SUBIR_SELECTOR              ' Si se presiono el boton de SUBIR va a la rutina "SUBIR_SELECTOR"
   DelayMS 50
   If SELECTOR_DOWN = 1  Then GoSub BAJAR_SELECTOR            ' Si se presiono el boton de BAJAR va a la rutina "SUBIR_SELECTOR"
   DelayMS 50
   
   GoSub PRINCIPAL
     
SUBIR_SELECTOR:                                                ' Si se presiono el boton de SUBIR, el programa establece
    SELECTOR_UP = 0                                            ' El nuevo estado del selector dependiendo del estado anterior
    ESTADO_SELECTOR = ESTADO_SELECTOR * 2                      ' Si el numero del estado supera el 8 es porque no puede subir mas
    If ESTADO_SELECTOR > 8 Then 
    ESTADO_SELECTOR = 8
    GoSub ESPERAR_CAMBIO           
    End If
    Return
    
BAJAR_SELECTOR:                                                 ' Si se presiono el boton de BAJAR, el programa establece
    SELECTOR_DOWN = 0                                           ' El nuevo estado del selector dependiendo del estado anterior
    If ESTADO_SELECTOR = 1 Then GoSub ESPERAR_CAMBIO            ' Si el NUMERO del estado es 1 es porque no puede bajar mas
    ESTADO_SELECTOR = ESTADO_SELECTOR / 2                       ' Y no cambia nada
    Return
 
Estás haciendo cualquier cosa con los Gosub (n).

De la subrutina se sale siempre con un Return. Vos estás saliendo con un Goto saltando al bucle principal o llamando de vuelta como subrutina al bucle principal --> terminás con un stack overflow.
 
Gracias por las respuestas gente amable. Pero no me quedo claro lo de los GoSub es decir, que diferencia hay con los Goto, y porque no puedo salir de una rutina como por ejemplo la de "Esperar_cambio" e ir a "Principal" eso no me queda claro, es decir si pongo siempre "Return" como dice Eduardo volvera a donde ha sido llamada la rutina, pero si no ha sido llamada desde principal? a donde se me escapa jaja? podrian poner un ejemplo porfa o ayudarme con este codigo en particular? gracias y un saludo grande.
 
Todo está en el datasheet de la mayoría de PICs, ahora si la gracia es solo programar sin saber nada de lo que hay dentro del PIC y como funciona, entonces:

GoSub, es un salto a una subrutina donde se ejecutan varias sentencias de código. La subrutina está señalada por una etiqueta como punto de entrada y finaliza al encontrar la primera sentencia RETURN devolviendo el control a la siguiente instrucción que invocó la subrutina (debajo del GoSub). Dentro del PIC se llene un buffer con la dirección de retorno al usar GoSub, en los PIC16 solo soporta hasta 8 direcciones de retorno, es decir que solo puedes usar hasta 8 GoSub anidados que muy rara vez se usa.

GoTo, es un salto sin condiciones a una etiqueta (label), no tiene retorno.

Ejemplo:
Código:
Goto Loop

SubA:
...     
...
return

SubB:
...
...
return

Loop:
GoSub SubA      ' Salta a SubA
High PORTB.0    ' Regresa aquí luego de ejecutar SubA y pone a 1 RB0.
DelayMs 200
GoSub SubB      'Salta a SubA
Low PORTB.0    ' Regresa y pone a 0 RB0
DelayMs 200
goto Loop
' Continua con la ejecución

end
 
Todo está en el datasheet de la mayoría de PICs, ahora si la gracia es solo programar sin saber nada de lo que hay dentro del PIC y como funciona, entonces:

GoSub, es un salto a una subrutina donde se ejecutan varias sentencias de código. La subrutina está señalada por una etiqueta como punto de entrada y finaliza al encontrar la primera sentencia RETURN devolviendo el control a la siguiente instrucción que invocó la subrutina (debajo del GoSub). Dentro del PIC se llene un buffer con la dirección de retorno al usar GoSub, en los PIC16 solo soporta hasta 8 direcciones de retorno, es decir que solo puedes usar hasta 8 GoSub anidados que muy rara vez se usa.

GoTo, es un salto sin condiciones a una etiqueta (label), no tiene retorno.

Ejemplo:
Código:
Goto Loop

SubA:
...     
...
return

SubB:
...
...
return

Loop:
GoSub SubA      ' Salta a SubA
High PORTB.0    ' Regresa aquí luego de ejecutar SubA y pone a 1 RB0.
DelayMs 200
GoSub SubB      'Salta a SubA
Low PORTB.0    ' Regresa y pone a 0 RB0
DelayMs 200
goto Loop
' Continua con la ejecución

end

Querido colega, gracias por tu respuesta, comenzare a tomar el datasheet del 4550 como parte de mi biblioteca de datos, pero no corresponde decir que programo por programar y sin saber nada, y no es ninguna gracia :confused:.
Intentare cambiar el codigo utilizando solo goto cuando tenga que salir y no volver y utilizare gosub - return cuando lo necesite, gracias a los dos y no hace falta "reirse" del trabajo de uno, sino ayudar e intentar orientar a los demas, eso hago yo. Un abrazo y nuevamente gracias. (y)
 
Aqui esta el proyecto terminado:


Presentación del proyecto



NUEVO VIDEO!
http://www.youtube.com/watch?v=pupKeu_M-og&feature=youtube_gdata

Hola antes que nada me presento ante esta fabulosa comunidad, mi nombre es Gastón y soy aficionado a la aeronáutica virtual, soy también aficionado a la programación y técnico en electrónica.
El proyecto que les presento es un muy apasionante y exigente al mismo tiempo, son meses de estudio y trabajo lo que me llevo a decidirme por el diseño de este "archifundio" en particular y la decisión de compartirlo con ustedes.
A quienes está destinado esto?:
*TODOS AQUELLOS AFICIONADOS A LA SIMULACION DE VUELO.
*QUIENES DESEEN CONSTRUIR SU PROPIA CABINA VIRTUAL.
*AFICIONADOS A LA ELECTRONICA DIGITAL, PROGRAMADORES, ETC.


De que se trata?
De la construcción de un panel externo, con conexión por USB, como si fuese un joystick convencional pero con la sumatoria de que por medio un LCD nos muestra los valores y nos deja controlar los botones del piloto automático, como ser la altitud la velocidad vertical el HDG etc. La idea es que podamos ponerlo sobre nuestro escritorio o introducirlo en un supuesto gabinete de nuestra cabina virtual, las dos opciones son validas, lo importante es que podamos controlar el AP (desde ahora en mas Piloto Automático) desde un panel externo y no desde la pantalla del PC.
Está basado en el multipanel de la marca Saitek, pero con algunas modificaciones que luego explicare, les paso una foto y un poco de info:
Saitek_PZ70.jpg


Como funciona?
En resumen, el funcionamiento se centra en una interface construida en base en el uso de un microcontrolador PIC4550 conectada con el puerto USB y por medio de un software realizado en Visual net, se comunica al juego leyendo los valores y escribiendo los ingresados desde la interface, si los valores se modifican desde el juego también se modifican en el panel LCD y viceversa.
Obviamente esta es una explicación muy básica, ya que detrás hay un diseño muy complejo, pero para que se entienda alcanza.

ACLARACION: les comento que el proyecto está en la fase final, ya está montado el circuito, probado el software y la interface con el FSX y hasta ahora funciona perfecto, iré subiendo fotos del proyecto y de su funcionamiento. Pero de momento tengo que solucionar el tema del gabinete donde iría montado y el tema de iluminar los botones ya que en la Argentina es muy difícil conseguir este tipo de botones y tendría que fabricarlos yo mismo.
Puedo armarlo yo mismo?
Si claro, de esto se trata este tema, de que todos puedan construirlo y probarlo, claro que para aquellos que no tengan conocimientos de electrónica o de programación les será muy difícil construirlo, pero no dejen de hacerme preguntas yo los guiare en lo que pueda. Una vez acabado y recontra probado pienso fabricarlo en serie para compartirlo a un precio muy accesible a todos los fanáticos del aire!
OTRA ACLARACION: No es el propósito de este tema la venta de este panel, sino compartir conocimiento, si alguien estuviese interesado en adquirirlo porque no se siente capaz o no tiene ganas de construirlo, una vez finalizado el proyecto podrá comunicarse conmigo fuera de esta comunidad.
Espero que les interese el tema, prometo ir subiendo las imágenes y actualizando los detalles, espero también que los que entiendan de electrónica o de programación se interesen y compartan también su saber, yo no tengo interés de lucrar con esto, es más bien una pasión y si puedo compartirlo, mejor. Abajo iré subiendo los planos del circuito, los detalles del lenguaje que utilice, los programas que use y hasta el código fuente, claro que también deseo que colaboren también con mis necesidades y ayuden a mejorar este magnífico proyecto!!

[/SIZE]Que necesito para empezar a armarlo?

Primero que nada, tratar de entender que no es fácil y que se necesita mucho tiempo y dedicación, conocimientos de electrónica y de programación, tanto con microcontroladores como con el lenguaje orientado a objetos.

Es necesario tener este programa para poder ver el diseño del circuito y del PCB:
Proteus de labcenter electronics.Para la programación del PIC utilizo:
Proton Ide

Para la creación del software del PC y de la interface con el FSX:
Visual Studio 2010
FSUIPC y las librerías DLL necesarias para el Visual Studio

Más adelante, cuando ya esté finalizado, subiré el manual completo del funcionamiento y la construcción del panel en un archivo pdf, ahora me basta con presentar el proyecto y compartir ideas y mejoras del mismo.
Donde están los archivos?

Bueno dado que esta pagina no me deja poner mas de 5 links, tendre que subir las cosas en otro lado o poner los link en los mensajes, asi que vayan viendo.Aqui les dejo el esquematico ACTUALIZADO para que vayan viendo:
NUEVO!!! Video demostracion!
http://www.youtube.com/watch?v=pupKeu_M-og&feature=youtube_gdata
 
Última edición por un moderador:
Atrás
Arriba