commit ef7328c0f1090d4e081da2e7a8723788a364784e Author: Dustin Brunner Date: Sat Aug 28 09:36:25 2021 +0200 Upload 1 diff --git a/Binaeruhr.fzz b/Binaeruhr.fzz new file mode 100644 index 0000000..cdd3858 Binary files /dev/null and b/Binaeruhr.fzz differ diff --git a/Binaeruhr_Platine.fzz b/Binaeruhr_Platine.fzz new file mode 100644 index 0000000..9af6450 Binary files /dev/null and b/Binaeruhr_Platine.fzz differ diff --git a/Frontplatte.pdf b/Frontplatte.pdf new file mode 100644 index 0000000..0a32744 Binary files /dev/null and b/Frontplatte.pdf differ diff --git a/Frontplatte.png b/Frontplatte.png new file mode 100644 index 0000000..9ac78c5 Binary files /dev/null and b/Frontplatte.png differ diff --git a/Frontplatte_10x15_Bilderrahmen.fpd b/Frontplatte_10x15_Bilderrahmen.fpd new file mode 100644 index 0000000..7c690ca Binary files /dev/null and b/Frontplatte_10x15_Bilderrahmen.fpd differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..9f35ebd --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# Arduino Binäruhr +Eine Binäruhr basierend auf einem Arduino Nano. Die LEDs werden mit Hilfe von 74HC595 Schieberegistern angesteuert. + +[](pictures/Uhr_1.jpg) +[](pictures/Uhr_2.jpg) +[](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)**

+[](pictures/Binaeruhr_Schaltplan.png) + +## Leiterplatte +[](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. +

+[](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# + +

+

This work by Dustin Brunner is licensed under CC BY 4.0

+ +Creative Commons Lizenzvertrag
Dieses Werk von Dustin Brunner ist lizenziert unter einer Creative Commons Namensnennung 4.0 International Lizenz. + + diff --git a/pictures/Binaeruhr_Platine_Leiterplatte.png b/pictures/Binaeruhr_Platine_Leiterplatte.png new file mode 100644 index 0000000..91e0ef8 Binary files /dev/null and b/pictures/Binaeruhr_Platine_Leiterplatte.png differ diff --git a/pictures/Binaeruhr_Schaltplan.png b/pictures/Binaeruhr_Schaltplan.png new file mode 100644 index 0000000..5852b26 Binary files /dev/null and b/pictures/Binaeruhr_Schaltplan.png differ diff --git a/pictures/Uhr_1.jpg b/pictures/Uhr_1.jpg new file mode 100644 index 0000000..803eecc Binary files /dev/null and b/pictures/Uhr_1.jpg differ diff --git a/pictures/Uhr_2.jpg b/pictures/Uhr_2.jpg new file mode 100644 index 0000000..7398559 Binary files /dev/null and b/pictures/Uhr_2.jpg differ diff --git a/pictures/Uhr_innen.jpg b/pictures/Uhr_innen.jpg new file mode 100644 index 0000000..4e85944 Binary files /dev/null and b/pictures/Uhr_innen.jpg differ diff --git a/software_binaeruhr/software_binaeruhr.ino b/software_binaeruhr/software_binaeruhr.ino new file mode 100644 index 0000000..40f8c9f --- /dev/null +++ b/software_binaeruhr/software_binaeruhr.ino @@ -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); +} diff --git a/software_binaeruhr/src/DS3231.cpp b/software_binaeruhr/src/DS3231.cpp new file mode 100644 index 0000000..5e90dbe --- /dev/null +++ b/software_binaeruhr/src/DS3231.cpp @@ -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; +} + diff --git a/software_binaeruhr/src/DS3231.h b/software_binaeruhr/src/DS3231.h new file mode 100644 index 0000000..882a492 --- /dev/null +++ b/software_binaeruhr/src/DS3231.h @@ -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 diff --git a/software_binaeruhr/src/hardware/arm/HW_ARM.h b/software_binaeruhr/src/hardware/arm/HW_ARM.h new file mode 100644 index 0000000..6614ef7 --- /dev/null +++ b/software_binaeruhr/src/hardware/arm/HW_ARM.h @@ -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(); + } +} + diff --git a/software_binaeruhr/src/hardware/arm/HW_ARM_defines.h b/software_binaeruhr/src/hardware/arm/HW_ARM_defines.h new file mode 100644 index 0000000..2fff1f1 --- /dev/null +++ b/software_binaeruhr/src/hardware/arm/HW_ARM_defines.h @@ -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 diff --git a/software_binaeruhr/src/hardware/avr/HW_AVR.h b/software_binaeruhr/src/hardware/avr/HW_AVR.h new file mode 100644 index 0000000..73583e3 --- /dev/null +++ b/software_binaeruhr/src/hardware/avr/HW_AVR.h @@ -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(); + } +} + diff --git a/software_binaeruhr/src/hardware/avr/HW_AVR_defines.h b/software_binaeruhr/src/hardware/avr/HW_AVR_defines.h new file mode 100644 index 0000000..e29c940 --- /dev/null +++ b/software_binaeruhr/src/hardware/avr/HW_AVR_defines.h @@ -0,0 +1,6 @@ +// *** Hardwarespecific defines *** +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) + +#ifndef TWI_FREQ + #define TWI_FREQ 400000L +#endif diff --git a/software_binaeruhr/src/hardware/pic32/HW_PIC32.h b/software_binaeruhr/src/hardware/pic32/HW_PIC32.h new file mode 100644 index 0000000..bdc23e4 --- /dev/null +++ b/software_binaeruhr/src/hardware/pic32/HW_PIC32.h @@ -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(); + } +} diff --git a/software_binaeruhr/src/hardware/pic32/HW_PIC32_defines.h b/software_binaeruhr/src/hardware/pic32/HW_PIC32_defines.h new file mode 100644 index 0000000..16822be --- /dev/null +++ b/software_binaeruhr/src/hardware/pic32/HW_PIC32_defines.h @@ -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 +