Bryta upp ett nummer och ladda in i en array

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
ekman
Inlägg: 280
Blev medlem: 13 januari 2009, 14:04:35

Bryta upp ett nummer och ladda in i en array

Inlägg av ekman »

Hej

Jag använder AVR studio 5 och försöker programmera i C.
Jag får numret 00111000 som är deklarerat med uint8_t.

Hur kan jag göra för att ladda det numret in i en array så att det ser ut så här om vi säger att array'en heter 8bit:

8bit[0] = 0
8bit[1] = 0
8bit[2] = 0
8bit[3] = 1
8bit[4] = 1
8bit[5] = 1
8bit[6] = 0
8bit[7] = 0

PS. nybörjare .DS
Nerre
Inlägg: 27235
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Bryta upp ett nummer och ladda in i en array

Inlägg av Nerre »

Varför vill du göra det? Om du vill kunna kolla de enskilda bitarna så finns det nog bättre sätt.

Googlade lite snabbt och i på den här sidan finns en massa olika tips:
http://stackoverflow.com/questions/4798 ... e-bit-in-c
Användarvisningsbild
Icecap
Inlägg: 26652
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Bryta upp ett nummer och ladda in i en array

Inlägg av Icecap »

Det finns olika sätt och vilket som är bäst beror på vad man vill använda bit-en till. Om man har dom som flaggor och måste snäla på minnet kan man deklarera:

Kod: Markera allt

union
  {
  struct
    {
    uint8 B0 : 1;
    uint8 B1 : 1;
    uint8 B2 : 1;
    uint8 B3 : 1;
    uint8 B4 : 1;
    uint8 B5 : 1;
    uint8 B6 : 1;
    uint8 B7 : 1;
    } Bits;
  uint8 As_Byte;
  } The_One;
Då kan man komma åt båda hela bytes (The_One.As_Byte) och varje bit (The_One.Bits.B0 - The_One.Bits.B7).

Men om man vill göra om ett värde till en binär utskrift är det bättre att lösa det på ett annat sätt.
ekman
Inlägg: 280
Blev medlem: 13 januari 2009, 14:04:35

Re: Bryta upp ett nummer och ladda in i en array

Inlägg av ekman »

Jo, för att sedan kunna loopa igenom array'n och skicka respektive 0 och 1 i tur och ordning till en shiftregister. Som vill bli matad ett nummer i taget.

Av länken där förstod jag inte mycket :(
Användarvisningsbild
Icecap
Inlägg: 26652
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Bryta upp ett nummer och ladda in i en array

Inlägg av Icecap »

Om du vill skriva ut ett värde som '0' och '1', alltså det binära mönster, är det bättre att shifta - men det verkar du förstå.

Länken anger hur man kan använda bitmässiga konstanter men jag ser den inte som speciellt bra beskrivning.

Så egentligen behöver vi nog veta: vad vill du med det? Vad ska det göra?
Användarvisningsbild
LHelge
Inlägg: 1772
Blev medlem: 2 september 2007, 18:25:31
Ort: Östergötland
Kontakt:

Re: Bryta upp ett nummer och ladda in i en array

Inlägg av LHelge »

Finns många sätt att komma åt varje enskild bit, ett av dem är

Kod: Markera allt

uint8_t num = 0b00111000;

8bit[0] = num & 1;
8bit[1] = (num & (1 << 1)) >> 1;
8bit[2] = (num & (1 << 2)) >> 2;
8bit[3] = (num & (1 << 3)) >> 3;
osv...
(1 << 2) betyder att du skiftar en etta två steg åt höger så du får 0b00000100 (4 decimalt) om du sedan kör en and med detta

Kod: Markera allt

0bXXXXXaXX
and
0b00000100
=
0b00000a00
då återstår bara att skifta biten a tillbaka två steg.

Eftersom det är konstanter i detta fallet skulle du lika gärna kunna skriva

Kod: Markera allt

uint8_t num = 0b00111000;

8bit[0] = num & 1;
8bit[1] = (num & 2) >> 1;
8bit[2] = (num & 4) >> 2;
8bit[3] = (num & 8) >> 3;
osv...
Men det blir kanske inte lika lättläst för en ovan kodare.

men som ekman säger så kan det, beroende på vad du försöker göra, vara lika bra att använda t ex (num & (1 << 2)) >> 2 direkt i koden där du vill ha bit med index 2.

vill jag loopa igenom varje bit så brukar jag personligen göra något i stil med detta

Kod: Markera allt

uint8_t = 0b00111000;
uint8_t i;

for(i = 0; i < 8; i++)
{
    bit = num && 1;
    num = num >> 1;
}
Vill man istället spara flaggor på ett kompakt sätt är Icecaps variant väldigt bra.
johano
Inlägg: 1943
Blev medlem: 22 januari 2008, 10:07:45
Ort: Stockholm

Re: Bryta upp ett nummer och ladda in i en array

Inlägg av johano »

eller såhär:

Kod: Markera allt

for(uint8_t i=0; i < 8; i++)
{
  sendtoshiftregister( num & ( 1 << i ) );
}
/johan
Användarvisningsbild
LHelge
Inlägg: 1772
Blev medlem: 2 september 2007, 18:25:31
Ort: Östergötland
Kontakt:

Re: Bryta upp ett nummer och ladda in i en array

Inlägg av LHelge »

Om man är säker på att funktionen sendtoshiftregister() hanterar värdet som en boolean. Annars kan det vara bra att lägga till en extra ">> i" efter.
ekman
Inlägg: 280
Blev medlem: 13 januari 2009, 14:04:35

Re: Bryta upp ett nummer och ladda in i en array

Inlägg av ekman »

Tack för svaren. Nu förstår jag bättre. Tyvärr så verkar problemet ligga någon annanstans. Det jag försöker göra är att använda en shiftregister för att skicka data till LCD (HD44780). Avr -> Shiftregister -> LCD.
RS,RW,E pinnarna på LCD'n är kopplad direkt till Avr'n. Tänkte jag skulle vara smart och använda mindre I/O pinnar och testa med shiftregister :)

Tror det blir fel med timeingen? då jag fått för mig att det är rätt kritiskt. LCD koden har jag hittat på AVRfreaks forum och försökt anpassat. Är rätt trött nu och ska ta en pause för att försöka hitta felet senare (ikväll för förhoppningsvis). Men tänkte först visa hur jag försökte implementera den funktionen jag frågade efter:

Kod: Markera allt

void LcdSendByte(uint8_t theByte)
{
	// Short delay needed here...
	_delay_us(50);
	// Output the byte (to shiftregister)
	PORTD &= (0<<3); // Set Register pin LOW
			for(uint8_t i=0; i < 8; i++)
			{
				Send(theByte & ( 1 << i ));
			}
	PORTD |= (1<<3); // Set Register pin HIGH to show change
	
	// Toggle the E line
	LCD_CTRL_PORT |= (1<<LCD_E);   // Going up..
	// Short delay needed here...
	_delay_us(50);
	LCD_CTRL_PORT &= ~(1<<LCD_E);  // ..and down.
}


Jag tänkte på en sak. När jag använder denna funktion och skriver till ex. LcdSendByte(0x38); så tänkte jag att uint8_t gjorde om hex talet till binärt? till 00111000 ? om den inte göra det så funkar ju det inte :humm:

Ps. Jag vet att jag tog förmodligen vatten över huvudet med shiftregistert. Ska testa bara Avr -> LCD, efter lite mer försök :) .ds
Användarvisningsbild
Icecap
Inlägg: 26652
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Bryta upp ett nummer och ladda in i en array

Inlägg av Icecap »

Det kan fungera helt OK med ett shiftregister men du måste ha koll på att det inte blir kastat om på MSB och LSB.

Jag ser omedelbart ett par problem som kan göra det hela lite svårare att läsa allt, du bör alltså förtydliga för dig själv. Du använder (1<<3) som en bit men om du vore lite bättre på att göra läsbara program hade du, först i programmet, skrivit:
#define Set_Shift_Latch() (PORTD |= (1<<3))
#define Clear_Shift_Latch() (PORTD &= ~(1<<3))

Sedan använder du Set_Shift_Latch(); eller Clear_Shift_Latch(); i programmet, det är extremt mycket enklare att läsa.

Och samma sak ger vilket fel du gör!
"PORTD &= (0<<3); // Set Register pin LOW"
Detta kommando nollar hela PORTD! Du ska skriva:
"PORTD &= ~(1<<3);" istället.
Senast redigerad av Icecap 13 december 2011, 14:04:09, redigerad totalt 1 gång.
Användarvisningsbild
pbgp
Inlägg: 1450
Blev medlem: 11 november 2010, 09:09:22
Ort: Uppsala

Re: Bryta upp ett nummer och ladda in i en array

Inlägg av pbgp »

Det ser ut som du fått bra hjälp i inlägget ovan, så jag tänkte svara på den här frågan istället:
ekman skrev:Jag tänkte på en sak. När jag använder denna funktion och skriver till ex. LcdSendByte(0x38); så tänkte jag att uint8_t gjorde om hex talet till binärt? till 00111000 ? om den inte göra det så funkar ju det inte :humm:
Om ett tal är hex, binärt, decimalt eller octalt spelar ingen roll, det är bara för att göra det enklare (eller svårare :D ) när man programmerar.

Nedanstående rader betyder alla samma sak:

Kod: Markera allt

uint8_t x;
x = 12; // decimalt
x = 0xC; // Hexadecimalt
x = 014; // Octalt
x = 0b1100 // Binärt
Ett ganska vanligt missförstånd i början :)
Nerre
Inlägg: 27235
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Bryta upp ett nummer och ladda in i en array

Inlägg av Nerre »

Precis, en dator jobbar i princip ALLTID med binära tal. Sen kan de i och för sig "tolkas" på olika sätt (som flyttal, heltal, bokstäver).
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Bryta upp ett nummer och ladda in i en array

Inlägg av jesse »

Tror det blir fel med timeingen? då jag fått för mig att det är rätt kritiskt.
Sätt en fördröjning på en sekund mellan varje förändring på utgången och sätt dit lysdioder så ser du i vilken ordning det kommer ut (om du inte har ett oscilloskop förstås, då är det enklare - men ändra tiderna så att du kör med millisekunder - inte mikrosekunder - då är du säker på att det inte är för korta tider i alla fall - sedan, när allt fungerar , kan du prova att öka hastigheten).

Nu vet jag inte riktigt vad "register pin" är för något? Kan du inte rita ett schema på hur du har kopplat så vi får se? Annars kan det vara svårt att avgöra om du gör rätt eller fel.

Kod: Markera allt

Send(theByte & ( 1 << i ));
Den raden verkar vara ganska smart, om nu "send()" rutinen tolkar allt som är skilt från noll som en etta.

/************ Här kommer överkurs för oss programmeringstokiga:

När man loopar en variabel, i och sedan gör (1 << i) inne i loopen kan det kanske ta en massa onödig tid, om den i varje varv ska shifta i antal gånger. Nu kan det hända att GCC ser dett och optimerar bort det, men om den inte gör det , så är detta alltså ett klumpigt sätt för processorn att shifta ett åttabitars tal. **************/


Jag hade gjort så här:

Kod: Markera allt

for (i = 0; i<8 ; i++) {
    send(data & 1);
    data >> 1;
}
Variablen data förstörs visserligen i operationen, men då det ändå sker inne i en funktion sendByte() så bör det inte spela någon roll då variabeln är lokal.

Jag tor att du shiftar ut bitarna i fel ordning. Om du sänder bit 0 först , så kommer den till slut att hamna sist i shiftregistret, dvs på utgång Q7, den sista biten du shiftar in (bit 7 ) kommer att hamna i Q0. Om du vill ha det i rätt ordning ska du alltså börja med bit 7 och sluta med bit 0.
ekman
Inlägg: 280
Blev medlem: 13 januari 2009, 14:04:35

Re: Bryta upp ett nummer och ladda in i en array

Inlägg av ekman »

Nu har jag försökt debuggat lite mer. Jag har satt data pinnarna från shiftregistret ut till 8st LED's. Så nu kan jag visuellt se vilka pinnar som blir höga osv.

men jag kan fortfarande inte läs in theByte bit för bit.
Jag försökte först med Johano's exempel med:

Kod: Markera allt

for(uint8_t i=0; i < 8; i++)
{
  send( theByte & ( 1 << i ) );
}
Men inget utslag.
Så då tänkte jag att jag ska lägga in bit för bit i en array som LHelge visade. Så här gjorde jag:

Kod: Markera allt

	uint8_t ShiftArray[8];

		ShiftArray[0] = theByte & 1;
		ShiftArray[1] = (theByte & 2) >> 1;
		ShiftArray[2] = (theByte & 3) >> 2;
		ShiftArray[3] = (theByte & 4) >> 3;
		ShiftArray[4] = (theByte & 5) >> 4;
		ShiftArray[5] = (theByte & 6) >> 5;
		ShiftArray[6] = (theByte & 7) >> 6;
		ShiftArray[7] = (theByte & 8) >> 7;
Men helt dött. Men då testade jag att slänga in en '1' mitt i arrayen. Och då lyser respektive LED upp

Kod: Markera allt

	uint8_t ShiftArray[8];

		ShiftArray[0] = theByte & 1;
		ShiftArray[1] = (theByte & 2) >> 1;
		ShiftArray[2] = (theByte & 3) >> 2;
		ShiftArray[3] = (theByte & 4) >> 3;
		ShiftArray[4] = (theByte & 5) >> 4;
		ShiftArray[5] = 1; //(theByte & 6) >> 5;
		ShiftArray[6] = (theByte & 7) >> 6;
		ShiftArray[7] = (theByte & 8) >> 7;
Jag gissar på att dom laddas med fler än ett nummer? :humm:
Jag försökte till och med, med någon slags if statement som skulle sortera in 1 och 0 i array'n. Så här:
Detta innan jag skickar till Shiftregister.

Kod: Markera allt

uint8_t ShiftArray[8];
	
	for(int k=0; k<8; k++)
	{
		//Ladda array
		if((theByte<<k)==1)
		{
			ShiftArray[k] = 1;
		} else
		{
			ShiftArray[k] = 0;
		}
	}
Inte heller det lyckades. Så har ni några fler förslag? :)
ps. Jag har ändrat PORTD &= (0<<3); till PORTD &= ~(1<<3); .ds
ekman
Inlägg: 280
Blev medlem: 13 januari 2009, 14:04:35

Re: Bryta upp ett nummer och ladda in i en array

Inlägg av ekman »

Kan ju vara intressant å se min send rutin som jag har för att ladda shiftregistern:

Kod: Markera allt

void Send(int g)
{
	if (g == 1)
	{
		PORTB=0x40; // Set Serial Pin to 1
	} 
	else
	{
		PORTB=0x00; // Set Serial Pin to 1
	}
		//Send pulse to SERCLK
		PORTD |= (1<<4); // HIGH
		PORTD &= ~(1<<4); // LOW
}
Jag vet att jag ändrar hela port B. Och att jag borde använt mig av define. Får snygga till det :vissla:
Skriv svar