2016年4月12日 星期二

Arduino Tiny RTC I2C Module

最近在學習Arduino和RTC的使用,看了葉難先生寫的「輕鬆入門Arduino範例分析與實作設計」一書,其中提到DS1307即時時鐘晶片的使用。就很有興趣的想買一顆來試試,到ICSHOP網站一看,哇!一顆要79塊台幣。這這也不算便宜,而且還要買石英晶體和其他小零件,特別是要一個CR2032電池座,還要把這些東西焊在一起。想想自己手藝不精,眼力也不行了,只怕這些零件到時玩過就散在一邊,浪費了。
沒想到,看到他們也賣另一個[DS1307時鐘模組],而且只要60塊台幣,內含DS1307晶片、石英晶體、CR2032電池座等,還都焊的好好的。

那就先來試試了。
貨到了,看了一下電路圖和文件。哈,除了DS1307外,還有一顆24C32 32K I2C EEPROM,還留了3個接點給DS18B20溫度感測器。太多東西可以玩了,當下不知由那裡玩起啊。
先Google一下好了,果然有一大堆的資料。首先由Matthew的Arduino RTC: TinyRTC v1 with Arduino Mega 2560開始看。
他說只要接Vcc, GND, SCL, SDA這四條線就好了。然後他不知由那裡找到的三支草稿碼:SetRTC,GetRTC,I2CScanner。首先用I2CScanner來找DS1307的位址,嗯,是0x68。
然後再用SetRTC這支來設定日期時間,嘔,要直接改程式才能設定哦!再來就是可以用GetRTC這支來讀取日期時間了。試了一下,沒問題,都可以正常運作的。而且,這三支都只用到內建的Wire程式庫。

可是第一個問題,就是要設定日期時間,還要改草稿碼,然後再上傳,實在有點不方便啊!
此時回頭看看葉難的書,發現他用的是另外的方法,是別的程式庫。不過葉先生寫的設定日期時間的程式很好用的,我就先直接把Matthew的草稿碼GetRTC改成可以設定日期時間。

/* Downloaded from http://projectsfromtech.blogspot.com/
*Connect SCL, SDA, Vcc, and GND
*Open Serial Monitor and enjoy!
*/

//Arduino 1.0+ Only

#include "Wire.h"
#define DS1307_ADDRESS 0x68

void setDateTime(byte second, byte minute, byte hour, 
    byte weekDay, byte monthDay, byte month, byte year);

void setup(){
  Wire.begin();
  Serial.begin(9600);
}

void loop(){
  printDate();
  delay(1000);
}

void pf(const char *fmt, ...) {
  char tmp[128]; // max 128 chars
  va_list args;
  va_start(args, fmt);
  vsnprintf(tmp, 128, fmt, args);
  va_end(args);
  Serial.print(tmp);
}

byte decToBcd(byte val){
// Convert normal decimal numbers to binary coded decimal
  return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val)  {
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}

void printDate(){

  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);

  byte zero = 0x00;
  Wire.write(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());

  //print the date EG   3/1/11 23:59:59
  Serial.print(month);
  Serial.print("/");
  Serial.print(monthDay);
  Serial.print("/");
  Serial.print(year);
  Serial.print(" ");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.println(second);
}

void serialEvent()
{
  int type = Serial.read();
  int v = 0;
  int temp;
  while ((temp =  Serial.read()) > '0' - 1) {
    pf("temp - 0 : %d\n", temp - '0');
    v = v * 10 + (temp - '0');
    pf("v : %d\n", v);
  }
  pf("type: %c\n", type);
  pf("v : %d\n", v);
  // -------------------------------
  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);

  byte zero = 0x00;
  Wire.write(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  byte s = bcdToDec(Wire.read());
  byte m = bcdToDec(Wire.read());
  byte h = bcdToDec(Wire.read() & 0b111111); //24 hour time
  byte weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  byte d = bcdToDec(Wire.read());
  byte M = bcdToDec(Wire.read());
  byte y = bcdToDec(Wire.read());
  
  switch(type) {
    case 'y':
      y = v - 2000;
      break;
    case 'M':
      M = v;
      break;
    case 'd':
      d = v;
      break;
    case 'h':
      h = v;
      break;
    case 'm':
      m = v;
      break;
    case 's':
      s = v;
      break;
    default:
     Serial.println("Wrong\n");
     break;
  }
  
  setDateTime(s, m, h, weekDay, d, M, y);
}

void setDateTime(byte second, byte minute, byte hour, 
    byte weekDay, byte monthDay, byte month, byte year) {
  byte zero = 0x00;
    
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero); //stop Oscillator

  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(weekDay));
  Wire.write(decToBcd(monthDay));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));

  Wire.write(zero); //start 

  Wire.endTransmission();
}



跑起來的樣子,如下圖:
設定日期時間的方法和葉先生書上寫的一樣,在上圖上方的文字框內輸入y2017後,再按Enter就可以把年份設成2017。要設定月份就用M09之類,日期就用d01之類,小時就用h12之類,分鐘就用m20之類,秒數就用s30之類。

沒想到一個RTC就有這許多玩意可以玩,模組上還有24C32 晶片,放在那裡沒用到呢!下次有時間,再來研究了。
張貼留言