Sida 1 av 2
Hur uC behandlar negativa tal?
Postat: 6 mars 2011, 23:10:48
av Christian
Hej! Ska ställa frågan så konkret som möjligt.
jag har en float variabel:
float variable = 130.0;
Värdet på denna vill jag förmedla via UART:en på en PIC.
Jag försöker med följande:
send( ( variable/100 ) + 48 ); // dela 130 med 100 = 1 ==> Lägg till 48 för att hamna på motsvarande tecken i ASCII tabellen, Skicka 1
Detta fungerar!
Men kompilatorn gnäller om jag ska "extrahera" och skicka resten av talet:
send( ( (variable%100) /10) + 48); //Här vill jag dela 130 med 100, ta resten = 30 , dela 30 med 10 = 3, ==> skicka 3:an
Då säger kompilatorn:
Error [205] 149.30 integral type required
Warning [356] 149.35 implicit conversion of float to integer
Hur skulle ni göra om ni skulle "extrahera" siffrorna ur 130.0 och skicka dem?
Min andra fråga är om det står ett minustecken framför 130, hur "extraherar" man det och sedan resten av talet? Jag gör ett program där jag måste behandla både positiva och negativa tal och skicka ut det..
Re: Hur uC behandlar negativa tal?
Postat: 6 mars 2011, 23:48:17
av 4kTRB
Om du använder tvåkomplementsrepresentation så är talet negativt om MSB är en etta.
Re: Hur uC behandlar negativa tal?
Postat: 6 mars 2011, 23:51:36
av hh
Du har tydligen ingen printf?
% fungerar väl inte med float? Tror det är fmod som gör det.
Re: Hur uC behandlar negativa tal?
Postat: 7 mars 2011, 00:12:21
av Christian
Kan jag använda printf för det här? Alltså att ta ut (minustecknet) , (hundratal), (tiotal) , (ental)?
Jag vet inte vad den gör förrutom att formatera text..
Jag har ju min egen send funktion för UART:en..
Kan du ge exempel på hur jag skulle använda printf?
Re: Hur uC behandlar negativa tal?
Postat: 7 mars 2011, 00:32:16
av Icecap
OM den stödjer float är det enkelt.
printf("+f1.1", F_Value); // Ger förtecken (+ eller -), minst en siffra innan kommat (som är ett punkt) samt en siffra efter.
Då går output via putchar(), tecken för tecken.
Annars kan du använda sprintf till en buffer.
Men MÅSTE du använda float? Float slukar minne och programtid och ger sällan speciella fördelar.
Om vi tar ditt exempel med 130.0 och du bara använder 1/10-del kan du likaväl använda 1300 som heltal och sedan skriva ut på rätt sätt.
Re: Hur uC behandlar negativa tal?
Postat: 7 mars 2011, 00:33:17
av sodjan
> jag har en float variabel:
Här ligger kanske grundproblemet...

Är du 100% övertygad om att du behöver en float på en microcontroller ?
Om du måste skicka float så är det kanske bättre att formattera värdet
med en sprintf (eller liknande) och skicka allt som en sträng direkt.
> Jag har ju min egen send funktion för UART:en..
Men du har väl någon rutin som kan sända från en textsträng ?
Du låter alltså C göra konverteringen/formatteringen av en float
till en sträng och sedan sänder du bara hela strängen (eller ett
tecken i taget om du måste det).
Re: Hur uC behandlar negativa tal?
Postat: 7 mars 2011, 01:04:32
av Christian
Jag har resonerat lite och jag tror det duger med att typa variabeln som en int..
Men hur gör jag om det är en negativt int? Då fungerar ju inte min metod med att dela och modolus..?
Re: Hur uC behandlar negativa tal?
Postat: 7 mars 2011, 01:22:30
av sodjan
> Då fungerar ju inte min metod med att dela och modolus..?
Var vi inte överens om att det sannolikt är fel metod i alla fall ?
Med en int kan du kanske använda itoa() och skicka strängen.
Om du har, säg värden mellan -100 och +100 så kan du öka det med 100,
skicka och minska med 100 i andra änden. Då blir allt positivt "på linjen"
(0-200)...
Re: Hur uC behandlar negativa tal?
Postat: 7 mars 2011, 01:23:54
av jesse
det går ju att ta reda på hur float representeras binärt och från detta göra en algoritm som extraherar alla decimala siffror plus exponent. Ett float kan ju anta väldigt många konstiga värden, tex. 0.004734, 200.02E+8, 3.14159 eller -130.002 När man extrahetar siffror får man alltid till en början samma representation - ett antal siffror och en exponent. Från talen ovan hade du då fått ut: 4.73400E-03, 2.0002E+10, 3.14159E+00 och -1.30002E+02 Så om man vill ha det snyggare (utan exponent) får man flytta runt punkten och eventuellt lägga till nollor. Eventuellt ska du kunna avrunda också.
Om du tycker det ovanstående är överkurs tror jag du ska välja att skicka värdet som ett heltal istället, med eller utan en decimalpunkt instoppad nånstans.
Om du bara ska extrahera tre heltalssiffror, t.ex 1,3 och 0 i talet 130.1234 så är det absolut enklaste att först omvandla talet till heltal. Om du vill ha med en decimal - multiplicera med 10 först - då får du 1301.234 => 1301. Heltal är enkelt att plocka ut siffror från.
Själv har jag en termometer som mäter temperatur med upplösningen 0.1 grad. För att representera 25.7 grader C har jag ett heltal på 257. jag skriver ut heltalet 257, men lägger dit en punkt före sista siffran. mycket enkelt.
Om talet är negativt så brukar jag göra så att jag helt enkelt först skriver ut ett minustecken - sedan tar jag och skriver ut den positiva motsvarigheten av talet.
Här kommer först kod att omvandla ett 32-bitars heltal till siffror:
Kod: Markera allt
#define UASTR 12 // max antal tecken
char siffror[UASTR]; // teckenbuffert för sifferomvandling
char uint_to_string(uint32_t value, uint8_t punkt) {
char p = UASTR;
punkt = UASTR-1-punkt;
siffror[(uint16_t)--p] = '\0';
do {
char ch = value % 10 + '0';
// if (ch > '9') ch += 'a' - '9' - 1;
siffror[(uint16_t)--p] = ch;
value /= 10;
if (p == punkt) siffror[(uint16_t)--p] = POINT;
} while (value || p > punkt-2 );
for (uint8_t i = 0; i<p; i++) siffror[i] = ' ';
return p;
}
sedan kommer en rutin som kan skriva ut "decimaltal" med valfritt antal decimaler och eventuellt inledande nollor:
Kod: Markera allt
void printDecimalPunkt(int32_t nummer,uint8_t storlek,uint8_t decimaler){
uint8_t i,n = 0;
if (nummer < 0 ) {
n = 1;
nummer = -nummer;
}
i=uint_to_string(nummer,decimaler);
if (n) {
siffror[i-1] = '-';
i--;
}
n = (UASTR - 1) -storlek;
if ( i > n) i = n;
for (; i < (UASTR - 1); i++)
putChar( siffror[(uint8_t)i] );
}
Det är möjligt att jag har krånglat till det en aning, men jag får i alla fall decimalpunkten där jag vill

Re: Hur uC behandlar negativa tal?
Postat: 7 mars 2011, 01:27:14
av sodjan
Bara nyfiken, vad skiljer din uint_to_string() från itoa() ?
Re: Hur uC behandlar negativa tal?
Postat: 7 mars 2011, 01:35:15
av jesse
Absolut ingen aning, eftersom jag aldrig kollat in itoa.
Jag kände antagligen inte till itoa när jag skrev den här, och nu hade jag glömt att den fanns.
Jag kanske skulle använda mig av den i fortsättningen

Re: Hur uC behandlar negativa tal?
Postat: 7 mars 2011, 01:39:45
av jesse
från
avr-libc dokumentation stdlib.hKod: Markera allt
char* itoa ( int __val,
char * __s,
int __radix
)
Convert an integer to a string.
The function itoa() converts the integer value from val into an ASCII representation that will be stored under s. The caller is responsible for providing sufficient storage in s.
Note:
The minimal size of the buffer s depends on the choice of radix. For example, if the radix is 2 (binary), you need to supply a buffer with a minimal length of 8 * sizeof (int) + 1 characters, i.e. one character for each bit plus one for the string terminator. Using a larger radix will require a smaller minimal buffer size.
Warning:
If the buffer is too small, you risk a buffer overflow.
Conversion is done using the radix as base, which may be a number between 2 (binary conversion) and up to 36. If radix is greater than 10, the next digit after '9' will be the letter 'a'.
If radix is 10 and val is negative, a minus sign will be prepended.
The itoa() function returns the pointer passed as s.
Re: Hur uC behandlar negativa tal?
Postat: 7 mars 2011, 08:59:06
av sodjan
Ja, jag vet vad *itoa* gör...

Det var igentligen inte det jag frågade om utan vad som
skiljer din kod från itoa (eller gör den bättre).
Re: Hur uC behandlar negativa tal?
Postat: 7 mars 2011, 09:39:43
av bos
Christian skrev:Men hur gör jag om det är en negativt int? Då fungerar ju inte min metod med att dela och modolus..?
Jag kanske missar något, men varför inte bara skicka värdet som det är:
?
Re: Hur uC behandlar negativa tal?
Postat: 7 mars 2011, 09:58:42
av Icecap
Kanske för att det finns ett protokoll som ska fungera.
Jag brukar gärna ha STX och ETX till att rama in en block, sedan kommer alla parameter och värden i textform med en avskiljare mellan, t.ex. komma.
Det ger lite overhead men "smyglyssning" är hur enkel som helst att utföra o tolka.
Och att i det läge skicka binära värden kan bara ge pannkaka.
Och hur ska man skicka värdet 256? 1000?
Jag har som regel att ett protokoll ska fungera så att man ska kunde bryta valfri ledare i kommunikationen utan att det leder till att fel data mottas och/eller utföras. Man ska återkoppla på helt valfri tidpunkt och protokollet ska synkronisera sig själv direkt. MAn ska helt enkelt kunde dra ut och sätta i kontakten utan att det blir fel data som det reageras på. Med binära värden i rå form skulle jag gärna vilja se dig utföra det...