USB 18F4550, CDC, VisualB, y Motores PaP. Problema

Hola muchachos....
Saludos a todos.

Que gran comunidad, aportan, dan ideas, usan ideas, una retroalimentación muy buena.
Espero en lo futuro aportar a la comunidad.

En esta ocasión acudo a ustedes con el siguiente problema:

Mi objetivo:
*Mover un motor de paso, tipo unipolar, a través del puerto USB del computador usando el 18F4550 y un programa en visualB_6.

Como bien para empezar decidí por usar el com virtual que se genera con el 18F4550
Usando el compilador CCS y las respectivas librerias usb_cdc.h y usb_desc_cdc.h

Lo anterior lo realice con éxito, instalando el mchpcdc.inf. Y listo aparece muy bonito en administrador de hardware mi puerto COM virtual.

En la parte de visualB_6 hice un pequeño entorno asi como este:

1_560.jpg


Este es el código en visualB_6:

Código:
    Option Explicit

    Private Sub Form_Load()
    puerto.AddItem "COM1"
    puerto.AddItem "COM2"
    puerto.AddItem "COM3"
    puerto.AddItem "COM4"
    puerto.AddItem "COM5"
    puerto.AddItem "COM6"
    puerto.ListIndex = 0
        MSComm1.Settings = "9600,N,8,1"
        MSComm1.OutBufferSize = 1
        MSComm1.InBufferSize = 14
        MSComm1.InputMode = comInputModeText
        MSComm1.InputLen = 14
        MSComm1.RThreshold = 8
    Timer1.Interval = 1000
    Timer1.Enabled = True
    End Sub


    Private Sub MSComm1_OnComm()
     
    Dim InBuff As String
      Select Case MSComm1.CommEvent
             Case comEvReceive
                  Debug.Print MSComm1.InBufferSize
                  InBuff = MSComm1.Input
                  MSComm1.InBufferCount = 0  'Vacia el buffer de recepción
                  Debug.Print MSComm1.InBufferSize
                  Debug.Print InBuff
                  Recibir.Text = ""
                  Recibir.Text = Left$(InBuff, 14)
      End Select
    End Sub

    Private Sub Timer1_Timer()
    DoEvents 'Para que windows y el programa pueda realizar otras cosas
         If MSComm1.PortOpen = True Then
            estado.BackColor = &HFF00& 'Verde
            Debug.Print "Conectado"
            Label3.Caption = "USB ON"
            MSComm1.PortOpen = False 'Se cierra el puerto y se abre
            MSComm1.PortOpen = True  'si permite abrirlo es porque el puerto existe
                                     'y esta conectado, sino, genera un error
            Exit Sub
         Else
         estado.BackColor = &HFF& 'rojo
         Debug.Print "Desconectado"
         Label3.Caption = "USB OFF"
         End If
    End Sub

    Private Sub conectar_Click()
        If MSComm1.PortOpen = False Then
            'determina el puerto que hemos seleccionado.
            If puerto.ListIndex = 0 Then
                MSComm1.CommPort = 1
                End If
            If puerto.ListIndex = 1 Then
                MSComm1.CommPort = 2
                End If
            If puerto.ListIndex = 2 Then
                MSComm1.CommPort = 3
                End If
            If puerto.ListIndex = 3 Then
                MSComm1.CommPort = 4
                End If
            If puerto.ListIndex = 4 Then
                MSComm1.CommPort = 5
                End If
            If puerto.ListIndex = 5 Then
                MSComm1.CommPort = 6
                End If
        End If
        MSComm1.PortOpen = True
    End Sub

    Private Sub Detener_Click()
        Timer1.Enabled = False
        If MSComm1.PortOpen = True Then
           MSComm1.Output = "s"
           MSComm1.OutBufferCount = 0 'Vacia el buffer de transmisión
           Debug.Print "MSComm1.OutBufferCount"; MSComm1.OutBufferCount
        End If
        Timer1.Enabled = True
    End Sub

    Private Sub Girar1_Click()
        Timer1.Enabled = False
        If MSComm1.PortOpen = True Then
           MSComm1.Output = "d"
           MSComm1.OutBufferCount = 0 'Vacia el buffer de transmisión
           Debug.Print "MSComm1.OutBufferCount"; MSComm1.OutBufferCount
        End If
        Timer1.Enabled = True
    End Sub

    Private Sub Girar2_Click()
        Timer1.Enabled = False
        If MSComm1.PortOpen = True Then
           MSComm1.Output = "i"
           MSComm1.OutBufferCount = 0 'Vacia el buffer de transmisión
           Debug.Print "MSComm1.OutBufferCount"; MSComm1.OutBufferCount
        End If
        Timer1.Enabled = True
    End Sub

    Private Sub Form_Unload(Cancel As Integer)
    If MSComm1.PortOpen = True Then
       MSComm1.PortOpen = False
    End If
    End Sub

Este es el código del pic:

Código:
    #include <18F4550.h>


    #FUSES HSPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,PLL3,USBDIV,CPUDIV1,VREGEN,NOPBADEN
    #use delay(clock=48000000) //Microcontroller Clock Frequency 48MHz

    #define USB_CON_SENSE_PIN PIN_C2
    #include <usb_cdc.h> 

    void main()
    {

    //Variables
    int8 BobinaA, BobinaB, BobinaC, BobinaD;
    short Girar_D, Girar_I;

    OUTPUT_A(0);  // Inicializacion de los puertos
    OUTPUT_B(0);           
    OUTPUT_C(0);
    OUTPUT_D(0);           
    OUTPUT_E(0);

    // Secuencia de Giro del Motor.
       BobinaA=0b00000011;
       BobinaB=0b00000110;
       BobinaC=0b00001100;
       BobinaD=0b00001001;

    usb_init_cs(); 
    while(true)
         {
          usb_task();
          if (usb_attached())
              {
              output_low(PIN_C0);  // (Apaga LED Rojo)
              output_high(PIN_C1); // (Enciende LED Verde)
              }   
             else
                {
                output_high(PIN_C0); //(Enciende LED Rojo)
                output_low(PIN_C1);  //(Apaga LED Verde)
                }
          if(usb_cdc_connected())
             {
              if (usb_enumerated())
                  {
                   if(usb_cdc_kbhit())
                      {
                       if(usb_cdc_getc()=='d')
                          {
                           printf(usb_cdc_putc,"Dale Derecha");
                           Girar_D=true;
                           Girar_I=false;
                          }
                       if(usb_cdc_getc()=='i')
                          {
                           printf(usb_cdc_putc,"Dale Izquierda");
                           Girar_I=true;
                           Girar_D=false;
                          }
                       if(usb_cdc_getc()=='s')
                          {
                           printf(usb_cdc_putc,"No Girar");
                           Girar_I=false;
                           Girar_D=false;
                           output_d(0);       //Desenergiza las bobinas
                          }                 
                      }
                  }
             }
         if (Girar_D) //Bandera Girar Derecha
             {
              output_d(BobinaA);
              delay_ms(80);
              output_d(BobinaB);
              delay_ms(80);
              output_d(BobinaC);
              delay_ms(80);
              output_d(BobinaD);
              delay_ms(80);       
             }
         if (Girar_I) //Bandera Girar Derecha
             {
              output_d(BobinaD);
              delay_ms(80);
              output_d(BobinaC);
              delay_ms(80);
              output_d(BobinaB);
              delay_ms(80);
              output_d(BobinaA);
              delay_ms(80);       
             }
    } //fin while
    } //fin!

Esto es el diagnostico:

-El programa en visual permite elegir el puerto COM a usar y conectarse a el. Esto funciona sin problemas.

-El pic se identifica con el host intercambia descriptores y todo lo demas, pide al driver etc.. Esto funciona sin problemas.

Pero cuando en visual presionas un botón, el pic debería responder a ese botón, devolver un mensaje a visual y ejecutar la rutina correspondiente.

Lo anterior se realiza, pero no como debería, me explico:

--Supón que presionas el botón "Girar Derecha" en visual, este debe mandarle al pic la letra "d", el pic debe identificar que letra le llego, si es la letra "d" manda un mensaje a visual que dice "Dale Derecha", ademas, activa la bandera para girar a la derecha, luego el pic debe salir de ese IF, ver que bandera tiene activada, y comenzar la rutina de energizar las bobinas para mover el motor.

Lo anterior no se realiza hasta que presionas el botón en visual dos o tres veces
Si presionas el botón una vez, el pic queda en stand-by
Si presionas el botón una segunda vez, el pic sigue en stand-by
Si presionas el botón una tercera vez, el pic mueve el motor...

Cuando depuro el programa en proteus, dándole pausa a la simulación e ir al código, para ver que esta haciendo en ese supuesto "stand-by" me encuentro que el pic esta en la siguiente instrucción dentro de usb_cdc.h:

Código:
    ...
    ...
    ////////////////// END USB CONTROL HANDLING //////////////////////////////////
    ////////////////// BEGIN USB<->RS232 CDC LIBRARY /////////////////////////////

    char usb_cdc_getc(void) {
       char c;

       while (!usb_cdc_kbhit()) {}

       c=usb_cdc_get_buffer_status_buffer[usb_cdc_get_buffer_status.index++];
       if (usb_cdc_get_buffer_status.index >= usb_cdc_get_buffer_status.len) {
          usb_cdc_get_buffer_status.got=FALSE;
          usb_flush_out(USB_CDC_DATA_OUT_ENDPOINT, USB_DTS_TOGGLE);
       }

       return(c);
    }
    ...
    ...

Esta pegado en esta línea while (!usb_cdc_kbhit()) {} :eek: :eek: :eek:

Que la traducción seria algo así: "Mientras NO se hayan recibido uno o mas datos quédate aquí"

La ayuda del CCS dice que: usb_cdc_kbhit() - Returns TRUE if there is one or more character received and waiting in the receive buffer.

Pero se supone que estoy enviando 1 dato (un carácter)
Por qué el pic se queda en esta línea?
Por qué al presionar el botón mas de dos veces el pic hace lo que debe?
Cómo corrijo que solo al presionar una vez el botón el pic haga lo que debe?

Alguna idea, sugerencia, comentario...?

Como todavía no he podido solventar este problema, tengo unos días leyendo sobre HID y sobre el modo BULK usando mpusbapi.dll, ambos me gusta, me inclino mas por el HID solo, sin tener que instalar nada, lo difícil viene en la parte del software, pero con unos ejemplos que encontré, plus los ejemplos que publicó el amigo moyano, he estado entendiendo cada vez mas...
Sin embargo, me gustaría mucho resolver este problema, me tiene la cabeza dando vueltas.

He probado varias cosas:
-Si quito la linea while (!usb_cdc_kbhit()) {} el programa responde al presionar una sola vez el botón, pero cuando presionas otro botón no responde a nada, se queda haciendo lo que el primer botón le dijo que hiciera.

-Si cambio la instrucción y le quito la negación (!)... while (usb_cdc_kbhit()) {} hace lo mismo.

Gracias de antemano.
 
No me he podido ver bien tu código pero me parece que podrías optimizar un poco más el código de C del programa del PIC es decir hacerlo más corto limpio, la aplicacion en VB ya la revise y no te tendría que hacer problema.

Es un problema me parece en la forma de programación que tenés en el PIC. Si tuviera más tiempo te escribiría una posible solución pero el tiempo es algo de lo caresco.
 
No hay problema moyano. Gracias por darle un vistazo. :)

Aunque ya estaba realizando tu sugerencia, estoy optimizando el código, más para depurar bien lo que hace. (Y a la par voy desarrollando el mismo programa pero en HID ).

Algo que si descubrí, es que cuando transmitimos usando COM virtual, la transmisión serial no es como la tradicional, no se envían bit a bit los datos y al final un ACK, en este caso, se envía un paquete y en él los bits agrupados en bytes. Así que muchos conceptos en la transmisión serial tradicional no se cumplen en este tipo de transmisión. Esto incluye también la velocidad, no esta regida por los limites RS-232, sino por el limite USB.

Por lo que he descubierto hasta ahora, cuando se programa usando el COM virtual, el CCS usa varios endpoints, todavía no he descubierto por cual endpoint transmite los datos y para que usa los demás.

Le pedí a unos amigos que realizaran lo mismo, programaran usando el CCS y la clase CDC usando sus respectivos estilos de programación, les funciona correctamente si declaran usb_init(), pero cuando quieren realizar otros procesos que deben usar usb_init_cs(), tienen diferentes problemas en la recepción. ...

Por ahora sigo en la investigación.

Siguen siendo bienvenidos cualquier idea, sugerencia, o comentario...
 
hola, esta bueno tu proyecto, yo tambien tengo ese mismo problema, cuando uso la comunicacion serie desde el CCS pasa lo mismo, pero como es un trabajo para la escuela y no quiero perder tiempo simplemente puse la opcion 2 veces, jajajaja esta mal pero pues bueno, es eso o reprobar.

MSComm1.Output = "d"
MSComm1.Output = "d"

aunque se que esta mal pero pues ni modo todavia estoy buscando una manera de hacerlo bien.

Saludos
 
Hola a tod@s;

Estoy programando un 18f4550 para el control de motor pap bipolar, con el problema que no puedo programarlo como dispositivo CDC, he instalado el bootloader con el pickit2 y una vez instalados los driver de Microchip me detecta el dispositivo pero como HID. He probado a cambiar el controlador, haciendo de nuevo los driver con el programa de "INF Enumeración Datos uC PIC-USB", pero no he tenido suerte.

¿Alguien conoce otra forma de hacerlo?

Muchas gracias.
 
Atrás
Arriba