nonkel_dw
nonkel dw
Hoi,
Na een maand zelf testen en zoeken werkt er al een groot stuk van een programma, alleen blijft er 1 struikel blok het berekenen van het aantal pulsen.
Daarmee roep ik jullie hulp in, ik denk dat ik voledig verkeerd aan het denken ben hoe het te berekenen.
Hier onder probeer ik uit teleggen hoe ik alles zie.
Ik heb het volgende probleem, ik zou een 16 Bit waarde moeten berekenen.
Met zo een klein mogelijke afwijking.
De formule die ik ga gebruiken is de volgende
(Teller (16bit) / 255)*waarde = het aantal pulsen(16bit).
Maar nu zit ik de handen in het haar om dit in ASM te verwezenlijken.
IK had al een opzet gemaakt maar dit heeft een veel te grote afwijking.
(Eerste idee dat werkt maar te grote afwijking geeft)
De teller is opgesplitst in 2 stukken TellerL TellerH
In tellerH komen de vollen tellerL ( als tellerL vol is gaat deze een bit setten in tellerH dit heb ik werkend)
Nu dacht ik dit is al het eerste stuk van de formule
Bv tellerH zit 9 dus moesten we alleen tellerH * waarde = en we hadden het aantal pulsen.
Maar dit geeft een grote afwijking, zoals volgend voorbeeld: stel er staat in tellerH 9 en in tellerL 250 dit is bijna 1 byte, maar als ik alleen ga rekenen met tellerH dan krijg een afwijking van 250 bitjes en dat scheelt een hoop pulsen bij de eindafrekening.
Hoe kan ik dit adequaat oplossen?
Als er nog onduidelijkheden instaan, dan hoor ik wel.
Alvast bedankt
(Z)weetvoetje
Hogepriester in het genootschap der mexicaanse hond. // // Aan 2% van de mensen is 50% van het bezit ; 1% van het bezit is aan 50% van de mensen.
Eerst de vermenigvuldiging doen, en dan pas delen door 255.
Is waarde een 8 of 16 bit getal?
Doe het net als je op de basisschool geleerd hebt:
antw=TelL*waarde+TelH*waarde*256
En daar pak je dan de eerste byte van.
nonkel_dw
nonkel dw
Waarde is een 8 bit getal
Alleen teller en aantalpulsen is 16 BIT
Hoe kan ik het beste vermenigvuldigen, voor de kleinste afwijking?
Martijn Berntsen
pe4mb
bij tellerL eerst 128 optellen, dan kun je daarna tellerH * waarde doen. dan heb je hem afgerond.
(0 - 127) + 128 < 256
(128 - 255) + 128 >= 256
afhankelijk van je toepassing kan gewoon het 7e bit checken sneleler zijn (7e bit zegt: 128 of hoger):
if (tellerL & 0x80) then tellerH++;
tellerH * waarde
[Bericht gewijzigd door Martijn Berntsen op (36%)]
nonkel_dw
nonkel dw
ik snap je niet helemaal denk ik
Stel er staat 200 in tellerL.
Dan tel je er 128 bij dan zit je aan 328 dus 1 byte en 72 bits.
je telt in tellerH 1 bij op en dan tel bij de 72 nog eens 128 bij of ben ik verkeerd?
Daan Timmer
Ik ben programmeur! geen electronicus! http://www.daantimmer.nl/ Er is een ontwerp! nu nog inhoud :-)
Martijn Berntsen
pe4mb
als je een 16 bits optel functie hebt (bijvoorbeeld adiw in geval van avr), dan kun je gewoon zeggen teller + 128, en als je dan alleen tellerH gebruikt, heb je iets gemaakt wat teller / 256 doet, met afronden.
maar checken of je tellerL een bepaalde waarde bereikt heeft is denk ik in jouw geval makkelijker, dus hoger dan X, dan tellerH + 1.
overigens, ik ging uit van teller / 256, moet dit precies 255 zijn? want dan moet je toch echt een routine maken die kijkt hoevaak hij teller met 255 kan verlagen, en dan naar de rest kijken voor het afronden.
(ps: 1 byte = 8 bits, je spreekt niet van 1 byte en 72 bits)
nonkel_dw
nonkel dw
ik dacht zo een routine te maken
een lus met de vermenigvuldiging in
dus teller met 6 vermenigvuldigen(= maal)
zou ik dan zo doen
lus:
tel bij resultaat de teller op
trek 1 af van maal
goto lus:
maal 0 ; dan is alles berekent
men taal is ASM
Martijn Berntsen
pe4mb
moet je door 255 delen, of bedoel je 256? 256 is easy, 255, dan moet je inderdaad een lus maken, en dan op basis van de rest afronden.
nonkel_dw
nonkel dw
kijk ik zal je het principe uitleggen wat het moet doen
op een ketting zit een encoder op, deze geeft dus pulsen af als de ketting beweegd.
Nu heb ik een register dat ik analoog in lees (heb ik werkend) van 8 bit. dit zal ik waarde noemen.
Nu heb ik voor het opstarten de ketting van helemaal boven tot helemaal beneden laten lopen en dit geeft BV 2000 pulsen.
Nu moet ik te pulsen berekenen die ik moet maken als ik bv een ander getal in waarde stop.
Een voorbeeld:
pulsen = 2000
waarde = 20
hoeveel pulsen moet ik doen :
2000*20/255 = 156.86 pulsen
Dat is het principe
snap je men andwoord?
Martijn Berntsen
pe4mb
mijn vraag is dan, waar komt de 255 weg? is dit een waarde die je berekend hebt en afhankelijk is van je hardware? of wat?
als 255 goed is, dan (zoals jij deels voorstelde):
een lus om te bepalen hovaak 255 in 'teller' past,
dan kijken of de rest (wat je over hebt) hoger is dan 255/2, om af te ronden (hoger = afronden naar boven, lager = naar beneden)
als die 255 ook een getal mag zijn wat een macht van 2 is (256, 128, 64, enzovoort) dan kun je de deling doen door te bitshiften, of door het hele laagste byte (tellerL) te laten vallen. en daarna af te ronden.
[Bericht gewijzigd door Martijn Berntsen op (65%)]
nonkel_dw
nonkel dw
de 255 komt van de resolutie van men analoge ingang
ik kan regelen tussen 0 en 255 dus moet dit toch mee verrekent worden
Martijn Berntsen
pe4mb
Op 29 oktober 2008 14:38:09 schreef nonkel_dw:
de 255 komt van de resolutie van men analoge ingangik kan regelen tussen 0 en 255 dus moet dit toch mee verrekent worden
0 t/m 255 = 256 stapjes, dus dan deel je door een macht van 2, en ook nog eens precies 1 byte, dus mijn advies:
pseudo asm:
als (tellerL < 128) goto next;
tellerH = tellerH + 1
next:
aantal_pulsen = tellerH * waarde
Martijn Berntsen
pe4mb
dat is afronden:
dus als je wilt afronden op eenheden:
waarde + (eenheid / 2), en dan het deel achter de komma weglaten, dus:
5.3 afronden geeft 5, want: 5.3 + 0.5 = 5.8, dan het deel achter de komma weglaten, en dan krijg je 5, dat klopt
5.5 afronden geeft 6, want: 5.5 + 0.5 = 6.0, dan het deel achter de komma weglaten, en dan krijg je 6, voila
dat doe ik ook met die digitale variant:
tellerH = deel voor de komma
tellerL = deel achter de komma
voorbeeld:
//1380 / 256 = 5.39
1380 geeft:
tellerH = 5
tellerL = 100
//5.39 + 0.5 = 5.89, deel achter de komma weg = 5
halve eenheid van een byte is 128
tellerL + 128 = 228 (byte is niet hoger dan 255, dus tellerH blijft gelijk)
en deel achter de komma weglaten (tellerL weg) geeft 5
overigens was de methode van (Z)weetvoetje beter, omdat je dan geen nauwkerigheid verliest.
teller = 1380
waarde = 210
pulsen = 1380 / 256 * 210 = 1132.03
als je eerst deelt krijg je 5, dan keer 210 doet, krijg je 1050, wat dus een afwijking oplevert.
als je eerst vermenigvuldigd krijg je 1380 * 210 = 289800, als je dat deelt door 256 krijg je 1132
dus mijn verhaal is leuk over afronden, en als je geen 24 bits getallen wilt gebruiken, maar niet nauwkeurig!
nonkel_dw
nonkel dw
ja ik snap wat je wil zeggen
maar dan heb je nog altijd maar een waarde van 1 byte.
Terwijl het voor een word moet gedaan worden.
Zoals het er al eerder stond.
Martijn Berntsen
pe4mb
nonkel_dw
nonkel dw
Martijn Berntsen
pe4mb
jazeker wel, supersimpel:
'tellerH * waarde' levert resultaat1H + resultaat1L
'tellerL * waarde' levert resultaat2H + resultaat2L
dan heb je 2 keer een 16 bits getal, dan zeg je:
byte0 = resultaat2L
byte1 = resultaat2H + resultaat1L
byte2 = resultaat1H + (eventueel teveel in byte1)
[bad habit edit mode]
overigens werken veel assembler commando's met carry bits, deze bewaren het 9e bit als je bijvoorbeeld 200 + 200 doet, dan krijg je een getal wat niet meer in 1 byte past, en dan bevat het carrybit (C) je 9e bit. Als je dan daarna weer het optelcommando gebruikt, dan neemt hij dit bit mee, voorbeeld volgens bovenstaande tekst:
resultaat2L = 200
resultaat2H = 150
resultaat1L = 130
resultaat1H = 250
byte0 = 200
byte1 = 150 + 130 = 260 = 4 + carrybit
byte2 = 250 + carrybit = 251
[/bad habit edit mode]
[Bericht gewijzigd door Martijn Berntsen op (48%)]
nonkel_dw
nonkel dw
Nu heb ik wat gevonden alleen zit er nog een fout in 
Als ik dit simuleer met pic simultor
list P=16F628a
#INCLUDE <P16F628a.INC>
__CONFIG _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC
CBLOCK 0X20
TELLER
PULS
PULSH
TELLER2
TELLER2H
PP0
PP0H
PP1
PP1H
PP2
PP2H
PP3
PP3H
PP6H
ENDC
ORG 00h
GOTO init ;Initialize PIC
;-------------------------------------------
init
movlw d'200'
movwf TELLER
movlw d'100'
movwf PULSH
movwf PULS
; teller 2 staat de uitkomt teller2L teller2h
goto MAIN
MAIN
Clrf PP3H
Movf TELLER,W
Movwf PP3
Movf PULSH,W
Movwf PP1H
Movf PULS,W
Movwf PP1
Call m@py
Movwf TELLER2
Movf PP2H,W
Movwf TELLER2H
Movf TELLER2H,W
Movwf PP0H
Movf TELLER2,W
Movwf PP0
Clrf PP1H
Movlw d'255'
Movwf PP1
Call d@vd
Movwf TELLER2
Movf PP0H,W
Movwf TELLER2H
Goto MAIN
d@vd clrf PP2H
clrf PP2
d@vd2 movlw 16
movwf PP3
rlf PP0H,w
rlf PP2,f
rlf PP2H,f
movfw PP1
subwf PP2,f
movfw PP1H
skpc
incfsz PP1H,w
subwf PP2H,f
skpnc
goto $ + 8
movfw PP1
addwf PP2,f
movfw PP1H
skpnc
incfsz PP1H,w
addwf PP2H,f
clrc
rlf PP0,f
rlf PP0H,f
decfsz PP3,f
goto $ - 21
movfw PP0
goto i@nt
m@py movlw 16
movwf PP6H
clrf PP0H
clrf PP0
rrf PP3H,f
rrf PP3,f
skpc
goto $ + 7
movfw PP1
addwf PP0,f
movfw PP1H
skpnc
incfsz PP1H,w
addwf PP0H,f
rrf PP0H,f
rrf PP0,f
rrf PP2H,f
rrf PP2,f
decfsz PP6H,f
goto $ - 15
movfw PP2
goto i@nt
i@nt bcf 3,7
i@nt2 bcf 3,5
bcf 3,6
nop
return
END
Wil iemand hier even mee op kijken?
i@nt bcf 3,7
i@nt2 bcf 3,5
bcf 3,6
nop
return
dit stukje is me voorlopig ook nog een raadsel voor wat dit mag zijn.
Als je een grotere nauwkeurigheid wil ontkom je er niet aan met meer bits te gaan werken.
Dus moet er een 16x8 multiply worden gedaan.
Hiervoor kun je zo een kant en klare subroutine plukken van www.piclist.com
Je krijgt dan een 24 bits getal als uitkomst.
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Om het geheel te kunnen begrijpen: Wat heeft de analoge ingang met het verhaal te maken? De puls-counter op de ketting is zo te zien digitaal?
nonkel_dw
nonkel dw
een potensiometer
waar ik de de byt waarde kan mee instellen
dit moet latere met wat extra code de takel omhoog en omlaag sturen.
maar eerst het rekenwerk werkende krijgen
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Ah,
Dat is al een stuk duidelijker...
Je wilt dus dat de potmeterstand <min> gelijk is aan '0', en <max> gelijk is aan 2000...
Over dit probleem hebben we het geloof ik al eerder over gehad. Als je de A/D converter zo instelt, dat het aantal pulsen er door deelbaar is, wordt alles veel simpeler en nauwkeuriger.
Als de ketting totaal 2000 pulsen geeft, dan A/D op max. 500 of 1000 zetten.
Je hoeft dan alleen de A/D waarde met 2 of 4 te vermenigvuldigen. (Kan het nog simpeler?
)
