first commit
This commit is contained in:
commit
81a1e77896
|
@ -0,0 +1,7 @@
|
|||
.login-header {
|
||||
text-align: center;
|
||||
}
|
||||
.login-button {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
session_start();
|
||||
|
||||
// Cek apakah user sudah login
|
||||
if (!isset($_SESSION['username'])) {
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Ambil data session
|
||||
$username = $_SESSION['username'];
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['time1']) && isset($_POST['time2'])) {
|
||||
$time1 = $_POST['time1'];
|
||||
$time2 = $_POST['time2'];
|
||||
|
||||
// Insert or update feed times
|
||||
$sql = "UPDATE feed_times SET time1='$time1', time2='$time2'";
|
||||
|
||||
if ($conn->query($sql) === TRUE) {
|
||||
echo "<script>alert('Feed times have been saved!');</script>";
|
||||
} else {
|
||||
echo "<script>alert('Error!');</script>";
|
||||
}
|
||||
}
|
||||
|
||||
$conn->close();
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Pengaturan Waktu Pakan Ikan</title>
|
||||
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.custom-container {
|
||||
max-width: 600px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container custom-container">
|
||||
<h1 class="mb-4 text-center">Pengaturan Waktu Pakan Ikan</h1>
|
||||
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
|
||||
<div class="form-group">
|
||||
<label for="time1">Waktu Pakan 1:</label>
|
||||
<input type="time" class="form-control" id="time1" name="time1" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="time2">Waktu Pakan 2:</label>
|
||||
<input type="time" class="form-control" id="time2" name="time2" required>
|
||||
</div>
|
||||
<button type="submit" name="submit" class="btn btn-primary float-right">Set Waktu Pakan</button>
|
||||
<div class="text-left mb-3">
|
||||
<a href="logout.php" class="btn btn-danger">Logout</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS CDN (Optional) -->
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,66 @@
|
|||
-- phpMyAdmin SQL Dump
|
||||
-- version 5.2.1
|
||||
-- https://www.phpmyadmin.net/
|
||||
--
|
||||
-- Host: 127.0.0.1
|
||||
-- Generation Time: Jun 24, 2024 at 02:58 PM
|
||||
-- Server version: 10.4.32-MariaDB
|
||||
-- PHP Version: 8.1.25
|
||||
|
||||
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||
START TRANSACTION;
|
||||
SET time_zone = "+00:00";
|
||||
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8mb4 */;
|
||||
|
||||
--
|
||||
-- Database: `db_pakaniwak`
|
||||
--
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `feed_times`
|
||||
--
|
||||
|
||||
CREATE TABLE `feed_times` (
|
||||
`id` int(11) NOT NULL,
|
||||
`time1` time NOT NULL,
|
||||
`time2` time NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
--
|
||||
-- Dumping data for table `feed_times`
|
||||
--
|
||||
|
||||
INSERT INTO `feed_times` (`id`, `time1`, `time2`) VALUES
|
||||
(1, '16:49:00', '16:51:00');
|
||||
|
||||
--
|
||||
-- Indexes for dumped tables
|
||||
--
|
||||
|
||||
--
|
||||
-- Indexes for table `feed_times`
|
||||
--
|
||||
ALTER TABLE `feed_times`
|
||||
ADD PRIMARY KEY (`id`);
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT for dumped tables
|
||||
--
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT for table `feed_times`
|
||||
--
|
||||
ALTER TABLE `feed_times`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
|
||||
COMMIT;
|
||||
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$sql = "SELECT time1, time2 FROM feed_times LIMIT 1";
|
||||
$result = $conn->query($sql);
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
$row = $result->fetch_assoc();
|
||||
echo $row['time1'] . ',' . $row['time2'];
|
||||
} else {
|
||||
echo "No feed times set.";
|
||||
}
|
||||
|
||||
$conn->close();
|
||||
?>
|
|
@ -0,0 +1,42 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login Pakan Iwak</title>
|
||||
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<section class="vh-100" style="background-color: #508bfc;">
|
||||
<div class="container py-5 h-100">
|
||||
<div class="row d-flex justify-content-center align-items-center h-100">
|
||||
<div class="col-12 col-md-8 col-lg-6 col-xl-5">
|
||||
<div class="card shadow-2-strong" style="border-radius: 1rem;">
|
||||
<div class="card-body p-5 text-center">
|
||||
|
||||
<h3 class="mb-5">Login</h3>
|
||||
|
||||
<form action="login.php" method="POST">
|
||||
<div data-mdb-input-init class="form-outline mb-4">
|
||||
<input type="text" id="username" name="username" placeholder="Masukkan Username" class="form-control form-control-lg" />
|
||||
</div>
|
||||
|
||||
<div data-mdb-input-init class="form-outline mb-4">
|
||||
<input type="password" id="password" name="password" placeholder="Masukkan Password" class="form-control form-control-lg" />
|
||||
</div>
|
||||
|
||||
<button data-mdb-button-init data-mdb-ripple-init class="btn btn-primary btn-lg btn-block" type="submit">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
$servername = "localhost";
|
||||
$username = "root";
|
||||
$password = "";
|
||||
$dbname = "db_pakaniwak";
|
||||
|
||||
// Create connection
|
||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
||||
|
||||
// Check connection
|
||||
if ($conn->connect_error) {
|
||||
die("Connection failed: " . $conn->connect_error);
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,332 @@
|
|||
// Based on the work by DFRobot
|
||||
|
||||
#include "LiquidCrystal_I2C.h"
|
||||
#include <inttypes.h>
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#define printIIC(args) Wire.write(args)
|
||||
inline size_t LiquidCrystal_I2C::write(uint8_t value) {
|
||||
send(value, Rs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
|
||||
#define printIIC(args) Wire.send(args)
|
||||
inline void LiquidCrystal_I2C::write(uint8_t value) {
|
||||
send(value, Rs);
|
||||
}
|
||||
|
||||
#endif
|
||||
#include "Wire.h"
|
||||
|
||||
|
||||
|
||||
// When the display powers up, it is configured as follows:
|
||||
//
|
||||
// 1. Display clear
|
||||
// 2. Function set:
|
||||
// DL = 1; 8-bit interface data
|
||||
// N = 0; 1-line display
|
||||
// F = 0; 5x8 dot character font
|
||||
// 3. Display on/off control:
|
||||
// D = 0; Display off
|
||||
// C = 0; Cursor off
|
||||
// B = 0; Blinking off
|
||||
// 4. Entry mode set:
|
||||
// I/D = 1; Increment by 1
|
||||
// S = 0; No shift
|
||||
//
|
||||
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
|
||||
// can't assume that its in that state when a sketch starts (and the
|
||||
// LiquidCrystal constructor is called).
|
||||
|
||||
LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows)
|
||||
{
|
||||
_Addr = lcd_Addr;
|
||||
_cols = lcd_cols;
|
||||
_rows = lcd_rows;
|
||||
_backlightval = LCD_NOBACKLIGHT;
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::oled_init(){
|
||||
_oled = true;
|
||||
init_priv();
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::init(){
|
||||
init_priv();
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::init_priv()
|
||||
{
|
||||
Wire.begin();
|
||||
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
begin(_cols, _rows);
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
|
||||
if (lines > 1) {
|
||||
_displayfunction |= LCD_2LINE;
|
||||
}
|
||||
_numlines = lines;
|
||||
|
||||
// for some 1 line displays you can select a 10 pixel high font
|
||||
if ((dotsize != 0) && (lines == 1)) {
|
||||
_displayfunction |= LCD_5x10DOTS;
|
||||
}
|
||||
|
||||
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
|
||||
// according to datasheet, we need at least 40ms after power rises above 2.7V
|
||||
// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
|
||||
delay(50);
|
||||
|
||||
// Now we pull both RS and R/W low to begin commands
|
||||
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
|
||||
delay(1000);
|
||||
|
||||
//put the LCD into 4 bit mode
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// figure 24, pg 46
|
||||
|
||||
// we start in 8bit mode, try to set 4 bit mode
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// second try
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// third go!
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// finally, set to 4-bit interface
|
||||
write4bits(0x02 << 4);
|
||||
|
||||
|
||||
// set # lines, font size, etc.
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
|
||||
// turn the display on with no cursor or blinking default
|
||||
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
|
||||
display();
|
||||
|
||||
// clear it off
|
||||
clear();
|
||||
|
||||
// Initialize to default text direction (for roman languages)
|
||||
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
|
||||
|
||||
// set the entry mode
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
|
||||
home();
|
||||
|
||||
}
|
||||
|
||||
/********** high level commands, for the user! */
|
||||
void LiquidCrystal_I2C::clear(){
|
||||
command(LCD_CLEARDISPLAY);// clear display, set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
if (_oled) setCursor(0,0);
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::home(){
|
||||
command(LCD_RETURNHOME); // set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::setCursor(uint8_t col, uint8_t row){
|
||||
int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
|
||||
if ( row > _numlines ) {
|
||||
row = _numlines-1; // we count rows starting w/0
|
||||
}
|
||||
command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
|
||||
}
|
||||
|
||||
// Turn the display on/off (quickly)
|
||||
void LiquidCrystal_I2C::noDisplay() {
|
||||
_displaycontrol &= ~LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal_I2C::display() {
|
||||
_displaycontrol |= LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turns the underline cursor on/off
|
||||
void LiquidCrystal_I2C::noCursor() {
|
||||
_displaycontrol &= ~LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal_I2C::cursor() {
|
||||
_displaycontrol |= LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turn on and off the blinking cursor
|
||||
void LiquidCrystal_I2C::noBlink() {
|
||||
_displaycontrol &= ~LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal_I2C::blink() {
|
||||
_displaycontrol |= LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// These commands scroll the display without changing the RAM
|
||||
void LiquidCrystal_I2C::scrollDisplayLeft(void) {
|
||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
|
||||
}
|
||||
void LiquidCrystal_I2C::scrollDisplayRight(void) {
|
||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
|
||||
}
|
||||
|
||||
// This is for text that flows Left to Right
|
||||
void LiquidCrystal_I2C::leftToRight(void) {
|
||||
_displaymode |= LCD_ENTRYLEFT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This is for text that flows Right to Left
|
||||
void LiquidCrystal_I2C::rightToLeft(void) {
|
||||
_displaymode &= ~LCD_ENTRYLEFT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This will 'right justify' text from the cursor
|
||||
void LiquidCrystal_I2C::autoscroll(void) {
|
||||
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This will 'left justify' text from the cursor
|
||||
void LiquidCrystal_I2C::noAutoscroll(void) {
|
||||
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// Allows us to fill the first 8 CGRAM locations
|
||||
// with custom characters
|
||||
void LiquidCrystal_I2C::createChar(uint8_t location, uint8_t charmap[]) {
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
command(LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i=0; i<8; i++) {
|
||||
write(charmap[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//createChar with PROGMEM input
|
||||
void LiquidCrystal_I2C::createChar(uint8_t location, const char *charmap) {
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
command(LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i=0; i<8; i++) {
|
||||
write(pgm_read_byte_near(charmap++));
|
||||
}
|
||||
}
|
||||
|
||||
// Turn the (optional) backlight off/on
|
||||
void LiquidCrystal_I2C::noBacklight(void) {
|
||||
_backlightval=LCD_NOBACKLIGHT;
|
||||
expanderWrite(0);
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::backlight(void) {
|
||||
_backlightval=LCD_BACKLIGHT;
|
||||
expanderWrite(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********** mid level commands, for sending data/cmds */
|
||||
|
||||
inline void LiquidCrystal_I2C::command(uint8_t value) {
|
||||
send(value, 0);
|
||||
}
|
||||
|
||||
|
||||
/************ low level data pushing commands **********/
|
||||
|
||||
// write either command or data
|
||||
void LiquidCrystal_I2C::send(uint8_t value, uint8_t mode) {
|
||||
uint8_t highnib=value&0xf0;
|
||||
uint8_t lownib=(value<<4)&0xf0;
|
||||
write4bits((highnib)|mode);
|
||||
write4bits((lownib)|mode);
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::write4bits(uint8_t value) {
|
||||
expanderWrite(value);
|
||||
pulseEnable(value);
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::expanderWrite(uint8_t _data){
|
||||
Wire.beginTransmission(_Addr);
|
||||
printIIC((int)(_data) | _backlightval);
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::pulseEnable(uint8_t _data){
|
||||
expanderWrite(_data | En); // En high
|
||||
delayMicroseconds(1); // enable pulse must be >450ns
|
||||
|
||||
expanderWrite(_data & ~En); // En low
|
||||
delayMicroseconds(50); // commands need > 37us to settle
|
||||
}
|
||||
|
||||
|
||||
// Alias functions
|
||||
|
||||
void LiquidCrystal_I2C::cursor_on(){
|
||||
cursor();
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::cursor_off(){
|
||||
noCursor();
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::blink_on(){
|
||||
blink();
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::blink_off(){
|
||||
noBlink();
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::load_custom_character(uint8_t char_num, uint8_t *rows){
|
||||
createChar(char_num, rows);
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::setBacklight(uint8_t new_val){
|
||||
if(new_val){
|
||||
backlight(); // turn backlight on
|
||||
}else{
|
||||
noBacklight(); // turn backlight off
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::printstr(const char c[]){
|
||||
//This function is not identical to the function used for "real" I2C displays
|
||||
//it's here so the user sketch doesn't have to be changed
|
||||
print(c);
|
||||
}
|
||||
|
||||
|
||||
// unsupported API functions
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
void LiquidCrystal_I2C::off(){}
|
||||
void LiquidCrystal_I2C::on(){}
|
||||
void LiquidCrystal_I2C::setDelay (int cmdDelay,int charDelay) {}
|
||||
uint8_t LiquidCrystal_I2C::status(){return 0;}
|
||||
uint8_t LiquidCrystal_I2C::keypad (){return 0;}
|
||||
uint8_t LiquidCrystal_I2C::init_bargraph(uint8_t graphtype){return 0;}
|
||||
void LiquidCrystal_I2C::draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end){}
|
||||
void LiquidCrystal_I2C::draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_row_end){}
|
||||
void LiquidCrystal_I2C::setContrast(uint8_t new_val){}
|
||||
#pragma GCC diagnostic pop
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
//YWROBOT
|
||||
#ifndef LiquidCrystal_I2C_h
|
||||
#define LiquidCrystal_I2C_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "Print.h"
|
||||
#include <Wire.h>
|
||||
|
||||
// commands
|
||||
#define LCD_CLEARDISPLAY 0x01
|
||||
#define LCD_RETURNHOME 0x02
|
||||
#define LCD_ENTRYMODESET 0x04
|
||||
#define LCD_DISPLAYCONTROL 0x08
|
||||
#define LCD_CURSORSHIFT 0x10
|
||||
#define LCD_FUNCTIONSET 0x20
|
||||
#define LCD_SETCGRAMADDR 0x40
|
||||
#define LCD_SETDDRAMADDR 0x80
|
||||
|
||||
// flags for display entry mode
|
||||
#define LCD_ENTRYRIGHT 0x00
|
||||
#define LCD_ENTRYLEFT 0x02
|
||||
#define LCD_ENTRYSHIFTINCREMENT 0x01
|
||||
#define LCD_ENTRYSHIFTDECREMENT 0x00
|
||||
|
||||
// flags for display on/off control
|
||||
#define LCD_DISPLAYON 0x04
|
||||
#define LCD_DISPLAYOFF 0x00
|
||||
#define LCD_CURSORON 0x02
|
||||
#define LCD_CURSOROFF 0x00
|
||||
#define LCD_BLINKON 0x01
|
||||
#define LCD_BLINKOFF 0x00
|
||||
|
||||
// flags for display/cursor shift
|
||||
#define LCD_DISPLAYMOVE 0x08
|
||||
#define LCD_CURSORMOVE 0x00
|
||||
#define LCD_MOVERIGHT 0x04
|
||||
#define LCD_MOVELEFT 0x00
|
||||
|
||||
// flags for function set
|
||||
#define LCD_8BITMODE 0x10
|
||||
#define LCD_4BITMODE 0x00
|
||||
#define LCD_2LINE 0x08
|
||||
#define LCD_1LINE 0x00
|
||||
#define LCD_5x10DOTS 0x04
|
||||
#define LCD_5x8DOTS 0x00
|
||||
|
||||
// flags for backlight control
|
||||
#define LCD_BACKLIGHT 0x08
|
||||
#define LCD_NOBACKLIGHT 0x00
|
||||
|
||||
#define En B00000100 // Enable bit
|
||||
#define Rw B00000010 // Read/Write bit
|
||||
#define Rs B00000001 // Register select bit
|
||||
|
||||
class LiquidCrystal_I2C : public Print {
|
||||
public:
|
||||
LiquidCrystal_I2C(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows);
|
||||
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS );
|
||||
void clear();
|
||||
void home();
|
||||
void noDisplay();
|
||||
void display();
|
||||
void noBlink();
|
||||
void blink();
|
||||
void noCursor();
|
||||
void cursor();
|
||||
void scrollDisplayLeft();
|
||||
void scrollDisplayRight();
|
||||
void printLeft();
|
||||
void printRight();
|
||||
void leftToRight();
|
||||
void rightToLeft();
|
||||
void shiftIncrement();
|
||||
void shiftDecrement();
|
||||
void noBacklight();
|
||||
void backlight();
|
||||
void autoscroll();
|
||||
void noAutoscroll();
|
||||
void createChar(uint8_t, uint8_t[]);
|
||||
void createChar(uint8_t location, const char *charmap);
|
||||
// Example: const char bell[8] PROGMEM = {B00100,B01110,B01110,B01110,B11111,B00000,B00100,B00000};
|
||||
|
||||
void setCursor(uint8_t, uint8_t);
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
virtual size_t write(uint8_t);
|
||||
#else
|
||||
virtual void write(uint8_t);
|
||||
#endif
|
||||
void command(uint8_t);
|
||||
void init();
|
||||
void oled_init();
|
||||
|
||||
////compatibility API function aliases
|
||||
void blink_on(); // alias for blink()
|
||||
void blink_off(); // alias for noBlink()
|
||||
void cursor_on(); // alias for cursor()
|
||||
void cursor_off(); // alias for noCursor()
|
||||
void setBacklight(uint8_t new_val); // alias for backlight() and nobacklight()
|
||||
void load_custom_character(uint8_t char_num, uint8_t *rows); // alias for createChar()
|
||||
void printstr(const char[]);
|
||||
|
||||
////Unsupported API functions (not implemented in this library)
|
||||
uint8_t status();
|
||||
void setContrast(uint8_t new_val);
|
||||
uint8_t keypad();
|
||||
void setDelay(int,int);
|
||||
void on();
|
||||
void off();
|
||||
uint8_t init_bargraph(uint8_t graphtype);
|
||||
void draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end);
|
||||
void draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end);
|
||||
|
||||
|
||||
private:
|
||||
void init_priv();
|
||||
void send(uint8_t, uint8_t);
|
||||
void write4bits(uint8_t);
|
||||
void expanderWrite(uint8_t);
|
||||
void pulseEnable(uint8_t);
|
||||
uint8_t _Addr;
|
||||
uint8_t _displayfunction;
|
||||
uint8_t _displaycontrol;
|
||||
uint8_t _displaymode;
|
||||
uint8_t _numlines;
|
||||
bool _oled = false;
|
||||
uint8_t _cols;
|
||||
uint8_t _rows;
|
||||
uint8_t _backlightval;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
# LiquidCrystal_I2C
|
||||
|
||||
LiquidCrystal Arduino library for I2C LCD displays
|
||||
|
||||
**Status: Archived**
|
||||
This repository has been transfered to GitLab at https://gitlab.com/tandembyte/LCD_I2C
|
|
@ -0,0 +1,70 @@
|
|||
//YWROBOT
|
||||
//Compatible with the Arduino IDE 1.0
|
||||
//Library version:1.1
|
||||
#include <Wire.h>
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#define printByte(args) write(args);
|
||||
#else
|
||||
#define printByte(args) print(args,BYTE);
|
||||
#endif
|
||||
|
||||
uint8_t bell[8] = {0x4,0xe,0xe,0xe,0x1f,0x0,0x4};
|
||||
uint8_t note[8] = {0x2,0x3,0x2,0xe,0x1e,0xc,0x0};
|
||||
uint8_t clock[8] = {0x0,0xe,0x15,0x17,0x11,0xe,0x0};
|
||||
uint8_t heart[8] = {0x0,0xa,0x1f,0x1f,0xe,0x4,0x0};
|
||||
uint8_t duck[8] = {0x0,0xc,0x1d,0xf,0xf,0x6,0x0};
|
||||
uint8_t check[8] = {0x0,0x1,0x3,0x16,0x1c,0x8,0x0};
|
||||
uint8_t cross[8] = {0x0,0x1b,0xe,0x4,0xe,0x1b,0x0};
|
||||
uint8_t retarrow[8] = { 0x1,0x1,0x5,0x9,0x1f,0x8,0x4};
|
||||
|
||||
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
|
||||
|
||||
void setup()
|
||||
{
|
||||
lcd.init(); // initialize the lcd
|
||||
lcd.backlight();
|
||||
|
||||
lcd.createChar(0, bell);
|
||||
lcd.createChar(1, note);
|
||||
lcd.createChar(2, clock);
|
||||
lcd.createChar(3, heart);
|
||||
lcd.createChar(4, duck);
|
||||
lcd.createChar(5, check);
|
||||
lcd.createChar(6, cross);
|
||||
lcd.createChar(7, retarrow);
|
||||
lcd.home();
|
||||
|
||||
lcd.print("Hello world...");
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print(" i ");
|
||||
lcd.printByte(3);
|
||||
lcd.print(" arduinos!");
|
||||
delay(5000);
|
||||
displayKeyCodes();
|
||||
|
||||
}
|
||||
|
||||
// display all keycodes
|
||||
void displayKeyCodes(void) {
|
||||
uint8_t i = 0;
|
||||
while (1) {
|
||||
lcd.clear();
|
||||
lcd.print("Codes 0x"); lcd.print(i, HEX);
|
||||
lcd.print("-0x"); lcd.print(i+15, HEX);
|
||||
lcd.setCursor(0, 1);
|
||||
for (int j=0; j<16; j++) {
|
||||
lcd.printByte(i+j);
|
||||
}
|
||||
i+=16;
|
||||
|
||||
delay(4000);
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
//YWROBOT
|
||||
//Compatible with the Arduino IDE 1.0
|
||||
//Library version:1.1
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
|
||||
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
|
||||
|
||||
void setup()
|
||||
{
|
||||
lcd.init(); // initialize the lcd
|
||||
// Print a message to the LCD.
|
||||
lcd.backlight();
|
||||
lcd.setCursor(3,0);
|
||||
lcd.print("Hello, world!");
|
||||
lcd.setCursor(2,1);
|
||||
lcd.print("Ywrobot Arduino!");
|
||||
lcd.setCursor(0,2);
|
||||
lcd.print("Arduino LCM IIC 2004");
|
||||
lcd.setCursor(2,3);
|
||||
lcd.print("Power By Ec-yuan!");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Displays text sent over the serial port (e.g. from the Serial Monitor) on
|
||||
* an attached LCD.
|
||||
* YWROBOT
|
||||
*Compatible with the Arduino IDE 1.0
|
||||
*Library version:1.1
|
||||
*/
|
||||
#include <Wire.h>
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
|
||||
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
|
||||
|
||||
void setup()
|
||||
{
|
||||
lcd.init(); // initialize the lcd
|
||||
lcd.backlight();
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// when characters arrive over the serial port...
|
||||
if (Serial.available()) {
|
||||
// wait a bit for the entire message to arrive
|
||||
delay(100);
|
||||
// clear the screen
|
||||
lcd.clear();
|
||||
// read all the available characters
|
||||
while (Serial.available() > 0) {
|
||||
// display each character to the LCD
|
||||
lcd.write(Serial.read());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
###########################################
|
||||
# Syntax Coloring Map For LiquidCrystal_I2C
|
||||
###########################################
|
||||
|
||||
###########################################
|
||||
# Datatypes (KEYWORD1)
|
||||
###########################################
|
||||
|
||||
LiquidCrystal_I2C KEYWORD1
|
||||
|
||||
###########################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
###########################################
|
||||
init KEYWORD2
|
||||
begin KEYWORD2
|
||||
clear KEYWORD2
|
||||
home KEYWORD2
|
||||
noDisplay KEYWORD2
|
||||
display KEYWORD2
|
||||
noBlink KEYWORD2
|
||||
blink KEYWORD2
|
||||
noCursor KEYWORD2
|
||||
cursor KEYWORD2
|
||||
scrollDisplayLeft KEYWORD2
|
||||
scrollDisplayRight KEYWORD2
|
||||
leftToRight KEYWORD2
|
||||
rightToLeft KEYWORD2
|
||||
shiftIncrement KEYWORD2
|
||||
shiftDecrement KEYWORD2
|
||||
noBacklight KEYWORD2
|
||||
backlight KEYWORD2
|
||||
autoscroll KEYWORD2
|
||||
noAutoscroll KEYWORD2
|
||||
createChar KEYWORD2
|
||||
setCursor KEYWORD2
|
||||
print KEYWORD2
|
||||
blink_on KEYWORD2
|
||||
blink_off KEYWORD2
|
||||
cursor_on KEYWORD2
|
||||
cursor_off KEYWORD2
|
||||
setBacklight KEYWORD2
|
||||
load_custom_character KEYWORD2
|
||||
printstr KEYWORD2
|
||||
###########################################
|
||||
# Constants (LITERAL1)
|
||||
###########################################
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "LiquidCrystal_I2C",
|
||||
"keywords": "LCD, liquidcrystal, I2C",
|
||||
"description": "A library for DFRobot I2C LCD displays",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/marcoschwartz/LiquidCrystal_I2C.git"
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms":
|
||||
[
|
||||
"atmelavr",
|
||||
"espressif8266"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
name=LiquidCrystal_I2C
|
||||
version=1.1.4
|
||||
author=Frank de Brabander
|
||||
maintainer=Marco Schwartz <marcolivier.schwartz@gmail.com>
|
||||
sentence=A library for I2C LCD displays.
|
||||
paragraph= The library allows to control I2C displays with functions extremely similar to LiquidCrystal library. THIS LIBRARY MIGHT NOT BE COMPATIBLE WITH EXISTING SKETCHES.
|
||||
category=Display
|
||||
url=https://github.com/marcoschwartz/LiquidCrystal_I2C
|
||||
architectures=avr
|
|
@ -0,0 +1,77 @@
|
|||
# RTClib [](https://github.com/adafruit/RTClib/actions)[](http://adafruit.github.io/RTClib/html/index.html)
|
||||
|
||||
This is a fork of JeeLab's fantastic real time clock library for Arduino.
|
||||
|
||||
Works great with Adafruit RTC breakouts:
|
||||
|
||||
- [DS3231 Precision RTC](https://www.adafruit.com/product/3013) (breakout) and [Stemma QT version](https://www.adafruit.com/product/5188)
|
||||
- [PCF8523 RTC](https://www.adafruit.com/product/3295)
|
||||
- [DS1307 RTC](https://www.adafruit.com/product/3296)
|
||||
|
||||
Please note that dayOfTheWeek() ranges from 0 to 6 inclusive with 0 being 'Sunday'.
|
||||
|
||||
<!-- START COMPATIBILITY TABLE -->
|
||||
|
||||
## Compatibility
|
||||
|
||||
MCU | Tested Works | Doesn't Work | Not Tested | Notes
|
||||
------------------ | :----------: | :----------: | :---------: | -----
|
||||
Atmega328 @ 16MHz | X | | |
|
||||
Atmega328 @ 12MHz | X | | |
|
||||
Atmega32u4 @ 16MHz | X | | | Use SDA/SCL on pins D3 & D2
|
||||
Atmega32u4 @ 8MHz | X | | | Use SDA/SCL on pins D3 & D2
|
||||
ESP8266 | X | | | SDA/SCL default to pins 4 & 5 but any two pins can be assigned as SDA/SCL using Wire.begin(SDA,SCL)
|
||||
Atmega2560 @ 16MHz | X | | | Use SDA/SCL on Pins 20 & 21
|
||||
ATSAM3X8E | X | | | Use SDA1 and SCL1
|
||||
ATSAM21D | X | | |
|
||||
ATtiny85 @ 16MHz | X | | |
|
||||
ATtiny85 @ 8MHz | X | | |
|
||||
Intel Curie @ 32MHz | | | X |
|
||||
STM32F2 | | | X |
|
||||
|
||||
* ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini
|
||||
* ATmega328 @ 12MHz : Adafruit Pro Trinket 3V
|
||||
* ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0
|
||||
* ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro
|
||||
* ESP8266 : Adafruit Huzzah
|
||||
* ATmega2560 @ 16MHz : Arduino Mega
|
||||
* ATSAM3X8E : Arduino Due
|
||||
* ATSAM21D : Arduino Zero, M0 Pro
|
||||
* ATtiny85 @ 16MHz : Adafruit Trinket 5V
|
||||
* ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V
|
||||
|
||||
<!-- END COMPATIBILITY TABLE -->
|
||||
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
|
||||
|
||||
# Dependencies
|
||||
* [Adafruit BusIO](https://github.com/adafruit/Adafruit_BusIO)
|
||||
|
||||
# Contributing
|
||||
|
||||
Contributions are welcome! Please read our [Code of Conduct](https://github.com/adafruit/RTClib/blob/master/code-of-conduct.md)
|
||||
before contributing to help this project stay welcoming.
|
||||
|
||||
## Documentation and doxygen
|
||||
For the detailed API documentation, see https://adafruit.github.io/RTClib/html/index.html
|
||||
Documentation is produced by doxygen. Contributions should include documentation for any new code added.
|
||||
|
||||
Some examples of how to use doxygen can be found in these guide pages:
|
||||
|
||||
https://learn.adafruit.com/the-well-automated-arduino-library/doxygen
|
||||
|
||||
https://learn.adafruit.com/the-well-automated-arduino-library/doxygen-tips
|
||||
|
||||
## Code formatting and clang-format
|
||||
The code should be formatted according to the [LLVM Coding Standards](https://llvm.org/docs/CodingStandards.html), which is the default of the clang-format tool. The easiest way to ensure conformance is to [install clang-format](https://llvm.org/builds/) and run
|
||||
|
||||
```shell
|
||||
clang-format -i <source_file>
|
||||
```
|
||||
|
||||
See [Formatting with clang-format](https://learn.adafruit.com/the-well-automated-arduino-library/formatting-with-clang-format) for details.
|
||||
|
||||
Written by JeeLabs
|
||||
MIT license, check license.txt for more information
|
||||
All text above must be included in any redistribution
|
||||
|
||||
To install, use the Arduino Library Manager and search for "RTClib" and install the library.
|
|
@ -0,0 +1,127 @@
|
|||
# Adafruit Community Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and leaders pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level or type of
|
||||
experience, education, socio-economic status, nationality, personal appearance,
|
||||
race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
We are committed to providing a friendly, safe and welcoming environment for
|
||||
all.
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Be kind and courteous to others
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Collaborating with other community members
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and sexual attention or advances
|
||||
* The use of inappropriate images, including in a community member's avatar
|
||||
* The use of inappropriate language, including in a community member's nickname
|
||||
* Any spamming, flaming, baiting or other attention-stealing behavior
|
||||
* Excessive or unwelcome helping; answering outside the scope of the question
|
||||
asked
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate
|
||||
|
||||
The goal of the standards and moderation guidelines outlined here is to build
|
||||
and maintain a respectful community. We ask that you don’t just aim to be
|
||||
"technically unimpeachable", but rather try to be your best self.
|
||||
|
||||
We value many things beyond technical expertise, including collaboration and
|
||||
supporting others within our community. Providing a positive experience for
|
||||
other community members can have a much more significant impact than simply
|
||||
providing the correct answer.
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project leaders are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project leaders have the right and responsibility to remove, edit, or
|
||||
reject messages, comments, commits, code, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any community member for other behaviors that they deem
|
||||
inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Moderation
|
||||
|
||||
Instances of behaviors that violate the Adafruit Community Code of Conduct
|
||||
may be reported by any member of the community. Community members are
|
||||
encouraged to report these situations, including situations they witness
|
||||
involving other community members.
|
||||
|
||||
You may report in the following ways:
|
||||
|
||||
In any situation, you may send an email to <support@adafruit.com>.
|
||||
|
||||
On the Adafruit Discord, you may send an open message from any channel
|
||||
to all Community Helpers by tagging @community helpers. You may also send an
|
||||
open message from any channel, or a direct message to @kattni#1507,
|
||||
@tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or
|
||||
@Andon#8175.
|
||||
|
||||
Email and direct message reports will be kept confidential.
|
||||
|
||||
In situations on Discord where the issue is particularly egregious, possibly
|
||||
illegal, requires immediate action, or violates the Discord terms of service,
|
||||
you should also report the message directly to Discord.
|
||||
|
||||
These are the steps for upholding our community’s standards of conduct.
|
||||
|
||||
1. Any member of the community may report any situation that violates the
|
||||
Adafruit Community Code of Conduct. All reports will be reviewed and
|
||||
investigated.
|
||||
2. If the behavior is an egregious violation, the community member who
|
||||
committed the violation may be banned immediately, without warning.
|
||||
3. Otherwise, moderators will first respond to such behavior with a warning.
|
||||
4. Moderators follow a soft "three strikes" policy - the community member may
|
||||
be given another chance, if they are receptive to the warning and change their
|
||||
behavior.
|
||||
5. If the community member is unreceptive or unreasonable when warned by a
|
||||
moderator, or the warning goes unheeded, they may be banned for a first or
|
||||
second offense. Repeated offenses will result in the community member being
|
||||
banned.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct and the enforcement policies listed above apply to all
|
||||
Adafruit Community venues. This includes but is not limited to any community
|
||||
spaces (both public and private), the entire Adafruit Discord server, and
|
||||
Adafruit GitHub repositories. Examples of Adafruit Community spaces include
|
||||
but are not limited to meet-ups, audio chats on the Adafruit Discord, or
|
||||
interaction at a conference.
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. As a community
|
||||
member, you are representing our community, and are expected to behave
|
||||
accordingly.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 1.4, available at
|
||||
<https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>,
|
||||
and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html).
|
||||
|
||||
For other projects adopting the Adafruit Community Code of
|
||||
Conduct, please contact the maintainers of those projects for enforcement.
|
||||
If you wish to use this code of conduct for your own project, consider
|
||||
explicitly mentioning your moderation policy or making a copy with your
|
||||
own moderation policy so as to avoid confusion.
|
|
@ -0,0 +1,122 @@
|
|||
/* Example implementation of an alarm using DS3231
|
||||
*
|
||||
* VCC and GND of RTC should be connected to some power source
|
||||
* SDA, SCL of RTC should be connected to SDA, SCL of arduino
|
||||
* SQW should be connected to CLOCK_INTERRUPT_PIN
|
||||
* CLOCK_INTERRUPT_PIN needs to work with interrupts
|
||||
*/
|
||||
|
||||
#include <RTClib.h>
|
||||
// #include <Wire.h>
|
||||
|
||||
RTC_DS3231 rtc;
|
||||
|
||||
// the pin that is connected to SQW
|
||||
#define CLOCK_INTERRUPT_PIN 2
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
// initializing the rtc
|
||||
if(!rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC!");
|
||||
Serial.flush();
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
if(rtc.lostPower()) {
|
||||
// this will adjust to the date and time at compilation
|
||||
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
}
|
||||
|
||||
//we don't need the 32K Pin, so disable it
|
||||
rtc.disable32K();
|
||||
|
||||
// Making it so, that the alarm will trigger an interrupt
|
||||
pinMode(CLOCK_INTERRUPT_PIN, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN), onAlarm, FALLING);
|
||||
|
||||
// set alarm 1, 2 flag to false (so alarm 1, 2 didn't happen so far)
|
||||
// if not done, this easily leads to problems, as both register aren't reset on reboot/recompile
|
||||
rtc.clearAlarm(1);
|
||||
rtc.clearAlarm(2);
|
||||
|
||||
// stop oscillating signals at SQW Pin
|
||||
// otherwise setAlarm1 will fail
|
||||
rtc.writeSqwPinMode(DS3231_OFF);
|
||||
|
||||
// turn off alarm 2 (in case it isn't off already)
|
||||
// again, this isn't done at reboot, so a previously set alarm could easily go overlooked
|
||||
rtc.disableAlarm(2);
|
||||
|
||||
// schedule an alarm 10 seconds in the future
|
||||
if(!rtc.setAlarm1(
|
||||
rtc.now() + TimeSpan(10),
|
||||
DS3231_A1_Second // this mode triggers the alarm when the seconds match. See Doxygen for other options
|
||||
)) {
|
||||
Serial.println("Error, alarm wasn't set!");
|
||||
}else {
|
||||
Serial.println("Alarm will happen in 10 seconds!");
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// print current time
|
||||
char date[10] = "hh:mm:ss";
|
||||
rtc.now().toString(date);
|
||||
Serial.print(date);
|
||||
|
||||
// the stored alarm value + mode
|
||||
DateTime alarm1 = rtc.getAlarm1();
|
||||
Ds3231Alarm1Mode alarm1mode = rtc.getAlarm1Mode();
|
||||
char alarm1Date[12] = "DD hh:mm:ss";
|
||||
alarm1.toString(alarm1Date);
|
||||
Serial.print(" [Alarm1: ");
|
||||
Serial.print(alarm1Date);
|
||||
Serial.print(", Mode: ");
|
||||
switch (alarm1mode) {
|
||||
case DS3231_A1_PerSecond: Serial.print("PerSecond"); break;
|
||||
case DS3231_A1_Second: Serial.print("Second"); break;
|
||||
case DS3231_A1_Minute: Serial.print("Minute"); break;
|
||||
case DS3231_A1_Hour: Serial.print("Hour"); break;
|
||||
case DS3231_A1_Date: Serial.print("Date"); break;
|
||||
case DS3231_A1_Day: Serial.print("Day"); break;
|
||||
}
|
||||
|
||||
// the value at SQW-Pin (because of pullup 1 means no alarm)
|
||||
Serial.print("] SQW: ");
|
||||
Serial.print(digitalRead(CLOCK_INTERRUPT_PIN));
|
||||
|
||||
// whether a alarm fired
|
||||
Serial.print(" Fired: ");
|
||||
Serial.print(rtc.alarmFired(1));
|
||||
|
||||
// Serial.print(" Alarm2: ");
|
||||
// Serial.println(rtc.alarmFired(2));
|
||||
// control register values (see https://datasheets.maximintegrated.com/en/ds/DS3231.pdf page 13)
|
||||
// Serial.print(" Control: 0b");
|
||||
// Serial.println(read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL), BIN);
|
||||
|
||||
// resetting SQW and alarm 1 flag
|
||||
// using setAlarm1, the next alarm could now be configurated
|
||||
if (rtc.alarmFired(1)) {
|
||||
rtc.clearAlarm(1);
|
||||
Serial.print(" - Alarm cleared");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
delay(2000);
|
||||
}
|
||||
|
||||
void onAlarm() {
|
||||
Serial.println("Alarm occured!");
|
||||
}
|
||||
|
||||
/*static uint8_t read_i2c_register(uint8_t addr, uint8_t reg) {
|
||||
Wire.beginTransmission(addr);
|
||||
Wire.write((byte)reg);
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.requestFrom(addr, (byte)1);
|
||||
return Wire.read();
|
||||
}*/
|
|
@ -0,0 +1,120 @@
|
|||
/* Using DS3231 (or other supported RTC) with a custom TwoWire instance
|
||||
*
|
||||
* If using a microcontroller which supports additional i2c ports,
|
||||
* such as the SAMD21's SERCOMX, a user can define a custom i2c bus
|
||||
* to use with an RTC.
|
||||
* This example builds the custom i2c bus using SERCOM0 and leverages the "wiring_private.h" APIs
|
||||
*
|
||||
* Connecting the device:
|
||||
* VCC and GND of RTC should be connected to some power source
|
||||
* SDA, SCL of RTC should be connected to the custom SDA and SCL pins.
|
||||
* In this particular example we are using a Nano 33 IoT and routing
|
||||
* the custom Wire instance over pins 6 (SDA) and 5 (SCL)
|
||||
*
|
||||
* This example will work with Arduino Zero, any Arduino MKR board based on SAMD21, Nano 33 IoT
|
||||
* and any board by Adafruit, Sparkfun, Seeed Studio based on the same microcontroller
|
||||
*
|
||||
*/
|
||||
#include <Wire.h>
|
||||
#include "wiring_private.h"
|
||||
#include <RTClib.h>
|
||||
|
||||
/* Defining the custom TwoWire instance for SAMD21 */
|
||||
TwoWire myWire(&sercom0, 6, 5); // Create the new wire instance assigning it to pin 0 and 1
|
||||
extern "C"{
|
||||
void SERCOM0_Handler(void);
|
||||
|
||||
void SERCOM0_Handler(void) {
|
||||
|
||||
myWire.onService();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Creating a new DS3231 object */
|
||||
RTC_DS3231 myRTC;
|
||||
|
||||
String daysNames[] = {
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday"
|
||||
};
|
||||
String monthsNames[] = {
|
||||
"-",
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December"
|
||||
};
|
||||
|
||||
void setup() {
|
||||
Serial.begin(57600);
|
||||
Serial.println("start");
|
||||
|
||||
unsigned long setupStartTime = millis();
|
||||
/*** Waiting for Serial to be ready or timeout ***/
|
||||
while(!Serial && millis() - setupStartTime < 3000);
|
||||
|
||||
/*
|
||||
* Initialising pins 6 and 5 to be routed to the SERCOM0 pads 0 and 1 in order
|
||||
* to be used as SDA and SCL. Without this step the periphearl won't be patched through
|
||||
*/
|
||||
pinPeripheral(6, PIO_SERCOM_ALT); // PAD[0] //Assign SDA function to pin 0
|
||||
pinPeripheral(5, PIO_SERCOM_ALT); // PAD[1] //Assign SCL function to pin 1
|
||||
|
||||
/* We now pass our custom TwoWire object to the RTC instance */
|
||||
myRTC.begin(&myWire);
|
||||
|
||||
/*
|
||||
* From this moment on every operation on the RTC will work as expected
|
||||
* But the i2c bus being used will be the one we manually created using SERCOM0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creating a Date object with
|
||||
* YEAR, MONTH, DAY (2021, January, 1)
|
||||
* HOUR, MINUTE, SECONDS (0, 0, 0)
|
||||
* Midnight of January 1st, 2021
|
||||
*/
|
||||
DateTime newDT = DateTime(2021, 1, 1, 0, 0, 0);
|
||||
|
||||
/* Pushing that date/time to the RTC */
|
||||
myRTC.adjust(newDT);
|
||||
Serial.println("setup done");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
/* creating a temporary date/time object to store the data coming from the RTC */
|
||||
DateTime dt = myRTC.now();
|
||||
|
||||
/* printing that data to the Serial port in a meaningful format */
|
||||
Serial.println("************");
|
||||
Serial.print(daysNames[dt.dayOfTheWeek()]);
|
||||
Serial.print(" ");
|
||||
Serial.print(monthsNames[dt.month()]);
|
||||
Serial.print(" ");
|
||||
Serial.print(dt.day());
|
||||
Serial.print(", ");
|
||||
Serial.println(dt.year());
|
||||
Serial.print(dt.hour());
|
||||
Serial.print(":");
|
||||
Serial.print(dt.minute());
|
||||
Serial.print(":");
|
||||
Serial.println(dt.second());
|
||||
/* Delays are bad, but let's not flood the Serial for this silly example */
|
||||
delay(500);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
// Simple date conversions and calculations
|
||||
|
||||
#include "RTClib.h"
|
||||
|
||||
void showDate(const char* txt, const DateTime& dt) {
|
||||
Serial.print(txt);
|
||||
Serial.print(' ');
|
||||
Serial.print(dt.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(dt.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(dt.day(), DEC);
|
||||
Serial.print(' ');
|
||||
Serial.print(dt.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(dt.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(dt.second(), DEC);
|
||||
|
||||
Serial.print(" = ");
|
||||
Serial.print(dt.unixtime());
|
||||
Serial.print("s / ");
|
||||
Serial.print(dt.unixtime() / 86400L);
|
||||
Serial.print("d since 1970");
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void showTimeSpan(const char* txt, const TimeSpan& ts) {
|
||||
Serial.print(txt);
|
||||
Serial.print(" ");
|
||||
Serial.print(ts.days(), DEC);
|
||||
Serial.print(" days ");
|
||||
Serial.print(ts.hours(), DEC);
|
||||
Serial.print(" hours ");
|
||||
Serial.print(ts.minutes(), DEC);
|
||||
Serial.print(" minutes ");
|
||||
Serial.print(ts.seconds(), DEC);
|
||||
Serial.print(" seconds (");
|
||||
Serial.print(ts.totalseconds(), DEC);
|
||||
Serial.print(" total seconds)");
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
|
||||
#ifndef ESP8266
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
#endif
|
||||
|
||||
DateTime dt0 (0, 1, 1, 0, 0, 0);
|
||||
showDate("dt0", dt0);
|
||||
|
||||
DateTime dt1 (1, 1, 1, 0, 0, 0);
|
||||
showDate("dt1", dt1);
|
||||
|
||||
DateTime dt2 (2009, 1, 1, 0, 0, 0);
|
||||
showDate("dt2", dt2);
|
||||
|
||||
DateTime dt3 (2009, 1, 2, 0, 0, 0);
|
||||
showDate("dt3", dt3);
|
||||
|
||||
DateTime dt4 (2009, 1, 27, 0, 0, 0);
|
||||
showDate("dt4", dt4);
|
||||
|
||||
DateTime dt5 (2009, 2, 27, 0, 0, 0);
|
||||
showDate("dt5", dt5);
|
||||
|
||||
DateTime dt6 (2009, 12, 27, 0, 0, 0);
|
||||
showDate("dt6", dt6);
|
||||
|
||||
DateTime dt7 (dt6.unixtime() + 3600); // One hour later.
|
||||
showDate("dt7", dt7);
|
||||
|
||||
DateTime dt75 = dt6 + TimeSpan(0, 1, 0, 0); // One hour later with TimeSpan addition.
|
||||
showDate("dt7.5", dt75);
|
||||
|
||||
DateTime dt8 (dt6.unixtime() + 86400L); // One day later.
|
||||
showDate("dt8", dt8);
|
||||
|
||||
DateTime dt85 = dt6 + TimeSpan(1, 0, 0, 0); // One day later with TimeSpan addition.
|
||||
showDate("dt8.5", dt85);
|
||||
|
||||
DateTime dt9 (dt6.unixtime() + 7 * 86400L); // One week later.
|
||||
showDate("dt9", dt9);
|
||||
|
||||
DateTime dt95 = dt6 + TimeSpan(7, 0, 0, 0); // One week later with TimeSpan addition.
|
||||
showDate("dt9.5", dt95);
|
||||
|
||||
DateTime dt10 = dt6 + TimeSpan(0, 0, 42, 42); // Fourty two minutes and fourty two seconds later.
|
||||
showDate("dt10", dt10);
|
||||
|
||||
DateTime dt11 = dt6 - TimeSpan(7, 0, 0, 0); // One week ago.
|
||||
showDate("dt11", dt11);
|
||||
|
||||
TimeSpan ts1 = dt6 - dt5;
|
||||
showTimeSpan("dt6-dt5", ts1);
|
||||
|
||||
TimeSpan ts2 = dt10 - dt6;
|
||||
showTimeSpan("dt10-dt6", ts2);
|
||||
}
|
||||
|
||||
void loop () {
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
// Date and time functions using a DS1307 RTC connected via I2C and Wire lib
|
||||
#include "RTClib.h"
|
||||
|
||||
RTC_DS1307 rtc;
|
||||
|
||||
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
|
||||
#ifndef ESP8266
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
#endif
|
||||
|
||||
if (! rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC");
|
||||
Serial.flush();
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
if (! rtc.isrunning()) {
|
||||
Serial.println("RTC is NOT running, let's set the time!");
|
||||
// When time needs to be set on a new device, or after a power loss, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
}
|
||||
|
||||
// When time needs to be re-set on a previously configured device, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
}
|
||||
|
||||
void loop () {
|
||||
DateTime now = rtc.now();
|
||||
|
||||
Serial.print(now.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(now.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(now.day(), DEC);
|
||||
Serial.print(" (");
|
||||
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
|
||||
Serial.print(") ");
|
||||
Serial.print(now.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(now.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(now.second(), DEC);
|
||||
Serial.println();
|
||||
|
||||
Serial.print(" since midnight 1/1/1970 = ");
|
||||
Serial.print(now.unixtime());
|
||||
Serial.print("s = ");
|
||||
Serial.print(now.unixtime() / 86400L);
|
||||
Serial.println("d");
|
||||
|
||||
// calculate a date which is 7 days, 12 hours, 30 minutes, and 6 seconds into the future
|
||||
DateTime future (now + TimeSpan(7,12,30,6));
|
||||
|
||||
Serial.print(" now + 7d + 12h + 30m + 6s: ");
|
||||
Serial.print(future.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(future.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(future.day(), DEC);
|
||||
Serial.print(' ');
|
||||
Serial.print(future.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(future.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(future.second(), DEC);
|
||||
Serial.println();
|
||||
|
||||
Serial.println();
|
||||
delay(3000);
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
// SQW/OUT pin mode using a DS1307 RTC connected via I2C.
|
||||
//
|
||||
// According to the data sheet (http://datasheets.maxim-ic.com/en/ds/DS1307.pdf), the
|
||||
// DS1307's SQW/OUT pin can be set to low, high, 1Hz, 4.096kHz, 8.192kHz, or 32.768kHz.
|
||||
//
|
||||
// This sketch reads the state of the pin, then iterates through the possible values at
|
||||
// 5 second intervals.
|
||||
//
|
||||
|
||||
// NOTE:
|
||||
// You must connect a pull up resistor (~10kohm) from the SQW pin up to VCC. Without
|
||||
// this pull up the wave output will not work!
|
||||
|
||||
#include "RTClib.h"
|
||||
|
||||
RTC_DS1307 rtc;
|
||||
|
||||
int mode_index = 0;
|
||||
|
||||
Ds1307SqwPinMode modes[] = { DS1307_OFF, DS1307_ON, DS1307_SquareWave1HZ, DS1307_SquareWave4kHz, DS1307_SquareWave8kHz, DS1307_SquareWave32kHz};
|
||||
|
||||
|
||||
void print_mode() {
|
||||
Ds1307SqwPinMode mode = rtc.readSqwPinMode();
|
||||
|
||||
Serial.print("Sqw Pin Mode: ");
|
||||
switch(mode) {
|
||||
case DS1307_OFF: Serial.println("OFF"); break;
|
||||
case DS1307_ON: Serial.println("ON"); break;
|
||||
case DS1307_SquareWave1HZ: Serial.println("1Hz"); break;
|
||||
case DS1307_SquareWave4kHz: Serial.println("4.096kHz"); break;
|
||||
case DS1307_SquareWave8kHz: Serial.println("8.192kHz"); break;
|
||||
case DS1307_SquareWave32kHz: Serial.println("32.768kHz"); break;
|
||||
default: Serial.println("UNKNOWN"); break;
|
||||
}
|
||||
}
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
|
||||
#ifndef ESP8266
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
#endif
|
||||
|
||||
if (! rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC");
|
||||
Serial.flush();
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
print_mode();
|
||||
}
|
||||
|
||||
void loop () {
|
||||
rtc.writeSqwPinMode(modes[mode_index++]);
|
||||
print_mode();
|
||||
|
||||
if (mode_index > 5) {
|
||||
mode_index = 0;
|
||||
}
|
||||
|
||||
delay(5000);
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
// Example of using the non-volatile RAM storage on the DS1307.
|
||||
// You can write up to 56 bytes from address 0 to 55.
|
||||
// Data will be persisted as long as the DS1307 has battery power.
|
||||
|
||||
#include "RTClib.h"
|
||||
|
||||
RTC_DS1307 rtc;
|
||||
|
||||
void printnvram(uint8_t address) {
|
||||
Serial.print("Address 0x");
|
||||
Serial.print(address, HEX);
|
||||
Serial.print(" = 0x");
|
||||
Serial.println(rtc.readnvram(address), HEX);
|
||||
}
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
|
||||
#ifndef ESP8266
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
#endif
|
||||
|
||||
if (! rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC");
|
||||
Serial.flush();
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
// Print old RAM contents on startup.
|
||||
Serial.println("Current NVRAM values:");
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
printnvram(i);
|
||||
}
|
||||
|
||||
// Write some bytes to non-volatile RAM storage.
|
||||
// NOTE: You can only read and write from addresses 0 to 55 (i.e. 56 byte values).
|
||||
Serial.println("Writing NVRAM values.");
|
||||
// Example writing one byte at a time:
|
||||
rtc.writenvram(0, 0xFE);
|
||||
rtc.writenvram(1, 0xED);
|
||||
// Example writing multiple bytes:
|
||||
uint8_t writeData[4] = { 0xBE, 0xEF, 0x01, 0x02 };
|
||||
rtc.writenvram(2, writeData, 4);
|
||||
|
||||
// Read bytes from non-volatile RAM storage.
|
||||
Serial.println("Reading NVRAM values:");
|
||||
// Example reading one byte at a time.
|
||||
Serial.println(rtc.readnvram(0), HEX);
|
||||
Serial.println(rtc.readnvram(1), HEX);
|
||||
// Example reading multiple bytes:
|
||||
uint8_t readData[4] = {0};
|
||||
rtc.readnvram(readData, 4, 2);
|
||||
Serial.println(readData[0], HEX);
|
||||
Serial.println(readData[1], HEX);
|
||||
Serial.println(readData[2], HEX);
|
||||
Serial.println(readData[3], HEX);
|
||||
|
||||
}
|
||||
|
||||
void loop () {
|
||||
// Do nothing in the loop.
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
// Date and time functions using a DS3231 RTC connected via I2C and Wire lib
|
||||
#include "RTClib.h"
|
||||
|
||||
RTC_DS3231 rtc;
|
||||
|
||||
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
|
||||
#ifndef ESP8266
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
#endif
|
||||
|
||||
if (! rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC");
|
||||
Serial.flush();
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
if (rtc.lostPower()) {
|
||||
Serial.println("RTC lost power, let's set the time!");
|
||||
// When time needs to be set on a new device, or after a power loss, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
}
|
||||
|
||||
// When time needs to be re-set on a previously configured device, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
}
|
||||
|
||||
void loop () {
|
||||
DateTime now = rtc.now();
|
||||
|
||||
Serial.print(now.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(now.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(now.day(), DEC);
|
||||
Serial.print(" (");
|
||||
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
|
||||
Serial.print(") ");
|
||||
Serial.print(now.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(now.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(now.second(), DEC);
|
||||
Serial.println();
|
||||
|
||||
Serial.print(" since midnight 1/1/1970 = ");
|
||||
Serial.print(now.unixtime());
|
||||
Serial.print("s = ");
|
||||
Serial.print(now.unixtime() / 86400L);
|
||||
Serial.println("d");
|
||||
|
||||
// calculate a date which is 7 days, 12 hours, 30 minutes, 6 seconds into the future
|
||||
DateTime future (now + TimeSpan(7,12,30,6));
|
||||
|
||||
Serial.print(" now + 7d + 12h + 30m + 6s: ");
|
||||
Serial.print(future.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(future.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(future.day(), DEC);
|
||||
Serial.print(' ');
|
||||
Serial.print(future.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(future.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(future.second(), DEC);
|
||||
Serial.println();
|
||||
|
||||
Serial.print("Temperature: ");
|
||||
Serial.print(rtc.getTemperature());
|
||||
Serial.println(" C");
|
||||
|
||||
Serial.println();
|
||||
delay(3000);
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/***********************************************************************
|
||||
|
||||
Combining RTClib with the avr-libc timing functions
|
||||
===================================================
|
||||
|
||||
The standard way of getting the current time and date with RTClib is to
|
||||
call the now() method of the appropriate RTC class. This, however, is
|
||||
somewhat slow, as it involves communicating with the RTC through the I2C
|
||||
bus. An alternative, more lightweight method involves configuring the
|
||||
RTC to deliver one pulse per second to an interrupt pin, and counting
|
||||
the seconds in the interrupt handler. The timekeeping is then entirely
|
||||
handled in the Arduino, with no I2C communication with the RTC other
|
||||
than during the initialization phase.
|
||||
|
||||
On AVR-based Arduinos (Uno, Nano, Micro, ...), the Arduino core library
|
||||
is built on top of avr-libc, which is an implementation of the standard
|
||||
C library for the AVR platform. This library provides the standard C
|
||||
functions for handling time:[1] time(), gmtime(), mktime(), etc. The
|
||||
time() function is normally used to retrieve the current time from the
|
||||
operating system, but since we have no operating system, the avr-libc
|
||||
provides its own non-standard functions for implementing a time source:
|
||||
|
||||
- set_system_time() initializes the library's idea of the current time
|
||||
- system_tick() steps the system time by one second.
|
||||
|
||||
This sketch demonstrates how to combine RTClib and avr-libc in order to
|
||||
handle the timekeeping entirely on the Arduino from an interrupt
|
||||
delivered by the RTC:
|
||||
|
||||
- RTClib is used to configure the RTC and retrieve the initial time
|
||||
- avr-libc is used for regular timekeeping
|
||||
|
||||
This sketch only works on AVR-based Arduinos, as it relies on
|
||||
non-standard functions provided by avr-libc.
|
||||
|
||||
[1] https://www.nongnu.org/avr-libc/user-manual/group__avr__time.html
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include <RTClib.h>
|
||||
#include <time.h> // standard C timing functions
|
||||
|
||||
// Pin receiving the one-pulse-per-second signal from the RTC.
|
||||
// This should be an interrupt-capable pin.
|
||||
const uint8_t pin1pps = 2;
|
||||
|
||||
// We will use the PCF8523 RTC, which has the handy "Second Timer".
|
||||
// Other RTCs could be used with their "square wave" output configured
|
||||
// to 1 Hz.
|
||||
RTC_PCF8523 rtc;
|
||||
|
||||
void setup() {
|
||||
|
||||
// Initialize the serial port.
|
||||
Serial.begin(57600);
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
|
||||
// Initialize the RTC.
|
||||
if (! rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC");
|
||||
Serial.flush();
|
||||
while (1) delay(10);
|
||||
}
|
||||
if (!rtc.initialized() || rtc.lostPower()) {
|
||||
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
}
|
||||
rtc.deconfigureAllTimers(); // undo previous configuration, if any
|
||||
|
||||
// Initialize the system time from the RTC time. Both avr-libc and
|
||||
// DateTime::secondstime() use the start of year 2000 as their
|
||||
// reference "epoch".
|
||||
set_system_time(rtc.now().secondstime());
|
||||
|
||||
// Keep the time in sync using the one-pulse-per-second output of the
|
||||
// RTC as an interrupt source and calling system_tick() from the
|
||||
// interrupt service routine.
|
||||
pinMode(pin1pps, INPUT_PULLUP);
|
||||
rtc.enableSecondTimer();
|
||||
attachInterrupt(digitalPinToInterrupt(pin1pps), system_tick, FALLING);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
// From here on, we only use the standard C timing functions.
|
||||
// time() returns the current time as a single number of type time_t,
|
||||
// this is the number of seconds elapsed since a reference "epoch".
|
||||
time_t now = time(nullptr);
|
||||
|
||||
// gmtime() converts the time to a broken-down form (year, month...)
|
||||
// similar to the DateTime class. Unlike localtime(), it doesn't
|
||||
// attempt timezone conversions.
|
||||
struct tm *broken_down_time = gmtime(&now);
|
||||
|
||||
// asctime() returns a textual representation of the date and time as
|
||||
// a C string (pointer to a character array). The format is similar to
|
||||
// the DateTime::toString() format "DDD MMM DD hh:mm:ss YYYY".
|
||||
Serial.println(asctime(broken_down_time));
|
||||
|
||||
delay(1000);
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
// Date and time functions using a PCF8523 RTC connected via I2C and Wire lib
|
||||
#include "RTClib.h"
|
||||
|
||||
RTC_PCF8523 rtc;
|
||||
|
||||
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
|
||||
#ifndef ESP8266
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
#endif
|
||||
|
||||
if (! rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC");
|
||||
Serial.flush();
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
if (! rtc.initialized() || rtc.lostPower()) {
|
||||
Serial.println("RTC is NOT initialized, let's set the time!");
|
||||
// When time needs to be set on a new device, or after a power loss, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
//
|
||||
// Note: allow 2 seconds after inserting battery or applying external power
|
||||
// without battery before calling adjust(). This gives the PCF8523's
|
||||
// crystal oscillator time to stabilize. If you call adjust() very quickly
|
||||
// after the RTC is powered, lostPower() may still return true.
|
||||
}
|
||||
|
||||
// When time needs to be re-set on a previously configured device, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
|
||||
// When the RTC was stopped and stays connected to the battery, it has
|
||||
// to be restarted by clearing the STOP bit. Let's do this to ensure
|
||||
// the RTC is running.
|
||||
rtc.start();
|
||||
|
||||
// The PCF8523 can be calibrated for:
|
||||
// - Aging adjustment
|
||||
// - Temperature compensation
|
||||
// - Accuracy tuning
|
||||
// The offset mode to use, once every two hours or once every minute.
|
||||
// The offset Offset value from -64 to +63. See the Application Note for calculation of offset values.
|
||||
// https://www.nxp.com/docs/en/application-note/AN11247.pdf
|
||||
// The deviation in parts per million can be calculated over a period of observation. Both the drift (which can be negative)
|
||||
// and the observation period must be in seconds. For accuracy the variation should be observed over about 1 week.
|
||||
// Note: any previous calibration should cancelled prior to any new observation period.
|
||||
// Example - RTC gaining 43 seconds in 1 week
|
||||
float drift = 43; // seconds plus or minus over oservation period - set to 0 to cancel previous calibration.
|
||||
float period_sec = (7 * 86400); // total obsevation period in seconds (86400 = seconds in 1 day: 7 days = (7 * 86400) seconds )
|
||||
float deviation_ppm = (drift / period_sec * 1000000); // deviation in parts per million (μs)
|
||||
float drift_unit = 4.34; // use with offset mode PCF8523_TwoHours
|
||||
// float drift_unit = 4.069; //For corrections every min the drift_unit is 4.069 ppm (use with offset mode PCF8523_OneMinute)
|
||||
int offset = round(deviation_ppm / drift_unit);
|
||||
// rtc.calibrate(PCF8523_TwoHours, offset); // Un-comment to perform calibration once drift (seconds) and observation period (seconds) are correct
|
||||
// rtc.calibrate(PCF8523_TwoHours, 0); // Un-comment to cancel previous calibration
|
||||
|
||||
Serial.print("Offset is "); Serial.println(offset); // Print to control offset
|
||||
|
||||
}
|
||||
|
||||
void loop () {
|
||||
DateTime now = rtc.now();
|
||||
|
||||
Serial.print(now.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(now.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(now.day(), DEC);
|
||||
Serial.print(" (");
|
||||
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
|
||||
Serial.print(") ");
|
||||
Serial.print(now.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(now.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(now.second(), DEC);
|
||||
Serial.println();
|
||||
|
||||
Serial.print(" since midnight 1/1/1970 = ");
|
||||
Serial.print(now.unixtime());
|
||||
Serial.print("s = ");
|
||||
Serial.print(now.unixtime() / 86400L);
|
||||
Serial.println("d");
|
||||
|
||||
// calculate a date which is 7 days, 12 hours and 30 seconds into the future
|
||||
DateTime future (now + TimeSpan(7,12,30,6));
|
||||
|
||||
Serial.print(" now + 7d + 12h + 30m + 6s: ");
|
||||
Serial.print(future.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(future.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(future.day(), DEC);
|
||||
Serial.print(' ');
|
||||
Serial.print(future.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(future.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(future.second(), DEC);
|
||||
Serial.println();
|
||||
|
||||
Serial.println();
|
||||
delay(3000);
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
/**************************************************************************/
|
||||
/*
|
||||
Countdown Timer using a PCF8523 RTC connected via I2C and Wire lib
|
||||
with the INT/SQW pin wired to an interrupt-capable input.
|
||||
|
||||
According to the data sheet, the PCF8523 can run countdown timers
|
||||
from 244 microseconds to 10.625 days:
|
||||
https://www.nxp.com/docs/en/data-sheet/PCF8523.pdf#page=34
|
||||
|
||||
This sketch sets a countdown timer, and executes code when it reaches 0,
|
||||
then blinks the built-in LED like BlinkWithoutDelay, but without millis()!
|
||||
|
||||
NOTE:
|
||||
You must connect the PCF8523's interrupt pin to your Arduino or other
|
||||
microcontroller on an input pin that can handle interrupts, and that has a
|
||||
pullup resistor. The pin will be briefly pulled low each time the countdown
|
||||
reaches 0. This example will not work without the interrupt pin connected!
|
||||
|
||||
On Adafruit breakout boards, the interrupt pin is labeled 'INT' or 'SQW'.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include "RTClib.h"
|
||||
|
||||
RTC_PCF8523 rtc;
|
||||
|
||||
// Input pin with interrupt capability
|
||||
// const int timerInterruptPin = 2; // Most Arduinos
|
||||
const int timerInterruptPin = 5; // Adafruit Feather M0/M4/nRF52840
|
||||
|
||||
// Variables modified during an interrupt must be declared volatile
|
||||
volatile bool countdownInterruptTriggered = false;
|
||||
volatile int numCountdownInterrupts = 0;
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
|
||||
#ifndef ESP8266
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
#endif
|
||||
|
||||
if (! rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC");
|
||||
Serial.flush();
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
||||
// Set the pin attached to PCF8523 INT to be an input with pullup to HIGH.
|
||||
// The PCF8523 interrupt pin will briefly pull it LOW at the end of a given
|
||||
// countdown period, then it will be released to be pulled HIGH again.
|
||||
pinMode(timerInterruptPin, INPUT_PULLUP);
|
||||
|
||||
Serial.println(F("\nStarting PCF8523 Countdown Timer example."));
|
||||
Serial.print(F("Configured to expect PCF8523 INT/SQW pin connected to input pin: "));
|
||||
Serial.println(timerInterruptPin);
|
||||
Serial.println(F("This example will not work without the interrupt pin connected!\n\n"));
|
||||
|
||||
// Timer configuration is not cleared on an RTC reset due to battery backup!
|
||||
rtc.deconfigureAllTimers();
|
||||
|
||||
Serial.println(F("First, use the PCF8523's 'Countdown Timer' with an interrupt."));
|
||||
Serial.println(F("Set the countdown for 10 seconds and we'll let it run for 2 rounds."));
|
||||
Serial.println(F("Starting Countdown Timer now..."));
|
||||
|
||||
// These are the PCF8523's built-in "Timer Source Clock Frequencies".
|
||||
// They are predefined time periods you choose as your base unit of time,
|
||||
// depending on the length of countdown timer you need.
|
||||
// The minimum length of your countdown is 1 time period.
|
||||
// The maximum length of your countdown is 255 time periods.
|
||||
//
|
||||
// PCF8523_FrequencyHour = 1 hour, max 10.625 days (255 hours)
|
||||
// PCF8523_FrequencyMinute = 1 minute, max 4.25 hours
|
||||
// PCF8523_FrequencySecond = 1 second, max 4.25 minutes
|
||||
// PCF8523_Frequency64Hz = 1/64 of a second (15.625 milliseconds), max 3.984 seconds
|
||||
// PCF8523_Frequency4kHz = 1/4096 of a second (244 microseconds), max 62.256 milliseconds
|
||||
//
|
||||
//
|
||||
// These are the PCF8523's optional 'Low Pulse Widths' of time the interrupt
|
||||
// pin is held LOW at the end of every countdown (frequency 64Hz or longer).
|
||||
//
|
||||
// PCF8523_LowPulse3x64Hz = 46.875 ms 3/64ths second (default)
|
||||
// PCF8523_LowPulse4x64Hz = 62.500 ms 4/64ths second
|
||||
// PCF8523_LowPulse5x64Hz = 78.125 ms 5/64ths second
|
||||
// PCF8523_LowPulse6x64Hz = 93.750 ms 6/64ths second
|
||||
// PCF8523_LowPulse8x64Hz = 125.000 ms 8/64ths second
|
||||
// PCF8523_LowPulse10x64Hz = 156.250 ms 10/64ths second
|
||||
// PCF8523_LowPulse12x64Hz = 187.500 ms 12/64ths second
|
||||
// PCF8523_LowPulse14x64Hz = 218.750 ms 14/64ths second
|
||||
//
|
||||
//
|
||||
// Uncomment an example below:
|
||||
|
||||
// rtc.enableCountdownTimer(PCF8523_FrequencyHour, 24); // 1 day
|
||||
// rtc.enableCountdownTimer(PCF8523_FrequencyMinute, 150); // 2.5 hours
|
||||
rtc.enableCountdownTimer(PCF8523_FrequencySecond, 10); // 10 seconds
|
||||
// rtc.enableCountdownTimer(PCF8523_Frequency64Hz, 32); // 1/2 second
|
||||
// rtc.enableCountdownTimer(PCF8523_Frequency64Hz, 16); // 1/4 second
|
||||
// rtc.enableCountdownTimer(PCF8523_Frequency4kHz, 205); // 50 milliseconds
|
||||
|
||||
attachInterrupt(digitalPinToInterrupt(timerInterruptPin), countdownOver, FALLING);
|
||||
|
||||
// This message proves we're not blocked while counting down!
|
||||
Serial.println(F(" While we're waiting, a word of caution:"));
|
||||
Serial.println(F(" When starting a new countdown timer, the first time period is not of fixed"));
|
||||
Serial.println(F(" duration. The amount of inaccuracy for the first time period is up to one full"));
|
||||
Serial.println(F(" clock frequency. Example: just the first second of the first round of a new"));
|
||||
Serial.println(F(" countdown based on PCF8523_FrequencySecond may be off by as much as 1 second!"));
|
||||
Serial.println(F(" For critical timing, consider starting actions on the first interrupt."));
|
||||
}
|
||||
|
||||
// Triggered by the PCF8523 Countdown Timer interrupt at the end of a countdown
|
||||
// period. Meanwhile, the PCF8523 immediately starts the countdown again.
|
||||
void countdownOver () {
|
||||
// Set a flag to run code in the loop():
|
||||
countdownInterruptTriggered = true;
|
||||
numCountdownInterrupts++;
|
||||
}
|
||||
|
||||
// Triggered by the PCF8523 Second Timer every second.
|
||||
void toggleLed () {
|
||||
// Run certain types of fast executing code here:
|
||||
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
|
||||
}
|
||||
|
||||
void loop () {
|
||||
if (countdownInterruptTriggered && numCountdownInterrupts == 1) {
|
||||
Serial.println(F("1st countdown interrupt triggered. Accurate timekeeping starts now."));
|
||||
countdownInterruptTriggered = false; // don't come in here again
|
||||
} else if (countdownInterruptTriggered && numCountdownInterrupts == 2) {
|
||||
Serial.println(F("2nd countdown interrupt triggered. Disabling countdown and detaching interrupt.\n\n"));
|
||||
rtc.disableCountdownTimer();
|
||||
detachInterrupt(digitalPinToInterrupt(timerInterruptPin));
|
||||
delay(2000);
|
||||
|
||||
|
||||
Serial.println(F("Now, set up the PCF8523's 'Second Timer' to toggle the built-in LED at 1Hz..."));
|
||||
attachInterrupt(digitalPinToInterrupt(timerInterruptPin), toggleLed, FALLING);
|
||||
rtc.enableSecondTimer();
|
||||
Serial.println(F("Look for the built-in LED to flash 1 second ON, 1 second OFF, repeat. "));
|
||||
Serial.println(F("Meanwhile this program will use delay() to block code execution briefly"));
|
||||
Serial.println(F("before moving on to the last example. Notice the LED keeps blinking!\n\n"));
|
||||
delay(20000); // less accurate, blocks execution here. Meanwhile Second Timer keeps running.
|
||||
rtc.disableSecondTimer();
|
||||
detachInterrupt(digitalPinToInterrupt(timerInterruptPin));
|
||||
|
||||
|
||||
Serial.println(F("Lastly, set up a Countdown Timer that works without attaching an interrupt..."));
|
||||
rtc.enableCountdownTimer(PCF8523_Frequency64Hz, 32, PCF8523_LowPulse8x64Hz);
|
||||
Serial.println(F("Look for the LED to turn on every 1/2 second and stay lit for 1/8th of a second."));
|
||||
Serial.println(F("The countdown was set to a source clock frequency of 64 Hz (1/64th of a second)"));
|
||||
Serial.println(F("for a length of 32 time periods. 32 * 1/64th of a second is 1/2 of a second."));
|
||||
Serial.println(F("The low pulse duration was set to 125 ms, or 1/8th of a second."));
|
||||
Serial.println(F("The loop() keeps the built-in LED set to the opposite state of the INT/SQW pin."));
|
||||
|
||||
|
||||
countdownInterruptTriggered = false; // don't come in here again
|
||||
}
|
||||
|
||||
// While countdown running, INT/SQW pullup to HIGH, set LED to LOW (off)
|
||||
// When countdown is over, INT/SQW pulled down LOW, set LED to HIGH (on)
|
||||
digitalWrite(LED_BUILTIN, !digitalRead(timerInterruptPin));
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
// Date and time functions using a PCF8563 RTC connected via I2C and Wire lib
|
||||
#include "RTClib.h"
|
||||
|
||||
RTC_PCF8563 rtc;
|
||||
|
||||
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
||||
|
||||
void setup () {
|
||||
Serial.begin(115200);
|
||||
|
||||
#ifndef ESP8266
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
#endif
|
||||
|
||||
if (! rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC");
|
||||
Serial.flush();
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
if (rtc.lostPower()) {
|
||||
Serial.println("RTC is NOT initialized, let's set the time!");
|
||||
// When time needs to be set on a new device, or after a power loss, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
//
|
||||
// Note: allow 2 seconds after inserting battery or applying external power
|
||||
// without battery before calling adjust(). This gives the PCF8523's
|
||||
// crystal oscillator time to stabilize. If you call adjust() very quickly
|
||||
// after the RTC is powered, lostPower() may still return true.
|
||||
}
|
||||
|
||||
// When time needs to be re-set on a previously configured device, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
|
||||
// When the RTC was stopped and stays connected to the battery, it has
|
||||
// to be restarted by clearing the STOP bit. Let's do this to ensure
|
||||
// the RTC is running.
|
||||
rtc.start();
|
||||
}
|
||||
|
||||
void loop () {
|
||||
DateTime now = rtc.now();
|
||||
|
||||
Serial.print(now.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(now.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(now.day(), DEC);
|
||||
Serial.print(" (");
|
||||
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
|
||||
Serial.print(") ");
|
||||
Serial.print(now.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(now.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(now.second(), DEC);
|
||||
Serial.println();
|
||||
|
||||
Serial.print(" since midnight 1/1/1970 = ");
|
||||
Serial.print(now.unixtime());
|
||||
Serial.print("s = ");
|
||||
Serial.print(now.unixtime() / 86400L);
|
||||
Serial.println("d");
|
||||
|
||||
// calculate a date which is 7 days, 12 hours and 30 seconds into the future
|
||||
DateTime future (now + TimeSpan(7,12,30,6));
|
||||
|
||||
Serial.print(" now + 7d + 12h + 30m + 6s: ");
|
||||
Serial.print(future.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(future.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(future.day(), DEC);
|
||||
Serial.print(' ');
|
||||
Serial.print(future.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(future.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(future.second(), DEC);
|
||||
Serial.println();
|
||||
|
||||
Serial.println();
|
||||
delay(3000);
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
// Date and time functions using a PCF8563 RTC connected via I2C and Wire lib
|
||||
#include "RTClib.h"
|
||||
|
||||
RTC_PCF8563 rtc;
|
||||
|
||||
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
||||
|
||||
// use D2 for INT0; attach to CLKOUT pin on RTC
|
||||
const uint8_t INT_PIN = 2;
|
||||
|
||||
// flag to update serial; set in interrupt callback
|
||||
volatile uint8_t tick_tock = 1;
|
||||
|
||||
// INT0 interrupt callback; update tick_tock flag
|
||||
void set_tick_tock(void) {
|
||||
tick_tock = 1;
|
||||
}
|
||||
|
||||
void setup () {
|
||||
Serial.begin(115200);
|
||||
|
||||
#ifndef ESP8266
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
#endif
|
||||
|
||||
|
||||
pinMode(INT_PIN, INPUT); // set up interrupt pin
|
||||
digitalWrite(INT_PIN, HIGH); // turn on pullup resistors
|
||||
// attach interrupt to set_tick_tock callback on rising edge of INT0
|
||||
attachInterrupt(digitalPinToInterrupt(INT_PIN), set_tick_tock, RISING);
|
||||
|
||||
if (! rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC");
|
||||
Serial.flush();
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
if (rtc.lostPower()) {
|
||||
Serial.println("RTC is NOT initialized, let's set the time!");
|
||||
// When time needs to be set on a new device, or after a power loss, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
//
|
||||
// Note: allow 2 seconds after inserting battery or applying external power
|
||||
// without battery before calling adjust(). This gives the PCF8523's
|
||||
// crystal oscillator time to stabilize. If you call adjust() very quickly
|
||||
// after the RTC is powered, lostPower() may still return true.
|
||||
}
|
||||
|
||||
|
||||
|
||||
// When time needs to be re-set on a previously configured device, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
|
||||
// When the RTC was stopped and stays connected to the battery, it has
|
||||
// to be restarted by clearing the STOP bit. Let's do this to ensure
|
||||
// the RTC is running.
|
||||
rtc.start();
|
||||
|
||||
// turn on 1Hz clock out, used as INT0 for serial update every second
|
||||
rtc.writeSqwPinMode(PCF8563_SquareWave1Hz);
|
||||
}
|
||||
|
||||
void loop () {
|
||||
|
||||
// check if time display should be output
|
||||
if(tick_tock) {
|
||||
|
||||
DateTime now = rtc.now();
|
||||
|
||||
char time_format[] = "hh:mm:ss AP";
|
||||
char date_format[] = "MM/DD/YYYY";
|
||||
|
||||
Serial.println(now.toString(time_format));
|
||||
Serial.println(now.toString(date_format));
|
||||
Serial.println();
|
||||
|
||||
tick_tock = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
// Date and time functions using just software, based on millis() & timer
|
||||
|
||||
#include "RTClib.h"
|
||||
|
||||
RTC_Millis rtc;
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
|
||||
#ifndef ESP8266
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
#endif
|
||||
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
rtc.begin(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
}
|
||||
|
||||
void loop () {
|
||||
DateTime now = rtc.now();
|
||||
|
||||
Serial.print(now.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(now.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(now.day(), DEC);
|
||||
Serial.print(' ');
|
||||
Serial.print(now.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(now.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(now.second(), DEC);
|
||||
Serial.println();
|
||||
|
||||
Serial.print(" seconds since 1970: ");
|
||||
Serial.println(now.unixtime());
|
||||
|
||||
// calculate a date which is 7 days and 30 seconds into the future
|
||||
DateTime future (now.unixtime() + 7 * 86400L + 30);
|
||||
|
||||
Serial.print(" now + 7d + 30s: ");
|
||||
Serial.print(future.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(future.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(future.day(), DEC);
|
||||
Serial.print(' ');
|
||||
Serial.print(future.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(future.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(future.second(), DEC);
|
||||
Serial.println();
|
||||
|
||||
Serial.println();
|
||||
delay(3000);
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/* Timestamp functions using a DS1307 RTC connected via I2C and Wire lib
|
||||
**
|
||||
** Useful for file name
|
||||
** ` SD.open(time.timestamp()+".log", FILE_WRITE) `
|
||||
**
|
||||
**
|
||||
** Created: 2015-06-01 by AxelTB
|
||||
** Last Edit:
|
||||
*/
|
||||
|
||||
#include "RTClib.h"
|
||||
|
||||
RTC_DS1307 rtc;
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
|
||||
#ifndef ESP8266
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
#endif
|
||||
|
||||
if (! rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC");
|
||||
Serial.flush();
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
if (! rtc.isrunning()) {
|
||||
Serial.println("RTC is NOT running, let's set the time!");
|
||||
// When time needs to be set on a new device, or after a power loss, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
}
|
||||
|
||||
// When time needs to be re-set on a previously configured device, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
DateTime time = rtc.now();
|
||||
|
||||
//Full Timestamp
|
||||
Serial.println(String("DateTime::TIMESTAMP_FULL:\t")+time.timestamp(DateTime::TIMESTAMP_FULL));
|
||||
|
||||
//Date Only
|
||||
Serial.println(String("DateTime::TIMESTAMP_DATE:\t")+time.timestamp(DateTime::TIMESTAMP_DATE));
|
||||
|
||||
//Full Timestamp
|
||||
Serial.println(String("DateTime::TIMESTAMP_TIME:\t")+time.timestamp(DateTime::TIMESTAMP_TIME));
|
||||
|
||||
Serial.println("\n");
|
||||
|
||||
//Delay 5s
|
||||
delay(5000);
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
#include <Wire.h>
|
||||
#include <RTClib.h>
|
||||
|
||||
RTC_DS1307 rtc;
|
||||
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
|
||||
#ifndef ESP8266
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
#endif
|
||||
|
||||
if (! rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC");
|
||||
Serial.flush();
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
if (! rtc.isrunning()) {
|
||||
Serial.println("RTC is NOT running, let's set the time!");
|
||||
// When time needs to be set on a new device, or after a power loss, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
}
|
||||
|
||||
// When time needs to be re-set on a previously configured device, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
DateTime now = rtc.now();
|
||||
|
||||
//buffer can be defined using following combinations:
|
||||
//hh - the hour with a leading zero (00 to 23)
|
||||
//mm - the minute with a leading zero (00 to 59)
|
||||
//ss - the whole second with a leading zero where applicable (00 to 59)
|
||||
//YYYY - the year as four digit number
|
||||
//YY - the year as two digit number (00-99)
|
||||
//MM - the month as number with a leading zero (01-12)
|
||||
//MMM - the abbreviated English month name ('Jan' to 'Dec')
|
||||
//DD - the day as number with a leading zero (01 to 31)
|
||||
//DDD - the abbreviated English day name ('Mon' to 'Sun')
|
||||
|
||||
char buf1[] = "hh:mm";
|
||||
Serial.println(now.toString(buf1));
|
||||
|
||||
char buf2[] = "YYMMDD-hh:mm:ss";
|
||||
Serial.println(now.toString(buf2));
|
||||
|
||||
char buf3[] = "Today is DDD, MMM DD YYYY";
|
||||
Serial.println(now.toString(buf3));
|
||||
|
||||
char buf4[] = "MM-DD-YYYY";
|
||||
Serial.println(now.toString(buf4));
|
||||
|
||||
delay(1000);
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For RTClib
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
DateTime KEYWORD1
|
||||
TimeSpan KEYWORD1
|
||||
RTC_DS1307 KEYWORD1
|
||||
RTC_DS3231 KEYWORD1
|
||||
RTC_PCF8523 KEYWORD1
|
||||
RTC_PCF8563 KEYWORD1
|
||||
RTC_Millis KEYWORD1
|
||||
RTC_Micros KEYWORD1
|
||||
Ds1307SqwPinMode KEYWORD1
|
||||
Ds3231SqwPinMode KEYWORD1
|
||||
Ds3231Alarm1Mode KEYWORD1
|
||||
Ds3231Alarm2Mode KEYWORD1
|
||||
Pcf8523SqwPinMode KEYWORD1
|
||||
PCF8523TimerClockFreq KEYWORD1
|
||||
PCF8523TimerIntPulse KEYWORD1
|
||||
Pcf8523OffsetMode KEYWORD1
|
||||
Pcf8563SqwPinMode KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
isValid KEYWORD2
|
||||
year KEYWORD2
|
||||
month KEYWORD2
|
||||
day KEYWORD2
|
||||
hour KEYWORD2
|
||||
twelveHour KEYWORD2
|
||||
isPM KEYWORD2
|
||||
minute KEYWORD2
|
||||
second KEYWORD2
|
||||
dayOfTheWeek KEYWORD2
|
||||
secondstime KEYWORD2
|
||||
unixtime KEYWORD2
|
||||
days KEYWORD2
|
||||
hours KEYWORD2
|
||||
minutes KEYWORD2
|
||||
seconds KEYWORD2
|
||||
totalseconds KEYWORD2
|
||||
begin KEYWORD2
|
||||
adjust KEYWORD2
|
||||
adjustDrift KEYWORD2
|
||||
isrunning KEYWORD2
|
||||
now KEYWORD2
|
||||
readSqwPinMode KEYWORD2
|
||||
writeSqwPinMode KEYWORD2
|
||||
timestamp KEYWORD2
|
||||
toString KEYWORD2
|
||||
readnvram KEYWORD2
|
||||
writenvram KEYWORD2
|
||||
setAlarm1 KEYWORD2
|
||||
setAlarm2 KEYWORD2
|
||||
disableAlarm KEYWORD2
|
||||
clearAlarm KEYWORD2
|
||||
alarmFired KEYWORD2
|
||||
getTemperature KEYWORD2
|
||||
lostPower KEYWORD2
|
||||
initialized KEYWORD2
|
||||
enableSecondTimer KEYWORD2
|
||||
disableSecondTimer KEYWORD2
|
||||
enableCountdownTimer KEYWORD2
|
||||
disableCountdownTimer KEYWORD2
|
||||
deconfigureAllTimers KEYWORD2
|
||||
calibrate KEYWORD2
|
||||
enable32K KEYWORD2
|
||||
disable32K KEYWORD2
|
||||
isEnabled32K KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
TIMESTAMP_FULL LITERAL1
|
||||
TIMESTAMP_DATE LITERAL1
|
||||
TIMESTAMP_TIME LITERAL1
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
name=RTClib
|
||||
version=2.1.4
|
||||
author=Adafruit
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=A fork of Jeelab's fantastic RTC library
|
||||
paragraph=Works with DS1307, DS3231, PCF8523, PCF8563 on multiple architectures
|
||||
category=Timing
|
||||
url=https://github.com/adafruit/RTClib
|
||||
architectures=*
|
||||
depends=Adafruit BusIO
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Adafruit Industries
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,134 @@
|
|||
#include "RTClib.h"
|
||||
|
||||
#define DS1307_ADDRESS 0x68 ///< I2C address for DS1307
|
||||
#define DS1307_CONTROL 0x07 ///< Control register
|
||||
#define DS1307_NVRAM 0x08 ///< Start of RAM registers - 56 bytes, 0x08 to 0x3f
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Start I2C for the DS1307 and test succesful connection
|
||||
@param wireInstance pointer to the I2C bus
|
||||
@return True if Wire can find DS1307 or false otherwise.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_DS1307::begin(TwoWire *wireInstance) {
|
||||
if (i2c_dev)
|
||||
delete i2c_dev;
|
||||
i2c_dev = new Adafruit_I2CDevice(DS1307_ADDRESS, wireInstance);
|
||||
if (!i2c_dev->begin())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Is the DS1307 running? Check the Clock Halt bit in register 0
|
||||
@return 1 if the RTC is running, 0 if not
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t RTC_DS1307::isrunning(void) { return !(read_register(0) >> 7); }
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the date and time in the DS1307
|
||||
@param dt DateTime object containing the desired date/time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS1307::adjust(const DateTime &dt) {
|
||||
uint8_t buffer[8] = {0,
|
||||
bin2bcd(dt.second()),
|
||||
bin2bcd(dt.minute()),
|
||||
bin2bcd(dt.hour()),
|
||||
0,
|
||||
bin2bcd(dt.day()),
|
||||
bin2bcd(dt.month()),
|
||||
bin2bcd(dt.year() - 2000U)};
|
||||
i2c_dev->write(buffer, 8);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the current date and time from the DS1307
|
||||
@return DateTime object containing the current date and time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_DS1307::now() {
|
||||
uint8_t buffer[7];
|
||||
buffer[0] = 0;
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 7);
|
||||
|
||||
return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5]),
|
||||
bcd2bin(buffer[4]), bcd2bin(buffer[2]), bcd2bin(buffer[1]),
|
||||
bcd2bin(buffer[0] & 0x7F));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read the current mode of the SQW pin
|
||||
@return Mode as Ds1307SqwPinMode enum
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Ds1307SqwPinMode RTC_DS1307::readSqwPinMode() {
|
||||
return static_cast<Ds1307SqwPinMode>(read_register(DS1307_CONTROL) & 0x93);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Change the SQW pin mode
|
||||
@param mode The mode to use
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS1307::writeSqwPinMode(Ds1307SqwPinMode mode) {
|
||||
write_register(DS1307_CONTROL, mode);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read data from the DS1307's NVRAM
|
||||
@param buf Pointer to a buffer to store the data - make sure it's large
|
||||
enough to hold size bytes
|
||||
@param size Number of bytes to read
|
||||
@param address Starting NVRAM address, from 0 to 55
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS1307::readnvram(uint8_t *buf, uint8_t size, uint8_t address) {
|
||||
uint8_t addrByte = DS1307_NVRAM + address;
|
||||
i2c_dev->write_then_read(&addrByte, 1, buf, size);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Write data to the DS1307 NVRAM
|
||||
@param address Starting NVRAM address, from 0 to 55
|
||||
@param buf Pointer to buffer containing the data to write
|
||||
@param size Number of bytes in buf to write to NVRAM
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS1307::writenvram(uint8_t address, const uint8_t *buf, uint8_t size) {
|
||||
uint8_t addrByte = DS1307_NVRAM + address;
|
||||
i2c_dev->write(buf, size, true, &addrByte, 1);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Shortcut to read one byte from NVRAM
|
||||
@param address NVRAM address, 0 to 55
|
||||
@return The byte read from NVRAM
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t RTC_DS1307::readnvram(uint8_t address) {
|
||||
uint8_t data;
|
||||
readnvram(&data, 1, address);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Shortcut to write one byte to NVRAM
|
||||
@param address NVRAM address, 0 to 55
|
||||
@param data One byte to write
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS1307::writenvram(uint8_t address, uint8_t data) {
|
||||
writenvram(address, &data, 1);
|
||||
}
|
|
@ -0,0 +1,384 @@
|
|||
#include "RTClib.h"
|
||||
|
||||
#define DS3231_ADDRESS 0x68 ///< I2C address for DS3231
|
||||
#define DS3231_TIME 0x00 ///< Time register
|
||||
#define DS3231_ALARM1 0x07 ///< Alarm 1 register
|
||||
#define DS3231_ALARM2 0x0B ///< Alarm 2 register
|
||||
#define DS3231_CONTROL 0x0E ///< Control register
|
||||
#define DS3231_STATUSREG 0x0F ///< Status register
|
||||
#define DS3231_TEMPERATUREREG \
|
||||
0x11 ///< Temperature register (high byte - low byte is at 0x12), 10-bit
|
||||
///< temperature value
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Start I2C for the DS3231 and test succesful connection
|
||||
@param wireInstance pointer to the I2C bus
|
||||
@return True if Wire can find DS3231 or false otherwise.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_DS3231::begin(TwoWire *wireInstance) {
|
||||
if (i2c_dev)
|
||||
delete i2c_dev;
|
||||
i2c_dev = new Adafruit_I2CDevice(DS3231_ADDRESS, wireInstance);
|
||||
if (!i2c_dev->begin())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check the status register Oscillator Stop Flag to see if the DS3231
|
||||
stopped due to power loss
|
||||
@return True if the bit is set (oscillator stopped) or false if it is
|
||||
running
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_DS3231::lostPower(void) {
|
||||
return read_register(DS3231_STATUSREG) >> 7;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the date and flip the Oscillator Stop Flag
|
||||
@param dt DateTime object containing the date/time to set
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS3231::adjust(const DateTime &dt) {
|
||||
uint8_t buffer[8] = {DS3231_TIME,
|
||||
bin2bcd(dt.second()),
|
||||
bin2bcd(dt.minute()),
|
||||
bin2bcd(dt.hour()),
|
||||
bin2bcd(dowToDS3231(dt.dayOfTheWeek())),
|
||||
bin2bcd(dt.day()),
|
||||
bin2bcd(dt.month()),
|
||||
bin2bcd(dt.year() - 2000U)};
|
||||
i2c_dev->write(buffer, 8);
|
||||
|
||||
uint8_t statreg = read_register(DS3231_STATUSREG);
|
||||
statreg &= ~0x80; // flip OSF bit
|
||||
write_register(DS3231_STATUSREG, statreg);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the current date/time
|
||||
@return DateTime object with the current date/time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_DS3231::now() {
|
||||
uint8_t buffer[7];
|
||||
buffer[0] = 0;
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 7);
|
||||
|
||||
return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5] & 0x7F),
|
||||
bcd2bin(buffer[4]), bcd2bin(buffer[2]), bcd2bin(buffer[1]),
|
||||
bcd2bin(buffer[0] & 0x7F));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read the SQW pin mode
|
||||
@return Pin mode, see Ds3231SqwPinMode enum
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Ds3231SqwPinMode RTC_DS3231::readSqwPinMode() {
|
||||
int mode;
|
||||
mode = read_register(DS3231_CONTROL) & 0x1C;
|
||||
if (mode & 0x04)
|
||||
mode = DS3231_OFF;
|
||||
return static_cast<Ds3231SqwPinMode>(mode);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the SQW pin mode
|
||||
@param mode Desired mode, see Ds3231SqwPinMode enum
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS3231::writeSqwPinMode(Ds3231SqwPinMode mode) {
|
||||
uint8_t ctrl = read_register(DS3231_CONTROL);
|
||||
|
||||
ctrl &= ~0x04; // turn off INTCON
|
||||
ctrl &= ~0x18; // set freq bits to 0
|
||||
|
||||
write_register(DS3231_CONTROL, ctrl | mode);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the current temperature from the DS3231's temperature sensor
|
||||
@return Current temperature (float)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float RTC_DS3231::getTemperature() {
|
||||
uint8_t buffer[2] = {DS3231_TEMPERATUREREG, 0};
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 2);
|
||||
return (float)buffer[0] + (buffer[1] >> 6) * 0.25f;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set alarm 1 for DS3231
|
||||
@param dt DateTime object
|
||||
@param alarm_mode Desired mode, see Ds3231Alarm1Mode enum
|
||||
@return False if control register is not set, otherwise true
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_DS3231::setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode) {
|
||||
uint8_t ctrl = read_register(DS3231_CONTROL);
|
||||
if (!(ctrl & 0x04)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t A1M1 = (alarm_mode & 0x01) << 7; // Seconds bit 7.
|
||||
uint8_t A1M2 = (alarm_mode & 0x02) << 6; // Minutes bit 7.
|
||||
uint8_t A1M3 = (alarm_mode & 0x04) << 5; // Hour bit 7.
|
||||
uint8_t A1M4 = (alarm_mode & 0x08) << 4; // Day/Date bit 7.
|
||||
uint8_t DY_DT = (alarm_mode & 0x10)
|
||||
<< 2; // Day/Date bit 6. Date when 0, day of week when 1.
|
||||
uint8_t day = (DY_DT) ? dowToDS3231(dt.dayOfTheWeek()) : dt.day();
|
||||
|
||||
uint8_t buffer[5] = {DS3231_ALARM1, uint8_t(bin2bcd(dt.second()) | A1M1),
|
||||
uint8_t(bin2bcd(dt.minute()) | A1M2),
|
||||
uint8_t(bin2bcd(dt.hour()) | A1M3),
|
||||
uint8_t(bin2bcd(day) | A1M4 | DY_DT)};
|
||||
i2c_dev->write(buffer, 5);
|
||||
|
||||
write_register(DS3231_CONTROL, ctrl | 0x01); // AI1E
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set alarm 2 for DS3231
|
||||
@param dt DateTime object
|
||||
@param alarm_mode Desired mode, see Ds3231Alarm2Mode enum
|
||||
@return False if control register is not set, otherwise true
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_DS3231::setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode) {
|
||||
uint8_t ctrl = read_register(DS3231_CONTROL);
|
||||
if (!(ctrl & 0x04)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t A2M2 = (alarm_mode & 0x01) << 7; // Minutes bit 7.
|
||||
uint8_t A2M3 = (alarm_mode & 0x02) << 6; // Hour bit 7.
|
||||
uint8_t A2M4 = (alarm_mode & 0x04) << 5; // Day/Date bit 7.
|
||||
uint8_t DY_DT = (alarm_mode & 0x08)
|
||||
<< 3; // Day/Date bit 6. Date when 0, day of week when 1.
|
||||
uint8_t day = (DY_DT) ? dowToDS3231(dt.dayOfTheWeek()) : dt.day();
|
||||
|
||||
uint8_t buffer[4] = {DS3231_ALARM2, uint8_t(bin2bcd(dt.minute()) | A2M2),
|
||||
uint8_t(bin2bcd(dt.hour()) | A2M3),
|
||||
uint8_t(bin2bcd(day) | A2M4 | DY_DT)};
|
||||
i2c_dev->write(buffer, 4);
|
||||
|
||||
write_register(DS3231_CONTROL, ctrl | 0x02); // AI2E
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the date/time value of Alarm1
|
||||
@return DateTime object with the Alarm1 data set in the
|
||||
day, hour, minutes, and seconds fields
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_DS3231::getAlarm1() {
|
||||
uint8_t buffer[5] = {DS3231_ALARM1, 0, 0, 0, 0};
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 5);
|
||||
|
||||
uint8_t seconds = bcd2bin(buffer[0] & 0x7F);
|
||||
uint8_t minutes = bcd2bin(buffer[1] & 0x7F);
|
||||
// Fetching the hour assumes 24 hour time (never 12)
|
||||
// because this library exclusively stores the time
|
||||
// in 24 hour format. Note that the DS3231 supports
|
||||
// 12 hour storage, and sets bits to indicate the type
|
||||
// that is stored.
|
||||
uint8_t hour = bcd2bin(buffer[2] & 0x3F);
|
||||
|
||||
// Determine if the alarm is set to fire based on the
|
||||
// day of the week, or an explicit date match.
|
||||
bool isDayOfWeek = (buffer[3] & 0x40) >> 6;
|
||||
uint8_t day;
|
||||
if (isDayOfWeek) {
|
||||
// Alarm set to match on day of the week
|
||||
day = bcd2bin(buffer[3] & 0x0F);
|
||||
} else {
|
||||
// Alarm set to match on day of the month
|
||||
day = bcd2bin(buffer[3] & 0x3F);
|
||||
}
|
||||
|
||||
// On the first week of May 2000, the day-of-the-week number
|
||||
// matches the date number.
|
||||
return DateTime(2000, 5, day, hour, minutes, seconds);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the date/time value of Alarm2
|
||||
@return DateTime object with the Alarm2 data set in the
|
||||
day, hour, and minutes fields
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_DS3231::getAlarm2() {
|
||||
uint8_t buffer[4] = {DS3231_ALARM2, 0, 0, 0};
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 4);
|
||||
|
||||
uint8_t minutes = bcd2bin(buffer[0] & 0x7F);
|
||||
// Fetching the hour assumes 24 hour time (never 12)
|
||||
// because this library exclusively stores the time
|
||||
// in 24 hour format. Note that the DS3231 supports
|
||||
// 12 hour storage, and sets bits to indicate the type
|
||||
// that is stored.
|
||||
uint8_t hour = bcd2bin(buffer[1] & 0x3F);
|
||||
|
||||
// Determine if the alarm is set to fire based on the
|
||||
// day of the week, or an explicit date match.
|
||||
bool isDayOfWeek = (buffer[2] & 0x40) >> 6;
|
||||
uint8_t day;
|
||||
if (isDayOfWeek) {
|
||||
// Alarm set to match on day of the week
|
||||
day = bcd2bin(buffer[2] & 0x0F);
|
||||
} else {
|
||||
// Alarm set to match on day of the month
|
||||
day = bcd2bin(buffer[2] & 0x3F);
|
||||
}
|
||||
|
||||
// On the first week of May 2000, the day-of-the-week number
|
||||
// matches the date number.
|
||||
return DateTime(2000, 5, day, hour, minutes, 0);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the mode for Alarm1
|
||||
@return Ds3231Alarm1Mode enum value for the current Alarm1 mode
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Ds3231Alarm1Mode RTC_DS3231::getAlarm1Mode() {
|
||||
uint8_t buffer[5] = {DS3231_ALARM1, 0, 0, 0, 0};
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 5);
|
||||
|
||||
uint8_t alarm_mode = (buffer[0] & 0x80) >> 7 // A1M1 - Seconds bit
|
||||
| (buffer[1] & 0x80) >> 6 // A1M2 - Minutes bit
|
||||
| (buffer[2] & 0x80) >> 5 // A1M3 - Hour bit
|
||||
| (buffer[3] & 0x80) >> 4 // A1M4 - Day/Date bit
|
||||
| (buffer[3] & 0x40) >> 2; // DY_DT
|
||||
|
||||
// Determine which mode the fetched alarm bits map to
|
||||
switch (alarm_mode) {
|
||||
case DS3231_A1_PerSecond:
|
||||
case DS3231_A1_Second:
|
||||
case DS3231_A1_Minute:
|
||||
case DS3231_A1_Hour:
|
||||
case DS3231_A1_Date:
|
||||
case DS3231_A1_Day:
|
||||
return (Ds3231Alarm1Mode)alarm_mode;
|
||||
default:
|
||||
// Default if the alarm mode cannot be read
|
||||
return DS3231_A1_Date;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the mode for Alarm2
|
||||
@return Ds3231Alarm2Mode enum value for the current Alarm2 mode
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Ds3231Alarm2Mode RTC_DS3231::getAlarm2Mode() {
|
||||
uint8_t buffer[4] = {DS3231_ALARM2, 0, 0, 0};
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 4);
|
||||
|
||||
uint8_t alarm_mode = (buffer[0] & 0x80) >> 7 // A2M2 - Minutes bit
|
||||
| (buffer[1] & 0x80) >> 6 // A2M3 - Hour bit
|
||||
| (buffer[2] & 0x80) >> 5 // A2M4 - Day/Date bit
|
||||
| (buffer[2] & 0x40) >> 3; // DY_DT
|
||||
|
||||
// Determine which mode the fetched alarm bits map to
|
||||
switch (alarm_mode) {
|
||||
case DS3231_A2_PerMinute:
|
||||
case DS3231_A2_Minute:
|
||||
case DS3231_A2_Hour:
|
||||
case DS3231_A2_Date:
|
||||
case DS3231_A2_Day:
|
||||
return (Ds3231Alarm2Mode)alarm_mode;
|
||||
default:
|
||||
// Default if the alarm mode cannot be read
|
||||
return DS3231_A2_Date;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Disable alarm
|
||||
@param alarm_num Alarm number to disable
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS3231::disableAlarm(uint8_t alarm_num) {
|
||||
uint8_t ctrl = read_register(DS3231_CONTROL);
|
||||
ctrl &= ~(1 << (alarm_num - 1));
|
||||
write_register(DS3231_CONTROL, ctrl);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Clear status of alarm
|
||||
@param alarm_num Alarm number to clear
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS3231::clearAlarm(uint8_t alarm_num) {
|
||||
uint8_t status = read_register(DS3231_STATUSREG);
|
||||
status &= ~(0x1 << (alarm_num - 1));
|
||||
write_register(DS3231_STATUSREG, status);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get status of alarm
|
||||
@param alarm_num Alarm number to check status of
|
||||
@return True if alarm has been fired otherwise false
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_DS3231::alarmFired(uint8_t alarm_num) {
|
||||
return (read_register(DS3231_STATUSREG) >> (alarm_num - 1)) & 0x1;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Enable 32KHz Output
|
||||
@details The 32kHz output is enabled by default. It requires an external
|
||||
pull-up resistor to function correctly
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS3231::enable32K(void) {
|
||||
uint8_t status = read_register(DS3231_STATUSREG);
|
||||
status |= (0x1 << 0x03);
|
||||
write_register(DS3231_STATUSREG, status);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Disable 32KHz Output
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_DS3231::disable32K(void) {
|
||||
uint8_t status = read_register(DS3231_STATUSREG);
|
||||
status &= ~(0x1 << 0x03);
|
||||
write_register(DS3231_STATUSREG, status);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get status of 32KHz Output
|
||||
@return True if enabled otherwise false
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_DS3231::isEnabled32K(void) {
|
||||
return (read_register(DS3231_STATUSREG) >> 0x03) & 0x01;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#include "RTClib.h"
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the current date/time of the RTC_Micros clock.
|
||||
@param dt DateTime object with the desired date and time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_Micros::adjust(const DateTime &dt) {
|
||||
lastMicros = micros();
|
||||
lastUnix = dt.unixtime();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Adjust the RTC_Micros clock to compensate for system clock drift
|
||||
@param ppm Adjustment to make. A positive adjustment makes the clock faster.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_Micros::adjustDrift(int ppm) { microsPerSecond = 1000000 - ppm; }
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the current date/time from the RTC_Micros clock.
|
||||
@return DateTime object containing the current date/time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_Micros::now() {
|
||||
uint32_t elapsedSeconds = (micros() - lastMicros) / microsPerSecond;
|
||||
lastMicros += elapsedSeconds * microsPerSecond;
|
||||
lastUnix += elapsedSeconds;
|
||||
return lastUnix;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#include "RTClib.h"
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the current date/time of the RTC_Millis clock.
|
||||
@param dt DateTime object with the desired date and time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_Millis::adjust(const DateTime &dt) {
|
||||
lastMillis = millis();
|
||||
lastUnix = dt.unixtime();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Return a DateTime object containing the current date/time.
|
||||
Note that computing (millis() - lastMillis) is rollover-safe as long
|
||||
as this method is called at least once every 49.7 days.
|
||||
@return DateTime object containing current time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_Millis::now() {
|
||||
uint32_t elapsedSeconds = (millis() - lastMillis) / 1000;
|
||||
lastMillis += elapsedSeconds * 1000;
|
||||
lastUnix += elapsedSeconds;
|
||||
return lastUnix;
|
||||
}
|
|
@ -0,0 +1,292 @@
|
|||
#include "RTClib.h"
|
||||
|
||||
#define PCF8523_ADDRESS 0x68 ///< I2C address for PCF8523
|
||||
#define PCF8523_CLKOUTCONTROL 0x0F ///< Timer and CLKOUT control register
|
||||
#define PCF8523_CONTROL_1 0x00 ///< Control and status register 1
|
||||
#define PCF8523_CONTROL_2 0x01 ///< Control and status register 2
|
||||
#define PCF8523_CONTROL_3 0x02 ///< Control and status register 3
|
||||
#define PCF8523_TIMER_B_FRCTL 0x12 ///< Timer B source clock frequency control
|
||||
#define PCF8523_TIMER_B_VALUE 0x13 ///< Timer B value (number clock periods)
|
||||
#define PCF8523_OFFSET 0x0E ///< Offset register
|
||||
#define PCF8523_STATUSREG 0x03 ///< Status register
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Start I2C for the PCF8523 and test succesful connection
|
||||
@param wireInstance pointer to the I2C bus
|
||||
@return True if Wire can find PCF8523 or false otherwise.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_PCF8523::begin(TwoWire *wireInstance) {
|
||||
if (i2c_dev)
|
||||
delete i2c_dev;
|
||||
i2c_dev = new Adafruit_I2CDevice(PCF8523_ADDRESS, wireInstance);
|
||||
if (!i2c_dev->begin())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check the status register Oscillator Stop flag to see if the PCF8523
|
||||
stopped due to power loss
|
||||
@details When battery or external power is first applied, the PCF8523's
|
||||
crystal oscillator takes up to 2s to stabilize. During this time adjust()
|
||||
cannot clear the 'OS' flag. See datasheet OS flag section for details.
|
||||
@return True if the bit is set (oscillator is or has stopped) and false only
|
||||
after the bit is cleared, for instance with adjust()
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_PCF8523::lostPower(void) {
|
||||
return read_register(PCF8523_STATUSREG) >> 7;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check control register 3 to see if we've run adjust() yet (setting
|
||||
the date/time and battery switchover mode)
|
||||
@return True if the PCF8523 has been set up, false if not
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_PCF8523::initialized(void) {
|
||||
return (read_register(PCF8523_CONTROL_3) & 0xE0) != 0xE0;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the date and time, set battery switchover mode
|
||||
@param dt DateTime to set
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::adjust(const DateTime &dt) {
|
||||
uint8_t buffer[8] = {3, // start at location 3
|
||||
bin2bcd(dt.second()),
|
||||
bin2bcd(dt.minute()),
|
||||
bin2bcd(dt.hour()),
|
||||
bin2bcd(dt.day()),
|
||||
bin2bcd(0), // skip weekdays
|
||||
bin2bcd(dt.month()),
|
||||
bin2bcd(dt.year() - 2000U)};
|
||||
i2c_dev->write(buffer, 8);
|
||||
|
||||
// set to battery switchover mode
|
||||
write_register(PCF8523_CONTROL_3, 0x00);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the current date/time
|
||||
@return DateTime object containing the current date/time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_PCF8523::now() {
|
||||
uint8_t buffer[7];
|
||||
buffer[0] = 3;
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 7);
|
||||
|
||||
return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5]),
|
||||
bcd2bin(buffer[3]), bcd2bin(buffer[2]), bcd2bin(buffer[1]),
|
||||
bcd2bin(buffer[0] & 0x7F));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Resets the STOP bit in register Control_1
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::start(void) {
|
||||
uint8_t ctlreg = read_register(PCF8523_CONTROL_1);
|
||||
if (ctlreg & (1 << 5))
|
||||
write_register(PCF8523_CONTROL_1, ctlreg & ~(1 << 5));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the STOP bit in register Control_1
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::stop(void) {
|
||||
write_register(PCF8523_CONTROL_1,
|
||||
read_register(PCF8523_CONTROL_1) | (1 << 5));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Is the PCF8523 running? Check the STOP bit in register Control_1
|
||||
@return 1 if the RTC is running, 0 if not
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t RTC_PCF8523::isrunning() {
|
||||
return !((read_register(PCF8523_CONTROL_1) >> 5) & 1);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read the mode of the INT/SQW pin on the PCF8523
|
||||
@return SQW pin mode as a #Pcf8523SqwPinMode enum
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Pcf8523SqwPinMode RTC_PCF8523::readSqwPinMode() {
|
||||
int mode = read_register(PCF8523_CLKOUTCONTROL);
|
||||
mode >>= 3;
|
||||
mode &= 0x7;
|
||||
return static_cast<Pcf8523SqwPinMode>(mode);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the INT/SQW pin mode on the PCF8523
|
||||
@param mode The mode to set, see the #Pcf8523SqwPinMode enum for options
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::writeSqwPinMode(Pcf8523SqwPinMode mode) {
|
||||
write_register(PCF8523_CLKOUTCONTROL, mode << 3);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Enable the Second Timer (1Hz) Interrupt on the PCF8523.
|
||||
@details The INT/SQW pin will pull low for a brief pulse once per second.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::enableSecondTimer() {
|
||||
uint8_t ctlreg = read_register(PCF8523_CONTROL_1);
|
||||
uint8_t clkreg = read_register(PCF8523_CLKOUTCONTROL);
|
||||
// TAM pulse int. mode (shared with Timer A), CLKOUT (aka SQW) disabled
|
||||
write_register(PCF8523_CLKOUTCONTROL, clkreg | 0xB8);
|
||||
// SIE Second timer int. enable
|
||||
write_register(PCF8523_CONTROL_1, ctlreg | (1 << 2));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Disable the Second Timer (1Hz) Interrupt on the PCF8523.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::disableSecondTimer() {
|
||||
write_register(PCF8523_CONTROL_1,
|
||||
read_register(PCF8523_CONTROL_1) & ~(1 << 2));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Enable the Countdown Timer Interrupt on the PCF8523.
|
||||
@details The INT/SQW pin will be pulled low at the end of a specified
|
||||
countdown period ranging from 244 microseconds to 10.625 days.
|
||||
Uses PCF8523 Timer B. Any existing CLKOUT square wave, configured with
|
||||
writeSqwPinMode(), will halt. The interrupt low pulse width is adjustable
|
||||
from 3/64ths (default) to 14/64ths of a second.
|
||||
@param clkFreq One of the PCF8523's Timer Source Clock Frequencies.
|
||||
See the #PCF8523TimerClockFreq enum for options and associated time ranges.
|
||||
@param numPeriods The number of clkFreq periods (1-255) to count down.
|
||||
@param lowPulseWidth Optional: the length of time for the interrupt pin
|
||||
low pulse. See the #PCF8523TimerIntPulse enum for options.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::enableCountdownTimer(PCF8523TimerClockFreq clkFreq,
|
||||
uint8_t numPeriods,
|
||||
uint8_t lowPulseWidth) {
|
||||
// Datasheet cautions against updating countdown value while it's running,
|
||||
// so disabling allows repeated calls with new values to set new countdowns
|
||||
disableCountdownTimer();
|
||||
|
||||
// Leave compatible settings intact
|
||||
uint8_t ctlreg = read_register(PCF8523_CONTROL_2);
|
||||
uint8_t clkreg = read_register(PCF8523_CLKOUTCONTROL);
|
||||
|
||||
// CTBIE Countdown Timer B Interrupt Enabled
|
||||
write_register(PCF8523_CONTROL_2, ctlreg |= 0x01);
|
||||
|
||||
// Timer B source clock frequency, optionally int. low pulse width
|
||||
write_register(PCF8523_TIMER_B_FRCTL, lowPulseWidth << 4 | clkFreq);
|
||||
|
||||
// Timer B value (number of source clock periods)
|
||||
write_register(PCF8523_TIMER_B_VALUE, numPeriods);
|
||||
|
||||
// TBM Timer B pulse int. mode, CLKOUT (aka SQW) disabled, TBC start Timer B
|
||||
write_register(PCF8523_CLKOUTCONTROL, clkreg | 0x79);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@overload
|
||||
@brief Enable Countdown Timer using default interrupt low pulse width.
|
||||
@param clkFreq One of the PCF8523's Timer Source Clock Frequencies.
|
||||
See the #PCF8523TimerClockFreq enum for options and associated time ranges.
|
||||
@param numPeriods The number of clkFreq periods (1-255) to count down.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::enableCountdownTimer(PCF8523TimerClockFreq clkFreq,
|
||||
uint8_t numPeriods) {
|
||||
enableCountdownTimer(clkFreq, numPeriods, 0);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Disable the Countdown Timer Interrupt on the PCF8523.
|
||||
@details For simplicity, this function strictly disables Timer B by setting
|
||||
TBC to 0. The datasheet describes TBC as the Timer B on/off switch.
|
||||
Timer B is the only countdown timer implemented at this time.
|
||||
The following flags have no effect while TBC is off, they are *not* cleared:
|
||||
- TBM: Timer B will still be set to pulsed mode.
|
||||
- CTBIE: Timer B interrupt would be triggered if TBC were on.
|
||||
- CTBF: Timer B flag indicates that interrupt was triggered. Though
|
||||
typically used for non-pulsed mode, user may wish to query this later.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::disableCountdownTimer() {
|
||||
// TBC disable to stop Timer B clock
|
||||
write_register(PCF8523_CLKOUTCONTROL,
|
||||
~1 & read_register(PCF8523_CLKOUTCONTROL));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Stop all timers, clear their flags and settings on the PCF8523.
|
||||
@details This includes the Countdown Timer, Second Timer, and any CLKOUT
|
||||
square wave configured with writeSqwPinMode().
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::deconfigureAllTimers() {
|
||||
disableSecondTimer(); // Surgically clears CONTROL_1
|
||||
write_register(PCF8523_CONTROL_2, 0);
|
||||
write_register(PCF8523_CLKOUTCONTROL, 0);
|
||||
write_register(PCF8523_TIMER_B_FRCTL, 0);
|
||||
write_register(PCF8523_TIMER_B_VALUE, 0);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Compensate the drift of the RTC.
|
||||
@details This method sets the "offset" register of the PCF8523,
|
||||
which can be used to correct a previously measured drift rate.
|
||||
Two correction modes are available:
|
||||
|
||||
- **PCF8523\_TwoHours**: Clock adjustments are performed on
|
||||
`offset` consecutive minutes every two hours. This is the most
|
||||
energy-efficient mode.
|
||||
|
||||
- **PCF8523\_OneMinute**: Clock adjustments are performed on
|
||||
`offset` consecutive seconds every minute. Extra adjustments are
|
||||
performed on the last second of the minute is `abs(offset)>60`.
|
||||
|
||||
The `offset` parameter sets the correction amount in units of
|
||||
roughly 4 ppm. The exact unit depends on the selected mode:
|
||||
|
||||
| mode | offset unit |
|
||||
|---------------------|----------------------------------------|
|
||||
| `PCF8523_TwoHours` | 4.340 ppm = 0.375 s/day = 2.625 s/week |
|
||||
| `PCF8523_OneMinute` | 4.069 ppm = 0.352 s/day = 2.461 s/week |
|
||||
|
||||
See the accompanying sketch pcf8523.ino for an example on how to
|
||||
use this method.
|
||||
|
||||
@param mode Correction mode, either `PCF8523_TwoHours` or
|
||||
`PCF8523_OneMinute`.
|
||||
@param offset Correction amount, from -64 to +63. A positive offset
|
||||
makes the clock slower.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8523::calibrate(Pcf8523OffsetMode mode, int8_t offset) {
|
||||
write_register(PCF8523_OFFSET, ((uint8_t)offset & 0x7F) | mode);
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
#include "RTClib.h"
|
||||
|
||||
#define PCF8563_ADDRESS 0x51 ///< I2C address for PCF8563
|
||||
#define PCF8563_CLKOUTCONTROL 0x0D ///< CLKOUT control register
|
||||
#define PCF8563_CONTROL_1 0x00 ///< Control and status register 1
|
||||
#define PCF8563_CONTROL_2 0x01 ///< Control and status register 2
|
||||
#define PCF8563_VL_SECONDS 0x02 ///< register address for VL_SECONDS
|
||||
#define PCF8563_CLKOUT_MASK 0x83 ///< bitmask for SqwPinMode on CLKOUT pin
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Start I2C for the PCF8563 and test succesful connection
|
||||
@param wireInstance pointer to the I2C bus
|
||||
@return True if Wire can find PCF8563 or false otherwise.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_PCF8563::begin(TwoWire *wireInstance) {
|
||||
if (i2c_dev)
|
||||
delete i2c_dev;
|
||||
i2c_dev = new Adafruit_I2CDevice(PCF8563_ADDRESS, wireInstance);
|
||||
if (!i2c_dev->begin())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check the status of the VL bit in the VL_SECONDS register.
|
||||
@details The PCF8563 has an on-chip voltage-low detector. When VDD drops
|
||||
below Vlow, bit VL in the VL_seconds register is set to indicate that
|
||||
the integrity of the clock information is no longer guaranteed.
|
||||
@return True if the bit is set (VDD droped below Vlow) indicating that
|
||||
the clock integrity is not guaranteed and false only after the bit is
|
||||
cleared using adjust()
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool RTC_PCF8563::lostPower(void) {
|
||||
return read_register(PCF8563_VL_SECONDS) >> 7;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the date and time
|
||||
@param dt DateTime to set
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8563::adjust(const DateTime &dt) {
|
||||
uint8_t buffer[8] = {PCF8563_VL_SECONDS, // start at location 2, VL_SECONDS
|
||||
bin2bcd(dt.second()), bin2bcd(dt.minute()),
|
||||
bin2bcd(dt.hour()), bin2bcd(dt.day()),
|
||||
bin2bcd(0), // skip weekdays
|
||||
bin2bcd(dt.month()), bin2bcd(dt.year() - 2000U)};
|
||||
i2c_dev->write(buffer, 8);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Get the current date/time
|
||||
@return DateTime object containing the current date/time
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime RTC_PCF8563::now() {
|
||||
uint8_t buffer[7];
|
||||
buffer[0] = PCF8563_VL_SECONDS; // start at location 2, VL_SECONDS
|
||||
i2c_dev->write_then_read(buffer, 1, buffer, 7);
|
||||
|
||||
return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5] & 0x1F),
|
||||
bcd2bin(buffer[3] & 0x3F), bcd2bin(buffer[2] & 0x3F),
|
||||
bcd2bin(buffer[1] & 0x7F), bcd2bin(buffer[0] & 0x7F));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Resets the STOP bit in register Control_1
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8563::start(void) {
|
||||
uint8_t ctlreg = read_register(PCF8563_CONTROL_1);
|
||||
if (ctlreg & (1 << 5))
|
||||
write_register(PCF8563_CONTROL_1, ctlreg & ~(1 << 5));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the STOP bit in register Control_1
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8563::stop(void) {
|
||||
uint8_t ctlreg = read_register(PCF8563_CONTROL_1);
|
||||
if (!(ctlreg & (1 << 5)))
|
||||
write_register(PCF8563_CONTROL_1, ctlreg | (1 << 5));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Is the PCF8563 running? Check the STOP bit in register Control_1
|
||||
@return 1 if the RTC is running, 0 if not
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t RTC_PCF8563::isrunning() {
|
||||
return !((read_register(PCF8563_CONTROL_1) >> 5) & 1);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read the mode of the CLKOUT pin on the PCF8563
|
||||
@return CLKOUT pin mode as a #Pcf8563SqwPinMode enum
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Pcf8563SqwPinMode RTC_PCF8563::readSqwPinMode() {
|
||||
int mode = read_register(PCF8563_CLKOUTCONTROL);
|
||||
return static_cast<Pcf8563SqwPinMode>(mode & PCF8563_CLKOUT_MASK);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set the CLKOUT pin mode on the PCF8563
|
||||
@param mode The mode to set, see the #Pcf8563SqwPinMode enum for options
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_PCF8563::writeSqwPinMode(Pcf8563SqwPinMode mode) {
|
||||
write_register(PCF8563_CLKOUTCONTROL, mode);
|
||||
}
|
|
@ -0,0 +1,764 @@
|
|||
/**************************************************************************/
|
||||
/*!
|
||||
@file RTClib.cpp
|
||||
|
||||
@mainpage Adafruit RTClib
|
||||
|
||||
@section intro Introduction
|
||||
|
||||
This is a fork of JeeLab's fantastic real time clock library for Arduino.
|
||||
|
||||
For details on using this library with an RTC module like the DS1307, PCF8523,
|
||||
or DS3231, see the guide at:
|
||||
https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
@section classes Available classes
|
||||
|
||||
This library provides the following classes:
|
||||
|
||||
- Classes for manipulating dates, times and durations:
|
||||
- DateTime represents a specific point in time; this is the data
|
||||
type used for setting and reading the supported RTCs
|
||||
- TimeSpan represents the length of a time interval
|
||||
- Interfacing specific RTC chips:
|
||||
- RTC_DS1307
|
||||
- RTC_DS3231
|
||||
- RTC_PCF8523
|
||||
- RTC_PCF8563
|
||||
- RTC emulated in software; do not expect much accuracy out of these:
|
||||
- RTC_Millis is based on `millis()`
|
||||
- RTC_Micros is based on `micros()`; its drift rate can be tuned by
|
||||
the user
|
||||
|
||||
@section license License
|
||||
|
||||
Original library by JeeLabs https://jeelabs.org/pub/docs/rtclib/, released to
|
||||
the public domain.
|
||||
|
||||
This version: MIT (see LICENSE)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include "RTClib.h"
|
||||
|
||||
#ifdef __AVR__
|
||||
#include <avr/pgmspace.h>
|
||||
#elif defined(ESP8266)
|
||||
#include <pgmspace.h>
|
||||
#elif defined(ARDUINO_ARCH_SAMD)
|
||||
// nothing special needed
|
||||
#elif defined(ARDUINO_SAM_DUE)
|
||||
#define PROGMEM
|
||||
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
|
||||
#endif
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Write value to register.
|
||||
@param reg register address
|
||||
@param val value to write
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void RTC_I2C::write_register(uint8_t reg, uint8_t val) {
|
||||
uint8_t buffer[2] = {reg, val};
|
||||
i2c_dev->write(buffer, 2);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read value from register.
|
||||
@param reg register address
|
||||
@return value of register
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t RTC_I2C::read_register(uint8_t reg) {
|
||||
uint8_t buffer[1];
|
||||
i2c_dev->write(®, 1);
|
||||
i2c_dev->read(buffer, 1);
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
// utility code, some of this could be exposed in the DateTime API if needed
|
||||
/**************************************************************************/
|
||||
|
||||
/**
|
||||
Number of days in each month, from January to November. December is not
|
||||
needed. Omitting it avoids an incompatibility with Paul Stoffregen's Time
|
||||
library. C.f. https://github.com/adafruit/RTClib/issues/114
|
||||
*/
|
||||
const uint8_t daysInMonth[] PROGMEM = {31, 28, 31, 30, 31, 30,
|
||||
31, 31, 30, 31, 30};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Given a date, return number of days since 2000/01/01,
|
||||
valid for 2000--2099
|
||||
@param y Year
|
||||
@param m Month
|
||||
@param d Day
|
||||
@return Number of days
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) {
|
||||
if (y >= 2000U)
|
||||
y -= 2000U;
|
||||
uint16_t days = d;
|
||||
for (uint8_t i = 1; i < m; ++i)
|
||||
days += pgm_read_byte(daysInMonth + i - 1);
|
||||
if (m > 2 && y % 4 == 0)
|
||||
++days;
|
||||
return days + 365 * y + (y + 3) / 4 - 1;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Given a number of days, hours, minutes, and seconds, return the
|
||||
total seconds
|
||||
@param days Days
|
||||
@param h Hours
|
||||
@param m Minutes
|
||||
@param s Seconds
|
||||
@return Number of seconds total
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static uint32_t time2ulong(uint16_t days, uint8_t h, uint8_t m, uint8_t s) {
|
||||
return ((days * 24UL + h) * 60 + m) * 60 + s;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Constructor from
|
||||
[Unix time](https://en.wikipedia.org/wiki/Unix_time).
|
||||
|
||||
This builds a DateTime from an integer specifying the number of seconds
|
||||
elapsed since the epoch: 1970-01-01 00:00:00. This number is analogous
|
||||
to Unix time, with two small differences:
|
||||
|
||||
- The Unix epoch is specified to be at 00:00:00
|
||||
[UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time),
|
||||
whereas this class has no notion of time zones. The epoch used in
|
||||
this class is then at 00:00:00 on whatever time zone the user chooses
|
||||
to use, ignoring changes in DST.
|
||||
|
||||
- Unix time is conventionally represented with signed numbers, whereas
|
||||
this constructor takes an unsigned argument. Because of this, it does
|
||||
_not_ suffer from the
|
||||
[year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem).
|
||||
|
||||
If called without argument, it returns the earliest time representable
|
||||
by this class: 2000-01-01 00:00:00.
|
||||
|
||||
@see The `unixtime()` method is the converse of this constructor.
|
||||
|
||||
@param t Time elapsed in seconds since 1970-01-01 00:00:00.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime::DateTime(uint32_t t) {
|
||||
t -= SECONDS_FROM_1970_TO_2000; // bring to 2000 timestamp from 1970
|
||||
|
||||
ss = t % 60;
|
||||
t /= 60;
|
||||
mm = t % 60;
|
||||
t /= 60;
|
||||
hh = t % 24;
|
||||
uint16_t days = t / 24;
|
||||
uint8_t leap;
|
||||
for (yOff = 0;; ++yOff) {
|
||||
leap = yOff % 4 == 0;
|
||||
if (days < 365U + leap)
|
||||
break;
|
||||
days -= 365 + leap;
|
||||
}
|
||||
for (m = 1; m < 12; ++m) {
|
||||
uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1);
|
||||
if (leap && m == 2)
|
||||
++daysPerMonth;
|
||||
if (days < daysPerMonth)
|
||||
break;
|
||||
days -= daysPerMonth;
|
||||
}
|
||||
d = days + 1;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Constructor from (year, month, day, hour, minute, second).
|
||||
@warning If the provided parameters are not valid (e.g. 31 February),
|
||||
the constructed DateTime will be invalid.
|
||||
@see The `isValid()` method can be used to test whether the
|
||||
constructed DateTime is valid.
|
||||
@param year Either the full year (range: 2000--2099) or the offset from
|
||||
year 2000 (range: 0--99).
|
||||
@param month Month number (1--12).
|
||||
@param day Day of the month (1--31).
|
||||
@param hour,min,sec Hour (0--23), minute (0--59) and second (0--59).
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime::DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour,
|
||||
uint8_t min, uint8_t sec) {
|
||||
if (year >= 2000U)
|
||||
year -= 2000U;
|
||||
yOff = year;
|
||||
m = month;
|
||||
d = day;
|
||||
hh = hour;
|
||||
mm = min;
|
||||
ss = sec;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Copy constructor.
|
||||
@param copy DateTime to copy.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime::DateTime(const DateTime ©)
|
||||
: yOff(copy.yOff), m(copy.m), d(copy.d), hh(copy.hh), mm(copy.mm),
|
||||
ss(copy.ss) {}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Convert a string containing two digits to uint8_t, e.g. "09" returns
|
||||
9
|
||||
@param p Pointer to a string containing two digits
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static uint8_t conv2d(const char *p) {
|
||||
uint8_t v = 0;
|
||||
if ('0' <= *p && *p <= '9')
|
||||
v = *p - '0';
|
||||
return 10 * v + *++p - '0';
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Constructor for generating the build time.
|
||||
|
||||
This constructor expects its parameters to be strings in the format
|
||||
generated by the compiler's preprocessor macros `__DATE__` and
|
||||
`__TIME__`. Usage:
|
||||
|
||||
```
|
||||
DateTime buildTime(__DATE__, __TIME__);
|
||||
```
|
||||
|
||||
@note The `F()` macro can be used to reduce the RAM footprint, see
|
||||
the next constructor.
|
||||
|
||||
@param date Date string, e.g. "Apr 16 2020".
|
||||
@param time Time string, e.g. "18:34:56".
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime::DateTime(const char *date, const char *time) {
|
||||
yOff = conv2d(date + 9);
|
||||
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
|
||||
switch (date[0]) {
|
||||
case 'J':
|
||||
m = (date[1] == 'a') ? 1 : ((date[2] == 'n') ? 6 : 7);
|
||||
break;
|
||||
case 'F':
|
||||
m = 2;
|
||||
break;
|
||||
case 'A':
|
||||
m = date[2] == 'r' ? 4 : 8;
|
||||
break;
|
||||
case 'M':
|
||||
m = date[2] == 'r' ? 3 : 5;
|
||||
break;
|
||||
case 'S':
|
||||
m = 9;
|
||||
break;
|
||||
case 'O':
|
||||
m = 10;
|
||||
break;
|
||||
case 'N':
|
||||
m = 11;
|
||||
break;
|
||||
case 'D':
|
||||
m = 12;
|
||||
break;
|
||||
}
|
||||
d = conv2d(date + 4);
|
||||
hh = conv2d(time);
|
||||
mm = conv2d(time + 3);
|
||||
ss = conv2d(time + 6);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Memory friendly constructor for generating the build time.
|
||||
|
||||
This version is intended to save RAM by keeping the date and time
|
||||
strings in program memory. Use it with the `F()` macro:
|
||||
|
||||
```
|
||||
DateTime buildTime(F(__DATE__), F(__TIME__));
|
||||
```
|
||||
|
||||
@param date Date PROGMEM string, e.g. F("Apr 16 2020").
|
||||
@param time Time PROGMEM string, e.g. F("18:34:56").
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime::DateTime(const __FlashStringHelper *date,
|
||||
const __FlashStringHelper *time) {
|
||||
char buff[11];
|
||||
memcpy_P(buff, date, 11);
|
||||
yOff = conv2d(buff + 9);
|
||||
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
|
||||
switch (buff[0]) {
|
||||
case 'J':
|
||||
m = (buff[1] == 'a') ? 1 : ((buff[2] == 'n') ? 6 : 7);
|
||||
break;
|
||||
case 'F':
|
||||
m = 2;
|
||||
break;
|
||||
case 'A':
|
||||
m = buff[2] == 'r' ? 4 : 8;
|
||||
break;
|
||||
case 'M':
|
||||
m = buff[2] == 'r' ? 3 : 5;
|
||||
break;
|
||||
case 'S':
|
||||
m = 9;
|
||||
break;
|
||||
case 'O':
|
||||
m = 10;
|
||||
break;
|
||||
case 'N':
|
||||
m = 11;
|
||||
break;
|
||||
case 'D':
|
||||
m = 12;
|
||||
break;
|
||||
}
|
||||
d = conv2d(buff + 4);
|
||||
memcpy_P(buff, time, 8);
|
||||
hh = conv2d(buff);
|
||||
mm = conv2d(buff + 3);
|
||||
ss = conv2d(buff + 6);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Constructor for creating a DateTime from an ISO8601 date string.
|
||||
|
||||
This constructor expects its parameters to be a string in the
|
||||
https://en.wikipedia.org/wiki/ISO_8601 format, e.g:
|
||||
|
||||
"2020-06-25T15:29:37"
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
DateTime dt("2020-06-25T15:29:37");
|
||||
```
|
||||
|
||||
@note The year must be > 2000, as only the yOff is considered.
|
||||
|
||||
@param iso8601dateTime
|
||||
A dateTime string in iso8601 format,
|
||||
e.g. "2020-06-25T15:29:37".
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime::DateTime(const char *iso8601dateTime) {
|
||||
char ref[] = "2000-01-01T00:00:00";
|
||||
memcpy(ref, iso8601dateTime, min(strlen(ref), strlen(iso8601dateTime)));
|
||||
yOff = conv2d(ref + 2);
|
||||
m = conv2d(ref + 5);
|
||||
d = conv2d(ref + 8);
|
||||
hh = conv2d(ref + 11);
|
||||
mm = conv2d(ref + 14);
|
||||
ss = conv2d(ref + 17);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check whether this DateTime is valid.
|
||||
@return true if valid, false if not.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool DateTime::isValid() const {
|
||||
if (yOff >= 100)
|
||||
return false;
|
||||
DateTime other(unixtime());
|
||||
return yOff == other.yOff && m == other.m && d == other.d && hh == other.hh &&
|
||||
mm == other.mm && ss == other.ss;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Writes the DateTime as a string in a user-defined format.
|
||||
|
||||
The _buffer_ parameter should be initialized by the caller with a string
|
||||
specifying the requested format. This format string may contain any of
|
||||
the following specifiers:
|
||||
|
||||
| specifier | output |
|
||||
|-----------|--------------------------------------------------------|
|
||||
| YYYY | the year as a 4-digit number (2000--2099) |
|
||||
| YY | the year as a 2-digit number (00--99) |
|
||||
| MM | the month as a 2-digit number (01--12) |
|
||||
| MMM | the abbreviated English month name ("Jan"--"Dec") |
|
||||
| DD | the day as a 2-digit number (01--31) |
|
||||
| DDD | the abbreviated English day of the week ("Mon"--"Sun") |
|
||||
| AP | either "AM" or "PM" |
|
||||
| ap | either "am" or "pm" |
|
||||
| hh | the hour as a 2-digit number (00--23 or 01--12) |
|
||||
| mm | the minute as a 2-digit number (00--59) |
|
||||
| ss | the second as a 2-digit number (00--59) |
|
||||
|
||||
If either "AP" or "ap" is used, the "hh" specifier uses 12-hour mode
|
||||
(range: 01--12). Otherwise it works in 24-hour mode (range: 00--23).
|
||||
|
||||
The specifiers within _buffer_ will be overwritten with the appropriate
|
||||
values from the DateTime. Any characters not belonging to one of the
|
||||
above specifiers are left as-is.
|
||||
|
||||
__Example__: The format "DDD, DD MMM YYYY hh:mm:ss" generates an output
|
||||
of the form "Thu, 16 Apr 2020 18:34:56.
|
||||
|
||||
@see The `timestamp()` method provides similar functionnality, but it
|
||||
returns a `String` object and supports a limited choice of
|
||||
predefined formats.
|
||||
|
||||
@param[in,out] buffer Array of `char` for holding the format description
|
||||
and the formatted DateTime. Before calling this method, the buffer
|
||||
should be initialized by the user with the format string. The method
|
||||
will overwrite the buffer with the formatted date and/or time.
|
||||
|
||||
@return A pointer to the provided buffer. This is returned for
|
||||
convenience, in order to enable idioms such as
|
||||
`Serial.println(now.toString(buffer));`
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
char *DateTime::toString(char *buffer) const {
|
||||
uint8_t apTag =
|
||||
(strstr(buffer, "ap") != nullptr) || (strstr(buffer, "AP") != nullptr);
|
||||
uint8_t hourReformatted = 0, isPM = false;
|
||||
if (apTag) { // 12 Hour Mode
|
||||
if (hh == 0) { // midnight
|
||||
isPM = false;
|
||||
hourReformatted = 12;
|
||||
} else if (hh == 12) { // noon
|
||||
isPM = true;
|
||||
hourReformatted = 12;
|
||||
} else if (hh < 12) { // morning
|
||||
isPM = false;
|
||||
hourReformatted = hh;
|
||||
} else { // 1 o'clock or after
|
||||
isPM = true;
|
||||
hourReformatted = hh - 12;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < strlen(buffer) - 1; i++) {
|
||||
if (buffer[i] == 'h' && buffer[i + 1] == 'h') {
|
||||
if (!apTag) { // 24 Hour Mode
|
||||
buffer[i] = '0' + hh / 10;
|
||||
buffer[i + 1] = '0' + hh % 10;
|
||||
} else { // 12 Hour Mode
|
||||
buffer[i] = '0' + hourReformatted / 10;
|
||||
buffer[i + 1] = '0' + hourReformatted % 10;
|
||||
}
|
||||
}
|
||||
if (buffer[i] == 'm' && buffer[i + 1] == 'm') {
|
||||
buffer[i] = '0' + mm / 10;
|
||||
buffer[i + 1] = '0' + mm % 10;
|
||||
}
|
||||
if (buffer[i] == 's' && buffer[i + 1] == 's') {
|
||||
buffer[i] = '0' + ss / 10;
|
||||
buffer[i + 1] = '0' + ss % 10;
|
||||
}
|
||||
if (buffer[i] == 'D' && buffer[i + 1] == 'D' && buffer[i + 2] == 'D') {
|
||||
static PROGMEM const char day_names[] = "SunMonTueWedThuFriSat";
|
||||
const char *p = &day_names[3 * dayOfTheWeek()];
|
||||
buffer[i] = pgm_read_byte(p);
|
||||
buffer[i + 1] = pgm_read_byte(p + 1);
|
||||
buffer[i + 2] = pgm_read_byte(p + 2);
|
||||
} else if (buffer[i] == 'D' && buffer[i + 1] == 'D') {
|
||||
buffer[i] = '0' + d / 10;
|
||||
buffer[i + 1] = '0' + d % 10;
|
||||
}
|
||||
if (buffer[i] == 'M' && buffer[i + 1] == 'M' && buffer[i + 2] == 'M') {
|
||||
static PROGMEM const char month_names[] =
|
||||
"JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
const char *p = &month_names[3 * (m - 1)];
|
||||
buffer[i] = pgm_read_byte(p);
|
||||
buffer[i + 1] = pgm_read_byte(p + 1);
|
||||
buffer[i + 2] = pgm_read_byte(p + 2);
|
||||
} else if (buffer[i] == 'M' && buffer[i + 1] == 'M') {
|
||||
buffer[i] = '0' + m / 10;
|
||||
buffer[i + 1] = '0' + m % 10;
|
||||
}
|
||||
if (buffer[i] == 'Y' && buffer[i + 1] == 'Y' && buffer[i + 2] == 'Y' &&
|
||||
buffer[i + 3] == 'Y') {
|
||||
buffer[i] = '2';
|
||||
buffer[i + 1] = '0';
|
||||
buffer[i + 2] = '0' + (yOff / 10) % 10;
|
||||
buffer[i + 3] = '0' + yOff % 10;
|
||||
} else if (buffer[i] == 'Y' && buffer[i + 1] == 'Y') {
|
||||
buffer[i] = '0' + (yOff / 10) % 10;
|
||||
buffer[i + 1] = '0' + yOff % 10;
|
||||
}
|
||||
if (buffer[i] == 'A' && buffer[i + 1] == 'P') {
|
||||
if (isPM) {
|
||||
buffer[i] = 'P';
|
||||
buffer[i + 1] = 'M';
|
||||
} else {
|
||||
buffer[i] = 'A';
|
||||
buffer[i + 1] = 'M';
|
||||
}
|
||||
} else if (buffer[i] == 'a' && buffer[i + 1] == 'p') {
|
||||
if (isPM) {
|
||||
buffer[i] = 'p';
|
||||
buffer[i + 1] = 'm';
|
||||
} else {
|
||||
buffer[i] = 'a';
|
||||
buffer[i + 1] = 'm';
|
||||
}
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Return the hour in 12-hour format.
|
||||
@return Hour (1--12).
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t DateTime::twelveHour() const {
|
||||
if (hh == 0 || hh == 12) { // midnight or noon
|
||||
return 12;
|
||||
} else if (hh > 12) { // 1 o'clock or later
|
||||
return hh - 12;
|
||||
} else { // morning
|
||||
return hh;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Return the day of the week.
|
||||
@return Day of week as an integer from 0 (Sunday) to 6 (Saturday).
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t DateTime::dayOfTheWeek() const {
|
||||
uint16_t day = date2days(yOff, m, d);
|
||||
return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Return Unix time: seconds since 1 Jan 1970.
|
||||
|
||||
@see The `DateTime::DateTime(uint32_t)` constructor is the converse of
|
||||
this method.
|
||||
|
||||
@return Number of seconds since 1970-01-01 00:00:00.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint32_t DateTime::unixtime(void) const {
|
||||
uint32_t t;
|
||||
uint16_t days = date2days(yOff, m, d);
|
||||
t = time2ulong(days, hh, mm, ss);
|
||||
t += SECONDS_FROM_1970_TO_2000; // seconds from 1970 to 2000
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Convert the DateTime to seconds since 1 Jan 2000
|
||||
|
||||
The result can be converted back to a DateTime with:
|
||||
|
||||
```cpp
|
||||
DateTime(SECONDS_FROM_1970_TO_2000 + value)
|
||||
```
|
||||
|
||||
@return Number of seconds since 2000-01-01 00:00:00.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint32_t DateTime::secondstime(void) const {
|
||||
uint32_t t;
|
||||
uint16_t days = date2days(yOff, m, d);
|
||||
t = time2ulong(days, hh, mm, ss);
|
||||
return t;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Add a TimeSpan to the DateTime object
|
||||
@param span TimeSpan object
|
||||
@return New DateTime object with span added to it.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime DateTime::operator+(const TimeSpan &span) const {
|
||||
return DateTime(unixtime() + span.totalseconds());
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Subtract a TimeSpan from the DateTime object
|
||||
@param span TimeSpan object
|
||||
@return New DateTime object with span subtracted from it.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
DateTime DateTime::operator-(const TimeSpan &span) const {
|
||||
return DateTime(unixtime() - span.totalseconds());
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Subtract one DateTime from another
|
||||
|
||||
@note Since a TimeSpan cannot be negative, the subtracted DateTime
|
||||
should be less (earlier) than or equal to the one it is
|
||||
subtracted from.
|
||||
|
||||
@param right The DateTime object to subtract from self (the left object)
|
||||
@return TimeSpan of the difference between DateTimes.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
TimeSpan DateTime::operator-(const DateTime &right) const {
|
||||
return TimeSpan(unixtime() - right.unixtime());
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@author Anton Rieutskyi
|
||||
@brief Test if one DateTime is less (earlier) than another.
|
||||
@warning if one or both DateTime objects are invalid, returned value is
|
||||
meaningless
|
||||
@see use `isValid()` method to check if DateTime object is valid
|
||||
@param right Comparison DateTime object
|
||||
@return True if the left DateTime is earlier than the right one,
|
||||
false otherwise.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool DateTime::operator<(const DateTime &right) const {
|
||||
return (yOff + 2000U < right.year() ||
|
||||
(yOff + 2000U == right.year() &&
|
||||
(m < right.month() ||
|
||||
(m == right.month() &&
|
||||
(d < right.day() ||
|
||||
(d == right.day() &&
|
||||
(hh < right.hour() ||
|
||||
(hh == right.hour() &&
|
||||
(mm < right.minute() ||
|
||||
(mm == right.minute() && ss < right.second()))))))))));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@author Anton Rieutskyi
|
||||
@brief Test if two DateTime objects are equal.
|
||||
@warning if one or both DateTime objects are invalid, returned value is
|
||||
meaningless
|
||||
@see use `isValid()` method to check if DateTime object is valid
|
||||
@param right Comparison DateTime object
|
||||
@return True if both DateTime objects are the same, false otherwise.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool DateTime::operator==(const DateTime &right) const {
|
||||
return (right.year() == yOff + 2000U && right.month() == m &&
|
||||
right.day() == d && right.hour() == hh && right.minute() == mm &&
|
||||
right.second() == ss);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Return a ISO 8601 timestamp as a `String` object.
|
||||
|
||||
The generated timestamp conforms to one of the predefined, ISO
|
||||
8601-compatible formats for representing the date (if _opt_ is
|
||||
`TIMESTAMP_DATE`), the time (`TIMESTAMP_TIME`), or both
|
||||
(`TIMESTAMP_FULL`).
|
||||
|
||||
@see The `toString()` method provides more general string formatting.
|
||||
|
||||
@param opt Format of the timestamp
|
||||
@return Timestamp string, e.g. "2020-04-16T18:34:56".
|
||||
*/
|
||||
/**************************************************************************/
|
||||
String DateTime::timestamp(timestampOpt opt) const {
|
||||
char buffer[25]; // large enough for any DateTime, including invalid ones
|
||||
|
||||
// Generate timestamp according to opt
|
||||
switch (opt) {
|
||||
case TIMESTAMP_TIME:
|
||||
// Only time
|
||||
sprintf(buffer, "%02d:%02d:%02d", hh, mm, ss);
|
||||
break;
|
||||
case TIMESTAMP_DATE:
|
||||
// Only date
|
||||
sprintf(buffer, "%u-%02d-%02d", 2000U + yOff, m, d);
|
||||
break;
|
||||
default:
|
||||
// Full
|
||||
sprintf(buffer, "%u-%02d-%02dT%02d:%02d:%02d", 2000U + yOff, m, d, hh, mm,
|
||||
ss);
|
||||
}
|
||||
return String(buffer);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Create a new TimeSpan object in seconds
|
||||
@param seconds Number of seconds
|
||||
*/
|
||||
/**************************************************************************/
|
||||
TimeSpan::TimeSpan(int32_t seconds) : _seconds(seconds) {}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Create a new TimeSpan object using a number of
|
||||
days/hours/minutes/seconds e.g. Make a TimeSpan of 3 hours and 45 minutes:
|
||||
new TimeSpan(0, 3, 45, 0);
|
||||
@param days Number of days
|
||||
@param hours Number of hours
|
||||
@param minutes Number of minutes
|
||||
@param seconds Number of seconds
|
||||
*/
|
||||
/**************************************************************************/
|
||||
TimeSpan::TimeSpan(int16_t days, int8_t hours, int8_t minutes, int8_t seconds)
|
||||
: _seconds((int32_t)days * 86400L + (int32_t)hours * 3600 +
|
||||
(int32_t)minutes * 60 + seconds) {}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Copy constructor, make a new TimeSpan using an existing one
|
||||
@param copy The TimeSpan to copy
|
||||
*/
|
||||
/**************************************************************************/
|
||||
TimeSpan::TimeSpan(const TimeSpan ©) : _seconds(copy._seconds) {}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Add two TimeSpans
|
||||
@param right TimeSpan to add
|
||||
@return New TimeSpan object, sum of left and right
|
||||
*/
|
||||
/**************************************************************************/
|
||||
TimeSpan TimeSpan::operator+(const TimeSpan &right) const {
|
||||
return TimeSpan(_seconds + right._seconds);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Subtract a TimeSpan
|
||||
@param right TimeSpan to subtract
|
||||
@return New TimeSpan object, right subtracted from left
|
||||
*/
|
||||
/**************************************************************************/
|
||||
TimeSpan TimeSpan::operator-(const TimeSpan &right) const {
|
||||
return TimeSpan(_seconds - right._seconds);
|
||||
}
|
|
@ -0,0 +1,519 @@
|
|||
/**************************************************************************/
|
||||
/*!
|
||||
@file RTClib.h
|
||||
|
||||
Original library by JeeLabs http://news.jeelabs.org/code/, released to the
|
||||
public domain
|
||||
|
||||
License: MIT (see LICENSE)
|
||||
|
||||
This is a fork of JeeLab's fantastic real time clock library for Arduino.
|
||||
|
||||
For details on using this library with an RTC module like the DS1307, PCF8523,
|
||||
or DS3231, see the guide at:
|
||||
https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef _RTCLIB_H_
|
||||
#define _RTCLIB_H_
|
||||
|
||||
#include <Adafruit_I2CDevice.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
class TimeSpan;
|
||||
|
||||
/** Constants */
|
||||
#define SECONDS_PER_DAY 86400L ///< 60 * 60 * 24
|
||||
#define SECONDS_FROM_1970_TO_2000 \
|
||||
946684800 ///< Unixtime for 2000-01-01 00:00:00, useful for initialization
|
||||
|
||||
/** DS1307 SQW pin mode settings */
|
||||
enum Ds1307SqwPinMode {
|
||||
DS1307_OFF = 0x00, // Low
|
||||
DS1307_ON = 0x80, // High
|
||||
DS1307_SquareWave1HZ = 0x10, // 1Hz square wave
|
||||
DS1307_SquareWave4kHz = 0x11, // 4kHz square wave
|
||||
DS1307_SquareWave8kHz = 0x12, // 8kHz square wave
|
||||
DS1307_SquareWave32kHz = 0x13 // 32kHz square wave
|
||||
};
|
||||
|
||||
/** DS3231 SQW pin mode settings */
|
||||
enum Ds3231SqwPinMode {
|
||||
DS3231_OFF = 0x1C, /**< Off */
|
||||
DS3231_SquareWave1Hz = 0x00, /**< 1Hz square wave */
|
||||
DS3231_SquareWave1kHz = 0x08, /**< 1kHz square wave */
|
||||
DS3231_SquareWave4kHz = 0x10, /**< 4kHz square wave */
|
||||
DS3231_SquareWave8kHz = 0x18 /**< 8kHz square wave */
|
||||
};
|
||||
|
||||
/** DS3231 Alarm modes for alarm 1 */
|
||||
enum Ds3231Alarm1Mode {
|
||||
DS3231_A1_PerSecond = 0x0F, /**< Alarm once per second */
|
||||
DS3231_A1_Second = 0x0E, /**< Alarm when seconds match */
|
||||
DS3231_A1_Minute = 0x0C, /**< Alarm when minutes and seconds match */
|
||||
DS3231_A1_Hour = 0x08, /**< Alarm when hours, minutes
|
||||
and seconds match */
|
||||
DS3231_A1_Date = 0x00, /**< Alarm when date (day of month), hours,
|
||||
minutes and seconds match */
|
||||
DS3231_A1_Day = 0x10 /**< Alarm when day (day of week), hours,
|
||||
minutes and seconds match */
|
||||
};
|
||||
/** DS3231 Alarm modes for alarm 2 */
|
||||
enum Ds3231Alarm2Mode {
|
||||
DS3231_A2_PerMinute = 0x7, /**< Alarm once per minute
|
||||
(whenever seconds are 0) */
|
||||
DS3231_A2_Minute = 0x6, /**< Alarm when minutes match */
|
||||
DS3231_A2_Hour = 0x4, /**< Alarm when hours and minutes match */
|
||||
DS3231_A2_Date = 0x0, /**< Alarm when date (day of month), hours
|
||||
and minutes match */
|
||||
DS3231_A2_Day = 0x8 /**< Alarm when day (day of week), hours
|
||||
and minutes match */
|
||||
};
|
||||
/** PCF8523 INT/SQW pin mode settings */
|
||||
enum Pcf8523SqwPinMode {
|
||||
PCF8523_OFF = 7, /**< Off */
|
||||
PCF8523_SquareWave1HZ = 6, /**< 1Hz square wave */
|
||||
PCF8523_SquareWave32HZ = 5, /**< 32Hz square wave */
|
||||
PCF8523_SquareWave1kHz = 4, /**< 1kHz square wave */
|
||||
PCF8523_SquareWave4kHz = 3, /**< 4kHz square wave */
|
||||
PCF8523_SquareWave8kHz = 2, /**< 8kHz square wave */
|
||||
PCF8523_SquareWave16kHz = 1, /**< 16kHz square wave */
|
||||
PCF8523_SquareWave32kHz = 0 /**< 32kHz square wave */
|
||||
};
|
||||
|
||||
/** PCF8523 Timer Source Clock Frequencies for Timers A and B */
|
||||
enum PCF8523TimerClockFreq {
|
||||
PCF8523_Frequency4kHz = 0, /**< 1/4096th second = 244 microseconds,
|
||||
max 62.256 milliseconds */
|
||||
PCF8523_Frequency64Hz = 1, /**< 1/64th second = 15.625 milliseconds,
|
||||
max 3.984375 seconds */
|
||||
PCF8523_FrequencySecond = 2, /**< 1 second, max 255 seconds = 4.25 minutes */
|
||||
PCF8523_FrequencyMinute = 3, /**< 1 minute, max 255 minutes = 4.25 hours */
|
||||
PCF8523_FrequencyHour = 4, /**< 1 hour, max 255 hours = 10.625 days */
|
||||
};
|
||||
|
||||
/** PCF8523 Timer Interrupt Low Pulse Width options for Timer B only */
|
||||
enum PCF8523TimerIntPulse {
|
||||
PCF8523_LowPulse3x64Hz = 0, /**< 46.875 ms 3/64ths second */
|
||||
PCF8523_LowPulse4x64Hz = 1, /**< 62.500 ms 4/64ths second */
|
||||
PCF8523_LowPulse5x64Hz = 2, /**< 78.125 ms 5/64ths second */
|
||||
PCF8523_LowPulse6x64Hz = 3, /**< 93.750 ms 6/64ths second */
|
||||
PCF8523_LowPulse8x64Hz = 4, /**< 125.000 ms 8/64ths second */
|
||||
PCF8523_LowPulse10x64Hz = 5, /**< 156.250 ms 10/64ths second */
|
||||
PCF8523_LowPulse12x64Hz = 6, /**< 187.500 ms 12/64ths second */
|
||||
PCF8523_LowPulse14x64Hz = 7 /**< 218.750 ms 14/64ths second */
|
||||
};
|
||||
|
||||
/** PCF8523 Offset modes for making temperature/aging/accuracy adjustments */
|
||||
enum Pcf8523OffsetMode {
|
||||
PCF8523_TwoHours = 0x00, /**< Offset made every two hours */
|
||||
PCF8523_OneMinute = 0x80 /**< Offset made every minute */
|
||||
};
|
||||
|
||||
/** PCF8563 CLKOUT pin mode settings */
|
||||
enum Pcf8563SqwPinMode {
|
||||
PCF8563_SquareWaveOFF = 0x00, /**< Off */
|
||||
PCF8563_SquareWave1Hz = 0x83, /**< 1Hz square wave */
|
||||
PCF8563_SquareWave32Hz = 0x82, /**< 32Hz square wave */
|
||||
PCF8563_SquareWave1kHz = 0x81, /**< 1kHz square wave */
|
||||
PCF8563_SquareWave32kHz = 0x80 /**< 32kHz square wave */
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Simple general-purpose date/time class (no TZ / DST / leap
|
||||
seconds).
|
||||
|
||||
This class stores date and time information in a broken-down form, as a
|
||||
tuple (year, month, day, hour, minute, second). The day of the week is
|
||||
not stored, but computed on request. The class has no notion of time
|
||||
zones, daylight saving time, or
|
||||
[leap seconds](http://en.wikipedia.org/wiki/Leap_second): time is stored
|
||||
in whatever time zone the user chooses to use.
|
||||
|
||||
The class supports dates in the range from 1 Jan 2000 to 31 Dec 2099
|
||||
inclusive.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class DateTime {
|
||||
public:
|
||||
DateTime(uint32_t t = SECONDS_FROM_1970_TO_2000);
|
||||
DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour = 0,
|
||||
uint8_t min = 0, uint8_t sec = 0);
|
||||
DateTime(const DateTime ©);
|
||||
DateTime(const char *date, const char *time);
|
||||
DateTime(const __FlashStringHelper *date, const __FlashStringHelper *time);
|
||||
DateTime(const char *iso8601date);
|
||||
bool isValid() const;
|
||||
char *toString(char *buffer) const;
|
||||
|
||||
/*!
|
||||
@brief Return the year.
|
||||
@return Year (range: 2000--2099).
|
||||
*/
|
||||
uint16_t year() const { return 2000U + yOff; }
|
||||
/*!
|
||||
@brief Return the month.
|
||||
@return Month number (1--12).
|
||||
*/
|
||||
uint8_t month() const { return m; }
|
||||
/*!
|
||||
@brief Return the day of the month.
|
||||
@return Day of the month (1--31).
|
||||
*/
|
||||
uint8_t day() const { return d; }
|
||||
/*!
|
||||
@brief Return the hour
|
||||
@return Hour (0--23).
|
||||
*/
|
||||
uint8_t hour() const { return hh; }
|
||||
|
||||
uint8_t twelveHour() const;
|
||||
/*!
|
||||
@brief Return whether the time is PM.
|
||||
@return 0 if the time is AM, 1 if it's PM.
|
||||
*/
|
||||
uint8_t isPM() const { return hh >= 12; }
|
||||
/*!
|
||||
@brief Return the minute.
|
||||
@return Minute (0--59).
|
||||
*/
|
||||
uint8_t minute() const { return mm; }
|
||||
/*!
|
||||
@brief Return the second.
|
||||
@return Second (0--59).
|
||||
*/
|
||||
uint8_t second() const { return ss; }
|
||||
|
||||
uint8_t dayOfTheWeek() const;
|
||||
|
||||
/* 32-bit times as seconds since 2000-01-01. */
|
||||
uint32_t secondstime() const;
|
||||
|
||||
/* 32-bit times as seconds since 1970-01-01. */
|
||||
uint32_t unixtime(void) const;
|
||||
|
||||
/*!
|
||||
Format of the ISO 8601 timestamp generated by `timestamp()`. Each
|
||||
option corresponds to a `toString()` format as follows:
|
||||
*/
|
||||
enum timestampOpt {
|
||||
TIMESTAMP_FULL, //!< `YYYY-MM-DDThh:mm:ss`
|
||||
TIMESTAMP_TIME, //!< `hh:mm:ss`
|
||||
TIMESTAMP_DATE //!< `YYYY-MM-DD`
|
||||
};
|
||||
String timestamp(timestampOpt opt = TIMESTAMP_FULL) const;
|
||||
|
||||
DateTime operator+(const TimeSpan &span) const;
|
||||
DateTime operator-(const TimeSpan &span) const;
|
||||
TimeSpan operator-(const DateTime &right) const;
|
||||
bool operator<(const DateTime &right) const;
|
||||
|
||||
/*!
|
||||
@brief Test if one DateTime is greater (later) than another.
|
||||
@warning if one or both DateTime objects are invalid, returned value is
|
||||
meaningless
|
||||
@see use `isValid()` method to check if DateTime object is valid
|
||||
@param right DateTime object to compare
|
||||
@return True if the left DateTime is later than the right one,
|
||||
false otherwise
|
||||
*/
|
||||
bool operator>(const DateTime &right) const { return right < *this; }
|
||||
|
||||
/*!
|
||||
@brief Test if one DateTime is less (earlier) than or equal to another
|
||||
@warning if one or both DateTime objects are invalid, returned value is
|
||||
meaningless
|
||||
@see use `isValid()` method to check if DateTime object is valid
|
||||
@param right DateTime object to compare
|
||||
@return True if the left DateTime is earlier than or equal to the
|
||||
right one, false otherwise
|
||||
*/
|
||||
bool operator<=(const DateTime &right) const { return !(*this > right); }
|
||||
|
||||
/*!
|
||||
@brief Test if one DateTime is greater (later) than or equal to another
|
||||
@warning if one or both DateTime objects are invalid, returned value is
|
||||
meaningless
|
||||
@see use `isValid()` method to check if DateTime object is valid
|
||||
@param right DateTime object to compare
|
||||
@return True if the left DateTime is later than or equal to the right
|
||||
one, false otherwise
|
||||
*/
|
||||
bool operator>=(const DateTime &right) const { return !(*this < right); }
|
||||
bool operator==(const DateTime &right) const;
|
||||
|
||||
/*!
|
||||
@brief Test if two DateTime objects are not equal.
|
||||
@warning if one or both DateTime objects are invalid, returned value is
|
||||
meaningless
|
||||
@see use `isValid()` method to check if DateTime object is valid
|
||||
@param right DateTime object to compare
|
||||
@return True if the two objects are not equal, false if they are
|
||||
*/
|
||||
bool operator!=(const DateTime &right) const { return !(*this == right); }
|
||||
|
||||
protected:
|
||||
uint8_t yOff; ///< Year offset from 2000
|
||||
uint8_t m; ///< Month 1-12
|
||||
uint8_t d; ///< Day 1-31
|
||||
uint8_t hh; ///< Hours 0-23
|
||||
uint8_t mm; ///< Minutes 0-59
|
||||
uint8_t ss; ///< Seconds 0-59
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Timespan which can represent changes in time with seconds accuracy.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class TimeSpan {
|
||||
public:
|
||||
TimeSpan(int32_t seconds = 0);
|
||||
TimeSpan(int16_t days, int8_t hours, int8_t minutes, int8_t seconds);
|
||||
TimeSpan(const TimeSpan ©);
|
||||
|
||||
/*!
|
||||
@brief Number of days in the TimeSpan
|
||||
e.g. 4
|
||||
@return int16_t days
|
||||
*/
|
||||
int16_t days() const { return _seconds / 86400L; }
|
||||
/*!
|
||||
@brief Number of hours in the TimeSpan
|
||||
This is not the total hours, it includes the days
|
||||
e.g. 4 days, 3 hours - NOT 99 hours
|
||||
@return int8_t hours
|
||||
*/
|
||||
int8_t hours() const { return _seconds / 3600 % 24; }
|
||||
/*!
|
||||
@brief Number of minutes in the TimeSpan
|
||||
This is not the total minutes, it includes days/hours
|
||||
e.g. 4 days, 3 hours, 27 minutes
|
||||
@return int8_t minutes
|
||||
*/
|
||||
int8_t minutes() const { return _seconds / 60 % 60; }
|
||||
/*!
|
||||
@brief Number of seconds in the TimeSpan
|
||||
This is not the total seconds, it includes the days/hours/minutes
|
||||
e.g. 4 days, 3 hours, 27 minutes, 7 seconds
|
||||
@return int8_t seconds
|
||||
*/
|
||||
int8_t seconds() const { return _seconds % 60; }
|
||||
/*!
|
||||
@brief Total number of seconds in the TimeSpan, e.g. 358027
|
||||
@return int32_t seconds
|
||||
*/
|
||||
int32_t totalseconds() const { return _seconds; }
|
||||
|
||||
TimeSpan operator+(const TimeSpan &right) const;
|
||||
TimeSpan operator-(const TimeSpan &right) const;
|
||||
|
||||
protected:
|
||||
int32_t _seconds; ///< Actual TimeSpan value is stored as seconds
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief A generic I2C RTC base class. DO NOT USE DIRECTLY
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class RTC_I2C {
|
||||
protected:
|
||||
/*!
|
||||
@brief Convert a binary coded decimal value to binary. RTC stores
|
||||
time/date values as BCD.
|
||||
@param val BCD value
|
||||
@return Binary value
|
||||
*/
|
||||
static uint8_t bcd2bin(uint8_t val) { return val - 6 * (val >> 4); }
|
||||
/*!
|
||||
@brief Convert a binary value to BCD format for the RTC registers
|
||||
@param val Binary value
|
||||
@return BCD value
|
||||
*/
|
||||
static uint8_t bin2bcd(uint8_t val) { return val + 6 * (val / 10); }
|
||||
Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface
|
||||
uint8_t read_register(uint8_t reg);
|
||||
void write_register(uint8_t reg, uint8_t val);
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief RTC based on the DS1307 chip connected via I2C and the Wire library
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class RTC_DS1307 : RTC_I2C {
|
||||
public:
|
||||
bool begin(TwoWire *wireInstance = &Wire);
|
||||
void adjust(const DateTime &dt);
|
||||
uint8_t isrunning(void);
|
||||
DateTime now();
|
||||
Ds1307SqwPinMode readSqwPinMode();
|
||||
void writeSqwPinMode(Ds1307SqwPinMode mode);
|
||||
uint8_t readnvram(uint8_t address);
|
||||
void readnvram(uint8_t *buf, uint8_t size, uint8_t address);
|
||||
void writenvram(uint8_t address, uint8_t data);
|
||||
void writenvram(uint8_t address, const uint8_t *buf, uint8_t size);
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief RTC based on the DS3231 chip connected via I2C and the Wire library
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class RTC_DS3231 : RTC_I2C {
|
||||
public:
|
||||
bool begin(TwoWire *wireInstance = &Wire);
|
||||
void adjust(const DateTime &dt);
|
||||
bool lostPower(void);
|
||||
DateTime now();
|
||||
Ds3231SqwPinMode readSqwPinMode();
|
||||
void writeSqwPinMode(Ds3231SqwPinMode mode);
|
||||
bool setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode);
|
||||
bool setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode);
|
||||
DateTime getAlarm1();
|
||||
DateTime getAlarm2();
|
||||
Ds3231Alarm1Mode getAlarm1Mode();
|
||||
Ds3231Alarm2Mode getAlarm2Mode();
|
||||
void disableAlarm(uint8_t alarm_num);
|
||||
void clearAlarm(uint8_t alarm_num);
|
||||
bool alarmFired(uint8_t alarm_num);
|
||||
void enable32K(void);
|
||||
void disable32K(void);
|
||||
bool isEnabled32K(void);
|
||||
float getTemperature(); // in Celsius degree
|
||||
/*!
|
||||
@brief Convert the day of the week to a representation suitable for
|
||||
storing in the DS3231: from 1 (Monday) to 7 (Sunday).
|
||||
@param d Day of the week as represented by the library:
|
||||
from 0 (Sunday) to 6 (Saturday).
|
||||
@return the converted value
|
||||
*/
|
||||
static uint8_t dowToDS3231(uint8_t d) { return d == 0 ? 7 : d; }
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief RTC based on the PCF8523 chip connected via I2C and the Wire library
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class RTC_PCF8523 : RTC_I2C {
|
||||
public:
|
||||
bool begin(TwoWire *wireInstance = &Wire);
|
||||
void adjust(const DateTime &dt);
|
||||
bool lostPower(void);
|
||||
bool initialized(void);
|
||||
DateTime now();
|
||||
void start(void);
|
||||
void stop(void);
|
||||
uint8_t isrunning();
|
||||
Pcf8523SqwPinMode readSqwPinMode();
|
||||
void writeSqwPinMode(Pcf8523SqwPinMode mode);
|
||||
void enableSecondTimer(void);
|
||||
void disableSecondTimer(void);
|
||||
void enableCountdownTimer(PCF8523TimerClockFreq clkFreq, uint8_t numPeriods,
|
||||
uint8_t lowPulseWidth);
|
||||
void enableCountdownTimer(PCF8523TimerClockFreq clkFreq, uint8_t numPeriods);
|
||||
void disableCountdownTimer(void);
|
||||
void deconfigureAllTimers(void);
|
||||
void calibrate(Pcf8523OffsetMode mode, int8_t offset);
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief RTC based on the PCF8563 chip connected via I2C and the Wire library
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class RTC_PCF8563 : RTC_I2C {
|
||||
public:
|
||||
bool begin(TwoWire *wireInstance = &Wire);
|
||||
bool lostPower(void);
|
||||
void adjust(const DateTime &dt);
|
||||
DateTime now();
|
||||
void start(void);
|
||||
void stop(void);
|
||||
uint8_t isrunning();
|
||||
Pcf8563SqwPinMode readSqwPinMode();
|
||||
void writeSqwPinMode(Pcf8563SqwPinMode mode);
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief RTC using the internal millis() clock, has to be initialized before
|
||||
use. NOTE: this is immune to millis() rollover events.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class RTC_Millis {
|
||||
public:
|
||||
/*!
|
||||
@brief Start the RTC
|
||||
@param dt DateTime object with the date/time to set
|
||||
*/
|
||||
void begin(const DateTime &dt) { adjust(dt); }
|
||||
void adjust(const DateTime &dt);
|
||||
DateTime now();
|
||||
|
||||
protected:
|
||||
/*!
|
||||
Unix time from the previous call to now().
|
||||
|
||||
This, together with `lastMillis`, defines the alignment between
|
||||
the `millis()` timescale and the Unix timescale. Both variables
|
||||
are updated on each call to now(), which prevents rollover issues.
|
||||
*/
|
||||
uint32_t lastUnix;
|
||||
/*!
|
||||
`millis()` value corresponding `lastUnix`.
|
||||
|
||||
Note that this is **not** the `millis()` value of the last call to
|
||||
now(): it's the `millis()` value corresponding to the last **full
|
||||
second** of Unix time preceding the last call to now().
|
||||
*/
|
||||
uint32_t lastMillis;
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief RTC using the internal micros() clock, has to be initialized before
|
||||
use. Unlike RTC_Millis, this can be tuned in order to compensate for
|
||||
the natural drift of the system clock. Note that now() has to be
|
||||
called more frequently than the micros() rollover period, which is
|
||||
approximately 71.6 minutes.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class RTC_Micros {
|
||||
public:
|
||||
/*!
|
||||
@brief Start the RTC
|
||||
@param dt DateTime object with the date/time to set
|
||||
*/
|
||||
void begin(const DateTime &dt) { adjust(dt); }
|
||||
void adjust(const DateTime &dt);
|
||||
void adjustDrift(int ppm);
|
||||
DateTime now();
|
||||
|
||||
protected:
|
||||
/*!
|
||||
Number of microseconds reported by `micros()` per "true"
|
||||
(calibrated) second.
|
||||
*/
|
||||
uint32_t microsPerSecond = 1000000;
|
||||
/*!
|
||||
Unix time from the previous call to now().
|
||||
|
||||
The timing logic is identical to RTC_Millis.
|
||||
*/
|
||||
uint32_t lastUnix;
|
||||
/*!
|
||||
`micros()` value corresponding to `lastUnix`.
|
||||
*/
|
||||
uint32_t lastMicros;
|
||||
};
|
||||
|
||||
#endif // _RTCLIB_H_
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
session_start();
|
||||
|
||||
// Cek jika form login telah disubmit
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
// Simpan data dari form
|
||||
$username = $_POST['username'];
|
||||
$password = $_POST['password'];
|
||||
|
||||
// Misalnya, username dan password sederhana untuk contoh
|
||||
$valid_username = "admin";
|
||||
$valid_password = "admin123";
|
||||
|
||||
// Cek kecocokan username dan password
|
||||
if ($username == $valid_username && $password == $valid_password) {
|
||||
// Login berhasil, set session dan redirect ke dashboard
|
||||
$_SESSION['username'] = $username;
|
||||
header("Location: dashboard.php");
|
||||
exit;
|
||||
} else {
|
||||
// Login gagal, kembalikan ke halaman login
|
||||
echo "<script>alert('Username atau Password salah!'); window.location='index.php';</script>";
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
session_start();
|
||||
|
||||
// Hapus semua session
|
||||
session_unset();
|
||||
session_destroy();
|
||||
|
||||
// Redirect ke halaman login
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
?>
|
Loading…
Reference in New Issue