PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Zusammensetzen von Bytes zu einem Single-Datentyp



Alf_Wuffi
01.12.2004, 23:19
Hallo,

ich möchte gerne über Uart eine Single-Variable verschicken und abholen und das über einen längeren Zeitraum. Mit inputbin, aber auch input klappt das auch. Nur, wenn irgendwas nicht stimmt, bleibt das Programm gnadenlos stehen. Man kann noch so komplexe Abfangroutinen 8 inkey(), ischarwaiting usw.) entwerfen, letztendlich gibts dann doch einen Hänger...

Will jetzt den Weg über den URXC Interrupt gehen. Es wird da byteweise eingelesen. Nur wie setzt man die Bytes - 4 glaube ich - einer ankommenden Single-Variablen wieder zu Single zusammen. Für Integer gibt es Makeint oder 256*msb+lsb. Wie geht das hier? Die ankommenden Bytes kann ich ich ja in ein Feld a(1) bis a(?) einlesen, aber dann ...?

Wäre nett, wenn mir da jemand auf die Sprünge helfen könnte.

Wolfgang

PicNick
02.12.2004, 09:08
Bin kein Basic-Guru, da werden sich gleich ein paar melden. vielleicht geht's so:
a = 0
i = 1
data

Interrrupt / character "data" kommt:
a = a * 256
a = a + ASC(data)
i = i + 1
if ( i> 4) signal "a is komplett"
ende Interrrupt


Ob das für Basic richtig formuliert is, weiss ich jetzt aber nicht mfg

Alf_Wuffi
03.12.2004, 18:37
Danke für deinen Beitrag. Entschuldigung, dass ich mich jetzt erst melde. War überrschend in der Zwischenzeit außer Haus, konnte daher hier nicht reinschauen.

Das Ganze scheint nicht ganz so einfach. Hier ein Ausschnitt aus der Bascom-Hilfe, der wahrscheinlich zeigt, dass das Zusammenfügen wohl aud unüberwindbare Schwierigkeiten stoßen wird:


Floating point (ASM code used is supplied by Jack Tidwell)
Single numbers conforming to the IEEE binary floating point standard.

An eight bit exponent and 24 bit mantissa are supported.
Using four bytes the format is shown below:

31 30________23 22______________________________0
s exponent mantissa

The exponent is biased by 128. Above 128 are positive exponents and
below are negative. The sign bit is 0 for positive numbers and 1 for
negative. The mantissa is stored in hidden bit normalized format so
that 24 bits of precision can be obtained.

Wolfgang

PicNick
03.12.2004, 19:21
Ich seh schon, alles klar.
Ein Kollege (VB Specialist) hat mir gesagt, dass es so etws wie ein Union wie bei C (Redefinition eines Feldes) nicht gibt.
Wenn'so ist, dann müssen wir das float eben auftröseln und wieder zusammenbauen. d.h wir interpretieren das Bit-Gewusel und rechnen die float einfach wieder aus.
Leider bin ich heut ein bißchen in Druck und kann mich erst morgen wieder rühren.
Bis dann halt, oder wem anderen fällt ein besserer Trick ein.
Kopf hoch ! gibt's nicht, gibt's nicht
mfg Robert

PicNick
04.12.2004, 12:02
Bist du noch da ?
Ich schreib mehr oder weniger Pseudo-Code, weil's schon lange her ist, daß ich Basic geschrieben habe. Aber Du denkst ja mit.

Bezieht sich auf das IEEE -Format, Microchip is a bißerl anders

Wir brauchen:
Vorzeichen = 0 (integer)
Exponent = 0 (integer)
Ergebnis = 0 (float 32 Bit == 4 Byte)

Wir haben:
Zeichen(1) bis Zeichen(4)

1) Vorzeichen/Exponent: (*g* was sein muß, muß sein *g*)
Das höchste Bit vom Exponenten ist das Vorzeichen
WENN (ASC(Zeichen(1)) >= 128) dann:
Vorzeichen = -1
Exponent = ASC(Zeichen(1)) - 128) * 2
ELSE
Vorzeichen = +1
Exponent = ASC(Zeichen(1)) * 2
END-WENN

2) Exponent Das kleinste Bit vom Exp. ist das höchste von Zeichen(2) bzw. der Mantisse (IEEE). Die Mantisse hat dort aber immer 1, deswegen steht der Einser explizit nicht da, den muß man sich denken

WENN (ASC(Zeichen(2)) >= 128) dann:
Exponent = Exponent + 1 (dort gehört der 1er hin)
ELSE
Zeichen(2) = CHR(ASC(Zeichen(2) + 128) (keiner da, g'hört aber hin)
END-WENN
Exponent = Exponent - 128 (Basis 128)

*schnauf* Diese eigentlich simple Bit-Shifterei geht vielleicht auch in Basic besser, weiss nicht.

2 Mantisse:
Ergebnis = asc(Zeichen(2)) * 65535
+ asc(Zeichen(3)) * 256
+ asc(Zeichen(4))

3 ergebnis zu von 1nnnn auf 1,nnn umrechnen

Ergebnis = Ergebnis / 8388480

3 Exponent reinrechnen
Exp. --> Ergebnis = Ergebnis * (2 hoch (+/-) Exponent)
Vielleicht als schleife, "exponent"-mal

4 Vorzeichen
Ergebnis = Ergebnis * Vorzeichen

*tiefseufz*

EXAMPLE
Testen natürlich mit bekannten Zahlen, einfachster Fall "+1.0"
es sollte sein
Zeichen(1) = 64
Zeichen(2) = 0
Zeichen(3) = 0
Zeichen(4) = 0


Vorzeichen = +1
Exponent = ASC(Zeichen(1)) * 2 => 128
Exponent = Exponent - 128 ==> 0
Zeichen(2) = CHR(ASC(Zeichen(2) + 128) (Einser muß aber sein)

Zeichen(2) = 128 (erst jetzt)
Zeichen(3) = 0
Zeichen(4) = 0

Ergebnis = 128 * 65535 + 0 + 0 => 8388480
Ergebnis = Ergebnis / 8388480 ==> 1

Exp. + --> Ergebnis = Ergebnis * (2 hoch 0 ) ==> 1

Vorzeichen ist +1 -- => also bleibt 1.0


*ganztiefseufz*


Ich hoffe, ich habe dir da keinen Stiefel erzählt, prinzipiell bin ich mir sicher, aber ich werd's selbst noch testen


Laß hören ! mfg robert :-b

Alf_Wuffi
04.12.2004, 12:20
bin noch da, muss zwar nicht essen, aber mit meiner Frau in die Stadt, es weihnachtet langsam... so gegen 19 Uhr denke ich wirds schon..

Alf_Wuffi
04.12.2004, 19:06
ooops, das ist ja ne ganze Doktorarbeit geworden. Irgendwie kriege ich keine freie Zeit hin. Jetzt haben wir auch noch Besuch... Aber ich denke, gegen 22 Uhr kann ich mich diesen tollen Gedanken widmen. Meine Güte, Du bist ja ganz schön drin in dieser Materie. Habe viel mit Zahlen zu tun, aber mit Mantissen und Exponenten schon lange nicht mehr.

Habe zwischenzeitlich auch in einem Bascom Buch das Kapitel über Single gelesen. Habe da nicht viel verstanden, wenn ich ehrlich bin. Habe aber eine Formel:

x=(-1)s*1.M*2(E-127)

wobei S das Vorzeichen, M Mantisse und E der Exponent ist. Das fett-geschriebene soll hoch..., also ein Eponent sein. Habe nichts gefunden, wie man das setzt.


b(31) = S
b(30-23)= E
b(22-0)=M

Aber wie gesagt, kann mich erst gleich darum kümmern. Es gibt irgendein Programm AVRCalc, mit dem man das besser aufrödeln kann. Kenne ich leider nicht.

Danke für die Lösung, die man jetzt noch schön verpacken muss. Tolle Leistung!

Alf_Wuffi
05.12.2004, 01:51
habe mal eine Struktur daraus gemacht, wie es im Programm aussehen könnte. Noch nicht getestet.


Dim Vorzeichen As Integer
Dim Exponent As Integer
Dim Ergebnis As Single
Dim Fertig As Bit
Dim Zähler As Byte '***** Feldzähler
Dim Zeichen(4) As Byte
Dim Temp As Byte
Dim Sendeanforderung As String * 1

Const True = 1
Const False = 0


On Urxc Hole_bytes

Enable Interrupts

Main:

Sendeanforderung = "!"
Do
'..
'..
'**** Aufforderung zum Senden
Printbin Sendeanforderung '**** ohne Chr(10) und Chr(13)
'**** Sender sendet nun
'***** eventuell nur temporär einschalten, falls noch andere Interrupts laufen
'enable urxc
i=1 '**** Feldzähler initialisieren
While Fertig = True
'***** geht in Bascom nicht in einer Zeile!
'***** braucht man wahrscheinlich Integer-Variablen für die Zwischenwerte
'***** muss ich noch klären
Ergebnis = Zeichen(2) * 65535 + Zeichen(3) * 256 + Zeichen(4)
Ergebnis = Ergebnis / 8388480 '**** warum?
Ergebnis = Ergebnis * 2 ^ Exponent
Ergebnis = Ergebnis * Vorzeichen
Print Ergebnis
Fertig = False
Wend
'disable urxc

Loop

End

Hole_bytes:
Temp = Udr '**** 1 Zeichen aus Register empfangen, ist ascii
Select Case Zähler
Case 1
If Temp.7 = 1 Then '**** größer 128
Vorzeichen=-1
Exponent = Temp - 128
Exponent = Exponent * 2
else
Vorzeichen = 1
Exponent = Temp * 2
endif
Zeichen(zähler) = Temp
Incr Zähler
Case 2
If Temp.7 = 1 Then
Incr Exponent
Else
Zeichen(Zähler) = Temp + 128 '**** du hast chr(..), warum?
End If
Exponent = Exponent - 128
Incr Zähler
Case 3 To 4
Zeichen(zähler) = Temp
Incr Zähler
Fertig = True
End Select

Return

Auf dieser Basis lässt sich vielleicht weiterarbeiten.

PicNick
05.12.2004, 08:45
Sag ich ja, wenn einer Basic kann, sieht das gleich besser aus, als bei mir.
Durch den Typ "BYTE", bei dem man die Bits offenbar auch einzeln anquatschen kann, ist natürlich die ganze "ASC" und "CHR" Sache überflüssig. ( ASC("A") => 65, CHR(65) => "A" )

hoppperla, ogott ogott ogott die zahl 8388480 ist falsch !
Das soll sein hex "00800000" ==> "8388608"
Ich bin für öffentliches Auspeitschen ! da kann sich ja keiner auskennen !

Code u. Test:
laß dir wirklich eine Zahl schicken, die einfach ist und die du kennst, wie eben 1.0 und schreib' dir auf, am besten als hex oder Bitmuster, wie die vier Zeichen tatsächlich aussehen. Und dann geh dein Programm, das mir übrigens koscher vorkommt, so richtig mit Taschenrechner, Bleistift und Papier step by step durch.

Tips:
aufpassen, ob der Typ "BYTE" mit oder ohne Vorzeichen ist. Wenn ja, wär's blöd, weil er dann alle Byte.7 =1 Zahlen als negative Zahlen sieht (das war auch der Grund für meine ASC und CHR)

Du wirst beim Testen gleich sehen, ob die 4 Byte von rechts oder links kommen.

Ebenso wirst du sehen, ob man vom Exponenten von wirklich 128 oder doch 127 abziehen muß.

Performance: Mantisse * 2 ^^ Exponent ist richtig, aber möglicherweise für Arbeit für deinen Fuzzy. Wenn möglich, Byte-Shiften (links => *2, rechts => /2) in einer Schleife.

Wie auch immer, wenn du da durch bist, hast du über "Computer inside" mehr erfahren als durch drei Mandelbrotmengen.

Auf geht's ! mfg Robert

PS Laß hören, ich will ja auch was lernen !

Joerg
05.12.2004, 11:04
Der Begriff union kam ja schon, ebenso die Aussage das dies in BASCOM nicht geht. Aber es gehen doch wohl absolute Vars.

Das heißt sowohl der Single Value als auch das Array auf dem selben Speicherplatz. Die BASCOM-Hilfe spuckt dazu aus:

DIM var AS [XRAM/SRAM/ERAM] type [AT location] [OVERLAY]

Also mit AT wird der Speicherplatz vorgegeben und die zweite Var muss wohl noch den Qualifier OVERLAY dazubekommen.

Hab's nicht ausprobiert, aber so sollte es auch gehen, ohne das Float-Format auseinanderzudrieseln.

Schönen 2. Advent und
Viele Grüße
Jörg

PicNick
05.12.2004, 11:21
Lieber Jörg, klingt ja verlockend, hoffentlich macht sich der Compiler nicht trotzdem ins halstuch, wenn er verschiedene datentypen mit der selben adresse (location, Overlay) kriegt.
Aber was red' ich herum, sowas probiert man einfach.
C ist ja da ein Dödi, wenn man nur lang genug casted, glaubt er einem alles. (ich glaub, "C" kommt ja eh von "casten")

Trotzdem, einmal zu Fuß ein Float aufmischen gehört zum Leben dazu.

Alf_wuffi wird uns berichten, bin neugierig mfg robert

05.12.2004, 15:17
habe momentan Schwierigkeiten, das zu testen. Blicke noch nicht ganz durch, was da abläuft. Print Testzahl, überhaupt print oder input??? Wo innerhalb do loop, oder am Anfang. Irgendwie werden die Bytes nicht richtig von diesem URXC Register wahrgenommen. Ich bleib am Ball, beiß mich da rein.

Frank
05.12.2004, 16:00
Hi PickNick,
das mit Overlay funktioniert aber gut, das hab ich des öfteren auch schon gemacht. Du kannst dann Variablen völlig unterschiedlich ansprechen.

Z.B. so

Dim Rs_textbuffer As String * 70
Dim Rs_textbufferbyte As Byte At Rs_textbuffer Overlay

Hier wurde das erste byte des Strings noch als Bytevariable definiert.
Duch den Overlay Befehl bist du genauso flexibel wie in C abe res geht noch bequemer als in C.

Bei Single Variablen dürfte es ähnlich einfach sein, einfach noch ein paar andere Variablen beliebigen Typs auf den Speicherbereich zeigen lassen

PicNick
05.12.2004, 17:24
Hi Frank, ich werd' mich hüten, irgendwelche Bemerkungen über Vor- und Nachteile von CompilerTypen zu machen, daß ergibt nur Religionskriege. Das sind Glaubensdinge mit absolut religösem Charakter.

Die Overlay Variante entspricht am ehesten dem "REDEFINES" beim Cobol, wenn den noch wer kennt.

@Wuffi: Jörg & Frank sind sich ihrer Sache sicher, und ich glaube ihnen.
Vergiß den ganzen Stiefel, den ich dir geschrieben habe *seufz* und mach das so, ist einfacher (solange Sender und receiver die gleiche Plattform haben).

DIM Ergebnis as single
DIM recv(4) as Byte at ergebnis overlay
DIM Counter as Byte

Init: Counter = 1

receive Interrupt:
recv(Counter) = received-byte
Counter = Counter + 1
if (counter > 4)
display (ergebnis) // is auch schon fertig
Counter = 1 // ready for next float
return interrupt

Anm: Das ganze kann natürlich ausser Tritt kommen, der Teulfel und Murphy schlafen nie.
Auch die Synchronisation mit dem non-Interrupt Level hat so ihre Extravaganzen.
Für alles gibt's mehrere Möglichkeiten, doch ich denke, für's Erste habe ich dir den Kopf schon ausgiebigst vollgestopft.
gruss an die Frau Gemahlin, unbekannterweise mfg robert

05.12.2004, 22:28
Alles klar, kein Problem. Werde das auch mal testen. Die bisherige Routine mit inputbin läuft ja. Es kommt nur manchmal zum Hänger im Programm, wenn irgendwas mit den reinkommenden Bytes nicht stimmt. Das tritt aber meist erst nach Stunden auf.

Es fehlt mir bei dieser Konstruktion mit den Standard-Befehlen wie input, inkey, waitkey und ischarwaiting einfach eine vernünftige Fehlerbehandlung. Die ist in Bascom eher noch rudimentär, meiner Meinung nach. Ich kenne von VB her on error resume.... am Anfang der Sub und ich kann steuern, dass das Hauptprogramm weiterläuft.

Also Dank für die Hilfe. Ich habe dabei einiges gelernt.

Wolfgang

Alf_Wuffi
06.12.2004, 00:37
Eure Hilfestellungen sind vom Erfolg gekrönt!

Es klappt wunderbar. Seit ca 2 Stunden läuft die Sache fehlerlos. Vor allen Dingen bleibt die Sache nicht mehr hängen. Wenn mal die Bytes aus der Reihe tanzen, entstehen nur unsinnige Zeichen. Beim nächsten Intervall ist wieder alles in Ordnung.


$regfile = "m32def.dat" ' Mega 32

$baud = 9600
$crystal = 16000000

'*** alle Stacks und framesize stehen auf 100

Dim Ergebnis As Single
Dim Fertig As Bit
Dim Zähler As Byte '***** Feldzähler
Dim Zeichen(4) As Byte At Ergebnis Overlay
Dim Sendeanforderung As String * 1
Dim Funk_anzeige As String * 7 '*** einige mehr als nötig

Const True = 1
Const False = 0

Empfangs_led Alias Portc.3

On Urxc Hole_bytes

Enable Interrupts

Enable Urxc

Sendeanforderung = "!"
Set Empfangs_led '**** anfangs aus
Do
'***** nachfolgendes if in meinem Programm alle 12 sec
'**** If Interrupt_zähler = Interrupt_intervall Then
Enable Urxc '***** Interrupt einschalten, stört sonst andere Interrups
'**** Aufforderung zum Senden
Printbin Sendeanforderung '**** ohne Chr(10) und Chr(13)
'**** Sender sendet nun

Zähler = 1 '**** Feldzähler initialisieren
Reset Empfangs_led '**** an
If Fertig = True Then
Fertig = False
Waitms 200 '**** wichtig, verzögern
'**** hier steht Ergebnis zur Verfügung
Funk_anzeige = Fusing(ergebnis , "##.#" ) '**** um aufzurunden!
'**** Routine zum Anzeigen
Set Empfangs_led '**** aus
End If
Disable Urxc
'**** weiterer Code
'*** end if
Loop

End

Hole_bytes:
Zeichen(zähler) = Udr '**** ein Byte angekommen
Incr Zähler
If Zähler > 4 Then
Fertig = True
'Zähler = 1
End If
Return

Ich kannte zwar die Geschichte mit dem Overlay, habe mich aber nicht dran getraut, weil man in den mir vorliegenden Beispielen ne Adresse angeben musste. Da fühlte ich mich doch überfordert. Das mit dem Location wars dann. Toll!

Nochmals Dank
Wolfgang

Joerg
06.12.2004, 14:00
Trotzdem, einmal zu Fuß ein Float aufmischen gehört zum Leben dazu.

Hallo Robert,

da hast du vollkommen Recht.

Je mehr man allerdings in die Materie einsteigt, um so mehr wundert man sich dann auch, dass bei den Berechnungen noch halbwegs sinnvolle Resultate rauskommen können. ;)

Viele Grüße
Jörg

PicNick
06.12.2004, 14:25
@Jörg: *schmunzel* ich mach das beruflich, und wenn ich mir ansehe, was da so den ganzen Tag produziert wird (auch von mir), sollten wir vielleicht das "halbwegs sinnvoll" nochmal überdenken, ob man das auch so stehenlassen kann. *resignier*
Keep coding ! mfg robert

Rage_Empire
28.12.2005, 15:16
Hallo,

ich weiß, daß der Thread schon über ein Jahr alt ist, das macht die Sache aber nicht unintresannter. Erstmal:

RESPEKT!!! an PicNick

Ich setz auch gleich mal mit meiner Frage ein. Geht das wirklich nur mit overlays, oder kann ich hier auch die high und low -Befehle benutzen? Der Hintergrund ist der: Für viele Single-Variablen muß ich sonst jedesmal overlayen, was mit einem Unterprogramm (Funktion) welches mir die Singles zerlegt einfacher wäre. Der Ansatz von PicNick ist hierfür zwar geeignet, aber geht dies auch einfacher und Resourcensparender? Ich habe bis jetz nur gesehen, das man mit "high" und "low" Word-Variabeln zerlegen kann.

PicNick
28.12.2005, 16:54
Hi, wenn man senden/empfangen mit subroutine gewissermassen allgemein lösen will, kann man die singles (oder sonstwas) auch per adresse übergeben. sagen wir mal senden:


dim einesingle as single
dim adr as word

adr = varptr(einesingle) ' adresse von der single
call send4( adr , 4)

sub sendbytes(byval adr as word, byval ln as byte)
local cnt as byte
local vll as byte
for cnt = 1 to len
vll = inp (adr) ' lesen byte aus SRAM
print chr (vll); ' weg damit
Incr Adr ' address ++
Next
End Sub


Analog ginge auch empfang, dann halt mit "OUT addr, val "

Rage_Empire
28.12.2005, 21:15
Hi PicNick,

sieht intresannt aus. Habs auch schon probiert, funktioniert soweit ganz gut mit dem senden und empfangen. Jedoch versteh ich das ganze noch nicht ganz. Bin ich der richtigen Annahme, daß das Single direkt aus dem Speicher Byte für Byte gelesen und gesendet wird? Oder lieg ich damit falsch? Ein Single besteht doch immer 4 Bytes?


Senden:

Sub Sendsingle(byval Einesingle01 As Single)

local cnt as byte
local vll as byte
Adr01 = Varptr(einesingle01) ' adresse von der single
For Cnt = 1 To 4
Vll = Inp(adr01) ' lesen byte aus SRAM
Printbin Vll; ' senden
Incr Adr01 ' address ++
Next
End Sub

Empfangen:

Sub Recsingle(byval Einesingle01 As Single)

local cnt as byte
local vll as byte
Adr01 = Varptr(einesingle01) ' adresse von der single
For Cnt = 1 To 4
Inputbin Vll, ' empfangen
Out Adr01 , Vll ' schreibt in SRAM
Incr Adr01 ' address ++
Next
End Sub

PicNick
29.12.2005, 06:36
Das stimmt schon. das sub-argument ist die adresse vom 1.Byte. in der schleife wir die adresse inkrementiert, also, 2., 3., u. 4. Byte, je nachdem, was als Länge angegeben wird.
Aufpassen: wenn du varptr in der sub machst, kriegst du nicht die addresse vom single selbst, sondern von der "byval" Kopie. beim Senden macht das nix. ist halt einmal ums Eck, aber beim empfangen steht dann im original nix drin.
deshalb müßte varptr eigentlich der aufrufer vor dem call machen.

Rage_Empire
29.12.2005, 08:29
Ok, habs verstenden. Danke für den Tip mit "varptr"....hab mich schon über die seltsamen Effekte gewundert. Da muß ich wohl nicht "byval" sondern "byref" verwenden.

PicNick
29.12.2005, 09:01
das Blöde ist, daß Bascom per default sowieso immer die Adresse auf den Softstack legt
https://www.roboternetz.de/wissen/index.php/Bascom_Inside#Call_Sub_.26_Function
d.h. den Varptr könnt' man sich sparen, nur müßt man dann die adresse vom Stack holen, wohl mit inline assembler.