Dela upp en byte?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
JimmyAndersson
Inlägg: 26611
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Dela upp en byte?

Inlägg av JimmyAndersson »

Låt säga att en variabel innehåller talet 66. Binärt 01000010. Talet kan förresten vara allt mellan 0 till 255.
Det vill jag dela upp till två variabler. Så att i detta fallet X = 0100 (dvs 4). Y = 0010 (dvs 2.)

Programmerar som vanligt i MikroBasic, men matte är ju ett universiellt språk. :wink:

MikroBasic har kommandon som kan dela upp ett word till två bytes, men jag har inte hittat något som delar upp en byte till två 'grupper' med 4 bytes i varje.


Först trodde jag att jag löst det. Jag gjorde såhär:
(Psuedo-kod, mellanslag i binära tal för att det ska vara lättare att läsa.)

Talet som ska delas upp = 0100 0010 (dvs 66)
x = Talet + 990
x är nu 0100 0010 0000.

oversta = hi(x)
'oversta innehåller nu 0100
under = lo(x)
'under innehåller nu 0010 0000
understa = under - 30
'understa innehåller nu 0010

Men det är ingen bra lösning på andra tal eftersom det är en statisk uträkning. Om Talet som ska delas upp är t.ex 0010 0000 så blir oversta 11 och understa 1110 0000. :shock:


Det måste ju finnas bättre sätt att lösa detta. Hur?
AND fungerar ju för att få t.ex 1111 1111 att bli 1111 1111 0000. Men sedan måste jag ju få 1111 0000 till att bli 1111. Om jag löser den biten så behövs visserligen ingen AND. Hmm.. har jag missat någon logik-operator.


Jag ska förresten använda det till en liten rutin för en LCD som ska fungera såhär:
*Lägg in t.ex "Hej" i en sträng.
*Plocka ut bokstav för bokstav och gör om till ascii-kod.
*Dela upp ascii-koden (t.ex 32) till två delar, dvs 0010 och 0000. Skicka först 0010 och sedan 0000 till LCD'ns.

Det är alltså den sista punkten som jag behöver hjälp med.

Om jag förklarat rörigt så är det bara att ropa. :D
Senast redigerad av JimmyAndersson 12 augusti 2006, 16:26:35, redigerad totalt 2 gånger.
Användarvisningsbild
Greve Hamilton
EF Sponsor
Inlägg: 544
Blev medlem: 4 september 2004, 15:03:35
Ort: GBG

Inlägg av Greve Hamilton »

För att få de "nedre" bitarna kan du ju köra:

Ny_byte = (0x0F & byten);

Och den "övre" delen:

Ny_byte2 = ( (0xF0 & byten) >> 4 );


Kan hända att jag har missuppfattat något. Det händer nämligen allt för ofta.


Bonusfråga; Dessa "halv-bytes" kallas för något, minns inte vad bara. Någon som vet?
Användarvisningsbild
oJsan
EF Sponsor
Inlägg: 1541
Blev medlem: 11 november 2005, 21:36:51
Ort: Umeå
Kontakt:

Inlägg av oJsan »

Skiftoperatorn!
Jag kan ju inte svära på att den finns i MikroBasic, men den finns definitivt i asm.
c-kod:
tal = 0x43;
tal_h = a>>4; //, skifta åt höger fyra ggr, ersätts med fyra enkelskiftningar i följd i asm
tal_l = a & 0x0F;

tal_h blir då 0x4 och tal_l blir 0x3.

Om du inte hittar någon skiftoperator så funkar nog detta också:
tal = 0x43;
tal_h = a/16;
tal_l = a & 0x0F;
Att skifta ett steg är samma som att dela med två. Att skifta fyra steg är alltså samma som att dela med 2^4=16

Edit: GreveH: Jag tror inte att det är nödvändigt att maska den del som skiftas. "Halvorna" brukar kallas för nibbles.
Senast redigerad av oJsan 11 augusti 2006, 16:00:38, redigerad totalt 1 gång.
AndXy
Inlägg: 12
Blev medlem: 30 september 2005, 08:40:49

Inlägg av AndXy »

halv byte = nibble
läs om "SWAP" i manualen till mikrobasic
Användarvisningsbild
oJsan
EF Sponsor
Inlägg: 1541
Blev medlem: 11 november 2005, 21:36:51
Ort: Umeå
Kontakt:

Inlägg av oJsan »

Om swap finns som assemblerfunktion så den förmodligen effektivast.
Användarvisningsbild
JimmyAndersson
Inlägg: 26611
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

Tackar för svaren! :)

Hade helt glömt bort skift. Jodå, det finns i MikroBasic. Man använder << och >>

"Hmm.. har jag missat någon logik-operator"
Det hade jag alltså. :D

edit: Swap verkar också fungera.

Perfekt! :tumupp:
Tack för alla snabba svar. :)
Senast redigerad av JimmyAndersson 11 augusti 2006, 16:08:16, redigerad totalt 1 gång.
Användarvisningsbild
Greve Hamilton
EF Sponsor
Inlägg: 544
Blev medlem: 4 september 2004, 15:03:35
Ort: GBG

Inlägg av Greve Hamilton »

Ah, nibble - där satt den!

oJsan: Just fan, tänkte inte så långt. :D Men man förstår ju syftet i alla fall.
Användarvisningsbild
JimmyAndersson
Inlägg: 26611
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

Upptäckte just en bugg i MikroBasic.

Med min rutin kan jag skriva t.ex
lcd_skriv("H")
lcd_skriv("e")
lcd_skriv("j")


Det fungerar bra.
(ska ordna så man kan skriva hela meningar i en sträng sedan.)
Men om jag skickar:
lcd_skriv("!")

så blir det helt fel. Plockar jag bort raden så är det ändå fel. Jag måste starta om MikroBasic och ändra massa saker tills den "glömt bort" utropstecknet. :?

Felmeddelandena blir:
164:1 24 Supplied and formal parameters do not match ('latc.5' to byte) nataggregat1.pbas
164:1 4 Syntax error: Expected ')' but '.' found nataggregat1.pbas
164:1 10 Too many parameters nataggregat1.pbas
164:1 4 Syntax error: Expected 'end' but '' found nataggregat1.pbas
164:1 4 Syntax error: Expected '.' but '' found nataggregat1.pbas


Trots att allt är *exakt* som innan jag lade till utropstecknet.

edit: Tryckte kortkommandot för Build istället för att klicka på 'Skicka' inlägget. :lol:
mullemeck
Inlägg: 1306
Blev medlem: 27 maj 2003, 23:52:06
Ort: Lund
Kontakt:

Inlägg av mullemeck »

vad är det lcd_skriv() vill ha in för datatyp?
Är det en sträng eller en byte?

Hur blir det om du skriver lcd_skriv(33) istället?
33 är det decimala talet för "!"
Användarvisningsbild
JimmyAndersson
Inlägg: 26611
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

datatypen är egentligen byte, men i MikroBasic kan man skriva t.ex lcd_skriv("A") som tas emot som 65 (ascii-kod för A.)

Har som sagt rensat bort "!". Faktum är att jag rensat bort allt i hela rutinen och anropen till rutinen, men det blir ändå felmeddelanden. Nu har jag fått bort de gamla, men nu får jag istället detta:

0:0 0 Linker error: Routine not found: lcd_skriv


Förstår inte alls varför den klagar. Koden fungerade innan jag lagt till lcd_skriv("!") och nu har jag alltså tagit bort alla sådana rader.

Kan bjuda på lite kod, trots att den är ok:


Kod: Markera allt

sub procedure lcd_skriv(dim value as byte)
   oversta = 0
   understa = 0
   flytta = 0

   oversta = value >> 4 ' Flyttar de översta (4st) fyra steg åt höger.
   flytta = value << 4 ' Flyttar fyra steg åt vänster för att de fyra översta ska försvinna.
   understa = flytta >> 4 'Flytta tillbaka igen och nu har de tidigare översta försvunnit.

   LATC = oversta ' Skicka översta delen
   lcd_vanta ' E och vänta
   LATC = understa ' Skicka understa delen
   lcd_vanta ' E och vänta
end sub


lcd_skriv(65)
Jag får alltså felmeddelandet ovan även om jag plockar bort *allt* i sub-rutinen. :?

edit: Eh... jahopp, nu fick jag bort felmeddelandet. Plockade som sagt bort allt i sub-rutinen tidigare. Nu skrev jag in:
dim oversta as byte
value = 0
som enda innehåll i rutinen och då försvann felmeddelandet.

Sedan kunde jag stoppa tillbaka rätt innehåll (det som visas i kod-rutan) i rutinen och felmeddelandet är fortfarande borta.

Ibland längtar man faktiskt tillbaka till assembler för DOS 3.1 :roll:
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Jag är helt övertygad om att en TOM sub (utan någon exekverbar kod)
kommer att optimeras bort helt av kompilatorn, d.v.s att en
helt tom "lcd_skriv" kommer att "saknas". Helt logiskt och precis vad man
förväntar sig av varje vettig kompilator. Dock borde det komma en
varning vid kompileringen, så att man inte missar det...

> Sedan kunde jag stoppa tillbaka rätt innehåll...

Även "!" ? Naturligtsvis borde även "!" fungera...

Sen är swap mycket effektivare än att göra 4 st shift (">> 4").
En (maskin-) instruktion istället för 4.

Jag gissar att detta genererar mer kompakt kod :

Kod: Markera allt

 sub procedure lcd_skriv(dim value as byte)
   tmp = 0

   tmp = value
   value = swap(value)
   value = value and $0F

   LATC = value ' Skicka översta delen
   lcd_vanta ' E och vänta

   value = tmp
   value = value and $0F

   LATC = value ' Skicka understa delen
   lcd_vanta ' E och vänta
end sub
Jag förutsätter att swap() amvänder asm-instruktionen swap !
Det sparar även 2 byte RAM.

Om PORTC.4-7 används till något vettigt, så
fungerar dock varken din eller min kod...
AndXy
Inlägg: 12
Blev medlem: 30 september 2005, 08:40:49

Inlägg av AndXy »

Jimmy, avsluta genast dina "märkliga övningar" med mikrobasic :shock: och börja omgående med assembler till PIC, jamenar Basic é rätt basic, du vet ju inte vad som händer eller :oops: ?? Dessutom e PIC:s assembler (instruktionslista) ytterst enkel att lära sig :razz: !!
Användarvisningsbild
lgrfbs
Inlägg: 7350
Blev medlem: 28 januari 2005, 15:48:53
Ort: X-län
Kontakt:

Inlägg av lgrfbs »

Rapportera in felet till http://www.mikroe.com/
mikroPascal har kommit ut i en ny version så det bör inte dröja länge tills
mikroBasic också får en uppdaterning.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Jag skulle bara vilja göra en liten kommenter till...

Hela problemet ligger igentligen i denna fras från Jimmy :

>>>> ...men matte är ju ett universiellt språk...

Att dela (eller swap'a) en byte har mycket lite med matematik att göra !
Hela Jimmys problem i första inlägget beror på försöket att *räkna* ut det.
Det är helt vanlig bit-hantering, och alla processorer har bra verktyg (d.v.s
instruktioner typ SWAP och AND) för att lösa denna typ av problem.
Användarvisningsbild
JimmyAndersson
Inlägg: 26611
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

>> Sedan kunde jag stoppa tillbaka rätt innehåll...

> Även "!" ? Naturligtsvis borde även "!" fungera...

sodjan:
Det har blivit fel varje gång jag försökt stoppa in "!". Har inte så mycket lust att testa igen eftersom det tar en stund att ordna upp allt igen.

Tack för koden! Jag hade gjort ett litet fel när jag testade med Swap som gjorde att det inte fungerade. Därför använde jag skift (<< och >>).

> Om PORTC.4-7 används till något vettigt, så fungerar dock varken din eller min kod...

Javisstja, du har ju helt rätt. Jo, PORTC.6 (TX) och PORTC.7 (RX) ska användas till seriekommunikation. Men om jag gör om koden lite så att det bara skickar till PORTC.0-3 så borde det väl fungera?

PORTC.0-3 används för att visa inställda värden på LCD'n. Man ställer in dessa värden med några knappar och encoders. Men man ska även kunna ställa in dessa värden på en dator (via serieporten.) Både knappar/encoders och RX/TX ska använda interrupt.


AndyXy: :D

lgrfbs: Bra idé. Hm, jag har aldrig hittat var man laddar ner uppdateringarna. ..


sodjan igen:

> Hela Jimmys problem i första inlägget beror på försöket att *räkna* ut det.

Exakt. Lyckligtvis insåg jag det och efterlyste därför ett annat sätt. (Jag hade provat flera bitwise-operatorer.)
Skriv svar