Autor Tema: Ayuda con el uso de estructuras y su declaración  (Leído 4314 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado vra

  • PIC10
  • *
  • Mensajes: 27
Ayuda con el uso de estructuras y su declaración
« en: 17 de Diciembre de 2019, 15:59:41 »
Hola a todos, estoy escribiendo un programa para PIC24 y estoy viendo a través de las referencias y códigos de microchip que cuando declaro una estructura debo hacer lo siguiente (esa parte es de mi propio código):

Código: [Seleccionar]
volatile unsigned int BANDERAS;         /* Variable tipo estructura para      */
typedef struct tagBANDERASBits          /* marcar eventos de interrupciones en*/
{                                       /* las interrupciones.                */
    unsigned int :15;
    unsigned int tecla:1;               /* Bandera para indicar el uso de la
                                         * interrupción por notificación de
                                         * cambio en un pin.                  */
} BANDERASBits;

lo que no se es por cuál razón debo usar el prefijo "tag" en el nombre de la estructura cuando la defino.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Ayuda con el uso de estructuras y su declaración
« Respuesta #1 en: 17 de Diciembre de 2019, 21:03:56 »
Es que en realidad ahi estas creando 3 cosas distintas.

El primero es un entero sin signo llamado BANDERAS.
El segundo es un struct llamado tagBANDERASBits (es el nombre de la DEFINICION de estructura) y que dice como esta conformado. Formado por esta parte del codigo:

Código: C
  1. struct tagBANDERASBits          /* marcar eventos de interrupciones en*/
  2. {                                       /* las interrupciones.                */
  3.     unsigned int :15;
  4.     unsigned int tecla:1;               /* Bandera para indicar el uso de la
  5.                                          * interrupción por notificación de
  6.                                          * cambio en un pin.                  */
  7. }

Luego tenes el typedef que "convierte" el struct tagBANDERASBits en BANDERASBits

Es decir TU codigo y este que voy a poner son equivalentes:

Código: C
  1. volatile unsigned int BANDERAS;
  2.  
  3. struct tagBANDERASBits {                                      
  4.     unsigned int :15;
  5.     unsigned int tecla:1;}
  6.  
  7. typedef struct tagBANDERASBits BANDERASBits;


Uno usa el typedef para luego resumir la definición de la variable:

Código: C
  1. // Con typedef
  2. BANDERASBits my_struct;
  3.  
  4. // Sin typedef
  5. struct tagBANDERASBits my_struct;

Desconectado vra

  • PIC10
  • *
  • Mensajes: 27
Re:Ayuda con el uso de estructuras y su declaración
« Respuesta #2 en: 18 de Diciembre de 2019, 18:29:47 »
Es que en realidad ahi estas creando 3 cosas distintas.

El primero es un entero sin signo llamado BANDERAS.
El segundo es un struct llamado tagBANDERASBits (es el nombre de la DEFINICION de estructura) y que dice como esta conformado. Formado por esta parte del codigo:

Código: C
  1. struct tagBANDERASBits          /* marcar eventos de interrupciones en*/
  2. {                                       /* las interrupciones.                */
  3.     unsigned int :15;
  4.     unsigned int tecla:1;               /* Bandera para indicar el uso de la
  5.                                          * interrupción por notificación de
  6.                                          * cambio en un pin.                  */
  7. }

Luego tenes el typedef que "convierte" el struct tagBANDERASBits en BANDERASBits

Es decir TU codigo y este que voy a poner son equivalentes:

Código: C
  1. volatile unsigned int BANDERAS;
  2.  
  3. struct tagBANDERASBits {                                      
  4.     unsigned int :15;
  5.     unsigned int tecla:1;}
  6.  
  7. typedef struct tagBANDERASBits BANDERASBits;


Uno usa el typedef para luego resumir la definición de la variable:

Código: C
  1. // Con typedef
  2. BANDERASBits my_struct;
  3.  
  4. // Sin typedef
  5. struct tagBANDERASBits my_struct;

Gracias por la aclaratoria @KILLERJC, entiendo que la primera línea es una definición de un entero que no debe ser optimizado por el compilador según la palabra "volatile" pero esa forma de definir el dato la vi en los archivos de cabecera de microchip.

En el caso inicial de mi pregunta el entero de la primera línea es una variable externa (el puerto D por ejemplo), y la estructura lo que contiene es los bits de ese puerto, lo que no entiendo es por cuál razón ellos la definen de esa manera, si bien se sabe que los campos de bits de la estructura son los bits de la variable externa no se por cuál razón ellos hacen eso para finalmente redefinir la variable creada en la estructura de PORTDBITS a PORTDBits. A continuación el código del archivo de cabecera:

Código: [Seleccionar]
extern volatile uint16_t  PORTD __attribute__((__sfr__));
typedef struct tagPORTDBITS {
  uint16_t RD0:1;
  uint16_t RD1:1;
  uint16_t RD2:1;
  uint16_t RD3:1;
  uint16_t RD4:1;
  uint16_t RD5:1;
  uint16_t RD6:1;
  uint16_t RD7:1;
  uint16_t RD8:1;
  uint16_t RD9:1;
  uint16_t RD10:1;
  uint16_t RD11:1;
} PORTDBITS;
extern volatile PORTDBITS PORTDbits __attribute__((__sfr__));

el código anterior no lo entiendo y en ese caso, si yo quisiera hacer algo parecido con mi variable y mi estructura, tendría que crear la variable entera como un puntero y luego crear mi variable tipo estructura referenciándola a mi variable entera tipo puntero mediante su dirección?, algo así como lo siguiente:

Código: [Seleccionar]
volatile unsigned int *BANDERAS;         /* Variable tipo estructura para      */
typedef struct tagBANDERASBits          /* marcar eventos de interrupciones en*/
{                                       /* las interrupciones.                */
    unsigned int :15;
    unsigned int tecla:1;               /* Bandera para indicar el uso de la
                                         * interrupción por notificación de
                                         * cambio en un pin.                  */
} &BANDERASBits;

Gracias de antemano nuevamente por la ayuda brindada.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Ayuda con el uso de estructuras y su declaración
« Respuesta #3 en: 18 de Diciembre de 2019, 19:14:54 »
Comprendo ahora que estas intentando hacer.. Pero para lo que vos buscas hacer es mejor usar una union.

Cada compilador tiene su forma que no es estandar ni pertenece a C de definir algunas cosas, como es el caso de los registros en XC8 y luego tenemos XC16 que es mas parecido a gcc. Voy a copiar de forma completa la definicion de un puerto en XC8, el de  XC16 ya lo pasaste, asi que lo voy a explicar nomas.

XC8:
Código: C
  1. // Register: PORTC
  2. #define PORTC PORTC
  3. extern volatile unsigned char           PORTC               @ 0x007;
  4. #ifndef _LIB_BUILD
  5. asm("PORTC equ 07h");
  6. #endif
  7. // bitfield definitions
  8. typedef union {
  9.     struct {
  10.         unsigned RC0                    :1;
  11.         unsigned RC1                    :1;
  12.         unsigned RC2                    :1;
  13.         unsigned RC3                    :1;
  14.         unsigned RC4                    :1;
  15.         unsigned RC5                    :1;
  16.         unsigned RC6                    :1;
  17.         unsigned RC7                    :1;
  18.     };
  19. } PORTCbits_t;
  20. extern volatile PORTCbits_t PORTCbits @ 0x007;

De aca tenes que observar 2 cosas.... el @ 0x007, que es la direccion de memoria que ocupa el registro PORTC.
Y la otra es que se definen 2 cosas en la misma direccion , uno que es el PORTC, y otro que es la estructura que es PORTCbits, por eso acceden a lo mismo.

En cambio XC16 pertenece o es un GCC modificado por Microchip.. El cual podes hacer uso de los atributos:

https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Function-Attributes.html

Observaras en la lista que no existe ningun atributo __sfr__ , y que es especial de Microchip.
Esto hace muy parecido a lo visto con XC8 y lo maneja de forma interna el compilador (realizado unicamente para sus registros). Por eso lo que planteas no funcionaria....

-----------------------------------

Si podes hacerlo con una union, ejemplo:


Código: C
  1. typedef union BANDERA_t {
  2.    uint16_t completo;
  3.    struct bits_s {
  4.         uint16_t bandera:15;
  5.         uint16_t tecla:1;} bits;
  6. } BANDERA_t;

En tu main:

Código: C
  1. BANDERA_t BANDERAS;
  2.     while(1){
  3.    
  4.  
  5.         BANDERAS.completo = 0x0AA0; // Con esto accedo a los 16 bits
  6.         BANDERAS.bits.tecla = 1; // Con esto accedo a la parte de 1 bit
  7.         BANDERAS.bits.bandera = 12;  // Con esto accedo a los demas 15 bits
  8.     }

Tanto el completo como los bits, ocupan una sola posicion de memoria. El unico problema de los bitfields, es que es de implementacion especifica de cada compilador el orden de los mismos. Por ejemplo, en la simulacion puedo observar que el bit de tecla es el de mayor peso. Pero que en otro compilador (por si deseas usar el mismo codigo en otro lado) podria no ser asi. Asi que necesitas tener eso en cuenta.

Si te preguntas , uint16_t significa entero sin signo de 16 bits y esta definido en stdint.h el cual necesitas agregar si queres usar esas definiciones, sino reemplazalo por tu unsigned int.

Desconectado vra

  • PIC10
  • *
  • Mensajes: 27
Re:Ayuda con el uso de estructuras y su declaración
« Respuesta #4 en: 22 de Diciembre de 2019, 17:18:20 »
Comprendo ahora que estas intentando hacer.. Pero para lo que vos buscas hacer es mejor usar una union.

Cada compilador tiene su forma que no es estandar ni pertenece a C de definir algunas cosas, como es el caso de los registros en XC8 y luego tenemos XC16 que es mas parecido a gcc. Voy a copiar de forma completa la definicion de un puerto en XC8, el de  XC16 ya lo pasaste, asi que lo voy a explicar nomas.

XC8:
Código: C
  1. // Register: PORTC
  2. #define PORTC PORTC
  3. extern volatile unsigned char           PORTC               @ 0x007;
  4. #ifndef _LIB_BUILD
  5. asm("PORTC equ 07h");
  6. #endif
  7. // bitfield definitions
  8. typedef union {
  9.     struct {
  10.         unsigned RC0                    :1;
  11.         unsigned RC1                    :1;
  12.         unsigned RC2                    :1;
  13.         unsigned RC3                    :1;
  14.         unsigned RC4                    :1;
  15.         unsigned RC5                    :1;
  16.         unsigned RC6                    :1;
  17.         unsigned RC7                    :1;
  18.     };
  19. } PORTCbits_t;
  20. extern volatile PORTCbits_t PORTCbits @ 0x007;

De aca tenes que observar 2 cosas.... el @ 0x007, que es la direccion de memoria que ocupa el registro PORTC.
Y la otra es que se definen 2 cosas en la misma direccion , uno que es el PORTC, y otro que es la estructura que es PORTCbits, por eso acceden a lo mismo.

En cambio XC16 pertenece o es un GCC modificado por Microchip.. El cual podes hacer uso de los atributos:

https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Function-Attributes.html

Observaras en la lista que no existe ningun atributo __sfr__ , y que es especial de Microchip.
Esto hace muy parecido a lo visto con XC8 y lo maneja de forma interna el compilador (realizado unicamente para sus registros). Por eso lo que planteas no funcionaria....

-----------------------------------

Si podes hacerlo con una union, ejemplo:


Código: C
  1. typedef union BANDERA_t {
  2.    uint16_t completo;
  3.    struct bits_s {
  4.         uint16_t bandera:15;
  5.         uint16_t tecla:1;} bits;
  6. } BANDERA_t;

En tu main:

Código: C
  1. BANDERA_t BANDERAS;
  2.     while(1){
  3.    
  4.  
  5.         BANDERAS.completo = 0x0AA0; // Con esto accedo a los 16 bits
  6.         BANDERAS.bits.tecla = 1; // Con esto accedo a la parte de 1 bit
  7.         BANDERAS.bits.bandera = 12;  // Con esto accedo a los demas 15 bits
  8.     }

Tanto el completo como los bits, ocupan una sola posicion de memoria. El unico problema de los bitfields, es que es de implementacion especifica de cada compilador el orden de los mismos. Por ejemplo, en la simulacion puedo observar que el bit de tecla es el de mayor peso. Pero que en otro compilador (por si deseas usar el mismo codigo en otro lado) podria no ser asi. Asi que necesitas tener eso en cuenta.

Si te preguntas , uint16_t significa entero sin signo de 16 bits y esta definido en stdint.h el cual necesitas agregar si queres usar esas definiciones, sino reemplazalo por tu unsigned int.

Muchas gracias @KILLERJC, ahora tengo todo mucho más claro.

Desconectado vra

  • PIC10
  • *
  • Mensajes: 27
Re:Ayuda con el uso de estructuras y su declaración
« Respuesta #5 en: 22 de Diciembre de 2019, 19:06:47 »
Comprendo ahora que estas intentando hacer.. Pero para lo que vos buscas hacer es mejor usar una union.

Cada compilador tiene su forma que no es estandar ni pertenece a C de definir algunas cosas, como es el caso de los registros en XC8 y luego tenemos XC16 que es mas parecido a gcc. Voy a copiar de forma completa la definicion de un puerto en XC8, el de  XC16 ya lo pasaste, asi que lo voy a explicar nomas.

XC8:
Código: C
  1. // Register: PORTC
  2. #define PORTC PORTC
  3. extern volatile unsigned char           PORTC               @ 0x007;
  4. #ifndef _LIB_BUILD
  5. asm("PORTC equ 07h");
  6. #endif
  7. // bitfield definitions
  8. typedef union {
  9.     struct {
  10.         unsigned RC0                    :1;
  11.         unsigned RC1                    :1;
  12.         unsigned RC2                    :1;
  13.         unsigned RC3                    :1;
  14.         unsigned RC4                    :1;
  15.         unsigned RC5                    :1;
  16.         unsigned RC6                    :1;
  17.         unsigned RC7                    :1;
  18.     };
  19. } PORTCbits_t;
  20. extern volatile PORTCbits_t PORTCbits @ 0x007;

De aca tenes que observar 2 cosas.... el @ 0x007, que es la direccion de memoria que ocupa el registro PORTC.
Y la otra es que se definen 2 cosas en la misma direccion , uno que es el PORTC, y otro que es la estructura que es PORTCbits, por eso acceden a lo mismo.

En cambio XC16 pertenece o es un GCC modificado por Microchip.. El cual podes hacer uso de los atributos:

https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Function-Attributes.html

Observaras en la lista que no existe ningun atributo __sfr__ , y que es especial de Microchip.
Esto hace muy parecido a lo visto con XC8 y lo maneja de forma interna el compilador (realizado unicamente para sus registros). Por eso lo que planteas no funcionaria....

-----------------------------------

Si podes hacerlo con una union, ejemplo:


Código: C
  1. typedef union BANDERA_t {
  2.    uint16_t completo;
  3.    struct bits_s {
  4.         uint16_t bandera:15;
  5.         uint16_t tecla:1;} bits;
  6. } BANDERA_t;

En tu main:

Código: C
  1. BANDERA_t BANDERAS;
  2.     while(1){
  3.    
  4.  
  5.         BANDERAS.completo = 0x0AA0; // Con esto accedo a los 16 bits
  6.         BANDERAS.bits.tecla = 1; // Con esto accedo a la parte de 1 bit
  7.         BANDERAS.bits.bandera = 12;  // Con esto accedo a los demas 15 bits
  8.     }

Tanto el completo como los bits, ocupan una sola posicion de memoria. El unico problema de los bitfields, es que es de implementacion especifica de cada compilador el orden de los mismos. Por ejemplo, en la simulacion puedo observar que el bit de tecla es el de mayor peso. Pero que en otro compilador (por si deseas usar el mismo codigo en otro lado) podria no ser asi. Asi que necesitas tener eso en cuenta.

Si te preguntas , uint16_t significa entero sin signo de 16 bits y esta definido en stdint.h el cual necesitas agregar si queres usar esas definiciones, sino reemplazalo por tu unsigned int.

Muchas gracias @KILLERJC, ahora tengo todo mucho más claro.

Disculpa, pensé que había entendido todo pero ahora que releo veo que hay algo que no entendí: tanto en la definición de xc8 como en la de xc16 definen el puerto antes y después de la definición de la unión, ¿Por qué hacen esto?, ¿Es lo que me explicas de interno a cada compilador?.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Ayuda con el uso de estructuras y su declaración
« Respuesta #6 en: 22 de Diciembre de 2019, 19:17:50 »
Citar
tanto en la definición de xc8 como en la de xc16 definen el puerto antes y después de la definición de la unión, ¿Por qué hacen esto?, ¿Es lo que me explicas de interno a cada compilador?.

No importa el orden de la definicion.
Siempre que apunte hacia el mismo lado, que en XC8 gracias al @ y e XC16 al atributo __sfr__ lo hacen, uno de forma mas explicita que el otro , en XC8 indica la direccion, mientras que XC16 lo hace interno al compilador, es decir no ves la direccion de memoria a la que se apunta.

Pero de todas formas esto no es necesario para lo que estabas buscando hacer, y como te digo es especifico de estos compiladores. Los de otras marcas se manejan de forma distinta.
La forma que deberias hacerlo es con la union como te lo plantee. Intenta liberarte de lo que hacen los compiladores.

Desconectado vra

  • PIC10
  • *
  • Mensajes: 27
Re:Ayuda con el uso de estructuras y su declaración
« Respuesta #7 en: 25 de Diciembre de 2019, 14:47:41 »
Citar
tanto en la definición de xc8 como en la de xc16 definen el puerto antes y después de la definición de la unión, ¿Por qué hacen esto?, ¿Es lo que me explicas de interno a cada compilador?.

No importa el orden de la definicion.
Siempre que apunte hacia el mismo lado, que en XC8 gracias al @ y e XC16 al atributo __sfr__ lo hacen, uno de forma mas explicita que el otro , en XC8 indica la direccion, mientras que XC16 lo hace interno al compilador, es decir no ves la direccion de memoria a la que se apunta.

Pero de todas formas esto no es necesario para lo que estabas buscando hacer, y como te digo es especifico de estos compiladores. Los de otras marcas se manejan de forma distinta.
La forma que deberias hacerlo es con la union como te lo plantee. Intenta liberarte de lo que hacen los compiladores.

Muchas gracias @KILLERJC, han sido de gran ayuda tus comentarios.

Desconectado vra

  • PIC10
  • *
  • Mensajes: 27
Re:Ayuda con el uso de estructuras y su declaración
« Respuesta #8 en: 15 de Enero de 2020, 20:30:22 »
Feliz y próspero año 2020 para todos, disculpa la pregunta @KILLERJC pero tengo otra duda, después de aplicar tus consejos y escribir la definición como sigue en mi archivo llamado "globales.h":

Código: [Seleccionar]
typedef union                           /* Variable tipo estructura para      */
{                                       /* marcar eventos de interrupciones en*/
    unsigned int Banderas;              /* marcar eventos de interrupciones en*/
    struct                              /* las interrupciones.                */
    {                                   
        unsigned int restantes:15;
        unsigned int tecla:1;           /* Bandera para indicar el uso de la
                                         * interrupción por notificación de
                                         * cambio en un pin.                  */
    } BANDERASBits;
} SENALES;

la bandera SENALES.BANDERASBits.tecla la utilizo en otro archivo llamado "interrupt.h" y por lo tanto defino la variable como sigue:

Código: [Seleccionar]
#include "globales.h"

/*            Definición de constantes a usar en las interrupciones.          */

SENALES senales;                    /* Depende de las variables definidas     */
senales.banderas = 0;               /* en globales.h.                         */

dentro del archivo "interrupt.h".

cuando compilo esto me está dando el error

[code]
interrup.h:17:16: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'senales'

Esa fila y columna del error es justo antes del ";" de la línea SENALES senales;
[/code]

he leído una y mil veces más el código a ver si encuentro el error pero no lo veo.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Ayuda con el uso de estructuras y su declaración
« Respuesta #9 en: 15 de Enero de 2020, 20:49:11 »
Dos cosas:

Estas poniendo esto en algun lugar fuera de una funcion, por lo tanto te da error. acabo de probarlo y es el mismo error que te da.
Código: C
  1. senales.banderas = 0;


Y segundo es Banderas con B mayuscula, C es case sensitive, el MPLAB te permite completarlo, al presionar el punto si no se abre enseguida (que se puede cambiar para que lo haga) podes presionar Ctrl + Barra espaciadora, y te abre las sugerencias.

Desconectado vra

  • PIC10
  • *
  • Mensajes: 27
Re:Ayuda con el uso de estructuras y su declaración
« Respuesta #10 en: 20 de Enero de 2020, 09:19:47 »
Dos cosas:

Estas poniendo esto en algun lugar fuera de una funcion, por lo tanto te da error. acabo de probarlo y es el mismo error que te da.
Código: C
  1. senales.banderas = 0;


Y segundo es Banderas con B mayuscula, C es case sensitive, el MPLAB te permite completarlo, al presionar el punto si no se abre enseguida (que se puede cambiar para que lo haga) podes presionar Ctrl + Barra espaciadora, y te abre las sugerencias.

Gracias, ya lo corregí quitando la asignación, alguien me dijo que no puedo hacer asignaciones de valores (de esa forma) en un .h.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Ayuda con el uso de estructuras y su declaración
« Respuesta #11 en: 20 de Enero de 2020, 15:32:33 »
Vos podes hacer lo que quieras, pero se intenta mantener un estandar, y es el de no incluir nada que implique "memoria" en un .h, unicamente los "prototipos" o definiciones.


 

anything