Forum: Mikrocontroller und Digitale Elektronik PIC18F2431 Probleme mit dem ADC


von Tobias N. (tobi03)


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

}

: Bearbeitet durch User
von Max H. (hartl192)


Lesenswert?

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.

von Tobias N. (tobi03)


Lesenswert?

Funktioniert normal auch nicht, allerdings kann ich normal keine 
Ergebnisse mit MPLab auslesen.
Syntax Highlighting sagt mir nichts. Was ist das?

von Max H. (hartl192)


Lesenswert?

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

von Tobias N. (tobi03)


Lesenswert?

ouh okay sry.

von Max H. (hartl192)


Angehängte Dateien:

Lesenswert?

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
von Michael S. (rbs_phoenix)


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.

von Tobias N. (tobi03)


Lesenswert?

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?

von Michael S. (rbs_phoenix)


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.

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.