PWM @ PIC16F877A - hjälp

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
$tiff
Inlägg: 4941
Blev medlem: 31 maj 2003, 19:47:52
Ort: Göteborg
Kontakt:

PWM @ PIC16F877A - hjälp

Inlägg av $tiff »

Nu har jag äntligen köpt mig en programmerare (ISP-PRO, säljes på Elfa) som pallar de flesta (alla?) PICar och lite annat mums.

Nu vill jag ju naturligvis leka med de smaskiga funktionerna de lite tuffare PICarna har att erbjuda (tuffare än PIC16F84A, d.v.s. alla :roll: ).

Vad jag är ute efter först och främst är hårdvaru-PWM-funktionen hos PIC16F877A. Jag vill ha den att oscillera IR-LEDs på 38kHz med 50% dutycycle. Ja, det är IR-modulering jag håller på med.

Jag kör med PicBasic. Här finns en färdig funktion, "HPWM", där man lätt kan ställa in duty och frekvens. Men naturligtvis finns en hake; högsta tillåtna frekvens med denna funktion är ca 32767Hz (signerat 16-bitstal?). Och jag vill ju ha 38kHz.

Så då är det bara att öppna databladet för prollen och leta upp PWM-konfigurationen. Har läst igenom den några gånger nu och har fortfarande några frågetecken att räta ut.
Processorn jag använder är som sagt en 877A som tuffar på i 20Mhz.

Jag hittade den här sidan som gör precis det jag vill göra, fast med en 4MHz kristall, så alla registerna är fel inställda för att köras på 20MHz. Hursomhelst vill jag ju ändå lära mig hur det går till att konfigurera PWMen "på riktigt".
Jag kikar i databladet och hittar en flock formler för hur man räknar fram registervärdena. Matte har jag räknat förut. Inga problem:
[besparar er en massa uträkningar och hoppas de är rätt]
PR2 = 131
Resolution = 9bits
Duty = 66

Trevligt. Men vad är det egentligen jag räknar fram? Jag syftar på max resolution. Vad ska man ha det till? Och så var det dutyn: Detta omvandlar jag till ett 10-bitstal: 66 = 0001000010.
Hur ska man nu stoppa in detta i registerna, med tanke på att de är delade?

Saxat från databladet:
The PWM duty cycle is specified by writing to the CCPR1L register and to the CCP1CON<5:4> bits. Up to 10-bit resolution is available. The CCPR1L contains the eight MSbs and the CCP1CON<5:4> contains the two LSbs.

Som jag fattat det ska de två första bitsen (d.v.s. de två bitsen längst till höger) in i CCP1CON bit 5 och 4. Resten i CCPR1L?


Så här tycker jag registerna ska se ut:

Kod: Markera allt

TRISC.2 = 0            'PortC.2 output
CCP1CON = %00001100    'PWM-mode
T2CON = %00000100      'Timer2 ON + 1:1 prescale
CCP1CON = %00100000    '50% duty
CCPR1L = %00010000     '50% duty
PR2 = 131              '38kHz @ 20MHz OSC

Jag bränner in prgrammet i PICen och finner att LEDsen blinkar med modulerat ljus eftersom mina avstämda IR-mottagare mottagarna reagerar på ljuset ibland. Men bara lite. Alltså är det något som inte stämmer helt. Tyvärr strejkar mitt oscilloskop så jag kan inte undersöka vad jag får ut för frekvens/duty :( . Det vore väldigt snällt om någon ville hjälpa mig med att reda ut dessa register så jag kan PWMa hur mycket jag vill i framtiden :D
Det finns ju en risk att jag har fattat rätt och att det är hårdvaran som skojar med mig.
hebbe
Inlägg: 162
Blev medlem: 29 maj 2003, 00:45:20

Inlägg av hebbe »

Från boken 'Mikrodatorteknik' av Lars Bengtsson (16C64):

Under tiden som Timer 2 räknar upp, jämförs dess innehåll dels med CCPR1H-registret, dels med PR2-registret, varav det senare är laddat med ett större värde än det förra.

När innhehållet i CCPR1H och TMR2 överenstämmer, resettas RS-vippan. En stund senare, när innehållet TMR2 och PR2 överensstämmer, händer tre saker samtidigt:

1) RS-vippan sätts till ett
2) TMR2 resettas
3) Innehållet i CCPRL1L överförs till CCPR1H

[figur]

Därmed kan vi dra följande slutsatser:

1) Det är innehållet i PR2 som avgör hur lång perioden blir, därav namnet 'period register'.
2) Det är innehållet i CCPR1H som avgör pulslängden, dvs duty cylen.

Observera att i PWM-moden är inte CCPR1H-registret skrivbart utan man måste skriva till CCPR1L-registret. Överföringen sker sedan automatiskt till CCPR1H när TMR2 resettas.

...

Kod: Markera allt

bsf	3,5	;välj registersida 1 (PWM register finns här)
movlw	0fb	;11111011 (en utpinne (PWM), resten inngångar)
movwf	7	;CCP1 blir utgång (skicka till TRIS register)
movlw	0ff	;11111111
movwf	12	;PR2 blir 255 (periodtiden=256 - en siffra högre)
bcf	3,5	;välj registersida 0 (tillbaka till standardregistren)
movlw	7f	;01111111
movwf	15	;CCPR1L blir 127 (villket betyder 50% mot 255 period)
movlw	0c	;00001100 (kod för PWM-mode)
movwf	17	;CCP1CON (programmera)
bsf	12,2	;(starta PWM hårdvaran)
(Frekvensen på PWM-hårdvaran kommer genom TMR2 som drivs på 1/4 frekvens av kristallen. Räknaren startar på sista kommandot. Dom två första bitarna i detta register (12,0 och 12,1) kan dela ned frekvensen i en prescaler (1,4,16)).
Användarvisningsbild
$tiff
Inlägg: 4941
Blev medlem: 31 maj 2003, 19:47:52
Ort: Göteborg
Kontakt:

Inlägg av $tiff »

Tack hebbe, men jag kom på vad som var fel:

Jag var helt rätt på det hela tiden. Om man bara helt sonika ignorerar att skriva in Duty Cyclen via CCP1CON<5:4> så funkar allt bra (dessutom skrev jag till den två gånger i mitt förra exempel, klantigt).

Det som spökade var IR-mottagarna. Jag har inte fattat förrän nu att de reagerar på förändringar, därför blev allt galet när jag försökte få dem att reagera på en kontinuerlig högt modulerad ljus. Det var bara att ändra koden lite så fungerar allt underbart!

Vad jag håller på med är IR-sensorer för avståndsbedömning till min & Mullemeks robot. De detekterar min hand på 0,5m. Ganska bra måste jag säga. Fast de fungerar nog inte lika bra på mattsvarta flyffiga saker :roll:
Skriv svar