PIC18F2431 Probleme mit dem ADC

OP #3568806
Lesenswert?

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);

}
#3569522
Lesenswert?

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.
#3570028
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren