Forum: Mikrocontroller und Digitale Elektronik LEDs an PIC ausglimmen lassen


von nighti (Gast)


Lesenswert?

Hallo zusammen,

ich hoffe, es erbarmen sich ein paar von euch, um mir zu helfen.
Was ist mein Problem?
Ich habe einen PIC16F µC und möchte 8 LEDs separat ansteuern und damit 
das kurze Aufleuchten nicht alzu ruppig erscheint, sollte es 
ausglimmen/"faden".

Beim PIC werden 8 Ports als Input und entsprechend 8 als Output 
verwendet. Die pull-up Widerstände sind ausgeschalten. 
Versorgungsspannung des PIC ist 5V und die LEDs sind standard 5mm und 
benötigen 20mA und 2,1V.

Googln hat mir zwar schon ne Menge Ideen gebracht, aber nicht wirklich 
eine Lösung passend für mein Problem.
Was habe ich bisher probiert?
ELKOs in verschiedensten Dimensionen von 100µF bis 3300µF. Leider will 
es mir nicht einleuchten, warum bei Reihenschaltung von LED+Widerstand 
und dem ELKO direkt am Ausgang des PIC die LED permanent leuchtet. Es 
scheint fast so, als würde der ELKO den Ausgang ständig offen halten.
Also danach mit einer Diode probiert. Die Diode an einen Ausgangspin und 
daran ELKO und LED+Widerstand parallel in Richtung GND geschalten. 
Klappt soweit, aber bsp. beim 1000er ELKO glimmt die LED gefühlt ne 
Ewigkeit nach bis sie tatsächlich "erloschen" ist.
Also brauch ich ein Bauteil, was erst ab einer gewissen Stromspannung 
aktiviert wird und sonst sperrt, also der ELKO nicht ewig die LED mit 
minimalem Strom versorgen soll. Da dachte ich an einen Transistor. Da 
scheitere ich allerdings etwas an einer vernünftigen Schaltung. Gibt es 
vielleicht auch eine andere Diode, die mir bei dem Problem weiterhelfen 
kann? Das Problem ist ja die doch sehr geringe Spannung die als 
Aktivierung nur benötigt werden soll. Vielleicht 0,3 V o.ä..

Mit den Transistoren wären mir ehrlich gesagt auch zu viele Bauteile für 
die 8 LEDs zu verbauen.
Gibt es eine Möglichkeit mit nur einem ELKO alle 8 LEDs separat zu 
versorgen, um den gewünschten Nachleuchteffekt zu erhalten?

Ist die Idee mit der Diode grundsätzlich ok, oder hab ich da eventuell 
Probleme mit unerwünschten Strömen?

Beim PIC gibt es fürs Dimmen ja auch das PWM. Analog zur Frage oben, 
gibt es eine Schlatung, bei der ich mit nur einem PWMsignal alle 8 LEDs 
separat ansteuern kann? D.h. wenn ich Inputpin1 aktiviere und Outpupin1 
auf High schaltet, dass dann nur die LED an Outputpin1 nachglimmt?

Wäre für Hilfe wirklich dankbar, da ich langsam etwas verzweifele.

Besten Dank im Voraus für eure Mühen und konstruktiven Hinweise!

von multimeter90 (Gast)


Lesenswert?

Moin,

soll dir der Elko die Spannung solange halten, dass die LED verzögert 
bzw langsam ausgeht?
Wie sagst du denn, dass die LED ausgehen soll? Ich hoffe du schaltest 
den Pin des PICs nicht auf GND? Du müsstest wenn zwischen HIGH und 
Tristate umschalten.

Willst du immer nur eine LED an schalten, oder mehrere völlig unabhängig 
voneinander? Ich empfehle eine Software-PWM mit einem Timer zu bauen. 
Ist auch hier als Artikel vorhanden. Es reicht ja relativ langsam, 
sodass du nix flackern siehst.

von Teo D. (teoderix)


Lesenswert?

Das mit dem Elko vergiß mal schnell!
Lies dich mal besser ins Thema (Soft-)PWM ein.

http://www.mikrocontroller.net/articles/AVR-Tutorial:_PWM
Auch wenn's da nicht um PICs geht, die Technik ist die gleiche.

: Bearbeitet durch User
von nighti (Gast)


Lesenswert?

multimeter90 schrieb:
> Moin,
>
> soll dir der Elko die Spannung solange halten, dass die LED verzögert
> bzw langsam ausgeht?
Genau das ist das Ziel.

> Wie sagst du denn, dass die LED ausgehen soll? Ich hoffe du schaltest
> den Pin des PICs nicht auf GND? Du müsstest wenn zwischen HIGH und
> Tristate umschalten.
Also momentan sind an den Outputpins je ein Widerstand und eine LED 
gegen GND geschalten. Wird Inputpin von High auf Low gesetzt, dann wird 
das Outputpin auf High gesetzt und die Led leuchtet kurz auf und der 
Outputpin wird wieder auf Low gesetzt.


> Willst du immer nur eine LED an schalten, oder mehrere völlig unabhängig
> voneinander? Ich empfehle eine Software-PWM mit einem Timer zu bauen.
> Ist auch hier als Artikel vorhanden. Es reicht ja relativ langsam,
> sodass du nix flackern siehst.
Wenn du so fragst, dann wohl eher mehrere völlig unabhänig voneinander. 
Da ist auch mein Problem, dass ich das mit einem PWMsignal und nem PIC 
nicht wirklich gebastelt bekomm, oder anders- nicht weiß wie da eine 
Schaltung aussehen könnte.

@Teo Derix:
Den Beitrag hatte ich auch entdeckt, aber brachte mich nicht wirklich 
weiter, da ich wie oben beschrieben, leider nicht weiß, wie ich mit 
einem PWM Signal meherere LEDs unabhängig ansteuern kann.
Dennoch besten Dank für den Link.

von nighti (Gast)


Lesenswert?

Hat noch jemand hilfreiche Hinweise für mich?

von X-X (Gast)


Lesenswert?

nighti schrieb:
> Beim PIC gibt es fürs Dimmen ja auch das PWM. Analog zur Frage oben,
> gibt es eine Schlatung, bei der ich mit nur einem PWMsignal alle 8 LEDs
> separat ansteuern kann? D.h. wenn ich Inputpin1 aktiviere und Outpupin1
> auf High schaltet, dass dann nur die LED an Outputpin1 nachglimmt?

Du bräuchtest 8 PWM Kanäle einzeln steuerbar und auch noch in dem 
Bereich.

Das wird schwierig.

Soft PWM ist das Mittel der Wahl, Beispiele gibt es im Netz zu hauf.

von nighti (Gast)


Lesenswert?

Ähm. Ich hatte doch geschrieben,  dass ich nur einen pwm-port habe. D.h. 
dein Vorschlag klappt leider nicht.

Könnte mir jemand bzgl. Kondensatorschaltung helfen? (Siehe erster Post)

von Markus (Gast)


Lesenswert?

nighti schrieb:
> Ich hatte doch geschrieben,  dass ich nur einen pwm-port habe.

Darum eben mit Soft-PWM. Da brauchst du keinen PWM-Port, dafür etwas 
mehr an SW.
http://www.mikrocontroller.net/articles/AVR-Tutorial:_PWM#PWM_in_Software

http://www.mikrocontroller.net/articles/Soft-PWM

Das mit Kondensator zu lösen, wenn schon ein Controller da ist, ist doch 
murks.

von Roland (Gast)


Lesenswert?

nighti schrieb:
> Könnte mir jemand bzgl. Kondensatorschaltung helfen? (Siehe erster Post)

mach mal noch einen Widerstand parallel zur LED

von nighti (Gast)


Lesenswert?

Markus schrieb:
> nighti schrieb:
>> Ich hatte doch geschrieben,  dass ich nur einen pwm-port habe.
>
> Darum eben mit Soft-PWM. Da brauchst du keinen PWM-Port, dafür etwas
> mehr an SW.
> http://www.mikrocontroller.net/articles/AVR-Tutori...
>
> http://www.mikrocontroller.net/articles/Soft-PWM
>
> Das mit Kondensator zu lösen, wenn schon ein Controller da ist, ist doch
> murks.

Ach herje. Jetzt begreif ich so langsam in welche Richtung es gehen soll 
;-)
Danke für die nochmalige Verdeutlichung des SoftPWM. Das scheint auch 
die beste Lösung des Problems zu sein. Nun bin ich allerdings Neuling 
was die Programmierung von PICs betrifft und bin schon froh ein 
Lauflicht programmiert zu haben. Ohne Vorkenntnisse habe ich da mit 
Assembler begonnen.

Habt ihr da mal einen Link für mich wo jemand SoftPWM mit Assembler 
programmiert hat? Optimalerweise für LEDs?

Habe bereits den Link entdeckt 
Beitrag "LED Fading mir PIC"
Allerdings ist der Kommentar "Du musst nur die
Register belegen und ab geht die Post, in C geht das sogar noch
einfacher." für mich etwas unklar. Könnte mir jemand einen Ansatz 
bringen, was ich tun muss, damit z.B. PORTB1 mit PWM ausfaded? 
Entsprechend würd ich das ja dann für die andren Pins anpassen können.
Wäre demjenigen (derjeinigen? ;-) )hier echt dankbar :)

von nighti (Gast)


Lesenswert?

Hat jemand vielleicht ein paar codeschipsel für mich? Bzw einen 
passenden link, den ich noch nicht entdeckt habe?

von Stefan (Gast)


Lesenswert?


von nighti (Gast)


Lesenswert?

Stefan schrieb:
> Versuch es mal hier:
> http://www.sprut.de/electronic/pic/grund/pwm.htm

Leider hilft mir das bei multiplen unabhängig schaltbaren leds nicht 
wirklich weiter.

von Karl H. (kbuchegg)


Lesenswert?

Na ja. So schwer ist das auch wieder nicht.

Kannst du bereits mit einem Timer und einer zugehörigen Interrupt 
Service Routine (ISR) umgehen?

Das wäre dein erster Schritt.
Lass dich nicht irre machen von denen, die dir einreden, das ginge auch 
ohne.
Ja es geht auch ohne. In Demonstrationsprogrammen. Aber wenn es etwas 
vernünftiges sein soll, kommst du um Timer + ISR nicht herum.

Die ISR ist dann für dich einfach nur ein Stück Code, welches 
(timergesteuert) regelmässig alle x µ-Sekunden ausgeführt wird. Das x 
wird durch die Timereinstellungen gesteuert.


Eine Soft-PWM ist dann im Grunde ganz einfach. Zu jeder LED gehört ein 
Zahlenwert, der eine Aussage darüber macht, wie hell sie leuchten soll. 
Ich nehm jetzt der Einfachheit halber an, das wären Zahlen von 0 bis 3.

D.h. wenn die LED1 mit Helligkeit 2 und die LED2 mit Helligkeit 1 
leuchten soll, dann bedeutet das einfach nur, dass LED1 von 4 Perioden 2 
eingeschaltet und 2 ausgeschaltet sein soll. LED2 hingegen ist von den 4 
Perioden nur 1 eingeschaltet und 3 ausgeschaltet
1
  Zeitschritt   LED1 (2)    LED2 (1)
2
 -------------------------------------
3
      0           ein       ein
4
      1           ein       aus
5
      2           aus       aus
6
      3           aus       aus

Das ist aber nicht weiter schwer.
Ein derartiger Zeitschritt, das ist nichts anders als der Aufruf deiner 
ISR. Jeder Aufruf der ISR ist ein Zeitschritt.
Du brauchst dann noch einen unabhängigen Zähler, der die Schrittnummer 
zählt.
Denn jetzt kommts. Wie kannst du leicht entscheiden, ob die LED ein oder 
aus sein muss, in einem bestimmten Zeitschritt.
Schau dir die Tabelle an. Jede LED ist genau dann eingeschaltet, wenn 
ihr vorgegebener Helligkeitswert kleiner als die SChrittnummer des 
Zeitschritts ist.
Im SChritt 0 gilt:
LED1 soll einen Helligkeitswert von 2 haben. 0 ist kleiner als 2, daher 
ist die LED in diesem Schritt eingeschaltet.
LED2 soll einen Helligkeitswert von 1 haben. 0 ist kleiner als 1, daher 
ist die LED in diesem Schritt eingeschaltet.
Im Schritt 1 gilt:
LED1 soll einen Helligkeitswert von 2 haben. 1 ist kleiner als 2, daher 
ist diese LED in diesem Schritt eingeschaltet.
LED2 soll einen Helligkeitswert von 1 haben. 1 ist aber nicht kleiner 
als 1, daher ist die LED in diesem Zeitschritt ausgeschaltet.

Und so werden die LED eine nach der anderen in jedem Zeitschritt (bei 
jedem ISR Aufruf) gegen die Schrittnummer geprüft und je nach Ergebnis 
ein oder ausgeschaltet.
In Summe kommt dann eben raus, dass die LED über die Schritte gemittelt 
mal mehr bzw. wenig oft eingeschaltet ist. Demenstprechend leuchtet sie 
für uns Menschen heller oder weniger hell (tatsächlich blinken sie nur 
unterschiedlich. Aber das merken wir nicht)

Das ist das Grundprinzip einer PWM. Das ist jetzt eine sehr einfache 
Variante von PWM und es gibt algorithmisch bessere Versionen. Aber fürs 
erste wirds auch das tun.

Aber: Alles beginnt mit einem Timer und seiner ISR, die du brauchst um 
das Konzept der Zeitschritte zu implementieren.

: Bearbeitet durch User
von Stefan (Gast)


Lesenswert?

Kein Mensch wird dir hier
ein fertiges Programm schreiben.
Da wirste dich schon selber dran machen müßen.
Beispiele gibt es genug im Netz, sogar hier im
Forum. Und wie es geht, wurde ja hier auch
schon beschrieben. Nun fang an zu Programmieren
und wenn du nicht weiter weist, dann zeig was
du bis jetzt gemacht hast, dann wird dir
auch weiter geholfen.

von nighti (Gast)


Lesenswert?

Karl Heinz schrieb:
> Na ja. So schwer ist das auch wieder nicht.
>

Hab ganz lieben Dank für die ausführliche Erklärung! Sehr verständlich- 
auch für Anfänger ;)
Mein Problem ist allerdings, dass ich mit den Timerinterrupts so meine 
Probleme bekommen werde.
Momentan ist die Struktur meines Programms wie folgt:
1
Variablendeklarationen
2
start
3
     Anfangssetup
4
loop
5
    ;***********************************
6
;*** A4 wird gedrückt (Pinwatch0)
7
8
  btfsc  PINWatch,0    ;bleibt A4 gedrückt, so sollen die LEDs nicht nochmal ausgelöst werden
9
  goto  $+5
10
  btfss  PORTA,4
11
  call  Wait20      ;wenn Taste gedrückt warte 20ms um Prellen zu verhindern
12
  btfss  PORTA,4      ;wenn A4=0, dann löse entsprechende LED-Laufreihe aus
13
  call  A4LED
14
15
  analog die anderen Pins von PortA
16
17
   Pinwatch wird gecheckt, ob z.B. A4 gedrückt bleibt und somit in der nächsten Schleife nicht ausgelöst wird.
18
19
   goto loop
20
21
LEDEffekte
22
A4LED
23
A4LED
24
  bsf  PORTB, 2
25
  call  Wait100
26
27
  bsf  PORTB, 3
28
  bsf  PORTB, 5
29
  bsf  PORTB, 1
30
  call  Wait100
31
  
32
  bcf  PORTB, 3
33
  bcf  PORTB, 5
34
  bcf  PORTB, 1
35
  bsf   PORTB, 4
36
  bsf  PORTB, 6
37
  bsf  PORTB, 0  
38
  call  Wait100
39
40
  bcf   PORTB, 4
41
  bcf  PORTB, 6
42
  bcf  PORTB, 0
43
  bsf   PORTB, 7  
44
  call  Wait100
45
46
  bcf   PORTB, 7
47
48
  bsf  PINWatch,0    ;wird Bit gesetzt, so wird die LED nicht nochmals ausgelöst durch gedrücktlassen von A4
49
  
50
  bcf  PORTB, 2
51
52
  return
53
end.
--------------------------------

Da ist zwar noch ein wenig mehr an Basteleien drin enthalten, aber die 
tun erstmal nix zur Sache.
Wenn ich nun mit nem Timer permanent Interrupts auslöse, dann wird im 
blödesten Falle ja immer das LEDAnsteuern unterbunden.

Wie ihr vielleicht auch seht, möchte ich nicht nur eine LED mit einem 
PORTApin auslösen, sondern eine Abfolge von LEDs. Die sollten dann aber 
eben nachglimmen.

Eine Idee von mir wäre nun die (main) loop als ISR zu setzen und am Ende 
irgendwie den Vorschlag von Karl Heinz aufzugreifen und die Leds via 
Counter zu dimmen.
Allerdings müsste das Dimmen sich ja auf die LEDEffekte beziehen und die 
zeitlich in ihrer Abfolge auch noch irgendwie berücksichtigen. Hat da 
jeamdn einen Gedankenstoß für mich?

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

nighti schrieb:

> Wenn ich nun mit nem Timer permanent Interrupts auslöse, dann wird im
> blödesten Falle ja immer das LEDAnsteuern unterbunden.

Ähm.
Im Timerinterrupt werden die LED angesteuert. Und NUR im Timerinterrupt.

Dein Hauptprogramm steuert die LEDs insofern an, dass es die gewünschten 
Helligkeitswerte setzt. Nicht mehr und nicht weniger. Umgesetzt, im 
Sinne von 'durch die Art der Led Ansteuerung realisiert' werden die 
Helligekeitswerte dann im Timer Interrupt.

Und ja. In deinem Programm bleibt kein Stein auf dem anderen. Wenn du 
mit der Aufgabenstellung dann fertig bist, sieht es komplett anders aus 
als jetzt.

: Bearbeitet durch User
von nighti (Gast)


Lesenswert?

Dann frag ich mal anders:
Würde jemand für eine Aufwandsentschädigung mir nach obigen Vorgaben ein 
Programm schreiben?
Wenn ja, dann bitte hier posten, dann meld ich mich im Forum an und 
schreib eine pn.
Würd mich freuen.

von pic p. (pic0)


Lesenswert?

Schreib bitte die Vorgaben nochmals zusammen.

von Nosnibor (Gast)


Lesenswert?

Karl Heinz schrieb:
> Und ja. In deinem Programm bleibt kein Stein auf dem anderen.

Kompromißvorschlag: Das Hauptprogramm macht weiterhin seine LED-Effekte, 
aber anstatt ins Portregister schreibt es an eine bestimmte 
Speicherstelle. Und der Interrupt sieht an dieser Speicherstelle nach, 
wie er seine PWM-Werte ändern soll. Wenn da steht LED an, dann setzt er 
den entsprechenden PWM-Wert auf Maximum, wenn da steht LED aus, dann 
zieht er 1 vom PWM-Wert ab, falls er noch nicht 0 ist. Dadurch erledigt 
der Interrupt das Ausglimmen, und das Hauptprogramm bleibt im 
wesentlichen unverändert.

von pic0 (Gast)


Lesenswert?

memory reservieren fuer leds:
1
 leds res 8 ; 8 byte for led pwm state
2
 led  res 1 ; leds werden hier und nicht in portb reingeschrieben.
3
4
; angenommen wird, portb high = led on
5
6
7
#define endPWM
8
startPWM macro 
9
 local done
10
 decfsz pwm
11
 goto done
12
 decfsz pwm ; 
13
 clrf portb
14
done
15
 endm
16
17
doPWM macro bit
18
 movlw 0xff
19
 btfsc led,bit
20
 decfsz leds+bit,w
21
 movwf leds+bit
22
 xorwf pwm,w
23
 skpnz
24
 bsf  portb,bit
25
 endm

Code fuer Timer Interrupt:
1
 startPWM
2
 doPWM 0
3
 doPWM 1
4
 doPWM 2
5
 doPWM 3
6
 doPWM 4
7
 doPWM 5
8
 doPWM 6
9
 doPWM 7
10
 endPWM

Damit sollte eigentlich alles klar sein, wenn du Fragen hast, einfach 
reinschreiben.

: Bearbeitet durch User
von nighti (Gast)


Lesenswert?

pic0 hab echt vielen lieben Dank! Zumindest ist mir nun klar, wie das 
ganze laufen kann.

Mit Interrupts hab ich bisher leider noch keine Erfahrungen gemacht, 
aber sprut und co helfen mir da grad auf die Sprünge.

pic0 schrieb:
> #define endPWM
> startPWM macro
>  local done
>  decfsz pwm
>  goto done
>  decfsz pwm ;
>  clrf portb
> done
>  endm

Hier verstehe ich nur nicht ganz den Block. Bezieht sich endPWM durch 
das "define" nun auf den ganzen Macroblock?

Besten Dank mal wieder im voraus :)

von Chris (Gast)


Lesenswert?

> das "define" nun auf den ganzen Macroblock?

Nein, es ist nur eine Konvention von mir, dass es auch ein endPWM gibt.
 z.B. folgender Code, auch pwm.

#define TICK flags,3

startPWM macro
  bcf   TICK
  movlw 0x04   ; 64 pwm steps
  addwf led_pwm
  skpnc
  bsf   TICK
  endm

doPWM macro bit
  comf  led_cnt+bit,w
  addwf  led_pwm,w
  rlf  led_tmp
  endm

endPWM macro
  movfw  led_tmp
  movwf  portb
  endm

hier braucht es ein endPWM. Da es im obigen Falle kein endPWM braucht,
wird einfach ein leeres define verwendet.
Define ist vom c preprozessor, und wird vor dem Macro angewendet.
Define kann nur eine Zeile gehen, ein macro kann mehrere Zeilen haben.
Ich kann z.B folgendes machen
#define noop goto $+1
dasselbe ist
noop macro
    goto $+1
  endm
auch kann man machen:
noop macro
   clrwdt
   nop
   endm

dasselbe geht aber nicht mehr mit einem define.
Auch kann man folgendes mit einem Macro nicht nachbilden:
#define TICK flags,3
und z.B der Befehl bz ist ein macro wie folgt welches der assembler 
kennt:
bz macro lbl
  btfsc 3,2
  goto lbl
  endm

von nighti (Gast)


Lesenswert?

Besten Dank für die Erklärung.

Ich trau mich ja schon fast gar nicht mehr zu fragen und ich fühl mich, 
je länger ich am Rechner sitze, immer mehr so nach dem Motto: "Gehe 
zurück zur Badstrasse" weil mehr unklar wird als klar..

Verzeih mir die doofen Nachfragen aber folgende Probleme hab ich:

Wozu ein endPWM "leer" definieren, wenns doch gar nicht gebraucht wird? 
Dann kann ich den Zugriff auf endPWM doch einfach als Befehl löschen, 
oder hat es einen tieferen Sinn im Interrupt zu haben?

pic0 schrieb:
> startPWM macro
>  local done
>  decfsz pwm
>  goto done
>  decfsz pwm ;
>  clrf portb
> done
>  endm

Bei mir meckert der Assembler, dass "Using default destination of 1 
(file)." in den Zeilen wo pwm geprüft wird, also hier Zeile 3 und 5. 
Eine Ahnung woran das liegt? Ich habe das Macro in keine andere Datei 
ausgelagert- liegt es daran?

pic0 schrieb:
> doPWM macro bit
>  movlw 0xff
>  btfsc led,bit
>  decfsz leds+bit,w
>  movwf leds+bit
>  xorwf pwm,w
>  skpnz
>  bsf  portb,bit
>  endm

Die Var "leds" soll a 8 byte groß sein, um vermutlich die PWM für jede 
LED festzulegen, aber was bewirkt die Addition "leds+bit"? Ist mir 
leider schleierhaft. Oder beziht sich die "PWMstate" leds auf die 8 
Helligkeitsstufen der LEDs? Dummerweise ist mir auch da schleierhaft, 
was die Addition bewirkt..

Ich hoffe, es nervt nicht zu sehr zu viele Anfängerfragen zu 
beantworten.

Besten Dank!

von pic0 (Gast)


Lesenswert?

nighti schrieb:
> Besten Dank für die Erklärung.
>
> Ich trau mich ja schon fast gar nicht mehr zu fragen und ich fühl mich,
kein Problem

> Wozu ein endPWM "leer" definieren, wenns doch gar nicht gebraucht wird?
einfach als Konvention, weil ich es meistens dann doch noch brauch, z.B.
fuer ein Multiplexing, oder sonstwas.
> Dann kann ich den Zugriff auf endPWM doch einfach als Befehl löschen,
> oder hat es einen tieferen Sinn im Interrupt zu haben?
klar hatte man dies auch loeschen konnen.
Der Grund ist vielleicht, dass die Macros bei mir vor dem Programm und 
Variablen sind und deshalb die Definition und Implementierung getrennt 
sind, ist aber keine wirkliche Erklaerung. Ist halt eine Konvention von 
mir, bzw mache ich es so. Andere machen es anders.
>
>>  decfsz pwm
>>  goto done
>>  decfsz pwm ;
>
> Bei mir meckert der Assembler, dass "Using default destination of 1
> (file)." in den Zeilen wo pwm geprüft wird, also hier Zeile 3 und 5.
> Eine Ahnung woran das liegt? Ich habe das Macro in keine andere Datei
> ausgelagert- liegt es daran?

Nein, es haengt von meiner schlechten Programmierung ab.
man muesste es so schreiben, dann meckert der Assembler nicht mehr
>>  decfsz pwm,f
>>  goto done
>>  decfsz pwm,f ;

Am Anfang ist es gut, diese Warnings eingeschaltet zu haben.
Message[302] C:\MTC_3_T-336.ASM 115 : Register in operand not in bank 0.
Ensure that bank bits are correct.
Message[305] C:\MTC_3_T-336.ASM 151 : Using default destination of 1
(file).
Wenn man dann ASM beherrscht, dann schaltet man diese gerne aus mittels
 errorlevel -302,-305
um jetzt, z.B. diese zwei Warnings auszuschalten.
Auch ein
 radix dec
 wird gerne verwendet. Man kann aber auch immer ,f schreiben, und auch
 D'10' fuer dezimal 10 usw. Ich bevorzuge den Radix auf dezimal zu 
stellen
 und 0xff sowie 0b111 fuer hex sowie binary zu verwenden. Auf octal
 muss man halt noch aufpassen, sprich keine Zahl mit 0 anzufangen.

> Die Var "leds" soll a 8 byte groß sein, um vermutlich die PWM für jede
> LED festzulegen, aber was bewirkt die Addition "leds+bit"? Ist mir
> leider schleierhaft.
Angenommen du hast eine 16bit Variable foo und dein Konvention ist, 
zuerst low byte und dann high byte, sprich little endian und du willst 
die Zahl 12345 laden, dann ist der Code folgender:
 movlw high(12345)
 movwf foo+1
 movlw low(12345)
 movwf foo
foo ist eine Variable mit adresse 0x20 als Beispiel
 man kann eine Variable wie folgt definieren
; =
foo = 0x20
bar = 0x22
; equ
foo equ 0x20
bar equ 0x22
; set
foo set 0x20
bar set 0x22
; define
#define foo 0x20
; res
foo res 2
bar res 2
; cblock
  foo :2
  bar :2

Egal, welche Methode man benutzt, foo hat die Adresse 0x20 und folgender
code ist identisch:
 movwf foo
 movwf .32 ; .32 = D'32' , eine kurzschreibweise
 und natuerlich foo + 1 ist dasselbe wie 32+1 = 33 , also Adresse 33, 
das
 high byte von foo, oder wenn foo ein Array von bytes ist, index 1.

Poste mal deinen Code, dann schaue ich darueber und korrigiere ich den.

von M. H. (nighti)


Lesenswert?

Zunächst einmal sry für das sinnfreie doppelte Nachfragen bzgl endPWM. 
Da ich aber noch nicht angemeldet war, konnte ich den Post nicht mehr 
ändern.. Hattest ja schon vorher geschrieben, dass es eine reine 
Konvention von dir ist. Da hatten sich eigentlich schon alle Fragen 
erübrigt ;-)

Aber nun zurück..
Also ich verzweifel gerade an dem Setzen der Bank1. Keine Ahnung warum 
das gerade nichtmehr klappt. Dachte, es liegt an der 
Speicheraddressierung, aber die Variablen liegen ja nun deutlich weit 
hinten..
1
  list  p=16F628A
2
3
  __CONFIG  _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _BODEN_OFF & _MCLRE_OFF & _CP_OFF & _LVP_OFF
4
5
  #include <P16f628A.INC>
6
7
;******************************************************************************************
8
  ORG  0x60
9
pwm  RES  1
10
leds  RES  8
11
led  RES  1
12
loops  RES  1
13
loops2  RES  1
14
PINWatch  RES  1    ;0=B4; 1=B5; 2=B6; 3=B7; 4=B3; 5=B2; 6=B1; 7=B0
15
16
TKTZ1  RES  1
17
TKTZ2  RES  1
18
TKTZ3  RES  1
19
w_temp  RES  1
20
status_temp  RES  1
21
22
startPWM macro 
23
   local   done
24
  decfsz   pwm, f
25
   goto   done
26
   decfsz   pwm, f
27
   clrf   PORTB
28
done
29
  endm
30
31
doPWM   macro  bit
32
   movlw   0xff
33
   btfsc   led,bit
34
   decfsz   leds+bit,w
35
   movwf   leds+bit
36
   xorwf   pwm,w
37
   skpnz
38
   bsf    PORTB,bit
39
  endm
40
41
;******************************************************************************************
42
43
  ORG  0x00
44
  goto  start
45
46
;******************************************************************************************
47
48
  ORG  0x04
49
50
  movwf   w_temp
51
      swapf   STATUS,w
52
      bcf     STATUS, RP0         ; status_temp in Bank 0
53
      movwf   status_temp
54
55
  startPWM
56
  doPWM 0
57
  doPWM 1
58
  doPWM 2
59
  doPWM 3
60
  doPWM 4
61
  doPWM 5
62
  doPWM 6
63
  doPWM 7
64
      
65
  swapf   status_temp,w
66
      movwf   STATUS
67
      swapf   w_temp,f
68
      swapf   w_temp,w
69
      retfie 
70
71
;******************************************************************************************
72
73
start
74
  BSF      CMCON, CM0    
75
      BSF      CMCON, CM1
76
      BSF      CMCON, CM2
77
78
  bcf  STATUS,RP1
79
  bsf  STATUS,RP0    ;Bank 1 wird gesetzt
80
  bcf  OPTION_REG, 7    ;keine pull up Widerstände an PortB
81
  movlw  B'00000000'    ;Output: alle PortB
82
  movwf  TRISB
83
  movlw  B'11111111'    ;Input: alle PortA
84
  movwf  TRISA
85
  bcf  STATUS, RP0    ;wieder Bank 0
86
87
  ; Timer 2 für PWM einstellen
88
89
    clrf     T2CON
90
  bsf      T2CON, T2CKPS1      ; Vorteiler 16:1
91
  ; bsf   T2CON, T2CKPS0
92
  bsf      T2CON, TMR2ON       ; Timer2 ein
93
94
  ; Frequenz + duty cycle
95
96
    bsf  STATUS, RP0    ;Bank 1 wird gesetzt
97
    movlw    d'128'              ; xxx kHz
98
    movwf    PR2
99
100
    bcf  STATUS, RP0    ;wieder Bank 0
101
    movlw    d'64'               ; duty cycle: 50% von xxx sind yyy
102
    movwf    CCPR1L
103
104
    movlw    b'00001100'         ; Start, PWM active high
105
    movwf    CCP1CON
106
107
  bcf  STATUS, RP0    ;wieder Bank 0
108
109
110
111
  clrf  PORTA
112
  clrf  PORTB
113
  clrf  PINWatch    ;jeder Inputpin (1-8 lt. Beschreibung) kann aktiviert werden, bei 1 wird LED nicht ausgleöst
114
  movlw  D'2'
115
  movwf  TKTZ1
116
  movwf  TKTZ2
117
  movlw  D'2'
118
  movwf  TKTZ3
119
120
121
loop
122
123
;***********************************
124
;*** A4 wird gedrückt (Pinwatch0)
125
126
  btfsc  PINWatch,0    ;bleibt A4 gedrückt, so sollen die LEDs nicht nochmal ausgelöst werden
127
  goto  $+5
128
  btfss  PORTA,4
129
  call  Wait20      ;wenn Taste gedrückt warte 50ms um Prellen zu verhindern
130
  btfss  PORTA,4      ;wenn A4=0, dann löse entsprechende LED-Laufreihe aus
131
  call  A4LED
132
133
;#################################################################
134
;... analoger Code für die andren Pins
135
136
137
  btfsc  PORTA, 1    ;wenn A1 gedrückt bleibt, dann wird jede Schleife runtergezählt, bis der Saver startet
138
  goto  $+11
139
  decfsz  TKTZ1,F      ;Überspringe nächsten Befehl, wenn Z=1 (Differenz gleich Null)
140
  goto  loop
141
  
142
  btfsc  PORTA, 1
143
  goto  $+7
144
  decfsz  TKTZ2,F
145
  goto  loop
146
147
  btfsc  PORTA, 1
148
  goto  $+4
149
  decfsz  TKTZ3,F
150
  goto  loop  
151
152
  goto  LEDSaver    ;LEDSaver
153
154
  movlw  D'2'
155
  movwf  TKTZ1
156
  movwf  TKTZ2
157
  movlw  D'2'
158
  movwf  TKTZ3
159
160
  goto  loop
161
162
;******************************************************************************************
163
;*** LED-Effekte für einzelne Pins
164
165
A5LED
166
  bsf  PORTB, 3
167
  call  Wait100
168
169
  bsf  PORTB, 2
170
  bsf  PORTB, 4
171
  call  Wait100
172
  
173
  bcf   PORTB, 2
174
  bcf   PORTB, 4
175
  bsf   PORTB, 1
176
  bsf  PORTB, 5  
177
  call  Wait100
178
179
  bcf   PORTB, 1
180
  bcf   PORTB, 5
181
  bsf   PORTB, 0
182
  bsf  PORTB ,6  
183
  call  Wait100
184
185
  bcf   PORTB, 0
186
  bcf   PORTB, 6
187
  bsf  PORTB, 7  
188
  call  Wait100
189
190
  bcf   PORTB, 7
191
  bsf  PINWatch,1    ;wird Bit gesetzt, so wird die LED nicht nochmals ausgelöst durch gedrücktlassen von A4
192
  
193
  bcf  PORTB, 3
194
195
  return
196
197
198
;#################################################################
199
;... analoger Code für die andren Pins
200
201
;**********************************************************
202
; Warteschleife 150 ms
203
Wait150
204
        movlw   D'150'          ; 150 ms Pause
205
        movwf   loops 
206
  goto  Wai
207
208
;**********************************************************
209
; Warteschleife 250 ms
210
Wait250
211
        movlw   D'250'          ; 250 ms Pause
212
        movwf   loops 
213
  goto  Wai
214
215
;**********************************************************
216
; Warteschleife 20 ms
217
Wait20
218
        movlw   D'20'          ; 20 ms Pause
219
        movwf   loops 
220
  goto  Wai
221
222
;**********************************************************
223
; Warteschleife 100 ms
224
225
Wait100
226
        movlw   D'100'          ; 100 ms Pause
227
        movwf   loops 
228
229
Wai
230
        movlw   .110           ; Zeitkonstante für 1ms
231
        movwf   loops2
232
Wai2    nop                    ; 
233
        nop
234
        nop
235
        nop
236
        nop
237
        nop
238
        decfsz  loops2, F      ; 1 ms vorbei?
239
        goto    Wai2           ; nein, noch nicht
240
                               ;
241
        decfsz  loops, F       ; 250 ms vorbei?
242
        goto    Wai            ; nein, noch nicht
243
        return                 ; das Warten hat ein Ende

Nun meckert er, dass bei
1
start
2
  BSF      CMCON, CM0    
3
      BSF      CMCON, CM1
4
      BSF      CMCON, CM2
5
6
  bcf  STATUS,RP1
7
  bsf  STATUS,RP0    ;Bank 1 wird gesetzt
8
  bcf  OPTION_REG, 7    ;keine pull up Widerstände an PortB
9
  movlw  B'00000000'    ;Output: alle PortB
10
  movwf  TRISB
11
  movlw  B'11111111'    ;Input: alle PortA
12
  movwf  TRISA
13
  bcf  STATUS, RP0    ;wieder Bank 0

Optionreg, trisb und trisa "Register in operand not in bank 0.  Ensure 
that bank bits are correct.".
Ich weiß gerade beim besten Willen nicht, warum der Assembler nicht das 
Stausbit setzt und auf Bank 1 umschaltet. Laut Datenblatt muss RP0 
gesetzt und RP1 gelöscht sein?

: Bearbeitet durch User
von chris (Gast)


Lesenswert?

Der Compiler Meckert nur, dies heisst nicht, dass es nicht passt.
aber ich glaube, du hast ganz andere Fehler, wieso es nicht passt.

list  p=16F628A

  __CONFIG  _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _BODEN_OFF & 
_MCLRE_OFF & _CP_OFF & _LVP_OFF

  #include <P16f628A.INC>

_WDT_OFF usw wird erst in der Include definierte, schon deshalb duerft 
dein
Programm nicht compilierbar sein und der assembler muesste ein unknown 
symbol oder sonstwas ausspucken, mit einer grossen Error dran.

Um das Meckern abzustellen, wie bereits oben geschrieben kannst du dies 
machen, aber wie gesagt, Anfaenger sollten es an lassen.

 list  p=16F628A
 errorlevel -302,-305
 radix dec

  #include <P16f628A.INC>

  __CONFIG  _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _BODEN_OFF & 
_MCLRE_OFF & _CP_OFF & _LVP_OFF


Werde mir den Code ansehen. Hast du den jemals assembliert ?

von Chris B. (dekatz)


Lesenswert?

Das ist ja keine Fehlermeldung sondern eine Warnung, das du auf die 
Bankumschaltung achten solltest (weil nach einem Reset ist immer Bank 0 
eingestellt ist). Diese Hinweise werden immer dann auftauchen wenn auf 
ein Register zugegriffen wird, welches NICHT in Bank 0 liegt. Man kann 
diese Warnung allerdings auch abschalten - wurde glaube ich schon oben 
erwähnt).

Da du es ja gemacht hast, kannst du das Ignorieren.

Und wenn du dir das Disassembler Listing ansiehst, findest dort auch die 
beiden "STATUS"-Befehle samt erzeugten Opcode. Also alles im grünen 
Bereich.

von Patrick B. (p51d)


Lesenswert?

Ich finde es ja gut, wenn heute noch jemand mit Assembler programmieren 
kann, und es auch noch lernen will. Aber wieso machst du dir das Leben 
unnötig schwer? Lerne doch gleich C, da bist du innerhalb von ~10h am 
Ziel und hast ein funktionierendes Programm. Weiter hast du die 
Vorteile, dass du auch gleich auf dem PC mit C programmieren kannst, 
oder du gehts noch etwas weiter und lernst C# und C++ für den PC, was 
auch nicht viel Aufwand ist (für kleine Erfolge). Der einzige Grund für 
Assembler ist aus meiner Sicht die Optimierung bis zum geht-nicht-mehr. 
Aber selbst da greift man lieber zum nächsten uC und kopiert den Code 
mit ein paar kleinen Anpassungen und muss nicht wie in Assembler gleich 
alles neu schreiben.

von M. H. (nighti)


Lesenswert?

Hi Chris, schön, dass du regelmäßig hier reinschaust. Das freut mich 
sehr. Danke für den Hinweis.
Bzgl. PWM ist da aber noch nix weiter passiert. Das muss ich noch 
machen/vertshen. :)
Ich wollt den Auszug aus dem Quellcode nur posten, damit man das Gefühl 
hat, ich mache auch tatsächlich was und fordere nicht nur Dinge :)

chris schrieb:
> Werde mir den Code ansehen. Hast du den jemals assembliert ?

Jupp und der Assembler meckert da nicht im Ansatz ;P Den Code brauchst 
dir glaube in dem Status noch nicht weiter anschauen, da ich wie gesagt 
noch am PWM dran bin...

Chris B. schrieb:
> Und wenn du dir das Disassembler Listing ansiehst, findest dort auch die
> beiden "STATUS"-Befehle samt erzeugten Opcode. Also alles im grünen
> Bereich.

Danke für den Hinweis :)

Patrick B. schrieb:
> Aber wieso machst du dir das Leben
> unnötig schwer?

Hi Patrick, gute Frage. Ehrlich gesagt bin ich da einer Empfehlung 
gefolgt (ich glaube sprut?), zuerst Assembler zu lernen und dann eine 
höhere Sprache, da man dann auch weiß, was man hardwareseitig zu 
berücksichtigen hat. C soll danach Einfach zu verstehen sein. Also gibt 
es nicht wirklich einen guten Grund dafür ;-) Außerdem gefiel mir die 
doch sehr überschaubare Anzahl an möglichen Befehlen, die in Kombi eben 
dennoch alles bewerkstelligen können.

So far..

Besten Dank bis dahin ;)

von chris (Gast)


Lesenswert?

dann muss die IDE automatisch die Datei inkludieren.

Ich habe hier dann einen Code fuer dich, nicht getestet.

;**********************************************************************
;   This file is a basic code template for assembly code generation   *
;   on the PIC16F628A. This file contains the basic code              *
;   building blocks to build upon.                                    *
;                                                                     *
;   Refer to the MPASM User's Guide for additional information on     *
;   features of the assembler (Document DS33014).                     *
;                                                                     *
;   Refer to the respective PIC data sheet for additional             *
;   information on the instruction set.                               *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Filename:      xxx.asm                                           *
;    Date:                                                            *
;    File Version:                                                    *
;                                                                     *
;    Author:                                                          *
;    Company:                                                         *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files Required: P16F628A.INC                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes:                                                           *
;                                                                     *
;**********************************************************************

  list      p=16f628A           ; list directive to define processor
  #include <p16F628A.inc>       ; processor specific variable 
definitions

  errorlevel  -302              ; suppress message 302 from list file
    radix dec
  __CONFIG   _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF 
& _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT

; '__CONFIG' directive is used to embed configuration word within .asm 
file.
; The lables following the directive are located in the respective .inc 
file.
; See data sheet for additional information on configuration word 
settings.

#define skip    goto $+2
#define PWM_STEP  32
#define TICK_FLAG  intcon,t0if

#define TICK_PER_MS  1000/256

#define pressed 0

waitMS  macro  ms
    movlw  -(ms/4)
    movwf  cnt1
  if (ms/4) > 128
    tstf  cnt1
    bnz    $-2
  else
    btfss  cnt1,7
    goto  $-1
  endif
  endm

if_pressed MACRO port,pin
  if (pressed)
    btfsc  port, pin
  else
    btfss  port, pin  ;   Wait for Button Released
  endif
    goto   done+1
    waitMS  50

  if (pressed)
    btfsc  port, pin
  else
    btfss  port, pin  ;   Wait for Button Released
  endif
done
  endm


;***** VARIABLE DEFINITIONS
  cblock  0x70
    isr_w    ; holds W reg during interrupt
    ticks:3
    cnt1    ; timer that is looked at 0
  endc

  clbock  0x20
    isr_status
    isr_fsr
    led      ; led bit pattern
    leds:8    ; leds pwm value
    pwm      ; pwm timer
    pwm_tmp
    pwm_cnt

  endc




PORTA_INIT  =  0b00000000  ;
PORTB_INIT  =  0b00000000  ;
TRISA_INIT  =  0b11111111  ; all input
TRISB_INIT  =  0b00000000  ; all output
OPTION_INIT  =  0b10001000  ; | !RBPU |INTEDG| T0CS | T0SE | PSA | PS2 | 
PS1 | PS0 |
        ; 1-------  => no internal pullup on portb
        ; ----1---  => prescaler assigned to WDT
INTCON_INIT  =  (1<<GIE)|(1<<T0IE)  ;


;**********************************************************************
  ORG     0x000             ; processor reset vector
  nop
  clrf  PCLATH
  call  init
  goto    main              ; go to beginning of program


  ORG     0x004             ; interrupt vector location
  movwf   isr_w            ; save off current W register contents
  movf  STATUS,w          ; move status register into W register
  movwf  isr_status       ; save off contents of STATUS register
  movfw  fsr
  movwf  isr_fsr

; isr code can go here or be located as a call subroutine elsewhere
   btfsc   intcon,t0ie
   btfss  intcon,t0if
   goto    t0_done

   movlw  -((1000000/256/PWM_STEPS-2) ; PWM_STEPS = 1 tick, 256 Tick = 1 
sec
   addwf  tmr0

   movlw  leds
   movwf  fsr

   bsf    TICK_FLAG
   movlw  256/PWM_STEPS
   addwf  pwm
   skpc
   bcf    TICK_FLAG

   movfw  led
   movwf  pwm_tmp

   movlw  8
   movwf  pwm_cnt
pwm_loop
       rrf    pwm_tmp
     skpnc
     clrf    0
     comf    0,w
     addwf  pwm
     btfsc  TICK_FLAG
     incfsz  0
     skip
     decfsz  0
     incfsz  4
  decfsz  pwm_cnt
  goto  pwm_loop

  rrf    pwm_tmp,w
  movwf  portb

  btfss  TICK_FLAG
  goto  t0_done-1

  incfsz  ticks
  skip
  incfsz  ticks+1
  skip
  incf  ticks+2

   decfsz  cnt1  ; 3,9ms timer
   incfsz  cnt1
   incfsz  cnt1

  bcf  intcon,t0if
t0_done

; isr code can go here or be located as a call subroutine elsewhere

  movfw  isr_fsr
  movwf  fsr
  movf    isr_status,w     ; retrieve copy of STATUS register
  movwf  STATUS            ; restore pre-isr STATUS register contents
  swapf   isr_w,f
  swapf   isr_w,w          ; restore pre-isr W register contents
  retfie                    ; return from interrupt



init
  clrf   status
  movlw  7
  movwf  CMCON
  movlw  PORTA_INIT
  movwf  PORTA
  movlw  PORTB_INIT
  movwf  PORTB
  clrf  1
  clrwdt
  bsf    STATUS,RP0
  movlw  OPTION_INIT
  movwf  1
  movlw  TRISA_INIT
  movwf  TRISA
  movlw  TRISB_INIT
  movwf  TRISB

  clrf  status
  movlw  0x20
  movwf  4
  clrf  0
  incf  4
  btfss  4,7
  goto  $-3

  movlw  INTCON_INIT
  movwf  INTCON
  return


main

; remaining code goes here
; es gibt nur ein Timer, also gehen nicht mehrere Tasten gleichzeitig.

  clrw
    if_pressed  porta,0
      iorlw  1<<0
    if_pressed  porta,1
      iorlw  1<<1
    if_pressed  porta,2
      iorlw  1<<2
    if_pressed  porta,3
      iorlw  1<<3
    if_pressed  porta,4
      iorlw  1<<4
  movwf  led

    waitMS 100

  goto  main      ;loop forever, remove this instruction, for test only


; initialize eeprom locations

  ORG  0x2100
;  DE  0x00, 0x01, 0x02, 0x03


  END                       ; directive 'end of program'

von M. H. (nighti)


Lesenswert?

Zunächst einmal vielen lieben Dank Chris!

Leider spuckte der Assembler mir einen Batzen Fehler vor die Füße und 
selbst nachdem ich alle Ungereimtheiten beseitigt hatte, kann ich als 
Anfänger deinen Code nicht ganz nachvollziehen. Ohne Dokumentation kann 
ich da leider wenig mit anfangen :(
Das if_pressed Macro z.B. bleibt mir völlig schleierhaft. Die 
btfss/btfsc Befehle machen doch rein technisch gesehen gar nichts. Auch 
die Sprungmarke 'done' mag der Assembler so nicht akzeptieren. Habe mal 
spaßenshalber statt auf done+1 zu verweisen auf $+7 verwiesen.

Was die gesamte Logik des PWM betrifft, scheine ich allerdings auch noch 
nicht wirklkich verstanden zu haben, was ich wann wie an welche Variable 
übergeben muss. Muss wohl doch die Artikel nochmals lesen- vielleicht 
diesmal mit etwas mehr Aha-Effekten..

von chris (Gast)


Angehängte Dateien:

Lesenswert?

> Ohne Dokumentation kann
> ich da leider wenig mit anfangen :(
Einfach fragen, was du nicht verstehst.

> Das if_pressed Macro z.B. bleibt mir völlig schleierhaft. Die
> btfss/btfsc Befehle machen doch rein technisch gesehen gar nichts.
doch die machen genau dies, was das Datasheet sagt.

#define pressed 0 ; Wann ist die Taste gedrueckt (pressed),
                  ;  wenn 0 oder 1 gelesen wird. Hier im Beispiel 0

Macro reduziert auf den Fall pressed = 0

if_pressed MACRO port,pin
  local  done
    btfsc  port, pin  ; skip if pin is 0
    goto   done+1     ; jump to end of of
    waitMS  20        ; 20 ms Warten

    btfss  port, pin  ; skip if pin is 1
done
  endm

 also wenn man es so benutzt

if_pressed porta,0
  goto button_pressed

dann wenn die Taste gedrueckt wird, wird button_pressed angesprungen,
ansonsten wird der nächste Befehl nach if_pressed einfach uebersprungen.

Je nach Qualität der Taster muss man ev. die 20ms raufsetzen.



;***** VARIABLE DEFINITIONS
  cblock  0x70 ; variablen welche aus allen Banks erreichbar sind
  cblock  0x20 ; variablen in Bank0

; init, kann auch mit #define gemacht werden, ich habe dies lieber,
; da es dann in der .lst aufgelistet wird.
PORTA_INIT  =    00000000b  ;

; isr code can go here or be located as a call subroutine elsewhere
   btfsc   intcon,t0ie ; if not T0 Interrupt enabled
   btfss  intcon,t0if  ; or T0 Interrupt not fired
   goto    t0_done     ; then goto to t0_done
                       ; else :

   movlw  -(1000000/PWM_RATE/PWM_STEPS-2) ; PWM_STEPS = 1 tick, 256 Tick 
= 1 sec
   addwf  tmr0 ; nächsten Interrupt nach 122 uS als Beispiel nach diesem

   movlw  leds ; lade Pointer auf Array leds[8]
   movwf  fsr  ; in das INDF register

   bsf    TICK_FLAG     ; setze Flag auf 1
   movlw  256/PWM_STEPS ; lade Increment Wert in W
   addwf  pwm           ; addiere es zu pwm , setzt Carry flag im 
Overflow
   skpc                 ; sprich nach jedem PWM Zyklus.
   bcf    TICK_FLAG     ; lösche Flag wenn kein neuer Zyklus
; ab hier ist TICK_FLAG jedesmal wahr, wenn pwm den Wert 0 hat.
   movfw  led           ; lade Led
   movwf  pwm_tmp       ; in tmp register

   movlw  8             ; for(pwm_cnt=0;pwm_cnt<8;pwm_cnt++) ...
   movwf  pwm_cnt
pwm_loop                ; {
       rrf    pwm_tmp   ; tmp>>=1  ; lsb von tmp geht ins Carry
     skpnc              ; wenn Led gesetzt
     clrf    0          ; lösche leds[pwm_cnt] -- bit0 = leds[0] , ....
     comf    0,w        ; W = ~led[pwm_cnt] ; complementäre Logic
     addwf  pwm         ; W = W + pwm , Carry gesetz wenn Überlauf
     btfsc  TICK_FLAG   ; wenn neue PWM Periode
     incfsz  0          ; decrementiere (incr) led PWM Wert,
     skip               ; limitiere led[pwm_cnt] auf 0 (0xff)
     decfsz  0
     incfsz  4          ; pwm_cnt++ , incrementiert Pointer auf leds
  decfsz  pwm_cnt       ;
  goto  pwm_loop       ; }

  rrf    pwm_tmp,w     ; schiebt letztes Carry von PWM ein und läd W
  movwf  portb         ; gibt PWM auf portb aus

  btfss  TICK_FLAG     ; wenn neue PWM Periode
  goto  t0_done-1      ; ende von t0_int

  incfsz  ticks        ; incrementiere Ticks
  skip
  incfsz  ticks+1      ; 16bit increment
  skip
  incf  ticks+2        ; 24bit increment

   decfsz  cnt1  ; 3,9ms timer
   incfsz  cnt1  ; welcher hochzählt
   incfsz  cnt1  ; und auf 0 stehenbleibt

  bcf  intcon,t0if ; Lösche Interrupt Flag
t0_done

; isr code can go here or be located as a call subroutine elsewhere

  movfw  isr_fsr
  movwf  fsr
  movf    isr_status,w     ; retrieve copy of STATUS register
  movwf  STATUS            ; restore pre-isr STATUS register contents
  swapf   isr_w,f
  swapf   isr_w,w          ; restore pre-isr W register contents
  retfie                    ; return from interrupt



init
  ; status löschen
  ; comparator ausschalten
  ; Portregister setzen
  ; Timer löschen
  ; Wdt löschen
  ; Option setzen
  ; Trisregister setzen
  ; status löschen
  ; Ram von 0x20 - 0x7f löschen
  ; Interrupt Register setzten
  ; return  ich hab dies lieber,
  ; da ich ev. dann init im Programm aufrufen kann.

main

; remaining code goes here
; es gibt nur ein Timer, also gehen nicht mehrere Tasten gleichzeitig.

; taster 1-5 (bit0-4) wird auf led gesetzt

  clrw
    if_pressed  porta,0
      iorlw  1<<0
    if_pressed  porta,1
      iorlw  1<<1
    if_pressed  porta,2
      iorlw  1<<2
    if_pressed  porta,3
      iorlw  1<<3
    if_pressed  porta,4
      iorlw  1<<4
  movwf  led

    waitMS 80

  goto  main      ;loop forever, remove this instruction, for test only

Was versteht du da genau nicht ?

von M. H. (nighti)


Lesenswert?

chris schrieb:
> movlw  leds ; lade Pointer auf Array leds[8]
>    movwf  fsr  ; in das INDF register
>
>    bsf    TICK_FLAG     ; setze Flag auf 1
>    movlw  256/PWM_STEPS ; lade Increment Wert in W
>    addwf  pwm           ; addiere es zu pwm , setzt Carry flag im
> Overflow
>    skpc                 ; sprich nach jedem PWM Zyklus.
>    bcf    TICK_FLAG     ; lösche Flag wenn kein neuer Zyklus
> ; ab hier ist TICK_FLAG jedesmal wahr, wenn pwm den Wert 0 hat.
>    movfw  led           ; lade Led

Hi Chris, ich bin dir wirklich dankbar für deine Hilfe.

Im Prinzip fehlt mir die generelle Logik des Programmaufbaus. So alla 
Flußdiagramm. Ich weiß einfach nicht, welche Variablen ich in der Main 
ändern bzw. setzen muss, damit etwas in der ISR ausgelöst wird.
Würde mich vor allem gerade echt ärgern, weil du dir ja augenscheinlich 
extra Zeit genommen hast, um das Programm anzupassen...

chris schrieb:
> iorlw  1<<0

Auch diese Anweisung hab ich im Buch leider nicht gefunden. Was bewirkt 
'<<'?

: Bearbeitet durch User
von chris (Gast)


Lesenswert?

Die Variable LED wird verwendet, um die Leds an Portb anzuzeigen, mit 
automatischen fading out in ca 1 Sekunde.
Sei es PWM_RATE sowie PWM_STEPS ändern diese Zeit.
PWM_RATE ist die PWM Frequenz, 256 HZ derzeit, und PWM_STEPS die Anzahl 
der
PWM Schritte, derzeit 32. Bei beiden können auch krumme Werte verwendet 
werden, wie z.b. 100, 60, .. .
http://www.microautomate.com/PIC/pic-timing-timers.php
erklärt dir die 2/3 Register, welche fuer den Timerinterrupt
zuständig sind. Im Datenblatt steht dasselbe, bzw steht es genauer.
Diesem Code generiert einen T0 Interrupt  alle
4Mhz/4/PWM_RATE/PWM_STEPS = 1000000/256/32 = 122 µS .
Dies ist im OPTION_INIT und INTCON_INIT und durch setzen des TMR0 
Register
im Interrupt definiert. Mehr gibt es da nicht.

Eigentlich, da ich dort einen kleinen Fehler gemacht habe, das
   movlw  -(1000000/256/PWM_STEPS-2) ; PWM_STEPS = 1 tick, 256 Tick = 1 
sec
müsste so sein
   movlw  -(1000000/256/PWM_STEPS-2) ; PWM_STEPS = 1 tick, 256 Tick = 1 
sec
Die CPU braucht 2 clk um den Timer update zu machen.
Also wenn die CPU ein addwf tmr0 macht, und in W -100 drinsteht, dann
bei prescaler 0 braucht es 100 clk Cyclen

von chris (Gast)


Lesenswert?

1<<0 => 1 , oder bit 0 ist on
 1<<3 => 8 , oder bit 3 ist on
INTCON = 1<<GIE|1<<T0IE ; -- INTCON = 0x84 -- oder 10000100b ,
also bit GIE und bit T0IE ist on, sprich die Zahl eins 7 mal nach links 
geschoben und 1<<T0IE ist eins 3 mal nach links geschieben,  | ist ein 
verodern der bits, hier dasselbe wie ein + .

Eine Übersicht über die Operatoren: 
http://www.peacesoftware.de/ckurs4.html
abgesehen von den Operatoren mit = werden alle unterstuetzt, die
Vergleichsoperatoren werden unterstuetzt.

von chris (Gast)


Lesenswert?

der code ist derselbe:
 clrw
    if_pressed  porta,0
      iorlw  00001b
    if_pressed  porta,1
      iorlw  00010b
    if_pressed  porta,2
      iorlw  00100b
    if_pressed  porta,3
      iorlw  01000b
    if_pressed  porta,4
      iorlw  10000b
  movwf  led

von M. H. (nighti)


Lesenswert?

Besten Dank für die Hinweise! Wieder was dazugelernt bzgl. 
Programmierung.

Nun aber noch einmal zurück zu der Frage, was ich in der Main(loop) 
ansteuern muss, damit eine LED auf high gesetzt wird und anschließend 
ausfaded? Reicht ein einfaches bsf led,pin?

: Bearbeitet durch User
von chris (Gast)


Lesenswert?

Alles was du in led reinschreibst, wird auf den leds rausgeschrieben,
ob mit direkter Zuweisung oder mit Bits setzen.
Das fading ist automatisch, nachdem das Bit gelöscht wurde.
Nur, das Register led wird alle 122µS gelesen, bzw aktualisiert.
Also wenn du ein
  bsf led,0
 machst, und dann ein
  bcf led 0,
 wird warscheinlich nichts passieren, aber wenn du z.B. den obigen
Code nimmst, mit if_pressed , oder inzwischen ein waitMS machst, dann
funktioniert es, da dann sichergestellt ist, daß ein Interrupt 
inzwischen
aufgetreten ist.

von M. H. (nighti)


Lesenswert?

Ahh... das klingt sehr elegant.
Nun habe ich auf meiner Testplatine den Pic damit ausprobiert, aber beim 
Start leuchten alle LEDs, die einen mehr die andre weniger.
Die Eingänge sind bei mir alle auf High gesetzt und werden dann gegen 
GND gezogen, sodass ein LOW die LED auslösen soll. Kann durch diese 
Logikumkehrung dieses Problem entstehen?

von pic p. (pic0)


Angehängte Dateien:

Lesenswert?

Dies tut mir Leid.
Die Zeile      addwf  pwm  war falsch, sollte      addwf  pwm,w sein.

Im Anhang habe ich dir noch was reinkopiert, schau es dir mal an,
EEprom read sowie Flash read und random

Die Obige Source sollte gelöscht werden, werde es flaggen.

Wenn was nicht funktioniert oder du was anderst haben willst, einfach
melden.

von M. H. (nighti)


Lesenswert?

pic prog schrieb:
> Dies tut mir Leid.
> Die Zeile      addwf  pwm  war falsch, sollte      addwf  pwm,w sein.
>
> Im Anhang habe ich dir noch was reinkopiert, schau es dir mal an,
> EEprom read sowie Flash read und random
>
> Die Obige Source sollte gelöscht werden, werde es flaggen.
>
> Wenn was nicht funktioniert oder du was anderst haben willst, einfach
> melden.

Wow. Bin beeindruckt wie hilfsbereit du bist!
Allerdings wird dein Programm immer komplexer und für mich immer weniger 
nachvollziehbar. Muss ich wohl mal Zeile für Zeile durchgehen und für 
mich sortieren.
Leider scheint auf PORTA nur ein High die Leds auszulösen. Bräuchte ja 
genau den umgekehrten Fall, d.h. High ist Standardzustand und bei 
Lowpegel sollte LED ausgelöst werden. Ehrlich gesagt, kann ich aber eine 
Anpassung hier auch nichtmehr wirklich annehmen. Hast mir schon eine 
Menge gezeigt und hab viel gelernt. Bin grad selbst dran für mich das 
Fading von grundauf zu verstehen und zu programmieren. Es scheitert bei 
mir schon an den Grundlagen, dass für mich unklar ist, was XORLW 
tatsächlich bewirkt.. Brauche wohl mal einen Intensivkurs..

Also vielen lieben Dank für deine Hilfe!

von Ottmar K. (wil1)


Lesenswert?

M. Hahn schrieb:
> Es scheitert bei mir schon an den Grundlagen, dass für mich unklar
> ist, was XORLW tatsächlich bewirkt..

Hallo,
Ich mach' mal den Versuch - vielleicht hilft dies:
;
;Beispiel zum Vergleich zweier beliebiger Zahlenwerte 0-255
;----------------------------------------------------------
;---Initialisierung der zu vergleichende Zahlen
movlw d'101'          ;Istwert (z.B. Zählerstand)
movwf Zahl_beliebig
movlw d'100'          ;zu prüfender Sollwert
movwf Zahl_Sollwert
;
;---Zahlenwerte vergleichen (hier gehts los)
;
movf  Zahl_beliebig,w  ;1. Istwert ins WREG
xorwf Zahl_Sollwert,w  ;2. WREG (Istwert) mit Sollwert vergleichen
                       ;   oder
                       ;   xorlw d'100' Istwert mit Festwert (Literal)
                       ;   vergleichen.
                       ;   Ergebnis steht in beiden Fällen im WREG
                       ;   oder
                       ;   xorwf Zahl_Sollwert,f
                       ;   Ergebnis steht im File, also im Register
                       ;   Zahl_Sollwert)
;---Ergebnis auswerten
btfss STATUS,Z             ;Zeroflag abfragen
GOTO  Zahlen_ungleich_100  ;verzweigen, wenn Zeroflag=0
GOTO  Zahlen_gleich_100    ;            bzw. wenn Z=1
                           ;oder anderen Job erledigen z.B.
                           ;clrf ... mov...
                           ;bsc...   usw.
;----------------------------------------------------------
;
;---Erklärung des Funktionsablaufes
;
1. Istwert in das WREG kopieren
2. Exclusive ODER-Verknüpfung der beiden Zahlen
2.1 Möglichkeit 1:  Werte sind ungleich
                    Dann wird das Zeroflag in STATUS auf 0 gesetzt
    Möglichkeit 2:  Werte sind gleich
                    Dann wird das Zeroflag in STATUS auf 1 gesetzt

Exclusive ODER (XOR)
   korrespondierende Bits in zwei Binärwerten werden verglichen.
   Das Ergebnis kann nur dann 1 sein, wenn alle korrespondierenden
   Bits den gleichen Wert haben. Beispiele:

   WREG: binär 01100100 (dezimal 100)
   Zahl: binär 01100100 (dezimal 100)
               --------
   Ergebnis:   11111111 =  TRUE (1) alle Bits stimmen überein
                           TRUE = "1" wird in das Z-Flag übertragen

   WREG: binär 01100101 (dezimal 101)
   Zahl: binär 01100100 (dezimal 100)
               --------
   Ergebnis:   11111110 = FALSE (0) nicht alle Bits stimmen überein
                          FALSE ="0" wird in das Z-Flag übertragen.

mfg Ottmar

von nighti (Gast)


Lesenswert?

Schon fast ein Jahr ist es nun her, dass ich dieses Bastelprojekt in 
Angriff genommen hatte. Leider hatte ich nun zwischenzeitlich andere 
Sorgen, aber nun bin ich wieder motiviert, das endlich fertigzustellen.
Grundsätzlich habe ich mich auch wieder in die Materie eingearbeitet, 
aber muss nach wie vor gestehen, dass ich das Programm leider nicht 
nachvollziehen kann, da man z.t. über 3 Ecken schauen muss, was gemeint 
ist (Makrozugriff, Verweis auf Funktion und dann erst die jeweilige 
Operation.)
Erst einmal die Grundlegende Frage: ist das ohne externen Oszillator 
lauffähig und es wird beschrieben, dass aufgrund nur des einen Timers 
auch nur ein Taster abgefragt werden kann- heißt das, dass auch nur eine 
LED ausfaden kann oder funktioniert es dennoch, alle 8 LEDS anzusteuern 
und unterschiedliche Stufen des Fadings zu übergeben?

Besten Dank an der Stelle schon einmal vorab!

von Erich (Gast)


Lesenswert?

Hier ist alles din was du suchst, aber lesen und es versuchen zu 
verstehen solltest du selbst
http://electromotiveforces.blogspot.de/2011/10/cascading-snowfall-led-lights.html
Hinweise: Dieses Programm nutzt keine Inputs sondern erzeugt nur 
Ausgabemuster. Musst eben anpassen an was du erreichen möchstest.
Falls du das Prj neu beginnst, bitte verwende moderneren uC Pic16F1827 
o.ä., mit ner vierstelligen Nummer.
Gruss

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Ottmar K. schrieb:
> Exclusive ODER (XOR)
>    korrespondierende Bits in zwei Binärwerten werden verglichen.
>    Das Ergebnis kann nur dann 1 sein, wenn alle korrespondierenden
>    Bits den gleichen Wert haben. Beispiele:

 LOL.
 Das ist mir aber neu.

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.