From 517d2f2199bd077745c831f48e9edb7669753cb4 Mon Sep 17 00:00:00 2001 From: Jim Lindblom Date: Wed, 31 Oct 2012 09:19:38 -0600 Subject: [PATCH] Reverting to the latest working version All commits after this use the SevSeg library to control the display and do not work with the display at the moment. As these displays are beginning to go live, I'd like a working version only of the code to be hosted here. --- README => README.txt | 0 firmware/{README => README.txt} | 0 .../S7S_Example_BasicSerial.ino | 55 +++ .../Serial_7_Segment_Display_Firmware.ino | 462 +++++++++++++++++ .../Serial_7_Segment_Display_v3_0_1.ino | 465 ------------------ .../settings.h | 138 +----- hardware/{README => README.txt} | 0 7 files changed, 523 insertions(+), 597 deletions(-) rename README => README.txt (100%) rename firmware/{README => README.txt} (100%) create mode 100644 firmware/Serial 7-Segment Display/Arduino_Examples/S7S_Example_BasicSerial/S7S_Example_BasicSerial.ino create mode 100644 firmware/Serial 7-Segment Display/Serial_7_Segment_Display_Firmware/Serial_7_Segment_Display_Firmware.ino delete mode 100644 firmware/Serial 7-Segment Display/Serial_7_Segment_Display_Firmware/Serial_7_Segment_Display_v3_0_1.ino rename hardware/{README => README.txt} (100%) diff --git a/README b/README.txt similarity index 100% rename from README rename to README.txt diff --git a/firmware/README b/firmware/README.txt similarity index 100% rename from firmware/README rename to firmware/README.txt diff --git a/firmware/Serial 7-Segment Display/Arduino_Examples/S7S_Example_BasicSerial/S7S_Example_BasicSerial.ino b/firmware/Serial 7-Segment Display/Arduino_Examples/S7S_Example_BasicSerial/S7S_Example_BasicSerial.ino new file mode 100644 index 0000000..f99a5e4 --- /dev/null +++ b/firmware/Serial 7-Segment Display/Arduino_Examples/S7S_Example_BasicSerial/S7S_Example_BasicSerial.ino @@ -0,0 +1,55 @@ +/* + 9-23-2012 + Spark Fun Electronics + Nathan Seidle + + This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). + + Serial7Segment is an open source seven segment display. + + This is example code that shows how to display basic numbers on the display. + + To get this code to work, attached an Serial7Segment to an Arduino Uno using the following pins: + Pin 7 on Uno (software serial RX) to TX on Serial7Segment + Pin 8 on Uno to RX on Serial7Segment + VIN to PWR + GND to GND + +*/ + +#include + +SoftwareSerial Serial7Segment(7, 8); //RX pin, TX pin + +int cycles = 0; + +void setup() { + + Serial.begin(9600); + Serial.println("OpenSegment Example Code"); + + Serial7Segment.begin(9600); //Talk to the Serial7Segment at 9600 bps + + //Reset the display + Serial7Segment.write('v'); //This forces the cursor to return to the beginning of the display +} + +void loop() { + Serial.print("Cycle: "); + Serial.println(cycles++); + + char tempString[10]; //Used for sprintf + sprintf(tempString, "%4d", cycles); //Convert deciSecond into a string that is right adjusted + //sprintf(tempString, "%d", cycles); //Convert deciSecond into a string that is left adjusted (requires digit 1 command) + //sprintf(tempString, "%04d", cycles); //Convert deciSecond into a string with leading zeros + //sprintf(tempString, "%4X", cycles); //Count in HEX, right adjusted + //int negativeCycles = cycles * -1; + //sprintf(tempString, "%4d", negativeCycles); //Shows a negative sign infront of right adjusted number + + Serial7Segment.print(tempString); + +// delay(1); +} + + + diff --git a/firmware/Serial 7-Segment Display/Serial_7_Segment_Display_Firmware/Serial_7_Segment_Display_Firmware.ino b/firmware/Serial 7-Segment Display/Serial_7_Segment_Display_Firmware/Serial_7_Segment_Display_Firmware.ino new file mode 100644 index 0000000..f944a13 --- /dev/null +++ b/firmware/Serial 7-Segment Display/Serial_7_Segment_Display_Firmware/Serial_7_Segment_Display_Firmware.ino @@ -0,0 +1,462 @@ +/* Serial 7 Segment Display Firmware + Version: 3.0.1 + By: Jim Lindblom (SparkFun Electronics) + Date: August 24, 2012 + License: This code is beerware: feel free to use it, with or without attribution, + in your own projects. If you find it helpful, buy me a beer next time you see me + at the local pub. + + Description: This firmware goes on the SparkFun Serial 7-Segment displays. + https://www.sparkfun.com/search/results?term=serial+7+segment&what=products + + You can send the display serial data over either UART, SPI, or I2C. It'll + sequentially display what it reads. There are special commands to control + individual segments, clear the display, reset the cursor, adjust the display's + brightness, UART baud rate, i2c address or factory reset. + + Arduino addon: This code should remain with the Serial7Seg Arduino hardware + addon. New pin defines are required for pins 22 and 23 - PB6:7. Because the + Serial 7-Segment runs on the ATmega328's internal oscillator, these two pins + open up for our use. + + Hardware: You can find the Serial 7-Segment Display Schematic here: + !!! Add schematic link + + */ +#include // Handles I2C +#include // Brightness, Baud rate, and I2C address are stored in EEPROM +#include "settings.h" // Defines command bytes, EEPROM addresses, display data +#include "SevSeg.h" //Library to control generic seven segment displays + +SevSeg myDisplay; //Create an instance of the object + +// Struct for circular data buffer data received over UART, SPI and I2C are all sent into a single buffer +struct dataBuffer +{ + unsigned char data[BUFFER_SIZE]; // THE data buffer + unsigned int head; // store new data at this index + unsigned int tail; // read oldest data from this index +} +buffer; // our data buffer is creatively named - buffer + +unsigned char commandMode = 0; // Used to indicate if a commandMode byte has been received + +// Struct for 4-digit, 7-segment display +// Stores display value (digits), decimal status (decimals) for each digit, and cursor for overall display +struct display +{ + char digits[4]; + unsigned char decimals; + unsigned char cursor; +} +display; // displays be displays + +// displayPeriod conrols the brightness of the display it controls how long in microseconds a display will be active +const int displayPeriodMax = 10000; //microseconds - how long to run through one cycle of display PWM +int displayPeriod = 2000; // microseconds, maximum of 3000 - length of time each digit on display is active + +// SPI byte received interrupt routine +ISR(SPI_STC_vect) +{ + noInterrupts(); // don't be rude! I'll be quick... + + unsigned int i = (buffer.head + 1) % BUFFER_SIZE; // read buffer head position and increment + unsigned char c = SPDR; // Read data byte into c, from SPI data register + + if (i != buffer.tail) // As long as the buffer isn't full, we can store the data in buffer + { + buffer.data[buffer.head] = c; // Store the data into the buffer's head + buffer.head = i; // update buffer head, since we stored new data + } + + interrupts(); // Fine, you were saying? +} + +// UART0 byte received interrupt routine +ISR(USART_RX_vect) +{ + noInterrupts(); // We'll be quick... + + unsigned int i = (buffer.head + 1) % BUFFER_SIZE; // read buffer head position and increment + unsigned char c = UDR0; // Read data byte into c, from UART0 data register + + if (i != buffer.tail) // As long as the buffer isn't full, we can store the data in buffer + { + buffer.data[buffer.head] = c; // Store the data into the buffer's head + buffer.head = i; // update buffer head, since we stored new data + } + + interrupts(); // Okay, resume interrupts +} + +// I2C byte receive interrupt routine +// Note: this isn't an ISR. I'm using wire library (because it just works), so +// Wire.onReceive(twiReceive); should be called +void twiReceive(int rxCount) +{ + while(Wire.available() > 0) // Do this while data is available in Wire buffer + { + unsigned int i = (buffer.head + 1) % BUFFER_SIZE; // read buffer head position and increment + unsigned char c = Wire.read(); // Read data byte into c, from Wire data buffer + + if (i != buffer.tail) // As long as the buffer isn't full, we can store the data in buffer + { + buffer.data[buffer.head] = c; // Store the data into the buffer's head + buffer.head = i; // update buffer head, since we stored new data + } + } +} + +// The display data is updated on a Timer interrupt +ISR(TIMER1_COMPA_vect) +{ + noInterrupts(); + + // if head and tail are not equal, there's data to be read from the buffer + if (buffer.head != buffer.tail) + updateBufferData(); // updateBufferData() will update the display info, or peform special commands + + interrupts(); +} + +void setup() +{ + pinMode(10, OUTPUT); + digitalWrite(10, LOW); + delayMicroseconds(1); + pinMode(10, INPUT_PULLUP); + + // Set the initial state of displays and decimals 'x' = off + display.digits[0] = 'x'; + display.digits[1] = 'x'; + display.digits[2] = 'x'; + display.digits[3] = 'x'; + display.decimals = 0x00; // Turn all decimals off + + display.cursor = 0; // Set cursor to first (left-most) digit + buffer.head = 0; // Initialize buffer values + buffer.tail = 0; + + // displayPeriod controls the brightness of our display read the brightness value from EEPROM and map the 0 + displayPeriod = map(EEPROM.read(BRIGHTNESS_ADDRESS), 0, 255, 0, 2000); + + setupTimer(); // Setup timer to control interval reading from buffer + setupUart(); // initialize UART stuff (interrupts, enable, baud) + setupSPI(); // Initialize SPI stuff (enable, mode, interrupts) + setupTWI(); // Initialize I2C stuff (address, interrupt, enable) + + //This pinout is for OpenSegment PCB layout + //Declare what pins are connected to the digits + int digit1 = 9; //Pin 12 on my 4 digit display + int digit2 = 16; //Pin 9 on my 4 digit display + int digit3 = 17; //Pin 8 on my 4 digit display + int digit4 = 3; //Pin 6 on my 4 digit display + + //Declare what pins are connected to the segments + int segA = 14; //Pin 11 on my 4 digit display + int segB = 2; //Pin 7 on my 4 digit display + int segC = 8; //Pin 4 on my 4 digit display + int segD = 6; //Pin 2 on my 4 digit display + int segE = 7; //Pin 1 on my 4 digit display + int segF = 15; //Pin 10 on my 4 digit display + int segG = 4; //Pin 5 on my 4 digit display + int segDP= 5; //Pin 3 on my 4 digit display + + int numberOfDigits = 4; //Do you have a 2 or 4 digit display? + + int displayType = COMMON_CATHODE; //Your display is either common cathode or common anode + + //Initialize the SevSeg library with all the pins needed for this type of display + myDisplay.Begin(displayType, numberOfDigits, digit1, digit2, digit3, digit4, segA, segB, segC, segD, segE, segF, segG, segDP); + + //Only used for testing: Preload the display buffer + display.digits[0] = 1; + display.digits[1] = 2; + display.digits[2] = 3; + display.digits[3] = 4; + + interrupts(); // Turn interrupts on, and les' go +} + +// The display is constantly PWM'd in the loop() +void loop() +{ + int delayTimer = 0; + + // displayDigit(display.digits[i], i); // Set all the segments correctly + myDisplay.DisplayString(display.digits, 3); //(numberToDisplay, decimal point location) + + // To control the brightness, delay for what's left of our maximum displayPeriod + delayMicroseconds((displayPeriodMax - 5 * displayPeriod) + 1); +} + +// updateBufferData(): This beast of a function is called by the Timer 1 ISR if there is new data in the buffer. +// If the data controls display data, that'll be updated. +// If the data relates to a command, commandmode will be set accordingly or a command +// will be executed from this function. +void updateBufferData() +{ + // First we read from the oldest data in the buffer + unsigned char c = buffer.data[buffer.tail]; + buffer.tail = (buffer.tail + 1) % BUFFER_SIZE; // and update the tail to the next oldest + + // if the last byte received wasn't a command byte (commandMode=0) + // and if the data is displayable (0-0x76 or 0x78), the display will be updated + if ((commandMode == 0) && ((c < 0x76) || (c == 0x78))) + { + display.digits[display.cursor] = c; // just store the read data into the cursor-active digit + display.cursor = ((display.cursor + 1) % 4); // Increment cursor, set back to 0 if necessary + } + else if (c == RESET_CMD) // If the received char is the reset command + { + for (int i=0; i<4; i++) + display.digits[i] = 'x'; // clear all digits + display.decimals = 0; // clear all decimals + display.cursor = 0; // reset the cursor + } + else if (commandMode != 0) // Otherwise, if data is non-displayable and we're in a commandMode + { + unsigned int baud = 103; // Default to 9600 if non-usable data received + + switch (commandMode) + { + case DECIMAL_CMD: // Decimal setting mode + display.decimals = c; // decimals are set by one byte + break; + case BRIGHTNESS_CMD: // Brightness setting mode + displayPeriod = map(c, 0, 255, 0, 2000); // Adjust the amount of time digits are on + EEPROM.write(BRIGHTNESS_ADDRESS, c); // write the new value to EEPROM + break; + case BAUD_CMD: // Baud setting mode + switch (c) + { + case 0: // 2400 + baud = 416; + break; + case 1: // 4800 + baud = 207; + break; + case 2: // 9600 + baud = 103; + break; + case 3: // 14400 + baud = 68; + break; + case 4: // 19200 + baud = 51; + break; + case 5: // 38400 + baud = 25; + break; + case 6: // 57600 + baud = 16; + break; + case 7: // 76800 + baud = 12; + break; + case 8: // 115200 + baud = 8; + break; + case 9: // 250000 + baud = 3; + break; + case 10: // 500000 + baud = 1; + break; + case 11: // 1000000 + baud = 0; + break; + } + UBRR0 = baud; // UBRR0 is set with no regard to F_CPU, assuming 8MHz 2x speed + EEPROM.write(BAUD_ADDRESS_H, (unsigned char)(baud>>8)); // Update EEPROM baud setting + EEPROM.write(BAUD_ADDRESS_L, (unsigned char)(baud & 0xFF)); + break; + case CURSOR_CMD: // Set the cursor + if (c <= 3) // Limited error checking, if >3 cursor command will have no effect + display.cursor = c; // Update the cursor value + break; + case TWI_ADDRESS_CMD: // Set the I2C Address + if ((c > 0) && (c < 0x7F)) + { // As long as the address value is valid msb can't be set, can't be 0 (general call) + EEPROM.write(TWI_ADDRESS_ADDRESS, c); // Update the EEPROM value + Wire.begin(c); // on-the fly I2C address update + } + break; + case FACTORY_RESET_CMD: // Factory reset + factoryReset(); // Let's do that in a function + break; + case DIGIT1_CMD: // Single-digit control for digit 1 + display.digits[0] = c | 0x80; // set msb to indicate single digit control mode + break; + case DIGIT2_CMD: // Single-digit control for digit 2 + display.digits[1] = c | 0x80; + break; + case DIGIT3_CMD: // Single-digit control for digit 3 + display.digits[2] = c | 0x80; + break; + case DIGIT4_CMD: // Single-digit control for digit 4 + display.digits[3] = c | 0x80; + break; + } + // Leaving commandMode + // !!! If the commandMode isn't a valid command, we'll leave command mode, should be checked below? + commandMode = 0; + } + else // Finally, if we weren't in command mode, if the byte isn't displayable, we'll enter command mode + { + commandMode = c; // which command mode is reflected by value of commandMode + } +} + +// seutpTimer(): Set up timer 1, which controls interval reading from the buffer +void setupTimer() +{ + // Timer 1 is se to CTC mode, 16-bit timer counts up to 0xFF + TCCR1B = (1< 0x7F)) + { // If the TWI address is invalid, use a default address + twiAddress = TWI_ADDRESS_DEFAULT; + EEPROM.write(TWI_ADDRESS_ADDRESS, TWI_ADDRESS_DEFAULT); + } + + Wire.begin(twiAddress); // Initialize Wire library as slave at twiAddress address + Wire.onReceive(twiReceive); // setup interrupt routine for when data is received +} + +// factoryReset(): Uhoh! If something breaks, try sending a factory reset command to the device +// This will reset baud, TWI address, and brightness to default values +void factoryReset() +{ + // Reset Baud (9600) + unsigned int baud = BAUD_DEFAULT; + UBRR0 = baud; + EEPROM.write(BAUD_ADDRESS_L, (unsigned char)(baud & 0xFF)); + EEPROM.write(BAUD_ADDRESS_H, (unsigned char)(baud >> 8)); + + + // Reset TWI Address (0x71) + Wire.begin(TWI_ADDRESS_DEFAULT); + EEPROM.write(TWI_ADDRESS_ADDRESS, TWI_ADDRESS_DEFAULT); + + // Reset Brightness (FULL BRIGHNESS!) + displayPeriod = map(255, 0, 255, 0, 2000); + EEPROM.write(BRIGHTNESS_ADDRESS, BRIGHTNESS_DEFAULT); + +} + +// displayDigit(byte number, byte digit): Displays number on digit. +// This function actually displays stuff. It sets the anodes to turn activate a digit, +// and it sets the cathodes to turn on the proper segments. It'll decode 0-F and ASCII +// e.g. displayDigit(8, 0) makes the left-most digit display '8'. +// displayDigit('b', 3) displays 'b' on 3. +// if digit=4, the colon and apostrophes are controlled +/*void displayDigit(byte number, byte digit) + { + clearDisplay(); // Clear the display + digitalWrite(anodes[digit], HIGH); // pull the proper anode HIGH + + if (digit == 4) // if digit=4, the colon and apostrophe are being controlled + { + digitalWrite(anodes[5], HIGH); // We'll also need to activate the apostrophe anode + if ((display.decimals & (1<<4))) // Turn the colon on if bit set + digitalWrite(6, LOW); // Colon cathode is shared with A segment cathode + if ((display.decimals & (1<<5))) // Turn the apostrophe on if bit set + digitalWrite(7, LOW); // Apostrophe cathode shared with F segment cathode + } + else // otherwise digit should be 0-3 + { + if (number & 0x80) // If msb is set, we're in single-digit control mode for this digit + { + for (int i=0; i<7; i++) // in single digit control mode ASCII isn't decode, bit-for-segment control + { + if (number & (1< // Handles I2C -#include // Brightness, Baud rate, and I2C address are stored in EEPROM -#include "settings.h" // Defines command bytes, EEPROM addresses, display data - -/* Digit Defines - Used with cathodes[] array (below) to reference specific segments */ -const int A_SEG = 0; -const int B_SEG = 1; -const int C_SEG = 2; -const int D_SEG = 3; -const int E_SEG = 4; -const int F_SEG = 5; -const int G_SEG = 6; -const int DP_SEG = 7; - -/* Pin defines for LED anodes and cathodes */ -const byte anodes[6] = {A2, A3, 3, 4, 2, 9}; // Dig0, Dig1, Dig2, Dig3, Colon, Apostrophe -const byte cathodes[8] = {8, A0, 6, A1, 23, 7, 5, 22}; // A, B, C, D, E, F, G, DP -//const byte cathodes[8] = {6, 8, A0, A1, 23, 7, 5, 22}; // A, B, C, D, E, F, G, DP - -/* Struct for circular data buffer - data received over UART, SPI and I2C are all sent into a single buffer */ -struct dataBuffer -{ - unsigned char data[BUFFER_SIZE]; // THE data buffer - unsigned int head; // store new data at this index - unsigned int tail; // read oldest data from this index -} buffer; // our data buffer is creatively named - buffer - -unsigned char commandMode = 0; // Used to indicate if a commandMode byte has been received - -/* Struct for 4-digit, 7-segment display - Stores display value (digits), decimal status (decimals) for each digit, - and cursor for overall display */ -struct display -{ - unsigned char digits[4]; - unsigned char decimals; - unsigned char cursor; -} display; // displays be displays - -/* displayPeriod conrols the brightness of the display - it controls how long in microseconds a display will be active */ -const int displayPeriodMax = 10000; //microseconds - how long to run through one cycle of display PWM -int displayPeriod = 2000; // microseconds, maximum of 3000 - length of time each digit on display is active - -/* SPI byte received interrupt routine */ -ISR(SPI_STC_vect) -{ - noInterrupts(); // don't be rude! I'll be quick... - - unsigned int i = (buffer.head + 1) % BUFFER_SIZE; // read buffer head position and increment - unsigned char c = SPDR; // Read data byte into c, from SPI data register - - if (i != buffer.tail) // As long as the buffer isn't full, we can store the data in buffer - { - buffer.data[buffer.head] = c; // Store the data into the buffer's head - buffer.head = i; // update buffer head, since we stored new data - } - - interrupts(); // Fine, you were saying? -} - -/* UART0 byte received interrupt routine */ -ISR(USART_RX_vect) -{ - noInterrupts(); // We'll be quick... - - unsigned int i = (buffer.head + 1) % BUFFER_SIZE; // read buffer head position and increment - unsigned char c = UDR0; // Read data byte into c, from UART0 data register - - if (i != buffer.tail) // As long as the buffer isn't full, we can store the data in buffer - { - buffer.data[buffer.head] = c; // Store the data into the buffer's head - buffer.head = i; // update buffer head, since we stored new data - } - - interrupts(); // Okay, resume interrupts -} - -/* I2C byte receive interrupt routine - Note: this isn't an ISR. I'm using wire library (because it just works), so - Wire.onReceive(twiReceive); should be called */ -void twiReceive(int rxCount) -{ - while(Wire.available() > 0) // Do this while data is available in Wire buffer - { - unsigned int i = (buffer.head + 1) % BUFFER_SIZE; // read buffer head position and increment - unsigned char c = Wire.read(); // Read data byte into c, from Wire data buffer - - if (i != buffer.tail) // As long as the buffer isn't full, we can store the data in buffer - { - buffer.data[buffer.head] = c; // Store the data into the buffer's head - buffer.head = i; // update buffer head, since we stored new data - } - } -} - -/* The display data is updated on a Timer interrupt */ -ISR(TIMER1_COMPA_vect) -{ - noInterrupts(); - - // if head and tail are not equal, there's data to be read from the buffer - if (buffer.head != buffer.tail) - updateBufferData(); // updateBufferData() will update the display info, or peform special commands - - interrupts(); -} - -void setup() -{ - pinMode(10, OUTPUT); - digitalWrite(10, LOW); - delayMicroseconds(1); - pinMode(10, INPUT_PULLUP); - - /* Set the initial state of displays and decimals 'x' = off */ - display.digits[0] = 'x'; - display.digits[1] = 'x'; - display.digits[2] = 'x'; - display.digits[3] = 'x'; - display.decimals = 0x00; // Turn all decimals off - - display.cursor = 0; // Set cursor to first (left-most) digit - buffer.head = 0; // Initialize buffer values - buffer.tail = 0; - - /* Initialize anode pin states to OUTPUTS, all LOWs */ - for (int i=0; i<6; i++) - { - pinMode(anodes[i], OUTPUT); - digitalWrite(anodes[i], LOW); - } - - /* Initialize cathode pin states to OUTPUTS all HIGHs */ - for (int i=0; i<8; i++) - { - pinMode(cathodes[i], OUTPUT); - digitalWrite(cathodes[i], HIGH); - } - - /* displayPeriod controls the brightness of our display - read the brightness value from EEPROM and map the 0 */ - displayPeriod = map(EEPROM.read(BRIGHTNESS_ADDRESS), 0, 255, 0, 2000); - - setupTimer(); // Setup timer to control interval reading from buffer - setupUart(); // initialize UART stuff (interrupts, enable, baud) - setupSPI(); // Initialize SPI stuff (enable, mode, interrupts) - setupTWI(); // Initialize I2C stuff (address, interrupt, enable) - - interrupts(); // Turn interrupts on, and les' go -} - -/* The display is constantly PWM'd in the loop() */ -void loop() -{ - int delayTimer = 0; - - for (int i=0; i<5; i++) // Run through this once for each digit and once for the decimals - { - displayDigit(display.digits[i], i); // Set all the segments correctly - - delayMicroseconds(displayPeriod+1); // Blocking delay while the digit is on - } - - clearDisplay(); // Clear the display, this is how we adjust brightness - /* delay for whats left of our maximum displayPeriod */ - delayMicroseconds((displayPeriodMax - 5 * displayPeriod) + 1); -} - -/* updateBufferData(): This beast of a function is called by the Timer 1 ISR if there is - new data in the buffer. - If the data controls display data, that'll be updated. - If the data relates to a command, commandmode will be set accordingly or a command - will be executed from this function. */ -void updateBufferData() -{ - /* First we read from the oldest data in the buffer */ - unsigned char c = buffer.data[buffer.tail]; - buffer.tail = (buffer.tail + 1) % BUFFER_SIZE; // and update the tail to the next oldest - - /* if the last byte received wasn't a command byte (commandMode=0) - and if the data is displayable (0-0x76 or 0x78), the display will be updated*/ - if ((commandMode == 0) && ((c < 0x76) || (c == 0x78))) - { - display.digits[display.cursor] = c; // just store the read data into the cursor-active digit - display.cursor = ((display.cursor + 1) % 4); // Increment cursor, set back to 0 if necessary - } - else if (c == RESET_CMD) // If the received char is the reset command - { - for (int i=0; i<4; i++) - display.digits[i] = 'x'; // clear all digits - display.decimals = 0; // clear all decimals - display.cursor = 0; // reset the cursor - } - else if (commandMode != 0) // Otherwise, if data is non-displayable and we're in a commandMode - { - unsigned int baud = 103; // Default to 9600 if non-usable data received - - switch (commandMode) - { - case DECIMAL_CMD: // Decimal setting mode - display.decimals = c; // decimals are set by one byte - break; - case BRIGHTNESS_CMD: // Brightness setting mode - displayPeriod = map(c, 0, 255, 0, 2000); // Adjust the amount of time digits are on - EEPROM.write(BRIGHTNESS_ADDRESS, c); // write the new value to EEPROM - break; - case BAUD_CMD: // Baud setting mode - switch (c) - { - case 0: // 2400 - baud = 416; - break; - case 1: // 4800 - baud = 207; - break; - case 2: // 9600 - baud = 103; - break; - case 3: // 14400 - baud = 68; - break; - case 4: // 19200 - baud = 51; - break; - case 5: // 38400 - baud = 25; - break; - case 6: // 57600 - baud = 16; - break; - case 7: // 76800 - baud = 12; - break; - case 8: // 115200 - baud = 8; - break; - case 9: // 250000 - baud = 3; - break; - case 10: // 500000 - baud = 1; - break; - case 11: // 1000000 - baud = 0; - break; - } - UBRR0 = baud; // UBRR0 is set with no regard to F_CPU, assuming 8MHz 2x speed - EEPROM.write(BAUD_ADDRESS_H, (unsigned char)(baud>>8)); // Update EEPROM baud setting - EEPROM.write(BAUD_ADDRESS_L, (unsigned char)(baud & 0xFF)); - break; - case CURSOR_CMD: // Set the cursor - if (c <= 3) // Limited error checking, if >3 cursor command will have no effect - display.cursor = c; // Update the cursor value - break; - case TWI_ADDRESS_CMD: // Set the I2C Address - if ((c > 0) && (c < 0x7F)) - { // As long as the address value is valid msb can't be set, can't be 0 (general call) - EEPROM.write(TWI_ADDRESS_ADDRESS, c); // Update the EEPROM value - Wire.begin(c); // on-the fly I2C address update - } - break; - case FACTORY_RESET_CMD: // Factory reset - factoryReset(); // Let's do that in a function - break; - case DIGIT1_CMD: // Single-digit control for digit 1 - display.digits[0] = c | 0x80; // set msb to indicate single digit control mode - break; - case DIGIT2_CMD: // Single-digit control for digit 2 - display.digits[1] = c | 0x80; - break; - case DIGIT3_CMD: // Single-digit control for digit 3 - display.digits[2] = c | 0x80; - break; - case DIGIT4_CMD: // Single-digit control for digit 4 - display.digits[3] = c | 0x80; - break; - } - /* Leaving commandMode - !!! If the commandMode isn't a valid command, we'll leave command mode, should be checked below? */ - commandMode = 0; - } - else // Finally, if we weren't in command mode, if the byte isn't displayable, we'll enter command mode - { - commandMode = c; // which command mode is reflected by value of commandMode - } -} - -/* seutpTimer(): Set up timer 1, which controls interval reading from the buffer */ -void setupTimer() -{ - /* Timer 1 is se to CTC mode, 16-bit timer counts up to 0xFF */ - TCCR1B = (1< 0x7F)) - { // If the TWI address is invalid, use a default address - twiAddress = TWI_ADDRESS_DEFAULT; - EEPROM.write(TWI_ADDRESS_ADDRESS, TWI_ADDRESS_DEFAULT); - } - - Wire.begin(twiAddress); // Initialize Wire library as slave at twiAddress address - Wire.onReceive(twiReceive); // setup interrupt routine for when data is received -} - -/* factoryReset(): Uhoh! If something breaks, try sending a factory reset command to the device - This will reset baud, TWI address, and brightness to default values */ -void factoryReset() -{ - /* Reset Baud (9600) */ - unsigned int baud = BAUD_DEFAULT; - UBRR0 = baud; - EEPROM.write(BAUD_ADDRESS_L, (unsigned char)(baud & 0xFF)); - EEPROM.write(BAUD_ADDRESS_H, (unsigned char)(baud >> 8)); - - - /* Reset TWI Address (0x71) */ - Wire.begin(TWI_ADDRESS_DEFAULT); - EEPROM.write(TWI_ADDRESS_ADDRESS, TWI_ADDRESS_DEFAULT); - - /* Reset Brightness (FULL BRIGHNESS!) */ - displayPeriod = map(255, 0, 255, 0, 2000); - EEPROM.write(BRIGHTNESS_ADDRESS, BRIGHTNESS_DEFAULT); - -} - -/* displayDigit(byte number, byte digit): Displays number on digit. - This function actually displays stuff. It sets the anodes to turn activate a digit, - and it sets the cathodes to turn on the proper segments. It'll decode 0-F and ASCII - e.g. displayDigit(8, 0) makes the left-most digit display '8'. - displayDigit('b', 3) displays 'b' on 3. - if digit=4, the colon and apostrophes are controlled */ -void displayDigit(byte number, byte digit) -{ - clearDisplay(); // Clear the display - digitalWrite(anodes[digit], HIGH); // pull the proper anode HIGH - - if (digit == 4) // if digit=4, the colon and apostrophe are being controlled - { - digitalWrite(anodes[5], HIGH); // We'll also need to activate the apostrophe anode - if ((display.decimals & (1<<4))) // Turn the colon on if bit set - digitalWrite(6, LOW); // Colon cathode is shared with A segment cathode - if ((display.decimals & (1<<5))) // Turn the apostrophe on if bit set - digitalWrite(7, LOW); // Apostrophe cathode shared with F segment cathode - } - else // otherwise digit should be 0-3 - { - if (number & 0x80) // If msb is set, we're in single-digit control mode for this digit - { - for (int i=0; i<7; i++) // in single digit control mode ASCII isn't decode, bit-for-segment control - { - if (number & (1<' NO DISPLAY - {0, 0, 0, 0, 0, 0, 0}, // 63 '?' NO DISPLAY - {0, 0, 0, 0, 0, 0, 0}, // 64 '@' NO DISPLAY - {1, 1, 1, 0, 1, 1, 1}, // 65 'A' - {0, 0, 1, 1, 1, 1, 1}, // 66 'B' - {1, 0, 0, 1, 1, 1, 0}, // 67 'C' - {0, 1, 1, 1, 1, 0, 1}, // 68 'D' - {1, 0, 0, 1, 1, 1, 1}, // 69 'E' - {1, 0, 0, 0, 1, 1, 1}, // 70 'F' - {1, 0, 1, 1, 1, 1, 0}, // 71 'G' - {0, 1, 1, 0, 1, 1, 1}, // 72 'H' - {0, 1, 1, 0, 0, 0, 0}, // 73 'I' - {0, 1, 1, 1, 0, 0, 0}, // 74 'J' - {0, 0, 0, 0, 0, 0, 0}, // 75 'K' NO DISPLAY - {0, 0, 0, 1, 1, 1, 0}, // 76 'L' - {0, 0, 0, 0, 0, 0, 0}, // 77 'M' NO DISPLAY - {0, 0, 1, 0, 1, 0, 1}, // 78 'N' - {1, 1, 1, 1, 1, 1, 0}, // 79 'O' - {1, 1, 0, 1, 1, 1, 1}, // 80 'P' - {1, 1, 1, 0, 0, 1, 1}, // 81 'Q' - {0, 0, 0, 0, 1, 0, 1}, // 82 'R' - {1, 0, 1, 1, 0, 1, 1}, // 83 'S' - {0, 0, 0, 1, 1, 1, 1}, // 84 'T' - {0, 1, 1, 1, 1, 1, 0}, // 85 'U' - {0, 0, 0, 0, 0, 0, 0}, // 86 'V' NO DISPLAY - {0, 0, 0, 0, 0, 0, 0}, // 87 'W' NO DISPLAY - {0, 0, 0, 0, 0, 0, 0}, // 88 'X' NO DISPLAY - {0, 1, 1, 1, 0, 1, 1}, // 89 'Y' - {0, 0, 0, 0, 0, 0, 0}, // 90 'Z' NO DISPLAY - {1, 0, 0, 1, 1, 1, 0}, // 91 '[' - {0, 0, 0, 0, 0, 0, 0}, // 92 '\' NO DISPLAY - {1, 1, 1, 1, 0, 0, 0}, // 93 ']' - {0, 0, 0, 0, 0, 0, 0}, // 94 '^' NO DISPLAY - {0, 0, 0, 1, 0, 0, 0}, // 95 '_' - {0, 0, 0, 0, 0, 1, 0}, // 96 '`' - {1, 1, 1, 0, 1, 1, 1}, // 97 'a' SAME AS CAP - {0, 0, 1, 1, 1, 1, 1}, // 98 'b' SAME AS CAP - {0, 0, 0, 1, 1, 0, 1}, // 99 'c' - {0, 1, 1, 1, 1, 0, 1}, // 100 'd' SAME AS CAP - {1, 1, 0, 1, 1, 1, 1}, // 101 'e' - {1, 0, 0, 0, 1, 1, 1}, // 102 'f' SAME AS CAP - {1, 0, 1, 1, 1, 1, 0}, // 103 'g' SAME AS CAP - {0, 0, 1, 0, 1, 1, 1}, // 104 'h' - {0, 0, 1, 0, 0, 0, 0}, // 105 'i' - {0, 1, 1, 1, 0, 0, 0}, // 106 'j' SAME AS CAP - {0, 0, 0, 0, 0, 0, 0}, // 107 'k' NO DISPLAY - {0, 1, 1, 0, 0, 0, 0}, // 108 'l' - {0, 0, 0, 0, 0, 0, 0}, // 109 'm' NO DISPLAY - {0, 0, 1, 0, 1, 0, 1}, // 110 'n' SAME AS CAP - {0, 0, 1, 1, 1, 0, 1}, // 111 'o' - {1, 1, 0, 0, 1, 1, 1}, // 112 'p' SAME AS CAP - {1, 1, 1, 0, 0, 1, 1}, // 113 'q' SAME AS CAP - {0, 0, 0, 0, 1, 0, 1}, // 114 'r' SAME AS CAP - {1, 0, 1, 1, 0, 1, 1}, // 115 's' SAME AS CAP - {0, 0, 0, 1, 1, 1, 1}, // 116 't' SAME AS CAP - {0, 0, 1, 1, 1, 0, 0}, // 117 'u' - {0, 0, 0, 0, 0, 0, 0}, // 118 'b' NO DISPLAY - {0, 0, 0, 0, 0, 0, 0}, // 119 'w' NO DISPLAY - {0, 0, 0, 0, 0, 0, 0}, // 120 'x' NO DISPLAY - {0, 0, 0, 0, 0, 0, 0}, // 121 'y' NO DISPLAY - {0, 0, 0, 0, 0, 0, 0}, // 122 'z' NO DISPLAY - {0, 0, 0, 0, 0, 0, 0}, // 123 '{' NO DISPLAY - {0, 0, 0, 0, 0, 0, 0}, // 124 '|' NO DISPLAY - {0, 0, 0, 0, 0, 0, 0}, // 125 '}' NO DISPLAY - {0, 0, 0, 0, 0, 0, 0}, // 126 '~' NO DISPLAY - {0, 0, 0, 0, 0, 0, 0}, // 127 'DEL' NO DISPLAY -}; diff --git a/hardware/README b/hardware/README.txt similarity index 100% rename from hardware/README rename to hardware/README.txt