Sida 1 av 6
Mäta en puls med ccp och timer
Postat: 30 november 2006, 17:51:48
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
Postat: 30 november 2006, 18:44:53
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.
Postat: 30 november 2006, 19:01:36
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
Postat: 30 november 2006, 19:04:25
av bearing
Det står i kapitlet om CCP-enheten. REgistret CCP1CON har jag för mig.
Postat: 30 november 2006, 19:09:43
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
Postat: 30 november 2006, 19:10:40
av bearing
Jepp!
Postat: 30 november 2006, 19:22:06
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
Postat: 30 november 2006, 19:41:59
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...
Postat: 30 november 2006, 19:58:17
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.
Postat: 30 november 2006, 20:36:14
av Kalf
Hej, hitils ser min kod ut enligt följande: Vad har jag glömt? Det är säkert något

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
Postat: 30 november 2006, 21:08:04
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.

Postat: 30 november 2006, 21:24:39
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
Postat: 30 november 2006, 21:43:41
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.
svar på 3. tack nu skall jag räkna lite
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
Postat: 30 november 2006, 22:06:10
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...

)
Postat: 30 november 2006, 22:10:56
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".