Forum: Mikrocontroller und Digitale Elektronik String vergleichen


von Marcus (Gast)


Lesenswert?

Hallo Leute,

ich habe ein Programm für einen Mega8 in Assembler geschrieben, das mir
zyklisch den Akku-Ladezustand eines Handys abfragt. Ist der Akku unter
40%, dann wird er geladen bis er voll ist.

Ich habe das so gelöst:

ldi  ZL, LOW(cbc100)    ; Startadresse im EEPROM für den
ldi  ZH, HIGH(cbc100)  ; Vergleich laden

rcall  Num_Check    ; Vergleichsroutine aufrufen

sbrc  FlagReg, Match    ; wenn AKKU voll geladen
rjmp  ladung_aus    ; Sprung nach Ladung_aus

ldi  ZL, LOW(cbc90)    ; Startadresse im EEPROM für den
ldi  ZH, HIGH(cbc90)    ; Vergleich laden

rcall  Num_Check    ; Vergleichsroutine aufrufen

sbrc  FlagReg, Match    ; wemm AKKU zu 90% geladen
rjmp  ladung_aus    ; Sprung nach Ladung_aus

......

Immer Text aus dem EEPROM laden, vergleichen, Flag auswerten (Match
wird bei Gleichheit SRAM und EEPROM gesetzt) und springen.

Das mach ich solange bis ich alle möglichen Meldungen vom Handy
abgeklappert hab. Ab 40% springe ich dann nach "ladung_ein".

Erscheint mir etwas uneffektiv. Gibts da noch eine elegantere
Möglichkeit?

Für Vorschläge bin ich dankbar.


Gruß Marcus

von Karl H. (kbuchegg)


Lesenswert?

> Erscheint mir etwas uneffektiv

> Das mach ich solange bis ich alle möglichen Meldungen

Das Problem ist aber, dass dein Program a priori weiss,
wiviele das sind. Besser wäre es, wenn du diese Anzahl
auch noch ins EEPROM legst und über die Vergleiche noch
eine Schleife legst, die auf dieser Anzahl basiert.


  NrWerte = vom EEProm lesen

  for i = 0 to NrWerte - 1 do
    Grenzwert = i-ten Vergleichswert vom EEprom holen
    vergleichen und gegebenenfalls springen
  next

von Marcus (Gast)


Lesenswert?

Ich hab 10 mögliche Werte im EEPROM stehen: 1,90 ; 0,90 ; 0,80 ; .... ;
0,10
Hab ich dich richtig verstanden das ich in einer Schleife, in meinem
Fall  10 mal, die Daten vom EEPROM hole und vergleiche? Ist die 10 (bzw
9) voll, gehts im Programm normal weiter. Da muß ich die Anzahl ja nicht
im EEPROM ablegen, kann ich ja gleich mit LDI den entsprechenden Wert in
ein Register laden, dieses mit INC erhöhen und mit CPI vergleichen?

Das würde mir zumindest mal Schreibarbeit ersparen und evtl. die
Lesbarkeit vom Code verbessern, vom Rechenaufwand für den µC ist es
aber kein Unterschied. Mich stört halt das da der AVR recht lange in
der Schleife hängt, wobei das für meine Anwendung sicherlich keine
Rolle spielt.

Gruß Marcus

von Karl H. (kbuchegg)


Lesenswert?

> Da muß ich die Anzahl ja nicht im EEPROM ablegen, kann ich ja
> gleich mit LDI den entsprechenden Wert in ein Register laden

Genau das würde ich nicht tun. Bei einer Änderung musst
du dann an 2 Stellen ändern: im Programm und in der Datentabelle.

> Mich stört halt das da der AVR recht lange in
> der Schleife hängt, wobei das für meine Anwendung sicherlich keine
> Rolle spielt.

Der Löwenanteil der Zeit wird wohl für das Lesen aus dem
EEprom draufgehen. Die 10 Schleifeniterationen hat der µC in
ein paar µSek durch. Also: Bei Programmstart die Daten aus dem
EEprom ins RAM umkopieren und von dort weg arbeiten.

Stell dir mal eine andere Frage: musst du die Tabelle eigentlich
abgrasen, oder kannst du dir nicht einfach ausrechnen, welcher
Tabelleneintrag der richtige ist. So wie ich das sehe hat
deine Tabelle lauter 10-er Abstufungen. d.h. wenn du deine
Prozentzahl durch 10 dividierst, hast du die Nummer des zuständigen
Eintrags. Ich werde allerdings aus deiner ganzen Beschreibung nicht
ganz schlau, was du eigentlich machen willst. Daher schlag ich
das jetzt einfach mal so vor, ohne zu wissen ob dich das wohin
führt.
(Anstatt 10 Einträge würde ich aber dann 8 oder 16 nehmen. Die
Division wird dann einfacher).

von Marcus (Gast)


Lesenswert?

Die Sache mit dem Tabelleneintrag ausrechnen hört sich doch recht gut
an. Hab nur leider keine Ahnung wie ich das bewerkstelligen soll.
Kannst du mir hierzu einen Denkanstoss geben?

Das Programm das ich geschrieben hab funktioniert, so wie es ist,
tadellos. Mich stört halt nur die Art wie ich es gelöst habe.

von Karl heinz B. (kbucheg)


Lesenswert?

Wie gesagt: Ich bin mir nicht sicher überhaupt zu verstehen,
was du da überhaupt machst.

Ich denke (und rate) mal:

* Du holst dir vom Handy einen String.
* In diesem String ist die Prozentzahl in irgendeiner Form
  codiert.
* Du weist wie die Strings aussehen muessen, und hast alle
  vom Handy benutzten Strings im EEprom abgelegt.

* Die Aufgabe ist es jetzt aus dem String abzuleiten ob du
  die Ladung anstossen musst oder nicht.

Nein. Ich verstehs immer noch nicht. Warum musst du alle
möglichen Strings abklappern um zu entscheiden ob du jetzt
laden musst oder nicht.
Die Prozentzahl wird doch an immer der gleichen Stelle im String
stehen. Wenn du dir von dort den Teilstring mit der Zahl
rausholst und in eine Zahl umwandelst, dann musst du doch
nur noch vergleichen ob diese Zahl grösser als 40 ist oder
nicht.

Oder versteh ich da was grundsätzlich falsch.

von Marcus (Gast)


Lesenswert?

Liegst mit deiner Vermutung absolut richtig:

die Schaltung macht nichts anderes als auf einen Anruf warten. Bei
einem Anruf wird die Rufnummer mit einer zuvor gespeicherten verglichen
und bei Gleichheit ein Ausgang geschaltet. Alle 60 Sekunden schicke ich
über den UART den Befehl at+cbc zum Handy und frage damit den
Ladezustand ab. Als Antwort erhalte ich vom Handy mehrere Linefeeds und
Zeilenumbrüche gefolgt von +cbc= 0,xx und wieder einigen Linefeeds und
Zeilenumbrüchen. Wobei xx für den Ladezustand steht. Wenn Zeichen auf
dem UART empfangen werden, speichere ich diese ab dem Leerzeichen im
SRAM ab, bis ich ein Linefeed erhalte. Danach vergleiche ich den String
im SRAM mit dem im EEPROM.
Da ich die berechtigte Rufnummer mit einem Jumper und einem Anruf
programmiere, ist es nötig ab dem Leerzeichen zu speichern.

Ich denke, das es die beste Lösung ist, wenn ich den hinteren Teil des
Strings auswerte. Vorne ist es eigentlich immer gleich, ausser wenn
geladen wird, dann steht eine 1,xx. Mir ist nur noch nicht ganz klar
wie ich aus dem eingelesenen String einen Teil rausfischen kann.
Darüber werde ich mir Morgen Gedanken machen. Hab heute keinen Kopf
mehr dazu.

Dir vielen Dank für die Denkanstösse und die Mühe.

von Karl H. (kbuchegg)


Lesenswert?

Ist doch einfach:
Du hast den String.
Dann gehst du den Zeichen für Zeichen durch, bis ein ','
auftaucht. Jetzt weist du das danach die dich interessierende
Zahl kommt. Die Zahl ist abgeschlossen mit einem LineFeed.
Jetzt setzt du die Zahl aus den einzelnen Zeichen zusammen:

In PseudoCode:

   Zahl = 0
   while( ZifferCharacter ungleich LineFeed )
     Zahl = Zahl * 10 + ( ZifferCharacter - '0' )
     ZifferCharacter auf das nächste Zeichen im String

Angenommen der Ziffern-String lautet "56" + LineFeed

  Zahl startet mit 0
  ZifferCharacter ist '5', also unglich LineFeed
  -> ein Durchlauf durch die while Schleife
  ZifferCharacter, also '5' minus '0' (also die
  ASCII Codes voneinander abziehen) ergibt 5.
  Zahl, also 0, mal 10 ergibt wieder 0 plus die 5 macht 5

  while Schleife wieder von vorne beginnen:
  ZifferCharcter ist um ein Zeichen weiter nach rechts gegangen
  und ist jetzt 6. 6 ist nicht gleich LineFeed, also noch
  ein Durchgang durch die Schleife:
  wieder: von '6' die '0' abziehen. Ergibt 6
  Zahl, also 5, mal 10 ergibt 50 plus die 6 macht 56.

  Das nächste Zeichen ist ein LineFeed, damit ist die Bedingung
  für die while-Schleife nicht mehr erfüllt, sie wird nicht
  mehr ausgeführt und Zahl enthält das Ergebnis: 56
  Aber diesmal als echte Zahl und nicht als String.

Eine Multiplikation mit 10 ist einfach zu machen:
  2 mal nach links schieben                  = * 4
  die Originalzahl noch mal dazuaddieren     = * 5
  und nachmal nach links schieben            = * 10

  Bsp:   dezimal 4     binär  00000010

    einmal schieben           00000100
    zweites mal schieben      00001000
    die 4 addieren            00001010
    und nochmal schieben      00010100

    binär 0010100 ist dezimal ( 8 + 32 ) also 40

von Marcus (Gast)


Lesenswert?

Ich seh schon, da gibts für mich noch einiges zu lernen.

Meine jetzige Lösung von heute Vormittag sieht so aus:

im SRAM steht nach der Abfrage " 0,x0" gefolgt von LineFeed. Da sich
nur die erste Stelle nach dem Komma ändert, speichere ich diese mit dem
Befehl STS und direkter Adressierung (Speicheradresse +3) in ein
Register und ziehe anschliessend $30 ab um den ASCII zu wandeln. Jetzt
vergleiche ich ob >= 4 und entscheide dann, ob ich laden muß oder
nicht.

Ich seh grad das ich mir die 30 abziehen eingentlich sparen kann und
gleich auf >= $34 vegleichen kann.

von Karl H. (kbuchegg)


Lesenswert?

Geht auch.

Du hast halt 2 Annahmen getroffen:
* Das dich interessierende Zeichen steht immer an Position 3
* Dein Schwellwert ist immer eine 'Zehner-Zahl'. In deinem
  Fall halt 40

Wenn du mit diesen beiden Annahmen leben kannst, dann lass es
so. Annahme 1 ist dabei der dicke Hund, denn du kannst das
Format nicht beeinflussen sondern das wird dir vom Handyhersteller
aufgedrückt. Zumindest den Teil würde ich durch eine aktive
Suche nach dem vorhergehenden ',' ersetzen. So eine Schleife
die dir das Zeichen sucht, ist doch kein Problem:
1) Startadresse ins X-Register.
2) Zeichen über das X-Register holen.
3) War es ','?
    Wenn nein: X Register erhöhen und weiter bei 2
4) X-Register nochmal erhöhen, um an das Zeichen nach dem ','
   zu kommen
5) Zeichen über das X-Register holen.
6) Mit $34 vergleichen
7) kleiner?
   Wenn ja: Ladung einleiten

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.