Mäta en puls med ccp och timer

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Mäta en puls med ccp och timer

Inlägg av Kalf »

Hej som rubriken, så vill jag mäta hur lång tid en puls är etta. Då hade jag tänkt mig att använda CCP modulen tillsammans med Timer1 i min PIC16F628A. Men jag fattar inte riktigt hur allting fungerar. Jag har ängnat hela eftermiddagen att läsa i databladet. Nu börjar jag förstå de mästa, men några saker är fortfarande oklara.

Pulsen jag skall mäta kommer in på ben RB3/CCP1 på PIC'en Den är emellan 115uS och 18,5mS. Det jag vill göra är att starta Timer1 när pulsen börjar (Rising edge, positiv flank) och stoppa den när den slutar (Falling edge, negativ flank) Och då läsa av värdet på CCPR1L & CCPR1H. Om jag fattar det rätt så kopierar den över värdet på TMR1L & TMR1H när det kommer en negativ flank om jag ställer in CCP1M<3:0> i registret CCP1CON till 0100.

Så det jag skall göra är att:

1. starta timern när det kommer en positiv flank.
2. när det kommer en negatv flank kopieras värdet på TMR1L & TMR1H över till CCPR1L & CCPR1H
3. Reset'a timern
4. Använda värderna i CCPR1L &CCPR1H och sedan rensa de med.

Det jag egentligen inte vet är:
1. Hur jag startar timern när det kommer en positiv flank.
2. Hur jag tar reda på ifall jag skall använda prescalern i timern.

Tack på förhand
//Kalf
bearing
Inlägg: 11677
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Inlägg av bearing »

1.
Vid initiering:
-Ställ in så att TMR1 alltid nollställs vid triggning samt triggar på positiv flank. Sätt igång timern.

Vid CCP1IF:
-Om den triggat på positiv flank: Ställ in triggning på neg. flank
-Om den triggat på negativ flank: Ställ in triggning på pos. flank samt spara CCPR1

2.
Kör antingen alltid högsta presc, eller börja alltid med presc 1 och:
Vid TMR1IF:
Lägg in 0x10000/2 i TMR1 och dubblera prescalern.
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Inlägg av Kalf »

>Ställ in så att TMR1 alltid nollställs vid triggning samt triggar på positiv flank. Sätt igång timern.

Detta har jag letat efter i databladet, men inte hittat. Det jag hittat är:
bit 1 i T1CON heter TMR1CS Citat: Timer1 Clock source select bit
1=External clock from pin RB6/T1OSO/T1CKI/PGC(on the rising edge)
0=Internal Clock (Fosc/4)


Jag kan inte koppla pulsen till RB6 eftersom CCP modulen kräver att Pulsen skall komma på RB3. Så därför hade jag tänkt och sätta den biten till 0 eftersom det står senare att ifall man vill köra i timer mode istället för countermode så skall den vara satt till 0a

Jag fattar inte var jag ställer in det.

//Kalf
bearing
Inlägg: 11677
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Inlägg av bearing »

Det står i kapitlet om CCP-enheten. REgistret CCP1CON har jag för mig.
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Inlägg av Kalf »

bara så vi är på det klara, det är capture mode jag skall använda va? och inte compare, för det har jag inte läst något om.

//Kalf
bearing
Inlägg: 11677
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Inlägg av bearing »

Jepp!
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Inlägg av Kalf »

Nu har jag läst det kapitlet en gång till och kommit fram till att jag skall göra på följande sätt:

1. Konfiguera CCP så att den reagerar på positiva flanker
2. När en flankkommer så sker en interrupt.
3. I denna interrupt'en så konfigueras och startas timern.
4. CCP'n konfigueras om för att detektera negativa flanker.
5. När detta sker så kopieras värdet på timern till CCP registret.

Allting funkar som det skall, är det rätt?

//Kalf
Användarvisningsbild
vfr
EF Sponsor
Inlägg: 3515
Blev medlem: 31 mars 2005, 17:55:45
Ort: Kungsbacka

Inlägg av vfr »

Gör du på det sättet så kan få du ett visst jitter/onoggrannhet just vid starten eftersom det blir en fördröjning från pulsen till avbrottet hunnit reagera och att koden sedan startar timern. Kanske inte noggrannheten behöver vara så fruktansvärt hög, då det ändå är ett fåtal klockcykler vi talar om.

Det noggrannaste sättet att göra det, är att låta timern vara igång och sedan ta _både_ den positiva och den negativa flanken med capture. Sedan subtraherar man värdena från varandra. Finns det risk att timern slår runt så får man även hålla koll på det avbrottet. Precis som sagts så växlar man "flankbiten" i konfigen varje gång avbrottet kommer.

Det största problemet med denna metod är att mäta riktigt korta pulser där man inte hinner svara på det första avbrottet och ställa om timern innan nästa kommer. Fast då har man problem med dom flesta metoder...
bearing
Inlägg: 11677
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Inlägg av bearing »

Det blir lika hög nogrannhet med min metod, men den har fördelen att man kan använda variabel prescaler på ett enkelt sätt. Det kanske även går med frilöpande timer, men det kan bli problem då om timern slår runt medans ett interrupt sker.
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Inlägg av Kalf »

Hej, hitils ser min kod ut enligt följande: Vad har jag glömt? Det är säkert något :-P Skrivet i C

Kod: Markera allt

/****************************************
*                                       *
*    Safety Electronics UF              *
*                                       *
*    Programerad av: Karl-fredrik       *
*    Datum: 2006-11-30                  *
*    Version: V.0.3                     *
*                                       *
****************************************/

void start_pulse(void);
void recive(void);
void count(void);

int CCP_Value_1_L;
int CCP_Value_1_H;
int CCP_Value_2_L;
int CCP_Value_2_H;
int CCP_Result_L;
int CCP_Result_H;

void main()
     {
     while(1)
             {
             TRISA = 0;
             TRISB = 0;
             PORTA = 0x00;              //0'ställer Alla utgångar
             start_pulse();
             TRISB = 1;                 //PORTB.3 blir ingång
             recive();
             }
     }

void start_pulse(void)
     {
     PORTB = 0x00;
     PORTB = 0b00001000;                //1 skickar en puls till ping)))...
     delay_us(5);                       //...Som varar i 5us
     PORTB = 0x00;                      //0'ställer igen
     }
     
void recive(void)
     {
     T1CON = 0b00110001;                //startar timer 1 med prescaler 1:8
     CCP1CON = 0b00000101;              //Sätter igång CCP'n, positiv flank
     while(PIR1.CCP1IF == 0)            //Väntar på flank
                       {
                       void;
                       }
     PIR1.CCP1IF = 0;
     CCP_Value_1_L = CCPR1L;            //Stoppar in värdet på CCPR1L i en varabel...
     CCP_Value_1_H = CCPR1H;            //Samma med CCPR1H
     CCPR1L = 0x00;                     //Nollställer dessa två
     CCPR1H = 0x00;
     CCP1CON = 0b00000100;              //Ställer om för negativa flanker
     while(PIR1.CCP1IF == 0)            //Väntar igen
                       {
                       void;
                       }
     PIR1.CCP1IF = 0;                   //Nollställer interuppt registret
     CCP_Value_2_L = CCPR1L;            //Stoppar in i varablar
     CCP_Value_2_H = CCPR1H;
     T1CON = 0x00;                      //Stoppar timern
     count();
     }
     
void count(void)
     {
     CCP_Result_L = CCP_Value_2_L - CCP_Value_1_L;
     CCP_Result_H = CCP_Value_2_H - CCP_Value_1_H;
     }
Änså länge gör den inget, men nu några nya frågor:
1. CCP_Result_L & CCP_Result_H Är resultatet utav hur lång pulsen är, hur lägger jag ihop dessa till ett enda långt tal i C?
2. När jag gjort som jag har, i vilket talsystem är CCP_Result_L & CCP_Result_H, decimala?
3. När jag fått reda på hur lång pulsen är, hur räknar jag om det i mS?

//Kalf
Användarvisningsbild
vfr
EF Sponsor
Inlägg: 3515
Blev medlem: 31 mars 2005, 17:55:45
Ort: Kungsbacka

Inlägg av vfr »

bearing> Jag missförstod nog dig. Jag fattade det som att du menade igångsättning av timern på första avbrottet och inte av triggningen i sig. När jag läste en gång till så greppade jag vad du menar. :)
bearing
Inlägg: 11677
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Inlägg av bearing »

Jag skulle använt interrupts till detta, enklare tycker jag. Dessutom kan man använda kod i main() till annat medans man väntar på pulserna. T.ex. skicka värdet någonstans/visa på display.

1. I min kompilator skriver man t.ex. period.high8=CCP1H; period.low8=CCP1L;
Det funkar även med period=CCP1H<<8 + CCP1L; (mer generellt)
Där period är 16 bitars unsigned.

2. Om man gör som ovan blir period = antalet instruktionscykler mellan flanker dividerat med prescalern. Decimalt, binärt, hexidecimalt eller oktalt beroende på hur väljer att se på det. Värdet är samma oavsett.

3. Tid [ms] = period * 1000 * 4 * prescaler / Klockfrekvens
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Inlägg av Kalf »

Jag vet att man kan skriva kod i main(), men jag vill ha main() så ren som möjligt och lägga saker i funktioner istället, men det är jag det. Jag skall senara kolla ifall värdet ligger innom en viss gräns så skall jag tända en LED. ;-)

svar på 1. Jag använder mikroC, skall testa detta imrgon då jag stängt av den datorn jag programerar på.

svar på 2. Det jag tänkte på är att en int är 32bitar(iaf. i C++) och eftersom jag knappt programerat i C innan, när jag programerat PIC'ar. För i C++(för PC) använder jag bara decimala tal. Men 16 bitar är 16 bitar oavsätt i vilket talsystem man plockar ut det med kom jag på nu, när du sa det. :-p

svar på 3. tack nu skall jag räkna lite :-P

Tack för detta, jag återkommer imorgon med reultat, nu skall jag räkna lite tid och plugga, har prov i digitalteknik A imorgon, det skall nog gå bra:-P.
//Kalf
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Jag vet att man kan skriva kod i main().... lägga saker i funktioner istället...

I just det här fallet så är jag säker på att *all* kod antingen direkt
i main() eller *anropade* från main() anses tillhöra main(). Det spelar
(i detta fall) alltså ingen roll om det är funktioner eller inte.

Detta för att skillja det från kod som ligger i en interrupt rutin...

Det var det som bearing avsåg med att "använda kod i main() till annat".
(Är jag ganska överygad om... :-) )
bearing
Inlägg: 11677
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Inlägg av bearing »

Precis som sodjan skriver. Menar inte just i main()-funktionen, utan att i "huvudprogrammet" - det som inte sker i interrupt. I huvudprogrammet kan man göra en massa grejer medans interrupten kör sina processer "parallellt".
Skriv svar