Hallo zusammen,
ich habe an einem Arduino Uno (ATmega328p) einen Poti (1,2kOhm)
angeschlossen und möchte diesen nun auslesen. Wenn ich das richtig
verstanden habe, wird der Spannungsabfall am analogen Eingang gemessen
und in einen digitalen Wert zwischen 0 und 1024 gewandelt.
Referenzspannung ist Vcc vom Arduino Uno. Der mittlere Pin des Poti ist
mit PC0 verbunden, die anderen beiden mit GND und Vcc.
Die Ausgabe an das Terminal in Atmel Studio funktioniert auch
problemlos. Wenn ich jetzt aber den Wert vom Poti dort auslesen möchte,
erscheinen dort Werte von denen ich nicht unbedingt auf die
Poti-Stellung schließen kann. Den Poti nach rechts voll durchgedreht
erscheinen im Terminal (Dec) Werte um 67 70 68 .....
Voll nach links: 14 15 14 .....
Wie kann ich diese Werte nun richtig interpretieren? Was mache ich
falsch?
Liegt es evtl. daran, dass ich bei einem Wert über 255 mehr als ein Byte
für die Übertragung des vollständigen Wertes benötige? Im Terminalwindow
in der Dec-Einstellung nur zweistellige Werte angezeigt werden können?
Bisher habe ich folgenden Code:
QQuestion schrieb:> PORTC |= (1<<PC0); /* internen Pull-Up an PC0 aktivieren */
Pullup solltest du nicht einschalten, der verfälscht die Messwerte.
Daran liegt allerdings dein Problem nicht.
QQuestion schrieb:> Wie kann ich diese Werte nun richtig interpretieren? Was mache ich> falsch?> Liegt es evtl. daran, dass ich bei einem Wert über 255 mehr als ein Byte> für die Übertragung des vollständigen Wertes benötige? Im Terminalwindow> in der Dec-Einstellung nur zweistellige Werte angezeigt werden können?QQuestion schrieb:> putchar2(result);
So geht das natürlich nicht, du solltest den Wert in einen String
umwandeln und diesen dann senden.
such mal nach itoa bzw utoa (sind in der stdlib.h enthalten)
> Liegt es evtl. daran, dass ich bei einem Wert über 255 mehr als> ein Byte für die Übertragung des vollständigen Wertes benötige?
Wenn deine Bytes nicht größer sind als die Bytes der restlichen weiten
Welt, dann wird es wohl daran liegen.
Das hätte man allerdings auch ausprobieren können :-)
1
intmain()
2
{
3
...
4
5
while(1)
6
{
7
putchar2(768);
8
_delay_ms(5);
9
}
10
}
was siehst du an deiner Ausgabe und was noch viel wichtiger ist: warum
siehst du es?
Danke für die Antworten. Ich habe nun folgendes eingebunden:
1
intmain(void)
2
{
3
intresult=0;
4
charBuffer[10];
5
uart_init(F_CPU,BAUD);
6
DDRC&=~(1<<PC0);/* Pin PC0 als Eingang */
7
PORTC|=(1<<PC0);/* internen Pull-Up an PC0 aktivieren */
8
ADC_Init();// Initialisierung Analogeingang
9
10
while(1)
11
{
12
result=ADC_Read(0);
13
utoa(result,Buffer,10);
14
put2s(Buffer);
15
//putchar2(Buffer);
16
_delay_ms(1000);
17
}
18
}
Wenn ich mir jetzt im Terminalwindow die Werte in ASCII anzeigen lasse,
bekomme ich Werte zwischen 13 und 70, ohne Leerzeichen dazwischen. Schon
mal ein Anfang.
Wenn ich anstelle von ASCII im Terminalwindow Dec einstelle, kriege ich
immer einen Werte um 52 oder 252, aber dann mit Leerzeichen dazwischen
und unabhängig von der tatsächlichen Stellung des Poti.
Wenn ich den Pullup-Widerstand nicht aktiviere, bekomme ich nur
0000000...
1. Ist der Pullwiderstand wirklich so schädlich? Ich habe ihn zur
Sicherheit aktiviert. Die Werte werden wegen dem dortigen
Spannungsabfall vermutlich verfälscht, aber mich interessiert in diesem
Fall imgrunde nur die Poti-Stellung und nicht die tatsächliche Spannung
am Poti.
2. atoi wandelt ja eine Zeichenkette, die eine Zahl darstellt, in eine
Integer-Zahl. Das geschieht in dem die ASCII-Zahl für 0 abgezogen wird,
oder?
utoa ist das Gegenteil und wandelt demnach eine vom ADC kommende Zahl zu
einer ASCII-Zeichenkette, oder?
3. Das erklärt mir noch nicht ganz das oben dargestellte Verhalten, aber
klingt grundsätzlich logisch. Ich erwarte ja Zahlen zwischen 0 und 1023.
Liegt es am Pullup das ich mit 13 bis 70 deutlich niedriger liege?
Karl Heinz schrieb:>> Liegt es evtl. daran, dass ich bei einem Wert über 255 mehr als>> ein Byte für die Übertragung des vollständigen Wertes benötige?>> Wenn deine Bytes nicht größer sind als die Bytes der restlichen weiten> Welt, dann wird es wohl daran liegen.>> Das hätte man allerdings auch ausprobieren können :-)> int main()> {> ...>> while( 1 )> {> putchar2( 768 );> _delay_ms(5);> }> }>> was siehst du an deiner Ausgabe und was noch viel wichtiger ist: warum> siehst du es?
Jede Zahl über 255 führt zu 00000000 oder Dec 0.
QQuestion schrieb:> Wenn ich mir jetzt im Terminalwindow die Werte in ASCII anzeigen lasse,> bekomme ich Werte zwischen 13 und 70, ohne Leerzeichen dazwischen. Schon> mal ein Anfang.
Ja. Aber den AVR nach jedem Text ein Leerzeichen ausgeben zu lassen, ist
ja nicht so schwer.
> Wenn ich anstelle von ASCII im Terminalwindow Dec einstelle, kriege ich> immer einen Werte um 52 oder 252, aber dann mit Leerzeichen dazwischen> und unabhängig von der tatsächlichen Stellung des Poti.
Das ist aber etwas anderes.
Du musst unterscheiden zwischen dem Text an sich und wie er binär
repräsentiert wird. In einem COmputer ist ja erst mal alles eine Zahl.
Wenn dein AVR am Terminal ain 'A' anzeigen lassen will, dann flitzt da
ja kein 'A' über die Leitung sondern eine Codezahl dafür. Wenn dein AVR
ein 'A' ausgibt, dann wird der laut ASCII entsrechende Code dafür
geschickt. Laut ASCII Tabelle ist das die Codezahl 65 (oder Hexadezimal
0x41). Du siehst nur deshalb ein 'A' am Terminal, weil das Terminal auf
Textmodus geschaltet ist und dann eben bei Erhalt eines Bytes mit dem
Wert 65 die entsprechenden Pixel so einschwärzt, dass dein Gehirn 'A'
liest.
Schaltest du hingegen das Terminal in einen Modus, so dass es diese
Textinterpretation nicht macht, dann malt das Terminal dann auch 65 hin
(im Dezimalmodus) bzw 41 (im Hexadezimalmodus). Und damit du weißt, wo
eine Zahl aufhört und die nächste anfängt, fügt das Terminal dann
Leerezeichen zwischen die Codezahlen ein. Denn ansonsten ist die
INterpretation von 124327 eine schwierige Angelegenheit. Sind das jetzt
die Codezahlen 12, 43 und 27; oder waren das die Codes 124, 3 und 27;
oder war das 124, 32 und 7 oder ....
> Wenn ich den Pullup-Widerstand nicht aktiviere, bekomme ich nur> 0000000...
Pullup?
Wenn du mit dem ADC misst, dann willst du keinen Pullup-Widerstand.
Das Poti arbeitet bereits sauber als Spannungsteiler und erzeugt eine
von der Potistellung abhängige Spannung, die dann vom ADC gemessen wird
und mit einem Zahlenwert von 0 bis 1023 ausgedrückt wird.
> 1. Ist der Pullwiderstand wirklich so schädlich? Ich habe ihn zur> Sicherheit aktiviert. Die Werte werden wegen dem dortigen> Spannungsabfall vermutlich verfälscht, aber mich interessiert in diesem> Fall imgrunde nur die Poti-Stellung und nicht die tatsächliche Spannung> am Poti.
Du kannst die Poti-Stellung nur über die gemessene Spannung messen. Die
gemessene Spannung IST in einem gewissen Sinne die Poti Stellung.
Mit dem Pullup, der Einfluss auf die Spannung hat, hast du dir damit
dein Messergebnis versaut.
> 2. atoi wandelt ja eine Zeichenkette, die eine Zahl darstellt, in eine> Integer-Zahl. Das geschieht in dem die ASCII-Zahl für 0 abgezogen wird,> oder?
nein.
Der Text "123" besteht aus 3 Zeichen und je nachdem an welcher Stelle zb
die 2 vorkommt, hat sie eine andere Wertigkeit. Das muss natürlich
berücksichtigt werden. Mit dem Abziehen von '0' ist das noch lange nicht
getan. Das funktioniert bei einzelnen Ziffern, aber eine Zahl besteht ja
aus mehreren Ziffern, die dann auch entsprechend ihrer Wertigkeit als
Hunderter, Zehner oder Einer wieder richtig zusammengesetzt werden muss.
Über die Leitung geht in diesem Fall einfach nur Text. "123"
unterscheidet sich so gesehen in nichts vom Text "AVR", nur dass andere
'Buchstaben' benutzt werden. Aber Text ist Text. Und atoi versucht
diesem Text einen 'Sinn' zu entlocken, indem es die korrespondierende
Zahl dazu erzeugt. Das gelingt bei "123", nicht jedoch bei "AVR".
> utoa ist das Gegenteil und wandelt demnach eine vom ADC kommende Zahl zu> einer ASCII-Zeichenkette, oder?
Ja.
Lies es als 'unsigned' to 'ascii'. Dann ist die Richtung klar.
Genauso wie atoi. 'ascii' to 'integer'.
Genau genommen ist jedoch utoa nicht das Gegenteil von atoi. Hier sind
die Buchstaben
'a'....ascii
'i'....integer (also int)
'u'....unsigned (also unsigned int)
'l'....long
int und unsigned int sind aber 2 verschiedene Paar Schuhe. Daher kann
atoi nicht das Gegenteil von utoa sein. Das wäre itoa.
> 3. Das erklärt mir noch nicht ganz das oben dargestellte Verhalten, aber> klingt grundsätzlich logisch. Ich erwarte ja Zahlen zwischen 0 und 1023.> Liegt es am Pullup das ich mit 13 bis 70 deutlich niedriger liege?
Sehr wahrscheinlich.
Grundsätzlich: Wenn du Spannungen mit dem ADC misst, dann hat da ein
Pullup nichts daran verloren. Zumindest dann nicht, wenn es der
eingebaute ist und du keine Ahnung hast, welchen Widerstandswert der
genau repräsentiert. Denn dein Spannungsteiler, der so aussehen sollte
1
5V o----+
2
|
3
+-+
4
| |
5
<---------- zum ADC
6
| |
7
+-+
8
|
9
GND o----+
sieht dann so aus
1
5V o----+-----+
2
| |
3
+-+ +-+ Rp
4
| | +-+
5
| | |
6
<-------+-- zum ADC
7
| |
8
+-+
9
|
10
GND o----+
du hast also eine Parallelschaltung des oberen Teils des Widerstands vom
Poti (vom + Anschluss bis zum Abgriff) mit einem unbekannten Widerstand
Rp. Und damit ist der Widerstand dieses oberen Teils der Schaltung nicht
mehr bekannt. Und damit ist es unberecehnbar geworden, wo der Abgriff an
der Widerstandsbahn im Poti erfolgt, der die physikalische
Widerstandsbahn in 2 Widerstandsteile aufteilt, deren Verhältnis
einerseits die daraus resultierende Spannung festlegt und dir
andererseits durch Messen der Spannung den Rückschluss auf die
Potistellung erlaubt.
>> while( 1 )>> {>> putchar2( 768 );>> _delay_ms(5);>> }>> }>>>> was siehst du an deiner Ausgabe und was noch viel wichtiger ist: warum>> siehst du es?>> Jede Zahl über 255 führt zu 00000000 oder Dec 0.
Ganz sicher nicht.
Das setzen von UMSEL01 ist laut Datenblatt 'reserved'. D.h. was da genau
passiert, weiß keiner (ausser Atmel).
Was ist falsch an?
1
voiduart_init(longOszi,longBaud)
2
{
3
UBRR0H=(unsignedchar)((Oszi/16L/Baud-1)>>8);
4
UBRR0L=(unsignedchar)(Oszi/16L/Baud-1);
5
6
UCSR0B=(1<<TXEN0)|(1<<RXEN0);
7
UCSR0C=(1<<UCSZ01)|(1<<UCSZ00);
8
}
Genau so stehts auch im Datenblatt des 328. (man beachte auch die
umgekehrte Reihenfolge beim Setzen der beiden Register für die Baudrate.
Das ist wichtig, dass hier die richtige Reihenfolge eingehalten wird!).
Und ich denke mal, wenn jemand weiß, wie das funktionieren soll, dann
wird das ja wohl Atmel selber sein.
Ob du jetzt zusätzlich (wie im Beispiel im Datenblatt) noch 2 Stoppbits
setzt oder nicht, ist hingegen wieder relativ egal.
PS:
Zum Test, ob die UART grundsätzlich richtig funktioniert, ist es eine
extrem gute Idee, erst mal einen Text ausgeben zu lassen.
Denn wenn dieser Text nicht korrekt erscheint, dann weißt du, dass
irgendetwas schief gegangen ist. In den meisten Fällen wird das eine
falsche Baudrate sein.
D.h. man gibt sich irgendetwas aus, das man im Terminal ganz sicher als
korrekt wieder erkennen kann. zb
1
intmain()
2
{
3
....
4
5
put2s("ADC Messung: PC0\n");
6
7
while(1)
8
{
9
result=ADC_Read(0);
10
11
utoa(result,Buffer,10);
12
put2s("Wert: ");
13
put2s(Buffer);
14
putchar2('\n');
15
16
_delay_ms(1000);
17
}
18
}
wenn du den Text nicht siehst, dann weißt du, dass auch der Rest der
Ausgabe nix taugt, sondern dass statt dessen die Übertragung gestört bzw
nicht funktionierend ist.
Unter anderem ist auch deswegen eine Textübertragung für den Anfang auch
einfacher: man kann leichter kontrollieren, ob die Übertragung
fehlerfrei ist, als bei rein binärer Übertragung, in der ein Bytewert
fast alles darstellen kann.
Echt gute und verständliche Erklärung.
Jedoch wurde mir bei tatsächlich nur 00000000 immer wieder angezeigt,
wenn ich nur über putchar2(768); die Zahl 768 auf das Terminalwindow
geben wollte. Bei 255 kam in der Bin-Einstellung dann 11111111.
Wenn ich denn Pullup deaktiviere, passiert folgendes:
In der ASCII-Einstellung im Terminalwindow kommen lauter 0000 ohne
Lehrzeichen. In der Dec-Einstellung kommt immer wieder: 48 48 48 48
Beides unabhängig von der tatsächhlichen Poti-Stellung.
1
intmain(void)
2
{
3
intresult=0;
4
charBuffer[10];
5
uart_init(F_CPU,BAUD);
6
DDRC&=~(1<<PC0);/* Pin PC0 als Eingang */
7
//PORTC |= (1<<PC0); /* internen Pull-Up an PC0 aktivieren */
8
PORTC=0;
9
ADC_Init();// Initialisierung Analogeingang
10
11
while(1)
12
{
13
result=ADC_Read(0);
14
utoa(result,Buffer,10);
15
put2s(Buffer);
16
//putchar2(Buffer);
17
_delay_ms(1000);
18
}
19
}
Wenn ich put2s ausklammere und es über putchar2 ohne Pullup probiere,
bekomme ich Dec 242 242 242 ... und in ASCII halt das jeweilige Zeichen.
Ansonsten habe ich den Code nicht geändert.
Aktiviere ich dann wieder den Pullup, so bekomme ich mit put2s und der
ASCII-Terminaleinstellung wieder die korrekte Stellung über Werte
zwischen 13 und 70. Über Dec im Terminal hingegen kommen dann werde
zwischen 49 und 56 mit einem Leerzeichen dazwischen.
Über Putchar2 mit Pullup kommt immer wieder ein ASCII-Zeichen, dass der
Dec Zahl 242 entspricht.
putchar2 überträgt beliebige Zeichen, aber put2s überträgt auch eine
beliebige Zeichenkette nicht richtig auf das Terminal. Scheinbar liegt
hier der Fehler, muss die Funktion mal prüfen.
QQuestion schrieb:> Echt gute und verständliche Erklärung.>> Jedoch wurde mir bei tatsächlich nur 00000000 immer wieder angezeigt,> wenn ich nur über putchar2(768); die Zahl 768 auf das Terminalwindow> geben wollte.
Autsch.
Das war Pech.
Da hab ich zufällig eine Zahl erwischt, deren Lowbyte tatsächlich lauter
0-Bits aufweist. Mist.
Die Binärdrastellung für 768 lautet (als 16 Bit Zahl)
1
0000 0011 0000 0000
Schmeiss die oberen 8 Bits weg (weil putchar2 nur einen unsigned char,
also 8 Bit, übernimmt) und es bleibt tatsächlich 0000 0000 (also dezimal
0) übrig.
Das war Pech. Bei 769 hättest du im Terminal dann 0000 0001 bzw. 1
(dezimal) gesehen. etc.
Mein Fehler. Ich hätte die Binärdarstellung prüfen sollen. Aber wer ahnt
auch schon, dass er zufällig eine Zahl rauspickt, deren niedrigsten 8
Bit tatsächlich allesamt 0 sind :-)
> In der ASCII-Einstellung im Terminalwindow kommen lauter 0000 ohne> Lehrzeichen.
Tu dir selbst einen Gefallen und wirf da nach einer Zahl Leerzeichen
raus! Sonst kannst du 123 nicht von 12 und 3 unterscheiden!
> In der Dec-Einstellung kommt immer wieder: 48 48 48 48> Beides unabhängig von der tatsächhlichen Poti-Stellung.
Was nichts andres heißt, als dass dein ADC nicht arbeitet.
D.h. höchst wahrscheinlich.
> Wenn ich put2s ausklammere und es über putchar2 ohne Pullup probiere,> bekomme ich Dec 242 242 242 ... und in ASCII halt das jeweilige Zeichen.
Du bellst den falschen Baum an.
Lass dir Text mit dazu ausgeben, damit du unterscheiden kannst, ob du
ein Problem mit dem UART oder ein Problem mit dem ADC siehst.
> Aktiviere ich dann wieder den Pullup,
Vergiss bitte den Pullup.
Den willst du nicht haben.
Punkt.
Können wir damit das Thema 'Pullup ja oder nein' zugunsten von 'Nein'
als beendet erklären?
D.h. jede weitere Tests mit 'aktiviertem Pullup' sind kontraproduktiv.
Du kannst dich gerne für dich selbst damit spielen aber aussagekräftig
ist das alles nicht. Aussagekräftig wäre es zb. mit einem Voltmeter die
Spannung am Pin PC0 zu messen (also dem ADC Eingang) und zu
verifizieren, dass sich die Mit dem Poti tatsächlich zwischen 0 und der
Versorungsspannung verändern lässt. Denn das würde verifizieren, dass du
dein Poti korrekt und am richtigen Pin angeschlossen hast.
QQuestion schrieb:> result = ADC_Read(0);> putchar2(result);
Oh je, das schmerzt.
Könntest du bitte mal begreifen, daß ein ADC keine Buchstabenfolge
ausgibt, sondern eine ZAHL? Du mußt diese Zahl in 'result' erst mal
konvertieren, und zwar von Integer nach String. Den kannst du
anschließend ausgeben. Sonst wird das nix.
W.S.
Vielen Dank für die Tipps, Karl. Also ich habe den Poti erneut
durchgemessen und er funktioniert noch. Eine Drehung gegen den
Uhrzeigersinn führt bis zum größtmöglichen Widerstand. Eine Drehung mit
dem Uhrzeigersinn bis zum niedrigsten Widerstand (8 Ohm).
Die Funktionen sind wie im Eingangspost (plus die stdlib.h für utoa).
Die folgende main ist der neuste Stand und führt dazu, dass im Terminal
manchmal der richtige Wert (zwischen 27 und 1012 gerade) auftritt.
Meistens wird jedoch folgendes ausgegeben: "Wert: 0Wert: 0...". Das
klingt nach einem Wackelkontakt vom dünnen Draht, oder?
1
intmain(void)
2
{
3
intresult=0;
4
charBuffer[20];
5
uart_init(F_CPU,BAUD);
6
DDRC&=~(1<<PC0);/* Pin PC0 als Eingang */
7
//PORTC |= (1<<PC0); /* internen Pull-Up an PC0 aktivieren */
Als sich der Draht von Poti zu GND vorhin löste, kamen im Terminal
dauerhaft wechselnde Werte mit realistischer Höhe 650, 490, 230...,
jedoch ohne das ich den Poti gedreht habe.
Ich habe alle Kontakierungen geprüft, passt. Alles richtig verbunden
kriege ständig nur "Wert: 0Wert: 0Wert: 0...", egal wie oder ob ich an
dem Poti drehe.
Wenn ich dann zu Testzwecken mit dem aktivierten Pullup wieder
verfälsche, gibt er wenigstens je nach Position einen Wert zwischen 13
und 70 aus, der die Stellung verdeutlicht.
Hat noch jemand einen Vorschlag?