Electrónica y Programación en Personal
«Si no se soluciona con un script en Python entonces no es viable»

por Yeison Cardona el 10 de febrero del 2014 a las 6:41 am UTC

Como ya somos niños grandes debemos dejar atrás CDC y optar por USB siempre que sea posible, y es que esas es una de las ventajas de Pinguino sobre Arduino, ¡ya tenemos módulo USB integrado!, no tenemos que comprar una costosa shield que nos ocupará todos los pines.
Además, hay algunas ventajas, por ejemplo: la velocidad de conexión y sabremos exactamente a que dispositivo conectarnos.

Pinguino Pinguino 47j53A, disponible en la Tienda de Pinguino

Del lado de Pinguino

Los comandos para usar USB en Pinguino no podrían ser mas sencillos, como siempre, son:

USB.available
USB.gets
USB.printf
USB.puts
USB.read
USB.send
USB.write
O con BULK, que son exactamente los mismos anteriores pero con otros nombres en el editor.
BULK.available
BULK.gets
BULK.printf
BULK.puts
BULK.read
BULK.send
BULK.write
Junto con Pinguino IDE se distribuyen algunos ejemplos, son muy sencillos de entender y si ya se ha usado CDC, entonces les serán mucho mas familiares.

Pynguino2.0

Tal vez les sean conocidas mis intenciones con Pynguino, pues es muy simple, «Enviar comandos transparentes a Pinguino y que este los ejecute», aunque por ahora sólo hay algunos scripts y ejemplos con CDC es buen momento para agregar soporte USB (básicamente es cuestión de cambiar unas cuantas líneas y listo)
Dicho código es el siguiente, simplemente abrir con el IDE compilar y listo, Sólo para 8-bits, es decir 18F2550 y 18F4550:

//-----------------------------------------------------
//Author:  Yeison Cardona --<yeison.eng@gmail.com>
//First release: 10/Feb/2014
//Last release: 10/Feb/2014
//Description: Control de la tarjeta pinguino mediante
//comandos transparentes enviados por USB.
//-----------------------------------------------------

  
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define TotalPines 21
   
char lectura[21], *bloque;
char enviar[21]="";
int par1, valor, cont, i;

char *strtok(char *str, char *control) {
//Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
static  char * s; register char * s1; if (str)s = str; if (!s)return NULL;
while (*s) { if (strchr(control,*s))s++; else break;}
s1 = s ; while (*s) { if (strchr(control,*s)) {*s++ = '\0'; return s1 ;} s++ ;}
s = NULL;  if (*s1)return s1; else return NULL; }
   
void setup() {
 }

void leer_cadena() {
    unsigned char buffer[21];
    unsigned char receivedbyte=0;
    if(USB.available()) receivedbyte = USB.read(buffer);  
    buffer[receivedbyte] = 0;
    if (receivedbyte > 0) strcpy(lectura, buffer);
    }

    
void loop() {

leer_cadena();
strcpy(enviar, "");
cont=0;
   
if (strncmp(lectura, "pinMode", 7)==0){
 for (bloque = strtok(lectura,"("); bloque != NULL; bloque = strtok(NULL, ",") ){ 
 switch (cont){
 case 0: break;
 case 1:
  par1=atoi(bloque);
  break;
 case 2:
  if (strncmp(bloque, "INPUT", 5)==0) pinMode(par1,INPUT);
  else if (strncmp(bloque, "OUTPUT", 6)==0) pinMode(par1,OUTPUT);
  break;
 } 
 cont+=1;
 }
}
   
else if (strncmp(lectura, "digitalWrite", 12)==0){
 for (bloque = strtok(lectura,"("); bloque != NULL; bloque = strtok(NULL, ",") ){
 switch (cont){
 case 0: break;
 case 1:
  par1=atoi(bloque);
  break;
 case 2:
  if (strncmp(bloque, "HIGH", 4)==0) digitalWrite(par1,HIGH);
  else if (strncmp(bloque, "LOW", 3)==0) digitalWrite(par1,LOW);
  break;
 } 
 cont+=1;
 }
}
   
else if (strncmp(lectura, "analogWrite", 11)==0){
 for (bloque = strtok(lectura,"("); bloque != NULL; bloque = strtok(NULL, ",") ){
 switch (cont){
 case 0: break;
 case 1:
  par1=atoi(bloque);
  break;
 case 2:
  analogWrite(par1,atoi(bloque));
  break;
 } 
 cont+=1;
 }
}
   
else if (strncmp(lectura, "digitalRead", 11)==0){
 for (bloque = strtok(lectura,"("); bloque != NULL; bloque = strtok(NULL, ")") ){
 switch (cont){
 case 0: break;
 case 1:
  sprintf(enviar, "%d\n", digitalRead(atoi(bloque)));
  USB.write(enviar, strlen(enviar));
  
  break;
 } 
 cont+=1;
 }
}
   
else if (strncmp(lectura, "analogRead", 10)==0){
 for (bloque = strtok(lectura,"("); bloque != NULL; bloque = strtok(NULL, ")") ){
 switch (cont){
 case 0: break;
 case 1:
  sprintf(enviar, "%d\n", analogRead(atoi(bloque)));
  USB.write(enviar, strlen(enviar));
  break;
 } 
 cont+=1;
 }
}
  
else if (strncmp(lectura, "eepromRead", 10)==0){
 for (bloque = strtok(lectura,"("); bloque != NULL; bloque = strtok(NULL, ")") ){
 switch (cont){
 case 0: break;
 case 1:
  sprintf(enviar, "%d\n", EEPROM.read(atoi(bloque)));
  USB.write(enviar, strlen(enviar));
  break;
 } 
 cont+=1;
 }
}
  
else if (strncmp(lectura, "eepromWrite", 11)==0){
 for (bloque = strtok(lectura,"("); bloque != NULL; bloque = strtok(NULL, ",") ){
 switch (cont){
 case 0: break;
 case 1:
  par1=atoi(bloque);
  break;
 case 2:
  bloque = strtok(bloque,")");
  EEPROM.write(par1, atoi(bloque));
  break;
 } 
 cont+=1;
 }
}
  
else if (strncmp(lectura, "delay", 5)==0){
 for (bloque = strtok(lectura,"("); bloque != NULL; bloque = strtok(NULL, ")") ){
 switch (cont){
 case 0: break;
 case 1:
  delay(atoi(bloque));
  break;
 } 
 cont+=1;
 }
}
    
else if (strncmp(lectura, "delayMicroseconds", 17)==0){
 for (bloque = strtok(lectura,"("); bloque != NULL; bloque = strtok(NULL, ")") ){
 switch (cont){
 case 0: break;
 case 1:
  delayMicroseconds(atoi(bloque));
//   USB.printf("Done\n");  
//   sprintf(enviar, "%d\n", digitalRead(atoi(bloque)));
  USB.write("Done\n", 5);
  break;
 } 
 cont+=1;
 }
}
    
else if (strcmp(lectura, "allOutput")==0){
 for (i=0;i<=TotalPines;i++){
  pinMode(i,OUTPUT);
  digitalWrite(i,LOW);
 }
}
  
else if (strcmp(lectura, "allInput")==0){
 for (i=0;i<=TotalPines;i++)
  pinMode(i,INPUT);
}
  
else if (strcmp(lectura, "allHigh")==0){
 for (i=0;i<=TotalPines;i++){
  pinMode(i,OUTPUT);
  digitalWrite(i,HIGH);
 }
}
  
else if (strcmp(lectura, "allLow")==0){
 for (i=0;i<=TotalPines;i++){
  pinMode(i,OUTPUT);
  digitalWrite(i,LOW);
 }
}
    
else if (strcmp(lectura, "reset")==0)
 reset();
    
}

En Python

En Python no es tan corto como con CDC pero igual de sencillo al fin y al cabo.
Debemos de tener el módulo USB para python

sudo pip install pyusb==1.0.0b1
Hay algunos datos que debemos declarar primero que todo:
VENDOR = 0x04D8
PRODUCT = 0xFEAA

TIMEOUT = 100
INTERFACE = 0
ENDPOINT_OUT = 0x01

# if bootloader v4.x
#CONFIGURATION = 0x01
#ENDPOINT_IN = 0x81

# if bootloader v2.x
CONFIGURATION = 0x03
ENDPOINT_IN = 0x82
Muy importante configurar correctamente según el bootloader que se esté usando, como se indica en el código.

El siguiente paso sería buscar el dispositivo conectado y crear el objeto dh sobre el cual leeremos y escribiremos, así:
busses = usb.busses()

# Search pinguino between all the usb devices
for bus in busses:
    devices = bus.devices
    for dev in devices:
        if dev.idVendor==VENDOR and dev.idProduct==PRODUCT:
            pinguino = dev

# Get a device handler for the usb device
dh = pinguino.open()
dh.setConfiguration(CONFIGURATION)
dh.claimInterface(INTERFACE)
Vamos a definir unas funciones para enviar comandos y leer lo que nos retorna pinguino.
def read():
    return "".join(map(chr, dh.bulkRead (ENDPOINT_IN, 21, TIMEOUT)))
El objeto dh luego de leer nos retorna un array con los valores enteros de cada carácter, esto simplemente es para convertir estos valores en letras normales y unirlas en una sóla cadena, el 21 se refiere a la longitud de la cadena a leer, en Pinguino ya definimos que sería de este tamaño.
def write_command(command):
    dh.bulkWrite(ENDPOINT_OUT, command, TIMEOUT)
Para escribir en el dispositivo es mas sencillo, simplemente enviamos la cadena que deseamos.

BlinkLED

Ahora ya con estas instrucciones podremos interactuar con nuestro Pinguino con simples comandos, el ejemplo mas común que siempre se me ocurre es el eterno «Hola mundo» de la electrónica: hacer parpadear un LED.

write_command("pinMode(6,OUTPUT)")

while True:
    write_command("digitalWrite(6,HIGH)")
    time.sleep(0.3)
    write_command("digitalWrite(6,LOW)")
    time.sleep(0.3)
O un poco (pero apenas si un poco) mas interesante, leer una entrada análoga:
write_command("pinMode(13,INPUT)")

while True:
    write_command("analogRead(13)")
    print read()
    time.sleep(0.3)

EL código todo junto

#!/usr/bin/env python
#-*- coding: utf-8 -*-

import usb
import time

VENDOR = 0x04D8
PRODUCT = 0xFEAA

TIMEOUT = 100
INTERFACE = 0
ENDPOINT_OUT = 0x01

# if bootloader v4.x
#CONFIGURATION = 0x01
#ENDPOINT_IN = 0x81

# if bootloader v2.x
CONFIGURATION = 0x03
ENDPOINT_IN = 0x82

def read():
    return "".join(map(chr, dh.bulkRead (ENDPOINT_IN, 21, TIMEOUT)))

def write_command(command):
    dh.bulkWrite(ENDPOINT_OUT, command, TIMEOUT)

busses = usb.busses()

# Search pinguino between all the usb devices
for bus in busses:
    devices = bus.devices
    for dev in devices:
        if dev.idVendor==VENDOR and dev.idProduct==PRODUCT:
            pinguino = dev

assert pinguino

# Get a device handler for the usb device
dh = pinguino.open()
dh.setConfiguration(CONFIGURATION)
dh.claimInterface(INTERFACE)

write_command("pinMode(6,OUTPUT)")
while True:
    write_command("digitalWrite(6,HIGH)")
    time.sleep(0.3)
    write_command("digitalWrite(6,LOW)")
    time.sleep(0.3)
    
#write_command("pinMode(13,INPUT)")
#while True:
    #write_command("analogRead(13)")
    #print read()
    #time.sleep(0.3)

Conclusiones

Es mejor USB que CDC
USB nos brinda ciertas ventajas sobre CDC que deben considerarse seriamente a la hora de desarrollar interfaces, sobre todo cuando se requiere de una alta velocidad y/o cuando se están enviando muchos datos, claro la máxima velocidad siempre dependerá de otros factores como el computador y la carga sobre este (el computador no es un sistema en tiempo real).


También podría interesarte:

Añadir un comentario:
Si desean una respuesta para su comentario sólo deben agregarme en G+ y hacer una mención a Yeison Cardona, así les podré responder lo antes posible.