marți, 14 mai 2013

Ceas de timp real (RTC) cu DS1307 si Arduino

   Deoarecea placa de dezvoltare Arduino se bazeaza pe un microcontroler ATmega 328 (sau cele mai vechi pe ATmega168 sau ATmega8), nu au incorporat un "ceas de timp real", care sa "numere si sa memoreze" timpul trecut, secunde, ore, zile, luni, ani si in cazul cand placa de dezvoltare a fost deconectata de la sursa de alimentare.
   Un integrat care sa faca acest lucru este DS1307 produs de MAXIM INTEGRATED, dupa cum se poate afla din fisa tehnica (datasheet).

   Am desenat cu ajutorul programului EAGLE PCB DESIGN SOFTWARE o schema, pentru a realiza si o varianta proprie de cablaj:
 
   Acest modul are modul de comuncare prin protocol i2c (2 fire active, SDA = intrare/iesire date, respectiv SCL = intrare seriala ceas), ceasul intern se bazeaza pe un cristal de cuart de 32,768kHz (cum sunt cele din ceasurile de mana), iar partea de alimentare de rezerva (in cazul intreruperii alimentarii) se realizeaza cu o baterie de 3V tip CR2302 (cum sunt cele de pe placile de baza ale calculatoarelor (PC), dar s epot folsi si 2 inseriate de 1,5V...
   Pe site-ul Arduino se gasesc informatii despre libraria RTC-ului, dar si la ROBOFUN. O prezentare pas cu pas a modulul de asamblare a unui kit RTC cu DS1307 si conectare la un Arduino se gaseste la Adafruit Learning System.
   Prezentare in limba romana am gasit in articolul http://www.electronicstefan.ro/2013/02/ceas-de-timp-real-rtc-cu-ds1307-si-arduino/ de pe blogul Electronic Stefan.

   Schema "clasica" de conectare pentru modulul RTC folosind protocolul de communicare i2c este:
   In articolul Using the ATMEGA168/Arduino with a DS1307 Real Time Clock scris de Lewis Loflin gasim o schema si un sketch care soloseste 3 butoane pentru reglajul orelor si minutelor:
// http://www.bristolwatch.com/arduino/arduino_ds1307.htm

#include <Wire.h> // specify use of Wire.h library.

byte blinkPin = 13;
byte SW0 = 4;
byte SW1 = 5;
byte SW2 = 6;


void setup()

{
  Wire.begin(); // join i2c bus (address optional for master)
  Serial.begin(9600);
  pinMode(blinkPin, OUTPUT);
  digitalWrite(blinkPin, 0);

  pinMode(SW0, INPUT);  // for this use a slide switch
  pinMode(SW1, INPUT);  // N.O. push button switch
  pinMode(SW2, INPUT);  // N.O. push button switch

  digitalWrite(SW0, HIGH); // pull-ups on
  digitalWrite(SW1, HIGH);
  digitalWrite(SW2, HIGH);
}

void loop()
{
  Wire.beginTransmission(0x68);
  Wire.write(0);
  Wire.endTransmission();

  Wire.requestFrom(0x68, 7);
  byte secs = Wire.read();
  byte mins = Wire.read();
  byte hrs = Wire.read();
  byte day = Wire.read();
  byte date = Wire.read();
  byte month = Wire.read();
  byte year = Wire.read();

  // hours, minutes, seconds

  Serial.print("The time is "); 
  if (hrs < 10) Serial.print("0");
  Serial.print(hrs,HEX);    
  Serial.print(":");
  if (mins < 10) Serial.print("0");
  Serial.print(mins, HEX);
  Serial.print(":");
  if (secs < 10) Serial.print("0");
  Serial.println(secs, HEX);

  // use MM-DD-YYYY

  Serial.print("The date is "); 
  if (month < 10) Serial.print("0");
  Serial.print(month,HEX);    
  Serial.print("-");
  if (date < 10) Serial.print("0");
  Serial.print(date, HEX);
  Serial.print("-");
  Serial.print("20");
  if (year < 10) Serial.print("0");
  Serial.println(year, HEX);
  Serial.println();


  if (!(digitalRead(SW0))) set_time(); // hold the switch to set time
  delay(1000);    //wait a second before next output
  toggle(blinkPin);
} 

// toggle the state on a pin
void toggle(int pinNum) 
{  
  int pinState = digitalRead(pinNum);
  pinState = !pinState;
  digitalWrite(pinNum, pinState); 
}

void set_time()   {
  byte minutes = 0;
  byte hours = 0;

  while (!digitalRead(SW0))  // set time switch must be released to exit
  {
    while (!digitalRead(SW1)) // set minutes
    { 
      minutes++;          
      if ((minutes & 0x0f) > 9) minutes = minutes + 6;
      if (minutes > 0x59) minutes = 0;
      Serial.print("Minutes = ");
      if (minutes >= 9) Serial.print("0");
      Serial.println(minutes, HEX);

      delay(750);
    }

    while (!digitalRead(SW2)) // set hours
    { 
      hours++;          
      if ((hours & 0x0f) > 9) hours =  hours + 6;
      if (hours > 0x23) hours = 0;
      Serial.print("Hours = ");
      if (hours <= 9) Serial.print("0");
      Serial.println(hours, HEX);
      delay(750);
    }

    Wire.beginTransmission(0x68); // activate DS1307
    Wire.write(0); // where to begin
    Wire.write(0x00);          //seconds
    Wire.write(minutes);          //minutes
    Wire.write(0x80 | hours);    //hours (24hr time)
    Wire.write(0x06);  // Day 01-07
    Wire.write(0x01);  // Date 0-31
    Wire.write(0x05);  // month 0-12
    Wire.write(0x09);  // Year 00-99
    Wire.write(0x10); // Control 0x10 produces a 1 HZ square wave on pin 7. 
    Wire.endTransmission();
  }    
}

   Am completat schema modululului cu un LED care clipeste cu frecventa de 1Hz:
 
17.mai.2013
   O varianta care nu mai contine bateria de 3V, ci doar un conector cu 2 pini:


03.06.2013
   Am realizat, spre rusinea mea, ca tutoriale sau articole, despre ceas cu DS1307 si Arduino, in limba romana se mai gasesc pe net, asa ca o sa le enumar:
- tutorialul intitulat KitDS1307 de la ROROID;
- articolul intitualt DS1307 RTC - ceas de timp real de pe blogul Arduino in Romania;






joi, 9 mai 2013

Interfata i2c la LCD pentru Arduino

    Deoarece am incarcat de pe mai multe calculatoare programioarele (sketch-urile) pentru Arduino, am avut surpriza neplacuta sa constat ca uneori apar probele cu librariile si mai ales cu porturile, adresele... la interfata i2c dintre Arduino si afisajul LCD cu 165 coloane si 2 randuri, pe care o folosisem la afisarea temperaturii si umiditatii pe un LCD cu 16 coloane si 2 randuri (16x2), vezi Ministatie meteo cu senzorul DHT11 si.. Arduino.

   Conectarea e simpla:

   Am cautat ceva informatii si am gasit pe forumul Arduino o discutie despre aceasta problema, care facea printre altele trimitere la un sketch numit "i2c scanner":



// --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// 
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//

#include <Wire.h>


void setup()
{
  Wire.begin();

  Serial.begin(9600);
  Serial.println("\nI2C Scanner");
}


void loop()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ ) 
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) 
    {
      Serial.print("Unknow error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
}


   Trebuie sa descarcam o librarie pentru afisaje LCD care include si acest protocol de comunicare, pe care o gasim la https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads.
   Pe site-ul Arduino, se recomanda descarcarea librariei de la http://hmario.home.xs4all.nl/arduino/LiquidCrystal_I2C/
apoi am folosit primul sketch de la http://blog.gotencool.com/2012/03/arduino-lcd-via-i2c.html pe care-l mai testasem:


#include <Wire.h>
  
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); // 0x27 es la direccion del LCD 16x2
void setup(){
    lcd.init();
    lcd.backlight(); //enciende la iluminacion
    lcd.setCursor(0, 0);
    lcd.print("Probando i2c");
}
void loop(){
    delay(1000);
}

am schimbat adresa in 0x20 din 0x27 si apoi am inceput sa ma joc cu sketch-ul:


#include <Wire.h>
  
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x20,16,2); // 0x20 is adresss for LCC 16x2
void setup(){
   lcd.init(); 
  lcd.backlight(); //backlight is now ON
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  // Print a logo message to the LCD.
  lcd.print("www.tehnic.go.ro");  
  lcd.setCursor(0, 1);
  lcd.print("creat de niq_ro");
  delay (2500);
  lcd.clear();
   
  // Print a permanent message to the LCD.
  lcd.print(" teste interfata");
  lcd.setCursor(0, 1);
  lcd.print("i2c pt. LCD 16x2");
  delay (2500);
}
void loop(){
    delay(1000);
}


9.iul.2013
   Conectand placuta Arduino impreuna cu afisajul LCD si interfata i2c pe un calculator nou cu Windows 7, am constatat ca la programul de test nu se aprinde afisajul, asa ca am rulat si programiorul de verificare a adresei.. am (re)constatat ca adresa interfetei i2c pentru LCD1602 este 0x20...