Fler problem med avbrottsrutin * LÖST VIDEO BIFOGAD*
-
- Inlägg: 120
- Blev medlem: 3 mars 2011, 01:58:43
Re: Fler problem med avbrottsrutin
Det fungerar ju, men den kod som ligger i tråden tar INGEN hänsyn ÖVER HUVUD TAGET vad jag kan se, till Timer1 overflow. Så om man är säker på att tiden man mäter ryms inom en cykel på timer1 räcker det att kolla (och vid overflow nolla) timer1:s overflow-flagga, räcker inte den periodtiden får man börja räkna antal overflow precis som du beskriver men det görs ju INTE i koden!
Jag är skeptisk till att det faktiskt blir rätt om man kör och hoppas på att ALU inte tar med carryflaggan (borrow) till nästa uträkning, det blir ju rätt även om talet blir "negativt" då det är tvåkomplements matte men jag skulle inte satsa på att kompilatorn får det att bli rätt om man låter ett negativt tal gå in i en variabel som bara kan anta positiva värden. Jag skulle ha använt timer1 overflow-flagga som en 17-bit (precis som microchip beskriver i sin "Tips 'n tricks" när man mäter periodtid med en CCP modul).
Ett extremt snarlikt bygge jag gjorde för några år sen med en PIC 16F886 (och tyvärr MikroC...) gav konstiga ostabila värden om man inte tog hänsyn till Timer1 overflow som en 17-bit (jag behövde inte räkna antalet timer1 overflow då tiden jag mätte var såpass kort).
Jag är skeptisk till att det faktiskt blir rätt om man kör och hoppas på att ALU inte tar med carryflaggan (borrow) till nästa uträkning, det blir ju rätt även om talet blir "negativt" då det är tvåkomplements matte men jag skulle inte satsa på att kompilatorn får det att bli rätt om man låter ett negativt tal gå in i en variabel som bara kan anta positiva värden. Jag skulle ha använt timer1 overflow-flagga som en 17-bit (precis som microchip beskriver i sin "Tips 'n tricks" när man mäter periodtid med en CCP modul).
Ett extremt snarlikt bygge jag gjorde för några år sen med en PIC 16F886 (och tyvärr MikroC...) gav konstiga ostabila värden om man inte tog hänsyn till Timer1 overflow som en 17-bit (jag behövde inte räkna antalet timer1 overflow då tiden jag mätte var såpass kort).
Re: Fler problem med avbrottsrutin
Låt oss nu se... Jag skrev: "samt att RPM-mätningen bör expanderas till att tiderna är 32 bit istället för 16 bit."
Och det är sant att det nuvarande program inte har med Timer1 overflow, det var ju anledningen till att jag skrev att det behövdes eller hur?
Uträkningarna kommer att bli rätt om man ser till att räkna med unsigned long (unsigned 32 bit) och håller sig inom vettiga värden, vilket i detta fall definitivt kommer att ske.
Och det är sant att det nuvarande program inte har med Timer1 overflow, det var ju anledningen till att jag skrev att det behövdes eller hur?
Uträkningarna kommer att bli rätt om man ser till att räkna med unsigned long (unsigned 32 bit) och håller sig inom vettiga värden, vilket i detta fall definitivt kommer att ske.
-
- Inlägg: 120
- Blev medlem: 3 mars 2011, 01:58:43
Re: Fler problem med avbrottsrutin
Jag försökte bara komma fram till varför de olika program TS-prövade inte fungerade och jag har haft problematiken (visserligen med en usel kompilator) då man var tvungen att ta hänsyn till timer1:s overflow annars blev det fel (fråga mig inte varför för det vet jag inte men jag misstänker att nån av flaggorna i ALU blev kvar till nästa gång) och dessutom skriver microchip det i sin dokumentation:
1. Configure control bits CCPxM3:CCPxM0
(CCPxCON<3:0>) to capture every rising
edge of the waveform.
2. Configure the Timer1 prescaler so Timer1
with run Tmax
(1)
without overflowing.
3. Enable the CCP interrupt (CCPxIE bit).
4. When a CCP interrupt occurs:
a) Subtract saved captured time (t1) from
captured time (t2) and store (use Timer1
interrupt flag as overflow indicator).
b) Save captured time (t2).
c) Clear Timer1 flag if set.
The result obtained in step 4.a is the period (T).
1. Configure control bits CCPxM3:CCPxM0
(CCPxCON<3:0>) to capture every rising
edge of the waveform.
2. Configure the Timer1 prescaler so Timer1
with run Tmax
(1)
without overflowing.
3. Enable the CCP interrupt (CCPxIE bit).
4. When a CCP interrupt occurs:
a) Subtract saved captured time (t1) from
captured time (t2) and store (use Timer1
interrupt flag as overflow indicator).
b) Save captured time (t2).
c) Clear Timer1 flag if set.
The result obtained in step 4.a is the period (T).
- SeniorLemuren
- Inlägg: 8410
- Blev medlem: 26 maj 2009, 12:20:37
- Ort: Kristinehamn
Re: Fler problem med avbrottsrutin
Ja, jag tog notis om det med overflow i en av de tidigare försöken där jag hoppade över uträkningen om det var overflow. Det var precis samma resultat vilket det var med eller ej.
Jag håller på med detta i båten och där har jag inget oscilloscope. Det blir nog nödvändigt att åka upp till hobbyverkstaden och hämta ner ett sådant, för att informera sig om hur pulserna på ingången från hallgivaren ser ut, innan man lägger ner mer krut på programmeringen.
Jag håller på med detta i båten och där har jag inget oscilloscope. Det blir nog nödvändigt att åka upp till hobbyverkstaden och hämta ner ett sådant, för att informera sig om hur pulserna på ingången från hallgivaren ser ut, innan man lägger ner mer krut på programmeringen.

Re: Fler problem med avbrottsrutin
Lite saxning från ett tidigare projekt:
Varsågod, 1 st Capture-rutin med 32 bitars tidsmätning.
När det är mätt ett värde aktiveras Flag.Running och det ska nollas innan en ny mätning kan utföras.
Om flaggan Flag.Timeout aktiveras kan man utgå ifrån 0 RPM.
När flaggan Flag.Update är aktiv har det kommit en uppdatering och RPM-utläsningen kan uppdateras.
Kod: Markera allt
#define false 0
#define true 1
typedef unsigned char BYTE;
typedef unsigned int WORD;
typedef unsigned long DWORD;
typedef union
{
DWORD DW;
WORD WO[2];
BYTE BY[4];
} T_ALL_ACCESS;
T_ALL_ACCESS Time_Now, Time_Then, Time_Diff;
struct
{
byte Running : 1;
byte Update : 1;
byte Timeout : 1;
} Flag;
WORD RPM;
#define Overflow Time_Now.BY[2]
#define PRESCALE 8 /* In this case */
#define MAGIC_CONSTANT (60000000 / PRESCALE) /* med 4MHz kristall blir värdet 60 000 000 / prescale = verklig räknarfrekvens * 60 sekunder */
void interrupt(void)
{
if(PIR1.TMR1IF)
{
PIR1.TMR1IF = false; // Acknowledge interrupt
if(Flag.Running) if(++Overflow > 200) Flag.Timeout = true; // The 200 is just an example, other values might be used
}
if(PIR1.CCP1IF)
{ // Save data
Time_Now.Byte[0] = CCPR1L; // Transfer the value, low byte
Time_Now.Byte[1] = CCPR1H; // Transfer the value, high byte
if(!Flag.Running)
{
Time_Diff = Time_Now - Time_Then;
}
Time_Then = Time_Now;
Overflow = 0; // Start from known state
Flag.Running = true;
PIR1.CCP1IF = false; // Acknowledge interrupt
}
}
I main-loop lägger man in:
if(Flag.Running)
{
RPM = MAGIC_CONSTANT / Time_Diff;
Flag.Running = false;
Flag.Update = true;
}
if(Flag.Timeout)
{
RPM = 0;
Flag.Timeout = false;
Flag.Update = true;
}
if(Flag.Update)
{
// Print out RPM as needed
Flag.Update = false;
}
När det är mätt ett värde aktiveras Flag.Running och det ska nollas innan en ny mätning kan utföras.
Om flaggan Flag.Timeout aktiveras kan man utgå ifrån 0 RPM.
När flaggan Flag.Update är aktiv har det kommit en uppdatering och RPM-utläsningen kan uppdateras.
Senast redigerad av Icecap 1 september 2012, 21:16:11, redigerad totalt 1 gång.
Re: Fler problem med avbrottsrutin
SeniorLemuren: Problemet med din original-put_rpm() tror jag ingen har påpekat ännu. Problemet var att dina variabler tenthousands etc. inte nollställs mellan körningarna. Flyttar man in initieringen till 0 i funktionen borde den fungera vad jag kan se. Jag skulle väl välja att inte använda globala variabler heller, men jag tänker inte klaga. 
Om unsigned int har omfånget 0-65535 (16 bitar) blir det så att 0U - 1U == 65535U.
Det är också garanterat att om man omvandlar signed-typer (eller unsigned för den delen) till unsigned så blir det som väntat och talet "rullas runt" åt det håll som krävs tills det passar i destinationsvariabeln.
Gör man overflow med signed-typer ges däremot inga som helst garantier. Det är så kallad "undefined behavior" och då tillåts vad fan som helst att hända. Inte bara att resultatet blir fel alltså, utan vad som helst kan hända!
Eventuellt kan en viss implementation välja att göra operationen väldefinierad. Exempelvis GCC gör det, men bara om man specificerar flaggan -fwrapv vid kompileringen.

C-standarden garanterar att om man räknar med unsigned-typer så rullar resultatet runt när man kommer över gränsen. Man kan tänka sig att tallinjen är ihoplimmad till en cirkel så att 0 kommer efter (2^bitar)-1, och att a - b betyder avstånd framåt i steg från b till a. Det förklarar varför tidberäkningen blir rätt även när man slår runt.gokartnisse skrev:Jag är skeptisk till att det faktiskt blir rätt om man kör och hoppas på att ALU inte tar med carryflaggan (borrow) till nästa uträkning, det blir ju rätt även om talet blir "negativt" då det är tvåkomplements matte men jag skulle inte satsa på att kompilatorn får det att bli rätt om man låter ett negativt tal gå in i en variabel som bara kan anta positiva värden. Jag skulle ha använt timer1 overflow-flagga som en 17-bit (precis som microchip beskriver i sin "Tips 'n tricks" när man mäter periodtid med en CCP modul).

Om unsigned int har omfånget 0-65535 (16 bitar) blir det så att 0U - 1U == 65535U.
Det är också garanterat att om man omvandlar signed-typer (eller unsigned för den delen) till unsigned så blir det som väntat och talet "rullas runt" åt det håll som krävs tills det passar i destinationsvariabeln.
Gör man overflow med signed-typer ges däremot inga som helst garantier. Det är så kallad "undefined behavior" och då tillåts vad fan som helst att hända. Inte bara att resultatet blir fel alltså, utan vad som helst kan hända!

Re: Fler problem med avbrottsrutin
Har inte läst alla detaljer i tråden, men jag skulle ha löst det så här:
ISR 1 tar emot interupt från givaren och uppdaterar räknare, ev med extra 8 eller 16 bitar såsom Icecap föreslår.
ISR 2 snurrar i t ex en eller två Hz och vid varje interupt så gör den ett "snapshot" på räknaren, 16, 24 eller 32 bits beroende på vad du valt samt sätter en flagga. Genom att göra detta i en egen ISR så riskerar du inte att räknaren uppdateras under utläsningen, då interrupen är avstängda under tiden.
Mainloopen kollar om flaggan är satt och i så fall räknar den ut aktuellt varvtal/presentation och skriver ut det på displayen. På detta sett sker uppdateringen regelbundet t ex en eller två ggr per sekund oavsett varvtal. Om displayen uppdateras för ofta kan det resultera i flimmer. Efter utskrift nollställs flaggan.
Se bara till att utskrift sker snabbare än ISR2 triggas.
ISR 1 tar emot interupt från givaren och uppdaterar räknare, ev med extra 8 eller 16 bitar såsom Icecap föreslår.
ISR 2 snurrar i t ex en eller två Hz och vid varje interupt så gör den ett "snapshot" på räknaren, 16, 24 eller 32 bits beroende på vad du valt samt sätter en flagga. Genom att göra detta i en egen ISR så riskerar du inte att räknaren uppdateras under utläsningen, då interrupen är avstängda under tiden.
Mainloopen kollar om flaggan är satt och i så fall räknar den ut aktuellt varvtal/presentation och skriver ut det på displayen. På detta sett sker uppdateringen regelbundet t ex en eller två ggr per sekund oavsett varvtal. Om displayen uppdateras för ofta kan det resultera i flimmer. Efter utskrift nollställs flaggan.
Se bara till att utskrift sker snabbare än ISR2 triggas.
-
- Inlägg: 120
- Blev medlem: 3 mars 2011, 01:58:43
Re: Fler problem med avbrottsrutin
kimmen: Det var som fan att det var definerat i C, det blir ju ytterligare ett bevis på att mikroC inte är det vassaste besticket i lådan.
Re: Fler problem med avbrottsrutin
ie: du har tydligen missat flaggorna jag använder för att säkra just att det inte ska bli fel med utläsningen.
Men egentligen borde man lägga till en form av utjämningsrutin till det hela så att siffrorna inte fladdrar alldeles för mycket men det får bli en senare fråga skulle jag tro.
Men egentligen borde man lägga till en form av utjämningsrutin till det hela så att siffrorna inte fladdrar alldeles för mycket men det får bli en senare fråga skulle jag tro.
- SeniorLemuren
- Inlägg: 8410
- Blev medlem: 26 maj 2009, 12:20:37
- Ort: Kristinehamn
Re: Fler problem med avbrottsrutin
Ok. Nu har jag i alla fall kollat input. Från hall-givaren och jag tycker det ser helt ok. ut.
Jag kör med skruvdragaren på högsta fart. Spänning mellan strecken 0,15 volt. Tid mellan strecken 50 ms. Ger 5 volt och 80 ms mellan pulserna. (750 r/min)
Edit: Har inte testat senaste programmet ännu.
Jag kör med skruvdragaren på högsta fart. Spänning mellan strecken 0,15 volt. Tid mellan strecken 50 ms. Ger 5 volt och 80 ms mellan pulserna. (750 r/min)
Edit: Har inte testat senaste programmet ännu.
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Re: Fler problem med avbrottsrutin
Det finns många lösningar som ger det resultat du vill ha. En lösning som jag själv ofta brukar använda i dessa sammanhang är att koppla utgången från hallsensorn till den externa klockningen på en timer i mikroprocessorn. Om det finns någon sådan på en PIC-processor vet jag dock inte. Genom detta kommer timern att räkna upp ett steg för varje puls från hallgivaren. Det brukar gå att ställa in om det skall vara på negativ eller positiv flank som räknaren ökar. Använder du en 16-bits räknare så kan du mäta upp till drygt 65 000 varv per minut.
För att få fram varvtalet per sekund kan man sedan sätta upp ytterligare en timer som ge ett interrupt vaje sekund eller att den räknar ned en variabel till noll så att det går att läsa av timern som är kopplad till hallgivaren en gång i sekunden. Varje gång man läser av hallgivaren nollställer man räknaren.
Genom att timer två är inställd för att skapa en avläsning varje sekund så får du vartalet direkt utan ytterligare beräkningar. Timerns värde lägger du lämpligast i en global variabel som du läser av i main eller i en funktion som anropas från mainloopen.
Jag brukar börja med att trimma timer två med hjälp av ett oscilloskop så att jag är säker på att det blir en sekund mellan avläsninarna. Det görs enklast genom att toggla en I/O-port där man ansluter oscilloskopets mätprob.
För att få fram varvtalet per sekund kan man sedan sätta upp ytterligare en timer som ge ett interrupt vaje sekund eller att den räknar ned en variabel till noll så att det går att läsa av timern som är kopplad till hallgivaren en gång i sekunden. Varje gång man läser av hallgivaren nollställer man räknaren.
Genom att timer två är inställd för att skapa en avläsning varje sekund så får du vartalet direkt utan ytterligare beräkningar. Timerns värde lägger du lämpligast i en global variabel som du läser av i main eller i en funktion som anropas från mainloopen.
Jag brukar börja med att trimma timer två med hjälp av ett oscilloskop så att jag är säker på att det blir en sekund mellan avläsninarna. Det görs enklast genom att toggla en I/O-port där man ansluter oscilloskopets mätprob.
Re: Fler problem med avbrottsrutin
> Om det finns någon sådan på en PIC-processor vet jag dock inte.
En timer i "counter" mod.
Det klassiska problemet vid mätning av varvtal är ju om man ska mäta
antal pulser under en viss tid, eller om man ska mäta pulstiden för
en enstaka puls. Det är en avvägning mot bl.a svarstid och med
hänsyn till det aktuella varvtalsområdet (som ska mätas).
Programmeringsmässigt är det nog enklare att mäta antalet pulser
under en fast tid, men exakt "på varvet" blir det ju inte om man
inte mäter under en hel minut, vilket kanske ger för dålig svarstid.
Om man mäter t.ex under 6 sekunder, så får man ett maximalt fel
på ca +/- 10 rpm. D.v.s om 6 sekunder är en acceptabel svarstid
för varvtalet. O.s.v.
En mätning under 7.5 sek är smidigt eftersom det blir en multiplikation
med 8 för att få "varv per minut", d.v.s 3 shiftoperationer av värdet
och ett (max) fel i mätningen på ca +/- 8 rpm.
Som vanligt så kan man göra stora förenklingar i koden genom att tänka
till lite hur man gör mätningen, t.ex genom att som ovan räkna pulser
under 7.5 sekunder istället för något annat mer "jämt".
En timer i "counter" mod.
Det klassiska problemet vid mätning av varvtal är ju om man ska mäta
antal pulser under en viss tid, eller om man ska mäta pulstiden för
en enstaka puls. Det är en avvägning mot bl.a svarstid och med
hänsyn till det aktuella varvtalsområdet (som ska mätas).
Programmeringsmässigt är det nog enklare att mäta antalet pulser
under en fast tid, men exakt "på varvet" blir det ju inte om man
inte mäter under en hel minut, vilket kanske ger för dålig svarstid.
Om man mäter t.ex under 6 sekunder, så får man ett maximalt fel
på ca +/- 10 rpm. D.v.s om 6 sekunder är en acceptabel svarstid
för varvtalet. O.s.v.
En mätning under 7.5 sek är smidigt eftersom det blir en multiplikation
med 8 för att få "varv per minut", d.v.s 3 shiftoperationer av värdet
och ett (max) fel i mätningen på ca +/- 8 rpm.
Som vanligt så kan man göra stora förenklingar i koden genom att tänka
till lite hur man gör mätningen, t.ex genom att som ovan räkna pulser
under 7.5 sekunder istället för något annat mer "jämt".
Re: Fler problem med avbrottsrutin
wapper: den mätmetod är skapligt bra vid höga varvtal medan den ger mycket låg upplösning vid låga varv. Om räknaren tar 1 steg per sekund motsvarar det 60 RPM, 2 steg ger 120 RPM, alltså i steg om 60 RPM. Vid 200 RPM blir mätresultatet alltså växlande mellan 180 och 240 RPM, knappast en bra upplösning eller pålitlig utläsning.
Samtidig är utläsningen i steg om 1 sekund vilket inte heller är användbart i detta, det är helt enkelt för långsamt. För en användbar utläsning som kan avläsas är 3 utläsningar per sekund bra men i detta fall behöver Senior mest att få stabila värden till att börja med.
EDIT: Sedan är det knappast ett problem att mäta tiden mellan pulserna och kanske även mellan fler pulser (medan man räknar antal pulser) så länga frekvensen på pulserna är skaplig låg, allt beror ju på just detta: vilken frekvens som ska mätas. I ena ytterända är den ena metod bra, i den andra är den andra metod bra och i mitten kan det vara ung. rimligt lika.
Samtidig är utläsningen i steg om 1 sekund vilket inte heller är användbart i detta, det är helt enkelt för långsamt. För en användbar utläsning som kan avläsas är 3 utläsningar per sekund bra men i detta fall behöver Senior mest att få stabila värden till att börja med.
EDIT: Sedan är det knappast ett problem att mäta tiden mellan pulserna och kanske även mellan fler pulser (medan man räknar antal pulser) så länga frekvensen på pulserna är skaplig låg, allt beror ju på just detta: vilken frekvens som ska mätas. I ena ytterända är den ena metod bra, i den andra är den andra metod bra och i mitten kan det vara ung. rimligt lika.
Re: Fler problem med avbrottsrutin
Icecap, jag har inte tolkat det som att SeniorLemuren har tändkulemotorer i sin båt och då är inte upplösningen på låga varv ett problem.
Om det är varvtalet på propelleraxeln som skall mätas så tror jag inte det skapar något problem heller ty om propelleraxeln snurrar 60 varv per minut så lär inte den tunga båten flytta sig. Med andra ord, jag tror att det är varvtal över 500 RPM eller kanske till och med uppåt 1 000 RPM som minsta belopp men det kan väl SeniorLemuren redogöra för.
Om det är varvtalet på propelleraxeln som skall mätas så tror jag inte det skapar något problem heller ty om propelleraxeln snurrar 60 varv per minut så lär inte den tunga båten flytta sig. Med andra ord, jag tror att det är varvtal över 500 RPM eller kanske till och med uppåt 1 000 RPM som minsta belopp men det kan väl SeniorLemuren redogöra för.
Re: Fler problem med avbrottsrutin
> För att få fram varvtalet per sekund...
Jag har aldrig hört talas om att man anger varvet för en motor i "varv per sekund" !
Självklart är det "varv per minut" som man vill ha.
Icecap har helt rätt när det gäller upplösningen men vad har denna motor för
tomgångvarv? Kanske 6-800 rpm? Hur det fungerar vid 200 rpm blir ju då
väldigt ointressant.
Så jag tror att en räkning av pulser inom 6-10 sek ger en helt OK upplösning (inom 6-10 rpm).
Och behövs det snabbare uppdatering av värdet än så? Hur snabbt ändrar denna motor varvtal?
Det är ju ingen rallybil direkt...
Jag har aldrig hört talas om att man anger varvet för en motor i "varv per sekund" !
Självklart är det "varv per minut" som man vill ha.
Icecap har helt rätt när det gäller upplösningen men vad har denna motor för
tomgångvarv? Kanske 6-800 rpm? Hur det fungerar vid 200 rpm blir ju då
väldigt ointressant.
Så jag tror att en räkning av pulser inom 6-10 sek ger en helt OK upplösning (inom 6-10 rpm).
Och behövs det snabbare uppdatering av värdet än så? Hur snabbt ändrar denna motor varvtal?
Det är ju ingen rallybil direkt...
