# ATMEL mikrokontrolleri >  [ ATmega ] Paralēlie procesi

## Hank

Radās _perversa_ doma 3x3 LED matricā vidējo LED atstāt mirgojošu @ 20ms, tai pašā laikā malas dzenot pa rinķi @ 75ms ( tikai piemērs ).

Tā kā delay abiem tāskiem atšķiras, vienkāršā ciklā palaist to neizdosies.

Vai kādam ir kādas idejas, kā to panākt ?

Māte Google uz šo jautājumu atbildi nezin, vai arī es vienkārši nemāku noformulēt jautājumu ( _ATmega multithreading_ )  ::

----------


## Vikings

Pārtraukums pa 5ms un skaiti pa 4 (20ms) un 15 (75ms). Attiecīgi saskaitot izpildi vajadzīgo un skaiti no jauna.

----------


## australia

nu, diezgan primitīvām ATmegām ir vairāki taimeri.
viens rausta vidu, otrs griež riņķi

----------


## Vikings

> nu, diezgan primitīvām ATmegām ir vairāki taimeri.
> viens rausta vidu, otrs griež riņķi


 IMHO pārāk izšķērdīgi.

----------


## australia

> IMHO pārāk izšķērdīgi.


 nu labi. Ja jau būvēs kosmosa raķetes vadību  :: 

var jau palikt pie tava - viens taimeris, kas dauza pa daudz smalkākām laika iedaļām un ik pa laikam veic izmaiņas

----------


## Slowmo

Izšķērdīgi vai ne izšķērdīgi, bet, ja tie taimeri nekam citam nav vajadzīgi, kāpēc gan tos neizmantot?

----------


## JDat

Un kā ar IRQ sinhronizāciju? Itkā jau maza šķirba, bet tomēr... Ja tiek izsaukti divi IRQ vienlaicīgi? Ar vienu timer tas nenotiks principā...

----------


## Vikings

> Izšķērdīgi vai ne izšķērdīgi, bet, ja tie taimeri nekam citam nav vajadzīgi, kāpēc gan tos neizmantot?


 Nu, piemēram, treniņa pēc lai izdomātu kā to izdarīt ar vienu taimeri, vai ja nu nākotnē savajagās otru lai nav jāčakarējas ar viena atbrīvošanu.

----------


## Hank

Paldies par ieteikumiem  :: 

Sataisīju ar pārtraukumiem ( interrupts ), bet kad kāds no tiem tiek izsaukts un savu darbu beidz, programma neturpina no vietas kur tā palika, t.i., while cikla vidus, bet gan sāk while ciklu no gala, kas man nebūt neder, jo ja lieku vienu LED @ 20ms, malā vairāk par 1 ( pirmo ) degam neredzu.

Vai tiešām vienīgais variants ir lietot pliku taimeri un programmā skaitīt laika dalījumu ?

----------


## JDat

kodu studijā. Izskatās ka kaut kas aizmirsts kodējot... Piemēram Return from IRQ nenotiek.

----------


## RobinDAB

Ja ASM - kosjaks klasiskais...
stack pointer programmas sākumā ir inicializēts?
 ::

----------


## Hank

> kodu studijā. Izskatās ka kaut kas aizmirsts kodējot... Piemēram Return from IRQ nenotiek.


 Tā kā neko sev saprotamu par Tevis minēto IRQ neatrodu, copy/paste:



```
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/io.h>

int main(void)
{

    sei();

    DDRB = 0xFF;
    
    DDRD = 0xFF;

    static int defaultDelay = 500;

    PORTB = 0b00000010;

    PORTD = 0b11111111;

    TCCR1B |= 1 << CS10 | 1 << CS11 | 1 << WGM12;

    TIMSK |= 1 << OCIE1A;

    OCR1A = 15624 * 0.2;    // 200ms

    while (1)
    {


        PORTB = 0b00000001;

        PORTD = 0b11111110;

        _delay_ms(defaultDelay);

        PORTD = 0b11111101;

        _delay_ms(defaultDelay);

        PORTD = 0b11111011;

        _delay_ms(defaultDelay);

        PORTB = 0b00000010;

        PORTD = 0b11111011;

        _delay_ms(defaultDelay);

        PORTB = 0b00000100;

        PORTD = 0b11111011;

        _delay_ms(defaultDelay);

        PORTD = 0b11111101;

        _delay_ms(defaultDelay);

        PORTD = 0b11111110;

        _delay_ms(defaultDelay);

        PORTB = 0b00000010;

        PORTD = 0b11111110;

        _delay_ms(defaultDelay);

        PORTD = 0b11111101;

        _delay_ms(defaultDelay);

    }
    
}

ISR(TIMER1_COMPA_vect)
{
    
    PORTB = 0b00000010;

    PORTD = 0b11111101;

}
```

 Ko es daru nepareizi ?

----------


## Hank

> Ja ASM - kosjaks klasiskais...
> stack pointer programmas sākumā ir inicializēts?


 Ar C netieku galā, kur nu vēl ASM  ::  Visam savs laiks.

----------


## JDat

> Ar C netieku galā, kur nu vēl ASM  Visam savs laiks.


 ar ASM kaut kā tieku galā, kur nu ar C... Es pass, lai mokās C zinātāji...

----------


## RobinDAB

1)
TIMSK |= 1 << OCIE1A; -?
2)
sei
palaižam taimeri
uzstādam taimerim nosacījumus...

neloģiska secība, right?

----------


## karloslv

Omg, omg, Tu visu dari nepareizi, piedod. Kāpēc Tev ir cikls, kurš rausta lampiņas, un vēl pārtraukums, kurš rausta lampiņas? Tie konfliktē, jo abi procesi nav sinhroni. Pārtraukums var tikt izsaukts jebkurā brīdī.
1) Kā jau RobinDAB minēja, vispirms sakonfigurē taimeri un tikai tad atļauj pārtraukumus ar sei()
2) Visa laika uzskaite un lampiņu darbības taimera kodā, nevis galvenajā cilpā. 
3) Galvenā cilpa NEKO nedara, guļ ar sleep_mode().

Šāda pieeja ir ok līdz brīdim, kamēr taimera kods kļūs pārāk smags. Kad tas notiek, jādara citādi, taimerī jāskaita laiks un noteiktos brīžos jāpaziņo par to galvajai cilpai. Galvenā cilpa guļ ar sleep_mode(), kad pamostas, pārbauda, vai Visumā nekas nav mainījies, ja nav, guļ tālāk. Ja ir, parausta lampiņas, izrēķina kvadrātsakni un guļ tālāk.

----------


## Vikings

Nē, nu tik pat labi jau vari izmantot _delay_ms() funkciju un dzīvot vispār bez pārtraukumiem.

----------


## Hank

> 2) Visa laika uzskaite un lampiņu darbības taimera kodā, nevis galvenajā cilpā. 
> 3) Galvenā cilpa NEKO nedara, guļ ar sleep_mode().


 Vai ir pieejams kāds piemērs, kas atbilst Tevis aprakstītajam ? Īsti netieku skaidrs, ko ar to biji domājis ..  ::

----------


## Velko

> Vai ir pieejams kāds piemērs, kas atbilst Tevis aprakstītajam ? Īsti netieku skaidrs, ko ar to biji domājis ..


 Nu, apmēram tā:


```
int main() {
    // setupojam portus, taimeri un cits startup blablabla.
    sei();
    for (;;)
        sleep_mode();
}

ISR(TIMER1_COMPA_vect) {

    // šo procesors izsauc "ik pa brīdim"
    // te arī pārslēdzam LEDus kā patīk
    // piemēram:
    PORTB <<= 1;
    if (PORTB == 0)
        PORTB = 1;
}
```

----------


## Hank

> Nu, apmēram tā:
> 
> 
> ```
> int main() {
>     // setupojam portus, taimeri un cits startup blablabla.
>     sei();
>     for (;;)
>         sleep_mode();
> ...


 Un kur paliek vidējā LED ?

----------


## Vikings

Nu kā, vidējā LED. Tur takš komentāros teikts - "pārslēdzam ledus kā patīk", tātad, te pats saliec savas LED kombinācijas kā gribās.

----------


## Hank

> Nu kā, vidējā LED. Tur takš komentāros teikts - "pārslēdzam ledus kā patīk", tātad, te pats saliec savas LED kombinācijas kā gribās.


 Nu tad vēlreiz atgriežamies pie jautājuma būtības .. Kā panākt to, lai vidējā LED mirgo @ 20ms kamēr pārējās skrien pa malu uz rinķi @ 75ms ?

----------


## karloslv

Eh... viss ar karoti. 

Ieviešam skaitītāju. x=0 sākumā. Katru reizi, kad izsaucas pārtraukums, palielinām skaitītāja vērtību. Piemēram, pātraukums izsaucas katras 5 ms.
Tālāk pārbaudām, ja x=2, ieslēdzam vidējo LED. Ja x=4, izslēdzam vidējo LED un uzstādām x=0.
Ar līdzīgām darbībām var panākt, ka pārējās diodes skraida, riņķo vai nu ko nu vajag.



```
ISR(TIMER1_COMPA_vect) {
  static cnt = 0;

  cnt++;
  if (cnt == 2) { 
    // ieslēdzam ledu
  }
  if (cnt == 4) {
    // izslēdzam ledu
    cnt = 0;
  }
    
      //darbojamies ar pārējiem lediem, iespējams, ieviešam vēl vienu ciklisku skaitītāju
  // un izmantojam switch(), ja citādi neprotam 
}
```

----------


## JDat

rakstīšu kā maku (pseidokods):
Init(){
   setup timer to 5 msec;
   setup timerIRQ;
};
Main(){
      sleep
};


On TimerIRQ(){
count=count+1
If count=4 then Do 20 msec stuff: blinken center LED;
If count=15 then Do 75 msec stuff: Blinken outer LEDs;
};

Blinken center LED(){
if led off then led on else led off;
};

Blinken Outer led(){
selec case bilden
        case bilden 1
                do bilden 2
        case bilden 2
                 do bilden 3
        case bilden 3
                 do bilden 1
end select
};

Idejiski. Ja šitādu principu sanāk realizēt, tad nianses jau mācēši piekoriģēt.

(C) Vikinga ideja par vienu taimeri.

----------

