Pages: [1]   Go Down
Author Topic: conflitto RTC e lib LiquidCrystal(modificata)?  (Read 1024 times)
0 Members and 1 Guest are viewing this topic.
Milan, Italy
Offline Offline
Newbie
*
Karma: 0
Posts: 11
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Salve a tutti, sto sviluppando un progetto espandendo quello della sveglia uscito su Wired(aggiunta di led, sensore luce ecc..)
Per comandare lo schermo lcd uso un SPI LCD Backpack acquistato su Adafruit, per risparmiare pin.
Ho installato correttamente la libreria LiquidCrystal modificata, se provo un esempio funziona tutto.
Se carico il mio codice SCHERMO NERO!
Se invece commento la parte di codice in cui dialoga con l' RTC (Philips PCF8563), oppure se collego l'lcd in modo classico, funziona tutto!
Credo che il problema sia un conflitto tra l'RTC e la libreria LiquidCrystal, ma non capisco perchè e come sistemarlo...

qui info su LCD backpack http://www.ladyada.net/products/i2cspilcdbackpack/


ecco a voi il codice, spero in qualche aiuto smiley

grazie!

Code:
// Sveglia Tutorial Wired Settembre 2010
//
// Versione 03


// libreria I2C per parlare con il PCF8563
#include <Wire.h>

// Codice di gestione del RTC (Real Time Clock)
#include "PCF8563.h"
// include the library code:
#include <LiquidCrystal.h>

int sensePin = 0;
int ledPin = 11;

// inizializza la libreria che gestisce gli LCD
LiquidCrystal lcd(3, 2, 4);

// Diamo un nome ai piedini connessi ai pulsanti
const int btn01Pin = 10;
const int btn02Pin = 9;
const int btn03Pin = 8;
const int btn04Pin = 7;


// variabili che contengono lo stato dei pulsanti
int btn01State = HIGH;
int btn02State = HIGH;
int btn03State = HIGH;
int btn04State = HIGH;

// variabli che contengono lo stato precedente del pulsante
int btn01Prev = HIGH;
int btn02Prev = HIGH;
int btn03Prev = HIGH;
int btn04Prev = HIGH;

// flag che segnale se un certo pulsante è stato effettivamente premuto
int btn01Pressed = false;
int btn02Pressed = false;
int btn03Pressed = false;
int btn04Pressed = false;


// Definizione stati
const int NORMAL  = 0;
const int ALARM1  = 1;
const int ALARM2  = 2;
const int ALARM3  = 3;
const int ALARM4  = 4;

// partiamo con stato NORMAL
int state = NORMAL;

// cache ore e minuti
int a_hh = 0;
int a_mm = 0;


// siamo in allarme?
int alarm = false;


// array della combinazione di sblocco
int unlock_sequence[4] = {
  1,2,3,4};

// stampa un numero aggiungendo uno zero prima
// dei valori inferiori a 10
void printPadded(int num) {
  if (num < 10)
    lcd.print("0");

  lcd.print(num,DEC);
}


// legge i 4 pulsati
void readButtons() {
  btn01State = digitalRead(btn01Pin);
  btn02State = digitalRead(btn02Pin);
  btn03State = digitalRead(btn03Pin);
  btn04State = digitalRead(btn04Pin);

  if ((btn01State == LOW) && (btn01Prev == HIGH)) {
    btn01Pressed = true;
  }
  btn01Prev = btn01State;

  if ((btn02State == LOW) && (btn02Prev == HIGH)) {
    btn02Pressed = true;
  }
  btn02Prev = btn02State;

  if ((btn03State == LOW) && (btn03Prev == HIGH)) {
    btn03Pressed = true;
  }
  btn03Prev = btn03State;

  if ((btn04State == LOW) && (btn04Prev == HIGH)) {
    btn04Pressed = true;
  }
  btn04Prev = btn04State;


}

// Dato il numero di un pulsate imposta il flag
// corrispondente se è premuto
int buttonPressed(int btn) {
  int result = false;

  switch(btn) {

  case 1:
    if (btn01Pressed) result = true;
    break;
  case 2:
    if (btn02Pressed) result = true;
    break;
  case 3:
    if (btn03Pressed) result = true;
    break;
  case 4:
    if (btn04Pressed) result = true;
    break;
  }

  btn01Pressed = false;
  btn02Pressed = false;
  btn03Pressed = false;
  btn04Pressed = false;


  return result;
}

// genera una sequenza semi a caso
void generateSequence() {
  randomSeed(analogRead(0));

  unlock_sequence[0] = random(1,5);
  unlock_sequence[1] = random(1,5); 
  unlock_sequence[2] = random(1,5); 
  unlock_sequence[3] = random(1,5);

  Serial.print(unlock_sequence[0]);
  Serial.print( " ");
  Serial.print(unlock_sequence[1]);
  Serial.print( " ");
  Serial.print(unlock_sequence[2]);
  Serial.print( " ");
  Serial.print(unlock_sequence[3]);
  Serial.println( " ");
}

// Mostra la sequenza sul display
void displaySequence(int n) {

  // visualizza sequenza
  lcd.setCursor(0,0);
  lcd.print("Premi   ");
  lcd.setCursor(0,1);
  if (n > 3)
    lcd.print(unlock_sequence[0]);
  else
    lcd.print(" ");   
  lcd.print(" ");
 
  if (n > 2)
    lcd.print(unlock_sequence[1]);
  else
    lcd.print(" ");   
  lcd.print(" ");
 
  if (n > 1)
    lcd.print(unlock_sequence[2]);
  else
    lcd.print(" ");   
  lcd.print(" "); 
 
  if (n > 0)
    lcd.print(unlock_sequence[3]);
  else
    lcd.print(" ");   
  lcd.print(" ");
}


// inizializza la scheda
void setup()
{
  //mettiamo a output il led
  analogReference(DEFAULT);
  pinMode(ledPin, OUTPUT);
 
  // mettiamo a INPUT gli ingressi dei pulsanti
  pinMode(btn01Pin,INPUT);
  pinMode(btn02Pin,INPUT);
  pinMode(btn03Pin,INPUT);
  pinMode(btn04Pin,INPUT);

  // LED 13 usato per il debug e per il cicalino
  pinMode(13,OUTPUT);

  // Apre comunicazione con l'RTC e lo inizializza
  Wire.begin();     // join i2c bus (address optional for master)
  Serial.begin(9600);  // per debugging
 
  /////// QUESTA E LA PARTE DI CODICE CHE DA PROBLEMI
  RTC.init();       // init variables, get info from the clock and store in in the register
  RTC.registersRTC[0] = 0;
  RTC.writeRTCregister(0);
  RTC.registersRTC[2] = 0;
  RTC.writeRTCregister(2);
  ////////

  // imposta il display
  // il nostro display è 1 riga di 16 caratteri ma internamente
  // crede di avere 2 righe di 8 caratteri
  // dovete aggiustare il codice in base al vostro display
  lcd.begin(8, 2);
  lcd.print("Hello world");
  generateSequence();
}

void loop()
{
  //gestione luce
  //legge dal sensore
  int val = analogRead(sensePin);
  //limuta a valori soglia
  val = constrain(val, 300, 750);
  //mappa i valori da 0 a 255
  int ledLevel = map(val, 300, 750, 255, 0);
  //accende il led a seconda della luminosità rilevata
  analogWrite(ledPin, ledLevel);
 
 
 
  // Legge l'RTC
  RTC.readRTC();
  // negli ultimi 20 secondi del minuto l'ora è aumentata di 40, mah..
  // è un baco della libreria ma non ho tempo di debuggarlo :) :)
  if (RTC.hour > 23) RTC.hour = RTC.hour - 40; 

  // legge i pulsanti
  readButtons();


  // in base allo stato in cui ci troviamo vengono eseguiti diversi
  // pezzi di codice.. poi un giorno devo scrivere un tuttorial
  switch(state) {

  // visualizza l'ora o l'allarme in base al pulsante 1
  case NORMAL:
    // se il pulsante 01 NON è premuto visualizzo l'ora
    if (btn01State == HIGH) {
     
      // se il pulsante 3 è premuto aumento le ore
      if (btn03Pressed) {
        RTC.hour++;
        // dopo 23 torna a 0
        if (RTC.hour  > 23) RTC.hour  = 0;
        // scrivi nell'RTC l'ora impostata
        RTC.writeRTC();
        // dopo aver gestito l'evento azzero il flag
        btn03Pressed = false;
      }

      // stessa cosa per i minuti     
      if (btn04Pressed) {
        RTC.minute++;
        if (RTC.minute  > 59) RTC.minute  = 0;
        RTC.writeRTC(); 
        btn04Pressed = false;
      }

      // visualizza ora
      lcd.setCursor(0,0);
      lcd.print("        ");
      lcd.setCursor(0,1);
      printPadded(RTC.hour);
      lcd.print(":");
      printPadded(RTC.minute);
      lcd.print(":");
      printPadded(RTC.second);
    }
    else {
      // pulsante 1 premuto allora aggiorniamo l'ora
      // dell'allarme
      if (btn03Pressed) {
        a_hh++;
        if (a_hh  > 23) a_hh  = 0;
        btn03Pressed = false;
      }

      if (btn04Pressed) {
        a_mm++;
        if (a_mm  > 59) a_mm  = 0;
        btn04Pressed = false;
      }
     
      //visualizza l'allarme
      lcd.setCursor(0,0);
      lcd.print("Alarm   ");
      lcd.setCursor(0,1);
      printPadded(a_hh);
      lcd.print(":");
      printPadded(a_mm);
      lcd.print(":");
      printPadded(0);
    }

    // banale verifica se è l'ora di far partire l'allarme
    if ((RTC.hour == a_hh) && (RTC.minute == a_mm) & (RTC.second == 0)) {
      alarm = true;

      // genera sequenza random
      generateSequence();
      state = ALARM1;
    }
    break;

  // gestisce la prima cifra dell'allarme
  case ALARM1:
    // do it
    displaySequence(4);
    if (buttonPressed(unlock_sequence[0])) {
      state = ALARM2;
    }
    break;

  // gestisce la seconda cifra dell'allarme
  case ALARM2:
    // do it
    displaySequence(3);
    if (buttonPressed(unlock_sequence[1])) {
      state = ALARM3;
    }
    break;

  // gestisce la terza cifra dell'allarme
  case ALARM3:
    // do it
    displaySequence(2);
    if (buttonPressed(unlock_sequence[2])) {
      state = ALARM4;
    }
    break;

  // gestisce la quarta cifra dell'allarme
  case ALARM4:
    // do it
    displaySequence(1);
    if (buttonPressed(unlock_sequence[3])) {
      alarm = false;
      state = NORMAL;     
    }
    break;
  }

  // suona l'allarme , 100 va regolato per avere il suono migliore
  if (alarm) {
    digitalWrite(13,HIGH);
    delayMicroseconds(100);
    digitalWrite(13,HIGH);
    delayMicroseconds(100);
  }
  else
    digitalWrite(13,LOW);


}
Logged

Milan, Italy
Offline Offline
Newbie
*
Karma: 0
Posts: 11
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Facendo ulteriori prove, ho scoperto che è RTC.init() a dare problemi, se commento questa riga di codice e lascio il resto, funziona!
Apparentemente l'orologio si comporta bene anche senza init(), come mai?
Logged

Global Moderator
Milano, Italy
Offline Offline
Edison Member
*****
Karma: 19
Posts: 1176
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Premetto che non ho trovato la libreria "PCF8563.h" ma solo questa ma non credo sia la stessa. Se sicuro che nella tua libreria esista la funzione init()? In quella che ti ho linkato esiste invece initClock().
Comunque puoi scoprirlo facilmente aprendo il file PCF8574.h o PCF8563.cpp e cercando se tra le funzioni definite c'è.
Controlla che nell'inizializzazione del RTC delle funzioni contenute nella libreria non sia già presente la funzione Wire.begin(), altrimenti vorrebbe dire che nel tuo setup è presente due volte, sicuramente non combina nessun guaio, però una sarebbe comunque di troppo.
Logged

F

Milan, Italy
Offline Offline
Newbie
*
Karma: 0
Posts: 11
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

La libreria "PCF8563.h" si trova qui insieme allo sketch:
https://github.com/mbanzi/Wired.it-Tutorials/tree/master/201009_sveglia/

da quello che vedo la funzione init() c'è..

in "PCF8563.cpp" nella init() non c'è Wire.begin(), ma in altre funzioni come readRTC() o writeRTC() è presente una "Wire.beginTransmission(RTC_ADDRESS)"

continuo a non capire perchè non gradisce la init()...se la commento sembra funzionare tutto!
Code:
/*
  PCF8563.h - Controlling the RTC PCF8563 from Arduino
  Copyright (c) 2009 David Cuartielles.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
  Created 5 January 2009 by David J. Cuartielles
*/

#ifndef Pins_Arduino_h
#include "pins_arduino.h"
#endif

#ifndef PCF8563_h
#define PCF8563_h

#define RST_RTC 2 // pin where we will get alarms from the clock

#define DAY_1 "Mo"
#define DAY_2 "Tu"
#define DAY_3 "We"
#define DAY_4 "Th"
#define DAY_5 "Fr"
#define DAY_6 "Sa"
#define DAY_7 "Su"

#include <inttypes.h>

#define RTC_ADDRESS 0x51
#define RTC_DATA_SIZE 0x0F

class PCF8563
{
  private:

  public:
    PCF8563();
    uint8_t BCD2byte(uint8_t number);

    uint8_t BCD2byte(uint8_t high, uint8_t low);
    uint8_t byte2BCD(uint8_t theNumber);
    uint8_t registersRTC[RTC_DATA_SIZE];
    uint8_t year;
    uint8_t month;
    uint8_t day;
    uint8_t hour;
    uint8_t minute;
    uint8_t second;
    uint8_t date;
    char auxBuffer[50];
    void init();

    void resetVars();

    char* getRTCarray();
    char* getTimestamp();
    void writeRTC();
    void readRTC();
    void writeRTCregister(uint8_t theAddress);
    void readRTCregister(uint8_t theAddress);
    void setWatchdog(uint8_t seconds, uint8_t tenths);
    void resetWatchdog();
};

extern PCF8563 RTC;

#endif
Logged

0
Offline Offline
Shannon Member
****
Karma: 131
Posts: 10474
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

analizziamo la init():
Code:
void PCF8563::init()
{
  // enable the internal pull-up resistor for the RTC-interrupt pin
  pinMode(RST_RTC, INPUT);
  digitalWrite(RST_RTC, HIGH);
 
  // initialize the variables used to store the data
  // from the RTC
  readRTC();
}

direi che readRTC(); non dà problemi perchè non la usi.

pinMode(RST_RTC, INPUT);
digitalWrite(RST_RTC, HIGH);

dove #define RST_RTC 2 è definito nel file .h

server per leggere se l'RTC ha fatto scattare la sveglia, quindi se non ti serve è ok non usare init().

Ora bisognerebbe vedere cosa utilizza il pin 2... beh nel tuo codice...
// inizializza la libreria che gestisce gli LCD
LiquidCrystal lcd(3, 2, 4);

bel casino vero?
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Milan, Italy
Offline Offline
Newbie
*
Karma: 0
Posts: 11
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

per prima cosa GRAZIE, almeno ora ho capito dove sta esattamente il problema!
il controllo sulla sveglia viene gestito direttamente nello sketch, senza usare quello del RTC, quindi a questo punto non uso la init() e stop.

In generale però, se dovessi utilizzare la init() dovrei risolvere il conflitto sul pin 2 giusto?
Logged

0
Offline Offline
Shannon Member
****
Karma: 131
Posts: 10474
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

semplicemente in LiquidCrystal lcd(3, 2, 4); usi un altro pin al posto del 2 smiley
e comunque sul 2 dovresti collegare il pin dell'RTC che fa da allarme...cosa che non hai fatto.
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Milan, Italy
Offline Offline
Newbie
*
Karma: 0
Posts: 11
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

chiarissimo grazie!
Logged

Pages: [1]   Go Up
Jump to: