Serial LCD keypad panel, the phi-panel

[UPDATE] Demonstration videos included:

Hi everyone,

Been busy developing the hardware and firmware of this sweet LCD keypad panel lately. I thought I should show it off.

The above panel only requires 2 arduino pins to run NewSoftSerial to connect. You will have full control of the LCD with serial.print, sense the keypad with serial.read, and other hardware including the following software and hardware functions:

A video demonstrating all features of the panel on the compact 16x2 panel

This is the on board menu for parameter adjustment: baud rate, startup beep, back light, and key repeat speed.

This is the compact size panel quick look around:

Hardware:

*ATMEGA328 microcontroller manages all hardware
*TTL-Serial (0-5V) interface, compatible with all Arduino variants and most other microcontrollers
*16X2 character display
*Keypad has 0-9, four directional keys, enter, and escape
*4 LEDs
*Buzzer for simple buzz or any tone
*Software adjustable LCD back light intensity
*Reset key behind the panel so you can decide whether the user can reset the panel
*Firmware can be upgraded for more functions

Software (display):

*Wraps messages automatically at the end of a line.
*Automatic scrolls lines up with new messages.
*Supports control characters: newline (‘\n’), return (‘\r’), backspace (‘\b’), tab (‘\t’).
*Supports most ANSI escape sequences: cursor position, blinking/underline cursor.
*Supports local echo of key presses for regular inputs or no local echo of key presses to conceal inputs for password fields.
*Supports LCD back light brightness control 0-255.

Software (keypad):

*Relays key presses via serial port such as ’0? to ’9? on the number pad and 1, 2, 3, 4, 5 and 6 on the arrow pad and enter and escape.
*Getting user input with multi-tap (like on cell phone number pad) for alphanumerical and symbol inputs
*Getting numbers and passwords is as easy as 1-2-3 with few lines of code.

Software (interactive features):

*Supports phi_prompt user interface library such as long text areas, interactive lists or menus, YES/NO or OK dialogs and various number and text inputs.
*Supports on-the-fly baud rate change.
*Planned upgrade will support “store and recall” functions to store messages, menus and lists on-board the panel so they can be recalled by their indices (like display menu#1 instead of sending of the entire menu) to free your Arduino FLASH by up to 256KB (requires serial adapter, special software and external EEPROM).

Software (peripheral):

*Can control 4 LEDs for status indication
*Can output any tone on the buzzer

The panel has integrated functions to render interactive menus and long messages to display menus and long information texts besides all the screen manipulation functions I can think off, all accessible via serial.print commands. A menu can be made simply like the following:

Serial.println(“Menu:”); // Display ” Menu” on line 1
Serial.println(“1.Display GPS info”); // Display option 1 on line 2
Serial.println(“2.Record GPS info”); // Display option 2 on line 3

while(1) {

if (Serial.available()) { // Make sure there is a key press
char response=Serial.read(); // Read key press from phi-panel
if (response==’1?) display_GPS(); // Display GPS info on LCD
if (response==’2?) record_GPS(); // Record GPS info on SD card or EEPROM
break; // Breaks out of the while (1) loop.
}
}

I also have a 20X4 full size version:

A video of multi-tap on the full-size panel:

I will shoot some videos on how to use the panel later.

This is the blog page for this project:

It is available on inmojo.com

Very nice. Now, attack the problem of a front panel that can be used with this. It should be precut for the lcd, leds and buttons and look nice enough to install in some enclosure or other. A wall mount display kind of thing would be nice for controlling things. The panel could be put in a belkin enclosure to make an instrument. That kind of thing.

What we're all missing is the ability to make our project look nice on a shelf, wall or dashboard. I think that's why many of us don't progress past the stage of, "Gee, look what I did!" to "Yes, I've got several of those around the house".

draythomp:
Very nice. Now, attack the problem of a front panel that can be used with this. It should be precut for the lcd, leds and buttons and look nice enough to install in some enclosure or other. A wall mount display kind of thing would be nice for controlling things. The panel could be put in a belkin enclosure to make an instrument. That kind of thing.

What we're all missing is the ability to make our project look nice on a shelf, wall or dashboard. I think that's why many of us don't progress past the stage of, "Gee, look what I did!" to "Yes, I've got several of those around the house".

Hey thanks for the compliments. Could you give me a link to belkin enclosures?

I am going to use ponoko to do acrylic front panel like I did for this other project:

I will do a solid color instead of clear, which was meant to inspire curiosity.

I've also done this but cutting plastic was the most difficult part:

This is my "journey" to get an enclosure for my project a while back:

I lost the link!! However, the kind of thing I envision is : Hammond Mfg. - Sloping Plastic Console Enclosures (1595 Series) Or maybe http://www.pactecenclosures.com/product-detail.php?classid=28

There's a scad of other possibilities, but I can see that you've already thought of it. My problem has always been the inaccuracy of grabbing a drill and poking a hole in something that took three weeks to get. Then, finding out that the hole is "just a little off". Buttons that look like crap, you know the stuff we run into. Heck, even a membrane switch panel is a pain to make look nice.

I'm starting to think about a cheap tablet computer as the display and control. Getting tired of trying to make a project look nice.

However, it's nice to see someone actually making a useful display and multipurpose keyboard for home projects. One thing you might try is using those tactile switches that have the long buttons on them. I used them on one project and stuck the buttons through the holes and cut them off to the right height with a dremel tool. That way they weren't too long or hiding down in a hole that so that I had to get a pencil to push them.

Yes, I have tactile switches with long stems too. Membrane keypads are too expensive to have made and too crude looking if DIY. I even thought about 3-D printing but that's too expensive too slow and crude. Maybe I should construct an automated router to cut enclosures.

If you build an automated router to build enclosures, I'll be so jealous.

Not fair.

draythomp:
If you build an automated router to build enclosures, I'll be so jealous.

Not fair.

That was just a thought :slight_smile:

draythomp:
What we're all missing is the ability to make our project look nice on a shelf, wall or dashboard. I think that's why many of us don't progress past the stage of, "Gee, look what I did!" to "Yes, I've got several of those around the house".

Well, except for those folks who have / are building CNC milling machines or 3D printers. I've been thinking on this topic a bit myself, and my solution will likely be either getting some assistance from a friend, or using a day pass at Club Workshop. Depending on where you live, there might be a local Maker group with similar facilities, or access to some assistance.

liudr:
I am going to use ponoko to do acrylic front panel like I did for this other project:

That looks promising, as long as you don't intend on working in stainless steel.

Why not stain steel? I thought they have cutting tools for that too. You will need plasma, right?

liudr:
Why not stain steel? I thought they have cutting tools for that too. You will need plasma, right?

Check the pricing: http://www.ponoko.com/make-and-sell/show-material/196-metal-stainless-steel

And, there are some caveats for getting the cutouts. Yes, you can cut stainless with a laser. For my purposes, i.e. one-off front panels, finding a way to mill will be much easier.

I just added demonstration videos.

A video demonstrating all features of the panel on the compact 16x2 panel

This is the on board menu for parameter adjustment: baud rate, startup beep, back light, and key repeat speed.

This is the compact size panel quick look around:

Very nice and perfect for use with CastDuino :wink:

But 1 question, why don't you use a rotary encoder to select characters, numbers an menu items? I think it would be faster, not?

BTW got my phi-panel in the mail today and mine has S/N 000003, very nice. :smiley:

JO3RI:
Very nice and perfect for use with CastDuino :wink:

But 1 question, why don't you use a rotary encoder to select characters, numbers an menu items? I think it would be faster, not?

BTW got my phi-panel in the mail today and mine has S/N 000003, very nice. :smiley:

Jo3ri,

Thanks! The reason of directional keys instead of rotary encoder is cheap and available parts for tactile buttons. In the menu that has 1-9 options, you can press any option at any time. You don't have to scroll to that page to show the item before you select it. So I think that is fast. If you know you want option 9, just push 9 as soon as you see the menu printed out. The interactive menu with an arrow works best on 20X4 displays.

BTW, I'm still writing assembly instructions. At the same time, if you want to pop in the buttons and solder them in place, go ahead.

Made a video of a mock menu for a joint project with Jo3ri on the other side of the globe:

This is supposed to be a menu that resides on one of many slaves that display messages sent by the master, all over Ethernet.

Jo3ri's CastDuino blog page:

http://www.jo3ri.be/arduino/blogduino/castduinoanarrowcastingsolutionforarduino

Video:

Code:

#include <NewSoftSerial.h>
#include <avr/pgmspace.h>

PROGMEM prog_char menu_0_00[]="Slave Menu";
PROGMEM prog_char menu_0_01[]="1.Make slave";
PROGMEM prog_char menu_0_02[]="2.NR slave 1-8";
PROGMEM prog_char menu_0_03[]="3.4th IP field";
PROGMEM prog_char menu_0_04[]="4.Group # 1-8";
PROGMEM prog_char menu_0_05[]="5.Submit";
PROGMEM const char *menu_0_items[]= {menu_0_00,menu_0_01,menu_0_02,menu_0_03,menu_0_04,menu_0_05};
char out_buffer[32];
char YN_dialog[]="\eB", interactive_menu[]="\eF", long_msg[]="\eF";
char intro[]="Joint project between:\nJO3RI\n    and\n        Liudr\n";
char esc[]="Press any key to continue...";

NewSoftSerial NSS(2,3);

void setup()
{
  NSS.begin(19200);
  delay(100);
  credits();
}

void loop()
{
  main_menu();
} 

void main_menu()
{
  NSS.print("\eG"); // Start long message
  for (byte i=0;i<sizeof(menu_0_items)/sizeof(menu_0_items[0]);i++) // Print the menu from PROGMEM. The fist sizeof() on the array name will give number of bytes of the pointer array and dividing by sizeof() the first array element will give you number of elements of the array. It's a bit of pre-compiler automation. 
  {
    PROGMEM_to_NSS((char*)pgm_read_word(menu_0_items+i),out_buffer);
    if (i<sizeof(menu_0_items)-1) NSS.print('\n'); // Print new line only between items.
  }
  NSS.print('~'); // End of long message
  
  while(1) {
    if (NSS.available()) {
      char response=NSS.read();
      if (response=='1') make_slave(); 
      if (response=='2') NR_slave(); 
      if (response=='3') ip_field(); 
      if (response=='4') group_number(); 
      if (response=='5') submit();
      break; // This breaks out of the while(1) loop.
    }
  }
}

void make_slave()
{
  NSS.print('\f'); // Clear screen
  NSS.print("Making slave");
  delay(3000);
}

void NR_slave()
{
  NSS.print('\f'); // Clear screen
  NSS.print("NR slave");
  delay(3000);
}
void ip_field()
{
  long response; // Numerical value of the user response
  NSS.print('\f'); // Clear screen
  NSS.print("\e[5m~"); // Enable blinking cursor
  NSS.print("4th IP field:\n"); // Print the question
  
  response=get_int(); // Calls the get_int function to get an integer number from phi-panel
  
  NSS.print("\e[25m~"); // Disable blinking cursor
  NSS.print("\nAddress is:\n");
  NSS.print("192.168.0.");
  NSS.print(response);
  delay(3000);
}

void group_number()
{
  NSS.print('\f'); // Clear screen
  NSS.print("Enter group #:");
  while(1) {
    if (NSS.available()) {
      char response=NSS.read();
      if ((response>'0')&&(response<'9'))
      {
        NSS.print("\nSelected ");
        NSS.print(response);
        break;
      }
    } // Wait until the user presses 1-8 for group
  }
  delay(3000);
}
void submit()
{
  NSS.print('\f'); // Clear screen
  NSS.print(YN_dialog); // Display a YN dialog with the following information
  NSS.print("Submit?");
  NSS.print('~'); // End the YN dialog
  while(1) {
    if (NSS.available()) {
      char response=NSS.read();
      if (response=='Y') NSS.print("\nSubmitted!");
      else NSS.print("\nCanceled!");
      break;} // Wait until the user presses the enter to either choose yes or no on the dialog
  }
  delay(3000);
}

void credits()
{
  NSS.print("\eG"); // Start long message
  NSS.print(intro); // Print introduction as long message
  NSS.print(esc); // Print "press any key to continue"
  NSS.print('~'); // End of long message
  
  while(1) {
    if (NSS.available()) {
      char response=NSS.read();
      break;} // Wait until a key is pressed before continue
  }
}

long get_int() // Understands backspace and enter
{
  char in_char[16]; // Char buffer to store incoming characters
  int i=0;
  int response; // Numerical value of the user response
  while(1) {
    if (NSS.available()) {
      in_char[i]=NSS.read(); // Read in one character
      NSS.print(in_char[i]); // Echo key press back to the panel for the user to see
      if ((in_char[i]=='\b')&&(i>0)) i-=2; // Handles back space.
      if (in_char[i]=='\n') { // The \n represents enter key.
        in_char[i]=0; // Terminate the string with 0.
        sscanf(in_char, "%d", &response); // Get the number from the string
        break; // This breaks out of the while(1) loop.
      }
      i++;
      if (i<0) i=0;
    }
  }
  return response;
}

void PROGMEM_to_NSS(char* msg_line, char* msg_buffer) // This function simply copies a char array from PROGMEM, msg_line, to a provided buffer, msg_buffer, then print it to NSS, new soft serial object.
{
  strcpy_P(msg_buffer,msg_line); 
  NSS.print(msg_buffer);
}