PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ADCx liefern ständig Werte obwohl nichts angeschlossen ist



benx
05.02.2009, 22:11
Hallo,

ich wollte die beiden ADC-Ports nutzen um dort je einen Mikroschalter anzuschließen. Zum Auslesen der Werte nutze ich die Var. adc0 und adc1 die durch den adc-task gefühlt werden. Zum testen gebe ich das alles direkt in der while-Schleife alle 500ms aus.
Problem ist nun das obwohl nichts an den ADC-Ports angeschlossen ist, dort Werte ausgegeben werden. Wie kann das sein? Kann das vielleicht jemand nachvollziehen?

Anbei das Mini-Programm und die Terminal-Ausgaben:



#include "RP6RobotBaseLib.h"
int main(void)
{
initRobotBase();

// Main loop
while(true)
{
task_ADC();
mSleep(500);
writeString_P("ADC0: ");
writeInteger(adc0, DEC);
writeString_P("\n");

writeString_P("ADC1: ");
writeInteger(adc1, DEC);
writeString_P("\n");
}
return 0;
}




Terminal:

[READY]
ADC0: 0
ADC1: 0
ADC0: 0
ADC1: 0
ADC0: 0
ADC1: 0
ADC0: 0
ADC1: 0
ADC0: 0
ADC1: 0
ADC0: 716
ADC1: 0
ADC0: 716
ADC1: 529
ADC0: 716
ADC1: 529
ADC0: 716
ADC1: 529
ADC0: 716
ADC1: 529
ADC0: 716
...


Vielleicht weiß ja einer von euch Rat....:-)

mfg
benx

Besserwessi
05.02.2009, 22:28
Das Programm weiss gar nicht, dass nichts angeschlossen ist. Irgendein Ergebnis gibt die AD Wandlung immer. Wenn der Eingang offen ist, ist das ein mehr oder weniger zufälliger Wert der duch Störungen beeinflußt wird.
Für Schalter sind ADC Eingänge irgendwie nicht das ideale.

Klingon77
05.02.2009, 22:47
hi,

nun kenne ich die interne Beschaltung der ADC´s nicht.

Such doch bitte mal unter dem Stichwort "Pullup" und "Pulldown" - Widerstände.

Das könnte evtl. Dein Problem beheben.


Falls ich mich irre korriegiert mich bitte.

liebe Grüße,

Klingon77

benx
06.02.2009, 13:35
@Besserwessi: Ich dachte das ganze Port öffnen etc. übernimmt mir die Funktion task_adc() des RP6. Hmm.
Der RP6 hat leider nur zwei freie ADC-Ports. Alles andere ist bereits belegt..

@Klingon77: Soweit ich das gelesen habe, hat der Controller einen PullDown-Wiederstand bereits integriert....aber sicher bin ich mir nicht.

Hmm.. Hat vielleicht sonst noch jemand einen Tipp?

mfg
benx

Besserwessi
06.02.2009, 14:23
Die Atmel Controller haben die möglichkeit interne Pullups zu aktivieren. Bei ADCs weden die aber in aller Regel nicht aktiviert. Das müßte man also schon noch selber machen. Gerade wenn die ADC Eingänge knapp sind, sollte man für einen Schalten einen Digitlen Eingang nutzen.

benx
06.02.2009, 15:59
Es sind am RP6 soweit ich weiß leider keine digitalen Eingänge mehr frei. Daher der Versuch das ganze über den A/D-Eingang zu bewerkstelligen...

mfg
benx

radbruch
06.02.2009, 16:34
Hallo

Übrigends sind die ADC-Ports natürlich auch digitale Ports. Man kann sie also auch digital abfragen:

if(PINA & 1) ... // ADC0
if(PINA & 2) ... // ADC1

Zusätzliche "freie" digitale Ports wären noch die 4 LEDs (die keine Bumpers haben) und SCL/SDA des I2C am XBUS. Die haben allerdings je einen PullUp. E-INT am XBUS ist noch ein zusätzlich nutzbarer ADC-Port:

https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=348695#348695
https://www.roboternetz.de/phpBB2/viewtopic.php?t=32677

Gruß

mic

benx
06.02.2009, 17:52
Hi mic,

ich dachte ich könnte mir das direkte ansprechen der PINs sparen und die Var. der task_ADC() Funktion nutzen. Wie muss ich die Schalter eigentlich anschließen, damit das klappt?

thx.

mfg
benx

radbruch
06.02.2009, 18:27
Hallo

Normalerweise schaltet man einen Taster zwischen Pin und GND. Der Pin wird dann als Eingang mit aktiviertem PullUp definiert. Ohne Taster ergibt die Abfrage eine 1 (5V über PullUp), mit Taster gedrückt erhält man 0 (Pin an GND):

// Initialisierung
DDRA &= ~3; // ADC0+1 auf Eingang (ist zwar default nach dem Einschalten, aber sicher ist sicher :)
PORTA |= 3; // PullUp einschalten

Nun kann man so die Tasten einlesen:

// Abfrage
uint8_t x;
x=PINA & 3;

Ohne Tasten ist x==3 weil beide Pins high sind (PullUps). Wenn eine Taste gedrückt wird, wird das entsprechende Bit zu 0:

Taste gedrückt an ADC0 -> x==2 (3-1)
Taste gedrückt an ADC1 -> x==1 (3-2)
Beide Tasten -> x==0 (3-(2+1))

Ein Beispiel:

while(PINA & 2); // wartet bis Taste an ADC1 gedrückt wird

Verwirrt? Ich hoffe nicht.

Gruß

mic

radbruch
06.02.2009, 20:18
Hallo

Bei mir funktioniert es wunderbar, vermutlich ist dein Taster nicht richtig angeschlossen.


#include "RP6RobotBaseLib.h"

uint8_t x;

int main(void)
{
initRobotBase();
startStopwatch1();

DDRA &= ~3; // ADC0+1 auf Eingang und
PORTA |= 3; // PullUps einschalten

// Main loop
while(true)
{
if (getStopwatch1() > 500 ) {
// Abfrage

x=PINA & 3;

// Taste gedrückt
writeString_P(" Port A: ");
writeInteger(x, 2); // Bitmuster binär ausgeben
writeString_P("\n");
switch (x) {
case 2:
writeString_P("ADC0 gedrückt!!! \n");
break;
case 1:
writeString_P("ADC1 gedrückt!!! \n");
break;
case 0:
writeString_P("ADC0 und ADC1 gedrückt!!! \n");
break;
}
/*
writeString_P("ADC0: ");
writeInteger(adc0, DEC);
writeString_P("\n");

writeString_P("ADC1: ");
writeInteger(adc1, DEC);
writeString_P("\n");
*/
setStopwatch1(0);
}
}
return 0;
}


Macht diese Ausgabe:

Port A: 11
Port A: 11
Port A: 11
Port A: 11
Port A: 11
Port A: 11
Port A: 1
ADC1 gedrûckt!!!
Port A: 1
ADC1 gedrûckt!!!
Port A: 1
ADC1 gedrûckt!!!
Port A: 1
ADC1 gedrûckt!!!
Port A: 1
ADC1 gedrûckt!!!
Port A: 1
ADC1 gedrûckt!!!
Port A: 1
ADC1 gedrûckt!!!
Port A: 1
ADC1 gedrûckt!!!
Port A: 11
Port A: 10
ADC0 gedrûckt!!!
Port A: 10
ADC0 gedrûckt!!!
Port A: 10
ADC0 gedrûckt!!!
Port A: 10
ADC0 gedrûckt!!!
Port A: 10
ADC0 gedrûckt!!!
Port A: 10
ADC0 gedrûckt!!!
Port A: 11
Port A: 11
Port A: 11
Port A: 0
ADC0 und ADC1 gedrûckt!!!
Port A: 0
ADC0 und ADC1 gedrûckt!!!
Port A: 0
ADC0 und ADC1 gedrûckt!!!
Port A: 0
ADC0 und ADC1 gedrûckt!!!
Port A: 11
Port A: 11
Port A: 11
Port A: 11


Gruß

mic

Edit: Scheint ja nun doch zu funktionieren :)

benx
07.02.2009, 12:17
Hi mic,

jepp... dachte du hast meinen Beitrag nicht mehr gesehen, daher hatte ich ihn gelöscht... :-) Hat doch geklappt. Besten Dank dafür.

Kurze Frage zu den wohl wichtigsten Zeilen aus Deinem Beispiel:
DDRA &= ~3; // ADC0+1 auf Eingang und
PORTA |= 3; // PullUps einschalten
x=PINA & 3;

Du hast die Zeilen zwar gut dokumentiert, aber so richtig verstehen kann ich das noch nicht was da abläuft. Habe mir gerade in einem C-Tutorial die Bit-Operationen angeschaut, aber der "Versteh-Durchbruch" kam dadurch leider noch nicht.. :-)
Kannst Du vielleicht dazu noch ein paar erklärende Sätze verfassen? Wäre super...

thx

mfg
benx

radbruch
07.02.2009, 14:33
Hallo

Zu den Ports: Ein Port wird über drei Register angesprochen. Das Datenrichtungsregister entscheidet zwischen Ein- oder Ausgangsfunktion, mit dem Portregister kann man den Port (und den PullUp) steuern, mit PIN liest man den Status des Ports ein.

Jeder Port hat 8 Pins die man immer gleichzeitig liest oder schreibt, jeder Pin entspricht dann einem Bit im Datenwort. Pin(Bit)0 hat die Wertigkeit 1, Pin7(Bit)7 hat 128. Im Beispiel mit den ADCs verwenden wir Pin0 und Pin1, das sind die Werte 1 und 2. Binär dargestellt sieht das so aus:

0b00000001 für Bit 0
0b00000010 für Bit 1
0b00000011 für beide Bits

Zuerst setzen wir die Datenrichtung für Port A. (Obwohl die Datenrichtung nach einem Reset Eingang sein sollte machen wir das zur Übung selbst) Eine 0 in dem entsprechenden Register definiert den Pin als Eingang, also müssen wir Bit0 und Bit1 löschen. Dazu verwenden wir eine Bitmaske mit der wir das aktuelle Datenrichtungsregister mit UND verknüpfen. Eine 1 in der Maske erhält dabei den alten Zustand, eine 0 löcht das betreffende Bit. Die Maske müßte also so aussehen: 0b11111100. Alternativ verwendet man hier gerne die Tilde ~ die das Einerkomplement(1 wird 0, 0 wird 1) erzeugt. Unsere Maske würde man dann so darstellen: ~0b00000011 (oder kurz ~3:) Und so setzt man dann schließlich das Datenrichtungsregister:

DDRA = DDRA & ~3; oder kurz DDRA &= ~3;

Da die Datenrichtung nun stimmt können wir den PullUp einschalten. Dazu müssen wir im Port das entsprechende Bit setzen. Da wir dabei die anderen Pins des Ports nicht verändern wollen verwenden wir wieder eine Maske, die diesmal allerdings mit ODER verküpft wird. Ein 1 in der Maske setzt dann den Pin auf High (PullUp ein), eine 0 ändert hingegen nichts:

PORTA |= 3;

Nun können wir den Status des Port einlesen. Da uns nur Pin0 und Pin1 interessieren blenden wir die anderen Bits im Wert aus, natürlich wieder mit einer UND-Maske:

x=PINA & ~3;

Ächz, reicht das schon als Erklärung?

Gruß

mic

Gerko
07.02.2009, 16:40
Also mir reichts :)
Ich programmiere zwar schon eine Zeitlang, aber C ist für mich dennoch eine neue Programmiersprache, da sind so Hinweise wie |=... OR und &=... AND ziemlich hilfreich um den Code zu verstehn. Ich wollte gestern schon fast ein neues Thema starten wegen so einem Ausdruck :P

Gerko
08.02.2009, 14:14
Eine Frage hätte ich noch zu dem Code, es wird ständig uint8_t und uint16_t verwendet. Heißt das Unsigned Integer 8/16 bit?, für was steht das "t" und gibt es auch signed Integers in dem Format?
Ist dieser Variablentyp in irgendeiner Library definiert, oder ein Standard?

radbruch
08.02.2009, 15:45
Hallo

Wo das festgelegt wird (GCC?) weiß ich auch nicht. Wie du richtig vermutest, uint steht für unsigned integer:

int8_t - char
uint8_t - unsigned char
int16_t - integer
uint16_t - unsigned int

Das t steht vielleicht für Type? Ich weiß es nicht...

Gruß

mic