C-Aufgabe: bedingtes Inkrementieren

Gast #4037871
Lesenswert?

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
#4037882
Lesenswert?

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.
Gast #4037889
Lesenswert?

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
(Firma: O.D.I.S.) #4037921
Lesenswert?

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;
}
Gast #4037924
Lesenswert?

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:
1
if(++currentID & 16) {
2
offset += 16;
3
if(offset > 80) offset = 0;
4
currentID = 1;
5
}
6
values[currentID + offset] = readSlave(currentID + offset);

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).
(Firma: O.D.I.S.) #4037926
Lesenswert?

So kannst Du beliebige Reihenfolgen festlegen: 3. Versuch


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(aSlaves[uIndex]);

        uIndex++;

        if(uIndex >= sizeof(aSlaves))
                uIndex = 0;
}
Gast #4037928
Lesenswert?

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
Gast #4037957
Lesenswert?

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
1
for BlockNr=1 to 4 
2
  for j=1 to 16 
3
  {
4
    Abfrage (j);
5
    Abfrage (BlockNr*16 + j);
6
  }
Gast #4037967
Lesenswert?

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
Gast #4037999
Lesenswert?

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);
}
Angehängte Dateien:
Gast #4038003
Lesenswert?

1
int counter()
2
{
3
  static int a = 0;
4
  static int b = 16; 
5
  static int i = 0;
6
  
7
  if (a++ < 16)
8
    return a;
9
  
10
  if (i++ < 16)
11
    return ++b;
12

13
  if (b == 80)
14
    b = 16;
15
    
16
  a = 1; i = 0;
17
  
18
  return a;
19
}
#4038024
Lesenswert?

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.
#4038098
Lesenswert?

1
#include "stdafx.h"
2

3
unsigned char cnt = 0x10;
4

5
int ISR()
6
{
7
  unsigned char address;
8

9
  address = cnt & 0x0F;
10
  if( !( cnt & 0x10 ) )     // LSB vom 'Block-Nibble' ungerade
11
    address += ( cnt & 0xF0 ) >> 1;
12

13
  cnt++;
14
  if( cnt == 0x90 )
15
    cnt = 0x10;
16

17
  return address + 1;
18
}
19

20

21
int main(int argc, char* argv[])
22
{
23
  for( int j = 0; j < 10; j++ ) {
24
    for( int i = 0; i < 16; i++ ) {
25
      printf( "%2d ", ISR() );
26
    }
27
    printf( "\n" );
28
  }
29

30
  return 0;
31
}

1
 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
2
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
3
 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
4
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
5
 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
6
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
7
 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
8
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
9
 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
10
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
Moderator #4038144
Lesenswert?

Ä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:
1
void isr(void) {
2
  static unsigned char i;
3
  do_something((i&15|~(i&16)+1&(i>>1&48)+16)+1);
4
  i++;
5
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren