Skriva ut en byte på valfri pinne?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
FS
Inlägg: 245
Blev medlem: 14 januari 2005, 23:35:45

Skriva ut en byte på valfri pinne?

Inlägg av FS »

Hur gör man för att skriva ut en byte på en pinne? Använder AVR och GCC...

tex.
Jag vill skriva ut 0x51 (10001010 binärt),
det är ju lite omständigt att köra:
sbi(PORTD, PD0);
cbi(PORTD, PD0);
cbi(PORTD, PD0);
cbi(PORTD, PD0);
sbi(PORTD, PD0);
cbi(PORTD, PD0);
sbi(PORTD, PD0);
cbi(PORTD, PD0);

Hur gör man en snygg slinga som plockar rätt bit och sätter pinnen till 1 eller 0?
Virror
Inlägg: 1025
Blev medlem: 28 april 2004, 11:03:14
Ort: Göteborg
Kontakt:

Inlägg av Virror »

PORTD = 0x51;

Det funkar väll?
Användarvisningsbild
Icecap
Inlägg: 26736
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Om man kör en cyklus om 8 steg:

Kod: Markera allt

for(Räknare = 0;Räknare < 8;Räknare++)
  { // Utföras 8 gg.
  if(Data & 0x80) sbi(PORTD, PD0); // Om MSB är satt settas porten
  else cbi(PORTD, PD0); // Annars cleares den
  Data <<= 1; // Betyder skifta 'Data' till vänster 1 steg
  }
Blandning av C och Assembler?
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg av cyr »

Kod: Markera allt


char tmp = 0x51;
int i;

for(i=0;i<8;i++)
{
   if(tmp&0x80) sbi(PORTD,PD0);
   else cbi(PORTD,PD0);
   
   tmp<<=1;
}

Kan inte AVR så jag vet inte om det går att tilldela biten direkt istället för att använda sbi, cbi - men det där borde iaf funka. Lägg in lagom fördröjning i loopen också om det ska vara någon slags seriell kommunikation...

edit: ja idag var man ju snabb... :oops:
Användarvisningsbild
björn
EF Sponsor
Inlägg: 2570
Blev medlem: 29 mars 2004, 23:09:55

Inlägg av björn »

Vad jag minns så används inte cbi och sbi längre i gcc, utan man får skriva i ANSI-C(?) instället (sbi och cbi är "depricated").

Eller lägga till tex:

Kod: Markera allt

#define cbi(port, bitnum) port &= ~(1 << bitnum)
#define sbi(port, bitnum) port |= (1 << bitnum)
Användarvisningsbild
Icecap
Inlägg: 26736
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Eller
asm cbi(sbi(PORTD,PD0);
och
asm cbi(PORTD,PD0);
FS
Inlägg: 245
Blev medlem: 14 januari 2005, 23:35:45

Inlägg av FS »

Icecap skrev:Om man kör en cyklus om 8 steg:

Kod: Markera allt

for(Räknare = 0;Räknare < 8;Räknare++)
  { // Utföras 8 gg.
  if(Data & 0x80) sbi(PORTD, PD0); // Om MSB är satt settas porten
  else cbi(PORTD, PD0); // Annars cleares den
  Data <<= 1; // Betyder skifta 'Data' till vänster 1 steg
  }
Blandning av C och Assembler?
Tack! Om man vill göra det motsatta, dvs läsa in 8 bitar till en byte. Vad använder man då?
Användarvisningsbild
oJsan
EF Sponsor
Inlägg: 1541
Blev medlem: 11 november 2005, 21:36:51
Ort: Umeå
Kontakt:

Inlägg av oJsan »

I båda fallen (in och ut) måste det läggas till en klocka!
För varje hög (eller låg) flank på klockan så läser man värdet på data-in-pinnen och skiftar in det i en byte. Typ såhär, åsså får man se till att göra det åtta gånger bara:

Kod: Markera allt

if(PIND & PD0)
   Data |= 0x01;
Data <<= 1;
Sånna här bit-skift in och ut går att göra mycket effektivare i asm genom att använda carry-biten. HAr tyvärr inget exempel såhär på kvällskvisten.. läggdags nu.. :(
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg av cyr »

Man kan göra det utan några extra klocka (asynkront), en vanlig serieport är ju exempel på det. Fast om man gör det måste förstås både sändare och mottagare vara överens om exakt hur snabbt data skickas och man måste ha någon metod för att återsynka då och då (t.ex. startbit/stopbit som på serieporten).
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Inlägg av Korken »

Hej!

Detta är en kod som fungerar när man ska skriva en byte på en pinne.

Kod: Markera allt

void send_data(uint8_t mybyte) 
{ 
   for(int i = 0; i < 8; i++) 
   { 
      if (mybyte & 0x80) 
         LCD_PORT |= (1<<LCD_DATA_PIN); 
      else 
         LCD_PORT &= ~(1<<LCD_DATA_PIN); 

      mybyte <<= 1; 
   } 
    
}
Den var för en LCD styrning med ett 8bitars parallelt shiftregister.

//Emil
Användarvisningsbild
$tiff
Inlägg: 4941
Blev medlem: 31 maj 2003, 19:47:52
Ort: Göteborg
Kontakt:

Inlägg av $tiff »

>> FS

Det är kanske dax att titta på hårdvarufunktionerna UART och SPI som finns att tillgå i de flesta AVR.
FS
Inlägg: 245
Blev medlem: 14 januari 2005, 23:35:45

Inlägg av FS »

Håller på att kommunicera med en temperatur sensor. Så SPI/UART känns lite overkill, eller? Vad är standard sättet för att kommunicera med dylika externa enheter? Jag klockar ju bara ut bitarna en efter en, finns det nåt bättre sätt?

Hur är det med dessa timing kraven som finns i databladen? Måste man leva i en perfekt värld för att uppnå dem? Jag har lött på virkablar på den ytmonterade kretsen som sedan sitter i en labbplatta. Detta borde väl inte vara bra alls, men att gå från de specade ~100ns till att vara tvungen att lägga in delays på 40us känns lite väl hårt, eller? :roll:

Dessutom ger sensorn ett värde som är 4 grader celsius för högt, vad beror detta på? Enligt databladet ska den vara bra mycket bättre än så...

Datablad för DS1626:
http://pdfserv.maxim-ic.com/en/ds/DS1626-DS1726.pdf

Kod:

Kod: Markera allt

#define F_CPU 1000000
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))

#define TEMP PORTD
#define RST PD0
#define CLK PD1
#define DQ PD2

#include <avr/io.h>
#include <util/delay.h>

int i, data;
void wait()
{
	sbi(PORTA, PA0);
	sbi(PORTA, PA0);
	sbi(PORTA, PA0);
	sbi(PORTA, PA0);
	sbi(PORTA, PA0);
}

void read_temp(void)
{
	// start temperature conversion, send 0x51 LSb first...
	DDRD = 0xFF; // DQ pin as output
	data = 0x51;
	sbi(TEMP, RST); // RST high
	for(i = 0; i < 8; i++)
	{
		cbi(TEMP, CLK); // clock low
		if(data & 0x01)
			sbi(TEMP, DQ);
		else
			cbi(TEMP, DQ);
		data >>= 1; // shift data right
		sbi(TEMP, CLK); // clock high
	}
	cbi(TEMP, RST); // RST low


	// wait 800ms for temperature conversion to complete
	for(i = 0; i < 4; i++)
		_delay_ms(200);


	// read temperature
	// send 0xAA LSb first...
	data = 0xAA;
	sbi(TEMP, RST); // RST high
	for(i = 0; i < 8; i++)
	{
		cbi(TEMP, CLK); // clock low
		if(data & 0x01)
			sbi(TEMP, DQ);
		else
			cbi(TEMP, DQ);
		data >>= 1; // shift data right
		sbi(TEMP, CLK); // clock high
	}
	// ...then read temperature register
	DDRD = 0xFB; // DQ pin as input
	for(i = 0; i < 12; i++)
	{
		data >>= 1; // shift data right
		cbi(TEMP, CLK); // clock low
		if(PIND & (1 << DQ))
			data |= 0x80;
		sbi(TEMP, CLK); // clock high
	}
	cbi(TEMP, RST); // RST low
}

int main(void)
{
	DDRA = 0xFF; // PORTA output

	while(1)
	{
		read_temp();
		PORTA = data;
	}
}
wait() ger ett avbrott på ca 40us...

Ska man ha något annat upplägg på koden? Det blir ju en del kod...

Edit: Kod uppdaterad, hastighetsproblem löst...
Senast redigerad av FS 30 juli 2006, 00:27:51, redigerad totalt 2 gånger.
FS
Inlägg: 245
Blev medlem: 14 januari 2005, 23:35:45

Inlägg av FS »

Egentligen borde jag inte behöva några delayer alls då kretsen går i 1MHz...
Om jag kör tex:

Kod: Markera allt

while(1)
{
	cbi(PORTA, PA0);
	sbi(PORTA, PA0);
}
Får jag en periodtid på ca 10us (uppmätt med oscilloskop). Så varför behöver jag delayer öht? Är det pga. den kassa uppkopplingen med virtråd och labbplatta?

Edit: Hmm var tog björn:s inlägg som jag svarade på vägen?
Användarvisningsbild
björn
EF Sponsor
Inlägg: 2570
Blev medlem: 29 mars 2004, 23:09:55

Inlägg av björn »

Jag tog bort det, jag antog utan att ha tittat på länken att det var 1-wire protokoll vilket var fel.
sodjan
EF Sponsor
Inlägg: 43266
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Trevlig tråd och ett bra exempel på en fullständigt felaktigt ställd första fråga.

Istället för "Hur gör man för att skriva ut en byte på en pinne?" skulle det
naturligtsvis ha varit "Hur kommunicaerar jag enklast/bäst med en DS1626 ?"
Och så en länk till databladet i *FÖRSTA* inlägget !

Då hade alla svar antagligen sett annorlunda ut.

Det framgår t.ex inte förrens ganska sent att du faktiskt även
*har* en CLK-linje.

> Så SPI/UART känns lite overkill, eller?
> Vad är standard sättet för att kommunicera med dylika externa enheter?

SPI kanske ? Varför är det "overkill" ? Du tycker ju själv att det "Det blir ju en del kod...".
Jo visst, det är därför man bygger in olika hårdvaruenheter för kommunikation.
Men å andra sidan, inte är det där speciellt mycket kod för att bitbanga en seriell temp sensor !

Jag tror att, om man inte vill köra hårdvaru-SPI, så är det nog enklare
att skriva en ASM rutin och anropa från C-koden...

> Dessutom ger sensorn ett värde som är 4 grader celsius för högt,...

Eller så visar det du jämför med 4 grader för lågt...

En annan liten detalj, var växlar du data pinnen mellan ingång och utgång ?
Skriv svar