Serielle Datenübertragung

Themabewertung:
  • 0 Bewertung(en) - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
Unilein
Fachgebiet Rauchentwicklung
*******

Beiträge: 735
Registriert seit: Apr 2014
Bewertung: 5
#1
15.12.2016, 16:03

Hallo zusammen,

heute mal ein Beispiel für serielle Datenübertragung. In diesem Fall die Ausgabe von Zeichen über die Atmega-eigene Schnittstelle. Das Programm ist für den Atmega8 geschrieben. Prinzipiell sollte es jedoch auch mit einem Atmega168 oder einem Atmega328 funktionieren. Es muss allerdings die passende Definitionsdatei inkludiert werden.

 
.include "m8def.inc"
 
.def temp    = r16                              ; Register für kleinere Arbeiten
.def zeichen = r17                              ; in diesem Register wird das Zeichen an die
                                               ; Ausgabefunktion übergeben
 
.equ F_CPU = 4000000                            ; Systemtakt in Hz
.equ BAUD  = 9600                               ; Baudrate
 
; Berechnungen
.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
 
   ; Stackpointer initialisieren
 
   ldi     temp, HIGH(RAMEND)
   out     SPH, temp
   ldi     temp, LOW(RAMEND)
   out     SPL, temp
 
   ; Baudrate einstellen
 
   ldi     temp, HIGH(UBRR_VAL)
   out     UBRRH, temp
   ldi     temp, LOW(UBRR_VAL)
   out     UBRRL, temp
 
   ; Frame-Format: 8 Bit
 
   ldi     temp, (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0)
   out     UCSRC, temp
 
   sbi     UCSRB,TXEN                  ; TX aktivieren
 
loop:
   ldi     zeichen, 'T'
   rcall   serout                      ; Unterprogramm aufrufen
   ldi     zeichen, 'e'
   rcall   serout                      ; Unterprogramm aufrufen
   ldi     zeichen, 's'
   rcall   serout                      ; ...
   ldi     zeichen, 't'
   rcall   serout
   ldi     zeichen, '!'
   rcall   serout
   ldi     zeichen, 10
   rcall   serout
   ldi     zeichen, 13
   rcall   serout
   rcall   sync                        
   rjmp    loop
 
serout:
   sbis    UCSRA,UDRE                  ; Warten bis UDR für das nächste
                                       ; Byte bereit ist
   rjmp    serout
   out     UDR, zeichen
   ret                                 ; zurück zum Hauptprogramm
 
; kleine Pause zum Synchronisieren des Empfängers, falls zwischenzeitlich
; das Kabel getrennt wurde
                                   
sync:
   ldi     r16,0
sync_1:
   ldi     r17,0
sync_loop:
   dec     r17
   brne    sync_loop
   dec     r16
   brne    sync_1  
   ret
 
 

Bitte beachtet, dass der Atmega kein RS232-Signal ausgibt. Also keinem echten Standard entspricht. Mit einem MAX232 kann aber leicht aus dem Signal ein RS232-kompatibeles Signal erzeugt werden.

Übrigens: Mit der Ausgabe über die serielle Schnittstelle des Atmega könnte man einen ESP8266 (serieller WiFi-Adapter) steuern und so Datgen senden.


Aber was bringt es, wenn man über die serielle Schnittstelle nur Daten ausgeben kann? Ok, für die Ausgabe auf einem Terminal reicht das. Was aber, wenn man auch Daten empfangen will? Dann braucht man eine Routine, die Daten über die Schnittstelle empfangen kann.

Das folgende Beispiel ist wieder für einen AtMega8 gedacht, sollte aber auch mit AtMega168 und AtMege328 funktionieren.

Die Besonderheit hier: Das Programm empfängt Daten per Interrupt. Man kann also gleichzeitig andere Dinge auf dem Chip erledigen. Der Interrupt wartet auf Daten. Nur, wenn Daten da sind, werden diese verarbeitet.

 
.include "m8def.inc"
 
.def temp = R16
 
.equ F_CPU = 4000000                            ; Systemtakt in Hz
.equ BAUD  = 9600                               ; Baudrate
 
; Berechnungen
.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
 
.org 0x00
       rjmp main
 
.org URXCaddr                                   ; Interruptvektor für UART-Empfang
       rjmp int_rxc
 
; Hauptprogramm
 
main:
 
   ; Stackpointer initialisieren
 
   ldi     temp, HIGH(RAMEND)
   out     SPH, temp
   ldi     temp, LOW(RAMEND)
   out     SPL, temp
 
   ; Port D = Ausgang
 
   ldi     temp, 0xFF
   out     DDRD, temp
 
   ; Baudrate einstellen
 
   ldi     temp, HIGH(UBRR_VAL)
   out     UBRRH, temp
   ldi     temp, LOW(UBRR_VAL)
   out     UBRRL, temp
 
   ; Frame-Format: 8 Bit
 
   ldi     temp, (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0)
   out     UCSRC, temp
 
   sbi     UCSRB, RXCIE                    ; Interrupt bei Empfang
   sbi     UCSRB, RXEN                     ; RX (Empfang) aktivieren
   
   sei                                     ; Interrupts global aktivieren
   
loop:
   rjmp loop                               ; Endlosschleife
 
; Interruptroutine: wird ausgeführt sobald ein Byte über das UART empfangen wurde
 
int_rxc:
   push    temp                            ; temp auf dem Stack sichern
   in      temp, UDR                       ; empfangenes Byte lesen,
                                           ; dadurch wird auch der Interrupt gelöscht
   out     PORTD, temp                     ; Daten ausgeben
   pop     temp                            ; temp wiederherstellen
   reti                                    ; Interrupt beenden
 

Auch hier sei noch einmal angemerkt, dass der AtMega kein RS232-Signal verträgt.

Gruß
Uni
-----

Klopapier beidseitig verwenden und der Erfolg liegt auf der Hand!
(Dieser Beitrag wurde zuletzt bearbeitet: 07.09.2017, 17:43 von Unilein.)
Zitieren
mc-gl
Junior Member
**

Beiträge: 16
Registriert seit: Dec 2016
Bewertung: 0
#2
16.12.2016, 19:19

Hi Uni

Könnte es sein, dass ich dich da zu etwas inspiriert habe? Aber kool dass du solche Problemlösungen teilst, werde das sicher auch mal noch brauchen können Smile

Gruss GL

Gesendet von meinem SM-G935F mit Tapatalk
Zitieren
Unilein
Fachgebiet Rauchentwicklung
*******

Beiträge: 735
Registriert seit: Apr 2014
Bewertung: 5
#3
16.12.2016, 19:30

Zitat:Könnte es sein, dass ich dich da zu etwas inspiriert habe?

durchaus! Big Grin
Ich hatte mal vorgehabt, regelmäßig Codeschnipsel zu posten. Das war ein wenig in Vergessenheit geraten bzw. ich hatte auch nur wenig Zeit.

Die aktuelle Schnittstellendiskussion hat mich tatsächlich dazu verleitet, mal wieder etwas mit Assembler zu machen und hier zu posten.

Gruß
Uni
-----

Klopapier beidseitig verwenden und der Erfolg liegt auf der Hand!
Zitieren


Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste