Dear Users,
Can you please help me with the following problem?
I have written some C code on AVR studio 4 to run an AVR Atmega 164p chip, to take input from a 4X4 matrix keypad and output the number pressed on an LCD.
The LCD and the code behind it is fine. However, there is a problem reading in the numbers from the keypad. When I press the keys '0' to '9' and 'A' to 'C' I get no response whatsoever. When I press 'D' and 'F' I get the number 0 appearing on the LCD. When I press 'E' I get the number two appearing on the LCD.
I have connected the Column wires from the keypad to 4.3Kohm resistors down to ground, I have set the row wires to constantly get a signal in from the AVR.
Additional information:
I am using an 8MHZ crystal oscillator
Please let me know if you need more information in order to help me.
***THE CODE IS BELOW:***
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/*----------- LCD and PORTA(Data) PORTD(Commands)------------------*/
#define LCD_Data PORTA //LCD Data output
#define LCD_Data_DDR DDRA //LCD Direction port
#define LCD_Data_RD PINA //LCD Data input
#define LCD_Control PORTD //Port where LCD control signals are
#define LCD_Control_RD PIND
#define LCD_Control_DDR DDRD
#define LCD_RS 0 //Pin on which LCD Register Select is
#define LCD_RW 1 //Pin on which LCD Read/Write is
#define LCD_E 2 //Pin on which LCD Enable is
/*------------------------- HEX keypad and PORTC----------------------*/
//define pins0-3 as rowsA-D (the rows of the hexadecinal keypad)***They will be defined as outputs from AVR to the Keypad****
#define rowA PC7 //This row is the bottom row, the numbers 0,1,2 and 3
#define rowB PC6
#define rowC PC5
#define rowD PC4//this row is the top row; the keys C,D,E and F
//define pins4-7 as columns 1-4 (columns of the hexadecimal keypad)
#define column1 PC3 // This is the leftmost column, the number 0,4,8 and C
#define column2 PC2
#define column3 PC1
#define column4 PC0// This is the rightmost column; the keys 3,7,B and F
// Meanings of the keys:
// A-
// B- Back to previous section
// C- Cancel
// D- Delete
// E- Enter (as in confirm)
// F-
/*Constants derived from information within Hitachi HD44780 datasheet--*/
// This command structure is used on every alphanumeric LCD.
#define DISP_FS 0x3f //Function set
#define DISP_ON 0x0c //Display on w/o blink or flash
#define DISP_OFF 0x08 //Display, blink, cursor off
#define DISP_CL 0x01 //Clear display
#define DISP_EN 0x06 //Data entry mode
#define LINE_1 0x80 //DDRAM address for first line
#define LINE_2 0xc0 //DDRAM address for second line
#define SH_LFT 0x18 //Left-shift display
#define SH_RT 0x1c //Right-shift display
#define HOME 0x02 //Return home
char dispstr[17];
uint8_t Captured;
uint16_t amplitude;
/*******************************************************/
/* LCD Function prototypes */
void LCD_Send_Command(uint8_t);
void LCD_Send_Data(uint8_t);
void LCD_Initialise(void);
void LCD_GOTOXY(uint8_t,uint8_t);
void LCD_Send_Data_XY(uint8_t /*data*/,uint8_t/*X coord*/,uint8_t/*Y coord*/);
void LCD_Send_String(char *);
/*******************************************************/
//#define Interval_1s 15625
//char freq[17] ="Frequency: Hz";
//char ampl[17] ="Average: V";
/********************************************************/
int main (void)
{
DDRC=(1<<rowA |1<<rowB | 1<<rowC| 1<<rowD);
LCD_Data_DDR=0xff;
LCD_Control_DDR|=(1<<LCD_RS | 1<<LCD_RW | 1<<LCD_E);
LCD_Control &=~(1<<LCD_RW);
LCD_Initialise();
_delay_ms(1);
//LCD_Send_String("");
//_delay_ms(1);
//LCD_GOTOXY(0,1);//sends the above string to the left-most position (x=0) on the top line (y=1 [indexed from zerol; zero being the bottom line])
while (1)
{
int some_var = PINC & 0x0F;//some variable that holds the value of the column you are on
//0001 is the right key/column of the particular row you are on
//1000 is the left key of the particular row you are on
PORTC = 1<<rowA; // Make rowA high
if(some_var)//if some var is not zero (i.e a button is pressed) do the following
{
if(some_var == 0x01)//0000 0001
{
LCD_Send_String("3");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x02) //0000 0010
{
LCD_Send_String("2");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x03)
{
LCD_Send_String("1");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x04)
{
LCD_Send_String("0");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
}
PORTC = 1<<rowB; // Make rowA high
if(some_var)
{
if(some_var == 0x01)
{
LCD_Send_String("7");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x02)
{
LCD_Send_String("6");
_delay_ms(500);
LCD_GOTOXY(0,0);/
}
else if(some_var == 0x03)
{
LCD_Send_String("5");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x04)
{
LCD_Send_String("4");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
}
PORTC = 1<<rowC; // Make rowA high
if(some_var)
{
if(some_var == 0x01)
{
LCD_Send_String("B");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x02)
{
LCD_Send_String("A");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x03)
{
LCD_Send_String("9");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x04)
{
LCD_Send_String("8");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
}
PORTC = 1<<rowD; // Make rowA high
if(some_var)
{
if(some_var == 0x01)
{
LCD_Send_String("F");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x02)
{
LCD_Send_String("E");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x03)
{
LCD_Send_String("D");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x04)
{
LCD_Send_String("C");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
}
// Enable global interrupts
asm("sei");
asm("nop");
}
return(0);
}
/****************************************************************/
/*
LCD ROUTINES
Below are the routines to write data and commands to the
LCD. They differ only in the state of the Register
Select (LCD_RS) pin.
*/
void LCD_Send_Command(uint8_t command)
{
_delay_us(100);
LCD_Control &= ~(1<<LCD_RS);
LCD_Data = command;
LCD_Control |= (1<<LCD_E);
LCD_Control &= ~(1<<LCD_E);
}
void LCD_Send_Data(uint8_t data)
{
_delay_us(100);
LCD_Control |= (1<<LCD_RS);
LCD_Data = data;
LCD_Control |= (1<<LCD_E);
LCD_Control &= ~(1<<LCD_E);
}
//Go to a specific location on the LCD. 0,0 is the top left character
void LCD_GOTOXY(uint8_t x,uint8_t y)
{
if (x>39) x=0;
if (y>1) y=0;
//Ensure that the x,y values are within range
if (y==0) LCD_Send_Command(LINE_1+x);
if (y==1) LCD_Send_Command(LINE_2+x);
}
//Send a single character to a specific loaction
void LCD_Send_Data_XY(uint8_t d,uint8_t x,uint8_t y)
{
LCD_GOTOXY(x,y);
LCD_Send_Data(d);
}
//Send a string to the display.
void LCD_Send_String(char *ch)
{
int i=0;
while(ch!='\0')
{
LCD_Send_Data(ch[i++]);
}
}
//Initialise the LCD
void LCD_Initialise(void)
{
_delay_ms(10); //Ensure start-up delay
LCD_Send_Command(DISP_FS);
//Function set #
_delay_ms(16);
//16ms delay
LCD_Send_Command(DISP_FS);
//Function set
_delay_ms(5);
//5ms Delay
LCD_Send_Command(DISP_FS); //Function set
_delay_ms(5);
//1ms delay
LCD_Send_Command(DISP_FS); //Function set
_delay_ms(1);
//1ms delay
LCD_Send_Command(DISP_ON); //Turn Display on
_delay_ms(1);
//1ms delay
LCD_Send_Command(DISP_EN); //Set entry mode
_delay_ms(1);
//1ms delay
LCD_Send_Command(DISP_CL); //Clear Display
_delay_ms(1); //1ms delay
}
Can you please help me with the following problem?
I have written some C code on AVR studio 4 to run an AVR Atmega 164p chip, to take input from a 4X4 matrix keypad and output the number pressed on an LCD.
The LCD and the code behind it is fine. However, there is a problem reading in the numbers from the keypad. When I press the keys '0' to '9' and 'A' to 'C' I get no response whatsoever. When I press 'D' and 'F' I get the number 0 appearing on the LCD. When I press 'E' I get the number two appearing on the LCD.
I have connected the Column wires from the keypad to 4.3Kohm resistors down to ground, I have set the row wires to constantly get a signal in from the AVR.
Additional information:
I am using an 8MHZ crystal oscillator
Please let me know if you need more information in order to help me.
***THE CODE IS BELOW:***
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/*----------- LCD and PORTA(Data) PORTD(Commands)------------------*/
#define LCD_Data PORTA //LCD Data output
#define LCD_Data_DDR DDRA //LCD Direction port
#define LCD_Data_RD PINA //LCD Data input
#define LCD_Control PORTD //Port where LCD control signals are
#define LCD_Control_RD PIND
#define LCD_Control_DDR DDRD
#define LCD_RS 0 //Pin on which LCD Register Select is
#define LCD_RW 1 //Pin on which LCD Read/Write is
#define LCD_E 2 //Pin on which LCD Enable is
/*------------------------- HEX keypad and PORTC----------------------*/
//define pins0-3 as rowsA-D (the rows of the hexadecinal keypad)***They will be defined as outputs from AVR to the Keypad****
#define rowA PC7 //This row is the bottom row, the numbers 0,1,2 and 3
#define rowB PC6
#define rowC PC5
#define rowD PC4//this row is the top row; the keys C,D,E and F
//define pins4-7 as columns 1-4 (columns of the hexadecimal keypad)
#define column1 PC3 // This is the leftmost column, the number 0,4,8 and C
#define column2 PC2
#define column3 PC1
#define column4 PC0// This is the rightmost column; the keys 3,7,B and F
// Meanings of the keys:
// A-
// B- Back to previous section
// C- Cancel
// D- Delete
// E- Enter (as in confirm)
// F-
/*Constants derived from information within Hitachi HD44780 datasheet--*/
// This command structure is used on every alphanumeric LCD.
#define DISP_FS 0x3f //Function set
#define DISP_ON 0x0c //Display on w/o blink or flash
#define DISP_OFF 0x08 //Display, blink, cursor off
#define DISP_CL 0x01 //Clear display
#define DISP_EN 0x06 //Data entry mode
#define LINE_1 0x80 //DDRAM address for first line
#define LINE_2 0xc0 //DDRAM address for second line
#define SH_LFT 0x18 //Left-shift display
#define SH_RT 0x1c //Right-shift display
#define HOME 0x02 //Return home
char dispstr[17];
uint8_t Captured;
uint16_t amplitude;
/*******************************************************/
/* LCD Function prototypes */
void LCD_Send_Command(uint8_t);
void LCD_Send_Data(uint8_t);
void LCD_Initialise(void);
void LCD_GOTOXY(uint8_t,uint8_t);
void LCD_Send_Data_XY(uint8_t /*data*/,uint8_t/*X coord*/,uint8_t/*Y coord*/);
void LCD_Send_String(char *);
/*******************************************************/
//#define Interval_1s 15625
//char freq[17] ="Frequency: Hz";
//char ampl[17] ="Average: V";
/********************************************************/
int main (void)
{
DDRC=(1<<rowA |1<<rowB | 1<<rowC| 1<<rowD);
LCD_Data_DDR=0xff;
LCD_Control_DDR|=(1<<LCD_RS | 1<<LCD_RW | 1<<LCD_E);
LCD_Control &=~(1<<LCD_RW);
LCD_Initialise();
_delay_ms(1);
//LCD_Send_String("");
//_delay_ms(1);
//LCD_GOTOXY(0,1);//sends the above string to the left-most position (x=0) on the top line (y=1 [indexed from zerol; zero being the bottom line])
while (1)
{
int some_var = PINC & 0x0F;//some variable that holds the value of the column you are on
//0001 is the right key/column of the particular row you are on
//1000 is the left key of the particular row you are on
PORTC = 1<<rowA; // Make rowA high
if(some_var)//if some var is not zero (i.e a button is pressed) do the following
{
if(some_var == 0x01)//0000 0001
{
LCD_Send_String("3");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x02) //0000 0010
{
LCD_Send_String("2");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x03)
{
LCD_Send_String("1");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x04)
{
LCD_Send_String("0");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
}
PORTC = 1<<rowB; // Make rowA high
if(some_var)
{
if(some_var == 0x01)
{
LCD_Send_String("7");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x02)
{
LCD_Send_String("6");
_delay_ms(500);
LCD_GOTOXY(0,0);/
}
else if(some_var == 0x03)
{
LCD_Send_String("5");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x04)
{
LCD_Send_String("4");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
}
PORTC = 1<<rowC; // Make rowA high
if(some_var)
{
if(some_var == 0x01)
{
LCD_Send_String("B");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x02)
{
LCD_Send_String("A");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x03)
{
LCD_Send_String("9");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x04)
{
LCD_Send_String("8");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
}
PORTC = 1<<rowD; // Make rowA high
if(some_var)
{
if(some_var == 0x01)
{
LCD_Send_String("F");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x02)
{
LCD_Send_String("E");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x03)
{
LCD_Send_String("D");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
else if(some_var == 0x04)
{
LCD_Send_String("C");
_delay_ms(500);
LCD_GOTOXY(0,0);
}
}
// Enable global interrupts
asm("sei");
asm("nop");
}
return(0);
}
/****************************************************************/
/*
LCD ROUTINES
Below are the routines to write data and commands to the
LCD. They differ only in the state of the Register
Select (LCD_RS) pin.
*/
void LCD_Send_Command(uint8_t command)
{
_delay_us(100);
LCD_Control &= ~(1<<LCD_RS);
LCD_Data = command;
LCD_Control |= (1<<LCD_E);
LCD_Control &= ~(1<<LCD_E);
}
void LCD_Send_Data(uint8_t data)
{
_delay_us(100);
LCD_Control |= (1<<LCD_RS);
LCD_Data = data;
LCD_Control |= (1<<LCD_E);
LCD_Control &= ~(1<<LCD_E);
}
//Go to a specific location on the LCD. 0,0 is the top left character
void LCD_GOTOXY(uint8_t x,uint8_t y)
{
if (x>39) x=0;
if (y>1) y=0;
//Ensure that the x,y values are within range
if (y==0) LCD_Send_Command(LINE_1+x);
if (y==1) LCD_Send_Command(LINE_2+x);
}
//Send a single character to a specific loaction
void LCD_Send_Data_XY(uint8_t d,uint8_t x,uint8_t y)
{
LCD_GOTOXY(x,y);
LCD_Send_Data(d);
}
//Send a string to the display.
void LCD_Send_String(char *ch)
{
int i=0;
while(ch!='\0')
{
LCD_Send_Data(ch[i++]);
}
}
//Initialise the LCD
void LCD_Initialise(void)
{
_delay_ms(10); //Ensure start-up delay
LCD_Send_Command(DISP_FS);
//Function set #
_delay_ms(16);
//16ms delay
LCD_Send_Command(DISP_FS);
//Function set
_delay_ms(5);
//5ms Delay
LCD_Send_Command(DISP_FS); //Function set
_delay_ms(5);
//1ms delay
LCD_Send_Command(DISP_FS); //Function set
_delay_ms(1);
//1ms delay
LCD_Send_Command(DISP_ON); //Turn Display on
_delay_ms(1);
//1ms delay
LCD_Send_Command(DISP_EN); //Set entry mode
_delay_ms(1);
//1ms delay
LCD_Send_Command(DISP_CL); //Clear Display
_delay_ms(1); //1ms delay
}