Daan Timmer
Ik ben programmeur! geen electronicus! http://www.daantimmer.nl/ Er is een ontwerp! nu nog inhoud :-)
Beste circuits-onliners.
Ik neuzel al een tijdje rond op deze site en ben nu eindelijk beetje begonnen met een klein projectje (voor school).
Mijn idee is om een 2x2mtr grote *sterrenhemel* met 200 witte en 200blauwe ledjes (gedimt) te gaan maken.
Dit wil ik dan gaan besturen d.m.v. een nC (in mijn geval de PIC 16F628A)
De ledjes, worden onderverdeeld in 8groepen, van ieder 25-75 leds. Deze worden dan via een transistor aangesloten op de nC of indien mijn idee niet zal werken, via een d-latch op de nC.
Nu kwam mijn school dus met de gedachte om met de PWM-module van mijn nC te gaan werken.
Nu heb ik gegoogled, en gegoogled en nog eens gegoogled tot ik er dood bij neerviel. tevergeefs. Ik kan alleen dergelijke informatie vinden in Assembly en helaas, we moeten in ansi-C programmeren. (Dit doe ik overigens via SourceBoost).
Nu las ik alleen ergens in dit forum (Topic genaamt *Beginnen met PWM*) dat je alleen portb3 kan gebruiken inc. met PWM. En niet de andere poort van portb (als ik het goed heb begrepen). ~~uitleg nodig
Mijn vraag is dus eigelijk.
Heeft iemand voorbeeld code? om met PWM in C te programmeren, of kan iemand mij hiermee verder helpen, want verderkomen kom ik op het moment niet (en heb nog maar kort tijd ~~1week, donderdag 1dec. moet het af zijn (prototype))
M.v.g.
Een TI-er in nood 
Als je graag 8 groepen tegelijk met PWM wil aansturen, dan moet je het gewoon met de hand doen. Ik neem aan dat je PICje een PORTB heeft waar je gewoon in een keer 8 bits heen kunt schrijven ? Je moet dan wel alleen elke 25a50 usec. die routine aanroepen, anders gaat het knipperen. In assembly kun je een routine schrijven die dat makkelijk redt, in C weet ik dat niet zeker. (Dan kun je nl. niet met de carry goochelen.) Het ligt er ook aan op hoeveel Mhz je PICje draait, bijvoorbeeld op 8Mhz kun je iets van 200 cycles verstoken ervoor, maar op 1Mhz moet je het in een zyzle of 30-40 redden.
Waarom moeten jullie zo nodig in C programmeren ? Zeker voor uCs is dat praktisch hetzelfde als assembly, je doet hetzelfde, je schrijft het alleen anders.
De PWM-module kan maar 1 pin aansturen, voor 8 pinnen zou je 8 PWM-modules nodig hebben.
Overigens is de datasheet van je PICje de beste plek om te beginnen. Daar staat vaak precies welke waardes je naar welke registers moet schrijven om de PWM op gang te krijgen. Ik neem aan dat je wel kunt uitvogelen hoe je in C een waarde naar een register schrijft ?
[Bericht gewijzigd door reynaert op ]
Daan Timmer
Ik ben programmeur! geen electronicus! http://www.daantimmer.nl/ Er is een ontwerp! nu nog inhoud :-)
Op 25 november 2005 00:27:03 schreef reynaert:
:tekst:
Waarom moeten jullie zo nodig in C programmeren ? Zeker voor uCs is dat praktisch hetzelfde als assembly, je doet hetzelfde, je schrijft het alleen anders.De PWM-module kan maar 1 pin aansturen, voor 8 pinnen zou je 8 PWM-modules nodig hebben.
:tekst:
Ik neem aan dat je wel kunt uitvogelen hoe je in C een waarde naar een register schrijft ?
1. Aangezien C meer aansluit op Java dan Ass. op Java doet. en we ansi-C moeten leren programmeren.
2. Okee, dus PWM is dus out of the picture
3. Ja dat weet ik gelukkig nog net wel 
Wat zou dan de beste oplossing voor mijn probleem zijn?
Ik zat zelf te denken aan dit:
Ik assign voor elke poort zijn eigen variabele (tussen bijv. de 0 en 10)
En laat dan een loop lopen 1 voor alle poorten, die dan per poort per keer dat hij loopt die variabele -1 doet.
Zolang die Var 1 of hoger is, zal de desbetrefende poort hoog blijven, zodra de Var 0 is, zal de desbetreffende poort laag worden.
Zodra de loop dan 10x (indien de maximum waarde 10 is) gelopen heeft, reseten de waardes naar hun basiswaarde.
Die loop zal dan op een bepaalde *frequentie* (moeten) lopen.
Het lijkt mij dat je hiermee de duty-cycle kan *simuleren*?
voorbeeld:
L0 L1 L2 L3 L4 L5 L6 L7 L8 L9
prtb1(8) 1 1 1 1 1 1 1 0 0 0
prtb2(2) 1 1 0 0 0 0 0 0 0 0
prtb3(10)1 1 1 1 1 1 1 1 1 1
De waarde achter de portbx is de waardie hoeveel keer v.d. 10 hij aan moet blijven.
Zou deze manier een soort van PWM kunnen simuleren? of is dit teveel reken werk?
Overigens draait mijn 16F628A op een externe osc. van 20mHz
T.Assies
Ik zie dingen die je nooit voor mogelijk hield. Ik maak ze mogelijk. Ik kan je pijn en lijden laten zien. In tegenslag vind ik hoop, in de verhalen die ik hoor inspiratie. Ik kan je veel vertellen. Wat ik doe? Ik ontdek. Mijn wereld is jouw wereld.
Je neemt voor iedere groep 1 pin (schakelen met een tor).
Wat je doet:
je hebt een teller van 0 - FF
een register met de waarde van een groep (bv: 20h)
je zet alle groepen aan
zodra teller gelijk is aan waarde van groep: groep uit
teller-1
en zo door...
op deze (niet nette) manier heb ik zonder problemen 12 kanaal pwm gemaak, zonder flikkeren!
Dit is dus hetzelfde als wat jij hierboven zei, maar dan op "mijn manier" uitgelegd!
[Bericht gewijzigd door T.Assies op ]
Het probleem met tegelijk aanzetten en dan 1 voor 1 uitzetten als je teller een bepaalde waarde bereikt werkt natuurlijk wel, maar je code wordt er efficienter van als je inplaats van een 'if' gewoon direkt met de uitkomst van de 'compare' je poort aanstuurt.
Maar het kutte is dat je met C nooit weet wat er precies voor assembly uitkomt. Wie weet maakt hij er toch wel if-jes van. Dan moet je verschillende mogelijkheden proberen en kijken wat je compiler ervan maakt.
Volgens mij het meest efficiente in assembly is dit:
cp val1, timer
rol bits
cp val2, timer
rol bits
cp val3, timer
...
cp val8, timer
rol bits
out PORTB, bits
Daarmee kun je zelfs met een 1Mhz uC nog makkelijk een fatsoenlijke duty-cycle maken.
> naaDje: als je maar tot 16 telt ipv. 256 heb je wel als voordeel dat je 16x zo lang kunt doen over je routinetje om toch dezelfde duty-cycle te halen. Nadeel is dat je dan maar 16 stappen kunt dimmen natuurlijk.
Simpele C-code is iets als:
unsigned char bits;
for (i = 0; i < 8; i++)
bits += bits + (val[1] > timer);
PORTB = bits;
maar het is maar gokken of dat efficiente assembly oplevert.
Trouwens als je controller op 20Mhz draait, dan heb je echt wel hartstikke genoeg tijd om dit te doen hoor, zelfs met 256 stappen. Reken maar na: Als je duty-cycle 100Hz wil hebben, dan moet je deze routine dus 256*100 keer per seconde aanroepen. Dus met 25.6Khz 20Mhz gedeeld door 25.6Khz is ongeveer 780, dus je kunt 780 processor-cykels verstoken in je routinetje. In assembly red je het in een cykel of 40-50. 20 als je de loop uitrolt. Met C gaat er hoogstens een factortje 2 of 3 inzitten. Kijk, als je nou op 1Mhz draait, dan zou het krap worden.
Daan Timmer
Ik ben programmeur! geen electronicus! http://www.daantimmer.nl/ Er is een ontwerp! nu nog inhoud :-)
Op 25 november 2005 14:37:43 schreef reynaert:
:tekst:
Simpele C-code is iets als:unsigned char bits;
for (i = 0; i < 8; i++)
bits += bits + (val[1] > timer);
PORTB = bits;maar het is maar gokken of dat efficiente assembly oplevert.
Is het niet makkelijk om een soort van struct aan te maken per *led-group* die o.a. de poort *code* (de bit v.d. poort) en het aantak cycles dattie aan moet staan
en idnien hij moet veranderen de huidige bits XOR-en met de bit-code van de desbetreffende groep? is dat niet efficienter dan bits += bits + ... ?
Op 27 november 2005 17:30:54 schreef NaaDje:
[...]Is het niet makkelijk om een soort van struct aan te maken per *led-group* die o.a. de poort *code* (de bit v.d. poort) en het aantak cycles dattie aan moet staan
en idnien hij moet veranderen de huidige bits XOR-en met de bit-code van de desbetreffende groep? is dat niet efficienter dan bits += bits + ... ?
Erg onwaarschijnlijk. Voor de gein zou je die manier eens in code kunnen schrijven, en kijken wat je compiler ervan maakt.
In assembly is de manier die ik beschreef de efficientste.
In C ligt het eraan wat je compiler ervan bakt.
Er zijn minstens twee redenen waarom je de bits direkt moet aansturen inplaats van enkele bits flippen:
- Je hoeft geen schaduw register te gebruiken.
- Er staan (als je compiler goed is) geen 'branches' in je code, wat de boel een stuk versnelt.
De manier 'bits += bits + ...' is maar 1 manier om het resultaat van een vergelijking bit voor bit in een register te schuiven. Hier zijn nog een paar mogelijkheden (let erop dat in C, het resultaat van een vergelijking altijd 1 of 0 is).
bits <<= 1; if (val > timer) bits++;
bits <<= 1; bits |= (val > timer);
bits = (bits << 1) | (val > timer);
bits = (bits << 1) + (val > timer);
bits += bits + (val > timer);
Het ligt aan je compiler welke manier de meest efficiente code oplevert, maar uiteindelijk is de snelste methode (die in C onmogelijk is) de volgende:
cp val_1, timer
rol bits
cp val_2, timer
rol bits
...
cp val_8, timer
rol bits
out PORTB, bits
Wat welgeteld 17 cycels duurt, voor 8 parallelle PWMs.