PIC Assembler auf- abzählen

Gast #3219270
Lesenswert?

Hallo,
ich arbeite seit ein paar Tagen mit meinem Ersten PIC (16f84a). Nun bin 
ich gerade dabei einen DAC0808 anzusteuern und damit verschiedene 
Spannungsformen zu erzeugen. Rechteck war kein Problem  ;)"Sägezahn" 
auch nicht.
Mein Problem ist jetzt die Dreieckspannung.
Ich kriege es einfach nicht hin, bei b"11111111" in meiner Speicherzelle 
dann rückwärts zu zählen und hin und her.
Ich habe probiert mit BTFSC/BTFSS zu arbeiten, kann man auch 8 Bit 
gleichzeitig abfragen? Außerdem habe ich schon probiert mit dem CARRY 
Bit im Statusregister zu arbeiten...
Bitte um unterstützung.

1
Main
2
  incf  0x20,1
3
  movf  0x20,0
4
  movwf  PORTB
5
  call  Wait
6
  goto  Main

Ich habe die Init und das Unterprogramm "Wait" hier mal raus gelassen, 
funkrioniert ja alles soweit.

MfG
Ralf
Gast #3219284
Lesenswert?

1
Main
2
  clrf 0x20
3
  decf 0x20
4
Loop1
5
  incf  0x20,1
6
  movf  0x20,0
7
  movwf  PORTB
8
  call  Wait
9
  btfss 3,0
10
  goto  Loop1
11
Loop0
12
  decf  0x20,1
13
  movf  0x20,0
14
  movwf  PORTB
15
  call  Wait
16
  btfss 3,0
17
  goto  Loop0
18
  goto  Loop1
Gast #3219291
Lesenswert?

Sorry, falsch geht, nicht. so sollte es gehen
1
Main
2
  clrf 0x20
3
Loop1
4
  movf  0x20,0
5
  movwf  PORTB
6
  call  Wait
7
  incfsz  0x20,1
8
  goto  Loop1
9
  decfsz  0x20,1
10
Loop0
11
  movf  0x20,0
12
  movwf  PORTB
13
  call  Wait
14
  decfsz 0x20,0
15
  goto  Loop0
16
  goto  Loop1
Gast #3219299
Lesenswert?

Also so?
1
Main
2
  clrf 0x20
3
Loop1
4
  movf  0x20,0
5
  movwf  PORTB
6
  call  Wait
7
  incfsz  0x20,1
8
  goto  Loop1
9
  decfsz  0x20,1
10
  decfsz  0x20,1
11

12
Loop0
13
  movf  0x20,0
14
  movwf  PORTB
15
  call  Wait
16
  decfsz 0x20,0
17
  goto  Loop0
18
  goto  Loop1
Tut mir leid, aber ich kann dir nicht ganz folgen.
Gast #3219506
Lesenswert?

Hallo,
klarer werden die Befehle decfsz,1 u.a. wenn statt der Zahl ein 
Buchstabe verwendet wird: Anstatt 0 der Buchstabe W und anstatt 1, der 
Buchstabe F.

DECFSZ Wert,F -> verminderte Wert um 1, wenn das Ergebnis der vorherigen 
Befehlsfolge (addwf, subwf usw) = 0 ist. Schreibe dann Wert-1 in Wert 
(F=File) zurück.

DECFSZ Wert,W im Prinzip wie vorstehend, nur dass Wert-1 in das 
Arbeitsregister (WREG) und nicht nach "Wert" zurückgeschrieben wird.

Der Wert von W bzw. F wird im File *.INC-File des Prozessors zugewiesen

mfG GroberKlotz
Gast #3219565
Lesenswert?

Hallo,
Habe erst jetzt den ganzen Threat gelesen...

Probieres doch mit nachstehenden Unterprogrammen. Anstatt der Zähler 
cntUp bzw. cntDWN, kanst Du ja jedes andere 8bit-Register oder eine 
Variable Deiner Wahl (z.B. PORTB)  verwenden. Zwischen den Schleifen 
Loop-Goto fügst Du Deine Wartezeiten ein.

COUNT_UP                   ;zählt aufwärts
    clrf    cntDWN         ;Abwärtszähler auf 0 setzen
CountUp_Loop:
    incf    cntUp,F        ;Zähler + 1
    btfss   STATUS,C       ;Carrybit=1? Zählerüberlauf?
    CALL    CountDOWN      ;JA, rückwärtszählen
    GOTO    CountUp_Loop   ;NEIN, weiter aufwärts zählen
RETURN

COUNT_DOWN                 ;zählt abwärts
    movlw   0xFF
    movwf   cntDWN         ;Startwert zuweisen
CountDown_Loop:
    decfsz  cntDWN,F       ;Zähler-1, Zerobit=1? Zähler=0?
    CALL    CounterUP      ;JA, wieder aufwärtszählen
    GOTO    CountDown_Loop ;NEIN weiter abwärts zählen
RETURN

mfG GroberKlotz
Gast #3220023
Lesenswert?

Hmm...

         CLRF    myCounter
UpLoop:  CALL    Wait
         INCFSC  myCounter,F
         GOTO    UpLoop

DnLoop:  CALL    Wait
         DECFSC  myCounter,F
         GOTO    DnLoop
         GOTO    UpLoop

GroberKlotz schrieb:
> incf    cntUp,F        ;Zähler + 1
>     btfss   STATUS,C       ;Carrybit=1? Zählerüberlauf?

Ist zwar schon zu spät für heute, aber ich glaube mich zu erinnern, daß 
Carry bei INCF und DECF nicht gesetzt wird.

W.S.
Gast #3220186
Lesenswert?

GroberKlotz schrieb:
> Probieres doch mit nachstehenden Unterprogrammen. Anstatt der Zähler

Idee dahinter habe ich verstanden, habe das Programm nun wie folgt:
1
COUNTUP                       ;zählt aufwärts
2
    clrf      0x21          ;Abwärtszähler auf 0 setzen
3
CountUpLoop:
4
  movf    0x20,0
5
  movwf    PORTB
6
  call    Wait
7
    incf      0x20,F          ;Zähler + 1
8
    btfss     STATUS,C         ;Carrybit=1? Zählerüberlauf?
9
    CALL      COUNTDOWN        ;JA, rückwärtszählen
10
    GOTO      CountUpLoop     ;NEIN, weiter aufwärts zählen
11
  RETURN
12

13
COUNTDOWN                     ;zählt abwärts
14
    movlw     0xFF
15
    movwf     0x21           ;Startwert zuweisen
16
CountDownLoop:
17
  movf    0x21,0
18
  movwf    PORTB
19
  call     Wait
20
    decfsz    0x21,F         ;Zähler-1, Zerobit=1? Zähler=0?
21
    CALL      COUNTUP        ;JA, wieder aufwärtszählen
22
    GOTO      CountDownLoop   ;NEIN weiter abwärts zählen
23
  RETURN


--> kommt wieder nur "Sägezahn"-Spannung bei raus. Zählt also nur Hoch 
und fängt wieder an.
#3220257
Lesenswert?

Klaus schrieb:
> Irgenwann habe ich aufgehört, mir über sowas Gedanken zu machen, und
>
> myCounter++;
>
> geschrieben.

Richtig, von dem Assembler kriegt man ja Augenkrebs.

Einfach:
1
int main()
2
{
3
  uint8_t val = 0, step = 1;
4
  for(;;){
5
    PORTB = val;
6
    wait();
7
    val += step;
8
    switch( val ){
9
      case 0:
10
      case 255: step = -step;
11
    }
12
  }
13
}

und gut is.
#3220431
Lesenswert?

Ralf G. schrieb:
> Ich bereite einen Kurs für unsere
> Azubis vor, die in der Schule nämlich Assembler programmieren müssen...

Dann bringt es aber nichts, wenn Dir ein anderer den Code schreibt.
Wenn Du anderen Assembler beibringen willst, mußt Du erstmal selber 
Assembler können. Daran führt kein Weg vorbei.
Nichts gegen Dich, aber was ich bisher gesehen habe, sieht eher nach 
Rumraten aus, statt nach Programmieren.
Gast #3220438
Lesenswert?

Bringt mir bei meinem momentanen Stand nichts, weil ich dann ja direkt 
wenn ich aus der schleife raus komme, wieder zurück springen würde oder?

1
Main
2
  btfsc  STATUS,Z    ; Wenn Zero-Bit=0 überspringe nächsten Befehl
3
  goto  hoch    ; Wenn Ergebnis = 0 (Z=1)
4
  goto  runter    ; Wenn Ergebnis!= 0 (Z=0)
5

6

7
hoch
8
  incf    0x20,1    ; + 1
9
    movf    0x20,0    ; 
10
    movwf    PORTB    ; Ausgeben
11
    call    Wait    ; Warten
12
  btfsc  STATUS,C    ; Wenn Carry-Bit=0 überspringe nächsten Befehl
13
  goto  hoch    ; Wenn Kein Überlauf
14
  goto  Main    ; Wenn Überlauf
15

16
runter
17
  movlw  0xFF    ; 
18
  movwf  0x20    ; 0x20 --> 11111111
19
  goto  runterzähler  
20

21
runterzähler
22
  decf  0x20,1    ; -1
23
  movf    0x20,0    ;
24
    movwf    PORTB    ; Ausgeben
25
    call    Wait    ; Warten
26
  btfsc  STATUS,Z    ; Wenn Zero-Bit=0 überspringe nächsten Befehl
27
  goto  Main    ; Wenn Ergebnis = 0 (Z=1)
28
  goto  runterzähler  ; Wenn Ergebnis!= 0 (Z=0)
Gast #3220440
Lesenswert?

Ich habe momentan die Zeit dazu, und wie du vielleicht merkst, 
beschäftige ich mich ja Intensiv damit. Ich will nicht, dass mir jemand 
nen Programm schreibt, sondern meinen Fehler finden. Genug offtopic.
#3220448
Lesenswert?

Mir ist da zwischen dem Dekrementieren und der dann eigentlichen Abfrage 
des Zero/Carry Bits
1
  decf  0x20,1    ; -1
2
  movf    0x20,0    ;
3
    movwf    PORTB    ; Ausgeben
4
    call    Wait    ; Warten
5
  btfsc  STATUS,Z    ; Wenn Zero-Bit=0 überspringe nächsten Befehl

einfach zu viel dazwischen. Zumal ich aus dem Bauch heraus das Gefühl 
habe, dass eine Funktion die 'Wait' heisst, ihrerseits sehr 
wahrscheinlich die Prozessorflags Zero bzw. Carry braucht um mittels 
eigener Funktionalität Takte in Schleifen zu vertrödeln.

Eine Gefahr bei Assembler ist es immer, wenn man die Bearbeitung mit dem 
Ziel einer Flag-Beeinflussung und die Auswertung dieser Flags durch 
andere Anweisungen unterbricht. Denn dann muss man von ALLEN Dingen 100% 
exakt und sicher wissen, wie sie sich auf die Flags auswirken. Daher ist 
es oftmals programmiertaktisch besser, diese Dinge beisammen zu lassen. 
Also nicht

     DEkrement
     mach was
     Werte die Flags vom Dekrement aus

sondern

     mach was
     Dekrement
     Werte die Flags vom Dekrement aus
#3220451
Lesenswert?

Du willst, dass die beide  Schleifen abwechselnd ausgeführt werde. Also 
musst du sobald eine Schleife fertig ist in die nächste springen.

beim raufzählen z.B.

aufwaerts
incf counter,f
movf counter,w
movwf PORTB
call wait
incfsz counter,w
goto aufwaerts
goto abwaerts

und fürs abwärtszählen ändert sich nicht viel...
#3220453
Lesenswert?

Ralf G. schrieb:
> Ich habe momentan die Zeit dazu, und wie du vielleicht merkst,
> beschäftige ich mich ja Intensiv damit. Ich will nicht, dass mir jemand
> nen Programm schreibt, sondern meinen Fehler finden. Genug offtopic.

Dann schnapp dir Papier und Bleistift und spiel COmputer.

Auf deinem Papier schreibst du dir alle Register und deren Werte auf. 
Und auch die ALLER Flags. Wenn du einen Befehl ausführst, dann machst du 
diese Operation auf dem Papier UND du vergisst dabei auch nicht auf die 
Flags! Wenn du dir nicht sicher bist, welche Flags beeinflusst werden, 
dann schau in den Instruction Datenblättern des Herstellers nach.
Und auch wichtig: Du machst nicht das, was du dir denkst das passiert, 
sondern du machst in deiner Papier-Simulation das was im Code steht und 
was in den Instructen Set Datenblättern des Herstellers steht!


Und PS: es hilft bei derartigen Simulation ungemein, wenn man die 
'großen' Zahlen erst mal kleiner macht. Es macht nicht viel Sinn eine 
Schleife 255 mal durchzusimulieren. 4 oder 5 mal tuts auch. 1 mal ist 
hingegen wieder relativ schlecht, denn du solltest mit der Simulation 
schon wenigstens 2 Durchläufe durch eine Schleife machen um alle Effekte 
zu sehen.


Wenn du anderen Assembler beibringen willst, dann musst du intime 
Kenntnisse haben. Und die gibt es nur in den Datenblättern. Dort steht 
exakt bei jedem Befehl drinnen, welche Flags wie verändert werden. Hört 
sich jetzt schlimmer an als es ist, weil Befehle ja in Gruppen/Familien 
auftauchen und normalerweise alle Befehle aus einer Familie sich gleich 
verhalten. Aber anders geht es nicht - wenn du ausbilden willst.
#3220455
Lesenswert?

Ralf G. schrieb:
> Wait ist einfach nur eine Warteschleife von 5 ms.

'einfach' ist in Assembler gar nichts.
Verändert 'Wait' die Flags oder tut es das nicht? Das ist die Frage, der 
du dich stellen musst.
Derjenige, der Wait geschrieben hat, kann darauf geachtet haben, da 
nichts zu verändern. Kann ... aber muss nicht. Ergo muss man das 
kontrollieren.

> Diese habe ich erstmal

Mit 'erst mal nur reingemacht' kannst du ein funktionsfähiges 
Assemblerprogramm ganz schnell vom Zustand "geht" in den Zustand "geht 
nicht" überführen, wenn du dir nicht absolut und 100% sicher bist, 
welche Nebenbedingunen bzw. Nebenwirkungen, wie zb die Veränderung von 
Zero/Carry Flag deine Änderung hat.
#3220462
Lesenswert?

Hallo Ralf,

du fragst ein Status-Flag (ich sge mal nichts dazu ob es das richtige 
ist) zu einem Zeitpunkt ab, wo es nicht den erwarteten Zustand aufweist. 
Die Abfrage eines Status-Flag muss direkt nach dem Befehl erfolgen, der 
es beeinflusst. Einzige Ausnahme sind Befehle, die das jeweilige 
Status-Flag unbeeinflusst lassen. Ich sehe zwar die Implementierung 
deiner 'wait' nicht, weis aber auch so dass darin Operationen vorkommen, 
die auf die Status-Flags wirken. Du musst also umstellen.

Kommst du damit weiter?

Grüße,
Edson
Gast #3220466
Lesenswert?

Ralf G. schrieb:

> Ich will nicht, dass mir jemand
> nen Programm schreibt, sondern meinen Fehler finden.

Bei Microchip gibt es das PICmicro™ Mid-Range MCU Family Reference 
Manual, man kann es sich dort herunter laden. Das Dokument heißt 
33023a.pdf. In den Datenblättern z.B. zum PIC12F675 wird an manchen 
Stellen auch dort hin verwiesen.

Auf jeden Fall wird dort der Befehlssatz noch mal etwas detaillierter 
erklärt. Section 29: Instruction Set.
#3220519
Lesenswert?

Ralf G. schrieb:
> Das mit den Status abfragen hat nicht geklappt. Habs jetzt mit incfsz
> und decfsz realisiert, nachdem ich mir nochmal die genaue Funktion
> angeschaut habe.

Die Befehle incfsz und decfsz enthalten ebenfalls Abfragen über ein 
Status-Flag, und zwar in beiden Fällen das Zero-Flag.

Semantisch ist
1
   incfsz   0x20, f
2
      goto   anywhere

äquivalent zu
1
   incf   0x20, f
2
   btfss  STATUS, Z
3
      goto   anywhere

Du hast in deinem Code vorhin nicht Z sondern C abgefragt.
Gast #3220544
Lesenswert?

M. H. schrieb:
> Kann es sein, dass incf das Carry Flag nicht beeinflusst? Probier mal
> statt dem Carry beim hinaufzählen das Zero-Flag zu testen.

Nachdem hatte ich das bereits geändert. Hat aber trotzdem irgendwie 
nicht richtig funktioniert, er hatte dann nurnoch heruntergezählt.
Gast #3220851
Lesenswert?

Hier der Schaltplan von meiner DAC Platine. Der PIC ist auf nem fertigen 
Modul, gehe also nur mit ner Flachbandleitung mit GND,VCC und den 8 Bit 
zum DAC. Die externen -15V hängen natürlich an der selben Masse.
Angehängte Dateien:
#3220905
Lesenswert?

Ralf G. schrieb:
> Ich frage mich jetzt nur, weshalb die "Stufen" so grob sind?

Ich habe etwas Probleme mit der Interpretation des Oszi-Bildes: Die 
einzelnen "Stücke" sind doch schräg und keine Stufen!
Kann es sein, dass du 2-kanalig im Multiplexbetrieb arbeitest, was diese 
Lücken erzeugen kann? Wenn ja, schalte mal auf 1 Kanal oder auf 
"Alternate".
Woher das Doppelbild herkommt, ist auch noch komisch... Es könnte daher 
durchaus ein Messfehler sein.

Gruß Dietrich
Gast #3220948
Lesenswert?

So würde es aussehen, wenn D3 immer auf low liegt (wenn D3 immer auf 
high liegt ist das Signal um 8 Werte in Y-Richtung verschoben).

Mess mal mit dem Oszi ob alle Signale (besonders D3) am D/A-Wandler 
ankommen. Wenn alle Signale da sind, dann ist vielleicht der Wander 
defekt.

Gruß
John
Angehängte Dateien:
Gast #3249012
Lesenswert?

Welche befehle wie welche Bit's beeinflusse lässt sich auf der sehr 
aufwendigen Homepage 
http://www.sprut.de/electronic/pic/assemble/befehle.html wunderbar auf 
Deutsch und verständlich nachlesen. Ich arbeite mit PIC und nur in 
Assembler, diese Homepage http://www.sprut.de/electronic/pic/index.htm 
hat mich dabei schon oft zum Verständnis und der Lösung eines Problems 
geführt.
Ein eher allgemeiner Tip zum Thema Assembler und der Arbeit damit.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren