#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.
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()
{
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());
+}