www.mikrocontroller.net

Forum: Compiler & IDEs Pins schnell schalten


Autor: Timo O. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Azrael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PORTD ^= 0x40;

Autor: Timo O. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Malte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei manchen AVRs (z.B. Tiny2313) kann man Pins mit
    PIN = 0x40;
toggeln.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Malte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... und der erzeugte Takt stolpert dank des loop unrolling. Keine gute
Idee, also lieber -Os statt -O2.

Autor: Stephan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.