Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: PCF8583_rtc mbed
Revision 0:f09cf90def53, committed 2014-02-09
- Comitter:
- dennyem
- Date:
- Sun Feb 09 00:25:21 2014 +0000
- Child:
- 1:a8b9fb95696b
- Commit message:
- First C++ revision for the LPC812
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/PCF8583_rtc.cpp Sun Feb 09 00:25:21 2014 +0000
@@ -0,0 +1,403 @@
+/*********************************************************************************
+ * An mbed class to control the PCF8583 Real time Clock/Calender
+ * Copyright (c) 2014 Dennis (Denny) Smith - dennyem
+ *
+ * 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.
+ *
+ * 13.01.14 initial design for PIC devices using PICC compiler
+ * 21.01.14 ported to mBed LPC1768 in 'C'
+ * 09.02.14 converted to C++ and ported to mBed LPC812
+ *
+ * TODO
+ * write function is still to be tested
+ * WriteNVram function is still to be tested
+ * ReadNVram function is still to be tested
+ * FormatDateTime needs am/pm, 12/24 hour parsing
+ * Alarm functions not yet implemented
+*/
+
+#include <mbed.h>
+#include <PCF8583_rtc.h>
+
+//-----------------------------------------------------------------------------
+// constructor -- accepts an I2c object to use for connection with the rtc
+PCF8583rtc::PCF8583rtc(I2C *i2c)
+{
+ _i2c = i2c;
+
+ ShortDateFormat = "d,m,yy";
+ LongDateFormat = "dddd dd mmmm yyyy";
+ ShortTimeFormat = "d:m:yy";
+ LongTimeFormat = "dd:nn:yyyy";
+
+ DateSeparator = '/';
+ TimeSeparator = ':';
+
+ ShortDayNames[0] = "Mon";
+ ShortDayNames[1] = "Tue";
+ ShortDayNames[2] = "Wed";
+ ShortDayNames[3] = "Thu";
+ ShortDayNames[4] = "Fri";
+ ShortDayNames[5] = "Sat";
+ ShortDayNames[6] = "Sun";
+
+ LongDayNames[0] = "Monday";
+ LongDayNames[1] = "Tuesday";
+ LongDayNames[2] = "Wednesday";
+ LongDayNames[3] = "Thursday";
+ LongDayNames[4] = "Friday";
+ LongDayNames[5] = "Saturday";
+ LongDayNames[6] = "Sunday";
+
+ ShortMonthNames[0] = "Jan";
+ ShortMonthNames[1] = "Feb";
+ ShortMonthNames[2] = "Mar";
+ ShortMonthNames[3] = "Apr";
+ ShortMonthNames[4] = "May";
+ ShortMonthNames[5] = "Jun";
+ ShortMonthNames[6] = "Jul";
+ ShortMonthNames[7] = "Aug";
+ ShortMonthNames[8] = "Sep";
+ ShortMonthNames[9] = "Oct";
+ ShortMonthNames[10] = "Nov";
+ ShortMonthNames[11] = "Dec";
+
+ LongMonthNames[0] = "January";
+ LongMonthNames[1] = "February";
+ LongMonthNames[2] = "March";
+ LongMonthNames[3] = "April";
+ LongMonthNames[4] = "May";
+ LongMonthNames[5] = "June";
+ LongMonthNames[6] = "July";
+ LongMonthNames[7] = "August";
+ LongMonthNames[8] = "September";
+ LongMonthNames[9] = "October";
+ LongMonthNames[10] = "November";
+ LongMonthNames[11] = "December";
+};
+
+void PCF8583rtc::write(const char address)
+{
+ pauseCounting(); //Must stop counting before initialising Date/time
+
+ _i2c->start(); // Issue start signal
+ _i2c->write(Write_addr); // Address PCF8583, see PCF8583 datasheet
+ _i2c->write(address); // Address is 1 for Time or 10 for Alarm
+ _i2c->write(dt.time.hundreds); // Hundredths of a second
+ _i2c->write(dt.time.seconds); // Seconds
+ _i2c->write(dt.time.minutes); // Minutes
+ _i2c->write(dt.time.hours); // Hours
+ _i2c->write(dt.date.day & 0x3F); // Always set the 3 year bits to 0
+
+ if(address == TIME)
+ _i2c->write(((dt.date.weekday & 7) << 5 )| dt.date.month); // Weekday/month
+ else
+ _i2c->write(dt.date.month & 0x1f); // No Weekday for alarm
+
+ _i2c->stop(); // Issue stop signal
+
+ if(address == TIME) {
+ writeByte(CENTURY_REG, dt.date.century); // Store the full 4 digit year in NV Ram
+ writeByte(YEAR_REG, dt.date.year);
+ };
+
+ enableCounting();
+};
+
+//--------------------- Reads time and date information from RTC (PCF8583)
+void PCF8583rtc::read(const char address)
+{
+ char tmp[8];
+ char year_bits = 0; // To test for year change
+
+ tmp[0] = address;
+ _i2c->write(PCF8583_addr, tmp, 1); // Address PCF8583, see PCF8583 datasheet
+ _i2c->read(PCF8583_addr, tmp, 6); // Address PCF8583 for reading R/W=1
+
+ dt.time.hundreds = ((tmp[0] & 0xF0) >> 4) * 10 + (tmp[0] & 0x0F); // Transform hundredths of seconds
+ dt.time.seconds = ((tmp[1] & 0xF0) >> 4) * 10 + (tmp[1] & 0x0F); // Transform seconds
+ dt.time.minutes = ((tmp[2] & 0xF0) >> 4) * 10 + (tmp[2] & 0x0F); // Transform minutes
+ dt.time.hours = ((tmp[3] & 0x30) >> 4) * 10 + (tmp[3] & 0x0F); // Transform hours
+ dt.time.fmt_hours = (tmp[3] & 0x80); // 12/24 hour format
+ dt.time.am_pm_flag = (tmp[3] & 0x40); // Am/Pm flag
+ dt.date.day = ((tmp[4] & 0x30) >> 4) * 10 + (tmp[4] & 0x0F); // Transform day
+
+ if(address == TIME)
+ year_bits = (tmp[4] & 0xC0) >> 6;
+ else
+ dt.date.year = 0; // No year for alarm
+
+ dt.date.month = ((tmp[5] & 0x10) >> 4) * 10 + (tmp[5] & 0x0F); // Transform month
+
+ if(address == TIME)
+ dt.date.weekday = tmp[5] >> 5;
+ else
+ dt.date.weekday = 0; // No weekday for alarm
+
+ if(address == TIME) {
+ tmp[0] = readByte(CENTURY_REG);
+ dt.date.century = ((tmp[0] & 0xF0) >> 4) * 10 + (tmp[0] & 0x0F);
+ tmp[0] = readByte(YEAR_REG);
+ dt.date.year = ((tmp[0] & 0xF0) >> 4) * 10 + (tmp[0] & 0x0F);
+
+ if(year_bits > 0) { // Midnight on new years eve?
+ dt.date.year += 1; // Increment the year
+ writeByte(YEAR_REG, dt.date.year); // Save the new year value to NV Ram
+ writeByte(5, dt.date.day & 0x3F); // Clear the year bits but preserve the date
+ }
+ }
+};
+
+struct DateTime_t PCF8583rtc::GetDateTime(void)
+{
+ return dt;
+}
+
+struct DateTime_t PCF8583rtc::GetDateTimeBCD(void)
+{
+ struct DateTime_t dtb;
+
+ dtb = dt;
+ dtb.time.hours = bin2bcd(dt.time.hours);
+ dtb.time.minutes = bin2bcd(dt.time.minutes);
+ dtb.time.seconds = bin2bcd(dt.time.seconds);
+ dtb.time.hundreds = bin2bcd(dt.time.hundreds);
+
+ dtb.date.day = bin2bcd(dt.date.day);
+ dtb.date.month = bin2bcd(dt.date.month);
+ dtb.date.year = bin2bcd(dt.date.year);
+ dtb.date.century = bin2bcd(dt.date.century);
+
+ return dtb;
+}
+
+void PCF8583rtc::FormatDateTime(char *dest, char *f)
+{
+ if(f != 0 && *f != 0) { //If the format param is empty then do a default 'c'
+ while(*f != 0) { //expect null terminated string (we hope)
+ switch(*f) {
+ case 'c':
+ break;
+ case 'd':
+ if(*(f+1) != 'd') { //'d' - Day with no leading zero
+ dest += Bcd2Char(dest, dt.date.day, FALSE);
+ } else {
+ f++;
+ if(*(f+1) != 'd') //'dd' - Day with leading zero
+ dest += Bcd2Char(dest, dt.date.day, TRUE);
+ else {
+ f++;
+ if(*(f+1) != 'd') { //'ddd' - Short day name
+// i = 0;
+// while(ShortDayNames[dt.date.weekday][i] != 0)
+// *dest++ = ShortDayNames[dt.date.weekday][i++];
+ } else {
+ f++;
+// i = 0;
+// while(LongDayNames[dt.date.weekday][i] != 0)
+// *dest++ = LongDayNames[dt.date.weekday][i++];
+ }
+ }
+ }
+ break;
+ case 'm':
+ if(*(f+1) != 'm') { //'m' - Month with no leading zero
+ dest += Bcd2Char(dest, dt.date.month, FALSE);
+ } else {
+ f++;
+ if(*(f+1) != 'm') //'mm' - Month with leading zero
+ dest += Bcd2Char(dest, dt.date.month, TRUE);
+ else {
+ f++;
+ if(*(f+1) != 'm') { //'mmm' - Short month name
+// i = 0;
+// while(ShortMonthNames[dt.date.month - 1][i] != 0)
+// *dest++ = ShortMonthNames[dt.date.month - 1][i++];
+ } else {
+ f++;
+// i = 0;
+// while(LongMonthNames[dt.date.month - 1][i] != 0)
+// *dest++ = LongMonthNames[dt.date.month - 1][i++];
+ }
+ }
+ }
+ break;
+ case 'y':
+ if(*(f+1) == 'y') {
+ f++; //We have at least a 'yy'
+ if(*(f+1) == 'y' && *(f+2) == 'y') { //'yyyy' - 4 digit year
+ dest += Bcd2Char(dest, dt.date.century, TRUE);
+ f += 2;
+ }
+ dest += Bcd2Char(dest, dt.date.year, TRUE);
+ }
+ break;
+ case 'h':
+ if(*(f+1) != 'h') { //'h' - Hour with no leading zero
+ dest += Bcd2Char(dest, dt.time.hours, FALSE);
+ } else {
+ f++;
+ dest += Bcd2Char(dest, dt.time.hours, TRUE);
+ }
+ break;
+ case 'n':
+ if(*(f+1) != 'n') { //'m' - Minutes with no leading zero
+ dest += Bcd2Char(dest, dt.time.minutes, FALSE);
+ } else {
+ f++;
+ dest += Bcd2Char(dest, dt.time.minutes, TRUE);
+ }
+ break;
+ case 's':
+ if(*(f+1) != 's') { //'s' - Seconds with no leading zero
+ dest += Bcd2Char(dest, dt.time.seconds, FALSE);
+ } else {
+ f++;
+ dest += Bcd2Char(dest, dt.time.seconds, TRUE);
+ }
+ break;
+ case 'z':
+ if(*(f+1) != 'z') { //'z' - Hundredths with no leading zero
+ dest += Bcd2Char(dest, dt.time.hundreds, FALSE);
+ } else {
+ f++;
+ dest += Bcd2Char(dest, dt.time.hundreds, TRUE);
+ }
+ break;
+ case '/':
+ *dest++ = DateSeparator;
+ break;
+ case ':':
+ *dest++ = TimeSeparator;
+ break;
+ case 39 :
+ while(*++f != 0 && *f != 39) *dest++ = *f;
+ break; //Ignore the first '
+ default:
+ *dest++ = *f;
+ break; //Anything we don't recognise, return it
+ }
+ f++;
+ }
+ }
+ *dest = 0; //Null terminate
+};
+
+bool PCF8583rtc::WriteNVram(char address, char *value, char num)
+{
+ if((address < USER_REG) || (num == 0)) // dont allow overwriting first 2 user bytes
+ return false;
+
+ _i2c->write(PCF8583_addr, &address, 1); // set the rom address
+ return _i2c->write(PCF8583_addr, value, num); // write the data
+};
+
+bool PCF8583rtc::ReadNVram(char address, char * dest, char num)
+{
+ if((address < USER_REG) || (num == 0)) // dont allow overwriting first 2 user bytes
+ return false;
+
+ _i2c->write(PCF8583_addr, &address, 1); // set the rom address
+ _i2c->read(PCF8583_addr, dest, num); // read the data
+
+ return true;
+};
+
+/*****************************************************************************/
+/************************** Private Functions ********************************/
+/*****************************************************************************/
+
+char PCF8583rtc::Bcd2Char(char *d, char val, char WantLeadZero)
+{
+ char n = 0;
+
+ if(WantLeadZero == TRUE || (val / 10) != 0) {
+ *d++ = (val / 10) + 48;
+ n++;
+ }
+ *d = (val % 10) + 48;
+ return(n + 1);
+}
+
+//----------------------------------------------
+// This function converts an 8 bit binary value to a 2 byte BCD value.
+// The input range must be from 0 to 99.
+int PCF8583rtc::bin2bcd(char value)
+{
+ int tmp = 0;
+
+ while(1) {
+ // Get the tens digit by doing multiple subtraction
+ // of 10 from the binary value.
+ if(value >= 10) {
+ value -= 10;
+ tmp += 0x10;
+ } else { // Get the ones digit by adding the remainder.
+ tmp += value;
+ break;
+ }
+ }
+ return tmp;
+}
+
+void PCF8583rtc::writeByte(char address, char d)
+{
+ _i2c->start();
+ _i2c->write(Write_addr);
+ _i2c->write(address);
+ _i2c->write(d);
+ _i2c->stop();
+}
+
+void PCF8583rtc::configureControlReg(char control)
+{
+ _i2c->start();
+ _i2c->write(Write_addr);
+ _i2c->write(0x00);
+ _i2c->write(control);
+ _i2c->stop();
+}
+
+void PCF8583rtc::configureAlarmReg(char alarm)
+{
+ _i2c->start();
+ _i2c->write(Write_addr);
+ _i2c->write(0x08);
+ _i2c->write(alarm);
+ _i2c->stop();
+}
+
+char PCF8583rtc::readByte(char address)
+{
+ char var;
+ _i2c->start();
+ _i2c->write(Write_addr);
+ _i2c->write(address);
+ _i2c->start();
+ _i2c->write(Read_addr);
+ var = _i2c->read(0) ;
+ _i2c->stop();
+ return var;
+}
+
+void PCF8583rtc::pauseCounting()
+{
+ char tmp;
+ tmp = readByte(0x00);
+ tmp = tmp | 0x80;
+ writeByte(0x00, tmp);
+}
+
+void PCF8583rtc::enableCounting()
+{
+ char tmp;
+ tmp = readByte(0x00);
+ tmp = tmp ^ 0x80;
+ writeByte(0x00, tmp);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/PCF8583_rtc.h Sun Feb 09 00:25:21 2014 +0000
@@ -0,0 +1,165 @@
+#include <mbed.h>
+
+#ifndef rtc_included
+#define rtc_included
+
+#define PCF8583_addr 0xA2 // PCF8583 Write address,
+#define Write_addr 0xA2 // PCF8583 Write address,
+#define Read_addr 0xA3 // PCF8583 Read address
+#define SET_DATE_TIME 0x01
+#define GET_DATE_TIME 0x02
+#define SET_ALARM 0x09
+#define GET_ALARM 0x0A
+#define ON 1
+#define OFF 0
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+//Configuration Alarm Control Register
+#define alarm_enable_bit 0x04
+#define alarm_flag 0x02;
+#define timer_hundsek 0x01
+#define timer_seconds 0x02
+#define timer_minutes 0x03
+#define timer_hours 0x04
+#define timer_days 0x05
+#define timer_int_enable 0x08
+#define daily_alarm 0x10
+#define weekday_alarm 0x20
+#define dated_alarm 0x30
+#define timer_alarm_enable 0x40
+#define alarm_int_enable 0x80
+#define timer_alarm_enable 0x40
+#define alarm_int_enable 0x80
+
+// Use the first 2 NVRAM addresses for the century and year bytes.
+#define CENTURY_REG 0x10
+#define YEAR_REG 0x11
+#define USER_REG 0x12
+
+#define TIME 1
+#define ALARM 9
+
+struct Time_t {
+ char fmt_hours;
+ char am_pm_flag;
+ char hours;
+ char minutes;
+ char seconds;
+ char hundreds;
+};
+
+struct Date_t {
+ char day;
+ char month;
+ char year;
+ char century;
+ char weekday;
+};
+
+struct DateTime_t {
+ struct Date_t date;
+ struct Time_t time;
+};
+
+class PCF8583rtc {
+ I2C *_i2c;
+
+public:
+ //Set these public variables according to your locale, default is Australia English
+ char *ShortDateFormat;
+ char *LongDateFormat;
+ char *ShortTimeFormat;
+ char *LongTimeFormat;
+
+ char DateSeparator;
+ char TimeSeparator;
+
+ char *ShortDayNames[7];
+ char *LongDayNames[7];
+ char *ShortMonthNames[12];
+ char *LongMonthNames[12];
+
+ PCF8583rtc(I2C *i2c);
+
+ int bin2bcd(char value);
+ void read(const char address);
+ void write(const char address);
+ void FormatDateTime(char *dest, char *format);
+ bool WriteNVram(char address, char * value, char num);
+ bool ReadNVram(char address, char * dest, char num);
+ struct DateTime_t GetDateTime(void);
+ struct DateTime_t GetDateTimeBCD(void);
+private:
+ struct DateTime_t dt;
+
+ char Bcd2Char(char *d, char val, char WantLeadZero);
+ void enableCounting(void);
+ void pauseCounting(void);
+ char readByte(char address);
+ void writeByte(char address, char d);
+ void configureAlarmReg(char alarm);
+ void configureControlReg(char control);
+};
+
+/** PCF8583_rtc class.
+ *
+ * Example:
+ * @code
+ * #include <mbed.h>
+ * #include <PCF8583_rtc.h>
+ *
+ * I2C i2c(P0_10, P0_11); // sda, scl
+ * PCF8583rtc rtc(&i2c);
+ *
+ * int main() {
+ *
+ * rtc.read(TIME);
+ * i2c.write(ADDR_8574_1, &rtc.HoursBCD, 1); //write hours to display
+ * i2c.write(ADDR_8574_2, &rtc.MinsBCD, 1); //write minutes to display
+ * }
+ * @endcode
+ */
+
+/** Create a PCF8583rtc object using a pointer to the given I2C object.
+ *
+ * @param i2c pointer to an I2C object to which the PCF8583 device is connected.
+ */
+//PCF8583rtc(I2C *i2c);
+
+/** the Read_DateTime function.
+ *
+ * @param address Determines whether to read the date/time or alarm registers
+ * Values are retrieved from the internal datetime structure
+ */
+//void read(const char address);
+
+/** the Write_DateTime function.
+ *
+ * @param address Determines whether to set the date/time or alarm registers
+ * Values are first set into the internal datetime structure prior to calling
+ */
+//void write(const char address);
+
+/** the FormatDateTime function.
+ *
+ * @param dest a pointer to a char array where formatted values are to be placed
+ * @param format a pointer to a string describing how to format the values
+ */
+//void FormatDateTime(char *dest, char *format);
+
+/** the WriteNVram function.
+ *
+ * @param address address where value is to be placed
+ * @param value pointer to char array containing the value(s) to be stored
+ * @param num the number bytes to store
+ */
+//void WriteNVram(char address, char *value, char num);
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Sun Feb 09 00:25:21 2014 +0000
@@ -0,0 +1,82 @@
+#include "mbed.h"
+#include "PCF8583_rtc.h"
+
+void NixieDisplay(void);
+//void ChangeTime(void);
+
+DigitalOut Red(P0_7);
+DigitalOut Green(P0_17);
+DigitalOut Blue(P0_16);
+
+I2C i2c(P0_10, P0_11); // sda, scl
+Serial pc(USBTX, USBRX); // tx, rx
+Ticker TickerFunc;
+PCF8583rtc rtc(&i2c);
+
+// i2c addresses
+const int ADDR_8574_1 = 0x70;
+const int ADDR_8574_2 = 0x72;
+
+int alarm = OFF;
+int setTimer = OFF;
+
+int main()
+{
+ struct DateTime_t dtBCD;
+
+ Red = Green = Blue = 1;
+// TickerFunc.attach(&NixieDisplay, 1.0); // The address of the function to be attached and the interval (1 seconds)
+
+ i2c.frequency(400000);
+
+ while(1) {
+ rtc.read(TIME);
+ dtBCD = rtc.GetDateTimeBCD(); //get the date and time in BCD form
+ i2c.write(ADDR_8574_1, &dtBCD.time.hours, 1);
+ i2c.write(ADDR_8574_2, &dtBCD.time.minutes, 1);
+
+ Blue = !Blue;
+ wait(.5);
+// if(!sw3.read()) { // Change Time
+// ChangeTime();
+// }
+
+// pc.printf("Magnet = %d\n", magnet.read());
+ }
+}
+
+void NixieDisplay()
+{
+// i2c.write(ADDR_8574_1, &HoursBCD, 1);
+// i2c.write(ADDR_8574_2, &MinsBCD, 1);
+
+ Red = !Red;
+// time_t seconds = time(NULL);
+// struct tm *t = localtime(&seconds);
+//
+// data = bin2bcd(t.tm_hour);
+// i2c.writeite(ADDR_8574_1, &data, 1);
+//
+// data = bin2bcd(t.tm_min);
+// i2c.writeite(ADDR_8574_2, &data, 1);
+}
+
+//void ChangeTime() {
+// time_t seconds = time(NULL);
+// wait(0.1);
+// struct tm *t = localtime(&seconds);
+//
+// while(!sw3.read()) {
+// if(!sw2.read()) { //Change Hour
+// t.tm_hour += 1;
+// } else {
+// if(!sw1.read()) { //Change Minute
+// t.tm_min += 1;
+// }
+// }
+//
+// set_time(mktime(t));
+// wait(0.2);
+// }
+//}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Sun Feb 09 00:25:21 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f \ No newline at end of file