Hallo Forum,
ich habe eine kleine Aufgabe. Es ist nichts schulisches oÄ sondern nur
für ein privates Projekt. Also:
ich habe eine (globale) Variable currentID;
Diese soll bei jedem Durchlauf eins erhöht werden, allerdings in einem
bestimmten Muster:
01-16
17-32
01-16
33-48
01-16
49-64
01-16
65-80
und dann wieder von vorne
(hoffe die Zahlenreihe stimmt so ;) )
Also soll praktisch immer ein 16er-Block genommen werden und zwischen
jedem block ein mal der block 1-16.
eig müsste mann es ja irgendwie mit if(currentID & 16) lösen können,
aber ich komme auf keine Lösung...
Wahrscheinlich sehr trivial, aber ich bitte trotzdem um Hilfe ;)
Danke schon mal
nga schrieb:> Es ist nichts schulisches oÄ sondern nur für ein privates Projekt.
Das klänge angesichts dieser exotischen Aufgabe überzeugender, wenn du
was zum Projekt verrätst.
Kleiner Tip: Wenn ausschliesslich die gezeigten Information vorhanden
ist, also ein einziger Zahlenwert zwischen 1 und 80, geht es nicht. Du
kannst dir aber aussuchen, ob die fehlende Information aus Daten
besteht, oder aus der Position im Verfahren.
A. K. schrieb:> Das klänge angesichts dieser exotischen Aufgabe überzeugender, wenn du> was zum Projekt verrätst.
Haha, okay
Also ich habe ein System mit 80 Slaves (angesteuert über einen
parallel-Bus und eigenem "Protokoll")
Die ersten 16 davon sind kritischer/wichtiger deswegen sollten die so
oft ausgelesen werden.
Ausgelesen werden diese in einer Timer-ISR, einer nach dem anderen und
bei jedem Durchlauf soll der nächste Slave angesprochen werden
Du brauchst auf alle Fälle zwei Variablen. Eine für den aktuellen
Zählstand 1...16 und eine für den Offset (z. B. x * 16).
Für beide Variablen reichen 4 Bit. ;-)
i = 0;
ISR:
if (i & 1)
sensor(1 + (i >> 1) % 16)
else
sensor(17 + (i >> 1));
if (++i == 128)
i = 0;
Gibt nicht die gleiche Reihenfolge, aber die gleiche Abfragefrequenz.
Ich würde es auch mit 2 getrennten Timern machen. Bsp.: Timer 1 läuft
mit 1 ms und fragt die Eingänge 1-16 ab, Timer 2 Läuft mit 5 ms und
fragt die restlichen Eingänge ab.
Mini Mem schrieb:> Du brauchst auf alle Fälle zwei Variablen. Eine für den aktuellen> Zählstand 1...16 und eine für den Offset (z. B. x * 16).
Natürlich, aber ich bin wohl nicht fähig auf eine Lösung zu kommen:
A. K. schrieb:> i = 0;>> ISR:> if (i & 1)> sensor(1 + (i >> 1) % 16)> else> sensor(17 + (i >> 1));> if (++i == 128)> i = 0;>> Gibt nicht die gleiche Reihenfolge, aber die gleiche Abfragefrequenz.
Danke schon mal dafür, ich muss den Code nur noch verstehen ;)
Werde mich aber mal dransetzen
libba schrieb:> Ich würde es auch mit 2 getrennten Timern machen. Bsp.: Timer 1 läuft> mit 1 ms und fragt die Eingänge 1-16 ab, Timer 2 Läuft mit 5 ms und> fragt die restlichen Eingänge ab.
Wäre eine Idee, aber ich habe keinen Timer mehr frei (eigentliches
Target ist ein AVR aber ich fand dass die Frage allgemein für
Programierung gilt, deswegen in diesem Unterforum).
Olaf Dreyer schrieb:> So kannst Du beliebige Reihenfolgen festlegen:>> char aSlaves = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,> 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,> 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,> 33,34,.....>> char uIndex = 0;>> ISR(XXX) {> doSomethingWithSlave(uIndex);> uIndex++;> if(uIndex >= sizeof(aSlaves))> uIndex = 0;> }
Eigentlich keine schlechte Idee, aber liegt dass Array dann nicht im RAM
und wird erst zur Laufzeit ausgewertet? In einer ISR ist das glaube
nicht so gut
A. K. schrieb:> Martin B. schrieb:>> Keiner sagt das das ganze getimed sein soll.>> Doch. Er sagt das.
OK,
aber man kann doch auch in einem Timer zwei Variablen zählen.
Olaf Dreyer schrieb:> Ja das ist richtig. Speicherintensiv, aber flexibel.> Und einfach zu verstehen :-)>> Gruß>> Olaf
Das array kann const sein und damit im Flash liegen.
Aber mit Zahl variablen finde ich das bedeutend besser.
A. K. schrieb:> Olaf Dreyer schrieb:> Speicherintensiv,>> Ach wo. ROM pur geht auch:> const _flash char aSlaves[] = ...> wenn leidlich aktueller avr-gcc.
Na ja, Speicher intensiv bleibt es trotzdem. Flash ist auch Speicher.
;-)
Olaf Dreyer schrieb:> Speicherintensiv
Man kann ja auch mischen.
Nur den Anfangswert für jeweils 16 Durchläufe im Array ablegen.
Dann sind das gerade mal acht Byte.
(Ich würde neun nehmen und als letztes eine 0 (oder -1) als Endekennung
ablegen)
nga schrieb:> Wahrscheinlich sehr trivial, aber ich bitte trotzdem um Hilfe ;)
Offensichtlich möchtest du 4 Abfrageblöcke machen, in denen du jeweils
einmal von [1 .. 16] und einmal von BlockNr*16 + [1..16] zählst (mit
Blocknummer=1..4), also
1
for BlockNr=1 to 4
2
{
3
for j=1 to 16
4
Abfrage (j);
5
6
for j=1 to 16
7
Abfrage (BlockNr*16 + j);
8
}
und das ganze in C.
Einfacher wird das Programm, wenn die Reihefolge nicht so festgelegt ist
nga schrieb:> ich muss den Code nur noch verstehen ;)
Sollte nicht so schwer sein, das einfach mal durchlaufen zu lassen und
den Index auszugeben. Dann siehst du auch, ob die abweichende
Reihenfolge den Anforderungen entspricht.
0815 schrieb:> Offensichtlich möchtest du 4 Abfrageblöcke machen,
Jetzt musst du das nur noch so umstellen, dass eine ISR draus wird. ;-)
Dass es darum geht hatte er erst verspätet verraten.
A. K. schrieb:> nga schrieb:>> ich muss den Code nur noch verstehen ;)>> Sollte nicht so schwer sein, das einfach mal durchlaufen zu lassen und> den Index auszugeben. Dann siehst du auch, ob die abweichende> Reihenfolge den Anforderungen entspricht.
Ich werde es testen, muss nur noch (selbst ;) ) rausfinden warum
geshiftet wird.
Ich werde auch noch die Array-Variante austesten und schauen wie gut was
funktioniert. Auch 0815s Programm werde ich testen
Danke schon mal an alle
Man erkennt ein paar Gesetzmäßigkeiten:
* Innerhalb der 16er-Blöcke zählt es stetig hoch. Also ist ein Teil des
Ergebnisses schonmal i % 16 (unten a genannt).
* Alle 16 ändert sich der Status von "erster block" auf "normal
ansteigend". Alle 16 ändert sich auch das entsprechende Bit, was man mit
i%16 herausfindet.
* Zu a muss man ggf. noch eine Zahl addieren, die alle 32 um 16
springt.
uint8_t id(uint8_t i)
{
uint8_t a = 1 + (i & 15);
bool use_first = ! (i%16);
uint8_t base = 16 + (i/32)*16;
return a + (use_first ? 0 : base);
}
Ok, ich hab ne Idee. Die ist echt nicht so ganz trivial zu verstehen,
aber mich hat das Problem gereizt.
Vielleicht hab ich auch was übersehen, dann bitte ich um ne Korrektur.
Zunächst mal braucht man als Ausgangspunkt ja einen Anhaltspunkt, wo man
gerade in der Sequenz ist. Also zählt man mal statt der gesuchten Folge
einfach von 0 bis 127 und schaut wie der gesuchte Wert korrespondiert.
Dabei geh ich jetzt mal davon aus, dass der gesuchte Wert bei 0 beginnt
und nicht bei 1, weil es das Rechnen erleichtert. Bei Bedarf halt eine 1
am Ende addieren.
Also 16er Blöcke:
0 - 15 => 0 - 15 = Ausgangswert - 0
16 - 31 => 16 - 31 = Ausgangswert - 0
32 - 47 => 0 - 15 = Ausgangswert - 32
48 - 63 => 32 - 47 = Ausgangswert - 16
64 - 79 => 0 - 15 = Ausgangswert - 64
80 - 95 => 48 - 63 = Ausgangswert - 32
96 - 111 => 0 - 15 = Ausgangswert - 96
112 - 127 => 64 - 79 = Ausgangswert - 48
Wenn ich nun das obere Nibble des Ausgangswert betrachte und das Nibble
des gesuchten Subtraktors daneben schreibe, komm ich auf:
000 | 000
001 | 000
010 | 010
011 | 001
100 | 100
101 | 010
110 | 110
111 | 011
(Das untere Nibble wird ja eh übernommen, also lass ich das hier weg.)
Ist das niedrigte Bit auf der linken Seite 0, bleibt der Wert
unverändert. Ist er 1, wird der Wert um 1 nach rechts geschoben.
Der Wert wäre also (ich nehm mal index als 'Ausgangswert'.
index & 16 == 0 ? index & 0xf0 : (index & 0xf0) >> 1;
Also jetzt mal in einer Schleife:
for( int i = 0; i < 127; ++i) {
int subtract = i & 0xf0;
if( i & 16) {
subtract >>= 1;
}
int result = i - subtract + 1; // Add 1 to start the counting at 1.
}
Lieg ich falsch? Hab das jetzt mal nicht gecoded, also praktisch
getestet, aber ich hoffe mal die Idee kommt rüber.
Mist! In meiner Lösung ist zumindest noch ein Fehler! Beim Schieben nach
rechts, wird ja das unterste Bit ins untere Nibble geschoben.
Also hinter
subtract >>= 1;
noch ein subtract &= 0xf0;
(7f ginge auch, da ja das oberste Bit eh nicht benutzt werden sollte.)
Ähnlich wie Arc Nets Vorschlag (und genauso kryptisch ;-)), aber
zusätzlich ohne die Multiplikation. Außerdem muss die Zählvariable nicht
auf 0..127 begrenzt werden, man kann sie einfach bis zum Wrap-Around
durchlaufen lassen:
Leute, Leute, das geht ja schnell hier ;)
Ich werde heute oder in den nächsten Tagen die Lösungen testen, dann
werde ich berichten.
Nochmal ein großes Dankeschön an alle