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!
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.
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
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.
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.
Ä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)
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.
nighti schrieb: > Könnte mir jemand bzgl. Kondensatorschaltung helfen? (Siehe erster Post) mach mal noch einen Widerstand parallel zur LED
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 :)
Hat jemand vielleicht ein paar codeschipsel für mich? Bzw einen passenden link, den ich noch nicht entdeckt habe?
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.
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
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.
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
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
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.
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.
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
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 :)
> 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
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!
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.
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
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 ?
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.
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.
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 ;)
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'
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..
> 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 ?
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
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
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.
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
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
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.
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?
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.
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!
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
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!
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.