Moin Moin Wissende,
ATMEGA88 als DDS LFO. PORTD nutze ich als 8Bit Ausgabe über ein R2R
Netzwerk.
Jetzt benötige ich jedoch den UART an PD0 und PD1 und muss deshalb den
PORTD splitten. Über eine ISR zähle ich einfach rauf/runter und setze
dann den entspr. Wert:
1
volatileuint8_tcnt=0;
2
ISR(TIMER1_COMPA_vect){
3
4
if(cnt>=255)
5
direction=DOWN;
6
7
if(cnt<=0)
8
direction=UP;
9
10
if(direction){
11
PORTD=cnt--;
12
}else{
13
PORTD=cnt++;
14
}
15
16
}
Um nun PORTD 7-2 und PORTB 1-0 als 8Bit Ausgang mit dem jeweiligen Wert
von cnt zu nutzen benötige ich immer zwei Operationen pro PORT:
1) Löschen der vorherigen Bits
2) Setzen der neuen Bits
1
// 6Bit on PORTD
2
PORTD&=~(0xFC);
3
PORTD|=(cnt<<2);
4
5
// 2 Bit on PORTB
6
PORTB&=~(0x3);
7
PORTB|=(cnt>>6);
Das ist unschön, da ja jedes mal das Ausgangssignal zunächst auf 0V geht
( alle Bits aus ) und dann den neuen Wert erhält.
Habt Ihr vielleicht eine schlauere Lösung? Also am besten nur das delta
setzen. AGenial wäre es natürlich auch die beiden Ports in nur einer
Operation verändern zu können...
Daaaanke für jeden Tip!
Gruß
Karsten
@Karsten K. (karsten42)
>Um nun PORTD 7-2 und PORTB 1-0 als 8Bit Ausgang mit dem jeweiligen Wert>von cnt zu nutzen benötige ich immer zwei Operationen pro PORT:>1) Löschen der vorherigen Bits>2) Setzen der neuen Bits
Niemand hindert dich, die Berechnung des neuen PORT-Wertes zuerst zu
machen und dann erst die Zuweisung an den echten Port. Damit hast du bei
2 Ports minimal 1 Takt Versatz bei den Portzuweisungen.
>setzen. AGenial wäre es natürlich auch die beiden Ports in nur einer>Operation verändern zu können...
Das geht nicht.
Karsten K. schrieb:> Genial wäre es natürlich auch die beiden Ports in nur einer> Operation verändern zu können...
Das geht mit keiner Hardware. Weswegen man ein solches Splitting wie du
machst, ja auch möglichst vermeidet. Insbesondere wenn an den Pins eine
externe Hardware hängt, die timing-sensitiv ist.
Die einzige Möglichkeit, das wieder sauber zu bekommen ist, ein Latch
zwischen deinen 8-Bit "Port" und das R2R-Netzwerk zu schalten. Dann
brauchst du natürlich noch einen 9. Pin, der dem Latch das "Daten jetzt
übernehmen" Signal gibt. Da der Krempel ja wohl recht langsam ist,
könntest du statt des parallelen Latches auch ein Schieberegister mit
Latch nehmen. Siehe AVR-Tutorial: Schieberegister
Bliebe noch die Möglichkeit, eine Software-UART zu benutzen, dann bist
du mit den dafür benutzen Pins frei.
Oder eine externe UART (I2C oder SPI), geht auch. Eigentlich aber nicht
zu empfehlen, teurer als der komplette Prozessor.
Ich würde auch sagen: Prozessorwechsel.
Axel Schwenke schrieb:> Das geht mit keiner Hardware. Weswegen man ein solches Splitting wie du> machst, ja auch möglichst vermeidet. Insbesondere wenn an den Pins eine> externe Hardware hängt, die timing-sensitiv ist.
Es geht aber in zwei aufeinanderfolgenden Takten. Dazwischen liegen dann
wohl wieder einige hundert Takte, bis der nächste Wert kommt. Somit ist
diese winzige Verzögerung vernachlässigbar bzw. herausfilterbar, da die
Frequenz des generierten Signals sicher viel niedriger ist.
Hey Jungs,
Ohh Daaanke für die vielen guten Tips!
Processorwechsel:
Ja, eine Option die sicher vieles einfacher macht. Ich werde darüber
ernsthaft nachdenken!
Alles in einer Zuweisung:
Au fein! Das geht schön, DAAANKE! Bei LFO, also F <=5 Hz wird der sprung
zum zweiten Port nicht auffallen. ich werde es austesten.
Hab ich schon gesagt, das Ihr alle waaaahnsinnig tolle Leute seid?
Daaanke für eure Mühe!
Gruß
Karsten
Karsten K. schrieb:> Bei LFO, also F <=5 Hz wird der sprung zum zweiten Port nicht auffallen.
Da die beiden höchsten Bits nachgereicht werden, macht sich der Versatz
ohnehin nur 4x pro Umlauf (0, 64, 128, 192) bemerkbar. Man kann sich die
Ausgabe auf PORTB durch Abfrage von cnt auch grundsätzlich 252x pro
Umlauf sparen.
mfg.
Karsten K. schrieb:> Processorwechsel:> Ja, eine Option die sicher vieles einfacher macht. Ich werde darüber> ernsthaft nachdenken!
Die AVRs sind äusserst gute Kerle. Sehr einfach zu programmieren, sehr
robust, praktisch kein Overhead in Soft- und Hardware. Und erstaunlich
leistungsfähig, wenn man's richtig macht. So lange ich nicht an
schmerzhafte Leistungsgrenzen stosse, würde ich mich nicht mit einer
komplexeren Architektur herumschlagen wollen.
H.Joachim Seifert schrieb:> Darum gehts doch gar nicht. Die Option war, einen AVR zu nehmen, der> sowohl einen kompletten 8bit-Port und dessen UART auf einem anderen Port> liegt.
Achso, hab ich wohl falsch verstanden.
Aber selbst dann... Der vorliegende Fall kann locker mit dem aktuellen
Prozessor gelöst werden. Den Aufwand eines Prozessorwechsels nur um eine
etwas "sauberere" Lösung zu haben, würde ich mir jedenfalls nicht antun.
Kann man pauschal nicht sagen.
Es kommt eben auf die Anforderungen an.
Der Wechsel von z.B. 0x7F auf 0x80 verursacht einen heftigen
kurzzeitigen Fehler (0x7F -> 0x70 -> 0x80).
Ausserdem wird die max. mögliche Ausgabefrequenz durch die mehrfachen
Portzugriffe herabgesetzt.
Wenn das alles kein Problem ist, ist es doch gut.
Ich bin etwas irritiert. Der serielle Port überschreibt die normale I/O
Funktion von PD0 und PD1. Also kann man die Ausgabe einfach auf PORTB =
(cnt << 2) reduzieren - denke ich.
Stefan us schrieb:> Ich bin etwas irritiert. Der serielle Port überschreibt die normale I/O> Funktion von PD0 und PD1. Also kann man die Ausgabe einfach auf PORTB => (cnt << 2) reduzieren - denke ich.
Für Tx trifft das zu. Am Rx würde in diesem Fall der Pullup toggeln. Mag
sein, dass das keinen grossen Geist stört. Schön ist es trotzdem nicht.
Schon gar nicht, wenn die Eingangsschaltung so ausgelegt ist, dass sie
den Pullup braucht.
mfg.