Forum: Compiler & IDEs 2 Byte Variablen für 8Bit PIC aus und einlesen mit Pic-as oder mpasm-Assembler


von Rudi R. (microwitsch)


Lesenswert?

Hallo zusammen,

hier ist mal ein C-Code-Dissassemling von der Dutyvalue-Funktion eines 
CCP-PWM-Programs,bei dem ich gerne wissen würde wie man mit 
Assemblercode diese Funktion schreiben würde?

Mir ist nicht klar wenn ich eine 2 Byte große Variable anlege, wie diese 
sich in zwei 8bittige aufteilt und dann zusammenhängend arbeitet?

__pcstackBANK0 hat der Compiler erzeugt, dir Declaration dazu sehe ich 
leider nicht!?
Ebenso ist 0x21 der andere Teil der 16bit-Variable.
Eine Festwerteingabe von zb.1000 dezimal, müsste hier also mit 
irgendeiner Funktion gemacht werden, die in High und Lowbits aufteilt??

Das Dutyregister kann 10bittig sein (Wert 1023) damit kommt man durch 
den ganzen Wertebereich.
Der Compiler hat jedenfalls zwei 8bit-Files angelegt, die irgendwie 
zusammenhängend verarbeitet werden?Ich will das ganze mal in 
uncompiliertem Assembler-Code sehen!?

1
82:            void PWM1_LoadDutyValue(uint16_t dutyValue)
2
83:            {
3
84:                dutyValue &= 0x03FF;
4
00D7  30FF     MOVLW 0xFF
5
00D8  0140     MOVLB 0x0
6
00D9  05A0     ANDWF __pcstackBANK0, F
7
00DA  3003     MOVLW 0x3
8
00DB  05A1     ANDWF 0x21, F
9
85:                
10
86:                // Load duty cycle value
11
87:                if(CCP1CONbits.CCP1FMT)
12
00DC  0146     MOVLB 0x6
13
00DD  1E0E     BTFSS CCP1CON, 0x4
14
00DE  28E0     GOTO 0xE0
15
00DF  28E1     GOTO 0xE1
16
00E0  28E7     GOTO 0xE7
17
88:                {
18
89:                    dutyValue <<= 6;
19
00E1  3006     MOVLW 0x6
20
00E2  0140     MOVLB 0x0
21
00E3  35A0     LSLF __pcstackBANK0, F
22
00E4  0DA1     RLF 0x21, F
23
00E5  0B89     DECFSZ WREG, F
24
00E6  28E3     GOTO 0xE3
25
90:                    CCPR1H = dutyValue >> 8;
26
00E7  0140     MOVLB 0x0
27
00E8  0821     MOVF 0x21, W
28
00E9  0146     MOVLB 0x6
29
00EA  008D     MOVWF CCPR1H
30
91:                    CCPR1L = dutyValue;
31
00EB  0140     MOVLB 0x0
32
00EC  0820     MOVF __pcstackBANK0, W
33
00ED  0146     MOVLB 0x6
34
00EE  008C     MOVWF CCPR1
35
92:                }
36
93:                else
37
94:                {
38
95:                    CCPR1H = dutyValue >> 8;
39
96:                    CCPR1L = dutyValue;
40
97:                }
41
98:            }
42
00EF  0008     RETURN
43
99:            
44
100:           bool PWM1_OutputStatusGet(void)
45
101:           {
46
102:               // Returns the output status
47
103:               return(CCP1CONbits.OUT);
48
104:           }
49
105:           /**
50
106:            End of File
51
107:           */

von Meister E. (edson)


Lesenswert?

Rudi R. schrieb:
> Hallo zusammen,

Servus,

> hier ist mal ein C-Code-Dissassemling von der Dutyvalue-Funktion eines
> CCP-PWM-Programs,bei dem ich gerne wissen würde wie man mit
> Assemblercode diese Funktion schreiben würde?

bei Fragen zu Assembler sollte man unbedingt die genaue Bezeichnung des 
uC angeben. PICs haben teils spezifische Instruktions-Implementierungen, 
die man dann auch gerne im "Instruction Set Summary" nachschlagen 
möchte.
Die Instruktionen schauen nach einem PIC16 aus, aber welcher ist es 
genau?

> Mir ist nicht klar wenn ich eine 2 Byte große Variable anlege, wie diese
> sich in zwei 8bittige aufteilt und dann zusammenhängend arbeitet?

Naja, die zwei Byte bleiben auch zwei Byte. "Zusammenhängend arbeiten" 
können sie durch die Beachtung/Behandlung des Carry-Flag der ALU. Das 
nur nebenbei, denn bei ANDWF/ANDLW spielt Carry keine Rolle.

> __pcstackBANK0 hat der Compiler erzeugt, dir Declaration dazu sehe ich
> leider nicht!?

Wenn man sich den Opcode von ANDWF anschaut, sieht man ja den Daten bzw. 
Adressteil. Die Deklaration des Platzhalters ist hier erstmal nicht so 
wichtig. Nur zu Info, die Variable wird auf einem Datenstack gehalten 
d.h. ihre Adresse ist nicht zwingend bei jedem Aufruf der (leider nicht 
vollständig gezeigten Funktion) gleich.
1
00D9  05A0     ANDWF __pcstackBANK0, F

Der Opcode von ANDWF ist "00 0101 dfff ffff", dabei ist 'd' das 
Direction-Bit und die 'f' stehen für eine Adresse im GPRAM. ANDWF kann 
Werte von 0..127 verarbeiten, also 7 Bit. In der obigen Zeile steht also 
die Adresse 0100000b == 0x20, das ist die niedrigste Adresse im GPRAM.

> Ebenso ist 0x21 der andere Teil der 16bit-Variable.
> Eine Festwerteingabe von zb.1000 dezimal, müsste hier also mit
> irgendeiner Funktion gemacht werden, die in High und Lowbits aufteilt??

Jein, die Aufteilung ist durch die Reihenfolge der Instruktionen 
gegeben. Das untere (LSB) ist an der Adresse 0x20 abgelegt, das höhere 
(MSB) an der Adresse 0x21.

> Das Dutyregister kann 10bittig sein (Wert 1023) damit kommt man durch
> den ganzen Wertebereich.

Es ist 10 Bit breit und weil in ein Byte nur 8 Bit passen, stehen die 
verbleibenden 2 in einem weiteren Byte. Das verUNDen von 0x03ff in 
C-Zeile 84 sorgt dafür, dass in 0x20 und 0x21 die 6 msb Null sind, also 
10 Bit "übrigbleiben", so kann man 0x20 und 0x21 nach der späteren 
Schiebeoperation direkt in die 2 Byte des "Duty-Register" übertragen.

> Der Compiler hat jedenfalls zwei 8bit-Files angelegt, die irgendwie
> zusammenhängend verarbeitet werden?

> Ich will das ganze mal in
> uncompiliertem Assembler-Code sehen!?

Dann muss man das selber schreiben.

Nachtrag:
>
>
1
> 88:                {
2
> 89:                    dutyValue <<= 6;
3
> 00E1  3006     MOVLW 0x6
4
> 00E2  0140     MOVLB 0x0
5
> 00E3  35A0     LSLF __pcstackBANK0, F
6
> 00E4  0DA1     RLF 0x21, F
7
> 00E5  0B89     DECFSZ WREG, F
8
> 00E6  28E3     GOTO 0xE3

In den ASM-Zeilen 00E3 und 00E4 spielt Carry eine Rolle. Was bei LSLF 
nach links aus dem LSB "herausgeschoben" wird, kommt beim RLF von rechts 
ins MSB. Beantwortet das deine Fragen wenigstens zum Teil?

: Bearbeitet durch User
von Meister E. (edson)


Lesenswert?

Rudi R. schrieb:
>
1
> 90:                    CCPR1H = dutyValue >> 8;
2
> 00E7  0140     MOVLB 0x0
3
> 00E8  0821     MOVF 0x21, W
4
> 00E9  0146     MOVLB 0x6
5
> 00EA  008D     MOVWF CCPR1H

Vielleicht noch fürs Verständnis, wie in ASM mit Datentypen umgegangen 
werden kann: Die der in C geschriebenen Schiebeoperation folgende 
Zuweisung soll die oberen 8 Bit von dutyValue nach CCPR1H übertragen. 
Das muss "der Assembler" aber gar nicht machen, hier nimmt er einfach 
das auf 0x21 liegende MSB (das ist es per Konvention) und überträgt es 
übers W-Register nach CCPR1H. Die MOVLB-Instruktionen sind wegen der 
Bankumschaltung nötig, da Daten aus dem GPRAM in Bank0 in ein SFR in 
Bank6 übertragen werden müssen.

von Rudi R. (microwitsch)


Lesenswert?

Meister E. schrieb:
>> Mir ist nicht klar wenn ich eine 2 Byte große Variable anlege, wie diese
>> sich in zwei 8bittige aufteilt und dann zusammenhängend arbeitet?
>
> Naja, die zwei Byte bleiben auch zwei Byte. "Zusammenhängend arbeiten"
> können sie durch die Beachtung/Behandlung des Carry-Flag der ALU. Das
> nur nebenbei, denn bei ANDWF/ANDLW spielt Carry keine Rolle.

Na es sind doch aber jeweils 1 Byte die zusammen eine 2 Byte-Einheit 
bilden!?

Wie ist es mit dem Überlauf der LSB bei 256...dann wird doch in der 
weiteren 8Byte-Einheit weitergeschrieben!?Wie geht der Sprung?Das sehe 
ich hier nicht.
Wenn ich das jetzt als Assemblercode selbst schreiben will, müsste ich 
von einer Variable zur nächsten wechseln um dort die folgenden Bits 
weiterschreiben zu lassen.

Ich habe das mal mit diesem einfachem Code hier probiert, doch das File 
der Adresse 0x21 blieb leer obwohl ich ja 1023 an die Variable übergeben 
hatte, die ich als 2bytige angelegt habe, hier der PICAS-Test-Code:
1
; Main application data Variables
2
    
3
    PSECT   MainData,global,class=RAM,space=1,delta=2,noexec
4
   global   dutyvalue
5
    
6
dutyvalue:  DS      2      ; Variable 2 Byte
7
    
8
; Main application code
9
10
    PSECT   MainCode,global,class=CODE,delta=2
11
    
12
MAIN:
13
    
14
   BANKSEL  PORTA      ; Power on LED RA0
15
   BSF    BANKMASK(PORTA),PORTA_RA0_POSITION  
16
   MOVLW  0x03FF      ; 16 Bit 0000 0011 1111 1111 (1023) geladen        
17
   MOVWF  dutyvalue,F    ; an dutyvalue übergeben und gespeichert( Adresse 0x20 Lowbits und 0x21 Highbits?? )
18
   MOVLW  0xFF      ; 1111 1111 (256) ins W-Register geladen
19
   BANKSEL  0x21      ; hier sollten jetzt die Highbits sein also 0000 0011 (3)
20
   ANDWF  0x21,W      ; Undung mit dem  geladenem W (256) Ergebnis ins W zurück
21
   MOVWF  PORTD      ; W an Ausgänge übergeben, hier sollten jetzt die RD0 und RD1 jetzt high sein
22
   
23
WORK:      
24
    GOTO  WORK       
25
      
26
; Declare Power-On-Reset entry point

von Meister E. (edson)


Lesenswert?

Rudi R. schrieb:
> Meister E. schrieb:
>>> Mir ist nicht klar wenn ich eine 2 Byte große Variable anlege, wie diese
>>> sich in zwei 8bittige aufteilt und dann zusammenhängend arbeitet?
>>
>> Naja, die zwei Byte bleiben auch zwei Byte. "Zusammenhängend arbeiten"
>> können sie durch die Beachtung/Behandlung des Carry-Flag der ALU. Das
>> nur nebenbei, denn bei ANDWF/ANDLW spielt Carry keine Rolle.
>
> Na es sind doch aber jeweils 1 Byte die zusammen eine 2 Byte-Einheit
> bilden!?

Ja, dann sind wir uns ja (fast) einig :)
Zwei Byte bleiben aber immer zwei Byte, eine "Einheit" bilden sie nur, 
wenn der ASM-Code die Einzel-Bytes so behandelt, dass am Ende das 
Ergebnis stimmt, von allein geht das nicht.
Aber in Deinem Code hast Du trotzdem versucht, gleich 10 Bit in ein Byte 
zu schreiben:
1
   MOVLW  0x03FF      ; 16 Bit 0000 0011 1111 1111 (1023) geladen

Hat der Assembler da gar nicht gemeckert? Mehr als die letzten 8 Bits 
(11111111b) wird er in MOVLW nicht unterbringen können.

> Wie ist es mit dem Überlauf der LSB bei 256...dann wird doch in der
> weiteren 8Byte-Einheit weitergeschrieben!?Wie geht der Sprung?Das sehe
> ich hier nicht.

Es gibt keinen "Sprung", der Überlauf ist im/am Carry-Flag zu sehen. Und 
um dieses sinnvoll zu nutzen, muss der gesamte Code das berücksichtigen. 
Alle Instruktionen müssen so gewählt werden, dass die Information im 
Carry-Flag so lange bestehen bleibt bis die gesamte Verarbeitung 
abgeschlossen ist.

Schau nochmal in den Code von gestern. __pcstackBANK0 liegt auf Adresse 
0x20, das höherwertige Byte auf Adresse 0x21 könnte man auch als 
__pcstackBANK0+1 betrachten, das hätte Dich vielleicht weniger 
irritiert.

> Wenn ich das jetzt als Assemblercode selbst schreiben will, müsste ich
> von einer Variable zur nächsten wechseln um dort die folgenden Bits
> weiterschreiben zu lassen.

Genau, das ist völlig richtig.

> Ich habe das mal mit diesem einfachem Code hier probiert, doch das File
> der Adresse 0x21 blieb leer obwohl ich ja 1023 an die Variable übergeben
> hatte, die ich als 2bytige angelegt habe, hier der PICAS-Test-Code:

Obwohl Du oben richtig lagst, hast Du hier einen Fehler gemacht. Du 
kannst nicht 1023 in einem Datentyp speichern, der nur bis 255 geht.
Wie im gestern gezeigten Compilat muss sich das aufteilen auf zwei Byte, 
eins in dem 0xff steht und ein Byte in dem 0x03 steht. Das Byte mit den 
0x03 ist aber "256 mal soviel Wert" wie da steht. So kommt man auf 
3*256+255=1023.
Ist es jetzt klarer?

: Bearbeitet durch User
von Meister E. (edson)


Lesenswert?

Ok, hier habe ich Dein Testprogramm mal so geschrieben, dass es 
funktioniert:
1
    banksel PORTA
2
    bsf     BANKMASK(PORTA), 0  ; Power on LED @RA0
3
    banksel dutyvalue
4
    movlw   0xFF                ; diese und die nächste Zeile kann
5
    andwf   dutyvalue, f        ; man sich sparen, ein verUNDen mit
6
                                ; 0xff ändert den Wert in dutyvalue
7
                                ; nämlich überhaupt nicht
8
    movlw   0x03
9
    banksel dutyvalue+1         ; dutyvalue+1 könnte in einer
10
                                ; anderen Bank stehen als dutyvalue
11
                                ; (außer man hat das aktiv vermieden)
12
13
    andwf   dutyvalue+1, f      ; hier bleiben nur die Bits 0 und 1 
14
                                ; in dutyvalue+1 stehen
15
    movf    dutyvalue+1, w      ; weil der vorige Befehl sein Ergebnis
16
                                ; in dutyvalue+1 ablegt, muss man den Wert
17
                                ; jetzt wieder ins W-Register holen
18
    banksel PORTD
19
    movwf   PORTD               ; jetzt das W-Register nach PORTD schreiben,
20
                                ; dann werden auch RD0 und RD1 gesetzt

So sieht das aus. Man kann mit einer 8-Bit CPU eben nur so tun, als 
hätte man größere Datentypen zur Verfügung. Stell Dir vor, du möchtest 
einen 32-Bit Wert über eine serielle Schnittstelle übertragen, da 
sendest Du vier Byte hintereinander und das empfangende System muss 
wissen, in welcher Reihenfolge die Bits in den Bytes stehen und die 
Reihenfolge der Bytes muss auch vorher ausgemacht sein, dann kann der 
Wert im Zielsystem auch wieder richtig zusammengebaut werden.
Wenn du das innerhalb eines 8-Bit Systems machst, stimmt die Reihenfolge 
der Bits schonmal, um den Rest musst Du Dich aber selbst kümmern. 
Werkzeuge liefert der Befehlssatz genügend. Nenn doch bitte mal den 
PIC-Typ, den Du konkret benutzt, dann kann ich ein Beispiel zeigen, dass 
die vorhandenen Werkzeuge optimal ausnutzt. Weil z.B. nicht jeder PIC16 
den Befehl ADDWFC kennt, mit dem man eine Addition mit Überlauf bequem 
vornehmen kann.

: Bearbeitet durch User
von Rudi R. (microwitsch)


Lesenswert?

Meister E. schrieb:
> So sieht das aus. Man kann mit einer 8-Bit CPU eben nur so tun, als
> hätte man größere Datentypen zur Verfügung. Stell Dir vor, du möchtest
> einen 32-Bit Wert über eine serielle Schnittstelle übertragen, da
> sendest Du vier Byte hintereinander und das empfangende System muss
> wissen, in welcher Reihenfolge die Bits in den Bytes stehen und die
> Reihenfolge der Bytes muss auch vorher ausgemacht sein, dann kann der
> Wert im Zielsystem auch wieder richtig zusammengebaut werden.
> Wenn du das innerhalb eines 8-Bit Systems machst, stimmt die Reihenfolge
> der Bits schonmal, um den Rest musst Du Dich aber selbst kümmern.
> Werkzeuge liefert der Befehlssatz genügend. Nenn doch bitte mal den
> PIC-Typ, den Du konkret benutzt, dann kann ich ein Beispiel zeigen, dass
> die vorhandenen Werkzeuge optimal ausnutzt. Weil z.B. nicht jeder PIC16
> den Befehl ADDWFC kennt, mit dem man eine Addition mit Überlauf bequem
> vornehmen kann.

Hallo Danke erst einmal für deine Hilfe, damit kann ich schon was 
anfangen!...habe natürlich selbst weiter im Code geschaut um nach 
brauchbare stellen  zu gucken, da habe ich noch folgendes interessantes 
gefunden!:

Hier geht es in einer weiteren Funktion darum für dutyvalue eine 
Ersatzvariable zu beschreiben...die in Dutyvalue kopiert wird.Das hier 
ist eine Zustandsabfrage von 2 Tastern die über TMR1-interrupt zyklisch 
vollzogen wird und die Ersatzvariable bearbeitet...da ist diese 
Überlaufaktion zu sehen, die du hier meinst!hiermit wird diese Variable 
in ihren Grenzen definiert...zu deiner Frage welcher PIC hier bei mir 
verwendet wird:es ist der PIC16F18877, den ich durch ein Lehrbuch wählte 
in dem andere Beispiele durchgenommen werden.:0)

1
73:                  if(++counter >=512)counter =0;                    // Variable Counter hochzählen
2
007D  3001     MOVLW 0x1
3
007E  07F8     ADDWF counter, F
4
007F  3000     MOVLW 0x0
5
0080  3DF9     ADDWFC 0x79, F
6
0081  3002     MOVLW 0x2
7
0082  0279     SUBWF 0x79, W
8
0083  3000     MOVLW 0x0
9
0084  1903     BTFSC STATUS, 0x2
10
0085  0278     SUBWF counter, W
11
0086  1C03     BTFSS STATUS, 0x0
12
0087  2889     GOTO 0x89
13
0088  288A     GOTO 0x8A
14
0089  288C     GOTO 0x8C
15
008A  01F8     CLRF counter
16
008B  01F9     CLRF 0x79
17
74:                  }
18
75:                  if(IO_RB0_PORT == 1 && IO_RB1_PORT == 0)

: Bearbeitet durch User
von Meister E. (edson)


Lesenswert?

Rudi R. schrieb:
> Hallo Danke erst einmal für deine Hilfe, damit kann ich schon was
> anfangen!...habe natürlich selbst weiter im Code geschaut um nach
> brauchbare stellen  zu gucken, da habe ich noch folgendes interessantes
> gefunden!:

Gerne, freut mich dass meine Beiträge nützlich sind.

> Hier geht es in einer weiteren Funktion darum für dutyvalue eine
> Ersatzvariable zu beschreiben...die in Dutyvalue kopiert wird.Das hier
> ist eine Zustandsabfrage von 2 Tastern die über TMR1-interrupt zyklisch
> vollzogen wird und die Ersatzvariable bearbeitet...da ist diese
> Überlaufaktion zu sehen, die du hier meinst!hiermit wird diese Variable
> in ihren Grenzen definiert...zu deiner Frage welcher PIC hier bei mir
> verwendet wird:es ist der PIC16F18877, den ich durch ein Lehrbuch wählte
> in dem andere Beispiele durchgenommen werden.:0)
>
>
>
1
73:                  if(++counter >=512)counter =0; 
2
> // Variable Counter hochzählen
3
> 007D  3001     MOVLW 0x1
4
> 007E  07F8     ADDWF counter, F
5
> 007F  3000     MOVLW 0x0
6
> 0080  3DF9     ADDWFC 0x79, F
7
> 0081  3002     MOVLW 0x2
8
> 0082  0279     SUBWF 0x79, W
9
> 0083  3000     MOVLW 0x0
10
> 0084  1903     BTFSC STATUS, 0x2
11
> 0085  0278     SUBWF counter, W
12
> 0086  1C03     BTFSS STATUS, 0x0
13
> 0087  2889     GOTO 0x89
14
> 0088  288A     GOTO 0x8A
15
> 0089  288C     GOTO 0x8C
16
> 008A  01F8     CLRF counter
17
> 008B  01F9     CLRF 0x79
18
> 74:                  }
19
> 75:                  if(IO_RB0_PORT == 1 && IO_RB1_PORT == 0)

Ok, ich glaube hier müssen wir jetzt bremsen. Sowohl das Beispiel als 
das  Compilat sind nicht wirklich sinnvoll, sowas macht eine kostenlose 
Compiler-Version um einem die Kaufvariante schmackhafter zu machen. Die 
selbe Funktionalität kann man mit nur 6 oder 7 Instruktionen erreichen, 
ganz ohne ADDWFC...
1
    banksel counter
2
    incf    counter, f        ; counter (LSB) wird um 1 erhöht
3
    banksel counter+1         ; -> kann man weglassen, wenn LSB und MSB von counter in der selben Bank liegen
4
    btfsc   STATUS, Z         ; nach einem Überlauf ist das LSB==0
5
        incf    counter+1, w  ; dann zählt das MSB 1 (entspricht 1 mal 256) hoch
6
    btfsc   counter+1, 1      ; wenn zwei mal 256==512, dann
7
        clrf    counter+1     ; wird das MSB genullt, das LSB ist zu diesem
8
                              ; Zeitpunkt eh schon 0x00, fertig!

Geht also alles ohne Carry. Wir brauchen andere Beispiele ;)

Wenn Du noch Fragen hast, schau ich mir das gerne an.

: Bearbeitet durch User
von Rudi R. (microwitsch)


Lesenswert?

Meister E. schrieb:
> Ok, ich glaube hier müssen wir jetzt bremsen. Sowohl das Beispiel als
> das  Compilat sind nicht wirklich sinnvoll, sowas macht eine kostenlose
> Compiler-Version um einem die Kaufvariante schmackhafter zu machen. Die
> selbe Funktionalität kann man mit nur 6 oder 7 Instruktionen erreichen,
> ganz ohne ADDWFC...

OK,das hatte der Autor (Hanna Tam) hier im Buch auch erwähnt!...Ich habe 
sowas schon geahnt und beschäftige mich nun mit den grundsätzlichen 
Instruktionen vom Assembler...Nun muss ich sagen, das der 
C-Codegenerator einem natürlich auch entgegenkommt, wenn man nur 
Standardfunktionen benötigt, die nicht weiter verkoppelt und mit 
Sonderfunktionen verbunden werden.Hier springt nähmlich eine Variable 
für die andere ein und dadurch gibt es haufenweise GOTOs,die man so nur 
schlecht auseinander Pflücken kann.Also gerade als Anfänger eine 
bombastische Aufgabe.OK, wenn ich in Zukunft einfach mal logisch mit den 
gegebenen Instruktionen arbeite, werde ich das wohl genau so sehen wie 
du jetzt!;o)
Das sieht man erst,wenn man schon einige Programme und Probleme durch 
hat denke ich.Ich danke mal wieder für die Mühe einem Einsteiger zu 
helfen!Solche Leute wie du machen das Forum zu einem echt brauchbarem 
Tool!

Das mit "counter+1" hatte ich bisher in noch keinem Assemblercode 
gesehen, das muss ich doch nun gleich mal ausprobieren!

grundsätzlich ist die Seite https://www.sprut.de/index.htm ja sehr gut 
dokumentiert, da hat sich jemand sehr große Mühe gegeben.Schade das hier 
solche Variablen nicht beschrieben wurden, hier ist bei PWM in den 
Beispielen nur das Lowregister benutz worden.Ich hätte lieber die volle 
Bandbreite der Pulsmodulierung um später flexibler einstellen zu 
können.(das ist für ein neuartiges Ladegerät für Bleiakkus)...muss ich 
mir selbst bauen, gibt es so noch nicht auf dem Markt. Ich lade zwar 
schon mit dem Prinzip sehr gut aber ich muss immer die Spannung 
überwachen, was irgendwie blöd ist.

Gruß André :)

: Bearbeitet durch User
von Meister E. (edson)


Lesenswert?

Hallo André,

vielen Dank für die Rückmeldung, so machts Spaß!

Edit:
Klingt interessant, was Du da vor hast. Würde mich freuen noch mehr 
darüber zu erfahren, vielleicht magst Du Dein Projekt ja hier in der 
Rubrik "Projekte & Code" vorstellen?

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Rudi R. schrieb:
> 00DD  1E0E     BTFSS CCP1CON, 0x4
> 00DE  28E0     GOTO 0xE0
> 00DF  28E1     GOTO 0xE1
> 00E0  28E7     GOTO 0xE7

Hier sind aber 2 GOTOs zuviel.

von Rudi R. (microwitsch)


Lesenswert?

Meister E. schrieb:
> Hallo André,
>
> vielen Dank für die Rückmeldung, so machts Spaß!
>
> Edit:
> Klingt interessant, was Du da vor hast. Würde mich freuen noch mehr
> darüber zu erfahren, vielleicht magst Du Dein Projekt ja hier in der
> Rubrik "Projekte & Code" vorstellen?

Kann ich dann gern machen.

Nur kurz zudem was das Ding bei mir machen soll:

Die PWM soll für einen Step-UP Wandler am Ausgang einstellbar sein(für 
unterschiedliche Spulen,die dann über einen MOSFET kurzgeschlossen 
werden können bis deren Magnetfeld aufgebaut ist.
Die Energie, die die Spule nach dem Abschalten wieder abgibt soll auf 
eine größere Kondensatorbank gehen.In dem Projekt habe ich 0,68F die ich 
auf ca 30V bringe.
Wenn die Spannung erreicht ist, wird ein anderer Mosfet angesteuert, der 
die Kondensatorbank über einen Bleiakku kurzschließt.Da fließt 
kurzzeitig eine Menge Strom!(je nach Innenwiderstand der Batterie)
Der Kondensator wird aber nur auf ca 20V wieder entladen(über eine 
andere Pulsweite im Millisekundenbereich.
Je besser die Batterie noch in Schuss ist, um so kürzer dürfen diese 
Impulse dann sein und die Spannung am Kondensator kann auch 
runtergestellt werden.

Das ist alles dann nach dem John Bedini-Prinzip...und das funktioniert 
bisher mit meinem analogen Aufbau sehr gut.Die Batterien werden nicht 
überhitz, es gibt weniger Gasung und man hat bei ca.15-16V Ladespannung 
alles an Sulfhationen wieder umgewandelt, was nicht schon zu sehr großen 
Kristallen herangewachsen ist!Und das ist heute leider immer durch die 
unvollständigen Aufladungen von Standardgeräten der Fall!
Mein Solarregler macht zb. schon bei 14,2V Schluss...das ist nicht gut 
für die Haltbarkeit der Batterie, weil so jedes mal nicht umgewandelte 
Kristalle zurückbleiben, die dann auch noch immer größer werden, bis die 
Kapazität merklich, frühzeitig sinkt.
Hier kommen noch kleine Phänomene dazu.(die Spannung nach erreichten 
15,8V oder höher,bleibt nach abklemmen noch eine ganze Weile bei 13V 
stehen!)
Ich glaube der Typ Bedini hat Recht mit seiner Energie aus dem Vakuum 
oder wie auch immer.Nach Batteriekonditionierung,mehrfachen Ladungen und 
Entladungen nur mit Strömen unter C/20, brauchen diese immer weniger 
Zeit für die Ladung, weil die Platten immer glatter werden.(und eine 
Batterie sollte niemals zu lange ruhen)
Nikola Tesla meinte ebenfalls, dass das Vakuum sehr viel mehr Energie 
hat als wir uns vorstellen können!Der Casimir-effekt ist auch schon 
entdeckt worden, doch wer redet denn mal über die Energie des Vakuums?
Und irgendwie ist unser Sonnensystem auch ein Perpetum,wenn man das mal 
überdenkt,mir ist nicht bekannt, dass irgendwelche 
Umrundungsgeschwindigkeiten um die Sonne abnehmen!?

Das Projekt ist eigenartig aber ich muss zeitig genug die Ladung 
abschalten können,um später die Energieaufnahme messen zu können!?

Behauptung Bedinis:gut konditionierte Batterien nehmen im besten Fall 
weniger Energie aus dem Eingangsstromkreis, als sie letztendlich 
aufgenommen haben. Vermutlich Kaltströme der "Gegenseite" die an den 
Zuleitungen zur Batterie mitwandern und keinen Leiter brauchen(Strudel, 
Wirbel um den Leiter) ...keine Ahnung aber ich wills wissen.(Kalte 
Fusion???)...halbwegs plausible Erklärungen gibt es dazu bereits 
schon.Zb. Konstantin Meyl https://youtu.be/nWfI5hYvE88 Und ich glaube da 
ist was...ich weiß auch nicht... auch wenn man mich jetzt für einen 
Spinner hält! ;o)

von Rudi R. (microwitsch)


Lesenswert?

Peter D. schrieb:
> Rudi R. schrieb:
>> 00DD  1E0E     BTFSS CCP1CON, 0x4
>> 00DE  28E0     GOTO 0xE0
>> 00DF  28E1     GOTO 0xE1
>> 00E0  28E7     GOTO 0xE7
>
> Hier sind aber 2 GOTOs zuviel.

Ja ich weiß...der Codegenerator MCC und das Dissassemling spuckt mir 
auch noch die C-Code rein, die letztlich gar nicht aufgerufen 
werden!?...nun ja, wer will über umgewandelte C-Code Assemblercode 
lernen?? :o)

von Rudi R. (microwitsch)


Lesenswert?

Vielleicht mal für jemanden der auch mit 8BIT-Mikros und Assemlercoden 
rumfummelt. Hier habe ich jetzt mal meine TMR1 Interruptroutine und den 
Variablentest, den ich zur Funktion gebracht habe,nachdem ich einige 
Schlamper-Fehler finden musste.

Die Variablen Counterhigh und Counterlow, werden dann als nächstes an 
die CCP1-Dutyvalue- Register übergeben oder ich nehme direkt die 
Register dafür.
Timer1-Rollover lässt  hier ein mal die Sekunde durch die 
Tasterabfrageroutine laufen.Hier kann man noch mit Macros optimieren 
usw.aber ich habe wie gesagt den umgewandelten C-Code studiert...und das 
kam dabei raus!
1
; File:     main.S
2
; Target:   PIC16F18877
3
; Author:   Mikrowitsch
4
; Date:     
5
; Compiler: pic-as(v2.20)
6
; IDE:      MPLABX v5.40
7
;
8
; Description:
9
;    
10
;   PWM mit Festwert am Ausgang RC3
11
;
12
;   Add this line in the project properties box, pic-as Global Options -> Additional options: 
13
;    -Wl,-DCODE=2 -Wl,-pPor_Vec=0h       when interrupts(-pIsr_Vec=4h)
14
;
15
16
PROCESSOR   16F18877
17
PAGEWIDTH   132
18
RADIX       DEC
19
   
20
#include <xc.inc>
21
22
; PIC16F18313 Configuration Bit Settings
23
    
24
; CONFIG1
25
config FEXTOSC =    OFF      ; External Oscillator mode selection bits // Oscillator not enabled
26
config RSTOSC =      HFINT1  ; Power-up default value for COSC bits // HFINTOSC (1MHz)
27
config CLKOUTEN =   OFF      ; Clock Out Enable bit // CLKOUT function is disabled; i/o or oscillator function on OSC2
28
config CSWEN =      ON      ; Clock Switch Enable bit // Writing to NOSC and NDIV is allowed
29
config FCMEN =      ON      ; Fail-Safe Clock Monitor Enable bit // FSCM timer enabled
30
31
; CONFIG2
32
config MCLRE =      ON      ; Master Clear Enable bit // MCLR pin is Master Clear function
33
config PWRTE =      OFF      ; Power-up Timer Enable bit // PWRT disabled
34
config LPBOREN =    OFF      ; Low-Power BOR enable bit // ULPBOR disabled
35
config BOREN =      ON      ; Brown-out reset enable bits // Brown-out Reset Enabled, SBOREN bit is ignored
36
config BORV =      LO      ; Brown-out Reset Voltage Selection // Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices
37
config ZCD =      OFF      ; Zero-cross detect disable // Zero-cross detect circuit is disabled at POR.
38
config PPS1WAY =    ON      ; Peripheral Pin Select one-way control // The PPSLOCK bit can be cleared and set only once in software
39
config STVREN =      ON      ; Stack Overflow/Underflow Reset Enable bit // Stack Overflow or Underflow will cause a reset
40
config DEBUG =      OFF      ; Background Debugger // Background Debugger disabled
41
42
; CONFIG3
43
config WDTCPS =      WDTCPS_31   ; WDT Period Select bits // Divider ratio 1:65536; software control of WDTPS
44
config WDTE =      OFF      ; WDT operating mode // WDT Disabled, SWDTEN is ignored
45
config WDTCWS =      WDTCWS_7    ; WDT Window Select bits // window always open (100%); software control; keyed access not required
46
config WDTCCS =      SC      ; WDT input clock selector // Software Control
47
48
; CONFIG4
49
config WRT =      OFF      ; UserNVM self-write protection bits // Write protection off
50
config SCANE =      available; Scanner Enable bit // Scanner module is available for use
51
config LVP =      ON      ; Low Voltage Programming Enable bit // Low Voltage programming enabled. MCLR/Vpp pin function is MCLR.
52
53
; CONFIG5
54
config CP =      OFF      ; UserNVM Program memory code protection bit // Program Memory code protection disabled
55
config CPD =      OFF      ; DataNVM code protection bit // Data EEPROM code protection disabled
56
57
;*******************************************************************************************************************************    
58
;    
59
;            ++++ Macrodefininations ++++
60
;   
61
; Skip macros:
62
;
63
  skipnc    MACRO
64
  BTFSC      STATUS,STATUS_C_POSITION
65
  ENDM
66
67
  skipc      MACRO
68
  BTFSS      STATUS,STATUS_C_POSITION
69
  ENDM
70
71
  skipnz    MACRO
72
  BTFSC      STATUS,STATUS_Z_POSITION
73
  ENDM
74
75
  skipz      MACRO
76
  BTFSS      STATUS,STATUS_Z_POSITION
77
  ENDM
78
  
79
;***************************************************************************************************************************************
80
    
81
; Power-On-Reset entry point
82
  
83
PSECT   Por_Vec,global,class=CODE,delta=2
84
global  resetVec
85
    
86
resetVec:
87
    
88
    PAGESEL  START
89
    GOTO  START
90
    
91
;******************************************** Data space use by interrupt handler to save context ******************************************
92
93
94
PSECT   Isr_Data,global,class=RAM,space=1,delta=1,noexec
95
96
GLOBAL  WREG_save,STATUS_save,PCLATH_save
97
98
WREG_save:      DS  1
99
STATUS_save:    DS  1
100
PCLATH_save:    DS  1
101
102
; Interrupt vector and handler
103
  
104
PSECT   Isr_Vec,global,class=CODE,delta=2
105
GLOBAL  IsrVec
106
107
IsrVec:
108
    
109
    MOVWF  WREG_save        ; This context saving and restore  
110
    SWAPF  STATUS, W  
111
    CLRF  STATUS
112
    MOVWF  STATUS_save     
113
    MOVF  PCLATH, W        
114
    MOVWF  PCLATH_save
115
    CLRF  PCLATH
116
117
;IsrHandler:
118
      
119
    MOVLB  0xE
120
    BTFSS  PIR4, 0x0
121
    NOP
122
  
123
UButton:       
124
       
125
    ; if(IO_RB0_PORT == 0 && IO_RB1_PORT == 1) // Up-Button
126
  
127
    MOVLB  0x0
128
    BTFSC  PORTB, 0x0
129
    GOTO  DButton
130
    BTFSS  PORTB, 0x1
131
    GOTO  DButton
132
    GOTO  VCountInc
133
134
VCountInc:
135
136
    ; if(++counter >=512)counter =0; // Variablenpaar Counter inkrementieren
137
  
138
    MOVLW  0x1
139
    ADDWF  countlow, F
140
    MOVLW  0x0
141
    ADDWFC  counthigh, F
142
    MOVLW  0x2
143
    SUBWF  counthigh, W
144
    MOVLW  0x0
145
    BTFSC  STATUS, 0x2
146
    SUBWF  countlow, W
147
    BTFSS  STATUS, 0x0
148
    GOTO  DButton
149
    CLRF  countlow
150
    CLRF  counthigh
151
152
DButton:
153
154
    ; if(IO_RB0_PORT == 1 && IO_RB1_PORT == 0)  
155
  
156
    BTFSS  PORTB, 0x0
157
    GOTO  IsrExit
158
    BTFSC  PORTB, 0x1
159
    GOTO  IsrExit
160
    GOTO  VCountDec
161
162
VCountDec:
163
164
    ; if(counter > 0)counter --;
165
   
166
    MOVF  countlow, W
167
    IORWF  counthigh, W
168
    BTFSC  STATUS, 0x2
169
    GOTO  IsrExit
170
    MOVLW  0x1
171
    SUBWF  countlow, F
172
    MOVLW  0x0
173
    SUBWFB  counthigh, F
174
175
IsrExit:
176
177
    MOVF  PCLATH_save, W    ; This context saving and restore
178
    MOVWF  PCLATH          
179
    SWAPF  STATUS_save, W   
180
    MOVWF  STATUS          
181
    SWAPF  WREG_save, F
182
    SWAPF  WREG_save, W
183
    MOVLB  0xE      ; Clearing IF flag 
184
    BCF    PIR4, 0x0
185
    RETFIE        ; Return from interrupt
186
187
;****************************************************************************************************************************************
188
189
START:
190
    
191
    ; PINS  INITIALISIEREN
192
    
193
    ; TRIS alle auf Output, außer RB0 und RB1 = Inputs
194
  
195
    MOVLB   0x0       ; Bank 0
196
    CLRF    TRISA
197
    MOVLW   0x03
198
    MOVWF   TRISB
199
    CLRF    TRISC
200
    CLRF    TRISD
201
    CLRF    TRISE
202
    
203
    ; Data Latch Register
204
205
    CLRF   LATA
206
    CLRF   LATB
207
    CLRF   LATC
208
    CLRF   LATD
209
    CLRF   LATE
210
    
211
    ; PORT Register // 1 = Port pin is > V IH // 0 = Port pin is < V IL
212
  
213
    CLRF   PORTA
214
    CLRF   PORTB
215
    CLRF   PORTC
216
    CLRF   PORTD
217
    CLRF   PORTE
218
    
219
    ; ANSEL ANALOG SELECT REGISTER // 1 = Analog input. Pin is assigned as analog input (1) . Digital input buffer disabled. // 0 = Digital I/O. Pin is assigned to port or digital special function.
220
221
    MOVLB   0x3E        ; Bank 62
222
    CLRF    ANSELA
223
    CLRF    ANSELB
224
    CLRF    ANSELC
225
    CLRF    ANSELD
226
    CLRF    ANSELE
227
    
228
    ;WPU WEAK PULL-UP PORTB REGISTER // 1 = Pull-up enabled // 0= Pull-up disabled
229
    
230
    CLRF    WPUA
231
    MOVLW   0x03      ;RB0 und RB1 mit Pull-UP mit interne  Widersände
232
    MOVWF   WPUB
233
    CLRF    WPUC
234
    CLRF    WPUD
235
    CLRF    WPUE
236
    
237
    ; ODCON OPEN-DRAIN CONTROL REGISTER // 1 = Port pin operates as open-drain drive (sink current only) // 0 = Port pin operates as standard push-pull drive (source and sink current)
238
239
    CLRF    ODCONA
240
    CLRF    ODCONB
241
    CLRF    ODCONC
242
    CLRF    ODCOND
243
    CLRF    ODCONE
244
    
245
    ; SLRCON SLEW RATE CONTROL REGISTER // 1 = Port pin slew rate is limited // 0 = Port pin slews at maximum rate
246
 
247
    MOVLW   0xFF
248
    MOVWF   SLRCONA
249
    MOVLW   0xFF
250
    MOVWF   SLRCONB
251
    MOVLW   0xFF
252
    MOVWF   SLRCONC
253
    MOVLW   0xFF
254
    MOVWF   SLRCOND
255
    MOVLW   0x07
256
    MOVWF   SLRCONE
257
    
258
    ; INLVL INPUT LEVEL CONTROL REGISTER // 1 = ST input used for PORT reads and interrupt-on-change // 0 = TTL input used for PORT reads and interrupt-on-change
259
            
260
    MOVLW   0xFF
261
    MOVWF   INLVLA
262
    MOVLW   0xFF
263
    MOVWF   INLVLB
264
    MOVLW   0xFF
265
    MOVWF   INLVLC
266
    MOVLW   0xFF
267
    MOVWF   INLVLD
268
    MOVLW   0x0F
269
    MOVWF   INLVLE
270
      
271
    ; TIMER 1 INIT:
272
273
    MOVLB  0x4        
274
    CLRF  T1GCON
275
    CLRF  T1GATE          
276
    MOVLW  0x1    ; FOSC/4 1Mhz
277
    MOVWF  T1CLK
278
    MOVLW  0xB    ; TMR1H = 0xB; 1s Timerperiode
279
    MOVWF  TMR1H
280
    MOVLW  0xDC    ; TMR1L = 0xDC 
281
    MOVWF  TMR1L
282
    MOVLB  0xE    ; Clearing IF flag before enabling the interrupt.PIR4bits.TMR1IF = 0
283
    BCF    PIR4, 0x0
284
    MOVLB  0x4    ; Load the TMR value to reload variable // timer1ReloadVal=(uint16_t)((TMR1H << 8) | TMR1L)
285
    MOVF  TMR1H, W
286
    MOVWF  0x277
287
    MOVF  TMR1L, W
288
    MOVWF  0x276             
289
    MOVLB  0xE    ; Enabling TMR1 interrupt.PIE4bits.TMR1IE = 1
290
    BSF    PIE4, 0x0
291
    MOVLB  0x4
292
    MOVLW  0x25    ; 0010 0101 > 1:4 Prescale Timer on
293
    MOVWF  T1CON 
294
    
295
    ; TIMER 2 INIT:
296
297
    BANKSEL  T2CLKCON            ; T2CS FOSC/4 (1Mhz)
298
    BSF    BANKMASK(T2CLKCON),T2CLKCON_CS0_POSITION    
299
    CLRF  T2HLT              ; T2PSYNC Not Sync // T2MODE Software control // T2CKPOL Rising Edge // T2CKSYNC Not Sync          
300
    CLRF  T2RST              ; T2RSEL T2CKIPPS pin              
301
    MOVLW  0x7C              ; PR2 124  2Khz  PWM-Frequenz
302
    MOVWF  T2PR
303
    CLRF  T2TMR              ; TMR2 0
304
    BANKSEL  PIR4              ; Clearing TMR2IF
305
    CLRF  PIR4
306
    BANKSEL  T2CON
307
    BSF   BANKMASK(T2CON),T2CON_TMR2ON_POSITION      ; T2CKPS 1:1 // T2OUTPS 1:1 // TMR2ON on 
308
309
    ; CCP1 PWM INIT:
310
311
    BANKSEL  CCP1CON              ; MODE PWM; EN enabled; CCP1FMT right_aligned
312
    MOVLW  0x8F
313
    MOVWF  CCP1CON
314
    MOVLW  0xFF              ; Dutywert 255
315
    MOVWF  CCPR1L
316
    CLRF  CCPR1H
317
    BANKSEL  CCPTMRS0            ; Selecting Timer 2
318
    MOVLW  0x01
319
    MOVWF  CCPTMRS0
320
    BANKSEL  RC3PPS              ; Output RC3
321
    MOVLW  0x09
322
    MOVWF  RC3PPS
323
324
    PAGESEL  MAIN
325
    GOTO  MAIN    
326
      
327
    ; Main application data Variables
328
    
329
    PSECT  MainData,global,class=RAM,space=1,delta=1,noexec
330
    global  counthigh,countlow
331
    
332
    counthigh:  DS      1      ; Variable 1 Byte
333
    countlow:  DS  1
334
    
335
    ; Main application code
336
337
    PSECT   MainCode,global,class=CODE,delta=2
338
    global  MAIN
339
    
340
MAIN:
341
    
342
    ; Enable the Global Interrupts                           
343
    ; Enable the Peripheral Interrupts      
344
               
345
    BSF    INTCON, 0x6
346
    BSF    INTCON, 0x7
347
    BANKSEL  countlow
348
    CLRF  countlow
349
    CLRF  counthigh
350
    
351
WORK:
352
353
    BANKSEL  countlow
354
    MOVF  countlow, W
355
    MOVWF  PORTD
356
    MOVF  counthigh, W
357
    MOVWF  PORTA   
358
    GOTO  WORK       
359
      
360
; Declare Power-On-Reset entry point
361
362
END    resetVec

: Bearbeitet durch User
von Paul2 (Gast)


Lesenswert?

Der Dateianhang wurde bereits erfunden.

von Rudi R. (microwitsch)


Lesenswert?

Paul2 schrieb:
> Der Dateianhang wurde bereits erfunden.

ups,sorry ok gucke mal wie das hier geht!;o)

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.