-
-
Save mpflaga/4404996 to your computer and use it in GitHub Desktop.
/*** | |
InputCapture.ino | |
Timer 1 high-resolution timing facility. | |
Copyright (C) 2008-2012 Bill Roy | |
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. | |
This library 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 | |
Lesser General Public License for more details. | |
You should have received a copy of the GNU Lesser General Public | |
License along with this library; if not, write to the Free Software | |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
***/ | |
#include "Arduino.h" | |
#include <avr/interrupt.h> | |
/* | |
TO DO | |
analog threshold-based tick timer | |
set comparator to use internal reference | |
*/ | |
// rising/falling edge tracking | |
// per '168 data sheet page 121, must clear ICF1 after edge direction change | |
// | |
volatile uint8_t rising; | |
//#define catchRisingEdge() (TCCR1B |= (1<<ICES1); TIFR1 |= (1<<ICF1); rising = 1;); | |
//#define catchFallingEdge() (TCCR1B &= ~(1<<ICES1); TIFR1 |= (1<<ICF1); rising = 0;); | |
// Event queue | |
#define MAX_EVENT_BUFF 32 | |
uint64_t last_event; | |
volatile uint8_t event_buffer_head; | |
uint8_t event_buffer_tail; | |
uint64_t event_buffer[MAX_EVENT_BUFF]; | |
uint64_t eventRead(void) { | |
uint64_t event; | |
if (event_buffer_tail == event_buffer_head) { | |
Serial.println("Event buffer underrun"); | |
return -1; | |
} | |
event = event_buffer[event_buffer_tail] - last_event; | |
last_event = event_buffer[event_buffer_tail]; | |
uint8_t oldsreg = SREG; | |
cli(); | |
if (++event_buffer_tail >= MAX_EVENT_BUFF) event_buffer_tail = 0; | |
SREG = oldsreg; | |
return event; | |
} | |
uint8_t eventAvailable(void) { | |
uint8_t head; | |
uint8_t oldsreg = SREG; | |
cli(); | |
head = event_buffer_head; | |
SREG = oldsreg; | |
return event_buffer_tail != head; | |
} | |
// Our virtual timer counts 2^64 clocks (provided sizeof(unsigned long long) == 8) | |
// The low order 16 bits are maintained by timer1 and are snapshotted by the | |
// TIMER1_CAPT input capture interrupt below. | |
// | |
// We maintain the high order 48 bits here by incrementing the virtual timer. | |
// | |
volatile uint64_t t1_virtual_count; | |
ISR(TIMER1_OVF_vect) { | |
t1_virtual_count += (uint64_t) 0x10000; | |
} | |
uint32_t lost_event_count; | |
// Interrupt capture handler | |
// | |
ISR(TIMER1_CAPT_vect) { | |
union twobyte { | |
uint32_t word; | |
uint8_t byte[2]; | |
} timevalue; | |
timevalue.byte[0] = ICR1L; // grab captured timer value | |
timevalue.byte[1] = ICR1H; // grab captured timer value | |
// watch for the other edge to catch the half-pulse width | |
//rising ? catchFallingEdge() : catchRisingEdge(); | |
if (rising) { TCCR1B &= ~(1<<ICES1); TIFR1 |= (1<<ICF1); rising = 0; } | |
else {TCCR1B |= (1<<ICES1); TIFR1 |= (1<<ICF1); rising = 1;} | |
// push the timestamp into the buffer | |
uint8_t newhead = event_buffer_head + 1; | |
if (newhead >= MAX_EVENT_BUFF) newhead = 0; | |
if (newhead != event_buffer_tail) { | |
event_buffer[event_buffer_head] = t1_virtual_count + timevalue.word; | |
event_buffer_head = newhead; | |
} | |
else ++lost_event_count; | |
} | |
void printEvent(uint64_t n, uint32_t base) { | |
char buf[32]; // stack for the digits | |
char *ptr = buf; | |
if (n == (uint64_t) 0) { | |
Serial.write('0'); | |
return; | |
} | |
while (n > 0) { | |
*ptr++ = n % base; | |
n /= base; | |
} | |
while (--ptr >= buf) Serial.write((*ptr < 10) ? (*ptr + '0') : (*ptr - 10 + 'A')); | |
} | |
void initTimer(void) { | |
// Input Capture setup | |
// ICNC1: Enable Input Capture Noise Canceler | |
// ICES1: =1 for trigger on rising edge | |
// CS10: =1 set prescaler to 1x system clock (F_CPU) | |
TCCR1A = 0; | |
TCCR1B = (0<<ICNC1) | (0<<ICES1) | (1<<CS10); | |
TCCR1C = 0; | |
//catchFallingEdge(); // initialize to catch | |
{ TCCR1B &= ~(1<<ICES1); TIFR1 |= (1<<ICF1); rising = 0; } | |
// Interrupt setup | |
// ICIE1: Input capture | |
// TOIE1: Timer1 overflow | |
TIFR1 = (1<<ICF1) | (1<<TOV1); // clear pending | |
TIMSK1 = (1<<ICIE1) | (1<<TOIE1); // and enable | |
// Set up the Input Capture pin, ICP1, which corresponds to Arduino D8 | |
pinMode(8, INPUT); | |
digitalWrite(8, 0); // leave floating to count 60 Hz etc. | |
//digitalWrite(8, 1); // or enable the pullup | |
} | |
void setup(void) { | |
pinMode(13, OUTPUT); | |
// Power up the light sensor | |
//pinMode(9, OUTPUT); digitalWrite(9, 0); | |
//pinMode(10, OUTPUT); digitalWrite(10, 1); | |
Serial.begin(57600); | |
initTimer(); | |
Serial.println("timing..."); | |
} | |
int32_t count, sumt, bogon_count; | |
uint32_t updatetime; | |
void loop60hz(void) { | |
int32_t t; | |
int32_t dt; | |
while (eventAvailable()) { | |
t = (int32_t) eventRead(); | |
dt = t - (F_CPU/60); | |
if (abs(dt) < (int32_t) 2000) { | |
count = count + 1; | |
sumt += dt; | |
} | |
else ++bogon_count; | |
if (millis() > updatetime) { | |
Serial.println(""); | |
Serial.print("t="); Serial.print(t); | |
//Serial.print(" dt="); Serial.print(dt); | |
Serial.print(" sdt="); Serial.print(sumt); | |
Serial.print(" n="); Serial.print(count); | |
Serial.print(" a="); Serial.print(sumt/count); | |
Serial.print(" e="); Serial.print(lost_event_count); | |
Serial.print(" b="); Serial.print(bogon_count); | |
updatetime = millis() + (int32_t) 1000; | |
} | |
Serial.print(" "); Serial.print(dt); | |
} | |
} | |
void loop(void) { | |
delay(3000); | |
while (eventAvailable()) { | |
Serial.print(count++); Serial.write(':'); | |
printEvent(eventRead(), 10); | |
Serial.write(' '); Serial.println(lost_event_count); | |
} | |
} | |
fixed / thanks
Im Looking to capture a Manchester stream using the timer however the ISR(TIMER1_CAPT_vect) is missing stage changes !! and ideas Im compiling for a nano 328p;
boolean rising;
boolean data_ready;
unsigned char high;
unsigned char low;
void setup() {
TCCR1A = 0;
TCCR1B = (0<<ICNC1) | (0<<ICES1) | (2<<CS10);
TCCR1C = 0;
TCCR1B &= ~(1<<ICES1); TIFR1 |= (1<<ICF1); rising = 0;
TIFR1 = (1<<ICF1) | (1<<TOV1); // clear pending
TIMSK1 = (1<<ICIE1) | (1<<TOIE1); // and enable
pinMode(8, INPUT);
digitalWrite(8, 0); // leave floating to count 60 Hz etc.
pinMode(5, OUTPUT);
//Serial.begin(115200);
}
ISR(TIMER1_CAPT_vect) {
high = ICR1H;
low = ICR1L;
data_ready=1;
digitalWrite(5,!digitalRead(5));
rising=!rising;
if (rising) {
TCCR1B |= (1<<ICES1);
TIFR1 |= (1<<ICF1);
}else {
TCCR1B &= ~(1<<ICES1);
TIFR1 |= (1<<ICF1);
}
}
void loop() {
}
I have tested this on mega2560 on timer5 using 3600 ppr encoder. i changed the code accordingly. but working only in slow rotation how to speedup the counting?
Thanks for this, very very much appreciated.
Pls excuse my newby question: Trying to compile, get compile error - not found SDI.h. I've pasted it everywhere I can think of, the error persists. ?? help / thanks!