Only long after submitting the question and looking at the data, I realised that the triangulation works as expected.
There are still issues like delays which have not been considered for the current test setup.
I use the at2313/at4313 in order to measure the time for one or more echoes.
As the timer starts from zero when the echo pin of the transmitter/receiver rises, all three timers start
from zero at the same time, within a few clocks. As no other interrupt than the analog comparator is active, it is easy to get accurate timestamps.
Hence no need to check for overflow as it takes 32K usec using a 2 Mhz timer clock.
If an 8-bit timer is used, however, the overflow would need to be handled as you do in the FastTimer example.
Here is the sketch used as is.
It compiles for the at4313, but an additional non-buffered serial library is needed for the at2313 due to the smaller memory.
/***
ATMEL (ATTINY2313a)/4313a / ARDUINO
Pin 1 (PA2) analog input Vcc = 1, Vcc -1.2v = 0. Above 2.2v for 5v vcc to avoid reset!
+-\/-+
RESET PA2 1| |20 Vcc 5v
RXD PD0 2| |19 PB7 SCL/SCK/PCINT17
Data out<- TXD PD1 3| |18 PB6 MISO/DO/PCINT16
XT2/PCINT9 PA1 4| |17 PB5 MOSI/DI/PCINT5
XT1/PCINT8 PA0 5| |16 PB4 OC1B/PCINT4
INT0/PCI13 PD2 6| |15 PB3 OC1A/PCINT3 Echo from T/X HC, start timer pos. edge
PCI14/INT1 PD3 7| |14 PB2 OC0A/PCINT2 Pulse in, start tx data negative edge
PCI15/T0 PD4 8| |13 PB1 AIN1/PCINT1 Reference voltage 10K pot + 0.1uF center tap(0.5v).
PCI16/T1 PD5 9| |12 PB0 AIN0/PCINT0 Signal in from HC detector output, positive
GND 10| |11 PD6 ICIPI/PCINT17
+----+
PB0 = In, signal from HC-sr04, positive pulses 40 Khz
PB1 = Reference voltage, adjustable.
PB2 = In, pulse in, send data via TXD. Trig on negative edge comp.
PB3 = In, Start timer1 Trig on positive edge from echo positive start timer
PD1 = Tx, send data
Uses the analog comparator to save the timer count when an echo is detected.
8 mhz cpu, timer clock 1 Mhz, 16Mhz timer clock 2 Mhz
On a standard Arduino UNO execution of the user code within the ISR starts after 3,1 microsecond, 16Mhz,
8 Mhz 6.2 usec
***/
#include <PinChangeInterrupt.h>
#if defined( __AVR_ATtiny2313__ ) || defined( __AVR_ATtiny2313A__ )
#include <Tx313SerOut.h> //Custom no buffer serial out only
#endif
//16Mhz clock/8 = 2 Mhz, 0.5 usec per tick. Max 32768 usec = 574.8 cm - enough
#if (F_CPU == 16000000)
#define USE_16MHZXTAL
#warning "Using 16Mhz clock"
#endif
#if defined( __AVR_ATtiny4313__ ) || defined( __AVR_ATtiny4313A__ )
#define SerialOut Serial
#else
Tx313SerOut SerialOut; //at2313 has not sufficient ram for default serial print
#endif
#define ROUNDTRIP_CM 57
#define MAX_ECHOS 4 //Adjust if memory allows.
#define TXTXT PIN_PB2 //<- Send value(s)
#define STARTPIN PIN_PB3 //<- Start timer, echo out hc04
#ifdef USE_16MHZXTAL
#define MIN_ECHO_DISTANCE ROUNDTRIP_CM * 2
#else
#define MIN_ECHO_DISTANCE ROUNDTRIP_CM //Ignore pulse train from transmitter
#endif
volatile uint16_t distance[MAX_ECHOS]; //Store up to 4 echos
volatile int8_t distcount;
volatile uint16_t old_clock;
volatile byte estate; // 0-> 1 start timer, 1 = store echo time, 3 = send result(s)
//Timer runs at clock(8Mhz)/8, 1 us between ticks. up to 65 ms, 16Mhz 0.5 usec gives 32ms
ISR(TIMER1_OVF_vect) //Timer overflow vector
{
//Stop timer! just in case.
TCCR1B = 0;
}
//Start timer on positive edge from hc-sr04 echo pin
void timerStart(void) {
distcount = 0;
old_clock = ROUNDTRIP_CM; //Ignore echo first few centimeters , avoid end of pulse train
estate = 1; //Timer started
cli();
TCNT1 = 0;
// Using 8Mhz, this sets timer to 1 Mhz
// For 16mhz, 2Mhz
TCCR1B = _BV(CS11);
sei();
}
void txoutStart(void) {
estate = 3; //For send tx result
}
//Interrupt code of the comparator
// NB : you need to stabilize the power rail with a capacitor (otherwise you'll have ripples and misreading).
ISR(ANA_COMP_vect) {
//Always catch timer count?
uint16_t clocks = TCNT1; //16 bits, 1 mhz 60 ms = 60000 us, 2mhz 32ms no overflow
ACSR &= ~(1 << ACIE);
//Ignore pulses until timer trigger has arrived or when array filled.
if ( estate == 1 && distcount < MAX_ECHOS) {
//Prevent too close echoes. Needed for decoding 40khz pulse first rise.
//Pulses within delay are ignored and sets new delay
if ( clocks > old_clock ) { //xxx ticks, 8 pulses, min. diff. distance, approx 4 cm
distance[distcount++] = clocks; //Ticks from timer start
}
old_clock = clocks + MIN_ECHO_DISTANCE; //Avoid saving within a pulse train.
}
ACSR |= (1 << ACIE);
}
void setup() {
pinMode(STARTPIN, INPUT_PULLUP);
pinMode(TXTXT, INPUT_PULLUP);
//NOTE: At2313, do not use hardwareserial and built-in Print. Buffers too big!
SerialOut.begin( 38400 );
//Latency 6 cycles for PinChangeInterrupt - 0.75 us at 8 Mhz (plus enter isr ~6 us)
//From hc-sr04 echo goes heigh when echo timing starts.
attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(STARTPIN), timerStart, RISING);
attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(TXTXT), txoutStart, FALLING);
cli();
TCCR1B = 0; //Timer stopped.
OCR1B = 0x00;
TIMSK = _BV(TOIE1); // Enable overflow interrupt - just to stop after ~60 ms/ ~30 ms.
PORTB &= ~(1 << PB0); // no Pull-up on PB0
DIDR = (1 << AIN0D | 1 << AIN1D );
ACSR |=
(0 << ACD) | // Comparator ON
(0 << ACBG) | // Disconnect 1.23V reference from AIN0 (use AIN0 and AIN1 pins)
(0 << ACIC) | // input capture disabled
(1 << ACIS1) | // set interrupt bit on rising edge (AIN0)
(1 << ACIS0); // (ACIS1 and ACIS0 == 11)
// Enable the interrupt
ACSR |= (1 << ACIE);
sei(); // enable global interrupts
}
void loop() {
if ( estate == 3 ) {
TCCR1B = 0; //Stop timer before transmit of data.
for (int i = 0; i < distcount; i++ ) {
#ifdef USE_16MHZXTAL
SerialOut.println(distance[i]/2); //16Mhz, 0,5 usec make it 1 usec count
#else
SerialOut.println(distance[i]); //8 mhz, 1us.
#endif
}
SerialOut.print(F("44444\n")); //End marker, 44444 to avoid receiver time-out(parseInt).
estate = 0; //Wait for echo timer start
}
}