Hallo! Wie schon im Betreff steht, habe ich Probleme mit dem ADC des PIC18F2431. Ich möchte nur die zwei Eingänge AN0 und AN1 auslesen und in 2 Variablen speichern. Allerdings bekomme ich da im Debug-Modus immer verschiedene und falsche Ergebnisse. Hier ist mein Programmcode. Sollte etwas sehr unschön programmiert sein, könnt ihr mich gerne darauf hinweisen. Bin relativ neu in der Materie. Danke schon im Voraus! Mfg #include <p18cxxx.h> #include "init.h" #include <delays.h> //Code in Programmspeicher #pragma code /* Configuration ************************************************************************ ****************/ #pragma config OSC = IRCIO // Internal oscillator block, port function on RA6 and RA7 #pragma config FCMEN = OFF // Fail-Safe Clock Monitor disabled #pragma config IESO = OFF // Internal External Osc. Switch Over disabled #pragma config PWRTEN = OFF // Power-Up Timer #pragma config BOREN = OFF // Brown-out Reset disabled #pragma config WDTEN = OFF // Watchdog Timer disabled #pragma config MCLRE = ON // MCLR enabled #pragma config T1OSCMX = OFF // T1 Oscillator disabled #pragma config CP2 = OFF // CCP2 = RC1 #pragma config LPOL = LOW // Low Voltage Programming #pragma config STVREN = ON // Stack Full/Underflow Reset #pragma config LVP = OFF // Stack Full/Underflow Reset //#pragma config DEBUG = ON //Prototypes for Interrupt Handler Routines void HighIntHndl(void); //Prototypes for Individual Interrupt Handlers void ADIFIntHndl(void); //Interrupt-Handler für AD-Interrupt-Flag void Timer5IntHndl(void); //Interrupt-Handler für Externen Interrupt //Insert High Interrupt Vector at 0x08 including code pragma #pragma code IntVectHigh=0x08 void IntVectHigh(void) { _asm GOTO HighIntHndl _endasm } //pragma to return to normal program section #pragma code //Globale variablendefinition int lk,rk, xh, xl, yh, yl; // Variablen definieren //Hier wird überprüft, ob der ADC oder die USART den Interrupt ausgelöst hat // und die entsprechende Verarbeitungsroutine (Interrupt-Handler) ausgelöst #pragma interrupt HighIntHndl void HighIntHndl (void) { //Determine which Interrupt occurred Nop(); if (PIR3bits.TMR5IF) //Überprüfung TMR5I-Flag gesetzt ist { Timer5IntHndl(); //Aufruf des Timer5-Interrupt Handlers return; } if (PIR1bits.ADIF) //Überprüfung ob Analog-Digital-Interrupt-Flag { ADIFIntHndl(); //Aufruf des AD-Interrupt-Handlers return; } return; //Verlassen der Interrupt-Service-Routine, wenn der Interrupt durch etwas anderes ausgelöst wurde z.B: Timer2 } //Interrupt Handler für Externen Interrupt void Timer5IntHndl(void) { ADCON0bits.GO_DONE=1; //Konvertiervorgang starten TMR5H = 0xFC; //Zählerstand auf neuen Reload Wert setzen TMR5L = 0xDF; //Zählerstand auf neuen Reload Wert setzen PIR3bits.TMR5IF = 0; //Interruptflag löschen ADCON1bits.FIFOEN=1; //FIFO Buffer wird eingeschalten return; } //Interrupt Handler für ADConvertierung void ADIFIntHndl(void) { ADCON1bits.ADPNT1=0; ADCON1bits.ADPNT0=0; Nop(); xh= ADRESH; xl= ADRESL; rk=(ADRESH*256) + ADRESL; ADCON1bits.ADPNT1=0; ADCON1bits.ADPNT0=1; Nop(); yh= ADRESH; yl= ADRESL; lk=(ADRESH*256) + ADRESL; //ADCON1bits.BFEMT=1; return; } void main() { init() } //PIC #include <p18cxxx.h> //Warteschleifen #include "delays.h" #include "adc.h" void init_osc(void){ //Internen Oszillator auf 8MHz einstellen OSCCON=0b01110010; } void init_vref(void){ } void init_ports(void){ TRISA = 0b00000011; ANSEL0bits.ANS0=1; ANSEL0bits.ANS1=1; LATA = 0b00000000; TRISB = 0b00000000; LATB = 0b00000000; TRISC = 0b11111111; LATC = 0b00000000; //Pause für Verarbeitung Delay1KTCYx(100); } void init_adc(void){ //OPEN ADC ( //ADC AUS ADCON0 = 0b00001001; ADCON3bits.ADRS1=0; ADCON3bits.ADRS0=1; ADCHS = 0b00000000; ADCON2bits.ADFM=1; //Pause für Verarbeitung Delay1KTCYx(100); } void init_timers(void){ //Pause für Verarbeitung Delay1KTCYx(100); T5CON=0b01000101; } void init_interrupts(void){ //Pause für Verarbeitung Delay1KTCYx(100); INTCONbits.GIE=1; INTCONbits.PEIE=1; PIE1bits.ADIE=1; //PIR3bits.TMR5IF=1; PIE3bits.TMR5IE=1; } void init_usb(void){ //vorerst global deaktivieren // UCONbits.USBEN = 0; } void init(void){ init_osc(); init_vref(); init_ports(); init_adc(); init_usb(); init_timers(); init_interrupts(); //Pause für Verarbeitung Delay1KTCYx(100); }
:
Bearbeitet durch User
Tobias N. schrieb: > Allerdings bekomme ich da im Debug-Modus immer > verschiedene und falsche Ergebnisse. Nur im Debug-Modus oder auch normal? Das nächste Mal bitte Syntax Highlighting( [c] ) verwenden.
Funktioniert normal auch nicht, allerdings kann ich normal keine Ergebnisse mit MPLab auslesen. Syntax Highlighting sagt mir nichts. Was ist das?
Tobias N. schrieb: > Syntax Highlighting sagt mir nichts. Was ist das? [*c]C-Code[/c] Nur ohne das '*'
1 | if (PIR3bits.TMR5IF) //Überprüfung TMR5I-Flag gesetzt ist |
2 | {
|
3 | Timer5IntHndl(); //Aufruf des Timer5-Interrupt Handlers |
4 | return; |
5 | }
|
Sieht dan z.B. so aus, und ist viel besser beim Lesen
Versuch mal ADCS<2:0> (ADCON2) auf 0b100 zu setzen. Es könnte sein, dass du dem ADC einen zu schnellen Takt gibst.
:
Bearbeitet durch User
Wenn das der gesamte Code ist, kann es nicht funktionieren. Die main () sollte niemals leer sein. Die ganzen init Funktionen, ohne auf die Register geguckt zu haben, werden garnicht aufgerufen. Wenn es rein Interrupt gesteuert sein soll, dann muss in die main immernoch der Aufruf von init () und eine Endlosschleife, damit der ProgramCounter nicht ins Nirvana zählt.
Das mit dem ADCON2 probiere ich einmal. hoppla bei der main hab ich aus versehen init() rausgelöscht. Das steht in meinem Programm natürlich schon drin. Welche Endlosschleife? Der Timer sollte bei einem Überlauf ohnehin wieder zurückgesetzt werden oder?
Das Programm wird ja für den PIC übersetzt. Der Einstiegspunkt ist die main. Es wird dann also die Initialisierung durchgeführt. Am Ende der init () springt der counter wieder in die main zurück. Wenn aber außer dem Aufruf nichts mehr kommt, können 2 Sachen passieren. Entweder es kommt einfach nichts mehr, dann zählt der Programmzähler immer weiter, bis er irgendwo, vermutlich in einer anderen Funktion angekommen ist. Das ist aber nicht gewünscht und relativ riskant, da er dann Dinge tut, die er nich soll. Oder der Compiler erkennt das Ende einer main () und setzt den "ASM-Befehl" END. www.sprut.de/electronic/pic/assemble/pseudo.html#end Es ist also ratsam ein while (1); zu schreiben, wenn nichts außer Interrupts etwas tun sollen. Aber bedenken, das Interrupts so kurz wie möglich sein sollen. Also sowas wie eine Datenübertragung mit einem Bus oder an ein Display gehört nicht mit rein. Die globalen Variablen werden nich nicht genutzt, das soll wohl noch kommen. Die Verarbeitung kann dann in der while (1){ } gemacht werden. Und wozu brauchst du den Timer? Der ADC macht doch einen interrupt, wenn er fertig ist. Also kannst du ihn beim Init anwerfen und wenn er fertig ist machst du in der ISR vom ADC dann die Channelwahl, das kopieren des Wertes in die globalen Variablen und das neustarten der Wandlung.
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.