Moin Moin Bin gerade dabei mir einen Digitalen Rechteckgenerator zu bauen. Nun suche ich eine schnelle Möglichkeit einen Pin zu tickern. Mit einem 10MHz Quarz komme ich mit diesem Code... for(;;) PORTD = ~PORTD; ...auf ca. 1MHz an PORTD. Allerdings brauche ich das Ganze für nur einen Pin an PORTD. Mit folgendem Code funktionert es zwar aber die Frequnez fällt auf ca. 110KHz ab. for(;;){ if((PORTD&0x40)==0x00) PORTD += 0x40; else PORTD -= 0x40; } Wie schaffe ich es nun den Pin möglichst schnell zu tickern ? MFG Timo O.
Soll der Controller nichts anderes machen? Noch schneller geht es unter Umständen mit inline-Assembler. Ich an deiner Stelle würde mir einen externen Schaltkreis dafür nehmen. Bei dir darf in einem späteren Programm weder ein Interrupt noch Code in die Hauptschleife kommen, ohne das es dir das Signal versaut. Welchen Frequenzbereich musst du abedecken?
Ich würde versuchen das ganze in assembler zu schreiben. aber möchtest du nicht lieber einen timer mit pwm verwenden? hab schon lange keinen AVR mehr programmiert, kann es sein das er den wert 0x40 jedes mal aus dem speicher liest? oder ist der schon im befehl integriert? wenn nicht würde ich ein register nehmen mit dem wert, dadurch sparst du dir nochmals einen cyclus in dem du nur eine fixe variable ladest. for(;;){ PORTD += 0x40; nop(); nop(); PORTD -= 0x40; } so hast du zwar eine längere auszeit als einzeit, aber das könntest du mit ein paar nop angleichen. allerdings wenn dir jetzt ein interrupt in die quere kommt kannst du deine frequenz vergessen. bzw. kannst du derzeit nichts nebenbei machen. mfg Azrael
Erstmal danke für eure Antworten. Die Idee von Azrael ist natürlich top. Das ich da nicht selber drauf gekommen bin. So eine Schande. :-( Aber das Posting von Jörg beschreibt genau das wonach ich gesucht habe. Mit diesem befehl komme ich wieder auf ca. 1MHz. Besten Dank Timo O.
int main(void) { DDRD |= (1<<4); for(;;) { PORTD |= (1<<4); PORTD &= ~(1<<4); } } müsste einen Takt (compiliert mit -O2) von 3,33MHZ erzeugen wenn der AVR mit 10MHZ getaktet wird. Ist dann allerdings nicht exakt wegen dem Rücksprung. Vielliecht ist für dich noch http://www.myplace.nu/avr/minidds/index.htm interessant.
> müsste einen Takt (compiliert mit -O2) von 3,33MHZ erzeugen wenn der > AVR mit 10MHZ getaktet wird. Ich komme dabei auf 6 Takte pro Iteration (CBI,CBI,BRxx brauchen je 2 Takte). Ergibt bei 10MHz Takt also 1,67MHz. Besser wird's mit h = PIND | 1<<6; l = PIND & ~(1<<6); for (;;) { PORTD = h; PORTD = l; } da komme ich auf 4 Takte = 2,5MHz.
Hmm, du hast Teilweise recht. Ich hatte cbi und sbi mit 1 Takt Ausführungszeit in Erinnerung, sind aber wie du sagst zwei. Dann müsste meine Routine 2MHZ erzeugen. Der Compiler scheint die Schleife teilweise zu entrollen, so dass sbi-cbi zwei mal ausgeführt werden bevor der Sprung erfolgt. Wenn der Compiler deinen Quelltext genau so entrollt, müsste deiner dann aber 3,33MHZ ausgeben.
... und der erzeugte Takt stolpert dank des loop unrolling. Keine gute Idee, also lieber -Os statt -O2.
Also, im Datenblatt zu meinem uC steht bei den Timern, dass man 1/4 vom Clock maximal erhalten kann; das wären bei meinen 20MHz immerhin 5MHz. Aber eben mit dem Timer und natürlich dem dazu gehörigen Timer-Ausgangs-Pin. Weiterer Vorteil der Timer ist, dass sie vollkommen autonom laufen; sie benötigen nur beim ersten Verwenden die Initialisierung. Danach ist die CPU frei für andere Aufgaben. Stephan.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.