Hallo Ich hab aktuell ein Problem mit einer Joystick Applikation mit einem PIC18F4520. Bin in Punkto AD leider auch kein Profi... Im Programm soll ein 10kOhm Joystick an den Pins AN0 und AN1 erfasst werden. Leider scheint das Programm jedoch stets ausschließlich AN0 zu lesen, obwohl ich im entsprechenden Interrupt den Channel wechsle? Interruptcode: if (ADIF==1) {if (CHS0==1) {adc_schiene = (ADRESH<<8)+(ADRESL); } if (CHS0==0) {adc_horizont = (ADRESH<<8)+(ADRESL); } CHS0 = ~CHS0; ADIF = 0; } Das Hauptprogramm tut aktuell nichts anderes, als bei Werten == 0 eine LED einzuschalten. Eine LED für die "X-Achse", eine für die "Y-Achse" des Joysticks. Leider schaltet mir das Programm stets beide LEDs ein, wenn ich ausschließlich in der X-Achse auf 0 fahre... Die Y-Achse ist vollkommen egal und wird überhaupt nicht beachtet? Es scheinen also beide Variablen stets den Wert des Pins AN0 anzunehmen. Woran kann das liegen? ACQT hab ich entsprechend gesetzt, im Hauptprogramm befindet sich mittlerweile sogar ein 5ms Delay... das müsste doch mehr als ausreichend sein? Danke Vinci
Versuchs doch mal so:
1 | if (ADIF==1) |
2 | {if (CHS0==1) |
3 | {adc_schiene = (ADRESH<<8)+(ADRESL); |
4 | CHS0 = 0; |
5 | }
|
6 | else
|
7 | {adc_horizont = (ADRESH<<8)+(ADRESL); |
8 | CHS0 = 1; |
9 | }
|
10 | ADIF = 0; |
11 | }
|
Zeige uns den gesammten Code, sonst ist das Helfen ziemlich schwer!
Setz hier das GO/DONE bit auch noch mal wieder auf 1. GO = 1; // Schau bei deinem Compiler nach wie dat heisst ADIF = 0; }
kannst du nicht nicht debuggen? So ein PICkit3 für ca. 50 Euro zahlt sich schnell aus, finde ich... Sonst kannst du es mit dem Microchip Simulator testen und kucken ob sich die Registern korrekt ändern.
Der Hauptcode sieht folgendermaßen aus: GODONE = 1; // ADC starten while(GODONE==1); *2x IF für die LEDs* DelayMs(5); GODONE ist definitiv richtig benannt, nutze hier Hi-Tech C und habe im entsprechenden 18F4520 file nachgesehen. Der Simulator sagt mir, dass der Channel richtig umgeschaltet wird. Werden morgen mal holgers Vorschlag ausprobieren, Debugger besitze ich leider (noch) keinen.
ohne den kompletten Code zu sehen, kann man natürlich kaum helfen. Steht da wo "*2x IF für die LEDs* steht der Code für den Interrupt? Ich hoffe nicht... Dann wäre es kein Interrupt sondern polling. Also poste doch mal deinen kompletten Code.
interrupt isr() {if (ADIF==1) // ADC Interrupt {if (CHS0==1) {adc_schiene = (ADRESH<<8)+(ADRESL); } if (CHS0==0) {adc_horizont = (ADRESH<<8)+(ADRESL); } CHS0 = ~CHS0; // schaltet abwechselnd AN0 / AN1 ADIF = 0; // ADC Interrupt-Flag löschen } if (TMR2IF==1) // Timer2 @125µs {TMR2IF = 0; TMR2 = 37; if (schiene_enable==1) {counter_schiene--; if (counter_schiene==0) {CLK_schiene = 1; counter_schiene = counter_schiene_save; DelayUs(10); CLK_schiene = 0; } } if (horizont_enable==1) {counter_horizont--; if (counter_horizont==0) {CLK_horizont = 1; counter_horizont = counter_horizont_save; DelayUs(10); CLK_horizont = 0; } } } if (INT0IF==1) // Schranke { INT0IF = 0; } } void main() {TRISA = 0b11010011; // RA2,RA3,RA5 Output TRISB = 0b11111111; // RB0 Input (Schranke), Rest ebenfalls Input TRISC = 0b00000110; // RC1-RC2 Input; RC0,RC3-RC7 Output TRISD = 0b11000000; // RD6,RD7 Input; RD0-RD5 Output TRISE = 0b00001100; // RE0,RE1 Output; RE2,RE3 Input PCFG0 = 1; PCFG1 = 0; PCFG2 = 1; PCFG3 = 1; // RA0(AN0) und RA1(AN1) analog, Rest digital PORTA = 0x00; // Initialize PORTA PORTB = 0x00; // Initialize PORTB PORTC = 0x00; // Initialize PORTC PORTD = 0x00; // Initialize PORTD PORTE = 0x00; // Initialize PORTE // ADC Einstellung (DA HATS NOCH WAS bezügl. ACQT usw.?) ADCS0 = 0; ADCS1 = 1; //ADCS2 = 0; // FOSC/32 ACQT0 = 0; ACQT1 = 0; ACQT2 = 0; // Aquisition Time manuell vergeben VCFG0 = 0; // Voltage Reference VDD VCFG1 = 0; // Voltage Reference VSS CHS0 = 1; CHS1 = 0; CHS2 = 0; CHS3 = 0; // AN1 auswählen ADFM = 1; // right justified conversion ADON = 1; // ADC enabled ADIF = 0; INT0IF = 0; TMR2IF = 0; // Interrupt Flags löschen ADIE = 1; // ADC Interrupt zulässig PEIE = 1; // Peripheral Interrupts zulässig GIE = 1; // Global Interrupts zulässig // ext. Interrupt ; Timer2 @ 125µs INTEDG0 = 0; // Interrupt on falling edge of RB0/INT0 //INT0IE = 1; // ext. Interrupt INT0 enable T2OUTPS0 = 1; T2OUTPS1 = 1; T2OUTPS2 = 0; T2OUTPS3 = 0; // Postscaler Timer 2 select (1:8) T2CKPS0 = 0; T2CKPS1 = 0; // Prescaler Timer2 select (1:1) TMR2 = 37; // Timer2 @ 125µs do { //-------------------------------------- // while(modus1==0 && modus2==0) {led1 = 0; led2 = 0; TMR2ON = 1; // Timer2 starten TMR2IE = 1; // Timer2 Interrupt zulassen while(save_taster==0) {// Speichern der vorherigen Werte, um den Counter nicht fälschlich neu zu setzen swcase_schiene_save = swcase_schiene; swcase_horizont_save = swcase_horizont; GODONE = 1; // ADC starten while(GODONE==1); if ((adc_horizont/64)==0) {CLK_horizont=1; } if ((adc_schiene/64)==0) {CLK_schiene=1; } if ((adc_horizont/64)>0) {CLK_horizont=0; } if ((adc_schiene/64)>0) {CLK_schiene=0; } //Aquisition Time? ka ob des automatisch hinhaut... DelayMs(5); } // Video starten //TRISB = 0b11111110; //RB0 = 0; /*TMR2IE = 0; // Timer2 Interrupt ausschalten led1 = 0; led2 = 0; DelayBigMs(500); led1 = 1; led2 = 1; DelayBigMs(500); led1 = 0; led2 = 0; DelayBigMs(500); led1 = 1; led2 = 1; DelayBigMs(500); led1 = 0; led2 = 0;*/ } //-------------------------------------- //-------------------------------------- // while(modus1==0 && modus2==1) {led1 = 0; led2 = 1; } //-------------------------------------- //-------------------------------------- // while(modus1==1 && modus2==0) {led1 = 1; led2 = 0; } //-------------------------------------- //-------------------------------------- // while(modus1==1 && modus2==1) {led1 = 1; led2 = 1; } //-------------------------------------- }while(1); } Wie gesagt... imho unnötig viel Information ;) Da wo die ich vorher die Sternchen gemacht hab stehen natürlich nur die IFs... kein Interrupt.
die Acquistion Time auf Null zu stellen war sicherlich nicht die klügste Lösung. Hast du Tad mal ausgerechnet, wie groß du es eingestellt hast? Dann ist im Datenblatt eine Beispielrechnug wie groß die Aquisition Time berechnet wird. Das musst du auch ausrechnen und einstellen.
Martin S. schrieb: > die Acquistion Time auf Null zu stellen war sicherlich nicht die klügste > Lösung. > > Hast du Tad mal ausgerechnet, wie groß du es eingestellt hast? > Dann ist im Datenblatt eine Beispielrechnug wie groß die Aquisition Time > berechnet wird. Das musst du auch ausrechnen und einstellen. Ich verstehe nicht so ganz. Die ACT wird doch eingehalten, da in der Programmschleife, die ich aktuell ausschließlich durchlaufe (1.while), ein Delay von 5ms erfolgt. Diese Zeit ist laut Datenblatt ein vielfaches der benötigten (10k Impedanz @ max. 50°C). ACQT auf 0 heißt somit nur, dass ich die ACT manuell mittels Programmcode berücksichtige.
Ja ok man kann es auch auf 0 einstellen, wenn man es selbst überwacht. Aber einfacher wäre es einfach einzustellen. Dein Programm ist etwas wirr. Vielleicht kannst du mal kurz beschreiben was es denn mal können soll. Z.B. Wo wird modus1 und modus2 gesetzt? Auf welchem Ausgang liegt led1 und led2. Das ist immer noch nicht der komplette Code. Sonst mach dich doch einfach mal mit dem Simulator vertraut. So schlecht ist der gar nicht. Dann kannst du mal schauen ob er den Kanal überhaupt richtig wechselt, wenn du schon kein Debugger hast.
Martin S. schrieb: > Ja ok man kann es auch auf 0 einstellen, wenn man es selbst überwacht. > Aber einfacher wäre es einfach einzustellen. > > Dein Programm ist etwas wirr. Vielleicht kannst du mal kurz beschreiben > was es denn mal können soll. > > Z.B. Wo wird modus1 und modus2 gesetzt? Auf welchem Ausgang liegt led1 > und led2. Das ist immer noch nicht der komplette Code. > > Sonst mach dich doch einfach mal mit dem Simulator vertraut. So schlecht > ist der gar nicht. Dann kannst du mal schauen ob er den Kanal überhaupt > richtig wechselt, wenn du schon kein Debugger hast. Sag ja, dass der komplette Code nur verwirrt... und doch, das ist der komplette Code. folgender Code wird aktuell durchlaufen und ist relevant: interrupt isr() {if (ADIF==1) // ADC Interrupt {if (CHS0==1) {adc_schiene = (ADRESH<<8)+(ADRESL); } if (CHS0==0) {adc_horizont = (ADRESH<<8)+(ADRESL); } CHS0 = ~CHS0; // schaltet abwechselnd AN0 / AN1 ADIF = 0; // ADC Interrupt-Flag löschen } } void main() {TRISA = 0b11010011; // RA2,RA3,RA5 Output TRISB = 0b11111111; // RB0 Input (Schranke), Rest ebenfalls Input TRISC = 0b00000110; // RC1-RC2 Input; RC0,RC3-RC7 Output TRISD = 0b11000000; // RD6,RD7 Input; RD0-RD5 Output TRISE = 0b00001100; // RE0,RE1 Output; RE2,RE3 Input PCFG0 = 1; PCFG1 = 0; PCFG2 = 1; PCFG3 = 1; // RA0(AN0) und RA1(AN1) analog, Rest digital PORTA = 0x00; // Initialize PORTA PORTB = 0x00; // Initialize PORTB PORTC = 0x00; // Initialize PORTC PORTD = 0x00; // Initialize PORTD PORTE = 0x00; // Initialize PORTE ADCS0 = 0; ADCS1 = 1; ADCS2 = 0; // FOSC/32 ACQT0 = 0; ACQT1 = 0; ACQT2 = 0; // Aquisition Time manuell vergeben VCFG0 = 0; // Voltage Reference VDD VCFG1 = 0; // Voltage Reference VSS CHS0 = 1; CHS1 = 0; CHS2 = 0; CHS3 = 0; // AN1 auswählen ADFM = 1; // right justified conversion ADON = 1; // ADC enabled ADIF = 0; INT0IF = 0; TMR2IF = 0; // Interrupt Flags löschen ADIE = 1; // ADC Interrupt zulässig PEIE = 1; // Peripheral Interrupts zulässig GIE = 1; // Global Interrupts zulässig // ext. Interrupt ; Timer2 @ 125µs INTEDG0 = 0; // Interrupt on falling edge of RB0/INT0 //INT0IE = 1; // ext. Interrupt INT0 enable T2OUTPS0 = 1; T2OUTPS1 = 1; T2OUTPS2 = 0; T2OUTPS3 = 0; // Postscaler Timer 2 select (1:8) T2CKPS0 = 0; T2CKPS1 = 0; // Prescaler Timer2 select (1:1) TMR2 = 37; // Timer2 @ 125µs do { //-------------------------------------- // while(modus1==0 && modus2==0) {led1 = 0; led2 = 0; TMR2ON = 1; // Timer2 starten TMR2IE = 1; // Timer2 Interrupt zulassen while(save_taster==0) {GODONE = 1; // ADC starten while(GODONE==1); // - IRGENDWELCHE IF-ANWEISUNGEN // //Aquisition Time DelayMs(5); } } }while(1); } Das ganze ist jetzt hoffentlich ein wenig einfacher zu verstehen. Was ich von DIESEM Code will, ist ausschließlich eine AD-Conversion einer Joystick-Position (X und Y Werte quasi). Später steuere ich damit 2 Stepper an, aber das spielt aktuell keine Rolle, da wie gesagt der Channelwechsel nicht funktioniert. Im SIMULATOR funktioniert der Wechsel jedoch! Die anderen Programmteile sind andere Modi, andere Funktionen... für mein konkretes Problem nicht relevant, deswegen wollte ich auch nicht den gesamten Code posten. Unter "IRGENDWELCHE IF-Anweisungen" hab ich wirklich nur irgendwelche Werteabfragen reingeschrieben um die Funktion zu prüfen. Also z.B. if (Position X < 123) {Schalte LED ein } if (Position Y < 123) {Schalte 2.LED ein } Damit hab ich ausgetestet, ob der AD Wandler die Joystick Positionen richtig erkennt. Zu diesem Zeitpunkt hab ich erst gemerkt, dass stets nur die X-Achse des Joysticks gewandelt wird. Also egal ob ich X oder Y Achse des Joysticks betätige, ich bekomme stets ausschließlich die X-Werte, die aber auch als Y interpretiert werden. Wenn ich also auf meiner X-Achse (Channel0) mit dem Stick spazieren fahr, so werden diese Werte für Channel0 und Channel1 angennommen. Fahr ich auf der Y-Achse spazieren, so tut sich gar nichts. Hab auch bereits geprüft, ob ich nicht in der Hardware einen Kurzen oder so hab... aber nichts dergleichen, sollte alles passen.
Das ist doch nicht der komplette Code. Wo sind die Variablendeklarationen? Du bleibst doch immer in der while Schleife, oder?
1 | while(save_taster==0) |
2 | {// Speichern der vorherigen Werte, um den Counter nicht fälschlich |
3 | neu zu setzen |
4 | swcase_schiene_save = swcase_schiene; |
5 | swcase_horizont_save = swcase_horizont; |
6 | |
7 | GODONE = 1; // ADC starten |
8 | while(GODONE==1); |
9 | |
10 | if ((adc_horizont/64)==0) |
11 | {CLK_horizont=1; |
12 | } |
13 | |
14 | if ((adc_schiene/64)==0) |
15 | {CLK_schiene=1; |
16 | } |
17 | |
18 | if ((adc_horizont/64)>0) |
19 | {CLK_horizont=0; |
20 | } |
21 | |
22 | if ((adc_schiene/64)>0) |
23 | {CLK_schiene=0; |
24 | } |
25 | |
26 | |
27 | //Aquisition Time? ka ob des automatisch hinhaut... |
28 | DelayMs(5); |
29 | |
30 | } |
save_taster wird doch nirgends verändert... Sind dann CLK_horizont und CLK_schiene deine LEDs? Woher soll man das wissen? Und weißt du was du mit der Abfrage machst? ((adc_horizont/64)==0)
Die "CLK_****" Variablen sind eigentlich Clock Signale für einen TB6560, testweise hab ich hier aber LEDs ein und ausgeschalten. Die "ADC_****" Variablen, sprich die ADC Werte die ich erhalte, teile ich durch 64 um eine Joystick Achse in 16 Stufen zu unterteilen. Quasi 1024 / 64 = 16. Jede Stufe entspricht einer gewissen Periodendauer, mit der das Clock Signal erzeugt wird. Das spielt aber, wie ich bereits erwähnt habe, für die AD Wandlung eigentlich keine Rolle. Das Problem, das nach wie vor besteht, ist, dass ich von 2 verschiedenen AD Channeln nur 1 Signal bekomme. __ Man stelle sich folgendes Beispiel mit 2 Potis vor, die an AD0 und AD1 hängen. Drehe ich Poti 1, so soll ab einem gewissen Schwellwert eine LED eingeschaltet werden. Drehe ich an Poti 2, so soll eine andere LED ab dem selben Schwellwert eingeschaltet werden. Problem ist nun: Ich drehe an Poti 1 und BEIDE LEDS leuchten. Ich drehe an Poti 2, nichts passiert. __ Natürlich verstehe ich, dass der Code hierfür wichig ist, man anstelle sich an Stelle der If's einfach die Abfragen für den ADC Wert und die LEDS vor. Diese waren 100% richtig! Die gepostete Schleife stellt nur einen Teil des Codes dar, der aktuell aber NICHT verlassen wird. Später soll dieser Teil nur einen Modus darstellen, der ab Programmstart ausgewählt werden kann.
Wähl doch einfach den MPLAB Simulator als Debugger und schau nach warum die LEDs gleich geschalten werden. Oder funktionierte da richtig?
Im MPLAB Sim funktioniert die AD-Wandlung. Da schaltet er mir meine Ausgänge nicht ständig gleichzeitig.
Hast du mal die Spannung an den Pins mit einem Messgerät gemessen?
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.