Forum: Mikrocontroller und Digitale Elektronik UART-Codeproblem in Assembler


von Echo (Gast)


Lesenswert?

Moin,

ich hab momentan ein Problem mit dem UART-Codeteil meines Projekts. Im 
großen und ganzen wird das ganze die Elektronik eines Spektrometers, 
liest also ne CCD-Zeile schnell aus, speichert die Daten im SRAM und 
sendet die Daten über UART an den PC. Das ganze Programm ansich läuft, 
allerdings schickt der µC die ins UDR0-Senderegister geladenen 
Datenblöcke nich raus. Momentan nutze ich einen Logic Analyser zum test 
der Software indem ich einfach Testpulse über nen separaten Port 
ausgeben lasse. Der LA sagt mir hierbei auch das die Sendeschleife läuft 
und sich wiederholt wie gewünscht. Allerdings kommen eben keine Daten 
raus über den UART Tx-Pin.

Der LA sagt das regelmäßig 3 Testpulse erzeugt werden (wie gewünscht 
werden 3 Datenblöcke ins UDR0-Register geladen: Daten, New Line und 
Carriage Return). Eine Variation der Baudrate von 9600 auf 28800 Baud 
brachte auch keine Änderung.

Wobei die gleiche hardware allerdings mit dem UART-Beispielcode aus der 
Artikelsammlung von µc.net funzt (natürlich abgewandelt auf den 
ATMega2560 und seine Register).

Hier mal das Codefragment, kann auch gerne den vollständigen Code 
reinstellen.

Quarzfrequenz is momentan 24MHz  (funzt wie gesagt mit dem 
UART-Codebeispiel ausm Artikelbereich)

;---------------------------------------------------------
;----------------------Daten senden-----------------------
;---------------------------------------------------------

; Baudrate einstellen

    ldi     temp, HIGH(UBRR_VAL)  ; Wert = 58dec, für 8MHz und 9600Baud
    sts     UBRR0H, temp
    ldi     temp, LOW(UBRR_VAL)
    sts     UBRR0L, temp

; Frame-Format: 8 Bit

    ldi     temp, (1<<UCSZ01)|(1<<UCSZ00)
    sts     UCSR0C, temp

    ldi     temp, (1<<TXEN0)
    sts      UCSR0B, temp                ; TX aktivieren


Speicherabbruch:        ; Speichern beendet, Speicherschleife fertsch 
durchlaufen

  .EQU Sendedurchlaeufe = 0x1068    ; wieder festlegung der Größe der 
Zählschleife fürs Senden, 0x1068 = 4200Dec

  LDI   ZH, High(Sendedurchlaeufe)  ; Z-Pointer als 16bit-Zähler für 
Sendeschleife
  LDI   ZL, Low(Sendedurchlaeufe)

  LDI   temp2, 0x00          ; dient als Vergleichszahl = 0 für 
BREQ-Sendeabbruch

Daten_laden:

  SBIW   ZH:ZL, 1          ; Subtrahiert 1 vom Z-Pointer
  CP     ZH, temp2          ; Vergleich Z-Pointer-Highbyte
  CPC   ZL, temp2          ; Vergleich Z-Pointer-Lowbyte
  BREQ   Sendeabbruch        ; springe zu Sendeabbruch wenn Schleife 
durchlaufen
  LD     temp, -X          ; lade obersten Datenblock ins Temp-register, 
dekrement dann X-Pointer
  rjmp   Senden            ; rjmp zu senden um dort den datenblock 
wegzusenden




Sendeabbruch:

  nop

  rjmp   Sendeabbruch        ; Programm fertsch, vllt noch n Taster dran 
damit er wieder zur Main springt um den
                    ; ganzen kram nochma durchläuft->tasterentprellung, 
muss aber nich da er
                    ; höchstwahrscheinlich schon ganz woanders im 
Programm is wenn der Taster wieder
                    ; zurückprellt und ihn dann der Tasterzustand 
nichmehr interessiert, noch gucken
                    ; wegen

Senden:



    mov     zeichen, temp        ; Unterprogramm aufrufen
    rcall   serout
    ldi     zeichen, 10          ; New_Line_ASCII-Befehl!
    rcall   serout
    ldi     zeichen, 13          ; Carriage Return, Zeichen an 
Zeilenanfang darstellen
    rcall   serout
    rcall   sync
    rjmp    Daten_laden

serout:

    LDS   temp,UCSR0A            ; Prüfen auf leeren Datensendepuffer
    SBRS   temp,UDRE0             ; Skip if bit in register set


    rjmp    serout



    sts     UDR0, zeichen

  LDI testpuls, 0x00
  OUT PORTC, testpuls
  LDI testpuls, 0xFF
  OUT PORTC, testpuls
  LDI testpuls, 0x00
  OUT PORTC, testpuls

    ret                                 ; zurück zum Hauptprogramm

                    ; kleine Pause zum Synchronisieren des Empfängers, 
falls zwischenzeitlich
                    ; das Kabel getrennt wurde

sync:

    ldi     warten1,0

sync_1:

    ldi     warten2,0

sync_loop:

    dec     warten2
    brne    sync_loop
    dec     warten1
    brne    sync_1
    ret

MfG Echo

von Daniel F. (df311)


Lesenswert?

Echo schrieb:
> Quarzfrequenz is momentan 24MHz
                            ^^^^^
[...]
1
>     ldi     temp, HIGH(UBRR_VAL)  ; Wert = 58dec, für 8MHz und 9600Baud
2
                                                        ^^^^

wäre es möglich, dass hier schon der hund begraben liegt?
24MHz und ein UBRR wert von 58 für 9600 kann eigentlich nicht stimmen - 
soweit ich mich erinnere, hatte ich neulich einen ubrr-wert von 63 für 
9,8304 MHz und 9600...

von Echo (Gast)


Lesenswert?

Hmm, eigentlich errechnet sich der UBBR-Val-Wert automatisch durch das 
Konstrukt:

.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)        ; clever runden
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))            ; Reale Baudrate
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)        ; Fehler in 
Promille

.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))             ; max. +/-10 
Promille Fehler
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit 
zu hoch!"
.endif

MfG Echo

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.