Detectando la entrada del interruptor en ARM 7 y multiplexando dos pantallas de siete segmentos

0

Estoy intentando multiplexar dos pantallas de siete segmentos, una vez que se detecta una entrada de interruptor.

  1. Si se presiona un interruptor, las siete pantallas de segmento deberían mostrar 1
  2. Si se presiona de nuevo, 2 , luego 3 y así sucesivamente.

Mi problema surge cuando alcanzo el número 9 ya que la siguiente entrada del interruptor mostrará 10 . 1 en el primer SSD y 0 en el segundo SSD. A continuación se muestra un fragmento de mi código con respecto a cómo estoy detectando entradas de 1 a 9.

   int k = 0;
   unsigned int SW1;

   PINSEL0 = 0;                             //Set P0.0 - P0.15 as GPIOS
   PINSEL1 = 0;                             //Set P0.16 - P0.31 as GPIOS
   IO0DIR  = 0xFFFFF9FF;                //Setting  P0.9 as input for SW1     

    while (1)
   {

    SW1 = IO0PIN & 0x00000200; //switch connected on P0.9
    if ( SW1 != 0x00000200 )  //when pressed        
      {
        k++;                
        IO0SET = T1;
        IO0SET = T2;

        if (k == 1){
        IO0SET = T1;               //switching on left seven segment display
        IO0CLR = T2;               //clearing the right seven segment display 
        IO0CLR = a;
        IO0SET = b;
        IO0SET = c;
        IO0CLR = d;             
        IO0CLR = g;                //displaying number 1
        IO0CLR = e;
        IO0CLR = f;
        small_delay();
        }       
       }

Estoy siguiendo la misma estructura para el décimo interruptor presionando:

        else if (k == 10){ 
        IO0CLR = 0x000000FF;        //turn off all the segments as well as both common anodes. Then your outputs will be ready for the new segment patterns to be set up.
        IO0SET = T2;                //switching on first display                            
        IO0SET = b;                     
        IO0SET = c;                 //displaying number 1         
        small_delay();              //calling short delay           
        IO0CLR = 0x000001FF;        

        IO0SET = a;
        IO0SET = b;
        IO0SET = c;             
        IO0SET = d;                 //displaying number 0
        IO0SET = e;
        IO0SET = f;
        IO0SET = T1;    
        small_delay();
        IO0CLR = 0x000000FF;}

El problema con el segundo código que proporciono es que la pantalla de siete segmentos solo muestra 10 una vez. Es decir, el primer 1 se muestra en la pantalla izquierda y luego 0 en la segunda pantalla según sea necesario, sin embargo, esto se realiza solo una vez y no continúa hasta que se detecta la siguiente entrada de interruptor.

Una de las soluciones con las que he encontrado este problema es que incluí una sentencia while después de if else , de manera que:

    else if (k == 10){
        while (k == 10) {   //rest of code

Esto realmente hace lo que quiero que haga, y continúa multiplexando ambos siete segmentos, mostrando el número 10 , sin embargo, el problema en este caso es que no se sale del bucle while para acomodar la siguiente entrada del interruptor.

¿Cómo puedo multiplexar ambas pantallas hasta que se detecte la siguiente entrada del interruptor? Cualquier idea / sugerencia sería muy apreciada.

    
pregunta Rizzo

3 respuestas

2

Dos opciones:

La forma correcta de hacer esto sería que su código de conteo solo cuenta, no configura la pantalla que establece una variable. Luego tiene el código ejecutándose en una interrupción de temporizador que lee la variable de conteo y muestra el número. Si el número es superior a 9, este temporizador puede cambiar entre los dígitos según sea necesario.

La segunda forma es establecer solo un dígito cada vez a través de su bucle

int digitToDisplay = 0; // track which digit we need to display next
while (true) {          // loop forever 
  if (buttonPress())      // count button presses
    count++;

  // no need to do this every time, could be only when count changes but I'm being lazy
  int topDigit = count / 10;       // split value into separate digits.
  int bottomDigit = count % 10;      

  setDisplayOff();                // avoid glitches by turning all LED pins off

  displaySelect(digitToDisplay);  // select the display digit to drive
  if (digitToDisplay == 0)         
    setDisplay(bottomDigit);      // set the pins to display a number
  else
    setDisplay(topDigit);

  if (++digitToDisplay == 2)      // next time we display the other digit
    digitToDisplay = 0;
}

He asumido algunas funciones, bool buttonPress(void) que devuelve tru si se presiona el botón, void setDisplay(int value) que establece los pines IO correctos activos para mostrar el valor dado de 0 a 9 y void setDisplayOff(void) que se apaga todos los leds.
Al configurar las líneas IO en una función separada, mantendrá alejado el comando de cambio desordenado (o si ... más si ... más si ...) lejos de su lógica central, esto hace que la lógica sea mucho más fácil de seguir ya que Ahora todo encaja en la pantalla al mismo tiempo.

Actualización -
En caso de que su aversión a las funciones y los comandos de conmutación se deban a la falta de familiaridad con su uso aquí están las definiciones de funciones. Estos deben ir antes que main () o usted debe declararlos por adelantado y luego colocar el código después de main (). También moví la selección de pantalla a una función para que todo el IO esté fuera del código principal.
Necesitará completar los valores restantes del conmutador, pero debería ser bastante obvio cómo.

void setDisplay(int value) {
  IO0CLR = 0x000000FF; // all pins low (probably redundant but best to be safe.)
  switch (value) {
    default:
        // outside the allowed range. Ignore it. (or display an E I suppose)
      break;
    case 0:
      IO0SET = a;
      IO0SET = b;
      IO0SET = c;             
      IO0SET = d; 
      IO0SET = e;
      IO0SET = f;
      break;
    case 1:
      IO0SET = b;                     
      IO0SET = c;
      break;
    case 2:
      IO0SET = a;
      IO0SET = b;
      IO0SET = d; 
      IO0SET = e;
      IO0SET = g;
      break;
    }
}

void displaySelect(int digitToDisplay) {
  if (digitToDisplay == 0) { // right hand digit
    IO0CLR = T1;  // always clear first.
    IO0SET = T2;           
  } else {
    IO0CLR = T2;  // always clear first.
    IO0SET = T1;           
  }
}


void setDisplayOff(void) {
  IO0CLR = 0x000000FF;
}


// detect button press with basic de-bouncing
// button must have been down exactly 5 calls to this function to return true.

int buttonPress(void) {
  static int downCount= 0; // static = value isn't lost between calls.
  //switch connected on P0.9
  int currentButton = ((IO0PIN & 0x00000200) == 0x00000200); 

  if (currentButton) { // button is down
    if (downCount == 5) { // button has been down for 5 counts
        downCount++;      // increase the count so we don't trigger next time
        return 1;
    } else {              // some count other than 5
      if (downCount < 5)  // increase if it's less than 5
         downCount++;
    }
  } else  // button is up
    downCount=0; 

  return 0;
}
    
respondido por el Andrew
1

Para las pantallas LED, prefiero asegurarme de que cada vez que se encienda el LED 100 veces por segundo. Entonces, en este caso, me gustaría que su rutina de "pequeña demora" sea aproximadamente \ $ 5 \: \ textrm {ms} \ $.

También utilizo una máquina de estado, documentada en EE.SE aquí , para deshacer cambios.

Con eso en la mano:

int main() {
    unsigned int previous, temp;
    unsigned int state= 0;
    unsigned int current= 0;
    unsigned int debounced= 0;
    unsigned int prior_debounced= 0;
    unsigned int ones_digit= 0;
    unsigned int tens_digit= 0;
    unsigned int multiplex= 0;
    IO0CLR= T1;
    IO0CLR= T2;
    for ( ; ; small_delay() ) {

        /* debounce the switch */
        previous= current;
        current= (IO0PIN & 0x00000200);
        temp= (previous ^ current) | state;
        prior_debounced= debounced;
        debounced= (debounced & temp) | (current & ~temp);
        state= previous ^ current;

        /* increment the display value each time a button is pressed */
        if ( debounced != prior_debounced && debounced != 0 ) {
            if ( ++ones_digit > 9 ) {
                if ( ++tens_digit > 9 ) tens_digit= 0;
                ones_digit= 0;
            }
        }

        /* multiplex */
        IO0CLR= T1;
        IO0CLR= T2;
        if ( multiplex == 0 ) {
            set_segments( ones_digit );
            IO0SET= T2;
        } else {
            set_segments( tens_digit );
            IO0SET= T1;
        }
        multiplex= 1 - multiplex;
    }
    return 0; /* never gets here */
}

Por supuesto, no tengo forma de verificar el código anterior. Y es muy posible que me haya perdido un detalle. No sé cómo configuró sus elecciones de segmento A a F a partir de un valor de dígito binario, así que simplemente usé una función "set_segments ()" que supuestamente logra esto. Tendrá que reemplazarlo con el código apropiado. (Sin embargo, su código especifica cómo habilitar cada dígito para la visualización. Así que simplemente copié eso, tal como lo entendí).

    
respondido por el jonk
1

Es posible que desee buscar una rutina rápida que publiqué sobre la conducción de 14 LED de segmento. El proceso básico es el mismo.

  1. Apague la pantalla actual.
  2. Enviar datos de segmento al led.
  3. Enciende el siguiente dígito.

Puede escribirlo de forma genérica para que el código sea útil para todos los mcus. También desea llamarlo desde un Isr de temporizador para que la pantalla se actualice en intervalos fizzed.

editar: aquí está el enfoque anterior implementado en un lpc2106:

//update the display
void led7_display(void) {
    static uint8_t dig=0;         //current digit to be displayed

//blanking
DIG_OFF(DIG_0 | DIG_1 | DIG_2 | DIG_3 | DIG_4 | DIG_5 | DIG_6 | DIG_7);     //turn off all digits
SEG_OFF(SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_DP);    //turn off all segments

//update segment data
SEG_ON(led7_font[lRAM[dig]]); //update the segment data

//turn on the current digit, and advance to the next
//expand to support more digits
//set dig to 0 to force an earlier return - to support fewer digits
switch (dig) {
    case 0: DIG_ON(DIG_0); dig = 1; break;
    case 1: DIG_ON(DIG_1); dig = 0; break;      //only need to support 2 digits
    case 2: DIG_ON(DIG_2); dig = 3; break;
    case 3: DIG_ON(DIG_3); dig = 4; break;
    case 4: DIG_ON(DIG_4); dig = 5; break;
    case 5: DIG_ON(DIG_5); dig = 6; break;
    case 6: DIG_ON(DIG_6); dig = 7; break;
    case 7: DIG_ON(DIG_7); dig = 0; break;      //round off to digit 0 on the next round
    default: DIG_ON(DIG_0); dig = 1; break;     //default to digit 0
}

}

te darás cuenta de que sigue exactamente la misma lógica. tal como está, el código admite 8 dígitos, pero puede expandirse en este chip en particular para admitir hasta 32 dígitos. el código aquí solo admite dos dígitos.

aquí es cómo se encuentra en la simulación: muestra un número fijo de 12 - > solo se muestra '2' debido a la multiplexación.

Noejecutéelled_display()enuntemporizadorisrporsimplicidadaquí,peroenunproyectoreal,debería.

Comopuedever,elcódigoesinmensamenteportátil:nohayformadesabersielcódigoseejecutaenunmcuenparticular.Dehecho,elcódigoseejecutóoriginalmenteenunPICde8bitsylocambiéligeramenteparaejecutarloenunARM7de32bits.

enunPICde8bits,elcódigosecompilaaunos100bytesconXC8enmodolibre.

edición2:aquíseestáejecutandoelmismocódigoenunattiny2313bajoquemuestraunnúmero2313.

elcódigopermitelaconexiónarbitrariadelospinesmcualospinesdelled,loqueesexcelenteparaloschicosdeldiseño.

yenlamedidaenquehayapinesnoutilizadosenunpuerto,susoperacionesnosevenobstaculizadasporelcódigo,esdecir,puedeusarlasparaotracosa.

todoloqueelusuariohaceesincluirlosarchivos.h/.cenelproyecto,especificarlaconexiónyllenarelbúferdepantallalRAM[]conlosnúmerosquesemostrarányelmódulohacesuspropiascosas,disparary-paraolvidarse

oh,elcódigoescompatibleconlosánodoscomunesylosledscatódicoscomunes:losledsenlpc2106sonuntipodecátodocomúnylosdelasimulacióndeataquesonuntipodeánodocomún.

edición3:

elcontroladorledanteriorpermitelaasignaciónarbitrariadepinesledamcupins,siemprequeesténenelmismopuerto.

Aquíhayunaversiónrevisadadondelospinesledpuedenconectarseapinestotalmentediferentesendiferentespuertos,completamentearbitrarios.

sigueelmismoprocesoqueelcontroladoranterior.Aquíestálasimulacióndondeseejecutaenunpic16f1936conduciendounapantallaleddeánodocomún.

    
respondido por el dannyf

Lea otras preguntas en las etiquetas