Forum: Mikrocontroller und Digitale Elektronik UART -> PC


von binomie (Gast)


Lesenswert?

Hi
Kann mir irgendjemand für eine AVR-PC-Verbindung die Sourcecodes für AVR 
und PC schicken oder einen Link angeben. Am besten wäre es für Delphi, 
alles andere geht aber auch.
Ich versuche gerade die Verbindung hintukriegen und schicke alle Zahlen 
von 0-255 im Sekundentakt zum PC bekomme aber nur komische Zeichen, die 
nicht dem geschickten Entsprechen.

Schonmal vielen Dank
Binomie

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Hallo,

> Ich versuche gerade die Verbindung hintukriegen und schicke
> alle Zahlen von 0-255 im Sekundentakt zum PC bekomme aber nur
> komische Zeichen, die nicht dem geschickten Entsprechen.

kannst du mal das Programm posten? Ich kann mir vorstellen woran's 
liegen könnte...

MfG
Andreas

von binomie (Gast)


Lesenswert?

Hi,
Das ganze läuft auf einem AT90s2333 und die Datenübertragung läuft noch 
über Optokoppler. Den Code zum Übertragen hab ich von jemand anderen, 
bin nicht sicher ob der so richtig ist. Beim durchlesen ist mir gerade 
aufgefallen, dass das Ändern der Funktion des Txd-Pins stören könnte, 
hab ich noch nicht gecheckt.
Binomie

.org 0000

rjmp  main_prog    ; RESET   =$001    ;Reset
RETI    ; INT0addr=$001    ;External Interrupt0 Vector Address
RETI    ; INT1addr=$002    ;External Interrupt1 Vector Address
RETI    ; ICP1addr=$003    ;Input Capture1 Interrupt Vector Address
RETI    ; OC1Aaddr=$004    ;Output Compare1A Interrupt Vector Address
rjmp  check    ; OVF1addr=$005    ;Overflow1 Interrupt Vector Address
RETI    ; OVF0addr=$006    ;Overflow0 Interrupt Vector Address
RETI    ; SPIaddr =$007    ;SPI Interrupt Vector Address
RETI    ; URXCaddr=$008    ;UART Receive Complete Interrupt Vector 
Address
RETI    ; UDREaddr=$009    ;UART Data Register Empty Interrupt Vector 
Address
RETI    ; UTXCaddr=$00a    ;UART Transmit Complete Interrupt Vector 
Address
RETI    ; ADCCaddr =$00b  ;ADC Interrupt Vector Address
RETI    ; ERDYaddr =$00c  ;EEPROM Interrupt Vector Address
RETI    ; ACIaddr  =$00d  ;Analog Comparator Interrupt Vector Address

reset:


main_prog:
         ldi r17,25  ; 9600 baud bei 4.000.000 Hz
         out ubrr,r17
         ldi r17,0xFF  ; hab da noch nen paar LEDs hängen
         out ddrb,r17
         out portb,r17

; Timer initialisieren

  ldi r18,0x00    ; kein pwm und kein output-pin
  out tccr1a,r18
  ldi r18,0b00000101   ; /1024
  out tccr1b,r18
  ldi r18,240    ; Werte für 1 Sekunde verzögerung
  out tcnt1h,r18
  ldi r18,190
  out tcnt1l,r18
  ldi r18,0b10000000  ; Interrupt freigeben
  out timsk,r18
  sei      ; Allgemeine Interruptfreigabe
  rjmp loop

check:
        in r25,sreg  ; Status-Reg sichern

  ldi r18,0x00  ; kann grad nicht auswendig sagen, was das soll
  out tifr,r18

  ldi r18,240  ; Timer wieder updaten
  out tcnt1h,r18
  ldi r18,190
  out tcnt1l,r18

  out portb,r17  ; Zählerstand auf den Port geben
  inc r17    ; selbsterklärend

rs_send:
  ;Hab ich aus nem anderen UART-Projekt rausgenommen

         sbi ucr,txen         ;set sender bit
         sbis usr,udre        ;wait till register is cleared
         rjmp rs_send
         out udr,r17          ;send the variable
         cbi ucr,txen         ;clear sender bit

  out sreg,r25  ;Status-Reg wiederherstellen
  sei

loop:  nop
        rjmp loop

von Oliver Hanka (Gast)


Lesenswert?

Moin...

Mit dem uC Programm kann dir sicherlich der Andreas besser helfen als 
ich (siehe posting weiter unten). Unter Delphi habe ich die 
ComPort-Komponente benutzt. (weiß jetzt nicht genau wie sie heißt)

Wenn du möchtest kann ich sie dir zumailen. (ist kostenlos)

Du benötigst dann zum senden nur noch einen Befehl wie:

comport1.write(buffer,1);

(buffer : integer oder char)

mit comport1.writestr(text,1);

kannst du sogar ganze Strings versenden. Das ganze gilt natürlich auch 
zum empfangen.

Gruß Oliver

von binomie (Gast)


Lesenswert?

wäre sehr nett, wenn du mir die Komponente schicken könntest.

Ich hab jetzt auch mal den Code vom Tutorial ausprobiert, er funktioiert 
bei mir aber erst teilweise, das erste bit fehlt noch und man muss alle 
bits invertieren. das erste bit verschläft der pc wahrscheinlich, aber 
das liegt sicher an meiner Verdrahtung.

Deshalb kauf ich mir die Woche endlich mal einen max232 und dann läuft 
die sache sicher besser, bis jetzt noch alles mit optokopplern, bzw. 
direkt an den PC.

Vielen Dank
Binomie

von Oliver Hanka (Gast)


Lesenswert?

binomie schrieb:
>
> wäre sehr nett, wenn du mir die Komponente schicken
> könntest.

Ich hab es hochgeladen:

www.superchecker.net/projekt/comport.zip  (159k)

> Ich hab jetzt auch mal den Code vom Tutorial ausprobiert, er
> funktioiert bei mir aber erst teilweise, das erste bit fehlt
> noch und man muss alle bits invertieren. das erste bit
> verschläft der pc wahrscheinlich, aber das liegt sicher an
> meiner Verdrahtung.
>
> Deshalb kauf ich mir die Woche endlich mal einen max232 und
> dann läuft die sache sicher besser, bis jetzt noch alles mit
> optokopplern, bzw. direkt an den PC.

Ähm.... und da liegt das Problem würd ich sagen. Der Mikrocontroller 
gibt an seinen Pins (RXD/TXD) Pegel zwischen 0 und 5 Volt aus. (0V = low 
; 5V = high)

Die serielle Schnittstelle des Computer (RS232) erwartet aber gemäß 
Standart einen Pegel zwischen 3 und -12 V (3V = low ; -12 = high)

Das dein PC überhaupt etwas empfängt liegt nur daran, dass die 
"Empfangsbausteine" im PC eine extrem gute Fehlerkorrektur haben. 
Allerdings hast du ja selbst gesagt, dass du alle Bits invertieren mußt. 
Das kommt daher, dass der Empfangsbaustein vom PC den 0V Lowpegel des 
Mikrocontrollers als "sehr" geschädigten -12V High Pegel erkennt.

Das das erste Bit Fehlt liegt daran, dass das RS232 Protokoll einen 
Highpegel als Startbit erwartet. Da du deine Bits aber "falsch" sendest 
und der PC diese nur invertiert empfangen kann, erkennt er den ersten 
Highpegel nicht, und interpretiert das erste Lowsignal (vom 
Mikrocontroller aus gesehen) als Startbit.

Also, erst nach der Schaltung im Tutorial den MAX232 einbauen.

Dann sollte es wesentlich besser gehen.... :-)


Gruß Oliver

von binomie (Gast)


Lesenswert?

Danke für die Komponente!

Den Max werd ich bald verbauen, war bisher erst mal die Billiglösung zum 
rumspielen.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Hallo,

die Binärwerte von 0 bis 255, die du mit dem Programm an deinen PC 
sendest, werden im Terminal nicht als Zahlen, sondern als <font 
color="green">ASCII-Zeichen</font> dargestellt (eine Übersicht gibt's 
hier). Wenn du also z.B. die Zahl 82 sendest, stellt dies das Terminal 
als ein "R" dar (probiers mal aus!).
Um eine Zahl von 0 bis 9 anzuzeigen, musst du 48 dazu addieren: 0+48 
wird im Terminal als eine "0" dargestellt, 9+48 als eine "9" (siehe 
Tabelle). Bei mehrstelligen Zahlen wird die Sache schon komplizierter: 
dann musst du die Zahlen in das BCD-Format umrechnen. BCD ist die 
Abkürzung für "Binary Coded Decimal". In diesem Format werden 4 Bits für 
jede Dezimalziffer benutzt. Normalerweise werden 2 Ziffern in ein Byte = 
8 Bits "gepackt", in diesem Programm aber werden von jedem der beiden 
BCD-Register nur 4 Bits verwendet.
In einer gepackten BCD-Zahl wird die Zahl 25 z.B. so dargestellt:

<pre>
1 Byte   0 0 1 0 0 1 0 1
         |_____| |_____|
            2       5     =25
</pre>
<br>

Wenn man die beiden Ziffern in getrennten Bytes abspeichert, sieht es so 
aus:

<pre>
2 Bytes  0 0 0 0 0 0 1 0   0 0 0 0 0 1 0 1
                 |_____|           |_____|
                    2                 5      = 25
</pre>
<br>

Das hat den Vorteil, dass man zu jedem der Register einfach 48
addieren muss, und schon hat man die ASCII-Werte der beiden
Ziffern, die man direkt ans Terminal-Programm senden kann.

Ich habe dein Programm mal ein bisschen modifiziert ;-)
Schreib einfach nochmal wenn du noch irgendwelche Fragen hast!

MfG
Andreas
<hr>
<pre>
.include "tutorial/uart/2313def.inc" ;Pfad zur Include-Datei ggf. 
anpassen

.def temp = r18
.def counter = r17

.def fbin = r19        ;Ausgangswert
.def tBCDL = r19       ;Obere Dezimalstelle
.def tBCDH = r20       ;Untere Dezimalstelle

.org 0000

rjmp reset ; RESET =$001 ;Reset
RETI ; INT0addr=$001 ;External Interrupt0 Vector Address
RETI ; INT1addr=$002 ;External Interrupt1 Vector Address
RETI ; ICP1addr=$003 ;Input Capture1 Interrupt Vector Address
RETI ; OC1Aaddr=$004 ;Output Compare1A Interrupt Vector Address
rjmp check ; OVF1addr=$005 ;Overflow1 Interrupt Vector Address
RETI ; OVF0addr=$006 ;Overflow0 Interrupt Vector Address
RETI ; SPIaddr =$007 ;SPI Interrupt Vector Address
RETI ; URXCaddr=$008 ;UART Receive Complete Interrupt Vector Address
RETI ; UDREaddr=$009 ;UART Data Register Empty Interrupt Vector Address
RETI ; UTXCaddr=$00a ;UART Transmit Complete Interrupt Vector Address
RETI ; ADCCaddr =$00b ;ADC Interrupt Vector Address
RETI ; ERDYaddr =$00c ;EEPROM Interrupt Vector Address
RETI ; ACIaddr =$00d ;Analog Comparator Interrupt Vector Address

reset:

;Stackpointer initialisieren
ldi temp, RAMEND
out SPL, temp

ldi temp, 25     ;9600 baud bei 4.000.000 Hz
out UBRR, temp
ldi temp, 0xFF   ;hab da noch nen paar LEDs hängen
out DDRB, temp
out PORTB, temp
ldi counter, 0   ;Counter auf 0 setzen

; Timer initialisieren

ldi temp, 0x00         ;kein pwm und kein output-pin
out tccr1a, temp
ldi temp, 0b00000101   ;/1024
out tccr1b, temp
ldi temp, 240          ;Werte für 1 Sekunde verzögerung
out tcnt1h, temp
ldi temp, 190
out tcnt1l, temp
ldi temp, 0b10000000   ;Interrupt freigeben
out timsk, temp
sei                    ;Allgemeine Interruptfreigabe

loop:
rjmp loop

check:
  in r25,sreg          ;Status-Reg sichern

  ldi temp, 240        ;Timer wieder updaten
  out TCNT1H, temp
  ldi temp, 190
  out tcnt1l, temp

  mov fbin, counter    ;counter nach fbin kopieren

  rcall bin2bcd8       ;fbin in tBCDL und tBCDH aufteilen

  mov temp, tBCDH      ;obere Dezimalstelle
  subi temp, -48       ;48 addieren um in ASCII umzuwandeln
                       ;die AVRs haben keinen Befehl zum Addieren von
                       ;Konstanten, deshalb -48 abziehe.
  rcall serout         ;Byte senden

  mov temp, tBCDL      ;untere Dezimalstelle
  subi temp, -48       ;48 addieren um in ASCII umzuwandeln
  rcall serout         ;Byte senden

  ldi temp, 10         ;ASCII-Wert für "Neue Zeile"
  rcall serout         ;Byte senden

  ldi temp, 13         ;ASCII-Wert für "Cursor zurück"
  rcall serout         ;Byte senden

  out PORTB, counter   ;Zählerstand auf den Port geben
  inc counter          ;counter += 1

  cpi counter, 100     ;Zähler bei 100?
  brne weiter          ;wenn nicht, dann zu "weiter" springen
  ldi counter, 0       ;andernfalls counter zurück auf 0 setzen
  weiter:
  out sreg,r25         ;Status-Reg wiederherstellen
reti

bin2bcd8:
  clr  tBCDH    ;clear result MSD
bBCD8_1:subi  fbin,10    ;input = input - 10
  brcs  bBCD8_2    ;abort if carry set
  inc  tBCDH    ;inc MSD
  rjmp  bBCD8_1    ;loop again
bBCD8_2:subi  fbin,-10  ;compensate extra subtraction
  ret

serout:
  sbi ucr,txen ;set sender bit
  sbis usr,udre ;wait till register is cleared
  rjmp serout
  out udr,temp ;send the variable
  cbi ucr,txen ;clear sender bit
ret
</pre>

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.