Actualmente estoy trabajando en un marcador simple usando dos pantallas de 7 segmentos, un registro de desplazamiento (74HC595N), dos transistores PNP (2N3906) y un arduino uno.
Cada pantalla de 7 segmentos es un ánodo común, sin embargo, una pantalla es azul con un voltaje directo de ~3.3V, la otra pantalla es roja y tiene un voltaje directo de ~2V.
Estoy usando resistencias limitadoras de corriente de 220 ohmios en serie con el registro de desplazamiento y los cátodos de los LED. (Sospecho que esto podría ser parte de mi problema, ya que cada pantalla tiene una caída de voltaje diferente en los LED).
Estoy intentando multiplexar las pantallas, pero tengo problemas con las imágenes fantasma. Estoy usando timer1 en el arduino para facilitar este comportamiento.
He configurado el temporizador con el siguiente código:
// Setup TIMER2
/* First disable the timer overflow interrupt while we're configuring */
TIMSK2 &= ~(1<<TOIE2);
/* Configure timer2 in normal mode (pure counting, no PWM etc.) */
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
/* Select clock source: internal I/O clock */
ASSR &= ~(1<<AS2);
/* Disable Compare Match A interrupt enable (only want overflow) */
TIMSK2 &= ~(1<<OCIE2A);
/* Now configure the prescaler to CPU clock divided by 128 */
TCCR2B |= (1<<CS22) | (1<<CS20); // Set bits
TCCR2B &= ~(1<<CS21); // Clear bit
/* We need to calculate a proper value to load the timer counter.
* The following loads the value 131 into the Timer 2 counter register
* The math behind this is:
* (CPU frequency) / (prescaler value) = 125000 Hz = 8us.
* (desired period) / 8us = 125.
* MAX(uint8) + 1 - 125 = 131;
*/
/* Save value globally for later reload in ISR */
tcnt2 = 5;
/* Finally load end enable the timer */
TCNT2 = tcnt2;
TIMSK2 |= (1<<TOIE2);
En el desbordamiento del temporizador, se ejecuta la siguiente función:
ISR(TIMER2_OVF_vect){
// Turn off the active display
if(active_display == 0){
digitalWrite(BLUETRANS, LOW);
}
else{
digitalWrite(REDTRANS, LOW);
}
delayMicroseconds(1000);
// Toggle Display
active_display ^= 1;
// Shift out screen bits
if(active_display == 0){
displayDigit(blueByte);
}
else{
displayDigit(redByte);
}
// Turn display back on
if(active_display == 0){
digitalWrite(BLUETRANS, HIGH);
}
else{
digitalWrite(REDTRANS, HIGH);
}
// Reload the timer
TCNT2 = tcnt2;
}
No entiendo completamente el uso de Timer2, por lo que cualquier ayuda también sería apreciada. Entiendo que el temporizador cuenta hasta el valor de desbordamiento especificado y luego ejecuta el ISR. Sin embargo, mis intentos de reducir la frecuencia de actualización de las dos pantallas parecen hacer que mi programa no responda.
Creo que estoy multiplexando correctamente la pantalla:
Desafortunadamente, parece que no puedo reducir el efecto fantasma en la pantalla roja (el efecto fantasma no parece ocurrir en la pantalla azul).
¡Cualquier ayuda sería muy apreciada!
Entiendo que es posible que no haya incluido toda la información relevante, ¡así que pregunte y recibirá!
¡Gracias!
EDITAR 1
Gracias a Justing, ahora entiendo mucho mejor cómo funciona Timer2 en Arduino. Gracias por eso.
Desafortunadamente, incluso a 60 Hz, puedo ver un efecto fantasma significativo, junto con un parpadeo desagradable y perceptible a medida que alterna entre las pantallas. Con mi nuevo conocimiento de Timer1, pude aumentar con éxito la frecuencia de actualización hasta 244 Hz. Mi circuito actual sigue este diseño básico:
Como se indicó anteriormente, mis resistencias limitadoras de corriente son de 220 ohmios. ¿Podrían los diferentes voltajes directos entre la pantalla AZUL de 7 segundos y la pantalla ROJA de 7 segundos estar causando este problema de efecto fantasma? Una vez más, el único dígito que experimenta este problema es la pantalla ROJA, la pantalla con el voltaje directo más bajo (2 V [rojo] frente a 3 V [azul]). Si esta es realmente la causa, ¿el uso de 8 resistencias adicionales para la segunda pantalla solucionaría este problema? Esperaba poder salirme con la mía con menos resistencias para ahorrarme algo de soldadura en el futuro, pero si soluciona este problema de visualización, valdría la pena.
¿Alguna idea más chicos? ¡Gracias!
EDITAR 2
Estoy publicando mi función displayDigit:
void displayDigit(byte screen){
// Shift data into the shift register
digitalWrite(latchPin, 0); // LATCH LOW TO SHIFT
shiftOut(dataPin, clockPin, MSBFIRST, screen);
digitalWrite(latchPin, 1); // ENABLE SHIFTED BITS
}
EDITAR 3
¿Podrían mis transistores PNP 2N3906 ser los culpables? Me parece que si bien los transistores permiten que la pantalla se encienda muy rápidamente, apagarlos ocurre mucho más lento. Permitiendo que el dígito rojo "vea" el valor de los dígitos anteriores. Sin embargo, esto no explica por qué no hay imágenes fantasma en la pantalla azul. ¿Puedo "levantar" fácilmente el ánodo de la pantalla con una resistencia para ayudar al transistor en su estado "apagado"? "Apagado" aquí es técnicamente Vcc (5V) debido al diseño de ánodo común. La pantalla funciona cuando el ánodo se pone a tierra.
EDICIÓN FINAL
Agradezco a Myforwik por proporcionar la respuesta más breve y también más útil a mi pregunta. Mi ISR ahora se ve así:
ISR(TIMER2_OVF_vect){
// Turn off the active display
if(active_display == 0){
digitalWrite(BLUETRANS, HIGH);
}
else{
digitalWrite(REDTRANS, HIGH);
}
delayMicroseconds(1000);
// Toggle Display
active_display ^= 1;
// Shift out screen bits
if(active_display == 0){
displayDigit(blueByte);
}
else{
displayDigit(redByte);
}
// Turn display back on
if(active_display == 0){
digitalWrite(BLUETRANS, LOW);
}
else{
digitalWrite(REDTRANS, LOW);
}
// Reload the timer
TCNT2 = tcnt2;
}
Resulta que estaba pasando por alto algunas de las partes más fundamentales de mi código. Ambas pantallas estaban encendidas en un instante dado, atormentándome con este problema de imágenes fantasma que en realidad no era un problema de imágenes fantasma en absoluto.
Muchas gracias a Justing, quien proporcionó posiblemente la mejor explicación que he visto sobre cómo configurar el temporizador en el Arduino. Mike DeSimone y Oli Glaser también ayudaron mucho cuando se trataba de solucionar problemas en mi circuito. ¡No puedo expresarles cuánto aprecio su ayuda!
Si bien mi problema real fue extremadamente básico, ¡espero que todas las respuestas que se encuentran en esta página puedan ser útiles para alguien, en algún lugar en el futuro!
¡Gracias de nuevo!
El problema es que tienes encendido y apagado mezclado.
El transistor pnp estará en corte cuando la salida sea alta, no baja.
Por lo tanto, está encendiendo ambas pantallas durante la espera de 1000us.
Para complementar la respuesta de Oli, continuaré y revisaré el código de configuración de Timer2. Asumiré que el Arduino está funcionando a un reloj de 16 MHz (la búsqueda en Google reveló que esto es probablemente el valor predeterminado) y el chip es un ATMEGA328P .
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
Como dice el comentario, esta parte desactiva las características especiales de este contador (PWM, PWM rápido, etc.). Se puede ver que los bits WGM2 se dividen entre los registros de control A y B:
Se puede ver que los valores iniciales de estos registros al reiniciar son todos ceros de todos modos, por lo que el código anterior realmente ni siquiera es necesario.
A continuación configuramos la fuente del reloj:
ASSR &= ~(1<<AS2);
El registro y la descripción de bit anterior nuevamente nos muestran borrando un bit, esta vez el bit AS2. Esto indica que el temporizador contará desde el reloj de E/S del reloj principal del sistema. La alternativa se describe como un cristal externo que podría usarse. (puede ser más lento, menos potencia, mejor precisión)
La siguiente línea inhabilita una interrupción de comparación de salida:
/* Disable Compare Match A interrupt enable (only want overflow) */
TIMSK2 &= ~(1<<OCIE2A);
La descripción describe lo que se está deshabilitando. ¡Por qué se molestó en deshabilitar solo la comparación A y no la comparación B (que de todos modos están desactivadas de forma predeterminada en primer lugar) me supera! ¡Próximo!
/* Now configure the prescaler to CPU clock divided by 128 */
TCCR2B |= (1<<CS22) | (1<<CS20); // Set bits
TCCR2B &= ~(1<<CS21); // Clear bit
¡Es hora de configurar la velocidad del reloj del temporizador! Esto preescalará (dividirá) el reloj IO que seleccionamos anteriormente para alimentar el temporizador. Esto permitirá una velocidad de reloj más baja que es más práctica para nuestra aplicación para el temporizador.
La tabla anterior muestra que borrar los bits CS20 y CS22 y configurar CS21 pero preescalará el reloj IO en 128. Esto significará que el reloj que alimenta el temporizador 2 será:
16MHz/128 = 125 kHz
lo que significa un pulso de reloj cada:
1/125kHz = 8us
que desbordaría un temporizador de 8 bits cada:
8us*2^8 = 2ms -> 488 Hz
¡que es mucho más rápido que los 50 Hz que sugiere Oli!
Lo primero que podríamos intentar sería aumentar el prescaler desde arriba a 1024 (el máximo):
TCCR2B |= (1<<CS22) | (1<<CS21) | (1<<CS20); // Set bits
El uso de este preescalador daría un intervalo de interrupción de:
16MHz / 1024 = 15.625 kHz
dando un pulso de reloj de:
1/15.625kHz = 64us
Desbordando el temporizador cada:
64us * 2^8 = 16.384 ms --> 61 Hz
Esto da un valor muy cercano a la recomendación de Oli de 50 Hz y debería brindarle una pantalla de aspecto razonable.
Si aún necesita ajustar la pantalla, tiene dos opciones:
Incrementa una variable cada interrupción. Una vez que esta variable alcance un valor determinado, realice las funciones de interrupción deseadas (actualice la pantalla) y vuelva a establecer la variable en cero. Esto le dará la posibilidad de realizar la interrupción de cualquier múltiplo entero del intervalo de desbordamiento.
El intervalo de interrupción se puede reducir desde el valor preescalado cargando previamente el registro del contador del temporizador (tcnt2). Esto significa que el registro del temporizador comenzará a contar en ese valor especificado en lugar de cero. Este valor deberá recargarse en cada ISR. Este método le permite disminuir el intervalo de interrupción en un múltiplo entero del reloj de E/S preescalado que se alimenta al temporizador. (este método no le permitirá aumentar el retraso)
Parece que su rutina de interrupción se activa demasiado rápido, y más rápido no deja tiempo para ejecutar el código principal, por lo que el uC parecerá no responder.
Para una pantalla típica, una frecuencia de actualización de alrededor de 50 Hz es adecuada para engañar al ojo haciéndole creer que es continuo.
Ajuste su temporizador por un período de alrededor de 10 ms (100 Hz dividido por dos pantallas equivale a una actualización de 50 Hz para cada pantalla) entre interrupciones (si es solo un temporizador de 8 bits, use el preescalador para dividir el reloj un poco más, o si el divisor no lo hace). t vaya lo suficientemente alto, entonces, como dice Mike en los comentarios, use una variable de conteo en el ISR y ejecute el evento cada n interrupciones. O use el temporizador de 16 bits)
EDITAR: está bien, entonces corrigió el tiempo de interrupción a un valor más razonable pero el parpadeo persiste. Por la forma en que tiene el código en el ISR, parece que el período entre el apagado de una pantalla y el encendido de la otra está fijo en el retraso de 1000us de todos modos, siempre que no llame al ISR tan rápido como para hacer el uC no responde, entonces no debería importar demasiado (aunque obviamente demasiado rápido limita el tiempo que tiene en su ciclo principal para realizar otras cosas, así que solo vaya tan rápido como necesite para detener el parpadeo, digamos <400Hz o menos)
De todos modos, habría pensado que el retraso de 1 ms debería ser suficiente para volver a apagar el PNP. Supongo aquí que el pin es una salida push-pull con un impulso razonable para alto y bajo (lo comprobaré en breve)
Así que un par de cosas para probar:
Tendría sentido que las imágenes fantasma no ocurran en la pantalla azul, ya que tendrá un voltaje directo más alto que la pantalla roja, por lo que se apagará más rápido (y se encenderá más lentamente)
Si tiene un osciloscopio, pruebe la base del PNP y las líneas del colector mientras cambia para ver cuánto tarda la transición.
Me gustaría ampliar la respuesta de Oli con respecto a los transistores.
Los BJT, en una configuración de emisor común como la que está usando, son básicamente amplificadores de corriente: toman su corriente base, la multiplican por su , y sacar esa cantidad de corriente de su colector.
Por lo tanto, su transistor debe poder generar la corriente máxima (todos los segmentos) de 5 V fuera del colector. Dado tu 220 resistencias de segmento y los voltajes directos de 2 o 3 V, obtenemos:
(En mi humilde opinión, estos parecen bastante altos. Por lo general, solo necesito un promedio de 2 mA, que sería 4 mA aquí debido a su ciclo de trabajo del 50%, para iluminar los LED más antiguos, y mucho menos para los LED más nuevos de "alta eficiencia").
Entonces, las corrientes totales son 84 mA para el rojo y 49 mA para el azul. Mirando la hoja de datos 2N3906 , veo un par de problemas potenciales, mirando los gráficos en la página 3:
Entonces, averigüemos cuál debe ser su corriente base en el peor de los casos. Supongamos un mínimo de 30 (de la tabla "Sobre las características" en la página 2, usando = -100mA). Eso significa que necesita 2,8 mA de impulso en la base. Usando un de -1,0 V de la misma tabla:
Entonces los 2.2 k resistencias no son suficientes (pero son suficientes para típico en lugar de mínimo ; típico es al menos 75 del gráfico en la página 3) y el 470 La resistencia debe ser bastante fuerte. También verifique que su pin de E / S pueda absorber tanta corriente.
En mi humilde opinión, está poniendo demasiada corriente a través de cada segmento o simplemente está pidiendo demasiado al 2N3906. Realmente desea que su transistor tenga un nivel razonablemente plano. a lo largo de su rango actual.
Además, al conducir altas corrientes en pantallas de 7 segmentos, he visto efectos de "fantasma" en los que la luz de un segmento simplemente se derrama hacia los segmentos físicamente vecinos. Asegúrese de que esto no le suceda a usted: controle todos los segmentos en una pantalla y uno en la otra, y vea si los 6 segmentos "apagados" muestran diferentes brillos fantasma dependiendo de la proximidad al segmento iluminado.
Personalmente, uso MOSFET para estas aplicaciones. Típico de 1 da una caída de voltaje mucho menor y cambio de corriente frente a segmentos iluminados (siempre y cuando ), la corriente de la compuerta es tan baja que cualquier cosa puede impulsarla (está impulsada por voltaje, no por corriente), y no hay que lidiar con el voltaje de saturación.
A menudo, para cosas como esta, la multiplexación de LED no requiere una escritura completa en el LED con cada interruptor. Personalmente, bloquearía lo que debe estar en AMBOS 7 segmentos, y luego solo usaría la interrupción del temporizador SOLAMENTE para cambiar el LED que está manejando, y simplemente dejaría que la interrupción se ejecutara libremente. Cargue números nuevos en los pestillos SOLO cuando necesite cambiar lo que hay en los 7 segmentos.
Tener que lidiar con los 7 segmentos completos correctamente con cada conmutador múltiplex parece que está incrustando esta tarea en el nivel incorrecto, lo que genera grandes ineficiencias.
Alternativamente, hay circuitos integrados que hacen esto específicamente para 7 segmentos, como el SAA1064.
justamente
justamente
tim bueno
miforwik
Jasén
Codebeat