Autor Tema: Puedo asignar una direccion a una variable?  (Leído 3305 veces)

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

Desconectado micro_carp

  • PIC10
  • *
  • Mensajes: 13
Puedo asignar una direccion a una variable?
« en: 21 de Enero de 2012, 06:51:05 »
Estimados foristas,

Quisiera saber si en mikro c existe la posibilidad de guardar datos en una posición de memoria que yo quisiera. Por ejemplo tengo 4 variables A, B,C y D y necesito que se guarden en posiciones consecutivas tales como 0x0072, 0x0073, 0x0074 y 0x0075 Estas posiciones de memoria yo los podría elegir. Luego en otra parte del programa necesito leer  los datos guardados en estos registros simplemente incrementado un puntero que me sirva para direccionar a la memoria donde he guardado estas variables.

Esto con la finalidad de reducir la cantidad de código de mi aplicación.

Desconectado MGLSOFT

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 7912
Re: Puedo asignar una direccion a una variable?
« Respuesta #1 en: 21 de Enero de 2012, 07:58:57 »
Tendrias que declarar un arreglo de datos, de la cantidad que necesites.
El compilador asigna direcciones consecutivas al mismo y puedes accederlo mediante el uso de punteros.
Todos los dias aprendo algo nuevo, el ultimo día de mi vida aprenderé a morir....
Mi Abuelo.

Desconectado PalitroqueZ

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5474
    • Electrónica Didacta
Re: Puedo asignar una direccion a una variable?
« Respuesta #2 en: 21 de Enero de 2012, 11:38:46 »
si se puede
La propiedad privada es la mayor garantía de libertad.
Friedrich August von Hayek

Desconectado MerLiNz

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2463
Re: Puedo asignar una direccion a una variable?
« Respuesta #3 en: 21 de Enero de 2012, 11:44:39 »
char *p=0x73;

Desconectado micro_carp

  • PIC10
  • *
  • Mensajes: 13
Re: Puedo asignar una direccion a una variable?
« Respuesta #4 en: 29 de Enero de 2012, 13:42:21 »
Gracias a todos por sus aportes. Sobre todo a MGLSOFT. Dos cosas que me sirvieron mucho son:

- El arreglo de datos y
- El uso de punteros

Ambas cosas juntas me permitieron solucionar un problema y reducir la cantidad de líneas de mi aplicación. Quisiera darme  el  tiempo para explicar ambos puntos porque creo que a muchos les va a servir!!!

ARREGLO DE DATOS

El arreglo de datos es un conjunto de datos que se guardan en la memoria en posiciones continuas. Todos los datos se guardan con el mismo nombre. Veamos un ejemplo:

      short int A[3]={2,3,4};

Aquí se ha creado la variaba “A”. El valor entre llaves [3] Significa que se ha creado un arreglo de 3 elementos a los cuales se les ha asignado los valores {2,3 y 4}. Es decir:
 
  A[0] = 2
  A[1] = 3
  A[2] = 4

Vemos que en realidad se han creado 3 elementos, como es del tipo “Short Int” significa que cada uno de los elementos es de 1 byte y como hemos creado un arreglo de 3  significa que en realidad tenemos 3 elementos con el mismo nombre. A cada uno se le puede  manipular enumerándolos entre corchetes con los números 0, 1,2. Asi por ejemplo yo puedo hacer operaciones con cada elemento del arreglo, por ejemplo :

  A[0]=A[1]+3;

Algo importante es que cada elemento del arreglo de datos se guarda en una posición continua. Por ejemplo en mi programa tenemos que la posición de memoria que ocupa cada elemento es como sigue:

 A[0] = 2     Posición de memoria  0x20
 A[1] = 3    Posición de memoria  0x21
 A[2] = 4    Posición de memoria  0x22

USO DE PUNTEROS

Un  puntero o apuntador es una variable que contiene la dirección en memoria de otra variable. Se pueden tener apuntadores a cualquier tipo de variable. Los operandos con los que se maneja una variable puntero son los siguientes:

      &x:   El operando “&” indica que se va a extraer la dirección de memoria de la variable   “x”
     *x:    Apuntar y extraer el dato que se encuentra en la dirección guardada en la variable   “x”

Quizá sea un poco complicado entender lo anterior, pero si tienen un poco de paciendia y ven el siguiente ejemplo que vi en la web, estoy seguro que el concepto quedará mas claro. Veamos el siguiente cuadro


         DIRECCION   100   200   1000
         VARIABLE     x        y      ap
         
         VALOR    1   2   100


Ahora desarrollemos el siguiente programa en base al cuadro anteriror:


     main()
     {
         int x=1, y=2;  //Creamos las variables enteras "x" e "y" con los valores 1 y 2
         int *ap;          //Creamos la variable "ap" que en ralidad es un puntero
   
         ap=&x;       
         y=*ap;
         x=ap;
        *ap=3;
      }

Veamos el desarrollo de este programa y que es lo que sucede en cada linea:

                ap = &x  ….  ap = direccion de memoria de “x”, es decir ap=100
               y = *ap   ….  y = al valor de registro a donde apunta “ap”, es decir  y=1
               x = ap     ….  x = al valor del registro “ap”, es decir  x = 100
                 *ap = 3  …. La variable cuya posición de memoria es la guardada en el puntero “ap” deberá cargarse con el valor 3, es decir 
                                    x=3 (El valor cargado en “ap” es 100 que apunta a la variable “x” que tiene ese valor de dirección de memoria es decir 100)
 

Estoy seguro que quedan varias dudas, el concepto es algo dificil entender cuando recien es explicado, solo recomiendo releer varias veces el ejemplo y estoy seguro que se entendera mejor. Luego me gustaria colocar el ejemplo muy util sobre el uso de estos dos conceptos!!!

Saludos

Desconectado Miquel_S

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1251
Re: Puedo asignar una direccion a una variable?
« Respuesta #5 en: 29 de Enero de 2012, 17:57:24 »
Gracias micro_carp por la explicacion, los que recien empezamos este tipo de explicaciones son de agradecer.

Saludos!
Todos somos muy ignorantes. Lo que ocurre es que no todos ignoramos las mismas cosas.

Desconectado micro_carp

  • PIC10
  • *
  • Mensajes: 13
Re: Puedo asignar una direccion a una variable?
« Respuesta #6 en: 30 de Enero de 2012, 15:59:40 »
Que bueno que se entiende el concepto!!!

Desconectado micro_carp

  • PIC10
  • *
  • Mensajes: 13
Un ejemplo interesante
« Respuesta #7 en: 30 de Enero de 2012, 16:26:31 »
La idea de usar un arreglo de datos y puntero surgío de la necesidad que tenia en mi programa de poder reducir la cantidad de codigo que estaba utilizando. No se si realmente ha reducido sustancialmente el codigo asembler (debe haber forma de saberlo), pero por lo menos se hace mas facil de entender ya que utilizo menos lineas en C.

Mi programa hace lo siguiente:

Utilizo 4 displays de 7 segmentos para mostrar unos datos numericos. En cada interrupcion generada por desbordamiento de TMR1 se debe actualizar un display, es decir quiero hacer un barrido de los displays cada cierto tiempo (lo suficiente como para no ver el parpadeo). El usar la interrupcion para el scaneo de los 4 displays es importante porque asi el microcontrolador puede hacer otras tareas. Asi no me preocupo por el tema de mostrar los valores en el display, simplemente actualizo los datos en un par de registro y en cada interrupcion estos registros van mostrandose en los display. Mas o menos he experimentado que cada 10 ms de barrido evito el parpadeo, si demoro mas el parpadeo se nota.

Como uso el arreglo de datos y punteros?. Pues he creado un arreglo de datos que me permite guarda alli los datos que debo mostrar en pantalla y otro arreglo que me permite guardar el valor del puerto que activaré. Tratare de explicar...

Tengo dos registros punteros:
   *pointer_port
   *pointer_display

y dos arreglos de datos
   display_data[4]={5,6,7,8}
   display_port[4]={1,2,4,8}

Como los arreglos de datos se guardan en direcciones consecutiva, aqui uso los punteros de tal manera que en cada interrupcion incremento los punteros hasta lograr barrer con todos los diplays. No olviden que el puntero guarda una direccion a que deseo acceder. Fijense que el arreglo "display_port" guarda los valores 1,2,4,8 que si lo convierten a binario nos permite en cada interrupcion activar solo un bit del puerto. Asi vamos haciendo un barrido uno por uno de cada display. En cada interrupcion saco por un puerto un dato que le corresponde a ese display.

Aqui dejo en programa que he probado en mi tarjeta de pruebas. Hago uso de Interrupcion por TMR1 y Funciones. Ojo que si simulan en proteus deberan hacer que la interrupcion por TMR1 se al menos cada 20ms incluso mas, de otro no van a poder ver nada. Espero se entienda.







//*****DECLARACION DE LAS FUNCIONES
void BIN_7SEG(int f_data1bin,int f_data2bin);//Usado en la conversion de datos a
//valor de 7segmentos. Ingresas dos registros por ejemplo el de los segundos y
//minutos y entrega los datos en los registros (displa[0] ... display[3])

int BCD_7SEG(int f_digit);//Usado en la conversion de los datos a 7 segmentos
//Convierte valor BCD a 7 segmentos, cada registro es convertido a BCD y guardado
//en dos registros.


//*****DECLARACION DE VARIABLES USADAS PARA MOSTRAR VALOR EN DISPLAYS
unsigned short int display_data[4]={5,6,7,8};//Carga cada valor a mostrar
unsigned short int display_port[4]={1,2,4,8};//Puerto a activar en interrupcion
unsigned short int *pointer_display;//Puntero para manejo sacar valor por puerto
unsigned short int *pointer_port;//Puntero para activar un bit del puerto


//*****DECLARACION DE VARIABLES USADAS PARA LA CONVERSION DE DATOS A VALORES DE
//7 SEGMENTOS. POR EJEMPLO EL REGISTRO SEGUNDOS ES CONVERTIDO PRIMERO A DOS
//REGISTROS EN BCD Y LUEGO PASADO A DOS REGISTROS CODIFICADO PARA 7 SEGMENTOS.
unsigned short int valor1_bcd=0;//Contiene el valor en BCD de f_data1bin
unsigned short int data1_7seg=0;//Contiene el primer digito en 7segmentos de Valor1_bcd
unsigned short int data2_7seg=0;//Contiene el segundo digito en 7segmentos de Valor2_bcd

unsigned short int valor2_bcd=0;//Contiene el valor en BCD de f_data2bin
unsigned short int data3_7seg=0;//Contiene el primer digito en 7segmentos de Valor2_bcd
unsigned short int data4_7seg=0;//Contiene el segundo digito en 7segmentos de Valor2_bcd


short int count_1=0;//Contador para lograr 1 segundo
short int minutes_bin=0;
short int seconds_bin=0;


void interrupt() {

//------------- RUTINA DE ATENCION A INTERRUPCIONES POR TMR1 -------------------
if (PIR1.TMR1IF==1){//Verificar si la interrupcion es por TMR1

//En cada interrupcion se muestra un display. Se hace uso de un arreglo de regis
//tros y punteros. display_port, display_data, pointer_display, pointer_port.

   PORTA=*pointer_port;//Apuntar al valor guardado en el registro apuntado
   PORTD=*pointer_display;//Apuntar al valor guardado en el registro apuntado
   *pointer_display++;//Incrementar la direccion guardada en el registro
   *pointer_port++;//Incrementar la direccion guardad en el registro puntero
   if((pointer_display-1)==&display_data[3]) pointer_display=&display_data[0];
   if((pointer_port-1)==&display_port[3]) pointer_port=&display_port[0];
 }

//REINICIO DE INTERRUPCION POR TMR1
  TMR1H=0XEA;//Cargamos TMR1 para lograr 0,25 ms
  TMR1L=0X60;
  PIR1.TMR1IF=0;//Reset flag de desbordamiento por TMR1
}


//--------------------------- RUTINA PRINCIPAL ---------------------------------
void main() {
 ADCON1=0X06; //Configurar IOs como digitales
 TRISA=TRISD=0X00;
 PORTA=PORTD=0X00;  //Inicializar con los puertos apagados

//Configurar la interrupcion por TMR1
 PIR1.TMR1IF=0; //Reset flag de desbordamiento del tmr1
 TMR1H=0XEA;   //Cargamos TMR1 para lograr 0,25 ms
 TMR1L=0X60;
 T1CON=0b00000001;//<bit_0>: TMR1ON. Habilitar TMR1
                 //<bit_1>: TMR1CS. Usar reloj interno
                 //<bit_2>: T1SYNC: Bit de sincronizacion de reloj (ignorado)
                 //<bit_3>: T1OSCEN: Habilita las entradas RC para osc externo
                 //<bit_4,5>: Prescalador a 1
                 //<bit_6,7>: No habilitado
 INTCON.PEIE=1;//Habilitar la interrupcion de perifericos
 INTCON.GIE=1;//Habilitar la interrupcion general
 PIE1.TMR1IE=1;//Habilitar interrupcion por tmr1

//Inicializamos los punteros declarados antes de ser usados. Cargamos punteros
//con la direccion de los primeros registros que debe mostrar en la primera inte
//rrupcion.
 pointer_display=&display_data[0];//Cargar puntero con primera direccion
 pointer_port=&display_port[0];//Cargar puntero con primera direccion a mostrar


 while (1){

 seconds_bin++;
 Delay_ms(100);
 if (seconds_bin==99) {
    minutes_bin++;
    seconds_bin=0;
    }
 BIN_7SEG(minutes_bin,seconds_bin);
 if (minutes_bin==99 & seconds_bin==99) minutes_bin=seconds_bin=0;
}
}


//++++++++++++++++++++DESARROLLO DE LAS FUNCIONES+++++++++++++++++++++++++++++++


//*****DESARROLLO DE FUNCION PARA CONVERTIR LOS DATOS BINARIOS A 4 VALORES GUAR
//DADOS EN DISPLAY_1 AL 4. F_DATA1BIN CONTIENE EL PRIMER VALOR BINARIO QUE SE
//CONVERTIRA EN BCD Y LUEGO A 7SEGMENTOS.  F_DATA2BIN ES EL SEGUNDO VALOR BINARIO
//f_data1bin es convertido y luego guardado en displays 1 y 2
//f_data2bin sobre los displays 3 y 4

   void  BIN_7SEG(int f_data2bin,int f_data1bin){
     valor1_bcd=Dec2Bcd(f_data1bin);//Funcion para convertir binario a BCD
     data1_7seg=valor1_bcd & 0b00001111;//Separar el primer digito BCD
     data2_7seg=(valor1_bcd & 0b11110000)>>4;//Separar el segundo digito BCD
     display_data[0]=BCD_7SEG(data1_7seg);
     display_data[1]=BCD_7SEG(data2_7seg);

     valor2_bcd=Dec2Bcd(f_data2bin);//Funcion para convertir binario a BCD
     data3_7seg=valor2_bcd & 0b00001111;//Separar el primer digito BCD
     data4_7seg=(valor2_bcd & 0b11110000)>>4;//Separar el segundo digito BCD
     display_data[2]=(BCD_7SEG(data3_7seg)|0b10000000);//Colocamos el punto decimal
     display_data[3]=BCD_7SEG(data4_7seg);//Funcion convierte el valor BCD a 7 Seg
     }

//*****DESARROLLO DE FUNCION PARA PASAR BCD A 7 SEGMENTOS
int BCD_7SEG(int f_digit){

 switch (f_digit){
         case 0: return 0x3F; //0x3F es el código 7-segmentos del 0.
         case 1: return 0x06; //0x06 es el código 7-segmentos del 1.
         case 2: return 0x5B;
         case 3: return 0x4F;
         case 4: return 0x66;
         case 5: return 0x6D;
         case 6: return 0x7D;
         case 7: return 0x07;
         case 8: return 0x7F;
         case 9: return 0x6F;
 }
 }


Desconectado PalitroqueZ

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5474
    • Electrónica Didacta
Re: Puedo asignar una direccion a una variable?
« Respuesta #8 en: 30 de Enero de 2012, 19:30:30 »
buen aporte micro_carp.

Gracias por la explicación!!!  :)
La propiedad privada es la mayor garantía de libertad.
Friedrich August von Hayek


 

anything