Kahden timerin käynnistys (Atmel328)

Hei!

Olisiko jollakulla vinkkiä siitä, miten Arduinossa saisi kaksi ajastinta käyntiin, niin että ne kävisivät ikään kuin tausta-ajona muun ohjelman ohessa? Jonkinlaisilla keskeytyksillä varmaan onnistuu?

Tarve olisi:

main loop
code…
code…
StartTimer1(10)
StartTimer2(5)
code…
code.
end

Timerien tarkoitus olisi sytyttää ledi pinnoissa 11 ja 12, ja sammuttaa ledi parametrina annetun ajan kuluttua. Ajastimen tarkkuus ei ole kriittinen.

Tämä pätkä tulisi lisäksi sellaiseen paikkaan, johon mennään Sleep Modesta palaamisen jälkeen, mikä ehkä aiheuttaa lisää päänsärkyä… Ohjelmoin C:lla.

Keskeytyksillä nimen omaan.
Oisiko tämä hyvä lähtökohta?
http://www.arduino.cc/playground/Main/MsTimer2
Miten se sitten tuossa tehdäänkään, kopioidaan toiselle timerille tai jotain vastaavaa. En katsonut miten tuo on toetettu, mutta sanovat ainakin keskytyksillä tehdyksi.

Olen yrittänyt saada MsTimer2:ta, mutta en ole saanut sitä kääntymään… koodissa on jotain kupruja tai sitten se on tehty eri IDElla (minulla on käytössä 0022).

Virheilmoitus auttaisi kovasti arvaamaan vikaa.

Ja tuo ei taida olla hakemasi ratkaisu vaan ehdotin sitä omaan ongelmaasi pohjaksi miten keskeytyksillä ajetaan niitä laskureita. Tuohan tekee tosiaan yhdellä timerillä vain juttuja. Tarvitset kaksi keskeytystä esimerkiksi ISR(TIMER1_COMPA_vect) ja ISR(TIMER1_COMPB_vect) jotka sitten jossain sopivassa kohdassa laukeavat.

Mikäköhän tässä mättää? Esimerkki on ihan copy-pastella otettu, ja virhettä pukkaa…

Eli

// Toggle LED on pin 13 each second
#include <Avr/MsTimer2.h>

void flash() {
static boolean output = HIGH;

digitalWrite(13, output);
output = !output;
}

void setup() {
pinMode(13, OUTPUT);

MsTimer2::set(500, flash); // 500ms period
MsTimer2::start();
}

void loop() {
}

MsTimer2.h

#ifndef MsTimer2_h
#define MsTimer2_h

#include <avr/interrupt.h>

namespace MsTimer2 {
extern unsigned long msecs;
extern void (*func)();
extern volatile unsigned long count;
extern volatile char overflowing;
extern volatile unsigned int tcnt2;

void set(unsigned long ms, void (*f)());
void start();
void stop();
void _overflow();

}

#endif

Ja kääntäessä tulee virhe

sketch_jul31a.cpp.o: In function setup': C:\DOCUME~1\User1\LOCALS~1\Temp\build3140068248651898377.tmp/sketch_jul31a.cpp:18: undefined reference toMsTimer2::set(unsigned long, void (*)())’
C:\DOCUME~1\User1\LOCALS~1\Temp\build3140068248651898377.tmp/sketch_jul31a.cpp:19: undefined reference to `MsTimer2::start()’

Nimim. Ei se tyhmä ole, joka ei tiedä, vaan se, joka ei kysy :slight_smile:

Tässä löytämäni (toimiva) koodi, joka vilkuttelee lediä

electronicsblog.net/examples … tal-clock/

// timer example from electronicsblog.net
#define LED 11

boolean x=false;

ISR(TIMER1_OVF_vect) {
x=!x;
}

void setup() {

PinMode(LED, OUTPUT);

TIMSK1=0x01; // enabled global and timer overflow interrupt;
TCCR1A = 0x00; // normal operation page 148 (mode0);
TCNT1=0x0000; // 16bit counter register
TCCR1B = 0x04; // start timer/ set clock
};

void loop () {

digitalWrite(LED, x);

};

Osaako joku sanoa, pystyykö koodia modifiomaan niin, että tästä saisi ajastimen?
Eli vaikkapa kutsulla Delay1Timer(20) ohjelma sytyttää ledin noin 20 sekunniksi ja
sen jälkeen sammuttaa sen?

Olisin neuvoista kiitollinen.

Lauri Jämsä vastasi 2.8.2011:

En ole vuoteen pariin juurikaan AVR:ien kanssa pelaillut, mutta mitä nyt hämärästi muistan, niin timerin saa pois päältä asettamalla tuonne TCCR1B-rekisterin bitit CS12, CS11 ja CS10 nolliksi. Katso datalehden sivu 139:

‚Äú0 0 0 No clock source (Timer/Counter stopped).‚ÄĚ

atmel.com/dyn/resources/prod … oc8271.pdf


Kokeilin, ja toimii! Eli kun keskytys ISR(TIMER1_OVF_vect) on tarpeen lopettaa,
niin komennolla TCCR1B = 0x00; homma hoituu. Bitit voi asettaa nolliksi, sillä
rekisterin TCCR1B ‚Äď Timer/Counter1 Control Register B init-bitit ovat nollassa.

Pitää vielä kokeilla, lähteekö taas käyntiin rekisteriä muokkaamalla, luultavasti
kyllä.

Hyvä juttu, ja kiitos vastauksesta, sillä ankarasta nettiselauksesta huolimatta
en l√∂yt√§nyt kovin hyv√§√§ tapaa ‚Äútappaa‚ÄĚ ISR. Ilmeisesti k√§√§nt√§j√§ k√§√§nt√§√§ ohjelman
alussa olevan määrityksen jonkinmoisena makrona, ja siellähän se sitten pysyy
koodissa kuin kuppa Töölössä.

Kari

Kyllä. ISR on nimenomaan keskeytysrutiini ja sitä ei helposti saa muutettua. Tai funktio pointteri ja käskee sen ajaa…
ISR(){
*fp();
}
Kuitenkin itsellä on tuossa yhdessä projektissa kello, joka pyörii kokoajan ja keskeytykset ABC on aina vain yksi valittuna. Tän saa TIMSK, ETIMSK TIMSK0 TIMSK1 rekistereistä säädettyä. Riippuu AVR:n mallista. Kaikki keskeytykset käyvät sei(); komennolla ja estetään cli(); komennolla. Syytä tehdä esim eeprommia kirjoitettaessa.

http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html kertoo AVR:n keskeytyksistä.

Itsellä on käytössä ATMega8535, ATMega128, ATMega88, ATMega328 ja ATTiny2313 ja kaikki ovat erilaisia ja tulee luettua niiden datalehtiä melko paljon kun noiden kanssa pelaa. Atmelin datalehdet ovat hyviä ja parantuneet vain vuosien saatossa.

Ja jos haluat käpistellä jotenkin seuraavasti:

volatile uint16_t laskuri = 0;
ISR(KESKEYTYS_vect){
  laskuri++;
}
void funktio(void){
  while(laskuri){
    //tee jotain
  }
}

tarvitsee olla nimenomaan tuo volatile tuolla edessä. muuten tuo optimoituu joko ikuiseksi silmukaksi tai ohitetaan kokonaan ja joka kierroksen välein ei laskurin arvoa tarkisteta. volatile siis kertoo, etttä tätä arvoa muutetaan ulkoa päin.

Ja miten Arduino on sekottanut tämänkin, en tiedä.

Kiitos mainiosta vastauksesta.

Opin paljon ajastinkeskeytyksistä, ja jotain niiden käpistelystä.

MUTTA. Sovellukseni koodissa on kohta, joka pistää kontrollerin lepotilaan pian käynnistämisen jälkeen (sleep.h -includesta). Tarkoitus on miniminimoida virrankäyttö, kun ei ole tarvetta toimia (tavoitteena paristokäyttöisyys). Sleep sotkee jotenkin timer-ISR:t (1 ja 2), ja koodi ei enää etenekään wakeupin jälkeen niin kuin luulisi. Vaikka kaikki oleelliset ohjausmuuttujat on määritelty volatileksi. En tiedä mistä johtuu. Sleepin jälkeen ISR timer menee kerran läpi (FFFF asti) mutta sitten runko-ohjelma ei enää etene, vaan kontrolleri nukahtaa (menee sleep-tilaan).

Virrankäyttö on kriittinen kysymys, teen sovelluksen ja testit Duemilanoven boardilla ja nypin sitten piirin irti ja pistän sen omalle breadbordilleen, jossa voin minimoida virtaa syövät komponentit (kuten esim. regulaattorin). Meinaan myös ainakin yrittää kellottaa 32kHz kiteellä.

Sain tarvitsemani toteutettua ilman ISR-timereita, ja toimii, MUTTA mielestäni ratkaisuni on hiukka hanurista, sillä se ei ole oikein elegantti. Jos haluaisin käyttää ISR-timereita yhdessä sleepin kanssa, niin voisi olla aika paljon selvitettävää… ellei mitään patenttiratkaisua tule mieleen?

Hyviä tutkimisen kohteita:
sei(); Timerit ovat päällä? Varmasti keskeytysrutiinit pyörivät. Jos niistä vaikka vilkkuu ledi niin ota nukkuminen pois ja tarkista toimivuus.

Liian syvä uni voi olla myös ongelma. Timer2 voi herättää unilta Idlestä, Power-Savesta ja extended standbystä. Timer1 ei kaiketi osaa. Katselen doc8161.pdf sivua 39. Jos laite oli 328P.

Ja Block diagramista sanottakoon, että timerit voivat kellottua joko CLKasy tai CLKio ja tämä tarkoittaa power mode idlen käyttöä tai ulkoista 32k kidettä timer2:lle. Ja silloin laskureista vain timer2 herättää.

Tai sitten WDT:tä väärinkäyttämällä…

Tämä ei oikeastaan enää tähän ketjuun kuulu, mutta.

Voiko 16Mhz:n kiteen paikalle vain kylmästi lyödä 32kHz kiteen, ja heti toimii? :stuck_out_tongue:
Rakentelen siis breadbordille, johon ei tule juuri muuta kuin 328-piiri ja liittimet.

Ei ihan. Tarttee ainakin fuset ohjelmoida oikein. Sivulla 3, 26 ja 82 on ainakin luettavaa datasheetissä. lisäksi Fusejen ohjelmointi ja timer2 kannattaa lukea huolella. unohdinkohan jotain?

Rakentelin proton tyhjälle levylle (Target board MadEvilSciencesta, 3 taalaa, näitä myy Robomaa). Ulkoisina komponentteina kiteen 2 konkkaa ja 1 jännitevakavointikonkka, sekä piikkirimaa.

Tämä oli ensimmäinen proto, joka toimi laakista!!

Virrankulutus on lepotilassa nyt 760 mikroampeeria, mutta alemmas pitäisi painaa. Kide on nyt 16MHz, koitin heittää paikalle 32kHZ, mutta ei toiminut, niin kuin sanoitkin :slight_smile:

Eli mitä pitäisi nyt tehdä? Poltan Arduino Duemillanovella (kiskon piirin irti ja pistän tyhjän paikalleen…), mutta kidettä en kai voi kehitysalustaan vaihtaa.

Ja jos laitan asetukset 32kHZ, niin Duemillanove ei varmaan enää toimi. Pitäisiköhän hommata ISP_6 -polttokaapeli… voikohan Ardoinon IDEsta polttaa suoraan ISP_6 piuhalla?

Kari

Sillä Arduinollakin voi ohjelmoida piirejä: ruuvipenkki.fi/2011/01/13/ar … ointilaite

Moi

Kiitos kommentista!

Joo, olen tietoinen tuosta mainitsemastasi virittelystä. MUTTA siinä on, että alle pitää ladata ISR-softa, ja sitten käyttää ilmeisesti avrdudea tms. Ei se varmaan monimutkaista ole, mutta haen helppoa ja idioottivarmaa ratkaisua, jossa poltetun piirin toiminnan voisi todentaa heti; poltetun piirin siirrän breadbordille, mutta olisihan se kiva testata ennen siirtoa. Olen kokeillut EvilMadSciencen ISR Shieldia, mutta silläkään ei voi testata lopputoiminnallisuutta, ellei tee korttiin omia lisälangoituksia.

Jotenkin olen taipuvainen siihen, että tinaan Duemilanoven mikropiirinpitimen irti, ja juotan tilalle nollavoimakannan, johon saa poltettavan piirin kiinni ja irti enempiä repimättä. Näin saisin homman tehtyä Arduinon IDE:n uploadilla ilman erillistä ohjelmointilaitetta. Duemilanovessa voisin myös testata heti, että poltettu piiri toimii kuten pitääkin.

Kari

Edelleen mistään Arduinon ihanuudesta tietämättä, kysäsenpä tyhmiä.

Onko ihan mahdoton asia saada selville minne se .hex tiedosto menee ja sitten laittaa ne kuusi karvaa ja vaikka tuolla arduinolla tai sitten jollain vaikka tilata kolmenkympin + rahti olimexin isp ohjelmointi palikan? Polttaminen on mukavaa AVR burn-o-mat java softalla.

Tai vastaavasti tutustua Makefileen sen verran, että katsoo miten make program toimii. Se on melko suoraviivainen tiedosto ja kommentoitu, mitä yleensä AVR projektiessa tapaa. Lisäksi WinAVR:n mukana tulee hieno ohjelma Mfile, jolla voi samanlaisia Makefilejä tehdä.

Lopuksi… Voipi olla että pilaat Arduinosi ZIFfillä. Jos jostain kumman syystä saat kannan huonosti asennettua, voi softan debuggaus muuttua tuskalliseksi jos kanta aiheuttaa ongelmia. Esimerkiksi kide voi käyttäytyä todella huonosti. Kääydä vain välillä ja MCU toteaa, että nyt tää tarkoittaa tätä ja kello on päin seiniä.

Ohjenuorani on KISS (Keep It Simple, keep it Stupid). 30 vuotta koodanneena, en tosin avr-maailmassa.

Ajattelin järjestää asian näin:

  1. Kehityskone ja hiekkalaatikko (devolopment and sandbox): Duemilonuva tms. Arduinon vakiopulikka ehostettuna nollavoimakannalla. Nollavoimakannan saa toki piirilevylle, kun tinaa vakiokannan pois, tarvittaessa poraa 28 reikää vähän isommiksi, ja juottaa kiinni. Ei ongelmaa.
    Arduinon C++ IDE ohjelmointialustana. Menn√§√§n Arduinon ‚Äústandardin‚ÄĚ mukaan, k√§ytett√§viss√§ kirjastot yms. Arduinon tarjokkaat.
  2. Kun toimii, niin 328 irrotus ja siirto breadbordille.
  3. Testikone EvilMadSciencen Target boardille rakennettuna (sama kuin 1., paitsi että jännitteen regulointi, elektroniikan suojakset sekä USB puuttuu. Muutoin 1:1 Arduinon kanssa. Piikkirimoitus vastaa Arduinon I/O:ta.
  4. Valmis sovellus (ehkä myös Evilin) boardille, tässä voi koettaa erilaisia kiteitä. Liittimet yms. karsittu minimiin. ==> jos toimii niin hyvä, jos kärähtää jotain, niin korkeintaan 328 (5e).

Ei tämä mielestäni hullummalta vaikuta. Saa esittää tietenkin paremmankin läpivientiputken :slight_smile:

-kari

Offtopiccia, mutta eikös se ole Keep it simple, Stupid! :smiley:

Joo noin se taisi olla :smiley:

Nimim. Stupid Dementicus