Upload 1
This commit is contained in:
commit
ef7328c0f1
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 203 KiB |
Binary file not shown.
|
@ -0,0 +1,46 @@
|
|||
# Arduino Binäruhr
|
||||
Eine Binäruhr basierend auf einem Arduino Nano. Die LEDs werden mit Hilfe von 74HC595 Schieberegistern angesteuert.
|
||||
|
||||
[<img src="pictures/Uhr_1.jpg" height="400px">](pictures/Uhr_1.jpg)
|
||||
[<img src="pictures/Uhr_2.jpg" height="400px">](pictures/Uhr_2.jpg)
|
||||
[<img src="pictures/Uhr_innen.jpg" height="400px">](pictures/Uhr_innen.jpg)
|
||||
|
||||
## Features
|
||||
- Einbau in einem IKEA Ribba Bilderrahmen 13x18 cm (bzw. 10x15 cm)
|
||||
- Die Zeit wird von einer DS3231 RTC bereitgestellt
|
||||
- Ein Taster zum ändern der Anzeige:
|
||||
- Normalmodus: Zeitanzeige - Stunden, Minuten, Sekunden
|
||||
- Datumsanzeige - Tag, Monat, Tag der Woche (1-7)
|
||||
- Temperaturanzeige - Temperaturmessung erfolgt durch das RTC-Modul
|
||||
- Wenn die Anzeige im Datum- oder Temperaturmodus ist, wechselt sie nach 10 Sekunden automatisch zum Normalmodus zurück
|
||||
- Eine extra LED blinkt 2 mal jede Sekunde
|
||||
|
||||
# Hardware
|
||||
## Schaltplan
|
||||
**Im Schaltplan sind keine Vorwiderstände für die einzelnen LEDs eingetragen, diese sollten jedoch verbaut werden! (Wert: 220R)** <br><br>
|
||||
[<img src="pictures/Binaeruhr_Schaltplan.png" height="700px">](pictures/Binaeruhr_Schaltplan.png)
|
||||
|
||||
## Leiterplatte
|
||||
[<img src="pictures/Binaeruhr_Platine_Leiterplatte.png" height="400px">](pictures/Binaeruhr_Platine_Leiterplatte.png)
|
||||
|
||||
## Frontplatte
|
||||
Ich habe für den Bilderrahmen eine Frontplatte erstellt (Software: Frontplatten Designer, Schaeffer AG). Diese ist passend für den IKEA Bilderrahmen und kann im Format **10x15 cm** ausgeruckt werden.
|
||||
<br><br>
|
||||
[<img src="Frontplatte.png" height="600px">](Frontplatte.png)
|
||||
|
||||
# Software
|
||||
Der Code kann ohne weitere Änderungen verwendet werden. Um die Zeit des RTC-Moduls einzustellen müssen im Code die entsprechenden Zeilen auskommentiert und mit der aktuellen Uhrzeit gefüllt werden. Anschließend muss dieser Code **einmalig** auf dem Arduino ausgeführt werden.
|
||||
|
||||
Die Verwendete Bibiliothek für die DS3231 ist im Ordner des Programmes bereits hinterlegt und muss nicht extra heruntergeladen werden. Zusätzlich ist die Quelle der Bibiliothek jedoch im Code verlinkt.
|
||||
|
||||
# Quellen
|
||||
- https://pascalstechtips.weebly.com/projekte/arduino-binruhr-v10
|
||||
- DS3231: http://www.rinkydinkelectronics.com/library.php?id=73
|
||||
- Software für Frontplatte: https://www.schaeffer-ag.de/frontplatten-designer#
|
||||
|
||||
<br><br>
|
||||
<p xmlns:dct="http://purl.org/dc/terms/" xmlns:cc="http://creativecommons.org/ns#" class="license-text">This work by <span property="cc:attributionName">Dustin Brunner</span> is licensed under <a rel="license" href="https://creativecommons.org/licenses/by/4.0">CC BY 4.0<img style="height:15px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" /><img style="height:15px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" /></a></p>
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons Lizenzvertrag" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />Dieses Werk von <span xmlns:cc="http://creativecommons.org/ns#" property="cc:attributionName">Dustin Brunner</span> ist lizenziert unter einer <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Namensnennung 4.0 International Lizenz</a>.
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 103 KiB |
Binary file not shown.
After Width: | Height: | Size: 176 KiB |
Binary file not shown.
After Width: | Height: | Size: 234 KiB |
Binary file not shown.
After Width: | Height: | Size: 269 KiB |
Binary file not shown.
After Width: | Height: | Size: 375 KiB |
|
@ -0,0 +1,179 @@
|
|||
#include "src/DS3231.h" //http://www.rinkydinkelectronics.com/library.php?id=73
|
||||
|
||||
DS3231 rtc(SDA, SCL);
|
||||
|
||||
//Pins
|
||||
//Pins für Sekunden-Schieberegister
|
||||
const int clockPinS = 4;
|
||||
const int latchPinS = 3;
|
||||
const int dataPinS = 2;
|
||||
//Pins für Minuten-Schieberegister
|
||||
const int clockPinM = 7;
|
||||
const int latchPinM = 6;
|
||||
const int dataPinM = 5;
|
||||
//Pins für Stunden-Schieberegister
|
||||
const int clockPinH = 10;
|
||||
const int latchPinH = 9;
|
||||
const int dataPinH = 8;
|
||||
|
||||
const int tickled = 13;
|
||||
const int taster = 12;
|
||||
|
||||
//Variablen
|
||||
long prevMillis = 0;
|
||||
long interval = 500;
|
||||
Time t;
|
||||
int stunden;
|
||||
int minuten;
|
||||
int sekunden;
|
||||
int tag;
|
||||
int monat;
|
||||
int wochentag;
|
||||
int temp;
|
||||
int halbesekunde = 0;
|
||||
int modus = 1;
|
||||
int modustimer = 0;
|
||||
|
||||
void setup(){
|
||||
//Outputpins
|
||||
pinMode(clockPinS, OUTPUT);
|
||||
pinMode(dataPinS, OUTPUT);
|
||||
pinMode(latchPinS, OUTPUT);
|
||||
pinMode(clockPinM, OUTPUT);
|
||||
pinMode(dataPinM, OUTPUT);
|
||||
pinMode(latchPinM, OUTPUT);
|
||||
pinMode(clockPinH, OUTPUT);
|
||||
pinMode(dataPinH, OUTPUT);
|
||||
pinMode(latchPinH, OUTPUT);
|
||||
pinMode(tickled, OUTPUT);
|
||||
|
||||
//Inputpin
|
||||
pinMode(taster, INPUT_PULLUP);
|
||||
|
||||
//RTC
|
||||
rtc.begin();
|
||||
|
||||
// Nachfolgende Linien zur Zeiteinstellung unkommentieren
|
||||
//rtc.setDOW(2); // Wochentag einstellen -> 1=Montag, 2=Dienstag, ...
|
||||
//rtc.setTime(16, 58, 00); // Uhrzeit einstellen (Stunde, Minute, Sekunde)
|
||||
//rtc.setDate(02, 04, 2019); // Datum einstellen (Tag, Monat, Jahr)
|
||||
|
||||
|
||||
//für Debugging un-kommentieren
|
||||
//Serial.begin(9600);
|
||||
} //Ende von setup()
|
||||
|
||||
void loop(){
|
||||
/*if (digitalRead(addhour) == LOW){ //falls Minuten erhöht werden sollen
|
||||
delay(100);
|
||||
minutes += 1;
|
||||
if (minutes > 58){
|
||||
minutes = 0;
|
||||
}
|
||||
Serial.println("Minute++");
|
||||
while(digitalRead(2) == LOW){
|
||||
delay(10);
|
||||
}
|
||||
}*/
|
||||
|
||||
if (digitalRead(taster) == LOW){
|
||||
modus++;
|
||||
modustimer = 0;
|
||||
if (modus == 4){
|
||||
modus = 1;
|
||||
}
|
||||
while(digitalRead(taster) == LOW){}
|
||||
delay(100);
|
||||
}
|
||||
|
||||
if(modustimer >= 10){
|
||||
modus = 1;
|
||||
modustimer = 0;
|
||||
}
|
||||
|
||||
unsigned long currentMillis = millis();
|
||||
if (currentMillis - prevMillis > interval) {
|
||||
prevMillis = currentMillis;
|
||||
|
||||
if(halbesekunde == 1){
|
||||
if (modus == 1){
|
||||
t = rtc.getTime();
|
||||
stunden = t.hour, DEC;
|
||||
minuten = t.min, DEC;
|
||||
sekunden = t.sec, DEC;
|
||||
digitalWrite(tickled, HIGH);
|
||||
displayTime();
|
||||
}
|
||||
else if (modus == 2){
|
||||
t = rtc.getTime();
|
||||
tag = t.date, DEC;
|
||||
monat = t.mon, DEC;
|
||||
wochentag = t.dow, DEC;
|
||||
modustimer++;
|
||||
displayDate();
|
||||
}
|
||||
else if (modus == 3){
|
||||
temp = int(rtc.getTemp());
|
||||
modustimer++;
|
||||
displayTemp();
|
||||
}
|
||||
|
||||
//für Debugging un-kommentieren
|
||||
/*Serial.println("");
|
||||
Serial.println("Zeit:"); //für debugging
|
||||
Serial.print(String(stunden));
|
||||
Serial.print(":");
|
||||
Serial.print(String(minuten));
|
||||
Serial.print(":");
|
||||
Serial.print(String(sekunden));
|
||||
//*/
|
||||
|
||||
halbesekunde = 0;
|
||||
}
|
||||
else{
|
||||
digitalWrite(tickled, LOW);
|
||||
halbesekunde = 1;
|
||||
}
|
||||
}
|
||||
|
||||
} //Ende von loop()
|
||||
|
||||
|
||||
void displayTime(){ //Sendet die Zeit zu den Shiftregistern
|
||||
//Sekunden
|
||||
digitalWrite(latchPinS, LOW);
|
||||
shiftOut(dataPinS, clockPinS, MSBFIRST, sekunden);
|
||||
digitalWrite(latchPinS, HIGH);
|
||||
//Minuten
|
||||
digitalWrite(latchPinM, LOW);
|
||||
shiftOut(dataPinM, clockPinM, MSBFIRST, minuten);
|
||||
digitalWrite(latchPinM, HIGH);
|
||||
//Stunden
|
||||
digitalWrite(latchPinH, LOW);
|
||||
shiftOut(dataPinH, clockPinH, MSBFIRST, stunden);
|
||||
digitalWrite(latchPinH, HIGH);
|
||||
}
|
||||
|
||||
void displayDate(){ //Sendet Datum zu den Shiftregistern
|
||||
digitalWrite(latchPinS, LOW);
|
||||
shiftOut(dataPinS, clockPinS, MSBFIRST, wochentag);
|
||||
digitalWrite(latchPinS, HIGH);
|
||||
digitalWrite(latchPinM, LOW);
|
||||
shiftOut(dataPinM, clockPinM, MSBFIRST, monat);
|
||||
digitalWrite(latchPinM, HIGH);
|
||||
digitalWrite(latchPinH, LOW);
|
||||
shiftOut(dataPinH, clockPinH, MSBFIRST, tag);
|
||||
digitalWrite(latchPinH, HIGH);
|
||||
}
|
||||
|
||||
void displayTemp(){ //Sendet Temperatur zu den Shiftregistern
|
||||
digitalWrite(latchPinS, LOW);
|
||||
shiftOut(dataPinS, clockPinS, MSBFIRST, temp);
|
||||
digitalWrite(latchPinS, HIGH);
|
||||
digitalWrite(latchPinM, LOW);
|
||||
shiftOut(dataPinM, clockPinM, MSBFIRST, 0);
|
||||
digitalWrite(latchPinM, HIGH);
|
||||
digitalWrite(latchPinH, LOW);
|
||||
shiftOut(dataPinH, clockPinH, MSBFIRST, 0);
|
||||
digitalWrite(latchPinH, HIGH);
|
||||
}
|
|
@ -0,0 +1,447 @@
|
|||
/*
|
||||
DS3231.cpp - Arduino/chipKit library support for the DS3231 I2C Real-Time Clock
|
||||
Copyright (C)2015 Rinky-Dink Electronics, Henning Karlsen. All right reserved
|
||||
|
||||
This library has been made to easily interface and use the DS3231 RTC with
|
||||
an Arduino or chipKit.
|
||||
|
||||
You can find the latest version of the library at
|
||||
http://www.RinkyDinkElectronics.com/
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the CC BY-NC-SA 3.0 license.
|
||||
Please see the included documents for further information.
|
||||
|
||||
Commercial use of this library requires you to buy a license that
|
||||
will allow commercial use. This includes using the library,
|
||||
modified or not, as a tool to sell products.
|
||||
|
||||
The license applies to all part of the library including the
|
||||
examples and tools supplied with the library.
|
||||
*/
|
||||
#include "DS3231.h"
|
||||
|
||||
// Include hardware-specific functions for the correct MCU
|
||||
#if defined(__AVR__)
|
||||
#include "hardware/avr/HW_AVR.h"
|
||||
#elif defined(__PIC32MX__)
|
||||
#include "hardware/pic32/HW_PIC32.h"
|
||||
#elif defined(__arm__)
|
||||
#include "hardware/arm/HW_ARM.h"
|
||||
#endif
|
||||
|
||||
#define REG_SEC 0x00
|
||||
#define REG_MIN 0x01
|
||||
#define REG_HOUR 0x02
|
||||
#define REG_DOW 0x03
|
||||
#define REG_DATE 0x04
|
||||
#define REG_MON 0x05
|
||||
#define REG_YEAR 0x06
|
||||
#define REG_CON 0x0e
|
||||
#define REG_STATUS 0x0f
|
||||
#define REG_AGING 0x10
|
||||
#define REG_TEMPM 0x11
|
||||
#define REG_TEMPL 0x12
|
||||
|
||||
#define SEC_1970_TO_2000 946684800
|
||||
|
||||
static const uint8_t dim[] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
|
||||
|
||||
/* Public */
|
||||
|
||||
Time::Time()
|
||||
{
|
||||
this->year = 2014;
|
||||
this->mon = 1;
|
||||
this->date = 1;
|
||||
this->hour = 0;
|
||||
this->min = 0;
|
||||
this->sec = 0;
|
||||
this->dow = 3;
|
||||
}
|
||||
|
||||
DS3231::DS3231(uint8_t data_pin, uint8_t sclk_pin)
|
||||
{
|
||||
_sda_pin = data_pin;
|
||||
_scl_pin = sclk_pin;
|
||||
}
|
||||
|
||||
Time DS3231::getTime()
|
||||
{
|
||||
Time t;
|
||||
_burstRead();
|
||||
t.sec = _decode(_burstArray[0]);
|
||||
t.min = _decode(_burstArray[1]);
|
||||
t.hour = _decodeH(_burstArray[2]);
|
||||
t.dow = _burstArray[3];
|
||||
t.date = _decode(_burstArray[4]);
|
||||
t.mon = _decode(_burstArray[5]);
|
||||
t.year = _decodeY(_burstArray[6])+2000;
|
||||
return t;
|
||||
}
|
||||
|
||||
void DS3231::setTime(uint8_t hour, uint8_t min, uint8_t sec)
|
||||
{
|
||||
if (((hour>=0) && (hour<24)) && ((min>=0) && (min<60)) && ((sec>=0) && (sec<60)))
|
||||
{
|
||||
_writeRegister(REG_HOUR, _encode(hour));
|
||||
_writeRegister(REG_MIN, _encode(min));
|
||||
_writeRegister(REG_SEC, _encode(sec));
|
||||
}
|
||||
}
|
||||
|
||||
void DS3231::setDate(uint8_t date, uint8_t mon, uint16_t year)
|
||||
{
|
||||
if (((date>0) && (date<=31)) && ((mon>0) && (mon<=12)) && ((year>=2000) && (year<3000)))
|
||||
{
|
||||
year -= 2000;
|
||||
_writeRegister(REG_YEAR, _encode(year));
|
||||
_writeRegister(REG_MON, _encode(mon));
|
||||
_writeRegister(REG_DATE, _encode(date));
|
||||
}
|
||||
}
|
||||
|
||||
void DS3231::setDOW()
|
||||
{
|
||||
int dow;
|
||||
byte mArr[12] = {6,2,2,5,0,3,5,1,4,6,2,4};
|
||||
Time _t = getTime();
|
||||
|
||||
dow = (_t.year % 100);
|
||||
dow = dow*1.25;
|
||||
dow += _t.date;
|
||||
dow += mArr[_t.mon-1];
|
||||
if (((_t.year % 4)==0) && (_t.mon<3))
|
||||
dow -= 1;
|
||||
while (dow>7)
|
||||
dow -= 7;
|
||||
_writeRegister(REG_DOW, dow);
|
||||
}
|
||||
|
||||
void DS3231::setDOW(uint8_t dow)
|
||||
{
|
||||
if ((dow>0) && (dow<8))
|
||||
_writeRegister(REG_DOW, dow);
|
||||
}
|
||||
|
||||
char *DS3231::getTimeStr(uint8_t format)
|
||||
{
|
||||
static char output[] = "xxxxxxxx";
|
||||
Time t;
|
||||
t=getTime();
|
||||
if (t.hour<10)
|
||||
output[0]=48;
|
||||
else
|
||||
output[0]=char((t.hour / 10)+48);
|
||||
output[1]=char((t.hour % 10)+48);
|
||||
output[2]=58;
|
||||
if (t.min<10)
|
||||
output[3]=48;
|
||||
else
|
||||
output[3]=char((t.min / 10)+48);
|
||||
output[4]=char((t.min % 10)+48);
|
||||
output[5]=58;
|
||||
if (format==FORMAT_SHORT)
|
||||
output[5]=0;
|
||||
else
|
||||
{
|
||||
if (t.sec<10)
|
||||
output[6]=48;
|
||||
else
|
||||
output[6]=char((t.sec / 10)+48);
|
||||
output[7]=char((t.sec % 10)+48);
|
||||
output[8]=0;
|
||||
}
|
||||
return (char*)&output;
|
||||
}
|
||||
|
||||
char *DS3231::getDateStr(uint8_t slformat, uint8_t eformat, char divider)
|
||||
{
|
||||
static char output[] = "xxxxxxxxxx";
|
||||
int yr, offset;
|
||||
Time t;
|
||||
t=getTime();
|
||||
switch (eformat)
|
||||
{
|
||||
case FORMAT_LITTLEENDIAN:
|
||||
if (t.date<10)
|
||||
output[0]=48;
|
||||
else
|
||||
output[0]=char((t.date / 10)+48);
|
||||
output[1]=char((t.date % 10)+48);
|
||||
output[2]=divider;
|
||||
if (t.mon<10)
|
||||
output[3]=48;
|
||||
else
|
||||
output[3]=char((t.mon / 10)+48);
|
||||
output[4]=char((t.mon % 10)+48);
|
||||
output[5]=divider;
|
||||
if (slformat==FORMAT_SHORT)
|
||||
{
|
||||
yr=t.year-2000;
|
||||
if (yr<10)
|
||||
output[6]=48;
|
||||
else
|
||||
output[6]=char((yr / 10)+48);
|
||||
output[7]=char((yr % 10)+48);
|
||||
output[8]=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
yr=t.year;
|
||||
output[6]=char((yr / 1000)+48);
|
||||
output[7]=char(((yr % 1000) / 100)+48);
|
||||
output[8]=char(((yr % 100) / 10)+48);
|
||||
output[9]=char((yr % 10)+48);
|
||||
output[10]=0;
|
||||
}
|
||||
break;
|
||||
case FORMAT_BIGENDIAN:
|
||||
if (slformat==FORMAT_SHORT)
|
||||
offset=0;
|
||||
else
|
||||
offset=2;
|
||||
if (slformat==FORMAT_SHORT)
|
||||
{
|
||||
yr=t.year-2000;
|
||||
if (yr<10)
|
||||
output[0]=48;
|
||||
else
|
||||
output[0]=char((yr / 10)+48);
|
||||
output[1]=char((yr % 10)+48);
|
||||
output[2]=divider;
|
||||
}
|
||||
else
|
||||
{
|
||||
yr=t.year;
|
||||
output[0]=char((yr / 1000)+48);
|
||||
output[1]=char(((yr % 1000) / 100)+48);
|
||||
output[2]=char(((yr % 100) / 10)+48);
|
||||
output[3]=char((yr % 10)+48);
|
||||
output[4]=divider;
|
||||
}
|
||||
if (t.mon<10)
|
||||
output[3+offset]=48;
|
||||
else
|
||||
output[3+offset]=char((t.mon / 10)+48);
|
||||
output[4+offset]=char((t.mon % 10)+48);
|
||||
output[5+offset]=divider;
|
||||
if (t.date<10)
|
||||
output[6+offset]=48;
|
||||
else
|
||||
output[6+offset]=char((t.date / 10)+48);
|
||||
output[7+offset]=char((t.date % 10)+48);
|
||||
output[8+offset]=0;
|
||||
break;
|
||||
case FORMAT_MIDDLEENDIAN:
|
||||
if (t.mon<10)
|
||||
output[0]=48;
|
||||
else
|
||||
output[0]=char((t.mon / 10)+48);
|
||||
output[1]=char((t.mon % 10)+48);
|
||||
output[2]=divider;
|
||||
if (t.date<10)
|
||||
output[3]=48;
|
||||
else
|
||||
output[3]=char((t.date / 10)+48);
|
||||
output[4]=char((t.date % 10)+48);
|
||||
output[5]=divider;
|
||||
if (slformat==FORMAT_SHORT)
|
||||
{
|
||||
yr=t.year-2000;
|
||||
if (yr<10)
|
||||
output[6]=48;
|
||||
else
|
||||
output[6]=char((yr / 10)+48);
|
||||
output[7]=char((yr % 10)+48);
|
||||
output[8]=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
yr=t.year;
|
||||
output[6]=char((yr / 1000)+48);
|
||||
output[7]=char(((yr % 1000) / 100)+48);
|
||||
output[8]=char(((yr % 100) / 10)+48);
|
||||
output[9]=char((yr % 10)+48);
|
||||
output[10]=0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return (char*)&output;
|
||||
}
|
||||
|
||||
char *DS3231::getDOWStr(uint8_t format)
|
||||
{
|
||||
char *output = "xxxxxxxxxx";
|
||||
char *daysLong[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
|
||||
char *daysShort[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
|
||||
Time t;
|
||||
t=getTime();
|
||||
if (format == FORMAT_SHORT)
|
||||
output = daysShort[t.dow-1];
|
||||
else
|
||||
output = daysLong[t.dow-1];
|
||||
return output;
|
||||
}
|
||||
|
||||
char *DS3231::getMonthStr(uint8_t format)
|
||||
{
|
||||
char *output= "xxxxxxxxx";
|
||||
char *monthLong[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
|
||||
char *monthShort[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
Time t;
|
||||
t=getTime();
|
||||
if (format == FORMAT_SHORT)
|
||||
output = monthShort[t.mon-1];
|
||||
else
|
||||
output = monthLong[t.mon-1];
|
||||
return output;
|
||||
}
|
||||
|
||||
long DS3231::getUnixTime(Time t)
|
||||
{
|
||||
uint16_t dc;
|
||||
|
||||
dc = t.date;
|
||||
for (uint8_t i = 0; i<(t.mon-1); i++)
|
||||
dc += dim[i];
|
||||
if ((t.mon > 2) && (((t.year-2000) % 4) == 0))
|
||||
++dc;
|
||||
dc = dc + (365 * (t.year-2000)) + (((t.year-2000) + 3) / 4) - 1;
|
||||
|
||||
return ((((((dc * 24L) + t.hour) * 60) + t.min) * 60) + t.sec) + SEC_1970_TO_2000;
|
||||
|
||||
}
|
||||
|
||||
void DS3231::enable32KHz(bool enable)
|
||||
{
|
||||
uint8_t _reg = _readRegister(REG_STATUS);
|
||||
_reg &= ~(1 << 3);
|
||||
_reg |= (enable << 3);
|
||||
_writeRegister(REG_STATUS, _reg);
|
||||
}
|
||||
|
||||
void DS3231::setOutput(byte enable)
|
||||
{
|
||||
uint8_t _reg = _readRegister(REG_CON);
|
||||
_reg &= ~(1 << 2);
|
||||
_reg |= (enable << 2);
|
||||
_writeRegister(REG_CON, _reg);
|
||||
}
|
||||
|
||||
void DS3231::setSQWRate(int rate)
|
||||
{
|
||||
uint8_t _reg = _readRegister(REG_CON);
|
||||
_reg &= ~(3 << 3);
|
||||
_reg |= (rate << 3);
|
||||
_writeRegister(REG_CON, _reg);
|
||||
}
|
||||
|
||||
float DS3231::getTemp()
|
||||
{
|
||||
uint8_t _msb = _readRegister(REG_TEMPM);
|
||||
uint8_t _lsb = _readRegister(REG_TEMPL);
|
||||
return (float)_msb + ((_lsb >> 6) * 0.25f);
|
||||
}
|
||||
|
||||
/* Private */
|
||||
|
||||
void DS3231::_sendStart(byte addr)
|
||||
{
|
||||
pinMode(_sda_pin, OUTPUT);
|
||||
digitalWrite(_sda_pin, HIGH);
|
||||
digitalWrite(_scl_pin, HIGH);
|
||||
digitalWrite(_sda_pin, LOW);
|
||||
digitalWrite(_scl_pin, LOW);
|
||||
shiftOut(_sda_pin, _scl_pin, MSBFIRST, addr);
|
||||
}
|
||||
|
||||
void DS3231::_sendStop()
|
||||
{
|
||||
pinMode(_sda_pin, OUTPUT);
|
||||
digitalWrite(_sda_pin, LOW);
|
||||
digitalWrite(_scl_pin, HIGH);
|
||||
digitalWrite(_sda_pin, HIGH);
|
||||
pinMode(_sda_pin, INPUT);
|
||||
}
|
||||
|
||||
void DS3231::_sendNack()
|
||||
{
|
||||
pinMode(_sda_pin, OUTPUT);
|
||||
digitalWrite(_scl_pin, LOW);
|
||||
digitalWrite(_sda_pin, HIGH);
|
||||
digitalWrite(_scl_pin, HIGH);
|
||||
digitalWrite(_scl_pin, LOW);
|
||||
pinMode(_sda_pin, INPUT);
|
||||
}
|
||||
|
||||
void DS3231::_sendAck()
|
||||
{
|
||||
pinMode(_sda_pin, OUTPUT);
|
||||
digitalWrite(_scl_pin, LOW);
|
||||
digitalWrite(_sda_pin, LOW);
|
||||
digitalWrite(_scl_pin, HIGH);
|
||||
digitalWrite(_scl_pin, LOW);
|
||||
pinMode(_sda_pin, INPUT);
|
||||
}
|
||||
|
||||
void DS3231::_waitForAck()
|
||||
{
|
||||
pinMode(_sda_pin, INPUT);
|
||||
digitalWrite(_scl_pin, HIGH);
|
||||
while (digitalRead(_sda_pin)==HIGH) {}
|
||||
digitalWrite(_scl_pin, LOW);
|
||||
}
|
||||
|
||||
uint8_t DS3231::_readByte()
|
||||
{
|
||||
pinMode(_sda_pin, INPUT);
|
||||
|
||||
uint8_t value = 0;
|
||||
uint8_t currentBit = 0;
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
digitalWrite(_scl_pin, HIGH);
|
||||
currentBit = digitalRead(_sda_pin);
|
||||
value |= (currentBit << 7-i);
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(_scl_pin, LOW);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void DS3231::_writeByte(uint8_t value)
|
||||
{
|
||||
pinMode(_sda_pin, OUTPUT);
|
||||
shiftOut(_sda_pin, _scl_pin, MSBFIRST, value);
|
||||
}
|
||||
|
||||
uint8_t DS3231::_decode(uint8_t value)
|
||||
{
|
||||
uint8_t decoded = value & 127;
|
||||
decoded = (decoded & 15) + 10 * ((decoded & (15 << 4)) >> 4);
|
||||
return decoded;
|
||||
}
|
||||
|
||||
uint8_t DS3231::_decodeH(uint8_t value)
|
||||
{
|
||||
if (value & 128)
|
||||
value = (value & 15) + (12 * ((value & 32) >> 5));
|
||||
else
|
||||
value = (value & 15) + (10 * ((value & 48) >> 4));
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8_t DS3231::_decodeY(uint8_t value)
|
||||
{
|
||||
uint8_t decoded = (value & 15) + 10 * ((value & (15 << 4)) >> 4);
|
||||
return decoded;
|
||||
}
|
||||
|
||||
uint8_t DS3231::_encode(uint8_t value)
|
||||
{
|
||||
uint8_t encoded = ((value / 10) << 4) + (value % 10);
|
||||
return encoded;
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
DS3231.cpp - Arduino/chipKit library support for the DS3231 I2C Real-Time Clock
|
||||
Copyright (C)2015 Rinky-Dink Electronics, Henning Karlsen. All right reserved
|
||||
|
||||
This library has been made to easily interface and use the DS3231 RTC with
|
||||
an Arduino or chipKit.
|
||||
|
||||
You can find the latest version of the library at
|
||||
http://www.RinkyDinkElectronics.com/
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the CC BY-NC-SA 3.0 license.
|
||||
Please see the included documents for further information.
|
||||
|
||||
Commercial use of this library requires you to buy a license that
|
||||
will allow commercial use. This includes using the library,
|
||||
modified or not, as a tool to sell products.
|
||||
|
||||
The license applies to all part of the library including the
|
||||
examples and tools supplied with the library.
|
||||
*/
|
||||
#ifndef DS3231_h
|
||||
#define DS3231_h
|
||||
|
||||
#if defined(__AVR__)
|
||||
#include "Arduino.h"
|
||||
#include "hardware/avr/HW_AVR_defines.h"
|
||||
#elif defined(__PIC32MX__)
|
||||
#include "WProgram.h"
|
||||
#include "hardware/pic32/HW_PIC32_defines.h"
|
||||
#elif defined(__arm__)
|
||||
#include "Arduino.h"
|
||||
#include "hardware/arm/HW_ARM_defines.h"
|
||||
#endif
|
||||
|
||||
#define DS3231_ADDR_R 0xD1
|
||||
#define DS3231_ADDR_W 0xD0
|
||||
#define DS3231_ADDR 0x68
|
||||
|
||||
#define FORMAT_SHORT 1
|
||||
#define FORMAT_LONG 2
|
||||
|
||||
#define FORMAT_LITTLEENDIAN 1
|
||||
#define FORMAT_BIGENDIAN 2
|
||||
#define FORMAT_MIDDLEENDIAN 3
|
||||
|
||||
#define MONDAY 1
|
||||
#define TUESDAY 2
|
||||
#define WEDNESDAY 3
|
||||
#define THURSDAY 4
|
||||
#define FRIDAY 5
|
||||
#define SATURDAY 6
|
||||
#define SUNDAY 7
|
||||
|
||||
#define SQW_RATE_1 0
|
||||
#define SQW_RATE_1K 1
|
||||
#define SQW_RATE_4K 2
|
||||
#define SQW_RATE_8K 3
|
||||
|
||||
#define OUTPUT_SQW 0
|
||||
#define OUTPUT_INT 1
|
||||
|
||||
class Time
|
||||
{
|
||||
public:
|
||||
uint8_t hour;
|
||||
uint8_t min;
|
||||
uint8_t sec;
|
||||
uint8_t date;
|
||||
uint8_t mon;
|
||||
uint16_t year;
|
||||
uint8_t dow;
|
||||
|
||||
Time();
|
||||
};
|
||||
|
||||
class DS3231
|
||||
{
|
||||
public:
|
||||
DS3231(uint8_t data_pin, uint8_t sclk_pin);
|
||||
void begin();
|
||||
Time getTime();
|
||||
void setTime(uint8_t hour, uint8_t min, uint8_t sec);
|
||||
void setDate(uint8_t date, uint8_t mon, uint16_t year);
|
||||
void setDOW();
|
||||
void setDOW(uint8_t dow);
|
||||
|
||||
char *getTimeStr(uint8_t format=FORMAT_LONG);
|
||||
char *getDateStr(uint8_t slformat=FORMAT_LONG, uint8_t eformat=FORMAT_LITTLEENDIAN, char divider='.');
|
||||
char *getDOWStr(uint8_t format=FORMAT_LONG);
|
||||
char *getMonthStr(uint8_t format=FORMAT_LONG);
|
||||
long getUnixTime(Time t);
|
||||
|
||||
void enable32KHz(bool enable);
|
||||
void setOutput(byte enable);
|
||||
void setSQWRate(int rate);
|
||||
float getTemp();
|
||||
|
||||
private:
|
||||
uint8_t _scl_pin;
|
||||
uint8_t _sda_pin;
|
||||
uint8_t _burstArray[7];
|
||||
boolean _use_hw;
|
||||
|
||||
void _sendStart(byte addr);
|
||||
void _sendStop();
|
||||
void _sendAck();
|
||||
void _sendNack();
|
||||
void _waitForAck();
|
||||
uint8_t _readByte();
|
||||
void _writeByte(uint8_t value);
|
||||
void _burstRead();
|
||||
uint8_t _readRegister(uint8_t reg);
|
||||
void _writeRegister(uint8_t reg, uint8_t value);
|
||||
uint8_t _decode(uint8_t value);
|
||||
uint8_t _decodeH(uint8_t value);
|
||||
uint8_t _decodeY(uint8_t value);
|
||||
uint8_t _encode(uint8_t vaule);
|
||||
#if defined(__arm__)
|
||||
Twi *twi;
|
||||
#endif
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,154 @@
|
|||
void DS3231::begin()
|
||||
{
|
||||
_use_hw = false;
|
||||
if ((_sda_pin == SDA) and (_scl_pin == SCL))
|
||||
{
|
||||
_use_hw = true;
|
||||
twi = TWI1;
|
||||
pmc_enable_periph_clk(WIRE_INTERFACE_ID);
|
||||
PIO_Configure(g_APinDescription[PIN_WIRE_SDA].pPort, g_APinDescription[PIN_WIRE_SDA].ulPinType, g_APinDescription[PIN_WIRE_SDA].ulPin, g_APinDescription[PIN_WIRE_SDA].ulPinConfiguration);
|
||||
PIO_Configure(g_APinDescription[PIN_WIRE_SCL].pPort, g_APinDescription[PIN_WIRE_SCL].ulPinType, g_APinDescription[PIN_WIRE_SCL].ulPin, g_APinDescription[PIN_WIRE_SCL].ulPinConfiguration);
|
||||
NVIC_DisableIRQ(TWI1_IRQn);
|
||||
NVIC_ClearPendingIRQ(TWI1_IRQn);
|
||||
NVIC_SetPriority(TWI1_IRQn, 0);
|
||||
NVIC_EnableIRQ(TWI1_IRQn);
|
||||
|
||||
}
|
||||
else if ((_sda_pin == SDA1) and (_scl_pin == SCL1))
|
||||
{
|
||||
_use_hw = true;
|
||||
twi = TWI0;
|
||||
pmc_enable_periph_clk(WIRE1_INTERFACE_ID);
|
||||
PIO_Configure(g_APinDescription[PIN_WIRE1_SDA].pPort, g_APinDescription[PIN_WIRE1_SDA].ulPinType, g_APinDescription[PIN_WIRE1_SDA].ulPin, g_APinDescription[PIN_WIRE1_SDA].ulPinConfiguration);
|
||||
PIO_Configure(g_APinDescription[PIN_WIRE1_SCL].pPort, g_APinDescription[PIN_WIRE1_SCL].ulPinType, g_APinDescription[PIN_WIRE1_SCL].ulPin, g_APinDescription[PIN_WIRE1_SCL].ulPinConfiguration);
|
||||
NVIC_DisableIRQ(TWI0_IRQn);
|
||||
NVIC_ClearPendingIRQ(TWI0_IRQn);
|
||||
NVIC_SetPriority(TWI0_IRQn, 0);
|
||||
NVIC_EnableIRQ(TWI0_IRQn);
|
||||
}
|
||||
|
||||
if (_use_hw)
|
||||
{
|
||||
// activate internal pullups for twi.
|
||||
digitalWrite(SDA, 1);
|
||||
digitalWrite(SCL, 1);
|
||||
|
||||
// Reset the TWI
|
||||
twi->TWI_CR = TWI_CR_SWRST;
|
||||
// TWI Slave Mode Disabled, TWI Master Mode Disabled.
|
||||
twi->TWI_CR = TWI_CR_SVDIS;
|
||||
twi->TWI_CR = TWI_CR_MSDIS;
|
||||
// Set TWI Speed
|
||||
twi->TWI_CWGR = (TWI_DIV << 16) | (TWI_SPEED << 8) | TWI_SPEED;
|
||||
// Set master mode
|
||||
twi->TWI_CR = TWI_CR_MSEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
pinMode(_scl_pin, OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
void DS3231::_burstRead()
|
||||
{
|
||||
if (_use_hw)
|
||||
{
|
||||
// Set slave address and number of internal address bytes.
|
||||
twi->TWI_MMR = (1 << 8) | TWI_MMR_MREAD | (DS3231_ADDR << 16);
|
||||
// Set internal address bytes
|
||||
twi->TWI_IADR = 0;
|
||||
// Send START condition
|
||||
twi->TWI_CR = TWI_CR_START;
|
||||
|
||||
for (int i=0; i<6; i++)
|
||||
{
|
||||
while ((twi->TWI_SR & TWI_SR_RXRDY) != TWI_SR_RXRDY)
|
||||
{
|
||||
};
|
||||
_burstArray[i] = twi->TWI_RHR;
|
||||
}
|
||||
|
||||
twi->TWI_CR = TWI_CR_STOP;
|
||||
while ((twi->TWI_SR & TWI_SR_RXRDY) != TWI_SR_RXRDY) {};
|
||||
_burstArray[6] = twi->TWI_RHR;
|
||||
while ((twi->TWI_SR & TWI_SR_TXCOMP) != TWI_SR_TXCOMP) {};
|
||||
}
|
||||
else
|
||||
{
|
||||
_sendStart(DS3231_ADDR_W);
|
||||
_waitForAck();
|
||||
_writeByte(0);
|
||||
_waitForAck();
|
||||
_sendStart(DS3231_ADDR_R);
|
||||
_waitForAck();
|
||||
|
||||
for (int i=0; i<7; i++)
|
||||
{
|
||||
_burstArray[i] = _readByte();
|
||||
if (i<6)
|
||||
_sendAck();
|
||||
else
|
||||
_sendNack();
|
||||
}
|
||||
_sendStop();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t DS3231::_readRegister(uint8_t reg)
|
||||
{
|
||||
uint8_t readValue=0;
|
||||
|
||||
if (_use_hw)
|
||||
{
|
||||
// Set slave address and number of internal address bytes.
|
||||
twi->TWI_MMR = (1 << 8) | TWI_MMR_MREAD | (DS3231_ADDR << 16);
|
||||
// Set internal address bytes
|
||||
twi->TWI_IADR = reg;
|
||||
// Send START and STOP condition to read a single byte
|
||||
twi->TWI_CR = TWI_CR_START | TWI_CR_STOP;
|
||||
while ((twi->TWI_SR & TWI_SR_RXRDY) != TWI_SR_RXRDY) {};
|
||||
readValue = twi->TWI_RHR;
|
||||
while ((twi->TWI_SR & TWI_SR_TXCOMP) != TWI_SR_TXCOMP) {};
|
||||
}
|
||||
else
|
||||
{
|
||||
_sendStart(DS3231_ADDR_W);
|
||||
_waitForAck();
|
||||
_writeByte(reg);
|
||||
_waitForAck();
|
||||
_sendStart(DS3231_ADDR_R);
|
||||
_waitForAck();
|
||||
readValue = _readByte();
|
||||
_sendNack();
|
||||
_sendStop();
|
||||
}
|
||||
return readValue;
|
||||
}
|
||||
|
||||
void DS3231::_writeRegister(uint8_t reg, uint8_t value)
|
||||
{
|
||||
if (_use_hw)
|
||||
{
|
||||
// Set slave address and number of internal address bytes.
|
||||
twi->TWI_MMR = (1 << 8) | (DS3231_ADDR << 16);
|
||||
// Set internal address bytes
|
||||
twi->TWI_IADR = reg;
|
||||
// Send a single byte to start transfer
|
||||
twi->TWI_THR = value;
|
||||
while ((twi->TWI_SR & TWI_SR_TXRDY) != TWI_SR_TXRDY) {};
|
||||
// Send STOP condition
|
||||
twi->TWI_CR = TWI_CR_STOP;
|
||||
while ((twi->TWI_SR & TWI_SR_TXCOMP) != TWI_SR_TXCOMP) {};
|
||||
}
|
||||
else
|
||||
{
|
||||
_sendStart(DS3231_ADDR_W);
|
||||
_waitForAck();
|
||||
_writeByte(reg);
|
||||
_waitForAck();
|
||||
_writeByte(value);
|
||||
_waitForAck();
|
||||
_sendStop();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// *** Hardwarespecific defines ***
|
||||
#define SDA 20
|
||||
#define SCL 21
|
||||
#define SDA1 70
|
||||
#define SCL1 71
|
||||
|
||||
#define TWI_SPEED TWI_SPEED_400k // Set default TWI Speed
|
||||
#define TWI_SPEED_100k 208
|
||||
#define TWI_SPEED_400k 101
|
||||
|
||||
#define TWI_DIV TWI_DIV_400k // Set divider for TWI Speed (must match TWI_SPEED setting)
|
||||
#define TWI_DIV_100k 1
|
||||
#define TWI_DIV_400k 0
|
|
@ -0,0 +1,153 @@
|
|||
void DS3231::begin()
|
||||
{
|
||||
if ((_sda_pin == SDA) and (_scl_pin == SCL))
|
||||
{
|
||||
_use_hw = true;
|
||||
// activate internal pullups for twi.
|
||||
digitalWrite(SDA, HIGH);
|
||||
digitalWrite(SCL, HIGH);
|
||||
//delay(1); // Workaround for a linker bug
|
||||
|
||||
// initialize twi prescaler and bit rate
|
||||
cbi(TWSR, TWPS0);
|
||||
cbi(TWSR, TWPS1);
|
||||
TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
|
||||
|
||||
// enable twi module, acks, and twi interrupt
|
||||
TWCR = _BV(TWEN) | _BV(TWIE)/* | _BV(TWEA)*/;
|
||||
}
|
||||
else
|
||||
{
|
||||
_use_hw = false;
|
||||
pinMode(_scl_pin, OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
void DS3231::_burstRead()
|
||||
{
|
||||
if (_use_hw)
|
||||
{
|
||||
// Send start address
|
||||
TWCR = _BV(TWEN) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); // Send START
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
TWDR = DS3231_ADDR_W;
|
||||
TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA); // Clear TWINT to proceed
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
TWDR = 0;
|
||||
TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA); // Clear TWINT to proceed
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
|
||||
// Read data starting from start address
|
||||
TWCR = _BV(TWEN) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); // Send rep. START
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
TWDR = DS3231_ADDR_R;
|
||||
TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA); // Clear TWINT to proceed
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
for (int i=0; i<7; i++)
|
||||
{
|
||||
TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA); // Send ACK and clear TWINT to proceed
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
_burstArray[i] = TWDR;
|
||||
}
|
||||
TWCR = _BV(TWEN) | _BV(TWINT); // Send NACK and clear TWINT to proceed
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
|
||||
TWCR = _BV(TWEN)| _BV(TWINT) | _BV(TWSTO); // Send STOP
|
||||
}
|
||||
else
|
||||
{
|
||||
_sendStart(DS3231_ADDR_W);
|
||||
_waitForAck();
|
||||
_writeByte(0);
|
||||
_waitForAck();
|
||||
_sendStart(DS3231_ADDR_R);
|
||||
_waitForAck();
|
||||
|
||||
for (int i=0; i<7; i++)
|
||||
{
|
||||
_burstArray[i] = _readByte();
|
||||
if (i<6)
|
||||
_sendAck();
|
||||
else
|
||||
_sendNack();
|
||||
}
|
||||
_sendStop();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t DS3231::_readRegister(uint8_t reg)
|
||||
{
|
||||
uint8_t readValue=0;
|
||||
|
||||
if (_use_hw)
|
||||
{
|
||||
// Send start address
|
||||
TWCR = _BV(TWEN) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); // Send START
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
TWDR = DS3231_ADDR_W;
|
||||
TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA); // Clear TWINT to proceed
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
TWDR = reg;
|
||||
TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA); // Clear TWINT to proceed
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
|
||||
// Read data starting from start address
|
||||
TWCR = _BV(TWEN) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); // Send rep. START
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
TWDR = DS3231_ADDR_R;
|
||||
TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA); // Clear TWINT to proceed
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA); // Send ACK and clear TWINT to proceed
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
readValue = TWDR;
|
||||
TWCR = _BV(TWEN) | _BV(TWINT); // Send NACK and clear TWINT to proceed
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
|
||||
TWCR = _BV(TWEN)| _BV(TWINT) | _BV(TWSTO); // Send STOP
|
||||
}
|
||||
else
|
||||
{
|
||||
_sendStart(DS3231_ADDR_W);
|
||||
_waitForAck();
|
||||
_writeByte(reg);
|
||||
_waitForAck();
|
||||
_sendStart(DS3231_ADDR_R);
|
||||
_waitForAck();
|
||||
readValue = _readByte();
|
||||
_sendNack();
|
||||
_sendStop();
|
||||
}
|
||||
return readValue;
|
||||
}
|
||||
|
||||
void DS3231::_writeRegister(uint8_t reg, uint8_t value)
|
||||
{
|
||||
if (_use_hw)
|
||||
{
|
||||
// Send start address
|
||||
TWCR = _BV(TWEN) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); // Send START
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
TWDR = DS3231_ADDR_W;
|
||||
TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA); // Clear TWINT to proceed
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
TWDR = reg;
|
||||
TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA); // Clear TWINT to proceed
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
TWDR = value;
|
||||
TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA); // Clear TWINT to proceed
|
||||
while ((TWCR & _BV(TWINT)) == 0) {}; // Wait for TWI to be ready
|
||||
|
||||
TWCR = _BV(TWEN)| _BV(TWINT) | _BV(TWSTO); // Send STOP
|
||||
}
|
||||
else
|
||||
{
|
||||
_sendStart(DS3231_ADDR_W);
|
||||
_waitForAck();
|
||||
_writeByte(reg);
|
||||
_waitForAck();
|
||||
_writeByte(value);
|
||||
_waitForAck();
|
||||
_sendStop();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// *** Hardwarespecific defines ***
|
||||
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
||||
|
||||
#ifndef TWI_FREQ
|
||||
#define TWI_FREQ 400000L
|
||||
#endif
|
|
@ -0,0 +1,192 @@
|
|||
inline void _waitForIdleBus() { while (I2C1CON & 0x1f) {} }
|
||||
|
||||
void DS3231::begin()
|
||||
{
|
||||
if ((_sda_pin == SDA) and (_scl_pin == SCL))
|
||||
{
|
||||
uint32_t tpgd;
|
||||
|
||||
_use_hw = true;
|
||||
pinMode(SDA, OUTPUT);
|
||||
digitalWrite(SDA, HIGH);
|
||||
IFS0CLR = 0xE0000000; // Clear Interrupt Flag
|
||||
IEC0CLR = 0xE0000000; // Disable Interrupt
|
||||
I2C1CONCLR = (1 << _I2CCON_ON); // Disable I2C interface
|
||||
tpgd = ((F_CPU / 8) * 104) / 125000000;
|
||||
I2C1BRG = (F_CPU / (2 * TWI_FREQ) - tpgd) - 2; // Set I2C Speed
|
||||
I2C1ADD = DS3231_ADDR; // Set I2C device address
|
||||
I2C1CONSET = (1 << _I2CCON_ON) | (1 << _I2CCON_STREN); // Enable I2C Interface
|
||||
}
|
||||
else
|
||||
{
|
||||
_use_hw = false;
|
||||
pinMode(_scl_pin, OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
void DS3231::_burstRead()
|
||||
{
|
||||
if (_use_hw)
|
||||
{
|
||||
_waitForIdleBus(); // Wait for I2C bus to be Idle before starting
|
||||
I2C1CONSET = (1 << _I2CCON_SEN); // Send start condition
|
||||
if (I2C1STAT & (1 << _I2CSTAT_BCL)) { return; } // Check if there is a bus collision
|
||||
while (I2C1CON & (1 << _I2CCON_SEN)) {} // Wait for start condition to finish
|
||||
I2C1TRN = (DS3231_ADDR<<1); // Send device Write address
|
||||
while (I2C1STAT & (1 << _I2CSTAT_IWCOL)) // Check if there is a Write collision
|
||||
{
|
||||
I2C1STATCLR = (1 << _I2CSTAT_IWCOL); // Clear Write collision flag
|
||||
I2C1TRN = (DS3231_ADDR<<1); // Retry send device Write address
|
||||
}
|
||||
while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
|
||||
while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
|
||||
I2C1TRN = 0; // Send the register address
|
||||
while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
|
||||
while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
|
||||
_waitForIdleBus(); // Wait for I2C bus to be Idle before starting
|
||||
I2C1CONSET = (1 << _I2CCON_RSEN); // Send start condition
|
||||
if (I2C1STAT & (1 << _I2CSTAT_BCL)) { return; } // Check if there is a bus collision
|
||||
while (I2C1CON & (1 << _I2CCON_RSEN)) {} // Wait for start condition to finish
|
||||
I2C1TRN = (DS3231_ADDR<<1) | 1; // Send device Read address
|
||||
while (I2C1STAT & (1 << _I2CSTAT_IWCOL)) // Check if there is a Write collision
|
||||
{
|
||||
I2C1STATCLR = (1 << _I2CSTAT_IWCOL); // Clear Write collision flag
|
||||
I2C1TRN = (DS3231_ADDR<<1) | 1; // Retry send device Read address
|
||||
}
|
||||
while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
|
||||
while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
|
||||
byte dummy = I2C1RCV; // Clear _I2CSTAT_RBF (Receive Buffer Full)
|
||||
for (int i=0; i<7; i++)
|
||||
{
|
||||
_waitForIdleBus(); // Wait for I2C bus to be Idle before continuing
|
||||
I2C1CONSET = (1 << _I2CCON_RCEN); // Set RCEN to start receive
|
||||
while (I2C1CON & (1 << _I2CCON_RCEN)) {} // Wait for Receive operation to finish
|
||||
while (!(I2C1STAT & (1 << _I2CSTAT_RBF))) {} // Wait for Receive Buffer Full
|
||||
_burstArray[i] = I2C1RCV; // Read data
|
||||
if (i == 6)
|
||||
I2C1CONSET = (1 << _I2CCON_ACKDT); // Prepare to send NACK
|
||||
else
|
||||
I2C1CONCLR = (1 << _I2CCON_ACKDT); // Prepare to send ACK
|
||||
I2C1CONSET = (1 << _I2CCON_ACKEN); // Send ACK/NACK
|
||||
while (I2C1CON & (1 << _I2CCON_ACKEN)) {} // Wait for ACK/NACK send to finish
|
||||
}
|
||||
I2C1CONSET = (1 << _I2CCON_PEN); // Send stop condition
|
||||
while (I2C1CON & (1 << _I2CCON_PEN)) {} // Wait for stop condition to finish
|
||||
}
|
||||
else
|
||||
{
|
||||
_sendStart(DS3231_ADDR_W);
|
||||
_waitForAck();
|
||||
_writeByte(0);
|
||||
_waitForAck();
|
||||
_sendStart(DS3231_ADDR_R);
|
||||
_waitForAck();
|
||||
|
||||
for (int i=0; i<7; i++)
|
||||
{
|
||||
_burstArray[i] = _readByte();
|
||||
if (i<6)
|
||||
_sendAck();
|
||||
else
|
||||
_sendNack();
|
||||
}
|
||||
_sendStop();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t DS3231::_readRegister(uint8_t reg)
|
||||
{
|
||||
uint8_t readValue=0;
|
||||
|
||||
if (_use_hw)
|
||||
{
|
||||
_waitForIdleBus(); // Wait for I2C bus to be Idle before starting
|
||||
I2C1CONSET = (1 << _I2CCON_SEN); // Send start condition
|
||||
if (I2C1STAT & (1 << _I2CSTAT_BCL)) { return 0xff; }// Check if there is a bus collision
|
||||
while (I2C1CON & (1 << _I2CCON_SEN)) {} // Wait for start condition to finish
|
||||
I2C1TRN = (DS3231_ADDR<<1); // Send device Write address
|
||||
while (I2C1STAT & (1 << _I2CSTAT_IWCOL)) // Check if there is a Write collision
|
||||
{
|
||||
I2C1STATCLR = (1 << _I2CSTAT_IWCOL); // Clear Write collision flag
|
||||
I2C1TRN = (DS3231_ADDR<<1); // Retry send device Write address
|
||||
}
|
||||
while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
|
||||
while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
|
||||
I2C1TRN = reg; // Send the register address
|
||||
while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
|
||||
while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
|
||||
_waitForIdleBus(); // Wait for I2C bus to be Idle before starting
|
||||
I2C1CONSET = (1 << _I2CCON_RSEN); // Send start condition
|
||||
if (I2C1STAT & (1 << _I2CSTAT_BCL)) { return 0xff; }// Check if there is a bus collision
|
||||
while (I2C1CON & (1 << _I2CCON_RSEN)) {} // Wait for start condition to finish
|
||||
I2C1TRN = (DS3231_ADDR<<1) | 1; // Send device Read address
|
||||
while (I2C1STAT & (1 << _I2CSTAT_IWCOL)) // Check if there is a Write collision
|
||||
{
|
||||
I2C1STATCLR = (1 << _I2CSTAT_IWCOL); // Clear Write collision flag
|
||||
I2C1TRN = (DS3231_ADDR<<1) | 1; // Retry send device Read address
|
||||
}
|
||||
while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
|
||||
while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
|
||||
byte dummy = I2C1RCV; // Clear _I2CSTAT_RBF (Receive Buffer Full)
|
||||
_waitForIdleBus(); // Wait for I2C bus to be Idle before continuing
|
||||
I2C1CONSET = (1 << _I2CCON_RCEN); // Set RCEN to start receive
|
||||
while (I2C1CON & (1 << _I2CCON_RCEN)) {} // Wait for Receive operation to finish
|
||||
while (!(I2C1STAT & (1 << _I2CSTAT_RBF))) {} // Wait for Receive Buffer Full
|
||||
readValue = I2C1RCV; // Read data
|
||||
I2C1CONSET = (1 << _I2CCON_ACKDT); // Prepare to send NACK
|
||||
I2C1CONSET = (1 << _I2CCON_ACKEN); // Send NACK
|
||||
while (I2C1CON & (1 << _I2CCON_ACKEN)) {} // Wait for NACK send to finish
|
||||
I2C1CONSET = (1 << _I2CCON_PEN); // Send stop condition
|
||||
while (I2C1CON & (1 << _I2CCON_PEN)) {} // Wait for stop condition to finish
|
||||
}
|
||||
else
|
||||
{
|
||||
_sendStart(DS3231_ADDR_W);
|
||||
_waitForAck();
|
||||
_writeByte(reg);
|
||||
_waitForAck();
|
||||
_sendStart(DS3231_ADDR_R);
|
||||
_waitForAck();
|
||||
readValue = _readByte();
|
||||
_sendNack();
|
||||
_sendStop();
|
||||
}
|
||||
return readValue;
|
||||
}
|
||||
|
||||
void DS3231::_writeRegister(uint8_t reg, uint8_t value)
|
||||
{
|
||||
if (_use_hw)
|
||||
{
|
||||
_waitForIdleBus(); // Wait for I2C bus to be Idle before starting
|
||||
I2C1CONSET = (1 << _I2CCON_SEN); // Send start condition
|
||||
if (I2C1STAT & (1 << _I2CSTAT_BCL)) { return; } // Check if there is a bus collision
|
||||
while (I2C1CON & (1 << _I2CCON_SEN)) {} // Wait for start condition to finish
|
||||
I2C1TRN = (DS3231_ADDR<<1); // Send device Write address
|
||||
while (I2C1STAT & (1 << _I2CSTAT_IWCOL)) // Check if there is a Write collision
|
||||
{
|
||||
I2C1STATCLR = (1 << _I2CSTAT_IWCOL); // Clear Write collision flag
|
||||
I2C1TRN = (DS3231_ADDR<<1); // Retry send device Write address
|
||||
}
|
||||
while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
|
||||
while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
|
||||
I2C1TRN = reg; // Send the 1st data byte
|
||||
while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
|
||||
while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
|
||||
I2C1TRN = value; // Send the 2nd data byte
|
||||
while (I2C1STAT & (1 << _I2CSTAT_TRSTAT)) {} // Wait for transmit to finish
|
||||
while (I2C1STAT & (1 << _I2CSTAT_ACKSTAT)) {} // Wait for ACK
|
||||
I2C1CONSET = (1 << _I2CCON_PEN); // Send stop condition
|
||||
while (I2C1CON & (1 << _I2CCON_PEN)) {} // Wait for stop condition to finish
|
||||
}
|
||||
else
|
||||
{
|
||||
_sendStart(DS3231_ADDR_W);
|
||||
_waitForAck();
|
||||
_writeByte(reg);
|
||||
_waitForAck();
|
||||
_writeByte(value);
|
||||
_waitForAck();
|
||||
_sendStop();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// *** Hardwarespecific defines ***
|
||||
|
||||
#if !defined(_UP_MCU_)
|
||||
#if defined(__32MX320F128H__)
|
||||
#define SDA 18 // A4 (Remeber to set the jumper correctly)
|
||||
#define SCL 19 // A5 (Remeber to set the jumper correctly)
|
||||
#elif defined(__32MX340F512H__)
|
||||
#define SDA 18 // A4 (Remeber to set the jumper correctly)
|
||||
#define SCL 19 // A5 (Remeber to set the jumper correctly)
|
||||
#elif defined(__32MX795F512L__)
|
||||
#define SDA 20 // Digital 20
|
||||
#define SCL 21 // Digital 21
|
||||
#else
|
||||
#error "Unsupported PIC32 MCU!"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TWI_FREQ
|
||||
#define TWI_FREQ 400000L
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue