mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik PIC24FJ64 ADC Problem


Autor: Alexander (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Tag,

aktuell bin ich an einem Projekt für das es nötig ist zwei Spannungen zu 
vergleichen.
Die eine Spannung ist konstant und die andere kann schwanken. Sollte 
diese Spannung schwanken soll die über LEDs angezeigt werden.

Nun zu meinem Problem:
Es ist völlig egal was am PIC an Spannung anliegt. Er gibt für jede 
Spannung den gleichen Wert aus. Ich hatte mal ein kleines Programm was 
lief, wiederrum gab es da noch Probleme mit einer externen Hardware, 
welche die Spannungen liefert. Dieses Problem ist nun behoben aber das 
Programm funktioniert nicht mehr bzw. der PIC liefert falsche 
Ergebnisse.

Merkwürdig ist, dass wenn ich das AD1CON3 register ändere sich auch der 
Ergebnis der Convertierung ändert.

Beispiel:
AD1CON3  = 0b0000000100000010; : ADCrefValue = ADCValue = 127

AD1CON3  = 0b0001111100000111; : ADCrefValue = ADCValue = 0

AD1CON3  = 0b1001111100000010; : ADCrefValue = ADCValue = 1023

Hier ist der Code von meinem Testprogramm was nur dazu dient um zu 
schauen ob der PIC die Spannung korrekt umconvertiert.

#include <p24FJ64GB106.h>
#include <stdio.h>
#include <stdlib.h>

_CONFIG1 (FWDTEN_OFF)           //Watchdogtimer off


int main(void)

{
int ADCrefValue = 0;

PORTB    = 0b0000000000000000;
TRISB    = 0b1111111111111001;   //RB1-2 = Output, RB0/3-15 = Input


AD1CON1  = 0b0000000011100000;   // SSRC<2:0> = 111 implies internal 
counter ends sampling and starts converting.
AD1CON2  = 0b0010000000000000;  // Vr+ = Vref+
AD1CON3  = 0b1001111100000010;   // Sample time = 31Tad, Tad = 3Tcy
AD1PCFG  = 0b1111111111100110;  // AN0, AN3 & AN4 as Analog Input
AD1PCFGL = 0b1111111111100110;  // AN0, AN3 & AN4 as Analog Input
AD1PCFGH = 0b0000000000000011;
AD1CSSL  = 0b0000000000000000;
AD1CSSH  = 0b0000000000000000;
AD1CHS   = 0b0000000000000011;    // Negative Input Vr-, analog signal 
from PIR (MUX A = AN4)


AD1CON1bits.ADON = 1;          //Turn on ADC

while (1)               // repeat continuously
{

  AD1CON1bits.SAMP=1;          //start sampling
  while(!AD1CON1bits.DONE);      //conversion done?
  AD1CON1bits.SAMP=0;          //start sampling
  ADCrefValue = ADC1BUF0;      //yes then get ADC value

  if (ADCrefValue > 300){
    PORTB = 0b0000000000000110;
  }
  else
    PORTB = 0b0000000000000010;


}                   // repeat

}

In diesem Fall liegt der Wert den der PIC einliest knapp über 300 (es 
leuchten beide LEDs an RB1 und RB2) aber auch hier ist es egal wie hoch 
die Spannung ist (auch wenn garkeine Spannung an dem PIN anliegt ist das 
Ergebnis wie sonst auch). Ich hab leider keine andere Möglichkeit mir 
den Wert der in ADC1BUF0 steht anders als über die beiden LEDs 
anzuzeigen.

Besteht vllt. die Möglichkeit der der interne AD-Converter defekt ist?
Ich würde mich über jede Art von Hilfe sehr freuen.
Danke schonmal im Vorraus.

Gruß Alex

Autor: Andreas Häusler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau Dir mal diese Routinen an, vielleicht helfen sie weiter:
void initADC( int amask)
{
  AD1PCFG = amask; // select analog input pins
  AD1CON1 = 0; // manual conversion sequence control
  AD1CSSL = 0; // no scanning required
  AD1CON2 = 0; // use MUXA, AVss and AVdd are used as Vref+/-
  AD1CON3 = 0x1F02; // Tad = 2 x Tcy = 125ns >75ns
  AD1CON1bits.ADON = 1; // turn on the ADC
} //initADC

int readADC( int ch)
{
  AD1CHS = ch; // 1. select analog input channel
  AD1CON1bits.SAMP = 1; // 2. start sampling
  TMR1 = 0; // 3. wait for sampling time

  while (TMR1< 100); // 6.25 us

  AD1CON1bits.DONE = 1; // 4. start the conversion

  while (!AD1CON1bits.DONE); // 5. wait for the conversion to complete

  return ADC1BUF0; // 6. read the conversion result
} // readADC

Automatic sampling timing:
void initADC( int amask)
{
  AD1PCFG = amask; // select analog input pins
  AD1CON1 = 0x00E0; // automatic conversion start after sampling
  AD1CSSL = 0; // no scanning required
  AD1CON2 = 0; // use MUXA, AVss and AVdd are used as Vref+/-
  AD1CON3 = 0x1F02; // Tsamp = 32 x Tad; Tad=125ns
  AD1CON1bits.ADON = 1; // turn on the ADC
} //initADC

int readADC( int ch)
{
AD1CHS = ch; // 1. select analog input channel
AD1CON1bits.SAMP = 1; // 2. start sampling
while (!AD1CON1bits.DONE); // 3. wait for the conversion to complete
return ADC1BUF0; // 4. read the conversion result
} // readADC

main ()
{
int a;
// initializations
initADC( AINPUTS); // initialize the ADC for the Explorer16 analog inputs
TRISA = 0xff00; // select the PORTA pins as outputs to drive the LEDs
// main loop
  while( 1)
  {
    a = readADC( POT); // select the POT input and convert
    // reduce the 10-bit result to a 3 bit value (0..7)
    // (divide by 128 or shift right 7 times
    a >>= 7;
    // turn on only the corresponding LED
    // 0 -> leftmost LED.... 7-> rightmost LED
    PORTA = (0x80 >> a);
  } // main loop
} // main

Autor: Alexander (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erstmal Danke Andreas.
Leider klappt es so auch nicht.

Erst habe ich mal eine Frage:
Kann ich den Inputchannel für den ADC überhaupt ändern wenn der ADC 
eingeschaltet ist? Weil zuerst wird bei dir die initADC aufgerufen, in 
der der ADC eingeschaltet wird, und dann wird erst der Channel 
ausgewählt welchen der ADC auslesen soll.

Bei deim ersten Beispiel hängt der PIC dann vor dem "while (TMR1< 100); 
// 6.25 us" und geht an dort nicht weiter.
Muss der Timer noch besonders initialisiert werden?

Beim 2ten Beispiel bekomme ich wieder den Wert "0" raus.

Ich hab auch die Beispiele von Microchip selbst versucht aber bei denen 
ist das gleiche Bild :(

Hat jemand vllt. mal ein ähnliches Problem gehabt und eine Lösung bzw. 
weitere Vorschläge?

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

bei mir funktioniert folgender Code auf einem PIC24FJ256GA110 mit dem 
C30 Compiler.

Ich habe Autosampling gewählt damit ich irgendwo im Code den AD-Wert aus 
dem register ADC1BUF3 lesen kann.
void ADC_Init(void)
  {
  AD1PCFGLbits.PCFG3 = 0; // AN3 PIN Analogfunktion
  TRISBbits.TRISB3 = 1;   // Input
  
  // Analogwert lesen von ADC1BUF3 !!!!
  
  AD1CON1bits.FORM = 0b00;   // integer format
  AD1CON1bits.SSRC = 0b111;  // auto convert
  AD1CON1bits.ASAM = 1;      // Auto-Sampling aktivieren
 
  AD1CON2bits.VCFG = 0b000;  // AVdd und AVss als referenz
  AD1CON2bits.CSCNA = 1;     // Scan inputs
  AD1CON2bits.SMPI = 0b1111; // 16 Werte in den den Buffer schreiben  
  
  AD1CON3bits.SAMC = 0b1111; // Auto Sample Time Tad
  AD1CON3bits.ADCS = 0b00111111;  // 64 TCY 
  
  AD1CSSL = 0xFFFF;    // Alle 16 AN Pins scanen auch wenn digital
                       // damit z.B. AN7 Wert im Buffer ADC1BUF7 liegt
      
  AD1CON1bits.ADON = 1; // ADC einschalten
  }


int main(void)  //  main
{
  uint16_t i,j,AdWert;

  ADC_Init();

  while(1)
  {
  for(i = 0; i < 65000; i++)
    {
      for(j = 0; j < 1000; j++)
      {
        AdWert = ADC1BUF3;
        printf("AD Wert: %d \r\n",AdWert); 

        Nop();
        Nop();
        Nop();
      }
    }
  }
}


Gruss Manuel

Autor: Andreas Häusler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, Du kannst meiner Meinung nach die Eingänge beim Auslesen ändern, 
auch wenn der ADC aktiv ist.

Ja, der Timer muss natürlich initiallisiert sein. Du kannst für Tests 
aber auch nur ein Delay (>6,25us) einfügen.

Hast Du die entsprechenden Inputs auch als Analogeingänge definiert?

Bsp: AD1PCFG = 0xFFFE;  // Select analog input pins

Autor: Andreas Häusler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier übrigens noch der Link zu einem sehr guten Buch für den Einstieg in 
die Pic24 Welt. Kann ich wärmstens empfehlen... (englisch)

http://www.amazon.com/Programming-16-Bit-PIC-Micro...

Programming 16-Bit PIC Microcontrollers in C - Learning to Fly the PIC24 
- Di Jasio (Newnes Verlag)

Autor: Alexander (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die jeweiligen Pins sind im Analogmodus. Leider funktioniert auch das 
Programm von Manuel nicht.
Ich denke das es nicht am Programm liegt sondern an der Hardware, was 
natürlich der schlimmste Fall wäre.
Aber mit dem Programm womit es mal lief, klappt es nun auch nicht mehr 
und ein anderes Programm macht auf diesem PIC leider auch Probleme die 
auf anderen Boards mit gleichem PIC fehlerfrei laufen.

Kann es sein das der ADC irgendwie einen Defekt hat, der PIC aber 
troztdem andere Aufgabe bearbeitet? Wenn ja gibt es eine Möglichkeit das 
festzustellen?

Ich bedanke mich aber schonmal für die bisherige Hilfe.
Gruß Alex

Autor: Arc Net (arc)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist das zufälligerweise ein PIC24FJ64GB mit 64-Pins? Dann könnte es auch 
daran liegen:
http://ww1.microchip.com/downloads/en/DeviceDoc/80369k.pdf
"When using PGEC1 and PGED1 to debug an application on any 64-pin 
devices in this family, all voltage references will be disabled. This 
includes VREF+, VREF-, AVDD and AVSS. Any A/D conversion will always 
equal 0x3FF."

Autor: Alexander (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja es handelt sich um ein PIC24FJ64 GB106 also ein PIC24 mit 64 PINs. 
Aber das bezieht sich nur aufs "Debuggen" und nicht aufs "Realeasen" 
oder irre ich?
Den debug-Modus kann ich leider garnicht nutzen wegen eines Fehlers 
(PK3Err0040).
In einem anderen Programm wiederrum funktioniert das debuggen weswegen 
ich dort auch hänge aber da es mal funktioniert hat (auch ohne den 
ebug-Modus) habe ich mich mit dem Problem nicht weiter beschäftigt.

Autor: Alexander (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Tag,

ich habe das ganze nun mal im "debug-Modus" laufen lassen und mir dann 
die Register angeguckt.

Die Register AD1CON2, AD1CON3, AD1CHS, AD1PCFGL, AD1PCFGH, AD1CSSL und 
AD1CSSH sind alle so wie ich sie eingestellt habe.
Im AD1CON1 Register wiederrum steht etwas völlig falsches.

Im Programmcode habe ich stehen: AD1CON1 = 0b0000000011100000;
Im Special Function Register Fenster wird mir aber angezeigt das im 
AD1CON1 Register xC0E1 steht. Müsste da nicht x00E0 stehen?

Ich Debuge mit PEGC2/PEGD2, also an dem Problem worauf mich Arc Net 
(danke nochmal) aufmerksam gemacht hat kann es nicht liegen.

Hat einer einen Rat für mich?

Gruß Alex

Autor: Alexander (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK die Frage hat sich selbst beantwortet.
Das C verwirrt zwar, da das bit 14 dem Datenblatt nach "unimplemented" 
ist und als 0 gelesen werden soll, aber auf 1 steht und somit nach dem 
setzten der ADON bits nicht 8 sondern C steht.

Auch das SAMP bit arbeitet völlig korrekt und setzt sich automatisch von 
1 auf 0 wenn das Sampeln fertig ist.

Ich werde nun erstmal schauen woran es genau liegt und mich nochmal 
melden.

Autor: Alexander (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe es nun ans Laufen bekommen.
Ich bedanke mich nochmal für die Hilfe.
Im Endeffekt hat mir das Programm von Manuel geholfen.

Ich habe hier nochmal den gesamten Programmcode gepostet.
Zum Verständniss:

ADCrefValue ist eine feste Spannung die 1/2*Vref+ beträgt.
ANAFValue ist die Spannung die aus dem Bewegungsmelder kommt und bei 
keiner Bewegung gleich ADCrefValue sein sollte und bei Bewegungen 
kleiner oder größer wird was dann über das leuchten der LEDs an RB1 und 
RB2 angezeigt wird.


Hier der Code:

#include <p24FJ64GB106.h>
#include <stdio.h>
#include <stdlib.h>

_CONFIG1(JTAGEN_OFF & GCP_OFF & GWRP_OFF & COE_OFF & FWDTEN_OFF & 
ICS_PGx2 & FWPSA_PR32 & WDTPS_PS2048);//& WINDIS_OFF & FWPSA_PR32 & 
WDTPS_PS2048

int reference(void);
int analog(void);
int difference(void);
int delay(void);

/**********************MAIN************************/

int main(void)

{
int ADCrefValue = 0;
int ANAFValue = 0;
int dif = 200;
int ug = 0;
int og = 0;

PORTB = 0b0000000000000000;
TRISB = 0b1111111111111001;     //RB1-2 = Output, RB0/3-15 = Input
PORTC = 0x0000;
TRISC = 0xFFFF;
PORTD = 0x0000;
TRISD = 0xFFFF;
PORTE = 0x0000;
TRISE = 0xFFFF;
PORTF = 0x0000;
TRISF = 0xFFFF;
PORTG = 0x0000;
TRISG = 0xFFFF;

T1CON = 0b0000000000110000;      //Stops the Timer1 and reset control 
reg.
TMR1 = 0x0000;             //Clear contents of the timer register
PR1 = 0xFFFF;             //Load the Period register with the value 
0xFFFF
IPC0bits.T1IP = 0x01;         //Setup Timer1 interrupt for desired 
priority level
                  // (This example assigns level 1 priority)
IFS0bits.T1IF = 0;           //Clear the Timer1 interrupt status flag
IEC0bits.T1IE = 1;           //Enable Timer1 interrupts


AD1CON1  = 0b0000000011100100;    // SAMP bit=0 ends sampling
AD1CON2  = 0b0010010000111100;    // Vref+ (^= Original reference signal 
from PIR (Vcc/2)
AD1CON3  = 0b0001111100111111;
AD1PCFGL = 0b1111111111000110;    // AN0, AN3 & AN4 as Analog Input
AD1PCFGH = 0b0000000000000000;
AD1CSSL  = 0b1111111111111111;    // Analog channel omitted from input 
scan

AD1CON1bits.ADON = 1;

while(1)
  {

    ADCrefValue = ADC1BUF4;
    ANAFValue = ADC1BUF3;
    og = ADCrefValue+dif;
    ug = ADCrefValue-dif;

      if ((ANAFValue < ug)||(ANAFValue > og)){
          PORTB = 0b0000000000000110;
        } //if ((ANAFValue < ADCrefValue)||(ANAFValue > ADCrefValue))
      else
          PORTB = 0b0000000000000000;
  } //while(1)

} //main

/******************END*MAIN************************/


Gruß Alex

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.