ATMEGA48 8MHz, nastavení čítače časovače, přerušení po 100ms

Prosím o radu s nastavením čítače/časovače1 Oscilátor je nastaven na 8MHz a já chci vyvolat přerušení po 100ms.

TCCR1A=0;
TCCR1B=0B01000011; //dělička nastavena na 64
OCR1AH=0B00110000;
OCR1AL=0B11010100; //OCR1A má hodnotu 12500

a jestli to je spravě nastaveno tak pak ješte nevím jak nastavit přerušení
TIMSK1 a TIFR1

Dále ještě co vynulovat nebo nastavit až budu v přerušení aby se opět aktivovalo.

Děkuji všem za radu

:arrow_right: administrator: přejmenováno z "ATMEGA48, nastavení čítače časovače"

Zřejmě používáš přerušení při porovnání - cpmpare match A

tak to bude takto

TCCR1A=0x00;
TCCR1B=0x03;

OCR1AH=0x30;
OCR1AL=0xD4;

dále

povol přerušení

TIMSK1=0x02;

a v rutině přerušení vynuluj TCNT1

a nakonec nezapomeň povolit globalní přerušení

[code]void init_timer1()
{
TCCR1A=0;
OCR1AH = 0x18; // 0x1869 => 6249 => 100ms
OCR1AL = 0x69; // najdi si vzoreček a zjisti, kde jsi udělal chybu
TCCR1B = (1<<WGM12)|(3<<CS10); // dělička/64 + CTC (normální režim není vhodný)
//(ICES, který jsi měl zapnutý slouží pro externí signál !!!

TIMSK1 = (1<<OCIE1A); //povolení přerušení od přetečení
}[/code]

Pokud použiješ přerušení, pak se příznak v TIFR vynuluje sám.
Př.:

[code]#include <avr/interrupt.h>

ISR(TIMER1_COMPA_vect)
{
//obsluha přerušení
}[/code]

Pokud však provádíš obsluhu časovače z hlavního programu,
pak musíš příznak v TIFRU vynulovat manuálně.

while (( TIFR & ( 1 << OCF1A)) == 0) ;  //čekej dokud nedojde k přerušení
TIFR = 1<<OCF1A;  // Vynulování příznaku

Děkuju všem, teď jdu do práce ale zítra s radostí otestuji. Smad to pochopím :slight_smile:

Zdarec,
máš vybrán mode 0 (TOP=0xFFFF, WGM3:0 = 0), aby sis mohl určít TOP sám, je vhodný mode 14/15 nebo CTC, tedy např. mode 14 (TOP=ICR1):
TCCR1A |= (1<<WGM11);
TCCR1B |= (1<<WGM13) | (1<<WGM12);
ICR1=12500-1; // překladač má definici pro tento 2B registr, uloží to správně, hodnota o 1 menší(!)

Dále máš v TCCR1B určený bit ICES1 - ty nevyužíváč IC jednotku, jen její registr -> zbytečné.
Dělička 64 je správně. Jen pro úplnost :slight_smile:
TCCR1B |= (1<<CS11) | (1<<CS11);

Nyní aktivace přerušení: pro mode 14/15 tě zajímá přetečení (= dosažení hodnoty TOP a přechod do nuly), při CTC je to snad compare-match.
TIMSK1 |= 1<<TOIE1; // Timer/Counter1, Overflow Interrupt Enable
“TOV1 is automatically cleared when the Timer/Counter1 Overflow Interrupt Vector is executed.
Alternatively, TOV1 can be cleared by writing a logic one to its bit location.”
Flag přerušení je nulován automaticky při vyvolání přerušení, nemusíš se o něj starat.

Obsluha přerušení bude v:
ISR(TIMER1_OVF_vect)
{ // “TIMER1_OVF_vect” najdeš v “avr-libc-user-manual.pdf” ve složce GCC
}

fovf = 8e6/64/12500 = 10 => T=0.1s, TOP máš správně.

edit: Teda chlapi, se tady s tim patlám. Dám refresh a zjistim že skoro zbytečně… :unamused: :smiley:

Myslím že na co jsem se ptal tak jste mi super vysvětlili.
Akorát já to píšu v programu mikroC PRO for AVR
A nevím jak pojmenovat podprogram pro přerušení. Když jsem dělal s PIC tak mi to fungovalo: void Interrupt () {

}

nastavení časovače:

void casovac () {
TCCR1A |= (1<<WGM11) | (1<<WGM10);
TCCR1B |= (1<<WGM13) | (1<<WGM12);
TCCR1B |= (1<<CS11) | (1<<CS10);
ICR1H=0B00110000;
ICR1L=0B11010011;
TIMSK1 |= 1<<TOIE1; //povoleni preruseni
}

a to přerušení:

void Interrupt () {
TIFR1=0;
hodiny (); // počítá čas co potřebuji
}

jinak jestli v tom programuněkdo náhodou pracuje budu opět vděčný za radu.

nebo nějakej manuál k tomu GCC?

Manual ke GCC asi není moc potřeba. Když nainstaluješ AVRStudio a winavr (=GCC), tak ti ten program půjde přeložit (to přerušení bude jak jsem ho napsal). Kdybys s tím měl problém, tak se ozvi, dám ti sem celej zdroják. Ovšem bude skoro stejnej jako by byl ve tvým překladači až právě na tu definici přerušení. C je víceméně stejný všude, jen někde jsou nějaký fičurky navíc a podobně. Rozdíly jsou akorát ve věcech specifických pro mcu, které nejsou v C explicitně definovány.

Moc si nedokážu představit jak funguje
“void Interrupt () {

}”.
Jak překladač pozná o jaké přerušení jde??

:smiley: :smiley:

to je právě ono :smiley: u PIC máš jenom jeden vektor přerušení kam skáčou všechny přerušení a je to konkrétně adresa 04 pokud si to ještě pamatuji dobře ze školy. Prostě děs. v tom přerušení musíš otestovat všechny příznaky a pak se rozhodnout. Proto se mi to už na střední nelíbilo…

u me ma kazdy preruseni svoje obslouzeni,isr PB0 / isr TMR1 …(v C), pokud se ale podivas do pdekladu do ASMka tak se nedeje nic jinyho nez skok na vektor preruseni 04 a nasledny testovani priznaku jednotlivych preruseni, ale testujou se jenom ty ktere pouzivas ne vsechny, jak vypada preruseni u AVR ? to ma pro kazdy preruseni jinej vektor ci jak ? to me teda zajima

ano přesně tak, každé přerušení má taky svůj vektor.

Přesně tak, i na x51 má každé přerušení svůj vektor (když neberu v úvahu společnej vektor pro rx a tx uartu), proto mě to tak překvapilo :slight_smile:
Na druhou stranu i softprocesor pro fpga nios má taky jen 1 vektor.

tak zdroják je:
#define __AVR_ATmega48
//#define OPTIMIZE

/nastaveni pro f_osc 8000000/
#define F_CPU 8000000

#include <avr/io.h>
#include <avr\interrupt.h>
#include <util\Delay.h>
int ba, b, c, d, e, f, g, x, yy;
int setup (void) {
_delay_ms (100);
DDRB=0B11000000;
DDRC=0B00111111;
DDRD=0B01111111;
PORTB=0;
PORTC=0;
PORTD=0;
ba=0;
b=0;
c=0;
d=0;
e=0;
f=0;
g=0;
x=0;
}
int zapis (void) {
PORTC=PORTC | 0B00000010;
_delay_ms (100);
}

int zapis1 (void) {
PORTC=PORTC | 0B00000010;
_delay_us (50);
}

int LCD (void) {
PORTC=0B00100100;
zapis ();
_delay_ms (4);
PORTC=0B00100100;
zapis ();
PORTC=0B00100100;
zapis ();
PORTC=0B00100000;
zapis ();
PORTC=0B00100000;
zapis ();
PORTC=0B00010000;
zapis ();
PORTC=0B00000000;
zapis ();
PORTC=0B00010000;
zapis ();
PORTC=0B00000000;
zapis ();
PORTC=0B00000100;
zapis();
_delay_ms (1);
PORTC=0B00000000;
zapis ();
PORTC=0B00101000;
zapis ();
PORTC=0B00000000;
zapis ();
PORTC=0B00011000;
zapis ();
}

int hodiny (void) {
yy=yy++;
if (yy>9) {
ba=ba++;
yy=0;
if (ba>9) {
b=b++;
ba=0;
if (b>5) {
c=c++;
b=0;
if (c>9) {
d=d++;
c=0;
if (d>5) {
e=e++;
g=g++;
d=0;
if (e>9) {
f=f++;
e=0;
if (g>23) {
e=0;
f=0;
g=0;
}
else return;
}
else return;
}
else return;
}
else return;
}
else return;
}
else return;
}
else return;
}

int predcisli (void) {
PORTC=37;
zapis1 ();
}

int tabulka_cisel (void) {
switch (x) {
case 0: PORTC=1, zapis1(); break;
case 1: PORTC=5, zapis1(); break;
case 2: PORTC=33, zapis1(); break;
case 3: PORTC=37, zapis1(); break;
case 4: PORTC=9, zapis1(); break;
case 5: PORTC=13, zapis1(); break;
case 6: PORTC=41, zapis1(); break;
case 7: PORTC=45, zapis1(); break;
case 8: PORTC=17, zapis1(); break;
case 9: PORTC=21, zapis1(); break;
}
}

int dvojtecka (void) {
predcisli();
PORTC=49;
zapis1();
}
int zobrazeni_hodin (void) {

// ADRESA 04h nastavení začátku
PORTC=0B00010000;
zapis1 ();
PORTC=0B00001000;
zapis1 ();

// zobrazení hodin
x=f;
predcisli();
tabulka_cisel();
x=e;
predcisli();
tabulka_cisel();
dvojtecka ();
x=d;
predcisli();
tabulka_cisel();
x=c;
predcisli();
tabulka_cisel();
dvojtecka ();
x=b;
predcisli();
tabulka_cisel();
x=ba;
predcisli();
tabulka_cisel();
}

int casovac (void) {
TCCR1A |= (1<<WGM11) | (1<<WGM10);
TCCR1B |= (1<<WGM13) | (1<<WGM12);
TCCR1B |= (1<<CS11) | (1<<CS10);
ICR1H=0B00110000;
ICR1L=0B11010011;
TIMSK1 |= 1<<TOIE1;
}

ISR (TIMER1_OVF_vect) {
TIFR1=0;
hodiny ();
}

int main() {
setup ();
LCD ();
_delay_ms(1000);
//casovac ();
do {
hodiny();
_delay_ms(100);
zobrazeni_hodin ();
}
while(1);
}

mám to napojení na LCD displej. hodiny() - počítá čas teď to přez zpoždění _delay_ms(100) to mi funguje

A teď jsem chtěl přičítat do hodin() když mi to skočí do přerušení. To mi ale nefunguje :frowning:

#define __AVR_ATmega48
//#define OPTIMIZE

/nastaveni pro f_osc 8000000/
#define F_CPU 8000000

#include <avr/io.h>
#include <avr\interrupt.h>
#include <util\Delay.h>
int ba, b, c, d, e, f, g, x, yy;
int setup (void) {
_delay_ms (100);
DDRB=0B11000000;
DDRC=0B00111111;
DDRD=0B01111111;
PORTB=0;
PORTC=0;
PORTD=0;
ba=0;
b=0;
c=0;
d=0;
e=0;
f=0;
g=0;
x=0;
}
int zapis (void) {
PORTC=PORTC | 0B00000010;
_delay_ms (100);
}

int zapis1 (void) {
PORTC=PORTC | 0B00000010;
_delay_us (50);
}

int LCD (void) {
PORTC=0B00100100;
zapis ();
_delay_ms (4);
PORTC=0B00100100;
zapis ();
PORTC=0B00100100;
zapis ();
PORTC=0B00100000;
zapis ();
PORTC=0B00100000;
zapis ();
PORTC=0B00010000;
zapis ();
PORTC=0B00000000;
zapis ();
PORTC=0B00010000;
zapis ();
PORTC=0B00000000;
zapis ();
PORTC=0B00000100;
zapis();
_delay_ms (1);
PORTC=0B00000000;
zapis ();
PORTC=0B00101000;
zapis ();
PORTC=0B00000000;
zapis ();
PORTC=0B00011000;
zapis ();
}

int hodiny (void) {
yy=yy++;
if (yy>9) {
ba=ba++;
yy=0;
if (ba>9) {
b=b++;
ba=0;
if (b>5) {
c=c++;
b=0;
if (c>9) {
d=d++;
c=0;
if (d>5) {
e=e++;
g=g++;
d=0;
if (e>9) {
f=f++;
e=0;
if (g>23) {
e=0;
f=0;
g=0;
}
else return;
}
else return;
}
else return;
}
else return;
}
else return;
}
else return;
}
else return;
}

int predcisli (void) {
PORTC=37;
zapis1 ();
}

int tabulka_cisel (void) {
switch (x) {
case 0: PORTC=1, zapis1(); break;
case 1: PORTC=5, zapis1(); break;
case 2: PORTC=33, zapis1(); break;
case 3: PORTC=37, zapis1(); break;
case 4: PORTC=9, zapis1(); break;
case 5: PORTC=13, zapis1(); break;
case 6: PORTC=41, zapis1(); break;
case 7: PORTC=45, zapis1(); break;
case 8: PORTC=17, zapis1(); break;
case 9: PORTC=21, zapis1(); break;
}
}

int dvojtecka (void) {
predcisli();
PORTC=49;
zapis1();
}
int zobrazeni_hodin (void) {

// ADRESA 04h nastavení začátku
PORTC=0B00010000;
zapis1 ();
PORTC=0B00001000;
zapis1 ();

// zobrazení hodin
x=f;
predcisli();
tabulka_cisel();
x=e;
predcisli();
tabulka_cisel();
dvojtecka ();
x=d;
predcisli();
tabulka_cisel();
x=c;
predcisli();
tabulka_cisel();
dvojtecka ();
x=b;
predcisli();
tabulka_cisel();
x=ba;
predcisli();
tabulka_cisel();
}

int casovac (void) {
TCCR1A |= (1<<WGM11) | (1<<WGM10);
TCCR1B |= (1<<WGM13) | (1<<WGM12);
TCCR1B |= (1<<CS11) | (1<<CS10);
ICR1H=0B00110000;
ICR1L=0B11010011;
TIMSK1 |= 1<<TOIE1;
}

ISR (TIMER1_OVF_vect) {
TIFR1=0;
hodiny ();
}

int main() {
setup ();
LCD ();
_delay_ms(1000);
casovac ();
do {
_delay_ms(10);
zobrazeni_hodin ();
}
while(1);
}

podle manuálu přerušení tak jsou nějak jinak pojmenovaná. Je to na linuxfocus.org/common/src2/a … -1.0.4.pdf

a str. 77.

nevím jak se to moje přerušení jmenuje?

:arrow_right: administrator: přiloženy externí soubory
avr-libc-user-manual-1.0.4.pdf (1.09 MB)

To bude asi ne dýl :slight_smile: Možná bys mohl zkusit začít něčím jednodušším a postupovat pozvolna :wink:.
Funkce “int setup(void){}” by měla vracet int, ovšem nikde tam nevidím “return”. Stejný problém je u dalších funkcí. Globální proměnné, se kterými pracuješ v přerušení (= asynchronní událost) musíš prefixovat slovem “volatile”.

Ohledně manuálu gcc se podívej do složky, kde ho máš nainstalované. Někde tam je a bude to ten správný k nainstalované verzi (vektory bývají kolem strany 230).

Zdrojáky dávej to tagu “CODE”, takhle je to nečitelné :frowning:.

Co to tam máš za šílený větvení v hodiny()? Co jednodušeji:

if(min>9) min=0; des_min++; if(des_min>5) des_min=0; hod++; ...
Na všechny tyto počítací proměnné by ti stačil “unsigned char” místo “int” :wink:.

Omlouvám se jsem takovej začátečník samouk.

  • mohu psát funkci takto?

void hodiny () { ..... }

Ano mám ve funkci hodiny () zbytecny veci

} else return;

ale když to vše pomineme jedná se mi hlavně o funkci přerušení. Ostatní mě funguje ikdyž to je krkolomě napsaný asi. Děkuji za upomímky také chci aby to mělo štábní kulturu.

[code]
//přerušení
ISR (TIMER1_OVF_vect) {
hodiny();
TIFR1=0;
}
// nastavení přerušení
void casovac () {
TCCR1A |= (1<<WGM11) | (1<<WGM10);
TCCR1B |= (1<<WGM13) | (1<<WGM12);
TCCR1B |= (1<<CS11) | (1<<CS10);
ICR1H=0B00110000;
ICR1L=0B11010011;
TIMSK1 |= 1<<TOIE1;
}

void main() {
casovac ();
do {
_delay_ms(100);
zobrazeni_hodin ();
}
while(1);
} [/code]

“TIFR1=0” je tam zbytečný, nuluje se automaticky. Navíc většina flagů se nuluje zápisem “1”. Přerušení máš dobře a nastavení timeru snad taky.
Hlavně dej “volatile” před “int ba, b, c, d, e, f, g, x, yy;”, protože s těma proměnnýma pracuješ v přerušení a musíš to překladači tím volatile říct aby jsi zamezil nežádoucím optimalizacím.

dal jsem

volatile int ba, b, c, d, e, f, g, x, yy;

ale porad mi to nefunguje. Vubec to nepocita takže mi přijde že to do přerušení neskočí ani :frowning:

[code]int casovac (void) {
TCCR1A |= (1<<WGM11) | (1<<WGM10);
TCCR1B |= (1<<WGM13) | (1<<WGM12);
TCCR1B |= (1<<CS11) | (1<<CS10);
ICR1H=0B00110000;
ICR1L=0B11010011;
TIMSK1 |= 1<<TOIE1;
}

ISR (SIG_OVERFLOW1) {
hodiny();
TIFR1=1;
}[/code]

v mainu po inicializaci procesoru a před nekonečnou smyčkou nemáš “sei();” což je globální povolení přerušení.
Mimochodem - zase tam máš “int casovac (void)” bez “return”. Když nechceš nic vracet, tak je to “void casovac (void)”.

“SIG_OVERFLOW1” je zastaralý zápis, používej ty novější (tady “TIMER1_OVF_vect”, všechny vektory krom manuálu gcc najdeš i v definičním souboru procesoru - tady iomx8.h)

edit: ještě v nastavení TCCR1A nemá být bit WGM10.
V simulátoru to ani nezkoušej, ten tady ukazuje u pwm nesmysly.

[code]#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

void tim1Start(void)
{
TCCR1A |= (1<<WGM11);
TCCR1B |= (1<<WGM13) | (1<<WGM12);
TCCR1B |= (1<<CS11) | (1<<CS10);
ICR1 = 12500-1;
TIMSK1 |= 1<<TOIE1;
}

ISR(TIMER1_OVF_vect)
{
//
PORTB ^= 1<<PB1; // blikani na PB1 s periodou 200ms
}

void main(void)
{
//
DDRB |= 1<<PB1;
tim1Start();
sei();

// main loop
for(;;)
{
	// nejaka cinnost
}

}[/code]

Paráda :smiley: :smiley:

Děkuju za trpělivost šlape to