Jump to content


Photo

Proiecte Atmel-based pentru incepatori


  • Please log in to reply
14 replies to this topic

#1 OFFLINE   ole

ole

    Membru

  • Membri
  • PipPip
  • 341 posts

Posted 11 September 2009 - 08:41 PM

Aici se vor posta doar proiecte pentru incepatori gen led-blinker sau mai stiu eu ce licurici, chiar si productii proprii. Va rog sa scrieti doar o scurta descriere si un link catre proiect. Ideal ar fi ca proiectul sa aiba o descriere cat mai detaliata si codul comentat "ca la gradinita".

Cu_reclama

Cu_reclama
  • Membri

#2 OFFLINE   Stefan Nicolae

Stefan Nicolae

    Opozitia

  • Moderatori
  • 4,645 posts
  • Locatie:KN24KU

Posted 13 September 2009 - 01:48 PM

oarecum pentru incepatori http://www.avr-asm-t...ial.net/avr_en/ (de parca eu sunt avansat :rade: )

#3 OFFLINE   caddyct

caddyct

    Nou venit

  • Membri
  • Pip
  • 80 posts

Posted 23 September 2009 - 01:10 PM

si asta ar fi o idee: http://www.avrprojec... ... &Itemid=54

#4 OFFLINE   RoGeorge

RoGeorge

    Electronist

  • Membri
  • PipPipPipPipPip
  • 2,685 posts
  • Locatie:Bucuresti - Cluj

Posted 03 January 2010 - 10:34 PM

Telecomanda fara fir (ML-L3) pentru aparate foto Nikon.
viewtopic.php?f=44&t=52292

Cred ca este cel mai simplu montaj posibil cu un microcontroller.
Contine doar un LED infrarosu, un ATtiny13 si o... bricheta! :rade:

#5 OFFLINE   RoGeorge

RoGeorge

    Electronist

  • Membri
  • PipPipPipPipPip
  • 2,685 posts
  • Locatie:Bucuresti - Cluj

Posted 27 January 2010 - 10:54 PM

Aceeasi telecomanda pentru aparate foto Nikon, update cu schema:

viewtopic.php?f=44&t=52292

#6 OFFLINE   ionu x

ionu x

    Nou venit

  • Membri
  • Pip
  • 75 posts

Posted 02 April 2010 - 06:57 PM

:freaza: cv smecher pt bicicleta...cu programul potrivit poti face diferite modele pe roata :dans:
http://www.johndawso... ... ematic.png
....rezistorul verde este de 10kohmi

#7 OFFLINE   MifTy

MifTy

    Insuficient Curentat

  • Moderatori
  • 5,325 posts
  • Locatie:Constanţa

Posted 30 June 2010 - 09:04 PM

miniplacă de "joacă" cu tiny2313: ftp://ftp.cadsoft.de/eagle/userfiles/pr ... 13mod1.zip

se dau schema şi cablajul, softul... treaba voastră, că ie de învăţat, nu de dat mură-n gură!!! :rade:

(uitaţi-vă mai cu atenţie pe-acolo, se dau cablaje pentru multe chestii drăguţe... :da )

#8 OFFLINE   Stefan Nicolae

Stefan Nicolae

    Opozitia

  • Moderatori
  • 4,645 posts
  • Locatie:KN24KU

Posted 30 June 2010 - 11:20 PM

off: se presupune ca o "placa de dezvoltare" nu are soft.
on: http://www.qsl.net/v.../avrdesign.html (daca a mai fost imi cer scuze)

#9 OFFLINE   radur

radur

    Nou venit

  • Membri
  • Pip
  • 39 posts

Posted 29 April 2011 - 10:52 PM

Hai ca sparg eu gheata dupa un an, motivat fiind de faptul ca n-am gasit pe acest forum bucati de cod explicate "ca la gradinita".

Va salut, incepator fiind propun altor incepatori un ceas binar cu afisaj pe 12 leduri, folosind pe post de creier orice attiny cu 8 pini (in cazul de fata attiny25, insa codul se poate modifica foarte usor pentru attiny13a de exemplu).
Sa incepem :speriat

Pentru inceput vom incepe cu schema de legare a ledurilor la uC, pentru ca avem doar 6 pini disponibili (de fapt, la inceput, vor fi doar 5 pini disponibili pentru ca pinul de reset ne trebuie la programare) le vom lega in mod charlieplex si le vom numerota in ordinea adaugarii lor (de la 0 la 11).
De retinut ca in modul charlieplex nu se poate aprinde mai mult de 1 led simultan, asadar pentru a aprinde mai multe leduri ne vom folosi de faptul ca ochiul uman nu mai percepe diferente peste 60hz sa zicem. Cu alte cuvinte ca sa aprindem 2 leduri "simultan" pentru noi, vom aprinde si vom stinge fiecare led in parte, succesiv, foarte rapid.
Avand in vedere ca vor sta aprinse o perioada relativ scurta ledurile ar trebui alese de tipul "ultrabright".
Rezistentele trebuie alese astfel inca 2 rezistente din schema atasate la 1 led sa dicteze curentul acestuia. In cazul de fata am folosit 4 rezistente de 220Ohm, astfel curentul ce va curge prin fiecare led este I = U / 2x220Ohm, unde U este tensiunea de alimentare - tensiunea necesara aprinderii ledului (in cazul nostru 5 - 3.1), rezulta ca I = (5-3.1) / 440 = 0.004 Ah, sau mai pe romaneste 4 miliamperi!
PB0,PB1,PB3,PB4 sunt pinii uC-ului, conform datasheet-ului, acestia sunt pinii 5,6,2,3. Veti observa ca am lasat liberi pinii PB2 si PB5 respectiv INT0 si RESET. Pinul INT0 il vom folosi pentru a seta ceasul (cand oi avea timp sa implementez aceasta functie), iar pinul RESET il folosim pentru programare. Retineti asta daca adaptati codul pentru alt attiny.
In primul atasament gasiti cablajul fara rezistente pentru aceasta schema (vedere dinspre leduri, chiar daca este "inversat" fata de schema).[attachment=0]cablaj leduri.png[/attachment]

Pentru alimentarea uC-ului se presupune ca folositi o sursa stabilizata de 5V.
Vom prezenta 2 programele, primul se foloseste de oscilatorul intern al uC-ului, iar pentru al 2-lea program vom incerca sa obtinem un ceas mai precis folosind un generator de semnal de 1Hz sau 2Hz. Daca sunteti norocosi le puteti gasi in ceasurile cu quartz. exemplu1, exemplu2. Daca nu sunteti norocosi veti folosi PCF8583, un circuit integrat RTC care are marele avantaj ca la pornire (fara a fi setat implicit) sa genereze un semnal de 1Hz pe pinul INT (cel putin asa reiese din datasheet sectiunea 7.11).
Acestea fiind spuse sa prezentam si niste cod. Eu personal folosesc AVR Studio 5 !

Cazul 1, folosind oscilatorul intern, pseudocod


//include headere utile

//defineste variabile (secunde,minute,ore,etc)

//functie care incrementeaza secundele pana la 59, minutele pana la 59, orele pana la 23

//functie care stinge toate ledurile

//functie care defineste ledurile folosite pentru afisarea minutelor

//functie care defineste ledurile folosite pentru afisarea orelor

//functie care aprinde ledurile pentru minute in functie de variabila "minute"

//functie care aprinde ledurile pentru ore in functie de variabila "ore"

//functie ce intrerupe bucla while(1) din main() odata la o secunda pentru a rula cod in afara buclei
//in cazul nostru va rula functia care incrementeaza secundele/minutele/orele si va aprinde un led


//prgramul propriuzis
int main(void)
{
	//seteaza chestii initiale(gen starea porturilor, interrupturi, etc)

	//bucla infinita care sa cheme functiile ce aprind ledurile pentru minute si ore
}



Si acum pentru fiecare portiune de pseudocod vom adauga cod real.

Headerele utile, in cazul de fata, ne permit accesarea unor variabile definite deja, de exemplu vom putea folosi PORTB sau PIN1 daca includem headerul io.h

//include headere utile
#define F_CPU 1000000UL //frecventa in Hz la care ruleaza uC-ul, Attiny25 vine setat din fabrica sa functioneze pe oscilatorul intern de 1Mhz
#include <util/delay.h> //necesar pentru a putea folosi _delay_ms()

#include <avr/io.h> //definitii pentru porturi
#include <avr/interrupt.h> //definitii pentru ISR-uri

Variabilele sunt ... variabile si trebuiesc definite :) Asadar ca sa putem folosi niste valori trebuie sa stim ce fel de valori sunt acestea si ce valoare au.
Declaram secundele minutele si orele de tipul "unsigned 8 bit integer", ceea ce inseamna ca pot avea valori intre 0 si 255, volatile ca sa fie "vazute" si in bucla infinita din main().
//defineste variabile (secunde,minute,ore,etc)
volatile uint8_t seconds, minutes, hours; //valorile se schimba in ISR (Interrupt Service Request), ca sa stie si bucla while(1) ca s-au schimbat trebuie sa fie VOLATILE
uint8_t overflow_counter; //o simpla variabila pe care o vom folosi sa stim de cate ori o valoare "da pe dinafara"

O functie ce incrementeaza secundele pana la 59, cand secundele ajung la 60 setam secundele = 0 si incrementam minutele cu 1, la fel pentru ore.
Aceasta functie o vom executa odata pe secunda.

//functie care incrementeaza secundele pana la 59, minutele pana la 59, orele pana la 23
void time_tick() //numele functiei
{
	seconds++; //incrementeaza secundele cu 1
	if (seconds > 59) //daca secundele sunt peste 59
	{
		seconds = 0; //reseteaza secundele
		minutes++; //si incrementeaza minutele cu 1
		if (minutes > 59)
		{
			minutes = 0;
			hours++;
			if (hours > 23)
			{
				hours = 0;
			}
		}
	}
}

Metoda prin care am legat ledurile (charlieplexing) nu ne permite sa aprindem mai mult de un led simultan, asadar inainte de a aprinde vreun led ne trebuie o functie care sa stinga toate ledurile.
Daca urmariti schema de legare a ledurilor la uC veti observa ca putem face asta in 3 feluri:
1. Setam toti pinii folositi pe OUTPUT LOW (in schema ca si cum am avea toate ledurile conectate la cate un semnal logic LOW)
2. Setam toti pinii folositi pe INPUT LOW (in schema ca si cum nici un led nu ar fi conectat la nici un fel de semnal)
3. Setam toti pinii folositi pe INPUT HIGH (in schema ca si cum toate ledurile ar fi conectate la cate un semnal logic HIGH, INSA cu rezistentele modificate la valori de gen 20KOhm-40KOhm

In loc de PB0, PB1, etc puteam folosi binemersi DDB0, DDB1, sau chiar 0 si 1 pentru ca in headerul io.h sunt definite astfel: PB0 = 0 si DDB0 = 0.
Setam intai daca portul este HIGH sau LOW si dupa aceea daca este INPUT sau OUTPUT pentru a evita o stare accidentala OUTPUT_HIGH

//functie care stinge toate ledurile
void leds_off() //functie ce seteaza (doar) pinii folositi de noi OUTPUT_LOW
{
	PORTB &= ~(1<<PB0) & ~(1<<PB1) & ~(1<<PB3) & ~(1<<PB4); //clear bit, seteaza bitii PB0, PB1, PB3, PB4 pe 0, adica LOW
	DDRB |= (1<<PB0) | (1<<PB1) | (1<<PB3) | (1<<PB4); //set bit, seteaza bitii PB0, PB1, PB3, PB4 pe 1, adica OUTPUT
}

Dupa urmatorul tabel stim exact in ce stare sa fie pinii pentru a aprinde cutarica led.
H = OUTPUT_HIGH
L = OUTPUT_LOW
X = INPUT_LOW

PB0	PB1	PB3	PB4	LED
H		L		X		X		0
L		H		X		X		1
X		H		L		X		2
X		L		H		X		3
H		X		L		X		4
L		X		H		X		5
X		X		H		L		6
X		X		L		H		7
X		H		X		L		8
X		L		X		H		9
H		X		X		L		10
L		X		X		H		11

Astfel ca sa aprindem ledul 0 trebuie sa setam o stare implicita, si anume ca nici un bec nu e aprins, si anume ca PB0,PB1,PB3,PB0 sunt OUTPUT_LOW, si anume fix ceea ce face functia leds_off();
Dupa aceea trebuie sa setam PB3 si PB4 pe INPUT.
Dupa aceea setam PB0 pe HIGH.

Daca facem invers nu prea e bine, si anume:
Setam intai PB0 pe HIGH. (rezultatul final este ca toti pinii sunt OUTPUT, 1 pin e HIGH, 3 sunt LOW, vezi pe schema de legare a ledurilor la uC ce se intampla in cazul asta.


Sa recapitulam pentru LED0
stare initiala: ledul este stins
PB0	PB1	PB3	PB4	LED
L		L		L		L		0
Setam PB3 si PB4 pe INPUT: ledul este stins
PB0	PB1	PB3	PB4	LED
L		L		X		X		0
Setam PB0 pe HIGH.: ledul se aprinde
PB0	PB1	PB3	PB4	LED
H		L		X		X		0

Pentru minute nu avem nevoie decat de definitiile ledurilor de la 0 la 5. Vezi cablajul cu leduri.

//functie care defineste ledurile folosite pentru afisarea minutelor
void minute_leds(uint8_t led) //functie ce are ca argument variabila led, se cheama ca minute_leds(led); unde led trebuie sa fie o valoare de la 0 la 5
{
	//inainte sa aprindem vreun led le stingem pe toate
	leds_off();
	
	switch(led) //in functie de valoarea variabilei "led" va executa codul respectiv
	{
		case 0: //setari pentru led 0
		DDRB &= ~(1<<PB3) & ~(1<<PB4); //clear bit, seteaza PB3, PB4 pe 0, adica INPUT
		PORTB |= (1<<PB0); //set bit, seteaza PB0 pe 1, adica HIGH
		break;
		case 1:
		DDRB &= ~(1<<PB3) & ~(1<<PB4); //etc :)
		PORTB |= (1<<PB1);
		break;
		case 2:
		DDRB &= ~(1<<PB0) & ~(1<<PB4);
		PORTB |= (1<<PB1);
		break;
		case 3:
		DDRB &= ~(1<<PB0) & ~(1<<PB4);
		PORTB |= (1<<PB3);
		break;
		case 4:
		DDRB &= ~(1<<PB1) & ~(1<<PB4);
		PORTB |= (1<<PB0);
		break;
		case 5:
		DDRB &= ~(1<<PB1) & ~(1<<PB4);
		PORTB |= (1<<PB3);
		break;
		default: //in cazul in care "led" nu este intre 0 si 5 aceasta functie nu va face nimic
		break;
	}
}

Functia pentru ore este identica insa trebuie luat aminte ca aceasta tine valorile pentru ledurile de la 6 la 11 !
Imediat voi explica de ce avem 2 functii ce tin setarile de la 0 la 5 fiecare in loc de o functie cu setari de la 0 la 11.

//functie care defineste ledurile folosite pentru afisarea orelor
void hour_leds(uint8_t led)
{
	leds_off();
	
	switch(led)
	{
		case 0: //ATENTIE, setari pentru led 6
		DDRB &= ~(1<<PB0) & ~(1<<PB1);
		PORTB |= (1<<PB3);
		break;
		case 1: //led 8
		DDRB &= ~(1<<PB0) & ~(1<<PB1);
		PORTB |= (1<<PB4);
		break;
		case 2: //etc
		DDRB &= ~(1<<PB0) & ~(1<<PB3);
		PORTB |= (1<<PB1);
		break;
		case 3:
		DDRB &= ~(1<<PB0) & ~(1<<PB3);
		PORTB |= (1<<PB4);
		break;
		case 4:
		DDRB &= ~(1<<PB1) & ~(1<<PB3);
		PORTB |= (1<<PB0);
		break;
		case 5:
		DDRB &= ~(1<<PB1) & ~(1<<PB3);
		PORTB |= (1<<PB4);
		break;
		default: //in cazul in care "led" nu este intre 0 si 5 aceasta functie nu va face nimic
		break;
	}
}

Motivul pentru care avem 2 functii ca cele de mai sus este simplu si voi incerca sa-l explic si eu cat se poate de simplu.

Avem 12 leduri, 6 sus, 6 jos.
Pe cele 6 de sus vrem sa afisam orele. (Ignoram momentan ledul pentru secunde)
Pe cele 6 de jos vrem sa afisam minutele.

Vom trata cele 6 leduri ca pe 6 biti, cu 6 biti poti numara pana la 63, in binar 111111.
Minutele pot fi maxim 59, ceea ce in binar inseamna 111011.

Asadar pentru a aprinde ledurile ce reprezinta 59 vrem sa putem zice:

minute_leds(0); //stinge toate ledurile si dupa aprinde led 0.
minute_leds(1);
minute_leds(3);
minute_leds(4);
minute_leds(5);

La fel si pentru ore.
Sa incercam sa aprindem ledurile pentru orele 23, in binar 10111. (dupa cum vedeti maximul pentru ore se poate reprezenta si in 5 biti, chiar daca noi avem definita functia pentru 6 biti)

hour_leds(0);
hour_leds(1);
hour_leds(2);
hour_leds(4);

Avand 2 functii separate de cate 6 leduri fiecare ne este foarte usor sa identificam cei 6 biti cu cele 6 leduri.

Mai departe avem doua functii ce verifica, pentru fiecare din cei 6 biti, daca bitul respectiv este 1 sau nu (sa stim daca-l aprindem sau nu).
Pentru minutes = 59, in binar 111011, functia minutes_led_on(59); ne va spune ca bitul 0 este 1, bitul 1 este 1, bitul 3 este 1, bitul 4 este 1 si bitul 5 este 1.
In functie de acesti biti care au valoarea 1 noi vom putea sa chemam functia minute_leds(led); si ca argument led o sa fie acesti biti.

//functie care aprinde ledurile pentru minute in functie de variabila "minute"
void minutes_led_on(uint8_t minute) //exemplu: pentru minutes = 59 (0b111011), minutes_led_on(59); va aprinde ledurile 0,1,3,4,5 (numaratoarea incepe de la 0 de la dreapta la stanga)
{
	for (int i=0; i<6; i++) //pentru fiecare bit in parte din cei 6 (de la 0 la 5)
	{
		if (minute & (1<<i)) //check bit si vezi daca e 1
		{
			minute_leds(i); //aprinde led-ul ce tine de bitul respectiv
		}
	}
}
//functie care aprinde ledurile pentru ore in functie de variabila "ore"
void hours_led_on(uint8_t hour) //exemplu: pentru hours = 23 (0b010111), hours_led_on(23); va aprinde ledurile 0,1,2,4 (numaratoarea incepe de la 0 de la dreapta la stanga)
{
	for (int i=0; i<6; i++) //pentru fiecare bit in parte din cei 6 (de la 0 la 5)
	{
		if (hour & (1<<i)) //check bit si vezi daca e 1
		{
			hour_leds(i); //aprinde led-ul ce tine de bitul respectiv
		}
	}
}

Acest interrupt bazat pe timer, intervine in program, ii pune pauza la executie, executa un cod anume, revine la executia programului.
In cazul nostru programul este bucla infinita while(1) ce ne clipoceste la nesfarsit ledurile in functie de variabilele "minutes" si "hours".
Attiny25 are 2 timere de 8 biti, vom folosi 1 singur timer, iar cand acesta va "da pe dinafara" (overflow) se va cere un interrupt.
Viteza cu care acest timer "da pe dinafara" este setata si explicata in main().

//functie ce intrerupe bucla while(1) din main() odata la o secunda pentru a rula cod in afara buclei
//in cazul nostru va rula functia care incrementeaza secundele/minutele/orele si va aprinde un led
ISR(TIM0_OVF_vect) //atunci cand timerul ajunge la 256 (la overflow)
{
	if(++overflow_counter > 61) //daca a ajuns la overflow de 62 de ori
	{
		hours_led_on(32); //aprinde ledul pentru ora 32, in binar 100000, adica va aprinde ledul de secunde! :)
		overflow_counter = 0; //reseteaza counterul
		time_tick(); //incrementeaza secundele, etc
	}
}

Programul propriuzis ce este executat la initializarea uC-ului.
timer0 interrupt ruleaza la frecventa uC-ului, adica la 1Mhz pentru attiny25, insa il putem micsora (pentru a-l imparti mai usor la 256) cu ajutorul prescalerului.
Avem astfel 1000000/64 = frecventa la care ruleaza timer0 pe care daca o impartim la 256 aflam de cate ori trebuie sa ajunga la overflow timer0 pentru a contoriza o secunda.
1000000/64/256=61.03 (valoarea de trecut in ISR-ul de mai sus), daca nu am fi folosit prescaler overflow_counter ar trebui sa fie mai mare de 3906.25 pentru a contoriza o secunda.

int main(void)
{
	//seteaza chestii initiale(gen starea porturilor, interrupturi, etc)

	//seteaza toti pinii ca OUTPUT_LOW
	PORTB = 0b000000;
	DDRB = 0b111111;
	
	//timer0 interrupt
	TCCR0B |= (1<<CS00) | (1<<CS01); // seteaza prescaler la clock/64
	TIMSK |= 1<<TOIE0; //seteaza interrupt atunci cand timer0 ajunge la overflow
	sei(); //activeaza sistemul de interrupts
	
    while(1) //coloana lui Brancusi
    {
		minutes_led_on(minutes);
		leds_off();
		hours_led_on(hours);
		leds_off();
    }
}

Pai ... cam asta e tot momentan, voi pune cand am timp si imbunatatirile, anume cum sa functioneze cu un semnal de 1Hz si cum sa-l setam. :sparge:
De asemenea orice tras de urechi/imbunatarile/sugestie este binevenita.

#10 OFFLINE   DJ_Speedy

DJ_Speedy

    Membru

  • Membri
  • PipPip
  • 197 posts

Posted 19 July 2011 - 04:25 AM

:multumesc

Sa-mi pice fata, nu alta. Mai repede inteleg codul tau intins pe 3 pagini decat alea 3 linii de cod folosite sa aprinzi 1 led din orice "tutorial" de pe net.

:aplauze

#11 OFFLINE   maciupiciu

maciupiciu

    Nou venit

  • Membri
  • Pip
  • 58 posts

Posted 20 October 2011 - 10:50 PM

Tiny AVR , merita aruncat un ochi !

http://www.fileshare.ro/31648965322.3

#12 OFFLINE   ole

ole

    Membru

  • Membri
  • PipPip
  • 341 posts

Posted 21 October 2011 - 02:40 PM

Hai ca sparg eu gheata dupa un an, motivat fiind de faptul ca n-am gasit pe acest forum bucati de cod explicate "ca la gradinita".

Va salut, incepator fiind propun altor incepatori un ceas binar cu afisaj pe 12 leduri...



Sa zicem ca fiind un proiect conceput de tine si neavand o pagina web pe care sa-l postezi se accepta astfel de posturi, desi tot textul ala putea fi scris intr-un txt si pus intr-o arhiva impreuna cu sursele si schema si urcata pe un site, iar apoi postat doar link-ul si descrierea. In felul acesta, cine doreste sa-si aleaga un proiect poate usor sa citeasca descriere dupa descriere, sa parcurga proiectele listate in scurt timp si sa se opreasca doar asupra celor care prezinta interes, accesand link-ul postat.

#13 OFFLINE   mincior

mincior

    Nou venit

  • Membri
  • Pip
  • 11 posts

Posted 03 December 2012 - 10:59 PM

Un tutorial pas cu pas pentru pre-incepatori in ale microcontrolerelor Atmel, adica cei care n-au programat niciodata un ATTiny13 folosind Algorithm Builder. De fapt sunt mai multe articole la sfarsitul carora un incepator isi construieste singur un programator, o placa de test si face un program pentru o lumina dinamica cu 5 canale folosind cel mai simplu microcontroler de la Atmel: ATTiny13.
http://electroni-city.com

#14 OFFLINE   unuldinei

unuldinei

    Membru

  • Membri
  • PipPip
  • 402 posts
  • Locatie:Bucuresti 5

Posted 26 December 2013 - 06:11 PM

foarte simpatic e montajul asta http://elm-chan.org/...mxb/report.html

numai ca nu reusesc sa folosesc scripturile de pearl ca sa pun si alte melodii...

Sarbatori fericite!

Cu_reclama

Cu_reclama
  • Membri

#15 OFFLINE   radu_bc

radu_bc

    Incepator

  • Membri
  • Pip
  • 83 posts
  • Locatie:Bacau

Posted 06 January 2014 - 04:15 PM

Asta ar mai fi ceva interesant...
http://www.gotronik.... ... rd_de.html




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users