PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Projekt: Taschenrechner



DaveWagner
09.06.2009, 14:26
Hallo

Ich habe vor einen Taschenrechner in Bascom zu programmieren.
Als Anzeige benutze ich ein 16*2 Display.

Mein Problem ist jetzt wie ich dem Controller sage welche Zahl eingegeben wurde.
Zur Erkennung welche Rechenoperation ausgeführt werden soll(+,-,* und /) habe ich mir gedacht, weise ich einem String die Rechenoperation zu und benutze diesen um das Ergebnis dann zu berechnen.

Momentan habe ich schon die Anzeige der Zahlen programmiert.
Hier der Quellcode:



$regfile = "M16def.dat" ' use the Mega16

$crystal = 1000000



Config Lcdpin = Pin , Db4 = Porta.3 , Db5 = Porta.2 , Db6 = Porta.1 , Db7 = Porta.0 , E = Porta.4 , Rs = Porta.5

Config Lcd = 16 * 2
Initlcd

Config Pinb.0 = Input 'Zahl 0

Config Portb.1 = Input 'Zahl 1

Config Portb.2 = Input 'Zahl 2

Config Portb.3 = Input 'Zahl 3

Config Portb.4 = Input 'Zahl 4

Config Portd.0 = Input 'Zahl 5

Config Portd.1 = Input 'Zahl 6

Config Portd.2 = Input 'Zahl 7

Config Portd.3 = Input 'Zahl 8

Config Portd.4 = Input 'Zahl 9

Config Portd.5 = Input 'Plus

Config Portd.7 = Input 'Minus



Config Porta.6 = Input 'Mal

Config Porta.7 = Input 'Geteilt

Config Portc.7 = Input 'DELETE

Config Portc.6 = Input 'AC

Config Portc.5 = Input '=

Config Portc.4 = Input 'Komma

Config Portc.3 = Input 'Shift

Config Portc.2 = Input 'x Hoch y








Portb.0 = 1 'Zahl 0

Portb.1 = 1 'Zahl 1

Portb.2 = 1 'Zahl 2

Portb.3 = 1 'Zahl 3

Portb.4 = 1 'Zahl 4

Portd.0 = 1 'Zahl 5

Portd.1 = 1 'Zahl 6

Portd.2 = 1 'Zahl 7

Portd.3 = 1 'Zahl 8

Portd.4 = 1 'Zahl 9

Portd.5 = 1 'Plus

Portd.7 = 1 'Minus



Porta.6 = 1 'Mal

Porta.7 = 1 'Geteilt

Portc.7 = 1 'keine Funktion

Portc.6 = 1 'AC

Portc.5 = 1 '=

Portc.4 = 1 'Komma

Portc.3 = 1 'Shift

Portc.2 = 1 'x Hoch y


Dim Positionzeile As Integer

Dim Positionspalte As Integer

Dim Variable2 As Integer

Dim Variable16 As Integer

Positionzeile = 1

Positionspalte = 1

Variable2 = 2

Variable16 = 16

Do




If Positionspalte > Variable16 Then
Positionzeile = 2
Waitms 50
End If

If Positionzeile > Variable2 Then
Positionzeile = 1
Waitms 50
End If



If Pinb.0 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte ' Zahl 0 schreiben
Lcd "0"
Positionspalte = Positionspalte + 1
Waitms 200
End If


If Pinb.1 = 0 Then
'Zahl 1 schreiben
Cursor Off
Locate Positionzeile , Positionspalte
Lcd "1"
Positionspalte = Positionspalte + 1
Waitms 200
End If


If Pinb.2 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "2"
Positionspalte = Positionspalte + 1
Waitms 200
End If


If Pinb.3 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "3"
Positionspalte = Positionspalte + 1
Waitms 200
End If



If Pinb.4 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "4"
Positionspalte = Positionspalte + 1
Waitms 200
End If


If Pind.0 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "5"
Positionspalte = Positionspalte + 1
Waitms 200
End If

If Pind.1 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "6"
Positionspalte = Positionspalte + 1
Waitms 200
End If

If Pind.2 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "7"
Positionspalte = Positionspalte + 1
Waitms 200
End If

If Pind.3 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "8"
Positionspalte = Positionspalte + 1
Waitms 200
End If

If Pind.4 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "9"
Positionspalte = Positionspalte + 1
Waitms 200
End If

If Pind.5 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "+"
Positionspalte = Positionspalte + 1
Waitms 200
End If

If Pind.7 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "-"
Positionspalte = Positionspalte + 1
Waitms 200
End If

If Pina.6 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "x"
Positionspalte = Positionspalte + 1
Waitms 200
End If

If Pina.7 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "/"
Positionspalte = Positionspalte + 1
Waitms 200
End If






If Pinc.6 = 0 Then
Cls
Cursor Off
Positionspalte = 1
Positionzeile = 1
Waitms 200
End If






Kann mir jemand einen Denkansatz geben wie ich das Problem lösen kann?

Mfg

David

DaveWagner
09.06.2009, 15:11
Kann man die einzelnen Zahlen in in Array Felder schreiben und dann zusammenfügen ?
Oder kann man die angezeigte Zahl auf dem Display irgendwie auslesen indem man sie als String speichert ?

Mfg

David

Che Guevara
09.06.2009, 15:36
Hallo David,

ich habe mal ein codeschloss entwickelt, bei dem ich den code folgendermassen zusammengefügt habe:



input code 'eingabe der einzelnen ziffern
if code <> "enter" then
mycode = mycode * 10
mycode = mycode + code
endif


vielleicht hilft dir das ja?!?!

gruß
Chris

Thomas$
09.06.2009, 15:39
ich würd alles in eine string schreiben z.B.
rechnung$="56+17="
for stelle = 1 to len(rechnung$)
if mid(rechnung$,stelle,1)="+" then Ergebniss=val(mid(rechnung$,1,stelle))+val(mid(rec hnung$,stelle+1,len(rechnung$)))
next stelle
oder so was ähnliches zur auswertung

Felix H.
09.06.2009, 18:50
Hi,

du hast die Eingänge mit:

Config Portb.1 = Input

anstatt

Config Pinb.1 = Input

festgelegt. Änder das mal ab sonst werden die nicht richtig funktionieren =)

DaveWagner
10.06.2009, 11:26
Hallo

danke erstmal für die Antworten.
@ Che Guevara
Dein Codeschloss verstehe ich ehrlich gesagt nicht.
Ich weiß nicht was mit Mycode gemeint ist und was der Unterschied zwischen code und Mycode ist.
Brauche ich für das Programm noch einen Enter-Button oder kann dass bestätigen des Codes durch ein Rechenzeichen erfolgen.
Also ich meine wenn z.B. + gedrückt wird dass die eingegeben Zahlen dann bestätigt werden.
Da ich nicht weiß was Mycode ist verstehe ich den Sinn von mit 10 mal nehmen und Code addieren nicht.
Kannst du mir das nochmal genauer erklären ?

@Thomas
Das Grundschema deines Codes verstehe ich nur bei der ersten Zeile also
rechnung$="56+17="
weiß ich nicht wie man das dem String zuweisen soll.
Kann man da falls die Zahl 1 gedrückt wird, schreiben rechnung$="1"
und falls danach 2 gedrückt wird rechnung$ = "vorherige eingabe(1) und 2"?
Gibt es so eine Art Befehl in Bascom oder muss man das ganz anders machen?

Wäre nett wenn jemand das ganze nochmal erläutern könnte.

Mfg

David

Che Guevara
10.06.2009, 13:06
Hallo David,

ich versuche mal dir das zu erklären:

'Mycode' ist die zahl, die du eingeben möchtest, z.b. '58'.
'Code' ist immer eine ziffer, in diesem fall erst die '5' und anschließend die '8'.
wenn man jetzt rechnet: 5 * 10 = 50 (also: mycode = mycode * 10)
50 + 8 (also 'code') = 58 (also: mycode = mycode + code)

du brauchst natürlich in deinem fall keine 'enter' taste.
du musst einfach nur nach jedem tastendruck abfragen, ob eine der 'entertasten' (also: + ; - ; * ; / ; =) gedrückt wurde.
ist das der fall, musst du die entsprechende rechenoperation ausführen.

ich hoffe, es ist jetzt etwas verständlicher für dich, ansonsten kannst du mir mal eine pn schicken, falls du interesse hast!

Gruß
chris

Thomas$
10.06.2009, 14:52
ich hab das so gedacht
wenn (1) gedrückt wurde dann rechnung$=rechnung$+"1"
oder wenn (+) gedrückt wurde dann rechnung$=rechnung$+"+"

Che Guevara
10.06.2009, 15:12
hallo Thomas$,

ich glaube(!), dass das zwar gut für die einfache darstellung auf dem display wäre, aber damit kann der µC dann doch nicht rechnen! dann müsste man alles doppelt machen, oder nicht?!?!

Gruß
chris

Thomas$
10.06.2009, 15:26
ich weis das das umständlich ist aber es hat vorteile was ist wenn ich ein was ändern will ? ich will doch nicht immer die lange zahl mehrmals eingeben weil ich mich vertippt hab ( ich bin classpad 300 verwöhnt) dann lösch ich die stelle am string da ist das umständliche von Vorteil auserdem find ich das leichter zu verstehen (ok das ist ansichts sache)

DaveWagner
10.06.2009, 17:40
Hallo

Ich habe jetzt versucht es mit der Methode mit String umzusetzen doch ich habe ein paar Probleme damit.
Und zwar muss ich die Variable Ergebnis als Double deklarieren damit keine Fehler angezeigt werden.
Zudem zeigt mir Bascom an dass 29% Speicher benutzt werden. Das heißt ich kann das Ganze nicht mehr kompilieren weil ich nur die Demo habe.

Wenn ich den Befehl Lcd Ergebnis weglasse nimmt das Programm nur 20% in Anspruch.
Ich war mir bei der Deklaration von Rechnung auch nicht ganz sicher ob das stimmt.

Hier der Quellcode




$regfile = "M16def.dat" ' use the Mega16

$crystal = 1000000



Config Lcdpin = Pin , Db4 = Porta.3 , Db5 = Porta.2 , Db6 = Porta.1 , Db7 = Porta.0 , E = Porta.4 , Rs = Porta.5

Config Lcd = 16 * 2
Initlcd

Config Pinb.0 = Input 'Zahl 0

Config Pinb.1 = Input 'Zahl 1

Config Pinb.2 = Input 'Zahl 2

Config Pinb.3 = Input 'Zahl 3

Config Pinb.4 = Input 'Zahl 4

Config Pind.0 = Input 'Zahl 5

Config Pind.1 = Input 'Zahl 6

Config Pind.2 = Input 'Zahl 7

Config Pind.3 = Input 'Zahl 8

Config Pind.4 = Input 'Zahl 9

Config Pind.5 = Input 'Plus

Config Pind.7 = Input 'Minus



Config Pina.6 = Input 'Mal

Config Pina.7 = Input 'Geteilt

Config Pinc.7 = Input 'DELETE

Config Pinc.6 = Input 'AC

Config Pinc.5 = Input '=

Config Pinc.4 = Input 'Komma

Config Pinc.3 = Input 'Shift

Config Pinc.2 = Input 'x Hoch y

Config Pinc.0 = Output ' Beleuchtung








Portb.0 = 1 'Zahl 0

Portb.1 = 1 'Zahl 1

Portb.2 = 1 'Zahl 2

Portb.3 = 1 'Zahl 3

Portb.4 = 1 'Zahl 4

Portd.0 = 1 'Zahl 5

Portd.1 = 1 'Zahl 6

Portd.2 = 1 'Zahl 7

Portd.3 = 1 'Zahl 8

Portd.4 = 1 'Zahl 9

Portd.5 = 1 'Plus

Portd.7 = 1 'Minus



Porta.6 = 1 'Mal

Porta.7 = 1 'Geteilt

Portc.7 = 1 'Beleuchtung

Portc.6 = 1 'AC

Portc.5 = 1 '=

Portc.4 = 1 'Komma

Portc.3 = 1 'Shift

Portc.2 = 1 'x Hoch y


Dim Positionzeile As Integer

Dim Positionspalte As Integer

Dim Stelle As Integer

Dim Ergebnis As Double

Dim X As Integer




Positionzeile = 1

Positionspalte = 1

Dim Rechnung$ As String * 15
Rechnung$ = String(15 , 65)




Do


If Positionspalte > 16 Then
Positionzeile = 2
Waitms 50
End If

If Positionzeile > 2 Then
Positionzeile = 1
Waitms 50
End If





If Pinb.0 = 0 Then
Cursor Off
Locate Positionzeile , Positionspalte ' Zahl 0 schreiben
Lcd "0"
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + "0"

Waitms 300
End If


If Pinb.1 = 0 Then
'Zahl 1 schreiben
Cursor Off
Locate Positionzeile , Positionspalte
Lcd "1"
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + "1"
Waitms 300
End If


If Pinb.2 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "2"
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + "2"
Waitms 300
End If


If Pinb.3 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "3"
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + "3"
Waitms 300
End If



If Pinb.4 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "4"
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + "4"
Waitms 300
End If


If Pind.0 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "5"
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + "5"
Waitms 300
End If

If Pind.1 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "6"
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + "6"
Waitms 300
End If

If Pind.2 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "7"
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + "7"
Waitms 300
End If

If Pind.3 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "8"
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + "8"
Waitms 300
End If

If Pind.4 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "9"
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + "9"
Waitms 300
End If

If Pind.5 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "+"
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + "+"
Waitms 300
End If

If Pind.7 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "-"
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + "-"
Waitms 300
End If

If Pina.6 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "x"
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + "x"
Waitms 300
End If

If Pina.7 = 0 Then

Cursor Off
Locate Positionzeile , Positionspalte
Lcd "/"
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + "/"
Waitms 300
End If


If Pinc.6 = 0 Then
Cls
Cursor Off
Positionspalte = 1
Positionzeile = 1
Waitms 300
End If

If Pinc.7 = 0 Then
Portc.0 = 1
Wait 7
Portc.0 = 0
Wait 4
End If

If Pinc.5 = 0 Then
Rechnung$ = Rechnung$ + "="
Waitms 300
Lcd Ergebnis
End If


For Stelle = 1 To Len(rechnung$)
If Mid(rechnung$ , Stelle , 1) = "+" Then
Ergebnis = Val(mid(rechnung$ , 1 , Stelle)) + Val(mid(rechnung$ , Stelle + 1 , Len(rechnung$)))
End If
Next Stelle



Loop







Kann man den Code noch irgendwie ändern dass ich wenigstens die vier Grundrechenarten in Bascom schaffe zu flashen ?

Mfg

David

Thomas$
10.06.2009, 18:18
config port b zeugs komt bei dir doch doppelt vor? hat das einen tieferen grund?

mare_crisium
10.06.2009, 18:26
@Thomas$,

Dein Verfahren ist nicht umständlich - nur aufwendig ;-). Man braucht dazu einen Formel-Interpreter, der aus dem String eine Datenstruktur macht. So wie hier vorgeführt:

http://www.delphipraxis.net/topic156836,0,asc,0.html

Dein Vorschlag belohnt den viel höheren Programmieraufwand mit dem Vorteil, auch kompliziertere Ausdrücke, auch mit Klammern usw., berechnen zu können.

@Dave,

für den Anfang würde ich nicht den aufwendigen Weg gehen, sondern einen ganz einfachen Rechner simulieren. Welche Tasten, hast Du Dir vorgestellt, soll das Teil haben?

Ciao,

mare_crisium

DaveWagner
10.06.2009, 18:34
Hallo mare_crisium

Mir würde es schon reichen wenn ich die Zahlen von 0 bis 9 eingeben könnte.
Es wäre nicht schlecht wenn das ganze auch mit Kommazahlen und nicht nur ganzzahligen Zahlen funktionieren würde.
Bei den Rechenoperationen wäre plus,minus,geteilt,mal und wurzel nicht schlecht.

@Thomas
Ich denke ich habe die Portbs nur einmal konfiguriert.

Mfg

David

Thomas$
10.06.2009, 21:00
sorry hab mich irgendwie getäuscht

Furtion
10.06.2009, 21:59
Hi,

ich hatte so ein ähnliches Projekt auch mal am Laufen und bin dort zu dem
Ergebniss gekommen, dass das Programm mit größeren Zahlen einfach
nicht umgehen kann/ ungenau wurde und viel zu viel Speicher verbraucht.
Ich meine auch, dass es iwie ein kleines Problem mit dieser E^-6
Darstellung gab. Ich bin mir deshalb nicht ganz sicher ob es so sinnvoll ist
den Taschenrechner in Bascom zu programmieren.

mare_crisium
11.06.2009, 07:39
Dave,

wenn ich so meinen Taschenrechner und Deine Vorstellungen angucke, dann brauchst Du folgende Tasten:
10 Stck für die Ziffern 0 bis 9,
1 für das Komma,
4 für die Rechenoperationen (Wurzel lassen wir erstmal weg),
1 für den Vorzeichenwechsel ("+/-")
1 für Reset /Clear ("C", löscht alles),
1 für Clear Eingabe ("CE", löscht nur die Eingabe) und
1 für "Lösche letztes Zeichen" ("CL" löscht nur das zuletzt eingebene Zeichen).
macht insgesamt 19. Es ist wichtig, das vorher festzulegen, weil es die Bedienung des Teils festlegt. Du wirst bald merken: Die Bedienerführung verursacht nachher im Programm mehr als doppelt soviel Aufwand, wie das eigentliche Rechnen.

Weil die Rechenoperationen (bis auf den Vorzeichenwechsel) immer zwei Zahlen mit einander verknüpfen, brauchst Du dafür zwei Speicher. Es ist praktisch, es so wie Du zu machen, und die beiden Zahlen als Strings zu speichern. Daneben brauchst Du auch einen Speicher für die Rechenoperation und einen Kommazähler. Die Rechenoperation kannst Du als ASCII-Zeichen oder als Nummer (0 = "+", 1 = "-" usw.) speichern. Der Kommazähler braucht nur von 0 bis 1 zu gehen. Er wird gebraucht, um zu merken, wenn der Bediener mehr als ein Komma pro Zahl eingeben will.

Wie man einen Zahlen-String in eine real-Variable umwandelt, habe ich in der angehängten .pdf-Datei aufgeschrieben. Wie immer: Es geht auch anders, aber damit kannst Du mal anfangen. Es ist praktisch, diesen Teil in eine Subroutine zu verpacken.

Wenn das Umwandeln klappt, musst Du Dich als nächstes um die Bedienerführung kümmern. Dabei geht's darum, auf jeden möglichen Tastendruck des Bedieners eine passende Reaktion einzubauen.

@Furtion,

gerade an der sauberen Programmierung der Benutzerführung beim Taschenrechner kann man viel über Ablaufsteuerungen lernen. Vor allem, dass man auf alles eine Reaktion vorgesehen haben muss, weil man das Verhalten eines Bedieners nie voraussehen kann. Insofern ist es doch nützlich, den Milliarden Taschenrechnern noch einen dazuzufügen :-).

Ciao,

mare_crisium

mare_crisium
12.06.2009, 23:07
Dave,

wenn ich mir Deine Code so angucke, kann ich mir vorstellen, mit welchem Enthusiasmus Du Dich ans Programmieren gemacht hast. Darunter hat die Systematik etwas gelitten ;-) . Zuerst ist das nicht weiter schlimm, aber es wird später lästig, wenn's ans Fehlersuchen geht.

Deshalb habe ich 'mal aufgeschrieben, was man sich, bevor man zu Programmieren beginnt, zur Struktur des Programms so ausdenken kann, damit es schön übersichtlich und entwicklungsfähig wird.

Wenn Du damit was anfangen kannst, können wir's ja noch weiter verfeinern.

Ciao,

mare_crisium

Edit: Das pdf-Dokument noch mal neu erzeugt und dabei die Grafik des Programmablaufs entwirrt.

Edit: Anhang gelöscht wg. Upload-Limit.

for_ro
16.06.2009, 19:31
Ich fand die Idee ganz witzig und habe mal Davids Programm etwas erweitert.
Funktionsumfang sollte ungefähr so sein wie von mare_crisium im PDF beschrieben.

Const Ok = 1
Const Not_ok = 0
Const Yes = 1
Const No = 0
Const Op = 2
Const Minus = 3

$regfile = "m16def.dat"
$crystal = 16000000
Const Print_ausgabe = No 'hier Yes/No um die Prints zu aktivieren
Const Use_double = No 'hier Yes/No um mit Double/Single zu rechnen
Const Enable_power = No 'hier Yes/No um den Power-Operator zu aktivieren
'Power und Double funktioniert nicht richtig, keine Ahnung warum
#if Print_ausgabe = Yes
$baud = 38400
#endif

$hwstack = 32
$swstack = 32
$framesize = 64

Config Lcd = 20 * 4
Config Lcdpin = Pin , Db4 = Porta.3 , Db5 = Porta.2 , Db6 = Porta.1 , Db7 = Porta.0 , E = Porta.5 , Rs = Porta.4 ', Rw = Portc. 5

Dim Positionzeile As Byte
Dim Positionspalte As Byte

#if Use_double = Yes
Dim Ergebnis As Double , Operand1 As Double , Operand2 As Double 'auskommentieren um nur Single zu rechnen
#else
Dim Ergebnis As Single , Operand1 As Single , Operand2 As Single 'auskommentieren, um Double zu rechnen
#endif

Dim Prta As Byte , Prtb As Byte , Prtd As Byte , Prtc As Byte 'die Masken der Ports, 1=wird verwendet, 0=wird nicht verwendet
Dim Port_masken As Long At Prta Overlay 'Long liegt über allen 4 Masken
Dim Alte_taste As Long

Dim Tastea As Byte , Tasteb As Byte , Tasted As Byte , Tastec As Byte 'Reihenfolge nicht ändern, sonst passt das Overlay nicht mehr
Dim Taste As Long At Tastea Overlay 'Long liegt über allen 4 Tasten-Ports

Dim Taste_string As String * 32 'definiert, welche Funktion auf welchem Pin liegt
Dim Taste_array(1) As Byte At Taste_string Overlay 'darüber ein Byte Array, damit man leichter eine Schleife drüber machen kann
Dim Taste_index As Byte

Dim Operator As String * 1 'das gefundene Operator Zeichen
Dim Operator_pos As Byte 'Position des Operators in Rechnung$
Dim Rechnung$ As String * 33 'die gesamte Eingabe
Dim String_length As Byte 'die Länge von Rechnung$
Dim Operand$(2) As String * 16 'die beiden Operanden
Dim Check As Byte 'gültige Eingabe
Dim Found As Byte 'alle Flags
Operation Alias 0 'es wurde schon ein Operator eingegeben
Comma_op1 Alias 1 'Komma in Operator 1 gefunden
Comma_op2 Alias 2 'Komma in Operator 2 gefunden
Minus_op1 Alias 3 'Operand 1 ist negativ
Minus_op2 Alias 4 'Operand 2 ist negativ

Prta = &B11000000
Prtb = &B00011111
Prtc = &B11110111
Prtd = &B10111100
Porta = Prta
Portb = Prtb
Portc = Prtc
Portd = Prtd
Initlcd
Cls
Cursor Off
Locate 2 , 1
Lcd "Taschenrechner"
Positionzeile = 1
Positionspalte = 1
' 123456789 123456789 123456789 12 Position in Taste_string = Taste_index
' AAAAAAAABBBBBBBBDDDDDDDDCCCCCCCC Dies ist meine Tastenbelegung
' 01234567012345670123456701234567 geringfügig anders als die ursprüngliche
#if Enable_power = Yes
Taste_string = " */01234 789+ -56^ .=CD" 'C=Clear all, D=Delete ein Zeichen
Prtc = &B11110111 ' 11101111
#else
Taste_string = " */01234 789+ -56 .=CD" 'C=Clear all, D=Delete ein Zeichen
Prtc = &B11110111 ' 11001111
#endif
Prtd = &B10111100 ' 00111101
Prtb = &B00011111 ' 11111000
Prta = &B11000000 '00000011

'weiteres Zeichen hinzufügen:
' 123456789 123456789 123456789 12
'Taste_string = " */01234 789+ -56^ .=CD" neues Zeichen an eine Leerstelle setzen
'Prtc = &B11110111 ' 11001111 im zugehörigen Port eine 1 setzen
'Prtd = &B10111100 ' 00111101
'Prtb = &B00011111 ' 11111000
'Prta = &B11000000 '00000011
'im Select case taste_index für die Position im String ein case schreiben

Porta = Prta 'setzen der PullUps
Portb = Prtb 's.o.
Portc = Prtc 's.o.
Portd = Prtd 's.o.
String_length = 0
Do
Tastea = Pina And Prta
Tasteb = Pinb And Prtb
Tastec = Pinc And Prtc ' c d b a
Tasted = Pind And Prtd '11110100 10111110 00011111 11000000
If Taste <> Port_masken Then
If Taste <> Alte_taste Then
Alte_taste = Taste
Taste_index = 0
Check = Not_ok
If Rechnung$ = "" Then Lcd Spc(20)
Do
If Port_masken.taste_index = 1 Then
If Taste.taste_index = 0 Then
Incr Taste_index
Select Case Taste_index
Case 9 To 13 : '01234 die Zahlen
Check = Ok
Case 19 To 21 : '789
Check = Ok
Case 25 To 26 : '56
Check = Ok
#if Enable_power = Yes
Case 7 To 8 Or Taste_index = 22 Or Taste_index = 27: '*****/////+++++^^^^^
#else
Case 7 To 8 Or Taste_index = 22: '*****/////+++++
#endif
If Found.operation = No Then 'die Operatoren, außer '-' wegen Vorzeichen-Sonderbehandlung
Check = Op
Found.operation = Yes
Operator_pos = String_length + 1
Operator = Chr(taste_array(taste_index))
End If
Case 29 : '.....
If Found.operation = No Then 'wenn noch kein Operator eingegeben wurde, ist das Komma im 1. Operanden
If Found.comma_op1 = No Then
Check = Ok
Found.comma_op1 = Yes
End If
Else
If Found.comma_op2 = No Then 'ansonsten im 2. Operanden
Check = Ok
Found.comma_op2 = Yes
End If
End If
Case 24: '-----
If String_length = 0 Then 'Fortsetzung der Berechnung mit letztem Ergebnis als Operand 1
If Found.operation = No Then 'dann muss der Operator als erstes Zeichen kommen, also kein Vorzeichen
Check = Op
Found.operation = Yes
Operator_pos = String_length + 1
Operator = "-"
End If
Elseif Found.operation = Yes Then 'wenn schon ein Operator eingegeben wurde, ist das '-' ein Vorzeichen des 2. Operanden
Found.minus_op2 = Yes
Check = Minus
Else
Found.minus_op1 = Yes 'dann muss das Vorzeichen des 1. Operanden sein
Check = Minus
End If
Case 32: 'D = Delete: ein zeichen löschen
Positionspalte = Positionspalte - 1
Locate Positionzeile , Positionspalte : Lcd " "
If Right(rechnung$ , 1) = "." Then
If Found.operation = Yes Then
Found.comma_op2 = No
Else
Found.comma_op1 = No
End If
Elseif Operator_pos = String_length Then
Found.operation = No
End If
Decr String_length
Rechnung$ = Left(rechnung$ , String_length)
Check = Not_ok
Case 31: 'C = Clear: alles löschen
Cls 'alles zurücksetzen
Positionspalte = 1
Positionzeile = 1
Rechnung$ = ""
Found = 0
Operator_pos = 0
Check = Not_ok
String_length = 0
Case 30: '=====
If Operator_pos > 1 Then
Decr Operator_pos 'Operand 1 endet links vom Operator
Operand$(1) = Left(rechnung$ , Operator_pos)
Operand1 = Val(operand$(1))
Operator_pos = Operator_pos + 1 'Operand 2 beginnt rechts vom Operator
Else 'Fortsetzung einer Berechnung
Operand1 = Ergebnis
Operand$(1) = Str(operand1)
Incr Operator_pos
End If
Operator_pos = String_length - Operator_pos
Operand$(2) = Right(rechnung$ , Operator_pos)
#if Print_ausgabe = Yes
Print Operand$(1) ; Operand$(2)
#endif
Operand2 = Val(operand$(2))
Select Case Operator
Case "+" : Ergebnis = Operand1 + Operand2
Case "-" : Ergebnis = Operand1 - Operand2
Case "*" : Ergebnis = Operand1 * Operand2
Case "/" : Ergebnis = Operand1 / Operand2
#if Enable_power = Yes
Case "^" : Ergebnis = Power(operand1 , Operand2)
#endif
End Select
Locate 2 , 1 : Lcd Spc(20)
Locate 2 , 1 : Lcd Ergebnis : Locate 1 , 1
#if Print_ausgabe = Yes
Print "ergebnis=" ; Ergebnis
#endif
Ergebnis = Operand1 ^ Operand2
Locate 2 , 20 : Lcd Ergebnis : Locate 1 , 1
Print "ergebnis=" ; Ergebnis
Positionspalte = 1 'alles zurücksetzen, nur Ergebnis bleibt auf dem alten Wert
Positionzeile = 1
Rechnung$ = ""
Found = 0 'alle Flags auf 0
Operator_pos = 0
Check = Not_ok
String_length = 0
End Select
If Check <> Not_ok Then 'wenn die Eingabe erlaubt war, wird das Zeichen ausgegeben und an Rechnung$ angehangen
Locate Positionzeile , Positionspalte ' Zahl 0 schreiben
Lcd Chr(taste_array(taste_index))
Positionspalte = Positionspalte + 1
Rechnung$ = Rechnung$ + Chr(taste_array(taste_index))
Incr String_length
#if Print_ausgabe = Yes
Print "Rechnung=" ; Rechnung$
#endif
End If
Exit Do
Decr Taste_index
End If
End If
Incr Taste_index
Loop Until Taste_index = 32
Waitms 200 'zum Tasten entprellen
End If
Else
Alte_taste = Port_masken 'wenn keine taste mehr gedrückt ist (dann ist Taste = Port_Masken) wird Alte_Taste auch zurückgesetzt
End If
Loop
End

Es können beim Compilieren über die Schalter
Const Print_ausgabe = No 'hier Yes/No um die Prints zu aktivieren
Const Use_double = No 'hier Yes/No um mit Double/Single zu rechnen
Const Enable_power = No 'hier Yes/No um den Power-Operator zu aktivieren
verschiedene zusätzliche Funktionen aktiviert werden.
Wenn alles auf No steht, compiliert er bei mir knapp unter 4KB, sollte also auch in der Demo laufen.
Mit allem auf Yes braucht es schon 8KB.
Vielleicht schaut es sich mal einer an.

Gruß

Rolf

DaveWagner
18.06.2009, 18:44
Hallo

Ich bin sehr dankbar für eure Antworten vor allem die von mare_crisium sind sehr hilfreich.
Leider werde ich in nächste Zeit eher weniger Zeit finden um das Projekt weiterzuführen.
Also werde ich mich erst ein bisschen später wieder melden.

Mfg

David

mare_crisium
19.06.2009, 13:18
@Fo-ro,

das mit den Overlays hast Du wirklich raffiniert und elegant ausgedacht :-) . Auf sowas kommt man nicht so leicht!

Als Anregung zur Verbesserung:

Die Tastenauswertung ist vllt. besser in einer separaten Subroutine untergebracht; falls jemand mal eine Tastatur mit gemultiplexter Abfrage anschliessen will. Kann natürlich sein, dass das Programm dann nicht mehr in die 4kB passt.

Durch die Schachtelung von "If Port_masken.taste_index = 1 Then..." und der "Select Case Taste_index"-Anweisung, entsteht eine implizite Verknüpfung zwischen den Werten von "Taste_index" und den Stellen von "Port_masken", die auf 1 gesetzt sind. Wenn jemand die Einsen in "Port_masken" verschiebt (z.B. weil er eine andere Portbelegung braucht), darf er nicht vergessen, die Wertebereiche von "Taste_index" für die einzelnen cases zu ändern. Wenn man das übersieht, speziell wenn man länger nicht mehr an dem Programm gearbeitet hat, ist das ein schwer zu findender Fehler.

Es kann vorkommen, dass der erste Operand eine ganze Zahl ist, der zweite eine reelle. Bei Deiner jetzigen Kommabehandlung findet das Programm, wenn das Komma des Operand2 eingegeben wird, die Variable "Found.comma_op1" auf NO und nimmt dann an, das Komma gehöre zu Operand1.

Das ist nicht als Herummäkeln gemeint, dafür ist Deine Idee mit den Overlays viel zu gut!

@David,

gut Ding will Weile haben ;-). Meld' Dich einfach, wenn's weitergehen soll.

Ciao,

mare_crisium

for_ro
19.06.2009, 15:39
Durch die Schachtelung von "If Port_masken.taste_index = 1 Then..." und der "Select Case Taste_index"-Anweisung, entsteht eine implizite Verknüpfung zwischen den Werten von "Taste_index" und den Stellen von "Port_masken", die auf 1 gesetzt sind. Wenn jemand die Einsen in "Port_masken" verschiebt (z.B. weil er eine andere Portbelegung braucht), darf er nicht vergessen, die Wertebereiche von "Taste_index" für die einzelnen cases zu ändern. Wenn man das übersieht, speziell wenn man länger nicht mehr an dem Programm gearbeitet hat, ist das ein schwer zu findender Fehler.
Ich hatte schon mal ausprobiert, anstelle von Taste_index in taste_string die Position z.B. des "+"-Zeichens zu finden. Aber selbst mit Bytes-Werten suchen habe ich es nicht geschafft, dies noch in den 4KB unterzubringen.


Es kann vorkommen, dass der erste Operand eine ganze Zahl ist, der zweite eine reelle. Bei Deiner jetzigen Kommabehandlung findet das Programm, wenn das Komma des Operand2 eingegeben wird, die Variable "Found.comma_op1" auf NO und nimmt dann an, das Komma gehöre zu Operand1.
Hast du das mal ausprobiert oder nur durch Code Analyse gefunden? Ich dachte nämlich, dass ich dies durch die Abfrage nach dem gefundenen Operator ausgeschlossen habe. Wenn der noch nicht da ist, handelt es sich um Operator 1, ansonsten Operator 2. Bin mir aber nicht sicher, ob ich mal probiert habe, im zweiten mehrere Kommas einzugeben, wenn im ersten Operator keines drin vorkommt.

mare_crisium
21.06.2009, 19:09
for-ro,

bei der Auswertung der Komma-Taste hatte ich die vorausgehende Abfrage von "Found.operation" übersehen :-( . Du hast recht: Das Komma wird richtig zugeordnet.

Ciao,

mare_crisium