0

I have a disappointing problem with a keypad module that when pressing on any of its keys, it normally shows up the key pressed on an LCD module. The problem is whenever I press the key, the rows stop being scanned and I have no ability to press any other key to be shown on my LCD if my application, for instance, a system to be recieving a password and shown on the LCD. Another problem facing me right now if I want to show a list on the LCD and I want to turn another page on the screen to resume showing my list. How can I manage to implement this ?! I'm attaching a screenshot for my schematic plus I'm providing the code for both the keypad and LCD to be checked. And thank you anyway for helping me. enter image description here

My application code:

#define F_CPU 8000000UL
#include <util/delay.h>
#include <avr/io.h>
#include "LCD.h"
#include "Keypad.h"

int main(void)
{
    /* Replace with your application code */
    uint8_t keypadPress = 0;
    Keypad_vInit();
    LCD_vInit();

    while( !Keypad_u8Scan() )
    {
        keypadPress = Keypad_u8Scan();
        if( keypadPress == '8' )
        {
            LCD_vPrintChar( '8' );
            while( keypadPress == '8' );
        }
    }
}

My LCD library:

#if defined MODE_4

static void sendFallingEdge( void ); /* This prototype is declared static       to avoid modifying it. */

static void sendFallingEdge( void )
{
    /* Initializing the EN pin of the LCD when detecting a falling edge. */
    /* The following code is the representation of falling edge using the   system clock. */
    PORTB |= ( 1 << EN );
    _delay_ms( 1 );
    PORTB &= ( ~ ( 1 << EN ) );
    _delay_ms( 1 );
}

void LCD_vSendCmd( char cmd )
{
    /* Transferring the first nibble. */
    PORTA &= 0x0F;
    PORTA |= ( cmd & 0xF0 );
    CLR_BIT( PORTB, RS ); /* Transferring instructions data. */
    sendFallingEdge( );

    /* Transferring the second nibble. */
    PORTA &= 0x0F;
    PORTA |= ( cmd << 4 );
    CLR_BIT( PORTB, RS ); /* Transferring instructions data. */
    sendFallingEdge( );
}

void LCD_vInit( void )
{
    DDRA |= 0xF0; /* DDRA |= 0b11110000; */
    DDRB |= 0x0E; /* DDRB |= 0b00001110; */ /* Those three HIGH bits are the RS, RW and EN respectively. */
    CLR_BIT( PORTB, RW ); /* Write mode enabled according to the LCD's datasheet. */

    LCD_vSendCmd( 0x33 );
    _delay_ms( 1 );

    LCD_vSendCmd( 0x32 );
    _delay_ms( 1 );

    LCD_vSendCmd( 0x28 );
    _delay_ms( 1 );

    LCD_vSendCmd( 0x01 );
    _delay_ms( 1 );

    LCD_vSendCmd( 0x0F );
    _delay_ms( 1 );
}

void LCD_vPrintChar( char data )
{
    PORTA &= 0x0F;
    PORTA |= ( data & 0xF0 );
    SET_BIT( PORTB, RS ); /* Transferring display data. */
    sendFallingEdge( );

    PORTA &= 0x0F;
    PORTA |= ( data << 4 ); 
    SET_BIT( PORTB, RS ); /* Transferring display data. */
    sendFallingEdge( );
}

void LCD_vPrintString( char * str )
{
    uint8_t counter;
    for( counter = 0; str[ counter ] != '\0'; counter ++ )
    {
        LCD_vPrintChar( str[ counter ] );
    }
}

void LCD_vPrintNumbers( uint8_t str[ ], uint8_t size )
{
    uint8_t counter;
    for( counter = 0; str[ counter ] < size; counter ++ )
    {
        LCD_vPrintChar( str[ counter ] );
    }
}

void LCD_vClrScreen( void )
{
    LCD_vSendCmd( CLR_SCRN );
}

void LCD_vMoveCursor( char row, char column )
{
    char cmd;
    if( row == 1 )
    {
        cmd = STARTROW0 + column - 1;
        LCD_vSendCmd( cmd );
    }
    else if( row == 2 )
    {
        cmd = STARTROW1 + column - 1;
        LCD_vSendCmd( cmd );
    }
}

#endif

My Keypad library:

#include <avr/io.h>
#include "std_macros.h"

void Keypad_vInit( void )
{
    DDRC = 0x0F; 
    CLR_BIT( SFIOR, PUD ); 
    PORTC = 0xFF;          
}
unsigned char Keypad_u8Scan( void )
{
    unsigned char row, column, scan, buttonPressed = 0;
    unsigned char KP[ 4 ][ 4 ] = { { '7', '8', '9', '/' },
                                   { '4', '5', '6', '*' },
                                   { '1', '2', '3', '-' },
                                   { ' ', '0', '=', '+' }           
                                 };
    for( row = 0; row < 4; row ++ )
    {
        PORTC |= 0x0F;
        CLR_BIT( PORTC, row );
        for( column = 4; column < 8; column ++ )
        {
            scan = READ_BIT( PINC, column );
            if( scan == 0 )
            {
                buttonPressed = KP[ row ][ column - 4 ];
            }
        }
    }
    return buttonPressed;
}

And at last my standard macros:

#define SET_BIT( REGISTER, BIT_NUM ) ( REGISTER = REGISTER | ( 1 << BIT_NUM ) )
#define CLR_BIT( REGISTER, BIT_NUM ) ( REGISTER = REGISTER & ( ~( 1 << BIT_NUM ) ) )
4
  • 1
    You might simplify this question - the text is less than clear. I suggest that you structure it as 1) What you require to happen 2) what actually happens, and restrict these to the externally observable behaviour - e.g. what happens if you press 8? What happens if you press 1? If you know that the LCD and Keypad functions work, You can probably omit all that code, and just show the main. Including the schematic may lead some to thinking it is a hardware question and therefore off-topic or too broad, and may vote to close - it is not really necessary.
    – Clifford
    Commented Oct 18, 2018 at 21:41
  • @Clifford I agree with you, but sometimes when you're helpless you do anything to be helped. Sorry for that headache and thank you for your help and advice .. :) Commented Oct 19, 2018 at 7:45
  • I appreciate that when you have no idea where the problem is providing everything is not unreasonable. I have no real problem; my concern was more that an otherwise reasonable question obfuscated attracts down/close votes when it could be fixed. It is not too late the fix it - the point of SO is that both questions and answers can be edited. You should however avoid fundamentally changing a question such that it renders existing answers nonsense if they were previously correct.
    – Clifford
    Commented Oct 19, 2018 at 8:35
  • @Clifford I appreciate being helpful and as I said, I'm grateful to you and your pieces of advice, have a good day :) Commented Oct 19, 2018 at 8:47

2 Answers 2

1

Your while loop terminated as soon as !Keypad_u8Scan() is false, and then main() terminates. This will happen when any key other than 8 is pressed, because you only wait for the key release if the key was 8.

In any "big-loop" scheduled embedded system, main() should not normally terminate - the outer loop should be indefinite.

The following scheduling loop will work (assuming the keypad and LCD functions work), and is more easily extensible - adding additional key-down event handlers is simply a matter of adding a new case block to the switch:

for(;;) // forever
{
    // Wait for key-down
    do
    {
        keypadPress = Keypad_u8Scan();

    } while( keypadPress == 0 ) ;

    // Process key
    switch( keypadPress )
    {
        case '8' :
        {
            LCD_vPrintChar( '8' );
        }
        break ;

        default :
        {
            // any other key not explicitly handled
        }
    }

    // Wait for key-up
    while( Keypad_u8Scan() != 0 )
    {
        // do nothing
    }
}

A better structure perhaps, is to have a separate function that waits for a key-down event as follows:

uint8_t getKey()
{
    uint8_t key = 0 ;

    // Wait for key release if pressed on entry
    while( Keypad_u8Scan() != 0 )
    {
        // do nothing          
    } 

    // Wait for new key press
    do
    {
        key = Keypad_u8Scan();

    } while( key == 0 ) ;

    return key ;
}

Then your main loop can become much simpler:

for(;;) // forever
{
    keypadPress = getKey() ;

    // Process key
    switch( keypadPress )
    {
        case '8' :
        {
            LCD_vPrintChar( '8' );
        }
        break ;

        default :
        {
            // any other key
        }
    }
}
1
  • you're genious, your solution helped me so much. Thank you I'm so grateful :) Commented Oct 19, 2018 at 7:53
0

Currently your while loop is looping while a key is not pressed:

while( !Keypad_u8Scan() )

It should just be looping forever.

The line after it:

keypadPress = Keypad_u8Scan();

is getting the key press, and once the while loop is fixed, will then be receiving multiple key pressed, so can then handle page buttons and displaying different pages.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.