/*
Copyright (C) 2016-2019, Ernst Jung
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 3 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, see .
Correspondence concerning this program can be directed to
dr.ernstjung@gmail.com
*/
#define VERSION "21-usb, Apr 12 2019"
#include
#include
#include
#include
// -- Pulse generator code for following hardware:
// - Arduino Uno or Nano
// - MCP4131 digital potentiometer
//
// Connections:
// MCP4131 pin -> Arduino pin
// 1 -> D4 (CS)
// 2 -> D13 (SCK)
// 3 -> D11 (SDI/SDO)
// 4 -> GND (Vss)
// 5 -> D2 (P0A)
// 6 (P0W, output)
// 7 -> GND (P0B)
// 8 -> 5V (Vdd)
//
// Other Arduino pins for shield:
// D6 for switching driver
// D7 for discharging capacitor
// A0 for selecting pulse generating function
// A1-A5 other analog inputs
//
// Other Arduino pins for control switches:
// D3, D5, D8, D9, D10, D12 reserved
//
// Used in prototype:
// D3 -> Start, via int.1
// D5 -> S5
// D8 -> S4
// D9 -> S3,
// D10 -> S2
//
// Timing parameters:
// clock frequency = 16 MHz
// TIMER1 with f/256 prescaler:
// scaled frequency = 62.5 kHz
// scaled period = 16 us
// maximum delay = 1.05 s
// TIMER2 with f/128 prescaler:
// scaled frequency = 125 kHz
// scaled period = 8 us
// maximum delay = 2 ms
// TIMER0 not used:
// remains available to Arduino IDE timing functions.
// pulse parameter generating function prototype.
// functions of this type can modify volatile variables
// p_amplitude, p_interval and p_width
typedef void (*pulse_gen)(void);
// generator mode handling function prototype.
typedef void (*generator_function)(void);
// -- SPI (mcp4131 digital potentiometer)
byte address = 0x00; // address on chip
int CS = 4; // chip select pin
int PA = 2; // potentiometer high pin
volatile int p_amplitude=0; // potentiometer setting 0..128
volatile int cur_ampl=0; // current setting
volatile int pulsing=0; // pulses being generated
// -- pins
int driver_pin = 6; // driver
int cd_pin = 7; // capacitor discharge pin
// -- discharge time formula:
// t = -ln(V2/V1)/RC
// for 300 uF and 0.5 Ohm and 18 us per period that is 18.75
int cdtimes[20]={62, 56, 43, 35, 30, 25, 22, 19, 17, 14, 12, 11, 9, 8, 6, 5, 4, 3, 0, 0};
int ncdtimes=sizeof(cdtimes)/sizeof(int);
int cdflag = 0;
static bool running=false; // generator running?
float loop_delay=0.01; // seconds delay in loop function
// -- map 10-bit value from analog pin to a pulse interval
// according to a quadratic scale.
int map_interval(int adc_value)
{
float pval=adc_value*0.009775171065493646;
return 1./((4.98*pval*pval+2)*16e-6);
}
// -- initial timer parameters
volatile int c_width = 64; // capacitor charge time (1ms, TIMER1)
volatile int p_width = 25; // pulse time (200us, TIMER2)
volatile int cur_width=0; // current value
volatile int p_interval = 125; // delay until next pulse
// -- flag used by capacitor discharge code
volatile int pulsed = 0; // driver activated?
// -- ADC handler variables
volatile int anapin=0; // current analog input pin for multiplexer
volatile int analog[6]; // values from ADC
volatile int anamask[6]={1,1,1,1,1,1}; // pins to convert
// -- PC-interrupt handler variables
volatile byte portBstate, portBpast, changedbits=0;
int runstored=0; // currently running a stored setting;
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// -- collection of functions for setting pulse generating parameters
// -- basic pulse.
// parameters to be determined by generator
static void basic_pulse()
{
}
// -- constant frequency and amplitude pulses
// - frequency derived from pin A1
// - pulse width derived from pin A5
// - amplitude determined by generator function
static void constant_pulse()
{
p_interval = map_interval(analog[1]);
p_width = map(analog[5], 0, 1023, 3, 50); // 24us .. 400us
}
// -- high frequency and amplitude pulses
// - frequency derived from pin A1
// - pulse width derived from pin A5
// - amplitude determined by generator function
static void high_pulse()
{
p_interval = map_interval(1023); // highest frequency
p_width = 25; // 200us
p_amplitude = 96;
}
// -- varying width pulses
// - frequency derived from pin A1
// - pulse width from internal array 'widths'
// - amplitude determined by generator function
//
static void varwid_pulse()
{
static int widths[]={4, 16, 27, 38, 50};
static int nw = sizeof(widths)/sizeof(int);
static int index=0;
p_interval = map_interval(analog[1]);
p_width = widths[index];
index = (index+1)%nw;
}
// -- varying interval
// - base frequency derived from pin A1
// - pulse width derived from pin A5
// - amplitude determined by generator function
// - pulse interval varies randomly around interval corresponding
// to base frequency.
//
static void varintv_pulse()
{
p_interval = map_interval(analog[1]);
p_interval = max(random((0.75*p_interval),(1.25*p_interval)),125);
p_width = map(analog[5], 0, 1023, 3, 50); // 24us .. 400us
}
// -- "spread" interval
// - base frequency derived from pin A1
// - pulse width derived from pin A5
// - amplitude determined by generator function
// - pulse interval is spread around interval corresponding
// to base frequency.
//
static void spread_pulse()
{
// static float factors[]={0.667, 0.333, 0.333, 0.667}; // "reine kwint"
// static float factors[]={1.0, 0.8, 0.5, 0.1}; // "chirp"
static float factors[]={1.0, 0.5, 0.25, 0.125}; // "chirp"
static int n_factors=sizeof(factors)/sizeof(float);
static int index=0;
p_interval = map_interval(analog[1])*factors[index];
index = (index+1)%n_factors;
p_width = map(analog[5], 0, 1023, 3, 50); // 24us .. 400us
}
// -- random pulses
// - pulse interval derived from random value between A1 and A2
// - pulse width derived from random value between A4 and A5
// - amplitude derived from random value between A3 and 127
static void random_pulse()
{
int f1, f2, w1, w2;
f1 = min(analog[1], analog[2]);
f2 = max(analog[1], analog[2]);
w1 = min(analog[4], analog[5]);
w2 = max(analog[4], analog[5]);
p_interval = map_interval(random(f1, f2)); // min-max interval
p_width = map(random(w1, w2), 0, 1023, 3, 50); // min-max width
p_amplitude = random(analog[3]/8, 127); // min-max amplitude
}
// -- pattern
// pulse interval, width and amplitude from data in function
//
static void pattern_pulse()
{
static int seqno=0;
static int repeat=0;
struct impulse {
int interval; // periods until next timer compare
int amplitude; // potmeter wiper setting (0..128)
int width; // pulse width
int repeat; // repeat count
};
static impulse pattern[] = {
{ 500, 128, 50, 1}, // 8ms, max, 400us
{ 125, 128, 50, 1},
{ 125, 64, 25, 2}, // 2ms, half, 200us
{ 125, 64, 3, 2} // 2ms, half, 24us
};
int npattern = sizeof(pattern)/sizeof(impulse);
impulse pulse;
if (repeat==0) {
pulse = pattern[seqno];
repeat = pulse.repeat;
p_interval = pulse.interval;
p_amplitude = pulse.amplitude;
p_width = pulse.width;
seqno = (++seqno)%npattern;
}
repeat--;
}
static pulse_gen pulse_variants[]={constant_pulse, varwid_pulse, spread_pulse};
//static pulse_gen pulse_variants[]={spread_pulse};
static int nvariants=3;
static int variant=0;
volatile pulse_gen get_pulse_parameters=basic_pulse;
volatile pulse_gen constfreq_pulse=pulse_variants[variant];
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// -- generator functions
//
// -- zero amplitude pulses
static void generator_zero()
{
if (!running) {
p_interval = 12500; // 5 Hz
p_amplitude = 0;
pulsing = 0;
get_pulse_parameters = basic_pulse;
running = true;
// Serial.println("zero"); // TEST
}
}
// -- constant frequency pulses of maximum amplitude;
//
static void generator_constant()
{
static float amplitude=0.0, increment;
get_pulse_parameters = constfreq_pulse;
if (!running) {
p_amplitude = 0;
amplitude=0.0;
pulsing = 1;
running = true;
// Serial.println("constant"); // TEST
} else {
increment = loop_delay*128.0/(0.1+(float)(analog[2])/1.707);
amplitude = min(128.0, amplitude+increment);
p_amplitude = amplitude;
// pulsing = 1;
}
}
// -- repeatedly ramp amplitude up from base value to maximum, then drop
// to base value.
// pulses are generated by constfreq_pulse()
// period (0.1 to 10 seconds) from A4.
// base value (0..128) is derived from A3.
static void generator_ramp()
{
get_pulse_parameters = constfreq_pulse;
static float amplitude=0.0, increment, base;
if (!running) {
p_amplitude = 0;
pulsing = 1;
running = true;
// Serial.println("ramp"); // TEST
}
base = float(analog[3]/8); // map 0..1023 to 0..127
increment = loop_delay*(128.0-base)/(0.1+(float)(analog[4])/102.40);
amplitude = amplitude+increment;
if (amplitude>128.0) amplitude = base;
p_amplitude = amplitude;
}
// -- repeatedly ramp frequency up from the value from A1 to a second value
// from A2, then drop to the first value.
// Period (0.1 to 10 seconds) from A3.
// pulses are generated by basic_pulse() which obtains its parameters from
// this generator.
static void generator_chirp()
{
static float frequency, increment, f1, f2;
if (!running) {
p_amplitude = 128;
pulsing = 1;
frequency = analog[1];
get_pulse_parameters = basic_pulse;
running = true;
// Serial.println("chirp"); // TEST
}
f1 = analog[1];
f2 = analog[2];
increment = loop_delay*(f2-f1)/(0.1+(float)(analog[3])/102.40);
frequency += increment;
if (frequency>max(f1,f2) || frequencylimit) {
amplitude = 0.0;
p_amplitude = 128;
count = 0;
phase = 1;
} else {
increment = loop_delay*128.0/(0.1+(float)(analog[2])/102.40);
amplitude = amplitude+increment;
p_amplitude = amplitude;
}
break;
}
case 1: {
limit = (float)(analog[3]/102.40)/loop_delay;
if (++count>limit) {
p_amplitude = 0;
count = 0;
phase = 2;
}
break;
}
case 2: {
limit = (float)(analog[4]/102.40)/loop_delay;
if (++count>limit) {
count = 0;
phase = 0;
}
break;
}
}
}
// -- repeatedly ramp amplitude up from zero to maximum, stay at maximum for
// some time, then drop to zero for some other time.
// pulses are generated by constfreq_pulse()
// on/off ratio by A3 and ramp/max ratio by A4.
static void generator_burst()
{
static int phase; // ramp, maximum or zero
int cycles, cycles_on, cycles_ramp, cycles_max, cycles_off, cycle_par;
static int count, limit; // counts for maximum and zero phase
static float increment, amplitude;
get_pulse_parameters = constfreq_pulse;
if (!running) {
p_amplitude = 0;
pulsing = 1;
amplitude = 0.0;
phase = 0;
count = 0;
running = true;
// Serial.println("burst"); // TEST
}
cycle_par = (1023-analog[2])>>3;
cycles = (float)(cycle_par*cycle_par/(1075.0*loop_delay))+10; // 0.1 - 15 seconds
cycles_off = cycles*(float)(1023-analog[3])*0.0009765625;
cycles_on = cycles-cycles_off;
cycles_ramp = cycles_on*(float)(1023-analog[4])*0.0009765625;
cycles_max = cycles_on-cycles_ramp;
switch (phase) {
case 0: {
pulsing = 1;
if ((count++)>=cycles_ramp) {
amplitude = 0.0;
p_amplitude = 128;
count = 0;
phase = 1;
} else {
increment = 127.0/(float)(cycles_ramp);
amplitude = min(amplitude+increment, 128);
p_amplitude = amplitude;
}
break;
}
case 1: {
if (++count>cycles_max) {
pulsing = 0;
p_amplitude = 0;
count = 0;
phase = 2;
}
break;
}
case 2: {
if (++count>cycles_off) {
count = 0;
phase = 0;
}
break;
}
}
}
// -- modulate frequency between values derived from A1 and A2.
// Modulation period (0.1 to 5 seconds) from A3.
static void generator_fm()
{
float min_interval, max_interval, increment;
static float angle=0.0, factor, twopi=2.0*3.141592653589793;;
if (!running) {
factor = loop_delay*twopi;
p_amplitude = 128;
pulsing = 1;
get_pulse_parameters = basic_pulse;
running = true;
// Serial.println("frequency modulation"); // TEST
}
p_width = map(analog[5], 0, 1023, 3, 50);
min_interval = map_interval(analog[2]);
max_interval = map_interval(analog[1]);
if (max_interval=twopi) angle = 0.0;
p_interval = ((1.0-cos(angle))/2.0)*(float)(max_interval-min_interval)+min_interval;
}
// -- random pulses
static void generator_random()
{
if (!running) {
get_pulse_parameters = random_pulse;
pulsing = 1;
running = true;
// Serial.println("random"); // TEST
}
}
// -- pattern pulses
static void generator_pattern()
{
if (!running) {
get_pulse_parameters = pattern_pulse;
pulsing =1;
running = true;
// Serial.println("pattern"); // TEST
}
}
#if 0 // not currently used
// -- alternate frequencies
static void generator_altfreq()
{
static int phase; // maximum or zero
static int count, limit; // counts for maximum and zero phase
static int ftoggle; // frequency toggle;
if (!running) {
p_amplitude = 0;
pulsing = 1;
phase = 1;
count = 0;
ftoggle = 0;
get_pulse_parameters = basic_pulse;
running = true;
// Serial.println("alternate frequencies"); // TEST
}
p_width = map(analog[5], 0, 1023, 3, 50);
switch (phase) {
case 0: { // off-state
limit = (float)(analog[4]/102.40)/loop_delay;
p_amplitude = 0;
if (++count>limit) {
count = 0;
phase = 1;
}
break;
}
case 1: { // on-state
limit = (float)(analog[3]/102.40)/loop_delay;
p_interval = map_interval(analog[1+ftoggle]);
p_amplitude = 128;
if (++count>limit) {
count = 0;
phase = 0;
ftoggle ^= 1; // select other frequency
}
break;
}
}
}
#endif // not currently used
// -- modulate amplitude with a period derived from A4.
// pulses are generated by constfreq_pulse()
static void generator_am()
{
float increment;
static float angle, factor, twopi=2.0*3.141592653589793;;
get_pulse_parameters = constfreq_pulse;
if (!running) {
angle = 0.0;
factor = loop_delay*twopi;
p_amplitude = 0;
pulsing = 1;
running = true;
// Serial.println("amplitude modulation"); // TEST
}
increment = factor/(0.1+(float)analog[4]/511.0);
angle += increment;
if (angle>=twopi) angle = 0.0;
p_amplitude = (1.0-cos(angle))*64.0;
}
// -- modulate frequency between values derived from A1 and A2 and
// at the same time modulate amplitude fro zero to max.
// Frequency modulation period (0.1 to 5 seconds) from A3.
// Amplitude modulation period (0.1 to 5 seconds) from A4.
static void generator_fm_am()
{
float min_interval, max_interval, f_increment, a_increment;
static float f_angle=0.0, a_angle=0.0, factor, twopi=2.0*3.141592653589793;;
if (!running) {
factor = loop_delay*twopi;
p_amplitude = 0;
pulsing = 1;
get_pulse_parameters = basic_pulse;
running = true;
// Serial.println("frequency and amplitude modulation"); // TEST
}
p_width = map(analog[5], 0, 1023, 3, 50);
min_interval = map_interval(analog[2]);
max_interval = map_interval(analog[1]);
if (max_interval=twopi) f_angle = 0.0;
a_increment = factor/(0.1+(float)analog[4]/511.0);
a_angle += a_increment;
p_amplitude = (1.0-cos(a_angle))*64.0;
}
// -- after a delay derived from A3, ramp amplitude up from zero to maximum,
// stay at maximum for some time, then stop. The total of ramp- and
// maximum time is derived from A2 and the ratio of ramp and maximum
// from A4.
static void generator_single()
{
static int count, upcount, count_ramp, count_max, delay_count, delay_pulses, phase;
static float increment, amplitude;
if (!running) {
p_amplitude = 0;
amplitude = 0;
get_pulse_parameters = high_pulse;
pulsing = 0;
running = true;
delay_count = (float)analog[3]/(loop_delay*51.2)+1.;
delay_pulses = delay_count*loop_delay-1; // number of pulses during delay
count = (float)analog[2]/(loop_delay*102.4)+10.;
upcount = 0;
count_max = count*(float)analog[4]*0.0009765625;
count_ramp = count-count_max;
increment = 127.0/(float)(count_ramp);
phase = 0;
// Serial.println("single shot"); // TEST
}
switch (phase) {
case 0: {
if (delay_count<=0) {
phase = 1;
get_pulse_parameters = constfreq_pulse;
} else {
// during initial delay short pulse train every second
if ((upcount%100)==0) {
if (delay_pulses>0) pulsing = 1;
delay_pulses--;
} else {
pulsing = 0;
}
delay_count--; // decrement delay count
upcount++;
}
break;
}
case 1: {
pulsing = 1;
if (count_ramp<=0) {
phase = 2;
} else {
amplitude = min(amplitude+increment, 128);
p_amplitude = amplitude;
count_ramp--;
}
break;
}
case 2: {
p_amplitude = 128;
if (count_max<=0) {
digitalWrite(2, LOW);
pulsing = 0;
} else {
count_max--;
}
}
}
}
generator_function generators[] = {
generator_zero,
generator_single,
generator_constant,
generator_burst,
generator_ramp2,
generator_am,
generator_fm,
generator_fm_am,
generator_chirp,
generator_random,
generator_ramp,
// generator_altfreq
};
int n_generators=sizeof(generators)/sizeof(generator_function);
int generator_index=0;
volatile generator_function generator=generator_zero;
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// -- select pulse generator function based on argument 'analog'.
// Argument 'analog' is the read-out of pin A0 connected
// to a rotary switch populated with 1k resistors.
//
static void select_generator(int analog)
{
static int votes=0, previous=0; // variables used in contact bounce handling
int index = map(analog+51, 0, 1023, 0, 10);
if (index!=generator_index) {
previous = index;
if (votes>200) {
// change generator after 200 identical indexes
votes = 0;
// running = false;
if (digitalRead(3)) {
digitalWrite(2, 0); // disable pulse generation
pulsing = 0;
p_amplitude = 0;
}
generator_index = index;
if (!runstored) generator=generators[generator_index%n_generators];
} else {
if (index==previous) votes++;
else votes = 0;
}
}
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// -- write to mcp4131 digital potentiometer
//
int digitalPotWrite(int value)
{
digitalWrite(CS, LOW);
SPI.transfer(address);
SPI.transfer(value);
digitalWrite(CS, HIGH);
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// -- start stop pulse generation
void start_stop()
{
static long now, timestamp;
now = millis();
if (now>(timestamp+500)) {
timestamp = now;
if (digitalRead(2)) {
digitalWrite(2, LOW);
p_amplitude = 0;
pulsing = 0;
} else {
digitalWrite(2, HIGH);
running = false; // restart generator
}
}
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// -- status report
void report()
{
char line[80];
sprintf(line, "\nSynthesizer version: %s", VERSION); Serial.println(line);
sprintf(line, "--------------------------------------"); Serial.println(line);
sprintf(line, "Analog: 0 1 2 3 4 5"); Serial.println(line);
sprintf(line, "--------------------------------------"); Serial.println(line);
sprintf(line, " %4d %4d %4d %4d %4d %4d",
analog[0], analog[1], analog[2], analog[3], analog[4], analog[5]); Serial.println(line);
sprintf(line, "--------------------------------------"); Serial.println(line);
sprintf(line, "Generator: %8d", generator_index); Serial.println(line);
sprintf(line, "Pulse interval: %8ld ms (%d Hz)",
16*(long)p_interval/1000, (int)(1.0/(p_interval*16e-6)+0.5)); Serial.println(line);
sprintf(line, "Pulse width: %8d µs", 8*p_width); Serial.println(line);
sprintf(line, "Pulse amplitude: %8d", p_amplitude); Serial.println(line);
sprintf(line, "======================================\n"); Serial.println(line);
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// -- monitor analog[] array
void mtr_analog()
{
char line[80];
static int count=0;
count = ++count%10; // display every 10th loop delay cycle
if (!count) {
sprintf(line, "Analog values: %4d %4d %4d %4d %4d %4d\r",
analog[0], analog[1], analog[2], analog[3], analog[4], analog[5]); Serial.print(line);
}
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// -- process switches 3 and 4
void process_switches()
{
static int settings[6];
static int saved=0;
int changed;
cli();
changed = changedbits;
changedbits = 0;
sei();
if (changed) {
if (changed&(1< signal light
pinMode(driver_pin, OUTPUT); // driver pin
pinMode(cd_pin, OUTPUT); // capacitor discharge pin
pinMode(3, INPUT_PULLUP); // used for interrupt 1; gray
pinMode(5, INPUT_PULLUP); // purple
pinMode(8, INPUT_PULLUP); // blue
pinMode(9, INPUT_PULLUP); // yellow
pinMode(10, INPUT_PULLUP); // orange
attachInterrupt(1, start_stop, FALLING);
// -- SPI setup
SPI.begin();
// -- prevent unwanted output because potentiometer's
// POR wiper setting is mid-scale.
digitalPotWrite(0); // set potentiometer to lowest value ...
digitalWrite(PA, HIGH); // ... then apply voltage to it -- disabled, done via interrupt
delay(250); // light for 250 ms (constant if zero generator is selected)
cli(); // disable interrupts
// -- TIMER1 setup
TCCR1A = 0; // stop timer as initialized ...
TCCR1B = 0; // ... by Arduino IDE
TCCR1A |= 0b00000011; // fast PWM
TCCR1B = 4; // f/256 prescaler
TCCR1B |= (1 << WGM12); // clear timer on compare match
TCCR1B |= (1 << WGM13); // fast PWM
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
TIMSK1 |= (1 << OCIE1B); // enable timer compare interrupt
TCNT1 = 0; // clear counter 1
OCR1A = c_width+1; // arbitrary first period
OCR1B = OCR1A-c_width; // before reset
// -- TIMER2 setup
TCCR2A = 0; // stop timer as initialized ...
TCCR2B = 0; // ... by Arduino IDE
TIMSK2 = 0;
// TCCR2B = 5; // f/128 prescaler
TIMSK2 |= (1 << OCIE2A); // enable timer compare interrupt
TIMSK2 |= (1 << OCIE2B);
OCR2A = p_width;
OCR2B = p_width + 5;
// -- adc setup
ADMUX = 0; // right adjust result
ADMUX |= 0b01000000; // reference voltage AV_CC
ADMUX |= anapin; // first analog pin
ADCSRA = 0b10000000; // enable ADC
ADCSRA |= 0b00000111; // f/128 prescaler
ADCSRA |= 0b00001000; // enable ADC interrupt
ADCSRB = 0;
ADCSRB |= 0b00000000; // free running trigger mode
DIDR0 = 0b00111111; // disable digital input on analog pins
// -- PC-interrupt setup
portBstate = PINB;
PCICR |= (1<4) {
OCR2B = cur_width+cdtime; // add capacitor discharge time
cdflag = 1; // set capacitor discharge flag
} else {
cdflag = 0;
}
}
}
ISR(TIMER1_COMPA_vect)
{
digitalPotWrite(0);
TCNT2 = 0; // restart TIMER2
TCCR2B = 5; // f/128 prescaler
if (pulsing) {
digitalWrite(driver_pin, HIGH); // activate driver
}
pulsed = 1; // indicate pulse is being generated
}
// -- TIMER2 interrupts
ISR(TIMER2_COMPA_vect)
{
if (pulsed) {
digitalWrite(driver_pin, LOW); // deactivate driver
if (cdflag) digitalWrite(cd_pin, HIGH); // discharge capacitor if necessary
cdflag = 0; // clear capacitor discharge flag
}
pulsed = 0; // clear pulse-generation flag
}
ISR(TIMER2_COMPB_vect)
{
TCCR2B = 0; // stop timer
digitalWrite(cd_pin, LOW); // stop discharging capacitor
}
// -- ADC interrupt
ISR(ADC_vect)
{
if (anamask[anapin]) {
analog[anapin] = ADCL | (ADCH << 8); // get value from A/D converter
if (anapin==0) {
select_generator(analog[anapin]); // special: A0 selects pulse generator
}
}
anapin = (++anapin)%6; // cycle through available pins
ADMUX = (ADMUX & 0xF0) | anapin; // select pin
ADCSRA |= 0b01000000; // restart ADC
}
// -- pin-change interrupt
ISR(PCINT0_vect)
{
static long now, timestamp;
now = millis();
portBpast = portBstate;
portBstate = PINB;
if (now>(timestamp+1000)) {
timestamp = now;
changedbits = portBpast ^ portBstate;
}
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// -- Arduino IDE loop function
//
void loop() {
check_running();
process_switches();
generator();
if (!digitalRead(5)) report();
if (!digitalRead(10)) mtr_analog();
delay((unsigned long)(loop_delay*1000.0));
}