【问题标题】:Interfacing 16*2 keypad and LCD with atmega32连接 16*2 键盘和 LCD 与 atmega32
【发布时间】:2019-03-23 16:55:34
【问题描述】:

我对键盘模块有一个令人失望的问题,当按下它的任何键时,它通常会显示在 LCD 模块上按下的键。问题是每当我按下键时,行就会停止扫描,如果我的应用程序(例如,接收密码并显示在 LCD 上的系统),我无法按下任何其他键以显示在我的 LCD 上。如果我想在 LCD 上显示一个列表并且我想在屏幕上翻另一页以继续显示我的列表,那么我现在面临的另一个问题是。我怎样才能实现这个?! 我附上了我的示意图的屏幕截图,另外我提供了要检查的键盘和 LCD 的代码。无论如何,谢谢你帮助我。

我的申请代码:

#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' );
        }
    }
}

我的 LCD 库:

#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

我的键盘库:

#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;
}

最后是我的标准宏:

#define SET_BIT( REGISTER, BIT_NUM ) ( REGISTER = REGISTER | ( 1 << BIT_NUM ) )
#define CLR_BIT( REGISTER, BIT_NUM ) ( REGISTER = REGISTER & ( ~( 1 << BIT_NUM ) ) )

【问题讨论】:

  • 您可以简化这个问题 - 文字不太清楚。我建议您将其构建为 1)您需要发生的事情 2)实际发生的事情,并将这些限制为外部可观察的行为 - 例如如果你按 8 会发生什么?如果按 1 会发生什么?如果您知道 LCD 和键盘功能可以工作,您可以省略所有代码,只显示主要代码。包含原理图可能会导致一些人认为这是一个硬件问题,因此离题或过于宽泛,并可能投票结束 - 这并不是真正必要的。
  • @Clifford 我同意你的看法,但有时当你无助时,你会做任何事来帮助你。很抱歉让您头疼,感谢您的帮助和建议.. :)
  • 我很感激,当您不知道问题出在哪里时,一切都不是不合理的。我没有真正的问题;我更担心的是,一个原本合理的模糊问题在可以解决时会吸引反对票/关闭票。现在修复它还为时不晚 - SO 的重点是问题和答案都可以编辑。但是,您应该避免从根本上改变一个问题,如果它们以前是正确的,它会使现有的答案变得毫无意义。
  • @Clifford 我很感激能提供帮助,正如我所说,我很感谢你和你的建议,祝你有美好的一天:)

标签: embedded avr lcd keypad atmega16


【解决方案1】:

一旦!Keypad_u8Scan() 为假,您的while 循环就会终止,然后main() 就会终止。这将在按下8 以外的任何键时发生,因为只有在键为8 时才等待释放键。

在任何“大循环”计划的嵌入式系统中,main() 不应正常终止 - 外循环应该是无限的。

以下调度循环将起作用(假设键盘和 LCD 功能起作用),并且更易于扩展 - 添加额外的按键事件处理程序只需将新的 case 块添加到 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
    }
}

也许更好的结构是有一个单独的函数来等待按键事件,如下所示:

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 ;
}

然后你的主循环可以变得更简单:

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

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

        default :
        {
            // any other key
        }
    }
}

【讨论】:

  • 你真是个天才,你的解决方案对我帮助很大。谢谢你,我很感激:)
【解决方案2】:

当前您的 while 循环正在循环,而未按下键:

while( !Keypad_u8Scan() )

它应该永远循环下去。

后面的那一行:

keypadPress = Keypad_u8Scan();

正在获取按键,一旦while循环被修复,将接收多个按键,因此可以处理页面按钮并显示不同的页面。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多