Sida 1 av 3
Enkel hastighetsmätare (programmeringsproblem)
Postat: 27 januari 2009, 15:08:57
av joakimholmberg
Hej.
Jag heter Joakim och håller på med ett projekt i skolan där jag bygger en enklare hastighetsmätare. Jag använder mig utav Microchips PIC 16F690 för beräkningarna. Jag har ett tungelement som fångar upp pulserna när hjulet snurrar.
Tyvärr har jag nu stött på ett problem med programmeringen som gör att projektet står still just nu.
Genom kompisar fick jag höra att detta forum skulle vara bra och ha många duktiga medlemmar. Eftersom jag är en nybörjare på detta så hoppas jag att ni inte skrattar ut mig om min fråga är för simpel. I projektet har jag programmerat i mikroC.
Mitt problem är följande:
När jag fångar upp signalerna med tungelemetet så använder jag mig utav CCP-enheten som är inställd i capture mode.
jag använder mig utav en while-sats för att vänta tills ccp-flaggan får ett värde och därmed kan gå vidare.
Problemet är då att programmet "fastnar" inuti while-satsen trots att magneten har gått förbi tungelementet.
Vad kan vara fel?
Hoppas att någon kan förstå sig på detta.
MVH Joakim
Re: Enkel hastighetsmätare (programmeringsproblem)
Postat: 27 januari 2009, 15:38:51
av Icecap
Skriv "while (!PIR1.CCP1IF) {}" istället.
CCP1IF kan knappast bli == 1 då den är bit 2 (vilket ger värdet 4 eller 0) medan "!PIR1.CCP1IF" betyder "sant så länge PIR1.CCP1IF inte är '1'"
Och void'en behövs inte!
Det är ett standard nybörjarproblem detta, man vill att det är vid ett visst värde som en funktion ska utlösas och då använder man "==" men man ska tänka på att det man (i detta fall) EGENTLIGEN vill veta är om den bit är sann eller falsk. Falsk är alltid 0 och allt annat är sant.
MikroC är inte vassaste kniven i lådan, jag har kollat just det problem som visas här och du skulle istället ha kollat om värdet var like med 4... men som sagt är även det ett dåligt sätt.
Re: Enkel hastighetsmätare (programmeringsproblem)
Postat: 27 januari 2009, 17:07:32
av joakimholmberg
Tack så mycket för ditt svar och din förklaring
Då kommer det troligtvis att fugera bättre.
//Joakim
Re: Enkel hastighetsmätare (programmeringsproblem)
Postat: 27 januari 2009, 17:55:07
av v-g
Glöm heller inte att du måste "nolla" räknaren. Dvs du måste först vänta på en passage då du börjar tidtagningen till nästa passage. Flera magneter är också att föredra. PICen är såpass snabb att den lätt hinner att räkna farten med 10+ magneter monterade på hjulet. Ta två men gärna 4 st så kommer du få snabb och fin uppdateringsfrekvens.
Betänk annars att ett hjul är över en meter i omkrets och vid lite lägre farter kommer uppdateringen ske typ 1 gång varannan sekund vilket ser lite trist ut när man ökar och sänker farten. Varje dubbling av antalet magneter halverar denna tid.
Re: Enkel hastighetsmätare (programmeringsproblem)
Postat: 29 januari 2009, 20:47:31
av joakimholmberg
Hej igen.
Jag har suttit och testat, men någonting är inte helt rätt. Jag har läst i databladet och andra trådar här på forumet men kan inte hitta om jag ska nollställa ccp/timer-enheten eller CCPR1H/CCPR1L-registerna ... Enligt databladet skall CCPR1H och CCPR1L skrivas över automatiskt...
Jag är också osäker på om man skall starta om timern och ccp när jag har fått ett nytt värde.
Programmet lyckas ett varv men stannar och ingenting händer. Displayen visar samma värde.
Drar in en del av koden. Jag har kanske gjort något uppenbart fel?
Kod: Markera allt
while(1)
{
T1CON=0b00110001;
CCP1CON=0b00000100;
PIR1.CCP1IF = 0;
while (!PIR1.CCP1IF){}
t1 = CCPR1H*256;
t1 += CCPR1L;
PIR1.CCP1IF = 0 ;
while (!PIR1.CCP1IF){}
t2 = CCPR1H*256;
t2 += CCPR1L;
T = t2 - t1;
IntToStr(T,svar);
Lcd_Custom_Out(1, 1, "Pulser: ");
Lcd_Custom_Out(2,1, svar );
T1CON=0x00;
CCP1CON=0x00;
}
MVH Joakim
Re: Enkel hastighetsmätare (programmeringsproblem)
Postat: 29 januari 2009, 21:05:39
av Icecap
Man mäter tiden vid att subtrahera förra värde från "nu"-värdet samt att spara undan "nu"-värdet efteråt som "förra"-värdet. Skulle det finnas overflow är det bara att skita i det om du är säker på att 2n pulstid alltid kommer att vara kortare än CCP-enhetens maximala tidmätning (16 bit tidräknaren alltså).
Sedan kör du C och då kan du ta lite genvägar:
Kod: Markera allt
typedef union
{
unsigned char Byte[2];
unsigned int Word;
} T_BYTE_N_WORD;
T_BYTE_N_WORD Time_Now, Time_Previous;
unsigned int Period;
void main(void)
{
T1CON=0b00110001;
CCP1CON=0b00000100;
PIR1.CCP1IF = 0;
while(1)
{
while (!PIR1.CCP1IF){} // Wait for CCP to capture an edge
Time_Now.Byte[1] = CCPR1H; // Read result
Time_Now.Byte[0] = CCPR1L; // Same thing
PIR1.CCP1IF = 0; // Clear flag
Period = Time_Now.Word - Time_Previous.Word; // Calculate period-time
Time_Previous.Word = Time_Now.Word; // Save for next time
... // Do whatever You need to do with the value
}
Re: Enkel hastighetsmätare (programmeringsproblem)
Postat: 30 januari 2009, 00:06:42
av gunne
Frågan är om man kan vara säker på det. Jag håller själv på med en varvräknade med halleffektelement men med AVR och jag summerar alla "overflows" oxå.
Typ såhär:
Kod: Markera allt
interrupt_timer_overflow {
overflows++;
}
interrupt_external {
ticks = TIMER + overflows*MAX(timer);
rpm = räkna ut varvtal från ticks, frekvens, prescaler m.m;
clear timer;
overflows = 0;
}
Edit: Men då måste man använda interrupts och det kanske är överkurs. Men bra att kunna.
Re: Enkel hastighetsmätare (programmeringsproblem)
Postat: 30 januari 2009, 01:26:54
av G4jm0r
Är jag extremt trött eller är inte
"while (!PIR1.CCP1IF) {}" = "while(PIR1.CCP1IF == false) {}" = "while(PIR1.CCP1IF == 0) {}"
dvs samma sak?, hur som helst så brukar man vilja använda någon form av större än eller mindre än operator i loopar för att undvika att de misslyckas på grund av att de bara kollar på ett värde, tänk om den hoppar med 2 eller 3 åt gången och hoppar över checken..
Re: Enkel hastighetsmätare (programmeringsproblem)
Postat: 30 januari 2009, 05:52:57
av Icecap
G4lm0r: Du KAN vara extremt trött men likaväl är det du skriver rätt... till viss del.
Det som kollas är IF (Interrupt Flag) vilket INTE är ett värde som sådan, bara en bit som sätts när en flank har detekterats. Alltså är '<'/'>' ganska utan betydelse, IF'en står ju kvar fram till man nollar den.
gunne: jovisst, jag har själv gjort något liknande och jag skrev ju också att det bara fungerar att skita i overflow om man är SÄKER på att tiderna är kortare än timerns maximala tid.
Jag har gjort en mätning med CCP och timer overflow inblandat där jag har en 32-bitars tidbas vid att räkna in timerns overflow och ha allt interruptstyrd, detta sätt kan relativt enkelt expanderas till att ha en tidbas på 64 bit om så önskas, i det projekt jag hade räckte det dock med en tidbas på 20 bit.
Re: Enkel hastighetsmätare (programmeringsproblem)
Postat: 1 februari 2009, 18:16:16
av joakimholmberg
Hej.
Jag har nu provat det som du skrev Icecap. Koden fungerar fint men resultatet blir likadant som tidigare. Jag får fram ett värde men ingen uppdatering sker. Jag får bara fram ett värde varje gång och programmet kommer inte vidare. Kan detta bero på overflow?
MVH Joakim
Re: Enkel hastighetsmätare (programmeringsproblem)
Postat: 1 februari 2009, 18:43:09
av Icecap
Nej!
Men om du använder MikroC kan den MÖJLIGEN göra ett misstag: när man nollar interrupt-flaggan kan den KANSKE välja fel bank och därmed nolla IE-flaggan istället. Jag har haft lite mycko fel med MikroC som jag förvisso klarade av med en fuling men jag kollade inte vidare på exakt vad som hände men alla tecken var just en bankning som sket sig.
Sedan tycker jag att du faktisk ska använda interrupten till detta "på riktigt" men det är upp till dig.
Re: Enkel hastighetsmätare (programmeringsproblem)
Postat: 1 februari 2009, 19:12:51
av joakimholmberg
Okej. Men hur gör jag då för att vara säker på att nolla den flaggan? Kan man inte nolla adressvärdet så att man är säker på att kompilatorn gör rätt?
MHV Joakim.
Re: Enkel hastighetsmätare (programmeringsproblem)
Postat: 1 februari 2009, 19:40:35
av Icecap
Förklara gärna för mig hur du sätter en bit till MERA '0' vid att sätta andra bit till '0', jag är inte säker på att jag förstår det helt faktisk. Och ett bankningsproblem har inget med bit eller byte att göra, det är helt enkelt ett kompilerproblem.
Jag antar att du faktisk VET att de pulser som ska mätas inte kommer snabbare än att din rutin hinner med och en tanke slår mig:
* HUR kan du veta att det inte händer någon uppdatering?
Det borde bara vara möjligt att ha koll på om du har kod som använder dessa värden... är du SÄKER på ett DEN inte hänger sig?
Re: Enkel hastighetsmätare (programmeringsproblem)
Postat: 1 februari 2009, 20:31:43
av joakimholmberg
Okej.
Jag vet att det inte sker någon uppdatering eftersom det alltid står samma värde på LCDn. Det är bara när tungelementet går förbi för första gången som den får ett värde, sedan händer något konstigt.
Här är hela programmet så som du skrev förut Icecap. Men det fungerar som det gjorde innan. Bara första gången som ett värde skrivs ut. Sedan "hänger" det sig.
Kod: Markera allt
typedef union {
unsigned char Byte[2];
unsigned int Word;
}T_BYTE_N_WORD;
unsigned int Period;
T_BYTE_N_WORD Time_Now;
T_BYTE_N_WORD Time_Previous;
void main(){
char svar[10];
ANSEL = 0;
ANSELH = 0;
PORTB = 0;
TRISC=00100000;
Lcd_Custom_Config(&PORTB,7,6,5,4,&PORTC,2,0,3);
Lcd_Custom_Cmd(LCD_CLEAR);
Lcd_Custom_Cmd(LCD_CURSOR_OFF);
delay_ms(500);
T1CON=0b00110001;
CCP1CON=0b00000100;
PIR1.CCP1IF = 0;
while(1)
{
while (!PIR1.CCP1IF){}
Time_Now.Byte[1] = CCPR1H;
Time_Now.Byte[0] = CCPR1L;
PIR1.CCP1IF = 0;
Period = Time_Now.Word - Time_Previous.Word;
Time_Previous.Word = Time_Now.Word;
IntToStr(Period,svar);
Lcd_Custom_Out(2,1, svar );
}
}
MVH Joakim
Re: Enkel hastighetsmätare (programmeringsproblem)
Postat: 2 februari 2009, 09:45:20
av Icecap
Men det program visar ju bara om svaret ändrar sig, inte om den inte "kommer runt" eller hur?
Jag hade lagt till en LED som växlade läge när den "kom runt" i programmet, då ser man om den hänger sig eller faktisk kör men att värden är fel.