Serieller Datenempfang im Interrupt / "Bascom"

laplace

Mitglied
26. Nov. 2008
111
0
16
Kronach / Oberfranken
Sprachen
  1. BascomAVR
  2. Assembler
  3. Pascal
Guten Tag,

ich wollte mal mein 'Erstlingswerk' hier hereinstellen. Diese Routine soll mir zukünftig für Folgeprojekte zur Kommunikation mit dem PC dienen.

Die Routine übernimmt den Datenempfang über die serielle Schnittstelle im Interrupt.
  1. Die Strings vom PC müssen mit CR/LF ($13/$10) getrennt werden, wobei das LF optional ist
  2. Längenbeschränkung auf 20 Zeichen (durch Anpassung der Konstanten CBuffSize erweiterbar)
  3. im Demoprogramm wird der String per 'PRINT' einfach zurückgeschickt (wobei wieder ein CR/LF) automatisch durch 'PRINT' angehängt wird; hier könnte die Auswertung erfolgen
  4. Die Routine benutzt ihren eigenen Puffer RSBuffer(CBuffsize) bzw. RSBuffstring, von Bascom wird nichts zusätzlich eingerichtet
  5. Das 'RETURN' am Ende der Routine wird von Bascom mit 'reti' übersetzt (hab' ich mit einem Disassembler geprüft)


Code:
[FONT="Courier New"][SIZE="2"]'------------------------------------------------------------------------------
'name                     : ser4.bas
'copyright                : Laplace/Werner
'purpose                  : Testprogramm Serielles Interrupt- Handling
'micro                    : ATMega 8
'commercial addon needed  : nein
'------------------------------------------------------------------------------
' Kleine bis große Nickligkeit (hat mich Stunden gekostet):
' SBR  Reg,Bitmuster : Setze Bit in Register      : 0 <= Bitmuster <= 255
'                      führt OR Operation: Reg OR Bitmuster aus  !!
' SBRS Reg,Bitmuster : Springe, falls Bit gesetzt : 0 <= Bitmuster <= 7
'                      hier muss die Position des Bits angegeben werden !!
'------------------------------------------------------------------------------
$regfile    = "m8def.dat"
$crystal    = 16000000
$baud       = 38400             ' 9600, 19200 ansonsten '8N1'
$hwstack    = 40                ' im Moment nicht benötigt
$swstack    = 24                ' im Moment nicht benötigt
$framesize  = 24                ' im Moment nicht benötigt
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
On     URXC RS232Receive NoSave ' Keine automatische Register-Rettung
Enable URXC                     ' Interrupt (Byte über USART erhalten) enabled
Enable Interrupts               ' Interrupts global zulassen
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
Const CBuffsize        = 20          ' Maximale Anzahl-1 der Stringzeichen
Const SkipChar         = 10          ' LineFeed       (ignorieren)
Const Terminator       = 13          ' CarriageReturn (Stringende)
Const RS232DataPresent = &b10000000  ' Bit 7 (Maske für Registeroperationen)
Const RS232DataBranch  = 7           ' Bit 7 für Branch (SBRS/SBRC)
mReg  Alias R16
zReg  Alias R17
fReg  Alias R18
'z2reg Alias R18
'------------------------------------------------------------------------------
Dim RSBuffcount         As Byte
Dim RSBuffer(CBuffsize) As Byte   ' von 1..CBuffSize Zeichen
Dim RSBuffstring        As String * CBuffsize At RSBuffer Overlay
Dim FlagReg             As Byte   ' Speicher für 8 Flags
'******************************************************************************
'***************************** HAUPTPROGRAMM **********************************
'******************************************************************************
FlagReg     = 0               ' alle Flags zurücksetzen
RSBuffCount = 0               ' Zeichenzähler zurücksetzen
Do
$ASM
Mainwait0:                    ' Auf kompletten String von RS232 (vom PC) warten
 lds   fReg,{FlagReg}         ' dazu FlagReg auf Bit 7 prüfen
 SBRS  fReg,RS232DataBranch   ' Sprung, falls Bit 7 gesetzt ist
 rjmp  MainWait0              ' sonst weiter warten
$END ASM
 Print RSBuffString           ' STRING ZURÜCKSCHICKEN
$ASM
 lds   fReg,{FlagReg}         ' FlagReg Bit 7
 CBR   fReg,RS232DataPresent  ' (CBR: Clear Bit in Register)
 sts   {FlagReg},fReg         ' löschen
$END ASM
Loop
End
'******************************************************************************
'********************* RS232- Interrupthandler (Receiver) *********************
'******************************************************************************
RS232Receive:
$ASM
  push  mReg                  ' 1.Arbeitsregister retten
  IN    mReg,SREG             ' Statusregister einlesen
  push  mReg                  ' und sichern
  push  zReg                  ' 2.Arbeitsregister retten
  PUSH  fReg                  ' eigenes Flagregister retten
'..............................................................................
  IN    mReg,UDR              ' Zeichen von COM-Schnittstelle einlesen
  cpi   mReg,SkipChar         ' falls zu überlesen, dann fertig
  breq  RS232Receive4         ' -> Sprung zum Ende
  lds   fReg,{FlagReg}        ' Flagregister lesen (nach fReg)
  SBRC  fReg,RS232DataBranch  ' Sprung, falls das RS232Data Bit gelöscht
  RJMP  RS232Receive4         ' sonst beenden (gesendetes Byte geht verloren)
'------------------------------------------------------------------------------
  lds   zReg,{RSBuffCount}    ' Zeichenzähler aus RAM lesen (nach zReg)
  push  YL                    ' Y-Pointer auf den Datenpuffer setzen
  push  YH
'  ldi  YL,low(RSBuffer)      ' Tabellenoffset im Datensegment
'  ldi  YH,high(RSBuffer)     ' .. so will's der Assembler
  LOADADR RSBuffer(1),Y       ' .. so will's BASCOM
'  LOADADR RSBuffString,Y     ' .. oder auch so
  add   YL,zReg               ' Zeichenzähler um eins erhöhen
  brcc  RS232Receive0         ' und zum Y-Pointer addieren
  inc   YH
RS232Receive0:
  cpi   mReg,Terminator       ' (CR #13): Endekennzeichen
  brne  RS232Receive2
RS232Receive1:
  clr   mReg                  ' Zeichen = #13, dann #0 eintragen UND
  CLR   zReg                  ' Zeichenzähler ebenfalls auf #0
  SBR   fReg,RS232DataPresent ' Bit 7: Flag für Daten vollständig setzen
  sts   {FlagReg},fReg        '        im Flagregister setzen
  rjmp  RS232Receive3         '        MIT MASKE $80 !!!!
RS232Receive2:
  inc   zReg                  ' Anzahl gelesener Zeichen erhöhen
  cpi   zReg,CBuffsize        ' Puffer schon voll
  brsh  RS232Receive1         ' Sprung, falls ja (dann als #13 behandeln)
RS232Receive3:
  st    Y,mReg                ' Zeichen in Puffer eintragen
  sts   {RSBuffCount},zReg    ' Counter eintragen
  pop   YH
  pop   YL
'..............................................................................
RS232Receive4:                ' Lead-Out
  POP   fReg
  pop   zReg                  ' benutzte Register restaurieren
  pop   mReg                  ' sowiw flags wiederherstellen
  OUT   SREG,mReg
  pop   mReg
' RETI                        ' BASCOM ersetzt in diesem Fall, d.h. ISR-Routine
$END ASM                      ' die über ON 'Interrupt' 'Label' deklariert ist
RETURN                        ' dieses 'RETURN' durch 'RETI' (nicht RET)
[/SIZE][/FONT]

Geprüft hab' ich die Routine mit einem eigenen Programm und den aktuellen Einstellungen im Listing.
Ich komme auf eine Übertragungsrate von ca. 1350 Zeichen/Sekunde (hin und zurück) also ca. 2700 Zeichen/Sekunde in eine Richtung.


Schönen Tag noch
Werner :)
 
Hallo Werner,

danke für diesen beitrag. Ich glaube ich werde mir das bei meinem nächsten Projekt mal genauer ansehen und ausprobieren. Bin gespannt.

Kannst Du uns noch ein bissle darüber erzählen, was die Intension war das so zu lösen und nicht die Standardmechanismen von BASCOm zu nutzen.

Sicherlich bist Du mit dem Interrupt-Handling komplett abgekoppelt von irgendwelchen anderen Prozessen, dennoch würde mich der Hintergrund interessieren. Ist die Lösung aus einem konkreten Problem bei Dir entstanden?

Grüße,
Ma
 
Hallo Markus,

dieser Programmteil ist aus keinem konkreten Problem/Projekt entstanden;
ich hab' ja bei meiner 'Vorstellung' geschrieben, dass ich ein Assemblerfreak bin. Ich wollte mehrere Punkte prüfen/checken:

1.)Natürlich mit der Anwendung von Assembler auf dem AVR praktische Erfahrung sammeln
2.)Die Kombination BASCOM/Assembler prüfen. Das war ja ein Grund, mir BASCOM zuzulegen. Ich find' diese Einbindung von der BASCOM-Seite her phänomenal, zumal die Einschränkungen in der BASCOM-Hilfe (von BASCOM benutzte Register) beschrieben sind. Einfach an beliebiger Stelle im Code die $ASM/$END ASM Statements einfügen.
Ich wollte kein 'sehr' langes Programm (wie ich sie in der Regel auf dem PC schreibe) so programmieren; da würde mir die Struktur etwas fehlen. Eine gewisse Strukturierung kann ich allerdings durch meine 'Trennstrukturen' – siehe das Listing oben – schaffen. Das mach' ich auf dem PC genauso.
Aber für eine überschaubare Messwertaufgabe ist das fast ideal: Was erstmal zu schwierig (oder komplex) ist, in BASCOM schreiben und wenn's zeitkritisch wird in Assembler.
3.)Ich weiß jetzt, wie ich einen x-beliebigen Interrupt in BASCOM einbinden kann – sprich die Adresse der Interruptroutine von BASCOM aus in die Vektortabelle eintragen lassen kann und wie ich das handhaben muss. Hab' ich ja auch mit einem Disassembler geprüft. Als nächstes werd' ich wahrscheinlich demnächst einen CTC-Timer(1) Interrupt einbinden, für einen genauen Zeittakt.
4.)Falls ich nicht Assemblerbefehle übersehen habe, die noch ein wenig effizienter sind, ist diese Receiver-Routine diejenige mit der höchsten Performance, sowohl was die RAM- als auch die Flashbelegung betrifft. Das ist nun mal eine Eigenschaft von Assembler – mehr bzw. weniger oder schneller geht nicht. Ich könnte zwar noch ein paar Takte (Befehle) sparen, indem ich die ein oder andere Überprüfung streichen würde, das ginge allerdings auf Kosten der Sicherheit.
5.)In meinem DDS Projekt (wird wohl noch etwas dauern) war der Flashspeicher schon ziemlich voll – wenn's geht, würd' ich gerne noch etwas hinzufügen. Da hab' ich bisher die BASCOM-Interruptroutine drin. Vielleicht kann ich noch ein paar Byte dort herausholen.
6.)Ich hab' jetzt auch einen recht genauen Anhaltspunkt, welche Abtastraten ich auf einem AVR- gesteuerten Messwerterfassungssystem realisieren kann. Was hier m.E. limitierend ist, ist die Geschwindigkeit, mit der ich die Daten wegschaufeln kann, sonst bräuchte ich externes RAM mit der entsprechenden Ansteuerung; ich weiß, das ist genau genommen der umgekehrte Weg, aber als Anhaltspunkt reichte mir das. Wenn ich auf ASCII-Textkonversion verzichte komm' ich mit Sicherheit auf mindestens 1 KHz für einen Kanal.
7.)Und last, but not least: den Spassfaktor nicht vergessen :p


Schönen Tag noch
Werner


P.S. Wozu ich noch nicht gekommen bin: warum geht die Datenübertragung nicht bei einer noch höheren Baud-Rate? Dazu müsste ich die Taktzyklen ausrechnen bzw. mal bei meinem USB/seriell Wandler nachschauen. Ist ein Billigteil, das 'nur' USB 1.1 kompatibel ist. Wenn du da eine brauchbare Idee hast, kannst du ja mal Bescheid geben ;) .
 
Hi Werner,

2.)Die Kombination BASCOM/Assembler prüfen. Das war ja ein Grund, mir BASCOM zuzulegen. Ich find' diese Einbindung von der BASCOM-Seite her phänomenal, zumal die Einschränkungen in der BASCOM-Hilfe (von BASCOM benutzte Register) beschrieben sind. Einfach an beliebiger Stelle im Code die $ASM/$END ASM Statements einfügen.
das macht doch gleich Lust auf mehr ... ;) So in der Art hab ich das auch
empfunden. Bei der Einbindung von Assembler in C bekommt man das :bad:
und bei Bascom ist das sehr einfach und verständlich gelöst :D

Besten Dank für das Code-Beispiel. Dann hab ich was zum abkupfern für
eigene Basteleien. Man muß das Rad ja nicht dauernd neu erfinden ;)

3.)Ich weiß jetzt, wie ich einen x-beliebigen Interrupt in BASCOM einbinden kann – sprich die Adresse der Interruptroutine von BASCOM aus in die Vektortabelle eintragen lassen kann und wie ich das handhaben muss.
Ich brauch mal dringend Zeit fürs Basteln :bawling: Aber es geht ja langsam
vorwärts :) Demnächst werde ich wohl auch mal mit Bascom anfangen.
Aber erst mal nur mit der Demo-Version.

7.)Und last, but not least: den Spassfaktor nicht vergessen :p
Das ist das wichtigste :D :cool:

P.S. Wozu ich noch nicht gekommen bin: warum geht die Datenübertragung nicht bei einer noch höheren Baud-Rate? Dazu müsste ich die Taktzyklen ausrechnen bzw. mal bei meinem USB/seriell Wandler nachschauen. Ist ein Billigteil, das 'nur' USB 1.1 kompatibel ist. Wenn du da eine brauchbare Idee hast, kannst du ja mal Bescheid geben ;) .
Also bei mir hab ich auch schon 2MBit hinbekommen :eek:
Das geht aber wirklich nur mit nem RS232-US-Wandler. Ich hab da den von
Reichelt mit USB2.0 (6,95 glaub ich) genommen. Aber die von Pollin gehen
glaube ich auch. War bei mir kein Problem. Auch wenn man mit dem Timing
so um 0,5-2% neben der genauen Baudrate hängt. Und alles ohne Handshaking.

Gruß
Dino
 
Guten Tag,

hab' mich ja lange nicht gemeldet, hab' halt leider viel zu wenig Zeit.
Erst jetzt komm' ich dazu, wieder etwas weiter zu machen. Jetzt bin ich auf 2 Fragen gestossen, wobei mir die erste schon damals gekommen ist.

1.) Egal was ich programmiere, ich komme mit meinem Programm oben nicht über 38400 Baud hinaus. Das kann eigentlich gar nicht sein. Ich hab' da einiges rumprobiert, ob's eventuell an der Hardware liegt - kann ich aber ausschliessen
a.) ich hab auf PC Seite an meinen USB-seriell Wandler einen Nullmodemstecker angeschlossen, so dass ich vom PC-gesendete Daten sofort in den Empfänger zurück("gespiegelt") bekomme. Das ging bis 500kBaud.
b.) ich hab' auf dem Pollinboard die 4* 10uF Kondensatoren der Ladungspumpen des MAX232 gegen 1uF ausgetauscht: kein Effekt
c.) ich hab' den Mega8 aus dem Sockel raus und Pin2 und Pin3 des Sockels verbunden (TxD mit RxD), also eine Art Nullmodemstecker hinter dem MAX232 - konnte ich bis 100kBaud betreiben (der MAX ist bis ca. 120 kBaud spezifiziert).
d.) Ich habe die Bascom-Initialisierung des UART's durch eine eigene in Assembler ersetzt (Beschreibung der internen 3 Register und den UBRR-Wert über das Tool von Rowalt berecnet) => wieder nur bis 38,4 kBaud.

Jetzt hab' ich keinen Plan mehr, woran meine Fehlversuche liegen könnten - vielleicht weiß hier jemand weiter? Vielleicht liegt's an den (Con)Fuse-Bits (meine Quarzfrequenz ist 16MHz)??

2.) DA ich jetzt schon die Routine zum setzen der USART-Parameter habe, würde ich das gerne nutzen, um den USART (genauer nur die Baudrate) im laufenden Betrieb umzustellen. Aber auch das funktioniert nicht. Im Datenblatt steht da aber nichts vermerkt, dass das nicht gehen sollte (ich hab' übrigens nicht vergessen, die Schnittstellenparameter auf dem PC umzustellen :p ).


Vielen Dank schon mal
Werner
 
So, hab' immer noch keine Lösung, auch die folgenden Versuche sind fehlgeschlagen:

e.) den Mega8 gegen einen anderen ausgetauscht
f.) Quarz gesockelt und einen 4,096 MHz verwendet => geht nicht mehr bis 38,4 kBaud aber noch mit 9600 Baud
g.) Mega8 gegen einen Mega16 ausgetauscht: geht wie der Mega8, also mit 16 MHz bis 38,4 kBaud und bei 4,096 MHz nur bis 9600 Baud
h.) benutze mittlerweile nur noch das Demoprogramm aus dem Walter-Buch (0409.bas) - zeigt die gleichen Effekte => an meiner Software liegt das nicht
i.) Hab' gestern noch nachgelesen, welche Fusebiteinstellungen für welchen Quarz ich brauche und bemerkt, dass CKOpt0 nicht direkt was mit der Taktfrequenz zu tun hat. Habe es jetzt gesetzt (also mit "0" angegeben) => hatte auch kein Effekt.

Bin echt ratlos, woran das hängt :rolleyes: .

Ich hänge mal einen Screenshot der Fusebiteinstellungen (für den Mega16) an, vielleicht weiß hier noch jemand einen Rat.


Schönen Sonntag noch
Werner
 

Anhänge

  • Fuse.gif
    Fuse.gif
    41,7 KB · Aufrufe: 29
Hallo laplace,

du kannst einem ja schon richtig leid tun ...

Da du ja auch schon mit Assembler rumgetestet hast, schau dir mal meinen
Quelltext an. Da benutze ich zwar nen Mega168 aber der USART wird bis zum
Ende gequält und läuft auch mit zig kBaud ohne Probleme ...

Analyzer für I2C/TWI und 1-Wire/microLAN - Seite 3

Beitrag #22

Gruß
Dino
 
Hallo Werner,
ich habe mir jetzt nicht durchgelesen, was du alles probiert hast. Aber denkst du nicht, dass es einfach die Unverträglichkeit der Taktfrequenzen und der sich daraus ergebenden Abweichungen ist?
Hast du einen "Baudraten-Quarz" zur Verfügung, also einen mit einer Frequenz, die ein ganzzahliges Vielfaches von 9600 ist?
Besonders wo du schreibst, dass mit der Verbindung von Rx und Tx höhere raten möglich sind, scheint mir dies die logische Erklärung.

HBA
 
Hallo,

Aber denkst du nicht, dass es einfach die Unverträglichkeit der Taktfrequenzen und der sich daraus ergebenden Abweichungen ist?
Hast du einen "Baudraten-Quarz" zur Verfügung, also einen mit einer Frequenz, die ein ganzzahliges Vielfaches von 9600 ist?
Ich hab bei mir nen normales 20MHz Quarz dran und selbst bei knapp 1%
Abweichung bleibt alles fehlerfrei. Trotz vollem Stoff auf der Schnittstelle und
bis über 500kBit/s. Immer mit 8Bit, keine Parität und 1 Stopbit (8n1). Die
RS232 ist da doch erstaunlich gutmütig wenn die Taktfrequenz etwas außer
Plan ist.

Beim letzten Test waren bei mir UBBRH und UBBRL auf 0 und U2X auf 1. Also
schneller ging dann nicht mehr ;)

Da muß irgendetwas grundsätzliches falsch sein wo man sich nachher wohl
nur an die Stirn packt wenn man es endlich gefunden hat.

Das worum es hauptsächlich geht ist dieser Teil für den USART ...


CodeBox ASM

; ##################################################################
; ##################################################################
; #### USART-Subroutinen ###########################################
; ##################################################################
; ##################################################################

; ==================================================================
; ===== USART initialisieren (115k2 8n1) ===========================
; ==================================================================
usartinit: ; 115200, 230400, 460800 Baud
push r18 ; r16 auf Stack retten (fuer wiederherstellung)
;
; ===== BAUDRATE fuer USART =====
;
; U2X=0 Baud = fosc / 16(UBBR+1) , UBBR = ( fosc / 16Baud )-1
; U2X=1 Baud = fosc / 8(UBBR+1) , UBBR = ( fosc / 8Baud )-1
; Baud = bps , fosc = SystemClock , UBBR = UBBRH+UBBRL (0-4095)
;
; 9k6 Baud => bei U2X=1 UBBR=259,4 @20MHz
; 129,2
; 115k2 Baud => bei U2X=1 UBBR= 20,7 @20MHz
;
; Baud U2X=0 UBBRH UBBRL U2X=1 UBBRH UBBRL
; 1k2 1040,67 4 17 2082,33 8 34
; 2k4 519,83 2 8 1040,67 4 17
; 4k8 259,42 1 3 519,83 2 8
; 9k6 129,21 0 129 259,42 1 3
; 19k2 64,1 0 64 129,21 0 129
; 38k4 31,55 0 32 64,1 0 64
; 57k6 20,7 0 21 42,4 0 42
; 115k2 9,85 0 10 20,7 0 21
; 230k4 4,43 0 4 9,85 0 10 <=== geht beim PC NICHT!!! COM kann das nicht!
;
;
; UBRRL - USART Baud Rate Register Low Byte
; * Bit 0..7 : USART Baud Rate Register bit 0..7
;
; UBRRH - USART Baud Rate Register High Byte
; * Bit 0 : USART Baud Rate Register bit 8
; * Bit 1 : USART Baud Rate Register bit 9
; * Bit 2 : USART Baud Rate Register bit 10
; * Bit 3 : USART Baud Rate Register bit 11
; * Bit 4 : 0
; * Bit 5 : 0
; * Bit 6 : 0
; * Bit 7 : USRSEL (Register Select) 1=UCSRC 0=UBRRH
;
; ldi r18,0 ; Baudrate-Register HighByte 9600Baud
sts UBRR0H,r17 ; Highpart = 0
; sts UBRR0H,r18 ; Highpart = 0
; ldi r18,21 ; Baudrate-Register LowByte
sts UBRR0L,r16 ; Lowpart = 21
; sts UBRR0L,r18 ; Lowpart = 21
;
; UCSRA - USART Control and Status Register A
; * Bit 0 : MPCM Multi-processor Communication Mode
; * Bit 1 : U2X Double the USART transmission speed
; * Bit 2 : UPE Parity Error
; * Bit 2 : PE = UPE For compatibility
; * Bit 3 : DOR Data overRun
; * Bit 4 : FE Framing Error
; * Bit 5 : UDRE USART Data Register Empty
; * Bit 6 : TXC USART Transmitt Complete <===
; * Bit 7 : RXC USART Receive Complete <===
; 76543210
ldi r18,0b00000010 ; U2X=1
sts UCSR0A,r18 ;
;
; URSEL UMSEL UPM1 UPM0 USBS UCSZ1 UCSZ0 UCPOL
; 7 6 5 4 3 2 1 0 UCSRC
;
; UCSRC - USART Control and Status Register C
; * Bit 0 : UCPOL Clock Polarity
; * Bit 1 : UCSZ0 Character Size Bit 0
; * Bit 2 : UCSZ1 Character Size Bit 1
; * Bit 3 : USBS Stop Bit Select 0 = 1Stop-Bit , 1 = 2 Stop-Bits
; * Bit 4 : UPM0 Parity Mode Bit 0
; * Bit 5 : UPM1 Parity Mode Bit 1
; * Bit 6 : UMSEL USART Mode Select Async=0 Sync=1
; * Bit 7 : URSEL Register Select
;
; UPM 00 Disabled UCSZ 000 5-Bit , 100 Reserved
; 01 Reserved 001 6-Bit , 101 Reserved
; 10 Even Parity 010 7-Bit , 110 Reserved
; 11 Odd Parity 011 8-Bit , 111 9-Bit
;
; SyncMode TxD Changed RxD Sampled
; UCPOL 0 Rising XCK Edge Falling XCK Edge
; 1 Falling XCK Edge Rising XCK Edge
; 76543210
ldi r18,0b10000110 ; URSEL=1 (UCSRC) , USBS=0 UCSZ=3 => Frame-Format 8Bit/1Stop
sts UCSR0C,r18 ;
;
; UCSRB - USART Control and Status Register B
; * Bit 0 : TXB8 Transmit Data Bit 8
; * Bit 1 : RXB8 Receive Data Bit 8
; * Bit 2 : UCSZ2 Character Size Bit 2
; * Bit 2 : CHR9 = UCSZ2 For compatibility
; * Bit 3 : TXEN Transmitter Enable
; * Bit 4 : RXEN Receiver Enable
; * Bit 5 : UDRIE USART Data register Empty Interrupt Enable
; * Bit 6 : TXCIE TX Complete Interrupt Enable <===
; * Bit 7 : RXCIE RX Complete Interrupt Enable <===
; 76543210
ldi r18,0b00011000 ; UCSZ2=0 (8Bit) , TXEN + RXEN => Enable Receiver/Transmitter
sts UCSR0B,r18 ;

pop r18 ; r18 wiederherstellen
ret ; Subroutine Ende


; ==================================================================
; ===== USART - Daten senden =======================================
; ==================================================================
usartwr: ; Wait for empty transmit buffer (ca 1ms bei 9k6/8n1)
push r17 ; r17 auf Stack retten (fuer wiederherstellung)
usartwrloop:
lds r17,UCSR0A ; Skip if Bit 5 is Set : UDRE USART Data Register Empty
sbrs r17,5 ; Skip if Bit 5 is Set : UDRE USART Data Register Empty
rjmp usartwrloop ; Sende-Buffer noch nicht leer
sts UDR0,r16 ; Put data (r16) into buffer, sends the data

pop r17 ; r17 wiederherstellen
ret ; Subroutine Ende


; ==================================================================
; ===== USART - Daten empfangen ====================================
; ==================================================================
usartrd: ; Wait for data to be received (ca 1ms bei 9k6/8n1)
push r17 ; r17 auf Stack retten (fuer wiederherstellung)
usartrdloop:
lds r17,UCSR0A ; Skip if Bit 7 is Set : RXC USART Receive Complete
sbrs r17,7 ; Skip if Bit 7 is Set : RXC USART Receive Complete
rjmp usartrdloop ; Noch nichts empfangen
lds r16,UDR0 ; Get and return received data from buffer

pop r17 ; r17 wiederherstellen
ret ; Subroutine Ende


; ==================================================================
; ===== USART - Daten senden/empfangen (Echo) ======================
; ==================================================================
usartecho: ; Wait for data to be received (ca 1ms bei 9k6/8n1)
push r17 ; r17 auf Stack retten (fuer wiederherstellung)

ldi r16,0x00 ; 0x00 als Leermeldung laden (nix empfangen)
lds r17,UCSR0A ; Skip if Bit 7 is Set : RXC USART Receive Complete
sbrs r17,7 ; Skip if Bit 7 is Set : RXC USART Receive Complete
rjmp usartechoend ; Noch nichts empfangen
lds r16,UDR0 ; Get and return received data from buffer
usartechowr:
lds r17,UCSR0A ; Skip if Bit 5 is Set : UDRE USART Data Register Empty
sbrs r17,5 ; Skip if Bit 5 is Set : UDRE USART Data Register Empty
rjmp usartechowr ; Sende-Buffer noch nicht leer
sts UDR0,r16 ; Put data (r16) into buffer, sends the data
usartechoend:

pop r17 ; r17 wiederherstellen
ret ; Subroutine Ende


; ==================================================================
; ===== String aus Flash auf USART ausgeben ========================
; ==================================================================
usartprt: ; Gibt String auf LCD aus (0x00=Ende).
push r16 ; r16 auf Stack retten (fuer wiederherstellung)
push r17 ; r17 auf Stack retten (fuer wiederherstellung)

ldi r17,255 ; Ausgabezaehler loeschen
usartprtloop: ; Ausgabeschleife
lpm r16,Z+ ; Zeichen laden und danach Pointer um +1 weiter
cpi r16,0x00 ; Test auf String-Ende (=0x00)
breq usartprtend ; Ende des Textes
rcall usartwr
dec r17 ; Ausgabezaehler -1
brne usartprtloop ; weiter ausgeben

usartprtend:
pop r17 ; r17 wiederherstellen
pop r16 ; r16 wiederherstellen
ret ; zurueck

Das ist Zeile 2000-2183 im Quelltext Version12 der oben als Link ist.
Bei ner normalen COM ist dann wie üblich bei 115kBaud Ende aber nen
USB-Dongle kommt teilweise weit darüber bis in den MBit/s Bereich.

Gruß
Dino
 
... selbst bei knapp 1% Abweichung bleibt alles fehlerfrei. Trotz vollem Stoff auf der Schnittstelle und
bis über 500kBit/s. Immer mit 8Bit, keine Parität und 1 Stopbit (8n1). ...
Da muß irgendetwas grundsätzliches falsch sein wo man sich nachher wohl
nur an die Stirn packt wenn man es endlich gefunden hat.
Da bin ich mir nicht so sicher. Bei 16MHz und 115200 hast du halt mehrere Prozent Abweichung und da kommt es hauptsächlich darauf an, wie pingelig der Empfänger beim Einlesen ist. Bis 1% ist bei 38400 Schluss.
So wie er schreibt, ist alles ok, wenn er jeweils nur ein Gerät betreibt und beim anderen einfach kurzschliesst. Das ist für mich ein ziemlich deutliches Anzeichen.
Und die Geräte sind unterschiedlich. Ich betreibe bei 16MHz eine RS232 mit 115200 baud über ein Kabel von etwa 12m Länge. Überhaupt kein Problem. Asbach-uralter PC. Nehme ich den relativ neuen Laptop meines Sohnes sieht die Sache ganz anders aus. Nicht einmal 57600 bekomme ich hin.

HBA
 
Hi Dino,

erstmal herzlichen Danke für deinen Link - ich bin schon beim Stöbern. Den Fehler für die Baudraten-Umschaltung hab' ich vielleicht schon.

Langfristig werd' ich wohl in meine Projekte einen FTDI232- Chip einbauen, um mit dem AVR zu kommunizieren. Da ich eh einen potentialfreien Betrieb zur Elektronik möchte, werde ich TxD und RxD über Optokoppler ansteuern/entkoppeln.

Bei Reichelt gibt's schon 2 sehr schnelle (~50 Cent für den Einjfachhoppler, 1,50 für den doppelten - beide in DIP8) mit mehr als 10 Megabit, womit du die volle Bandbreite der FTDI's mit ca. 1MBit ausnutzen könntest. Bei 8N1 kämst du dann auf etwa/über 100 kByte pro Sekunde.
Wenn du magst, such' ich dir die Bezeichnungen raus.


Bis bald
Werner
 
Hi Werner,

erstmal herzlichen Danke für deinen Link - ich bin schon beim Stöbern. Den Fehler für die Baudraten-Umschaltung hab' ich vielleicht schon.
Das hört sich doch schon gut an. Ich hab den entscheidenenden Bereich
nochmal rausgezogen und in den Beitrag gepackt. Der gesamte Quelltext
ist doch ein wenig länger :rolleyes:

Bei Reichelt gibt's schon 2 sehr schnelle (~50 Cent für den Einjfachhoppler, 1,50 für den doppelten - beide in DIP8) mit mehr als 10 Megabit, womit du die volle Bandbreite der FTDI's mit ca. 1MBit ausnutzen könntest. Bei 8N1 kämst du dann auf etwa/über 100 kByte pro Sekunde.
Wenn du magst, such' ich dir die Bezeichnungen raus.
Ich hab früher mal nen 6N139 verwendet. Aber da gibts glaube ich schon
schnellere ;) Wär schon interessant welche du da verwendest ;)

Gruß
Dino
 
Hallo HinterBlauenAugen,

danke erstmal für den Hinweis.
Ich habe mir erst einmal Baudraten ausgesucht, die beim AVR kleine Fehler ergeben (76800 Baud). Damit probier' ich's aus.
Ansonsten benutze ich ja einen USB-seriell Wandler (den ich über den "Spiegelstecker TxD-RxD" ja PC-seitig schon getestet habe. Ich kann (und habe auch) Baudraten geprüft, die genau auf den AVR passen, z.B. genau 100kBaud mit dem 16 MHz Quarz.
Das ging PC-seitig, aber mit dem AVR war dar nix :( .


Ich glaube langsam auch an eine sehr-lange-Leitungs-Lösung mit viel :rolleyes: :rolleyes: :rolleyes: :rolleyes:


Nochmals danke
Werner

P.S. und Edit: mit "sehr-lange-Leitungs-Lösung" meine ich natürlich eine, auf der ich stehe. Die Hardware-Verkabelung ist etwa 1 Meter lang
 
Ich kann (und habe auch) Baudraten geprüft, die genau auf den AVR passen, z.B. genau 100kBaud mit dem 16 MHz Quarz.
Das ging PC-seitig, aber mit dem AVR war dar nix :( .

Ich glaube langsam auch an eine sehr-lange-Leitungs-Lösung mit viel :rolleyes: :rolleyes: :rolleyes: :rolleyes:
Ich benutze immer PuTTY als Terminal. Das läßt sich auf beliebige Baudraten
einstellen die auch total dazwischen liegen (200Baud , 125kBaud, ...) also die,
die eigentlich beim Hyperterminal oder anderen erst mal angemotzt werden.

Aber für solche HighSpeed-Sachen werde ich mir wohl nochmal ne mehrfache
High-Speed-Seriell-Karte mit PCI oder PCIe holen. Damit auch ohne Dongle
bis mehrere Megabit drin ist. Wobei ich grad sehe das die nur bis 921kBaud
gehen :( So ein Mist. Also weiter rumdonglen im USB2.0 :D

P.S. und Edit: mit "sehr-lange-Leitungs-Lösung" meine ich natürlich eine, auf der ich stehe. Die Hardware-Verkabelung ist etwa 1 Meter lang
Bei mir benutze ich ne alte Config-Strippe von nem Router. Da sind immer
so viele von da das man schon entsorgen muß (bei jedem neuen Router eine).
Also wird die mal kurz Cisco-Konform mit RJ45 gemacht damit sie auf der
Atmel-Platine nicht so viel Platz wie nen SubD9 braucht. Das sind dann mal
schnell so um die 1,5...3m 3poliges Rundkabel ohne Schirm. Ich hab auch
schonmal 57k6 über 20m 3adrigen Klingeldraht geschickt (Amiga-Zeiten).
Das läuft absolut problemlos :eek:

Gruß
Dino
 
Im Westen nichts neues :confused: .

Habe anstelle der Stromversorgung über den Brenner das Netzteil am Pollinboard angeschlossen => keine Änderung.

Habe auch die 3 Steuerregister des USART ausgelesen. Da gibt es einen kleinen Unterschied im UCSRA Register. Jungfräulich, also wenn der AVR noch nichts geschickt hat, steht da $20 (nur URDE gesetzt) drin. Wenn schon mal Schreibbetrieb war, ist auch das TXC-Bit gesetzt (UCSRA=$60). Ich kann aber beide Initialierungen probieren - ein Umschalten der Baudrate im Betrieb geht nicht.

Die PC-Terminalumschaltung der Baudrate klappt aber (@Dino: ich schreib' das selbst in Delphi). Hab's überprüft mit meinem TxD/RxD Stecker und die Zeiten für die Übertragung von 200 Strings gemessen (Windoofs-Puffergröße:10kB):

BAUDRate(Zeit für Schreiben in ms)
4800(4087)
9600(2059)
19200(1014)
38400(515)
76800(343)
500000(187) - Teit etwa auch bei 100 kBaud

Die Zeiten passen also in etwa.

Sobald ich den AVR anschließe, ist aber wieder bei 38,4 kBaud Ende Gelände :stupido3: .


Schönen Tag noch
Werner

@Dino:
a.) genau den Optokoppler (6N...) hatte ich gemeint. Hat eine Übertragungsrate von 15 MBit/s - das ist schon heftig ;)
b.) Nachdem ich in deiner USART Routine gestöbert hatte, dachte ich, ich hätte den Fehler entdeckt: du beschreibst die USART-Register über die RAM-Adressen (z.B. mit STS xxx,REG17) während ich die I/O-Adresen nehme (also OUT xxx,REG17). Stimmt aber trotzdem, da BASCOM die entsprechenden Register als Konstanten vordefiniert hat und entsprechend die I/O Adressen gemeint sind.
 
Hi Werner,

Sobald ich den AVR anschließe, ist aber wieder bei 38,4 kBaud Ende Gelände :stupido3: .
:confused: komische Sache ...

@Dino:
a.) genau den Optokoppler (6N...) hatte ich gemeint. Hat eine Übertragungsrate von 15 MBit/s - das ist schon heftig ;)
Der hat ne interne digitale Empfangsstufe ;) Den hab ich mal vor Uhrzeiten
irgendwo ausgelötet und mich dann beim Datenblatt stöbern über das Ding
gefreut :D

b.) Nachdem ich in deiner USART Routine gestöbert hatte, dachte ich, ich hätte den Fehler entdeckt: du beschreibst die USART-Register über die RAM-Adressen (z.B. mit STS xxx,REG17) während ich die I/O-Adresen nehme (also OUT xxx,REG17). Stimmt aber trotzdem, da BASCOM die entsprechenden Register als Konstanten vordefiniert hat und entsprechend die I/O Adressen gemeint sind.
Manche Megas haben so viele Register das einige in den Memory-Bereich
ausgelagert sind. Dann muß man sie statt mit OUT mit dem STS ansprechen.
Der Befehl kostet aber leider zusätzliche Taktzyklen :( Beim Mega8 ist noch
alles IO-Mapped. Beim Mega168 sind die USART-Register Memory-Mapped.

Stell doch nochmal den Quellcode von deinem letzten Versuch hier rein.
Eventuell fällt ja irgendwas dabei auf wo der Bock begraben sein könnte ...

Gruß
Dino
 
Hi Dino ;),

leider ist das WE schon wieder vorbei :(.
Ich werd' versuchen, morgen oder übermorgen, den Code 'reinzustellen.
Ich hab' aber noch eine Idee, woran's liegen könnte :stupido3: .


Schönen Abend noch
Werner
 
Sodele,

ich hab' mal sämtliche Erweiterungen aus dem Programm entfernt, mit BASCOM compiliert und das Binärfile mit ReAVR reassembliert. Das Ergebnis hab' ich als Datei angehängt (der Basic Code am Anfang, das Assemblerfile am Ende) aber bin noch nicht zum Testen gekommen, werd' ich morgen machen.
Es dürfte nicht über 38,4 kBaud kommen.

Im Reassemblat (hab' ich soweit dokumentiert) kann ich absolut nichts ungewöhnliches finden :stupido3: .


Schönen Abend noch
Werner

EDIT: den Print-Befehl von BASCOM hab' ich erst später noch hinzugefügt. Der macht aber absolut das, was er soll und sonst nichts
 

Anhänge

  • ser4a.bas
    11,9 KB · Aufrufe: 16
Morgen noch dann hab ich ein wenig Luft um mal ein wenig zu proggen und
zu testen ;) und auch andere Pflichtaufgaben in Angriff zu nehmen :eek:

Gruß
Dino
 
Guten Tag,

ich bin immer noch am "Ball" :confused:.
Habe jetzt ein zweites Board probiert (easyavr5A von mikroe), das über einen 8MHz Quarzoszillator verfügt. Auch dort bleiben BEIDE Probleme.

zu fehlenden Umschaltung der Baudraten:
Ich habe alle "Automatismen" von Bascom entfernt und eine eigene Initialisierung geschrieben, die ich aus dem Bascom Reassemblat letztlich übernommen habe. Da brauche ich bei 8N1 nur noch UCSRB zu setzen - die Reihenfolge des Setzens des UBRR-Wertes (zuerst high, dann low) steht so im Datenblatt.

Die eigene Initialisierung sieht so aus:
Const QuarzFrequenz = 8000000
Const BaudRate = 4800
Const MinUBRR = (QuarzFrequenz\16\Baudrate)-1 ' UBRR-Wert
....
'..............................................................................
$ASM
_INIT_USART:
LDI zReg,MinUBRR\255 ' lädt das Highbyte
LDI mReg,MinUBRR ' lädt daS Lowbyte der Baudrate
'..............................................................................
_SET_Baudrate:
OUT UBRRH,zReg
OUT UBRRL,mReg
'..............................................................................
LDI mReg,&B00011000 ' Setzen von RXEN,TXEN =1 & UCSZ2=0
OUT UCSRB,mReg
SBI UCSRB,RXCIE ' Setzen von RXCIE,
RET
$END ASM

Bei der Initialisierung wird die berechnete MinUBRR-Konstante in low/high zerlegt (high=0) und im Registerpaar R16/R17 übergeben (= Aufruf von _INIT_USART). Das funktioniert auch beim jungfräulichen AVR (nach flashen und/oder RESET).

Wenn ich aber einen eigenen UBRR-Wert vom PC sende (habe überprüft, dass das auch stimmt), springe ich nur 2 Stellen tiefer ein (=_SET_Baudrate), mit den Werten in R16/R17. Es wird aber nicht umgeschaltet!!! Ich erhalte beim Senden nur ab und zu Zeichensalat vom AVR zurück.
Hat eigentlich schon jemand anders eine Umschaltung der Baudrate versucht ??

zur Baudratenlimitierung (38,4 kBaud):

Sobald ich mehr als 38,4 kBaud setzen will (z.B. 50000) geht nichts mehr. Unten stehen ein paar berechnete UBRR-Werte.

8MHz bei 4800 Baud = 103 UBRR
8MHz bei 9600 Baud = 51 UBRR
8MHz bei 38400 Baud = 12 UBRR
8MHz bei 50000 Baud = 9 UBRR

Die PC-Umschaltung in Delphi sieht so aus, mit Value als dem Wert der neuen BAUDRate. Zuvor wird jedoch dem AVR der neue UBRR-Wert geschickt (hab' ich wie gesagt geprüft).

{------------------------------------------------------------------------}
Procedure TRS232.ClearBuffer;
Const CAll = PURGE_RXABORT or PURGE_RXCLEAR or PURGE_TXABORT or PURGE_TXCLEAR;
BEGIN
PurgeComm(Handle,CAll);
SetCommMask(Handle,0);
END;
{-----------------------------------------------------------------------}
Procedure TRS232.SetBaudRate(Value:Integer);
var DCB : TDCB;
BEGIN
if Enabled then begin
ClearBuffer; //
GetCommState(Handle,DCB); // COMState Variable einlesen
DCB.BaudRate := Value;
if SetCommState(Handle,DCB) then begin
ClearBuffer;
end;
end;
END;

Auch das funktioniert nicht.
Jetzt gehen mir langsam die Ansatzpunkte aus.


Etwas Ratlos
Werner :stupido3:
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)