Forum: Mikrocontroller und Digitale Elektronik Ausgabe eines Wortes auf die RS232


von Thorsten F. (thorstencux)


Angehängte Dateien:

Lesenswert?

Hallo,

ich heiße Thorsten und würde gerne etwas mehr
mit PIC Prozessoren machen und lernen.
Ich hoffe hier kann mir etwas geholfen werden.
Ich sitze seit Tagen an einem Projekt mit einem PIC 16F84A.

Eigentlich möchte ich nur einen Text auf die RS232 senden.
Ich habe einen asm code bei www.sprut.de gefunden. Dieser gibt
den Buchstaben "A" immer wieder aus. Als erstes Versuchsprogramm
dachte das das ganz nett wäre. Leider bekomme ich es nicht hin aus dem 
"A"
ein Wort zu machen. Ich denke da fehlt das ein oder andere noch im 
Programm.
Ist es möglich das mir hier mal jemand etwas hilft?

Kann man mir bei diesem Problem helfen??

Eine kurze email wäre toll!!!


Gruß Thorsten

von Worschtsupp (Gast)


Lesenswert?

Ich würde es mal so probieren:

Loop
  movlw  'H'
         call  Send_RS
        movlw  'a'
         call  Send_RS
        movlw  'l'
         call  Send_RS
        movlw  'l'
         call  Send_RS
        movlw  'o'
         call  Send_RS

  goto  Loop

von Thorsten F. (thorstencux)


Lesenswert?

Vielen vielen Dank !!!!
Das haut ja schon super hin.

Würde es eigentlich gehen, wenn ich dort noch ein nop
einfüge, daß die Wiederholrate etwas langsamer wird ???

Gruß und 1000 Dank Thorsten


Loop
  movlw  'H'
         call  Send_RS
        movlw  'a'
         call  Send_RS
        movlw  'l'
         call  Send_RS
        movlw  'l'
         call  Send_RS
        movlw  'o'
         call  Send_RS
        nop
        nop
  goto  Loop

von Michael U. (Gast)


Lesenswert?

Hallo,

ja, geht. Aaaaber: schau mal nach, wieviele Takte Dein PIC für einen 
nop-Befehl braucht. Dann rechne mit Deiner benutzten Taktfrequenz die 
Zeit für einen nop aus.
Dann versinke in tiefes Nchdenken. ;)

Denkaufgabe: wie programmiere ich eine Warteschleife bestimmter Dauer...

Gruß aus Berlin
Michael

von Thorsten F. (thorstencux)


Lesenswert?

Hallo Michael,

du hast natürlich recht.
Das wären dann 6 Zyclen Schleife.
Ich würde natürlich gerne eine Warteschleife von etwa 10sec
programmieren. Aber wie schon gesagt ich lerne gerade erst das
Stehen. vom Laufen und rennen bin ich noch sehr weit entfernt.
Mein Lösungsversuch würde so aussehen:

Wait250
        movlw   D'10000'  ; 10sec Pause


Hoffe ich bin da auf dem richtige Weg .....

Grüße aus dem Norden!!!

von Worschtsupp (Gast)


Lesenswert?

> Hoffe ich bin da auf dem richtige Weg .....

Nicht ganz, denn du mußt noch berücksichtigen, dass 'W' 8 Bit breit ist. 
D. h. es geht höchstens ein

movlw D'255'

Also mußt du da mehrmals ineinander schachteln, am besten unter 
Zuhilfenahme weiterer Register. Aber das schöne ist ja, dass du mit 
MPLAB sehr genau simulieren kannst. Viel Spaß :)

Kleiner Tip noch zu PICs: http://www.sprut.de

Dort gibts auch massenhaft guter Infos.

von willivonbienemaya (Gast)


Lesenswert?

Wenigstens mal jemand der relativ klein anfängt. Lobenswert.

Um ne Verzögerung zu bekommen machst du am einfachsten sowas in der Art:

DelayCounter equ 0x20 ; Variable anlegen


main
   ...
   ...
   ...
   movlw 0xFF
   movwf DelayCounter
   call delay
   ...



delay
    decfsz  DelayCounter,f
    goto delay
    return


was immer wichtig ist: mitrechnen wie lange die ganze Aktion dauert, 
dass man ein Gefühl dafür bekommt.



@ Worschtsupp
Hast du den ersten Post gelesen g

von Worschtsupp (Gast)


Lesenswert?

Ups :) Ja da war was...

von Thorsten F. (thorstencux)


Lesenswert?

Reicht dieser eine Befehl aus um 250ms zu verzögern????

von willivonbienemaya (Gast)


Lesenswert?

Antwort 1:
Ja, bei einer Taktfrequenz von 16 Hz.

Antwort 2:
Nein, du musst eine Schleife bauen so wie ich es geschrieben habe.

von Thorsten F. (thorstencux)


Lesenswert?

Nun habe ich ( Ihr ) es also hinbekommen das das Wort hallo immer wieder 
wiederholt wird.
Das ist schon fast das was ich haben wollte.
Wie geht aber nun ein Zeilenumbruch. Also so sieht es jetzt aus:
hallohallohallohallo   usw.
Ich würde es aber gerne -

hallo
hallo
hallo
hallo
haben.

@ willivonbienemaya:

DelayCounter equ 0x20 ; Variable anlegen
main
   ...
   ...
   ...
   movlw 0xFF
   movwf DelayCounter
   call delay
   ...
delay
    decfsz  DelayCounter,f
    goto delay
    return

Das habe ich noch nicht  so ganz verstanden.
Wo kann ich denn den Wert für die Verzögerung eingeben?

Gruß Thorsten

von Thorsten F. (thorstencux)


Lesenswert?

Habe mal die Datei so eingefügt.
Das wORT wird nun 4 Mal ausgegeben und dann bleibt alles stehen....

Was das wohl wieder ist ?????

von willivonbienemaya (Gast)


Lesenswert?

Schau dir das Programm mal an.
Das ist nicht schwer zu verstehen.

Die Variable in Counter wird einfach runtergezählt bis sie null ist. 
erst dann gehts weiter.

du kannst also die verzögerung hier verändern: movlw 0xFF

von willivonbienemaya (Gast)


Lesenswert?

zu dem Problem mit der neuen Zeile musst du nur das ascii zeichen für 
Carriage Return raussuchen und ein PC terminal benutzen dass es 
unterstützt.

http://de.wikipedia.org/wiki/ASCII

Du brauchst 0x0D

von Thorsten F. (thorstencux)


Lesenswert?

willivonbienemaya wrote:
> Schau dir das Programm mal an.
> Das ist nicht schwer zu verstehen.
>
> Die Variable in Counter wird einfach runtergezählt bis sie null ist.
> erst dann gehts weiter.
>
> du kannst also die verzögerung hier verändern: movlw 0xFF

movlw 0xFF    <--- hmm grübel grübel.....

könntest Du mir bitte mal ein Beispiel für 2Sek geben???

Und wie bekomme ich den Zeilenumbruch hin???


Gruß und Danke Thorsten

von willivonbienemaya (Gast)


Lesenswert?

Du musst dir etwas mehr Zeit zum Grübeln lassen glaube ich.

wieviel takte musst du verbraten um auf zwei sekunden zu kommen?
ich kann es nicht wissen, da ich nicht weiss wie schnell dein controller 
läuft.

den zeilenumbruch bekommst du auch hin.

einzelne zeichen kannst du doch senden.

probier doch einfach mal aus was passsiert wenn du das zeichen 0x0D 
sendest.

von Thorsten F. (thorstencux)


Lesenswert?

Also mein Professor läuft mit 4MHz Takt.
Das mit dem 0x0D habe ich schon probiert.
Ich weiß nur nicht wie ich es senden soll.
Zur Zeit sieht es ja so aus:

Loop
  movlw  'H'
         call  Send_RS
        movlw  'a'
         call  Send_RS
        movlw  'l'
         call  Send_RS
        movlw  'l'
         call  Send_RS
        movlw  'o'
         call  Send_RS

Soll ich hier so eine Zeile einfügen???

call Send_0x0D


  goto  Loop

von willivonbienemaya (Gast)


Lesenswert?

Du weisst noch nicht so ganz was du da eiegntlich tust.

ein stück deines codes:
  movlw  'H'
  call  Send_RS

du lädst 0x48 ins W Register udn rufst dann ein Unterprogramm auf.
das solltest du verstehen.
nimm dir zeit dafür.

dann kannst du auch eine 0x0D senden.



4 MHz bedeutet, dass er für einen Takt 1µs brauchst.
Den Rest müsstest du hinbekommen.

von Thorsten F. (thorstencux)


Lesenswert?

Hallo nochmal....

Das mit der Verzögerung habe ich tatsächlich hinbekommen.
Nur ich bekomme einfach keinen Zusammenhang mit dem return Befehl
( 0x0D ) zustande.
MPLap zeigt mir auch keinen Fehler. Aber es wird halt immer nur das
Hallo hintereinander ausgegeben.

vieleicht noch so : putcUSART(0x0D)

Wie gesagt ich tappe da VOLL im dunkeln.
Bekomme auch erst morgen meine beiden Bücher über PIC´s

Gruß Thorsten

von Thorsten F. (thorstencux)


Lesenswert?

Thorsten Fischer wrote:
> Hallo nochmal....
>
> Das mit der Verzögerung habe ich tatsächlich hinbekommen.
> Nur ich bekomme einfach keinen Zusammenhang mit dem return Befehl
> ( 0x0D ) zustande.
> MPLap zeigt mir auch keinen Fehler. Aber es wird halt immer nur das
> Hallo hintereinander ausgegeben.
>
> vieleicht noch so : movlw  'h '
                      call  Send_RS
                      movlw  0x0d
                      call  Send_RS
>
> Wie gesagt ich tappe da VOLL im dunkeln.
> Bekomme auch erst morgen meine beiden Bücher über PIC´s
>
> Gruß Thorsten

von Dieter Werner (Gast)


Lesenswert?

Der ASCII Zeichensatz besteht aus darstellbaren Zeichen und 
Steuerzeichen.
Die darstellbaren Zeichen kann man (wie oben schon zu sehen) mit
movlw 'X' in das W-Register laden.

Für das Steuerzeichen "return" geht das etwas anders, nämlich
  movlw  0x0D    und danach
  call  Send_RS

Unter Umständen benötigt man auch noch ein "line feed"
  movlw  0x0A
  call  Send_RS

Viel Erfolg

von Peter D. (peda)


Lesenswert?

Muß man das aufm PIC wirklich immer so umständlich machen oder geht das 
nicht auch einfacher ?


Z.B. beim 8051 schreibe ich einfach:
1
mainloop:
2
        call    out_text
3
        db      'Hallo Welt', 0Ah, 0Dh
4
        db      0                      ;end mark
5
6
        call    delay_ms
7
        dw      10000
8
9
        jmp     mainloop

Und out_text bzw. delay_ms POPen sich dann einfach vom Stack die 
Returnadresse als Pointer auf die konstanten Daten, machen was damit und 
kehren dann hinter die Daten zurück.

Man hat doch öfters Texte auszugeben und möchte die auch bequem ändern 
können.


Peter

von willivonbienemaya (Gast)


Lesenswert?

Mir ist keine Möglichkeit bekannt wie das mit dem mini Befehlssatz der 
16er PIC´s möglich ist. Er beherrscht ja nur 35 Befehler soweit ich mich 
erinnere, da sieht vieles kompliziert aus.
Aber ich lasse mich gerne eines besseren belehren.


von crazy horse (Gast)


Lesenswert?

@peter
wie findet denn dein Programm nach call out_text call delay_ms? Müsste 
doch nach ret im Nirwana landen? Ist ne Weile her, aber das scheint mir 
suspekt.

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

~willivonbienemaya
Das ist bei anderen Prozessoren nicht anders, einer Routine / eines 
makros bedarf es zur Stringausgabe immer. Und wenn der Pic nicht zählen, 
vergleichen und schubsen könnte wäre er längst tot. Aber mehr bedarf es 
zur Stringasgabe nicht .

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

~crazy horse

denk mal nach,

out_text findet auf dem stack den Beginn des Strings.
Klappert den durch und findet am stringende die null. Nun pusht es die 
auf das Stringende folgende und durch mitzählen ermittelte Adresse auf 
den Stack und Springt mit Return dort hin.
Das wars.

delay, dito

peter hat hier nur DB 0
hinter dem asciistring für die Zeitangabe vergessen oder vewendet ne int 
oder long mit festem format.

von Peter D. (peda)


Lesenswert?

crazy horse wrote:
> @peter
> wie findet denn dein Programm nach call out_text call delay_ms? Müsste
> doch nach ret im Nirwana landen? Ist ne Weile her, aber das scheint mir
> suspekt.

Hab ne Weile gebraucht, es auszugraben.
Der Trick ist das abschließende 0-Byte hinter dem Text
1
;______________________________  Transmit Byte ___________________________
2
3
;input: ACC = byte to send
4
5
putchar:
6
  jnb TI, $  ;wait until last transmit finished 
7
  clr TI
8
  mov sbuf, a
9
  ret
10
;______________________________  Transmit String _________________________
11
12
;input: 0-terminated string after call
13
14
puts:
15
  pop dph         ;get address of string
16
  pop dpl
17
  sjmp ?put2
18
?put1:
19
  call putchar    ;send byte
20
  inc dptr        ;point to next address
21
?put2:
22
  clr a
23
  movc a, @a+dptr ;get byte pointed by DPTR
24
  jnz ?put1       ;send it if not zero
25
  jmp @a+dptr     ;jump back behind zero byte


Und das delay_ms nimmt sich immer genau 2 Bytes und springt nach 
Ausführung zurück, erhöht um 2.


Peter

von crazy horse (Gast)


Lesenswert?

ok, so macht es Sinn. Kann man nur in Verbindung mit der "Intelligenz" 
der UPs verstehen, nicht als Eigenschaft des 8051. Wie gesagt, lange (10 
Jahre) her, dass ich sowas gemacht habe.
Aber irgendwas ähnliches müsste doch auch mit dem PIC machbar sein?

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

@ Peter,

springst du wirklich direkt??

warum pusht du nicht den stack und gehst wie es sich gehört mit nem ret 
aus der routine?


das riecht mir ja verschärft nach spaghetti carbonara , hätt ich von dir 
nicht erwaret.

tricky ja aber so ?

von Peter D. (peda)


Lesenswert?

Winfried Jaeckel wrote:

> springst du wirklich direkt??

Nein, indirekt.


> warum pusht du nicht den stack und gehst wie es sich gehört mit nem ret
> aus der routine?

Warum soll ich 3 Befehle nehmen, wenn ich einen hab, der das alles 
zusammen macht ?

Die Umstände mit push+push+ret müßte man nur machen, wenn es keinen 
indirekten Sprungbefehl gäbe.

Und auch der AVR hat ja dafür den IJMP-Befehl.


Peter

von Thorsten F. (thorstencux)


Lesenswert?

Also erst einmal vielen Dank für die Hilfe!!!

Es funzt alles sehr gut.
Ich habe nur Probleme noch mit der Ausgabe.
Die ist nämlich etwas schnell.
Ich würde gerne alle 2Sek das Wort Hallo darstellen.
bringe ich aber die Warteschleife mit hinein, dann
gibt der PIC mir 5 MAl das Wort HALLO aus und dann kommt nichts
mehr.

Kann es sein das das Timing dann nicht mehr stimmt? Ich meine die
2400Baud. Da darf ja nur 5% Abweichung sein.

Ansonsten mußte ich noch hinter dem return eine neue Zeile setzen.
Das habe ich dann so gemacht:

        movlw  'H'
         call  Send_RS
        movlw  'A'
         call  Send_RS
        movlw  'L'
         call  Send_RS
        movlw  'L '
        call  Send_RS
        movlw  'O'
         call  Send_RS
        movlw  0x0d
         call  Send_RS
        movlw  0x0a
         call  Send_RS


Und genau hier sollte jetzt eine Pause von 2Sek sein und danach sollte 
das zweite Mal HALLO ausgegeben werden.

Hat jemand noch eine  Idee??

Gruß Thorsten

von Thorsten F. (thorstencux)


Lesenswert?

Hat niemand eine Idee ????


Gruß aus dem Norden!

von willivonbienemaya (Gast)


Lesenswert?

"
Kann es sein das das Timing dann nicht mehr stimmt? Ich meine die
2400Baud. Da darf ja nur 5% Abweichung sein.
"

Da hier niemand weiss wieviel takte die Funktion Send_RS benötigt, wird 
dir keiner helfen können.

Du kannst als debugger den siumlator auswählen und mit der Stopwatch 
schauen wie lange was dauert. dann kannst du dir deine genaue Baudrate 
ausrechnen.

von Karl H. (kbuchegg)


Lesenswert?

willivonbienemaya wrote:
> "
> Kann es sein das das Timing dann nicht mehr stimmt? Ich meine die
> 2400Baud. Da darf ja nur 5% Abweichung sein.
> "
>
> Da hier niemand weiss wieviel takte die Funktion Send_RS benötigt, wird
> dir keiner helfen können.

Interessant wäre auch, ob das eine Hardware UART darstellt
oder ob der PIC das alles in Software machen muss.

Aber prinzipiell:
Solange du an SendRS nichts veränderst, kannst du das Timing
der UART nicht dadurch stören, dass irgendwo anders eine
Warteschleife eingeführt wird.

von Thorsten F. (thorstencux)


Lesenswert?

Hallo,

da ich an der Baudrate nicht viel verändern kann für meine Zwecke,
muß ich mir also etwas anderes einfallen lassen.

Wie könnte ich denn noch softwaremäßig ein langsameres ausgeben der
Bauchstaben erreichen?

Gruß Thorsten

von Peter D. (peda)


Lesenswert?

Thorsten Fischer wrote:

> Wie könnte ich denn noch softwaremäßig ein langsameres ausgeben der
> Bauchstaben erreichen?

Indem Du einen Taschenrechner nimmst.

Dein obiges Delay müßte richtig sein, aber schau mal ins Datenblatt, 
wieviel Zyklen die beiden Instruktionen brauchen.

Bei 2 Instruktionen und einem Byte als Schleifenzähler kommst Du auf 
gerade mal 512 Zyklen. Und nun greif mal zum Taschenrechenr, welcher 
kurzen Zeit das entspricht.



...



Richtig, das ist hoffnungslos zu kurz.
Aber keine Angst, nimmste eben noch und nochn Byte und verschachtelst 
die Schleifen ineinander. Schon kommst Du bis zu 256*256*256*2 Zyklen, 
sollte also reichen. Wenns zu lang ist, lädste eben den äußeren Zähler 
nicht mit 256 (0), sondern weniger.


Und wende jetzt noch fragst, wie schachtelt man:
1
Del0 equ 0x20 ; Variable anlegen
2
Del1 equ 0x21 ; Variable anlegen
3
Del2 equ 0x22 ; Variable anlegen
4
5
main:
6
   ...
7
   ...
8
   ...
9
   movlw 100 ;100*256*256*2 Zyklen
10
   movwf Del2
11
delay:
12
    decfsz  Del0,f
13
    goto delay
14
    decfsz  Del1,f
15
    goto delay
16
    decfsz  Del2,f
17
    goto delay
18
    goto main


Und beim 8051 würde das so aussehen
1
main:
2
   ...
3
   ...
4
   ...
5
   mov r2, #100
6
delay:
7
   djnz r0, delay
8
   djnz r1, delay
9
   djnz r2, delay
10
   jmp main


Peter

von Thorsten F. (thorstencux)


Lesenswert?

>
1
> Del0 equ 0x20 ; Variable anlegen
2
> Del1 equ 0x21 ; Variable anlegen
3
> Del2 equ 0x22 ; Variable anlegen
4
> 
5
> main:
6
>    ...
7
>    ...
8
>    ...
9
>    movlw 100 ;100*256*256*2 Zyklen
10
>    movwf Del2
11
> delay:
12
>     decfsz  Del0,f
13
>     goto delay
14
>     decfsz  Del1,f
15
>     goto delay
16
>     decfsz  Del2,f
17
>     goto delay
18
>     goto main
19
>
>
Genau daswar die Lösung!!!! Jetzt kann ich den Intervall
so wählen wie ich ihn gerne hätte !!!!! Vielen Dank


Gruß Thorsten

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.