Go Down

Topic: Multiplexed 7-segments. Can this code be faster? (Read 2777 times) previous topic - next topic

thetaco

Mar 18, 2012, 08:13 pm Last Edit: Mar 18, 2012, 08:26 pm by thetaco Reason: 1
I've written a minutes/seconds countdown timer that sounds an audible alarm when the time reaches zero and has a "disarm" button that can halt the countdown. I'm going to use this for "diffuse the bomb" airsoft battles. It works as I want, but the display is a little dim. It's not bad, but I would like it to be brighter.

I know that speeding up loop() is going to get me the brightness that I'd like. Do you have any hints on streamlining the logic in loop() or have I reached the maximum reasonable brightness that one would expect when multiplexing four displays in parallel? What about alloff() ?

loop()
Code: [Select]
void loop (){

 switch (digitalRead(buttonPin)){ // read disarm button state
 case 0: // button is not held down.
   previousMillis = millis();      // keeps millis in sync
   currentMillis = previousMillis; // when button is open

 case 1: // button is held down
   currentMillis = millis(); // Grows away from previousMillis
                             // while button is held down.
 }

 // catches long press as soon as it crosses interval threshold.
 if(currentMillis - previousMillis > interval) { // long press?
   allOff();     // clear LEDS
   TIMSK1=0x00;  // stop timer interrupts
   while ( true ){ // LEDS off unconditionally.
   }
 }

 if (alarm == 1){ // countdown has reached zero
   PORTD = B1111111; // LED states cleared.
   digitalWrite(leftSecAnode,ON);  // ready for new LED states
   digitalWrite(rightSecAnode,ON); // ready for new LED states
   digitalWrite(rightMinAnode,ON); // ready for new LED states
   digitalWrite(leftMinAnode,ON);  // ready for new LED states
   while ( true ){   // blink G segments forever. Audible alarm comes later.
     digitalWrite(G,!digitalRead(G));
     delay(200);
   }

 }
 writeMinutes();
 writeSeconds();
}



Entire sketch
Code: [Select]
// Airsoft bomb utilizing timer1 interrupts
// Four digit, down timer. Able to count from 99m99s to 0m0s.

// Circuit description:
// Four 7-segment, common anode LEDS are connected in parallel.
// Multiplexing of display is achieved by switching the anodes
// on in sequence. Button input pins are tied low with 10Kohm
// resistors and go high when momentary push button (to 5V) is pressed.

// When power is applied initially, the program waits for user
// setup. Pressing the disarm/time-set button adds time, which
// is displayed on the 7 segment leds. Once the desired time has
// been set, the user presses the arm button and the timer begins
// counting down to zero.

// when the count reaches zero, the alarm goes off
// if the disarm button is depressed for more the defined
// interval, timer1 interrupt is disabled and the LEDs
// are cleared. If count reaches zero without being disarmed,
// then timer interrupt is disabled, LEDS cleared, middle LED
// segments flashes unconditionally.





// Common anode. LED on when pin is low.
// Anodes switched by PNP transistors, so
//   low on the anode is also on.

// Map segments to arduino pins. Not needed once
// alarm routine uses audible alarm instead of
// blinking led segment G.
const int A = 0;
const int B = 1;
const int C = 2;
const int D = 3;
const int E = 4;
const int F = 5;
const int G = 6;

const int buttonPin = 12; // Input pin for disarm button.

int alarm = 0; // set to 1 when countdown reaches zero

long previousMillis = 0; // synced with currentMillis if button is up.
unsigned long currentMillis = 0; // grows away from previousMillis
// when button is down

long interval = 2000; // how long the button must be pressed to disarm

// Common anode;
// on when pin is low
// and off when pin is high
const int ON = LOW;
const int OFF = HIGH;

int leftSecAnode = 8; // PNP switched, so LOW = on
int rightSecAnode = 9; // PNP switched, so LOW = on
int leftMinAnode = 10; // PNP switched, so LOW = on
int rightMinAnode = 11; // PNP switched, so LOW = on

int segBytes[] = {/* seg A is byte 6. seg G is byte 0.
__ABCDEFG There is no DP or colon on my displays */
 B1000000, // 0
 B1111001, // 1
 B0100100, // 2
 B0110000, // 3
 B0011001, // 4
 B0010010, // 5
 B0000011, // 6
 B1111000, // 7
 B0000000, // 8
 B0010000  // 9
};

// initial state. Time must be added by user.
int minutes = 0;
int seconds = 0;

// These are set by calcDigits()
int secLeft;
int secRight;
int minLeft;
int minRight;


////////////// Timer interrupt routine /////////////////

ISR(TIMER1_OVF_vect) { // initialize timer1
 TCNT1=0x0BDC; // set initial value to remove time error (16bit counter register)
 if (digitalRead(buttonPin) == 0){ // halt countdown while disarm button is down
   switch (seconds || minutes){
   case 0: // seconds and minutes are both zero.
     alarm = 1;
     break;
   default:
     if (seconds == 0){
       minutes--;
       seconds = 59;
       calcDigits();
       break;
     }
     seconds--;
     calcDigits();
     break;
   }
 }
}

///////////////////////////////////////////////////
//////////////// setup () /////////////////////////
///////////////////////////////////////////////////

void setup (){

 int armed = 0; // set to 1 once time to count down has been set
 int armButton = 13; // press this button to start countdown

 DDRD = B11111111; // PORTD pins are outputs.
 PORTD = B11111111; // start with LEDS off.

 pinMode(leftSecAnode,OUTPUT);
 digitalWrite(leftSecAnode,OFF);

 pinMode(rightSecAnode,OUTPUT);
 digitalWrite(rightSecAnode,OFF);
 
 pinMode(leftMinAnode, OUTPUT);
 digitalWrite(leftMinAnode, OFF);
 
 pinMode(rightMinAnode, OUTPUT);
 digitalWrite(rightMinAnode, OFF);

 pinMode(armButton, INPUT); // arm button
 pinMode(buttonPin, INPUT); // time-set/disarm button

 // Time must be set and bomb armed before counting down begins.
 while (armed == 0){  
   calcDigits();
   writeMinutes();
   writeSeconds();
   if ( digitalRead(buttonPin) == 1 ){
     minutes = minutes + 1; // add one minute every time button is pressed.
     delay(200); // simple debounce
   }
   if ( digitalRead(armButton) == 1){
     armed = 1; // exits the arming loop and begins countdown.
   }

 }

 TIMSK1=0x01; // enabled global and timer overflow interrupt;
 TCCR1A = 0x00; // normal operation page 148 (mode0);
 TCNT1=0x0BDC; // set initial value to remove time error (16bit counter register)
 TCCR1B = 0x04; // start timer/ set clock

}

///////////////////////////////////////////////////
/////////////////// loop() ////////////////////////
///////////////////////////////////////////////////
void loop (){

 switch (digitalRead(buttonPin)){ // read disarm button state
 case 0: // button is not held down.
   previousMillis = millis();      // keeps millis in sync
   currentMillis = previousMillis; // when button is open

 case 1: // button is held down
   currentMillis = millis(); // Grows away from previousMillis
                             // while button is held down.
 }

 // catches long press as soon as it crosses interval threshold.
 if(currentMillis - previousMillis > interval) { // long press?
   allOff();     // clear LEDS
   TIMSK1=0x00;  // stop timer interrupts
   while ( true ){ // LEDS off unconditionally.
   }
 }

 if (alarm == 1){ // countdown has reached zero
   PORTD = B1111111; // LED states cleared.
   digitalWrite(leftSecAnode,ON);  // ready for new LED states
   digitalWrite(rightSecAnode,ON); // ready for new LED states
   digitalWrite(rightMinAnode,ON); // ready for new LED states
   digitalWrite(leftMinAnode,ON);  // ready for new LED states
   while ( true ){   // blink G segments forever. Audible alarm comes later.
     digitalWrite(G,!digitalRead(G));
     delay(200);
   }

 }
 writeMinutes();
 writeSeconds();
}

//////// Function definitions: ///////////////
void allOff(){
 digitalWrite(rightSecAnode,OFF);
 digitalWrite(leftSecAnode,OFF);
 digitalWrite(rightMinAnode,OFF);
 digitalWrite(leftMinAnode,OFF);
}

void writeMinutes(){
 PORTD = segBytes[minLeft]; // display left digit
 digitalWrite(leftMinAnode, ON);
 allOff();
 PORTD = segBytes[minRight]; // display right digit
 digitalWrite(rightMinAnode, ON);
 allOff();
}

void writeSeconds(){
 PORTD = segBytes[secLeft]; // display left digit
 digitalWrite(leftSecAnode, ON);
 allOff();
 PORTD = segBytes[secRight]; // display right digit
 digitalWrite(rightSecAnode, ON);
 allOff();
}

void calcDigits(){
 secLeft = seconds / 10; // left digit
 secRight = seconds % 10; // right digit
 minLeft = minutes / 10; // left digit
 minRight = minutes % 10; // right digit
}

johnwasser

To get more brightness, spend more time with the LEDs on:

Code: [Select]

const unsigned long delayWhileLit = 1;  // Increase this until you get flickering, then reduce a step

void writeMinutes(){
  PORTD = segBytes[minLeft]; // display left digit
  digitalWrite(leftMinAnode, ON);
  delay(delayWhileLit);
  digitalWrite(leftMinAnode, OFF);
  PORTD = segBytes[minRight]; // display right digit
  digitalWrite(rightMinAnode, ON);
  delay(delayWhileLit);
  digitalWrite(leftMinAnode, OFF);
}

void writeSeconds(){
  PORTD = segBytes[secLeft]; // display left digit
  digitalWrite(leftSecAnode, ON);
  delay(delayWhileLit);
  digitalWrite(leftSecAnode, OFF);
  PORTD = segBytes[secRight]; // display right digit
  digitalWrite(rightSecAnode, ON);
  delay(delayWhileLit);
  digitalWrite(rightSecAnode, OFF);
}
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

thetaco

Oh, sure. Just go ahead and tackle the problem from the most simple and obvious angle. Sheesh.

Thank you, that was so obvious that it's no wonder I didn't think of it :)

Go Up