Life.augmented
Skip to main content
Go Search
  

STM8 Discovery

Modify settings and columns
Evaluation Boards for STM8 Product Family
Share Discussion
  
View: 
Post
Edited: 12/12/2010 3:46 PM
piovan.stefano
  Posts : 43
Discovery with LCD and 4x3 keypad example

Hi friends,

I'm working on an 2.4 GHz signal generator based on the National Semi LMX2326 PLL Frequency Synthesizer. I was looking for some LCD module code and I've found very useful the example developed by Jason Lopez.

Therefore I decided to connect a 4x3 keypad the the Discovery and to put all together. In the followings that's the C code. The LCD is connected to PORT.B in 4 bit mode as well.

The keypad rows are connected to PE.0, PE.1, PE.2, PE.3, input pins are software pulled up. Pay attention that PE.1 and PE.2 are "true open drain". This means that they're not provided with internal pull-up resistor therefore remind to connet them to the +5V via a 47kOhm resistor each one. The keypad columns are connectet to PA.4, PA.5 and PA.6 pins.

The keypad has keys from 0 to 9 the same layout as a mobile phone. There is a "backspace" in place of the "*" while the "#" acts as a right movement of the cursor. It'll be easy to add the "ENTER" function by changing the directive case: in the switch(key) section of the main (). Playing with some logical conditions when you keep pressing a key, the keycode is acquired once thus avoiding to fill-up the LCD display with undesired repetitions of the same character.

The GetKeyPressed() scans the keypad by cycling all the 4 rows for each of the 3 columns. When a key is pressed then the input pin, which corresponds to the row where the key belongs to, goes to low level exactly when the column out pin drives to low level the column where the key is. In other words the column low level signal is driven into the input row pin via the electrical connection which is made by the specific key pressed.

Sorry for boring with too many words, that's the code and picture.

Hope it helps as a base of study. Please feedback.

Enjoy

Stefano

#include "stm8s.h"                // file needed only for registers mask

#define LCD_PORT GPIOB
#define LCD_RS   GPIO_PIN_2
#define LCD_E    GPIO_PIN_3

//---------------------------------------------------------------------------------------
//Addresses of cursor position for 16x2 HD44780 LCD
//line1  80H  81H  82H  83H  84H  85H  86H  87H  88H  89H  8AH  8BH  8CH  8DH  8EH  8FH 
//line2  C0H  C1H  C2H  C3H  C4H  C5H  C6H  C7H  C8H  C9H  CAH  CBH  CCH  CDH  CEH  CFH 
//---------------------------------------------------------------------------------------

void DelayMS(int delay);
void initLCD(void);
void resetLCD(void);
void LCD_DATA(unsigned char data,unsigned char type);
void LCD_NYB(unsigned char nyb, char type);
void LCD_LINE(char line);
void LCD_STR(const unsigned char *text);
void LCD_CHR(u8);
u8   GetKeyPressed(void);

int main(void)
{
 u8 key;
 u8 oldkey;

/**
 * LCD PORT initialization pin [2..7] push-pull out
 */
 GPIO_DeInit(LCD_PORT);
 GPIO_Init(LCD_PORT, GPIO_PIN_HNIB | GPIO_PIN_3 | GPIO_PIN_2, GPIO_MODE_OUT_PP_LOW_FAST);
 
/**
 * KEYPAD PORT initialization
 * Port A pin[4,5,6] push-pull out, columns selection active LOW
 */
 GPIO_DeInit(GPIOA); 
 GPIO_Init(GPIOA, GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6, GPIO_MODE_OUT_PP_LOW_FAST);
 
/**
 * Port E pin[0,1,2,3] pull up input, rows read in,
 * NOTE: PE.2 and PE.3 DON'T HAVE INTERNAL PULL UP RESISTOR (see STM8S105xx datasheet)
 *    47 kOHm EXTERNAL RESISTORS REQUIRED
 */
 GPIO_DeInit(GPIOE);
 GPIO_Init(GPIOE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_MODE_IN_PU_NO_IT);

 // initialize the LCD
 initLCD();
 LCD_LINE(1);
 LCD_STR("Press a key:");
 
 oldkey = 255;
 LCD_LINE(2);

 while(1)
 {
  key = GetKeyPressed(); //Get the code of the key pressed
  if (key != oldkey) //new key has been pressed
  {
   if (key < 12) // a valid key is pressed
   {
    switch(key)
    {
     case 9: // backspace (mode entry is "right after writing" so we need to cursor left twice)
     LCD_DATA(0x10,0);
     LCD_CHR(32);
     LCD_DATA(0x10,0);
     break;
   
    case 11:
      LCD_DATA(0x14,0); // cursor right
     break;
     
     default:
      LCD_CHR(key + 48 + 1); // display keycode
     break;
    }
    oldkey = key;
   }
   else // keypad has been released then wait for a new key pressed
   {
    oldkey = 255;
   }
  }
 }
}

u8 GetKeyPressed()
{
 u8 r, c, data;
 
 for(c=0; c<3; c++)
 {
  // First deactivate all coloumns
  GPIO_WriteHigh(GPIOA, GPIO_PIN_6 | GPIO_PIN_5 | GPIO_PIN_4);
  // Then pull the coloumn low for selection
  GPIO_WriteLow(GPIOA, (GPIO_PIN_6 >> c) );
  
  for(r=0; r<4; r++)
  {
   data = GPIO_ReadInputData(GPIOE) & 0x0F;
   data &= (0x08 >> r);
   // Rows input pins have pull-up resistors so a negative logic is used
   if(!data)
   {
    return (r*3+c);
   }
  }
 }
 return 0xff;
}

void LCD_CHR(u8 val)
{
 LCD_DATA(val,1);
}

void LCD_STR(const unsigned char *text)
{
 while(*text)
 {
  LCD_DATA(*text++,1);
 }
}

void resetLCD(void)
{
 // Special procedure: "Initializing by instruction". See HD44780 lcd controller datasheet)
 
 GPIO_WriteLow(LCD_PORT, LCD_E); //clear enable
 GPIO_WriteLow(LCD_PORT, LCD_RS); //going to write command
 DelayMS(40); //delay more than 15 ms after power on
 LCD_NYB(0x03,0); // first init: lcd DB.4 = 1, DB.5 = 1
 DelayMS(10); // delay more then 4.1 ms
 LCD_NYB(0x03,0); // second init: lcd DB.4 =1, DB.5 = 1
 DelayMS(5); // delay more than 100 microsecs
 LCD_NYB(0x03,0); // third init: lcd DB.4 = 1, DB.5 = 1
 
 // lcd is inizialized (but the interface is still 8 bit long)
 LCD_NYB(0x02,0); // Set data width = 4 bit lcd DB.4 = 0, DB.5 = 1
 DelayMS(1);
}

void initLCD(void)
{
 resetLCD();
 LCD_DATA(0x28,0); //4 bit mode, 2 line and 5*8 font
 //LCD_DATA(0x0c,0); //c = 1100 Set display ON, cursor OFF
 //LCD_DATA(0x0e,0); //e = 1110 Set display ON, cursor ON type "_"
 //LCD_DATA(0x0d,0); //d = 1101 Set display ON, cursor ON type "solid" + BLINK
 LCD_DATA(0x0F,0); //f = 1111 Set display ON, cursor ON type "_" + "solid" + BLINK
 LCD_DATA(0x01,0); //clear display
 LCD_DATA(0x06,0); //entry mode set move cursor right after write
 LCD_DATA(0x80,0); //start writing upper left corner of the lcd
}

void LCD_DATA(unsigned char data,unsigned char type)
{
 DelayMS(5); //TEST LCD FOR BUSY
 LCD_NYB(data>>4, type); //WRITE THE UPPER NIBBLE
 LCD_NYB(data, type); //WRITE THE LOWER NIBBLE
}

void LCD_NYB(unsigned char nyb, char type)
{
 unsigned char temp;
 
 temp = (nyb<<4) & 0xF0;
 GPIO_Write(LCD_PORT, temp);
 if(type == 0)
 {
  GPIO_WriteLow(LCD_PORT, LCD_RS); //COMMAND MODE
 }
 else
 {
  GPIO_WriteHigh(LCD_PORT, LCD_RS); //CHARACTER/DATA MODE
 }
 GPIO_WriteHigh(LCD_PORT, LCD_E); //ENABLE LCD DATA LINE
 DelayMS(1); //SMALL DELAY
 GPIO_WriteLow(LCD_PORT, LCD_E); //DISABLE LCD DATA LINE
}

void LCD_LINE(char line)
{
 switch(line)
 {
  case 0:
  case 1:
   LCD_DATA(0x80,0);
   break;
  case 2:
   LCD_DATA(0xC0,0);
  break;
 }
}

void DelayMS(int delay)
{
 int nCount = 0;
 while (delay != 0)
 {
  nCount = 100;
  while (nCount != 0)
  {
   nCount--;
  }
  delay--;
 }
}


Tags: Discovery , stm8s , lcd , 4x3 keypad , C
Posted: 12/23/2010 1:26 AM
george
  Posts : 20
thank you for your code.
Can you give me the reference of the keyboard(4*3) that you used??

best regards
Edited: 12/23/2010 8:35 AM
neil.andrew
  Posts : 1317
Look at the JPEG attachment to the original post:



You can see that it's a hand-made keypad!

The connections for the rows & columns, and the key layout are described in the original post.
Posted: 12/23/2010 1:52 PM
piovan.stefano
  Posts : 43
Hi George,

the 4x3 keypad is home made. I've bought 12 single push-buttons and wired them together on a prototyping pcb as you can see in the photo.

Stefano


Posted: 1/2/2011 8:15 PM
piovan.stefano
  Posts : 43
Hi all,

Here's an improved code for the 4x3 keypad with debounce and autorepeat.
With STM8S 2MHz clock it performs pretty close to the PC keyboard.
The action() function is out from the keypad management state machine for clarity.
Suggestions and improvements are welcome.

Hope it helps.

Merry Xmas and happy holidays
Steven



u8 key = 255;
u8 oldkey = 255;
u8 AutoRptMax = 64;
u8 AutoRptCount = 0;

while(1)
    {
        key = GetKeyPressed(); //Scan the keypad to getting the code of the key pressed
    
        // < Is it a valid key pressed ? >
        if (key < 12) // YES
        {
            // < Is key still the old one ? >
            if (key == oldkey) // YES
            {
                // (Start counting for autorepeat to occour)
                DelayMS(50);
                AutoRptCount++;
                
                // < Is time to execute the key action? >
                if (AutoRptCount >= AutoRptMax) // YES
                {
                    Action(key); // perform the action according to the key code
                    AutoRptCount = 0; // reset the autorepeat counter to get ready for the next autorepeat event
                    AutoRptMax = 16; // make the autorepeat limit short for speeding up the next repetition when keeps keypressing
                }
            }
            else // NO, the key is new brand
            {
                Action(key); // perform the action according to the key code
                DelayMS(50); // and also make a little debouncing
            }
            
        } // END if (key < 12)
        
        else // NO, the key is not among the 12 defined keys
        {
            // < Was the key pad released ? >
            if (oldkey < 255 ) // YES
            {
                AutoRptCount = 0; // reset the autorepeat counter
                AutoRptMax = 128; // and restart using the first typing delay long
            }            
        }
        
        oldkey = key;
    }




void Action(u8 key)

{
    switch(key)
    {
        case 9: // backspace (mode entry is "right after writing" so we need to cursor left twice)
            LCD_DATA(0x10,0);
            LCD_CHR(32);
            LCD_DATA(0x10,0);
        break;

        case 11:
            LCD_DATA(0x14,0); // cursor right
        break;
       
        default:
            LCD_CHR(key + 48 + 1); // display keycode
        break;
    }
}


void DelayMS(int delay)

{
    int nCount = 0;
    while (delay != 0)
    {
        nCount = 100;
        while (nCount != 0)
        {
            nCount--;
        }
        delay--;
    }
}

Tags: 4x3 keypad

Browse Private Forums

NOTE: these forums are exclusive for users of this Extranet!)