January 29, 2011
by SpaceGhost
|
Here's something I have been playing around with. I put together a fairly simple vertically "scrolling" menu. You scroll the "arrow" (>) to the output that you want to activate. Pushing one button turns on the selected output, pushing another button turns it off. Two buttons are used to either navigate up the menu or back down, and the menu "wraps."
#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 -- MENU DE-SELECT PUSHBUTTON (pin 25)
// PC3 -- MENU DOWN PUSHBUTTON (pin 26)
// PC4 -- MENU UP PUSHBUTTON (pin 27)
// PC5 -- MENU SELECT PUSHBUTTON (pin 28)
// PB1 -- (+) output (pin 15)
// PB2 -- (+) output (pin 16)
// PB3 -- (+) output (pin 17)
// PB4 -- (+) output (pin 18)
// PB5 -- (+) output (pin 19)
// PC0 -- (+) output (pin 23)
int main() {
// fire up the LCD
lcd_init();
FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
lcd_home();
// Set the 6 output pins (sourcing outputs)
DDRB |= (1<<PB1);
DDRB |= (1<<PB2);
DDRB |= (1<<PB3);
DDRB |= (1<<PB4);
DDRB |= (1<<PB5);
DDRC |= (1<<PC0);
// Set the 4 input pins (sinking inputs)
DDRC &= ~(1<<PC2); // set PC3 as input (pin 25)
DDRC &= ~(1<<PC3); // set PC3 as input (pin 26)
DDRC &= ~(1<<PC4); // set PC4 as input (pin 27)
DDRC &= ~(1<<PC5); // set PC2 as input (pin 28)
// turn on the internal resistors for the input pins
PORTC |= (1<<PC2); // turn on internal pull up resistor (pin 25)
PORTC |= (1<<PC3); // turn on internal pull up resistor (pin 26)
PORTC |= (1<<PC4); // turn on internal pull up resistor (pin 27)
PORTC |= (1<<PC5); // turn on internal pull up resistor (pin 28)
// declare the variables to represent each pushbutton input
uint8_t enter_selection;
uint8_t deselect;
uint8_t menu_up;
uint8_t menu_down;
uint8_t j; // for selection indicator
for(j = 0; j <= 6; j++){
// Turn off all six outputs
PORTB &= ~(1<<PB1);
PORTB &= ~(1<<PB2);
PORTB &= ~(1<<PB3);
PORTB &= ~(1<<PB4);
PORTB &= ~(1<<PB5);
PORTC &= ~(1<<PC0);
lcd_line_one();
fprintf_P(&lcd_stream, PSTR("> output one "));
lcd_line_two();
fprintf_P(&lcd_stream, PSTR(" output two "));
lcd_line_three();
fprintf_P(&lcd_stream, PSTR(" output three "));
lcd_line_four();
fprintf_P(&lcd_stream, PSTR(" output four "));
}
j=0; // start position selection indicator @ "output one"
while(1) {
menu_up = (PINC & (1<<PC4)) >> PC4;
if (menu_up == 0)
{ if(j==0)
j=6;
if(j>0) //set 0 as lowest allowed count
j = j - 1; // if count down pressed, lower count by one
delay_ms(300); // switch "debounce"
}
menu_down = (PINC & (1<<PC3)) >> PC3;
if (menu_down == 0)
{ j = j + 1; //if button pressed, increase count by one
if (j >= 6 ) //set 0 as lowest allowed count, and if i is < 5,
j = 0; //count loops to five
delay_ms(300); // switch "debounce"
}
deselect = (PINC & (1<<PC2)) >> PC2;
enter_selection = (PINC & (1<<PC5)) >> PC5;
// Pushing pin 26 pushbutton advances to selection option(s).
// Pushing pin 27 pushbutton backs up to selection option(s).
if ( j == 0)
{ lcd_line_one();
fprintf_P(&lcd_stream, PSTR("> output one "));
lcd_line_two();
fprintf_P(&lcd_stream, PSTR(" output two "));
lcd_line_three();
fprintf_P(&lcd_stream, PSTR(" output three "));
lcd_line_four();
fprintf_P(&lcd_stream, PSTR(" output four "));
}
if (( j == 0 ) && (enter_selection == 0)) // pushbutton on pin 28 (PC5)
{ PORTB |= (1<<PB1); // turns pin 15 output ON
}
if (( j == 0 ) && (deselect == 0)) // pushbutton on pin 25 (PC2)
{ PORTB &= ~(1<<PB1); // turns pin 15 output OFF
}
if ( j == 1)
{ lcd_line_one();
fprintf_P(&lcd_stream, PSTR(" output one "));
lcd_line_two();
fprintf_P(&lcd_stream, PSTR("> output two "));
lcd_line_three();
fprintf_P(&lcd_stream, PSTR(" output three "));
lcd_line_four();
fprintf_P(&lcd_stream, PSTR(" output four "));
}
if (( j == 1 ) && (enter_selection == 0))
{ PORTB |= (1<<PB2); // turns pin 16 output ON
}
if (( j == 1 ) && (deselect == 0))
{ PORTB &= ~(1<<PB2); // turns pin 16 output OFF
}
if ( j == 2)
{ lcd_line_one();
fprintf_P(&lcd_stream, PSTR(" output one "));
lcd_line_two();
fprintf_P(&lcd_stream, PSTR(" output two "));
lcd_line_three();
fprintf_P(&lcd_stream, PSTR("> output three "));
lcd_line_four();
fprintf_P(&lcd_stream, PSTR(" output four "));
}
if (( j == 2 ) && (enter_selection == 0))
{ PORTB |= (1<<PB3); // pin 17 output ON
}
if (( j == 2 ) && (deselect == 0))
{ PORTB &= ~(1<<PB3); // pin 17 output OFF
}
if ( j == 3)
{ lcd_line_one();
fprintf_P(&lcd_stream, PSTR(" output one "));
lcd_line_two();
fprintf_P(&lcd_stream, PSTR(" output two "));
lcd_line_three();
fprintf_P(&lcd_stream, PSTR(" output three "));
lcd_line_four();
fprintf_P(&lcd_stream, PSTR("> output four ")); // output four selected
}
if (( j == 3 ) && (enter_selection == 0))
{ PORTB |= (1<<PB4); // pin 18 output ON
}
if (( j == 3 ) && (deselect == 0))
{ PORTB &= ~(1<<PB4); // pin 18 output OFF
}
if ( j == 4)
{ lcd_line_one();
fprintf_P(&lcd_stream, PSTR(" output two "));
lcd_line_two();
fprintf_P(&lcd_stream, PSTR(" output three "));
lcd_line_three();
fprintf_P(&lcd_stream, PSTR(" output four "));
lcd_line_four();
fprintf_P(&lcd_stream, PSTR("> output five ")); //output five selected
}
if (( j == 4 ) && (enter_selection == 0))
{ PORTB |= (1<<PB5); // pin 19 output ON
}
if (( j == 4 ) && (deselect == 0))
{ PORTB &= ~(1<<PB5); // pin 19 output OFF
}
if ( j == 5)
{ lcd_line_one();
fprintf_P(&lcd_stream, PSTR(" output three "));
lcd_line_two();
fprintf_P(&lcd_stream, PSTR(" output four "));
lcd_line_three();
fprintf_P(&lcd_stream, PSTR(" output five "));
lcd_line_four();
fprintf_P(&lcd_stream, PSTR("> output six "));
}
if (( j == 5 ) && (enter_selection == 0))
{ PORTC |= (1<<PC0); // pin 23 output ON
}
if (( j == 5 ) && (deselect == 0))
{ PORTC &= ~(1<<PC0); // pin 23 output OFF
}
}
return 0;
}
The program works good. LEDs on the outputs give visual indication of the individual output states (on of off).
I experimented with putting "ON" indicators on the LCD screen that corresponded with individual outputs and their on states (putting the ON indicators on the 17th - 20th position(s) of the LCD line).
Using a lot of "if" statements and more variables I had luck getting "ON" messages to move and wrap with the first two outputs ("output one" and "output two")... But getting "output three" to work that way with the other two outputs "ON" proved to be impossible! I kinda figured when I started that it probably wouldn't work or the file would be HUGE... but gave it several tries.
The code I have works as it is - but I'd love to improve on it! Does anyone have any hints or suggestions? I'm sure there's a concept to this that I need to learn & study...
Dave |
January 31, 2011
by SpaceGhost
|
Hey thanks Ralph, I will look that up. In the meantime though I figured out how to put the "ON"s on the LCD display to correspond with the output states of the MCU. Here is the code as I have it now -
#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 -- MENU DE-SELECT PUSHBUTTON (pin 25)
// PC3 -- MENU DOWN PUSHBUTTON (pin 26)
// PC4 -- MENU UP PUSHBUTTON (pin 27)
// PC5 -- MENU SELECT PUSHBUTTON (pin 28)
// PB1 -- (+) output (pin 15)
// PB2 -- (+) output (pin 16)
// PB3 -- (+) output (pin 17)
// PB4 -- (+) output (pin 18)
// PB5 -- (+) output (pin 19)
// PC0 -- (+) output (pin 23)
int main() {
// fire up the LCD
lcd_init();
FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
lcd_home();
// Set the 6 output pins (sourcing outputs)
DDRB |= (1<<PB1);
DDRB |= (1<<PB2);
DDRB |= (1<<PB3);
DDRB |= (1<<PB4);
DDRB |= (1<<PB5);
DDRC |= (1<<PC0);
// Set the 4 input pins (sinking inputs)
DDRC &= ~(1<<PC2); // set PC3 as input (pin 25)
DDRC &= ~(1<<PC3); // set PC3 as input (pin 26)
DDRC &= ~(1<<PC4); // set PC4 as input (pin 27)
DDRC &= ~(1<<PC5); // set PC2 as input (pin 28)
// turn on the internal resistors for the input pins
PORTC |= (1<<PC2); // turn on internal pull up resistor (pin 25)
PORTC |= (1<<PC3); // turn on internal pull up resistor (pin 26)
PORTC |= (1<<PC4); // turn on internal pull up resistor (pin 27)
PORTC |= (1<<PC5); // turn on internal pull up resistor (pin 28)
// declare the variables to represent each pushbutton input
uint8_t enter_selection;
uint8_t deselect;
uint8_t menu_up;
uint8_t menu_down;
uint8_t j; // for selection indicator
// declare the other variables
uint8_t a;
uint8_t b;
uint8_t c;
uint8_t d;
uint8_t e;
uint8_t f;
for(j = 0; j <= 6; j++){
// Turn off all six outputs
PORTB &= ~(1<<PB1);
PORTB &= ~(1<<PB2);
PORTB &= ~(1<<PB3);
PORTB &= ~(1<<PB4);
PORTB &= ~(1<<PB5);
PORTC &= ~(1<<PC0);
lcd_line_one();
fprintf_P(&lcd_stream, PSTR("> output one "));
lcd_line_two();
fprintf_P(&lcd_stream, PSTR(" output two "));
lcd_line_three();
fprintf_P(&lcd_stream, PSTR(" output three "));
lcd_line_four();
fprintf_P(&lcd_stream, PSTR(" output four "));
}
j=0; // start position selection indicator @ "output one"
a=0;
b=0;
c=0;
d=0;
e=0;
f=0; // and all outputs off
while(1) {
menu_up = (PINC & (1<<PC4)) >> PC4;
if (menu_up == 0)
{ if(j==0)
j=6;
if(j>0) //set 0 as lowest allowed count
j = j - 1; // if "up" button pressed, move arrow up menu
delay_ms(300); // switch "debounce"
}
menu_down = (PINC & (1<<PC3)) >> PC3;
if (menu_down == 0)
{ j = j + 1; //if "down" button pressed, move arrow down menu
if (j >= 6 ) //set 5 as highest count
j = 0; //count loops to zero
delay_ms(300); // switch "debounce"
}
deselect = (PINC & (1<<PC2)) >> PC2;
enter_selection = (PINC & (1<<PC5)) >> PC5;
if ( j == 0)
{ lcd_line_one();
fprintf_P(&lcd_stream, PSTR("> output one "));
lcd_line_two();
fprintf_P(&lcd_stream, PSTR(" output two "));
lcd_line_three();
fprintf_P(&lcd_stream, PSTR(" output three "));
lcd_line_four();
fprintf_P(&lcd_stream, PSTR(" output four "));
}
if (( j == 0 ) && (enter_selection == 0)) // pushbutton on pin 28 (PC5)
{ PORTB |= (1<<PB1); // turns pin 15 output ON
a = 1;
}
if (( j == 0 ) && (deselect == 0)) // pushbutton on pin 25 (PC2)
{ PORTB &= ~(1<<PB1); // turns pin 15 output OFF
a = 0;
}
if ( j == 1)
{ lcd_line_one();
fprintf_P(&lcd_stream, PSTR(" output one "));
lcd_line_two();
fprintf_P(&lcd_stream, PSTR("> output two "));
lcd_line_three();
fprintf_P(&lcd_stream, PSTR(" output three "));
lcd_line_four();
fprintf_P(&lcd_stream, PSTR(" output four "));
}
if (( j == 1 ) && (enter_selection == 0)) // pushbutton on pin 28 (PC5)
{ PORTB |= (1<<PB2); // turns pin 16 output ON
b = 1;
}
if (( j == 1 ) && (deselect == 0)) // pushbutton on pin 25 (PC2)
{ PORTB &= ~(1<<PB2); // turns pin 16 output OFF
b = 0;
}
if ( j == 2)
{ lcd_line_one();
fprintf_P(&lcd_stream, PSTR(" output one "));
lcd_line_two();
fprintf_P(&lcd_stream, PSTR(" output two "));
lcd_line_three();
fprintf_P(&lcd_stream, PSTR("> output three "));
lcd_line_four();
fprintf_P(&lcd_stream, PSTR(" output four "));
}
if (( j == 2 ) && (enter_selection == 0)) // ect.,
{ PORTB |= (1<<PB3); // pin 17 output ON
c = 1;
}
if (( j == 2 ) && (deselect == 0))
{ PORTB &= ~(1<<PB3); // pin 17 output OFF
c = 0;
}
if ( j == 3)
{ lcd_line_one();
fprintf_P(&lcd_stream, PSTR(" output one "));
lcd_line_two();
fprintf_P(&lcd_stream, PSTR(" output two "));
lcd_line_three();
fprintf_P(&lcd_stream, PSTR(" output three "));
lcd_line_four();
fprintf_P(&lcd_stream, PSTR("> output four ")); // output four selected
}
if (( j == 3 ) && (enter_selection == 0))
{ PORTB |= (1<<PB4); // pin 18 output ON
d = 1;
}
if (( j == 3 ) && (deselect == 0))
{ PORTB &= ~(1<<PB4); // pin 18 output OFF
d = 0;
}
if ( j == 4)
{ lcd_line_one();
fprintf_P(&lcd_stream, PSTR(" output two "));
lcd_line_two();
fprintf_P(&lcd_stream, PSTR(" output three "));
lcd_line_three();
fprintf_P(&lcd_stream, PSTR(" output four "));
lcd_line_four();
fprintf_P(&lcd_stream, PSTR("> output five ")); //output five selected
}
if (( j == 4 ) && (enter_selection == 0))
{ PORTB |= (1<<PB5); // pin 19 output ON
e = 1;
}
if (( j == 4 ) && (deselect == 0))
{ PORTB &= ~(1<<PB5); // pin 19 output OFF
e = 0;
}
if ( j == 5)
{ lcd_line_one();
fprintf_P(&lcd_stream, PSTR(" output three "));
lcd_line_two();
fprintf_P(&lcd_stream, PSTR(" output four "));
lcd_line_three();
fprintf_P(&lcd_stream, PSTR(" output five "));
lcd_line_four();
fprintf_P(&lcd_stream, PSTR("> output six "));
}
if (( j == 5 ) && (enter_selection == 0))
{ PORTC |= (1<<PC0); // pin 23 output ON
f = 1;
}
if (( j == 5 ) && (deselect == 0))
{ PORTC &= ~(1<<PC0); // pin 23 output OFF
f = 0;
}
// begin synching sequences
if ((a == 1) && (j <= 3)) //begin "screen #1"
{ lcd_goto_position(0, 17);
fprintf_P(&lcd_stream, PSTR(" ON"));
}
if ((a == 0) && (j <= 3))
{ lcd_goto_position(0, 17);
fprintf_P(&lcd_stream, PSTR(" "));
}
if ((b == 1) && (j <= 3))
{ lcd_goto_position(1, 17);
fprintf_P(&lcd_stream, PSTR(" ON"));
}
if ((b == 0) && (j <= 3))
{ lcd_goto_position(1, 17);
fprintf_P(&lcd_stream, PSTR(" "));
}
if ((c == 1) && (j <= 3))
{ lcd_goto_position(2, 17);
fprintf_P(&lcd_stream, PSTR(" ON"));
}
if ((c == 0) && (j <= 3))
{ lcd_goto_position(2, 17);
fprintf_P(&lcd_stream, PSTR(" "));
}
if ((d == 1) && (j <= 3))
{ lcd_goto_position(3, 17);
fprintf_P(&lcd_stream, PSTR(" ON"));
}
if ((d == 0) && (j <= 3))
{ lcd_goto_position(3, 17);
fprintf_P(&lcd_stream, PSTR(" ")); // end "screen #1"
}
if ((b == 1) && (j == 4)) // begin "screen #2"
{ lcd_goto_position(0, 17);
fprintf_P(&lcd_stream, PSTR(" ON"));
}
if ((b == 0) && (j == 4))
{ lcd_goto_position(0, 17);
fprintf_P(&lcd_stream, PSTR(" "));
}
if ((c == 1) && (j == 4))
{ lcd_goto_position(1, 17);
fprintf_P(&lcd_stream, PSTR(" ON"));
}
if ((c == 0) && (j == 4))
{ lcd_goto_position(1, 17);
fprintf_P(&lcd_stream, PSTR(" "));
}
if ((d == 1) && (j == 4))
{ lcd_goto_position(2, 17);
fprintf_P(&lcd_stream, PSTR(" ON"));
}
if ((d == 0) && (j == 4))
{ lcd_goto_position(2, 17);
fprintf_P(&lcd_stream, PSTR(" "));
}
if ((e == 1) && (j == 4))
{ lcd_goto_position(3, 17);
fprintf_P(&lcd_stream, PSTR(" ON"));
}
if ((e == 0) && (j == 4))
{ lcd_goto_position(3, 17);
fprintf_P(&lcd_stream, PSTR(" ")); // end "screen #2"
}
if ((c == 1) && (j == 5)) // begin "screen #3"
{ lcd_goto_position(0, 17);
fprintf_P(&lcd_stream, PSTR(" ON"));
}
if ((c == 0) && (j == 5))
{ lcd_goto_position(0, 17);
fprintf_P(&lcd_stream, PSTR(" "));
}
if ((d == 1) && (j == 5))
{ lcd_goto_position(1, 17);
fprintf_P(&lcd_stream, PSTR(" ON"));
}
if ((d == 0) && (j == 5))
{ lcd_goto_position(1, 17);
fprintf_P(&lcd_stream, PSTR(" "));
}
if ((e == 1) && (j == 5))
{ lcd_goto_position(2, 17);
fprintf_P(&lcd_stream, PSTR(" ON"));
}
if ((e == 0) && (j == 5))
{ lcd_goto_position(2, 17);
fprintf_P(&lcd_stream, PSTR(" "));
}
if ((f == 1) && (j == 5))
{ lcd_goto_position(3, 17);
fprintf_P(&lcd_stream, PSTR(" ON"));
}
if ((f == 0) && (j == 5))
{ lcd_goto_position(3, 17);
fprintf_P(&lcd_stream, PSTR(" "));
}
}
return 0;
}
This works pretty good, I'm happy with it. It would be pretty easy to modify also, add another output, etc. I might play around and see if I can do a one button input to turn the selected output on or off (push once for on, push again for off), and thus free up another port for another extra output...
I may have some redundant code in this program. I may try disecting it some later... I'm always of course, open to any suggestions or comments... Does this code seem kinda large for what I want it to do? It's really just a fancy selector switch...
I'm getting it with the "if" statements, I'm getting it now how to "and" things... And Rick, that counter program you helped me with was of great help here too, again!
But I know there is so much more that I need to learn! But sometimes I gotta just walk away from it for a while, too. Often that's what I gotta do to figure something out.
Anyway, hope someone else might find what I posted useful or inspire them to come up with something better.
Dave |