om te leren omgaan met pics (pic18F4550) ben ik begonnen meetapparatuur te maken met verschillende functies in 1: blokgolfgenerator, capaciteitsmeting, toerenteller, sinusgenerator.
de blokgolfgenerator met variabele frequentie en dutyratio is met glans geslaagd, maar voor de sinusgen, weet ik niet goed waar te beginnen:
-ik dacht om via een dac waarden van de sinus aan de uitgang te zetten, maar ik zie gelijk geen dac in die pic zitten.
-mijn tweede idee was om timer1 oscillator te gebruiken, maar da werkt gelijk ook niet.
- of is de enige mogelijkheid om met pwm een sinus na te bootsen?
-ik zou de sinusfrequentie variabel willen maken over een zo groot mogelijke range (zoals mijn blokgolfgenerator tussen 610Hz en 999999Hz variabel is)
en dan nog een bedenking: de waarden van die sinus zullen dan tussen 0 en 5V liggen? ik bedoel dat ie niet negatieve spanning kan leveren? of kan dat op een of andere manier opgelost worden?
FullPower
De grootste moeilijkheden liggen daar waar we ze niet zoeken. [Goethe]
Je kunt de sinus maken met behulp van een DAC achter de PIC. De PIC stuurt dan achtereenvolgens de juiste data voor de sinus. Deze data kan komen uit een tabel, maar kan ook berekend worden. Afhankelijk van de gewenste resolutie van de sinus in de tijd gezien, kun je de maximum frequentie berekenen.
Maar... 1MHz lijkt me niet haalbaar!
ad. negatieve uitgangsspanningen: je zult een level shifter moeten maken met een paar opamps.
FullPower
Bart Hiddink
Bart Hiddink is Ideetron; electronics and projects, http://www.ideetron.nl. LoRaWAN Nutcase.
Je kunt het op vele manieren doen.
Het beste kun je een externe DAC nemen.
Die pwm sinus is leuk voor een vrij lage en een vaste frequentie.
Als je 6 of 8 uitgangen neemt, dan kun je ook je DAC zelfmaken.
Je moet dan in je code een teller laten lopen van n stappen en dan die tellerwaarde d.m.v. een tabel omzetten in een waarde voor de sinus op dat moment.
De aansturing van je teller kun je het beste d.m.v. een timer doen.
Wat je even moet berekenen is het aantal stappen waaruit een sinus moet bestaan.
Teveel stappen en je PIC kan het niet bijbenen => de maximale frequentie blijft te laag.
Te weinig stappen en je krijgt teveel vervorming op je sinus. De sinus bestaat dan uit te grove stappen.
Dat laatste kun je wel filteren, maar een afstand van 1:4 is toch wel minimaal.
Zo kun je misschien wel die 1 MHz halen die je wilt.
Als je een lagere frequentie wilt, dan kun je meer stapjes nemen en dan wordt ook de vervorming minder.
De DAC kun je maken van alleen weerstanden, maar dit vergt een hoop reken en testwerk, of je maakt er eentje van een opamp => somversterker met 6 of 8 ingangen.
Ook hier heb je voor de negatieve uitgangsspanning een DC-DC converter nodig.
(stom eigenlijk dat er geen dac in de pic zelf zit, da zou toch veel gebruikt worden?)
externe dac is voor mijn toepassing niet echt mogelijk (wegens nog te weinig vrije pinnen), ik zou dan voor pwm willen gaan. wat is een elegant algoritme om dit aan te pakken? ik zit momenteel in mijn hoofd met de functie sin() te gebruiken op een of andere manier, maar ik vrees dat dat wat omslachtig is.
ps: qua maximale frequentie dacht ik iets van een 100kHz of zo.
pps: ik programmeer in C met C18 compiler
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
FullPower
De grootste moeilijkheden liggen daar waar we ze niet zoeken. [Goethe]
Sin() werkt in C18 met floats. Dit is veel te langzaam als je een hoge sinus frequentie wilt halen. Er zijn ook algorithmen die met integers werken, en dus sneller zijn.
Maar ik zou gewoon voor een look-up tabel gaan; veel simpeler en de waarden zijn uit rekenen met een rekenmachine 
Je kunt ook eens kijken naar een DDS-chip, Analog Devices maakt ze. Is misschien al met al wel wat ingewikkelder.
En waarom er geen DAC standaard is ingebouwd... dát heb ik me ook wel eens afgevraagd!
[Bericht gewijzigd door FullPower op (13%)]
Ik was ook even aan het rekenen omdat het mij interreseerde om eventueel in de CPLD MAXII board te plaatsen. Daar hebben we 50MHz clock ter beschikking. Met 32 sampels per volle sinus ( 8 sampels per quadrant) haal je dus 1.5 Mhz (via een R2R ladder netwerk = 5 bits PWM waarde. Maar het nadeel is dat de opeenvolgende uitgangsfrequentie in het hoogste gebied voor die sinus al direct de helft is nl 0.75 MHz. Immers je moet van 1 naar 2 clocks gaan tenzij je een PLL hebt. Hoe lager de uitgangsfrequentie hoe kleiner de onderlings frequentie stapjes worden. Immers de clockdeler gaat steeds fijner en fijner.
In een pic zal je zo hoog niet kunnen gaan en ook daar zullende stappen in het hoge frequentie gebied brut zijn. Zolang je daar kunt mee leven is er geen probleem. De meest eenvoudige oplossing is een lookup tabel zowel voor een software oplossing ( pic of avr) als een hardware oplossing (CPLD) Bij een FPGA hardware oplossing beschikken we doorgaans wel over een PLL en dan heb je het probleem van de brute stappen in het hoge frequentiegebied minder. ( Maar ook een FPGA PLL heeft zijn grenzen).
Ik ga hier eens en R2R lader netwerk aan 5 bits hangen van de MAXII board en een opname maken met de logic analyser. Die kan direct het signaal als een gesampelde amplitude weergeven wat visueel bijna een siuns zal zijn (opeenvolging van de kleine opeenvolgende blokgolfamplitudes) gewoon als experiment. Met de analoge scoop kan ik het dan ook zien aan de uitgang van het R2R ladder netwerk.
wat bedoelen jullie met lookup tabel? een rij van integers die een waarde voor de sinus weergeven?
zoiets als:
int sinus[100];
for(i=0 ; i<100 ; i++){ //met 100 het aantal samples
sinus = 1023 * sin(2*3.14*i/100); //met 1023 de maximale waarde voor het pwmsignaal (10bit)
}
om dan het pwm signaal te genereren iets van:
void genereer(int frequentie) {
int tijd_tussen_sample = (int) 1/frequentie/kloktijd/100;
for(i=0 ; i<100 ; i++) {
PWMset(sinus);
wait(tijd_tussen_sample);
}
}
ps: hierboven zijn fictieve functies gebruikt, maar het is het idee dat telt.
vinden jullie dit marginaal, of zouden jullie dit ook zo gedaan hebben (ik heb het evenwel nog niet getest)?
ik vermoed dat met deze manier de maximale frequentie wel behoorlijk laag zal liggen.
Inplaats van steeds de waarde te gaan uitrekenen plaats je die vooraf berekende waarde gewoon in een tabel (lookup tabel) Bij het uitgeven van de waarde moet je dan slechts een pointer gebruiken die de tabel steeds opnieuw afloopt. Voor 10 bit bekom je idd 1024 waarden. Maar als je dit gaat PWM'en ga je een heel lage uitgangsfrequentie bekomen. Je moet nog ook vastleggen hoeveel samples per sinusgolf je gaat gebruiken.
Als je echter een R2R ladder gebruikt ga je op de uitgang die tabelwaarde aanleggen maar in jou geval zou je 10 I/O pinnen nodige hebben die een een R2R ladder liggen. Met deze methode ga je zelf een DAC maken en dan zal de max frequentie 1024 maal hoger zijn. Dat ik was ik straks hier ga maken in mijn testopstelling. Maar ik ga slechts 5 bit resolutie gebruiken. Dat is reeds ruim voldoende om een globale sinus te vormen. ( sinus golf wordt opgebouwd door 32 blokjes naast elkaar)
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
Ik heb voor m'n sinusgenerator resoluut voor een DDS (de AD9835) gekozen. Die kost wel iets, maar je krijgt dan ook iets moois voor je geld.
Eenvoudig aan te sturen met een µC over 3 lijnen.
Frequentie in te stellen in stapjes van 0.1Hz (of minder, indien gewenst).
Neemt weinig plaats in op de print. 
Daar hoort uiteraard een LP-filtertje bij en een snelle opamp.
Ja pros, voor die functie is dit idd de enige goede oplossing. Spijtig dat ik zelden een sinus generator nodig heb anders zou ik het ook direct zo uitvoeren. Nu is dit voor mij enkel voor de show maar eigenlijk zonder waarde.
Om toch even de basisvorm te tonen heb ik zo een sinus tabel van 32 waarden in een lookup tabel geplaatst en een verilog routine aangemaakt die de waarde van de lookup tabel naar buiten stuurt. De sinus frequentie is nu 31.25 Khz omdat ik de lookup tabel stuur met een clock van 1 MHz.
Ik heb nu de logic analyser aan de outputpins verbonden van mijn MAXII boardje waar het R2R ladder moet aankomen. De LA geeft mij echter ook zonder de R2R weerstanden de juiste pulswaarden. Die kan ik direct opvragen als een analoog equivalente waarde. Op het display zie je boven het resultaat, eronder zijn de 5 bit waarden met LSB bovenaan, MSB onderaan.
Wil je een betere sinus, dan moeten er meer sampels uitgestuurt worden vb 64 of 128. Natuurlijk gaat je hoogst bereikbare sinus frequentie die je met dezelfde clock kunt maken evenredig verlagen. De lookup tabel wordt langer.
Zo zie je dat en hardware met een MAXII boardje heel snel dergelijke resultaten kunt maken. Ik heb nog eerst een connector moeten bijsolderen om de LA te kunnen connecteren.
Op 6 juli 2008 19:43:53 schreef fotoopa:
Inplaats van steeds de waarde te gaan uitrekenen plaats je die vooraf berekende waarde gewoon in een tabel (lookup tabel) Bij het uitgeven van de waarde moet je dan slechts een pointer gebruiken die de tabel steeds opnieuw afloopt. Voor 10 bit bekom je idd 1024 waarden. Maar als je dit gaat PWM'en ga je een heel lage uitgangsfrequentie bekomen. Je moet nog ook vastleggen hoeveel samples per sinusgolf je gaat gebruiken.
in mijn vb bereken je toch alle waarden op voorhand en steek ik in een array Tijdens het genereren van de sinus worden die
dan gewoon gelezen uit die array.
ik heb dit eens proberen uitvoeren (mits nog licht aanpassing:
genereersinus(long pulsfrequentie) {
int sinussamples1[50]; //50 samples per periode
int tussentijd;
int i;
float argument;
OpenTimer2(TIMER_INT_OFF & T2_PS_1_1 & T2_POST_1_1);
OpenPWM1(255);
tussentijd = (int) (20000/pulsfrequentie);
for(i=0; i<49; i++) {
argument = 2*3.141592654*i/50;
sinussamples1[i] = (int) (512 - 511 * sin(argument));
}
while(!BUTTON_CENTER_PRESSED && !BUTTON_LEFT_PRESSED) { i=0;
for(i=0; i<49; i++) {
SetDCPWM1(sinussamples1[i]);
Wait_us(tussentijd);
}
}
}
het bizarre nu is dat bij weglating van Wait_us(tussentijd)
(wat normaal voor de maximale frequentie moet geven) de frequentie slechts ongeveer 300Hz is. dit moet dan betekenen dat die forlus zoveel tijd inbeslag, is dit normaal? zoja, hoe op te lossen?
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Je kunt bij een Pic de Sin() functie niet gebruiken in real-time pwm opwekking. Dat duurt veel en veel te lang. Weet niet hoeveel tijd deze gebruikt, maar die uit de Microchip appnotes gebruikt 2500 cycles!
Je bent ze weer aan het uitrekenen. Dit is geen lookup tabel. Hieronder mijn verilog programma als voorbeeldje:
Update:
Sorry, ik heb niet goed gekeken. Je gaat ze maar 1 keer berekenen om een tabel te bekomen. ( ben geen C programmeur!)
Idd, het moet zijn dat je stukje programma zoveel tijd in beslag neemt. Ik zie dat je 50 waarden gebruikt. als iedere loop 20 usec duurt heb ja al 1000 usec. Haal je maar 300 Hz dan zou het rond de 60uS per loop zijn. In asssembler kan dit velemalen korter mits optimale code.
Laat die " Wait_us(tussentijd); " eens ervan tussen dan bekom je de max waarde en die zal wel veel hoger liggen.
Ik laat mijn stukje code toch maar staan, het kan nog bruikbaar zijn voor andere gebruikers.
module sinus
(
input CLK_50, // 50 MHz
output reg [4:0] sinus_waarde // 5 bit output
);
reg [4:0] sinus_pointer; // is een 5bit teller als pointer
always @(posedge CLK_50)
begin
sinus_pointer <= sinus_pointer + 1;
case (sinus_pointer)
0: sinus_waarde <= 5'd16;
1: sinus_waarde <= 5'd19;
2: sinus_waarde <= 5'd22;
3: sinus_waarde <= 5'd24;
4: sinus_waarde <= 5'd27;
5: sinus_waarde <= 5'd28;
6: sinus_waarde <= 5'd30;
7: sinus_waarde <= 5'd31;
8: sinus_waarde <= 5'd31;
9: sinus_waarde <= 5'd31;
10: sinus_waarde <= 5'd30;
11: sinus_waarde <= 5'd28;
12: sinus_waarde <= 5'd27;
13: sinus_waarde <= 5'd24;
14: sinus_waarde <= 5'd22;
15: sinus_waarde <= 5'd19;
16: sinus_waarde <= 5'd15;
17: sinus_waarde <= 5'd12;
18: sinus_waarde <= 5'd9;
19: sinus_waarde <= 5'd7;
20: sinus_waarde <= 5'd4;
21: sinus_waarde <= 5'd3;
22: sinus_waarde <= 5'd1;
23: sinus_waarde <= 5'd0;
24: sinus_waarde <= 5'd0;
25: sinus_waarde <= 5'd0;
26: sinus_waarde <= 5'd1;
27: sinus_waarde <= 5'd3;
28: sinus_waarde <= 5'd4;
29: sinus_waarde <= 5'd7;
30: sinus_waarde <= 5'd9;
31: sinus_waarde <= 5'd12;
endcase
end
endmodule
In dit voorbeeldje wordt om de 20 ns de teller verhoogt. Die teller is de pointer naar de tabel ( case waarden van 0 tot 31) waardoor de vooraf uitgerekende decimale waarde van de pointer op de uitgangsbits komen (sinus_waarde[4:0] Die tabel heb ik uitgerekend in excel en dan ingevuld in mijn case lijst. Omdat ik geen negatieve waarden kan verwerken heb ik een offset van 16 toegepast Daardoor loopt de sinus in de onderste piek juist tot 0, in de bovenste tot 2^5-1 of 31 dit is gedaan in excel.
Als je een PWM gebruikt zou je die sinus_waarde[4:0] bekomen uit je tabel moeten gebruiken als PWM waarde. Dit voorbeeldje draait hier op 50MHz/32= 1,5625 MHz Omdat ik in het voorgaande voorbeeld met de LA beelden de clock op 1MHz gezet had was die uitgangsfrequentie 1MHz/32 = 31,25 KHz.
Mijn voorbeelden spreken voor een CPLD oplossing en verilog maar dit verschilt in niets voor een software oplossing. Het gaat over het princiep.
Op 7 juli 2008 07:56:38 schreef fotoopa:
( ben geen C programmeur!)
me neither:)
Laat die " Wait_us(tussentijd); " eens ervan tussen dan bekom je de max waarde en die zal wel veel hoger liggen.
bij weglating van die wachttijd is de (maximale) frequentie
net die 300Hz, da vind ik nu vreemd. dat een stomme forlus zoveel tijd vraagt. ie moet ge woon zien of i aan de voorwaarden doet en dan i verhogen met 1...
Voor de verdere verwerking moet ik passen omdat ik geen kennis heb van de PIC devices. Maar als je een PWM gebruikt van 8 bit zal dit resulteren in een 256 x langere tijd. Dat heb ik niet als ik de sinuswaarde parrallel naar buiten stuur. Mijn opstelling is die zoals je zou werken met een DAC, je geeft de waarde aan de DAC en dat is je amplitude. Moet je dit eerst zelf gaan PWM'en dan zal het 2^n keren trager gaan waarbij n de resolutie is. Heb je echter een 5 tal I/O pinnen vrij als output dan zou je het ook zo kunnen doen en ga je wel veel hogere frequentie's kunnen genereren. Een R2R weerstandladder aan de 5 I/O pinnen hangen en je hebt de analoge waarde. Een opamp erachter en je kunt wat filteren en de juiste niveau's instellen.
Je gaat dus nooit behoorlijke resultaten bekomen door softwarematige te gaan PWM'en voor een sinusgolfvorm, zelfs al heb je een PWM in je chip. Daarom gaf Pros ook aan dat de goede methode voor deze opdracht een DDS systeem is.
Moet je slechts enkele vaste frequentie's hebben dan is het te doen, maar zeker niet voor een soort sinus generator waar je iedere mogelijke frequentie wenst te bekomen.