Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] interface keypad and lcd with atmega88

Status
Not open for further replies.

mr_l

Newbie level 5
Joined
Sep 16, 2011
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,372
Hello everyone.
I am a bit stuck with one task and i need help.
I am trying to read input from keypad and display it on the display.
I first wrote the program code which reads the input from the keyboard and tested it with LEDs and it works
well.
Then I wrote code that prints text to display with no input from the keyboard and then tested it and it also
works well.
But when I put together whole code it does not work as it should.
I am new in programming of embedded systems and i know
that my code is not the best and that probably has a lot of mistakes but I try to do the best they can.
Here is my code

Code:
#define F_CPU 8000000UL
#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>



#define RS 0 //pin nr in port
#define RW 1 //pin nr in port
#define E 2 //pin nr in port

FILE *myFile;
void write_LCD(unsigned char data, FILE *stream);
int get_char(FILE *stream);
void write_instruction(unsigned char data);
void init_LCD(void);
void delay8us(void);


void delay8us(void) {
volatile unsigned char x;
for(x=0;x<5;x++);
}

void test_if_busy(void) {
unsigned char x;
PORTC &=~(1<<RS);
PORTC |= (1<<RW);
DDRB &=~(1<<7);		// input
PORTB &=~(1<<7);	// remove pullup
do {
PORTC |= (1<<E);
delay8us();
x = (PINB & 0x80); // read high nibble
PORTC &=~(1<<E);
PORTC |= (1<<E);
PORTC &=~(1<<E);	// read low nibble
		 
}
while(x);
DDRB |= (1<<7);	// output
}

void write_LCD(unsigned char data, FILE *stream) {
char x;
PORTB = (data & 0xf0); //high nibble
PORTC &=~(1<<RW);
PORTC |= (1<<RS);
PORTC |= (1<<E);
PORTC &=~(1<<E);
x = (data<<4);
 _delay_ms(65);
PORTB = x; //low nibble
PORTC &=~(1<<RW);
PORTC |=(1<<RS);
PORTC |=(1<<E);
PORTC &=~(1<<E);
test_if_busy();
}

char get_key(void)
{
volatile char button;
volatile char position;

button = PINB;

if (button == 0b01111011)
position = 49;
else if (button == 0b01111101)
position = 50;
else if (button == 0b01111110)
position = 51;
else if (button == 0b10111011)
position = 52;
else if ( button == 0b10111101)
position = 53;
else if ( button == 0b10111110)
position = 54;
else if ( button == 0b11011011)
position = 55;
else if ( button == 0b11011101)
position = 56;
else if ( button == 0b11011110)
position = 57;
else if ( button == 0b11101011)
position = 8;
else if ( button == 0b11101011)
position = 48;
else if ( button == 0b11101101)
position = 13;
else if ( button == 0b11101110)
position = 68;
else if (button == 0b11101111)
position = 5;
return position;
}


int get_char(FILE *stream){
char c;
volatile char column;
volatile char row;

do{
row = 0b01111111;	// send 0 to first row
for (int i = 0; i<2; i++){ 
PORTB = row;
column = PINB;		// read input from keypad
}

for(int i = 0, a = 64; i<5; i++){  // check all 4 rows
if(column == row)// if key is not pressed in first row
row = column + a;		// check next row 
for(int j = 0; j < 2; j++){ 
PORTB = row;
column = PINB;
}
i++;
a = a/2;
}   
else
c = get_key();
}
c = get_key();
}while(column == 0b11101111); // if neither key is not pressed repeat loop

write_LCD(c, stream);
return (int)c;
	
}


void write_instruction(unsigned char data) {
unsigned char x;

PORTB = (data & 0xf0);
PORTC &=~(1<<RW);
PORTC &=~(1<<RS);
PORTC |= (1<<E);
PORTC &=~(1<<E);
x = (data<<4);
PORTB = x;
PORTC &=~(1<<RW);
PORTC &=~(1<<RS);
PORTC |= (1<<E);
PORTC &=~(1<<E);
test_if_busy();
}


void set4bitmode() {
_delay_ms(65);
PORTB = (0x20 & 0xf0);
PORTC &=~(1<<RW);
PORTC &=~(1<<RS);
PORTC |= (1<<E);
PORTC &=~(1<<E);
}


 void init_LCD(void) {
unsigned char x;
for(x= 0;x<5;x++) {
_delay_ms(65);
}
PORTB = 0; //all low
PORTC &=~(1<<RS);
PORTC &=~(1<<RW);
PORTC &=~(1<<E);
DDRB = 0xF0; // all output
PORTB = 0x0F;
DDRC |= (1<<RS);
DDRC |= (1<<RW);
DDRC |= (1<<E);
_delay_ms(65);
set4bitmode(); // 4 bit interface
for(x=0;x<3;x++) {
write_instruction(0x28);
_delay_ms(65);
}
write_instruction(0x0F);
write_instruction(6);
write_instruction(1);
}


int main(void) 
{
char teck;
init_LCD();
write_instruction(1); // clear display
myFile = fdevopen(write_LCD, get_char);
	
while(1){

scanf("%c", &teck);
printf("%d",teck);
}
}
 

I am trying to read input from keypad and display it on the display.
I first wrote the program code which reads the input from the keyboard and tested it with LEDs and it works
well.
Then I wrote code that prints text to display with no input from the keyboard and then tested it and it also
works well.
But when I put together whole code it does not work as it should.

Code:
while(1){

scanf("%c", &teck);
printf("%d",teck);
}

Could you please explain what those lines suppose to do? In which part exactly do you read from the keyboard? Where do you drive the LCD?
I am not using AVRStudio a lot, but I think that printf() and scanf() have to do with serial port.
Are those two functions tested in your keyboard and lcd demo projects as well?
Maybe you are using an interrupt somewhere that I failed to spot?
 

I think your problem is on the sharing of PORTB to the keyboard and to the lcd.... probably you are getting errors when you press the key and data is being transmitted...I can see that you are using and hitachi hd44780 compatible LCD in four bit mode... can't you put all the lcd pins on the portC?, also make sure you have enough time delay after the "E" Positive to Negative transition, since the LCD controller reads data on that transition, data needs to be available there to read, and I think that is possible that you get char routine is changing portB too soon..

also, you are writing two sequential times to the LCD.. One on the Get char routine.. and one on the main loop



---------- Post added at 00:09 ---------- Previous post was at 00:00 ----------

Code:
while(1){

scanf("%c", &teck);
printf("%d",teck);
}

I think is the

Code:
myFile = fdevopen(write_LCD, get_char);

that is doing the scanf and printf trick :)
 
Last edited:

Yes mgate you're right this part of code doing the scanf and printf trick

Code:
myFile = fdevopen(write_LCD, get_char)

and you were right about PORTB, I changed port i mean i put all lcd pins
on the PORTC and now it works. But now i have another problem.
Number printing works fine but as soon as I press the letter or symbol it prints
pressed letter and then lot of unpressed numbers.
I thought first that this is due data types so i tested to change type of variable position in
int type but the result was the same. Have you any idea what it could be.
 

Well.. I'm not sure but your get_char() routine is quiet a mess... I don't even know how can it compile...

You have an else without an if... @ line 29

You have one extra } that I can't figure out where it belongs .. don't know witch one is the correct... @ line 28 or @ line 31

You are writing to the lcd in the get char routine... @ line 35

You perform the same operation two times between line 10 and line 14... I can't understand why you repeat the operation... But it is clear that is intentional

You perform the same operation two times between line 21 and line 25... I can't understand why you repeat the operation... But it is clear that is intentional

get_key() on line 30 will always be overwritten by get_key() on line 32

variable a type is never declared at line 16


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
int get_char(FILE *stream)
{
    char c;
    volatile char column;
    volatile char row;
 
    do
    {
        row = 0b01111111;   // send 0 to first row
        for (int i = 0; i<2; i++)
        { 
            PORTB = row;
            column = PINB;      // read input from keypad
        }
 
        for(int i = 0, a = 64; i<5; i++)
        {  // check all 4 rows
            if(column == row)// if key is not pressed in first row
                row = column + a;       // check next row 
                
            for(int j = 0; j < 2; j++)
            { 
                PORTB = row;
                column = PINB;
            }
            i++;
            a = a/2;
        }   
        else// ?????????????????????? where is the if?
            c = get_key();
        }
        c = get_key();
    }while(column == 0b11101111); // if neither key is not pressed repeat loop
 
    write_LCD(c, stream); // why are you writing here if you write it on the main routine?
    return (int)c;
    
}



---------- Post added at 23:27 ---------- Previous post was at 22:42 ----------

If you want I can Help rewriting this routine... I only didn't post the corrections because I thought you might want to figure it out yourself, and that way you would loose all the fun ...

---------- Post added 08-05-12 at 00:00 ---------- Previous post was 07-05-12 at 23:27 ----------

I forgot to say .. your (column == 0b11101111) while condition, in that code, enables the possibility of pressing a button i.e. in the first line and release the button, of the poling byte to be read... this way, when it gets to get_key(), since you don't have a default position (you will bypass the if's), and you will get garbage because the function will be returning an uninitialized variable (position)... Meaning you will be printing garbage... To prevent it, you must initialize the variable "position" to a bad char, that you can test and ignore..

---------- Post added at 00:10 ---------- Previous post was at 00:00 ----------

Also, you should try to find information about debouncing buttons, either by software or hardware ... I think You can also be having problems with that... and can be easily minimized with a simple delay...
 
Last edited:

Yes Of course I want to figure it out myself. I have just asked for clues so do not waste my time looking in the wrong place.
In any case, your tips have helped me a lot mgate and i I solved the problem. First as I said, I put all LCD pins on the portC
and LCD started to work.
Another problem I've solved so that I changed

Code:
 char get_key(void) into int get_key(void)[\code]

because get_key function () should be returned characters ASCII value

I then deleted the row 
[code] write_LCD(c, stream); [\code]
because it returns the value of printf () function  and has nothing to do with scanf() function
so
[code] int get_char(FILE *stream) [\code]
function returns value to scanf() function
and the last thing I changed is in main() function
[code]
printf("%d",teck); into 
printf("%c",teck);
[\code]
And as I said, now it works well
thanks for help mgate.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top