Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien
Toon posts:

[PIC] Soft-PWM code: is dit efficiënt?

Pagina: 1
Acties:
  • 160 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Hello iedereen. Intussen ben ik een dikke week bezig met eenvoudige dingen te proberen met pic's.

Momenteel ben ik aan het spelen met een 12F675. Deze heeft geen PWM module aan boord. Daarom dacht ik het eens zelf in mikroC te schrijven als functie.


Ik heb een eerste implementatie geschreven, en die gaat als volgt:

C: soft_pwm
1
2
3
4
5
6
7
8
9
10
11
12
 
void soft_pwm (unsigned int waarde){
   int aa;
   for (aa=0;aa<waarde;aa++) {
      GPIO = 1;
      delay_us(1);
   }
   for (aa=0;aa<255-waarde;aa++) {
      GPIO = 0;
      delay_us(1);
   }
}

Mijn ervaring is dat delay_us() een vaste waarde moet krijgen, vandaar deze constructie.

Is dit ietwat "efficiënt", of kan er wat aan verbeterd worden?

[ Voor 9% gewijzigd door Verwijderd op 26-06-2007 18:05 ]


  • lemming_nl
  • Registratie: Juli 2004
  • Niet online
Ik weet niet hoe snel je PIC is maar een for loop kost meerdere clockcycles welke dus meer zijn dan die us delay die je erin hebt gezet. Dat gaat dus niet lekker werken.

Geluk is een weerloos oud vrouwtje, alleen op straat met een bom geld


  • Sprite_tm
  • Registratie: September 2002
  • Laatst online: 29-10 06:07

Sprite_tm

Semi-Chinees

Dit is best inefficient: naast de PWM kan je atm compleet niets anders doen. Ik zou het met een timer-interrupt proberen, in pseudo-code:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
unsigned char pwmval;

void main() {
 StelTimerIn();
 ZetInterruptOpTimer(TimerInterrupt);
 EnableInterrupts();
 while(1) {
  DoeIetsInteressants(pwmval);
 } 
}

INT TimerInterrupt() {
 static unsigned char ctr, realpwm;
 ctr++;
 if (ctr==0) {
  realpwm=pwmval;
  SetOutputPin(1);
 }
 if (ctr==realpwm) SetOutputPin(0);
}


Je kan dus nu gewoon in je hoofdprogramma de realpwm-waarde aanpassen, en de interrupt-logica doet dan net alsof je wel een hardwarematige PWM-controller hebt; qua coden heb je er verder geen omkijken meer naar.

En efwaaiaay: dit is nog niet eens de meest efficiente manier om het te coden: je zou de huidige waarde van de timer bijvoorbeeld ook on-the-fly kunnen aanpassen, waardoor je minder overhead hebt: slechts 2 interrupt-calls per pwm-cycle, waar het er nu 256 zijn. Als je geen PWM-signalen in de megahertzen wil maken, is dit echter makkelijker begrijpbaar en uit te breiden.

[ Voor 39% gewijzigd door Sprite_tm op 26-06-2007 18:22 ]

Relaxen und watchen das blinkenlichten. | Laatste project: Ikea Frekvens oog


  • Paul
  • Registratie: September 2000
  • Laatst online: 21-11 19:01
Wordt de carry bij een interrupt ook gebackupt? Anders loop je kans (als je er gebruik van maakt tenminste) dat dat fout gaat bij Sprite's code, toch :?

"Your life is yours alone. Rise up and live it." - Richard Rahl
Rhàshan - Aditu Sunlock


  • Zjosh
  • Registratie: November 2004
  • Laatst online: 20-11 12:58
Voor zo ver ik weet wordt het wreg, programcounter en status reg gebackupt... Dus ook het carry bit.
(in c18 als je je interupt door c laat afhandelen).

Verwijderd

Topicstarter
Sprite_tm schreef op dinsdag 26 juni 2007 @ 18:13:
Dit is best inefficient: naast de PWM kan je atm compleet niets anders doen.
Hier was ik me van bewust, maar eerst stappen en dan lopen ;)
Ik zou het met een timer-interrupt proberen, in pseudo-code:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
unsigned char pwmval;

void main() {
 StelTimerIn();
 ZetInterruptOpTimer(TimerInterrupt);
 EnableInterrupts();
 while(1) {
  DoeIetsInteressants(pwmval);
 } 
}

INT TimerInterrupt() {
 static unsigned char ctr, realpwm;
 ctr++;
 if (ctr==0) {
  realpwm=pwmval;
  SetOutputPin(1);
 }
 if (ctr==realpwm) SetOutputPin(0);
}


Je kan dus nu gewoon in je hoofdprogramma de realpwm-waarde aanpassen, en de interrupt-logica doet dan net alsof je wel een hardwarematige PWM-controller hebt; qua coden heb je er verder geen omkijken meer naar.
Dit ga ik eens proberen. Met interrupts heb ik nog nooit gewerkt, dus dat zal ik even moeten uitvlooien :) Eerst de pseudo code omzetten...
En efwaaiaay: dit is nog niet eens de meest efficiente manier om het te coden: je zou de huidige waarde van de timer bijvoorbeeld ook on-the-fly kunnen aanpassen, waardoor je minder overhead hebt: slechts 2 interrupt-calls per pwm-cycle, waar het er nu 256 zijn. Als je geen PWM-signalen in de megahertzen wil maken, is dit echter makkelijker begrijpbaar en uit te breiden.
uit te vlooien: part 2 ;)

Alvast bedankt voor de tips! Ik zal laten weten indien het gelukt is :)

  • M14
  • Registratie: Januari 2002
  • Laatst online: 21-11 00:11

M14

Een kleine aanpassing op de pseudocode van Sprite_tm :).

Op deze manier zet je de tijdens de interrupt de tijd die moet duren voordat de volgende interrupt komt. Zo kun je een vele hogere pwm frequentie krijgen. In het voorbeeld ga ik er vanuit dat de 1 cyclus 20 tellen duurt. De duty-cycle kun je dus aanpassen tussen 0 en 20. De variabele 'laag' en 'hoog' bereken je in de main, afhankelijk van je input. Ik vind het zelf het makkelijkst om hier in procenten te werken. Wanneer 'pwm' < 5% of > 95% zou worden, is het beter om de timer te stoppen en de waarde 1 of 0 op je output te zetten.


C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
unsigned char laag=15, hoog=5, pwm;

void main() {
 StelTimerIn();
 ZetInterruptOpTimer(TimerInterrupt);
 EnableInterrupts();
 while(1) {

pwm = haalwaardeop();
if(pwm<5) { disable_timer; outputpin=0; }
else if(pwm>95) { disable_timer; outputpin=1; }
else { enable_timer; berekenlaag; berekenhoog; }

 } 
}

INT TimerInterrupt() {
{
if(outputpin==0){
  outputpin=1;
  timerregister=hoog;
  }
else{
  outputpin=0;
  timerregister=laag;
  }
}

[ Voor 14% gewijzigd door M14 op 28-06-2007 03:30 ]

Mess with the best, Die like the rest
There is no such thing as Society
There are 2 kinds of people: Snipers and their targets
Never run for a sniper ... you only die tired :)

Pagina: 1