hallo zusammen!
analoge signale sollen mit meinem uc digitalisiert werden. nach dem
einlesen aller geforderten daten will ich das ergebnis sehen. leider ist
die ausgabe nicht gleichbleibend - z.b. lese ich zwei sensoren ein ist
s1 an der 1. und s2 an der 2. stelle im array; lese ich nur s1 ein, dann
ist das ergebnis an der 2. stelle. was mache ich falsch?
codeauszüge:
// die variablen
int Sensor_Nummer;
int Werte[8] = {0,0,0,0,0,0,0,0};
// auslesen
switch( Sensor_Nummer )
{
case 1:
read_adc(0);
Werte[1] = ADCW;
break;
case 2:
read_adc(1);
Werte[2] = ADCW;
break;
case 3:
read_adc(2);
Werte[3] = ADCW;
break;
case 4:
read_adc(3);
Werte[4] = ADCW;
break;
case 5:
read_adc(4);
Werte[5] = ADCW;
break;
case 6:
read_adc(5);
Werte[6] = ADCW;
break;
case 7:
read_adc(6);
Werte[7] = ADCW;
break;
case 8:
read_adc(7);
Werte[8] = ADCW;
break;
}
// ausgabe und werte wieder auf null setzen
stdout = &mystdout;
printf(" Werte: %u, %u, %u, %u, %u, %u, %u, %u
\n",Werte[1],Werte[2],Werte[3],Werte[4],Werte[5],Werte[6],Werte[7],Werte
[8]);
Werte[1] = 0;
Werte[2] = 0;
Werte[3] = 0;
Werte[4] = 0;
Werte[5] = 0;
Werte[6] = 0;
Werte[7] = 0;
Werte[8] = 0;
schon mal vielen dank für eure unterstützung.
gruß
der Flo
int Werte[8] = {0,0,0,0,0,0,0,0};
...
Werte[8] = ADCW;
Autsch.
In C wird bei 0 angefangen zu zählen. Ein Array mit 8 Elementen,
so wie hier
int Werte[8] = {0,0,0,0,0,0,0,0};
besitzt also die Indizes:
0, 1, 2, 3, 4, 5, 6, 7
(zähl nach. Es sind genau 8 Stück).
Ein Werte[8] existiert nicht! Du weist hier den Wert
irgendwohin zu und überschreibst dir damit wer weis was.
Aber warum so kompliziert mit einem switch-case? Deine
Fälle sind alle gleich, nur ein paar Zahenwerte ändern sich:
// auslesen
read_adc( Sensor_Nummer - 1 );
Werte[ Sensor_Nummer - 1] = ADCW;
macht genau das gleiche, wie dein 20 Zeilen switch-case Konstrukt
von oben.
anlegst, dann ist das ein Array mit 8 Werten, die bei 0 beginnend
indiziert werden. Der Wert "Werte[8]" existiert in dem Array gar nicht!
Der höchste Wert ist "Werte[7]"... Und da Du den Wert von Deinem ersten
Sensor an der Stelle Werte[1] speicherst, ist es klar, dass beim
Auslesen des Arrays Mist rauskommt. Am besten nummerierst Du Deine
Sensoren von 0 an (wie man es in der Elektronik/Digitaltechnik
eigentlich immer macht) und speicherst den ersten Wert (also den von
Sensor 0) auch in "Werte[0]". Was beim Auslesen von "Werte[8]"
rauskommt, ist undefiniert.
ist mir ja richtig peinlich....
vielen dank!
vor einiger zeit gab es mal einen betrag in dem der aufbau einer
statemachine beschrieben wurde. wollte diesen ansatz kopieren doch ich
kann meinen fehler nicht genau lokalisieren.
anbei der auszug:
while(1)
{
uart_gets(Buffer);
Index = 0;
while( Buffer[Index] != '_' )
{
NextChar = Buffer[Index++];
if( NextChar == ' ' || NextChar == '\t' || NextChar == '\n' )
continue;
switch( State )
{
case START_SENSOR_AUSWAHL:
if( NextChar >= '0' && NextChar <= '9' )
{
Sensor_Nummer = NextChar - '0';
switch( Sensor_Nummer )
{
case 1:
read_adc(0);
Werte[0] = ADCW;
break;
case 2:
read_adc(1);
Werte[1] = ADCW;
break;
case 3:
read_adc(2);
Werte[2] = ADCW;
break;
case 4:
read_adc(3);
Werte[3] = ADCW;
break;
case 5:
read_adc(4);
Werte[4] = ADCW;
break;
case 6:
read_adc(5);
Werte[5] = ADCW;
break;
case 7:
read_adc(6);
Werte[6] = ADCW;
break;
case 8:
read_adc(7);
Werte[7] = ADCW;
break;
}
Sensor_Nummer = 0;
State = FIND_SEMICOLON;
}
else
State = FIND_SEMICOLON;
break;
case FIND_SEMICOLON:
if( NextChar == ';' )
{
State = START_SENSOR_AUSWAHL;
}
// Ende vom switch
}
// Ende vom while(Buffer)
}
stdout = &mystdout;
printf(" Werte: %u, %u, %u, %u, %u, %u, %u, %u
\n",Werte[0],Werte[1],Werte[2],Werte[3],Werte[4],Werte[5],Werte[6],Werte
[7]);
Werte[0] = 0;
Werte[1] = 0;
Werte[2] = 0;
Werte[3] = 0;
Werte[4] = 0;
Werte[5] = 0;
Werte[6] = 0;
Werte[7] = 0;
// Ende vom while
}
wenn mich nicht alles täuscht, dann kam die damalige antwort von Karl
heinz. fand die idee echt klasse.
gruß
der Flo
Kürzen, kürzen, kürzen.
Arrays haben den grossen Vorteil, dass du als Indizierung
einen beliebigen arithmetischen Ausdruck benutzen kannst
solange der errechnete Wert nur in den Arraygrenzen liegt.
Nutze die Macht, Flo!
leider ist die macht noch nicht ganz auf meiner seite...
die ausgabe hakt! bei spannungsänderungen wird immer nur der zuerst
gemessene wert angezeigt - änderungen werden nicht registriert.
while(1)
{
uart_gets(Buffer);
Index = 0;
while( Buffer[Index] != '_' )
{
NextChar = Buffer[Index++];
if( NextChar == ' ' || NextChar == '\t' || NextChar == '\n' )
continue;
switch( State )
{
case START_SENSOR_AUSWAHL:
if( NextChar >= '0' && NextChar <= '9' )
{
Sensor_Nummer = NextChar - '1';
read_adc( Sensor_Nummer );
Werte[Sensor_Nummer] = ADCW;
}
State = FIND_SEMICOLON;
break;
case FIND_SEMICOLON:
if( NextChar == ';' )
{
State = START_SENSOR_AUSWAHL;
Sensor_Nummer = 0;
}
// Ende vom switch
}
// Ende vom while(Buffer)
}
stdout = &mystdout;
printf(" Werte: %u, %u, %u, %u, %u, %u, %u, %u
\n",Werte[0],Werte[1],Werte[2],Werte[3],Werte[4],Werte[5],Werte[6],Werte
[7]);
// Ende vom while
}
was mache ich falsch?
gruß
der Flo
der vergleich soll nur dazu dienen, dass eine numerische eingabe
ankommt. daher ist dort '0' oder '1' richtig - glaub ich zumindest.
dass mit Sensor_Nummer = ... - '1' muss so sein, da ich zuvor die
arraystruktur falsch angewendet habe.
da ich (in meinem jugendlichen Leichtsinn) davon ausgehe, dass
uart_gets(Buffer); das Array mit einem '\0' abschließt.
> ...da ich zuvor die arraystruktur falsch angewendet habe.
Dann prüfe aber auch ob NextChar von '1' bis '8' läuft. '0' und '9' sind
unzulässig.
Richtiger ist...
1
...
2
if(NextChar>'0'&&NextChar<'9')
3
...
Solche essetiellen Fehler können im Speicher ein echtes Kaos anrichten.
Kein Wunder wenn nur Müll rauskomt.
du hast recht! die if-abfrage sollte die von dir vorgeschlagene form
haben - änderung schon eingebaut. doch leider hat sich mein problem
damit noch nicht gelöst... die werte werden erst nach einem reset
richtig eingelesen und dann halt auch nur ein mal.
Dann musst du mal deine read_adc Funktion durchforsten.
Was mir etwas komisch vorkommt, ist dass du zwar eine
Funktion namens read_adc hast, den Messwert aber trotzdem
direkt aus dem ADCW Register holst.
Von einer Funktion, die read_adc heist, würde ich erwarten,
dass sie mir den Messwert direkt zurückliefert. Das
ich sie also so anwenden kann:
Wert[Sensor_Nummer] = read_adc( Sensor_Nummer );
Das aber nur nebenbei. Denn ob du den ADC Wert nach
dem Funktionsaufruf holst, oder ob die letzte Aktion
in read_adc ein
return ADCW;
ist, ist für das gegenständliche Problem (der Messwert
wird nicht gelesen) unerheblich. Da musst du dir die
read_adc() Funktion anschauen.
du hast natürlich recht...
die funktion sieht so aus - hat bisher eigentlich auch immer geklappt!
#define ADC_VREF_TYPE 0x40
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input|ADC_VREF_TYPE;
ADCSRA|=0x40;
while ((ADCSRA & 0x10)==0)
;
ADCSRA|=0x10;
return ADCW;
}
denke, es liegt an der schleife. lasse jetzt die gültige nummer
ausgeben, und auch hier hakt die sache. bei einer abfrage von zwei
sensoren, wird z.b. nur einer ausgelesen.
// Endlosschleife
while(1)
{
uart_gets(Buffer);
Index = 0;
while( Buffer[Index] != '_' )
{
NextChar = Buffer[Index++];
if( NextChar == ' ' || NextChar == '\t' || NextChar == '\n' )
continue;
switch( State )
{
case START_SENSOR_AUSWAHL:
if( NextChar > '0' && NextChar < '9' )
{
Sensor_Nummer = NextChar - '1';
Werte[Sensor_Nummer] = read_adc( Sensor_Nummer );
stdout = &mystdout;
printf(" Sensor_Nummer: %u", Sensor_Nummer);
printf(" Test %u",Werte[Sensor_Nummer]);
}
State = FIND_SEMICOLON;
break;
case FIND_SEMICOLON:
if( NextChar == ';' )
{
State = START_SENSOR_AUSWAHL;
}
// Ende vom switch
}
// Ende vom while(Buffer)
}
stdout = &mystdout;
printf(" Werte: %u, %u, %u, %u, %u, %u, %u, %u
\n",Werte[0],Werte[1],Werte[2],Werte[3],Werte[4],Werte[5],Werte[6],Werte
[7]);
// Ende vom while
}
sorry für die kryptische darstellung... füge immer kopierten code ein...
gruß
Flo
vielleicht ist ja auch mein uc kaputt...
zuerst gehe ich aber immer von fehlern in meinem code aus ;-)
wenn jemand diesen - siehe letzten beitrag - testen könnte, wäre ich
sehr dankbar.
gruß
Flo
>sorry für die kryptische darstellung... füge immer kopierten code ein...
Wenn du da vor ein
1
unddahinterein
setzt, wird es auch noch hübsch.
Du solltest mal über die serielle ausgeben, dass der Befehl richtig
empfangen wurde. Das wäre ein Test für die Statemachine.
Rahul hat recht.
Bau doch mal ein paar printf ein, damit du siehst was
überhaupt passiert:
1
// Endlosschleife
2
3
stdout=&mystdout;
4
5
while(1)
6
{
7
8
uart_gets(Buffer);
9
printf("%s\n",Buffer);
10
11
Index=0;
12
while(Buffer[Index]!='_')
13
{
14
NextChar=Buffer[Index++];
15
16
if(NextChar==' '||NextChar=='\t'||NextChar=='\n')
17
continue;
18
19
printf("Naechstes Zeichen: %c\n",NextChar);
20
21
switch(State)
22
{
23
caseSTART_SENSOR_AUSWAHL:
24
printf("Im Status SENSOR_AUSWAHL\n");
25
26
if(NextChar>'0'&&NextChar<'9')
27
{
28
Sensor_Nummer=NextChar-'1';
29
Werte[Sensor_Nummer]=read_adc(Sensor_Nummer);
30
printf(" Sensor_Nummer: %u",Sensor_Nummer);
31
printf(" Test %u",Werte[Sensor_Nummer]);
32
}
33
State=FIND_SEMICOLON;
34
break;
35
36
caseFIND_SEMICOLON:
37
printf("Im Status FIND_SEMICOLON\n");
38
if(NextChar==';')
39
{
40
State=START_SENSOR_AUSWAHL;
41
}
42
// Ende vom switch
43
}
44
45
// Ende vom while(Buffer)
46
}
Jetzt sagt dir das Programm was es tut und warum es das tut.
Daraus kannst du dann deine Schlüsse ziehen.
In welchem Status beginnt die Sate Maschine eigentlich?
ich werde das gleich testen, nachdem ich einen neuen uc organisiert
habe... hab gerade mal einzelne sensoren eingelesen und die ad-wandlung
springt (delta von 100 bei einer auflösung von 10bit) oder der port
reagiert gar nicht mehr. wie hab ich das denn geschafft?
der automat startet in: State = START_SENSOR_AUSWAHL;
bis demnächst
Flo
die eingabe sieht so aus:
sensor 1 -> ";1#_"
sensor 2 -> ";2#_"
sensor 1 u. 2 -> ";1;2#"
etc.
probleme:
- die erste rückgabe ignoriert die zweite while-schleife.
- bei zwei sensoren sind die positionen im array getauscht.
ich weiß nicht mehr weiter...
der müde Flo
ein sensor:
eingabe:
;1#_
ausgabe
Werte: 0, 0, 0, 0, 0, 0, 0, 0
eingabe:
;1#_
ausgabe
;1#
Naechstes Zeichen: ;
Im Status FIND_SEMICOLON
Naechstes Zeichen: 1
Im Status SENSOR_AUSWAHL
Sensor: 1 Test 0 Werte: 0, 0, 0, 0, 0, 0, 0, 0
änderungen werden registriert!
zwei sensoren (nach einem reset):
eingabe:
;1;2#_
ausgabe:
Werte: 0, 256, 0, 0, 0, 0, 0, 0 // richtige spannungen!
eingabe:
;1;2#_
ausgabe:
1;2#<\r>
Naechstes Zeichen: ;
Im Status FIND_SEMICOLON
Naechstes Zeichen: 1
Im Status SENSOR_AUSWAHL
Sensor: 1 Test 256Naechstes Zeichen: ;
Im Status FIND_SEMICOLON
Naechstes Zeichen: 2
Im Status SENSOR_AUSWAHL
Sensor: 2 Test 0 Werte: 256, 0, 0, 0, 0, 0, 0, 0
änderungen werden registriert!
so sieht es also aus.
>eingabe:>;1#_>>ausgabe>Werte: 0, 0, 0, 0, 0, 0, 0, 0
Da hakt doch deine Statemachine.
gib doch mal ";;1#_" ein. (Gibt es eigentlich einen sinnvollen Grund für
dieses "bekloppte" Protokoll?)
Ersetz das als State-Startwert mal durch:
State = FIND_SEMICOLON;
>>eingabe:>>;1#_>>>>ausgabe>>Werte: 0, 0, 0, 0, 0, 0, 0, 0>Da hakt doch deine Statemachine.
dem ist nicht so!
war vielleicht nicht das beste beispiel. in meinen beispielfällen war
sensor1 auf 0 V und sensor2 auf 1,2 V.
warum das so aussieht? ich brauchte ein protokoll. wollte den anwender
die wahl der sensorenselektion überlassen, und der uc wandelt dann die
geforderten (und auch nur die) analogen signale aus. sensor 1 sitzt pa0,
sensor 2 sitzt pa1, sensor 3 sitzt pa2, u.s.w. (max. 8 sensoren). hab im
forum ein bischen nachgelesen und wollte die statemachine
ausprobieren...
>war vielleicht nicht das beste beispiel
Würde ich auch sagen.
Poste doch einfach mal einen Ablauf, wie es nicht sein sollte (und
benutze Werte, die sich auch von dem unterscheiden, was vor der
Manipulation im Speicher stand).
Meiner Meinung nach solltennämlich immer die Meldung der Stati kommen.
Wenn sie ausbleiben, hängt die Statemachine irgendwo. Pack mal das
"printf( "Naechstes Zeichen: %c\n", NextChar );" vor die If-Abfrage mit
"continue".
danke für deine geduld!
also sensor1 = 1V und sensor2 = 3,6V
nach einem reset
erste eingabe:
;1;2#_
erste ausgabe:
Werte: 214, 214, 0, 0, 0, 0, 0, 0 // das soll schon mal nicht sein. wo
// bleibt die zweite schleife?
zweite eingabe:
;1;2#_
zweite ausgabe:
;1;2#
Naechstes Zeichen: ;<\r>
Im Status FIND_SEMICOLON<\r>
Naechstes Zeichen: 1<\r>
Im Status SENSOR_AUSWAHL<\r>
Sensor: 1 Test 741 <\r> // das ist nicht richtig
Naechstes Zeichen: ;<\r>
Im Status FIND_SEMICOLON<\r>
Naechstes Zeichen: 2<\r>
Im Status SENSOR_AUSWAHL<\r>
Sensor: 2 Test 214 <\r> // das auch nicht
Werte: 741, 214, 0, 0, 0, 0, 0, 0 // sensoren sind im array vertauscht
lese ich jeweils einen sensor ein, dann steht das ergebnis an der
richtigen stelle - leider auch hier fehlt bei der ersten ausgabe die
zweite schleife.
die eingaben werden von menschen gemacht. allerdings hab ich eine
oberfläche, in der ich nur einen haken mache. im hintergrund wird der
string in die gezeigt form gebracht.
Hast du den "Eröffnungsstate" inzwischen geändert?
>erste ausgabe:>Werte: 214, 214, 0, 0, 0, 0, 0, 0 // das soll schon mal nicht sein. wo> // bleibt die zweite schleife?
Nicht nur, dass die Schleife fehlt, es steht auch noch der falsche Wert
an einer der beiden Stellen. (ich gehe mal von 10Bit und Uref = 5V aus)
Eigentlich müsste da
Werte: 204, 736, 0, 0, 0, 0, 0, 0
stehen.
Dann mach mal bitte folgende beiden Änderungen (die ich oben auch schon
vorgeschlagen habe...):
(Irgendwo) vor der While-Schleife:
State = FIND_SEMICOLON;
Pack mal das "printf( "Naechstes Zeichen: %c\n", NextChar );" vor die
If-Abfrage mit "continue".
bin nicht unbedingt auf dieses protokoll angewiesen. wenn du/ihr eine
andere idee habt gerne. bedingungen: s1 auf pa0, ...., s8 auf pa7. am
ende soll ein array ausgegeben werden, in dem die eingelesenen werte an
der entsprechenden stellt stehen - [sensor1 sensor2 ....].
Hast du mal dran gedacht dass du nach dem Umschalten des ADMUX eine
Pause von min. 40µs machen musst? Beim Umschalten der Betriebsart
(single-ended <=> differentiell) sogar 120µs. Wenn du das nicht tust
kommt bei der Messung nur Mist 'raus!
@Sonic:
Jetzt muss ich aber auch mal nachhaken: In welchem Datenblatt und wo da
genau hast Du irgendwas darüber gelesen, dass man beim Umschalten des
Kanalmultiplexers eine Wartezeit einhalten muss? Ich habe im Datenblatt
nur die Info gefunden, dass man beim Umschalten der *Differenz*-Eingänge
sowie der Referenz 125 µs warten muss, aber nichts über das Ändern von
ADMUX...
Hmm.. habe grade auch nochmal nachgeschaut und vom MUX auch nichts
gefunden. Tatsache ist, dass ich das Problem mit dem Scannen mehrerer
Kanäle auch hatte und das mit der Pause einfach probiert habe. Das
Ergebnis war, dass bei einer Wartezeit von <40µs die Werte nicht mehr
stimmten. Probier's doch einfach mal, vielleicht klappt's bei dir auch?!
das ende von der geschichte lautet, kein protokoll! - leider.
die sprünge im array konnte ich nicht erklären bzw. dem entgegen wirken.
jetzt lese ich einfach alle ports der reihe nach ein. ich weiß, dass man
das als schmutziges programmieren bezeichnet, doch es geht nicht anders:
bei der gechifteten ausgabe (wer weiß warum) bekomme ich die gewünschte
ausgabe hin.
pausen führen zu keinen veränderungen in der darstellung.
dank den fleißigen lesern und schreibern,
habt ein schönes wochenend.
gruß
Flo