Forum: Mikrocontroller und Digitale Elektronik PIC Assembler - 8bit mit 10 LEDs ausgeben (als Prozent)


von Mario G. (rodenberger)


Lesenswert?

Hallo,

mir fällt gerade kein günstiger Lösungsweg zu folgendem Problem ein.

Ich möchte einfach einen 8bit-Wert (0 -255) mit 10 LEDs als 
Prozentanzeige ausgeben.
Also mal grob
0 alles aus
1 bis 25 eine LED an
26 bis 50 zwei LEDs an
....
255 alle 10 LEDs an

Mir fehlt im Moment ein kurzer Lösungsweg.
Mein Gedanke ist:
Den Wert in 10 Schleifen (!?) um jeweis 25 zu reduzieren, ist 0 noch 
nicht erreicht wird eine LED (PortPin) eingeschaltet.
Sprung dann zur nächsten Schleife usw.

Nachteil ist, das ich vorher ALLE LEDs löschen muss.

Habt Ihr einen günstigeren Vorschlag?
Der PIC hat natürlich noch mehr zu tun, deshalb soll das UP nicht so 
lang werden.
Wenn es die Arbeit erheblich erleichtert, reduziere ich auch auf 8 LEDs, 
dann könnte ich es auch mit einer Datentabelle machen, aber ist das 
Sinnvoll 255 Datensätze einzugeben?

Vielen Dank für Eure Hinweise!
Gruß Mario

von avr (Gast)


Lesenswert?

Das mit der Schleife ist schon der richtige Ansatz, die
Reihenfolge würde ich ändern.

Wert=Wert+1  Carry in LED10  bei 255

Wert=Wert+25  Carry in LED9  230
Wert=Wert+25  Carry in LED8
..
Wert=Wert+25  Carry in LED1

Wert=Wert+25  Carry in LED0


Geht aber nicht ganz auf. 10*25 < 255 daher mal 25 mal 26 damit
am Ende bei 1 auch LED1 brennt.

avr

von Mario G. (rodenberger)


Lesenswert?

Hallo AVR,
gut, dann versuche ich es mal so.
Danke!

Gruß Mario

von Vlad T. (vlad_tepesch)


Lesenswert?

gib doch das ergebnis einfach binär aus :-)
wenn du nur Prozent willst, reichen sogar 7 Leds

von Sven S. (stepp64) Benutzerseite


Lesenswert?

Wenn du 255 Flashworte übrig hast, würde ich dass über eine Tabelle 
machen. Aus dem Flash kommen ja 14 Bits zurück. Damit benötigst du für 
jeden der 8-Bit Werte nur ein Flash-Wort um die 10 LEDs anzusteuern. 
Nebenbei bist du bei diesem Ansatz auch variabel was die Prozente 
angeht. Du änderst halt nur die Tabelle, wenn du eine andere Aufteilung 
haben willst.

Gruß
Sven

von Karl H. (kbuchegg)


Lesenswert?

Es geht allerdings auch mit einer 'Vergleichsorgie'. Die 10 Vergleiche 
laufen so schnell ab, dass es gar nicht so einfach sein dürfte, dass mit 
Rechnerei zu schlagen


  if( Wert > 0 )
    LED0 einschalten

  if( Wert > 25 )
    LED1 einschalten

  if( Wert > 50 )
    LED2 einschalten

  etc.

und 10 Vergleiche wären für mich noch tragbar, um da mit der Brute-Force 
Holzhammermethode draufzuschlagen.

von Peter D. (peda)


Lesenswert?

Ich grübele auch schon, was das mit den 10 Schleifen sollte und warum 
nicht 10 Vergleiche genommen werden.

Auch, warum da Angst besteht, es könnte den PIC ausbremsen. Dazu müßte 
man ihn schon auf 100Hz CPU-Takt runtersetzen.

Das mit der Tabelle ist völliger Overkill.


Peter

von Mario G. (rodenberger)


Lesenswert?

Hallo,
na dann diskutieren wir das mal weiter.

Zu Sven: Für meine derzeitige Verwendung ist eine Tabelle unangemessen.
Als Overkill (wie Peter schreibt) möchte ich es aber nicht bezeichnen, 
denn das dürfte die rechnerisch schnellste Lösung sein. Also da wo es 
nötig ist.

Zu Peter: Der Begriff "Schleife" war von mir falsch gewählt.
Der Gedanke war schon so wie es "AVR" geschrieben hat, nur eben anders 
rum.

Zu Karl Heinz:
Ja, das sieht auf den ersten Blick sehr logisch aus, dann schreibe aber 
mal
  if( Wert > 25 )  LED1 einschalten
in Assembler (Pic 16F870)

Gruß Mario

von Klaus W. (mfgkw)


Lesenswert?

... oder die 8 Bit einfach ausgeben, und ein GAL macht daraus die
10 LED-Signale.
Rechenzeit: ca. 0, und spart 2 Beinchen.
Nötig wäre ein 22V10 oder 2 16V8.

von Sven S. (stepp64) Benutzerseite


Lesenswert?

In Assembler (PIC16F) sind es halt so 4-5 Zeilen pro Abfrage. Du musst 
ja nur die Werte subtrahieren, und dann das Carryflag testen. Damit 
bekommst du eine größer/gleich Funktionalität hin. Sind dann halt bei 10 
Wertebereichen so ca. 50-70 Zeilen Code. Sollte aber eigentlich mit das 
schnellste sein, da das Lesen von Daten aus dem Flash auch Zeit kostet 
und relativ umständlich ist (ich meine jetzt nicht die retlw Methode, 
sondern das Lesen von Daten aus dem Flash-Speicher)

Mit so einer Tabelle wird es halt übersichtlicher auf Kosten des 
Speicherplatzes.

Gruß
Sven

von Peter D. (peda)


Lesenswert?

Mario G. schrieb:
> Ja, das sieht auf den ersten Blick sehr logisch aus, dann schreibe aber
> mal
>   if( Wert > 25 )  LED1 einschalten
> in Assembler (Pic 16F870)

Warum must Du Dir aber auch ausgerechnet den schwierigsten Assembler 
aussuchen?

PIC ist die Härte, da muß man sich erstmal nen Haufen Macros schreiben, 
um die wichtigsten Befehle zusammen zu setzen.
Nichtmal nen Compare-Befehl oder nen Jump-if-Carry-Befehl scheint er zu 
haben.

Ich würde Dir raten, programmiere in C oder nimm ne Architektur mit 
leistungsfähigerem Befehlssatz.


Peter

von Karl H. (kbuchegg)


Lesenswert?

Peter Dannegger schrieb:

> Nichtmal nen Compare-Befehl oder nen Jump-if-Carry-Befehl scheint er zu
> haben.

Ehrlich?
Hätte ich nicht gedacht. Compare Immediate und diverse Jump-Flag 
Varianten hätte ich eigentlich so ziemlich jedem µC als Grundausstattung 
zugetraut. Ist ja nicht so, dass Vergleiche in einem Programm die grosse 
Ausnahme sind.

> Ja, das sieht auf den ersten Blick sehr logisch aus, dann schreibe
> aber mal
>  if( Wert > 25 )  LED1 einschalten
> in Assembler (Pic 16F870)

Wenn das schon schwer ist, dann wage ich mir gar nicht auszumalen, 
welche Klimmzüge bei Prozentrechnung notwendig sind :-) Und wie man dann 
aus der Prozentzahl die Anzahl der einzuschaltenden LED bestimmt 
repsektive die dann tatsächlich auch einschaltet.

   Prozent = Wert * 100 / 255
   for( i = 0; i < Prozent / 10; ++i )
     Turn_on_Led( i );

Ein kleiner Schritt für einen C-Programmierer, eine unüberwindliche 
Hürde in Assembler.
Oder so ähnlich

von Meister E. (edson)


Lesenswert?

Mario G. schrieb:
> Ja, das sieht auf den ersten Blick sehr logisch aus, dann schreibe aber
> mal
>   if( Wert > 25 )  LED1 einschalten
> in Assembler (Pic 16F870)

Könnte man so machen:
1
  movf  var, w
2
  call  vergleich
3
  ...
4
5
vergleich
6
  sublw  .25    ;w = #lit8 - wreg
7
8
  btfsc  STATUS, Z
9
          retlw          istGleich
10
11
   btfsc  STATUS, C
12
    retlw          istGroesser
13
  retlw   istKleiner

Die Enumerationen kannst du im Definitionsteil erstellen:

Beispiel:
1
istGleich   EQU 0
2
istGroesser EQU 1
3
istKleiner  EQU 2
4
...

Anmerkung: Nur so aus dem Gedächtnis notiert. Bitte melden wenns nicht 
hinhaut.

Grüße,
Edson

von Mario G. (rodenberger)


Lesenswert?

Hallo, also gelöst ist es ja.

Kann das mal einer in Assembler umwandeln.
   Prozent = Wert * 100 / 255
   for( i = 0; i < Prozent / 10; ++i )
     Turn_on_Led( i );
Wüste gerne als NICHT C-Programmierer wie es dann aussieht.


So habe ich es nun: (sind etwa 50 Zeilen)

1
     MOVLW   D'1'
2
    ADDWF   Wert,1    
3
    BTFSC   STATUS,C ; bei überlauf Sprung, restliche LED dann ON
4
    GOTO L9
5
6
     MOVLW   D'25'
7
    ADDWF   Wert,1    
8
    BTFSC   STATUS,C
9
    GOTO L8    
10
11
.....
12
.....
13
14
     MOVLW   D'25'
15
    ADDWF   Wert,1    
16
    BTFSC   STATUS,C
17
    GOTO L0
18
    GOTO AUS
19
20
L9    BSF PORTB,0
21
L8    BSF PORTB,1
22
L7    BSF PORTB,2
23
L6    BSF PORTB,3
24
L5    BSF PORTB,4
25
L4    BSF PORTB,5
26
L3    BSF PORTB,6
27
L2    BSF PORTB,7
28
L1    BSF PORTC,6
29
L0    BSF PORTC,7
30
AUS

Gruß Mario

von Meister E. (edson)


Lesenswert?

>Hallo, also gelöst ist es ja.

Ok. Um so besser.

>Kann das mal einer in Assembler umwandeln.

Am besten können das C-Compiler ;)

>   Prozent = Wert * 100 / 255
>   for( i = 0; i < Prozent / 10; ++i )
>     Turn_on_Led( i );
>Wüste gerne als NICHT C-Programmierer wie es dann aussieht.

Ernsthaft, ich würde auf diesem PIC nicht die Prozente zur Laufzeit 
berechnen wollen. In deinem Fall erhältst du ja auch keinerlei Vorteil 
daraus, du kannst ohnehin nur 10er Schritte auflösen.

>So habe ich es nun: (sind etwa 50 Zeilen)

Wenns so funktioniert ist es doch in Ordnung.

Grüße,
Edson

von Mario G. (rodenberger)


Lesenswert?

Hallo Edson,
das Programm selber bleibt nun so.

Da ich mich mit C nun gar nicht auskenne, bin ich am überlegen ob ich 
damit auch schnell als Gelegenheitsprogrammierer zurecht kommen würde.
Meine Projekte werden dann auch schnell mal groß, so das ich mit 
Speicher haushalten muss.

Am Anfang hatte ich es mal mit PIC-BASIC probiert.
Da klappte es nicht mal mit der Demo.
Auf der anderen Seite wurden für einfache Aufgaben umgewandelt ein 
haufen Zeilen (Speicher) benötigt, die ich in Assembler nicht annährend 
gebraucht habe.

von Peter D. (peda)


Lesenswert?

Mario G. schrieb:
> So habe ich es nun: (sind etwa 50 Zeilen)

50 Befehle dürfte für nen PIC vollkommen o.k. sein.
Weniger ist wohl kaum möglich.

Beim 8051 mit seinen leistungsfähigeren Befehlen reichen 20 aus:
1
led_bar:
2
        cjne    a, #1, _lb1
3
_lb1:   mov     p0.0, c                 ;  1 .. 255: p0.0 = 0 (on)
4
        cjne    a, #26, _lb2
5
_lb2:   mov     p0.1, c                 ; 26 .. 255: p0.1 = 0
6
        cjne    a, #51, _lb3
7
_lb3:   mov     p0.2, c                 ; 51 .. 255: p0.2 = 0
8
        cjne    a, #76, _lb4
9
_lb4:   mov     p0.3, c                 ; 76 .. 255: p0.3 = 0
10
        cjne    a, #101, _lb5
11
_lb5:   mov     p0.4, c                 ;101 .. 255: p0.4 = 0
12
        cjne    a, #126, _lb6
13
_lb6:   mov     p0.5, c                 ;126 .. 255: p0.5 = 0
14
        cjne    a, #151, _lb7
15
_lb7:   mov     p0.6, c                 ;151 .. 255: p0.6 = 0
16
        cjne    a, #176, _lb8
17
_lb8:   mov     p0.7, c                 ;176 .. 255: p0.7 = 0
18
        cjne    a, #201, _lb9
19
_lb9:   mov     p1.0, c                 ;201 .. 255: p1.0 = 0
20
        cjne    a, #226, _lb10
21
_lb10:  mov     p1.2, c                 ;226 .. 255: p1.1 = 0


Peter

von Peter D. (peda)


Lesenswert?

P.S.:
Zur Erklärung:


"CJNE" vergleicht ein Register mit einer Zahl und springt bei ungleich 
an das Label (Compare and Jump if Not Equal).
Der Vergleich entspricht einer Subtraktion, ohne daß das Ergebnis 
gespeichert wird. Das Register bleibt also unverändert.
Zusätzlich wird das Carry-Bit gesetzt, wenn der Registerwert kleiner als 
die Zahl ist.
Die Sprungfunktion wird hier nicht benötigt, daher der Sprung in die 
nächste Zeile.


"MOV Bit, C" lädt ein Bit (das kann ein Portpin sein) mit dem Carry-Bit.
Das Bit muß also vorher nicht gelöscht werden.


Beim 8051 sind alle Portpins nach dem Reset high, daher schaltet man 
LEDs immer gegen VCC, d.h. sie leuchten bei Pin = 0.


Peter

von Patrick W. (pw-sys) Benutzerseite


Lesenswert?

Hallo,

wenn ein if-Anweisungsmarathon aber dann bitte mit else-if weiter (spart 
im besten Fall 90% ein....

Alternativ wäre eine Rundung mit anschließender case-Struktur möglich

Gruß
Patrick

von Peter D. (peda)


Lesenswert?

Patrick Weggler schrieb:
> wenn ein if-Anweisungsmarathon aber dann bitte mit else-if weiter (spart
> im besten Fall 90% ein....

Na klar, ein Mensch kann ja auch LEDs schneller als 10µs ablesen.

Ein Aufruf alle 100ms ist ausreichend, ergibt bei 10µs Ausführungszeit 
eine lächerliche CPU-Last von 10µs / 100mS = 0,01%.

Ein Einfügen von nen Haufen Sprüngen hätte außer einer Explosion der 
Codegröße keinerlei meßbaren Effekt.
Und im Mittel wird sich dadurch die Ausführungszeit sogar deutlich 
verlängern (Sprünge sind teurer als Operationen).


Peter

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.