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
Schau Dir mal diese Routinen an, vielleicht helfen sie weiter:
1 | void initADC( int amask) |
2 | {
|
3 | AD1PCFG = amask; // select analog input pins |
4 | AD1CON1 = 0; // manual conversion sequence control |
5 | AD1CSSL = 0; // no scanning required |
6 | AD1CON2 = 0; // use MUXA, AVss and AVdd are used as Vref+/- |
7 | AD1CON3 = 0x1F02; // Tad = 2 x Tcy = 125ns >75ns |
8 | AD1CON1bits.ADON = 1; // turn on the ADC |
9 | } //initADC |
10 | |
11 | int readADC( int ch) |
12 | {
|
13 | AD1CHS = ch; // 1. select analog input channel |
14 | AD1CON1bits.SAMP = 1; // 2. start sampling |
15 | TMR1 = 0; // 3. wait for sampling time |
16 | |
17 | while (TMR1< 100); // 6.25 us |
18 | |
19 | AD1CON1bits.DONE = 1; // 4. start the conversion |
20 | |
21 | while (!AD1CON1bits.DONE); // 5. wait for the conversion to complete |
22 | |
23 | return ADC1BUF0; // 6. read the conversion result |
24 | } // readADC |
Automatic sampling timing:
1 | void initADC( int amask) |
2 | {
|
3 | AD1PCFG = amask; // select analog input pins |
4 | AD1CON1 = 0x00E0; // automatic conversion start after sampling |
5 | AD1CSSL = 0; // no scanning required |
6 | AD1CON2 = 0; // use MUXA, AVss and AVdd are used as Vref+/- |
7 | AD1CON3 = 0x1F02; // Tsamp = 32 x Tad; Tad=125ns |
8 | AD1CON1bits.ADON = 1; // turn on the ADC |
9 | } //initADC |
10 | |
11 | int readADC( int ch) |
12 | {
|
13 | AD1CHS = ch; // 1. select analog input channel |
14 | AD1CON1bits.SAMP = 1; // 2. start sampling |
15 | while (!AD1CON1bits.DONE); // 3. wait for the conversion to complete |
16 | return ADC1BUF0; // 4. read the conversion result |
17 | } // readADC |
18 | |
19 | main () |
20 | {
|
21 | int a; |
22 | // initializations
|
23 | initADC( AINPUTS); // initialize the ADC for the Explorer16 analog inputs |
24 | TRISA = 0xff00; // select the PORTA pins as outputs to drive the LEDs |
25 | // main loop
|
26 | while( 1) |
27 | {
|
28 | a = readADC( POT); // select the POT input and convert |
29 | // reduce the 10-bit result to a 3 bit value (0..7)
|
30 | // (divide by 128 or shift right 7 times
|
31 | a >>= 7; |
32 | // turn on only the corresponding LED
|
33 | // 0 -> leftmost LED.... 7-> rightmost LED
|
34 | PORTA = (0x80 >> a); |
35 | } // main loop |
36 | } // main |
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?
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.
1 | void ADC_Init(void) |
2 | {
|
3 | AD1PCFGLbits.PCFG3 = 0; // AN3 PIN Analogfunktion |
4 | TRISBbits.TRISB3 = 1; // Input |
5 | |
6 | // Analogwert lesen von ADC1BUF3 !!!!
|
7 | |
8 | AD1CON1bits.FORM = 0b00; // integer format |
9 | AD1CON1bits.SSRC = 0b111; // auto convert |
10 | AD1CON1bits.ASAM = 1; // Auto-Sampling aktivieren |
11 | |
12 | AD1CON2bits.VCFG = 0b000; // AVdd und AVss als referenz |
13 | AD1CON2bits.CSCNA = 1; // Scan inputs |
14 | AD1CON2bits.SMPI = 0b1111; // 16 Werte in den den Buffer schreiben |
15 | |
16 | AD1CON3bits.SAMC = 0b1111; // Auto Sample Time Tad |
17 | AD1CON3bits.ADCS = 0b00111111; // 64 TCY |
18 | |
19 | AD1CSSL = 0xFFFF; // Alle 16 AN Pins scanen auch wenn digital |
20 | // damit z.B. AN7 Wert im Buffer ADC1BUF7 liegt
|
21 | |
22 | AD1CON1bits.ADON = 1; // ADC einschalten |
23 | }
|
24 | |
25 | |
26 | int main(void) // main |
27 | {
|
28 | uint16_t i,j,AdWert; |
29 | |
30 | ADC_Init(); |
31 | |
32 | while(1) |
33 | {
|
34 | for(i = 0; i < 65000; i++) |
35 | {
|
36 | for(j = 0; j < 1000; j++) |
37 | {
|
38 | AdWert = ADC1BUF3; |
39 | printf("AD Wert: %d \r\n",AdWert); |
40 | |
41 | Nop(); |
42 | Nop(); |
43 | Nop(); |
44 | }
|
45 | }
|
46 | }
|
47 | }
|
Gruss Manuel
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
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-Microcontrollers-Technology/dp/0750682922 Programming 16-Bit PIC Microcontrollers in C - Learning to Fly the PIC24 - Di Jasio (Newnes Verlag)
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
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."
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.
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
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.
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
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.