NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Project Help and Ideas » Pushbutton state displayed by the LCD

January 15, 2011
by SpaceGhost
SpaceGhost's Avatar

Okay, I've been at it again. Now I'm trying to program my MCU to display on the LCD a button's function when pressed (on) and its state when it is not pressed (off), and at the same time turn on an LED with the same button (LED is off when the button is not pressed).

Here is what I've done so far:

#define F_CPU 14745600

#include <stdio.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"

// PIN DEFINITIONS:
// PC2 - RF-IR MODE SELECT SWITCH (pin 25)
// PC1 - TX PUSHBUTTON (pin 24)
// PB5 TX output indicator green LED (pin 19)

int main() {
// fire up the LCD
  lcd_init();
  FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
  lcd_home();

// Set the output pin
  DDRB |= (1<<PB5);

// Set the pin to input mode - Pushbutton
  DDRC &= ~(1<<PC2); // set PC2 as input

  // turn on the internal resistor for the pin
  PORTC |= (1<<PC2); // turn on internal pull up resistor

// declare the variables to represent pushbutton input
  uint8_t mode_select;

  while(1) {

mode_select = (PINC & (1<<PC2)) >> PC2;

  lcd_home();
  fprintf_P(&lcd_stream, PSTR("            STAND BY"));

        if (mode_select == 0)
        PORTB |= (1<<PB5);

  if (mode_select == 0)
  lcd_line_one();
  fprintf_P(&lcd_stream, PSTR("        TRANSMITTING"));

        if (mode_select == 1)
        PORTB &= ~(1<<PB5);

} 
  return 0;

}

Obviously this will be for a transmitter circuit. The LED part works fine - LED is off, and turns on when the button is pressed. LED returns to off when button is released.

The LCD part works too, sort of - "STAND BY" is displayed on line one of the LCD when the button is not pressed. "TRANSMITTING" is then displayed on line one when the button is pressed...

However "TRANSMITTING" is displayed on line three all the time, regardless of the button's on/off state.

I've tried several different things and the code above is the closest I've came to getting it work the way I want.

I'd like to be able to put the information on the LCD on another line if I decide later that's where I want it instead. I don't want to just "cover" line three... (I would like to still be able to possibly use other buttons to display other information on other lines.) Could someone give me a clue as to how to fix my code?

January 15, 2011
by SpaceGhost
SpaceGhost's Avatar

Hey, I think I know what I did wrong!!

I'll post later tonight or tomorrow.

Don't give it away to me yet!

Dave

January 15, 2011
by SpaceGhost
SpaceGhost's Avatar

Okay, it's working right now... Those darned brackets!!! It seems that I forgot a few of them (again!). Here's the fixed code, comments corrected also:

///////////////////////////////////////////////////
//                                               //
// LCD readout and LED switch position indicator //
// for the Nerdkit ATmega 168 MCU                //
// Dave Edwards - 2011                           //
//                                               //
///////////////////////////////////////////////////

#define F_CPU 14745600

#include <stdio.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"

// PIN DEFINITIONS:
// PC2 - TX PUSHBUTTON (pin 25)
// PB5 TX output indicator LED (CATHODE to pin 19)

int main() {
// fire up the LCD
  lcd_init();
  FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
  lcd_home();

// Set the output pin (pin 19)
  DDRB |= (1<<PB5);

// Set the pin to input mode for Pushbutton
  DDRC &= ~(1<<PC2); // set PC2 as input

  // turn on the internal resistor for the pin
  PORTC |= (1<<PC2); // turn on internal pull up resistor

// declare the variables to represent pushbutton input
  uint8_t mode_select;

  while(1) {

mode_select = (PINC & (1<<PC2)) >> PC2;
if (mode_select == 1) // Pushbutton switch "open"

{
  lcd_line_one();
  fprintf_P(&lcd_stream, PSTR("            STAND BY"));

  PORTB |= (1<<PB5); // LED is OFF            
}

if (mode_select == 0) // Pushbutton switch "closed" (tied to GND)

{
  lcd_line_one();
  fprintf_P(&lcd_stream, PSTR("        TRANSMITTING"));

  PORTB &= ~(1<<PB5); // LED is ON
}

} 
  return 0;

}

Feels great to finally figure something out on my own. I still have a long way to go to fully understanding this stuff!

I'm still just looking at other stuff (code) to figure out things. And that helps. Now I really want to dig deeper...

Still, I'd like to ask the experts: Did I do it right? Is there a better, or more proper way of doing it? I'm open to any suggestions or critique, as always.

Dave

January 16, 2011
by Rick_S
Rick_S's Avatar

Glad to see you got it on your own. I knew you could if you just looked at it long enough. Gives you a good feeling of accomplishment doesn't it. I know it does when I figure out bugs in my projects. As for the code, it looks fine.

Rick

January 21, 2011
by SpaceGhost
SpaceGhost's Avatar

Okay, another question related to this subject.

Let's say that I wanted to add another button and make PC3 that button's input. The variable that I use for that pushbutton input would be "freq_display."

Now, I want the program to display "433 Mhz" on the second line, but ONLY when BOTH switches are closed (PC2 and PC3) at the same time. I still want "TRANSMITTING" to display if only the switch on PC2 is closed...

I guess what I'm asking is - How do I "and" two inputs to produce an output, which in this case is a message on another line on the LCD? (Hope I've explained this right!)

I'm seriously pretty clueless on this one.

Dave

January 21, 2011
by hevans
(NerdKits Staff)

hevans's Avatar

Hi SpaceGhost,

I think you can take care of something like this with a simple if statement. In much the same way you "checked" the state of one pin, you can check and save the state of your second pin. It would look something like this.

uint8_t button1;
uint8_t button2;

button1 = (PINC & (1<<PC2)) >> PC2; //grab your current pin
button2 = (PINC & (1<<PC3)) >> PC3; //grab some other pin
if ((button1 == 1) && (button2 == 1)) // Pushbutton switch "open"
  {
    //do stuff
  }

Note that all I did was grab the two states and then write a more complicated if statement that checked both inputs and ANDed the results. You could add and else statement that would fire when either input is 0, or you could add more if statements that check the individual buttons. Hope that helps.

Humberto

January 21, 2011
by SpaceGhost
SpaceGhost's Avatar

This works. I had tried something similar but didn't enclose both sets of parenthesis in another set of parenthesis. Except that "433 Mhz" on lcd line two stays on the display after the button has been released... I figure another if statement such as

if ((button1 == 0) && (button2 == 0)) // Pushbutton switches in reverse state now

// turn off lcd_line_two

Would then work... But what command would I put in to replace "// turn off lcd_line_two", to actually turn off the line two message?

January 21, 2011
by SpaceGhost
SpaceGhost's Avatar
if ((button1 == 0) && (button2 == 0)) // Pushbutton switches in reverse state now
  { lcd_line_three();
    fprintf_P(&lcd_stream, PSTR("       "));
  }

Works. The five spaces cover the "433 Mhz" phrase on the LCD when both buttons are in their off state.

I was just wondering if there was a better way.

Dave

January 21, 2011
by SpaceGhost
SpaceGhost's Avatar

I've looked at some "else" statements. I need to study them some more and how they are used...

Post a Reply

Please log in to post a reply.

Did you know that the microcontroller's crystal oscillator can be used to keep accurate time? Learn more...