Reply To: Art Controller Adjustments

Home Evil Mad Scientist Forums Other kit and product support Art Controller Adjustments Reply To: Art Controller Adjustments

#27224
bafaction
Participant

I am using the relay to control a solenoid for a locking mechanism or a target face time for some target shooting events. One of the events requires a start and stop buzzer.

I had the original Art Controller file changed to give me a 3 sec delay when the start button has been pressed before the delay time is active. (Below is a copy of adjusted file) I have set up the delay time adjusts via a rotary binary switch. This allows me to select from 3 seconds up to 15 seconds delay time.

What I am trying to achieve is having another output from the art controller such as i/o PB3 to drive an external relay board which will activate the buzzer, But this relay drive has to be at the start of the delay time and at the end of the delay time and run for about half a second.

I hope this makes sense

/*
Title: artcon.c
Author: Windell H. Oskay
Date Created: 7/16/12
Last Modified: 9/13/12

the Art Controller relay board
Release version 1.0

Product info:
http://evilmadscience.com/productsmenu/tinykitlist/580

Documentation:
http://wiki.evilmadscience.com/Art_Controller

Target: Atmel ATtiny2313A MCU

Fuse configuration:
Use 8 MHz internal RC oscillator, with divide-by-8 clock prescaler: 1 MHz clock
BOD active at 2.7 V.

Fuses: -U lfuse:w:0x64:m -U hfuse:w:0xdb:m -U efuse:w:0xff:m

————————————————-
USAGE: How to compile and install

A makefile is provided to compile and install this program using AVR-GCC and avrdude.

To use it, follow these steps:
1. Update the header of the makefile as needed to reflect the type of AVR programmer that you use.
2. Open a terminal window and move into the directory with this file and the makefile.
3. At the terminal enter
make clean <return>
make all <return>
make install <return>
4. Make sure that avrdude does not report any errors. If all goes well, the last few lines output by avrdude
should look something like this:

avrdude: verifying …
avrdude: XXXX bytes of flash verified

avrdude: safemode: lfuse reads as 64
avrdude: safemode: hfuse reads as DB
avrdude: safemode: efuse reads as FF
avrdude: safemode: Fuses OK

avrdude done. Thank you.

If you a different programming environment, make sure that you copy over the fuse settings from the makefile.

*/

/*

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

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

*/

#include <avr/io.h> // device specific I/O definitions
#include <avr/interrupt.h>

// System clock : 1 MHz
// Set compare to once every 124 cycles– so every 124 microseconds
#define MICROSECONDS_PER_COMPARE 124

#define TurnCoilOn(); PORTB |= 16;
#define TurnCoilOff(); PORTB &= 239;

// Inputs: PA0, PA1
#define InputMaskA 3

// Inputs: PB0 – PB3
#define InputMaskB 15

// Inputs: PD0 – PD6
#define InputMaskD 127

//volatile variables: ones that may be modified in an ISR
volatile unsigned int timer0_microseconds;
volatile unsigned int timer0_millis;
volatile unsigned long timer0_seconds;

// Note: Seconds (timer0_seconds) will not overflow in realistic time periods.
// Maximum unsigned long is 2^32 – 1, or 4 294 967 295
// 4 294 967 295 seconds, or about 136 years.

unsigned long millis(void)
{ // Return total milliseconds ***since last timer reset***
// Will roll over after 49 days.

unsigned int mills;
unsigned long secs;
uint8_t oldSREG = SREG;

// disable interrupts while we read timer values or we might get an
// inconsistent value
cli();
mills = timer0_millis;
secs = timer0_seconds;
SREG = oldSREG;

secs = 1000 * secs + mills;

return secs;
}

unsigned long seconds(void)
{
unsigned long m;
uint8_t oldSREG = SREG;

// disable interrupts while we read timer0_seconds or we might get an
// inconsistent value (e.g. in the middle of a write to timer0_seconds)
cli();
m = timer0_seconds;
SREG = oldSREG;

return m;
}

void resetTimer(void)
{
uint8_t oldSREG = SREG;
cli();

// disable interrupts to avoid possible
// inconsistent values (e.g. in the middle of a write to timer0_millis)

timer0_microseconds = 0;
timer0_millis = 0;
timer0_seconds = 0;

SREG = oldSREG;
return;
}

unsigned long calculateStopTime (void)
{
unsigned long total = 0;
unsigned int temp = 1;

if ((PIND & _BV(5)) == 0)
total = 1;
if ((PIND & _BV(4))== 0)
total += 2;
if ((PIND & _BV(3)) == 0)
total += 4;
if ((PIND & _BV(2)) == 0)
total += 8;
if ((PINA & _BV(0)) == 0)
total += 16;

if (total == 0)
total = 1;

if ((PINA & _BV(1))== 0)
temp *= 6;
if ((PIND & _BV(1))== 0)
temp *= 10;
if ((PIND & _BV(0))== 0)
temp *= 60;

return total * temp;
}

int main (void)
{
unsigned long StopTime;
unsigned long debounceStartTime;

uint8_t Triggered;
uint8_t CoilOn;
uint8_t doCancel;
uint8_t debounced;
uint8_t TrigInLast;
uint8_t TrigIn;

DDRA = 0;
DDRB = _BV(4); // Set line B4 to be an output, the rest are inputs.
DDRD = 0;

// Pull-ups on inputs:
PORTA = InputMaskA;
PORTB = InputMaskB;
PORTD = InputMaskD;

CLKPR = (1 << CLKPCE); // enable clock prescaler update
CLKPR = 0; // set clock to maximum

WDTCSR = 0x00; // disable watchdog timer

// Set up the timer interrupt:

TCCR0A = 2;
OCR0A = 128;

TIFR = (1 << TOV0); // clear interrupt flag
TIMSK = (1 << OCIE0A); // enable compare interrupt
TCCR0B = (1 << CS01); // start timer, prescale by 8

asm(“sei”); // ENABLE global interrupts

uint8_t pinbCopy = PINB;

resetTimer();
StopTime = calculateStopTime();

if ((pinbCopy & 1) && ((pinbCopy & 2) == 0)) {
// If Cancel is false (b0 is high) and trigger at reset is true (B1 is low), trigger… Now!
TurnCoilOn();
Triggered = 1;
CoilOn = 1;

}
else
{
TurnCoilOff();
Triggered = 0;
CoilOn = 0;
}

debounced = 0;
debounceStartTime = 0;

TrigInLast = ((PIND & _BV(6)) == 0);

for (;;) { // main loop

TrigIn = ((PIND & _BV(6)) == 0); // 1 if trigger input is asserted (trigger pin is grounded). Zero otherwise.
doCancel = 0;

if ( TrigIn && (TrigInLast == 0) && (debounced > 1))
{ // Legitimate button press/input signal detected.

// Check for new trigger:
if (Triggered == 0)
{
if (PINB & 1) // Make sure that cancel pin is HIGH (not active):
{
resetTimer();
StopTime = 3;
while ( seconds () < StopTime)
{}
resetTimer();
StopTime = calculateStopTime();
TurnCoilOn();
Triggered = 1;
CoilOn = 1;
}
}
else if ((PINB & _BV(2)) == 0) // If start/stop on trig is selected (low)
{
doCancel = 1;
}
}

if ( TrigIn == 0 ){
if (TrigInLast) // Trig in button/signal just released
{
debounceStartTime = millis();
debounced = 1; // Intermediate Step
}
else
{
if ((millis() – debounceStartTime) > 50) // Trigger input released for 50 ms: “released”
{
debounced = 2; // Debouncing routine complete.
}

}
}

if (TrigIn)
{ //Input is asserted; reset debounce counter.
debounced = 0;
}

if (Triggered)
{

if ((PINB & _BV(0)) == 0) // If Cancel signal is asserted…
{
doCancel = 1;
}

if (seconds() >= StopTime) { // If time has run out
if (PINB & _BV(3))
{ // Repeat mode is off.
doCancel = 1;
}
else
{
// Repeat mode is ON; begin the next part of the cycle.
resetTimer();
StopTime = calculateStopTime();

if (CoilOn) {
TurnCoilOff();
CoilOn = 0;
}
else {
TurnCoilOn();
CoilOn = 1;
}
}
}

if (doCancel)
{
TurnCoilOff();
Triggered = 0;
CoilOn = 0;
}
}

TrigInLast = TrigIn;

} //End main loop
return 0;
}

SIGNAL (TIMER0_COMPA_vect) {
timer0_microseconds += MICROSECONDS_PER_COMPARE;
if (timer0_microseconds > 1000) {
timer0_millis++;
timer0_microseconds -= 1000;

if (timer0_millis > 1000) {
timer0_seconds++;
timer0_millis -= 1000;
}
}

}