Fler problem med avbrottsrutin * LÖST VIDEO BIFOGAD*
Re: Fler problem med avbrottsrutin
Ett tips bara: mät lika många pulser som det finns pulser per varv, alltså bara hela varv. Det eliminerar mekanisk onoggrannhet.
Re: Fler problem med avbrottsrutin
Nja, ÖDP givarna brukar väl vara hallgivare har jag för mig.
Med en hallgivare och en fast magnet, kan du använda startkransen.
Med en hallgivare och en fast magnet, kan du använda startkransen.
Re: Fler problem med avbrottsrutin
Det normala är väl att ta pulsen från tändningen (finns nog en del poster om detta tidigare).
Jag har inte lusläst tråden, så ber om ursäkt om detta avfärdats tidigare av någon anledning.
Jag har inte lusläst tråden, så ber om ursäkt om detta avfärdats tidigare av någon anledning.
Re: Fler problem med avbrottsrutin
Det är väl dieselmotorer, då brukar man iofs ta signalen från generatorn, i alla fall på äldre dieslar.
- SeniorLemuren
- Inlägg: 8410
- Blev medlem: 26 maj 2009, 12:20:37
- Ort: Kristinehamn
Re: Fler problem med avbrottsrutin
Är nog inte riktigt med på hur du tänker här. När du föreslog att man tar pulserna från startkransen så tydde jag det som att man skulle använda kuggarna för att få fler pulser. Något som du ju anser behövs. I så fall löser man ju det inte med en ÖDP-givare.TomasL skrev:Nja, ÖDP givarna brukar väl vara hallgivare har jag för mig.
Med en hallgivare och en fast magnet, kan du använda startkransen.
Så varför krångla till det för att få dit en magnet på startkransen som sitter väl oåtkommlig innanför svänghjulskåpan. Det ger ju inga fler pulser per varv än om jag placerar 2 magneter på tex. insprutningspumpens koppling eller en magnet på remskivan på vevaxeln i motorns framkant.
Det är kanske möjligt att hitta en signal från generatorn som man kan använda, men hur ser den ut rent elektriskt och vad är det för utväxling.
Som det är nu använder jag en hallgivare som jag vet driver porten på en PIC med 5 V direkt utan någon som helst anpassning och vad det gäller timingen så ska det helt klart funka bara programmeringen kommer på plats och det är just vad frågan gällde från början. Inte hur man skall plocka pulserna.
Jag har inte hunnit testa Icecaps programförslag ännu, men jag är ganska säker på att lösningen är inom synhåll.

Edit. När vi talar om äldre dieslar av mitt märke så talar vi om dieslar med likströmsgeneratorer. Växelströmsgeneratorena är ditmonterade senare.
Re: Fler problem med avbrottsrutin
Jag har räknar på MAGIC_CONSTANT och ändrat den bit i min programstump på sida två. Om du nöjer dig med en puls per varv av instrutningspumpen är det bara att dubbla värdet av konstanten, då blir RPM korrekt vid 1 puls/varv av pumpen.
Re: Fler problem med avbrottsrutin
Du behöver inte sätta nånting på svänghjulet, en ÖDP-givare innehåller en magnet och ett hallelement, vad du gör är att skapa ett magnetfält som förändras av startkransens tänder och dalar.
Re: Fler problem med avbrottsrutin
En liten uppdatering för andra som vill använda detta. Det fungerar numera hos SeniorLemuren, väldigt bra till o med och jag har skrivit in de viktiga saker här. Initieringen av portar osv. måste fortfarande göras och den delen är inte med, bara till vissa delar, det viktiga för mig var att visa hur man kan göra programmet så att det fungerar med 32 bit tidmätning.
Vid att använda flaggorna som jag gör det säkrar jag att ingen mätning spökar med utläsningen vid att t.ex. byta värde på Time_Diff mitt under en omräkning från tid till RPM.
Mätsättet är så att den 16-bit mätning som CCP1 ger expanderas med 16 bit från Timer1 overflow. Detta skapar ett 32 bit ord som tidsdifferensen sedan räknas ut på, därefter sparas bara de 16 LSB i "förra tiden" och overflow-delen av "Tid nu" nollas. Detta betyder att den nästföljande uträkning av tidsdifferensen kommer att vara korrekt.
Det finns en timeout-funktion med overflow-värdet som efter en viss tid nollar RPM, detta säkrar att det visas 0 RPM när det är ett faktum, vid vilket värde denna timeout-funktion ska ha beror såklart på vad man behöver.
Programmet är alltså bara en stomme som ge en 32 bits tidmätning med maximal upplösning, i detta fall 1MHz. Alltså kan man mäta tider upp till 4294 sekunder med en upplösning på 1µs - och det är väl helt OK. Och självklart kan man expandera antalet bit ytterligare om man vill det, jag ser dock ingen nytta just nu.
Med andra processorhastigheter blir det såklart andra upplösningar och tider men 32 bit räcker ganska långt.
EDIT: Lite småjusteringar.
Mer EDIT: Ändrat så att mätningen inte ska kunde gå fel.
Kod: Markera allt
#define false 0
#define true 1
#define _XTAL_FREQ 4000000
typedef unsigned char BYTE;
typedef unsigned int WORD;
typedef unsigned long DWORD;
typedef union
{
DWORD Dword;
WORD Word[2];
BYTE Byte[4];
} T_ALL_ACCESS;
T_ALL_ACCESS Time_Now, Time_Then, Time_Diff;
struct
{
BYTE Measured : 1;
BYTE Update : 1;
BYTE Timeout : 1;
} Flag;
DWORD RPM;
void Initiate_Hardware(void);
#define Overflow Time_Now.Word[1]
#define MAGIC_CONSTANT ((DWORD)_XTAL_FREQ * (DWORD)15)
#define TIMEOUT_LIMIT 255
#define SHIFTS 4 /* Not higher than 16, higher gives more filtering, 0 gives no filtering */
#if SHIFTS
DWORD Intermediate;
#endif // SHIFTS
void main(void)
{
Initiate_Hardware();
RPM = 0; // Initial value
Flag.Measured = false;
Flag.Update = true; // Forces a initial readout
Flag.Timeout = false;
#if SHIFTS
Intermediate = 0;
#endif // SHIFTS
while(true)
{
if(Flag.Measured)
{
RPM = (MAGIC_CONSTANT / Time_Diff.Dword); // Calculate the RPM
Flag.Measured = false; // Allow further updates
Flag.Update = true;
#if SHIFTS
Intermediate = (Intermediate - (Intermediate >> SHIFTS)) + RPM;
if(!Intermediate) Intermediate = RPM << SHIFTS; // Gives fast responce from zero
RPM = Intermediate >> SHIFTS;
#endif // SHIFTS
}
if(Flag.Timeout)
{
Flag.Timeout = false;
Flag.Update = true;
RPM = 0;
Intermediate = 0;
}
if(Flag.Update)
{ // Print out RPM as needed
// Här kan man skriva ut RPM om man vill det, en mätning är iaf. gjort
Flag.Update = false; // Mark that measurement as used
}
}
}
void interrupt(void)
{
if(PIR1.TMR1IF)
{ // ~15,26Hz
PIR1.TMR1IF = false; // Acknowledge interrupt
if(!PIR1.CCP1IF) if(Overflow < TIMEOUT_LIMIT) if(++Overflow >= TIMEOUT_LIMIT)
{ // Here after ~(TIMEOUT_LIMIT/15,26) sek, saying "0 RPM!"
Flag.Timeout = true; // Set the timed-out flag
Flag.Measured = false; // OK, a measurement is made - sort of...
}
}
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.Measured)
{
Time_Diff.Dword = Time_Now.Dword - Time_Then.Dword;
}
Time_Then.Word[0] = Time_Now.Word[0]; // Save only the lower word
Overflow = 0; // Start from known state
Flag.Measured = true;
PIR1.CCP1IF = false; // Acknowledge interrupt
}
}
void Initiate_Hardware(void)
{
// The port settings here are far from complete, only the rudimentary has been filled in
TRISC = 0xFF; // All input on PORTC
CMCON = 0x07; // No comparator inputs
CCP1CON = 0x05; // Set CCP1 to capture all rising edges
PIE1 = 0x05; // Enable CCP1 & Timer1 overflow interrupts
PIE2 = 0x00; // No other interrupts!
PIR1 = 0x00; // Clear all pending interrupts
PIR2 = 0x00; // Clear all pending interrupts
T1CON = 0x01; // Prescale 1:1, Timer1On = true
INTCON = 0xC0; // Enable GIE & PEIE
}
Mätsättet är så att den 16-bit mätning som CCP1 ger expanderas med 16 bit från Timer1 overflow. Detta skapar ett 32 bit ord som tidsdifferensen sedan räknas ut på, därefter sparas bara de 16 LSB i "förra tiden" och overflow-delen av "Tid nu" nollas. Detta betyder att den nästföljande uträkning av tidsdifferensen kommer att vara korrekt.
Det finns en timeout-funktion med overflow-värdet som efter en viss tid nollar RPM, detta säkrar att det visas 0 RPM när det är ett faktum, vid vilket värde denna timeout-funktion ska ha beror såklart på vad man behöver.
Programmet är alltså bara en stomme som ge en 32 bits tidmätning med maximal upplösning, i detta fall 1MHz. Alltså kan man mäta tider upp till 4294 sekunder med en upplösning på 1µs - och det är väl helt OK. Och självklart kan man expandera antalet bit ytterligare om man vill det, jag ser dock ingen nytta just nu.
Med andra processorhastigheter blir det såklart andra upplösningar och tider men 32 bit räcker ganska långt.
EDIT: Lite småjusteringar.
Mer EDIT: Ändrat så att mätningen inte ska kunde gå fel.
Senast redigerad av Icecap 9 september 2012, 08:31:55, redigerad totalt 2 gånger.
- SeniorLemuren
- Inlägg: 8410
- Blev medlem: 26 maj 2009, 12:20:37
- Ort: Kristinehamn
Re: Fler problem med avbrottsrutin
Så blev det. Med tålmodig hjälp av Icecap
så funkar nu varvräknaren utan kuggkransar och dyl. Den mäter med hjälp av en hallgivare och en magnet varvtal ner till mindre än 10 r/m utan problem. Problemet var ju att kunna mäta tillräckligt låga varvtal, högre varvtal är inga problem.
Provbänken består av en gammal sliten skruvdragare som har hög och låg växel. den går tyvärr inte att köra så där väääldigt långsamt eller fort. Det som hörs skrapa och knäppa är när jag ställer om växeln på den.
Som grädde på moset så fick jag lära mig en del om C-programmering i den högre skolan av Icecap.
Lade in en liten filmsnutt för skojs skull.
Edit: Icecap han före med sitt inlägg.

Provbänken består av en gammal sliten skruvdragare som har hög och låg växel. den går tyvärr inte att köra så där väääldigt långsamt eller fort. Det som hörs skrapa och knäppa är när jag ställer om växeln på den.
Som grädde på moset så fick jag lära mig en del om C-programmering i den högre skolan av Icecap.

Lade in en liten filmsnutt för skojs skull.
Edit: Icecap han före med sitt inlägg.

Re: Fler problem med avbrottsrutin
Jag ser att du har lagt in den "ska ändra sig minst 5 RPM innan uppdatering sker". Snyggt!
- SeniorLemuren
- Inlägg: 8410
- Blev medlem: 26 maj 2009, 12:20:37
- Ort: Kristinehamn
Re: Fler problem med avbrottsrutin * LÖST VIDEO BIFOGAD*
Lade in denna rutin.
Kod: Markera allt
void Check_RPM(void)
{
if (RPM >= RPMOLD + 5 || RPM <= RPMOLD - 5)
{
RPM = RPM / 5;
RPM = RPM * 5;
Print_RPM();
}
RPMOLD = RPM;
}
Re: Fler problem med avbrottsrutin * LÖST VIDEO BIFOGAD*
Blir inte det där knasigt? Borde inte RPMOLD = RPM; vara inuti if-satsen? Det där ser väl mer ut som att displayuppdatering sker om motorns acceleration är snabbare än +-5 RPM per mätning.
Det där att använda overflow och input capture tillsammans för att få utökad timerlängd har jag använt tidigare, men något att se upp med är vad som händer om input capture sker precis före overflow och man kommer in med båda flaggorna satta i interruptet (förutsatt att er processor gör det). I det fallet blir mätningen fel i det här fallet.
Min lösning var att jämföra capturevärdet med 0x8000 (på en 16-bitars timer) i det fall antalet overflow hade uppdaterats i samma interrupt. Om capturevärdet är större än 0x8000 hände input capture före overflowen och man får dra bort ett från overflowantalet i uträkningen av tiden. I det andra fallet blir det som vanligt.
Det där att använda overflow och input capture tillsammans för att få utökad timerlängd har jag använt tidigare, men något att se upp med är vad som händer om input capture sker precis före overflow och man kommer in med båda flaggorna satta i interruptet (förutsatt att er processor gör det). I det fallet blir mätningen fel i det här fallet.

Min lösning var att jämföra capturevärdet med 0x8000 (på en 16-bitars timer) i det fall antalet overflow hade uppdaterats i samma interrupt. Om capturevärdet är större än 0x8000 hände input capture före overflowen och man får dra bort ett från overflowantalet i uträkningen av tiden. I det andra fallet blir det som vanligt.
Re: Fler problem med avbrottsrutin * LÖST VIDEO BIFOGAD*
Jag får hålla med kimmen om att den rad bör flyttas.
Och det är sant att det finns ett läge där de två funktioner kan komma i konflikt med varandra, i detta fall kan det vara vid Capture-värden runt 0xFFFF och möjligen några steg innan. Jag har dock bedömd att för att visa RPM ville det vara likgiltigt då det bara är en visning.
EDIT: Har nu ändrat lite i programmet ett par inlägg uppåt så att detta problem med fel synkronisering mellan overflow och Capture ska undvikas.
Senior: den ändring som bör göras ska bli till:
Och det är sant att det finns ett läge där de två funktioner kan komma i konflikt med varandra, i detta fall kan det vara vid Capture-värden runt 0xFFFF och möjligen några steg innan. Jag har dock bedömd att för att visa RPM ville det vara likgiltigt då det bara är en visning.
EDIT: Har nu ändrat lite i programmet ett par inlägg uppåt så att detta problem med fel synkronisering mellan overflow och Capture ska undvikas.
Senior: den ändring som bör göras ska bli till:
Kod: Markera allt
void Check_RPM(void)
{
if((RPM >= RPMOLD + 5) || (RPM <= RPMOLD - 5))
{
RPMOLD = RPM;
RPM = RPM / 5;
RPM = RPM * 5;
Print_RPM();
}
}
- SeniorLemuren
- Inlägg: 8410
- Blev medlem: 26 maj 2009, 12:20:37
- Ort: Kristinehamn
Re: Fler problem med avbrottsrutin * LÖST VIDEO BIFOGAD*
Japp, jag såg det, man missar någon uppdatering här och där när man uppdaterar OLD vid varje avbrott. 

Re: Fler problem med avbrottsrutin * LÖST VIDEO BIFOGAD*
Sedan kan du ju göra det lite lättare att läsa och ändra om du vill:
Kod: Markera allt
#define CHANGE_BEFORE_UPDATE 5
void Check_RPM(void)
{
if((RPM >= RPMOLD + CHANGE_BEFORE_UPDATE) || (RPM <= RPMOLD - CHANGE_BEFORE_UPDATE))
{
RPM -= RPM % CHANGE_BEFORE_UPDATE;
RPMOLD = RPM;
Print_RPM();
}
}