TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: PalitroqueZ en 02 de Abril de 2007, 12:20:57

Título: el tema de los punteros...
Publicado por: PalitroqueZ en 02 de Abril de 2007, 12:20:57
Leyendo el documento que colgó elmasvital en este post (http://www.todopic.com.ar/foros/index.php?topic=16584.msg109814#msg109814) me dieron ganas de hacer un estudio de este tema en profundidad, así aprovecho voy escribiendo y lo pego aquí por si alguien tiene problemas o desconocimiento de como usarlo.

lo que sé de punteros está en esa guía punteros en C (http://www.lugro.org.ar/biblioteca/cursos/cursoc/Punteros.pdf) y en Curso de C (http://www.elrincondelc.com/cursoc/cursoc.html) del autor Gorka Urrutia (en las sección de punteros) y mucho de lo escribiré se basará en ambos documentos.

por supuesto que estará orientado a los uC PIC y usando el PIC C Compiler de CCS.
(a ver si este compilador nos lo permite)

¿Qué es un puntero?

un puntero es una variable cuya finalidad es almacenar numeros ENTEROS POSITIVOS. Estos numeros no son numeros al azar, son direcciones de memoria que poseen el hardware específico (memoria de programa o la RAM).

¿para que pueden servir los punteros?

esta pregunta puede alborotar a mas de un programador de C, sirve para muchiiisimas cosas:

- acceso a la memoria de un hardware y/o RAM, en este caso el uC PIC.

- ahorrar memoria RAM.

- modificar mas de una variable dentro de una función (por consiguiente devolver mas de un valor)

- en arreglos y cadenas strings (arrays, matrices) juega un papel importantisimo.

- crear tablas con montones de datos (en los uC PIC que soporten acceso a la memoria de programa).

- en las computadoras se amplia el abanico de opciones.

cada paso se irá explicando paulatinamente.

¿como funcionan los punteros?

para entender el uso debido de estas variables especiales, hay que comprender bien un concepto.

cuando se crea una variable en C (llamado registro en ensamblador), el compilador reserva un espacio de memoria (programa/ram) de acuerdo al tipo de dato.

como todo en el mundo electronico - digital está basado en 2 cosas:

- el registro: es la casilla donde se almacena el dato.

- la dirección del registro: es la posición en la memoria donde está alojado el registro.

así pués tenemos 2 elementos diferentes pero que se relacionan.

conociendo la dirección del registro o variable y pudiendolo manejar nos dá un poderosa herramienta para agilizar/simplificar nuestros programas.

pero ¿como podemos acceder a la dirección de una variable?

en C se hace a través del operador & vamos con un ejemplo:

Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3.  
  4. void main(){
  5. int t,k;
  6.         t=5;
  7.         k= &t;
  8.         delay_cycles(1);
  9. }

al simular en el MPLAB tenemos

(http://img119.imageshack.us/img119/240/41052499oe0.jpg)


cuando paramos en delay_cycles(1) vemos que en k se guarda la dirección de la variable t, ¿y que guarda t? guarda el número 5. todo se realiza usando memoria RAM ó el registro de propósito general GPR

vamos a cambiar ligeramente el código, usemos 3 variables tipo entero (int)

Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3.  
  4. void main(){
  5. int k,l,m;
  6. int t,u,v;
  7.         t=0xfa; u=0xfb; v=0xfc;
  8.         k= &t;  l= &u;  m= &v;
  9.         delay_cycles(1);
  10. }

(http://img119.imageshack.us/img119/1814/42806236sy7.jpg)


se repite lo mismo, el resultado de las direcciones en k, l y m son contiguas, ¿y porque digo esto?

para responder esta pregunta vamos a cambiar el código otra vez, declarando los 3 tipos de registros conocidos, int, long y float


Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3.  
  4. void main(){
  5. int k,l,m,n;
  6. int t;
  7. long u;
  8. float v;
  9. int z;
  10.         t=0xfa; z=0xff; u=0xfffa; v=3.45000000;
  11.         k= &t;  l= &u;  m= &v; n=&z;
  12.         delay_cycles(1);
  13. }

la simulación

(http://img119.imageshack.us/img119/1212/28759875md7.jpg)


observe que las direcciones de t, u , v saltan ¿porque?

dependiendo del tipo de dato se consume >= 1 byte

en el caso de t es un entero, los enteros llegan hasta 255 (1 byte)

u es un entero largo, que llega hasta 65535 (2 bytes)

v es un coma flotante, es decir, parte fraccionaria en el sistema decimal y toma 4 bytes de memoria (32 bits)

- en t tenemos una dirección que ocupa un byte [0xA]

- en u tenemos una dirección que ocupa 2 byte [0xB - 0xC]

- en v tenemos una dirección que ocupa 4 bytes [0xD - 0x10]

esto hay que tomarlo en cuenta para futuros ejemplos.

Título: Re: el tema de los punteros...
Publicado por: PalitroqueZ en 02 de Abril de 2007, 12:26:56
- probando punteros.

siempre que se declare una variable puntero, al momento de usarlo se debe especificar la dirección de apuntamiento de la variable normal, porque entonces no se puede guardar un dato sino sabemos donde lo vamos a guardar. (obvio ¿verdad?) :)

quiere decir que se le debe pasar el número por valor de la dirección de la variable normal.

nota:
 - pasar un dato por valor: se copia el dato de una variable a otra.
 - pasar un dato por referencia: se mueve/modifica el dato en la misma variable.
 - variable normal: la variable que normalmente usamos.
 - variable puntero: es la variable especial que estamos estudiando.

un ejemplo sencillo usando punteros, tenemos

Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3.  
  4. //*******************************
  5. void main(){
  6. int k;      // variable normal
  7. int *p;    // la variable puntero
  8.  
  9.  k=0xfa;    // k <- 0xfa
  10.  *p=0x5;      
  11.  delay_cycles(1);
  12. }

dentro del código reconocemos de inmediato quien es el puntero: el que tiene el simbolo * debe ir antes de la letra p y sin separación

*p

asi es como se debe declarar.

si nos vamos a MPLAB-SIM, y trazando hasta delay_cycles(1) vemos en la ventana LOCAL:

(http://img515.imageshack.us/img515/6845/95183095kp9.jpg)


pero -¡no aparece nada en p!- ¿porque?

es simple: porque no fijamos una dirección que apuntara p, y esto es muy importante saberlo, era lo que se decía al inicio de este post. vamos a darle la dirección de k


Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3.  
  4. //*******************************
  5. void main(){
  6. int k;      // variable normal
  7. int *p;    // la variable puntero
  8.  p=&k;     // dirección de k copiada a p
  9.  k=0xfa;    // k <- 0xfa
  10.  *p=0x5;      // k <- 0x5
  11.  delay_cycles(1);
  12. }

el resultado:

(http://img515.imageshack.us/img515/4756/66258703zw6.jpg)


ahora si funciona OK nuestro código. si ven la línea:

p=&k;

noten que se usa el puntero sin el * significa que voy a guardar allí una dirección y el compilador lo interpreta de esa manera.

y con esta línea:

*p=0x5;

estoy modificando el contenido de k, (indirectamente)


otro detalle a tomar en cuenta es que para apuntar cierto tipos de datos, se debe declarar al apuntador con el mismo tipo de datos.

 int k;   // si queremos apuntar a k
 int *p;  // p debe ser tipo int

 char c; // si queremos apuntar a c
 char *p // p debe ser tipo char

no estoy queriendo decir que el tipo de datos que contendrá el puntero sea de ese tipo de datos, el puntero siempre soportará numeros enteros positivos, en realidad esto ya es a nivel interno del compilador.

para entender el enredo que acabo de escribir vamos a hacer un ejemplo:

en este código voy a escribir 2 punteros y 3 variables normales

Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3.  
  4. //*******************************
  5. void main(){
  6. int i;      // variable normal
  7. int *p;    // la variable puntero
  8. int j;
  9. int *q;
  10. int k;
  11.  
  12.  p=&i;     // dirección de i copiada a p
  13.  q=&j;
  14.  
  15.  i=0xfa;    // i <- 0xfa
  16.  j=0x11;
  17.  k=0x22;
  18.  
  19.  *p=0x5;      // i <- 0x5
  20.  *q=0x33;
  21.  
  22.  delay_cycles(1);
  23. }

(http://img515.imageshack.us/img515/439/40379226fg4.jpg)


- entre i, p hay 1 byte -> i ocupa 1 byte.

- entre p, j hay 2 byte -> puntero p ocupa 2 byte

- entre j, q hay 1 byte -> j ocupa 1 byte

- entre q, k hay 2 byte -> puntero q ocupa 2 byte


modificando el código para que i sea del tipo float

Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3.  
  4. //*******************************
  5. void main(){
  6. float i;      // variable normal
  7. float *p;    // la variable puntero
  8.  
  9. long j;
  10. long *q;
  11. int k;
  12.  
  13.  i=2.51;    // i <- 0xfa
  14.  j=0x11;
  15.  k=0x22;
  16.  
  17.  p=&i;     // dirección de i copiada a p
  18.  q=&j;
  19.  
  20.  *p=3.99;      // i <- 0x5
  21.  *q=0x33;
  22.  
  23.  delay_cycles(1);
  24. }

(http://img258.imageshack.us/img258/9559/16175274qs6.jpg)


- entre i, p hay 4 byte -> i ocupa 4 byte.

- entre p, j hay 2 byte -> puntero p ocupa 2 byte

- entre j, q hay 2 byte -> j ocupa 2 byte

- entre q, k hay 2 byte -> puntero q ocupa 2 byte
 

en ambos casos a pesar que cambiamos el tipo de declaración de los punteros, se mantienen en 2 bytes, eso quiere decir que para el compilador el tamaño de un puntero es de 2 bytes, ojo no confundir con el tipo de datos a direccionar, eso es otra cosa.

PalitroqueZ ¡sigo sin entender!

vamos con otro ejemplo:

supongamos que i sea del tipo float (4 bytes) pero su apuntador lo declaramos como int (1 byte)

Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3.  
  4. //*******************************
  5. void main(){
  6. float i;      // variable normal
  7. int *p;    // la variable puntero
  8. long j;
  9. long *q;
  10. int k;
  11.  
  12.  i=2.51;    // i <- 0xfa
  13.  j=0x11;
  14.  k=0x22;
  15.  
  16.  p=&i;     // dirección de i copiada a p
  17.  q=&j;
  18.  
  19.  *p=3.99;      // i <- 0x5
  20.  *q=0x33;
  21.  delay_cycles(1);
  22. }

(http://img258.imageshack.us/img258/760/19603219yb2.jpg)


noten que el nuevo valor de i no corresponde con el valor que indirectamente le dimos con el apuntador. ¿porque?

porque declaramos a ese apuntador como entero (int) y con ello le estamos diciendo al compilador que reserve para p 1 byte de dirección en vez de 4 bytes que son los que se necesitan y por eso ocurre ese truncamiento y dá ese valor extraño.

para corregir esto, se declara a p del MISMO tipo de dato de i

Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3.  
  4. //*******************************
  5. void main(){
  6. float i;      // variable normal
  7. float *p;    // la variable puntero
  8. long j;
  9. long *q;
  10. int k;
  11.  
  12.  i=2.51;    // i <- 0xfa
  13.  j=0x11;
  14.  k=0x22;
  15.  
  16.  p=&i;     // dirección de i copiada a p
  17.  q=&j;
  18.  
  19.  *p=3.99;      // i <- 0x5
  20.  *q=0x33;
  21.  delay_cycles(1);
  22. }

(http://img515.imageshack.us/img515/5117/18617783oh6.jpg)


aquí se lee que está correcto el resultado, hay que estar pendiente con ese detalle.

nota: lo que he investigado hasta ahora, los punteros tiene un máximo de 2 bytes para almacenar direcciones y al parecer el CCS sigue la misma normativa.
si buscan en la ayuda veran que hay una directiva llamada  #device xxxxx

(http://img258.imageshack.us/img258/5064/60737976vz3.jpg)


con 4 modos de selección:

CCS2,CCS3,CC4 y ANSI

con CCS2 y CCS3 el tamaño (size) del puntero es de 1 byte en partes de 14, 16 bits
y con CCS4 (modo por defecto) el size es de 2 bytes

(comprobado en el MPLAB-SIM)

no se preocupen por esta última parte, como ya mencioné anteriormente esto lo realiza el compilador internamente, nosotros por lo que debemos preocuparnos es por el tipo de datos a declarar.

Título: Re: el tema de los punteros...
Publicado por: reiniertl en 02 de Abril de 2007, 12:40:55
¡Que bárbaro!

Te exhorto a que sigas haciendo este trabajo, que te está quedando muy bueno, siempre he querido hacerlo pero nunca he tenido la oportunidad por falta de tiempo y un poco de voluntad, pero a usted le está quedando como para chuparse los dedos.

Realmente me parece que voy a aprender mucho con este cursillo sobre punteros en C y con PIC. La razón: no es lo mismo punteros sobre una PC que en una máquina como los PIC, los PIC imponen limitaciones y ciertos cambios al concepto, pero aún así son herramientas de mucho poder y a mi me gusta mucho utilizarlos.

Un saludo Reinier
Título: Re: el tema de los punteros...
Publicado por: PalitroqueZ en 04 de Abril de 2007, 11:09:11
analizando nuevamente lo hablado referente al size de los punteros en CCS, y en un intento de explicar que el tipo de dato y el tamaño del apuntado son 2 cosas distintas, vamos hacer un ejemplo donde se verá claramente:

para ello vamos a usar una directiva llamada #locate

en ayuda del compilador reza asi:

#LOCATE works like #BYTE however in addition it prevents C from using the area

bueno esto quiere decir que mi variable normal la puedo alojar en la dirección de la ram que yo quiera (dentro de limites)

algo así como si en ensamblador fuera

variable_normal EQU 0xNNNN

esto nos va a servir porque sería como manipular el contenido de un puntero pero en tiempo de diseño

Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3. //*********************************
  4.  
  5.  int dato=0xaa;    // declaramos dato (GPR) y lo cargamos con 0xAA
  6.  #locate dato = 0xff  // le decimos al compilador que dato estará en la dirección 0xFF                  del área de registro de propósito general, traducido, en la RAM del PIC
  7.  
  8. void main(){
  9. int *p;  // declaramos un puntero como entero (igual que dato)
  10. int t;   // otra variable normal
  11.  
  12.  p=&dato;  // inicializamos al puntero
  13.  
  14.  *p=0xbb;  // dato <- 0xBB
  15.  
  16.  delay_cycles(1);  // un nop
  17. }


(http://img514.imageshack.us/img514/4638/image1up4.jpg)



(http://img478.imageshack.us/img478/7577/image2ir8.jpg)


(http://img514.imageshack.us/img514/5750/image3ex9.jpg)


fijense que el puntero p ocupa 2 bytes a pesar que está declarado como int (1 byte). ¿ven como es?

vamos a modificar este ejemplo pero usando float (4 bytes) y colocando el GPR en la dirección 0xAF


(http://img487.imageshack.us/img487/5493/image4he7.jpg)


(http://img487.imageshack.us/img487/9343/image5us7.jpg)


noten que el puntero p se mantuvo en 2 bytes siendo éste declarado como float

aquí podemos seguir inventando y crearnos situaciones dificiles que nos compliquen la vida, como por ejemplo, tratar de desbordar al puntero, o bajarle el size <= 1 byte y ver que sucede.

ya que quiero seguir inventando jeje, propongo una situación extrema, para el 18F4550, tenemos una memoria de datos que llega hasta 0x7FF (pag 66 39632D.pdf)

para que funcione 0x7FF debe ser el 4 byte para un float, entonces


float dato=1.23456789;
#locate dato = 0x7FB
...


(http://img514.imageshack.us/img514/682/image8wx7.jpg)

si funcionó

que pasa si asignamos el dato a 0x800


(http://img487.imageshack.us/img487/5275/image9me4.jpg)

allí vemos que el puntero se cargó bien, pero el MPLAB-SIM nos mandó a freir monos con el dato, ¿porque?

a partir de allí no hay memoria de datos y las direcciones se deberian leer como puros 0x0 a pesar que compiló bien, aquí también hay que estar pendiente con el direccionamiento (en programas de computadoras pueden ocurrir cuelgues)

Título: Re: el tema de los punteros...
Publicado por: PalitroqueZ en 04 de Abril de 2007, 11:13:12
- punteros en funciones:

todo lo que hagamos en C se hace a través de funciones o procedimientos, desde el punto de vista matemático una función se define así (viene de este link (http://descartes.cnice.mecd.es/4a_eso/El_lenguaje_de_las_funciones/funcion.htm) ):

Citar
cita:

Una función es una relación entre dos variables numéricas, habitualmente las denominamos x e y; a una de ellas la llamamos variable dependiente pues depende de los valores de la otra para su valor, suele ser la y; a la otra por tanto se la denomina variable independiente y suele ser la x.

Pero además, para que una relación sea función, a cada valor de la variable independiente le corresponde uno o ningún valor de la variable dependiente, no le pueden corresponder dos o más valores.



aplicandolo a la programación, significa que podemos tener varios argumentos o parametros de entrada, pero solo tendremos un dato de salida y eso no es todo, en C una función pasa los argumentos por valor.

¿que quiere decir esto?

que cuando llamemos a la función y le pasemos el dato como argumento, ésta copiará ese dato en su propia función sin alterar la variable original. veamos un ejemplo:


Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3. //*********************************
  4. int mi_funcion(int argumento1, argumento2){
  5.         delay_cycles(1);
  6. return (argumento1 + argumento2);
  7. }
  8.  
  9. //*******************************
  10. void main(){
  11. int k,l,resultado;
  12. k=5; L=2;
  13.         resultado = mi_funcion(k,L);
  14.         delay_cycles(1);
  15. }


(http://img514.imageshack.us/img514/9869/62674124bz1.jpg)


(http://img487.imageshack.us/img487/9071/72282541ae7.jpg)

fijense que cuando llamo a mi_funcion, se copia el contenido de k -> argumento1 y L -> argumento2 , luego hace la suma y regresa un dato con el resultado de la suma.

k y L se quedan con el mismo valor anterior.

¿y si queremos cambiar esas variables como se hace?

bueno seguro que alguien llegará y colocará a k y L como globales y entonces así se puede modificar en cualquier lado.

pero si la variable es local, dentro de main, no se puede modificar fuera de main...
a menos que usemos punteros. -aja- ¿y como se haría eso?

se haría pasando el argumento a la función como referencia, haciendo referencia a la dirección, es decir lo que le voy a pasar a la función es la dirección de k, L  entonces allí si se puede modificar a gusto. un ejemplo:


Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3.  
  4. //*********************************
  5. int mi_funcion(int argumento1, argumento2, *la_k, *la_L){
  6.         delay_cycles(1);
  7.         *la_k=0xFF; *la_L=0xAF;
  8. return (argumento1 + argumento2);
  9. }
  10.  
  11. //*******************************
  12. void main(){
  13. int k,l,resultado;
  14. k=5; l=2;
  15.         resultado = mi_funcion(k,l,&k,&l);
  16.         delay_cycles(1);
  17. }

para ver con claridad ese código, un videito simulando en MPLAB:

simulacion paso a paso (http://www.4shared.com/file/13471345/2bf5eec7/m3v1.html)


Título: Re: el tema de los punteros...
Publicado por: RiBerZerO en 04 de Abril de 2007, 23:01:25
Solo quiero dar mi mas sincero agradecimiento con esto me haces recordar muchas cosas que ya no ocupaba de mis clases de C jeje olvidemos las variables globales y a programar como los PIC mandan jeje con programacion de elite  :D

Vas por el mejor camino y lo sabes sigue asi :-/
Título: Re: el tema de los punteros...
Publicado por: maunix en 05 de Abril de 2007, 10:37:56
Yo opino que el uso de variables globales NO es un pecado.  En los microcontroladores es más necesario que en una pc.

Es más, hasta es ACONSEJABLE usarlas para evitar el uso excesivo del stack que en muchas aplicaciones es inaceptable por las demoras que conlleva.

Saludos
Título: Re: el tema de los punteros...
Publicado por: RiBerZerO en 06 de Abril de 2007, 02:27:27
Yo creo que como todos los metodos de programacion las variables globales y los apuntadores tienen un uso especifico, su utilidad depende mucho de la aplicacion que se este utilizando, es cierto no es un pecado. es un modo de programacion  :-)

Yo creo que comparar esto es como querer decir que es mejor un FOR( ; ; ) que un WHILE.  :lol:

Mientras una variable global nos da acceso a ella en todo el programa  solo llamandola por su nombre, un apuntador nos manda la direccion para que sea modificada solo desde una funcion llamada directamente de la funciona a la que pertenece esta variable. Por lo cual no puede ser modificada por funciones ajenas al flujo.

El uso de un apuntador nos ayudara a muchas cosas por ejemplo en aplicaciones en las cuales se quiera guardar algun archivo en forma de nodo y asi despues aumentar el tamaño claro esto usando extructuras. Tambien se puede utilizar para tener acceso a variables definidas en una funcion a las cuales queramos tener acceso. Tambien nos ofrece la posibilidad de manejar matrices redimencionables.

Muchas veces tambien los apuntadores se utilizan para seguridad, ya que una variable global pude ser llamada desde cualquier parte del programa, por lo cual no son recomendables para programas donde se guarden claves o algo parecido.

Bueno este es mi muy personal punto de vista se aceptan criticas para tener mejor angulo de vision.

Algo que no entiendo

Citar
para evitar el uso excesivo del stack

Como puede un apuntador el cual utilizas para que una funcion pase la direccion de memoria de una variable ya definida y una funcion a la cual tienes que llamar (por lo cual ya gastaste stack) gastar mas stack, creo que te refieres a gastar mas RAM, con la variable de 2 bytes que utilizas para guardar el apuntador, pero hasta donde yo se (que no es mucho) el stack solo se gasta al hacer un llamado a funcion por lo cual se genera un salto y en el stack se guarda la direccion del en la cual se encuentra en contador de programa antes realizar el salto y asi poder regresar. Por lo cual yo creo que el stack solo se puede gastar excesivamente si se realizan muchos llamados a funciones seguidos, es decir que llames a una funcion y luego cuando estes en esa funcion llames a otra y otra y asi sucecivamente.

Bueno ese es mi punto de vista que puede tal vez estar equivocado

Gracias por el tiempo y disculpen las molestias :-/
Título: Re: el tema de los punteros...
Publicado por: reiniertl en 06 de Abril de 2007, 13:01:55
Yo concuerdo en parte con Maunix y en parte con RiBerZerO, pero no del todo con ninguno de los dos

Por ejemplo los microprocesadores de la linea INTEL, dentro de los que caen los uC 8051 y algunos de sus parientes el STACK se utiliza no solo para guardar las direcciones que en algún momento se utilizarán para retornar de una llamada a subrutina o interrupción, también se puede guardar el contexto del programa antes del salto o inmediatemente después de entrar a una ISR, para ello están las instrucciónes POP y PUSH, en muchos procesadores. En los PIC, por lo menos en los que conozco, no hay POP y PUSH para todo tipo de registros y en las familias de gama media no se puede tener acceso al STACK, en los 18 tenemos acceso de lectura pero no podemos controlarla.

El uso de apuntadores es una herramienta poderosa, siempre que se sepa donde y para qué utilizarlos, por ejemplo pasar variables muy grandes (un arreglo, estructura o unión) con varios bytes puede costar más en RAM y pila que pasar un puntero con la dirección donde está esa estructura, ya que el compilador para pasar el dato tiene que hacer una copia en memoria, mientras que con el puntero solo reserva memoria para el apuntador que generalmente tienen tamaño fijo, acorde con el espacio de memoria que se puede direccionar en el sistema.

El uso de variables globales también es válido, y en la programación de uC y en todos los tipos de programación se utiliza habitualmente, pero los punteros no se crearon por gusto, ellos tienen su campo de aplicación y la programación con uC se puede ver muy beneficiada con ellos, por ejemplo tenemos muchas funciones como strcpy que utilizan apuntadores y nosotros mismos al declarar char MiVariable[10] estamos creando un aputador especial al tipo de datos char. Hay lenguajes que tratan de ocultar al programador el uso de aputadores los programadores en C son bastante críticos en cuanto a eso, por ejemplo tenemos a BASIC y PASCAL, donde el uso de apuntadores es pobre o simplemente no existe la posibilidad de utilizarlos aunque el compilador si utilice estas técnicas al compilar el código.

Esa es mi modesta opinión que también puede estar un poco equivocada.

De todos modos estos posts de PalitroqueZ me parecen muy buenos y esclarecedores.

Un saludo Reinier
Título: Re: el tema de los punteros...
Publicado por: maunix en 06 de Abril de 2007, 14:11:57
RiberZer0 y reintertl, ¡creo que han hecho mas extensivo mi comentario de lo que realmente fué!

Simplemente dije que el uso de variables globales no es ningún pecado! pero por supuesto depende del caso.

Cito un ejemplo, si usamos una variable local en cada subrutina que tenemos y dichas subrutinas no se llaman en simultáneo, entonces es ideal (pensando en velocidad y espacio de código) el usar una variable global, estática y en la access ram (si tenemos un 18F o un 16F de los grandes).

En ese caso, no hay acceso al stack para la creación de la variable, manipulación y posterior liberación!!  Ni hablar si usamos bancos contiguos para el stack y debe el compilador manejar el FSRnH y FSRnL

Por supuesto si tenemos arreglos de datos, el uso de punteros se hace fundamental e imprescindible para ahorrar código y velocidad, pero eso no es de lo que yo estaba hablando.

El uso de variables locales aumenta la legibilidad y la portabilidad pero también reduce la velocidad y aumenta el tamaño del código y eso hay que tenerlo muy en cuenta al trabajar con microcontroladores.

Saludos y espero haber aclarado el punto.

Título: Re: el tema de los punteros...
Publicado por: RiBerZerO en 06 de Abril de 2007, 18:03:23
Bueno lo de los apuntadores y variables globales esta claro se utilizan cuando hacen falta  :D lo que todavia no entiendo bien y me gustaria que me esplicaran, es que tiene que ver la creacion de una variable con el uso del stack, al menos yo no habia encontrado una relacion, por lo cual pido por favor que me expliquen :?

Bueno ya he corrido un programa y en la simulacion el hardware stack solo usa 2 localidades independientemente de si utilizo apuntadores y variables globales para el paso de los parametros.

Por su explicacion muchas gracias nos vemos luego :-/
Título: Re: el tema de los punteros...
Publicado por: maunix en 06 de Abril de 2007, 21:23:43
Bueno lo de los apuntadores y variables globales esta claro se utilizan cuando hacen falta  :D lo que todavia no entiendo bien y me gustaria que me esplicaran, es que tiene que ver la creacion de una variable con el uso del stack, al menos yo no habia encontrado una relacion, por lo cual pido por favor que me expliquen :?

El uso del stack (del compilador) está directamente relacionado al paso de parámetros y al uso de variables "locales" a una función.   Si usas una variable local, casi seguro que se crea en el stack (esto lo puedo afirmar en el caso del C18 que lo conozco bien) , pero pudiera ser que algún modo de optimización evite esto en ciertos casos en que la función sea llamada por ejemplo una sola vez.

Ahora bien, las razones son simples.  Las variables locales , como tales, "viven" durante la función y no fuera de ella.  Por ello se crean y destruyen  en la función, de ahí el que estén en el stack.  Llegado el caso es como un parámetro.

Espero se haya entendido.

PD: asumo que sabes lo que es el stack de variables del compilador.  Si lo desconoces por favor pregunta de nuevo. 
Título: Re: el tema de los punteros...
Publicado por: RiBerZerO en 07 de Abril de 2007, 01:56:20
Bueno la verdad yo pense que estabamos hablando del hardware stack del micro, lo de las variables locales lo sabia pero no de su almacenamiento en un stack, sobretodo a nivel compilador por lo cual agradeceria una pequeña explicacion gracias
Título: Re: el tema de los punteros...
Publicado por: Nocturno en 07 de Abril de 2007, 02:35:02
Gracias por tu esfuerzo Palitroquez. Me ha encantado leer tus artículos sobre punteros con tantísimo nivel de detalles y gráficos.
Título: Re: el tema de los punteros...
Publicado por: Cryn en 08 de Abril de 2007, 14:23:37
tengo esta funcion:

Código: [Seleccionar]
int32 entero(int dato[])   // funcion para convertir el array en entero
{
   int32 num=0;         // inicialización del número convertido
   cont=10000;         // valor inicial para el multiplicador
   dig=0;         // inicialización de dígtos
   do            // bucle de conversión
   {
      num=num+dato[dig]*cont;   // obtención del primer número del array (decenas de mil)
      cont=cont/10;      // se reduce orden de magnitud del miltiplicador
      dig++;         // incrementa el valor de la posición del array
   }while(dig!=5);      // se realiza mientras no se llegue al final del array
   return num;         // retorna el valor convertido
}

y el main tengo:
      num1=entero(dato1);   // lo convierte a entero

y defini antes: int dato1[5];

y este dato1 tiene 5 valores distintos cada vez, en un orden y lo quiero convertir a entero, osea digamos tengo {0,0,0,4,5}
lo convertira a un int=45 (la funcion hace la labor de no tomar en cuenta los ceros)

bueno lo hice de esa forma y funciona correctamente, ahora quiero usar punteros (para que el programa sea mas efectivo) y nose como hacerlo, me dan una ayudita?
Título: Re: el tema de los punteros...
Publicado por: PalitroqueZ en 09 de Abril de 2007, 17:08:17
Hola amig@s ya estoy de vuelta y leo varios mensajes  :)

que buen debate hay, yo les tengo que decir que sé muy poco sobre el tema del stack manejado en forma de parametros, como lo plantea Mauricio. no se si será mejor o peor, ya la experiencia me lo dirá. y sus opiniones deben ser tomadas muy en cuenta por la gran experiencia que poseen.

en base a esa pregunta que haces Cryn es parte del siguiente estudio, pero me atrevo a decirte que en lenguaje C no se pasa un array como argumento, y por eso el uso de puntero es un buen ejemplo de aplicación, en tu código lo que debes hacer es pasar la dirección del primer dato como parámetro (usando el operador & )y luego dentro del código haces el llamado de los demas datos (ya sea usando el operador * ó por medio de subindices)

parámetro= argumento

continuamos ....


-Punteros en Arrays

como sabran los arrays son arreglos de datos que van en direcciones consecutivas, es decir, uno detras del otro. un ejemplo de ello:

char cadena[7]={'T','o','d','o','P','i','c'};

probandolo en un código:

Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3. //*********************************
  4. char cadena[7]={'T','o','d','o','P','i','c'};
  5.  
  6. void main(){
  7. char c;
  8. int t;
  9.  
  10. for(t=0;t<7;t++){
  11.  c=cadena[t];
  12. }
  13.  delay_cycles(1);
  14. }

(http://img262.imageshack.us/img262/7065/image1ly5.jpg)



(http://img251.imageshack.us/img251/9850/image2vq7.jpg)


se puede usar punteros en el ejemplo anterior ¿como?

- declarando un puntero como char:

 char c, *p;

- lo inicializamos (le damos la dirección del primer elemento del array:

  p=&cadena[0];

- luego hacemos un barrido de direcciones para tomar el contenido de cada elemento y guardarlo en c

for(t=0;t<7;t++){
 c= *p + t;
}

ese programa tiene 2 errores y ya de una les digo que no funcionará:

- el primer error:

  según la precedencia del operador primero está el puntero y luego viene la suma, y así estariamos sumando direcciones que varian, la solución es usar *(p+i)

¿y que es eso de que varian?

cuando se recorre el arrays con el puntero, este debe ir sumando direcciones, pero direcciones de numeros constantes, es decir, si el tipo de datos es 1 byte, entonces el puntero debe acumular numeros enteros de 1 byte en 1 byte

si el tipo de datos es long (entero largo) entonces el puntero debe ir sumando direcciones de 2 bytes en 2 bytes

¿porque digo esto? es que p quedará fijo (la dirección) y el truco está en desplazar al puntero tantas posiciones sea el size del tipo de dato

este sería el segundo error y la solución es la misma *(p+i)

vamos a cambiar ese ejemplo por numeros long para que se entienda

Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3. //*********************************
  4. long cadena[7]={1000,2000,3000,4000,5000,6000,7000};
  5.  
  6. void main(){
  7. long c, *p;
  8. int t;
  9.  
  10.  p=&cadena[0];
  11.  
  12.  for(t=0;t<7;t++){
  13.   c= *p + t;
  14.  }
  15.  delay_cycles(1);
  16. }


(http://img251.imageshack.us/img251/4683/image3mq1.jpg)


(http://img260.imageshack.us/img260/4040/image4rr4.jpg)


(http://img251.imageshack.us/img251/641/image5th0.jpg)

fijense que p queda inmutable, y lo que hace el programa es contenido[0] + t

¡grave error!

arreglando el programa con *(p+t)



(http://img130.imageshack.us/img130/7672/image6du0.jpg)


(http://img251.imageshack.us/img251/8850/image7ss1.jpg)

con esto estamos garantizando que el puntero se moverá de 2 bytes en 2 bytes, es decir

*(p+t) =

 0x5 + 0x2 (desplazamiento de 2 byte)-> dame el contenido de la dirección 0x5
 0x5 + 1x2          "                -> dame el contenido de la dirección 0x7
 0x5 + 2x2          "                -> dame el contenido de la dirección 0x9
 0x5 + 3x2          "                -> dame el contenido de la dirección 0xA
 ...

  noten que la suma se realiza no intervalos de t sino en intervalos del ancho del tipo de dato.
  
una pregunta ¿y esto no es lo mismo que se hizo en el código del inicio del post?

o sea que ¿ c = cadena[t]; es igual a c = *(p + t) cuando p = &cadena[0]; ?

pues si señores y señoras, acabamos de ver un array al desnudo, como funciona en realidad, no es mas que un vulgar puntero escondido a nuestra vista.

solo que para hacer fácil la programación el compilador lo acepta de esta manera

si p es un puntero -> p = cadena (para el primer indice del arreglo)

es totalmente válido, se acepta que cadena es un puntero constante, o como le diría yo: un puntero nulo (ya que no se ve y tampoco se puede modificar)

ejemplos validos:

cadena[0]  =   *cadena

cadena[2]  = *(cadena + 2)

cadena  = *(cadena + i)


nota:
- el operador () es el primero que atiende el compilador antes que al resto

- cuando vayamos a matrices (arrays multidimensionales) vamos a ver con claridad el recorrido de un puntero

acomodando el código original, el que tenía la cadena de caracteres:

Código: C
  1. #include <18F4550.h>
  2. #use delay(clock=4000000)
  3. //*********************************
  4. char cadena[7]={'T','o','d','o','P','i','c'};
  5.  
  6. void main(){
  7. char c, *p;
  8. int t;
  9.  
  10.  p=cadena;
  11.  
  12. for(t=0;t<7;t++){
  13.   c=*(p+t);
  14.  }
  15.  delay_cycles(1);
  16. }


(http://img130.imageshack.us/img130/7061/image8dn6.jpg)


(http://img239.imageshack.us/img239/9139/image9cb5.jpg)


Nota Errata: los ejemplos de programas de este post, donde sale ...p+i... en realidad quise decir ...p+t... la variable i no existe en los ejemplos de este post

Título: Re: el tema de los punteros...
Publicado por: Cryn en 10 de Abril de 2007, 02:03:17
ahhh ok, ahora mismo lo reviso

te comentare, gracias.
Título: Re: el tema de los punteros...
Publicado por: gauchosuizo en 10 de Abril de 2007, 10:36:29
hola

muy bueno PalitroqueZ, segui asi, que vamos a aprender un monton.
Título: Re: el tema de los punteros...
Publicado por: jfh900 en 10 de Octubre de 2007, 08:58:56
Una pregunta referente a los tipos de variables. ¿Las variables locales en los pic de la gama alta se crean en el stack?.

Un saludo.
Título: Re: el tema de los punteros...
Publicado por: maunix en 10 de Octubre de 2007, 11:00:38
Una pregunta referente a los tipos de variables. ¿Las variables locales en los pic de la gama alta se crean en el stack?.

Un saludo.

Si, es más, es así en cualquier compilador que conozco.   No he revisado declararlas como static dentro de una función pero supongo que también la agregará al stack.

Título: Re: el tema de los punteros...
Publicado por: jfh900 en 10 de Octubre de 2007, 15:36:23
Pues el CCS por lo menos en los pic de la gama baja no loa hace así, ademas no lo puede hacer ya que el stack solo tgiene 8 posiciones y son muy pocas para ademas utilizarlo en la declaración de variables locales (esta comprobado en el listado de ASM que genera).

Un saludo.
Título: Re: el tema de los punteros...
Publicado por: maunix en 10 de Octubre de 2007, 15:50:13
Pues el CCS por lo menos en los pic de la gama baja no loa hace así, ademas no lo puede hacer ya que el stack solo tgiene 8 posiciones y son muy pocas para ademas utilizarlo en la declaración de variables locales (esta comprobado en el listado de ASM que genera).

Un saludo.

Jesús, estamos hablando del stack pror software no? no del stack para los calls verdad?  Digo esto por la coincidencia entre las 8 posiciones que mencionas y los 8 niveles de stack de hardware para los calls de los 16F.

Solo puedo decir que se puede hacer de otra forma, usando variables 'overloaded' , o superpuestas y manejar así a las variables locales para evitar tanto trabajo con el stack pero esto lo veo 'demasiado peligroso' si una función llama a otra y a otra... o si algún llamado a función depende del resultado de un cálculo.  ¿cómo sabría el compilador si va a sobreescribir o no dicha región como para asumir ubicarla 'superpuesta' con otra?   No se, no me parece ni cerca la mejor solución pero si los de CCS lo usan...  :shock: :shock:  , espero documenten en su manual las severísimas condiciones que esto puede acarrear.

Todavía recuerdo el Reset_CPU que en los 16F, según un código que subió Diego (RedPic) compilaba como un goto 0x0000 lo cual es hasta gracioso.

Saludos
Título: Re: el tema de los punteros...
Publicado por: RICHI777 en 10 de Octubre de 2007, 18:48:11
Normalmente las variables locales declaradas dentro de una función como static, no son otra cosa que variables globales. Con respecto a un comentario sobre el uso del Stack, el tema se maneja asi:
1. Si la arquitectura del micro tiene acceso y buen manejo de Stack, los parametros de las funciones, las variables locales y el retorno al llamador se hace sobre el stack, se conoce normalmente como "Stack Frame".
2. Existen ademas convenciones de llamadas donde algunos de estos se realizan sobre registros por cuestiones de optimizacion
3. En el caso donde la arquitectura no poseea una gran maniobrabilidad con el uso del Stack Pointer ( Ejemplo 8051 ) entonces el compilador y el linker arman un arbol de ejecucion y las variables locales son globales "compartidas", el arbol esta hecho de tal manera que dos variables locales dentro del mismo arbol de ejecucion nunca se pisen y los parametros se pasan por registros, ademas era posible una opcion de compilacion para instruir al mismo que el retorno al llamador se copiaba en variables locales, de esta manera y si tenias suficiente RAM tu "Max-Depth"( Maxima profundidad de llamada ) no estaba limitado por la  arquitectura.
Ejemplos de estos ultimos IAR para 8051 y derivados.

Estas son las razones por la cual FreeScale ( Ex Motorola ) tira a la basura la famila HC05 y la reemplazo por la HC08 justamente por no tener manejo de Stack y entonces no poder soportar compiladores "C".

Saludos a todos !
Título: Re: el tema de los punteros...
Publicado por: pajaro en 03 de Mayo de 2009, 20:38:16
hola amigos

amigo PalitroqueZ puedes revisar
algunos pos de este hilo, por el principio hay fotos que no aparecen
podrian reenlazarlas.

Magnificas estas explicaciones, saberes muy buenos.

Un saludo.
Título: Re: el tema de los punteros...
Publicado por: PalitroqueZ en 04 de Mayo de 2009, 18:21:55
Este Artículo también se encuentra en ucontrol:

http://www.ucontrol.com.ar/wiki/index.php/CCS_-_Punteros



Título: Re: el tema de los punteros...
Publicado por: xarox en 08 de Agosto de 2009, 18:45:55
Hay alguna manera de manejar un puntero de bits, si tengo una variable X y quiero leer el estado de los bits de la variable X con un for ¿Alguien sabe como hacerlo?
Título: Re: el tema de los punteros...
Publicado por: Suky en 08 de Agosto de 2009, 19:14:27
Puedes rotar y aplicar And:

Ejemplo, se lee el bit 3 y bit 5:

Byte>>3;
Bit=Byte&&0x01;
Byte>>2;
Bit=Byte&&0x01;

Saludos!
Título: Re: el tema de los punteros...
Publicado por: al9 en 12 de Agosto de 2009, 15:14:25
Hola.
Respecto a los punteros con cadenas, a ver que opinais de esta rutina y por que no funciona:

Código: C
  1. void displayString(char *x){
  2. int8 n;
  3. n=0;
  4.          i2cSTART();
  5.          while(x[n]!=0){
  6.             i2cWChar(x[n]);   //envia
  7.             n++;
  8.          }
  9.          i2cSTOP();
  10. ..
  11. ..
  12. void main()¨{
  13.   displayString("HOLA");
  14.  
  15. }
.. lastima que no vaya pues es muy elegante llamar asi a una funcion...

Las preguntas son:
¿En C las cadenas no acaba con el byte=0?
¿Que hacemos cuando llamamos a un procedimiento y ponemos las variables en el código?

Gracias.
Título: Re: el tema de los punteros...
Publicado por: migsantiago en 12 de Agosto de 2009, 16:23:22
Esto es inválido en cualquier compilador de C:

Código: [Seleccionar]
displayString("HOLA");
Debes armar el string y después pasar un puntero.

Código: [Seleccionar]
char temp[10];
...
sprintf(temp,"Hola");
displayString(temp);
Título: Re: el tema de los punteros...
Publicado por: Suky en 12 de Agosto de 2009, 16:42:13
Pero en CCS esto creo que funcionaria:

Código: C
  1. void displayString(char x){
  2.      i2cWChar(x);   //envia
  3. }
  4. void main(){
  5.     i2cSTART();
  6.     displayString("HOLA");  
  7.     i2cSTOP();
  8. }
Título: Re: el tema de los punteros...
Publicado por: gera en 12 de Agosto de 2009, 17:50:53
Esto es inválido en cualquier compilador de C:

Código: [Seleccionar]
displayString("HOLA");
Debes armar el string y después pasar un puntero.

Hola Santi. Hasta donde yo se, si se puede pasar un string a una funcion de esa forma (en cualquier compilador de C estandar).
Lo q hace el compilador es generar un puntero q apunta al pedazo de codigo donde esta escrito el "HOLA" o lo que sea. El tema es q estos son punteros estaticos y no podemos cambiar su valor (el lugar a donde apuntan). Si nuestra funcion va a operar sobre ese puntero, ahi si habria q hacer una igualacion de punteros o una copia del string.
saludos!!
Título: Re: el tema de los punteros...
Publicado por: migsantiago en 12 de Agosto de 2009, 18:50:58
Mmmhh... ando confundido  :D

Hace daño usar tanto C#... me confundo con los strings y chars  :oops:
Título: Re: el tema de los punteros...
Publicado por: gera en 12 de Agosto de 2009, 19:29:04
Jejeje, casi todos los productos de M$ hacen daño :P
Título: Re: el tema de los punteros...
Publicado por: Trev en 27 de Agosto de 2009, 23:21:46
Hola tengo una duda  :(,haber si alguien me la despeja :lol: ,porque al principio de este post alguien dijo que si no se le pasaban parametros por referencia a una función esta no podia modificar el valor de variables locales a main(q quisieramos pasar a esa función)pero q esto se podia solucionar usando variables globales(o bien los punteros claro) entonces yo pienso q no hay diferencia entre estos dos programas:(uso dev c++ para probar rápido la salida)


Código: [Seleccionar]

#include <stdio.h>


int suma(int a,int b)
{
int c;
c=a+b;
a=4;
b=8;
return(c);
}
 
main()
{
                                 int var,var2,resultado;

var1=2;
var2=3;
printf("%d %d\n\n",var1,var2); //Las variables antes de llamar a suma.
resultado=suma(var1,var2);
printf("El resultado de la suma es %d\n",resultado);
printf("%d %d\n\n",var1,var2); //El valor de las variables no
//se modifica dentro de main porq pasan por valor a la función suma.
getchar();
return(0);
}
O sea en este programa con variables locales a main var1 no es =4 ni var2=8.Lo mismo
que en este otro programa en donde pongo a las variables como globales..
Código: [Seleccionar]
#include <stdio.h>
int var1,var2,resultado; //Variables globales ahora

int suma(int a,int b)
{
int c;
c=a+b;
a=4;
b=8;
return(c);
}
 
main()
{
int var1,var2; //Son locales a main.
int resultado;
var1=2;
var2=3;
printf("%d %d\n\n",var1,var2); //Las variables antes de llamar a suma.
resultado=suma(var1,var2);
printf("El resultado de la suma es %d\n",resultado);
printf("%d %d\n\n",var1,var2); //El valor de las variables tampoco
//se modifica dentro de main por mas q ahora sean globales
getchar();//espera q se pulse un caracter del teclado
return(0);
}
Solo las modificaria haciendo algo asi si uso globales(ademas de los punteros claro)

int suma(int a,int b)
{
int c;
c=a+b;
var1=4;
var2=8;
return(c);
}
lo cual no tiene sentido porq seria una función exclusiva de dos variables,entonces esa es mi duda,Gracias espero se haya entendido lo q quise decir
   
Título: Re: el tema de los punteros...
Publicado por: gera en 27 de Agosto de 2009, 23:37:35
Si vas a usar variables globales, ya no es necesario pasarselas a la funcion.
por ej:

Código: [Seleccionar]
#include <stdio.h>
int a,b;
int suma()
{
   return (a+b);
}

int main()
{
   a=4;b=2;
   printf("%d\n", suma() );  //esto deberia dar 6
}
Título: Re: el tema de los punteros...
Publicado por: RALF2 en 19 de Octubre de 2009, 16:54:15
Que tal amigos!
Creo que llego un poco tarde a la funcion  :D
Pero de todas formas colocare mi granito de arena por si a alguien le sirve  :mrgreen:
Lo que dice migsantiago con respecto a pasar un string directamente a una funcion lo probe y es como el dice da error  :shock:
Por eso les coloco un ejemplito que lo he probado y funciona fino, de como pasar un string a una funcion utilizando punteros!.
Citar
#include <16F876a.h>
#device adc = 10
#use delay (CLOCK = 4000000)
#fuses XT,NOWDT,NOLVP

#define LCD_DB4   PIN_B4
#define LCD_DB5   PIN_B5
#define LCD_DB6   PIN_B6
#define LCD_DB7   PIN_B7

#define LCD_RS    PIN_C0
#define LCD_RW    PIN_C1
#define LCD_E     PIN_C2

#include <flex_lcd420.c>

void mostrar(char*ptr)

   while(*ptr)
   {
      printf(lcd_putc,"%c",*ptr);
      ptr++;
   }   
}


void main()
{
   char str1[21]="HOLA_TODOPIC";
   lcd_init();
   printf(lcd_putc,"Probando\n");
   mostrar(str1);
   
}

Les adjunto la foto del circuito en accion  :mrgreen:

Saludos
Título: Re: el tema de los punteros...
Publicado por: RALF2 en 19 de Octubre de 2009, 17:49:42
Otro ejemplito mas de como pasar una variable a una funcion por referencia  :mrgreen:

Citar
//En este caso muestro como pasar una variable por referencia a una funcion ulizando el &,
//luego dentro de la funcion muestro el valor de la variable y paso seguido modifico su valor
// original('R') y lo cambio por una 'H'
//para despues dentro del main mostrar su nuevo valor!
//!Este metodo no sirve para pasar un array o string¡  ;)
#include <16F876a.h>
#device adc = 10
#use delay (CLOCK = 4000000)
#fuses XT,NOWDT,NOLVP

#define LCD_DB4   PIN_B4
#define LCD_DB5   PIN_B5
#define LCD_DB6   PIN_B6
#define LCD_DB7   PIN_B7

#define LCD_RS    PIN_C0
#define LCD_RW    PIN_C1
#define LCD_E     PIN_C2

#include <flex_lcd420.c>


void mostrar (char & ptr);

void main()
{
   char str1= 'R';
   lcd_init();
   printf(lcd_putc,"Probando\n");
   mostrar(str1);
   printf(lcd_putc,"%c",str1);
   
}

void mostrar(char & ptr)

      printf(lcd_putc,"%c\n",ptr);
      ptr='H';
}

Saludos
Título: Re: el tema de los punteros...
Publicado por: Cryn en 20 de Octubre de 2009, 16:19:11
buenos ejemplos RALF, ya tomé nota

y ahora viendo ello me da mucha curiosidad lo siguiente:

void mostrar (char & ptr);
void mostrar (char * ptr);

cual es la diferencia en hacerlo de una u otra forma?? yo generalmente uso la segunda

saludos.
Título: Re: el tema de los punteros...
Publicado por: Suky en 20 de Octubre de 2009, 16:55:42
buenos ejemplos RALF, ya tomé nota

y ahora viendo ello me da mucha curiosidad lo siguiente:

void mostrar (char & ptr);
void mostrar (char * ptr);

cual es la diferencia en hacerlo de una u otra forma?? yo generalmente uso la segunda

saludos.


Aquí (http://www.todopic.com.ar/foros/index.php?topic=27462.msg226157#msg226157) una respuestas del maestro RICHI al respecto  ;-)

Saludos!
Título: Re: el tema de los punteros...
Publicado por: Cryn en 20 de Octubre de 2009, 18:22:34
mmm ya veo, en el fondo es lo mismo entonces, solo que hay que tener cuidao con su sintaxis entonces, para llamar a la función en el cualquier caso no hace falta colocar ni & ni * en el parámetro, no?

bien bien, no uso muchas veces punteros, y cuando los uso si que ayudan, y se me olvida rápido algunos detalles jeje

saludos, gracias por la respuesta suky

Título: Re: el tema de los punteros...
Publicado por: RALF2 en 20 de Octubre de 2009, 22:36:51
Que tal amigos!
cryn hay dos detalles en los ejemplos que coloque en iuno pase un array (string) por referencia a una funcion y en el otro ejemplo pase una variable por referencia a una funcion.
Se parecen pero no son iguales  :shock:
si vas a pasar un string por referencia a una funcion debes colocar dentro de los parametros de la funcion el *. Pero si vas a pasar es una variable a una funcion puedes hacerlo de dos maneras:
Una la que te coloque usando el & como parametro de la funcion la otra es como dice richi  :mrgreen:
yo iva a colocar otro ejemplo de ello pero me imagine que no hacia falta  :mrgreen:
aplicando el metodo que usa richi y que es mas conocido.  :mrgreen:

Bueno cualquier duda estamos por aqui  ;-)
Ah y los punteros son muy utilies no los olvides te ayudan muchisimo!

Saludos
Título: Re: el tema de los punteros...
Publicado por: lucaspascual en 02 de Mayo de 2013, 18:45:46
Buenas tardes, estoy haciendo un proyecto para introducir en el pic los datos de un calibre digital, el programa para tomar 8 bits de datos esta hecho, pero ahora cuando quiero visualizarlo en lcd no pasa nada, me parece q es un problema de donde inicializo el lcd(dentro de la interrupcion o fuera). y falta de uso de punteros puede ser cierto esto?
Este es el programa.
Espero q me puedan ayudar. Saludos

#include <16f877.h>
#fuses hs,nowdt,put,nowrt,nolvp,noprotect
#use delay(clock=20000000)
#use fast_io(b)
#include <lcd.c>
int8 dato;

#int_ext

ext_isr()
{
 
delay_us(496);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,0);
else
bit_clear(dato,0);
delay_us(12);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,1);
else
bit_clear(dato,1);
delay_us(12);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,2);
else
bit_clear(dato,2);
delay_us(12);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,3);
else
bit_clear(dato,3);
delay_us(12);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,4);
else
bit_clear(dato,4);
delay_us(12);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,5);
else
bit_clear(dato,5);
delay_us(12);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,6);
else
bit_clear(dato,6);
delay_us(12);
output_high(pin_b7);
output_low(pin_b7);
if (input(pin_b1)==1)
bit_set(dato,7);
else
bit_clear(dato,7);
printf(lcd_putc,"\f%u",dato);

}

void main()
{

lcd_init();
set_tris_b(0x03);
output_low(PIN_B7);
port_b_pullups(true);
enable_interrupts(int_ext);
ext_int_edge(l_to_h);
enable_interrupts(global);

while(1)
{
 
}
}