Forum: Projekte & Code Software UART mit FIFO


von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Ne UART mit ein paar Bytes Puffer ist doch ganz praktisch, nimmt ne 
ganze Menge Streß aus der Mainloop.

Hier mal mit der Software-UART kombiniert, für die schnuckeligen ATtinys 
(Beispiel mit ATtiny44).

Oder als 2.UART für nen ATmega328P.

Statt dem ICP kann man auch einen externen Interrupt nehmen 
(ATtiny25..85).


Peter

von Klaus der dünne (Gast)


Lesenswert?

... leider in C

aber der Algo. ist 1A Klaus

von Sabine (Gast)


Lesenswert?

@ Peter
Ich habe den Code auf meinem ATtiny44 ausprobiert, aber leider 
funktioniert er nicht so gut.

Der Code wird irgendwie langsamer ausgeführt als sonst. Die 
"delay-funktion" lässt eine LED ca. 10mal länger blinken als in einem 
einfachen main.c .
Die Daten die ich auf der UART sehe sind dem entsprechend auch nur wirr. 
ICh betreibe den Controller mit den 8Mhz vom internen Osz. ( ...denke 
ich, denn ich habe die fuses nie geändert und avr-studio zeigt es so 
an.)

Gleichzeitig bin auf der Suche nach einer anderen Portbelegung. Ich muss 
die RX und TX Leitungen auf anderen Pins haben. Auch bei deinen anderen 
Soft-UARTS verwendest du immer die gleichen. Wie kann ich diese Belegung 
ändern?

Es wäre schön, wenn du mir etwas Starthilfe geben könntest.
Danke

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Sabine schrieb:

> Der Code wird irgendwie langsamer ausgeführt als sonst. Die
> "delay-funktion" lässt eine LED ca. 10mal länger blinken als in einem
> einfachen main.c .

Kann es sein, dass die LED exakt 8 mal langsamer blinkt?

> Die Daten die ich auf der UART sehe sind dem entsprechend auch nur wirr.
> ICh betreibe den Controller mit den 8Mhz vom internen Osz. ( ...denke
> ich, denn ich habe die fuses nie geändert und avr-studio zeigt es so
> an.)

Ich nehme mal an, dass der ATTiny nur mit 1MHz statt 8MHz läuft. Dafür 
ist die CKDIV-Fuse zuständig, siehe auch:

http://www.engbedded.com/fusecalc/

Gruß,

Frank

von Sabine (Gast)


Lesenswert?

Danke für den Hinweis mit dem CKDIV.
Du hattest Recht im Auslieferungszustand steht er zwar auf 8MHz aber der 
Vorteiler ist auch gesetzt.

Mein Problem ist damit so recht immer noch nicht gelöst.
Wie kann es sein,das der folgende Code in einem einfachen MAIN die LED 
eine halbe Sekunde blinken läßt. Wenn ich die Zeilen aber in die Main 
aus Peters Code einfüge, blinkt sie 5 sekunden.
1
PORTA |= (1 << PA3);    //rot einschalten 
2
_delay_ms(500);      // verzögerung
3
PORTA &= ~(1 << PA3);


Dazu kommt noch erschwerend, dass ich doch die RX-TX auf anderen Pins 
brauche. Wenn du mir da auch noch einen Tip geben könntest, wäre ich dir 
sehr dankbar.

von Sabine (Gast)


Lesenswert?

Ich bins schon wieder.
Denn fehler mit den unterschiedlichen Zeiten habe ich gefunden.
Peter schreibt ich seiner MAIN.H:
1
#define  XTAL  11.0592e6
2
#define  BAUD  57600
3
#define F_CPU   XTAL

F_CPU wird wiederum für die "delay" verwendet ... und das sind 
eigentlich nun mal nur 1MHz.

F_CPU hatte ich in meinen Test-Programm nicht definiert....

Die 500ms, die "delay" produzieren soll, stimmen aber auch nicht.
Es sind 860ms.
Kannst du mir das bitte erklären?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Sabine schrieb:

> Die 500ms, die "delay" produzieren soll, stimmen aber auch nicht.
> Es sind 860ms.
> Kannst du mir das bitte erklären?

Nein, kann ich leider nicht. Wie hast Du denn nun XTAL resp. F_CPU im 
Programm eingestellt?

Wenn Du das folgendermaßen änderst:

#define  XTAL  8.0e6

dann sollte Dein delay richtig laufen.

Läuft der interne Takt nun mit 8MHz, d.h. Du hast die CKDIV-Fuse 
korrigiert?

Und wie hast Du die 860ms gemessen?

Beachte auch, dass Du eine identische F_CPU-Definition in allen 
Source-Modulen verwendest, am besten setzt Du F_CPU im Projekt und 
löscht Peters eigene Definitionen von XTAL und F_CPU.

Gruß,

Frank

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Sabine schrieb:

> Gleichzeitig bin auf der Suche nach einer anderen Portbelegung. Ich muss
> die RX und TX Leitungen auf anderen Pins haben. Auch bei deinen anderen
> Soft-UARTS verwendest du immer die gleichen. Wie kann ich diese Belegung
> ändern?

Peter nutzt den sog. ICP-Pin des Tinys und den dazugehörenden Interrupt. 
Um einen anderen Pin zu verwenden, musst Du einen anderen externen 
Interrupt verwenden. Ich weiß jetzt aber nicht, ob der ATTiny44 weitere 
Interrupts auf den anderen Pins bietet, habe noch nie mit dem ATTiny44 
gearbeitet bzw. mir das Datenblatt dazu angeschaut.

EDIT:
Habe gerade mal ins Datenblatt geschaut, es sagt: "External Interrupt 
Sources: Pin Change Interrupt on 12 Pins". Das heisst, Du kannst fast 
jeden Pin verwenden, Du musst dann aber die ISR auf den Pin Change 
Interrupt umstellen.

Eine andere Möglichkeit, einen Soft-Uart zu implementieren, ist die 
Verwendung eines Timer-Interrupts und dazugehörendes Polling. Das geht 
aber mit Peters Code nicht - jedenfalls nicht mit dem Code aus diesem 
Thread.

Tante Google mit folgenden Suchwörtern

  software uart avr timer

sollte dazu noch mehr sagen können.

Gruß,

Frank

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Noch eine Ergänzung: Einen Soft-Uart zu implementieren ohne 
angeschlossenen Quarz kann in die Hose gehen. Der interne Oszillator ist 
nicht sehr genau und insb. auch temperaturabhängig. Bei zu großen 
Abweichungen der realen Taktfrequenz kann es zu Übertragungsfehlern 
kommen - jedenfalls bei höheren Baudraten.

Bei 8MHz würde ich mich nicht trauen, mehr als 9600Bd zu verwenden - 
jedenfalls bei einem HW-Uart. Bei einem Soft-Uart könnten die 9600Bd 
auch schon zu viel sein, muss man ausprobieren.

Gruß,

Frank

von Peter D. (peda)


Lesenswert?

Sabine schrieb:
>
1
> #define  XTAL  11.0592e6
2
> #define  BAUD  57600
3
> #define F_CPU   XTAL
4
>

Wenn Du keine >=11MHz nimmst, könnten 57kB Probleme bereiten.
Nimm also ne entsprechend kleinere Baudrate, z.B. 9600.


> Die 500ms, die "delay" produzieren soll, stimmen aber auch nicht.
> Es sind 860ms.
> Kannst du mir das bitte erklären?

Delay ist keine Uhr. Wenn Du genaue Zeiten brauchst, nimm nen Timer.
Delay zählt einfach nur Befehle, d.h. jeder Interrupt verlängert es um 
seine Ausführungszeit.


Peter

von Sabine (Gast)


Lesenswert?

@ Frank
Die F_CPU habe ich als define in der main.h neu festgelegt und die 
definitionen von Peter habe ich entsorgt. (auskommentiert)
Sollte doch gehen. (oder)
Ja, die CKDIV-Fuse habe ich jetzt auch korrigiert.
Die 860ms habe ich mit einem Scope gemessen.

Die baudrate habe ich schon reduziert auf 4800.
Tja, und das mit den Schwankungen bei dem internen Oszillatorhabe ich 
als harmlos eingestuft, da ich den Controller sowieso immer bei 
Raumtemp. betreiben will.

Das mit den RX-TX-Pins ist so mein Problem, den Peter benutzt 3 
Interruptroutinen:
1
ISR( TIM1_CAPT_vect )  // start detection
2
ISR( TIM1_COMPB_vect )  // receive data bits
3
ISR( TIM1_COMPA_vect )  // transmit data bits

Jetzt ist für mich nicht so ganz klar, welcher Interrup für was 
zuständig ist.
... und laut Datenblatt, haben zwar einige Pins einen Interrupt, aber 
ich kann Sie in der Tabelle nicht finden. Da gibt es nur PCINT1 und 
PCINT2.
Wo bekomme ich denn den passenden Vector für PCINT1 und PCINT5 her?

@Peter
Könntest du bitte mal kurz nennen an welchen Stellen ich drehen muss, um 
RX auf PA5 und TX auf PA1 zu haben. (... das in main.h ist klar, das 
leuchtet sogar mir ein. Aber in uart.c wird es schwieriger.)
Ich denke das es für einen fortgeschrittenen Coder etwas leichter ist 
den Code zu lesen wie eine "Matrix". Aber dazu sehe ich mich noch nicht 
in der Lage.

Das die "delay" durch Interrupts länger wird leuchtet mir ein. Aber Sie 
ist konstant 860ms, auch wenn ich nur einen Pin mit dieser Funktion 
kippen lasse.
Könnte das schon ein Hinweis auf den sehr ungenauen internen Oszillator 
sein?

von Sabine (Gast)


Lesenswert?

So, ich habe es geschafft.
Ich kann nun mit dem internen Oszilator bei 4800Bd senden.
Empfangen habe ich noch nicht getestet.

Leider will es mir nicht gelingen den TX-Pin umzuverlegen.
In der main.h (nd auch in der uart.c) habe ich folgende zeilen ergänzt:
1
#define  NEU_STXD  SBIT( PORTA, PA1 )  // 
2
#define  NEU_STXD_DDR  SBIT( DDRA,  PA1 )

und in der suart.c bei jedem:
1
TX_OUT = TX_HIGH;
noch ein
1
PORTA |= (1 << PA1);    //High
bzw bei
1
TX_OUT = TX_LOW;
2
PORTA &= ~(1 << PA1);  //Low

Ich verstehe es nicht denn der PA1 bewegt sich garnicht. Dabei sollte 
doch der TX nun auf beiden Pins vorhanden sein. (oder?)
Es wäre schön, wenn da jemamd was zu sagen könnte.

von Basti (Gast)


Lesenswert?

Hallo,

hab den Softwareuart zum laufen bekommen...
Verwende AVR Studio (WinAVR) + Atmega48... 16Mhz cyristal

Musste nur alle interruptvectoren umbennenen... also aus TIM1_ -> 
TIMER1_ machen

Danke für den Quellcode... kombiniert mit deinem Bootloader muss ich 
fast nie mehr den RS232 Stecker am STK 500 umstecken :)

von Uwe S. (de0508)


Angehängte Dateien:

Lesenswert?

Hallo,

ich möchte den attiny861 mit diesen Code verwenden, leider fehlt mir 
noch die Erfahrung eine Anpassung durch zu führen.

Wer kann Helfen ?

Im Zielcode sind:

* OCR1A, OCR1B, bzw. die Pins PB1, PB3 belegt und geben ein Audio PWM 
Signal aus.

* Eine SD Karte ist über PB0 (CS), PA0 (DataIn), PA1 (DataOut) und PA2 
(Clk) angeschlossen.

* Der attiny861 läuft mit dem internen 8MHz Takt.

* PB4 - PB6 und PA3, PA4 - PA7 können für den "Software UART" verwendet 
werden.

von Sebastian (Gast)


Lesenswert?

Hallo.

Erstmal danke für den super SoftUART.
Hab ihn für nen ATmega32 modifiziert und bei 16MHz vom internen Oszi und 
57600 Baud laufen die ersten Versuche ohne Probleme.

Jetzt habe ich aber doch noch eine Schwierigkeit.
Ich schaffe es nicht mit uputchar() ein einzelnes Zeichen zu senden.
uputs("Hallo Peter \n\r") wie in der Test main.c läuft. Ich schaue mir 
den output via TeraTerm an.
Vielleicht kann mir ja jemand einen Tip geben.

Gruß Sebastian

von Matthias N. (nippey)


Lesenswert?

Von Sabine:
>Das die "delay" durch Interrupts länger wird leuchtet mir ein. Aber Sie
>ist konstant 860ms, auch wenn ich nur einen Pin mit dieser Funktion
>kippen lasse.
>Könnte das schon ein Hinweis auf den sehr ungenauen internen Oszillator
>sein?

Wenn das delay ohne die Interrupt-Funktionen im Hintergrund korrekt 
läuft, wird das Problem nicht vom Oszillator verursacht.

Auch wenn je nach Situation verschieden große Teile des Interrupt-Codes 
ausgeführt werden, so vermute ich dass die Prologe und Epiloge der 
Interruptroutinen so lang sind, dass sich verschieden lange 
Codeabschnitte innerhalb der Routinen zeitlich gar nicht bemerkbar 
machen.

//OT:
Ich bin eh kein Freund der mitgelieferten Delay-Funktion
Wenn ich die Chance habe, nutze ich meine eigene und greife dafür auf 
einen der Timer zurück. (In den meisten Fällen ist es sogar möglich auf 
einen bereits genutzten Timer aufzusatteln ;)
Auf diese Weise ist es sogar möglich nicht-blockierende Delays zu 
nutzen, also während der Wartezeit mit etwas anderem weiterzumachen!
//!OT

EDIT: hahahaaa, man sollte mal aufs Datum gucken...

von Lucky (Gast)


Lesenswert?

Hy zusammen,
Ich bin ein anfänger in sachen coden.
Ich versuche gerade den code auf den Attiny13 umzuschreiben, der erfolg 
hält sich aber in grenzen, bekomme fehler meldungen die ich nicht 
verstehe, es geht um DDRA und PORTA

=> ../MAIN.C:21: error: 'DDRA' was not declared in this scope
=> ../MAIN.C:23: error: 'PORTA' was not declared in this scope

Wie bekomme ich die felher weg und könnt ihr mir vieleicht erklären wo 
her die PORTS kommen, denn der attiny45 hat doch ur PB0-PB5.
und wenn ich die DDRA und PORTA auskommentiere bekomme ich 5 meldung

=>../SUART.C:105: error: 'PINA' was not declared in this scope

damit ihr wiesst wie ich vorgegangen bin, habe den codes geladen 
compeliert (48errors), und der code ist für timer1 geschrieben habe 
alles auf timer0 geändert und die register angepasst.
aus
#define  STXD    SBIT( PORTA, PA6 )  // = OC1A
#define  STXD_DDR  SBIT( DDRA,  PA6 )

#define  SRXD_PIN  SBIT( PINA,  PA7 )  // = ICP

habe ich gemacht
#define  STXD    SBIT( PORTB, PB4 )  // = OC1A
#define  STXD_DDR  SBIT( DDRB,  PB4 )

#define  SRXD_PIN  SBIT( PINB,  PB5 )  // = ICP

komme dann auf 11 warnung, laufen tuts trozdem nicht :(

hat das einer schon mal von euch gemacht den code für attiny13 geändert? 
mfg Lucky

von Uwe S. (de0508)


Lesenswert?

Hallo

der tiny13 hat kein

Input Capture Pin und auch kein OC1A !

also so einfach ist das leider nicht.

von Lucky (Gast)


Lesenswert?

aso, aber ei OC1A, kann ich denn den nicht nehmen? das es nicht leicht 
wierd habe ich leider auch schon gemerkt :( kennt ihr eine alternative 
für den attiny13 daten an den pc zu schiecken?

von Lucky (Gast)


Lesenswert?

sorry meinte OC0A

von Uwe S. (de0508)


Lesenswert?

nimm doch den attiny84, attiny2313, atmega48, -88, -168 oder -328.

die letzteren haben auch einen Hardware UART.

solong.

von Peter D. (peda)


Lesenswert?

Lucky schrieb:
> Ich bin ein anfänger in sachen coden.
> Ich versuche gerade den code auf den Attiny13 umzuschreiben, der erfolg
> hält sich aber in grenzen, bekomme fehler meldungen die ich nicht
> verstehe, es geht um DDRA und PORTA

Es beißt sich etwas, wenn man wenig Ahnung von C hat und dann gleich 
Beispiele auf den kleinst möglichen MC portieren will.
Versuch erstmal, das Beispiel auf dem genannten Typ laufen zu lassen 
oder wenigsten auf einem mit ICP.

Also immer einen Schritt nach dem anderen machen. Wenn man beide Beine 
gleichzeitig hebt, fällt man um.


Peter

von Uwe S. (de0508)


Angehängte Dateien:

Lesenswert?

Hallo,

erst mal danke an Peter für die kleine Lib !

Ich habe sie mir für den atMegax8 angepasst und konnte erfolgreich einen 
Datenstrom mit 57600 Baud 8,n,1 versenden.

Die angehängten Quellen habe einige Defines um die Sende- von der 
Empfangsroutine auch getrennt nutzen zu können.

Zu meiner Anwendung auf der Hardware Usart0 empfange ich einen 
Datenstrom, denn ich nach Datenanalyse umformatiert mit der Software 
Uart ausgebe.

Beide Libs könnte ihr in dem Anhang finden, viel Erfolg.

von Fred G. (sysrun)


Lesenswert?

Fred Granna schrieb:
> Code

Rudi schrieb:
> Wie ist bei dir eigentlich der Stand?

Tja, seit nem halben jahr läuft hier eine Bastellösung:

Atmel-Arduino mit einem externen UART (per i2c). Telegramme lesen und 
anmelden am System (registriert sich als Servicekey an der Heizung) 
laufen.

Will aber grad weg davon. Der Uart macht nur ärger.


Habe mir heute einen Atmel mit 4 Uarts besorgt und spiele grad mit 
deinem c-code rum. Leider ist dort nur der Empfangsteil drin und nicht 
der Sender. Stehe da grad komplett auf dem schlauch wie ich daten in den 
Bus pumpen soll...

von sn00py (Gast)


Lesenswert?

Hallo

ICh möchte das gerne auf einem ATTiny2313 zum laufen bringen

Nachdem ich nun alle TIMSK1 durch TIMSK ersetzt habe (und sonstige auch) 
lässt sich das teil nun kompilieren.

Habe uach die Ports umgelegt auf
#define  STXD    SBIT( PORTB, PB3 )  // = OC1A
#define  STXD_DDR  SBIT( DDRB,  PB3 )
#define  SRXD_PIN  SBIT( PIND,  PD6 )  // = ICP

Also sollte dann von OC1A und ICP wieder gleich sein.

Allerdings habe ich das problem, das er mir hängen bleibt
  TIMSK = 1<<ICIE1^1<<OCIE1A;    // enable tx and wait for start

zumindest blinkt mir meine LED nicht mehr, wenn ich diese Zeile im 
suart_init drinnen lasse, sobald ich die auskommentiere, dann blinkt 
meine led wieder ...

an was kann es noch liegen?

Hat wer einen code für den 2313?

von Niffko _. (niffko)


Lesenswert?

Könnte mir vorstellen, dass du hiermit:
1
 TIMSK = 1<<ICIE1^1<<OCIE1A;    // enable tx and wait for start
bereits getätigte Einstellungen im TIMSK-Register platt machst. Versuche 
es mal mit:
1
TIMSK |= 1<<ICIE1^1<<OCIE1A;
Die gleiche Problematik dann auch nachher beim Manipulieren des TIMSK in 
den ISR's!


//Niffko

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
Noch kein Account? Hier anmelden.