Code Help and Battery Question!

Store Forums Defusable Clock General Discussion Code Help and Battery Question!

Viewing 5 posts - 1 through 5 (of 5 total)
  • Author
    Posts
  • #618
    packe
    Member

    Hi everyone!

    First out, can I run the clock with either a 11.1V LiPo battery or a 7.4V LiPo battery? Or does it have to be a 9V/9.6V NiMh/NiCd? Don’t want to brake this fine piece of craftsmanship 😀

    Second, I know that Michael does not do coding for free anymore, but I though that if someone else could help me, or even Michael could I would be very glad.

    But is it possible to combine these 2 codes (viewtopic.php?f=33&t=2682 ) & (viewtopic.php?f=33&t=2491 )

    I.e. get the 24 hour clock with 00:00 after detonation, but with the “remember last detonation time” function.

    I tried to combine them, but it does not matter which way, I always end up with the “does not exist in scope” (or what it says).

    Any ideas?

    I have absolutely no skills in coding so hence my possible simple problem.

    Regards Pascal

    #1661
    Michael
    Keymaster

    Yes, you can power it from a 11.1V battery. A 7.4V battery will probably also work, so give it a try. You won’t break anything.

    If you want help with your coding issue, post the exact error messages you are getting from the compiler.

    #1663
    packe
    Member

    Perfect! I will try with a 7.4V LiPo and return with my results.

    This is the coude I’m using.

    And I get this error: (Marked in red) (Edit: Could not make the text red)

    DefusableClock2.pde: In function ‘void countdown()’:
    DefusableClock2:369: error: ‘defaultCountdownSeconds’ was not declared in this scope

    If I delete it, I get no errors, but I suppose that this part is the part that saves my last detonation time?

    /*
    Defusable Clock Firmware
    Copyright (C) 2011 nootropic design, LLC
    All rights reserved.

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    Special version for Niklas in Sweden!

    When holding down the red DET button, you can use the MIN and HOUR
    buttons to increase the countdown time. To *decrease* the countdown
    time, also press the ALARM button while holding down the DET button.

    When you release the DET button, the countdown starts and this
    countdown value is the new default. It is written to EEPROM and
    is saved even if the power is disconnected.
    */

    #include

    #define CLOCK 2
    #define LATCH 3


    #define DATA 4
    #define COLON 13
    #define MIN_BUTTON 0
    #define HOUR_BUTTON 1
    #define DET_BUTTON 2
    #define ALARM_BUTTON 3
    #define MIN_BUTTON_PIN 9
    #define HOUR_BUTTON_PIN 10
    #define DET_BUTTON_PIN 12
    #define ALARM_BUTTON_PIN 15
    #define LED_PM 16
    #define LED_ALARM 17
    #define LED_TOP 18
    #define LED_DET 19
    #define BUZZER 11
    #define WIRE_1 5
    #define WIRE_2 6
    #define WIRE_3 7
    #define WIRE_4 8
    #define TIMER1_SECOND_START 49910
    #define COUNTDOWN_DURATION 10
    #define SNOOZE_MINUTES 9
    #define ALARM_OFF 0
    #define ALARM_ON 1
    #define ALARM_DET 2

    volatile byte hours = 12;
    volatile byte minutes = 0;
    volatile byte seconds = 0;
    volatile unsigned int countdownSeconds;
    volatile boolean ticked = false;
    boolean displayCountdown = false;
    boolean displayZeros = false;
    boolean countdownRunning = false;

    byte buttonPins[4] = {MIN_BUTTON_PIN, HOUR_BUTTON_PIN, DET_BUTTON_PIN, ALARM_BUTTON_PIN};
    byte buttonState[4] = {HIGH, HIGH, HIGH, HIGH};
    unsigned long buttonChange[4] = {0L, 0L, 0L, 0L};

    byte alarmHours = 12;
    byte alarmMinutes = 0;
    byte alarmMode = ALARM_OFF;
    volatile boolean alarmRinging = false;
    boolean displayAlarmTime = false;

    byte snoozeHours = 12;
    byte snoozeMinutes = 0;
    boolean snoozeActivated = false;

    boolean blank = false;

    volatile byte currentDigit = 0;

    void setup() {

    pinMode(CLOCK, OUTPUT);
    pinMode(LATCH, OUTPUT);
    pinMode(DATA, OUTPUT);
    pinMode(COLON, OUTPUT);
    digitalWrite(COLON, LOW);

    pinMode(LED_PM, OUTPUT);
    pinMode(LED_ALARM, OUTPUT);
    pinMode(LED_TOP, OUTPUT);
    pinMode(LED_DET, OUTPUT);
    pinMode(BUZZER, OUTPUT);

    pinMode(HOUR_BUTTON_PIN, INPUT);
    pinMode(MIN_BUTTON_PIN, INPUT);
    pinMode(ALARM_BUTTON_PIN, INPUT);
    pinMode(DET_BUTTON_PIN, INPUT);
    pinMode(WIRE_1, INPUT);
    pinMode(WIRE_2, INPUT);
    pinMode(WIRE_3, INPUT);
    pinMode(WIRE_4, INPUT);

    digitalWrite(HOUR_BUTTON_PIN, HIGH);
    digitalWrite(MIN_BUTTON_PIN, HIGH);
    digitalWrite(ALARM_BUTTON_PIN, HIGH);
    digitalWrite(DET_BUTTON_PIN, HIGH);
    digitalWrite(WIRE_1, HIGH);
    digitalWrite(WIRE_2, HIGH);
    digitalWrite(WIRE_3, HIGH);
    digitalWrite(WIRE_4, HIGH);

    // Read time from EEPROM
    hours = EEPROM.read(0);
    minutes = EEPROM.read(1);
    seconds = EEPROM.read(2);
    alarmHours = EEPROM.read(4);
    alarmMinutes = EEPROM.read(5);
    alarmMode = EEPROM.read(7);
    if ((hours == 0) || (hours > 23) || (alarmHours == 0) || (alarmHours > 23) || (minutes >= 60) || (alarmMinutes >= 60) || (alarmMode > ALARM_DET)) {
    // invalid data in EEPROM (first time power up)
    hours = 12;
    minutes = 0;
    seconds = 0;
    alarmHours = 12;
    alarmMinutes = 0;
    alarmMode = ALARM_OFF;
    }



    // Initialize timers.
    // Timer1 is used to keep the clock time
    // Timer2 is used for the display multiplexing

    // Disable the timer overflow interrupt
    TIMSK2 &= ~(1 << TOIE2);

    // Set timer2 to normal mode
    TCCR2A &= ~((1 << WGM21) | (1 << WGM20));
    TCCR2B &= ~(1 << WGM22);

    // Use internal I/O clock
    ASSR &= ~(1 << AS2);

    // Disable compare match interrupt
    TIMSK2 &= ~(1 << OCIE2A);

    // Prescalar is clock divided by 128
    TCCR2B |= (1 << CS22);
    TCCR2B &= ~(1 << CS21);
    TCCR2B |= (1 << CS20);

    // Start the counting at 0
    TCNT2 = 0;

    // Enable the timer2 overflow interrupt
    TIMSK2 |= (1 << TOIE2);


    // init timer1
    // set prescaler to 1024
    TIMSK1 &= ~(1< TCCR1A = 0;
    TCCR1B = (1< TIMSK1 |= (1< // With prescalar of 1024, TCNT1 increments 15,625 times per second
    // 65535 - 15625 = 49910
    TCNT1 = TIMER1_SECOND_START;

    randomSeed(analogRead(0));
    }

    void loop() {

    if (ticked) {
    ticked = false;
    // write info to EEPROM
    EEPROM.write(0, hours);
    EEPROM.write(1, minutes);
    EEPROM.write(2, seconds);
    EEPROM.write(4, alarmHours);
    EEPROM.write(5, alarmMinutes);
    EEPROM.write(7, alarmMode);
    }

    if (alarmRinging) {
    if (alarmMode == ALARM_ON) {
    ringAlarm();
    }
    if (alarmMode == ALARM_DET) {
    for(int i=0;i<4;i++) {
    beep(3900, 250, false);
    delay(250);
    }
    displayCountdown = true;
    countdownSeconds = COUNTDOWN_DURATION;
    countdown();
    alarmRinging = false;
    }
    }

    delay(10); // this helps with button debouncing

    // check input
    if (buttonPressed(ALARM_BUTTON)) {
    displayAlarmTime = true;
    if (alarmMode == ALARM_OFF) {
    digitalWrite(LED_ALARM, LOW);
    digitalWrite(LED_DET, LOW);
    } else {
    digitalWrite(LED_ALARM, HIGH);
    if (alarmMode == ALARM_DET) {
    digitalWrite(LED_DET, HIGH);
    } else {
    digitalWrite(LED_DET, LOW);
    }
    }
    } else {
    displayAlarmTime = false;
    digitalWrite(LED_ALARM, LOW);
    digitalWrite(LED_DET, LOW);
    }

    if (buttonPressedNew(HOUR_BUTTON) || buttonHeld(HOUR_BUTTON, 150)) {
    if ((!displayAlarmTime) && (!displayCountdown)) {
    hours++;
    if (hours == 24) {
    hours = 0;
    }
    }
    if (displayAlarmTime) {
    // setting the alarm
    alarmHours++;
    if (alarmHours == 24) {
    alarmHours = 0;
    }
    snoozeHours = alarmHours;
    snoozeMinutes = alarmMinutes;
    }
    if (displayCountdown) {
    if (countdownSeconds < 5940) {
    countdownSeconds += 60;
    }
    }
    }

    if (buttonPressedNew(MIN_BUTTON) || buttonHeld(MIN_BUTTON, 150)) {
    if ((!displayAlarmTime) && (!displayCountdown)) {
    minutes++;
    if (minutes == 60) {
    minutes = 0;
    }
    seconds = 0;
    TCNT1 = TIMER1_SECOND_START;
    }
    if (displayAlarmTime) {
    // setting the alarm
    alarmMinutes++;
    if (alarmMinutes == 60) {
    alarmMinutes = 0;
    }
    snoozeHours = alarmHours;
    snoozeMinutes = alarmMinutes;
    }
    if (displayCountdown) {
    if (countdownSeconds < 5999) {
    countdownSeconds++;
    }
    }
    }

    if (buttonPressedNew(DET_BUTTON)) {
    if (displayAlarmTime) {
    alarmMode++;
    if (alarmMode > ALARM_DET) {
    alarmMode = ALARM_OFF;
    }
    if (alarmMode == ALARM_OFF) {
    snoozeActivated = false;
    }
    return;
    }
    if (displayZeros) {
    displayZeros = false;
    return;
    }
    // The DET button has been pressed but not released yet.
    displayCountdown = true;
    countdownSeconds = COUNTDOWN_DURATION;
    }

    if (!buttonPressed(DET_BUTTON)) {
    if (displayCountdown) {
    countdown();
    }
    }

    }


    void ringAlarm() {
    int frequency = 3900;
    int duration = 250; // each beep is .25s
    int us = 1000000 / frequency / 2;
    int toneLoopCount = (duration * ((float)frequency/1000.0));
    int pauseLoopCount = 20000;

    while (alarmRinging) {
    for(int i=0;i PORTB |= (1 << 3);
    if (buttonPressed(ALARM_BUTTON)) {
    alarmRinging = false;
    snoozeActivated = false;
    break;
    }
    delayMicroseconds(us);
    PORTB &= ~(1 << 3);
    if (buttonPressed(DET_BUTTON)) {
    alarmRinging = false;
    snooze();
    break;
    }
    delayMicroseconds(us);
    }

    for(int i=0;i if (buttonPressed(ALARM_BUTTON)) {
    alarmRinging = false;
    snoozeActivated = false;
    break;
    }
    if (buttonPressed(DET_BUTTON)) {
    alarmRinging = false;
    snooze();
    break;
    }
    }
    } // while (alarmRinging)
    }

    void snooze() {
    snoozeActivated = true;


    // set the snooze time to current time plus 9 minutes
    snoozeHours = hours;
    snoozeMinutes = minutes + SNOOZE_MINUTES;
    if (snoozeMinutes >= 60) {
    snoozeMinutes -= 60;
    snoozeHours++;
    if (snoozeHours == 24) {
    snoozeHours = 0;
    }
    }
    }

    void countdown() {
    int ledCounter = 0;
    int ledCounterThreshold = 100000;
    byte ledCurrentState = HIGH;
    byte defusePin;
    byte detPin;
    boolean defused = false;
    countdownRunning = true;
    int fractionalSecond;

    // Write countdownSeconds value to EEPROM
    defaultCountdownSeconds = countdownSeconds;
    EEPROM.write(8, (defaultCountdownSeconds >> 8));
    EEPROM.write(9, (defaultCountdownSeconds & 0xFF));


    // assign random pins
    defusePin = random(WIRE_1, (WIRE_4+1));
    detPin = defusePin;
    while (detPin == defusePin) {
    detPin = random(WIRE_1, (WIRE_4+1));
    }

    digitalWrite(LED_PM, LOW); // turn off the PM LED

    // Keep track of how far we are into the current
    // second so we can correct later.
    fractionalSecond = TCNT1 - TIMER1_SECOND_START;

    // Reset back to the last second boundary so we can start the countdown
    // immediately and so that the first second isn't truncated
    TCNT1 = TIMER1_SECOND_START;

    beep(3800, 30);
    digitalWrite(LED_DET, ledCurrentState);
    while ((countdownSeconds > 0) && (!defused)) {
    for(int i=0;i<10000;i++) {
    // get input
    if (digitalRead(defusePin) == HIGH) {
    defused = true;
    break;
    }
    if (digitalRead(detPin) == HIGH) {
    countdownSeconds = 0;
    break;
    }
    }
    delay(20);
    if (ledCounter++ > ledCounterThreshold) {
    ledCounter = 0;
    if (ledCurrentState == HIGH) {
    ledCurrentState = LOW;
    } else {
    ledCurrentState = HIGH;
    }
    digitalWrite(LED_DET, ledCurrentState);
    }
    }
    digitalWrite(LED_DET, LOW);
    countdownRunning = false;
    if (!defused) {
    detonate();
    } else {
    beep(4500, 80);
    delay(2000);
    displayCountdown = false;
    }

    // Now to keep the time accurate, add back in the fractional
    // second that we took off when we started the countdown sequence.
    // Wait until we can add it back to TCNT1 without overflowing.
    while (TCNT1 >= (65535 - fractionalSecond));
    TCNT1 += fractionalSecond;
    }

    void detonate() {
    for(int i=0;i<8;i++) {
    digitalWrite(LED_DET, HIGH);
    beep(5000, 50, false);
    delay(25);
    digitalWrite(LED_DET, LOW);
    delay(25);
    }

    blank = true;

    for(int i=0;i<50;i++) {
    digitalWrite(random(LED_PM, LED_DET+1), HIGH);
    digitalWrite(random(LED_PM, LED_DET+1), HIGH);
    for(int j=0;j<5;j++) {
    beep(random(100, 300), 10);
    }
    for(int led=LED_PM;led<=LED_DET;led++) {
    digitalWrite(led, LOW);
    }
    }
    delay(2000);
    displayCountdown = false;
    blank = false;
    }

    // return true if the button is pressed.
    boolean buttonPressed(byte button) {
    if (digitalRead(buttonPins[button]) == LOW) {
    // the button is currently pressed
    if (buttonState[button] == HIGH) {
    // if the button was not pressed before, update the state.
    buttonChange[button] = millis();
    buttonState[button] = LOW;
    }
    return true;
    } else {
    // The button is currently not pressed
    if (buttonState[button] == LOW) {
    // if the button was pressed before, update the state.
    buttonChange[button] = millis();
    buttonState[button] = HIGH;
    }
    return false;
    }
    }

    // return true if the button is pressed and it is a new press (not held)
    boolean buttonPressedNew(byte button) {
    if (digitalRead(buttonPins[button]) == LOW) {
    // The button is currently pressed
    if (buttonState[button] == HIGH) {
    // This is a new press.
    buttonChange[button] = millis();
    buttonState[button] = LOW;
    return true;
    }
    // This is not a new press.
    return false;
    } else {
    // The button is currently not pressed
    if (buttonState[button] == LOW) {
    buttonChange[button] = millis();
    buttonState[button] = HIGH;
    }
    return false;
    }
    }

    // return true if the button is pressed and has been held for at least n milliseconds
    boolean buttonHeld(byte button, int n) {
    if (digitalRead(buttonPins[button]) == LOW) {
    // the button is currently pressed
    if (buttonState[button] == HIGH) {
    // if the button was not pressed before, update the state and return false.
    buttonChange[button] = millis();
    buttonState[button] = LOW;
    return false;
    }
    if ((millis() - buttonChange[button]) >= n) {
    // the button has been pressed for over n milliseconds.
    // update the state change time even though the state hasn't changed.
    // we update the state change time so we can start the counting over
    buttonChange[button] = millis();
    return true;
    }
    // The button is being held, but has not been held for longer than n milliseconds.
    return false;
    } else {
    // The button is currently not pressed
    if (buttonState[button] == LOW) {
    // if the button was pressed before, update the state.
    buttonChange[button] = millis();
    buttonState[button] = HIGH;
    }
    return false;
    }
    }

    void beep(int frequency, int duration) {
    beep(frequency, duration, true);
    }

    void beep(int frequency, int duration, boolean disableDisplayInterrupt) {
    int us = 1000000 / frequency / 2;
    int loopCount = (duration * ((float)frequency/1000.0));
    if (disableDisplayInterrupt) {
    TIMSK2 &= ~(1 << TOIE2);
    }
    for(int i=0;i PORTB |= (1 << 3);
    delayMicroseconds(us);
    PORTB &= ~(1 << 3);
    delayMicroseconds(us);
    }
    TIMSK2 |= (1 << TOIE2);
    }


    // This is the display interrupt to implement multiplexing of the digits.
    ISR(TIMER2_OVF_vect) {
    byte nDigits = 4;
    byte data;
    byte digitValue;
    byte displayHours, displayMinutes;

    TCNT2 = 0;

    displayHours = hours;
    displayMinutes = minutes;
    if (displayAlarmTime) {
    displayHours = alarmHours;
    displayMinutes = alarmMinutes;
    }
    if (displayCountdown) {
    displayHours = countdownSeconds / 60;
    displayMinutes = countdownSeconds % 60;
    }

    if ((displayHours < 10) && (!displayCountdown)) {
    nDigits = 3;
    }


    if (++currentDigit > (nDigits-1)) {
    currentDigit = 0;
    }

    switch (currentDigit) {
    case 0:
    digitValue = displayMinutes % 10;
    break;
    case 1:
    digitValue = displayMinutes / 10;
    break;
    case 2:
    digitValue = displayHours % 10;
    break;
    case 3:
    digitValue = displayHours / 10;
    break;
    }

    // Upper 4 bits of data are the value for the current digit.
    // They are loaded into shift register outputs QA-QD
    data = (digitValue << 4);

    // Lower 4 bits 3-0 represent which digit to turn on.
    // 3 is most significant digit, 0 is least
    // They are loaded into shift register outputs QE-QH
    // Digit transistors are active low, so set them all high
    data |= 0x0F;

    if (!blank) {
    // now turn off the bit for digit we want illuminated.
    data &= ~(1 << currentDigit);
    }

    digitalWrite(LATCH, LOW);
    shiftOut(DATA, CLOCK, LSBFIRST, data);
    digitalWrite(LATCH, HIGH);
    }


    // Timer 1 interrupt. This executes every second.
    ISR(TIMER1_OVF_vect) {
    TCNT1 = TIMER1_SECOND_START;

    ticked = true;
    seconds++;
    if (seconds == 60) {
    seconds = 0;
    minutes++;
    if (minutes == 60) {
    minutes = 0;
    hours++;
    if (hours == 24) {
    hours = 0;
    }
    }
    }

    if ((!countdownRunning) && (alarmMode != ALARM_OFF)) {
    if ((alarmHours == hours) && (alarmMinutes == minutes) && (seconds == 0)) {
    alarmRinging = true;
    }
    if ((snoozeActivated) && (snoozeHours == hours) && (snoozeMinutes == minutes) && (seconds == 0)) {
    alarmRinging = true;
    }
    }

    if ((countdownRunning) && (countdownSeconds > 0)) {
    beep(3800, 30);
    countdownSeconds--;
    }
    }
    #1665
    Michael
    Keymaster

    You are using a variable that is never declared. Whichever program you got that line of code from, you need to carefully study how that program works and ensure that you are duplicating the right logic, including the variable declarations. Make sense?

    #1667
    packe
    Member

    It makes sense but I have no idea how to do it, since I have no coding skills.

    I am using the Andruino IDE(?) or is it IED? The one you linked to on your products page.

    And then I just copied your other codes and tried to combine them, which did not go as planed 😛

Viewing 5 posts - 1 through 5 (of 5 total)
  • You must be logged in to reply to this topic.