Hallo, ich muss mit einem 8MHz-Atmega8 zwei Takte generieren einen ganz normalen mit 500kHz und dann einen der nach 4096 Takten des ersten ein kurzes "High" ausgibt. Momentan nutzen ich den Counter1 um OC-Mode und lasse bei 0x08 den OC1A pin umschalten, für den zweiten Takt lasse ich den Timer2 zählen, generiere damit einen Interrupt nach 4096*16 Takten (Prescaler 1024 / OC-Wert 0x63), der dann kurz den Ausgang an- und ausschaltet. Das ganze scheint mir aber nicht gerade die ressourcensparendste Methode. Und da meine Software gerade sowieso ein paar Probleme macht versuche ich erstmal das in den Griff zu bekommen, könnte der Grund sein. Leider kann ich den OC2-Ausgang nicht nutzen, da ich den Pin für den SPI-Bus brauche. Hat jemand einen guten Tip für mich? Danke Thomas
Alle 4096 Takte ein Pin toggeln zu lasse genügt doch auch ein Register
>Hat jemand einen guten Tip für mich?
Ob der gut ist, kann ich nicht beurteilen
Du zählst in der OC-ISR eine Int-Variable von 4095 herunter. Immer,
wenn die 0 ist, schaltest du den Pin an (oder andersherum):
n=4095
if (n--)
{
PORTx &= ~(1<<ausgang2);
// Port wird bei jedem Interrupt ausgeschaltet
}
else
{
PORTx |=(1<<ausgang2); // bei n=0 wird er eingeschaltet
n = 4095;
}
kann auch 4096 sein...
Kommt drauf an, welche Ressourcen du sparen willst.
Willst du Rechenzeit sparen, dürfte deine Lösung mit zwei Countern die
beste sein.
Willst du einen Hardware-Counter sparen und hast genügend Rechenzeit,
dann fällt mir auch gerade keine Lösung ein, die nicht eine Auslastung
>60% verursacht
Sparen will ich Systemauslastung also Rechnenzeit, vor allem aber gern
den Interrupt, da das Timing probleme macht, wenn der mit anderen
(USART) Interrupts zusammenkommt.
>Alle 4096 Takte ein Pin toggeln zu lasse genügt doch auch ein
Register
Problem ist das ich da nicht togglen kann sondern nur ein kurzes High
senden darf (also an - aus).
Ist das mit dem OC-Pin eines Timers, überhaupt möglich?
>Ist das mit dem OC-Pin eines Timers, überhaupt möglich?
Nur wenn er nicht mit dem Timer verbunden ist.
Ich würde es wie der "inoffizieller WM-Rahul" machen. Da brauchst du nur einen Zähler und die Zusatzbelastung durch das Dekrementieren ist gering.
@Martin & WM-Rahul: Die Belastung durch diese Schleife ist ganz erheblich: Die OC-ISR würde alle 16 Systemtakte aufgerufen werden. Die Ausführungsdauer der Schleife würde ich mal mit 4-6 Takten annehmen. Dazu noch das Springen in und aus der ISR macht nochmal 6-8 Takte, damit wären wir bei 10-14 Takte Code, die alle 16 Takte ausgeführt werden. Auslastung alleine damit: 75%
Hallo, bin nicht sicher, ob es aufgeht: die 500kHz per Timer in Hardware erledigen. Die 4096 500kHz-Takte auch per Timer im CTC-Mode, sind ja dann rund 122 Hz. Den 2. Timer musst Du beim Initialisieren ja nur einmal Taktgenau starten, die bleiben dann ja syncron. Gruß aus Berlin Michael
die Auslastung hast Du immer. 500kHz sind halt mal 1/16 Deiner Taktfrequenz, wenn Du da noch viel agieren willst bleibt sehr wenig Zeit übrig, Jedenfalls nicht für zeitkritische Programmteile.
@Michael: Ich weiß nicht, wie Thomas das beschriebene umgesetzt hat, aber dein Text klingt praktisch identisch zum Original-Post @Sonic: In der ursprünglichen Umsetzung hat man keine ISR, die alle 16 Takte aufgerufen wird. Das toggeln von OC1A erfolgt automatisch ohne ISR. Nur für den langsamen Takt bräuchte man eine ISR. @Thomas Braun: Ich glaube, ich liege richtig, wenn ich deine Frage formuliere als "Wie kann ich nach einer bestimmten Anzahl Takte einen Pin kurz an und wieder ausschalten, ohne eine ISR bemühen zu müssen?"
> Die Ausführungsdauer der Schleife würde ich mal mit 4-6 Takten > annehmen. Dazu noch das Springen in und aus der ISR macht nochmal > 6-8 Takte, damit wären wir bei 10-14 Takte Code, die alle 16 Takte > ausgeführt werden. Auslastung alleine damit: 75% Das ist viel zu optimistisch. Im Interrupt-Fall dauert das Springen in den Interrupt-Vektor 4 Taktzyklen. Falls gerade ein Befehl ausgeführt wird, der mehr als einen Taktzyklus dauert, wird der vorher noch fertiggemacht. Der längste Befehl braucht vier, also können bis zu drei dazukommen. Das rjmp im Interrupt-Vektor braucht nochmal zwei. Das reti am Ende braucht vier. Damit braucht eine komplett leere Interrupt-Routine schon 10 bis 13 Taktzyklen. Ein Inkrement braucht zwar nur einen Taktzyklus, aber verändert die Flags. Das heißt, man muß erst das SREG sichern. Das geht aber nicht direkt, also muß man erst ein Register sichern. push + SREG lesen + push machen nochmal 5 Taktzyklen. Die umgekehrte Operation am Ende auch nochmal. Wenn wir also nur ein Register inkrementieren wollen, kommen wir mit 21 bis 24 Taktzyklen davon. Falls die Variable im RAM liegt, werden's nochmal vier mehr.
@Rolf Da hast du wohl Recht, da hab ich einiges vergessen. In dieser Anwendung ist es sogar nicht nur ein einfaches Register, sondern es braucht 16bit für die Variable.
Hallo, @Jan M.: da habe ich mich wohl dann irritieren lassen. Nur verstehe ich dann das Problem nicht. Wenn die 500kHz in Hardware erzeugt werden, gibt es nur alle rund 8ms (wenn ich mich nicht verrechnet habe) einen IRQ, der sbi/cbi macht. Das sind dann wie im vorigen Posting schon ausgerechnet 10-13 Takte + 2 für sbi/cbi. Da wüßte ich dann aber in Software aber nichts mehr einzusparen... Gruß aus Berlin Michael
@ Jan Genau das ist die Frage - wie mache ich das ohne ISR. @ Michael Naja es sind 122/s, klar nicht besonders oft, wenn aber gerade eine andere Interruptschleife läuft, wird der Takt dann verspätet ausgegeben und das macht Probleme. Daher würde ich das gern per Hardware machen.
Hallo, naja, kommt darauf an, wieviel sich der Impuls verspäten darf (in Taktzyklen des AVR), wie lang die anderen ISR sind, ob man die kürzen kann, welche auftreten können, wie zeitkritisch die sind, ob man darin evtl. den Interrupt freigeben könnte usw. usw. Ansonsten 12Bit-Zähler ran, Monoflop dahinter, mehr Hardware geht wohl nicht. ;) Gruß aus Berlin Michael
Hi! Nur so als Gedanke: T1 macht 500Khz, damit Timer2 in CTC-Mode(127) extern takten und bei OC2 Int. ausführen um Ausgang abzuschalten.(vorher natürlich setzen lassen) Wenn Platz in IRQ-Tabelle "CBI OC2" + reti ditekt eintragen. Der Imp.an OC2 wäre dann 4? Takte. Verbrät natürlich haufenweise Hardware und ich habe nicht alles überprüft. Viel Erfolg, Uwe
Aus dem Mega8 Datenblatt: 16-bit Timer/Counter1 The 16-bit Timer/Counter unit allows accurate program execution timing (event management), wave generation, and signal timing measurement. The main features are: True 16-bit Design (i.e., allows 16-bit PWM) Also: mit dem Timer erzeugst Du ein PWM-Signal mit 1/8192 oder noch kürzer. Den Prescaler und die PWM-Periode stellst du so ein, dass das Signal nur alle 2µs*4096=8192µs kommt. Die 500kHz erzeugst Du mit einem 8-bit-Counter.
Richtig, eine 16bit-PWM kann bei 8 Mhz alle 65535 Takte (aka 8192 µs) einen 1 Takt langen Impuls generieren. Sehr schön, und wie gewünscht ohne ISR. Bleibt nur das Problem, dass eben dieser PWM-Ausgang OC2 und MOSI auf dem selben pin liegen beim mega8 und Thomas SPI verwenden will...
Gerade gesehen: Ich weiß nicht, inwieweit dein Board schon fertig ist, aber wie sieht es mit einem Mega88 aus? Der ist pinkompatibel, kann aber auch an PD3 die 16bit-PWM ausgeben. Damit hättest du sowohl SPI als auch die PWM.
Das klingt gut, an die PWM hatte ich mal am Anfang gedacht, aber wegen OC2-Pin verworfen. Ein Mega88 als Austausch dürfte kein Problem sein, kostet zwar ein paar cent mehr, ist aber nicht viel. Danke !
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.