Problema con dado electrónico rand() y srand() en XC8

Hola.

Estoy intentando aprender a generar números aleatorios en XC8 haciendo un dado electrónico con un display de 7 segmentos. De momento estoy centrado en comprobar que me funciona la generación de un número aleatorio mediante rand() y srand() pero al compilar me da el siguiente error:

main.c:31: error: could not find space (20 bytes) for variable main@F403

(La línea 31 es --> int tabla7seg [10]={0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x98};)


Y este es el código:

PHP:
/* 
 * File:   main.c
 * Author: nimio
 *
 * 16F84A
 *
 * DADO ELECTRÓNICO
 * 7 SEGMENTOS DE ÁNODO COMÚN
 *
 * Created on 11 de marzo de 2013, 1:06
 */

#include <xc.h>
#include <stdlib.h> // LIBRERÍA PARA PODER USAR LA FUNCIÓN SRAND.


#define _XTAL_FREQ 4000000

#pragma config FOSC=XT, WDTE=OFF, PWRTE=ON, CP=OFF



/*
 * 
 */

void main(void) {

   
   char a; // VARIABLE PARA LA TABLA DE 0-9;
   int tabla7seg [10]={0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x98}; // 0-9 EN HEXADECIMAL.

   srand(10);
   

   TRISB=0;
   
   PORTB=1;

   do {
       
       a=rand();
       PORTB=(tabla7seg [a]);
       
   
   } while(1);


}

Agradecería que alguien me dijera donde está el error.
Si omito a=rand(); compila correctamente.

Decir que estoy aprendiendo a programar.

Gracias de antemano.

1 Saludo.
 
Última edición:
Probablemente se deba a su escasa memoria que tiene el 16F84 y esa funcion consuma mucha memoria
 
Gracias por responder Ajna.

Si... eso he pensado yo también aunque me sorprendería que fuera así.
La gente hace dados electrónicos con los 16F84A.

A ver si alguien sabría aclararlo y/o como comprobarlo.

Saludos.
 
Es cierto lo que dices, pero la mayoria de la gente que usa el 16F84 lo programa usando el lenguaje ensamblador, por lo cual tienen mayor control sobre la memoria utilizada, la verdad no conosco mucho de PIC pero no faltara alguien que te de la respuesta correcta. Lo que si te puedo decir es que usar funciones de C puede ocupar mucha mas memoria que si lo haces con ensamblador, "claro esta si lo haces bien"
 
Hola.
Una solución simple. Si no vas a utilizar para nada el Timer0 del PIC te sugiero que lo uses como base para generar números aleatorios, por ejemplo, capturas la cuenta del Timer0 cuando presionan el pulsador (acto de tirar lo dados) la rutina procede a verificar en que cuenta se encuentra el Timer0:

(0 - 10) Dígito 1
(11 - 20) Dígito 2
(21 - 30) Dígito 3
...

De acuerdo a esto, determina que dígito va a mostrar en el display.
Puedes adicionar un condensador de 1uF por ejemplo a la entrada del pulsador solo para mantener u obligar que el estado lógico sea indeterminado por mayor tiempo, haciendo que la rutina de comparación se repita más veces a pesar de haber soltado el pulsador.

PD. Sugiero que indagues sobre las funciones srand() y rand(), me parece que solo funciona para PIC18.

Saludos.
 
Última edición:
Gracias por la respuesta ByAxel.

Efectivamente no tengo pensado usar el Timer0.
Investigando he visto que usan el Timer 0 y el tiempo de pulsación de un pulsador para generar números aleatorios pero me interesaba saber usar srand() y rand().

Por lo visto tendré que probar estas funciones en un pic de más prestaciones como el 16F877 que es el otro que tengo, espero que con ese funcione (y que no sea exclusivo de los 18F).
Buscaré un poco más.

Entonces en un un principio se podría decir que mi código está bien?

Sigo investigando y toda ayuda será apreciada.

Gracias!!

1 Saludo
 
Tambien podrias usar el ADC del micro para capturar un valor de voltaje aleatorio, creo que eso si seria mas aleatorio la verdad no lo he probado, de todos modos el F84 no tiene adc
 
Exacto, no tiene ADC.

Sólo me interesa saber usar srand() y rand() y porque falla mi programa. Partiendo de ahí... ya se estudiarán otras posibilidades de aletoriedad.

Gracias por la respuesta.

1 Saludo.
 
Hola de nuevo.

Ya he dado con el problema, mi error estaba efectivamente en "tabla7seg" (línea 31) al definirla como int que ocupa 16 bits, así que la he redefinido como char que ocupa 8 bits. Así compila perfectamente.

Pero... sigue sin darme número aleatorio, es decir... si pongo srand(0); me sale un 0 y si pongo cualquier otro valor siempre me sale 8.

He probado con #define _RAND_MAX 10 y omitir srand(10); y sí, parece que hace "algo" aleatorio; tiene predilección por el 8 y lo va alternando con 2 o 3 números más pero hay otros que nunca muestra, también salen iluminaciones del display erráticas.

Sigo perdido.

Vuelvo a pedir ayuda porfavor.

Gracias por vuestra atención ;).

1 Saludo!

Hola de nuevo.

Ya he dado con el problema, mi error estaba efectivamente en "tabla7seg" (línea 31) al definirla como int que ocupa 16 bits, así que la he redefinido como char que ocupa 8 bits. Así compila perfectamente.

Pero... sigue sin darme número aleatorio, es decir... si pongo srand(0); me sale un 0 y si pongo cualquier otro valor siempre me sale 8.

He probado con #define _RAND_MAX 10 y omitir srand(10); y sí, parece que hace "algo" aleatorio; tiene predilección por el 8 y lo va alternando con 2 o 3 números más pero hay otros que nunca muestra, también salen iluminaciones del display erráticas.

Sigo perdido.

Vuelvo a pedir ayuda porfavor.

Gracias por vuestra atención ;).

1 Saludo!



Bueno, si elimino srand(10); y #define _RAND_MAX 10 y modifico la instrucción do para que sólo muestre los números aleatorios entre 0 y 9 funciona:

PHP:
do {

       a=rand();
       if (a<=9) {
       PORTB=(tabla7seg [a]);
       __delay_ms(1000);

       }
   
   } while(1);

Pero me resisto a pensar que esa tiene que ser la solución, para algo está srand() pero no logro que funcione.

Sigo en ello...

Saludos!
 
Última edición:
El problema que tienes es que un micro por si solo no puede generar numeros aleatorios, existen funciones pseudoaletorias que generan secuencias de numeros que parecen aleatorios, pero requieren un numero( mejor conocido como semilla) para comenzar. Si siempre le das la misma semilla siempre generaran la misma secuencia numerica cada vez que enciendas el micro

Y es por esto qeu se ocupan junto con algun otro dispositivo que sea externo y que pueda obtener datos aleatorios externamente, como medir el tiempo de pulsacion de un boton, o un voltaje en un pin al aire en el ADC

No conozco el XC8 pero leyendo un poco en internet puedo dedicir que srand inicializa la funcion pseudoaleatoria y rand obtiene el siguiente valor que requieres, si siempre inicializas srand con la misma semilla siempre obtendras la misma secuencia de valores con rand
 
Hola Chico3001, gracias por tu respuesta.

El tema de la semilla lo conozco, pero quería ir por partes... ser capaz de generar un número aleatorio y después intentar mejorarlo.

Pero el tema está en que no se que sentido tiene srand(); si ponga el valor que le ponga no parece respetar el rango y me obliga a tener que usar la condición de que el número sea menor o igual a 9, así funciona pero quiero ser capaz de poder usar srand() correctamente.
Esa es mi batalla actual.

A ver si alguien sabe el porqué.

1 Saludo!

y gracias!!
 
Hola Basalto.

Gracias por el link, ya estuve mirando por el foro de Microchip, pero creo que no me soluciona el problema.

En el link el problema es que siempre le genera la misma secuencia de números aleatorios y le proponen usar el TMR0 o el ADC para variar el valor de srand() cada vez, eso lo tengo presente y lo probaré cuando llegue el momento.

Mi problema es que según entiendo si pongo srand(10); los números aleatorios generados serán de 0 a 10 pero no es el caso y eso me descoloca (y si resulta que el rango se define con #define _RAND_MAX 10 tampoco me funciona), de paso si alguien me puede explicar las diferencias entre srand y RAND MAX..??.

Tal como lo tengo genera números aleatorios en todo su rango y luego visualiza sólo los que están entre 0 y 9, de esta manera se aprecia que a veces el "baile" de números mientras se generan se ralentiza, supongo que es cuando desecha números mayores de 9.

Acaso lo tengo mal entendido y srand() sólo sirve para variar el punto de inicio de aletoriedad cada vez mediante TMR0 u otra variable??

En resumen... como se acota el rango de aleatoriedad de 0-10????

Gracias por la atención

Saludos.
 
Hola Basalto.

Gracias por el link, ya estuve mirando por el foro de Microchip, pero creo que no me soluciona el problema.

En el link el problema es que siempre le genera la misma secuencia de números aleatorios y le proponen usar el TMR0 o el ADC para variar el valor de srand() cada vez, eso lo tengo presente y lo probaré cuando llegue el momento.

Mi problema es que según entiendo si pongo srand(10); los números aleatorios generados serán de 0 a 10 pero no es el caso y eso me descoloca (y si resulta que el rango se define con #define _RAND_MAX 10 tampoco me funciona), de paso si alguien me puede explicar las diferencias entre srand y RAND MAX..??.

Tal como lo tengo genera números aleatorios en todo su rango y luego visualiza sólo los que están entre 0 y 9, de esta manera se aprecia que a veces el "baile" de números mientras se generan se ralentiza, supongo que es cuando desecha números mayores de 9.

Acaso lo tengo mal entendido y srand() sólo sirve para variar el punto de inicio de aletoriedad cada vez mediante TMR0 u otra variable??

En resumen... como se acota el rango de aleatoriedad de 0-10????

Gracias por la atención

Saludos.

Hola. srand es para variar la secuencia, por ejemplo si pones srand(7) pues la secuencia de salida es {1,4,5,8,5,4,2,5} y siempre será la misma. Por eso tienes que hacer variar el numero k va dentro de srand. srand se puede decir que es el bombo que da vueltas, mientras que rand te da el numero. Si quieres sacar un numero entre 0 y 10 en el enlace de microchip te dicen como:

void main ()
{
srand (TMR0); // Done once

for(;; ){
int i = rand () % 10; // Esto lo divide entre diez y te devuelve el resto. que está entre 0-9
}
}
 
Última edición:
Hola de nuevo Basalto, muchas gracias por tu respuesta.

Entiendo que srand() sera para variar la secuencia pero... que lógica sigue?? es decir... en función a que muestra unos números u otros si se asigna un número u otro a srand()???


Tal como lo veo el planteamiento debe ser usar srand() para modificarle de alguna manera la semilla cada vez y así no repetir siempre la misma secuencia y definir el rango con otros sistemas, en este caso obteniendo el resto de dividir entre 10 (que no se me habría pasado por la cabeza).

En cualquier caso ya me queda mas claro.

Muy agradecido.

Saludos!
 
Hola una vez más.

He conseguido avanzar el programa aunque siga sin saber como funciona realmente srand().

Adjunto programa con uso del TMR0 como valor cambiante en srand():

PHP:
/* 
 * File:   main.c
 * Author: nimio
 *
 * 16F84A
 *
 * DADO ELECTRÓNICO
 * 7 SEGMENTOS DE ÁNODO COMÚN
 *
 * Created on 11 de marzo de 2013, 1:06
 */

#include <xc.h>
#include <stdlib.h> // LIBRERÍA PARA PODER USAR LA FUNCIÓN SRAND.


#define _XTAL_FREQ 4000000


#pragma config FOSC=XT, WDTE=OFF, PWRTE=ON, CP=OFF



/*
 * 
 */


void main(void) {
    
   
   char a; // VARIABLE PARA LA TABLA DE 0-9;
   char tabla7seg [10]={0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x98}; // 0-9 EN HEXADECIMAL.


   OPTION_REGbits.T0CS=0; // SELECCIÓN DEL RELOJ INTERNO DEL TIMER0, A 0 COMO TEMPORIZADOR, A 1 COMO CONTADOR.
   
   srand(TMR0);

   TRISAbits.TRISA1=1;
   
   TRISB=0;
   PORTB=1;


    do {

        
        if (RA1==0) {
            do {
                
                a=rand()%10; // SE DIVIDE EL NÚMERO RANDOM ENTRE 10 Y SE ALMACENA EL RESTO (ENTRE 0-9) EN a.
                PORTB=1;
               
            } while (RA1==0);
        }
        
               if (RA1==1); {
                       PORTB=(tabla7seg [a]);
                        __delay_ms(1000);
                }
           
               
    }while (1);
   
}

Ahora me surge un pequeño problema... (uno más); quiero que mientras no se active el pulsador el display permanezca apagado, para ello hago PORTB=1 ya que mi display de 7 segmentos es de ánodo común, pero no entiendo porque en lugar de apagarlo me enciende todos los segmentos excepto el superior (queda una "A" invertida). Los números se muestran correctamente.

Agradecería comentarios o sugerencias sobre el código.

Gracias por avanzado, sigo investigando.

Saludos.
 
Creo que deberías de poner el PORTB=0xFF para apagar el display. Si pones PORTB=1 lo que haces es poner PORTB=0b00000001. Pero ayudaría un pequeño esquema de como lo tienes conectado.

Un saludo
 
Atrás
Arriba