Rotationssensor (mikroC)

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Greve Hamilton
EF Sponsor
Inlägg: 544
Blev medlem: 4 september 2004, 15:03:35
Ort: GBG

Rotationssensor (mikroC)

Inlägg av Greve Hamilton »

God afton,

Tänkte att jag skulle utnyttja mitt medlemsskap lite... :roll:

Jag har pulat lite med en rotationssensor som jag har tänkt skall räkna upp/ned (CW/CWC) på en variabel, vilkets värde sedan skall skrivas till en LCD. Sensorn ger pulser på två ben, varav det ena är fasvridet 90grader. Dessa båda är försedda med varsitt pull-up och går sedan till PortC på en PIC16F877A (20MHz).

Kom över denna snutt på nätet:

Kod: Markera allt

char M;
char E;
.
.
M = 0x64;
E = 0;
.
.
while (1) {

     E.F0 = PORTC.F6;
     E.F1 = PORTC.F7;

     if (E == 0b0001) M--;
     if (E == 0b0100) M++;

     E.F2 = E.F0;
     E.F3 = E.F1;
.
.
}
Det fungerar sådär. Visst, den gör vad den ska, men man måste snurra på sensorn väldigt långsamt. Med andra ord verkar det som att programmet inte hänger med pulserna. Antagligen är programmet för långsamt, eller så får PIC:en fula pulser (vilket jag iofs inte tror).

Någon måste nog ha en bättre lösning.

Jag har skrivit ett program tidigare (i mBasic, iofs) som fungerade bra, men då använde jag mig av en flip-plop och två and-grindar, innan PIC:en, så man enbart få pulser på ena benet vid CW och vise versa. Men den lösningen har jag inte tillgång till i nuläget. Externa interupt är inte heller något som kan användas nu. Måste använda PORTC.

Är inte speciellt i bevandrad i programmeringsmetoder, så hjälp mottages tacksamt.

Sov gott!
Användarvisningsbild
strombom
Inlägg: 3305
Blev medlem: 27 maj 2003, 10:50:20
Ort: Västra Götaland
Kontakt:

Inlägg av strombom »

säker på att du inte får kontaktstudsar, lär ju inte skada med två små kondingar ?
Användarvisningsbild
Icecap
Inlägg: 26685
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

EDIT: DARN! Ledsen Icecap, råkade editera sönder ditt inlägg. Ska se om jag kan återställa det. Ber om ursäkt för det. //chille
bearing
Inlägg: 11678
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Inlägg av bearing »

Synd att du måsta använda PORTC, för då måste du ju polla och kan alltså missa om du gör annat i poll-loopen.

Att använda interrupt on change på PORTB.4-7 är annars idealiskt för detta.
Användarvisningsbild
Greve Hamilton
EF Sponsor
Inlägg: 544
Blev medlem: 4 september 2004, 15:03:35
Ort: GBG

Inlägg av Greve Hamilton »

Jo jag har två små kondingar där också, glömde bara nämna det (såklart). 2x10nF, det är väl lämpliga värden?

Icecap:
Ditt program fungerade faktiskt bättre. Dock inte bra nog. Speciellt långsamt måste man snurra för att få värdet att gå ned (Result--). Jag skulle tro att anledningen till att det går så segt, är att jag gör ganska mycket saker i samma while-loop (adc_read, spi osv.).

Jag får ta och koppla upp en testplatta och försöka få till det med interrupt, ikväll. Jag har emellertid aldrig använt mig av interrupt, men det har säkerligen nämnts massor av gånger här på forumet hur det går till, så det löser sig nog. Annars får jag återkomma.
bearing
Inlägg: 11678
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Inlägg av bearing »

Kondingarnas värden bör du räkna ut baserat på vilka pullup-motstånd du har och hur snabbt sensorn snurrar. Tidskonstanten, RC bör inte vara större än halva periodtiden för signalen tycker jag. Är det vettigt?

När vi använde en sån här i skolan hade vi inget studs-filter alls och det funkade.

Här finns ett exempel på hur interrupt används för detta. (Annan kompilator dock.)
http://www.isk.kth.se/kursinfo/6b2266/quad/rbint.htm
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Ett vanligt sätt att läsa dessa är att använda ett timer imterrupt.

Jag gjorde en rutin som kollade sensorn med 400 Hz intervall och jämförde
ingångar med förra läget. Beroende på utfallet är det "framåt" eller "bakåt".

Även med ett timer interrupt på 400 Hz så behövs mindre än 5% av
processorns tillgängliga cykler vid 20 Mhz. Jag minns inte exakt, men
det var snarare 1-2 %.

Om man vred väldigt fort ("snärtade" till), så kunde man få felaktiga
avläsningar, men det kan man i princip få med alla lösningar...

"Studsfiler" är mest användbart om man kopplar sensorn till interrupt
ingångar, med pollning är de betydligt mindre nödvändiga. Det studsar
färdigt mellan avläsningarna i alla fall.
Användarvisningsbild
Greve Hamilton
EF Sponsor
Inlägg: 544
Blev medlem: 4 september 2004, 15:03:35
Ort: GBG

Inlägg av Greve Hamilton »

Här kommer jag igen!

Har läst på lite om timers och interrupt. Det visade sig vara lättare än vad jag först trodde. Allt stod ju trots allt i databladet, det kluriga var bara att luska ut vad allt betydde och vad de hade för relationer med varandra. Timern (TMR0) fick jag att fungera precis som jag ville, men interrupten jäklas med mig.

Jag försöker få ISR:n att avbryta while-loopen och sedan hålla PORTD noll i 1s. Men när jag startar, så verkar det inte ens som om while-loopen körs; lysdioden jag satt dit på ett av PORTB's ben blinkar inte alls.

Har jag fattat något fel så säg till!

Kod: Markera allt

// PIC16F877A @ 20MHz

void interrupt () {
     if ( INTCON.RBIF == 1 ) {     /* behövs detta verkligen? */
        PORTD = 0;
        delay_ms(1000);
        INTCON.RBIF = 0;           /* nolla interrupt-flaggan */
     }
}

void main () {

TRISD = 0;
TRISB = 1;

INTCON.GIE = 1;             /* tillåt alla interrupt */
INTCON.RBIE = 1;            /* slå på förändringsinterrupt på <RB7:RB4> */

PORTD = 0;

while (1) {
      PORTD = ~PORTD;
      delay_ms(500);
      }
}
Förresten, i databladet, betyder 1:an som står i t.ex. R/W-1 (ovanför bit i registerförklaringar), att just den biten är 1 som default?

Nu kanske tråden spårade ut lite, men målet är fortfarande som tidigare, gäller bara att få fart på interrupten först. :)

Tacksam för hjälp!
Användarvisningsbild
Icecap
Inlägg: 26685
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

1: if (INTCON.RBIF) behövs om man har fler interrupts som är aktiverade. Vid att skriva som jag gjorde frågs det bara efter om den är noll eller annat, detta går snabbare då det är en bit. Man kan även skriva 'if(!INTCON.RBIF)' om man vill kolla om den är noll.

2: I ditt programexempel ser jag ingen start av timern och jag ser en "katastrofal" fel: delay_ms(1000); Sånt gör man inte i en interrupt!!!! Du använder till o med SAMMA rutin i main-loopen, var returnerar den då?

3: Ville det inte vara bättre att ha timer-interrupten att inkrementa en variabel och sedan i mainrutinen lägga ut en av biterna till en LED? då kommer blinkandet av timer-interrupten ju.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Allt stod ju trots allt i databladet,...

"Trots allt" ??? Det är väl självklart att det gör det... :-)

> Förresten, i databladet, betyder 1:an som står i t.ex. R/W-1 (ovanför bit
> i registerförklaringar), att just den biten är 1 som default?

Jo, men det är inte så intressant.
Om biten i fråga har betydelse för din applikation, så sätt den som du
vill ha den *oavsett* vad som är default. Om inte annat så talar det om för
oss andra att du faktiskt har tänkt över det och gjort ett medvetet val, och
du slipper frågor om just den biten. Koden blir också mer lättläst, eftersom
(speciellt vi andra som inte har kollat) man slipper slå upp databladet i onödan.

Så regeln är, sätt alla bitar som påverkar applikation som du vill ha dom.

Som Icecap noterde, delays i en ISR är no-no. Utom möjligtsvis om de är
mycket korta, som ett par cykler eller us, men absolut inte 1 sek !!

> Timern (TMR0) fick jag att fungera precis som jag ville,

Jasså ? Det syns inte i koden...

Slutligen så "kan" jag inte denna C-variant, men jag hoppas att
delay_ms() inte kopplar bort interrupt under tiden (sannolikt inte...).

Ditt kodexempel ser lite konstigt ut, kan du beskriva vad du vill uppnå ?
Användarvisningsbild
JimmyAndersson
Inlägg: 26603
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

Sant, delay_ms() kopplar inte bort interruptet, så där är det lugnt.
Användarvisningsbild
Greve Hamilton
EF Sponsor
Inlägg: 544
Blev medlem: 4 september 2004, 15:03:35
Ort: GBG

Inlägg av Greve Hamilton »

Nej, jag var nog lite för otydlig.

Det var inte meningen alls att timern skall användas i programmet. Den testade jag i ett annat program, och fick den att fungera. Detta är enbart ett test av RB change interrupt.

"1: if (INTCON.RBIF) behövs om man har fler interrupts som är aktiverade. Vid att skriva som jag gjorde frågs det bara efter om den är noll eller annat, detta går snabbare då det är en bit. Man kan även skriva 'if(!INTCON.RBIF)' om man vill kolla om den är noll."

Och eftersom jag enbart har en interrupt aktiverad, så kan jag ta bort den. Om jag tolkar dig rätt.

"...och jag ser en "katastrofal" fel: delay_ms(1000); Sånt gör man inte i en interrupt!!!!"

Mja, det är möjligt att det är god programmeringssed att inte göra det, men i ett av exemplen från mE själva används delay_ms() i interrupt, så det borde inte ge några problem. Jag avlägsnar allt som har med delay_ms() att göra över huvud taget, ändå.

Jag förenklar programmet lite:

Kod: Markera allt

// PIC16F877A @ 20MHz

char a;

void interrupt () {
        a = ~a;
        INTCON.RBIF = 0;           /* nolla interrupt-flaggan */
}

void main () {

TRISD = 0;
TRISB = 1;

INTCON = 0x88;       /* slå på förändringsinterrupt på <RB7:RB4> & GIE = 1 */
a = 1;

while (1) {
      PORTD = a;
      }

}


Denna gång kanske lite lättare att se vad jag vill åstadkomma. PORTB-pinnarna i fråga hålls nere av externa pull-down motstånd och när någon av dessa går från låg till hög, sätts PORTD till 0. När nästa förändring sker (hög -> låg), sätts PORTD till 1.
Det fungerar fortfarande inte. PORTD blir aldrig hög, av vad som kan ses av blotta ögat mha LED.

Vad har jag missat?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

*Hur* går PORTB pinnarna hög ?
D.v.s med vad ?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

En annan sak,
var "clearar" du PORTB's "missmatch condition" ?
Har du missat det, får du läsa på lite i kapitlet om
om PORTB...
Användarvisningsbild
Greve Hamilton
EF Sponsor
Inlägg: 544
Blev medlem: 4 september 2004, 15:03:35
Ort: GBG

Inlägg av Greve Hamilton »

Den går hög via en sladd som jag petar ned i hålraden där något av benen är nedstuckna på lappplattan (+pull-down), till +5V. :)

Vad jag fått fram av databladet om mismatch condition är att det kan avslutas genom att läsa/skriva PORTB, för att man sedan skall kunna cleara RBIF. Annars kommer flaggan att sättas om och om igen.
Så jag skall alltså läsa eller skriva tll PORTB innan jag nollar RBIF? Är jag på rätt spår?
Skriv svar