Arduino - noggrann tidmätning & interrupt
Postat: 19 maj 2021, 14:20:02
... eller "Uno - den italienske cykeltjuven ertappad på bar gärning!"
Har haft lite huvudbry med att få så noggranna tidmätningar som möjligt
på Arduino Uno (för användning till mätning av mynningshastighet på
luftpistol). Programstrukturen är enkel med en givare som nollställer
timer1 via interrupt från ISR0 (på pin 2). Nästa givare läser räknarvärdet
via interrupt TIMER1_CAPT (från pinne_8). Void loop () gör inget alls om inte
en flagga är satt som anger att ett värde finns att beräkna och visa på
LCD.
Fungerar stabilt så när som på att korta tider bli lite fel och efter att
ha gjort en längre mätserie med verkligt pulsavstånd och räknarvärde
över hela registret från ca. 10 us till 4000 us visar sig att någon snor
klockpulser som inte kommer med i resultatet. Excel har funktionerna
SLOPE och INTERCEPT som är användbara för att visa sambandet mellan
mätserier i form av offset och lutning på kurvan när man har räknarvärde
på X-axeln och verkligt pulsavstånd på Y-axeln. Resultatet blir ---
intercept = -57,09876275
slope = 16,0029568 => klocka ns (1000/slope) = 62,48845213
Det fattas 57 pulser på timern (och kristallen är lite "off")
Inga andra interrupt är aktiva under mätningen men kanske efter om
LCD-biblioteket smyger in något. Andra har samma erfarenhet och antyder
att boven (Uno) är inblandad via kompilatorn som lägger in en hel del
i hanteringen av interrupt som snor klockcykler utan att man kan se det direkt.
Sökning på "arduino interrupt overhead" ger bl.a. följande utmärkta förklaring:
https://billgrundmann.wordpress.com/200 ... nterrupts/
Har testat att tröska mig igenom detta recept:
https://blog.benoitblanchon.fr/arduino- ... -assembly/
och man kan se en massa maskinkod i interrupthanteringen som förklarar
de saknade klockpulserna. Listningarna kan bli låååånga så jag har nöjt mig
med att det inte är oförklarliga fenomen och jag kan med gott samvete lägga
till 57 på räknarvärdet. Det är dessutom alltid denna offset.
I toppen av assemblerlistningen får man en översikt av alla interruptvektorer
och oanvända pekar på 0xfc <__bad_interrupt>. Ska kolla om LCD-biblioteket
lägger till något när det är med. Att tjuvkika bakom kulisserna kan kanske ge
information (om man inte somnat dessförinnan).
Det är nog bara om man kör timer1 utan prescaler som man behöver bry sig om
cykeltjuvarna. Det här upplägget funkar nog inte för tidmätning < 57 klockpulser.
Andra gränsen blir 4096 us om man som jag inte har brytt sig om att hantera
att timer1 rullar över, det kommer inte att hända i mitt fall, kort mätsträcka
och hög hastighet. Normalt område blir 100 - 200 m/s, 500 - 250 us (på 50 mm)
Färdigtrimmat blir det [interval_us = 62.48845 * (timer1_count + 57) / 1000]
i min kod för denna mätpryl. Mindre än 100 ns fel upp till 4000 us pulsavstånd
blir det om man använder formeln på det redan uppmätta timertiderna. De "verkliga"
tiderna mätta på HP5315A med kalibrerad OXCO (återanvänd /// GSM REFO).
... undrar om någon orkar ända hit?
Har haft lite huvudbry med att få så noggranna tidmätningar som möjligt
på Arduino Uno (för användning till mätning av mynningshastighet på
luftpistol). Programstrukturen är enkel med en givare som nollställer
timer1 via interrupt från ISR0 (på pin 2). Nästa givare läser räknarvärdet
via interrupt TIMER1_CAPT (från pinne_8). Void loop () gör inget alls om inte
en flagga är satt som anger att ett värde finns att beräkna och visa på
LCD.
Fungerar stabilt så när som på att korta tider bli lite fel och efter att
ha gjort en längre mätserie med verkligt pulsavstånd och räknarvärde
över hela registret från ca. 10 us till 4000 us visar sig att någon snor
klockpulser som inte kommer med i resultatet. Excel har funktionerna
SLOPE och INTERCEPT som är användbara för att visa sambandet mellan
mätserier i form av offset och lutning på kurvan när man har räknarvärde
på X-axeln och verkligt pulsavstånd på Y-axeln. Resultatet blir ---
intercept = -57,09876275
slope = 16,0029568 => klocka ns (1000/slope) = 62,48845213
Det fattas 57 pulser på timern (och kristallen är lite "off")
Inga andra interrupt är aktiva under mätningen men kanske efter om
LCD-biblioteket smyger in något. Andra har samma erfarenhet och antyder
att boven (Uno) är inblandad via kompilatorn som lägger in en hel del
i hanteringen av interrupt som snor klockcykler utan att man kan se det direkt.
Sökning på "arduino interrupt overhead" ger bl.a. följande utmärkta förklaring:
https://billgrundmann.wordpress.com/200 ... nterrupts/
Har testat att tröska mig igenom detta recept:
https://blog.benoitblanchon.fr/arduino- ... -assembly/
och man kan se en massa maskinkod i interrupthanteringen som förklarar
de saknade klockpulserna. Listningarna kan bli låååånga så jag har nöjt mig
med att det inte är oförklarliga fenomen och jag kan med gott samvete lägga
till 57 på räknarvärdet. Det är dessutom alltid denna offset.
I toppen av assemblerlistningen får man en översikt av alla interruptvektorer
och oanvända pekar på 0xfc <__bad_interrupt>. Ska kolla om LCD-biblioteket
lägger till något när det är med. Att tjuvkika bakom kulisserna kan kanske ge
information (om man inte somnat dessförinnan).
Det är nog bara om man kör timer1 utan prescaler som man behöver bry sig om
cykeltjuvarna. Det här upplägget funkar nog inte för tidmätning < 57 klockpulser.
Andra gränsen blir 4096 us om man som jag inte har brytt sig om att hantera
att timer1 rullar över, det kommer inte att hända i mitt fall, kort mätsträcka
och hög hastighet. Normalt område blir 100 - 200 m/s, 500 - 250 us (på 50 mm)
Färdigtrimmat blir det [interval_us = 62.48845 * (timer1_count + 57) / 1000]
i min kod för denna mätpryl. Mindre än 100 ns fel upp till 4000 us pulsavstånd
blir det om man använder formeln på det redan uppmätta timertiderna. De "verkliga"
tiderna mätta på HP5315A med kalibrerad OXCO (återanvänd /// GSM REFO).
... undrar om någon orkar ända hit?