Sylphys works

SW12887 RTCモジュール

SW12887パッケージ内容 SW12887パッケージ内容

SW12887パッケージ内容
※ボタン電池の銘柄は変わる場合があります。
家電のケンちゃん様にて委託販売中! 完売御礼

SW12887パッケージ内容 SW12887 表面 SW12887 裏面 SW12887 装着状態

SW12887 RTCモジュール製品情報

DALLAS DS12887Aやその互換RTCモジュールと置き換える事が出来る電池交換可能なRTC+NVRAMモジュールです。

古いマザーボードや計測機器に搭載されている下図のモジュールと置き換えます。
有名どころではASUS P/I-P55T2P4(DS12B887)・TYAN S1668D(DS12887A)等で使われています。
DS12887A
このリアルタイムクロックモジュールは日時を保持するほか、BIOSの設定を保存しているため電池切れを起こすとCMOS CHECKSUM ERRORが発生しシステムの構成によっては起動不能になってしまう場合があります、当互換モジュールに置き換えることで修繕する事が可能です。
また、電池交換式であるため永続的にご使用いただけます。

■ 対応モジュール
DS1287 / DS12887 / DS12887A / DS12B887
※DS12887A+ など末尾に”+”が付くタイプは鉛フリーを意味しており機能上の違いはありませんので置き換えて使用することが可能です。

■ 限定的に対応可能?なモジュール
DS12C887 / DS12C887A
上記型番にCが付くRTCモジュールは年月日の他に世紀の値を持ち、利用できるNVRAMのサイズがC無しモデルより1バイト少なくなっています、具体的にはメモリー番地32Hに世紀の値を保持しているためこの番地をBIOSが使用している場合、当製品では対応出来ない場合があります。(試してみないと判らないというのが正直なところです)

■ 内容物

  • 製品本体 SW12887 x1
  • 24pin IC ソケット x1
  • CR1220ボタン電池 x1

技術情報

この製品はDALLAS社製DS12885Sを採用し、オシレーターには日本メーカーのクリスタルを使用しています。
DS12885SはMotorola・Intelどちらかのバスタイミングに設定可能ですが、この製品は一般的なPCで使用されているIntelバスタイミングで動作します。

■ 使用方法
1.まず最初に現在搭載されているRTCモジュールの型番を確認して下さい。
下図に代表的なモジュールのピン配置を記載します、各社相当品(ODIN OEC12C887等の互換モジュール)の場合はそれぞれのデータシートで確認してください。
必要に応じて使用していないピンを切除してください、基本的には既存モジュールと同じにすればOKです。
ピンアサイン
2.マザーボード等の基板より電池の切れた既存のリアルタイムクロックモジュールを取り外して下さい、一部のマザーボードではICソケットが実装されており簡単に取り外せる 場合もありますが、多くは基板上に直接半田付けされていますので基板を傷めないように半田吸い取り機などを使用して慎重に取り外してください。

3.1番ピンの向きを間違えないように当モジュールを基板に差し込み半田付けして下さい、付属の24pin ICソケットのご利用をお勧めいたします。

4.本製品に同梱のCR1220リチウムボタン電池を取り付けてください、ボタン電池ホルダーのツメ側に電池を差し込み板バネ側を静かに押し込みます。

5.CMOSクリア機能のあるマザーボードではそれを実施し、BIOS画面からLOAD DEFAULTを実行してください、CMOS checksum errorが解消し日時の保持が出来ることを確認してから任意のBIOS設定を行ってください。

おまけ1

保護ケースのSTLデータです、個々で3Dプリントしてご利用下さい。
コンピューター内部は高温になることがあるため、ABSなど比較的熱に強い素材を使用することをおすすめいたします。
3Dプリンタ毎の特性によって異なりますが、プリント時の収縮を考慮して数パーセント大きめに出力すると良いようです。保護ケース

SW12887CASE.zip (1KB)

おまけ2

取り外したDS12887シリーズで時計を作ってみよう!
■ 用意するもの

  • 取り外したDS12887シリーズもしくは当製品SW12887 x1
  • Arduino UNO またはその互換機 x1
  • I2Cキャラクタ液晶 または I2C変換基板+パラレルI/Fキャラクタ液晶(1602) x1
  • お好みのLED x1
  • 上記LEDをイイ感じの輝度にする抵抗器(1k-2kΩぐらい?) x1
  • ブレッドボード x1
  • ジャンパワイヤ x適量

■ 回路
下図の様に接続し て下さい 。ブレッドボード配線図

■ プログラムコード

下記のコードをコピーしてArduino IDEでコンパイルして書き込んで下さい。
あらかじめ「LiquidCrystal_I2C」をライブラリに組み込む必要があります、ライブラリマネージャーより"liquidcrystal i2c"で検索して下さい。
35行目キャラクタ液晶のI2Cアドレスは使用環境に応じて書き換えて下さい。(初期値" 0x27 ")

#include <LiquidCrystal_I2C.h>
//address data busの定義
#define ad0 13
#define ad1 12
#define ad2 11
#define ad3 10
#define ad4 9
#define ad5 8
#define ad6 7
#define ad7 6
//AS pin
#define as 3
//DS pin 
#define ds 5
//RW pin
#define rw 4
//INT_SQW pin
#define INT_SQW 2
//SQW pin
#define SQW 16

//RO registers A,B,C,D
#define regA 0x0A
#define regB 0x0B
#define regC 0x0C
#define regD 0x0D

String Year,Month,Date,Hour,Min,Sec;
byte readbyte(byte address);
void writebyte(byte address,byte value);
boolean adjust(byte address);
unsigned char led = 0;
char msgs[7][4] = {"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

LiquidCrystal_I2C lcd(0x27, 16, 2); //I2C番地は環境に合わせて変更のこと、初期値は” 0x27 ”

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

  lcd.init();
  lcd.backlight();
  lcd.home();
  lcd.print("DS12887A RTC");
  lcd.setCursor(0, 1);
  lcd.print("TEST SHIELD V1.1");
  delay(2000);
  lcd.clear();

  pinMode(as, OUTPUT);
  pinMode(ds, OUTPUT);
  pinMode(rw, OUTPUT);
  pinMode(INT_SQW, INPUT); 
  pinMode(SQW, OUTPUT);
  digitalWrite(as,LOW);
  digitalWrite(ds,LOW);
  digitalWrite(rw,LOW);
  digitalWrite(SQW,LOW);
  delay(100);

  attachInterrupt(digitalPinToInterrupt(2),sw_led, RISING);   //SQW信号のインタラプト開始

}   // end of setup

//ゼロフィルする関数------
String strPad(byte num,byte zeroCount){
  String str = String(num);
  String returnStr = "";
  if(zeroCount <= str.length()){
    return str;
  }
  for(byte i = 0;i < zeroCount - str.length();i++){
    returnStr += '0';
  }
  return returnStr + str;
}
//----------------------

void loop()
{
 
  if (Serial.available() > 0) {
     int inByte = Serial.read();
 
     switch (inByte) {
     case 'h': {
          if (adjust(4)) Serial.println("Hours increment"); 
       break;
     }
     case 'm': {   
          if (adjust(2)) Serial.println("Minutes increment"); 
       break;
     }
     case 'D':{    
          if (adjust(7)) Serial.println("Day increment"); 
       break;
     }
     case 'W':{    
          if (adjust(6)) Serial.println("Week increment"); 
       break;
     }
     case 'M':{    
          if (adjust(8)) Serial.println("Month increment"); 
       break;
     }
     case 'Y':{    
          if (adjust(9)) Serial.println("Year increment"); 
       break;
     }
     case 's':{    
          if (adjust(0)) Serial.println("Seconds reset"); 
       break;
     }
     case 't':{    
        if (!bitRead(readbyte(regA),7))
           {
           Serial.print("20");
           Serial.print(Year); 
           Serial.print('/'); 
           Serial.print(Month);  
           Serial.print('/'); 
           Serial.print(Date);      
           Serial.print(' ');
           byte day = readbyte(6)-1; // 1=Sunday
           char* msg = msgs[day];
           Serial.print(msg);
           Serial.print(' ');
           Serial.print(Hour); 
           Serial.print(':'); 
           Serial.print(Min);  
           Serial.print(':'); 
           Serial.print(Sec); 
           Serial.println();
          }
       break;
     }
     case 'R':{    
          Serial.print("A: ");
          Serial.print(readbyte(regA),BIN);
          Serial.println();
          Serial.print("B: ");
          Serial.print(readbyte(regB),BIN);
          Serial.println();
          Serial.print("C: ");
          Serial.print(readbyte(regC),BIN);
          Serial.println();
          Serial.print("D: ");
          Serial.print(readbyte(regD),BIN);
          Serial.println();
       break;
     }

     case 'I':{
        byte b = readbyte(regB);
        b = b|0x80;
        writebyte(regB,b);
        b=b|0x07;
        writebyte(regB,b);
        writebyte(0,0x15);
        writebyte(1,0x15);
        writebyte(2,0x3A);
        writebyte(3,0x3A);
        writebyte(4,0x05);
        writebyte(5,0x05);
        writebyte(6,0x05);
        writebyte(7,0x03);
        writebyte(8,0x0C);
        writebyte(9,0x09);        
        b=b&0x7F;
        writebyte(regB,b);
        Serial.print("init done");
        Serial.println();
       break;
     }

     case 'O':{
       //OSC start
        writebyte(regA,0x2F);
        Serial.println("OSC Start");
       break; 
     }     

     case 'o':{
       //OSC stop
        writebyte(regA,0x00);
        Serial.println("OSC Stop");
       break; 
     }

      case 'Q':{
       //SQW start
        writebyte(regB,0x0F);
        Serial.println("SQW Start");
       break; 
     } 

      case 'q':{
       //SQW stop
        writebyte(regB,0x07);
        digitalWrite(SQW,LOW);
        Serial.println("SQW Stop");
       break; 

     }            

      case '?':{
        Serial.println("I = Initialize RTC module");
        Serial.println("O = Start oscillator");
        Serial.println("o = Stop oscillator");
        Serial.println("Y = Increment Year");
        Serial.println("M = Increment Month");
        Serial.println("D = Increment Date");
        Serial.println("W = Increment Day of week");
        Serial.println("h = Increment Hour");
        Serial.println("m = Increment Minute");
        Serial.println("s = Set seconds to zero");
        Serial.println("Q = Start SQW");
        Serial.println("q = Stop SQW");
        Serial.println("t = Show current time and date");
        Serial.println("R = Show register values");
        Serial.println("? = Show this help text");
       break; 

     }            

//     default:

     } 
  } 
  byte BFLG = readbyte(regD);
  lcd.home();
  lcd.print("20"); 
  Year = strPad(readbyte(9),2);
  lcd.print(Year);
  lcd.print("/");
  Month = strPad(readbyte(8),2);
  lcd.print(Month);
  lcd.print("/");
  Date = strPad(readbyte(7),2);
  lcd.print(Date);
  lcd.print(" (");
  byte day = readbyte(6)-1; // 1->sun 2->mon 3...
  char* msg = msgs[day];
  lcd.print(msg);
  lcd.print(")    ");
  lcd.setCursor(0, 1);
  Hour = strPad(readbyte(4),2);
  Min = strPad(readbyte(2),2);
  Sec = strPad(readbyte(0),2); 
  lcd.print(Hour);
  lcd.print(":");
  lcd.print(Min);
  lcd.print(":");
  lcd.print(Sec);
  if (BFLG == 0) {
  lcd.print(" Low BTT");
    } else {
  lcd.print("        ");
  }

}   //end of loop

void bus2out(){
  pinMode(ad0,OUTPUT);
  pinMode(ad1,OUTPUT);
  pinMode(ad2,OUTPUT);
  pinMode(ad3,OUTPUT);
  pinMode(ad4,OUTPUT);
  pinMode(ad5,OUTPUT);
  pinMode(ad6,OUTPUT);
  pinMode(ad7,OUTPUT);
}

void bus2in(){
  pinMode(ad0,INPUT);
  pinMode(ad1,INPUT);
  pinMode(ad2,INPUT);
  pinMode(ad3,INPUT);
  pinMode(ad4,INPUT);
  pinMode(ad5,INPUT);
  pinMode(ad6,INPUT);
  pinMode(ad7,INPUT);
}

byte readbyte(byte address){
  byte readb=0;
  bus2out();    //address pinアウトプット
  digitalWrite(rw,HIGH);
  digitalWrite(ds,HIGH);
  digitalWrite(as,HIGH);
  digitalWrite(ad0,bitRead(address,0));
  digitalWrite(ad1,bitRead(address,1));
  digitalWrite(ad2,bitRead(address,2));
  digitalWrite(ad3,bitRead(address,3));
  digitalWrite(ad4,bitRead(address,4));
  digitalWrite(ad5,bitRead(address,5));
  digitalWrite(ad6,bitRead(address,6));
  digitalWrite(ad7,bitRead(address,7));
  digitalWrite(as,LOW);
  bus2in();     //address pinインプット
  digitalWrite(ds,LOW);
  readb = digitalRead(ad0)|(digitalRead(ad1)<<1)|(digitalRead(ad2)<<2)|(digitalRead(ad3)<<3)|(digitalRead(ad4)<<4)|(digitalRead(ad5)<<5)|(digitalRead(ad6)<<6)|(digitalRead(ad7)<<7);
  digitalWrite(ds,HIGH);
  return readb;
}

void writebyte(byte address,byte value){
  bus2out();    //address pinアウトプット
  digitalWrite(rw,HIGH);
  digitalWrite(ds,HIGH);
  digitalWrite(as,HIGH);
  digitalWrite(ad0,bitRead(address,0));
  digitalWrite(ad1,bitRead(address,1));
  digitalWrite(ad2,bitRead(address,2));
  digitalWrite(ad3,bitRead(address,3));
  digitalWrite(ad4,bitRead(address,4));
  digitalWrite(ad5,bitRead(address,5));
  digitalWrite(ad6,bitRead(address,6));
  digitalWrite(ad7,bitRead(address,7));
  digitalWrite(as,LOW);
  digitalWrite(rw,LOW);
  digitalWrite(ad0,bitRead(value,0));
  digitalWrite(ad1,bitRead(value,1));
  digitalWrite(ad2,bitRead(value,2));
  digitalWrite(ad3,bitRead(value,3));
  digitalWrite(ad4,bitRead(value,4));
  digitalWrite(ad5,bitRead(value,5));
  digitalWrite(ad6,bitRead(value,6));
  digitalWrite(ad7,bitRead(value,7));
  digitalWrite(rw,HIGH);
}

boolean adjust(byte address){
          byte value=0;
          byte b;
          if ( (address<0) || (address > 10)) return false;
          
           if (!bitRead(readbyte(regA),7)) value = readbyte(address);
          b = readbyte(regB);
          b=b|0x80;
          writebyte(regB,b);
           
           if (bitRead(readbyte(regB),7))        
          {
            
          switch (address){
          
          case 0:
              writebyte(address,0);
          break; 
          
          case 1:
          if (value == 59) {writebyte(address,0);}
          else {
              value++; 
              writebyte(address,value);
              }
          break;
          
          case 2:
          if (value == 59) {writebyte(address,0);}
          else {
             value++; 
              writebyte(address,value);
              }  
          break;
          
          case 3:
          if (value == 59) {writebyte(address,0);}
          else {
             value++; 
              writebyte(address,value);
              }  
          break;
          
          case 4:
          if (value == 23) {writebyte(address,0);}
          else {
             value++; 
              writebyte(address,value);
              }  
          break;
         case 5:
          if (value == 23) {writebyte(address,0);}
          else {
             value++; 
              writebyte(address,value);
              }  
          break;
         
         case 6:
          if (value == 7) {writebyte(address,1);}
          else {
             value++; 
              writebyte(address,value);
              }  
          break;
          case 7:
          if (value == 31) {writebyte(address,1);}
          else {
             value++; 
              writebyte(address,value);
              }  
          break;
          
         case 8:
          if (value == 12) {writebyte(address,1);}
          else {
             value++; 
              writebyte(address,value); 
              }  
          break;
          case 9:
          if (value == 99) {writebyte(address,0);}
          else {
             value++; 
              writebyte(address,value);
              }  
          break;
                } //end switch
          } //end upd
          
          b=b&0x7F;
          writebyte(regB,b);
      return true;
  
}
//SQW_LED点滅
  void sw_led(void) {
    led ^= 1;
    digitalWrite(SQW, led);
  }


■ 使い方

プログラムを書き込んだArduinoをパソコンにUSB接続し、Tera Tarmなどのコンソールソフトから9600bpsで接続して下さい、Arduino IDEのシリアルコンソールでも差し支えありません。
「?」を送信するとコマンドの一覧が表示されます。
「I」コマンドでイニシャライズ後、Y・M・D・W・h・m コマンド日付・曜日、時間を調整して下さい、「O」コマンドでオシレーターが動作を開始し時計が動き出します。
「Q」コマンドでSQW機能が動作しLEDが1秒間隔で点滅します。

出荷前動作テスト動画

「おまけ2」の回路・プログラムで全ての製品をチェック後出荷しています、その動作動画です。

<< 前のページに戻る