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
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
Datum:
Oh Mann Manne, schonmal eine weit verbreitete C-Compiler-Distribution angeschaut, der hier ein eigenes Forum gewidmet ist? Kopfschüttel, Stefan
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
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
Datum:
oh Mann ... einmal kurz drüberschauen wäre auch nicht schlecht: Sorry, ich konnte mich einfach nicht zurückhalten ;-) Gruß, Stefan
Datum:
Tja, der eine kennt sich nur mit IAR aus der andere hat Probleme mit dem schreiben ;-)) ( lol )
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
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.
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)
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...
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
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!
Datum:
Eine Frage wie viele Software-UART kann man da mit diesem Beispiel im Mega8 realisieren?
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!!!
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)
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
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
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
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
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
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.
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
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
Datum:
Hallo, wie werden die beiden "neuen" RX/TX-Pins mit dem PC verbunden, direkt oder per Max232?
Datum:
Es ist nach wie vor eine UART auf TTL Pegel. Also brauchst du zur Verbindung mit dem PC einen MAX232 oder ähnliches.
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?
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.
Datum:
Ich habe vergessen zu erwähnen, dass ich immer Frame-weise senden und empfangen muss und zwischen einzelnen Frames einige ms Pause sind.
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
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.
Datum:
> Wieso nicht einfach XTAL/BAUD?
Um zum nächstliegenden Wert auf- und abzurufen, dann wird ggf. der
Fehler kleiner.
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
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.
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
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.
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
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. ;-)
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).
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.
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
Datum:
PS: Hab doch noch was vergessen: der SUART-Code ist natürlich der ganz oben in diesem Fred...
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
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 :-)
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 |
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
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
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
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.
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 |
Datum:
Sorry ich nehme alles zurück. War ein anderer Code(I2Csniff) von Peter. Also einfach nicht weiter beachten :) Gruss, Jörg
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
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.
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



