El retraso se calcula mal en C incrustada

0

Soy nuevo en C incrustado y he estado luchando con él durante un tiempo. El resultado deseado para este proyecto es: Cuando no se presiona SW1, el LED azul debe estar encendido. Cuando se presiona SW1, el LED azul debe encenderse y apagarse cada 100 ms. Escribí este código pero no parece funcionar correctamente. Lo probé en el simulador y el LED cambia, pero el retraso es de más de 100 ms, es como un segundo. Y en el tablero real, obtengo resultados aleatorios, a veces no se apaga y a veces cambia de color a púrpura. ¿Por qué este código no se comporta como debería? ¿Por qué estoy obteniendo resultados aleatorios?

Código: pastebin.com/ShE9rDCG

// BranchingFunctionsDelays.c Lab 6
// Runs on LM4F120/TM4C123
// Use simple programming structures in C to
// toggle an LED while a button is pressed and
// turn the LED on when the button is released.  
// This lab will use the hardware already built into the LaunchPad.
// Daniel Valvano, Jonathan Valvano
// January 15, 2016

// built-in connection: PF0 connected to negative logic momentary switch, SW2
// built-in connection: PF1 connected to red LED
// built-in connection: PF2 connected to blue LED
// built-in connection: PF3 connected to green LED
// built-in connection: PF4 connected to negative logic momentary switch, SW1

#include "TExaS.h"

#define GPIO_PORTF_DATA_R       (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R        (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_AFSEL_R      (*((volatile unsigned long *)0x40025420))
#define GPIO_PORTF_PUR_R        (*((volatile unsigned long *)0x40025510))
#define GPIO_PORTF_DEN_R        (*((volatile unsigned long *)0x4002551C))
#define GPIO_PORTF_AMSEL_R      (*((volatile unsigned long *)0x40025528))
#define GPIO_PORTF_PCTL_R       (*((volatile unsigned long *)0x4002552C))
#define SYSCTL_RCGC2_R          (*((volatile unsigned long *)0x400FE108))
#define SYSCTL_RCGC2_GPIOF      0x00000020  // port F Clock Gating Control

// basic functions defined at end of startup.s
void DisableInterrupts(void); // Disable interrupts
void EnableInterrupts(void);  // Enable interrupts
void portF_init(void);
void delay100ms(unsigned long time);


int main(void)
{
        unsigned long volatile delay;
      // activate grader and set system clock to 80 MHz
        TExaS_Init(SW_PIN_PF4, LED_PIN_PF2);  
        portF_init();
        EnableInterrupts();      
        // set PF2
        GPIO_PORTF_DATA_R |= 0x04;
        while(1)
        {
                delay100ms(1);
              // if switch PF4 is pressed and LED is ON (00000101)
            if( GPIO_PORTF_DATA_R == 0x05)
                {
                      // turn LED OFF (clear bit)
                      GPIO_PORTF_DATA_R &= ~0x04;
                }      
                // if switch PF4 is pressed and LED is OFF (00000001)
                else if (GPIO_PORTF_DATA_R == 0x01)
                {
                        // set PF2 - turn LED ON
                      GPIO_PORTF_DATA_R |= 0x04;
                }
                else
                {
                        // set PF2
                        GPIO_PORTF_DATA_R |= 0x04; 
                }
        }
}

void portF_init(void)
{
        volatile unsigned long delay;
        SYSCTL_RCGC2_R |= 0x00000020;     // 1) F clock
        delay = SYSCTL_RCGC2_R;           // delay  
        GPIO_PORTF_AMSEL_R = 0x00;        // 3) disable analog function
        GPIO_PORTF_PCTL_R = 0x00000000;   // 4) GPIO clear bit PCTL  
        GPIO_PORTF_DIR_R = 0x04;          // 5) PF4 input, PF2 output  
        GPIO_PORTF_AFSEL_R = 0x00;        // 6) no alternate function
        GPIO_PORTF_PUR_R = 0x01;          // disble pull-up resistor
        GPIO_PORTF_DEN_R = 0x14;          // 7) enable digital pins PF4 & PF2        
}

void delay100ms(unsigned long time)
{
        unsigned long i;
        while(time > 0)
        {
                i = 1333333;  // this number means 100ms
                while(i > 0)
                {
                        i = i - 1;
                }
                time = time - 1; // decrements every 100 ms
      }
}
    
pregunta Mahmoud Khaled

3 respuestas

3
  • La función de retardo está rota.

    En primer lugar, debe evitar escribir retrasos con bucles de ocupado. Dichos retrasos son inestables, poco fiables y no portátiles. Crean un acoplamiento apretado a la frecuencia de reloj del sistema. También en el caso de los modos de reposo, hacen que la CPU consuma corriente innecesariamente. Siempre usa temporizadores de hardware en chip en su lugar.

    Ahora, si insiste en escribir dicho bucle de retardo, debe declarar el iterador del bucle real volatile . De lo contrario, el compilador podría eliminar todo el bucle, ya que no contiene efectos secundarios. No es suficiente hacer que la variable en la persona que llama volatile , ya que la función está utilizando una copia local de la variable pasada. La variable dentro de la función debe ser volatile .

  • Otro problema aquí es la falta de eliminación de cambios del conmutador. Solo puede escapar sin él si tiene un filtro RC de hardware en el interruptor.

  • Además, ¿el interruptor tiene una resistencia de extracción externa o asume que habilitas uno internamente? Necesitas compartir los esquemas.

respondido por el Lundin
1

Vuelva a comprobar qué interruptor está intentando usar y qué bit corresponde. Los comentarios cerca de la parte superior sugieren que SW2 está asociado con el bit 0 y SW1 está asociado con el bit 4. En portF_init() configuró GPIO_PORTF_DEN_R = 0x14; , lo que sugiere que desea usar SW1. Pero luego, en el bucle while en main() , prueba if( GPIO_PORTF_DATA_R == 0x05) , que lee SW2.

En cuanto al problema de la demora, no esperaría que el simulador muestre el mismo tiempo que el sistema de hardware real. No me sorprende que el simulador funcione más lento que el hardware.

    
respondido por el kkrambo
0

Creo que es necesario habilitar la resistencia de pull-up interna para PF4 (SW1). Pero sospecho que la siguiente línea no lo hace.

GPIO_PORTF_PUR_R = 0x01;          // disble pull-up resistor

¿Debería ser esto en su lugar?

GPIO_PORTF_PUR_R = 0x10;          // enable PF4 pull-up resistor

Además, el siguiente condicional se basa en el estado de cada bit del Puerto F cuando realmente solo estás interesado en dos de los ocho bits. (Por cierto, no está claro por qué espera que se establezca PF0 cuando no configuró / habilitó PF0).

      // if switch PF4 is pressed and LED is ON (00000101)
    if( GPIO_PORTF_DATA_R == 0x05)

Debes reescribir esto para que no dependa del valor de los bits que no te interesan. Utilice el operador bitwise Y para aislar los bits de interés. Y creo que sería bueno usar funciones de ayuda que hagan obvio cuál es su intención. Tal vez así:

#define BLUE_LED_BIT (0x04)
#define SW1_BIT (0x10)

bool IsSwitch1Pressed()
{
    // Bit is clear when switch is pressed.
    return ((GPIO_PORTF_DATA_R & SW1_BIT) == 0);
}

bool IsBlueLedOn()
{
    // Bit is set when LED is on.
    return ((GPIO_PORTF_DATA_R & BLUE_LED_BIT) != 0);
}

int main(void)
{
    ...

    while(1)
    {
        delay100ms(1);

        if( IsSwitch1Pressed() && IsBlueLedOn() )
        {
            // Turn LED off (clear bit)
            GPIO_PORTF_DATA_R &= ~BLUE_LED_BIT ;
        }      
        else
        {
            // Turn LED on
            GPIO_PORTF_DATA_R |= BLUE_LED_BIT ; 
        }
    }
}
    
respondido por el kkrambo

Lea otras preguntas en las etiquetas