domingo, 16 de septiembre de 2018

Las funciones básicas; void setup y void loop

Las funciones básicas
En la publicación anterior hemos visto que el sketch se diferencia en varias zonas, de hecho tiene dos que son de obligado cumplimiento; la funcion void setup() y la funcion void loop.
En la publicación anterior hemos visto que las variables se declaran al principio de todo, esto no es obligatorio ya que las variables pueden ser declaradas tanto dentro de void setup() como dentro del void loop() aunque esto si que va tener repercusiones desde el punto de vista del "Ambito". El ámbito ó alcance de una variable determina en que parte del programa ésta podrá ser empleada, así si declaramos una variable antes del void setup() ésta sera visible desde todo el programa, mientras que si declaramos una variable en el void setup() ésta solo sera visible dentro de esta función y no podremos hacer uso de ella en el void loop.
Por otro lado cuando conectamos nuestra Arduino a la corriente (que ésta la puede tomar tanto por cable serial/USB como por la conexión de fuente externa) el programa se ejecuta de manera lineal desde la primera linea hasta la última.
Al llegar al void loop() la ejecución cambiará su comportamiento y leerá ciclicamente todo el código existente en el void loop() de manera indeterminada a no ser que el propio código se lo impida.
Para poder manejar a nuestra antojo el flujo del programa el lenguaje de Arduino posee varias herramientas (de uso universal) como son los bucles y las condicionales.
Otro modo habitual de desviar el flujo, es a través de llamadas a funciones, cuando se llama a una de estas funciones el flujo se deriva a ésta, ejecuta todo su código y continua ejecutándose donde lo había dejado.
Aquí os dejo una imagen que ilustra el flujo del programa anterior.




Y su código correspondiente:


  // -------------------DECLARACION DE VARIABLES
byte b; 
int i;
long l;
float f;
double d;
boolean bol;
char ch;
String st;
int ctrl;
// -------------------INICIALIACION DE VARIABLES
void setup() { 
  Serial.begin(9600);
  b= 255;
  i= 65767;
  l= 2345678;
  f= 1.23;
  d= 1.2345;
  bol= true;
  ch= 'c';
  st= "cadena";
}
// -----------------------------------------------------------------PROGRAMA PRINCIPAL
void loop() { 
  controldeflujo(); // LLAMAMOS A LA FUNCION controldeflujo()
  Serial.println(b); // IMPRIME POR CONSOLA EL VALOR DE b SEGUIDO DE UN SALTO DE LINEA
  Serial.println(i); // IMPRIME POR CONSOLA EL VALOR DE i SEGUIDO DE UN SALTO DE LINEA
  Serial.println(l); // IMPRIME POR CONSOLA EL VALOR DE l SEGUIDO DE UN SALTO DE LINEA
  Serial.println(f); // IMPRIME POR CONSOLA EL VALOR DE f SEGUIDO DE UN SALTO DE LINEA
  Serial.println(d); // IMPRIME POR CONSOLA EL VALOR DE d SEGUIDO DE UN SALTO DE LINEA
  Serial.println(bol); // IMPRIME POR CONSOLA EL VALOR DE bol SEGUIDO DE UN SALTO DE LINEA
  Serial.println(ch); // IMPRIME POR CONSOLA EL VALOR DE ch SEGUIDO DE UN SALTO DE LINEA
  Serial.println(st); // IMPRIME POR CONSOLA EL VALOR DE st SEGUIDO DE UN SALTO DE LINEA
  Serial.println(); // IMPRIME POR CONSOLA UN SALTO DE LINEA
  ctrl++; // Esto es lo mismo que ctrl=ctrl+1; // SUMA UN VALOR A ctrl
}

//------------------------------------------------------------ FUNCIONES DEL PROGRAMA PRINCIAL
void controldeflujo(){
  Serial.println(ctrl); // IMPRIME POR CONSOLA EL VALOR DE ctrl. 
}

domingo, 2 de septiembre de 2018

Control de flujo; Condicional "if". Código ASCII

Condicional If
A continuación vamos a introducirnos con el condicional if, el sketch que acompaña esta publicación es un tanto particular, con él obtenemos por consola la tabla ASCII con su valor decimal, hexadecimal, octal y su valor char, a este programa yo le llamo "Utilidad" y así lo tengo guardado en su correspondiente carpeta.
El código ASCII es interesante tenerlo siempre a mano. Las particularidades de este scketch son dos, la primera es que vamos a controlar el flujo a través de un condicional IF, bueno en realidad hay que saber que la función void loop() va a seguir ejecutándose lo que hacemos es imprimir por pantalla UNA sola vez lo que nos interesa. (Lineas 33 y 58)
Y la otra particularidad está en la función write() que utilizamos en este caso para que nos haga un casting del valor decimal al valor de su Char correspondiente. (Linea 53) Como los valores Char no son todos imprimibles he tenido que auxiliarlo con un array de Strings, que imprime en su caso la actuación que lleva a cabo.
Nótese que la cabecera se imprime desde el void setup() que como ya sabemos solo se ejecutará una vez. También hay que fijarse en los nuevos parámetros que la función print() reconoce DEC, HEX, OCT y BIN, la función convierte o hace una especie de casting; coge el valor del primer parámetro, lo convierte al formato del segundo parámetro e imprime el resultado.

Aquí debajo os dejo una captura del resultado por consola:

Y a continuación el código:

  int i, x; // las variables declaradas aqui tienen un alcance global y seran reconocidas tanto por el void setup como por el void loop
// las variables anteriores NO se han inicializado, al hacer esto la variable toma su valor inicial por defecto, que es cero.

// declaramos un array de tipo String (que contendra cadenas de caracteres) llamada noImpr y que tendra 33 elementos
String noImpr[33]= {"[NULL],Caracter Nulo", "[SQH],Inicio Cabecera", "[STX],Inicio Texto", "[ETX],Fin texto", "[EOT],Fin Transmison", 
"[ENQ],Identificacion", "[ACK],Acuse recibo",
"[BEL],Timbre", "[BS],Retroceso", "[HT],Tab. horizontal", "[LF],Nueva Linea", "[VT],Tab. vertical", "[FF],Nueva Pagina", "[CR],Retorno carro", 
"[SO],Desplaza afuera", "[SI],Desplaza adentro", "[DLE],Esc. vinculo datos", "[DC1],Control disp.1", "[DC2],Control disp.2", 
"[DC3],Control disp.3", "[DC4],Control disp.4", "[NAK],Conf. negativa", "[SYN],Inactividad sincr.", "[ETB],Fin bloque trans.", "[CAN],Cancelar",
"[EM],Fin del Medio", "[SUB],Sustitucion", "[ESC],Escape", "[FS],Separacion arch.", "[GS],Separacion grupos", "[RS],Separacion registros", 
"[US],Separacion Unid.", "[ ],Espacio en blanco"
};

void setup() {

  Serial.begin(9600); // abre el puerto serie a 9600 bps para mostrar los resultados por consola 

  // imprime la cabecera
  Serial.print("DEC\t"); // imprime la cabecera DEC y tabula por \t
  Serial.print("HEX\t"); // imprime la cabecera HEX y tabula por \t
  Serial.print("OCT\t"); // imprime la cabecera OCT y tabula por \t
  Serial.print("BIN\t"); // imprime la cabecera BIN y tabula por \t
  Serial.print("Char\n");// imprime la cabecera Char y hace salto de linea por \n
}

void loop() {

  if (x < 128){ // Cuando x sea igual o mayor a 128 dejara de entrar en este condicional
    // imprime la salida en varios formatos:
    Serial.print(i, DEC); // imprime como un ASCII-codificado decimal
    Serial.print("\t"); // imprime un tab

    Serial.print(i, HEX); //imprime como un ASCII-codificado hexadecimal
    Serial.print("\t"); // imprime un tab

    Serial.print(i, OCT); // imprime como un ASCII-codificado octal
    Serial.print("\t"); // imprime un tab

    Serial.print(i, BIN); // imprime como un ASCII-codificado binario
    Serial.print("\t"); // imprime un tab

    if(i==127){Serial.print("[DEL],Suprimir");} // imprime el valor indicado, si i es igual a 127
    if(i<33){ // si i es inferior a 33 entra aqui
      Serial.println(noImpr[i]); // Toma la cadena del array noImpr
    } else { // si i NO es inferior a 33 entra aqui
       Serial.write(i); // imprime el valor char de ASCII
       Serial.println(); // imprime un salto de linea
      } 

    i++; // suma un valor a i
    x++; // suma un valor a x
  } // cierra el condicional de x
} // Cierra void loop

Por cierto, el código ASCII se diferencia en tres grupos; 1- Los no imprimibles (éstos son los que he incluido en el array noImpr[], para que sepais lo que hace) 2- Los imprimibles (son los que si se imprimen) y 3 - ASCII extendido; si deseas emplear algún "simbolito extraño" basta que cambies la linea 33: 'x < 128' por 'x < 256'