Autor Tema: Microcursillo en C  (Leído 178984 veces)

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

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
RE: Microcursillo en C
« Respuesta #75 en: 18 de Agosto de 2004, 11:18:00 »
Juer pues yo diría que las había visto declaradas como tipo long,ya te digo que cogí tu codígo,lo probé y funcionó bien.

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
RE: Microcursillo en C
« Respuesta #76 en: 19 de Agosto de 2004, 08:25:00 »
Mas cuestiones para echarle un ojo (o los dos 0_o).
Lo mas típico es basar nuestros programas en el uso de los tipos de datos básicos que
trae implementados el compilador.Son los tipos simples: int,char,short,long,float,enum,etc...
Lo bueno es que a partir de estos tipos predefinidos,el usuario puede crear sus propias
estructuras de datos (tipos definidos por el usuario) para hacer más ordenado y sencillo
el manejo de datos a escalas mayores.
Imaginemos que tenemos 5 sensores de temperatura conectados al micro,cada uno a una entrada
analógica.Para procesar la información recogida por estos sensores tendríamos que usar una
variable para cada uno de ellos y trabajar con estas variables de manera individual.
Sin embargo,es posible definir un tipo creado por nosotros,del cual podremos crear
una única variable en cualquier parte del código que pueda contener los 5 datos de los 5
sensores en cada momento.Podría ser una cosa así:


Codigo:

///////////////////////////////////// PREPROCESADO ////////////////////////////////////

#include <16F876.h>
#use delay(clock=10000000)
#fuses HS,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOWRT
#define use_portb_lcd TRUE
#include "lcd.c"

////////////////////////////////////// CONSTANTES /////////////////////////////////////

const unsigned int NUM_SENSORES = 5;

//////////////////////////////////////// TIPOS ////////////////////////////////////////

typedef int Tsensores[NUM_SENSORES];
// Esto es un array de 5 enteros(int es el tipo base).Puede albergar,pues eso,5 valores
// individuales comprendidos entre 0-255.
// Tsensores es el nombre que le hemos puesto al tipo,la T se suele poner para
// tener constancia,por si lo vemos en alguna parte del código,de que se trata de un
// tipo definido de usuario.

///////////////////////////////////// CABECERAS ///////////////////////////////////////

int temperatura(int canal);

/////////////////////////////////////// RUTINAS ///////////////////////////////////////

int temperatura(int canal)
  {
  // Esta rutina se supone que captura un valor en el canal adc que indique el
  // parámetro canal (0,1,2,3 ó 4),lo procesa y devuelve un valor de temperatura.
  int valor;
  // blablabla...
  return(valor);
  }

////////////////////////////////////// PRINCIPAL //////////////////////////////////////

void main()
   {
   int j;
   Tsensores sensores; // Array de 5 posiciones,cada posición es un entero.
   // La forma de acceder a cada uno de los elementos del array es usando su número de
   // orden (índice) dentro de él.
   // No olvidar que el primer elemento de un array tiene SIEMPRE índice 0.
   // Si el array tiene dimensión 5 -> primer elemento,índice 0
   //                               -> último elemento,índice 4
   
   for(j = 0; j <= 4; j++)  // Vamos a poner todos los valores a 0
     {
     sensores[j] = 0; // Así se accede al elemento de un array,mediante su índice.    
     }
   j = 0;  // Después del for,el valor de j es indeterminado,así que
           // la ponemos a 0 para afrontar el siguiente bucle.
   while(j < 5)  // Bucle infinito
     {
     // Capturamos la temperatura de todos los sensores continuamente,con un intervalo
     // de tiempo de un segundo entre sensor y sensor.
     // Se ve la correspondencia entre el número del canal y la posición dentro del array.
     sensores[j] = temperatura(j);
     delay_ms(1000);
     j++;
     if(j==5)  // Cuando j=5,la ponemos otra vez a 0 para no salir del bucle y empezar de nuevo
       {
       j = 0;
       }
     }
   }




El tipo base de un array puede ser cualquier tipo(int,char,boolean,array...).
Los arrays pueden ser multidimensionales,como por ejemplo...

typedef BOOLEAN Tmatriz[4][4]

...que es un tipo array bidimensional que contendrá 16 variables booleanas,y que puede servir por ejemplo para manejar una matriz de leds de 4x4.
Como comentario,hacer alusión al tipo "string",el cual no es más que un tipo array cuyo
tipo base es char.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
RE: Microcursillo en C
« Respuesta #77 en: 19 de Agosto de 2004, 11:09:00 »
Claro como el agua. Muchas gracias Modulay

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
RE: Microcursillo en C
« Respuesta #78 en: 20 de Agosto de 2004, 05:24:00 »
Un array puede ser de cualquier tipo,de caracteres,de enteros,de flotantes...
Pero sólo podrá contener un único tipo base,por lo que todos sus elementos,
da igual cuantos sean,serán del mismo tipo.
Otra estructura muy útil que nos permite implementar un conjunto con diferentes
tipos de datos es el registro.Para definir un tipo registro se usa la palabra
reservada "struct" (Las palabras reservadas son aquellas que UNICAMENTE pueden
ser utilizadas con el propósito para el que han sido concebidas: int,char,struct,
while,typedef,return,if,void,etc..).


Codigo:

///////////////////////////////////// PREPROCESADO ////////////////////////////////////

#include <16F876.h>
#use delay(clock=10000000)
#fuses HS,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOWRT
#define use_portb_lcd TRUE
#include "lcd.c"

//////////////////////////////////////// TIPOS ////////////////////////////////////////

struct Tregistro {  
         int edad;        
         float estatura;
         boolean casado;
         };
// Nuestro registro contiene tres campos,una variable booleana llamada "casado",
// una entera llamada "edad" y una real llamada "estatura".

////////////////////////////////////// PRINCIPAL //////////////////////////////////////

void main()
   {
   struct Tregistro juan,antonio; // Creamos 2 variables tipo registro.
   // Para acceder a un campo de un registro,se pone el nombre de la variable
   // registro seguido de un punto y el nombre del campo.
   juan.edad = 28;            // Llenamos los registros con datos
   juan.estatura = 1.75;      //
   juan.casado = TRUE;        //
   antonio.edad = juan.edad;  //
   antonio.estatura = 1.81;   //
   antonio.casado = FALSE;    //
   for(;;)  {}
   }




CCS no permite el paso de registros como parámetros a un procedimiento,pero es algo que
sí se puede hacer en C.La alternativa a esta limitación es el uso de punteros.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
RE: Microcursillo en C
« Respuesta #79 en: 20 de Agosto de 2004, 05:36:00 »
Intuyo que sí, pero ¿puede una matriz formar parte de un registro?, ¿y viceversa?

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
RE: Microcursillo en C
« Respuesta #80 en: 20 de Agosto de 2004, 06:09:00 »
Sip!!

Codigo:

///////////////////////////////////// PREPROCESADO ////////////////////////////////////

#include <18F258.h>
#use delay(clock=10000000)
#fuses HS,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOWRT
#define use_portb_lcd TRUE
#include "lcd.c"

//////////////////////////////////////// TIPOS ////////////////////////////////////////

struct Tregistro {        // Este es el más pequeño
         int edad;
         float estatura;
         boolean casado;
         };
         

typedef struct Tregistro TmatrizRegistros[5][5];  // Matriz de 25 registros
                                                  // Este es el mediano

                                           
struct TregistroMatrices {          // Este es el que los contiene a todos
         TmatrizRegistros hombres;  
         TmatrizRegistros mujeres;
         };

////////////////////////////////////// PRINCIPAL //////////////////////////////////////

void main()
   {
   struct TregistroMatrices poblacion;
   poblacion.mujeres[1][3].edad = 18;  
   for(;;)  {}
   }




Otra cosa,se me olvidó decir que CCS tampoco admite arrays ni matrices de booleanas


Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
RE: Microcursillo en C
« Respuesta #81 en: 20 de Agosto de 2004, 06:20:00 »
CRACK

(no me he roto, es sencillamente lo que eres)

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
RE: Microcursillo en C
« Respuesta #82 en: 24 de Agosto de 2004, 04:13:00 »
Ahora que por fin me funcionan mis malditas pantallitas LCD, puedo seguir aprendiendo C.

Como ejercicio me he planteado jugar con los bucles y aprender a dominarlos, sobre todo en cuanto a sintaxis. Para ello, y aprovechando que ya funcionan mis LCD, he diseñado una rutina que saca por la pantalla dos cadenas de caracteres usando un efecto parecido a Matrix, una cadena en la línea superior y la otra en la inferior.

Aunque funciona, el código no está depurado y tampoco está muy legible, pero todavía no estoy muy ducho en estas lides.

Bueno, lo pego aquí y lo comentamos, ¿no?

Codigo:
#include <16F877A.h>
#use delay(clock=20000000)
#fuses HS,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOWRT
#define use_portb_lcd TRUE
#include "lcd.c"
#include "string.h"

// Esta función la he tenido que incluir aquí porque si hacía un include de su librería y la llamaba me fallaba. Pegándola aquí funciona bien.

unsigned int32 _Randseed = 1;

long rand(void)
{
   _Randseed = _Randseed * 1103515245 + 12345;
   return ((unsigned long)(_Randseed >> 16) % 93);
}

// Esta función recibe dos cadenas de caracteres y sus longitudes, y las representa en un LCD 2x16 con un efecto parecido a Matrix

void matrix (char *cadena1, char *cadena2, int largo1, int largo2)
{
   int i,j;
   
   // durante 15 ciclos mostramos caracteres aleatorios
   for (i=0;i<=15;i++) {
      for (j=1;j<=16;j++) {          // va pasando por cada columna del LCD
         lcd_gotoxy (j,1);         // pone el cursor en la primera fila y la columna j
         printf (lcd_putc,"%C",rand()+161);   // escribe un caracter aleatorio comprendido entre el 161 y el 253
         lcd_gotoxy (j,2);         // pone el cursor en la segunda fila y la columna j
         printf (lcd_putc,"%C",rand()+161);   // escribe un caracter aleatorio comprendido entre el 161 y el 253
      };
      delay_ms (100);            // y esperamos una décima de segundo para que dé tiempo a verlo
   };

   // en los siguientes 16 ciclos vamos desvelando los caracteres correctos en posición par
   for (i=1;i<=16;++i) {          // repetimos 16 veces para acompañar el efecto Matrix
      for (j=0;j<=15;++j) {         // pero ya vamos cumplimentando los 16 caracteres, del 0 al 15
         if (j<=i & bit_test (j,0)) {      // sólo escribiremos el carácter si el bucle principal ha pasado por aquí y está en posición par
            lcd_gotoxy (j+1,1);         // vamos allí, en la primera fila
            if (j<largo1)         // si no hemos sobrepasado el tamaño de la cadena
               printf (lcd_putc,"%C",cadena1[j]); // escribimos la letra que corresponda
              else            // y si no
               printf (lcd_putc," ";      // un espacio en blanco
            lcd_gotoxy (j+1,2);         // vamos allí, en la segunda fila
            if (j<largo2)         // si no hemos sobrepasado el tamaño de la cadena
               printf (lcd_putc,"%C",cadena2[j]); // escribimos la letra que corresponda
              else            // y si no
               printf (lcd_putc," ";      // un espacio en blanco
         } else {            // si aún no hemos llegado o se trata de una posición impar
            lcd_gotoxy (j+1,1);         // en la primera fila
            printf (lcd_putc,"%C",rand()+161);   // escribimos carácter matrix aleatorio
            lcd_gotoxy (j+1,2);         // y en la segunda fila
            printf (lcd_putc,"%C",rand()+161);  // escribimos carácter matrix aleatorio
         };
      };
      delay_ms(100);            // y esperamos una décima de segundo para que dé tiempo a verlo
   };

      // y en los siguientes 16 ciclos vamos desvelando los caracteres correctos en cualquier posición
   // aunque para el espectador sólo son nuevos los impares
   // no comento esta rutina porque es igual que la anterior, exceptuando la condición de la paridad

   for (i=1;i<=16;++i) {
      for (j=0;j<=15;++j) {
         if (j<=i) {
            lcd_gotoxy (j+1,1);
            if (j<largo1)
               printf (lcd_putc,"%C",cadena1[j]);
              else
               printf (lcd_putc," ";
            lcd_gotoxy (j+1,2);
            if (j<largo2)
               printf (lcd_putc,"%C",cadena2[j]);
              else
               printf (lcd_putc," ";
         } else {
            lcd_gotoxy (j+1,1);
            printf (lcd_putc,"%C",rand()+161);
            lcd_gotoxy (j+1,2);
            printf (lcd_putc,"%C",rand()+161);
         };
      };

      delay_ms (100);

   };
}

void main()
   {
   char cad1[16],cad2[16];

   output_high (PIN_B0);      // es un led que se enciende al arrancar, y me sirve para señalar si ha habido un reset
   delay_ms (300);         // lo mantengo encendido 3 décimas de segundo
   output_low (PIN_B0);         // y lo apago
   lcd_init();            // inicializamos la pantalla
   strcpy (cad1,"EFECTO MATRIX";   // preparamos las strings a mostrar
   strcpy (cad2,"(por Nocturno)";  
   
   matrix (cad1,cad2,strlen(cad1),strlen(cad2));   // e invocamos a la función
   // no he conseguido calcular las longitudes de las strings en la función, por eso hago el cálculo en la llamada

   sleep();            // ponemos el bichito a dormir la siesta

   }


Ya me diréis.

Editado:
No sé porqué cojones saca los caretos si está en formato código, pero si queréis probar el código, donde aparezca un careto va un paréntesis cerrado.

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
RE: Microcursillo en C
« Respuesta #83 en: 24 de Agosto de 2004, 07:37:00 »
Aunque esté en formato código,tienes que desactivar la opción "usa caretos".
He probado a incluir la librería stdlib.h para no tener que implementar la función rand() en el código y no me da error.
La función rand() realiza una serie de pasos matemáticos para llegar a un resultado considerado "aleatorio".Estos pasos parten del valor de una variable "semilla"(_Randseed).Si esta semilla tiene siempre el mismo valor,obtendrás una secuencia de aleatorios que se repetirá de forma consecutiva.Para variar el valor de esta semilla se usa la función srand(semilla),también incluída en la librería,por lo que se me ocurre que cambies el valor de la semilla antes de cada llamada a rand().Podrías conseguirlo por ejemplo asignándole a la semilla el valor de alguna de las dos variables de control que usasen los bucles "for",que en cada iteración tendrían un valor diferente.Puede que tampoco fuese del todo aleatorio,pero la repetición de secuencias sería en menor grado.
Podrías intentar que los caracteres de las dos cadenas se fueran descubriendo tb de forma aleatoria,así quedaría más chulo.
Podría servir crear un array de enteros(ya que de booleanas no se puede) de igual longitud a tus cadenas que te indicase que carácter está descubierto y que carácter no lo está.Así en cada una de las iteraciones que descubren caracteres de la cadena,llamas a rand() para que te devuelva una posición de la cadena,compruebas si ya está destapada,y si no lo está la descubres.

La implementación de rand() y srand() podría ser algo asi:
Codigo:

#define RAND_MAX 255
#define LONG_CADENA 14

unsigned int32 semilla = 1;


long rand(unsigned int maximo)
{
   semilla = semilla * 1103515245 + 12345;
   return ((unsigned long)(semilla >> 16) % maximo);
}


void srand(unsigned int32 seed)
{
   semilla = seed;
}



De esta forma,si quieres que el aleatorio esté comprendido entre 0 y 14,haces rand(LONG_CADENA),y si es para generar el carácter aleatorio,usas RAND_MAX como parámetro.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
RE: Microcursillo en C
« Respuesta #84 en: 24 de Agosto de 2004, 07:47:00 »
Bien, gracias por tus consejos.

Depuraré el programa e intentaré lo del destape aleatorio, aunque en vez de buscar la posición a destapar de forma aleatoria, lo mejor va a ser desordenar la serie 1 a 16 de manera que me garantice que siempre se va a destapar todo. Aunque es improbable, con el método que me propones podría darse la casualidad de una posición que nunca sale, y entonces tardaría mucho en mostrarse el mensaje completo.

Gracias de nuevo

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
RE: Microcursillo en C
« Respuesta #85 en: 24 de Agosto de 2004, 08:18:00 »
En eso tienes razón,aunque todo se haría a la velocidad de la ostia,se apreciaría cierta tardanza en los últimos caracteres.
La solución podría ser esto:

int posiciones[14] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13};
// Generamos un aleatorio entre 0 y la longitud de la cadena(14).
// Accedemos a "posiciones" y vemos que elemento toca descubrir.
// Descubrimos el carácter.
// Despues "eliminamos" del array "posiciones" dicho elemento,y todos los que están después
// los reubicamos desplazándolos hacia atrás una posición...
// ...(en el caso de que no fuera el último).
// Ahora solo tenemos que generar el aleatorio con el parámetro "maximo" decrementado
// en una unidad.
// Así conseguimos que con cada aleatorio generado,descubrimos un carácter que aún
// sigue oculto.

O más fácil todavía,en vez de mover tantos elementos hacia atrás,coges el último y lo colocas en la posición que ha quedado "vacía".Eso si,cada vez que hagas esto, debes tener en cuenta en qué posicion de las 14 está el último elemento.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
RE: Microcursillo en C
« Respuesta #86 en: 25 de Agosto de 2004, 03:26:00 »
Pues ya he hecho los cambios que comentábamos ayer.
Finalmente he optado por desordenar una matriz de posiciones que contiene los números 1 al 16 y luego ir destapandolos siguiendo el desorden que haya quedado.

Está aquí y la verdad es que el resultado que ha quedado está chulísimo.

Aún así, tengo dos dudas que me gustaría lanzar al foro porque no acabo de entenderlas:

1.- ¿cómo puedo calcular en una función la longitud de un string que es recibido como parámetro?. No he conseguido que me funcione.

2.- ¿Cómo puedo hacer operaciones entre int y float y que el resultado sea un int?. En realidad, el problema lo tengo porque no domino las conversiones entre tipos de datos, pero no he encontrado documentación clara al respecto.

Desconectado oshow

  • PIC18
  • ****
  • Mensajes: 321
RE: Microcursillo en C
« Respuesta #87 en: 25 de Agosto de 2004, 04:01:00 »
Hola Nocturno.

En cuanto a lo primera pregunta, existen dos tipos de conversiones de tipos de datos implicitas y explicitas Cuando el compilador realiza la conversion de forma automatica como es el caso que planteas (sumar int + float , resultado float) es conversión implicita. La explicita es la que realiza el programador (casting de variables), se indican precediendo a la constante o variable que se desea convertir por el tipo a convertir  rodeado entre parentesis.

Por ejemplo en tu caso sería una conversion explícita:

int a=2,c;
float b=2.5;
 
c=(int) (a+b);

Con esto conviertes la suma de a y b (float, porque el compilador realiza una conversion implicita) y tu lo conviertes a int para almacenarla en la variable c (tipo entero).

Esto en cuanto a ansi C ahora no lo he probado con el CSS, no se si lo soporta, en caso de que no lo soporte,otra forma de hacerlo (un poco mas cutre) seria usando una varible temporal por ejemplo:


int a=2,c,temp;
float b=2.5;

temp=b;
c=a+temp;

Esto estoy casi seguro que lo aceptará el CCS (aunque no veo porque debería aceptar lo de arriba).

En cuanto a la segunda pregunta, para calcular la longitud de una cadena tienes la funcion strlen() que devuelve un entero con la cantidad de elementos de la cadena. También puedes hacerlo sin usar la funcion, mediante un for y esperando al caracter nulo "" que es el del final de la cadena.

Saludos.

PD: Vaya, he visto que he contestado las preguntas en orden inverso....

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
RE: Microcursillo en C
« Respuesta #88 en: 25 de Agosto de 2004, 04:10:00 »
Respecto a las conversiones de datos, la explicación que has hecho es como yo creía que el compilador lo hacía, pero he tenido problemas para implementarlo en mi programa y finalmente he tenido que decantarme por otra solución. No puedo garantizar que el CCS no lo admita porque puede ser que me haya confundido, pero me da la impresión de que no se comporta como el Ansy C.

Con respecto al segundo tema, al del cálculo de la longitud del array, lo he intentado con el strlen, pero sólo me funciona en el main(), no en la función a la que llamo. Si miras el ejemplo que he subido, verás a qué me refiero.

Muchas gracias por responder Oshow.

Desconectado MGLSOFT

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 7912
RE: Microcursillo en C
« Respuesta #89 en: 27 de Agosto de 2004, 13:29:00 »
Escrito originalmente por pocher
Muy sencillo, cogeros un libro con ejercicios en ensamblador (el de Angulo podría servir) y empezais por los primeros pasándolos a C.

Podeis plantear aquí el enunciado y su resolución.





En la pagina de Angulo encontraran los ejemplos en C, los mismos que hay en assembler...
Todos los dias aprendo algo nuevo, el ultimo día de mi vida aprenderé a morir....
Mi Abuelo.