-
-
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!