Skip to content

Instantly share code, notes, and snippets.

@gothamsound
Created January 2, 2014 06:59
Show Gist options
  • Select an option

  • Save gothamsound/8215851 to your computer and use it in GitHub Desktop.

Select an option

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
#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