Posts: 556
Threads: 11
Joined: Apr 2014
Reputation:
150
03-30-2018, 03:55 PM
(This post was last modified: 03-30-2018, 03:59 PM by Milan94.)
Pokusacu ja da objasnim algoritam kako bi to trebao da izvedes osvezavanje led displeja.
Tajmer podesis da pravi interrupt na 1ms. Prekid na 1s je mnogo sporo za osvezavanje displeja.
E sad u interrup rutini napises sledece:
Interrupt Ovf0(), Save 1
Pr = Pr + 1 ; neka promenljiva koja se uvecava svakim ulaskom u interrup rutini
IF Pr > 2 Then Pr = 0 ; ako je promenljiva veca od 2 vrati promenljivu na 0
Reset PORTB.0 ' turn off all segments
Reset PORTB.1
Reset PORTB.2
IF Pr = 0 Then
PORTD = segment_number((number mod 1000) / 100)
Set PORTB.0 ; Ukljuci prvu cifru
Endif
IF Pr = 1 Then
PORTD = segment_number((number mod 100) / 10)
Set PORTB.1 ; Ukljuci drugu cifru
Endif
IF Pr = 2 Then
PORTD = segment_number((number mod 10))
Set PORTB.2 ; Ukljuci trecu cifru
Endif
End Interrupt
Ovako bi trebalo da izgleda interap rutina u kojoj osvezavas displej.
Ne programiram AVR mikrokontrolere proveri da li ce tvoj kompajler da prihvati ovaj kod.
Posts: 8.740
Threads: 138
Joined: Apr 2013
Reputation:
3.629
03-30-2018, 04:23 PM
(This post was last modified: 03-30-2018, 04:38 PM by mikikg.)
^ Ovo je samo za selekt linije od pojedinacnih digita, isto tu treba dodati i postavljanje pojedinacnih segmenata dp, a, b, c ...
Pored toga vam treba tablica za dekodiranje karaktera, u mom primeru ima uradjeno sa switch/case + macro za vecinu karaktera (lako se dodaju ostali koji fale) i to sve da bude u interapt rutini koja kopira sadrzaj jednog 3-clanog niza/array (ili 4,5 koliko cifara ima) na displej prema switch/case pravilima. U main() se taj niz/array popunjava sa potrebnim vrednostima.
Ako se napisu macro-i sa low-level funcijama onda je tako kompajlirana ISR rutina izuzetno brza, zauzima malo vise programske memorije ali radi vrlo brzo, takav ISR vrlo malo zauzima procesorskog vremena. Posto smo to osvezavanje "resili" i ne zauzima bitno vremena, slobodno u isti ISR moze da se doda jos 4,8,16 komada (8/16/32/64bit po potrebi) software tajmera koji mogu da se koriste u programu za razne potrebe. Baza 1ms (1kHz), sve se lepo slozi ...
Posts: 1.244
Threads: 10
Joined: Apr 2015
Reputation:
509
Milane,
kod ti nije bas dobas. Trenutno sam u guzvi. Napisacu veceras program sa objasnjenjima.
Posts: 2.475
Threads: 84
Joined: Feb 2013
Reputation:
1.438
$Device = m168 ' used device
$Stack = 32 ' stack depth
$Clock = 12 ' used crystal
$Timer0 = Timer, Prescale = 256 ' use timer0
Declare Interrupt Ovf0() ' timer0 interrupt
Dim Counter As Byte ' define counter
Dim i As Integer ' define i number counter
Dim segment_number(9) As Byte ' define segment_number
segment_number = (&h3F, &h06, &h5B, &h4F, &h66, &h6D, &h7D, &h07, &h7F, &h6F)
DDRB = &h07 ' display select pins output
DDRD = &hFF ' segment display output
Enable Interrupts ' enable global interrupts
Enable Timer0
Start Timer0 ' start timer0
Do ' main loop
For i=0 To 480 ' increase segment number
WaitMs 50
Next i
Loop
Interrupt Ovf0(), Save 1
Timer0=&hd12f ' 1ms interrupt
Counter = Counter + 1 ' increase counter
If Counter > 2 Then ' reset counter
Counter = 0
End If
Reset PORTB.0 ' turn off all segments
Reset PORTB.1
Reset PORTB.2
Select Case Counter '
Case 0
PORTD = segment_number((128 mod 1000) / 100) ' display first digit
Set PORTB.0 ' turn on first segment
Case 1
PORTD = segment_number((i mod 100) / 10) ' display second digit
Set PORTB.1 ' turn on second segment
Case 2
PORTD = segment_number((i mod 10)) ' display third digit
Set PORTB.2 ' turn on third segment
End Select
End Interrupt
Stavio sam kod prema gore navedenim primjeru i u proteusus display je stalno prazan nista se ne dogadja...timer0 je podeseni na 1000uS tj 1mS ali simulacija ne radi sa ovim kodom...mora da sam negdje pogrijesio sa timerom....
SAMO-BANOVAN OD 01.11.2024
Posts: 8.740
Threads: 138
Joined: Apr 2013
Reputation:
3.629
03-30-2018, 08:07 PM
(This post was last modified: 03-30-2018, 08:22 PM by mikikg.)
Ova shema sa pocetka teme:
http://forum.yu3ma.net/attachment.php?aid=26311
moze da radi dobro bez problema stim sto ima jedna "koska" koja ce vas naterati da drugacije napisete program koji pak ne moze na drugim mestima/MCU da se iskoristi tek tako.
Problem je u portu, u shemi je iskoriscen tacno/kompletno jedan 8bit PORT-D koji vozi segmente, to je sve u redu i slaze se posto u programu mozemo da upisemo jedan 8bit podatak kad god hocemo i da ta operacija ne pravi nikakvih problema. Tako se onda uradi program i sve ok ...
Medjutim, ako se bilo kojim slucajem segmenti ne nalaze kompletno na jednom celom portu sto moze u vecini slucajeva da se dogodi nego na primer pola na PORTA, pola na PORTB, selekti mesani sa B i C, ili recimo port nije vise samo 8bit velicine (shirine) nego 16 ili 32bit kao na drugim kontrolerima, ovaj predhodno spomenuti program vise ne moze nikako da radi i moze da napravi ozbiljne probleme koje pocetnici jako tesko mogu da odklone ako se neke stvari ne postave na svoje mesto a to je da u interaptu NEMA read-modify-write operacija nad portovima jer moze prouzrokovati raise-condition i napravi kompletan zaglup, umesto toga se koristi samo operacije u jednom smeru, samo se pise na PORTx i to bit-po-bit (nozica po nozica). Tu se iskoriste low-level operacije za pisanje i to je efektan nacin da se taj konkretan programski zadatak odradi. Zato treba tablica, zato switch/case, makro ...
PS: Ne radim aktivno sa ATMega, ne znam da li moze da se upise jedan bit na port bez read-modify-write? Ako to ne moze, ovo moje pisanije onda ne vazi za njega, to je za ARM ...
Posts: 1.157
Threads: 27
Joined: Oct 2014
Reputation:
313
03-30-2018, 08:25 PM
(This post was last modified: 03-30-2018, 08:27 PM by gorankg.)
Blizu si što se tiče koda.
50ms za uvećavanje broja u glavnoj petlji je suviše brzo. Promenljivu i uvećavaj na 1 sekundu, recimo.
Ovde imaš grešku:
Case 0
PORTD = segment_number((128 mod 1000) / 100) ' display first digit
Treba da bude kao i za druge cifre:
Case 0
PORTD = segment_number((i mod 1000) / 100) ' display first digit
Posts: 1.244
Threads: 10
Joined: Apr 2015
Reputation:
509
03-30-2018, 09:52 PM
(This post was last modified: 03-30-2018, 10:20 PM by vojinilic.)
Evo kao sto sam obecao, napisacu program kako bi ovo trebalo da radi. Program mogu da pisem u C-u ili ASM-u. Basic, ne znam.
1- elektricna sema - zasto ne radi simulacija kada se pravilno postave NPN ili PNP tranzistori, ne znam. Ocigledno je nesto do simulacije. Najjednostavniji primer je da se postavi tranzistor na proto plocicu i da se proba logika sa LE-diodom.2
2 - Prilikom pisanja programa za mux LED displeja mora se izuztno voditi racuna o samoj semi pogona zajednicke katode (u ovom slucaju. Prica se samo inveruje za zajednicku anodu). Sa seme se moze videti da su select linije displeja rasporedjene na sledeci nacin:
Cifra 1 - PORTB.0
Cifra 2 - PORTB.1
Cifra 3 - PORTB.2
Ovakav redosled nam govori da se u mux rezimu rada samo vrsi prebacivanje sa jedne da drugu, po klasicnom kruznom fazonu. Znaci, prvo PB0, pa PB1, pa PB2 i tako u krug. Posto je takva sema veze, onda nam ne trebaju ti silni IF-ovi koji ce da produzavaju vreme izvrsavanja programa.
3- Pri radu sa 7-seg sisplejima je neophodno napraviti look-up tabelu, gde su definisani svi kodovi cifara koji mogu da se prikazu na displeju (Miki je to vec rekao, samo ponavljam). U visim programskim jezicima je to obican niz. Program i interaptu tajmera bi trebao ovako da izgleda (ovo je program koji je pokazni, nije kompajliran i treba ga prilagoditi konkretnim potrebama i MCU-u):
Code: unsigned char Cifra = 1; // Promenljiva koja govori koja se trenutno cifra prikazuje. Vrednost 1 kaze da se trenutno prikazuje prva cifra
unsigned char Digits[4];
#define Digit1 Digits[0];
#define Digit2 Digits[1];
#define Digit3 Digits[3];
unsigned Tabela7segCifara[10] = ... // Ovde treba ubaciti za svaku prikazanu cifru kod koji se salje displeju
void TMR_ISR(void)
{
// Prvo treba uraditi reload TMR-a, ako nije auto-reload
PORTD = 0x00;
PORTB &= 0b11111000; // Isklkjuci selekcije sve tri cifre
PORTB |= Cifra; // Slekcija zeljene cifre
PORTD = Digits[Cifra]; // Prikaz cifre na dipleju
if((Cifra <<= 0x01) > 0x04) // Predji na sledecu cifru
{Cifra = 0x01;}
}
// U main-u bi bilo sledece:
void main(void)
{
// inicijalizacija svega se podrazumeva
while(1)
{
Broj = 0;
Digit1 = ((Broj % 1000) / 100);
Digit2 = ((Broj % 100) / 10);
Digit3 = (Broj % 10);
Pauza(1s); // Pauza od 1s za prikaz inkrementa prikazanog broja
Broj++;
}
}
Ovde nisam pisao nikakve inicijalizacije TMR-ova i interapra, vec samo logiku, kako optimalno napisati program koji ce da prikazuje u MUX rezimu cifre na displeju.
Posts: 1.244
Threads: 10
Joined: Apr 2015
Reputation:
509
Obavezno obratite paznju na velicinu programa u interaptu koji radi celu logiku. Fora je i u definisanju promenljivih.
Posts: 1.966
Threads: 29
Joined: Jan 2015
Reputation:
669
03-31-2018, 08:31 AM
(This post was last modified: 03-31-2018, 08:52 AM by Želja.)
Upravo tako Vojine,
Evo dela koda iz PBP koji sam radio za 3 cifre 7 segmentnih displeja + 7 LED dioda ( sve iz multipleksa ).
Logika je sledeća:
U interaptu samo minimalni deo koda koji u krug pali svaki displej i postavlja UNAPRED pripremljenu masku te cifre.
Maska za cifru se radi VAN INTERAPTA i to samo kada se menja promeljiva (Brojač) pozivom potprograma "PRIPREMA"
Dakle u interaptu samo selekt odredjenog displeja i slanje njegove maske !
Razlog upotrebe Disreg je mogućnost upotrebe bilo kog pina sa različitih portova SAMO zbog lakšeg rutiranja jednoslojne PCB !
**** U interaptu :
Displej:
MPX = MPX + 1
if MPX = 5 then MPX = 1
PORTB = 0
SEL0 = 1
SEL1 = 1
SEL2 = 1
SEL3 = 1
select case MPX
CASE 1
Disreg = Maska0
low SEL0
CASE 2
Disreg = Maska1
low SEL1
CASE 3
Disreg = Maska2
low SEL2
CASE 4
Disreg = led
low SEL3
END SELECT
PORTB.6 = Disreg.0 ' Ovaj deo programa omogucava da se bilo koji
PORTB.4 = Disreg.1 ' od osam pinova na razlicitim portovima
PORTB.1 = Disreg.2 ' upotrebe za pogon miltiplex 7 segmentnog
PORTB.0 = Disreg.3 ' displeja u punom rezimu rada !!!
PORTB.2 = Disreg.4
PORTB.7 = Disreg.5
PORTB.5 = Disreg.6
'PORTB.3 = Disreg.7 'dp
**** Negde u programu :
Priprema:
W = Brojač
MASKE:
cifra = W dig 0 ' Vrednost jedinica ide u promenljivu "cifra"
gosub Bin2seg ' Pretvaranje cifre u masku
Maska0 = Cifra ' Maska 0 sadrzi maske "jedinica"
cifra = W dig 1 ' Vrednost desetica ide u promenljivu "cifra"
gosub Bin2seg ' Pretvaranje cifre u masku
Maska1 = Cifra ' Maska 1 sadrzi maske "desetica"
'Maska1 = Maska1 +128
cifra = W dig 2 ' Vrednost stotina ide u promenljivu "cifra"
gosub Bin2seg ' Pretvaranje cifre u masku
Maska2 = Cifra ' Maska 2 sadrzi maske "stotina"
return
Bin2seg: ' Tabela za pretvaranje decimlanog broja u masku za displeje
Lookup Cifra,[$3F,$06,$5B,$4F,$66,$6D,$7D,$07,$7F,$6F],Cifra
return ' Povratak iz tabela sa "maskom u cifri"
***************
Posts: 6.315
Threads: 56
Joined: Mar 2013
Reputation:
3.085
03-31-2018, 12:52 PM
(This post was last modified: 03-31-2018, 12:57 PM by Macola.)
Ronovar,
Nisam se nešto udubljivao u ovu temu i samo ću iskopirati i zalepiti neki primer koji sam nekada upotrebio.
Nekad, baš odavno, sam pisao u Pic Basic i staviću neki primer konverzije vrednosti u BCD za 7 segment.
Trebalo mi je tada ispisivanje tri cifre na neki displej koji je imao I2C interfejs (neko SAA IC ili tako nešto, već sam zaboravio).
No, konverzija u BCD je konverzija, bez obzira koji drive za 7 segment bio korišćen, direktno sa MCU ili nekim eksternim IC pa ti, osim ovog za I2C slanje, sve ostalo važi uz izmenu po pitanju broja cifara.
Možda ti bude korisno nešto odatle, uz sve ostale dobre savete koje si dobio od ostalih kolega. To je jedan od mnogo mogućih načina koji se svode na isto na kraju.
U toj verziji Basic je postojao makro > dig < za izdvajanje pojedinačnih cifara iz višecifarskog broja. Moguće je da radi i u tvojoj verziji Basic.
Ovo je neki radni primer iz neke moje mašine koja i dan danas radi. Ako ti posluži - dobro je, ako ne - onda neće mnogo ni smetati ovde...
Code: prikazibroj:;----------ispisivanje varijable 'vred_disp' na i2c displej(traje oko 1mS), tri cifre-------
cifra = 0
for cifra = 0 to 2 ; bcd konverzija
broj[cifra] = vred_disp dig cifra
lookup broj[cifra],[$3F,$06,$5B,$4F,$66,$6D,$7D,$07,$7F,$67,$38],temp
broj[cifra] = temp
next cifra
if broj[2] = $3F then ;brisanje suvisnih nula
broj[2] = 0
if broj[1] = $3F then
broj[1] = 0
endif
endif
i2cwrite sda,scl,disp_adr,1,[0,broj[2],broj[1],broj[0]] ;samo slanje traje oko 850uS!
temp = 0
return ;---------------------------------------------------------------------------------
Pozz
Posts: 2.475
Threads: 84
Joined: Feb 2013
Reputation:
1.438
Nisam se javljao jer gledam i primjere sa arduino i ovo sto ste gore postali kodove...idem dio po dio da shvatim logiku...inace probao sam i Bascom AVR i Arduino i za isti osnovni kod LED Blink Bascom AVR daje 1,2kB dok Arduino daje 2kb HEX file a FastAVR daje optimizirani asm kod koji bas pretvara u asm i daje nevjerojatnih 367bytova HEX file velicine...zato sam se odlucio za FastAVR mada znam da atmega ima i do 32kb flasha ali eto ocito je autor FastAVR-a napravio odlican posao optiomizacije BAS u ASM....
Proucavam ovaj timer i interupte nasao finu stranicu gdje sve pise pa dok to ne "svladam" nemam sto da radim sa 7 segmentnim displayem jer mi je to bitno da svladam kako bih mogao onda lakse da radim dalje.
Zahvaljujem svima na detaljnoj teoriji javit cu se cim sredim kod i savladam timer interrupt.
SAMO-BANOVAN OD 01.11.2024
Posts: 8.740
Threads: 138
Joined: Apr 2013
Reputation:
3.629
Poteraj pravi prototip, simulator je drugo, zatrebace i on, ovde imas displej i 11 nozica koje trebas pokrenuti, da se to spakovati caskom na nekoj plocici, posle lagano jedan po jedan segment, mozes u main() da napises rucno korak po korak kako sta da se upali i ugasi, nadam se da je deo oko osnovne logike Multiplexa za 7seg jasan, ako to proradi onda biraj, prevodilac, jezik, sa/bez tajmera i interapta i sta god hoces dalje da radis ... ; )
Posts: 2.475
Threads: 84
Joined: Feb 2013
Reputation:
1.438
Bit ce upravo tako..u praksi ce to mnogo bolje da izgleda...cekam da mi stignu displayi sa ebaya..trebali bi stici ovaj mjesec pa cim stignu idem prvo sa prvim segmentom pa onda prvi drugi i prvi drugi treci...i sa deleyom malo vecim da vidim koji se gasi koji se osvjezava itd...logika mi je jasna...samo jedno pitanje...
koristenjem timera i interrupta ako sam dobro shvatio CPU usage se drasticno smanjuje i time je CPU slobodan za druge operacije....zato se koriste timeri i interrupti?
SAMO-BANOVAN OD 01.11.2024
Posts: 1.244
Threads: 10
Joined: Apr 2015
Reputation:
509
CPU kod mikrokotrolera ima samo jedan zadatak. To je izvrsavanje masinskog koda. Ako npr. napravis kasnjenje pomocu petlji, onda CPU nece moci nista drugo da izvrsava do ne prodje zadato kasnjenje.
Mikrokontroleri u sebi pored CPU-a imaju mnogo hardverskih periferija. Svaku od periferija unutar mikrokontrolera CPU vidi preko SFR registara. Pristupom na odredjenoj SFR lokaciji, CPU pristupa periferiji koja je dodeljena toj lokaciji. Npr. podesavanje TMR-a itd.
Kada definises generisanje prekida pomocu TMR-a, to znaci da CPU ne mora nista da radi. TMR ce sam da radi u pozadini i kada istekne zadati interval vremena, on signalizira CPU-u da prekine sa izvrsavanjem glavnog programa i krene na izvrsavanje interapt rutine. Kada se interapt rutina zavrsi, nastavlja se sa izvrsavanjem glavnog programa od mesta gde je bio prekid.
Kod price sa displejima, stvar je prosta. Cak je ista kao da pravis da LED blinka, pri cemu se u mux rezimu to blinkanje ne vidi. Mozda ti je za pocetak najbolje da na protoboard postavis MCU plocicu i jednu LED. Napises program za blink i ne prelazis dalje dok to ne proradi. Kada proradi, krenes sa povecavanjem frekvencije blinkanja. Kada to usavrsis, 7-seg LED nema nikakve pameti u odnosu na LED blink. U postovima iznad imas dosta primenra multipleksiranja, koji su manje-vise isti. Razlika je jedino u nacinu pristupa. Svakako treba pogledati sve programe, pa na osnovu njih napraviti svoj i na taj nacin razviti logiku programiranja MCU-ova.
Posts: 2.475
Threads: 84
Joined: Feb 2013
Reputation:
1.438
Shvatio sam kako timer radi i mogu reci da je to fantasticna stvar...jako mi se dopada kako je to osmisljeno evo i malo matematickog primjera kako sam racunao 1sec interrupt delay:
- 12MHz Quarz
- Potrebno vrijeme interrupta (delaya 1sec)
------------------------------------------------------
Timer1_Value = 65535 (16-bitni timer1) - (Quarz / Prescaler)
Timer1_Value = 65535 - (12Mhz / 256) = 65535 - 46875 = 18660 decimalno => 48E4
-znači pošto je Timer1 16-bitni (2 na 16 je 65536, i znaci timer1 broji od 0 do 65535 to je brojac u timeru koji timer broji kada se enabla timer i kada dodje do maximalne vrijednosti on opet krene od postavljene vrijednosti ciklusa brojaca..
-da bismo znali koliko je ciklusa potrebno za jednu sekundu koristimo preskaler koji quarz takt dijeli sa preskalerom i time dobijamo da za jednu sekundu treba timer izbrojati 46875 ciklusa...dakle na 12MHz vanjskom taktu potrebno je sa preskalerom od 256 46875 ciklusa da izbroji timer1 u jednoj sekundi...
-pošto timer je 16-bitni on ide brojiti od 0 pa do 65535 i to je onda ako ide brojiti u tom punom ciklusu (65535/46875) 1,39808sekundi pa je potrebno oduzeti od maximalnog broja ciklusa 16 bitnog timera (65535) cikluse koji su potrebni za jednu sekundi i timer kod interrupta postaviti da brojac broji od tog ciklusa koji je po gornjoj formuli 18660...prema maximumu 16-bitnog timer1 ciklusa koji iznosi 65535.
-znaci spoji se napajanje na MCU timer1 se postavi na pocetnu vrijednost od 18660, enabla i pocne brojiti od 18660...kada dosegne vrijednost 65535 pokrene se interrupt Ovf1() koji postavlja taj brojac opet na 18660 jer ako se ne postavi brojač bi nakon izlaska iz interrupta počeo da broji od 0 i više nebismo imali sekundu nego 1,39808 sekundi...što nezelimo...skraćeno da kazem ja sam od 1,39808 uzeo sekundu a ovih 0,39808 sekundi sam "odrezao" i dobi se savršena preciznost dok radi do loop bez bilo kakvog cpu usage...
Primjer koji postavljam radi ko sat na breadboardu...dakle timer je postavljen da svake 1sekunde postavlja on ili off (ovisno o prethodnom stanju pina) i i da vrti do loop.
Samo mi nije jasno zasto nije u primjeru TempDiag.bas gdje je primjer timera postavljen na pocetku programa startni broj ciklusa..treba da je postavljen na 18660 jer kada se ukljuci prvi put napajanje na MCU vrijednost početnog timera1 je 0 i prvo brojanje ce biti 1,39808 umjesto sekunde dok se ne pokrene interrupt koji postavlja broj ciklusa na zadanu vrijednost 18660 i dalje ce da bude ok. Ja sam tu vrijednost dodao na pocetku programa kako se vidi u programu i to radi fantasticno:
I kako pravilno odabrati preskaler ovisno o taktu MCU jer preskaler "usporava" MCU timer jer ga dijeli sa main clockom...evo primjera:
npr zelimo 1sekundu delay imamo kristal 12MHz, preskaler stavimo 64
Po gornjoj formuli: 65535 - (12MHz/64) = 65535 - 187500 = -121965
Dakle broj ciklusa nesmije biti negativan tj veci od 16-bitnog timera1 jer timer1 moze da broji samo do 65535 ako stavimo jedan veci preskaler po redu a to je 256 dobijamo:
65535 - (12MHz/256) ) = 65535 - 46875 = 18660
I dobili smo broj ciklusa za jednu sekundu pozitivan broj koji je manji od 16-bitnog timera znaci 256 mora da bude najmanji preskaler da bi radilo...ako zelimo 2 sekunde delay samo pomnozimo dobivene cikluse sa 2 i oduzmemo od 16-bitnog timera (65535) ako je negativan broj onda povecamo na 1024 preskaler a ako bude i onda onda prilagodimo kvarz takta MCU-a dok ne dobimo pozitivan broj primjer delay 2 sekunde:
65535 - (12MHz/256) = 65535 - (46875 x 2) = -28215
znaci sljedeci preskaler je 1024 pa da vidimo sto cemo dobiti:
65535 - (12MHz/1024) = 65535 - (11718,75x2) = 42097,5 dakle zaokruzimo na 42097 i upisemo u program za programiranje dali binarno decimalno ili hexadecimalno..ja uvije stavljam hexadecimalno (ljepse mi izgleda program sa hex vrijednostima).
I jos jedna vrlo vazna caka je kod programiranja MCU-a treba da se LOW FUSE postavi id a se disablira bit divide clock by 8 i postave bit 3 - 0 na 1111 kako bi MCU radio na punom taktu jer ako nije ovo gore isprogramirnao dobija se 12MHz / 8 = 1,5MHz takt kristala na MCU cime ce nam timer raditi jako duggooo i neprecizno.
Evo programa:
'/////////////////////////////////////////////////////////
'/// FastAVR Basic Compiler for AVR by MICRODESIGN ///
'/// LED Blink - Timer0
'/////////////////////////////////////////////////////////
$Device= m8 ' used device
$Stack = 32 ' stack depth
$Clock = 12 ' adjust for used crystal
$Timer1=Timer, Prescale=256 ' config timer1
Declare Interrupt Ovf1() ' toggle led interrupt
'/// Timer
Timer1=&h48e4 ' 1sec interrupt
Enable Interrupts ' enable global interrupts
Enable Timer1 ' enable timer1
Start Timer1 ' start timer1
'/// Port
PORTD = &hFF ' define portd as output
Do ' place your code in next line
Loop
'/////////////////////////////////////////////////////////
Interrupt Ovf1(), Save 1
Timer1=&h48e4 ' 1sec interrupt
Toggle PORTD.0 ' turn led on/off
End Interrupt
Evo i video kako to radi:
http://streamable.com/ad0l7
Eto zanima me dali sam dobro to sve razumio sto se tice obicnog timera..znam da jos tu ima punooo vise kao npr rising edge falling edge comparator timer itd itd..ali za pocetak obicna led blink dioda i interrupt i za 7 segmentne displaye mi je ovo dovoljno...jedno pitanje zasto se koristi timer0? Posto je on 8 bitni i ide od 0 -255 koja mu je svrha? sa njim nebih mogao ovako precizno dobiti timing kao sa timer1 koji je 16 bitni....plan mi je da kada sredim 7 segmentne displaye da se refreshaju preko timer1 interrupta da stavim jos jedan timer0 koji ce svakih 500ms citati vrijednost sa senzora i pohranjivati u globalnu varijablu pen_temperarature koju ce onda kada se aktivira timer1 nakon sekunde da ucita i prikaze vrijednost na 7 segmentnom displayu...dakle mogu li da rade oba dva timera istovremeno? Posto su HW tipa timeri mislim da cpu usage nebi smio uopce biti...
Eto ako je to to sa timerom onda mogu da krenem na pisanje koda za refresh displaya jer delay timera od 1 sekunde imam...ostaje samo prilagoditi frekvenciju osvjezavanja i segmente postavio u stanja osvjezavanja jedan za drugim...
SAMO-BANOVAN OD 01.11.2024
Posts: 1.244
Threads: 10
Joined: Apr 2015
Reputation:
509
@ronovar
prijatelju, drago mi je da si uspeo da pokrenes interapt tajmera. Kompletna logika ti je OK, ali imas jednu gresku koja ce da ti pravi gresku generisanja vremena. TMR1 je 16-bitni tajmer kao sto si i rekao. Maksimalna vrednost je 65535, a minimalna 0. Interapt tajmera se generise kada tajmer prebaci sa 65535 na 0. To znaci da sa 16-bitnim tajmerom imas maksimalno 65536 nivoa. Kada vrsis proracun vremena, onda ce ti biti ovako:
Fosc = 12MHz
PRESCALER = 256
Tprescaler = 256 / 12MHz = 21,3us - Ovoliko tebi traje jedan inkrement tajmera. Posto je tajmer 16 bitni, znaci 65536 stanja, to znaci da max vreme sa ovakvim tajmerom moze da bude 1,398s.
Tebi treba vreme od 1s, sto znaci da tajmer treba da odbroji 46875 taktova. TMR mora da krene od neke vrednosti da bi odbrojao ovoliko taktova. Vrednost tajmera racunamo kao:
TMR1 = 65536 - 46875 = 18661
8 bitni tajmer moze da ti zadovolji dosta stvari. Ne mora tajmer da bude 16bitni da bi bio dobar. Za osvezavanje displeja mozes da koristis TMR0, cak isti taj tajmer da koristis i za citanje vrednosti sa senzora. Tajmer neka radi na 1ms za osvezavanje displeja. Definises jednu promeljivu koja ce da broji do 500. Kada ta promeljiva dodje do 500, onda das trigger AD-u da uradi konverziju. Na kraju konverizije se generise AD interapt. Prvu konzverziju odbacujes i uradis brzo jos 16 konverzija. Saberes ih sve i podelis sa 16 i dobijes usrednjenu vrednost. Posle novih 500 inkrementa, automatski se startuje AD konverzija i sve opet tako u krug. CPU odmara sve vreme, a harver u pozadini radi sam.
Pitao si da li dva tajmera mogu da rade u isto vreme. Mogu. Mogu sve periferije MCU-a da rade u isto vreme, a javljace se kada im dodje red na to.
Posts: 1.244
Threads: 10
Joined: Apr 2015
Reputation:
509
Jedna bitna stvar kod fuses na AVR-ovima. Pazi da slucajno ne otkacis rstdisable ili slicno. RST ulaz ce da postane klasican GPIO, i nikada vise neces moci da udjes u mod za programiranje. Jedino ces moci pomocu paralelnog programatora.
Posts: 1.157
Threads: 27
Joined: Oct 2014
Reputation:
313
Bravo! Odradio si dobar posao oko tajmera. Sad mogu i da ti olakšam malo. Imaš na netu razne kalkulatore za računanje. Recimo, Mikrolektronika ima besplatan alat za ovo:
https://www.mikroe.com/timer-calculator
Posts: 2.475
Threads: 84
Joined: Feb 2013
Reputation:
1.438
Da to sam postavio dakle brojac cim dodje do 65535 pokrene interrupt u kojemu se pocetna vrijednost postavlja na 18660 naredbom:
Timer1=&h48e4 ' 1sec interrupt
tako da kada se vrati iz interrupta timer1 pocinje brojati od 18660 pa do 65535 (to je sveukupno 46875 ciklusa bas koliko nam je potrebno za jednu sekundu).
Tako da ne razumijem gdje sam pogrijesio kod greske generiranja vremena..mozes li napisati u kodu gdje sam pogrijesio da znam za ubuduce.
Jedino sam pogrijesio sto nisam racunao 65536 kako je i pravilno to cu sada da ispravim i gore navedeni &h48e4 treba da bude h48e5 (18661 decimalno).
Za fuse ne diram nista osim LOW FUSE tako imama u programu...jednom davno sam bas po tim fuse nesto klikao i nisam vise mogao uci u mod programiranja tako da od onda sam pazljiv..jer nemam paralelni high volage programator ili ti fuse avr doctor...
Evo ako moze gdje sam pogrijesio pa da zakljucim za danas ovo sa timerima...
SAMO-BANOVAN OD 01.11.2024
Posts: 2.475
Threads: 84
Joined: Feb 2013
Reputation:
1.438
(04-01-2018, 09:32 PM)gorankg Wrote: Bravo! Odradio si dobar posao oko tajmera. Sad mogu i da ti olakšam malo. Imaš na netu razne kalkulatore za računanje. Recimo, Mikrolektronika ima besplatan alat za ovo:
https://www.mikroe.com/timer-calculator
Zahvaljujem...bolje je ovako "školski" kako sam uradio..tako sam naučio i malo se priblizio avr arhitekturi kako avr timeri rade...i mogu reci da mi se dopada ovaj pristup timerima...fantasticna stvar...ne trosi cpu nista a ugradjeni hw timeru odradjuju sve u pozadini...hvala za ovaj kalkulator za provjeru dali sam dobro rucno izracunao jakoo dobro dodje...
SAMO-BANOVAN OD 01.11.2024
|