1 votos

La pantalla LCD de 20x4 basada en HD44780 se retrasa en la impresión

Estoy usando mi LCD 20x4 basado en HD44780 con la famosa mochila I2C, alias el módulo expansor I2C I/O, el PCF8547, el módulo expansor I2C I/O está conectado al LCD 20x4 y está conectado a través del bus I2C a mi microcontrolador PIC de 8 bits, PIC18F4620.

Ahora lo que estoy tratando de hacer es tener diferentes menús en la pantalla LCD, cada menú utiliza todos los 80 caracteres de la pantalla, y yo uso un codificador giratorio para moverse entre los menús.

Ahora el código de todo esto está escrito y funciona. Mi problema es otra historia, mi problema es que cuando ejecuto el programa, la primera vez que intento desplazarme por todo los menús, hay un retraso notable en la impresión de las líneas, para ser muy específicos, a veces hay un retraso en la impresión a partir de la segunda línea (contando desde uno y no desde cero como suele contar la pantalla LCD), y a veces hay un retraso en la impresión a partir de la tercera línea. Ahora, cuando intento desplazarme de nuevo por todo los menús, este notable retardo desaparece, literalmente desaparece, no hay retardo, como debería ser. He adjuntado una URL de un vídeo de YouTube subido por mí que muestra este comportamiento completo desde el estado de apagado completo, espero que esto esté bien con la política del sitio web. https://youtu.be/ajXUXeMd_7U

En cuanto al código, efectivamente lo postearé, pero no creo que haya ningún problema con el código en absoluto, se trata de un código dirigido por interrupciones, con alrededor de 1k líneas de código en el archivo principal, sólo postearé la función principal, el ISR, y las funciones llamadas en ambos que están relacionadas con este asunto, si necesitan algo más no duden en preguntarme, estoy tratando de facilitar las cosas para ustedes :)

Definiciones constantes (#define)

#define _XTAL_FREQ                  16e6
#define _INPUT                      1
#define _OUTPUT                     0
#define _HIGH                       1
#define _LOW                        0
#define _RISING_EDGE                1
#define _FALLING_EDGE               0
#define _MAX_NUMBER_OF_IDLE_SECONDS 30

#define _RTC_SQW_DIR                TRISBbits.TRISB0
#define _RTC_SQW_INTERRUPT          INT0IE
#define _RTC_SQW_INTERRUPT_FLAG     INT0IF

#define _ROTARY_SW_DIR              TRISBbits.TRISB1
#define _ROTARY_SW_INTERRUPT        INT1IE
#define _ROTARY_SW_INTERRUPT_FLAG   INT1IF
#define _ROTARY_CLK_DIR             TRISBbits.TRISB2
#define _ROTARY_CLK_INTERRUPT       INT2IE
#define _ROTARY_CLK_INTERRUPT_FLAG  INT2IF
#define _ROTARY_CLK_PIN_READ        PORTBbits.RB2
#define _ROTARY_CLK_INTERRUPT_ON    INTEDG2
#define _ROTARY_DT_DIR              TRISBbits.TRISB3
#define _ROTARY_DT_PIN_READ         PORTBbits.RB3

#define testLED_DIR                 TRISBbits.TRISB4
#define testLED_PIN_WRITE           LATBbits.LATB4

Rutina principal:

void main(void)
{
// Inputs initialization
Inputs_Init();

// Outputs initialization
Outputs_Init();

// Peripherals initialization from in to out of the MCU.
I2C_Master_Init();
I2C_LCD_Init(LCD1_WRITE);
I2C_LCD_Clear(LCD1_WRITE);
DS3231_Init();
DHT22_Init();

// EEPROM Retrieval

// Interrupts initialization
Interrupts_Init();
while (1)
{
    // Section: Input

    // Section: Inputs Processing and Decision Taking 

    // Section: Output to User Interface
}
return;
}

Rutina ISR:

void __interrupt() ISR(void)
{
if (_ROTARY_CLK_INTERRUPT_FLAG)
{
    testLED_PIN_WRITE = _HIGH;
    if (_ROTARY_CLK_PIN_READ != _ROTARY_DT_PIN_READ)
    {
        // CW ==> ++
        if (rotarySetToChange)
        {
            cursorIncreaseValue();
        }
        else
        {
            cursorMoveToTheRight();
        }
    }
    else
    {
        // CCW ==> --
        if (rotarySetToChange)
        {
            cursorDecreaseValue();
        }
        else
        {
            cursorMoveToTheLeft();
        }
    }
    cursorGoToCorrectPosition();
    testLED_PIN_WRITE = _LOW;
    idleSeconds = 0;
    _ROTARY_CLK_INTERRUPT_ON = ~_ROTARY_CLK_INTERRUPT_ON; // Adjust next interrupt edge.
    _ROTARY_CLK_INTERRUPT_FLAG = _LOW;
}

if (_ROTARY_SW_INTERRUPT_FLAG)
{
    rotarySetToChange = ~rotarySetToChange;
    if (menu != 0)
    {
        if (rotarySetToChange)
        {
            I2C_LCD_BlinkON(LCD1_WRITE);
        }
        else
        {
            I2C_LCD_CursorON(LCD1_WRITE);
        }
    }
    idleSeconds = 0;
    _ROTARY_SW_INTERRUPT_FLAG = _LOW;
}
}

Funciones utilizadas en las rutinas main e ISR

void Inputs_Init(void)
{
_RTC_SQW_DIR = _INPUT;

_ROTARY_SW_DIR = _INPUT;
_ROTARY_CLK_DIR = _INPUT;
_ROTARY_DT_DIR = _INPUT;
}

void Outputs_Init(void)
{
testLED_PIN_WRITE = _LOW;
testLED_DIR = _OUTPUT;
}

void Interrupts_Init(void)
{
GIE = 1; // General Interrupt Enable.
PEIE = 1; // Peripheral Interrupt Enable.

_RTC_SQW_INTERRUPT = 1; // RB0 Interrupt Enable, on rising edge by default. (INTEDG0 = 1)

rotaryAdjustNextInterruptEdge();
_ROTARY_CLK_INTERRUPT = 1; // Rotary Interrupt Enable.

_ROTARY_SW_INTERRUPT = 1; // Rotary Switch Interrupt Enable, on rising edge by default. 
 (INTEDG2 = 1)
 }

void cursorMoveToTheRight(void)
{
switch (menu)
{
case 0: // General Menu
    menu = 1;
    cursorRow = 3;
    cursorCol = 9;
    printStrings();
    break;
case 1: // Pigeons Door Time Menu
    cursorMoveRightInMenus_1234(2);
    break;
case 2: // Pigeons Food Time Menu
    cursorMoveRightInMenus_1234(3);
    break;
case 3: // Watering 1 Menu
    cursorMoveRightInMenus_1234(4);
    break;
case 4: // Watering 2 Menu
    cursorMoveRightInMenus_1234(5);
    break;
case 5: // Spraying Menu
    cursorMoveRightInMenus_5();
    break;
case 6: // Air Conditioner Menu
    cursorMoveRightInMenus_6();
    break;
case 7: // Temperature-Humidity Menu
    cursorMoveRightInMenus_7();
    break;
}
}

void cursorMoveRightInMenus_1234(unsigned char newMenu)
{
switch (cursorRow)
{
case 3:
    switch (cursorCol)
    {
    case 9:
        cursorRow = 3;
        cursorCol = 12;
        break;
    case 12:
        cursorRow = 4;
        cursorCol = 9;
        break;
    }
    break;
case 4:
    switch (cursorCol)
    {
    case 9:
        cursorRow = 4;
        cursorCol = 12;
        break;
    case 12:
        menu = newMenu;
        if (menu == 5)
        {
            cursorRow = 2;
            cursorCol = 9;
        }
        else
        {
            cursorRow = 3;
            cursorCol = 9;
        }
        printStrings();
        break;
    }
    break;
}
}

void cursorMoveRightInMenus_5(void)
{
switch (cursorRow)
{
case 2:
    switch (cursorCol)
    {
    case 9:
        cursorRow = 2;
        cursorCol = 12;
        break;
    case 12:
        cursorRow = 3;
        cursorCol = 9;
        break;
    }
    break;
case 3:
    switch (cursorCol)
    {
    case 9:
        cursorRow = 3;
        cursorCol = 12;
        break;
    case 12:
        cursorRow = 4;
        cursorCol = 7;
        break;
    }
    break;
case 4:
    switch (cursorCol)
    {
    case 7:
        cursorRow = 4;
        cursorCol = 17;
        break;
    case 17:
        menu = 6;
        cursorRow = 2;
        cursorCol = 9;
        printStrings();
        break;
    }
    break;
}
}

void cursorMoveRightInMenus_6(void)
{
switch (cursorRow)
{
case 2:
    switch (cursorCol)
    {
    case 9:
        cursorRow = 2;
        cursorCol = 12;
        break;
    case 12:
        cursorRow = 3;
        cursorCol = 9;
        break;
    }
    break;
case 3:
    switch (cursorCol)
    {
    case 9:
        cursorRow = 3;
        cursorCol = 12;
        break;
    case 12:
        cursorRow = 4;
        cursorCol = 6;
        break;
    }
    break;
case 4:
    switch (cursorCol)
    {
    case 6:
        cursorRow = 4;
        cursorCol = 17;
        break;
    case 17:
        menu = 7;
        cursorRow = 3;
        cursorCol = 7;
        printStrings();
        break;
    }
    break;
}
}

void cursorMoveRightInMenus_7(void)
{
switch (cursorRow)
{
case 3:
    switch (cursorCol)
    {
    case 7:
        cursorRow = 3;
        cursorCol = 19;
        break;
    case 19:
        cursorRow = 4;
        cursorCol = 7;
        break;
    }
    break;
case 4:
    switch (cursorCol)
    {
    case 7:
        cursorRow = 4;
        cursorCol = 19;
        break;
    case 19:
        menu = 0;
        cursorRow = 3;
        cursorCol = 9;
        printStrings();
        break;
    }
    break;
}
}

void cursorMoveToTheLeft(void)
{
switch (menu)
{
case 0: // General Menu
    menu = 7;
    cursorRow = 4;
    cursorCol = 19;
    printStrings();
    break;
case 1: // Pigeons Door Time Menu
    cursorMoveLeftInMenus_1234(1);
    break;
case 2: // Pigeons Food Time Menu
    cursorMoveLeftInMenus_1234(2);
    break;
case 3: // Watering 1 Menu
    cursorMoveLeftInMenus_1234(3);
    break;
case 4: // Watering 2 Menu
    cursorMoveLeftInMenus_1234(4);
    break;
case 5: // Spraying Menu
    cursorMoveLeftInMenus_5();
    break;
case 6: // Air Conditioner Menu
    cursorMoveLeftInMenus_6();
    break;
case 7: // Temperature-Humidity Menu
    cursorMoveLeftInMenus_7();
    break;
}
}

void cursorMoveLeftInMenus_1234(unsigned char newMenu)
{
switch (cursorRow)
{
case 3:
    switch (cursorCol)
    {
    case 9:
        menu = newMenu - 1;
        cursorRow = 4;
        cursorCol = 12;
        printStrings();
        break;
    case 12:
        cursorRow = 3;
        cursorCol = 9;
        break;
    }
    break;
case 4:
    switch (cursorCol)
    {
    case 9:
        cursorRow = 3;
        cursorCol = 12;
        break;
    case 12:
        cursorRow = 4;
        cursorCol = 9;
        break;
    }
    break;
}
}

void cursorMoveLeftInMenus_5(void)
{
switch (cursorRow)
{
case 2:
    switch (cursorCol)
    {
    case 9:
        menu = 4;
        cursorRow = 4;
        cursorCol = 12;
        printStrings();
        break;
    case 12:
        cursorRow = 2;
        cursorCol = 9;
        break;
    }
    break;
case 3:
    switch (cursorCol)
    {
    case 9:
        cursorRow = 2;
        cursorCol = 12;
        break;
    case 12:
        cursorRow = 3;
        cursorCol = 9;
        break;
    }
    break;
case 4:
    switch (cursorCol)
    {
    case 7:
        cursorRow = 3;
        cursorCol = 12;
        break;
    case 17:
        cursorRow = 4;
        cursorCol = 7;
        break;
    }
    break;
}
}

void cursorMoveLeftInMenus_6(void)
{
switch (cursorRow)
{
case 2:
    switch (cursorCol)
    {
    case 9:
        menu = 5;
        cursorRow = 4;
        cursorCol = 17;
        printStrings();
        break;
    case 12:
        cursorRow = 2;
        cursorCol = 9;
        break;
    }
    break;
case 3:
    switch (cursorCol)
    {
    case 9:
        cursorRow = 2;
        cursorCol = 12;
        break;
    case 12:
        cursorRow = 3;
        cursorCol = 9;
        break;
    }
    break;
case 4:
    switch (cursorCol)
    {
    case 6:
        cursorRow = 3;
        cursorCol = 12;
        break;
    case 17:
        cursorRow = 4;
        cursorCol = 6;
        break;
    }
    break;
}
}

void cursorMoveLeftInMenus_7(void)
{
switch (cursorRow)
{
case 3:
    switch (cursorCol)
    {
    case 7:
        menu = 6;
        cursorRow = 4;
        cursorCol = 17;
        printStrings();
        break;
    case 19:
        cursorRow = 3;
        cursorCol = 7;
        break;
    }
    break;
case 4:
    switch (cursorCol)
    {
    case 7:
        cursorRow = 3;
        cursorCol = 19;
        break;
    case 19:
        cursorRow = 4;
        cursorCol = 7;
        break;
    }
    break;
}
}

void rotaryAdjustNextInterruptEdge(void)
{
if (_ROTARY_CLK_PIN_READ == _HIGH)
{
    _ROTARY_CLK_INTERRUPT_ON = _FALLING_EDGE;
}
else
{
    _ROTARY_CLK_INTERRUPT_ON = _RISING_EDGE;
}
}

void printStrings(void)
{
I2C_LCD_CursorOFF(LCD1_WRITE);

switch (menu)
{
case 0: // General Menu
    I2C_LCD_Goto(1, 4, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, humidityString);
    I2C_LCD_Goto(1, 3, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, temperatureString);
    I2C_LCD_Goto(1, 2, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, timeString);
    I2C_LCD_Goto(1, 1, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, "   [General Menu]   ");
    break;
case 1: // Pigeons Door Time Menu
    I2C_LCD_Goto(1, 4, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, pigeonsDoorTimeCloseString);
    I2C_LCD_Goto(1, 3, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, pigeonsDoorTimeOpenString);
    I2C_LCD_Goto(1, 2, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, "    [Door  Time]    ");
    I2C_LCD_Goto(1, 1, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, "   [Pigeons Menu]   ");
    break;
case 2: // Pigeons Food Time Menu
    I2C_LCD_Goto(1, 4, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, pigeonsFoodTimeCloseString);
    I2C_LCD_Goto(1, 3, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, pigeonsFoodTimeOpenString);
    I2C_LCD_Goto(1, 2, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, "    [Food  Time]    ");
    I2C_LCD_Goto(1, 1, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, "   [Pigeons Menu]   ");
    break;
case 3: // Watering 1 Menu
    I2C_LCD_Goto(1, 4, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, watering1ForString);
    I2C_LCD_Goto(1, 3, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, watering1OpenString);
    I2C_LCD_Goto(1, 2, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, "        [1]         ");
    I2C_LCD_Goto(1, 1, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, "     [Watering]     ");
    break;
case 4: // Watering 2 Menu
    I2C_LCD_Goto(1, 4, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, watering2ForString);
    I2C_LCD_Goto(1, 3, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, watering2OpenString);
    I2C_LCD_Goto(1, 2, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, "        [2]         ");
    I2C_LCD_Goto(1, 1, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, "     [Watering]     ");
    break;
case 5: // Spraying Menu
    I2C_LCD_Goto(1, 4, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, sprayingIntervalString);
    I2C_LCD_Goto(1, 3, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, sprayingToString);
    I2C_LCD_Goto(1, 2, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, sprayingFromString);
    I2C_LCD_Goto(1, 1, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, "     [Spraying]     ");
    break;
case 6: // Air Conditioner Menu
    I2C_LCD_Goto(1, 4, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, conditionerIntervalString);
    I2C_LCD_Goto(1, 3, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, conditionerToString);
    I2C_LCD_Goto(1, 2, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, conditionerFromString);
    I2C_LCD_Goto(1, 1, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, "  [Air Conditioner] ");
    break;
case 7: // Temperature-Humidity Menu
    I2C_LCD_Goto(1, 4, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, temperatureAndHumidityMaxString);
    I2C_LCD_Goto(1, 3, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, temperatureAndHumidityMinString);
    I2C_LCD_Goto(1, 2, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, "--------------------");
    I2C_LCD_Goto(1, 1, LCD1_WRITE);
    I2C_LCD_Print(LCD1_WRITE, "Temperature-Humidity");
    break;
}
}

void cursorGoToCorrectPosition(void)
{
switch (menu)
{
case 0: // General Menu, no Cursor
    break;
default:
    I2C_LCD_Goto(cursorCol, cursorRow, LCD1_WRITE);
    if (rotarySetToChange)
    {
        I2C_LCD_BlinkON(LCD1_WRITE);
    }
    else
    {

        I2C_LCD_CursorON(LCD1_WRITE);
    }
    break;
}
}

No quiero ir más allá con el código, esto ya es agotador, a no ser que quieras hacerlo.

Unas cuantas cosas para resumir mis pensamientos, tenga en cuenta que la función printStrings() se llama antes de la función cursorGoToCorrrectPosition(), por lo que estoy seguro de que es un problema de hardware, tal vez en la propia pantalla LCD , porque imprime una o dos líneas de las cuatro líneas de cadenas, luego actualiza la posición del cursor correctamente entonces vuelve a imprimir las líneas restantes de cadenas.

Mi pregunta es, ¿por qué hay un retraso en absoluto? ¿por qué el retraso es sólo en el primer desplazamiento? ¿cómo podría resolver este retraso?

Gracias a todos por adelantado.

0voto

Kartman Puntos 381

Si su LCD tiene algún defecto oscuro, no vamos a poder ayudarle. Podrías probar con otra lcd para ver si se comporta igual. Yo apostaría por el código que causa el problema. Desmonte su código hasta el mínimo que muestra el problema.

Como nota al margen, tener la lógica de tu programa en un isr es un mal yuyu. Además, tener un codificador rotativo generando interrupciones no es una buena práctica también. Haz que un temporizador isr lea los pines del codificador y decodifique el estado. Comunicar la posición del codificador hasta el código de la línea principal. Haz lo mínimo en el isr. Trate de minimizar el número de interrupciones y fuentes cuando sea posible. Este es un consejo general - puedes escribir tu código como quieras, pero algunas formas son mejores que otras.

0voto

user220607 Puntos 1

La solución es sencilla, como cualquier otra solución :)

Simplemente me olvidé de formatear las cadenas antes de imprimirlas.

Tengo matrices de caracteres que contienen cada línea que se imprime en la pantalla LCD para cada menú, y les doy formato con sprintf, ya que es la forma más fácil, pero como tengo muchos menús y por lo tanto muchas líneas y por lo tanto de nuevo muchas variables de matrices de caracteres, no les doy formato a todos, sólo doy formato a los que necesito. El problema es que olvidó para llamar a esta función, por lo que imprimo cadenas vacías, por lo que literalmente no se produce ningún cambio en la pantalla LCD, hasta una interrupción procedente del RTC del DS3231 cada segundo que formatea las cadenas antes de imprimirlas. Ahora, después de recorrer todo el menú, ya están todas formateadas y listas para usar.

Esto no tiene nada que ver con que mi código sea malo, o que mi implementación sea pobre, es simplemente que me olvidé de llamar a una función, mi implementación es muy amigable y actúa muy rápidamente a la interacción del usuario, y este es el punto principal en el proyecto. Creo que mi implementación es realmente buena, se ha demostrado que funciona sin problemas y rápidamente. Si usted tiene cualquier otra opinión, por favor, comparta con los detalles =)

Gracias a todos.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X