Eine weitere Bitumrechnung

Gast #5761530
Guten Abend,

Komme bei der ganzen Bitumrechnung nicht mehr klar. Habe folgendes 
Problem: Möchte die Dezimalzahl meines AD Wandlers (12-Bit Auflösung, 
3.3V Ref) in die Spannung umrechnen und per UART übertragen. Fordert 
mich mehr als ich dachte.
1
uint8_t buffer[10];
2

3
void scale(uint32_t vol){
4

5
  uint8_t i;
6
  uint8_t a;
7
  uint8_t b;
8
  uint8_t c;
9

10
  i = vol*100*0.0008056640;
11
  a = i/100;
12
  b = (i- (a*100))/10;
13
  c = (i- (a*100 + b*10));
14

15
  sprintf(buffer, "%hd.%hd%hdV\n",a,b,c);
16
  HAL_UART_Transmit(&huart2, buffer, 9, 1000);
17
}

Im Anhang sieht man was ich empfange. Wahrscheinlich ein kleiner dummer 
Fehler aber finde ihn nicht. Vllt hat jemand langeweile und hilft mir. 
Danke
Angehängte Dateien:
Gast #5761540
STm32 schrieb:
> Im Anhang sieht man was ich empfange. Wahrscheinlich ein kleiner dummer
> Fehler aber finde ihn nicht. Vllt hat jemand langeweile und hilft mir.
> Danke

Wenn du sowieso schon sprintf verwendest, kannst du auch gleich %f oder 
in deinem Fall %.2f verwenden.
Einfach mal sprintf googlen.
%hd geh;rt da eh nicht rein. Das gehört zu scanf
Gast #5761541
Das ist doch normaler Dreisatz:

X Bit (ADC Messwert)
max Zählerwert (100%) 4095 Bit (12-Bit Auflösung)
V_max = 3.3V

gesucht:
V_mess

V_mess    X
------ = ----
V_max    4095

nach umformen gilt:

V_mess = X * V_max /4095

man muss nur einen passenden Zahlentyp wählen.

Schau dir bitte mal 32Bit float an.
Gast #5761569
Karl M. schrieb:
> Schau dir bitte mal 32Bit float an.

Warum braucht man zur Darstellung von 12-Bit Werten eine 32Bit float 
Zahl.

Nur um bei der Ausgabe einen Dezimalpunkt zu erzeugen?
Dafür reicht es, an passender Stelle ein 0x2E zum UART zu schicken.
Gast #5761581
my2ct schrieb:
> Karl M. schrieb:
>> Schau dir bitte mal 32Bit float an.
>
> Warum braucht man zur Darstellung von 12-Bit Werten eine 32Bit float
> Zahl.
>
> Nur um bei der Ausgabe einen Dezimalpunkt zu erzeugen?
> Dafür reicht es, an passender Stelle ein 0x2E zum UART zu schicken.

Ja mir klar, aber der TO muss erst mal einen Fuß auf den Boden bekommen.

Sonst hätte ich auch schon eine Optimierung vorgestellt.
Gast #5761589
STm32,

wenn man anstatt V_max = 3,3V eine anderen Wertebereich nutzen möchte,
z.B. !!!!! 1mV,
dann wäre V_max = 3300mV und schon passt das in Ergebnis mit 
Nachkommastellen in eine 16Bit Variable.

Bei Berechnungen müssen dann auch Bereichsüberläufe beachtet werden.
D.h. eine Multiplikation von: 16Bit * 16Bit passt in 32Bit.
Gast #5761590
STm32 schrieb:
> Wahrscheinlich ein kleiner dummer Fehler a

In i, a, etc. passe  nur Werte von 0 bis 255 ohne Nacbkommastellen.

Deine mathematischen Formeln erzeugen aber weit mehr.

Ein sprintf zu verwenden ist Wahnsinn, das ist eine der aufwändigsten 
Funktionen die es gibt.

Rechne deine vol in eine 10Millivoltzahl um.

int i=(vol x 100L)/1241;

und schreibe selber die Ziffern mit Komma

char buffer[6];
buffer[5]='\0';
buffer[4]='V';
buffer[3]='0'+(i%10);
i/=10;
buffer[2]='0'+(i%10);
i/=10;
buffer[1]='.';
buffer[0]='0'+(i%10);
Gast #5761591
Gebe die Werte a, b und c auf meinem LCD-Display aus. Die Umrechnung des 
Dezimalwertes in die Spannung und in die Dezimalstellen passt also. Habe 
gedacht dass es an dem sprintf liegt.
Gast #5761595
Tausche deinen GCC mal durch GCC8 aus und mach -Wall -Werror an.
Dann lässt er dich das nicht kompilieren, weil du sprintf deinen Buffer 
überlaufen kann.
Gast #5761600
MaWin schrieb:

>
> char buffer[6];
> buffer[5]='\0';
> buffer[4]='V';
> buffer[3]='0'+(i%10);
> i/=10;
> buffer[2]='0'+(i%10);
> i/=10;
> buffer[1]='.';
> buffer[0]='0'+(i%10);

Mhm. Reicht eigentlich für die kleine Anwendung. Werde dann wohl noch 
etwas den Code verbessern.Danke
Gast #5761608
Variante 1, einfach Millivolt ausgeben:
1
void send_millivolt(uint16_t val)
2
{
3
  char buf[16];
4
  uint16_t x = (val * 3300ul + 2048) / 4095;
5

6
  HAL_UART_Transmit(&huart2, buf, sprintf(buf, "%umV\n", x), 1000);
7
}
Oder etwas anders, diesmal mit Nachkommastellen:
1
void uart_puts(char *buf)
2
{
3
  HAL_UART_Transmit(&huart2, buf, strlen(buf), 1000);
4
}
5

6
void send_volt(uint16_t val)
7
{
8
  char buf[16];
9
  uint16_t x = (val * 330ul + 2048) / 4095;
10

11
  sprintf(buf, "%u.%02uV\n", x/100, x%100);
12
  uart_puts(buf);
13
}

Das "ul" in "* 3300ul" damit eine 32-bit-Multiplikation gemacht wird. 
Das "+ 2048" zum Runden.  Zerlegung der Zahl mittels "/" und "%".
#5761758
Karl M. schrieb:
> Bei Berechnungen müssen dann auch Bereichsüberläufe beachtet werden.

Das hat mich früher auch genervt bzw. Fehler verursacht. Daher mache ich 
solche Rechnungen nur noch in float. So schlecht sind die Libs von 
AVR/8051 ja nicht.
Wenn "?" angezeigt werden, muß man noch den float Teil von sprintf dazu 
linken.
Die ersten AVRs litten noch unter Flash-Geiz (nur 1..2kB), aber das ist 
lange her.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 7 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.