Created
January 2, 2014 06:59
-
-
Save gothamsound/8215851 to your computer and use it in GitHub Desktop.
The file that is currently on an Arduino Uno with a serial number of 6493534323335150A2A1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <Wire.h> // Enable this line if using Arduino Uno, Mega, etc. | |
| //#include <TinyWireM.h> // Enable this line if using Adafruit Trinket, Gemma, etc. | |
| #include "Adafruit_LEDBackpack.h" | |
| #include "Adafruit_GFX.h" | |
| #include "ClickButton.h" | |
| #include "Timer.h" | |
| Adafruit_7segment matrix = Adafruit_7segment(); | |
| // the Button | |
| const int buttonPin1 = 2; | |
| ClickButton button1(buttonPin1, LOW, CLICKBTN_PULLUP); | |
| Timer t; | |
| #define icpPin 8 // ICP input pin on arduino | |
| #define one_time_max 588 // changed these values to reflect | |
| #define one_time_min 300 // mins and maxex for 23.98 to 30 | |
| #define zero_time_max 1080 // 80bits times 29.97 frames per sec | |
| #define zero_time_min 700 // equals 833 (divide by 8 clock pulses) | |
| #define end_data_position 63 | |
| #define end_sync_position 77 | |
| #define end_smpte_position 80 | |
| int analogVal = 0; // the value from the ADC | |
| int smoothed = 0; // a nicely smoothed result. This needs to be a global variable | |
| int alpha = 15; // the number of past samples to average by | |
| const unsigned long blinkColonRate = 1000; | |
| const unsigned long checkBattInterval = 60*1000; | |
| const int lowBattThreshold = 700; | |
| boolean clearedLowBatt = true; | |
| const uint8_t adaColon = 0xC;//this puts the left top & bottom dots (left colon) on the display when written to digit 2 | |
| const uint8_t adaDot = 0x10; //bitmask for the decimal point (dot) | |
| const uint8_t adaClearColon = 0x0; //clear the dots bitmask | |
| const int rawVoltPin = A0; // Arduino pin that has the power supply input (via voltage divider) | |
| const int brightPin = 3; //toggle switch for brightness connected to pin 3 | |
| const int fullBright = 15; | |
| const int halfBright = 4; | |
| boolean latchTCDisp = false; | |
| boolean quickPress = false; | |
| const float voltDivide =3.12; //voltage divide ratio = 4700/(10000+4700) = 0.32 | |
| const float adMax = 204.0; | |
| const int disp_time_fr = 13 ; //number of consecutive frames to display ssff | |
| const int disp_time_min = 4 ;//number of consecutive frame to display hhmm | |
| const int voltOffset = 60;// offset for a-d reading of voltage | |
| int disp_fr = 0; //keep track of how many sequential ssff frames we've displayed | |
| int disp_min = 0; //keep track of how many sequential frames we've displayed hhmm for | |
| int minutes1 = 0; | |
| int framertct = 0; | |
| const unsigned long microsmax = 0xFFFFFFFF; | |
| const int numofframetime = 40; | |
| const int fratecal = -95 ; //650; | |
| int blinkColon ; //i think i need this for timer library | |
| boolean colonStatus = false; //keep track of the colon being on or off | |
| volatile unsigned int numBadFrames = 0; //keep track of the number of bad frames | |
| volatile unsigned int bittimeoff; | |
| volatile unsigned int bit_time; | |
| volatile boolean valid_tc_word; | |
| volatile boolean ones_bit_count; | |
| volatile boolean tc_sync; | |
| volatile boolean write_tc_out; | |
| volatile boolean drop_frame_flag; | |
| volatile byte total_bits; | |
| volatile byte current_bit; | |
| volatile byte sync_count; | |
| volatile byte tc[8]; | |
| volatile char timeCode[11]; | |
| volatile char userBit[8]; | |
| volatile unsigned long fratest; | |
| volatile unsigned long frateend; | |
| volatile float frate; | |
| volatile unsigned long frame_time[numofframetime]; | |
| volatile unsigned long totalframetime; | |
| volatile unsigned int volts100 = 0; | |
| float getBattVolt() { | |
| float adVal = analogRead(rawVoltPin); | |
| float voltsRaw = ((voltDivide * adVal) / adMax); | |
| return voltsRaw; | |
| } | |
| void displayBattVolt(int x) { | |
| matrix.writeDigitNum(0, (x / 1000)); | |
| matrix.writeDigitNum(1, (x / 100) % 10); | |
| matrix.writeDigitNum(3, (x / 10) % 10); | |
| matrix.writeDigitNum(4, x % 10); | |
| matrix.writeDisplay(); | |
| } | |
| void blinkColonDisp() | |
| { | |
| colonStatus=!colonStatus; | |
| matrix.drawColon(colonStatus); | |
| matrix.writeDisplay(); | |
| } | |
| void checkBatt() | |
| { | |
| int volts100 = (int(getBattVolt())*100) ; | |
| if (volts100 > lowBattThreshold && !clearedLowBatt) //do only if it's a good batter and we haven't been here before | |
| { | |
| matrix.drawColon(false); | |
| matrix.writeDisplay(); | |
| clearedLowBatt = true; | |
| t.stop(blinkColon); | |
| } | |
| if (volts100 <= lowBattThreshold) | |
| { | |
| matrix.drawColon(true); | |
| matrix.writeDisplay(); | |
| blinkColon = t.every(blinkColonRate, blinkColonDisp); | |
| clearedLowBatt = false; | |
| } | |
| } | |
| void smoothValue(int rawValue) | |
| { | |
| if (rawValue > smoothed) { | |
| smoothed = smoothed + (rawValue - smoothed)/alpha; | |
| } | |
| else { | |
| smoothed = smoothed - (smoothed - rawValue)/alpha; | |
| } | |
| } | |
| /* ICR interrupt vector */ | |
| ISR(TIMER1_CAPT_vect) | |
| { | |
| //toggleCaptureEdge | |
| TCCR1B ^= _BV(ICES1); | |
| bit_time = ICR1; | |
| if (total_bits == 0) | |
| { | |
| fratest = micros() - bit_time; | |
| bittimeoff = bit_time; | |
| } | |
| //resetTimer1 | |
| TCNT1 = 0; | |
| if ((bit_time < one_time_min) || (bit_time > zero_time_max)) // get rid of anything way outside the norm | |
| { | |
| //Serial.println(bit_time, DEC); | |
| total_bits = 0; | |
| } | |
| else | |
| { | |
| frateend = micros(); | |
| if (ones_bit_count == true) // only count the second ones pluse | |
| ones_bit_count = false; | |
| else | |
| { | |
| if (bit_time > zero_time_min) | |
| { | |
| current_bit = 0; | |
| sync_count = 0; | |
| } | |
| else //if (bit_time < one_time_max) | |
| { | |
| ones_bit_count = true; | |
| current_bit = 1; | |
| sync_count++; | |
| if (sync_count == 12) // part of the last two bytes of a timecode word | |
| { | |
| sync_count = 0; | |
| tc_sync = true; | |
| total_bits = end_sync_position; | |
| } | |
| } | |
| if (total_bits <= end_data_position) // timecode runs least to most so we need | |
| { // to shift things around | |
| tc[0] = tc[0] >> 1; | |
| for(int n=1;n<8;n++) | |
| { | |
| if(tc[n] & 1) | |
| tc[n-1] |= 0x80; | |
| tc[n] = tc[n] >> 1; | |
| } | |
| if(current_bit == 1) | |
| tc[7] |= 0x80; | |
| } | |
| total_bits++; | |
| } | |
| if (total_bits == end_smpte_position) // we have the 80th bit | |
| { | |
| total_bits = 0; | |
| if (tc_sync) | |
| { | |
| tc_sync = false; | |
| valid_tc_word = true; | |
| } | |
| } | |
| else | |
| { | |
| frateend = 0; | |
| } | |
| if (valid_tc_word) | |
| { | |
| valid_tc_word = false; | |
| numBadFrames = 0; | |
| timeCode[10] = (tc[0]&0x0F)+0x30; // frames | |
| timeCode[9] = (tc[1]&0x03)+0x30; // 10's of frames | |
| timeCode[8] = '.'; | |
| timeCode[7] = (tc[2]&0x0F)+0x30; // seconds | |
| timeCode[6] = (tc[3]&0x07)+0x30; // 10's of seconds | |
| timeCode[5] = ':'; | |
| timeCode[4] = (tc[4]&0x0F)+0x30; // minutes | |
| timeCode[3] = (tc[5]&0x07)+0x30; // 10's of minutes | |
| timeCode[2] = ':'; | |
| timeCode[1] = (tc[6]&0x0F)+0x30; // hours | |
| timeCode[0] = (tc[7]&0x03)+0x30; // 10's of hours | |
| userBit[7] = ((tc[0]&0xF0)>>4)+0x30; // user bits 8 | |
| userBit[6] = ((tc[1]&0xF0)>>4)+0x30; // user bits 7 | |
| userBit[5] = ((tc[2]&0xF0)>>4)+0x30; // user bits 6 | |
| userBit[4] = ((tc[3]&0xF0)>>4)+0x30; // user bits 5 | |
| userBit[3] = ((tc[4]&0xF0)>>4)+0x30; // user bits 4 | |
| userBit[2] = ((tc[5]&0xF0)>>4)+0x30; // user bits 3 | |
| userBit[1] = ((tc[6]&0xF0)>>4)+0x30; // user bits 2 | |
| userBit[0] = ((tc[7]&0xF0)>>4)+0x30; // user bits 1 | |
| //we need to skip ASCII 0x3A to 0x40 | |
| int i; | |
| for (i = 0; i < 8; i = i + 1) { | |
| if (userBit[i] > 0x39) { | |
| userBit[i] = userBit[i]+0x7; | |
| } | |
| } | |
| drop_frame_flag = bit_is_set(tc[1], 2); | |
| //some sanity checking: | |
| if (timeCode[0] < 0x33) | |
| { | |
| write_tc_out = true; | |
| //lay the groundwork for averaging framerate calcs | |
| if (frateend < fratest) | |
| { | |
| frateend = frateend + (microsmax - fratest); | |
| fratest = 0; | |
| } | |
| if (framertct == numofframetime) { | |
| framertct = 0; | |
| } | |
| frame_time[framertct] = frateend - fratest; | |
| framertct = framertct + 1; | |
| } | |
| } | |
| } | |
| } | |
| void setup() | |
| { | |
| #ifndef __AVR_ATtiny85__ | |
| //Serial.println("7 Segment Backpack Test"); | |
| #endif | |
| matrix.begin(0x70); | |
| matrix.clear(); | |
| matrix.writeDisplay();//clear the display | |
| Serial.begin (115200); | |
| pinMode(icpPin, INPUT); // ICP pin (digital pin 8 on arduino) as input | |
| pinMode(brightPin,INPUT); //deal with brightness | |
| delay(5); //do we need to delay? | |
| t.every (checkBattInterval, checkBatt); | |
| if (digitalRead(brightPin)) | |
| { | |
| matrix.setBrightness(fullBright); | |
| } | |
| else | |
| { | |
| matrix.setBrightness(halfBright); | |
| } | |
| // Setup button timers (all in milliseconds / ms) | |
| // (These are default if not set, but changeable for convenience) | |
| button1.debounceTime = 20; // Debounce timer in ms | |
| button1.multiclickTime = 250; // Time limit for multi clicks | |
| button1.longClickTime = 1000; // time until "held-down clicks" register | |
| bit_time = 0; | |
| valid_tc_word = false; | |
| ones_bit_count = false; | |
| tc_sync = false; | |
| write_tc_out = false; | |
| drop_frame_flag = false; | |
| total_bits = 0; | |
| current_bit = 0; | |
| sync_count = 0; | |
| totalframetime = 0; | |
| fratest = 0; | |
| frateend = 0; | |
| framertct = 0; | |
| TCCR1A = B00000000; // clear all | |
| TCCR1B = B11000010; // ICNC1 noise reduction + ICES1 start on rising edge + CS11 divide by 8 | |
| TCCR1C = B00000000; // clear all | |
| TIMSK1 = B00100000; // ICIE1 enable the icp | |
| TCNT1 = 0; // clear timer1 | |
| } | |
| void frame_rate() | |
| { | |
| totalframetime = 0; | |
| int i; | |
| for (i = 0; i < numofframetime; i++) | |
| { | |
| totalframetime = totalframetime + frame_time[i] + fratecal; | |
| } | |
| if (totalframetime != 0) | |
| { | |
| frate = float(1.0 / totalframetime * (numofframetime * 1000000.0)) ; | |
| } | |
| else | |
| { | |
| frate = 0.0; | |
| } | |
| } | |
| void loop() | |
| { | |
| // Update button state | |
| button1.Update(); | |
| if (button1.depressed==false && !latchTCDisp) //if the button is now released, and we're not latched.... | |
| { | |
| matrix.clear(); | |
| matrix.writeDisplay(); //....clear the display | |
| } | |
| if (!write_tc_out) | |
| { | |
| numBadFrames++ ; | |
| } | |
| if ((write_tc_out && button1.depressed==true) || (write_tc_out && latchTCDisp)) //if there's valid timecode and the button is pressed, there's valid tc and we are in a latch state | |
| { | |
| write_tc_out = false; | |
| if (disp_fr < disp_time_fr ) | |
| { | |
| disp_fr ++; | |
| matrix.writeDigitNum(0,tc[3]&0x07); | |
| matrix.writeDigitNum(1, tc[2]&0x0F); | |
| matrix.writeDigitRaw(2,adaColon); | |
| matrix.writeDigitNum(3, tc[1]&0x03); | |
| matrix.writeDigitNum(4, tc[0]&0x0F); | |
| matrix.writeDisplay(); | |
| } | |
| else | |
| { | |
| if (disp_min < disp_time_min) | |
| { | |
| disp_min ++; | |
| matrix.writeDigitNum(0,tc[7]&0x03); | |
| matrix.writeDigitNum(1, tc[6]&0x0F); | |
| matrix.writeDigitRaw(2,adaClearColon); | |
| matrix.writeDigitNum(3, tc[5]&0x07); | |
| matrix.writeDigitNum(4, tc[4]&0x0F); | |
| matrix.writeDisplay(); | |
| } | |
| else | |
| { | |
| disp_min = 0; | |
| disp_fr = 0; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| if ((numBadFrames > 10000 && button1.depressed == true) || (numBadFrames > 10000 && latchTCDisp)) //if there's no incoming tc and the button is pressed or we are latched on then display the voltage | |
| { | |
| int volts100 = getBattVolt()*100 + voltOffset; | |
| smoothValue(volts100); | |
| displayBattVolt (smoothed); | |
| //Serial.println(volts100); | |
| } | |
| } | |
| if (button1.clicks ==2) { //if we're doubleclicked | |
| latchTCDisp = !latchTCDisp; | |
| } | |
| /*debugging | |
| //spit out the tc value to the USB/Serial port: | |
| int i; | |
| for (i = 0; i < 11; i = i + 1) { | |
| Serial.print(timeCode[i]); | |
| } | |
| Serial.print(" "); | |
| //and spit out user bits | |
| for (i = 0; i < 8; i = i + 1) { | |
| Serial.print(userBit[i]); | |
| } | |
| Serial.print(" "); | |
| frame_rate(); | |
| Serial.print(frate); | |
| Serial.print(" "); | |
| Serial.print(bittimeoff); | |
| Serial.println(); | |
| */ | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment