Prevención de desbordamientos de pila en PIC MCU utilizando lenguaje C MPLAB X

1

Estoy escribiendo un código de lenguaje C para PIC16f877a para un reloj de alarma. En resumen, el reloj de alarma muestra Hora, Configurar alarma y una temperatura & Lectura de humedad en una pantalla LCD.

He escrito interrupciones para actualizar la hora, para activar y desactivar la alarma y algunas otras que planeo escribir.

El problema es que estoy en medio punto de mi código y el problema de desbordamiento de pila ha aumentado en la simulación de proteus. He identificado la parte del código que causa el problema. Pero parece que no entiendo cómo debo cambiarlo para evitar el desbordamiento de pila.

¿Puede alguien ayudarme a depurar este código? ¿Y anote las malas prácticas en la programación del microcontrolador C que causan errores similares? Parece que no puedo encontrar esa lista de malas prácticas en Internet.

Aquí está el código que he escrito para configurar la alarma / hora en el reloj. El desbordamiento comienza a ocurrir una vez que selecciono la opción de configurar el tiempo. Luego sigue sucediendo hasta que el PIC se bloquea incluso cuando salgo de la rutina setTime.

#define UP RD0   // Push buttons active high
#define DOWN RD1
#define SELECT RD2
#define BACK RD3
#define SNOOZE RD4

void UpdateSetTimeScreen() {
    if (ptr > 1)
        LCD_cursor(ptr + 1, 1);
    else
        LCD_cursor(ptr, 1);

    if (set[ptr] == 0)
        LCD_puts("_");
    else
        LCD_display_value(set[ptr]);
}

void SetTime() {
    LCD_clear();
    LCD_puts("Set Time");

    LCD_cursor(0, 1);
    LCD_puts("__:__");
    LCD_cursor(0, 1);

    set[0] = 0;
    set[1] = 0;
    set[2] = 0;
    set[3] = 0;

    ptr = 0;

    unsigned int i =1;

    while (i) {
        if (UP == 1) {
            while (UP);
            switch (ptr) {
                case 0:
                {
                    if (set[ptr] < 2) {
                        set[ptr]++;
                        UpdateSetTimeScreen();
                    }
                    break;
                }
                case 1:
                {
                    if (set[ptr] < 3) {
                        set[ptr]++;
                        UpdateSetTimeScreen();
                    }
                    break;
                }
                case 2:
                {
                    if (set[ptr] < 5) {
                        set[ptr]++;
                        UpdateSetTimeScreen();
                    }
                    break;
                }
                case 3:
                {
                    if (set[ptr] < 9) {
                        set[ptr]++;
                        UpdateSetTimeScreen();
                    }
                    break;
                }
            }
        }
        if (DOWN == 1) {
            while (DOWN);
            if (set[ptr] > 0) {
                set[ptr]--;
                UpdateSetTimeScreen();
            }
        } else if (BACK == 1) {
            while (BACK);
            ptr--;
        } else if (SELECT == 1) {
            while (SELECT);
            if (ptr == 3)
                i=0;
            else
                ptr++;
        }
    }

    hour = (set[0]*10) + set[1];
    minute = (set[2]*10) + set[3];
}

void SetAlarm() {
    LCD_clear();
    LCD_puts("Set Alarm Time");
    LCD_cursor(0, 1);
    LCD_puts("__:__");
    LCD_cursor(0, 1);

    set[0] = 0;
    set[1] = 0;
    set[2] = 0;
    set[3] = 0;

    ptr = 0;
    unsigned int j = 1;

    while (j) {
        if (UP == 1) {
            while (UP);
            switch (ptr) {
                case 0:
                {
                    if (set[ptr] < 2) {
                        set[ptr]++;
                        UpdateSetTimeScreen();
                    }
                    break;
                }
                case 1:
                {
                    if (set[ptr] < 3) {
                        set[ptr]++;
                        UpdateSetTimeScreen();
                    }
                    break;
                }
                case 2:
                {
                    if (set[ptr] < 5) {
                        set[ptr]++;
                        UpdateSetTimeScreen();
                    }
                    break;
                }
                case 3:
                {
                    if (set[ptr] < 9) {
                        set[ptr]++;
                        UpdateSetTimeScreen();
                    }
                    break;
                }
            }
        }
        if (DOWN == 1) {
            while (DOWN);
            if (set[ptr] > 0) {
                set[ptr]--;
                UpdateSetTimeScreen(ptr);
            }
        } else if (BACK == 1) {
            while (BACK);
            if(ptr > 0)
                ptr--;
        } else if (SELECT == 1) {
            while (SELECT);
            if (ptr == 3)
                j=0;
            else
                ptr++;
        }
    }

    AlarmHr = (set[0]*10) + set[1];
    AlarmMin = (set[2]*10) + set[3];

}

void SetTemp() {
}

void print_configuration_screen() {
    LCD_clear();
    switch (scr) {
        case 1:
        {
            LCD_puts("* Set Time");
            LCD_cursor(0, 1);
            LCD_puts("  Set Alarm");
            break;
        }
        case 2:
        {
            LCD_puts("  Set Time");
            LCD_cursor(0, 1);
            LCD_puts("* Set Alarm");
            break;
        }
        case 3:
        {
            LCD_puts("  Set Alarm");
            LCD_cursor(0, 1);
            LCD_puts("* Temp Mode");
            break;
        }
        case 4:
        {
            LCD_puts("* Set Alarm");
            LCD_cursor(0, 1);
            LCD_puts("  Temp Mode");
            break;
        }
    }
}

void ConfigurationMode() {
    scr = 1;
    print_configuration_screen();
    while (mode == 2) {
        if (BACK == 1) {
            while (BACK);
            mode = 1;
        } else if (UP == 1) {
            while (UP);
            if (scr > 1) {
                if (scr == 3)
                    scr = 4;
                else if (scr == 4)
                    scr = 1;
                else
                    scr--;
            }
            print_configuration_screen();
        } else if (DOWN == 1) {
            while (DOWN);
            if (scr == 4)
                scr == 3;
            else if (scr < 3)
                scr++;
            print_configuration_screen();
        } else if (SELECT == 1) {
            while (SELECT);
            switch (scr) {
                case 1: SetTime(); // Set time
                    break;
                case 2:
                {
                    SetAlarm(); // Set Alarm
                    mode = 1;
                    break;
                }
                case 3: SetTemp();
                    break;
                case 4:
                {
                    SetAlarm();
                    mode = 1;
                    break;
                }
            }
            scr = 1;
            print_configuration_screen();
        }
    }
}

Adjunto capturas de pantalla para ayudarles a comprender mejor el momento en que surge el problema:

TodoestábienhastaqueentroenlarutinaSetTimeoSetAlarm.

AlpresionarARRIBA/ABAJOparaajustarlahora,encadapulsación,seproducenunos7a8desbordamientosdepila.

DespuésdesalirdeConfigurationMode()usandoBACK,laMCUsedescomponeylosdesbordamientosdepilacomienzanaocurrirenmileshastaquesebloquea.

    
pregunta Mohsin Anees

2 respuestas

2

Puede intentar, en el Modo de configuración (), combinar el caso 2 y el caso 4 y, en lugar de llamar a SetAlarm, corte el código y péguelo en el caso 2/4.

Lo mismo para el caso 3 si SetTemp va a tener algún código codificado en el caso 3 en lugar de llamar a SetTemp (). Por ahora puedes eliminar SetTemp () del caso 3.

Lo mismo para el caso 1, mueva setTime ()

Si se llama a ConfigurationMode () desde un solo lugar, mueva el código donde se llama.

La regla es, no llame a procedimientos a menos que haya una razón justificable.

    
respondido por el Misunderstood
4

La otra respuesta hizo sugerencias sobre cómo podría superar el problema de desbordamiento de pila. Sin embargo, creo que es necesario señalar por qué existe este problema con este tipo de microcontrolador.

De la hoja de datos de PIC16F87xA, el diagrama de bloques de la MCU muestra esto:

Estos procesadores tienen una pila de hardware de 8 niveles. Eso significa que el número de niveles de llamadas e interrupciones nunca se puede anidar más de 8 de profundidad. Supere eso y su programa toma un descanso y sale a almorzar, y nunca vuelve al trabajo.

Esta arquitectura tiene sus limitaciones sobre otras que colocan la pila en la memoria de datos donde la pila puede ser mucho más grande. La gran ventaja de usar una pila de archivos de pequeños registros dedicados como esta es la velocidad. No se necesitan ciclos de memoria separados para empujar y abrir la dirección de retorno para llamadas de subrutina e interrumpir las rutinas de servicio. Esa ventaja viene con la necesidad de administrar con cuidado la utilización del nivel de pila en todo el programa.

    
respondido por el Michael Karas

Lea otras preguntas en las etiquetas