Du må være registrert og logget inn for å kunne legge ut innlegg på freak.no
X
LOGG INN
... eller du kan registrere deg nå
Dette nettstedet er avhengig av annonseinntekter for å holde driften og videre utvikling igang. Vi liker ikke reklame heller, men alternativene er ikke mange. Vær snill å vurder å slå av annonseblokkering, eller å abonnere på en reklamefri utgave av nettstedet.
  6 1529
Tenkte jeg skulle dele dette i tilfellet noen var interessert. Har fullført del 1 av et todelt prosjekt jeg holder litt på med i jula og har dekket det meste på bloggen min Henrik.SandakerPalm.no, men tenkte å oversette til norsk her.


Etter å ha kjøpt meg et fjernstyrt lekehelikopter på teknikmagasinet ble jeg overrasket over hvor godt man kan styre en noe tidskritisk applikasjon med infrarødt lys.

Først litt basisinfo om de få og enkle komponentene som utgjør hoveddelen av kretsen. Det er viktig å vite hvordan mottakeren fungerer før man lager fjernkontrollen! Du trenger en eller fler LEDs som lyser med infrarødt lys, forkortet IR LED. Jeg brukte en TSOP4838 fra Tayda Electronics, produsert av Vishay, som er en IR mottaker modul. Hva "48" står for vet jeg ikke, men tallet 38 er mottakerens carrier frequency, som er 38KHz, oversetter her til bærefrekvens uten å vite om det er korrekt oversatt.

Bærefrekvensen er den frekvensen som IR LEDen må lyse med ("blinke") for at mottaker modulen skal oppfatte lyse. Når infrarødt lys lyser med denne frekvensen vil mottakeren oppfatte dette som et korrekt signal. Inni mottakermodulen finnes det bl.a. et båndpassfilter som jobber for å filtrere ut alt annet enn IR lys på bærefrekvensen, så alt annet infrarødt lys blir behandlet som søppel, f.eks vil lysstoffrør emmittere en viss mengde IR lys. Det er noe forhåndsregler som må tas hensyn til med slike mottakermoduler for å unngå tap av data. For eksempel må et lyssignal (på 38KHz) være på mellom 10 og 70 perioder (2,63e-4 til 1.8 ms med lys), og må bli etterfulgt av en pause på minst 14 perioder uten lys. Hvis et IR lyssignal overskrider dette antall perioder (10-70) gjelder andre regler. Fra databladet
For each burst which is longer than 1.8ms a
corresponding gap time is necessary at some time in
the data stream. This gap time should be at least 4
times longer than the burst.

Altså må hvert lyssignal som overstiger 1.8 millisekunder etterfølges av en pause på minst fire ganger lengden på lyssignalet.

Mottakermodulen har tre pinner. Den skal kobles til jord og strøm (foretrekker 5 volt), og har en Vut pinne hvor utgangssignalet oppstår. Utgangssignalet er aktivt lavt, det betyr at utgangen ligger på 5 volt helt til den oppdager et korrekt lyssignal og da går pinnen til 0v helt til lyssignalet opphører.

http://sandakerpalm.no/blog/wp-content/uploads/2010/12/burstsoflight.jpg

For å kontrollere lyssignalets periodetider og hvordan data skulle overføres brukte jeg en Atmega8. Det finnes proprietære funksjoner i mikrokontrollere og egne mikrokontrollere til å ta seg av IR kommunikasjon, men min metode funket veldig bra til mitt lavnivå formål! Fjernkontrollen min består av en Atmega8, en IR led og fire taktile knapper. De fire knappene er koblet til hver sin pinne på PORTB, fra pinne 0 til 3, men alle er også koblet til ekstern interrupt pinne PORTD PIN2 (INT0). Når en bryter trykkes så trekkes interrupt pinnen lav, og i interruptrutinen i programmet leser jeg av verdien på PORTB for å se hvilken knapp som ble trykket. Jeg bruker Timer 2 i CTC modus for å lage en output på OC2 pinnen med riktig frekvens, som avbrytes i sekvenser for å tilsvare forskjellige datasignaler avhengig av hvilken knapp som ble trykt. Jeg deler opp utgangssignalet i datapakker på 4 bit ved å skru av og på muligheten for utgangssignaler på porten, dette gjøres ved å skrive til DDR registeret (Data Direksjons Registreret) til den gjeldende porten.

En ting du bør ta hensyn til som ikke jeg gjorde, er å ikke drive IR LEDen direkte fra mikrokontrollerens utgang. En pinne på en mikrokontroller kan levere rundt 20mA, som er tilstrekkelig for en normal LED ved normal bruk. Men siden du skrur LED av og på med en viss frekvens så vil LED faktisk se en gjennomsnittsspenning avhengig av hvor lenge en periodetid er høy. Du kan dermed øke spenningen og strømmen slik at LEDen lyser kraftigere for hver høye puls på bærefrekvensen. Du må nå ta hensyn til LEDens maksimale peak current, i stedet for continuous current. LED bør derfor styres fra samme utgangsport, men via en transistor og en strømbegrensende motstand i passende størrelse.

http://sandakerpalm.no/blog/wp-content/uploads/2010/12/fjernkontroll.jpg
Diodene er satt feil vei i koblingsskjemaet! De er for å forhindre at en bryter vil trekke alle fire pinnene på PORTB til jord.

Dette er koden som ligger på mikrokontrolleren


Kode

#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 8000000UL
#include <util/delay.h>

int main(void)
{
	//timer 2
	TCCR2 |= (1<<WGM21) | (1<<COM20) | (1<<CS20);
	OCR2 = 48;	

	DDRC = 0x00;
	PORTC= 0xF; //Pullup
	PORTD=0xFF;

	//INT0
	MCUCR |= /*(1<<ISC00)*/ (1<<ISC01);
	GICR |= (1<<INT0);

	sei();

	while(1)
	{
	}
	
	return 0;
}

//Dette er interruptrutinen som utføres hver gang en bryter trykkes
//Datasignalet vises som kommentar over hver if-setning
ISR(INT0_vect)
{
	// -__----
	if ((PINC & (1<<PIN0)) == 0)
	{
		DDRB |= (1<<PIN3);
		_delay_us(2000);
		DDRB &= ~(1<<PIN3);
		
	}

	// -_-_--
	if ((PINC & (1<<PIN1)) == 0)
	{
		DDRB |= (1<<PIN3);
		_delay_us(1000);
		DDRB &= ~(1<<PIN3);
		_delay_us(1000);
		DDRB |= (1<<PIN3);
		_delay_us(1000);
		DDRB &= ~(1<<PIN3);
	}

	// -___--
	if ((PINC & (1<<PIN2)) == 0)
	{
		DDRB |= (1<<PIN3);
		_delay_us(3000);
		DDRB &= ~(1<<PIN3);
	}

	// -_--_-
	if ((PINC & (1<<PIN3)) == 0)
	{
		DDRB |= (1<<PIN3);
		_delay_us(1000);
		DDRB &= ~(1<<PIN3);
		_delay_us(2000);
		DDRB |= (1<<PIN3);
		_delay_us(1000);
		DDRB &= ~(1<<PIN3);
	}
}
Her er en video som demonstrerer bruken av fjernkontrollen. De fire nederste bitene på STK500 brettet forteller hvilken datapakke den mottok, nr 1, 2, 3 eller 4. Se på oscilloskopet for en eksakt måling av utgangssignalet på Vut pinnen på mottakeren! Denne kretsen som mottar signalene vil jeg ta for meg ved en senere anledning
http://www.youtube.com/v/BlZQTbCztkY?fs=1&amp;hl=nb_NO
Sist endret av wanna-b; 21. desember 2010 kl. 14:55.
Sitat av wanna-b Vis innlegg
DDRB |= (1<<PIN3);

DDRB &= ~(1<<PIN3);
Vis hele sitatet...
Kan du gi en kort forklaring på det noe kryptiske innholdet i disse to linjer ?
Dette er bit-operasjoner. Den første linja gjør en venstre bitshift på PIN3, for deretter å bruke en OR-operasjon for å slå på biten han ønsker. Har ikke tiden nå til å skrive en detaljert beskrivelse av operasjonene, men kan visualisere verdiene fortløpende veldig kjapt med en liten kodesnutt i C#. Les litt i linkene jeg henviser til, så skjønner du det nok mye bedre.

Denne koden kan kanskje visualisere litt bedre hva han gjør:

Kode

class MainClass
{
	public static void Main (string[] args)
	{
		int DDRB = 16;
		Console.WriteLine( toBinary(DDRB) );
		
		int PIN3 = 2;
		Console.WriteLine( toBinary(PIN3) );
		
		PIN3 = 1 << PIN3;
		Console.WriteLine( toBinary(PIN3) );
		
		DDRB = DDRB | PIN3;
		Console.WriteLine( toBinary(DDRB) );
		
		Console.ReadKey();
	}
	
	private static string toBinary( int input )
	{
		return Convert.ToString( input, 2 );	
	}
}
Utput av koden

Kode

10000
10
100
10100
Da kan du sikkert tenke deg hva neste linje gjør?

http://www.gamedev.net/reference/art...rticle1563.asp
http://en.wikipedia.org/wiki/Bitwise_operation
Sist endret av m0b; 25. desember 2010 kl. 17:48.
Sitat av asmika Vis innlegg
Kan du gi en kort forklaring på det noe kryptiske innholdet i disse to linjer ?
Vis hele sitatet...
|d13m0b tok teorien bak det, så da kan jeg jo si med ord hva det er godt for.

DDR registeret til en hver port (f.eks PORT B som i dette tilfellet, som inneholder 8 inn/ut pinner) bestemmer dataretningen til den gitte pinnen som du definerer.
DDR registeret til port b heter DDRB. Det består av åtte bits tilsvarende hver av pinnene. når det er tomt ser det slik ut: 00000000, hvor biten helt til høyre definerer inn/ut på pinne 0, og biten helt til venstre definerer inn/ut på pinne 7, og alt i mellom. Hvis det står en 1'er på plassen til f.eks pinne 0, slik: 0000001, så betyr det at pinne 0 er en ut-pinne, pinne 1-7 er inn-pinner.
Hvis du skal definere halvparten som ut, og halvparten som inn, så skriver du: PORTB = 0b00001111, hvor 0b betyr at vi ønsker å representere tallet binært, som også gir en mer visuell visning av hvordan porten er satt opp (tilsvarende hexadesimalt er 0x0F, og desimalt er 15). Problemet med å skrive det på denne måten er at noen ganger ønsker du å endre ut/inn egenskapene på én pinne uten å endre på de andre. Da hadde det vært deilig å f.eks kunne skrive PORTB = 0bXXXXXX0X for å endre pinne 1 til innport , og la resten stå som de er, men det går desverre ikke... Men en tilsvarende operasjon kan gjøres med operatoren "ELLER". Sannhetstabellen til ELLER (i c-kode ser den slik | ut)ser slik ut:
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
Så hver gang det er en 1er i operasjonen så blir utfallet 1. Hvis man bruker ELLER operatoren på større tall enn 1 og 0 så vil operasjonen skje bit for bit, slik:
00010001
| 00000001
= 00010001

Bingo, hvis jeg vil endre verdien til 1 (utport) på si pinne 2 så tar jeg "plassen til pinne 2" ELLER den verdien som allerede ligger der.
I kompilatoren jeg bruker så finnes det noen snarveier, f.eks PIN2 betyr "hvor mange plasser fra den laveste biten definerer pinne 2". Og det er jo 2 plasser. Så PIN2=2 (noe som høres tungvindt ut, men det gir en bedre visuell kode). << betyr "bitskift mot venstre", og skal brukes f.eks. slik: 1 << 3, som betyr at verdien 1 flyttes tre ganger til venstre. På et tomt 8 bits register vil utfallet se slik ut: 00001000 binært.


I koden min vil jeg sette pinne 3 i dataretningsregisteret til port b som ut-pinne.
DDRB |= (1<<PIN3);
I C kode så kan man bruke forkortelsene +=, -=, |=. F.eks betyr "verdi += 2" det samme som "verdi = verdi + 2"
Så i tekst betyr den første linjen min: DDRB = DDRB ELLER "plasseringen til pinne 3" som jo setter pinne 3 som utport uten å bry seg om hvilke andre verdier som ligger i registeret fra før av.

Den andre linjen du spurte om er litt mer vrien, men den kan du jo prøve å forstå selv nå med grunnlaget du fikk i linkene i posten over
Takker for forklaringene

Har nettopp startet med AVR programering, og lærer sakte men sikker.

Første program styrte 8 LED
http://www.youtube.com/watch?v=pz0WYliZnLc

Holder nå på med en enkel styring til en pumpe.
Prinsippet er tre elektroder som står i en beholder, første pinne jord, andre pinne er første nivå, tredje pinne er andre nivå.
Pumpen starter når andre nivå er nådd og holdes i gang til nivået er under første.
Litt drøyt å bruk såpass komplisert utstyr til noe så enkelt, men noe måtte jeg jo begynne med.
Tenkte videre å lage alarmindikering, registreing tid (feks pumpe i drift )
Start en prosjekttråd så vi kan følge med da vel
Sitat av wanna-b Vis innlegg
Start en prosjekttråd så vi kan følge med da vel
Vis hele sitatet...
Hmm, får se på den saken, når jeg har programmeringen litt mere på plass

Men kan til å begynne med å orientere om att inngangene på kretsen (via ett par ledninger ) registrerte kontakten med vann som nivåskifte. Brukte en metallboks som vannbeholder koblet til negativ del av strømforsyningen.