Go Down

Topic: Librerie e Timer1 (Read 10165 times) previous topic - next topic

zoomx

Sapete dirmi se qualcuna di queste librerie usa il Timer1, quello a 16 bit?

Code: [Select]
#include <Wire.h>
#include <DS1307new.h>
#include <SD.h>


PaoloP

Nessuna delle tre, a quanto mi risulta.

zoomx

Grazie,

il motivo della richiesta è che ho un programma in cui sembra che l'interrupt del timer1 non avvenga mai (dentro fra le altre cose accendo un led e il led non si accende mai) e sospettavo che qualcuna delle librerie interferisse perché invece un programmino di test senza le librerie funziona. La documentazione ufficiale purtroppo è un po' oscura per cui avevo chiesto qui. L'errore sarà da un'altra parte.

PaoloP

Non ho guardato la documentazione ma il codice sorgente delle librerie dell'IDE 1.0.4 e della DS-new presa da qui --> https://code.google.com/p/ds1307new/
;)
Quando non sai cosa fa una libreria... leggi il codice.  8)

nid69ita


Grazie,
il motivo della richiesta è che ho un programma in cui sembra che l'interrupt del timer1 non avvenga mai (dentro fra le altre cose accendo un led e il led non si accende mai) e sospettavo che qualcuna delle librerie interferisse perché invece un programmino di test senza le librerie funziona. La documentazione ufficiale purtroppo è un po' oscura per cui avevo chiesto qui. L'errore sarà da un'altra parte.


Perchè non provi a toglierne una alla volta invece di tutte e tre in un colpo? In questo modo puoi capire se per caso è una di queste.
Teoricamente: >> In the Arduino world the Servo library uses timer1 on Arduino Uno (timer5 on Arduino Mega).
http://letsmakerobots.com/node/28278
my name is IGOR, not AIGOR

zoomx

Questa è una buona idea, anche se ogni volta devo commentare un sacco.

leo72

Andrebbe studiato sia il tuo codice che quello delle librerie e vedere se magari in qualche punto vengono disattivati gli interrupt per una qualche ragione.

zoomx

E' quello che farò ma prima volevo eliminare le cause ovvie. Grazie per l'aiuto.

padoang

Qui http://playground.arduino.cc/code/timer1 c'e' un pezzo di codice che ho gia' provato e funziona sicuramente per testare il Timer1, Giorgio

leo72

Ma nel tuo codice usi interrupt?

zoomx

Come ho scritto prima, il codice del solo interrupt funziona.

E' un codice semplice, metto il Timer1 a conteggiare e faccio scattare l'interrupt all'overflow, dopo poco più di 4 secondi. Nel codice di prova nella routine cambiavo lo stato del piedino digitale 13 facendo così accendere e spegnere il led corrispondente.

Una volta messo il tutto nel programma più complesso ho notato che l'interrupt non partiva mai. Il resto funzionava. Poiché l'SD fa uso dello stesso piedino 13 ho cambiato piedino e adesso curiosamente il programma si inchioda nel mezzo della stampa su seriale di una stringa fissa, stampa che dovrebbe avvenire prima dell'avvio della routine che abilita l'interrupt. Non ci sono altri interrupt se non quelli usati dalle librerie.
Ho anche aggiunto questa routine presa dal Playground

Code: [Select]
int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}


per controllare se non ci fossero problemi di RAM ma sembra che non ce ne sono. Fra l'altro tutti i print a stringa fissa hanno l'(F("") in modo che la stringa non venga ricopiata in RAM.

Prima di arrendermi e chiedere aiuto però vorrei provare a scovare l'errore o gli errori. Solo che la documentazione è un po' carente.

La routine con interrupt che funziona è quella in fondo. Il progetto è quello di un Datalogger con menù dove l'acquisizione viene fatta su interrupt in modo che vada per i fatti suoi e sia sempre possibile accedere al Datalogger via seriale. Poiché il DS1307 non ha allarmi allora sto usando il Timer1 controllando che non sia l'ora dell'acquisizione, nell'esempio 5 minuti. Le acquisizioni devono essere fatte non ogni 5 minuti ma a 0, 5, 10, 15 ecc. minuti dell'ora, in modo da poter essere confrontate con misure prese da altri datalogger. Per cui quando scatta il timer controllo che i minuti non siano un multiplo di 5. Se invece del DS1307 usassi il PCF8563 metterei un allarme li e farei dormire il datalogger per il resto del tempo in modo da consumare poco.
Questo codice di prova è un po' sporco, non usa ancora il DS1307 ma la swRTC di leo72, però funziona perfettamente. Se abilito l'interrupt, ogni 5 minuti (circa, perde qualche secondo ma non ha importanza) stampa l'orario.

Il codice lo metto nel post seguente altrimenti supero il limite di 9500 caratteri.

zoomx

Code: [Select]
#include <Arduino.h>

#include <swRTC.h>

// avr-libc library includes
//http://arduinodiy.wordpress.com/2012/02/28/timer-interrupts/
#include <avr/io.h>
#include <avr/interrupt.h>

/*
Programma di test per provare la libreria swRTC e il modo di campionare ogni 5 minuti
a partire da 00. Il campionamento avviene via interrupt e quindi contemporaneamente si
gestisce un menu.
Aggiungiamo il settaggio della data e dell'ora.
Aggiungiamo lo start e stop dell'acquisizione
*/

//***************
//http://www.velocityreviews.com/forums/t316565-convert-__date__-to-unsigned-int.html
//read corrections!!!!!!
//http://lists.gnu.org/archive/html/avr-gcc-list/2009-01/msg00159.html
#define YEAR ((((__DATE__ [7] - '0') * 10 + (__DATE__ [8] - '0')) * 10 \
+ (__DATE__ [9] - '0')) * 10 + (__DATE__ [10] - '0'))

/* Month: 0 - 11 */
#define MONTH (__DATE__ [2] == 'n' ? (__DATE__ [1] == 'a' ? 0 : 5) \
: __DATE__ [2] == 'b' ? 1 \
: __DATE__ [2] == 'r' ? (__DATE__ [0] == 'M' ? 2 : 3) \
: __DATE__ [2] == 'y' ? 4 \
: __DATE__ [2] == 'l' ? 6 \
: __DATE__ [2] == 'g' ? 7 \
: __DATE__ [2] == 'p' ? 8 \
: __DATE__ [2] == 't' ? 9 \
: __DATE__ [2] == 'v' ? 10 : 11)

#define DAY ((__DATE__ [4] == ' ' ? 0 : __DATE__ [4] - '0') * 10 \
+ (__DATE__ [5] - '0'))
//*******************


#define INLENGTH 5          //Needed for input with termination
#define INTERMINATOR 13     //Needed for input with termination
char inString[INLENGTH+1];  //Needed for input with termination
int inCount;                //Needed for input with termination

#define LEDPIN 13

int ore,minuti,secondi;
//String MyString;
char Stringa2[2];
swRTC rtc;
boolean AcqDone = false;  //It's time to acquisition!
boolean InAcq = false;    //If true=Acquisition is made during intterrupt
char comm;

void GetCharFromSerial(){
    Serial.flush(); //flush all previous received and transmitted data
    inCount = 0;
          do
          {
            while (!Serial.available());             // wait for input
            inString[inCount] = Serial.read();       // get it
            //++inCount;
            if (inString [inCount] == INTERMINATOR) break;
          } while(++inCount < INLENGTH);
          inString[inCount] = 0;                     // null terminate the string
          //ch=inString;
    Serial.print("Ricevuto->");
    Serial.println(inString);
    comm=inString[0];
}

void GetTime(){
    Serial.println("Get Time");
    Serial.print(rtc.getHours(), DEC);
    Serial.print(":");
    Serial.print(rtc.getMinutes(), DEC);
    Serial.print(":");
    Serial.print(rtc.getSeconds(), DEC);
    Serial.print(" -- ");
    Serial.print(rtc.getDay(), DEC);
    Serial.print("/");
    Serial.print(rtc.getMonth(), DEC);
    Serial.print("/");
    Serial.println(rtc.getYear(), DEC);

}
void SetTime(){
    Serial.println("Set Time");
    //digitalWrite(13, LOW);
    Serial.print("Year");
    GetCharFromSerial();
    ore=atoi(inString); //Use the same variables for Year..
    Serial.print("Month");
    GetCharFromSerial();
    minuti=atoi(inString);
    Serial.print("Day");
    GetCharFromSerial();
    secondi=atoi(inString);

    rtc.stopRTC();
    rtc.setDate(ore,minuti,secondi);
    rtc.startRTC();

    Serial.print("Hour");
    GetCharFromSerial();
    ore=atoi(inString); //Use the same variables for Year..
    Serial.print("Minutes");
    GetCharFromSerial();
    minuti=atoi(inString);
    Serial.print("Seconds");
    GetCharFromSerial();
    secondi=atoi(inString);

    rtc.stopRTC();
    rtc.setTime(ore, minuti, secondi);
    rtc.startRTC();

    Serial.print("RTC changed->");
    GetTime();
}

void StartAcq(){
    Serial.println("Start Acquisition");
    if (InAcq==true) return;
    // initialize Timer1
    cli();         // disable global interrupts
    TCCR1A = 0;    // set entire TCCR1A register to 0
    TCCR1B = 0;

    // enable Timer1 overflow interrupt:
    TIMSK1 = (1 << TOIE1);

    // Set CS10 bit so timer runs at clock speed:
    TCCR1B |= (1 << CS10);
    TCCR2B &= ~(1 << CS11);
    TCCR1B |= (1 << CS12);
    //Serial.println(TCCR1B);
    // enable global interrupts:
    sei();
    InAcq=true;

}
void Download(){
    Serial.println("Download Data");
}
void StopAcq(){
    Serial.println("Stop Acquisition");
    cli();         // disable global interrupts
    TCCR1A = 0;    // set entire TCCR1A register to 0
    TCCR1B = 0;
    sei();
    InAcq=false;

}

void PrintMenu(){
    Serial.println("1 Start Acquisition");
    Serial.println("3 Stop Acquisition");
    Serial.println("8 Info");
    Serial.println("T Get Time");
    Serial.println("t Set Time");
    Serial.println("--------------------");
    Serial.println("Type the number and press enter");
}

void ParseMenu(char Stringa){
    Serial.println("Parse Menu");
    switch (Stringa) {
    case '1':
      StartAcq();
      break;
    case '2':
      Download();
      break;
    case '3':
      StopAcq();
      break;
    case '8':
      Serial.print("Acquisition->");
      Serial.println(InAcq,DEC);
      break;
    case 'T':
      GetTime();
      break;
    case 't':
      SetTime();
      break;
    default:
      Serial.print("Command Unknown! ->");
      Serial.println(Stringa,HEX);
    }
}
void setup()
{
Serial.begin(9600);

// initialize the digital pin as an output.
// Pin 13 has an LED connected on most Arduino boards:
pinMode(13, OUTPUT);

//Initialize swRTC
rtc.stopRTC();
//rtc.setClockWithTimestamp(__TIMESTAMP__);
rtc.setDate(DAY,MONTH+1,YEAR);
//MyString=__TIMESTAMP__;
Stringa2[0]=__TIMESTAMP__[11];
Stringa2[1]=__TIMESTAMP__[12];
Stringa2[2]=0;
ore = atoi(Stringa2);

Stringa2[0]=__TIMESTAMP__[14];
Stringa2[1]=__TIMESTAMP__[15];
minuti = atoi(Stringa2);

Stringa2[0]=__TIMESTAMP__[17];
Stringa2[1]=__TIMESTAMP__[18];
secondi = atoi(Stringa2);
/*
Serial.print(ore);
Serial.print(":");
Serial.print(minuti);
Serial.print(":");
Serial.println(secondi);
*/
rtc.setTime(ore, minuti, secondi);

rtc.startRTC();
GetTime();

// initialize Timer1
    cli();         // disable global interrupts
    TCCR1A = 0;    // set entire TCCR1A register to 0
    TCCR1B = 0;

    // enable Timer1 overflow interrupt:
    TIMSK1 = (1 << TOIE1);

    // Set CS10 bit so timer runs at clock speed:
    TCCR1B |= (1 << CS10);
    TCCR2B &= ~(1 << CS11);
    TCCR1B |= (1 << CS12);
    //Serial.println(TCCR1B);
    // enable global interrupts:
    sei();
    InAcq=true;

}

void loop()
{
    PrintMenu();
    GetCharFromSerial();

    ParseMenu(comm);
    //Serial.println(__TIMESTAMP__);


}

ISR(TIMER1_OVF_vect)
{
digitalWrite(LEDPIN, !digitalRead(LEDPIN));
if (rtc.getMinutes()%5==0) {  //Se il resto è zero i minuti finiscono per zero o 5
            if (AcqDone==false){  //Siccome il controllo viene fatto ogni 30 secondi evita
                GetTime();        //che la routine scatti 2 volte ad es a 05 e 35 secondi
                //Serial.println(); //usando la boolean AcqDone
                AcqDone=true;
            }
            /*
            else {
            Serial.println(AcqDone);
            */
            }

    else
    {
        AcqDone=false;
    }
}


leo72

Con la swRTC non hai problemi perché essa usa il timer 2.

zoomx

Infatti, la tua libreria è ben documentata, sapevo che usava un altro Timer.

Nel programma il blocco avviene in questa routine, presente anche nell'esempio messo sopra.

Code: [Select]
void GetCharFromSerial(){
   //Get string from serial and put in inString
   //first letter in comm
    Serial.flush(); //flush all previous received and transmitted data
    inCount = 0;
          do
          {
            while (!Serial.available());             // wait for input
            inString[inCount] = Serial.read();       // get it
            //++inCount;
            if (inString [inCount] == INTERMINATOR) break;
          } while(++inCount < INLENGTH);
          inString[inCount] = 0;                     // null terminate the string
          //ch=inString;
    Serial.print(F("Ricevuto->"));
    Serial.println(inString);
    comm=inString[0];
}


Si pianta dopo aver stampato il "Ri" di "Ricevuto". In questa fase ancora l'interrupt non è stato avviato. Mi chiedo se non sia un problema di questa routine, magari diverso da quello dell'interrupt, anche se nell'esempio per il timer che ho postato sopra e in altri sketch non mi ha dato problemi. La stringa che riceve è di un solo carattere terminata con il CR (ASCII 13).

PaoloP

Ho copiato il tuo sketch. Compila, ma l'IDE (formattazione automatica) mi dice che c'è una parentesi chiusa di troppo.
Boh!

Go Up