# Display 7 segmentos 4 dígitos con PIC16f84A fallo de luminiscencia...



## abeltomillo (Oct 16, 2013)

Buenas,

he diseñado y construído una plaquita que integra los siguientes componentes, para hacer una especie de entrenador muy sencillo, con un display de 7 segmentos, 4 dígitos y 1 botón...

os cuento el problema que le veo:

1. cuando lo conecto, los leds se encienden unos mas fuertes que otros (son los leds del 7 segmentos).

notas, descripción, especificaciones...:

1. las resistencias son de 330ohmios
2. el 7 segmentos es de 4 digitos, y reciclado de un viejo tdt que encontré...
3. el PIC que uso, es un pic16f84a
4. el código está en SDCC
5. los condensadores son de 27pF y el cristal de 4MHz...
6. la resistencia que va al MCLR es de 4.7K

disculpad que no os pinte el esquema, es que me da mucha pereza porque no sé usarlo bien, y total, adelanto más escribiéndolo, y supongo que con decir que los pines del 7 seg están conectado directamente al PIC los VCC y los GND directamente a las resistencias->y luego al PIC, basta.

os podéis hacer una imágen de lo que he escrito?

gracias a tod@s por compartir;

adios.

p.d. para quien no le quede claro, lo que quería saber es como solventar el problema de que unos dígitos brillen más que otros...
gracias.
adios. ...


----------



## Gudino Roberto duberlin (Oct 16, 2013)

Amigo, sin un esquema y codigo de programa, sera mas dificil adivinar. Pueden ser varias cosas, empezando por hardware. Ejem. Los display son identicos?, cada salida de segmento tiene su propia resistencia limitadora?, los transistores o drivers son los mismos?. Problema de software, los tiempos de acceso a cada display es el mismo?. O quizas hay una interrupcion, que al activarse impide que al menos uno de ellos no se ilumine durante uno o mas ciclos, etc.


----------



## abeltomillo (Oct 16, 2013)

Querido amigo,

gracias por tu respuesta.

me complace el anunciarte que voy a dibujar el esquema, aunque tarde mucho y me desespere... jeje.

también el anunciarte que me alegra mucho tu respuesta. y que además, tengo las siguientes informaciones que darte, al respecto de tu contestación:

1. el display es un 7 segmentos de 4 dígitos como el que se muestra a continuación (PDF datasheet): https://www.sparkfun.com/datasheets/Components/LED/7-Segment/YSD-439AR6B-35.pdf
2. ¿el driver que uso? si te refieres a un shift register, ya usé uno con arduino y funcionaba bien; pero en este caso conecto el pic directamente al GND de cada segmento del display, y el VCC al pin directamente del PIC. El PORTA, en su mayoría, (excepto RA4), es para el VCC (bits a 1), y el PORTB es para GND.
Se me olvidaba decirte que cada pin del PORTB tiene una resistencia a cada segmento del display. (siento mucho que tenga que describirlo, prometo terminar el esquema antes de irme a dormir).
3. sí, en efecto se usa una interrupción, pero únicamente es un contador de tiempo. A cada milésima la interrupción salta, y entonces, a la que cuento 1000, incremento en 1 el segundero. Sin embargo, el pintado de los números en el display, (o el dibujo, etc...), lo hago en el bucle main.
Como sí tengo el código, te lo adjunto aquí, en este mensaje!

Creo que se me olvida algo, ahora repasaré el mensaje, y te digo si me falta algo por contestar.

Gracias!
Un saludo amigo.

A continuación el código:

```
/* ----------------------------------------------------------------------- */
/* Template source file generated by piklab */
#include <pic16f84a.h>

/* ----------------------------------------------------------------------- */
/* Configuration bits: adapt to your setup and needs */
typedef unsigned int word;
word __at 0x2007 CONFIG = _XT_OSC & _WDT_OFF & _PWRTE_OFF & _CP_OFF;

#define BIN(x) \
( ((0x##x##L & 0x00000001L) ? 0x01 : 0) | ((0x##x##L & 0x00000010L) ? 0x02 : 0) | ((0x##x##L & 0x00000100L) ? 0x04 : 0) | ((0x##x##L & 0x00001000L) ? 0x08 : 0) | ((0x##x##L & 0x00010000L) ? 0x10 : 0) | ((0x##x##L & 0x00100000L) ? 0x20 : 0) | ((0x##x##L & 0x01000000L) ? 0x40 : 0) | ((0x##x##L & 0x10000000L) ? 0x80 : 0))

unsigned char tmr0_times  = 0;
unsigned char tmr0_times2 = 0;
unsigned char secs        = 0;
unsigned char mins        = 0x0b;
unsigned char hours       = 0x0b;
unsigned char hours_d1	  = 0;
unsigned char hours_d2	  = 0;
unsigned char mins_d3	  = 0;
unsigned char mins_d4	  = 0;

char print_digit(unsigned char position, unsigned char value) {
  unsigned char n;
  unsigned char v;
  
  switch (position) {
    case 1:
      n = BIN(1000);
      break;
      
    case 2:
      n = BIN(100);
      break;
      
    case 3:
      n = BIN(10);
      break;
      
    case 4:
      n = BIN(1);
      break;
    
    default:
      return -1;
  }
  
  switch (value) {
    case 0:
      v = BIN(00000100);
      break;
    case 1:
      v = BIN(11100110);
      break;
    case 2:
      v = BIN(00110000);
      break;
    case 3:
      v = BIN(10100000);
      break;
    case 4:
      v = BIN(11000010);
      break;
    case 5:
      v = BIN(10001000);
      break;
    case 6:
      v = BIN(00001000);
      break;
    case 7:
      v = BIN(11100100);
      break;
    case 8:
      v = BIN(00000000);
      break;
    case 9:
      v = BIN(10000000);
      break;
      
    default:
      return -1;
  }
  
  PORTA = n;
  PORTB = v;
  
  return 0;
}

void isr() __interrupt 0 {                                            /* interrupt service routine */
  TMR0 = 0x083;
  T0IF = 0;
  tmr0_times2 ++;
    
  if (tmr0_times2 == 10) {
    tmr0_times2 = 0;
    tmr0_times ++;
    if (tmr0_times == 100) {
      tmr0_times = 0;
      secs ++;
      if (secs == 60) {
	secs = 0;
	mins ++;
	if (mins == 60) {
	  hours ++;
	  if (hours == 24) {
	    hours = 0;
	  }
	}
      }
    }
  }
}

void main() {
  TMR0       = 0x083;
  OPTION_REG = BIN(10000010);
  INTCON     = BIN(10100000);
  TRISB      = 0;
  TRISA      = 0;
  
  while (1) {
      hours_d1 = hours / 10;
      print_digit(1, hours_d1);
      hours_d2 = hours % 10;
      print_digit(2, hours_d2);
      mins_d3 = mins / 10;
      mins_d4 = mins % 10;
      print_digit(3, mins_d3);
      print_digit(4, mins_d4);
  }
}
```


*Edit:*
Efectivamente al haber una interrupción o al haber mucho código detrás de cada impresión, el efecto de luminiscencia es menor en los últimos dígitos...

 pero, ahora que me he dado cuenta, ¿cómo lo soluciono?


*Edita tus mensajes en lugar de crear nuevos.*


----------



## Gudino Roberto duberlin (Oct 16, 2013)

Amigo, bien, segun tu comentario, utilizas el comun del display gatillado directamente desde un pin.
Bueno, seguramente la capacidad para drenar corriente por ese pin no sera suficiente como para abastecer a todos los segmentos, cuando deben iluminarse. Deberas utilizar un transistor PNP gobernado por dicho pin y luego podras alimentar el comun de los segmentos de cada digito, desde el colector de dicho transistor.
Recuerda que deberas negar la salida al transistor, pues este satura con señal 0V.
Aun asi, sube el esquema.


----------



## abeltomillo (Oct 17, 2013)

buenas amigo!

gracias por tu respuesta de nuevo.

anoche me lié programando. Y he conseguido mejorar la iluminación, reduciendo código y haciéndolo más uniformemente iluminado.

Lamentablemente no pude subirte el esqueme porque utilicé todo el tiempo, jojo.
Pero hoy en cuanto vuelva de clase te lo termino.

saludos!

gracias.


----------



## jmth (Oct 17, 2013)

Quizás no esté bien el tiempo que se enciende cada display. Hice lo mismo con un arduino hace 4 días y tuve que poner un delay de 1 o 2 ms entre el encendido de cada dígito, antes pude ver todo como 8 o que los números se veían muy tenues.


----------



## abeltomillo (Oct 17, 2013)

bueno, aqui tienes el esquema; es la primera vez que termino uno. es un rollo...

en fin, gracias.


y vas a tener razón otra vez, va a ser el pin de VCC que no suministra suficiente intensidad para los 7 segmentos del dígito... aparte, solucioné la programación que debido a la interrupción habian contrastes jeje.... eres un crack!

por cierto, lo del transistor, ¿cómo funciona? he estado leyendo en la wikipedia y veo que hay 3 tipos, supongo que este será bipolar, y habrá que hacer un conexionado del tipo "colector común". ¿Es así?

¿Cómo es eso de invertir 0V? :O

En fin, me disculpor por mi ignorancia, espero te sea leve, jojo.

Un saludo!

Gracias amigo 





jmth dijo:


> Quizás no esté bien el tiempo que se enciende cada display. Hice lo mismo con un arduino hace 4 días y tuve que poner un delay de 1 o 2 ms entre el encendido de cada dígito, antes pude ver todo como 8 o que los números se veían muy tenues.



Sí, tienes razón.
El problema que le veo al delay es que la programación en PIC es un poco rollo... por ejemplo en arduino te viene toda la libreria. Pues ahora con piklab para PICs tengo las funciones justas, o ninguna, no lo sé al complet. Lo cierto es que en algún código he leído el delay_ms().

Pero el problema real, no solo es el retardo entre escrituras (que he solucionado poniendo a 0 despues de cada escritura), es que tengo una interrupción cada 1ms que me alteraba un poco el resultado porque cortaba la impresión de X dígito... de modo que uno siempre se veía más, otro menos, otro menos y asi sucesivamente.

Lo he solucionado con este código, pero sigue estando el problema de corriente, de mi amigo el argentino!

bueno, os pongo aquí como queda finalmente el código.

saludos!


```
/* ----------------------------------------------------------------------- */
/* Template source file generated by piklab */
#include <pic16f84a.h>

/* ----------------------------------------------------------------------- */
/* Configuration bits: adapt to your setup and needs */
typedef unsigned int word;
word __at 0x2007 CONFIG = _XT_OSC & _WDT_OFF & _PWRTE_OFF & _CP_OFF;

#define BIN(x) \
( ((0x##x##L & 0x00000001L) ? 0x01 : 0) | ((0x##x##L & 0x00000010L) ? 0x02 : 0) | ((0x##x##L & 0x00000100L) ? 0x04 : 0) | ((0x##x##L & 0x00001000L) ? 0x08 : 0) | ((0x##x##L & 0x00010000L) ? 0x10 : 0) | ((0x##x##L & 0x00100000L) ? 0x20 : 0) | ((0x##x##L & 0x01000000L) ? 0x40 : 0) | ((0x##x##L & 0x10000000L) ? 0x80 : 0))

unsigned char tmr0_times  = 0;
unsigned char tmr0_times2 = 0;
unsigned char secs        = 0;
unsigned char mins        = 0x0b;
unsigned char hours       = 0x0b;
unsigned char hours_d1	  = 0;
unsigned char hours_d2	  = 0;
unsigned char mins_d3	  = 0;
unsigned char mins_d4	  = 0;

#define POSITION_1 8
#define POSITION_2 4
#define POSITION_3 2
#define POSITION_4 1
#define POSITION_OFF 0

unsigned char map[10] = {
  4, 230, 48, 160, 194, 136, 8, 228, 0, 128
};

void isr() __interrupt 0 {                                            /* interrupt service routine */
  TMR0 = 0x083;
  T0IF = 0;
  tmr0_times2 ++;
    
  if (tmr0_times2 == 10) {
    tmr0_times2 = 0;
    tmr0_times ++;
    if (tmr0_times == 100) {
      tmr0_times = 0;
      secs ++;
      if (secs == 60) {
	secs = 0;
	mins ++;
	if (mins == 60) {
	  hours ++;
	  if (hours == 24) {
	    hours = 0;
	  }
	  hours_d1 = hours / 10;
	  hours_d2 = hours % 10;
	}
	mins_d3  = mins / 10;
	mins_d4  = mins % 10;
      }
    }
  }
}

void main() {
  TMR0       = 0x083;
  OPTION_REG = BIN(10000010);
  INTCON     = BIN(10100000);
  TRISB      = 0;
  TRISA      = 0;

  hours_d1 = hours / 10;
  hours_d2 = hours % 10;
  mins_d3  = mins / 10;
  mins_d4  = mins % 10;
  
  while (1) {
    PORTB = map[hours_d1];
    PORTA = POSITION_1;
    
    PORTA = POSITION_OFF;
    
    PORTB = map[hours_d2];
    PORTA = POSITION_2;
    
    PORTA = POSITION_OFF;
    
    PORTB = map[mins_d3];
    PORTA = POSITION_3;
    
    PORTA = POSITION_OFF;
    
    PORTB = map[mins_d4];
    PORTA = POSITION_4;
    
    PORTA = POSITION_OFF;
  }
}
```



Ahora, el problema evidente es que cuando pinto un 1 en todos los digitos, se ven igual intensidad.
Pero si pinto 1 1 : 1 9
                              ^
                              Este nueve se ve más flojeras... jojo


----------



## Gudino Roberto duberlin (Oct 17, 2013)

Hola Amigo, bien!, debes utilizar los transistores en modo emisor comun (puedes implementar el BC327). 
Vale decir, el emisor de dicho transistor PNP, se conecta a Vdd. La base es accionada a traves de una "resistencia limitadora" digamos un valor como 2k7, desde el pin que antes alimentaba el comun de cada display. Y por ultimo, el colector se conecta al comun del display.
Respecto, a que debes negar la salida, se debe a que el transistor conducira cuando dicha salida(pin) sea 0.
Siendo que en el programa, habilitas la salida mencionada con 1.
Ahora bien, que problema "podria" aparecer?. Pues bien, los datos que muestra cada display puede interferir, levemente replicado(brillo inferior) hacia un digito contiguo. Esto se debe a que la conmutacion de un display a otro, es relativamente alta como para que el transistor que conducia, alcance el corte inmediato, cuando el proximo ya comienza a conducir. Si esto ocurre, debes agregar un pequeño retardo algo asi como 1ms. para crear un tiempo muerto entre la activacion de cada digito. Exitos con eso Amigo!.-


----------



## jmth (Oct 17, 2013)

Has tenido en cuenta la corriente que estás suministrando con resistencias de 330? Son 15 mA, no está mal aunque el 16f84 entrega hasta 25 mA. Quizás con resistencias de 220 se note el cambio, sería la solución sencilla y no creo que se queme ningún LED. La idea de los transistores es lo mejor porque caminas sobre seguro y evitarás calentar el micro.


----------



## cosmefulanito04 (Oct 17, 2013)

Ya se mencinó varias veces en el foro, para obtener una buena iluminación en todos los segmentos, tenés que lograr que:


 Todos los dígitos tengan el mismo tiempo de encendido, es decir el ciclo de trabajo (duty). 
 En base a ese ciclo de trabajo, tenés que calcular la corriente pico en c/led (es decir calcular la resistencia limitadora) en función de la corriente eficaz que estas buscando (normalmente 20mA para un buen brillo). Esto quiere decir que es posible que tu corriente pico sea alta, pero nunca debería superar la corriente pico del led (en los leds convencionales suele ser de 75mA).

Entonces, trabajar simplemente con los puertos del PIC, es peligroso, ya que el común tiene que soportar los 7 segmentos a la vez. Si hacés eso, mirá bien la hoja de datos.

Te aconsejo que uses transistores como mencionaron arriba, c/segmento es muy probable que puedas manejarlo directamente desde el puerto y para el común usá un transistor que aguante la corriente de los 7 segmentos a la vez.

Si empleas un PNP, como mencionó *Roberto*, usá un pull-up que te garantice poder deshabilitar la conducción del transistor, ya que si el pull-up del PIC es pobre y su tensión es lo suficientemente bajo, puede dejar al transistor a medio abrir.


----------



## abeltomillo (Oct 18, 2013)

Hola amig@s,

ya estoy de nuevo aquí, ya es fin de semana!!! jojo

os doy las nuevas...

1. compré los transistores y las resistencias de 2k7
2. he hecho hueco y he soldado todo
3. he añadido un delay de 0 < X < 1ms

el resultado es impresionante!!! los leds brillan con mayor intensidad que antes, y claro, esto se debe a que el transistor deja pasar más corriente que la salida del pic, claro... antes con 40mA se estaba soportando los 7 segmentos y por eso se veía tan flojito... ya entendí.

Ahora bien, amigo, ¿qué tipo de resistencia "pull-up" debo usar? ¿activo o pasivo? Sinceramente, no sabía ni lo que era esto... jojo
bien pues intentaré mejorar el código o investigar el motivo por el que ahora se ve mejor, pero no acaba de cuajar... me explico:

1. si el delay es de aprox. 1ms, los números parpadean, tiene que ser menor, aprox 0.550 ms
2. algunos fragmentos del dígito se ven mas oscuros que otros, esto se debe a un pequeño corto? :O

bueno, gracias a los 3 por todo,

espero que pueda acabar esto pronto, y a poder ser para hoy, jojo...

gracias,

un saludo!


----------



## cosmefulanito04 (Oct 18, 2013)

abeltomillo dijo:


> Ahora bien, amigo, ¿qué tipo de resistencia "pull-up" debo usar? ¿activo o pasivo? Sinceramente, no sabía ni lo que era esto... jojo



El pull-up, es poner una resistencia a Vcc de esta forma:







Entonces, para completar la configuración, descartá el pull-up interno del puerto PIC, configurandolo como puerto de alta impedancia (o colector abierto).

Sobre la multiplexación, para que se vea bien al ojo humano tenés que garantizar que todos los displays se enciendan en al menos 20mS (50Hz), entonces si tenés 4 dígitos, a c/dígito dale 5mS de Ton, de esta forma te queda que el periodo es 20mS y el duty 25%.

Si hacés lo que menciono arriba, para calcular las resistencias limitadoras de c/segmento usá esta fórmula:

[LATEX]I_{pico}=\frac{I_{ef}}{\sqrt{Duty}}[/LATEX]

Entonces en tus condiciones, para obtener un buen brillo en los leds:

[LATEX]I_{pico}=\frac{20mA}{\sqrt{0,25}}=40mA[/LATEX]

De ahí sacás la Rlimitadora de c/segmento, si tu fuente es de 5v:

[LATEX]R_{limitadora}=\frac{V_{fuente}-V_{led}}{I_{pico}}=\frac{5v-2,4v}{40mA} \approx 68 \Omega[/LATEX]

Por último, tené en cuenta que el transistor en el peor de los casos se tiene que bancar 40mA*7=280mA, ojo con eso.

Viendo la hoja de datos del display, la corriente pico que soporta es de 160mA, así que no vas a tener problemas.


----------



## abeltomillo (Oct 18, 2013)

Vale, 
ya lo tengo claro...

pero, ¿te refieres c/digito o a c/segmento?


----------



## cosmefulanito04 (Oct 18, 2013)

abeltomillo dijo:


> Vale,
> ya lo tengo claro...
> 
> pero, ¿te refieres c/digito o a c/segmento?



Un dígito está compuesto por 7 segmentos (o 7 leds), vos tenés 4 dígitos (28 leds en total).

A cada segmento lo tenés que alimentar mediante una resistencia limitadora, porque a la larga son simplemente leds.

Otra cosa que deberías tener en cuenta es si el PIC puede o no alimentar a 7 segmentos a la vez, siguiendo con lo que mencioné antes, debería entregar 280mA y estoy casi seguro que 200mA es todo lo que puede entregar en todos sus puertos, verificá eso.


----------



## abeltomillo (Oct 18, 2013)

Sí, ciertamente el puerto no es suficientemente potente como para alimentar todos los leds.
Si miras el esquema que puse, verás que uso una resistencia limitadora de 330ohms para c/segmento...

Al respecto de los transistores, lo que yo hice fue poner un transistor en pin VCC de los leds, por lo que tengo 5 transistores, porque son 4 dígitos + 1 pin de los ':' de la hora.

Pero, mi display muestra todos los segmentos bien iluminados, con un delay de 5ms entre cada impresión, (20 en total). Excepto en los que están conectado a RB1 y RB3.... que se ven más flojos en todos los dígitos.
Sin embargo, si en vez de pintar un numero distinto en cada dígito, pinto todos los dígitos iguales (no hay alternación de pines) y me meto en un bucle infinito sin hacer nada más, todos los leds se ven con la misma intensidad lumínica... 
¿Esto, a qué se debe? ¿Tiene que ver con el pull-up? Ya probé a conectarle una Resistencia de 100ohmios en la base y VCC, y sigue igual....

bueno, un abrazo amigo! gracias por todo...



Amigo, no sé qué hice, algo debío salir bien, hice contacto con la resistencia en no se a donde y se vió todo perfecto!
voy a ver si replico el tema, creo que vas a tener razón! la madre qué.... jojojo

Por lo que veo, es posible que solo haga falta una resistencia pull-up? Yo pensé que harían falta 5...


----------



## cosmefulanito04 (Oct 18, 2013)

abeltomillo dijo:


> Sí, ciertamente el puerto no es suficientemente potente como para alimentar todos los leds.
> Si miras el esquema que puse, verás que uso una resistencia limitadora de 330ohms para c/segmento...



Esto implica como si tuvieras un led común con una corriente de 3mA (corriente muy por debajo de los 20mA).



abeltomillo dijo:


> Al respecto de los transistores, lo que yo hice fue poner un transistor en pin VCC de los leds, por lo que tengo 5 transistores, porque son 4 dígitos + 1 pin de los ':' de la hora.



Está bien.



abeltomillo dijo:


> Amigo, no sé qué hice, algo debío salir bien, hice contacto con la resistencia en no se a donde y se vió todo perfecto!
> voy a ver si replico el tema, creo que vas a tener razón! la madre qué.... jojojo
> 
> Por lo que veo, es posible que solo haga falta una resistencia pull-up? Yo pensé que harían falta 5...



C/transistor debe tener su propio pull-up, controlado por puertos de alta impedancia.

Si estás conforme con la luminosidad así como está, dalo por terminado al circuito.

Si querés mejorarlo para obtener la mejor luminosidad, usá un integrado llamado ULN2803 que se conectan directamente a los puertos y a c/segmento.


----------



## abeltomillo (Oct 20, 2013)

Hola amigo! De nuevo aquí estoy...

Primero, gracias por contestar, y segundo, gracias por ser tan amable !

Bueno, el caso es que he vuelto a soldar la placa y se me olvidaron colocar las resistencias pull-up.. jo jo
pues ahora resulta que me pasa como al ppio.
Le cambie las resistencias de 330 ohmios a 220 ohmios, para que iluminase un poquitín más y ahora, no sé cuál es el valor de las resistencias pullup... o sea, nunca lo supe, al ppio puse de 100ohmios, (con las resistencias limitadoras de 330ohmios) pero no pintaba el primer dígito, aunque los demás se veían ¡explendidos! Pues ahora resulta, que ya se por qué volví a soldar la placa, y es que no solo porque era tan pequeñea que se hacía difícil operar, si no que creí que tenía alguna mala conexión y por eso no mostraba el dígito... pero resulta que ahora me pasa lo mismo, pero con más dígitos...

¿Es que estoy colocando mal la resistencia pull-up? ¿O es que el valor ha de ser mayor a 100ohmios? Yo he visto la imágen que me enviaste como unas 20 veces, y me he dado cuenta de que la resistencia pull-up es de 2.2 veces mayor que la Rlimitadora.. jojo, ¿es eso correcto para mi caso? es decir, ¿si tengo una Rlimitadora de ~2k7Ohmios y le pongo una pull-up de ~6k (tengo de 10k) funcionaría? O sea, ahora mismo tengo probadas las de 100ohmios y el resultado es raro... no lo entiendo y con las de 10k no hay diferencia (solo la he colocado en 3 transistores con la mano y viendo el display a ver qué tal...).

Bueno, un saludo amigo, espero que te vaya todo muy bien!

Gracias...!


----------



## cosmefulanito04 (Oct 20, 2013)

La resistencia de pull-up podés hacerla de 1kOhm a 10kOhm, a mayor resistencia, más débil el pull-up. Yo probaría directamente con un pull-up fuerte de 1kOhm.

En cambio la resistencia de base, tenés que calcularla en función de la corriente de carga que vas a manejar en el transistor y su Hfe, es decir:

[LATEX]I_{base-minima}=\frac{I{carga}}{H_{fe}}[/LATEX]

Suponiendo la condición límite que te mencioné de 280mA por c/dígito y el Hfe mínimo que figura en la hoja de datos:

[LATEX]I_{base-minima}=\frac{280mA}{40}=7mA[/LATEX]

Lo ideal es darle un margen a esa corriente y sobre saturar un poco el transistor:

[LATEX]I_{base} \geq 2.I_{base} \rightarrow I_{base} \approx 14mA[/LATEX]

De esta forma, cada puerto del PIC deberá drenar 14mA c/vez que se habilite un dígito (importante tenerlo en cuenta).

Volviendo a la resistencia de base, la misma sale de hacer esto:

[LATEX]R_{base}=\frac{Vcc-0,7v}{I_{base}}=\frac{5v-0,7v}{14mA} \approx 330 \Omega[/LATEX]

Dependiendo del pull-up que elijas, si es muy fuerte (1kOhm) agregará casi 1mA más que deberá drenar el puerto del PIC (15mA en total).


----------



## abeltomillo (Oct 20, 2013)

Buenas amigo,

muchas gracias por tu contestanción, ha sido grandiosa, ¡eres todo un entendido!
¿qué tal todo? Espero que bien.
Yo conecté las resistencias de 1kOhm (5 en total) y se enciende y se apaga en funcion de si toco o "destoco" el circuito, respectivamente...
No sé como hice, donde conecte aquella vez, pero conseguí que se viese bien, con una sola resistencia, sacrificando 1 digito... no sé si me explico.

El caso es que se siguen viendo los segmentos A y B más flojos que los demás... 

un saludo amigo, 
gracias por todo!


----------



## cosmefulanito04 (Oct 20, 2013)

abeltomillo dijo:


> Buenas amigo,
> 
> muchas gracias por tu contestanción, ha sido grandiosa, ¡eres todo un entendido!
> ¿qué tal todo? Espero que bien.
> ...



Ok.

Empezá a descartar cosas:


 Si tenés protoboard, probá todos los segmentos de un dígito conectandolo a 5v con una resistencia limitadora de 150 Ohms y verificá que todos encienden bien.
 Modificá el código para que solo encienda 1 digito y verificá que todos los segmentos encienden bien.

¿A todos los segmentos le pusiste resistencias de 220Ohms?


----------



## abeltomillo (Oct 20, 2013)

Buenas, 

gracias por tus contestaciones.

Aquí van mis respuestas:



cosmefulanito04 dijo:


> Ok.
> 
> Empezá a descartar cosas:
> 
> 1. Si tenés protoboard, probá todos los segmentos de un dígito conectandolo a 5v con una resistencia limitadora de 150 Ohms y verificá que todos encienden bien.



Si conecto uno a uno con Proto, la resistencia de 147ohm y a 5V, se ven bien los segmentos A y B.



cosmefulanito04 dijo:


> Modificá el código para que solo encienda 1 digito y verificá que todos los segmentos encienden bien.


Si modifico el códgio para que muestre 4 dígitos sin que sean distintos del mismo en todos, es decir: 4 4 : 4 4 ó 2 2 : 2 2, se ven todos bien iluminados y correctamente.


cosmefulanito04 dijo:


> ¿A todos los segmentos le pusiste resistencias de 220Ohms?


Sí, todas las salidas de los 7 segmentos tienen una R de 220 ohm.

saludos, gracias por contestar.. 

p.d.
Me doy cuenta de que cuando muestro 1 dígito distinto en cada dígito del 7-seg-4-digit es cuando falla la luminiscencia. va a ser fallo de que el refresco es demasiado alto, ¿no?

En fin.. no sé que puede ser...


----------



## cosmefulanito04 (Oct 20, 2013)

Los errores más comunes de código en el refresco pueden ser:


 Darle poco tiempo a un cierto dígito. Pero en este caso sería raro, ya que el resto de los segmentos si te funcionan bien.
 Cuando cambias de dígitos, antes de deshabilitar el dígito anterior ya estás colocando el valor del próximo dígito, esto genera un efecto "fantasma".
 Habilitar dos o más dígitos a la vez.

Secuencia correcta para el cambio de dígito:


Todos los dígitos deshabilitados.
Coloco en el puerto el valor del próximo dígito.
Habilito el dígito.
Dejo el dígito encendido el tiempo necesario.
Repito desde 1.

Hacé una prueba bien simple, asigná 4 valores distintos a c/dígito y hacé un refresco lento, es decir que tarde entre 1 o 2 seg para ver si la secuencia programada es la correcta.


----------



## abeltomillo (Oct 20, 2013)

Amigo mio, eres un ¡¡¡genio!!! El error fue mio desde que cambiamos la polaridad en los pines VCC jojojo
Al estar a 0 continuamente se encendían los 2 puntos del centro, lo que hacía que perdiese intensidad en los demás segmentos!
¡¡Bien, pues eso, solucionado!!

Jojojo

muchas gracias amigos, es un placer encontrar gente como uds.
gracias, gracias, gracias... ¡un abrazo! jjajajaja

Adjunto fotos del resultado


----------



## abeltomillo (Oct 22, 2013)

¡Buenas de nuevo!

Me conecto para plantearos unas dudas que tengo, en forma de preguntas!

claro, como si no iba a ser.. jojojo

veréis:

1. cuando le pongo 4 pilas recargables de 1.2V, el display de ve bien, pero lo deje conectado y al día siguiente se veía un tanto flojo. Al volver de clase, se veía solo el segundo digito y los dos puntos ':'. (Los demás muy flojos...) ¿Es esto que la bateria está descargándose? ¿O que requiere de algún componente más?

2. ¿Cómo puedo medir lo que consume el circuit? Probé a conectarle el miliamperímetro en serie y me marcaba .02A. pero lo que me paró fue que solo se encendía el primer dígito.. 

3. Quiero colocarle 2 botones pulsadores. Y quiero hacer la lectura en el mismo pin, poniendo 2 resistencias diferentes en cada botón, para diferenciar el valor analógico y poder operar... ¿Se puede hacer esto con el pin RA4? Siendo así, podría buscar en google códgio ejemplar...

Gracias cosme, amigo, por tu "me gusta"! Y gracias, muchas gracias, de nuevo, por tu gran ayuda, ¡Estoy muy conteto!

Un saludo.


----------



## cosmefulanito04 (Oct 22, 2013)

abeltomillo dijo:


> ...1. cuando le pongo 4 pilas recargables de 1.2V, el display de ve bien, pero lo deje conectado y al día siguiente se veía un tanto flojo. Al volver de clase, se veía solo el segundo digito y los dos puntos ':'. (Los demás muy flojos...) ¿Es esto que la bateria está descargándose? ¿O que requiere de algún componente más?



4 pilas en serie dan 6v (con pilas a full), ¿cómo limitas a 5v?



abeltomillo dijo:


> ...2. ¿Cómo puedo medir lo que consume el circuit? Probé a conectarle el miliamperímetro en serie y me marcaba .02A. pero lo que me paró fue que solo se encendía el primer dígito..



Amperimetro en serie entre la fuente de alimentacion y el Vcc del circuito. Yo creo que rondará entre 70 a 120mA, poco más poco menos.



abeltomillo dijo:


> 3. Quiero colocarle 2 botones pulsadores. Y quiero hacer la lectura en el mismo pin, poniendo 2 resistencias diferentes en cada botón, para diferenciar el valor analógico y poder operar... ¿Se puede hacer esto con el pin RA4? Siendo así, podría buscar en google códgio ejemplar...



No entiendo, ¿valor analógico en puertos digitales?¿Qué aplicación necesitás hacer con los botones?

Mira que solo tenés una interrupción externa.


----------



## abeltomillo (Oct 23, 2013)

Uhm... buenos días cosme; amigo 

te cuento:

4 pilas de 1.2 en serie, teoría dan 4.8V; lo medí con el voltímetro y rondaba los 5V...

Ok, debe ser problema del amperímetro porque no tengo fusible y estaba midiendo con el de 20A max... y seguramente lo conecté en GND jojo...

Pues, la idea es poner en hora el reloj, o cualquier otra aplicación con tiempos: pulsar durante 2 segundos, pulsar en menos de 1.3 segundos varias veces, etc... todo esto para controlar el un poco el aparato...
Yo es que no sé si el 16f84A tiene alguna entrada analógica, no lo he mirado a fondo, pero por ejemplo en arduino, los pines A0 hasta el A5 creo, son configurables como analógicos o digitales.
La idea era colocar una resistencia en cada boton de diferente valor, para leer un valor analógico diferente; pero claro, hace falta un pin ADC, ¿no? ¡Pues es que no sé si tiene! jojo

Respecto a la interrupción externa, si no me equivoco, solo podría lanzarla con 1 botón, ¿no? conectándolo a VCC o a GND y configurándola como Rising o lo otro que no recuerdo... 

Bueno, amigo, gracias por tu contestación y que pases un buen día. Me dispongo a ir a clase.

Un saludo!


----------



## cosmefulanito04 (Oct 23, 2013)

abeltomillo dijo:


> Uhm... buenos días cosme; amigo
> 
> te cuento:
> 
> 4 pilas de 1.2 en serie, teoría dan 4.8V; lo medí con el voltímetro y rondaba los 5V...c



Ok, solo digo, tené cuidado cuando las baterías están totalmente cargadas, en esa situación pueden llegar a tener 1,5v c/u por un cierto tiempo hasta que se descargan, ej. la baterías de 3,6v (3 celdas de 1,2v c/u) a máxima carga pueden llegar a 4,5v.



abeltomillo dijo:


> Yo es que no sé si el 16f84A tiene alguna entrada analógica, no lo he mirado a fondo, pero por ejemplo en arduino, los pines A0 hasta el A5 creo, son configurables como analógicos o digitales.



Mirá la hoja de datos del 16f84, olvidate del arduino.



abeltomillo dijo:


> La idea era colocar una resistencia en cada boton de diferente valor, para leer un valor analógico diferente; pero claro, hace falta un pin ADC, ¿no? ¡Pues es que no sé si tiene! jojo



Nuevamente, ver hoja de datos.



abeltomillo dijo:


> Respecto a la interrupción externa, si no me equivoco, solo podría lanzarla con 1 botón, ¿no? conectándolo a VCC o a GND y configurándola como Rising o lo otro que no recuerdo...



Si, pero como alternativa se me ocurre que podrías hacer un barrido, es decir usar 3 pines:


 Pin que tiene la interrupción externa.
 Pin 1 que hace de gnd o vcc.
 Pin 2 que hace de gnd o vcc.

La idea es por ej. configurar la externa para que detecte flancos descendentes (pin configurado como pull-up), y de ese pin conectar dos pulsadores, uno que vaya a Pin 1 y otro que vaya a Pin 2. Entonces con el soft deberías todo el tiempo cambiar de estado Pin 1 y Pin 2 (cuando uno está en Vcc, el otro en Gnd), solo se detectará aquel pulsador que fue presionado y que en ese momento su Pin estaba a Gnd. Obviamente el barrido deberías hacerlo con suficiente velocidad, yo le calculo que 75mS como máximo para el cambio de estado de c/ Pin.


----------



## abeltomillo (Dic 27, 2013)

Buenas,

en primer lugar, mis disculpas por la ausencia de respuesta.
en segundo lugar, decir que muchas gracias por la respuesta.

y por último punto de esta entrada, decir que cambie la configuración de pines, para tener RB0/INT disponible para el botón. 

Se me ocurre generar interrupciones con el <<push button>> (si es que fuera posible) y así, según los tiempos de pulsado, y la frecuencia con la que se pulsan, poder actualizar la hora del pic.

Me pregunto qué es lo que falla... conecté el botón como muestran todos los ejemplos de internet, google.com. Es decir, una resistencia de 4k7 entre GND y VCC el botón. Más o menos creo que es así de memoria. 

Ahora tengo RA4, que es open-drain, como el que ilumina los ':' del 7 seg, gracias a tu gran idea de poner transistores... ha sido posible poner esta maravilla en marcha y dejar un pin con interrupción o que pueda leer/escribir. 

Lo que hice fue activar las interrupciones, (GIE), (que ya estaban activadas antes...=) y/o después configuré RB0 como INT en vez de como RB0, valga la redundancia. Me pregunto, por qué al pulsar el botón, se vuelve loco el "circuito"... es decir, puse que si apretaba el boton, el pic se pone en modo MANUAL_PROG, y si lo vuelvo a apretar, se pone en DEF_MODE. Pero no funciona bien, porque si apreto el botón, debería aparecer 6666 y si lo vuelvo a apretar, debería salir la hora. Pero salen los 2 números entrecruzados... a veces pulso rapido o varias veces el boton y se queda en un modo, y si lo repito, se mueve al otro... me da que no entiendo bien lo que es una interrupción, ni cómo funciona tampoco... jojojo. 

Una ayudita mi gran amigo argentino?

Gracias por todo, a todo el foro, sois unos grandes maestros.


Saludos, 

abelillo.

A continuación os dejo el código, por si os hiciera falta 


```
/* ----------------------------------------------------------------------- */
/* Template source file generated by piklab */
#include <pic16f84a.h>

/* ----------------------------------------------------------------------- */
/* Configuration bits: adapt to your setup and needs */
typedef unsigned int word;
word __at 0x2007 CONFIG = _XT_OSC & _WDT_OFF & _PWRTE_OFF & _CP_OFF;

#define BIN(x) \
( ((0x##x##L & 0x00000001L) ? 0x01 : 0) | ((0x##x##L & 0x00000010L) ? 0x02 : 0) | ((0x##x##L & 0x00000100L) ? 0x04 : 0) | ((0x##x##L & 0x00001000L) ? 0x08 : 0) | ((0x##x##L & 0x00010000L) ? 0x10 : 0) | ((0x##x##L & 0x00100000L) ? 0x20 : 0) | ((0x##x##L & 0x01000000L) ? 0x40 : 0) | ((0x##x##L & 0x10000000L) ? 0x80 : 0))

unsigned char tmr0_times  = 0;
unsigned char tmr0_times2 = 0;
unsigned char secs        = 0;
unsigned char hours       = 7;
unsigned char mins        = 30;
unsigned char hours_d1	  = 0;
unsigned char hours_d2	  = 0;
unsigned char mins_d3	  = 0;
unsigned char mins_d4	  = 0;
unsigned char mode        = DEF_MODE;

#define POSITION_1 23    /**/// 0111  ===> 10111
#define POSITION_2 27    /**/// 1011  ===> 11011
#define POSITION_3 29    /**/// 1101  ===> 11101
#define POSITION_4 30    /**/// 1110  ===> 11110
#define POSITION_5 15    /**/// ----  ===> 01111  //** nuevo codigo de encendido del ':' **
#define POSITION_OFF 31  /**/// 1111  ===> 11111


enum {
  MANUAL_PROG,
  AUTO_PROG,
  DEF_MODE
};

/**
 * BIT NUMBER:VALUE/SIGNIFICANT
 * 0:
 * 1:
 * 2:enciende/apaga segmento central. (-)
 * 3:
 * 4:uno de los puntos de ':' y una barra del 7segmentos.
 * 5:
 * 6:uno de los puntos de ':' y una barra del 7segmentos.
 * 7:0V->enciende ':'; 5V->apaga ':'.
 *             
 * 
 *//// LOL
 
unsigned char map[] = {
  5,    /**/// 00000101 => 0   ===> 00000101
  231,  /**/// 11100111 => 1   ===> 11100111
  49,   /**/// 00110001 => 2   ===> 00110011
  161,  /**/// 10100001 => 3   ===> 10100001
  195,  /**/// 11000011 => 4   ===> 11000011
  137,  /**/// 10001001 => 5   ===> 10001001
  9,    /**/// 00001001 => 6   ===> 00001001
  229,  /**/// 11100101 => 7   ===> 11100101
  1,    /**/// 00000001 => 8   ===> 00000001
  129,  /**/// 10000001 => 9   ===> 10000001
  244   /**/// 11110100 => :   ===> 11110100
};


void delay_4ms(void) {
  int i;
  for (i=0;i<230;i++) ;
}

void isr() __interrupt 0 {                                            /* interrupt service routine */
  if (T0IF == 1) {
    TMR0 = 0x083;
    T0IF = 0;
    tmr0_times2 ++;
      
    if (tmr0_times2 == 10) {
      tmr0_times2 = 0;
      tmr0_times ++;
      if (tmr0_times == 100) {
	tmr0_times = 0;
	secs ++;
	if (secs == 60) {
	  secs = 0;
	  mins ++;
	  if (mins == 60) {
	    mins = 0;
	    hours ++;
	    if (hours == 24) {
	      hours = 0;
	    }
	    hours_d1 = hours / 10;
	    hours_d2 = hours % 10;
	  }
	  mins_d3  = mins / 10;
	  mins_d4  = mins % 10;
	}
      }
    }
  }
  
  if (INTF == 1) { /*** Service External Routine (button) ***/
    INTF = 0;
    switch (mode) {
      case DEF_MODE:
	mode = MANUAL_PROG;
	break;
      case MANUAL_PROG:
      case AUTO_PROG:
	mode = DEF_MODE;
	break;
    }
  }
}
/*
void delay_1s() {
  int times = 1000/4, i;
  for (i=0; i < times; i++) delay_4ms();
}
*/

void sayHELO() {
    PORTA = POSITION_1;
    PORTB = map[6];
    
    delay_4ms();
    
    PORTA = POSITION_2;
    PORTB = map[6];
    
    delay_4ms();
    
    PORTA = POSITION_3;
    PORTB = map[6];
    
    delay_4ms();
    
    PORTA = POSITION_4;
    PORTB = map[6];
    
    delay_4ms();
}

void main() {
  TMR0       = 0x083;
  OPTION_REG = BIN(11000010);
  INTCON     = BIN(10110000);
  TRISB      = 0;
  TRISA      = 0;
  
  hours_d1 = hours / 10;
  hours_d2 = hours % 10;
  mins_d3  = mins / 10;
  mins_d4  = mins % 10;
  
  /*** ¿¡¿QUÉ COÑO ES ESTO?!?
  PORTB = map[hours_d1];
  PORTA = POSITION_1 & POSITION_2 & POSITION_3 & POSITION_4;
  *////XD
  
  while (1) {
    
    if (mode == MANUAL_PROG) {
      sayHELO();
    } else if (mode == AUTO_PROG) {
      
    } else {
    
      /** Modo pintado de hora en display 7segmentos **/
      PORTB = 255;
      PORTA = POSITION_OFF;
      
      PORTB = map[hours_d1];
      PORTA = POSITION_1;
    
      delay_4ms();
    
      PORTB = 255;
      PORTA = POSITION_OFF;
      
      PORTB = map[hours_d2];
      PORTA = POSITION_2;
    
      delay_4ms();
      
      PORTB = 255;
      PORTA = POSITION_OFF;
      
      PORTB = map[mins_d3];
      PORTA = POSITION_3;
      
      delay_4ms();
      
      PORTB = 255;
      PORTA = POSITION_OFF;
      
      PORTB = map[mins_d4];
      PORTA = POSITION_4;
      
      delay_4ms();
      
      PORTB = 255;
      PORTA = POSITION_OFF;
      
      PORTB = map[sizeof(map) - 1];
      PORTA = POSITION_5;
      
      delay_4ms();
      /**///Fin del pintado de la hora actual.
    }
  }
}
```


----------



## cosmefulanito04 (Dic 27, 2013)

¿Como configuraste la interrupción?

Del modo que pusiste el pulsador, necesitas un flanco positivo.

Otra cosa muuuy importante, te falta un antirrebote, ya que el uC detecta esto cuando usas el pulsador:



Tenés dos opciones de resolverlo:

- Por soft, mediante una rutina. Acá te dejo una explicación de como debería funcionar esa rutina (ver abajo, cuando aparece el gráfico del rebote), pero esa rutina está pensada para un flanco descendente, a diferencia de tu configuración flanco ascendente.

- Por hard mediante un filtro R-C.


----------



## abeltomillo (Dic 27, 2013)

Buenas cosme,

gracias por tu respuesta.

Te diré como tengo configurado el botón: el VCC de la alimentación va a un pin del botón, y el GND está conectado por una resistencia de 21k creo (marron negro naranja oro) al otro pin del botón y al pin del PIC.

El tema del antirebote, no lo acabo de pillar con el código fuente que me has pasado, creo que tendré que buscar en google, o estudiar el tema de hacerlo por hardware con un filtro R-C, lo cual no sé lo que es... jejeje.

Lo del flanco positivo tampoco lo entendí al 100%, supongo que te refieres que debe de dar el VCC al pin, en vez del GND, es así?

Bueno, ya me dices algo al respecto, yo voy a ver si concilio el sueño... si no, te leo en breves, supongo jejeje.

Un saludo amigo!

Gracias por todo!

Hola amigo cosme,
ya entendí un poco mejor qué es el rebote. Leí tu POST y me gustó mucho.

Básicamente, el rebote es el continúo triggering de la interrupción en ese tiempo en el que el botón sigue pulsado y nosotros no somos capaces de soltar en lo que sería una sola interrupción, y por ello debemos regular con software o hardware para evitar interrupciones innecesarias, que es lo que me está pasando a mí creo.

Creo que leyendo tu explicación, me atrevería a lanzarme a la piscina y programar yo algo según mi configuración.

Lo que no acabo de entender bien, es según la configuración que tengo del botón, la cual no sabría decirte si es de flanco positivo o negativo, cuál sería la configuración adecuada de mi interrupción. 
Es decir, si debiera de ser on "rising-edege" ó "falling-edge"... (Yo creo que esta última, es así ?

Bueno, un saludo, y gracias de nuevo. 

Sos un maestro... jaja.

Abel.


----------



## cosmefulanito04 (Dic 28, 2013)

abeltomillo dijo:


> Básicamente, el rebote es el continúo triggering de la interrupción en ese tiempo en el que el botón sigue pulsado y nosotros no somos capaces de soltar en lo que sería una sola interrupción, y por ello debemos regular con software o hardware para evitar interrupciones innecesarias, que es lo que me está pasando a mí creo.



El rebote es producto del pulsador, cuando lo largas, justamente rebota y pasa lo que te puse en la figura de arriba, conduce... deja de conducir... todo en forma aleatoria. 



abeltomillo dijo:


> Creo que leyendo tu explicación, me atrevería a lanzarme a la piscina y programar yo algo según mi configuración.



La idea es que hagas eso, te bases en los 5 pasos que puse. Es altamente recomendable que esos pasos *no* los hagas dentro de la rutina de interrupción.



abeltomillo dijo:


> Lo que no acabo de entender bien, es según la configuración que tengo del botón, la cual no sabría decirte si es de flanco positivo o negativo, cuál sería la configuración adecuada de mi interrupción.
> Es decir, si debiera de ser on "rising-edege" ó "falling-edge"... (Yo creo que esta última, es así ?



Es cuestión de analizarlo amigo, cuando apretás el pulsador ¿de qué estado inicial a qué estado final pasas?


----------



## abeltomillo (Dic 29, 2013)

Buenos días por aquí amigo cosme,

gracias por tu respuesta, como siempre tan amigo mío... .


Bueno, citaría tus respuestas pero no sé cómo, así que como siempre te voy a responder como sé, jeje.

El rebote ya lo entendí mejor que antes, y eso me hace feliz. Así que gracias por tu explicación .

El tema del antirebote, lo voy a tener que estudiar cuando tenga tiempo, para entenderlo a mayor profundidad y así poder implementarlo.

Finalmente, te diré muy a mi pesar, que como decimos por aquí: "me has pillado!" jaja, es decir, no sé a qué te refieres con el estado inicial del que estoy al que paso finalmente. Sin embargo, puedo decirte, que por como está conectado el botón, yo siempre creí que esto tenía que ver con si quería la interrupción cuando pasase de GND a VCC, o viceversa... por lo que, según tengo conectado, diría que es "rising edge" porque quiero que la interrupción se genere en cuanto se pulse el botón. O sería mejor, cuando se pulsase y se dejase de pulsar? Sinceramente, creo que una interrupción sigue un ciclo, es decir, pasa por 2 estados, estando primero en 1: +...-...+ -> se genera interrupción. ó, -....+....- -> se genera interrupción. ¿Es así? 

Como siempre, disculpa mi ignorancia, ya me gustaría a mí saber lo que tú! jajaja

un saludo muy grato, y espero sigamos en contacto mucho tiempo más.

Un abrazo.

Abel.


----------



## cosmefulanito04 (Dic 29, 2013)

Exacto, así como colocaste el pulsador la interrupción debe ser configurada para detectar flanco ascendente porque la entrada de dicha interrupción pasa de GND (sin pulsar) a Vcc (pulsado).

Sobre el antirrebote, podés encontrar mucha información en el foro, algunos simplemente la implementan con un delay de 100 o 300 mSeg, no es la mejor solución, pero sirve.


----------



## abeltomillo (Dic 30, 2013)

Buenas amigo cosme,

esta mañana he estado estudiando el tema, ya he entendido cómo puedo hacer para controlar el rebote. O sea, implementar un anti-rebote. El problema que tengo ahora mismo, es que la interrupción salta sola, pasados 3 segundos desde que lo enchufo. Seguramente debe ser un error de programación.
Algo que veo no me gusta, es que uso la misma función para las 2 interrupciones (TMR0 e INT), porque con el SDCC compiler versión 3.3.0 no consigo definir 2 distintas, para cada. Por lo que en el código anterior que postee anteayer, está programado que la misma rutina compruebe la INTF y la T0IF, para saber qué interrupción ha saltado... pero creo que no es correcta esta programación, y puede ser causa de fallos en el futuro.

Por lo dicho antes, pregunto a tu persona, más experimentada y con más conocimiento, para adquirir consejo al respecto. ¿Debería cambiar de compilador, o simplemente es la versión?

He observado en la red, buscando por google.com, páginas que muestran como definir una interrupción para según qué acción, por ejemplo, una interrupción para la externa, debería usar una función tal que así:


```
void isr_intexterna (void) __interrupt 0 {
 // body
}
```

Y para la interrupción del timer 0, sería lo mismo, cambiando el nombre y el número correspondiente a la interrupción: __interrupt 1

Bien, pues esto hice, y al compilar el código C, el código ensamblador aparece repitiendo un label, y por tanto el ensamblamiento resulta en error.

¿Algún consejo, respecto a otro compilador, forma de programarlo o resolución de la duda sobre el por qué salta sola la interrupción? Con respecto a este último enumerado concepto, debo decir que si la interrupción salta sola, al cabo de 1 segundo, debería aparecer de nuevo la hora, en vez de 6666 todo el rato, tras 3 segundos.

Gracias,

un abrazo.

Saludos a todos los que nos leáis.

Abel.


----------



## cosmefulanito04 (Dic 30, 2013)

Nunca ví que una rutina de interrupción manejara dos periféricos distintos.

¿Qué dice el datasheet respecto a las interrupciones de c/periférico?

Nota: yo nunca usé PIC y menos el 16f84, por lo tanto te recomiendo que preguntes en la zona de uC.


----------



## abeltomillo (Dic 30, 2013)

Buenas,

amigo cosme, yo hace tiempo estuve leyendo un manual/libro del MCS51 para ayudar a un amigo a aprobar un exámen. Entonces aprendí que los uC utilizan un vector a partir de X dirección, en donde te caben justos unos jumps a las rutinas que manejan las interrupciones. Es por eso que estuve todo el día ofuscado, pensando que sdcc tenía un fallo; pero parece ser que cuando se programa en C y opcionalmente en ASM, se utiliza una sola rutina. En función de los flags establecidos por el uC, se detecta el tipo de interrupción ocurrida.

Voy a seguir ahora que ya sé, (porque descargué el MPLAB IDE y el XC8 para Linux y lo aprendí), verificando que mi código esté bien.

Muchas gracias por tu ayuda, pronto te informaré con más detalles.

Gracias.

Abel.


----------



## cosmefulanito04 (Dic 31, 2013)

No señor, por lo menos no con las familias de uC que usé, eso incluye familia 8051, AVR y ARM. Cada periférico tiene su propia rutina de interrupción.

La pregunta es, ¿el 16f84 tiene un vector de interrupciones? o ¿es tan precario que tenés una sola dirección de interrupción donde es necesario manejar a todos los periféricos dependiendo del estado de un bit?


----------



## abeltomillo (Dic 31, 2013)

Según el datasheet, el vector de interrupción está en la dirección 0004h, y no muestra ninguna otra dirección ni espacio del mismo. Así que debe ser lo que tú dices: precario.

Así que rectifico, tienes tú la razón cuando dices que cada servicio tiene su rutina, yo lo aprendí así. 
Y debe ser que sdcc detecta que es 16f84a y solo puede tener una rutina.

En todos los topics que he visto al respecto de la família 16f8XX (si mal no recuerdo), es que utilizan una sola rutina.

Y de hecho, el XC8 de microchip, utiliza una keyword para definir una rutina de interrupción.

Y en ningún caso, excepto en el MCS51 y código ASM, he visto que se puedan asociar rutinas a servicios de interrupción. 

Todos comentan, que utilizan una sola rutina en caso de estos uC.

Saludos,

gracias por la contestación.

Un abrazo.



Rectifico: En ningún caso he visto que se pueda asociar una rutina a un servicio concreto, excepto con SDCC cuando se usa la keyword __interrupt y entre '(' y ')' (paréntesis) el identificador según el uC, correspondiente a un servicio distinto: Ext, TMR0, Ext2, TMR1, etc.

En el caso de los uC 18F, existen interrupciones de alta y baja prioridad, y el vector y la definición de las mismas, se parece más a lo que me has dicho: una rutina por servicio.

Pero debe ser que la família 16F8XXy es más precaria.

Trabajando con arduino, recuerdo haber podido asociarlas a diferentes servicios. Pero esto no recuerdo bien cómo hacerlo y tampoco lo aprendí en profundidad.

EDIT: que no se me malinterprete, cuando digo "en ningún caso" me refiero a lo que conozco, supongo que las interrupciones y la forma de manejarlas varían según el uC, chip o lo que sea...



Por cierto, ya conseguí que funcionase el pulsador. Y ahora tengo el problema del rebote, antes lo que me ocurría puede ser por 2 razones:

1. no limpiaba el valor de RB0
2. no tenía el pin RB0 como entrada
3. 1 y 2.

Ahora tengo que hacer que cuando pulso el botón no rebote jeje...


----------



## cosmefulanito04 (Dic 31, 2013)

El antirrebote por soft más sencillo es usar un delay, con el inconveniente que desaprovechas la capacidad del uC (es decir, cero optimización).

La idea sería:

*Declarás una nueva variable global que vas a usar como flag (puede que necesite ser volátil)*


```
unsigned char flag_interrupcion_externa=0;
```

o


```
volatile unsigned char flag_interrupcion_externa=0;
```


*Incluís esa variable en tu rutina de interrupción*


```
void isr() __interrupt 0 {                                            /* interrupt service routine */
  
  if (T0IF == 1) {  
      ....// Tú código para el timer
  }
  
  if (INTF == 1) { /*** Service External Routine (button) ***/
    INTF = 0;    
    flag_interrupcion_externa=1;
  }
}
```

*Luego en main*


```
void main() {
   ... // Inicialización
   
   while (1) {
   ... // Tú código
   
   if(flag_interrupcion_externa)
     {
        ....//Deshabilitá la interrupción externa!
        flag_interrupcion_externa=0; //Reseteo el flag        
        delay(); //De 50 a 300mS, es cuestión de probar
        
        switch (mode) {
                  ...// Tú código que estaba en la rutina de interrupción      
        }
        
         ....//Habilitá la interrupción externa!
     }
   }
}
```


----------



## abeltomillo (Ene 1, 2014)

Aaaah!! cojones... jeje ya entendí.

Le podría poner algo más para aprovechar que tengo el timer0, o sea no haría falta el delay, pero ya lo entendí!!

muchas gracias, feliz año a tod@s!!
ya te cuento más cosas


----------



## SorReNtO (Nov 7, 2015)

¿Qué tal, amigos?
Acudo a ustedes ya que tengo un problema con un display de 7 segmento de 4 dígitos.
He programado un contador de 0 a 9999 y el programa corre bien, ya lo probé en Proteus.

El problema sucede cuando lo implemento físicamente, cuenta de 0 a 9999 pero una parte del dígito en los 4 dígitos siempre permanece prendida, lo que no me deja visualizar bien los números.
Si le reduzco la corriente de alimentación al display con una resistencia, disminuye ese defecto pero los dígitos se ven opacos.

¿A alguien le ha pasado algo parecido?

Gracias de antemano por sus respuestas.


----------



## D@rkbytes (Nov 7, 2015)

Eso puede ser problema del programa y debes adjuntar el proyecto completo para revisarlo.

Cuando usas varios displays tienes que compensar los retardos para que se logre una iluminación pareja en todos.


----------

