logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[ATMega32][BASCOM] ujemna single po potęgowaniu?

elektrofil 26 Paź 2010 21:46 2137 9
REKLAMA
  • #1 8667737
    elektrofil
    Poziom 17  
    Witam.

    Trochę nerwów zjadła mi procedura w której podnoszona jest liczba single (czasami ujemna) do kwadratu.
    wszystkie używane zmienne to SINGLE
    
    Temp2 = T1 - T0
    Temp2 = Temp2 ^ 2
    


    coś mnie pokusiło aby profilaktycznie wynik wysłać na terminal przez rs232c

    
    wynik z terminala:
    
    temp2: temp1: -2930.0
    temp2^2 przed korekcją: -8584895.0
    temp2^2 po korekcji: 8584895.0
    


    stosuje mnożenie przez minus jeden gdy wynik podnoszenia do kwadratu jest ujemny:

    
    Temp2 = T1 - T0
    Temp2 = Temp2 ^ 2
    Print "temp2^2 przed korekcją: " ; Temp2
    
    If Temp2 < 0 Then
       Temp2 = Temp2 *temp_minus
    End If
    
    Print "temp2^2 po korekcji: " ; Temp2
    


    czy ktoś spotkał się z tym problemem, czy robię tak oczywisty błąd, że go nie widzę??
  • REKLAMA
  • REKLAMA
  • #3 8667955
    elektrofil
    Poziom 17  
    Ja to wiem, wielu ludzi to wie, stary poczciwy QBASIC to wie.
    wersja bascom której używam to 12-stka, nowszej chyba nie ma.
    jeżeli ktoś mógłby to sprawdzić także na innych (starszych wersjach bascoma) będę bardzo wdzięczny.
    
    $projecttime = 2
    $regfile = "M32DEF.dat"                                     ' chip used
    $hwstack = 64                                               ' default use 32 for the hardware stack
    $swstack = 64                                               ' default use 10 for the SW stack
    $framesize = 64
    
    'Const _crystal = 7372800
    'Const _crystal = 8000000
    Const _crystal = 11059200
    'Const _crystal = 14745600
    'Const _crystal = 18432000
    'Const _crystal = 22118400
    $crystal = _crystal                                         ' xtal used
    
    'Const Baudrate = 9600
    Const Baudrate = 19200
    'Const Baudrate = 38400
    'Const Baudrate = 57600
    'Const Baudrate = 115200
    $baud = Baudrate                                            ' baud rate used
    
    Dim Lsb As Byte
    Dim Msb As Byte
    
    Dim D As Word                                               ' (0-65535)
    Dim T As Word
    Dim D0 As Word
    Dim T0 As Word
    Dim P0 As Word
    Dim S As Word
    Dim C As Word
    Dim Dup As Single
    Dim Dut As Single
    Dim Temp1 As Single                                         '- zmienne pomocnicze
    Dim Temp2 As Single                                         '- zmienne pomocnicze
    Dim Temp3 As Single                                         '- zmienne pomocnicze'Dim Cisnienie As Single
    Dim D1 As Word
    Dim T1 As Word
    Dim Presure As Single
    Dim Temp_minus As Single
    Temp_minus = -1
    
    D0 = 41058
    T0 = 32819
    P0 = 10143
    S = 294
    C = 320
    D1 = 42920
    T1=29889
    
    do
    Print "D0: " ; D0 ; " T0: " ; T0 ; " P0: " ; P0 ; " S: " ; S ; " C: " ; C ; " D1: " ; D1 ; " T1: " ; T1
    Print
    Dup = D1 - D0
    Print "dUP: " ; Dup
    'dUT=(29*(T1-T0)/50-(T1-T0)^2/76666)*S/C
    Temp1 = T1 - T0
    Temp1 = Temp1 * 29
    Temp1 = Temp1 / 50
    Print "temp1: " ; Temp1
    
    Temp2 = T1 - T0
    Print "temp2: " ; Temp2
    Temp2 = Temp2 ^ 2
    Print "temp2^2 przed korekcją: " ; Temp2
    
    If Temp2 < 0 Then
       Temp2 = Temp2 *temp_minus
    End If
    
    Print "temp2^2 po korekcji: " ; Temp2
    
    Temp2 = Temp2 / 76666
    Print "temp2 (111,977): " ; Temp2
    
    Temp3 = Temp1 - Temp2
    Temp3 = Temp3 * S
    Temp3 = Temp3 / C
    Dut = Temp3
    Print "dUT: " ; Dut
    Print
    'P=P0+100*(dUP+dUT)/S
    Temp1 = Dup + Dut
    Temp1 = Temp1 * 100
    Temp1 = Temp1 / C
    Temp1 = Temp1 + P0
    
    Presure = Temp1 / 10
    Print "presure(1021): " ; Presure ; " hPa"
    wait 1
    loop
    
    end
    


    dane z terminala po korekcji nieszczęsnego minusa:
    
    D0: 41058 T0: 32819 P0: 10143 S: 294 C: 320 D1: 42920 T1: 29889
    
    dUP: 1862.0
    temp1: -1699.399902343
    temp2: -2930.0
    temp2^2 przed korekcją: -8584895.0
    temp2^2 po korekcji: 8584895.0
    temp2 (111,977): 111.977851866
    dUT: -1664.203125
    
    presure(1021): 1020.480957031 hPa  <--- wynik prawie dobry, może być
    


    niestety bez sprawdzenia czy liczba podniesiona do kwadratu nie jest ujemna:

    D0: 41058 T0: 32819 P0: 10143 S: 294 C: 320 D1: 42920 T1: 29889
    
    dUP: 1862.0
    temp1: -1699.399902343
    temp2: -2930.0
    temp2^2 przed korekcją: -8584895.0
    temp2 (111,977): -111.977851866
    dUT: -1458.443847656
    
    presure(1021): 1026.910888671 hPa  <--- 6hPa różnicy niedopuszczalne
  • #4 8668306
    mirekk36
    Poziom 42  
    Tak z ciekawości tylko zapytam jakich ty czujników używasz i czy rzeczywiście potrzebna ci jest aż taka pracyzja w pomiarze temperatury do 9 miejsc po przecinku ?!?!?

    temp1: -1699.399902343
  • REKLAMA
  • #5 8668342
    elektrofil
    Poziom 17  
    Zmienne do obliczeń nazywam "temp1, temp2...." jakoś tak z programowania 6502 w assemblerze mi zostało.
    A czujnik to HP02S niby barometr kalibrowany.
    Niestety w HP02S temperatura w nieznanych jednostkach służy do prawidłowego obliczenia ciśnienia.
    dopiero czujnik HP03S ma podany sposób (i rejestry) do wyliczenia temperatury.
    dokumentacja HP02S
  • #6 8668490
    Jaca
    Poziom 31  
    Mam wersję 2.0.1.0 BASCOM'a i w symulatorze Twój kod działa prawidłowo.
  • Pomocny post
    #7 8668540
    mirekk36
    Poziom 42  
    No zajrzałem do noty ale nadal zachodzę w głowę dlaczego używasz do tego zaraz tak kosmicznego nieporozumienia jak liczby zmiennoprzecinkowe w Bascomie albo w ogóle na AVR. Najlepiej zawsze od nich uciekać jak tylko się da - a można to często bardzo łatwo zrobić - tą ucieczkę ;) szczególnie w takich prostych przypadkach:

    masz tam przykładowy wzrór z parametrami:

    Cytat:
    dUT=(29*(29889-32819)/50-(29889-32819)^2/76666)*294/320=-1664

    na tym przykładzie pokażę jak łatwo wykonać obliczenia z użyciem zwykłych zmiennych całkowitych!!! typu Long zdaje się w Bascomie
    (bez żadnych dziwolągów typu Single)

    Wszystkie je deklaruję tu jako Long (tzn przedstawiam super uproszczoną wersję bo później można ją dopracować i nie wszystkie deklarować jako long tylko te które trzeba a pozostałe albo jako Word albo jako Byte jeśli będzie to możliwe. Niestety w Bascomie będzie to rozbite na milion kawałków z racji tego, że można tylko jedno działanie wykonać w jednej linii (chore no ale też się da) ;) i to na każdej wersji Bascoma to rozwiązanie zadziała.

    Dim D0 As Long
    Dim T0 As Long
    Dim P0 As Long
    Dim S As Long
    Dim C As Long
    Dim D1 As Long
    Dim T1 As Long
    
    Dim R As Long
    Dim A1 As Long
    Dim A2 As Long
    Dim B As Long
    Dim M As Long
    
    
    D0 = 41058
    T0 = 32819
    P0=10143
    S=294
    C=320
    D1=42920
    T1 = 29889
    
    R = T1 - T0
    A1 = 2900 * R
    B = A1 / 50
    A1 = B
    
    A2 = R * R
    M = A2 * 100
    B = M / 76666
    A2 = B
    
    B = A1 - a2
    R = B * 294
    B = R / 32000


    na końcu otrzymujemy wynik dokładnie jak w nocie -1664 co do joty i to bez żadnych Single. Sprawdź sobie przy okazji ile teraz zajmie ci kod po wygenerowaniu w pamięci Flash ;)

    Spróbuj dojść już sam co tu się dzieje ale chyba to bardzo jasno widać prawda ? ;)

    W podobny sposób można wykonać wszystkie inne obliczenia z tej noty i zawsze będziesz miał na końcu dobre wynkiki a przy okazji jak mało kodu wynikowego ;) miodzio.

    Żeby nie było że kłamię poniżej widok z baskomicznego s(t)ymulatora:

    [ATMega32][BASCOM] ujemna single po potęgowaniu?
  • #8 8668874
    elektrofil
    Poziom 17  
    Dziękuję za sposób z long'ami.
    przynajmniej liczba ujemna mnożona przez siebie daje dodatnią:)
    w tym przypadku nie zależy mi ani na prędkości ani na objętości kodu, po prostu mam moduł MODBUS na atmega32 i tkneło mnie aby zrobić także barometr.
    Zajmuje to razem 24% FLASH'a a tempo działania programu niezbyt mnie interesuje ( a niech nawet sobie to minute liczy), jednak wyciągam z tego nauczkę na przyszłość, że stare nawyki z pakietem zmiennoprzecinkowym nie sprawdzają się zbyt dobrze.
    no i teraz konwersja tego na assembler będzie o wiele prostsza:)
    ciśnienie jest dobrze liczone od 920hPa do 1085hPa więc nie ma się co martwić, że zacznie źle wskazywać. co prawda jest rozjechane według lotniska na Ławicy, lecz "na oko" to z lotniska jest to ciśnienie sprowadzone do poziomu morza.
    lotnisko jest około 80m n.p.m. ciśnienie tam wskazywane w tech chwili to 1028hPa, mój barometr pokazuje około 1018hPa, biorąc poprawke, że na każde 8,5m w górę ciśnienie spada o 1hPa to z grubsza wszystko się zgadza.
    Dla "potomnych" Link z mapą wysokości
    Dziękuję za pomoc, tematu jeszcze nie zamykam...
  • REKLAMA
  • #9 8668884
    mirekk36
    Poziom 42  
    No ale właśnie mówiłem, że zysk na prędkości to wiadomo że jest pomijalny, jednak zysk na objętości kodu to już bardzo istotna sprawa i nie patrz na to w ten sposób, że tu akurat dałeś taki procek w którym masz aż tyle wolnej pamięci, bo po prostu na drugi raz będziesz wiedział że można to zrobić na mniejszym bez problemu ;) ..... a najważniejsze to to, żeby dostrzec ten prosty sposób omijania działań na liczbach zmiennoprzecinkowych w prockach AVR tak ogólnie. Prosto, łatwo i szybko ;)
  • #10 8672861
    piotr5000
    Poziom 21  
    sprawdziłem dziś u siebie i wersja 1.11.9.1 też błędnie liczy f=x^2
    wynik nie tylko ujemny ale i błędna wartość -8584895 (powinno być 8584900 )

    Jeśli zrobimy f=x*x jest ok

    Dla dociekliwych proponuję sprawdzić f=x^3 dla liczby np. 29
REKLAMA