www.mikrocontroller.net

Forum: Codesammlung Software UART


Autor: peter dannegger (Gast)
Datum:
Angehängte Dateien:

Da ja verschiedentlich nach ner Software-UART gefragt wurde, hier mal
meine Lösung.


Das Problem bei ner Soft-UART ist das Timing. Es darf nur ein geringer
Jitter entstehen und keinesfalls eine Jitterakkumulation, damit auch
noch das letzte Bit einwandfrei gesendet bzw. empfangen wird.

Daher bietet sich dazu der T1 an.

Das Senden ist einfach, man nimmt einen Compare-Output und hat damit
keinen Jitter.

Das Empfangen ist etwas komplexer. Um die Startflanke möglichst genau
festzustellen ist der Input-Capture Eingang zu verwenden. Danach kann
man dann mit dem 2 Compareinterrupt die einzelnen Bits abfragen.

Im Beispiel wird bei 16MHz eine Baudrate von 57,6kBaud eingestellt.


Werden noch andere Interrupts verwendet, ist darauf zu achten, daß der
Empfangsinterrupt (CompareB) nicht länger als 1/2 Bitzeit und der
Sendeinterrupt (CompareA) nicht länger als 1 Bitzeit verzögert werden.

Die höhere Baudrate sollte deshalb immer mit der Hardware-UART
erfolgen.


Die Soft-UART ist Voll-Duplex.

Der T1 ist durchlaufend (Mode 0), kann also per Overflow-Interrupt noch
anderweitig verwendet werden (z.B. als RTC, Debouncer usw.).

Bei anderen AVRs ist die andere Zuordnung der ICP- und OC1A-Pins zu
beachten. Es kann natürlich auch der OC1B Pin verwendet werden.


Peter
Autor: Manne (Gast)
Datum:

Hallo Peter,

ist ja ganz nett die Dateien in dieses Forum zu stellen,
aber die Dateien #include <interrupt.h> #include <signal.h>
fehlen, und somit ist das alles nicht zu gebrauchen.

Gruß Manne
Autor: Stefan Kleinwort (_sk_)
Datum:

Oh Mann Manne,

schonmal eine weit verbreitete C-Compiler-Distribution angeschaut, der
hier ein eigenes Forum gewidmet ist?

Kopfschüttel,

Stefan
Autor: TheMason (Gast)
Datum:

@manne

die dateien sind (soweit ich weiß) vom gcc, und wenn man diesen
installiert hat sind diese dateien automatisch dabei. hängt also nur am
compiler.
für andere compiler/prozessoren muß man eh den prototypen für die
interrupt routine anpacken.
also entweder gcc nutzen oder entsprechend dem verwendeten compiler
anpassen.

gruß
rene
Autor: Manne (Gast)
Datum:

Ja, es gibt auch noch andere Compiler als gcc.
zb. IAR
Das scheint, mir hier eher ein Verein für Hochnässige
zu sein, als ein Forum.

Rene: Danke für die Info
Autor: Stefan Kleinwort (_sk_)
Datum:

Sorry, ich konnte mich einfach nicht uirückhalten ;-)

Gruß, Stefan
Autor: Stefan Kleinwort (_sk_)
Datum:

oh Mann ... einmal kurz drüberschauen wäre auch nicht schlecht:

Sorry, ich konnte mich einfach nicht zurückhalten ;-)

Gruß, Stefan
Autor: Manne (Gast)
Datum:

Tja, der eine kennt sich nur mit IAR aus
der andere hat Probleme mit dem schreiben ;-))
( lol )
Autor: Peter Dannegger (peda)
Datum:

@Manne

Oh Gott, da geilt sich tatsächlich einer an der Interrupt-Syntax auf.

Interrupt-Handler gehören nunmal nicht zum C-Standard.
Jeder C-Programmierer weiß doch, daß jeder Compilerbauer da sein
eigenes Süppchen kocht.


Und wenn Du C könntest, dann wüßtest Du also, wie Du Interrupthandler
in die Form Deines Compilers umschreiben kannst (die Zeile vor der
'{').

Du hast wohl sehr viel Langeweile und wenig C-Kenntnis um sich über
sone Lappalien aufregen zu müssen.

Wie wärs denn mal mit konstruktiven Beiträgen ?


Peter
Autor: Michi (Gast)
Datum:

Tja Manne, frage mich wer hier hochnäsig ist.
"Ja es gibt noch andere Compiler z.B. IAR".
So wie man in den Wald hineinschreit kommt es zurück.
Autor: Rahul (Gast)
Datum:

Dann muss man sich halt mit den Fehlermeldungen des Compilers
auseinandersetzen, und sie beheben. Man könnte natürlich auch Peter
einen Obolus bezahlen, dass er das Programm auch an den IAR anpasst.
Dann werden aber die Codevision-Leute kommen und rumjammern...
Von den BASCOM-Leuten ganz zu schweigen - die jammern über alles
gerne...(BASCOM hat eine eigene SoftUART implementiert; das nur so am
Rande)
Autor: pittbull_nt@yahoo.com (Gast)
Datum:

mich würde mal ein software-uart interessieren, der ohne interruptfähige
eingänge auskommt d.h. wo alles eingesampled wird. das wär' mal
spannend...
Autor: peter dannegger (Gast)
Datum:

@pittbull_nt

Von Philips gibts dazu die application note AN446:

http://www.standardics.philips.com/support/documen...


Sowas ist allerdings extrem Ressourcen hungrig, daher eignet es sich
nur für kleine Baudraten und sollte in Assembler geschrieben sein.


Peter
Autor: komment (Gast)
Datum:

software serielle schnittstelle uart mega 8 c
Autor: tubbu (Gast)
Datum:

Hi,

vielen Dank, genau das, was ich brauche und des öfteren brauchen werde
:-)
An dieser Stelle auch vielen Dank für die anderen praktischen
Codebeispiele!
Autor: Marco S. (masterof)
Datum:

Eine Frage wie viele Software-UART kann man da mit diesem Beispiel im
Mega8 realisieren?
Autor: Thomas Zemanek (Gast)
Datum:

Hallo Götter des Mikrocontrollers,


ich habe mich sehr gefreut, dass ich eine SWUART lib wie vom Peter
Dannegger gefunden habe...aber leider funktioniert sie bei mir nicht so
recht.
Der pin(OC1A) geht einfach nur auf high und verbleibt so...leider keine
Frequenz zu finden....
Hänge mit dem Oszi dran.
Merkwürdig ist, dass mir das bei allen libs die ich getestet habe
passiert ist!

Das ist sicher ein triviales Problem.

Ich wäre echt froh wenn mir jemand helfen könnte.

Vielen Dank!!!
Autor: TheMason (Gast)
Datum:

@thomas

selbst auf die gefahr hin das ich verhauen werde ...

hast du die interrupts (vor allem den globalen) aktiviert ?! oder
anpassungen für deinen ziel-controller vergessen ?!

hab mich selbst auch mal an einem sw uart versucht, und bis auf ein
timing-problem funktionierte es wunderbar (senden war vollkommen
unproblematisch, empfangen schon eher)
Autor: Matthias Larisch (matze88)
Datum:

Hallo!

Erstmal danke an Peter für diese Lib! Ich werde die in meinem jetzigen
Projekt (GPS Logger mit Bluetooth zum PC) an nem Mega88 benutzen. Eine
Frage kommt mir hierzu auf: Die empfangenen Bits werden auf der Hälfte
der Bitzeit gesampled. Nun besteht das Problem, dass jegliche
Verschiebung des OC1B Interrups auch den Samplezeitpunkt weiter zum
Bitende verschiebt. Bei 3,6864 MHz und 38400 bps habe ich "nur" 96 Takte
pro Bitzeit, die halbe Bitzeit Verschiebung die maximal erlaubt ist
wären nun 48 Tate. Wenn nun ein anderer Interrupt 30 davon nimmt,
bleiben 18. Interrupt aufruf bis zum Sample sind auch schon nochmal 16
(4 für den Interrupt aufruf, der 13. Zyklus in der Funktion ist der in
Befehl in meinem Listing). Bedeutet: Das würde arg knapp werden.
Verschiebe ich nun den FRÜHESTEN Sample Zeitpunkt nur auf 0,1 Bitzeit,
so sollte das doch wesentlich besser funktionieren? Durch den Input
Capture Noisefilter habe ich ne verschiebung um 4 Takte, der Interrupt
nun jedes mal 16. Macht zusammen 20, was bei mir nun schonmal 0,2
Bitzeit ist.

Denkfehler meinerseits?

Bei kurzen Leitungen (5cm vom Bluetooth Modul zum µC, den HW Uart
bekommt das GPS wegen geringerem Stromverbrauch im Hauptbetrieb, das
Bluetooth Modul krieg ich eh nicht > 38400 bps konfiguriert von daher
ist das egal) sollte doch der Bitzustand ziemlich kurz nach den Flanken
bereits stabil sein.

Bin gespannt, wieviel von meinem Post jetzt auf Denkfehler
zurückzuführen ist :-)

cu
Matze
Autor: Peter Dannegger (peda)
Datum:

@Matthias Larisch,

ja, bei hohen Baudraten sollte man noch einen Korrekturwert abziehen.

Ich würde aber eher ein 18,432MHz Quarz nehmen, dann entschärft sich das
erheblich.


Peter
Autor: Matthias Larisch (matze88)
Datum:

Gut, ich werde einfach mal mit nem Korrekturwert testen. Habe gerade mal
schlampig alle benötigten ISRs zusammengeschrieben, die längste kommt
auf insgesamt 62 Takte. Etwas optimieren kann ich da allerdings sicher
noch, oder aber ich müsste für 100%ige Funktion den Sampleoffset auf
1,05 oder sogar 1,0 stellen (wie vorgerechnet kommt ja alleine durch die
ICP ISR "0,2 * Bitzeit" dazu, deshalb dürfte das keine Probleme
darstellen).

Ein anderer Quarz geht wegen des höheren Stromverbrauchs nicht. Bei 16
MHz @ 3,3V bin ich bei 5mA. Okay, sooo tragisch wäre das wohl auch
nicht, aber ich versuche halt, so batteriefreundlich wie möglich zu
arbeiten. Solange meine Taktfrequenz reicht, ist das in meinen Augen
auch völlig in Ordnung. Der µC muss eigentlich auch nur aktiv sein, wenn
er gerade GPS Daten empfängt (Allerdings kann ich meine SystemClock in
der Zwischenzeit nicht abschalten - wenn ich den über nen externen Int.
mit dem Startbit vom Uart aufwachen lassen, verpasse ich einige Bytes
bis mein Takt läuft, deshalb arbeite ich gleich mit einem möglichst
niedrigen Takt der wenig Strom verbraucht.)

cu
Matze
Autor: Gerhard. (Gast)
Datum:

Es gibt natürlich oft wichtige Gründe ein Software UART zu verwenden und
bin hier mit meinen Beitrag etwas eben dem ursprünglichen Thema dieses
Threads. (Bitte nicht gleich Kopf abbeissen; -)   )

Manchal ist ein zweites (zusätzliches) HW-UART sehr nützlich. Sehr gute
Erfahrungen machte ich vor jahren mit den SPI UARTS von MAXIM
(MAX3100-3110). Der dayu notwendige Code im Interruptbetrieb war sehr
einfach zu verwirklichen und funktionierte einwandfrei. Der MAX3110 ist
sehr bequem weil da ein RS232 Interface ähnlich des MAX232 gleich
mitintegriert ist.

Die I2C UARTS von NXP habe ich allerdings noch nicht ausprobiert.
Sollten aber auch sehr brauchbar sein ausser der 3.3V Betriebsspannung.

Grüsse,
Gerhard
Autor: holm (Gast)
Datum:

@Manne:
Was zahlst Du für die beiden Dateien?
Ich habe die hier und kann die Dir auf eine CD brennen.
Ich nehme 59 Euro /h.

Gruß,

Holm
Autor: Sitzer (Gast)
Datum:

holm (Gast)

Was möchtest du für die beiden Dateien?!
Autor: Matthias Larisch (matze88)
Datum:

Ich melde mich nochmal zu meinem Thema: 3,686400 MHz und 38400 bps. Es
geht nicht, zumindest nicht mit dem oben vorliegenden Code. Der Compare
Match B läuft in den letzten Bits "über", d.h. er wird aufgerufen noch
bevor er beendet ist, das füllt den nächsten Comparewert mit ner Zeit
aus der Vergangenheit und schwups haben wir ein Problem :-)

Ich könnte jetzt rumwuseln und den TX Compare Interrupt deaktivieren
wenn empfangen wird, aber das ist alles nur Mist und führt zu Problemen.
Meine Lösung sieht jetzt so aus, dass ich nen 8 MHz Quarz einsetze. Habe
leider keinen 7,??? Baudratenquarz mehr da, aber 8 MHz tuns ja auch
(0,2% Error).
Pauschal zum berechnen würde ich sagen, dass 3,6864 MHz für 38400 bps
~10-20% zu langsam sind. Damit stelle ich mal die Formel in den Raum:
maximale Baudrate SWUart = Fclk / 120. Dann hat man sogar noch ein paar
Instruktionen Luft :-) Schon erstaunlich, wieviel Arbeit ein HW Uart da
abnimmt.
Autor: Sven Fink (finkman)
Datum:

Hi!
Bis auf den ganzen ünnützigen, persönlichn Müll (mehr Keilerei als
Produktives) möchte ich mir für den Code bedanken.
Trotzdem habe ich folgendes Problem:
Dein Code verwendet den 16bit Timer1 des Atmega8s (richtig?).
Diesen brauch ich jedoch ganz dringent für einen Sensor, der über den
Timer gemessen wird.
Die beiden anderen Timer sind für die Messung leider zu klein mit ihren
8bit.
Gibts da Ausweichmöglichkeiten? Zb Nutzung der 8bit-Timer für das
SW-UART?

PS:
Das eine Interface brauch ich um mit einen RGB-Puls-Controller zu
kommunizieren und das zweite bräuchte ich um den Atmega per PC
anzusprechen.


Gruß und Danke im Vorraus

Sven Fink
Autor: Peter Dannegger (peda)
Datum:

Sven Fink wrote:

> Gibts da Ausweichmöglichkeiten? Zb Nutzung der 8bit-Timer für das
> SW-UART?

Ja.
Im
Beitrag "I2C (TWI) Sniffer mit AVR"
ist ne Senderoutine und im
Beitrag "LCD über nur einen IO-Pin ansteuern"
ein Empfänger.

Beides für nen ATtiny25.
Allerdings kann der den Prescaler in 2-er Schritten einstellen.
Bei 8-er Schritten kann es zu hohe Fehler bei bestimmten Baudraten geben
oder man nimmt ein Baudratenquarz.


Peter
Autor: Newbie (Gast)
Datum:

Hallo,

wie werden die beiden "neuen" RX/TX-Pins mit dem PC verbunden, direkt
oder per Max232?
Autor: Matthias Larisch (matze88)
Datum:

Es ist nach wie vor eine UART auf TTL Pegel. Also brauchst du zur
Verbindung mit dem PC einen MAX232 oder ähnliches.
Autor: Matthias R. (matsch)
Datum:

Hallo,
kann mir bitte jemand die Zeile
TIMSK = 1<<TICIE1^1<<OCIE1A;
aus suart.c erklären? Verallgemeinert kann die Zeile auch so aussehen
REGISTER = 1<<BIT5^1<<BIT4
Das '^' ist doch eine Bitweise EXOR Verknüpfung. Werden die Bits
Abhängig von ihrem Urzustand gesetzt bzw. gelöscht?

Da in dem Register TIMSK auch die Interrupts für Timer0 und Timer2
maskiert werden, muss ich eher so etwas schreiben, um die anderen Bits
nicht zu verändern.
TIMSK |= 1<<TICIE1;
TIMSK |= 1<<OCIE1A;
Ist das das Gleiche?
Autor: Micha (Gast)
Datum:

@ Matthias R.
Ist zwar schon ne Weile her, aber trotzdem:

> Das '^' ist doch eine Bitweise EXOR Verknüpfung. Werden die Bits
> Abhängig von ihrem Urzustand gesetzt bzw. gelöscht?
Es wird nur das hier 1<<TICIE1^1<<OCIE1A ver-x-odert und dann in TIMSK
geschrieben.

> Da in dem Register TIMSK auch die Interrupts für Timer0 und Timer2
> maskiert werden, muss ich eher so etwas schreiben, um die anderen Bits
> nicht zu verändern.
> TIMSK |= 1<<TICIE1;
> TIMSK |= 1<<OCIE1A;
>
> Ist das das Gleiche?
Theoretisch schon. Da TIMSK aber anfangs 0x00 ist, kannst du auch
TIMSK = 1<<TICIE1;
TIMSK |= 1<<OCIE1A;
schreiben. Oder eben Peters Schreibweise...


@ Peter Dannegger
Ich möchte gerne deinen Code aus dem ersten Post verwenden, habe
allerdings das Problem, dass ich auch 0x00 als Datum senden und
empfangen muss. Bei den zu sendenden und zu empfangenden Frames steht
dafür an 4. Stelle immer die Frame-Länge in Bytes.

Hattest du auch schon einmal einen solchen Fall und eine entsprechende
Version der Software?

Senden ist kein Problem, da ich statt
void sputs( u8 *txt )
{
  while( *txt )
    sputchar( *txt++ );
}
einfach
void sputs( u8 *txt, u8 bytes_to_send )
{
  while( bytes_to_send-- )
    sputchar( *txt++ );
}
schreiben kann.

Für das Empfangen ist mir allerdings noch nichts effektives eingefallen.
Autor: Micha (Gast)
Datum:

Ich habe vergessen zu erwähnen, dass ich immer Frame-weise senden und
empfangen muss und zwischen einzelnen Frames einige ms Pause sind.
Autor: Kermit (Gast)
Datum:

Hallo,
bei mir klappt das empfangen (9600baud) nicht auf einem Atmega644 mit
1Mhz internen Takt. Mit der HW UART klappts dagegen einwandfrei.

Was ich schon nicht verstehe ist die seltsame Formel für die Bitdauer:

#define BIT_TIME  (u16)((XTAL + BAUD/2) / BAUD)

Wieso nicht einfach XTAL/BAUD?


Hat jemand vielleicht schon jemand erfolgreich eine (für gcc
geschriebene) SW_UART auf dem Atmega644 laufen?

Vielen Dank,
Kermit
Autor: Kermit (Gast)
Datum:

Achso, senden mit der SW UART geht einwandfrei! Mus ich den ICP-Eingang
(beim Atmega644 PD6) vielleicht vorher noch als I/O Eingang
konfigurieren? In der suart_init() wird der TX-Port nämlich als Ausgang
gesetzt mit

STXDDR |= 1<<STX;      // TX output

Ein Eingang wird aber nicht konfiguriert?

Ich musste übrigens etliche Register- und Bitnamen anpassen, weil sie
beim Atmega644 leicht anders heißen.
Autor: Runder (Gast)
Datum:

> Wieso nicht einfach XTAL/BAUD?

Um zum nächstliegenden Wert auf- und abzurufen, dann wird ggf. der
Fehler kleiner.
Autor: Benjamin (Gast)
Datum:

>Ich musste übrigens etliche Register- und Bitnamen anpassen, weil sie
>beim Atmega644 leicht anders heißen.

Hi Kermit,

ich wollte in den nächsten Tagen ebenfalls anfangen mich mit der SW UART
für den ATmega644 zu beschäftigen.
Wenn du, wie du sagst, die Dateien schon für den ATmega644 angepaßt
hast, magst du die vielleicht auch hier zur Verfügung stellen?
Wäre wirklich ne super Sache.

Gruß,
Benjamin
Autor: Öpf (Gast)
Datum:

Hi,

ich habe den SW-UART mal auf einen ATMega644 portiert und benutze dort
Timer 0.

Ich habe einige Änderungen vorgenommen. Wie immer auch hier die
Auskunft, das die Änderungen meiner Ansicht nach keine wesentlichen
Auswirkungen haben. Naja, wie immer ist sowas mit Vorsicht zu geniessen.

Leider habe ich von dem System aus weder eine Internetverbindung noch
kann die Krücke hier meinen USB-Stick lesen. Vielleicht guckt Ihr
trotzdem mal.

Am Anfang habe ich in suart_init die Zeilen mit OCR0A = TCNT0 + 1 und
TCCR0A rausgelöscht. Ich war der Meinung das die nichts bewirken, aber
vielleicht habe ich mich geirrt.
Dann habe ich im Compare B Int noch eingesetzt, dass in EIFR der INTF0
gelöscht wird, weil er störte obwohl der INT selbst garnicht aktiviert
war.

Ausserdem habe ich zwei Stellen rausgelöscht, for ICF1 in TIFRx gesetzt
wird, da Timer 0 im 644 keine Capture Unit hat. Abgesehen davon bin ich
neugierig wozu das nutze ist, wenn die Capture-Unit im Original nicht
benutzt wird. Vielleichet in Bug.

Ich habe das Problem, das die Ganze Mimik gut funktioniert aber nur ein
gewisse Zeit lang. Dann wird kein Zeichen mehr empfangen.
Auffällig ist, das bei srx_done = 0 und srx_mask = 1 der Capture
Interrupt B nicht mehr enabled ist. (Nur noch der für A).

Es scheint das im INT0 die Bedingung, das der RX-Pin immer noch low ist
manchmal nicht zutrifft. Das ist, soweit ich sehe der einzige Punkt wo
OCIE0B aktiviert wird.

Zum einen möchte ich gerne fragen wozu die Bedingung an sich gut ist.
(Zum Entprellen oder sowas?) Wenn sie nicht zutrifft steht der Empfang
völlig, da der Flankeninterrupt nicht mehr aktiviert wird.
Zum anderen möchte ich wissen, ob es, abgesehen vom völligen entfernen
der Bedingung noch andere Möglichkeiten habe.
Der Eingang hängt an einem Ausgang von nem MAX202.

Vielleicht hat ja sogar Peter Dannegger einen Moment Zeit da mal
raufzugucken. Das wäre sehr nett.
Autor: Peter Dannegger (peda)
Datum:

Öpf schrieb:
> ich habe den SW-UART mal auf einen ATMega644 portiert und benutze dort
> Timer 0.

Das könnte bei einigen Baudraten Probleme mit der Genauigkeit geben. da
der Prescaler nur in 8-er Stufen wählbar ist.


> Ich habe einige Änderungen vorgenommen.

Ein exakter Quelltext sagt mehr als 1000 Beschreibungen.


> Am Anfang habe ich in suart_init die Zeilen mit OCR0A = TCNT0 + 1 und
> TCCR0A rausgelöscht. Ich war der Meinung das die nichts bewirken, aber
> vielleicht habe ich mich geirrt.

Steht doch im Kommentar (ist für eilige).


> Dann habe ich im Compare B Int noch eingesetzt, dass in EIFR der INTF0
> gelöscht wird, weil er störte obwohl der INT selbst garnicht aktiviert
> war.

???


> wenn die Capture-Unit im Original nicht
> benutzt wird.

Und was ist dann das hier:
...
SIGNAL( SIG_INPUT_CAPTURE1 )    // rx start
...


> Ich habe das Problem, das die Ganze Mimik gut funktioniert aber nur ein
> gewisse Zeit lang. Dann wird kein Zeichen mehr empfangen.
> Auffällig ist, das bei srx_done = 0 und srx_mask = 1 der Capture
> Interrupt B nicht mehr enabled ist. (Nur noch der für A).

Ohne Code schwer zu sagen.


Ich würde zu der SW-UART mit FIFO raten.


Peter
Autor: Öpf (Gast)
Datum:
Angehängte Dateien:

@ Peter Dannegger

>Und was ist dann das hier:

>...
>SIGNAL( SIG_INPUT_CAPTURE1 )    // rx start
>...

Da ist mir ein Irrtum unterlaufen. Es ist ein paar Monate her, das ich
den Code gezogen habe und ich finde die ZIP-Datei nicht mehr.
Tatsächlich steht in dem Download oben die von Dir genannte
Interrupt-Routine. Da ich aber Timer 0 verwenden musste, habe ich den
Code geändert und musste daher mit dem Flanken-Interrupt auskommen. Mag
sein, das ich dabei was übersehen habe.
Timer 1 brauchte ich um so eine Uhrensynchronisation à la ntp zu machen.

Daher betrachtest Du das vielleicht nicht mehr als Deinen Code, wenn er
auch auf Deinem basiert. Jedenfalls meine ich das es möglich ist, das Du
1. keinen Rat zu Code geben willst/kannst, der sich stark verändert hat
und das 2. evtl. ein zweiter Thread von Nöten ist. Ich hatte auf jeden
Fall im Kopf, das ich Deinen Code genommen und abgewandelt habe.
Gedanklich hat der Code damit zumindest teilweise immer noch Dir gehört.
(Bin so ein alter Vogel der in den 80igern mit Computern angefangen hat.
Da hat man noch Skrupel).

>Das könnte bei einigen Baudraten Probleme mit der Genauigkeit geben. da
>der Prescaler nur in 8-er Stufen wählbar ist.
Grundsätzlich ja, aber bei 18.432MHz und 9600 Baud ist das meiner
Rechnung nach kein Problem. Prescaler ist 64. OCR0A daher dezimal 30.

>> Ich habe einige Änderungen vorgenommen.
>Ein exakter Quelltext sagt mehr als 1000 Beschreibungen.
Sicherlich.

>> Am Anfang habe ich in suart_init die Zeilen mit OCR0A = TCNT0 + 1 und
>> TCCR0A rausgelöscht. Ich war der Meinung das die nichts bewirken, aber
>> vielleicht habe ich mich geirrt.
>Steht doch im Kommentar (ist für eilige).
Nun, dann habe ich mich missverständlich ausgedrückt. Da steht zwar, das
ein Overflow-Interrupt ausgelöst werden soll, aber nicht wozu das gut
ist.
Jetzt wo ich nochmal darauf schaue, denke ich, das es darum geht, das
die Prüfung auf ein zu sendendes Byte definitiv einmal sofort
stattfindet.

Ich füge hier mal den Code bei. Wenn wir den Fehler finden, dann mag er
vielleicht jemandem von Nutzen sein.

Ich meine allerdings, nach dem ein paar Stunden vergangen sind, das mein
Problem nicht von der SW her kommt, sondern von der HW. Wahrscheinlich
gibt die HW, der ich den Strom anschalte am Anfang mal so ein "Blurbs"
von sich, das die Interrupt-Routine triggert. Werde mal versuchen den
ISR zu disablen bis die Spannung sich stabilisiert hat und das Gerät
hochgekommen ist (ist auch nur ein uC, allerdings nicht von mir).

Fakt ist jedenfalls das der Empfang relativ lange Zeit geht. Es werden
teilweise Kilobyte empfangen ohne das Probleme auftreten (Und das ohne
FIFO).

>Ich würde zu der SW-UART mit FIFO raten.
Nun, da der Mechanismus der selbe ist nur eben der FIFO oben drauf,
würde das meiner Ansicht nach nichts bringen wenn das Problem
tatsächlich in der Empfangsmimik liegt. Aber wiegesagt, glaube ich das
nicht mehr.

Wäre trotzdem nett wenn Du mal einen Blick drauf wirfst.
Autor: Peter Dannegger (peda)
Datum:

@Öpf,
EIMSK &= ~(1 << INT0);      // disable edge interrupt
  if( !(SRXPIN & 1<<SRX))    // still low

Bei Dir greift die Störunterdrückung zu spät, d.h. Du hast den Interrupt
schon disabled.
Du darfst das Disable erst im if machen.


Peter
Autor: Öpf (Gast)
Datum:

"Bei Neumann" - das ist es.

Vor dem if weiss ich ja noch gar nicht ob es ein Störimpuls ist und darf
den INT noch nicht sperren. Erst wenn die Störbedingung ausgeschlossen
ist.

Also so:
if( !(SRXPIN & 1<<SRX)) {    // still low
  EIMSK &= ~(1 << INT0);      // disable edge interrupt
  TIMSK0 = 1<<OCIE0A^1<<OCIE0B;  // wait for first bit
}

Danke. ;-)
Autor: Öpf (Gast)
Datum:
Angehängte Dateien:

Ich habe die Änderung getestet und es läuft stabil.
Ich poste hier mal den Code für einen ATMega644.

Er basiert auf dem Code von Peter Dannegger.
Die Unterschiede sind:
1. Verwendung von Timer 0 (8-Bit) anstelle Timer 1 (16-Bit).
Das hat Auswirkung auf die möglichen Baudraten (wie P.D. schon bemerkt
hat)
läuft aber z.B. mit einem 18.432MHz Quarz und 9600 Baud.
2. Verwendung des Flankeninterrupts INT0 anstelle des
Capture-Interrupts.

Umstellung auf andere Flankeninterrupts oder Timer sollte gehen, ist
hier aber nicht mit #defines gemacht.

Da P.D.s SW-UART mit FIFO auf diesem Code basiert ist er auch einfach
mit FIFO auszurüsten. Einfach mal die Unterscheide ansehen.

Einiges an Code ist auskommentiert, aber ich bin jetzt zu faul, das
rauszulöschen.

Viel Spass und danke an Peter D. für die Hilfe bei der
Betriebsblindheit. (Ein INT der gesperrt ist, kann natürlich nicht mehr
auslösen).
Autor: Öpf (Gast)
Datum:

Habe leider einen Teil des Textes vergessen, den ich posten wollte.

Die Verwendung des Flanken-Interrupts anstelle des Caputure-Interrupts
hat den Nachteil, das die Bitzeit nicht mehr so genau stimmt wie im
ersten Fall.
Es muss also im Einzelfalls geprüft werden, ob evtl. noch eine Konstante
subtrahiert werden muss oder die Differenz von ausreichend geringer
Bedeutung ist. Grundsätzlich wird das kritischer je mehr höherpriore
Interrupts beteiligt sind und je höher die Baudrate wird.

Meine Variante ist also nicht grundsätzlich und immer ein Ersatz für
Peter Dannegers Originial.
Autor: Marc (Gast)
Datum:

Hallo liebe Experten!

Ich möchte gern diesen Software UART auf einem ATmega32 mit 16MHz
benutzen. Leider kommt jedoch schon beim Verwenden des Beispielcodes
eine Fehlermeldung des Compilers : undefined reference to 'suart_init'

Ich gehe mal davon aus, dass ich die Datei "suart.c" noch nicht richtig
ins Projekt eingebunden habe, weiß aber auch nicht wirklich wie das
geht.

Wenn ich den Code in meine .c kopiere wirds dann compiliert.

Beim versuch das ganze dann zu testen wird allerdings immer mein AVR
Dragon abgeschossen, sodass ich da erst die Firmware neu aufspielen
muss, damit es geht.

Vorher (ohne die Erweiterung mit dem SUART) ging das einwandfrei.


Ich benutze wie gesagt einen ATmega32 mit 16MHz, das AVR Studio mit
WINAVR und den AVR Dragon zum Programmieren und Debuggen.


Ich hoffe ihr könnt mir helfen, da ich das ganze noch bis zum Freitag
zum laufen bringen muss (Projektarbeit).

MfG und schönen 3. Advent
Marc
Autor: Marc (Gast)
Datum:

PS: Hab doch noch was vergessen: der SUART-Code ist natürlich der ganz
oben in diesem Fred...
Autor: Peter Dannegger (peda)
Datum:

Marc schrieb:
> Beim versuch das ganze dann zu testen wird allerdings immer mein AVR
> Dragon abgeschossen, sodass ich da erst die Firmware neu aufspielen
> muss, damit es geht.

Was bedeutet "abgeschossen"?
Was für eine Firmware?

Zu Dragon Problemen kann ich Dir nicht helfen.
Kann man den Dragon denn nicht wie jeden anderen AVR programmieren?


Peter
Autor: Marc (Gast)
Datum:

Hallo Peter,

der AVR Dragon ist ein Programmier und Debug Gerät! Und das Gerät hat
natürlich eine Firmware drauf.

Wenn du in AVR Studio Hilfe mal Dragon eingibst, findest du das. Und da
steht dann z.B. bei Troubleshooting, dass wenn die LED gelb leuchtet,
die Firmware korrupt ist und man sie neu aufspielen soll. Danach kann
ich wieder einmal das compilierte Programm auf den ATmega übertragen und
schwupps... LED des Dragon wieder gelb! Aber nur wenn ich den SoftUart
-Teil mit drin habe.

Hoffe das war jetzt verständlich :-)
Autor: Patrick Pomp (xadas)
Datum:

Super! Funktioniert einwandfrei, sowohl auf einem ATMega8 als auch auf
einem ATMega644.
Hier die Anpassungen für den ATMega644:
#ifdef _AVR_IOM644_H_
#define SRX     PD6     // ICP on Mega644
#define SRXPIN  PIND

#define STX     PD5     // OC1A on Mega644
#define STXDDR  DDRD

#define TIFR    TIFR1
#define TIMSK   TIMSK1
#define TICIE1  ICIE1
Autor: Thoralt Franz (thoralt)
Datum:

Hallo Leute,

ich weiß, der Thread ist schon nicht mehr ganz frisch, aber ich wollte
auf einen Fehler hinweisen, welcher weiter oben in die Diskussion
eingebracht wurde:
 TIMSK0 = 1<<OCIE0A^1<<OCIE0B;  // wait for first bit

Das führt nicht zum gewünschten Resultat, denn die Priorität des
Shift-Left-Operators ist viel niedriger als des EXOR. Im vorliegenden
Fall wird also folgendes compiliert:
 TIMSK0 = 1<<(OCIE0A^1)<<OCIE0B;  // wait for first bit

Um es richtig zu machen, sind bei Shift-Operationen fast immer Klammern
nötig:
 TIMSK0 = (1<<OCIE0A)^(1<<OCIE0B);  // wait for first bit

Ich hoffe, das hilft irgendjemandem.

Viele Grüße
Thoralt
Autor: Peter Dannegger (peda)
Datum:

Nö, es wird zuerst geschoben (Prio 11) und dann EXOR (Prio 7).
Siehe:
http://www.ostc.de/c-precedence.pdf

Klammern sind unnötig.

Klammern braucht man, wenn man bitweise Verknüpfungen vergleicht. Das
ist eine gern gemachte Fallgrube, da man intuitiv das Gegenteil
erwartet.
Z.B.
  if( i&7 == 1 )
ist falsch.


Peter
Autor: Edgar Michel (emi)
Datum:

Hallo,

zunächst mal vielen Dank an die beteiligten für den SOft UART. Genau das
habe ich gesucht. Zu dem Code habe ich doch eine Frage.
Ich benötige den UART für eine Schnittstelle die permanent Daten schickt
mit 2400 Baud. D.h. an dem Zeitpunkt, wenn der Soft UART
initialisiert wird ist es nicht synchronisiert. Damit meine ich -
das erkennen des Startbits kann durchaus ein Datenbit auf "0" sein.
Üblicherweise werden 10 Bits verschickt - Start+ 8 Daten + Stop.
In dem obigen Code wird das Stop-Bit nicht ausgewertet (oder ich
verstehe den Code nicht). Sollte man nicht
        srx_done = 1;      // mark rx data valid
erst dann setzen wenn als 10. Bit eine "1" anliegt???

Viele Grüße
Edgar
Autor: Öpf (Gast)
Datum:

>Zu dem Code habe ich doch eine Frage. ...
>In dem obigen Code wird das Stop-Bit nicht ausgewertet (oder ich
verstehe den Code nicht). Sollte man nicht
        srx_done = 1;      // mark rx data valid
>erst dann setzen wenn als 10. Bit eine "1" anliegt?

Nein. Das ist nicht der Zweck von srx_done. Es soll anzeigen, ob der
Empfang vollständig (nach Anzahl der Bits ) ist, und nicht, ob der
Empfang korrekt ist.
Autor: Jörg Esser (jackfritt)
Datum:

Is schon älter ich weiss. Kurze Frage zu Peters Code.
Dort wird ja in uart.c prescaler und bauddiv "berechnet". Da wird ja
Code erzeugt. Könnte ich das in unten aufgeführter Art erledigen? Würde
mir Codespeicher sparen ? Oder habe ich mal wieder einen "blutiger
Anfänger" Denkfehler ?
#if defined (__AVR_ATtiny13__) || (__AVR_ATtiny85__) || (__AVR_ATtiny84__)
#define OCR 255
#else
#error Look into Datasheet if 8 or 16 Bit Timer and change OCR=255 or OCR=65536
#endif
  // Find Prescaler
#if ( F_CPU/FREQ  ) <= OCR
TCCR0B = (0 << CS02)  | (0 << CS01) | (1 << CS00);
#define PRESCALER 1 // 0 but not good for Mathematics
#   warning Timer without Prescaler
#elif (F_CPU/8/FREQ ) <= OCR
TCCR0B = (0 << CS02)  | (1 << CS01) | (0 << CS00);
#define PRESCALER 8
#   warning Timer with 8 Prescaler
#elif (F_CPU / 64 / FREQ ) <= OCR
TCCR0B = (0 << CS02)  | (1 << CS01) | (1 << CS00);
#define PRESCALER 64
#   warning Timer with 64 Prescaler
#elif (F_CPU / 256 / FREQ ) <= OCR
TCCR0B = (1 << CS02)  | (0 << CS01) | (0 << CS00);
#define PRESCALER 256
#   warning Timer with 256 Prescaler
#elif (F_CPU / 1024 / FREQ ) <= OCR
TCCR0B = (1 << CS02)  | (0 << CS01) | (1 << CS00);
#define PRESCALER 1024
#   warning Timer with 1024 Prescaler
#elif (F_CPU / 1024 / FREQ ) > OCR
#   error No Prescaler could be defined !!
#endif
Autor: Jörg Esser (jackfritt)
Datum:

Sorry ich nehme alles zurück. War ein anderer Code(I2Csniff) von Peter.
Also einfach nicht weiter beachten :)

Gruss,

Jörg
Autor: Volker U. (volkeru)
Datum:

Peter Dannegger schrieb:
> Nö, es wird zuerst geschoben (Prio 11) und dann EXOR (Prio 7).
> Klammern sind unnötig.

Ich frage mich aber, warum du überhaupt eine XOR-Verknüpfung benutzt,
wenn es auch eine einfache OR-Verknüpfung täte!? Gefällt dir das Hütchen
einfach nur besser, als der senkrechte Strich, oder gibt es einen
plausiblen Grund dafür?

Da XOR eine andere logische Funktionalität besitzt, als ein OR, sollte
man es m.E. auch nur dann benutzen, wenn es einen echten Grund dafür
gibt.

Beim Bearbeiten deines Codes habe ich mich nämlich erheblich darüber
gewundert, warum du die Bits unnötigerweise ver"x"oderst und länger
überlegt, ob das im Gesamtkonzept irgendeinen Sinn hat. Ich kann aber
keinen erkennen. Insofern ist der Code verwirrend.

Und hier verstehe ich den Sinn auch nicht:

Du schreibst:
#define  TX_HIGH    (1<<COM1A1^1<<COM1A0)
#define  TX_LOW    (TX_HIGH^1<<COM1A0)

Warum schreibst du dafür nicht einfach folgendes, was viel
übersichtlicher ist:
#define  TX_HIGH    ((1<<COM1A1) | (1<<COM1A0))
#define  TX_LOW    (1<<COM1A1)

Gruß, Volker
Autor: Uwe (Gast)
Datum:

Hallo Volker,

ich erkläre mir die Schreibweise wie folgt:
jeder Programmierer hat seine Stiel, und Peters ist kurz und
zielführend.

Hier rechnet auch nicht der atmel, sondern der crosscomüiler, bzw. der
Präprozessor des avr-gcc.

Naja ich finde es sehr gut von Peter und anderen Funktionsmodule nutzen
zu können, das erspart mir doch Arbeit.
Autor: Volker U. (volkeru)
Datum:

Hi Uwe,

> jeder Programmierer hat seine Stiel, und Peters ist kurz und
> zielführend.

Ähm, ja sicher hat jeder seinen Stil. Aber trotzdem sollte man sich,
wenn man vorhat, den Code evtl. zu veröffentlichen, dem allgemein
gebräuchlichen Stil anpassen, wie ich finde. Allein schon deshalb, damit
man auch fremden Code schnell verstehen kann. Gerade C ermöglicht (durch
die Defines) einen Stil bis hin zur völligen Unkenntlichkeit. Viele
Defines sind vielleicht schnell und komfortabel beim Schreiben, aber
machen den Code sehr unübersichtlich.

Was "kurz und zielführend" betrifft: Ein "|" ist ebenso kurz wie ein
"^". Und in meinem obigen Beispiel ist der von mir vorgeschlagene Code
sogar kürzer als der von Peter. Übersichtlicher allemal.

> Hier rechnet auch nicht der atmel, sondern der crosscomüiler, bzw. der
> Präprozessor des avr-gcc.

Die Versionen oben werden beide vom Compiler gleich hoch optimiert. Ich
sehe da keinen Unterschied. Was wirklich VIEL Code verursacht, ist
Fließkommaarithmetik, weil die meisten AVRs keine FPU haben (gibts
überhaupt einen, der eine hat?) und die Fließkommaarithemtik daher
simuliert werden muss.

Beispiel:

#define BIT_TIME  (u16)(XTAL * 1.0 / BAUD + 0.5)

erzeugt (theoretisch) viel Code, weil mit Fließkomma gearbeitet wird.

#define BIT_TIME  (u16)(((XTAL * 10 / BAUD) + 5) / 10 )

erzeugt das selbe Ergebnis, kommt aber ohne Fließkomma aus und bedeutet
daher i.d.R. ganz erheblich weniger Code. Wenn man also Code einsparen
will, sollte man z.B. immer auf Fließkommaoperationen verzichten! In
diesem Beispiel ist das allerdings egal, weil nur Konstanten verwendet
werden und die vollständige Berechnung daher schon vom Compiler
durchgeführt wird und deshalb keine Arithmetik im Microcontroller
stattfinden muss. Aber wenn diese Berechnung nicht mit Konstanten,
sondern mit Variablen für XTAL oder BAUD dürchgeführt würde, entstünde
im ersten Beispiel erheblich mehr Code! Ich habe es gerade mal
ausprobiert. Eine kleine Testroutine erzeugt mit Fließkommaarithmetik
890 Bytes Code, während sie mit Integer-Arithmetik (unteres Beispiel)
nur 198 Bytes erzeugt. Das sind die Stellen, wo man richtig Code
einsparen kann. Und nicht bei irgendwelchen logischen Operationen.

> Naja ich finde es sehr gut von Peter und anderen Funktionsmodule nutzen
> zu können, das erspart mir doch Arbeit.

Aber klar, zweifelsohne! Dieses Forum ist ein wahrer Schatz! Aber wie
ich finde, sollte man doch auch gut verständlichen Code veröffentlichen.

Ich suche schon länger eine Routine für einen Softuart, die wirklich gut
ist. Alle die ich bisher finden konnte, waren leider wenig
leistungsfähig. Bei 4 MHz bekommen die meisten Routinen schon Probleme
mit 9600 baud und 19200 geht gar nicht.

Die hier vorgestellte Routine habe ich noch nicht getestet, aber sie ist
vermutlich erheblich besser. Sie hat aber auch einen riesigen Nachteil:
Sie läuft nur mit Controllern, die eine Input Capture Unit (ICP) im 16
Bit-Timer haben. Das sind nicht viele. Ich kenne nur die AtTiny
24/44/84, die das haben.

Insofern ist also auch diese Routine wieder nur auf wenigen, bestimmten
AVRs verwendbar :-(.

Gruß, Volker

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




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 erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net