Hi Leute,
ich habe in meinem Programm eine Bitmaske definiert.
Bsp: 0010 1101
Jede Stelle steht dafür, ob ein gewisser Messwert gemessen werden soll
oder nicht( z.b. 101 = Strom messen, Spannung nicht, Temeratur messen)
Jetzt habe ich mir eine Display Anzeige ausprogrammiert und bei dir
möchte ich diese Werte auch anzeigen lassen können. Also man sagt man
will den 3ten gemessen Wert haben, wie komme ich dann auf diese Stelle?
Im oberen Beispiel wäre ja:
Bitmaske: 0010 1101
Daten gemessen: 4
Mögliche Auswahl: 0-3
=> Auswahl: 3
Dann müsste ich intern im µC wissen, dass es Stelle 5 in der Bitmaske
ist. (Wenn man mit Stelle 0 zu zählen beginnt)
Mir würden zwar ein paar Lösungsansätze einfallen, allerdings nur welche
mit sehr langem Code. Wenn jemand eine elegante Lösung dafür hätte, wäre
ich wirklich sehr dankbar! Anscheinend stehe ich gerade auf der Leitung
:/
Also irgendwie versteh ich das nicht... die Bitmaske bestimmt doch nicht
das was gemacht wird. Sondern entsprechend dem, was gemacht wird, wird
die Bitmaske gesetzt :-)
Hier mal ein Ansatz:
char foo(char auswahl) {
unsigned char i,t;
for(i=0,t=1;t&&auswahl>=0;t<<=1,i++)
if (bitmask&t&&!auswahl--) return i;
return -1;
}
Also über den PC über USB kann ich die Bitmaske einstellen.
Je nach der Bitmaske messe ich dann die Werte und speichere sie in einem
Array ab. (erster abgespeicherte Wert entspricht der ersten 1 in der
Bitmaske).
Bitmaske: 0010 1101
Hier werden also 4 Werte gemessen. (weil 4 einser drinnen sind). Die
Stelle gibt an, welche Werte gemessen werden. Z.b. Stelle Null bedeutet,
dass Spannung gemessen wird. Stelle eins bedeutet, dass Strom gemessen
wird usw.
Also werden hier 4 Werte gemessen, also kann man auf dem Display auch 4
Werte anzeigen. Über einen Joystick kann man eine Variable
inkrementieren bzw. dekrementieren im Bereich von 0-3 (Weil es ja 4
Werte sind).
Wenn diese Variable jetzt 3 ist, dann soll der 4te gemessen Wert
angezeigt werden. Bei der Bitmaske 00101101 wäre dass dann 00!1!0 1101
(der einser zwischen den !) Also wäre dass die Stelle 5 in der Bitmaske.
Wie kann ich in dem programm diese 5 berechnen, indem ich die Bitmaske
und die Auswahl als Eingabe habe?
Ich interpretiere mal frei
> Bitmaske: 0010 1101
Du hast 8 mögliche Messwerte.
Davon wurden 4 tatsächlich gemessen.
Nämlich diejenigen auf den Kanälen 0, 2, 3, 5
> Daten gemessen: 4
OK. Dies deshalb, weil 4 Kanäle freigeschaltet wurden
> Mögliche Auswahl: 0-3> => Auswahl: 3
Finde ich keine gute Idee.
Je nachdem, wieviele Kanäle freigeschaltet sind, hat dann die
Temperatur einmal die Nummer 1, dann wieder die Nummer 2 usw.
Frag deinen Benutzer nach dem Kanal von dem er den Messwert haben
möchte. Diese Nummer bleibt immer gleich und ändert sich nicht.
> Mir würden zwar ein paar Lösungsansätze einfallen, allerdings nur> welche mit sehr langem Code.
Zeig doch mal was du ausbaldobert hast
> Wenn jemand eine elegante Lösung dafür hätte, wäre> ich wirklich sehr dankbar!
Ich würd mir in einem Array die Bitmasken der freigeschalteten Kanäle
bereit legen. Die Benutzereingabe ist dann Index in dieses Array, aus
dem ich dann die Kanalnummer des abzufragenden Wertes bekomme
Hol Dir zu Beginn eines Messzyklusses eine Kopie der Maske (um das
Original nicht zu beschädigen), zähle die Messstellennummer (ist auch
der Index auf das Array mit Ergebnissen) hoch und schiebe dabei die
Kopie der Maske nach rechts, wodurch das LSB der Maske im Carry landet.
Nun entscheidest Du anhand des Carrys, ob Du die Messung ausführst oder
überspringst.
...
Gast wrote:
> Hier werden also 4 Werte gemessen. (weil 4 einser drinnen sind).
Ja, und diese 4 Werte legst du in einem Wertearray nacheinander ab. In
der Reihenfolge in der sie gemessen wurden. Ohne Leerraum dazwischen.
> Wenn diese Variable jetzt 3 ist, dann soll der 4te gemessen Wert> angezeigt werden. Bei der Bitmaske 00101101 wäre dass dann 00!1!0 1101> (der einser zwischen den !) Also wäre dass die Stelle 5 in der Bitmaske.
Die brauchst du dann gar nicht mehr.
Wenn der Benutzer den 4.ten Wert sehen will (was auch immer der ist),
dann zeigst du ihm auch den 4.ten Wert aus dem Wertearray
Also mal überlegen.
Du könntest 8mal schieben, und je nachdem nach welchem Schieben eine 1
herauskommt, weißt du welcher Wert gemessen wurde:
if (Wert & 0x01 == 1)dann wurde Messwert 1 gemessen
if (Wert >> 1 & 0x01 == 1) dann wurde Messwert 2 gemessen
if (Wert >> 2 & 0x01 == 1) dann wurde Messwert 3 gemessen
if (Wert >> 3 & 0x01 == 1) dann wurde Messwert 4 gemessen
.
.
.
if (Wert >> 7 & 0x01 == 1) dann wurde Messwert 8 gemessen
Was hälts du davon?
Ja das stimmt schon Karl Heinz, allerdings zeige ich nicht nur den Wert
an, sondern auch, was dieser Wert bedeutet.
Also auf dem Display auf der ersten Zeile den Namen, z.b. "Voltage:" und
bei der 2ten Zeile dann den Wert.
So wie du es geschrieben hast, hatte ich auch vor den Wert auszugeben.
Allerdings habe ich die Registername in einem Array auch abgespeichert
und für diese benötige ich dann die Stelle in der Bitmaske (weil die dem
Index des Arrays entsprechen)
Die anderen Antworten kann ich mir erst später durchlesen, da ich gerade
unterricht habe. Danke schonmal
Stefan_KR, meine Bitmaske ist 64 Bit groß... So wie du es gelöst
hättest, wäre auch mein Ansatz gewesen =) Es muss doch auch eine
elegantere Lösung geben? (vielleicht passt eh schon eine hier gepostet
lösung, ich schaue es mir dann in 1 Stunde an)
Gast wrote:
> Ja das stimmt schon Karl Heinz, allerdings zeige ich nicht nur den Wert> an, sondern auch, was dieser Wert bedeutet.
Ja und?
Die Struktur ist schon erfunden
1
structResult
2
{
3
longValue;
4
charCaption[20];
5
charUnit[5];
6
};
> So wie du es geschrieben hast, hatte ich auch vor den Wert auszugeben.> Allerdings habe ich die Registername in einem Array auch abgespeichert> und für diese benötige ich dann die Stelle in der Bitmaske (weil die dem> Index des Arrays entsprechen)
Nicht wenn du dir beim Messwert selber mithilfe der Struktur die
relevanten Informationen dazuspeicherst. Anstalle eines simplen longs
für den Messwert, ist das Ergebnis einer Messung ein Result-Objekt,
welches Informationen darüber enthält, mit welcher Überschrift das
Ergebnis anzuzeigen ist, welche Einheit es hat etc.
1
structChannelDescription
2
{
3
charCaption[20];
4
charUnit[5];
5
};
6
7
structChannelDescriptionChannels[]=
8
{{"Temperatur","°C"},
9
{"Strom","A"},
10
{"Volt","V"},
11
{"Druck","hPa"},
12
{"Luftfeuchte","%"},
13
{"",""},
14
{"",""},
15
{"",""},
16
{"",""}
17
};
18
19
structResult
20
{
21
longValue;
22
structChannelDescription*pChannel;
23
};
24
25
#define MAX_NR_RESULTS 8
26
27
structResultResults[MAX_NR_RESULTS];
28
uint8_tNrResults;
29
30
...
31
32
//
33
// die freigegebenen Kanäle sampeln
34
//
35
NrResults=0;
36
for(i=0;i<MAX_NR_RESULTS;++i){
37
if(BitMaske&(1<<i)){
38
Results[NrResults].Value=SampleAdc(i);
39
Results[NrResults].pChannel=&Channels[i];
40
NrResults++;
41
}
42
}
43
44
// ... Benutzer nach einer Zahl zwischen 0 und NrResults fragen
Hmmm jetzt habe ich selbst eine Lösung gecodet und jetzt kommst du mit
dem daher :D Stimmt, dein Lösungsweg ist elegant, vielleicht schreibe
ich es noch so um. (zumindest ist deiner viel besser zu lesen) Der
Vollständigkeit halber schreibe ich mal meine Lösung her:
1
// Berechnung von benötigtem Registerstrings-Index
2
for(inti=0;i<32;++i)// Durchlaufen aller Stellen
3
{
4
if(((measurement_mask_low>>i)&&0x01)==1)// Kontrolle ob an der Stelle 1 steht
5
{
6
if(level_one!=measured_counter)// Wurde die Stelle noch nicht gefunden?
7
{
8
measured_counter++;// Erhöhe, da eine weitere "1" gefunden wurde
9
}
10
}
11
}
12
for(inti=0;i<7;++i)// Durchlauf der verbleibenden Stellen
13
{
14
if(((measurement_mask_high>>i)&&0x01)==1)// Kontrolle ob an der Stelle 1 steht
15
{
16
if(level_one!=measured_counter)// Wurde die Stelle noch nicht gefunden?
17
{
18
measured_counter++;// Erhöhe, da eine weitere "1" gefunden wurde
Noch eine kurze Erklärung:
In level_one steht die Auswahl von dem User (ich weiß, schlechter
Variablenname...)
In registernames sind die Indexe konstant durchnummeriert von 0-39
In measured sind die Indexe variable. Also [2] bedeutet einmal Spannung,
ein anderes mal Strom.
Würdet ihr mir trotzdem raten, das Programm so wie Karl Heinz es gesagt
hat abzuändern? Wie schaut es mit Speicherverbrauch aus? Wäre da ein
großer Unterschied zwischen den beiden Varianten? (bzw. in der Laufzeit
des Programmes?)
Danke schonmal
Gast wrote:
> Hmmm jetzt habe ich selbst eine Lösung gecodet und jetzt kommst du mit> dem daher :D
:-)
> Würdet ihr mir trotzdem raten, das Programm so wie Karl Heinz es gesagt> hat abzuändern? Wie schaut es mit Speicherverbrauch aus?
Wieviele Kanäle hast du?
Genausoviele Pointer hab ich zusätzlich im Array stehen :-)
Das ist alles.
Aber dafür ist die Ausgabe eine simple Sache :-)
(Dir ist hoffentlich aufgefallen, dass mein Code auch das Abfragen der
einzelnen ADC Kanäle umfasst. Die Auswertung anzeigen ist in einem
einzigen printf mit ein paar Array-Indexoperationen zusammengefasst :-)
PS: Du kannst da in der struct ChannelDescription auch die notwendigen
Umrechnungskonstanten für die einzelnen ADC Kanäle unterbringen. Nur mal
so als Hinweis, wozu man die Struktur zu noch so allem ausnutzen kann um
das Programm zu vereinheitlichen.
Wenn du in Zeitnot bist, oder dir Floating Point aus Speichergründen
nicht leisten kannst oder willst, müsste man das auf Festkommaarithmetik
umbauen. Aber das Prinzip bleibt das gleiche :-) Es gibt eine
Beschreibung für jeden einzelnen ADC Kanal, die alles enthält, was für
diesen Kanal interessant ist. Beim Messergebnis steht dabei aus welchem
Kanal es gewonnen wurde (über den Pointer; könnte man auch als Index
ausführen, wenn du dir den Speicher für n Pointer nicht leisten kannst
oder willst) und damit steht dann auch bei jedem Messergebnis die
komplette Palette an Informationen zur Verfügung die benötigt wird, um
die ADC Ergebnisse zu manipulieren (inkl. Umrechnung des ADC Wertes in
einen für den Leser vernünftigen Wert). Alle Sensoren werden gleich
behandelt, es gibt keinen Unterschied zwischen den Sonsoren. Jeder
Sensor kann für sich kalibriert werden (indem die Umrechnungskonstanten
beim Kanal kalibriert werden), einen neuen Kanal einfügen ist trivial,
einen Kanal herausnehmen ist trivial, feststellen welche ADC Kanäle
überhaupt mit einem Sensor bestückt sind ist trivial möglich (zb. über
die Umrechnungskonstanten), etc., etc.
Unterschätze nie die Möglichkeiten die sich eröffnen, wenn man Dinge die
zusammengehören auch beisammen lässt (zb. in dem man sie in einer
Struktur gruppiert)
Sehr schön danke, wieder was dazugelernt :D
Aber da ich meine Werte über einen Messchip bekomme, benötige ich den
ADC nicht (zumindest nicht für diese Zwecke ;) )
Ich werde alles mal so lassen, weil mein atmega32 zu 95,4% voll ist und
ich sowieso in extremer Zeitnot bin.
Somit bin ich mit meinem Projekt fertig :D Sobald ich alles nocheinmal
kontrolliert habe und eine Dokumentation davon fertiggestellt habe,
werde ich das Projekt hier raufladen. (ich freu mich schon auf
Verbesserungsvorschläge dann eurerseits) =)