-#include <LiquidCrystal.h>
+// No longer using HD44780-comaptible display,
+// Moving to a brand new world of dot-matrix display tech!
+// Using LCD library from http://code.google.com/p/pcd8544/
+#include <PCD8544.h>
+
#include <TimerOne.h>
#include <EEPROM.h>
unsigned char current_model; // Using uchar to spend a single byte of mem..
// ----------------- Display related stuffs --------------------
-LiquidCrystal lcd( 12, 11, 10, 6, 7, 8, 9);
-// Parameters are: rs, rw, enable, d4, d5, d6, d7 pin numbers.
+PCD8544 lcd( 8, 9, 10, 11, 12);
+// Param: sclk, sdin, dc, reset, sce
// ----------------- PPM related stuffs ------------------------
// The PPM generation is handled by Timer0 interrupts, and needs
unsigned long avg_loop_time;
unsigned long t;
#endif
-// -----------------------LCD--------------------------
-
-
-#define PIN_SCE 7 //Pin 3 on LCD
-#define PIN_RESET 6 //Pin 4 on LCD
-#define PIN_DC 5 //Pin 5 on LCD
-#define PIN_SDIN 4 //Pin 6 on LCD
-#define PIN_SCLK 3 //Pin 7 on LCD
-
-//The DC pin tells the LCD if we are sending a command or data
-#define LCD_COMMAND 0
-#define LCD_DATA 1
-
-//You may find a different size screen, but this one is 84 by 48 pixels
-#define LCD_X 84
-#define LCD_Y 48
-
-//This table contains the hex values that represent pixels
-//for a font that is 5 pixels wide and 8 pixels high
-static const byte ASCII[][5] = {
- {0x00, 0x00, 0x00, 0x00, 0x00} // 20
- ,{0x00, 0x00, 0x5f, 0x00, 0x00} // 21 !
- ,{0x00, 0x07, 0x00, 0x07, 0x00} // 22 "
- ,{0x14, 0x7f, 0x14, 0x7f, 0x14} // 23 #
- ,{0x24, 0x2a, 0x7f, 0x2a, 0x12} // 24 $
- ,{0x23, 0x13, 0x08, 0x64, 0x62} // 25 %
- ,{0x36, 0x49, 0x55, 0x22, 0x50} // 26 &
- ,{0x00, 0x05, 0x03, 0x00, 0x00} // 27 '
- ,{0x00, 0x1c, 0x22, 0x41, 0x00} // 28 (
- ,{0x00, 0x41, 0x22, 0x1c, 0x00} // 29 )
- ,{0x14, 0x08, 0x3e, 0x08, 0x14} // 2a *
- ,{0x08, 0x08, 0x3e, 0x08, 0x08} // 2b +
- ,{0x00, 0x50, 0x30, 0x00, 0x00} // 2c ,
- ,{0x08, 0x08, 0x08, 0x08, 0x08} // 2d -
- ,{0x00, 0x60, 0x60, 0x00, 0x00} // 2e .
- ,{0x20, 0x10, 0x08, 0x04, 0x02} // 2f /
- ,{0x3e, 0x51, 0x49, 0x45, 0x3e} // 30 0
- ,{0x00, 0x42, 0x7f, 0x40, 0x00} // 31 1
- ,{0x42, 0x61, 0x51, 0x49, 0x46} // 32 2
- ,{0x21, 0x41, 0x45, 0x4b, 0x31} // 33 3
- ,{0x18, 0x14, 0x12, 0x7f, 0x10} // 34 4
- ,{0x27, 0x45, 0x45, 0x45, 0x39} // 35 5
- ,{0x3c, 0x4a, 0x49, 0x49, 0x30} // 36 6
- ,{0x01, 0x71, 0x09, 0x05, 0x03} // 37 7
- ,{0x36, 0x49, 0x49, 0x49, 0x36} // 38 8
- ,{0x06, 0x49, 0x49, 0x29, 0x1e} // 39 9
- ,{0x00, 0x36, 0x36, 0x00, 0x00} // 3a :
- ,{0x00, 0x56, 0x36, 0x00, 0x00} // 3b ;
- ,{0x08, 0x14, 0x22, 0x41, 0x00} // 3c <
- ,{0x14, 0x14, 0x14, 0x14, 0x14} // 3d =
- ,{0x00, 0x41, 0x22, 0x14, 0x08} // 3e >
- ,{0x02, 0x01, 0x51, 0x09, 0x06} // 3f ?
- ,{0x32, 0x49, 0x79, 0x41, 0x3e} // 40 @
- ,{0x7e, 0x11, 0x11, 0x11, 0x7e} // 41 A
- ,{0x7f, 0x49, 0x49, 0x49, 0x36} // 42 B
- ,{0x3e, 0x41, 0x41, 0x41, 0x22} // 43 C
- ,{0x7f, 0x41, 0x41, 0x22, 0x1c} // 44 D
- ,{0x7f, 0x49, 0x49, 0x49, 0x41} // 45 E
- ,{0x7f, 0x09, 0x09, 0x09, 0x01} // 46 F
- ,{0x3e, 0x41, 0x49, 0x49, 0x7a} // 47 G
- ,{0x7f, 0x08, 0x08, 0x08, 0x7f} // 48 H
- ,{0x00, 0x41, 0x7f, 0x41, 0x00} // 49 I
- ,{0x20, 0x40, 0x41, 0x3f, 0x01} // 4a J
- ,{0x7f, 0x08, 0x14, 0x22, 0x41} // 4b K
- ,{0x7f, 0x40, 0x40, 0x40, 0x40} // 4c L
- ,{0x7f, 0x02, 0x0c, 0x02, 0x7f} // 4d M
- ,{0x7f, 0x04, 0x08, 0x10, 0x7f} // 4e N
- ,{0x3e, 0x41, 0x41, 0x41, 0x3e} // 4f O
- ,{0x7f, 0x09, 0x09, 0x09, 0x06} // 50 P
- ,{0x3e, 0x41, 0x51, 0x21, 0x5e} // 51 Q
- ,{0x7f, 0x09, 0x19, 0x29, 0x46} // 52 R
- ,{0x46, 0x49, 0x49, 0x49, 0x31} // 53 S
- ,{0x01, 0x01, 0x7f, 0x01, 0x01} // 54 T
- ,{0x3f, 0x40, 0x40, 0x40, 0x3f} // 55 U
- ,{0x1f, 0x20, 0x40, 0x20, 0x1f} // 56 V
- ,{0x3f, 0x40, 0x38, 0x40, 0x3f} // 57 W
- ,{0x63, 0x14, 0x08, 0x14, 0x63} // 58 X
- ,{0x07, 0x08, 0x70, 0x08, 0x07} // 59 Y
- ,{0x61, 0x51, 0x49, 0x45, 0x43} // 5a Z
- ,{0x00, 0x7f, 0x41, 0x41, 0x00} // 5b [
- ,{0x02, 0x04, 0x08, 0x10, 0x20} // 5c \
- ,{0x00, 0x41, 0x41, 0x7f, 0x00} // 5d ]
- ,{0x04, 0x02, 0x01, 0x02, 0x04} // 5e ^
- ,{0x40, 0x40, 0x40, 0x40, 0x40} // 5f _
- ,{0x00, 0x01, 0x02, 0x04, 0x00} // 60 `
- ,{0x20, 0x54, 0x54, 0x54, 0x78} // 61 a
- ,{0x7f, 0x48, 0x44, 0x44, 0x38} // 62 b
- ,{0x38, 0x44, 0x44, 0x44, 0x20} // 63 c
- ,{0x38, 0x44, 0x44, 0x48, 0x7f} // 64 d
- ,{0x38, 0x54, 0x54, 0x54, 0x18} // 65 e
- ,{0x08, 0x7e, 0x09, 0x01, 0x02} // 66 f
- ,{0x0c, 0x52, 0x52, 0x52, 0x3e} // 67 g
- ,{0x7f, 0x08, 0x04, 0x04, 0x78} // 68 h
- ,{0x00, 0x44, 0x7d, 0x40, 0x00} // 69 i
- ,{0x20, 0x40, 0x44, 0x3d, 0x00} // 6a j
- ,{0x7f, 0x10, 0x28, 0x44, 0x00} // 6b k
- ,{0x00, 0x41, 0x7f, 0x40, 0x00} // 6c l
- ,{0x7c, 0x04, 0x18, 0x04, 0x78} // 6d m
- ,{0x7c, 0x08, 0x04, 0x04, 0x78} // 6e n
- ,{0x38, 0x44, 0x44, 0x44, 0x38} // 6f o
- ,{0x7c, 0x14, 0x14, 0x14, 0x08} // 70 p
- ,{0x08, 0x14, 0x14, 0x18, 0x7c} // 71 q
- ,{0x7c, 0x08, 0x04, 0x04, 0x08} // 72 r
- ,{0x48, 0x54, 0x54, 0x54, 0x20} // 73 s
- ,{0x04, 0x3f, 0x44, 0x40, 0x20} // 74 t
- ,{0x3c, 0x40, 0x40, 0x20, 0x7c} // 75 u
- ,{0x1c, 0x20, 0x40, 0x20, 0x1c} // 76 v
- ,{0x3c, 0x40, 0x30, 0x40, 0x3c} // 77 w
- ,{0x44, 0x28, 0x10, 0x28, 0x44} // 78 x
- ,{0x0c, 0x50, 0x50, 0x50, 0x3c} // 79 y
- ,{0x44, 0x64, 0x54, 0x4c, 0x44} // 7a z
- ,{0x00, 0x08, 0x36, 0x41, 0x00} // 7b {
- ,{0x00, 0x00, 0x7f, 0x00, 0x00} // 7c |
- ,{0x00, 0x41, 0x36, 0x08, 0x00} // 7d }
- ,{0x10, 0x08, 0x08, 0x10, 0x08} // 7e ~
- ,{0x78, 0x46, 0x41, 0x46, 0x78} // 7f DEL
-};
-
-
-
-
-
-
-
// ---------- CODE! -----------------------------------
pinMode(4, OUTPUT); // s2
pinMode(5, OUTPUT); // e
- lcd.begin(16,2);
+ lcd.begin(84, 48);
lcd.print("Starting....");
+#ifdef DEBUG
Serial.begin(9600);
Serial.println("Starting....");
+#endif
+
delay(500);
model_defaults();
set_timer( seplength );
Timer1.initialize(framelength);
Timer1.attachInterrupt(ISR_timer);
+
+ lcd.clear();
}
// Test to see if dualrate-switch #1 applies to channel...
if ( ( current_input == ( model.dr[2]-1) ) || ( current_input == ( model.dr[3]-1) ) )
{
- if ( !keys[KEY_DR1] )
+ if ( !keys[KEY_DR2] )
dr_val = ((float)model.dr[6])/100.0;
else
dr_val = ((float)model.dr[7])/100.0;
lcd.setCursor(0 , 0);
lcd.print("D/R switch ");
lcd.print( no + 1 );
- lcd.print(" ");
+ //lcd.print(" ");
+
+ lcd.setCursor(0 , 1);
+ lcd.print(" ");
lcd.setCursor(0 , 1);
lcd.print("Input ");
lcd.print(in+1);
lcd.setCursor(0 , 0);
lcd.print("D/R switch ");
lcd.print( menu_substate - 3 );
- lcd.print(" ");
+
+
+ lcd.setCursor(0 , 1);
+ lcd.print(" ");
lcd.setCursor(0 , 1);
lcd.print( state ? "HI" : "LO" );
lcd.print(" Value :");
int col;
scan_keys();
+ if ( check_key( KEY_UP) || check_key(KEY_DOWN))
+ lcd.clear();
+
if ( displaystate != MENU )
{
menu_substate = 0;
return;
}
}
-
+
digitalWrite(13, digitalRead(13) ^ 1 );
switch ( displaystate )
{
case VALUES:
- int current_input;
+ int current_input;
+
+
+ row = 0;
+ col = 0;
+
+ lcd.setCursor(col, row);
+ lcd.print(" ");
+
+ lcd.setCursor(col, row);
+ lcd.print("S1:");
+ lcd.print( keys[KEY_DR1] ? "On " : "Off" );
+ lcd.print(" S2:");
+ lcd.print( keys[KEY_DR2] ? "On " : "Off" );
+
+ row = 2;
+ col = 0;
+
for (current_input=0; current_input<MAX_INPUTS; current_input++) {
- // In channel value display, do a simple calc
- // of the LCD row & column location. With 8 channels
- // we can fit eight channels as percentage values on
- // a simple 16x2 display...
- if ( current_input < 4 )
- {
- col = current_input * 4;
- row = 0;
- }
- else
- {
- col = (current_input-4) * 4;
- row = 1;
- }
+ if (row == 6)
+ {
+ row = 2;
+ col = 40;
+ }
+
// Overwriting the needed positions with
// blanks cause less display-flicker than
// actually clearing the display...
lcd.setCursor(col, row);
- lcd.print(" ");
+ lcd.print(" ");
+
lcd.setCursor(col, row);
+
+ char mod_indicator = NULL;
+
+ if (( keys[KEY_DR1] ) && (( model.dr[0] == current_input+1) || ( model.dr[1] == current_input+1)))
+ mod_indicator = '/';
+
+ if (( keys[KEY_DR2] ) && (( model.dr[2] == current_input+1) || ( model.dr[3] == current_input+1)))
+ if (mod_indicator) mod_indicator = '|';
+ else mod_indicator = '\\';
+
+ if ( mod_indicator) lcd.print(mod_indicator);
+ else lcd.print(" ");
+
+ lcd.print( current_input+1);
+ lcd.print(":");
// Display uses percents, while PPM uses ratio....
// New format on stick values
lcd.print( (int)model.stick[current_input] );
+
+ row++;
}
break;
case BATTERY:
- lcd.clear();
+ lcd.setCursor(0 , 0);
lcd.print("Battery level: ");
lcd.setCursor(0 , 1);
+ lcd.print( " ");
+ lcd.setCursor(0 , 1);
lcd.print( (float)battery_val/10);
lcd.print("V");
if ( battery_val < BATTERY_LOW ) lcd.print(" - WARNING");
int minutes;
int seconds;
- lcd.clear();
+ lcd.setCursor(0 , 0);
lcd.print("Timer: ");
lcd.print( clock_timer.running ? "Running" : "Stopped" );
lcd.setCursor(5 , 1);
+ lcd.print(" ");
+ lcd.setCursor(5 , 1);
if ( clock_timer.running )
{
clock_timer.value = millis() - (clock_timer.start + clock_timer.init);
case CURMODEL:
- lcd.clear();
+ lcd.setCursor(0 , 0);
lcd.print("Model #: ");
lcd.print( (int)current_model );
lcd.setCursor(0 , 1);
case MENU:
- lcd.clear();
+ lcd.setCursor(0 , 0);
switch ( menu_mainstate )
{
case TOP:
+ lcd.setCursor(0 , 0);
lcd.print("In MENU mode!");
lcd.setCursor(0 , 1);
- lcd.print("Esc UP. Scrl DN.");
+ lcd.print("UP to quit.");
+ lcd.setCursor(0 , 2);
+ lcd.print("DOWN to scroll");
+
menu_substate = 0;
if ( check_key(KEY_UP) ) {
displaystate = VALUES;
+ lcd.clear();
return;
}
else if ( check_key(KEY_DOWN) ) {
+ lcd.clear();
menu_mainstate = INVERTS;
return;
}
if ( check_key(KEY_UP) ) {
menu_mainstate = TOP;
+ lcd.clear();
return;
}
else if ( check_key(KEY_DOWN) ) {
menu_mainstate = DUALRATES;
+ lcd.clear();
return;
}
if ( check_key(KEY_UP) ) {
menu_mainstate = INVERTS;
+ lcd.clear();
return;
}
if ( check_key(KEY_DOWN) ) {
menu_mainstate = EXPOS;
+ lcd.clear();
return;
}
if ( check_key(KEY_RIGHT) ) {
// on the time-horizon :P
if ( check_key(KEY_UP ) ) {
menu_mainstate = DUALRATES;
+ lcd.clear();
return;
}
#ifdef DEBUG
if ( check_key(KEY_DOWN ) ) {
menu_mainstate = DEBUG_DUMP;
+ lcd.clear();
return;
}
#else
if ( check_key(KEY_DOWN ) ) {
menu_mainstate = TOP;
+ lcd.clear();
return;
}
if ( check_key(KEY_UP ) ) {
// FIXME: Remember to update the "Scroll up" state!
menu_mainstate = EXPOS;
+ lcd.clear();
return;
} else if ( check_key(KEY_DOWN ) ) {
menu_mainstate = SAVE;
+ lcd.clear();
return;
}
break;
return;
}
-// ----------- LCD related functions ---------------
-
-void LCDgotoXY(int x, int y) {
- LCDWrite(0, 0x80 | x); // Column.
- LCDWrite(0, 0x40 | y); // Row. ?
-}
-
-//This takes a large array of bits and sends them to the LCD
-void LCDBitmap(char my_array[]){
- for (int index = 0 ; index < (LCD_X * LCD_Y / 8) ; index++)
- LCDWrite(LCD_DATA, my_array[index]);
-}
-
-//This function takes in a character, looks it up in the font table/array
-//And writes it to the screen
-//Each character is 8 bits tall and 5 bits wide. We pad one blank column of
-//pixels on each side of the character for readability.
-void LCDCharacter(char character) {
- LCDWrite(LCD_DATA, 0x00); //Blank vertical line padding
-
- for (int index = 0 ; index < 5 ; index++)
- LCDWrite(LCD_DATA, ASCII[character - 0x20][index]);
- //0x20 is the ASCII character for Space (' '). The font table starts with this character
-
- LCDWrite(LCD_DATA, 0x00); //Blank vertical line padding
-}
-
-//Given a string of characters, one by one is passed to the LCD
-void LCDString(char *characters) {
- while (*characters)
- LCDCharacter(*characters++);
-}
-
-//Clears the LCD by writing zeros to the entire screen
-void LCDClear(void) {
- for (int index = 0 ; index < (LCD_X * LCD_Y / 8) ; index++)
- LCDWrite(LCD_DATA, 0x00);
-
- LCDgotoXY(0, 0); //After we clear the display, return to the home position
-}
-
-//This sends the magical commands to the PCD8544
-void LCDInit(void) {
-
- //Configure control pins
- pinMode(PIN_SCE, OUTPUT);
- pinMode(PIN_RESET, OUTPUT);
- pinMode(PIN_DC, OUTPUT);
- pinMode(PIN_SDIN, OUTPUT);
- pinMode(PIN_SCLK, OUTPUT);
-
- //Reset the LCD to a known state
- digitalWrite(PIN_RESET, LOW);
- digitalWrite(PIN_RESET, HIGH);
-
- LCDWrite(LCD_COMMAND, 0x21); //Tell LCD that extended commands follow
- LCDWrite(LCD_COMMAND, 0xB0); //Set LCD Vop (Contrast): Try 0xB1(good @ 3.3V) or 0xBF if your display is too dark
- LCDWrite(LCD_COMMAND, 0x04); //Set Temp coefficent
- LCDWrite(LCD_COMMAND, 0x14); //LCD bias mode 1:48: Try 0x13 or 0x14
-
- LCDWrite(LCD_COMMAND, 0x20); //We must send 0x20 before modifying the display control mode
- LCDWrite(LCD_COMMAND, 0x0C); //Set display control, normal mode. 0x0D for inverse
-}
-
-//There are two memory banks in the LCD, data/RAM and commands. This
-//function sets the DC pin high or low depending, and then sends
-//the data byte
-void LCDWrite(byte data_or_command, byte data) {
- digitalWrite(PIN_DC, data_or_command); //Tell the LCD that we are writing either to data or a command
-
- //Send the data
- digitalWrite(PIN_SCE, LOW);
- shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data);
- digitalWrite(PIN_SCE, HIGH);
-}
-
-
-
#ifdef DEBUG
/* The following code is taken from the
Arduino FAT16 Library by William Greiman