Final version
authorCamil Staps <info@camilstaps.nl>
Sat, 17 Jun 2017 14:38:33 +0000 (14:38 +0000)
committerCamil Staps <info@camilstaps.nl>
Sat, 17 Jun 2017 14:38:33 +0000 (14:38 +0000)
terminal/terminal.ino

index 643f2c2..7595e50 100644 (file)
@@ -1,9 +1,54 @@
 #include <LiquidCrystal.h>
 
-LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
+// LED pins
+#define LEDS_GRN   15 // Analog 1; Common green anode
+#define LEDS_RED   16 // Analog 2; Common red anode
+#define LED1       13 // LED1 cathode
+#define LED2       12 // LED2 cathode
+#define LED3       11 // LED3 cathode
+#define LED4       10 // LED4 cathode
 
-#define COLS 20
-#define ROWS 4
+#define LED_OFF   0x00
+#define LED_GRN   0x01
+#define LED_RED   0x02
+#define LED_BLINK 0x04
+
+struct leds {
+       byte a:3;
+       byte b:3;
+       byte c:3;
+       byte d:3;
+       unsigned int counter;
+};
+struct leds leds;
+
+// Button pin
+#define BUTTON     14 // Analog 0; push button
+
+// LCD pins
+#define LCD_REGSEL  3 // Register select
+#define LCD_ENABLE  4 // Chip enable
+#define LCD_D4      5 // Data line
+#define LCD_D5      6 // Data line
+#define LCD_D6      7 // Data line
+#define LCD_D7      8 // Data line
+#define LCD_BL      2 // Backlight
+
+LiquidCrystal lcd(LCD_REGSEL, LCD_ENABLE, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
+
+enum backlight_state {
+       BL_OFF,
+       BL_ON,
+       BL_FLASH
+};
+struct backlight {
+       enum backlight_state state;
+       unsigned int timer;
+};
+struct backlight backlight;
+
+#define COLS 40
+#define ROWS 2
 
 /**
  * Special characters.
@@ -99,10 +144,97 @@ void write(struct terminal *term, char ch)
 struct terminal term;
 
 char message[] =
-       "Beste Mart, van\r\n"
-       "harte gefeliciteerd!"
-       "Hier een herprogram-"
-       "meerbare terminal. ";
+       "Beste Mart, van harte gefeliciteerd! \x00\x00\r\n"
+       "Hier een herprogrammeerbare terminal. ";
+
+/**
+ * Tasks for the LEDs. Needs to be called every few ms(?) for multiplexing.
+ * When an LED is blinking and in the off period, it is necessary to call
+ * digitalWrite() twice and set the cathode. This ensures that the function
+ * takes equally long to return on every iteration, s.t. the blinking duty
+ * cycle is exactly 50% and LEDs blink equally bright, regardless of the status
+ * of other LEDs.
+ */
+void led_tasks()
+{
+       leds.counter++;
+       switch (leds.counter & 0x03) {
+               case 0:
+                       digitalWrite(LED4, 1);
+                       if ((leds.a & LED_BLINK) && leds.counter & 0x4000) {
+                               digitalWrite(LEDS_GRN, 0);
+                               digitalWrite(LEDS_RED, 0);
+                       } else {
+                               digitalWrite(LEDS_GRN, leds.a & 1);
+                               digitalWrite(LEDS_RED, leds.a & 2);
+                       }
+                       digitalWrite(LED1, 0);
+                       break;
+               case 1:
+                       digitalWrite(LED1, 1);
+                       if ((leds.b & LED_BLINK) && leds.counter & 0x4000) {
+                               digitalWrite(LEDS_GRN, 0);
+                               digitalWrite(LEDS_RED, 0);
+                       } else {
+                               digitalWrite(LEDS_GRN, leds.b & 1);
+                               digitalWrite(LEDS_RED, leds.b & 2);
+                       }
+                       digitalWrite(LED2, 0);
+                       break;
+               case 2:
+                       digitalWrite(LED2, 1);
+                       if ((leds.c & LED_BLINK) && leds.counter & 0x4000) {
+                               digitalWrite(LEDS_GRN, 0);
+                               digitalWrite(LEDS_RED, 0);
+                       } else {
+                               digitalWrite(LEDS_GRN, leds.c & 1);
+                               digitalWrite(LEDS_RED, leds.c & 2);
+                       }
+                       digitalWrite(LED3, 0);
+                       break;
+               case 3:
+                       digitalWrite(LED3, 1);
+                       if ((leds.d & LED_BLINK) && leds.counter & 0x4000) {
+                               digitalWrite(LEDS_GRN, 0);
+                               digitalWrite(LEDS_RED, 0);
+                       } else {
+                               digitalWrite(LEDS_GRN, leds.d & 1);
+                               digitalWrite(LEDS_RED, leds.d & 2);
+                       }
+                       digitalWrite(LED4, 0);
+                       break;
+       }
+}
+
+void button_tasks()
+{
+       if (digitalRead(BUTTON)) {
+               bl_flash();
+       }
+}
+
+void bl_tasks()
+{
+       if (backlight.state == BL_FLASH)
+               if (!--backlight.timer)
+                       backlight.state = BL_OFF;
+
+       switch (backlight.state) {
+               case BL_OFF:
+                       digitalWrite(LCD_BL, 0);
+                       break;
+               case BL_FLASH:
+               case BL_ON:
+                       digitalWrite(LCD_BL, 1);
+                       break;
+       }
+}
+
+void bl_flash()
+{
+       backlight.state = BL_FLASH;
+       backlight.timer = (unsigned int) -1;
+}
 
 void setup()
 {
@@ -117,18 +249,81 @@ void setup()
 
        lcd.begin(COLS, ROWS);
        lcd.blink();
-       Serial.begin(9600);
+       Serial.begin(115200);
 
        for (byte i = 0; i < ROWS * COLS; i++)
                term.contents[i] = ' ';
 
        for (byte i = 0; i < sizeof(message) - 1; i++)
                write(&term, message[i]);
+
+       pinMode(LCD_BL, OUTPUT);
+
+       pinMode(LEDS_GRN, OUTPUT);
+       pinMode(LEDS_RED, OUTPUT);
+       pinMode(LED1, OUTPUT);
+       pinMode(LED2, OUTPUT);
+       pinMode(LED3, OUTPUT);
+       pinMode(LED4, OUTPUT);
+
+       pinMode(BUTTON, INPUT);
+
+       leds.a = LED_GRN | LED_BLINK;
+       leds.b = LED_RED | LED_BLINK;
+       leds.c = LED_GRN | LED_BLINK;
+       leds.d = LED_RED | LED_BLINK;
 }
 
-void loop()
+enum read_state {
+       S_DEFAULT,
+       S_LED,
+       S_BACKLIGHT
+};
+enum read_state read_state;
+
+void handle_character(char c)
 {
-       if (Serial.available()) {
-               write(&term, Serial.read());
+       switch (read_state) {
+               case S_DEFAULT:
+                       switch (c) {
+                               case '\x11':
+                                       read_state = S_LED;
+                                       break;
+                               case '\x12':
+                                       read_state = S_BACKLIGHT;
+                                       break;
+                               default:
+                                       write(&term, c);
+                                       break;
+                       }
+                       break;
+
+               case S_LED:
+                       switch (c & 0x30) {
+                               case 0x00: leds.a = c & 0x0f; break;
+                               case 0x10: leds.b = c & 0x0f; break;
+                               case 0x20: leds.c = c & 0x0f; break;
+                               case 0x30: leds.d = c & 0x0f; break;
+                       }
+                       read_state = S_DEFAULT;
+                       break;
+
+               case S_BACKLIGHT:
+                       if (c == 0x02)
+                               bl_flash();
+                       else
+                               backlight.state = (enum backlight_state) c;
+                       read_state = S_DEFAULT;
+                       break;
        }
 }
+
+void loop()
+{
+       led_tasks();
+       button_tasks();
+       bl_tasks();
+
+       while (Serial.available())
+               handle_character(Serial.read());
+}