Forum: Mikrocontroller und Digitale Elektronik Lookup-Tabelle für Anfänger


von Philipp (Gast)


Lesenswert?

Hi Leute,

ich bin ein ziemlich unerfahrener Mikrocontroller-Programmierer und mein 
C-Programm soll ungefär folgendes machen:

- Der ADC liest eine Spannung ein
- Je nach ADC-Wertebereich sollen beliebige Ausgänge geschaltet werden

Es gibt insgesamt 2 verschiedene Tabellen mit je 30 Intervallen (z.B 
if(200<ADC<225) {schalte port bla bla})


Das Ganze habe ich jetzt erstmal mit 60 if-else Verzweigungen 
programmiert, was mir allerdings ziemlich primitiv erscheint, da im 
schlimmsten Fall 29 Abfragen umsonst durchlaufen werden müssen. Wie 
liese sich sowas denn eleganter lösen? (ich habe was von Lookup Tabelle 
gelesen?)


Gibt es ausserdem eine Möglichkeit im Compiler (AVR Studio 4.19) noch 
einen "Korrekturfaktor" auf meine Schaltschwellen (oder auf den 
ADC-Wert) draufzurechnen ohne, dass am Ende eine eklige Kommazahl 
herauskommt?


Besten Dank!

Gruß,
Philipp

von Wolfgang (Gast)


Lesenswert?

Philipp schrieb:
> Wie liese sich sowas denn eleganter lösen?

Das kommt drauf an, wie deine Schaltschwellen liegen.

Philipp schrieb:
> Gibt es ausserdem eine Möglichkeit im Compiler (AVR Studio 4.19) noch
> einen "Korrekturfaktor" auf meine Schaltschwellen (oder auf den
> ADC-Wert) draufzurechnen ohne, dass am Ende eine eklige Kommazahl
> herauskommt?

Rechne mit Ganzzahl, dann kann das nicht passieren.

von Uli (Gast)


Lesenswert?

Wie groß ist der Wertebereich Deiner Messung? Und sind das nur integer?

Wenn Du z.B. einen Wertebereich von 0-255 hast könntest Du ein Array 
anlegen in der für jeden Wert drinsteht was auf den Port ausgegeben 
werden soll...


Also z.B.:

0-9 => Port Pin 1 aktiv
10-19 => Port Pin 2 aktiv
20-255 => Port Pin 3 aktiv


Dann belegst Du Dein Array so vor:
1
 
2
uint8_t schaltzustand[255] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0-9 */
3
                               2, 2, 2, 2, 2, 2, 2, 2, 2, 2,  /* 10-19 */
4
                               4, 4, 4, 4, 4, ..... bis zum Ende }; /*20-255 */

Auswerten tust Du dann mit

in uint8_t adc_value steht Dein auswerteergebniss:
1
  PORT<blafasel> = schaltzustand[adc_value];

von Bernd N. (Gast)


Lesenswert?

Mal unterstellt deine Schaltschwellen sind linear aufsteigend dann 
dividiere deinen ADC Wert durch 10 und du erhältst 102 Schaltpunkte.

Beispiel Pseudocode
1
const u8 PortCombination [8] = {0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF};
2
3
Port = PortCombination [(getAdcValue () / 128];

Ergibt 8 verschiedene Zustände in Abhängigkeit deines AD Wertes.

von Philipp (Gast)


Lesenswert?

Wolfgang schrieb:
> Das kommt drauf an, wie deine Schaltschwellen liegen.
Uli schrieb:
> Wie groß ist der Wertebereich Deiner Messung? Und sind das nur integer?
Bernd N. schrieb:
> Mal unterstellt deine Schaltschwellen sind linear aufsteigend...

Die Tabelle fängt bei etwa ADC=200 an und geht bis etwa ADC=800. Das 
sind direkt die integer Werte die aus dem ADC kommen. Die 
Schaltschwellen sind aber NICHT linear aufsteigend sondern müssen 
beliebig festgelegt werden können.

Am schönsten wäre es natürlich, wenn man die Schaltschwellen direkt als 
Zahl eingeben könnte.


Wolfgang schrieb:
> Rechne mit Ganzzahl, dann kann das nicht passieren.

Wie genau funktioniert das denn?

von Philipp (Gast)


Lesenswert?

Ergänzung:

Alle Schaltschwellen die ich eingegeben habe sollen vom Compiler schon 
bevor das Programm erstellt wird z.B. mit 1,04 multipliziert und dann 
auf ganze Zahlen gerundet werden.

von Peter II (Gast)


Lesenswert?

Philipp schrieb:
> Die Tabelle fängt bei etwa ADC=200 an und geht bis etwa ADC=800. Das
> sind direkt die integer Werte die aus dem ADC kommen.
sind dann alle werte durch 4 Teilbar?

wenn ja dann passt es schon mal gute in ein byte rein. Das spart dann 
platz im speicher.

von abc123 (Gast)


Lesenswert?

Ist nur schnell hingeschmiert. Wenn die Tabelle länger ist kann man sie 
in den Flash verbannen.
1
typedef struct
2
{
3
  uint16_t max;
4
  uint8_t pin;
5
} schwelle_t;
6
7
#define NB_SCHWELLEN 5
8
9
...
10
11
schwelle_t schwellen[NB_SCHWELLEN]= { { 100, 1},
12
                                      { 250, 4},
13
                                      { 500, 5},
14
                                      { 500, 2},
15
                                      {1023, 6} };
16
17
uint8_t i=0;
18
for(i=0;i<NB_SCHWELLEN && !(schwellen[i].max>=ADC);i++);
19
if(schwellen[i].max>=ADC)
20
  PORTB|=(1<<schwellen[i].pin);

von abc123 (Gast)


Lesenswert?

Wenn der letzte Eintrag im Array 1023 = "uint10_max" enthält kann man 
sich die if-Abfrage sparen.

von Wolfgang (Gast)


Lesenswert?

Philipp schrieb:
> Wie genau funktioniert das denn?

Das kommt drauf an, was du genau vor hast.

z.B.
  a = (b * c - d) * 2^-d

Wobei 2^-d eine Shift-Operation um d Stellen ist.

von Philipp (Gast)


Lesenswert?

abc123 schrieb:
> Ist nur schnell hingeschmiert. Wenn die Tabelle länger ist kann man sie
> in den Flash verbannen.

Vielen Dank! Das gefällt mir jetzt schon recht gut. Da wär ich nie drauf 
gekommen.

abc123 schrieb:
> Wenn der letzte Eintrag im Array 1023 = "uint10_max" enthält kann man
> sich die if-Abfrage sparen.

Wegen der Abbruchbedingung der for-Schleife oder?

Wolfgang schrieb:
> Das kommt drauf an, was du genau vor hast.

Wenn ich jetzt z.B. die uint16_t max Werte in dem Array aus dem Beispiel 
von "abc123" alle mit einem Korrekturfaktor multiplizieren möchte. Aber 
ohne, dass der Compiler mir dann Kommawerte daraus macht und in den 
Atmega programmiert. Quasi so als würde ich die Werte alle manuell mit 
dem Korrekturfaktor multiplizieren und dann den gerundeten Wert in das 
Array reinschreiben.


Gruß,
Philipp

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.