将 16*2 键盘和 LCD 与 atmega32 接口
Interfacing 16*2 keypad and LCD with atmega32
我对键盘模块有一个令人失望的问题,当按下它的任何键时,它通常会显示在 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' );
}
}
}
我的液晶库:
#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 ] != '[=11=]'; 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 ) ) )
当前您的 while 循环在未按下某个键时循环:
while( !Keypad_u8Scan() )
它应该永远循环播放。
其后一行:
keypadPress = Keypad_u8Scan();
正在获取按键,一旦 while 循环固定,将接收多个按键,然后可以处理页面按钮并显示不同的页面。
您的 while
循环在 !Keypad_u8Scan()
为假时立即终止,然后 main()
终止。当按下 8
以外的任何键时都会发生这种情况,因为如果键是 8
.
则您只等待键释放
在任何 "big-loop" 预定的嵌入式系统中,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
}
}
}
我对键盘模块有一个令人失望的问题,当按下它的任何键时,它通常会显示在 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' );
}
}
}
我的液晶库:
#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 ] != '[=11=]'; 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 ) ) )
当前您的 while 循环在未按下某个键时循环:
while( !Keypad_u8Scan() )
它应该永远循环播放。
其后一行:
keypadPress = Keypad_u8Scan();
正在获取按键,一旦 while 循环固定,将接收多个按键,然后可以处理页面按钮并显示不同的页面。
您的 while
循环在 !Keypad_u8Scan()
为假时立即终止,然后 main()
终止。当按下 8
以外的任何键时都会发生这种情况,因为如果键是 8
.
在任何 "big-loop" 预定的嵌入式系统中,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
}
}
}