Sida 1 av 2
Skriva ut en byte på valfri pinne?
Postat: 28 juli 2006, 20:13:15
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?
Postat: 28 juli 2006, 20:29:06
av Virror
PORTD = 0x51;
Det funkar väll?
Postat: 28 juli 2006, 20:31:08
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?
Postat: 28 juli 2006, 20:35:52
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...

Postat: 28 juli 2006, 21:00:16
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)
Postat: 28 juli 2006, 22:00:36
av Icecap
Eller
asm cbi(sbi(PORTD,PD0);
och
asm cbi(PORTD,PD0);
Postat: 28 juli 2006, 23:19:42
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å?
Postat: 28 juli 2006, 23:29:15
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:
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..

Postat: 28 juli 2006, 23:57:16
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).
Postat: 29 juli 2006, 14:38:31
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
Postat: 29 juli 2006, 17:26:04
av $tiff
>> FS
Det är kanske dax att titta på hårdvarufunktionerna UART och SPI som finns att tillgå i de flesta AVR.
Postat: 29 juli 2006, 18:52:14
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?
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...
Postat: 29 juli 2006, 19:18:26
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?
Postat: 29 juli 2006, 20:01:33
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.
Postat: 29 juli 2006, 21:24:45
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 ?