Estructuras en Arduino C++

Objetivos

<  

  • Presentar el concepto de las estructuras C++.
  • Mostrar  la instrucción struct.
  • Ver unos ejemplos sencillos.
  •  

    Material requerido.

    Imagen de Arduino UNO

     Arduino UNO o equivalente.

     

    Estructuras

     

    Uno de los objetivos declarados de esta humilde pagina es ayudar, a quienes lo deseen, a aprender a programar . En esa linea hemos ido viendo pequeños ejemplos de como utilizar las instrucciones y variables de C para ir creando esos pequeños (O mayores) programa que dan vida a nuestros proyectos en Arduino.

    Siguiendo con las posibilidades del lenguaje C, se nos había quedado por el camino una instrucción importante como son las estructuras, y que resultan de la mayor importancia a medida que nuestros programas van ganando complejidad.

    El objetivo de esta sesión es corregir tan flagrante omisión, primero por su importancia intrínseca y segundo porque con esta sesión vamos a cerrar el ciclo de instrucciones que vienen de C para poder pasar en próximas sesiones ya, a la parte de C++ y la programación orientada a objetos (OOP).

    Como iremos viendo, C++ es un superset de C que se desarrolló con esta idea en mente de de incorporar la OOP , a uno de los lenguajes de mas éxito de la historia, y con la intención expresa de conservar en la medida de lo posible la sintaxis original de C.

    En este sentido, las sintaxis de las clases y métodos de C++ para OOP, descienden y aumentan muchas de las propiedades de las struct de C, por lo que su descripción es de la mayor importancia para poder enfilar la programación orientada a objetos en C++.

    A estas alturas de la película los habituales de estas paginas, estáis acostumbrados a la idea de usar variables para resolver algoritmos. Los tipos normales como int,long, char o string están incluidos en el propio C y dan buen juego, pero antes o después nos encontraremos con problemas en los que necesitamos algo un poco mas sofisticado.

    Por ejemplo, supón que necesitamos escribir un programa general que sepa qué modelo de Arduino estamos usando en un proyecto concreto, y de ese modo utilizar unos pines u otros.

    Seria interesante definir una variable que identificara tal modelo, pero si usamos una simple cadena de texto para el nombre, no incluye que pines hay disponibles o a que voltaje funciona. Es un caso en el que seria interesante disponer de mas información que el nombre del modelo. Nos gustaría tener también otras características interesantes como:

    Modelo Nombre

    npd Numero de pines digitales

    npa Numero de pines analogicos

    volt Tension de funcionamiento

    Es decir, necesitamos definir un conjunto de variables que representen una estructura conceptual mas compleja que una simple variable, y con la que podamos aumentar el nivel de abstracción en el que definimos nuestro programa. Y mira por donde, para eso es exactamente, para lo que C define la instrucción struct.

    struct Arduino
       {  string modelo ; // Nombre del modelo
          int npd ;       // Numero de pines digitales
          int npa ;       // Numero de pines analogicos
          float volt ;    // Tension de funcionamiento
       } ;

    La instrucción anterior declara una variable de tipo struct llamada Arduino, que esta compuesta por 4 variables de diferentes tipos que podemos usar como un conjunto único, del mismo modo que usamos cualquier otro tipo de variable, solo que este tipo es compuesto. Elegante ¿No?

  • Fijaros que la declaración acaba con un “;” al final de las llaves. Es una declaración y por tanto es imprescindible. Olvidar el ; es un error fulminate del compilador.
  •  

    Las instrucciones anteriores han declarado una tipo llamado Arduino, pero no hemos definido ninguna variable de este tipo aun. Para hacerlo:

    Arduino UNO_R3;

    Es decir, creamos una variable de tipo Arduino llamada UNO_R3.

  • Esto es importante y ocurre lo mismo con las variables. Una cosa es declarar una variable ( Como int i ) y otra cosa distinta definirla ( i = 0) y lo mismo ocurre con las struct.
  •  

    La primera parte declara como será el tipo Arduino pero aun no existe ninguna variable de ese tipo ( O sea, el compilador no asigna memoria) y la segunda instrucción crea una variable tipo Arduino llamada UNO_R3 (Ahora si que el compilador se pone las pilas y asigna el espacio necesario para representar UNO_R3).

    A cada una de las variables internas se les llama variables miembros de la estructura, o miembros para los amigos y al igual que con variables podemos definir y asignar directamente los valores internos de una struct, casi como cualquier otra variable

     

    Accediendo a los miembros de una estructuras

     

    Podemos asignar valores a la estructura como si fueran variables normales, mediante el operador ‘.’

    Arduino UNO_R3 ;
    UNO_R3.modelo = "uno" ;
    UNO_R3.npd = 13 ;
    UNO_R3.npa = 5 ;
    UNO_R3.volt = 5.0F ;

    Y podemos leer sus valores de la misma manera

    int numpd = UNO_R3.npd ;
    float voltage = UNO_R3.volt ;

    Veamos un pequeño programa completo con todo esto:

    struct Arduino
       {   String modelo ; // Nombre del modelo
           int npd ;       // Numero de pines digitales
           int npa ;       // Numero de pines analogicos
           float volt ;    //Tension de funcionamiento
       } ;
    
    void setup()
       { Serial.begin( 115200);
       }
    
    void loop()
       { Arduino UNO_R3 ;
         UNO_R3.modelo = "uno" ;
         UNO_R3.npd = 13 ;
         UNO_R3.npa = 5 ;
         UNO_R3.volt = 5.0F ;
         
         Serial.println(UNO_R3.npd) ;
         Serial.println(UNO_R3.modelo ) ;
         Serial.flush() ; exit(0) ;
       }

    Deberíais ver algo así:

    Salida de programa
    Y si, se parece mucho a la forma en como accedemos a las clases de C++ (Que casualidad). A riesgo de ponerme pesado, recordad que no podéis hacer esto:

     Arduino.npd = 13 ;

    Porque Arduino es un tipo como int y no una instancia que contiene los valores. Esta es UNO_R3. También podemos hacer algo asi:

    DUERMILANOVA = UNO_R3 ; // Asignamos los valores de una a la otra

    Veamos un ejemplo:

    struct Arduino 
         { String modelo ; // Nombre del modelo
           int npd ;       // Numero de pines digitales
           int npa ;       // Numero de pines analogicos
           float volt ;    //Tension de funcionamiento
         } ;
    
    void setup() 
       { Serial.begin( 115200);
       }
    
    void loop() 
       { Arduino UNO_R3 ;
         Arduino DUERMILANOVA ;
         UNO_R3.modelo = "uno" ;
         UNO_R3.npd = 13 ;
         UNO_R3.npa = 5 ;
         UNO_R3.volt = 5.0F ;
    
         Serial.println(UNO_R3.npd) ;
         Serial.println(UNO_R3.modelo ) ;
         DUERMILANOVA = UNO_R3 ;
    
         DUERMILANOVA.modelo = "duermilanova" ;
         Serial.println(DUERMILANOVA.npd) ;
         Serial.println(DUERMILANOVA.modelo ) ;
         Serial.flush() ; exit(0) ;
       }

    El resultado sería algo así:

    Muestra el resultado del programaPodemos asignar una struct a otra mediante el operador asignación, pero mucho cuidado porque no podemos hacer esto:

    if ( UNO_R3 == DUERMILANOVA )

    Porque nos levantará un ladrido fulminante del compilador. El operador = esta definido para el tipo struct, pero no el operador == . Y tampoco nos permite usar el operador + , por el mismo motivo :

     DUE = UNO_R3 + DUERMILANOVA ;  // Esto es un error instantaneo

    Mas adelante veremos que esto puede cambiarse redefiniendo el operador mediante la propiedad de operator overloading.

     

    Estructuras dentro de estructuras

     

    Como las cosas no son nunca sencillas ( y además, nos gusta enmarañar),  los problemas tienden a complicarse con rapidez,  y a veces nos puede interesar definir una struct cuyos miembros sean parcial o totalmente otras estructuras.

    Imaginate que queremos hacer el proyecto del blinking LED y que queremos por cualquier razón estúpida, definirlo mediante estructuras. Podríamos hacer algo como esto:

    struct Arduino
         { String modelo ;    // Nombre del modelo
           int npd ;          // Numero de pines digitales
           int npa ;          // Numero de pines analogicos
           float volt ;       //Tension de funcionamiento
         } ;
    
    struct Resistencia
         { long R ;           // Valor en ohmios de la resitencia
           int W ;            // Valor de la potencia aceptable en watios
         } ;
    
    struct LED
         { String color ;     // Color de la luz
           int caida ;        // Caida tipica de tension en milivoltios
         } ;

    Y una vez definidas las struct que corresponden a los componentes, podemos definir el proyecto asi:

    struct Proyecto
         { Arduino Ard ;
           Resistencia Res ;
           LED led ;
         } ;

    La idea es que los miembros de una struct pueden a su vez ser también otras struct , y para acceder a los miembros:

    void setup() 
       { Serial.begin(115200);
       }
    
    void loop() 
       {    Proyecto Pro1 ;
            Pro1.Ard.modelo = "UNO_R3" ;
            Pro1.Res.R = 330 ;
            Pro1.led.color="Rojo" ;
            Serial.println( Pro1.Ard.modelo) ;
            Serial.println( Pro1.Res.R ) ;
            Serial.println(Pro1.led.color) ;
            Serial.flush() ; exit (0) ;
       }

    El resultado seria, naturalmente, este :

    Muestra el resultado del programa

    C++ acepta tranquilamente esta especie de recursión de declaraciones y en principio no tiene un limite claro, de hasta cuantos niveles se puede hacer esto, porque seguro de que nos vamos a perder nosotros mucho antes antes de eso.

     

    Algunos comentarios finales

     

    Las estructuras de C son un elemento muy utilizado en la época de antes de la OOP y las clases, porque de algún modo nos permitía programar con mayor nivel de abstracción y las encontrareis muy a menudo en programas y librerías.

    Cuando se impone C++ , de algun modo las struct han sido sustituidas por las clases (Aunque siguen siendo muy útiles en mas de una ocasión) y su uso se ha reducido en beneficio de la OOP que nos ofrece herramientas mas potentes para realizar la misma función, pero sigue siendo necesario que las conozcáis, porque os irán apareciendo en muchos programas que veáis en Internet.

    Conviene decir que la sintaxis que he usado aquí ha sido la de C++, que simplifica un poco la definición de las struct y que no son necesariamente iguales en C.

    También tengo que reconocer que no me he extendido demasiado en las struct, porque no quiero desviaros de la OOP que comenzaremos en las sesiones próximas. Pero de algun modo, la sintaxis y los conceptos de la OOP se apoyan en la definición de las struct y por eso no he querido pasarlas por alto, porque iremos viendo que comparten conceptos, aunque el método de programar sea muy distinto.

    Así que animo, que pronto nos meteremos con la programación orientada a objetos o OOP.

     

    Resumen de la sesión

     

  • Hemos presentado las struct de C++.
  • Hemos visto como operar con ellas, su sintaxis y como acceder a sus mienmbros.
  • Presentamos algún pequeño ejemplo de uso.
  •  

    Deja una respuesta