Codexplosion bei _delay_ms mit ADC Wert

OP #1746147
Lesenswert?

Hallo,

ich möchte mit einem Attiny25 eine Spannung, welche durch ein Poti 
einstellbar ist, messen und diese dann mit der funktion _delay_ms(); als 
Wartezeit verwenden.

Funktionieren würde das ganze. Allerdings wenn ich den ADC Wert als 
Parameter an _delay_ms(); übergeben explodiert mein Code. Sprich er 
springt von ca. 250 Bytes auf ca. 4000 Bytes. Da ich aber wie oben 
geschreiben einen Attiny25 verwende hab ich jetzt ein Problem ;)

Code-Snippet:
1
uint16_t Pause;
2
Pause = 0x0000;
3

4
uint16_t ADC_messen(uint8_t channel)
5
{
6
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
7
  ADCSRA = (1<<ADSC);            // messen
8
  while (ADCSRA & (1<<ADSC) );    // auf AVR warten
9
  ADC_Hilfe = (ADCL<<8);  //ADCL um 8 Bit verschieben
10
  ADC_Hilfe = ADC_Hilfe + ADCH;  //ADCH hinzufügen
11
  return ADC_Hilfe;                    // ADC Wert zurückgeben
12
}
13

14
Pause = ADC_messen(0x01)
15
_delay_ms(Pause);

Kann mir jemand sagen, ob es geht den Code zu verkleinern. Um mir dann 
auch nen Tipp geben kann wie ich das anstellen muss. Die beiden Timmer 
sind leider für PWM belegt.

Gruß
#1746154
Lesenswert?

1
for (uint16_t i = Pause; i > 0; i--)
2
    delay_ms(1);
Grund: Aus der Dukumentation von delay.h:
1
In order for these functions to work as intended, compiler optimizations
2
 must be enabled, and the delay time must be an expression that is a known
3
constant at compile-time. If these requirements are not met, the resulting
4
 delay will be much longer (and basically unpredictable), and applications 
5
that otherwise do not use floating-point calculations will experience severe 
6
code bloat by the floating-point library routines linked into the
7
 application.
OP #1746201
Lesenswert?

danke @ all

auf die For Schleife hätte ich auch kommen können.

Das mit ADCH und ADCL war ein Fehler von mir, da ich ncht aufgepasst 
habe.

Den im Datenbaltt steht ja:
>When ADCL is read, the ADC Data Register is not updated until ADCH is read. 
>Consequently, if
>the result is left adjusted and no more than 8-bit precision is required,
>it is sufficient to read
>ADCH. Otherwise, ADCL must be read first, then ADCH.

Allerdings hab ich nicht auf die Bitwertigkeit geschaut.

ADC_Hilfe war auch deklariert hab ich nur im Snippet vergessen.

Gruß
Gast #1746240
Lesenswert?

Ich möchte noch auf richtige Datentypen hinweisen (den Code selber habe 
ich nicht nachgeschaut). Man MUSS dir Typen für Konstanten auch als 
unit16 machen mit dem Suffix "U". Nach ANSI ist jede Konstante immer 
"signed int"-Datatype und ohnen Suffix wir schreiben einen 
signed-Operand in die unsigned-Variable, was datentypmismatch bedeutet. 
Weiter, "bitwise and shift operations" nur für "unsigned" definiert 
sind. Und leztens, "Integer promotion" Regel achten, d.h. nach ANSI ist 
immer jede Opration auf mind. Integer-Breite durchgeführt und klenere 
Typen werden auf "signed int" im dem Fall hochcastet. Beim AVR kann zum 
Abweichung kommen, aber ANSI spricht klar und MISRA schreibt das vor.
1
uint16_t Pause;
2
Pause = 0x0000U;
3

4
uint16_t ADC_messen(uint8_t channel)
5
{
6
  ADMUX = (ADMUX & ~(0x1FU)) | (channel & 0x1FU);
7
  ADCSRA = (1U<<ADSC);            // messen
8
  while (ADCSRA & (1U<<ADSC) );    // auf AVR warten
9
  ADC_Hilfe = ((uint16_t)ADCL)<<8);  //ADCL um 8 Bit verschieben
10
  ADC_Hilfe = (uint16_t)ADC_Hilfe + (uint16_t)ADCH;  //ADCH hinzufügen
11
  return ADC_Hilfe;                    // ADC Wert zurückgeben
12
}
13

14
Pause = ADC_messen(0x01U)
15
_delay_ms(Pause);
OP #1746386
Lesenswert?

Ich stell gerade fest, dass die ADC Messung gar nicht funktioniert. 
Gemessen werden soll mit ADC1 bzw. PB2

Code-Snippet:
1
uint16_t Pause;
2
Pause = 0x0000;
3

4
ADMUX = (1<<ADLAR);  //"runden"
5
ADCSRA = (1<<ADATE);
6
ADCSRA = (1<<ADEN);  //ADC ein
7

8
uint16_t ADC_messen(uint8_t channel)
9
{
10
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
11
  ADCSRA = (1<<ADSC);            // messen
12
  while (ADCSRA & (1<<ADSC) );    // auf AVR warten
13
  return ADCH;                    // ADC Wert zurückgeben
14
}
15

16
Pause = ADC_messen(1);

Hat jemand nen Fehler entdeckt?

Gruß
#1746449
Lesenswert?

> Nach ANSI ist jede Konstante immer
> "signed int"-Datatype und ohnen Suffix wir schreiben einen
> signed-Operand in die unsigned-Variable, was datentypmismatch bedeutet.

In ANSI C gibt es kein Ding namens "datentypenmismatch", sondern 
"promotion rules".  Es ist also vielmehr genau definiert, zu welchem 
Typen erweitert wird, wenn 2 verschiedene Typen aufeinander treffen.

> Weiter, "bitwise and shift operations" nur für "unsigned" definiert
> sind.

Nein, auch für signed Integers ist Shift definiert, solange sie nicht 
negativ sind:
1
4. The result of E1 << E2 is E1 left-shifted E2 bit positions: vacated
2
bits are filled with zeros. ... If E1 has a signed type and a
3
nonnegative value, and E1x2^32 is representable in the result type,
4
then that is the resulting value; otherwise, the behavior is undefined.

> aber ANSI spricht klar und MISRA schreibt das vor.

Ich weiß nicht, was MISRA schreibt, aber ANSI sagt für den gezeigten 
Code klar aus, dass die Korrektur überflüssige Mühe ist.
Gast #1746520
Lesenswert?

4. The result of E1 << E2 is E1 left-shifted E2 bit positions: vacated
bits are filled with zeros. ... If E1 has a signed type and a
nonnegative value, and E1x2^32 is representable in the result type,
then that is the resulting value; otherwise, the behavior is undefined.

Das ist aber klare Problembeschreibung! Wenn ich 0xFF (also signed) 
8-mal nach links shifte, E1x2^16 (ich habe 16-Bit integer, deswegen nur 
16), E1 nicht mehr "representable" ist. 0xff00 (signed) bedeute -32512 
anstatt 65280 unsigned. Die ASNI-Zeile oben beschreibt nur die Werte, 
die maximal 0x7f haben. Für die Werte 0x80 bis 0xff ist "the behavior is 
undefined". Wer sicherheitsrelevente Systeme programiert, kennt diese 
Problematik und verwendet explizit Casting.
Moderator Persönliche Seite #1746527
Lesenswert?

Du hast mit deiner Erklärung Recht, aber das "2x2^32" bzw. "2x2^16"
da im Text ist falsch: im Standard steht "2 x 2^E2".  E2 ist hier
gleich 8.  Ändert nur nichts dran, dass 0xff00 nicht als signed int
darstellbar ist.

Allerdings trifft das auf das ADC-Ergebnis nicht zu: die ganzen
IO-Register sind vom Typ uint8_t, damit wird der Teil "If E1 has
an unsigned type, [...]" wirksam, für den das Ergebnis definiert
ist.

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