Autor Tema: Pasar por referencia una estructura  (Leído 3055 veces)

0 Usuarios y 3 Visitantes están viendo este tema.

Desconectado gu1llermo

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 217
Pasar por referencia una estructura
« en: 04 de Abril de 2008, 22:53:04 »
Saludos a todos, estoy tratando de pasar una estructura de datos por referencia a una función, ya tengo varios días tratando de hacer esto (hasta en assembler) pero no e tenido éxito, opté por declarar las variables globales y resolver, pero no es una forma muy elegante que se diga, es como caerle a palos pa que funcione  :? :lol:, bueno a continuación el código para ver si alguién me puede ayudar:

Código: [Seleccionar]
#include <18F4550.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN,NOPBADEN
#use delay(clock=48000000)

#USE RS232 (baud=9600,bits=8,parity=N,xmit=PIN_C6,rcv=PIN_C7)

//#build(reset=0x000800,interrupt=0x000808:0x000818)
// Necesario para indicarle al compilador a partir de donde alojar mi programa

//#ORG 0x000, 0x07FF {} // Espacio reservado para alojar el bootloader

#byte PORTA = 0xF80// Son las direcciones de memoria de los puertos en este PIC
#byte PORTB = 0xF81
#byte PORTC = 0xF82
#byte PORTD = 0xF83
#byte PORTE = 0xF84

#define  entrada1  PIN_A0
#define  entrada2  PIN_A1

#define  salida1  PIN_B0
#define  salida2  PIN_B1

#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)



typedef struct{
   long   pin;
   int8   contando;
   int8   pasaron_20ms;
} mi_LS;// mi Limit Switch

void estado_pin(int16);//

void main(void) {

   mi_LS ls_art_1, ls_art_2;
   int16 * ls1, * ls2;
   
   *ls1=ls_art_1;
   *ls2=ls_art_2;
   
   ls_art_1.pin=entrada1;
   ls_art_1.contando=0;
   ls_art_1.pasaron_20ms=0;
   
   ls_art_2.pin=entrada2;
   ls_art_2.contando=0;
   ls_art_2.pasaron_20ms=0;
   

   set_tris_a(0b00000011);
   set_tris_b(0);
   set_tris_c(0b10000000);
   
   output_low(salida1);
   output_low(salida2);
   
   while (TRUE){
     
      estado_pin(&ls1);
      if (ls_art_1.contando) {output_high(salida1);}
      else output_low(salida1);
     
      estado_pin(&ls2);
      if (ls_art_2.contando) {output_high(salida2);}
      else output_low(salida2);
     
   }
}

void estado_pin(int16 ls){

   if (input(*ls)) *(ls+2)=1;// hago un desplazamiento de 2 bytes para ubicar a
   else *(ls+2)=0;           // ls.contando y asignarle un valor

}

También he adjuntado un archivo de simulación en el proteus para verificar su funcionamiento.

Voy a tratar de explicar con más detalle lo que quiero, e declarado un tipo de dato mi_LS que es la siguiente estructura:

Código: [Seleccionar]
typedef struct{
   long   pin;
   int8   contando;
   int8   pasaron_20ms;
} mi_LS;// mi Limit Switch

a la vez declaro dos variables de ese tipo de dato

Código: [Seleccionar]
mi_LS ls_art_1, ls_art_2;
Inicializo sus valores:

Código: [Seleccionar]
   ls_art_1.pin=entrada1;
   ls_art_1.contando=0;
   ls_art_1.pasaron_20ms=0;
   
   ls_art_2.pin=entrada2;
   ls_art_2.contando=0;
   ls_art_2.pasaron_20ms=0;

Definí una función llamada

Código: [Seleccionar]
void estado_pin(int16);//
La cual recibe la dirección de memoria (supuestamente) de una de las variables de tipo mi_LS verifica el estado del pin, si es '0' entonces a ls.contando le asigno 0 (ls.contando=0) en caso contrario le asigno 1, con lo que el contenido de la variable ls_art_1 (por ejemplo) "debería" ser actualizado en el main,pero no sucede, por eso es mi grito de auxilio.

Gracias de antemano.

PD: Uso el compilador del CCS versión 4.023
« Última modificación: 05 de Abril de 2008, 10:02:05 por gu1llermo »

Desconectado migsantiago

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8257
    • Sitio de MigSantiago
Re: Pasar por referencia una estructura?
« Respuesta #1 en: 04 de Abril de 2008, 22:59:52 »
¡Hola!

Una pregunta tonta de mi parte... ¿qué pasaría si haces lo siguiente?

void estado_pin(int16 &ls)

 :P


Desconectado gu1llermo

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 217
Re: Pasar por referencia una estructura?
« Respuesta #2 en: 05 de Abril de 2008, 01:16:55 »
No compila  :?, así como lo e dejado me compila, pero no hace lo que quiero que haga y es actualizar a ls.contando  :?, de todas formas gracias por tomarte la molestia de leer éste post y contestar.

Saludos.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Pasar por referencia una estructura?
« Respuesta #3 en: 05 de Abril de 2008, 02:03:00 »
¿Y así?

Código: C
  1. estado_pin(ls_art_1);
  2.  
  3. ...
  4.  
  5. void estado_pin(mi_LS *ls){
  6.  
  7.    if (input(ls.pin)) ls.contador=1;// hago un desplazamiento de 2 bytes para ubicar a
  8.    else ls.contador=0;           // ls.contando y asignarle un valor
  9.  
  10.  
  11. }

De todas formas, no tengo claro que CCS admita una variable como parámetro para la función input().
Yo creo que las variables globales no es una mala solución, sobre todo teniendo en cuenta la de ciclos de micro que te ahorras al entrar y salir de las funciones.
Cuando lo consigas, haz la prueba compilando las dos versiones del programa y mirando el resultado.

Desconectado jgpeiro06

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 276
Re: Pasar por referencia una estructura?
« Respuesta #4 en: 05 de Abril de 2008, 06:23:04 »
Cierto es que el acceso a las variables globales es un poco mas rapido que a las variables locales, pero tambien es cierto que se ocupa mas memoria ram del micro. Pero ni una ni otra son razones de peso, ya que afectan muy poco al rendimineto total del programa. Yo evito en la medida de lo posible usar variables globales xq asi consigo un codigo mas sencillo y mas encapsulado.

Como dice nocturno, tienes que definir la funcion estado_pin de la siguiente manera:
void estado_pin( mi_LS *ls )

pero creq que como *ls es un puntero a una estructura para acceder a sus miembros tienes que usar el operador "->".
   if (input(???)) ls->conntador=1;  // La funcion input no se que argumentos necesita, pero supongo que "*(ls->pin)"
   else ls->contador=0;

Tambien puedes hacer

mi_LS estado_pin( mi_LS ls){
   if (input(ls.pin)) ls.conntador=1;
   else ls.contador=0;
   return ls;
}

void main(){
ls1 = estado_pin( ls1 );
}

Desconectado gu1llermo

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 217
Re: Pasar por referencia una estructura?
« Respuesta #5 en: 05 de Abril de 2008, 09:52:14 »
Lo hice!!!  :-/ :-/ :-/ gracias a uds. Nocturno y jgpeiro06.

Nocturno en un principio declaré la función como bien dices, pero dentro de la función no me dejaba acceder con la llamada ls.pin  :? entonces le dí más vueltas hasta que llegué con el código que publiqué.

jgpeiro06, es exactamente como dices a mi también me gustan los programas encapsulados y los más elegante posible, porque denota que tienes dominio, conocimiento y seguridad de lo que estas haciendo, gracias por indicarme como se accedían a los elementos dentro de la estructura con el indicador ->, yo hasta ví el .lst y me daba cuenta que tenía que incrementar el índice  del registro que maneja el direccionamiento indirecto pero no sabía como, y de aqui a que adivinara ufff  :?, bueno el código definitivo, simplificado y que funciona es éste:

Código: [Seleccionar]
#include <18F4550.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN,NOPBADEN
#use delay(clock=48000000)

#USE RS232 (baud=9600,bits=8,parity=N,xmit=PIN_C6,rcv=PIN_C7)

//#build(reset=0x000800,interrupt=0x000808:0x000818)
// Necesario para indicarle al compilador a partir de donde alojar mi programa

//#ORG 0x000, 0x07FF {} // Espacio reservado para alojar el bootloader

#byte PORTA = 0xF80// Son las direcciones de memoria de los puertos en este PIC
#byte PORTB = 0xF81
#byte PORTC = 0xF82
#byte PORTD = 0xF83
#byte PORTE = 0xF84

#define  entrada1  PIN_A0
#define  entrada2  PIN_A1

#define  salida1  PIN_B0
#define  salida2  PIN_B1

#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)

typedef struct{
   long   pin;
   int8   contando;
   int8   pasaron_20ms;
} mi_LS;// mi Limit Switch

void estado_pin(mi_LS *);//

void main(void) {

   mi_LS ls_art_1={entrada1 0 0};
   
   mi_LS ls_art_2={entrada2 0 0};

   set_tris_a(0b00000011);
   set_tris_b(0);
   set_tris_c(0b10000000);
   
   output_low(salida1);
   output_low(salida2);
   
   while (TRUE){
     
      estado_pin(&ls_art_1);
      if (ls_art_1.contando) {output_high(salida1);}
      else output_low(salida1);
     
      estado_pin(&ls_art_2);
      if (ls_art_2.contando) {output_high(salida2);}
      else output_low(salida2);
     
   }
}

void estado_pin(mi_LS *ls){

   if (input(ls->pin)) (ls->contando)=1;
   else (ls->contando)=0;

}

Lo pueden probar con el .dsn que monté anteriormente, la idea de esto es hacer un programa antirebote por interrupciones del timer 1, ya lo tengo implementado pero con variables globales,  manejo 6 finales de carrera asi que ya se imaginarán lo grande que es la rutina con ese pocote de ls.pin, ls.contando y ls.pasaron  :?.

Con respecto al argumento de input() es un número, en la ayuda del CCS dice:
Citar
Pin to read.  Pins are defined in the devices .h file.  The actual value is a bit address.  For example, port a (byte 5) bit 3 would have a value of 5*8+3 or 43.  This is defined as follows:  #define PIN_A3 43. 

The PIN could also be a variable.  The variable must have a value equal to one of the constants (like PIN_A1) to work properly

así que para PIN_A0 de éste pic sería: 0xF80*8+0=0x7C00 ó lo que es lo mismo un int16 ó long.

Espero que le sirva de utilidad a otros como lo ha sido para mí.

Gracias nuevamente y Saludos.
« Última modificación: 05 de Abril de 2008, 10:01:30 por gu1llermo »

Desconectado jgpeiro06

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 276
Re: Pasar por referencia una estructura
« Respuesta #6 en: 05 de Abril de 2008, 12:25:01 »
Por cierto, sobre eso que comentas de que no *(ls+2)=1 no hace ls.comando = 1...
Cuando declaras un puntero, el compilador trata ese puntero de manera similar a un array, me explico:
tenemos el codigo
char8 caracter; // ocupando la direccion 10;
int16 entero; // ocupando las direcciones 11 y 12
char8 *punteroC = &caracter;// 10
int16 *punteroI = &entero;//11
*(punteroC+1) = 8; // estamos asignando el 8 al siguiente char8 despues del 10, al 11
*(punteroI+1) = 8; // estamos asignando el 8 al siguiente int16 despues del 11, al 13

cuando incrementamos un puntero, el compilador le suma el numero de bytes que ocupa su tipo(¿?¿?¿?), me vuelvo a explicar:

long32 variable1;// direccion 0x10
long32 variable2;// direccion 0x14
long32 *ptr = &variable1;
printf( "direccion apuntada = ", ptr);//imprime 0x10
ptr++;
printf( "direccion apuntada = ", ptr);//imprime 0x14!!!!!!

el compilador trata este puntero de manera similar a un array. El siguiente codigo es equivalente:
 
long32 variable[2];// direccion 0x10
long32 *ptr = &variable[0];
printf( "direccion apuntada = ", &ptr[0]);//imprime 0x10
printf( "direccion apuntada = ", &ptr[1]);//imprime 0x14!!!!!!

Cuando accedias a *(ls+2) estabas accediendo a *(&ls + sizeof(mi_LS) * 2), comprueba en que direccion estaba ls, y si aparecia un 1 en alguna direccion de memoria cercana...

No se si le he dado mas vueltas de las necesarias al tema... de todas formas eso de que "ptr++" sume el numero de bits que ocupa el dato apuntado es algo que me sorprendio mucho....



Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Pasar por referencia una estructura
« Respuesta #7 en: 05 de Abril de 2008, 13:12:56 »
Pues yo no sabía lo del acceso con -> así que una cosa más aprendida.

Además, me alegro que se puedan utilizar los pines del micro como variables: no son pocas las veces que he descartado usarlos porque lo he dado por imposible.

Desconectado gu1llermo

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 217
Re: Pasar por referencia una estructura
« Respuesta #8 en: 05 de Abril de 2008, 17:04:26 »
Hola jgpeiro06, he entendido perfectamente lo que has dicho, gracias por la explicación, por lo que veo ya somos varios que estamos aprendiendo  :mrgreen:

con respecto a esto:
...
Cuando accedias a *(ls+2) estabas accediendo a *(&ls + sizeof(mi_LS) * 2), comprueba en que direccion estaba ls, y si aparecia un 1 en alguna direccion de memoria cercana...
...

Efectivamente es como explicas, ls_art_1 empieza en la dirección de memoria 0x06, por lo que ls.pin ocupa 0x06 y 0x07, ls_art_1.contando 0x08 y ls_art_1.pasaron_20ms 0x09, ahora ls_art_2 empieza en la 0x0A y ocupa desde la  0x0A (byte alto) a la 0x0B (byte bajo), ls_art_2.contando 0x0C y ls_art_2.pasaron_20ms 0x0D.

Entonces al pasar como referencia
Citar
estado_pin(&ls_art_1)
y haciendo *(ls+2)=1 modificamos el byte bajo de ls_art_2, es decir, a la dirección de memoria 0x0B le asignamos 1, esto es ls_art_2.pin=1

En vista de esto modifiqué el primer código que publiqué y en vez de hacer *(ls+2)=1 hago *(ls+1)=1, y en vez de preguntar por ls_art_1.contando, pregunto por ls_art_1.pasaron_20ms y efectivamente su valor es modificado y todo funciona  8), a continuación el código:

Código: [Seleccionar]
#include <18F4550.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN,NOPBADEN
#use delay(clock=48000000)

#USE RS232 (baud=9600,bits=8,parity=N,xmit=PIN_C6,rcv=PIN_C7)

//#build(reset=0x000800,interrupt=0x000808:0x000818)
// Necesario para indicarle al compilador a partir de donde alojar mi programa

//#ORG 0x000, 0x07FF {} // Espacio reservado para alojar el bootloader

#byte PORTA = 0xF80// Son las direcciones de memoria de los puertos en este PIC
#byte PORTB = 0xF81
#byte PORTC = 0xF82
#byte PORTD = 0xF83
#byte PORTE = 0xF84

#define  entrada1  PIN_A0
#define  entrada2  PIN_A1

#define  salida1  PIN_B0
#define  salida2  PIN_B1

#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)

typedef struct{
   long   pin;
   int8   contando;
   int8   pasaron_20ms;
} mi_LS;// mi Limit Switch

void estado_pin(mi_LS *);//

void main(void) {

   mi_LS ls_art_1={entrada1 0 0};
   
   mi_LS ls_art_2={entrada2 0 0};
   
   set_tris_a(0b00000011);
   set_tris_b(0);
   set_tris_c(0b10000000);
   
   output_low(salida1);
   output_low(salida2);
   
   while (TRUE){
     
      estado_pin(&ls_art_1);
      if (ls_art_1.pasaron_20ms) {output_high(salida1);}
      else output_low(salida1);
     
      estado_pin(&ls_art_2);
      if (ls_art_2.pasaron_20ms) {output_high(salida2);}
      else output_low(salida2);
     
   }
}

void estado_pin(mi_LS * ls){

   if (input(ls)) *(ls+1)=1;
   else *(ls+1)=0;

}

Igualmente lo pueden probar en el archivo .dsn que subí, para que vean como enciende y apaga el LED  :wink:

Saludos.

Desconectado gu1llermo

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 217
Re: Pasar por referencia una estructura
« Respuesta #9 en: 08 de Abril de 2008, 00:46:40 »
Hola!, escribo para decirles que publiqué el código en el que estaba trabajando, el que motivó la realización de esta consulta
Filtro antirebote mediante interrupción del timer1 (20ms)

A todos gracias por su ateción y ayuda prestada.

Saludos. 8)


 

anything