Jump to content
Sign in to follow this  
dan_e

Despre programarea microcontrolere Atmel AVR - intrebari si raspunsuri

Recommended Posts

ok, mersi, am rezolvat-o.

Mai am o intrebare, cum pot memora valoarea unei variabile (spre exemplu, tip float) astfel incat dupa ce tai alimentarea unui microcontroler, dupa ce il alimentez din nou acesta sa stie care a fost ultima valoarea a acelei variabile ?

Share this post


Link to post
Share on other sites

scrii in EEprom, si dupa reset citesti valoare din EEprom.

 

RR

Share this post


Link to post
Share on other sites

Am revenit cu o alta problema. De ceva timp incerc sa aflu si eu care e treaba cu timerele. Am invatat cum sa le declar dar am incercat sa generez un semnal dreptunghiular de 5Hz si nu prea imi iese. Timer-ul l-am setat asa:

//Timer0 Prescaler = 0; Preload = 8; Actual Interrupt Time = 1 us

void InitTimer0(){
 SREG_I_bit = 1;
 OCR0A = 8;
 TCCR0A = 0x82;
 TCCR0B |= 0x81;
 OCIE0A_bit = 1;
}

void Timer0Overflow_ISR() org IVT_ADDR_TIMER0_COMPA {
   // codul meu dar nu stiu cum sa-l scriu
}

 

La 5Hz, perioada rezulta: T = 1/f = 0,2 secunde = 200000 microsecunde.

Deci, semnalul trebuie sa basculeze 100000 us in 0 logic, 100000 in 1 logic, dar nu stiu cum sa scriu asta in C ?

roadrunner, imi dai o mana de ajutor. Please. :cheers:

 

stima

dan

Share this post


Link to post
Share on other sites

Dan,

 

se poate face in doua feluri cu comparatorul si automatic reload (care odata programat nu depinde de intreruperi) si modul 2 cu intrerupere de overflow.

 

modul 1.

Avantaje: odata programat genereaza semnal pe un pin fara sa mai consume resurse CPU (nu mai trebuie deservit de nici o intrerupere)

Dezavantaj: pinul (sau pinii) care fac toggle sunt pini dedicati si trebuie alesi cu grija, sunt pini care depind de timerul ales, si de unitatea de comparare (A,B)

 

Pentru metoda asta ai de programat 4 lucruri.

1. Pinul ales il programezi ca iesire

2. Programezi valoarea de comparare a timerului (asta iti va da semiperioada semnalului generat)

3. programezi timerul sa functioneze in modul respectiv (aici sunt doi registrii, unul care programeaza modul de functionare iar al doilea prescalerul timerului)

 

un exemplu pentru timerul 0 unitatea de comparare A - clock-ul timerului = clock-ul mcu pentru attiny84 (daca ai alt mcu vezi pe ce pin ai OC0A)

 

DDRB = (1 <<PB2) ; /* pinul PB2 - corespunde cu OC0A */
/* set timer 0 to generate 40KHz */
TCCR0A = (0 <<COM0A1) | (1 << COM0A0) |(0 <<COM0B1) | (1 << COM0B0) | (1<< WGM01) | (0<< WGM00); /* this should toggle OCR0A pin with 40KHz */
OCR0A = 98; /* ocr value for 40KHz @ 8M Clk*/
TCCR0B = (0 << WGM02) | (0 <<CS02)|(0 << CS01)|(1 << CS00); /* timer takes 8M clock */

 

cum functioneza codul de mai sus:

timerul numara de la zero in sus, cand valoarea din el devine egala cu OCR0A, face toggle la pinul OCR0A (toggle insemana ca-l inverseaza fata de cum a fost) si se reseteaza, dupa care incepe iar sa numere de la zero in sus.

Pentru a avea o perioada completa pe pinul de toggle e nevoie sa numere doua cicluri ( deci valoarea OCR0A este o semiperioada a semalului de iesire)

intrebare de ce am pus 98 in OCR0A si nu 100? pentru ca 8Mhz / (100 +100) = 40KHz (cat mi-am dorit eu sa obtin cu exemplul) - raspuns pentru ca se pierd doua perioade de ceas la fiecare ciclu de numarare, una cu compararea si a doua cu resetarea) deci copari cu 98 dar de fapt ciclul va fi de 100 perioade de clock.

 

legat de codul tau (plecand de la ideea ca ai programat timerul corect)

 

in rutina de intrerupere trebuie sa mentii un counter static (static insemna ca nu se reseteaza de cate ori ajunge executia acolo, sau mai poetic spus, counterul traieste in rutina aia)

 

 

SIGNAL(SIG_OUTPUT_COMPARE0A){
{
static unsigned char num=0;
num++;
if (num > 200){
	 // faci toggle la un pin *******************
num=0;
}
}

 

descriere : counterul num, contorizeaza de cate ori ai ajuns in rutina de intrerupere, la 200 de cicluri face ceva (de exemplu toggle la un pin) si reseteaza counterul.

 

RR

Edited by roadrunner

Share this post


Link to post
Share on other sites

mersi dar deja imi fac ochii in cap... nu stiu cum sa-ti spun. :cursing:

Programu meu as vrea sa-l fac ceva mult mai complex.

Adica, vreau sa generez trei tipuri de frecvente: 5Hz, 500Hz, 5kHz timp de 60 de secunde. Deci, trebuie cumva sa folosesc doua timere ? Testul ma gandesc sa-l fac pe un microcontroler Atmega8 iar daca soft-ul nu ocupa prea mult spatiu, poate reusesc sa-l mut intr-un uC mai mic. Dar asta vad eu pe urma.

 

Deci, :ewpu: care din cele doua metode de mai sus, pe care le-ai descris, crezi ca ocupa mai putin flash, sunt mai usoare, ca sa fac programul asta ? Imi poti prezenta o ciorna de program ? please.

 

stima

dan

Edited by dan_e

Share this post


Link to post
Share on other sites

eu le-as numii 3 frecvente (nu am inteles de unde vine "tipuri")

trebuie generate toate trei concomitent sau pe rand?

RR

Share this post


Link to post
Share on other sites

Nu concomitent. Deci, am un comutator pe un canal adc, care:

- daca tensiunea este sub 1.25V atunci f = 5kHz;

- daca tensiunea este intre 1.25 si 3V atunci f = 500Hz;

- daca tensiunea este mai mare de 3V atunci f = 5Hz.

 

Dupa aceea urmeaza niste instructiuni if de genul (adc este - unsigned int - citesc valoarea ADC):

   if(adc>=600 && adc<=1023) { f = 5; } // f = 5Hz
  if(adc>=399 && adc<=599) { f = 500; } // f = 500Hz
  if(adc>=1 && adc<=398) { f = 5000; } // f = 5000Hz

 

Dupa acea am inclus un buton start (la pinul PD2) pe care, dupa ce il apas, pe iesirea PB3 de la atmega8 se genereaza, in functie de tensiunea pe pinul PC0, una din cele trei frecvente de mai sus.

 

Ma gandesc sa folosesc pinul PC1 ca sa creez doua intervale de timp, de 60secunde si 120 secunde, dar asta dupa ce fac versiunea simpla a programului.

 

M-am blocat la partea cu timere.

Share this post


Link to post
Share on other sites

pai incepusei bine, programeaza un timer sa genereze o intrerupere de comparare la fiecare 100 uS,

mentii un counter static in rutina de intrerupere, iar pentru

5Hz compari counterul cu val 10Khz/5Hz = 2000

500Hz compari cu 10KHz / 500Hz = 20

5KHz compari cu 10KHz/5Khz =2

 

deci schimband val variabilei frecv in rutina de mai jos ( 2000, 20, 2) obtii cele trei frecvente pe pinul dorit. (e posibil sa fie nevoie sa le faci 1000,10,1 din cauza ca vei face toggle la pin si pentru o perioada a semnalului generat e nevoie de doua schimbari semiperioade)

 

 

SIGNAL(SIG_OUTPUT_COMPARE0A){
{
static unsigned int num=0;
num++;
if (num > frecv){
			 // faci toggle la un pin *******************
num=0;
}
}

 

iar pentru temporizarea de 60 se sec foseste functia delay, si opreste timerul dupa 60 secunde.

RR

Edited by roadrunner

Share this post


Link to post
Share on other sites

@dan_e,

O sa corectez exemplu dat de tine in mesajul #155 de mai sus ca sa vezi mai exact cum stau lucrurile.

 

Pasul 1 - se initializeaza timerul (am folosit un exemplu tipic pentru microcontrolere atmega):

void InitTimer0(){
 SREG_I_bit = 1;
 OCR0 = 124;
 TCCR0 = 0x28;
 TCCR0 |= 0x03;
 OCIE0_bit = 1;
}

 

Pasul 2 - Avand in vedere faptul ca unele microcontrolere Atmel au timere pe 8 biti, altele pe 16biti si tinand cont de faptul ca timerul pe 8 biti este cel mai intalnit, asta inseamna ca in codul de mai jos timerul de 8 biti va returna o intrerupere cand va termina de numarat de la 0 ... 255. Bineinteles ca putem forta codul sa returneze intreruperea la mai putin de 255 (asta voi evidentia mai jos). Apoi, spuneai mai sus ca ai configurat timerul la 1ms (lucru facut si de mine la pasul 1 de mai sus), deci fiecare intrerupere a timerului inseamna 1ms. Spre exemplu, daca vrei sa generezi 5Hz, acest lucru inseamna 1/f = 0,2secunde, iar jumatate de perioada inseamna 0,1secunde. Avand in vedere faptul ca 0,1 secunde = 100ms, asta inseamna ca va trebui sa lasam timerul sa numere pana la 100 si apoi sa-l resetam. Intre timp, vorba lui @roadrunner, va trebui sa faci "toggle la un pin" (mai pe intelesul tuturor, adica schimbi starea din 1 logic in 0 logic si viceversa, de fiecare data cand timerul numara pana la 100). Cum facem asta, relativ simplu (vedeti exemplul de mai jos - unde am considerat ca iesire pinul PB3):

Timer0Overflow_ISR() org IVT_ADDR_TIMER0_COMP {
 if (counter >= time) {
   PORTB3_bit = ~PORTB3_bit;
   counter = 0;			    // resetez counter
 }
 else
   counter++;				  // incrementez counter
}

 

Pasul 3 - Acum va trebui sa scriem codul complet a programului. Pentru inceput va trebui sa declaram variabila "time" (unde vom completa valoarea in milisecunde (1/2)T). Asadar:

const char time = 100;
char counter;

void InitTimer0(){
 SREG_I_bit = 1;
 OCR0 = 124;
 TCCR0 = 0x28;
 TCCR0 |= 0x03;
 OCIE0_bit = 1;
}

Timer0Overflow_ISR() org IVT_ADDR_TIMER0_COMP {
 if (counter >= time) {
   PORTB3_bit = ~PORTB3_bit;
   counter = 0;			    // resetez counter
 }
 else
   counter++;				  // incrementez counter
}

void main() {

 DDRB   =  0xFF;		    // setez PORTB ca iesire
 PORTB  =  0;				 // clear PORTB

 InitTimer0();

 while (1);				   
}

 

Deci, codul de mai sus genereaza la pinul PB3 a unui microcontroler atmega o frecventa rectangulara de 5Hz. Retine ca, asa cum este configurat timer-ul de mai sus, avem un domeniu de frecvente pe care le putem reproduce - nu am calculat acum dar parmise cel mult 1kHz). Spre exemplu, daca la inceputul codului de mai sus modificam:

time = 100;

in

time = 10;

vom obtine 50Hz s.a.m.d.

Daca vei configura timerul la 1us, atunci e bine sa te orientezi catre un microcontroler care are timer pe 16biti pentru a mari si mai mult domeniu de frecvente reprodus la iesire. Bineinteles ca se poate apela la un artificiu utilizand un timer tot pe 8 biti dar asta e alta "poveste".

 

Numai bine

si sper sa-ti fie util exemplul pe care l-am dat mai sus.

Share this post


Link to post
Share on other sites

Mda... chiar mi-a fost de folos.

Acum as vrea sa trec exemplu de mai sus in Atmel Studio si nu stiu cum sa fac asta?

Si ar vrea sa generez 5Hz numai 60 secunde (pentru inceput, ca dupa aia complic eu programul, dar sa inteleg cat de cat baza programului). Ma ajuta cineva?

Share this post


Link to post
Share on other sites

Ca sa opresti timer-ul 0 (configurat pentru generarea frecventei de 5Hz) dupa 60 de secunde, va trebui sa folosesti Timer-ul 1 (spre exemplu, configurat la 100ms):

void InitTimer1(){
SREG_I_bit = 1;
TCCR1A = 0x80;
TCCR1B = 0x0B;
OCR1AH = 0x30;
OCR1AL = 0xD3;
OCIE1A_bit = 1;
}

Mai sus am postat un exemplu tipic pentru un microcontroler Atmega care are in componenta doua timere.

 

Dupa aceea, configurezi "intreruperea" asa:

void Timer1Overflow_ISR() org IVT_ADDR_TIMER1_COMPA {
if (cnt >= 600)
		 {			
			OCIE0_bit = 0;	 // opreste timer0
		 OCIE1A_bit = 0; // opreste timer1
			PORTB3_bit = 0; // iesire in 0 logic
			cnt = 0;				// resetez counter
		 }
else		
cnt++;								// incrementez counter
}

 

Deci, la codul de mai sus, trebuie sa adaugi ceea ce am scris mai sus, si bineinteles, in bucla main sa adaugi

InitTimer1();

iar variabila cnt va fi declarata la fel ca cea counter de mai sus.

 

Referitor la trecerea codului scris mai sus din mikroC in Atmel Studio, cred ca e o complicatie inutila. Dar daca esti hotarat sa faci asta, atunci iti recomand sa rasfoiesti tutorialul de aici:

http://www.avrfreaks...ewtopic&t=50106

respectiv:

http://www.atmel.com...ges/doc2505.pdf

 

Numai bine

Share this post


Link to post
Share on other sites

Vreau sa-mi fac o placa de dezvoltare pentru un ATmega8 si am cateva intrebari:

  • Ce schema de programator cu port serial imi recomandati?
  • Am un display de Nokia 5110 pe care vreau sa-l conectez cu ATmega8 si nu stiu cum. Am gasit asta si vreu sa stiu daca e bine, pentru ca am gasit si alte variante:

post-17100-0-65943000-1388061426_thumb.jpg

Share this post


Link to post
Share on other sites

Nu recomand niciun programator cu port serial, recomand USBasp.

Nu am interfatat display-uri de acel gen, dar sunt o gramada de exemple pe net, cauta eventual o schema la care gasesti si codul.

Avand in vedere ca folosesti cristal de 16 Mhz: vrei sa faci clona de Arduino?

Share this post


Link to post
Share on other sites

Am atasat codul de interfata a gLCD Nokia 5110 mai jos:

LCD5110.rar

Dupa ce dezarhivati fisierul, in functie de compilatorul folosit, va trebui sa atasati fisierul de mai sus in header-ul programului, care va avea structural forma urmatoare:

#include "LCD5110.h"
// alte constante sau variabile definite

void main() {
LCDInit(); //Init the GLCD

// bucla main

do {
// program
}while(1);

}

 

EDITARE ULTERIOARA: Pentru programarea Atmega8 puteti folosi PonyProg pe portul serial sau o solutie de genul asta:

http://www.ebay.com/itm/USB-ISP-Programmer-For-ATMEL-AVR-ATMega-ATTiny-51-Development-Board-New-/390641137707?pt=AU_B_I_Electrical_Test_Equipment&hash=item5af406b82b

 

Numai bine

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...

Important Information

We use cookies and related technologies to improve your experience on this website to give you personalized content and ads, and to analyze the traffic and audience of your website. Before continuing to browse www.tehnium-azi.ro, please agree to: Terms of Use.