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.