sprintf verfälscht adc werte

#1372559
Lesenswert?

Hi,

ich habe vielleicht ein komisches Problem: Ändere ich die beschriftung 
meiner werte, kommen plötzlich falsche adc werte raus. Woran liegt das?

RS232 Log:
a 228 b 3 a 371
a 229 b 3 a 371
a 229 b 3 a 371
a 229 b 2 a 371
adc 228 b -2 a 24063
adc 14656 b 192 a 23744
adc 14656 b 192 a 23744
adc 14656 b 192 a 23744



Codeausschnitt:
    char buffer[20];
    send=adc_read_and_null(ADC_highmosfet);
    sprintf( buffer, "adc %i ", send);
    usart_puts( buffer);
    send=adc_read_and_null(0);
    sprintf( buffer, "b %i ", send);
    usart_puts( buffer);
    send=adc_read_and_null(ADC_supplyvoltageref);
    sprintf( buffer, "a %i ", send);
    usart_puts( buffer);
Persönliche Seite #1372592
Lesenswert?

Wieviel Platz hast du noch im µC?

    sprintf( buffer, "adc %i ", send);
    sprintf( buffer, "b %i ", send);
    sprintf( buffer, "a %i ", send);

Braucht 8+6+6 Bytes im ROM und nochmal im RAM für die Formatstrings.

    sprintf( buffer, "a %i ", send);
    sprintf( buffer, "b %i ", send);
    sprintf( buffer, "b %i ", send);

Braucht 6+6 Bytes im ROM und nochmal im RAM für die Formatstrings.
#1372793
Lesenswert?

Nachtrag: An sprintf liegts selbst nicht, folgendes funktioniert:

code:
char buffer[60];
sprintf( buffer, "s:%i hv%i o%i", send3, send2, OCR2);
usart_puts( buffer);
sprintf( buffer, "a%i b%i c%i d%i", 123, 456, 789, 12);
usart_puts( buffer);

log:
restart
s:22464 hv216 o0a123 b456 c789 d12
s:22528 hv13888 o14a123 b456 c789 d12
s:22464 hv13888 o14a123 b456 c789 d12
s:22528 hv13888 o14a123 b456 c789 d12
s:22464 hv13888 o14a123 b456 c789 d12

nur irgendwie verreists mir die adc werte.

Danke für eure Hilfe
#1372940
Lesenswert?

Soweit so gut.
Und wo sind jetzt besagte sprintf?

Edit:
Bis jetzt habe ich eigentlich nur gesehen, dass du Zugriffe auf _adcdata 
nicht gegen Interrupts abgesichert hast. Da _adcdata ein int ist, musst 
du das tun, da die Operation nicht atomar ausgeführt werden kann.

zb
1
unsigned int adc_read(unsigned char channel){
2
  unsigned int readit;
3
  do{
4
    cli();
5
    readit=_adcdata[channel];
6
    sei();
7
  } while(readit==ADC_value_nulled);
8

9
  cli();  
10
  readit = _adcdata[channel];
11
  sei();
12
  return readit;
13
}

Wenn man es ganz exakt machen will, müsste man anstelle des sei() 
eigentlich immer den vorhergehenden Zustand wiederherstellen. 
Schliesslich sagt ja niemand, dass Interrupts generell aktiviert sind, 
wenn adc_read aufgerufen wird. Aber in deinem Fall kann man wohl davon 
ausgehen, dass das immer so sein wird.


Nitpicking:
Namen, die mit einem _ beginnen, sind für den Compiler bzw. die Runtime 
Library reserviert.
#1373025
Lesenswert?

Hallo Jörg,

> cli() expandiert zu asm__ __volatile, das sollte der
> Compiler nicht umgruppieren.

ohne mich jetzt sooo besonders auszukennen:  Um nicht umgruppiert zu 
werden, müssten sei() und cli() dem Compiler mitteilen, dass ihre 
Seiteneffekte beliebigen Speicher und beliebige Register modifizieren 
können (was aus Gründen der Optimierung aber sonst unerwünscht ist, aber 
oben im Bezug auf den ADC-Wert der Fall ist).  So jedenfalls habe ich es 
aus einer längeren und sehr interessanten Diskussion vor ca. 2 Monaten 
in comp.embedded (mitlesend) geschlossen.  Der Compiler darf solange 
umgruppieren, wie das Ergebnis inklusive aller Seiteneffekte dasselbe 
bleibt, so mein Stand.
#1373908
Lesenswert?

Lösung gefunden. In meiner ADC Datei kommt beim ADMUX (Analog 
Multiplexer) scheinbar was durcheinander. Ich habe das jetzt ersetzt und 
wunderweis, es geht!
folgendes
  char temp;
  temp=ADMUX;
  temp&=~((1<<MUX3)+(1<<MUX2)+(1<<MUX1)+(1<<MUX0));
  temp|=_adc_current_pos;
  ADMUX=temp;;
durch:
ADMUX=ADMUX_CONFIG+_adc_current_pos;

ersetzt und es geht!

Hat jemand zufällig eine Erklärung dafür?
#1373929
Lesenswert?

Hmm

Ersetze mal
  char temp;
durch
  unsigned char temp;

(WEnn du mit Bytes arbeitest, sei immer explizit!
char benutzt du nur dann, wenn du es auch tatsächlich mit Charactern im 
Sinne von Textverarbeitung zu tun hast.
Du weißt nie (ausser du siehst in der Doku nach) ob der Compiler char 
als signed oder unsigned ansiehst. Je nachdem kann da einiges passieren.
#1374798
Lesenswert?

Ich bin kein Freund von uint8_t da mein Prog das nicht hervorhebt.

Jetzt müsst ihr mich aber mal ein bisschen Aufklären: was ist der 
unterschied zwischen uint_least8_t und uint_fast8_t? Bzw. was heißt das?

Übersetzt mir das Englische jetzt noch jemand bitte ins Deutsche? Ich 
komm trotz meinen 8 Jahren Englisch nicht dahinter was gemeint ist...
Moderator Persönliche Seite #1374918
Lesenswert?

Michael H. schrieb:
> Ich bin kein Freund von uint8_t da mein Prog das nicht hervorhebt.

Dann kannst du dir immer noch einen anderen Editor suchen oder aber
denjenigen, der ihn gebaut hat, darauf hinweisen, dass es an der
Zeit wäre, 10 Jahre nach der Verabschiedung des aktuellen C-Standards
sowas mit zu unterstützen.

> Jetzt müsst ihr mich aber mal ein bisschen Aufklären: was ist der
> unterschied zwischen uint_least8_t und uint_fast8_t?

uint8_t verlangt eine vorzeichenlose Ganzzahl, die exakt 8 bit
breit ist.  Wenn die zu Grunde liegende Maschine eine derartige
Zahl nicht darstellen kann (und der Compiler sie auch nicht emulieren
kann oder will), dann gibt es diesen Typ nicht, und entsprechender
Code lässt sich nicht compilieren.  Eine mögliche Folge davon ist,
dass eine derartige Zahl im Zugriff u. U. weniger effektiv ist, als
eine größere Zahl auf einer bestimmten Maschine wäre.  Damit ist
dieser Datentyp prädestiniert für Informationen, bei denen es wirklich
auf die genaue Bitanzahl ankommt, bspw. in irgendwelchen Kommunikations-
protokollen (Netzwerk, SCSI etc.) oder beim Zugriff auf bestimmte
Hardwarekomponenten.

uint_least8_t verlangt eine vorzeichenlose Ganzzahl, die mindestens
8 bit breit ist.  Falls die zu Grunde liegende Maschine eine solche
Zahl nicht darstellen kann, kann sie aber auch einen größeren Daten-
typ substituieren.  Das Augenmerk liegt aber auf dem Einsparen von
Speicherplatz, wenn die Maschine das also implementieren kann (auch
wenn es auf Kosten der Effektivität geht), dann ist er auch 8 bit
breit.

uint_fast8_t verlangt eine vorzeichenlose Ganzzahl, die mindestens
8 bit breit ist.  Falls die zu Grunde liegende Maschine jedoch mit
einer größeren Bitanzahl schnelleren Code erzeugt (weil bspw. auf
einer 32-bit-Maschine Zahlen von 32 bits schneller zu bearbeiten
sind als deren 8-bit-Teilwerte), dann soll dieser Typ substituiert
werden.  Augenmerk ist also die Geschwindigkeit, auch wenn es auf
Kosten des Speicherbedarfs möglicher Variablen geht.

Damit wäre an vielen Stellen, wo sich in der AVR-Community derzeit
uint8_t eingebürgert hat, eigentlich uint_fast8_t zu bevorzugen,
wenn der Code ggf. auch auf andere (größere) Architekturen portierbar
sein soll.

Die ganzen Datentypen gibt's dann auch noch ohne dem führenden u
für vorzeichenbehaftete Zahlen.
#1375190
Lesenswert?

Vielen Dank Jörg für deinen ausführliche Erklärung. Ich nutze zur Zeit 
geany und frage gleich mal in der Newsgroup nach, was man da machen 
kann...

>7.1.3 Reserved identifiers
>...
>-- All identifiers that begin with an underscore are always reserved
>   for use as identifiers with file scope in both the ordinary and
>   tag name spaces.
Kann mir das bitte noch jemand übersetzten, ich komme nicht dahinter was 
gemeint ist.

Update: geany unterstützt es seit der neuen Version, ich hatte es nur 
mit der alten probiert... Nochmal vielen Dank für deine Erklärungen!
Moderator Persönliche Seite #1375283
Lesenswert?

Michael H. schrieb:

>>7.1.3 Reserved identifiers
>>...
>>-- All identifiers that begin with an underscore are always reserved
>>   for use as identifiers with file scope in both the ordinary and
>>   tag name spaces.

> Kann mir das bitte noch jemand übersetzten, ich komme nicht dahinter was
> gemeint ist.

Die Details, an welchen Stellen man einen führenden Unterstrich auch
als Autor eines normalen Anwenderprogramms schreiben darf und an
welchen nicht, sind ein wenig, naja, nicht sofort offensichtlich.
Solange du dich mit den Details nicht befassen willst, kannst du
also oberste Regel nehmen: schreib keine Bezeichner, die mit einem
Unterstrich beginnen.  Die vielleicht prominenteste Ausnahme davon
wäre diese hier:
1
struct _foo {
2
   ...
3
};

Dort ist er immer zulässig, sofern es ein Unterstrich ist (nicht
zwei) und sofern danach ein Kleinbuchstabe folgt.

Ansonsten sind Bezeichner mit einem führenden Unterstich ,reserviert',
d. h. für die Benutzung durch den Compiler oder die Systembibliotheken
vorbehalten.  Natürlich darfst du sie dann trotzdem benutzen, aber
halt genau dann, wenn dir die Dokumentation des Compilers oder der
Bibliothek sowas sagt.  Beispiele dafür sind:
1
char x[] __attribute__((progmem)) = "Hi";
2
     /* Dokumentation von GCC beschreibt das */
3
#define __STDIO_FDEVOPEN_COMPAT_12 /* avr-libc-Dokumentation beschreibt,
4
                                      was dabei passiert */
5
PORTE = _BV(1);  /* ebenfalls Bestandteil der avr-libc */

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