From 20f384ee55da17f19ad14849c925e02c8dab0307 Mon Sep 17 00:00:00 2001 From: mlalondesvn Date: Wed, 17 Oct 2007 19:19:13 +0000 Subject: [PATCH] Initial import of the Cool Arduino Libraries Repository git-svn-id: svn+ssh://oldsvn/home/mlalondesvn/svn/cral@1 3ee9b42a-b53c-0410-a25e-f0b6218d5d5b --- StaticPrint/staticPrint.cpp | 37 +++ StaticPrint/staticPrint.h | 29 ++ configs/LCD/lcd.h | 58 ++++ configs/RTC/rtcConfig.h | 42 +++ ds1337/ds1337.cpp | 623 ++++++++++++++++++++++++++++++++++++ ds1337/ds1337.h | 349 ++++++++++++++++++++ ds1624/ds1624.cpp | 61 ++++ ds1624/ds1624.h | 57 ++++ ds1803/ds1803.cpp | 46 +++ ds1803/ds1803.h | 44 +++ global.h | 45 +++ twiLCD/twiLCD.cpp | 427 ++++++++++++++++++++++++ twiLCD/twiLCD.h | 220 +++++++++++++ twiLCD/twiLCDConfig.h | 42 +++ 14 files changed, 2080 insertions(+) create mode 100644 StaticPrint/staticPrint.cpp create mode 100644 StaticPrint/staticPrint.h create mode 100644 configs/LCD/lcd.h create mode 100644 configs/RTC/rtcConfig.h create mode 100644 ds1337/ds1337.cpp create mode 100644 ds1337/ds1337.h create mode 100644 ds1624/ds1624.cpp create mode 100644 ds1624/ds1624.h create mode 100644 ds1803/ds1803.cpp create mode 100644 ds1803/ds1803.h create mode 100644 global.h create mode 100644 twiLCD/twiLCD.cpp create mode 100644 twiLCD/twiLCD.h create mode 100644 twiLCD/twiLCDConfig.h diff --git a/StaticPrint/staticPrint.cpp b/StaticPrint/staticPrint.cpp new file mode 100644 index 0000000..076b12c --- /dev/null +++ b/StaticPrint/staticPrint.cpp @@ -0,0 +1,37 @@ +#include "../global.h" + +// call with printString(PSTR("My string")) +void SPrint_P(const char *data) +{ + char ch; + + for (;;) { + ch = pgm_read_byte( data++ ); + if ( !ch ) return; + Serial.print(ch); + } +} + +void SPrintln_P(const char *data) +{ + SPrint_P(data); + SPrint_P(PSTR("\r\n")); +} + +void SPrintHex_P(const char *data) +{ + char ch; + + for (;;) { + ch = pgm_read_byte( data++ ); + if ( !ch ) return; + Serial.print(ch, HEX); + } +} + +void SPrintlnHex_P(const char *data) +{ + printString(data); + + Serial.println(); +} diff --git a/StaticPrint/staticPrint.h b/StaticPrint/staticPrint.h new file mode 100644 index 0000000..3e27014 --- /dev/null +++ b/StaticPrint/staticPrint.h @@ -0,0 +1,29 @@ +#ifndef staticPrint_H +#define staticPrint_H + +#ifndef nop + #define nop() asm volatile ("nop") +#endif + +#ifndef SPrint + #define SPrint(str) SPrint_P(PSTR(str)) +#endif + +#ifndef SPrintln + #define SPrintln(str) SPrintln_P(PSTR(str)) +#endif + +#ifndef SPrintHex + #define SPrintHex(str) SPrintHex_P(PSTR(str)) +#endif + +#ifndef SPrint + #define SPrintlnHez(str) SPrintlnHex_P(PSTR(str)) +#endif + +void SPrint_P(const char *data); +void SPrintln_P(const char *data); +void SPrintHex_P(const char *data); +void SPrintlnHex_P(const char *data); + +#endif diff --git a/configs/LCD/lcd.h b/configs/LCD/lcd.h new file mode 100644 index 0000000..fb8a05d --- /dev/null +++ b/configs/LCD/lcd.h @@ -0,0 +1,58 @@ +#ifndef LCD_H +#define LCD_H + +#define LCD_ROWS 2 +#define LCD_COLUMNS 16 + +#define LCD_CURSOR_OFF 0x0C +#define LCD_CURSOR_OFF_BLINK 0x0D +#define LCD_CURSOR_NO_BLINK 0x0E +#define LCD_CURSOR_BLINK 0x0F +#define LCD_CLEAR 0x01 +#define LCD_CLOSE_INIT 0x80 + +/** + * Entry modes +**/ +#define LCD_ENTRY_AUTOINC 0x04 +#define LCD_ENTRY_SHIFT 0x02 + +/** + * Shifting commands +**/ +#define LCD_GO_HOME 0x02 +#define LCD_SHIFT_RIGHT 0x1C +#define LCD_SHIFT_LEFT 0x18 + +/** + * Display off command +**/ +#define LCD_TURN_OFF 0x0A + +/** + * Character font +**/ +#define LCD_CHARSET_0 0x00 +#define LCD_CHARSET_1 0x04 + +/** + * Number of lines +**/ +#define LCD_LINES_1 0x00 +#define LCD_LINES_2 0x08 + +#define LCD_FUNCTION_MASK B00100000 + +// Choose the fonction modes here +#define LCD_FUNCTION_SET LCD_LINES_2 | LCD_CHARSET_0 + +// Choose the cursor mode here +#define LCD_CURSOR LCD_CURSOR_OFF + +// Choose the entry mode here +#define LCD_ENTRY_MODE LCD_ENTRY_AUTOINC + +// Uncomment this if you want clearScreen to call back a function named onClearScreen +//#define LCD_USE_CLRSCREEN_CALLBACK + +#endif diff --git a/configs/RTC/rtcConfig.h b/configs/RTC/rtcConfig.h new file mode 100644 index 0000000..087ade0 --- /dev/null +++ b/configs/RTC/rtcConfig.h @@ -0,0 +1,42 @@ +#ifndef RTC_CONFIG_H +#define RTC_CONFIG_H + +/** + * Set this to your local GMT offset + * Comment to skip GMT offset calculations +**/ +#define RTC_GMT_OFFSET -5 + +/** + * Select your DST type + * Comment all to skip DST calculation +**/ +#define RTC_DST_TYPE 0 /* US */ +//#define RTC_DST_TYPE 1 /* EU */ + +// Uncomment this only if you need to check DST prior to 2006 +//#define RTC_CHECK_OLD_DST +#define RTC_DST_OLD_YEAR 2006 + +#define RTC_DOW_1 PSTR("Sun") /* First day of the week */ +#define RTC_DOW_2 PSTR("Mon") +#define RTC_DOW_3 PSTR("Tue") +#define RTC_DOW_4 PSTR("Wed") +#define RTC_DOW_5 PSTR("Thu") +#define RTC_DOW_6 PSTR("Fri") +#define RTC_DOW_7 PSTR("Sat") + +/* Wednesday is the first day of Epoch: This probably shouldn't change! */ +#define RTC_DOW_0 RTC_DOW_4 + +/** + * Macros +**/ +// Start (US/EU), Stop (EU) +#define DSTCALCULATION1(y) (31-((y * 5 / 4) + 1) % 7) + +// Stop (US) +#define DSTCALCULATION2(y) (7 - ((1 + y * 5 / 4) % 7)) + + +#endif diff --git a/ds1337/ds1337.cpp b/ds1337/ds1337.cpp new file mode 100644 index 0000000..c63d41c --- /dev/null +++ b/ds1337/ds1337.cpp @@ -0,0 +1,623 @@ +extern "C" { + #include +} + +#include "../global.h" +#include "../configs/RTC/rtcConfig.h" +#include "ds1337.h" + +// Internal macro for storing month days! +#ifndef GETMONTHDAYS +PROGMEM prog_uint16_t monthcount[] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; +#define GETMONTHDAYS(index) (pgm_read_word_near(monthcount + index)) +#endif + +#ifndef CI + #define CI(reg,bit) (reg & ~(bit)) +#endif + +#ifndef SI + #define SI(reg,bit) (reg | bit) +#endif + +DS1337::DS1337() +{ + clockExists = false; + alarmId = false; + +#ifdef WIRE_LIB_SCAN_MOD + /*if (!Wire.isStarted()) */Wire.begin(); +#else + Wire.begin(); +#endif +} + +DS1337 RTC = DS1337(); + +#ifdef WIRE_LIB_SCAN_MOD +int8_t DS1337::Init(void) +{ + // Account for the crystal power up! + delay(250); + + // Check address and returns false is there is an error + if (Wire.checkAddress(DS1337_WADDR)) { + // Possibly set the default registers here + + clockExists = true; + + // Start the oscillator if need + if (getRegisterBit(DS1337_SP, DS1337_SP_EOSC)) + { + if (getRegisterBit(DS1337_STATUS, DS1337_STATUS_OSF)) + { + unsetRegister(DS1337_STATUS, DS1337_STATUS_OSF); + } + + clockStart(); + } + + return DS1337_WADDR; + } else clockExists = false; + + return -1; +} +#else +int8_t DS1337::Init(void) +{ + // Account for the crystal power up! + delay(250); + + clockExists = true; + + // Start the oscillator if need + if (getRegisterBit(DS1337_SP, DS1337_SP_EOSC)) + { + if (getRegisterBit(DS1337_STATUS, DS1337_STATUS_OSF)) + { + unsetRegister(DS1337_STATUS, DS1337_STATUS_OSF); + } + + clockStart(); + + return DS1337_WADDR; + } + + return -1; +} +#endif + +boolean DS1337::checkClock() +{ + if (getRegisterBit(DS1337_STATUS, DS1337_STATUS_OSF)) + { + return false; + } + + return true; +} + +void DS1337::setRegister(uint8_t registerNumber, uint8_t registerMask) +{ + writeRegister(registerNumber, SI(getRegister(registerNumber), registerMask)); +} + +void DS1337::unsetRegister(uint8_t registerNumber, uint8_t registerMask) +{ + writeRegister(registerNumber, CI(getRegister(registerNumber), registerMask)); +} + +void DS1337::writeRegister(uint8_t registerNumber, uint8_t registerValue) +{ + if (!clockExists) return; + + Wire.beginTransmission(DS1337_WADDR); + Wire.send(registerNumber); + + Wire.send(registerValue); + + Wire.endTransmission(); +} + +uint8_t DS1337::getRegister(uint8_t registerNumber) +{ + if (!clockExists) return 0; + + Wire.beginTransmission(DS1337_WADDR); + Wire.send(registerNumber); + Wire.endTransmission(); + + Wire.requestFrom(DS1337_WADDR, 1); + + while (!Wire.available()); + + return Wire.receive(); +} + +void DS1337::clockRead(void) +{ + if (!clockExists) return; + + Wire.beginTransmission(DS1337_WADDR); + Wire.send(0x00); + Wire.endTransmission(); + + Wire.requestFrom(DS1337_WADDR, 7); + while (!Wire.available()); + + for(int i=0; i<7; i++) + { + if (Wire.available()) + rtc_bcd[i] = Wire.receive(); + } +} + +void DS1337::clockSave(void) +{ + if (!clockExists) return; + + Wire.beginTransmission(DS1337_WADDR); + Wire.send(0x00); + + for(int i=0; i<7; i++) + { + Wire.send(rtc_bcd[i]); + } + + Wire.endTransmission(); + + delay(10); +} + +void DS1337::clockGet(uint16_t *rtc) +{ + clockRead(); + + for(int i=0;i<8;i++) // cycle through each component, create array of data + { + rtc[i]=clockGet(i, 0); + } +} + +uint16_t DS1337::clockGet(uint8_t c, boolean refresh) +{ + if(refresh) clockRead(); + + int timeValue=-1; + switch(c) + { + case DS1337_SEC: + timeValue = bcdToBin(DS1337_SEC, DS1337_HI_SEC); + break; + case DS1337_MIN: + timeValue = bcdToBin(DS1337_MIN, DS1337_HI_MIN); + break; + case DS1337_HR: + timeValue = bcdToBin(DS1337_HR, DS1337_HI_HR); + break; + case DS1337_DOW: + timeValue = rtc_bcd[DS1337_DOW] & DS1337_LO_DOW; + break; + case DS1337_DATE: + timeValue = bcdToBin(DS1337_DATE, DS1337_HI_DATE); + break; + case DS1337_MTH: + timeValue = CI(bcdToBin(DS1337_MTH, DS1337_HI_MTH), DS1337_LO_CNTY); + break; + case DS1337_YR: + timeValue = bcdToBin(DS1337_YR, DS1337_HI_YR)+(1900 + (rtc_bcd[DS1337_MTH] & DS1337_LO_CNTY ? 100 : 0)); + break; + case DS1337_CNTY: + timeValue = rtc_bcd[DS1337_MTH] & DS1337_LO_CNTY>>7; + break; + } // end switch + + return timeValue; +} + +#ifdef DS1337_USE_BCD_CLOCKSET +void DS1337::clockSet(uint8_t timeSection, uint16_t timeValue) +{ + switch(timeSection) + { + case DS1337_SEC: + if(timeValue<60) + { + rtc_bcd[DS1337_SEC] = binToBcd(timeValue); + } + break; + + case DS1337_MIN: + if(timeValue<60) + { + rtc_bcd[DS1337_MIN] = binToBcd(timeValue); + } + break; + + case DS1337_HR: + // TODO : AM/PM 12HR/24HR + if(timeValue<24) + { + rtc_bcd[DS1337_HR] = binToBcd(timeValue); + } + break; + + case DS1337_DOW: + if(timeValue<8) + { + rtc_bcd[DS1337_DOW] = timeValue; + } + break; + + case DS1337_DATE: + if(timeValue<31) + { + rtc_bcd[DS1337_DATE] = binToBcd(timeValue); + } + break; + + case DS1337_MTH: + if(timeValue<13) + { + rtc_bcd[DS1337_MTH] = SI(CI(binToBcd(timeValue),DS1337_LO_CNTY), (rtc_bcd[DS1337_MTH] & DS1337_LO_CNTY)); + } + break; + + case DS1337_YR: + if(timeValue<1000) + { + rtc_bcd[DS1337_YR] = binToBcd(timeValue); + } + break; + + case DS1337_CNTY: + if (timeValue > 0) + { + rtc_bcd[DS1337_MTH] = SI(rtc_bcd[DS1337_MTH], DS1337_LO_CNTY); + } else { + rtc_bcd[DS1337_MTH] = CI(rtc_bcd[DS1337_MTH], DS1337_LO_CNTY); + } + break; + } // end switch + + clockSave(); +} +#endif + +#ifdef DS1337_USE_GET_UTS +uint32_t DS1337::calculateUTS(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) +{ + // Number of days per month + // Compute days + tt = (year - 1970) * 365 + GETMONTHDAYS(month) + day - 1; + + // Compute for leap year + for (month <= 2 ? year-- : 0; year >= 1970; year--) + if (ISLEAP(year)) + tt++; + + // Plus the time + tt = sec + 60 * (min + 60 * (tt * 24 + hour - RTC_GMT_OFFSET)); + + return tt; +} +#endif + +#ifdef DS1337_USE_SET_UTS +void DS1337::clockSetWithUTS(uint32_t unixTimeStamp, boolean correctedTime) +{ + int8_t ii; + uint16_t year; + uint16_t *yrPtr = &year; + uint16_t thisYear; + uint16_t *tyPtr = &thisYear; +#if defined(RTC_DST_TYPE) + uint8_t thisDate; + uint8_t *tdPtr = &thisDate; +#endif + + // Serial.print((uint32_t)unixTimeStamp, DEC); delay(5); SPrint(" "); + + /** + * Calculate GMT and DST + **/ +#if defined(RTC_GMT_OFFSET) + if (!correctedTime) unixTimeStamp = (uint32_t)unixTimeStamp + (RTC_GMT_OFFSET * 3600); +#endif + + // Years + tt = (uint32_t)unixTimeStamp / 3600 / 24 / 365; + year = tt + 1970; + + thisYear = year; + + // Set the century bit + if (tt > 30) { + rtc_bcd[DS1337_MTH] = SI(rtc_bcd[DS1337_MTH], DS1337_LO_CNTY); + tt-= 30; + } else { + rtc_bcd[DS1337_MTH] = CI(rtc_bcd[DS1337_MTH], DS1337_LO_CNTY); + } + + // Set the year + rtc_bcd[DS1337_YR] = binToBcd(tt); + + // Number of days left in the year + // Serial.print((uint32_t)unixTimeStamp, DEC); delay(5); SPrint(" "); delay(5); + // Serial.print((uint32_t)unixTimeStamp%31536000, DEC); delay(5); SPrint(" "); delay(5); + tt = ((uint32_t)(uint32_t)unixTimeStamp%31536000 / 3600 / 24) + 1; + + // Serial.print(tt, DEC); delay(5); SPrint(" "); delay(5); + + // leap year correction + for (year--; year > 1970; year--) { + if (ISLEAP(year)) + { + tt--; + } + } + + free(yrPtr); + + // Serial.print(tt, DEC); SPrint(" "); + + // Grab the number of previous days, account for leap years, and save the month + for (ii = 1; ii < 12; ii++) + { + if (( GETMONTHDAYS(ii+1) + ((ISLEAP(thisYear) && ii >= 2) ? 1 : 0) ) > tt) + { + rtc_bcd[DS1337_MTH] = SI(CI(binToBcd(ii), DS1337_LO_CNTY), (rtc_bcd[DS1337_MTH] & DS1337_LO_CNTY)); + break; + } + } + // Serial.print(ii, DEC); + // SPrint(" "); + + // Date +#if defined(RTC_DST_TYPE) + if (!correctedTime) { + thisDate = tt - (GETMONTHDAYS(ii) + ((ISLEAP(thisYear) && ii >= 2) ? 1 : 0)); + } +#endif + + // Date + rtc_bcd[DS1337_DATE] = binToBcd( tt - (GETMONTHDAYS(ii) + ((ISLEAP(thisYear) && ii >= 2) * 1)) ); + // Serial.print( tt - (GETMONTHDAYS(ii) + ((ISLEAP(thisYear) && ii >= 2) * 1)) , DEC); + // SPrint(" "); + + // Day of the week + rtc_bcd[DS1337_DOW] = ((tt)%7 + 1) & DS1337_LO_DOW; + // Serial.print(((tt)%7 + 1) & DS1337_LO_DOW, DEC); + // SPrint(" "); + + // Hour + tt = (uint32_t)unixTimeStamp%86400 / 3600; + rtc_bcd[DS1337_HR] = binToBcd(tt); + // Serial.print(tt, DEC); + // SPrint(" "); + +#if defined(RTC_DST_TYPE) + if (!correctedTime) { + uint8_t dstStartMo, dstStopMo, dstStart, dstStop; + uint8_t *dstStartMoPtr = &dstStartMo; + uint8_t *dstStopMoPtr = &dstStopMo; + uint8_t *dstStartPtr = &dstStart; + uint8_t *dstStopPtr = &dstStop; + + #ifndef RTC_CHECK_OLD_DST + dstStart = DSTCALCULATION1(thisYear); + #if RTC_DST_TYPE == 1 + dstStop = DSTCALCULATION1(thisYear); // EU DST + #else + dstStop = DSTCALCULATION2(thisYear); // US DST + #endif + dstStartMo = 3; + dstStopMo = 11; + #else + if (thisYear < RTC_DST_OLD_YEAR) { + dstStart = ((2+6 * thisYear - (thisYear / 4) ) % 7 + 1); + dstStop = (14 - ((1 + thisYear * 5 / 4) % 7)); + dstStartMo = 4; + dstStopMo = 10; + } else { + dstStart = DSTCALCULATION1(thisYear) + #if RTC_DST_TYPE == 1 + dstStop = DSTCALCULATION1(thisYear) // EU DST + #else + dstStop = DSTCALCULATION2(thisYear); // US DST + #endif + dstStartMo = 3; + dstStopMo = 11; + } + #endif + if (ii >= dstStartMo && ii <= dstStopMo) + { + if ( (ii < dstStopMo && (ii > dstStartMo || thisDate > dstStart || thisDate == dstStart && tt >= 2)) || + (thisDate < dstStop || thisDate == dstStop && tt < 2) ) + { + /** + * Free as much memory as possible before entering recursion + **/ + free(tyPtr); + free(tdPtr); + free(dstStopPtr); + free(dstStartPtr); + free(dstStopMoPtr); + free(dstStartMoPtr); + + clockSetWithUTS((uint32_t)unixTimeStamp + 3600, true); + return; + } + } + } +#endif + + // Minutes + tt = (uint32_t)unixTimeStamp%3600 / 60; + rtc_bcd[DS1337_MIN] = binToBcd(tt); + // Serial.print(tt, DEC); + // SPrint(" "); + + // Seconds + tt = ((uint32_t)unixTimeStamp%3600)%60; + rtc_bcd[DS1337_SEC] = binToBcd(tt); + // Serial.print(tt, DEC); + // SPrint(" "); + + // Stop the clock + //clockStop(); // Uneeded with the ds1337 + + // Save buffer to the RTC + clockSave(); + + // Restart the oscillator + //clockStart(); // Uneeded with the ds1337 +} +#endif + +uint8_t DS1337::bcdToBin(uint8_t index, uint8_t hi) +{ + return (10*((rtc_bcd[index] & hi)>>4))+(rtc_bcd[index] & DS1337_LO_BCD); +} +uint8_t DS1337::binToBcd(uint8_t val) +{ + return ((((val)/10)<<4) + (val)%10); +} + +/** + * Alarm support functions +**/ +#ifdef DS1337_USE_ALARMS + +void DS1337::alarmSelect(boolean alarm) +{ + alarmId = alarm; + return; +} + +void DS1337::alarmSet(uint8_t timeSection, uint8_t timeValue) +{ + if (timeSection > DS1337_ALARM_DT) return; + + if (alarmId == true) rtc_alarm[DS1337_SEC] = 0; + + switch(timeSection) + { + case DS1337_SEC: + if(alarmId == false && timeValue<60) + { + rtc_alarm[DS1337_SEC] = binToBcd(timeValue) & ~DS1337_ALARM_MASK | (rtc_alarm[DS1337_SEC] & DS1337_ALARM_MASK); + } + break; + + case DS1337_MIN: + if(timeValue < 60) + { + rtc_alarm[DS1337_MIN] = binToBcd(timeValue) & ~DS1337_ALARM_MASK | (rtc_alarm[DS1337_MIN] & DS1337_ALARM_MASK); + } + break; + + case DS1337_HR: + if(timeValue < 24) + { + rtc_alarm[DS1337_HR] = binToBcd(timeValue) & ~DS1337_ALARM_MASK | (rtc_alarm[DS1337_HR] & DS1337_ALARM_MASK); + } + break; + + case DS1337_DOW: + if(timeValue < 31) + { + rtc_alarm[DS1337_DOW] = binToBcd(timeValue) & ~DS1337_ALARM_MASK & ~DS1337_ALARM_DT_MASK | (rtc_alarm[DS1337_DOW] & DS1337_ALARM_MASK) | (rtc_alarm[DS1337_DOW] & DS1337_ALARM_DT_MASK); + } + break; + + case DS1337_ALARM_MODE: + { + if (alarmId) { + timeValue = (timeValue>>1)<<1; + } else + rtc_alarm[DS1337_SEC] = (rtc_alarm[DS1337_SEC] & ~DS1337_ALARM_MASK) | DS1337_ALARM_MASK & timeValue<<7; + + rtc_alarm[DS1337_MIN] = (rtc_alarm[DS1337_MIN] & ~DS1337_ALARM_MASK) | DS1337_ALARM_MASK & timeValue<<6; + rtc_alarm[DS1337_HR] = (rtc_alarm[DS1337_HR] & ~DS1337_ALARM_MASK) | DS1337_ALARM_MASK & timeValue<<5; + rtc_alarm[DS1337_DOW] = (rtc_alarm[DS1337_DOW] & ~DS1337_ALARM_MASK) | DS1337_ALARM_MASK & timeValue<<4; + + if (timeValue == DS1337_ALARM_MCH_DOWHRMINSEC) + { + rtc_alarm[DS1337_DOW] = rtc_alarm[DS1337_DOW] & ~DS1337_ALARM_DT_MASK | DS1337_ALARM_DT_MASK; + } + } + + break; + + case DS1337_ALARM_DT: + { + rtc_alarm[DS1337_DOW] = rtc_alarm[DS1337_DOW] & ~DS1337_ALARM_DT_MASK | (timeValue == 1 ? DS1337_ALARM_DT_MASK : 0); + } + break; + } // end switch + + alarmSave(); +} + +boolean DS1337::alarmCheck(boolean both) +{ + if (!both) return alarmCheck(); + bool res; + + if (getRegisterBit(DS1337_STATUS, DS1337_STATUS_A2F)) + { + res = true; + } + + if (getRegisterBit(DS1337_STATUS, DS1337_STATUS_A1F)) + { + unsetRegister(DS1337_STATUS, DS1337_STATUS_A1F); + unsetRegister(DS1337_STATUS, DS1337_STATUS_A2F); + res = true; + } else if (res) res = false; + + return res; +} + +boolean DS1337::alarmCheck(void) +{ + if (getRegisterBit(DS1337_STATUS, (alarmId == false ? DS1337_STATUS_A1F : DS1337_STATUS_A2F))) + { + unsetRegister(DS1337_STATUS, (alarmId == false ? DS1337_STATUS_A1F : DS1337_STATUS_A2F)); + + return true; + } + + return false; +} + +void DS1337::alarmSave(void) +{ + Wire.beginTransmission(DS1337_WADDR); + Wire.send((alarmId == false ? DS1337_ALARM1 : DS1337_ALARM2)); + + for(uint8_t i=(alarmId == false ? 0 : 1); i<4; i++) + { + Wire.send(rtc_alarm[i]); + } + + Wire.endTransmission(); + + delay(5); +} + +#endif + +void DS1337::printRegisters(void) +{ + for(int ii=0;ii<0x10;ii++) + { + SPrint("0x"); + Serial.print(ii, HEX); + SPrint(" "); + Serial.println(getRegister(ii), BIN); + } + + delay(200); +} diff --git a/ds1337/ds1337.h b/ds1337/ds1337.h new file mode 100644 index 0000000..605b902 --- /dev/null +++ b/ds1337/ds1337.h @@ -0,0 +1,349 @@ +/* + DS1337.h - library for DS1337 I2C Real Time Clock +*/ + +#ifndef DS1337_h +#define DS1337_h + +// include types & constants of Wiring core API +#include +#include + +// include types & constants of Wire ic2 lib +#include + +// Include global RTC configs +#include "../configs/RTC/rtcConfig.h" + +// Ucomment this to enable setting the clock from a +// unix time stamp with gmt and dst correction +#define DS1337_USE_SET_UTS + +// Uncomment this enable setting the clock using BCD +//#define DS1337_USE_BCD_CLOCKSET + +// Uncomment this if you need to read back unix time stamp (without DTS correction) +//#define DS1337_USE_GET_UTS + +// Uncomment this to support alarms +#define DS1337_USE_ALARMS + +/** + * Define the position of the RTC buffer values +**/ +#define DS1337_SEC 0 +#define DS1337_MIN 1 +#define DS1337_HR 2 +#define DS1337_DOW 3 +#define DS1337_DATE 4 +#define DS1337_MTH 5 +#define DS1337_YR 6 +#define DS1337_CNTY 7 + +// For use externally +#define RTC_SEC DS1337_SEC +#define RTC_MIN DS1337_MIN +#define RTC_HR DS1337_HR +#define RTC_DOW DS1337_DOW +#define RTC_DATE DS1337_DATE +#define RTC_MTH DS1337_MTH +#define RTC_YR DS1337_YR +#define RTC_CNTY DS1337_CNTY + +/** + * Define the DS1337 I2C addresses +**/ +#define DS1337_WADDR 0x68 +#define DS1337_RADDR DS1337_WADDR | 0x01 + +/** + * Define registers and bit masks +**/ +#define DS1337_LO_BCD B00001111 +#define DS1337_HI_BCD B01110000 + +#define DS1337_HI_SEC B01110000 +#define DS1337_HI_MIN B01110000 +#define DS1337_HI_HR B00110000 +#define DS1337_LO_DOW B00000111 +#define DS1337_HI_DATE B00110000 +#define DS1337_HI_MTH B00010000 +#define DS1337_LO_CNTY B10000000 +#define DS1337_HI_YR B11110000 + +#define DS1337_ARLM1 0x07 +#define DS1337_ARLM1_LO_SEC B00001111 +#define DS1337_ARLM1_HI_SEC B01110000 +#define DS1337_ARLM1_LO_MIN B01110000 +#define DS1337_ARLM1_HI_MIN B00001111 + +#define DS1337_SP 0x0E +#define DS1337_SP_EOSC B10000000 +#define DS1337_SP_RS2 B00010000 +#define DS1337_SP_RS1 B00001000 +#define DS1337_SP_INTCN B00000100 +#define DS1337_SP_A2IE B00000010 +#define DS1337_SP_A1IE B00000001 + +#define DS1337_STATUS 0x0F +#define DS1337_STATUS_OSF B10000000 +#define DS1337_STATUS_A2F B00000010 +#define DS1337_STATUS_A1F B00000001 + +// Alarm registers and masks +#define DS1337_ALARM1 0x07 +#define DS1337_ALARM2 0x0B + +#define DS1337_ALARM_DT_MASK B01000000 +#define DS1337_ALARM_MASK B10000000 + +#define DS1337_ALARM_MODE 4 +#define DS1337_ALARM_DT 5 + +#define DS1337_ALARM_DT_DOW true +#define DS1337_ALARM_DT_DATE false + +#define DS1337_ALARM_PER_SEC B00001111 +#define DS1337_ALARM_PER_MIN B00000111 /* Used for alarm 2 only*/ +#define DS1337_ALARM_MCH_SEC B00001110 /* Used for alarm 1 only */ +#define DS1337_ALARM_MCH_MINSEC B00001100 +#define DS1337_ALARM_MCH_HRMINSEC B00001000 /* Used for alarm 1 only */ +#define DS1337_ALARM_MCH_DATEHRMINSEC B00000000 +#define DS1337_ALARM_MCH_DOWHRMINSEC B10000000 + +// Alarm mode masks +#define DS1337_ALARM2_MODE_MASK B00001000 +#define DS1337_ALARM_M1 B00000001 +#define DS1337_ALARM_M2 B00000010 +#define DS1337_ALARM_M3 B00000100 +#define DS1337_ALARM_M4 B00001000 + +/** + * Macros +**/ +#define clockStart() unsetRegister(DS1337_SP, DS1337_SP_EOSC) +#define clockStop() setRegister(DS1337_SP, DS1337_SP_EOSC) + +#define getRegisterSP() getRegisterSP(DS1337_SP) +#define getRegisterStatus() getRegisterStatus(DS1337_STATUS) + +#define getRegisterBit(reg, bitMask) (getRegister(reg) & bitMask) && bitMask + +#ifndef ISLEAP +#define ISLEAP(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) +#endif + +#ifndef BCDTOBIN +// This marco is for internal use only! +#define BCDTOBIN(index, hi) (10*((rtc_bcd[index] & hi)>>4))+(rtc_bcd[index] & DS1337_LO_BCD) +#endif + +#ifndef BINTOBCD +#define BINTOBCD(val) ((((val)/10)<<4) + (val)%10) +#endif + +/** + * getUTS: Macro for calculateUTS + * returns the time as a unix time stamp + * This function doesn't take into account having DST set or not! +**/ +#ifdef DS1337_USE_GET_UTS +#define getUTS(refresh) calculateUTS( RTC.clockGet(DS1337_YR, true), RTC.clockGet(DS1337_MTH, false), \ + RTC.clockGet(DS1337_DATE, false), RTC.clockGet(DS1337_HR, false), \ + RTC.clockGet(DS1337_MIN, false), RTC.clockGet(DS1337_SEC, false) \ + ) +#endif + +/** + * Use this macro to the time from a unix time stamp +**/ +#if defined(DS1337_USE_SET_UTS) +#define clockSet(UTS) clockSetWithUTS(UTS, false) +#endif + +/** + * Macros for getting time values without refreshing the RTC buffer +**/ +#define clockGetSec() clockGet(DS1337_SEC, false) +#define clockGetMin() clockGet(DS1337_MIN, false) +#define clockGetHour() clockGet(DS1337_HR, false) +#define clockGetDate() clockGet(DS1337_DATE, false) +#define clockGetMonth() clockGet(DS1337_MTH, false) +#define clockGetDow() clockGet(DS1337_DOW, false) + +/** + * Macros for getting time values refreshing the RTC buffer before each read. +**/ +#define clockGetRSec() clockGet(DS1337_SEC, true) +#define clockGetRMin() clockGet(DS1337_MIN, true) +#define clockGetRHour() clockGet(DS1337_HR, true) +#define clockGetRDate() clockGet(DS1337_DATE, true) +#define clockGetRMonth() clockGet(DS1337_MTH, true) +#define clockGetRDow() clockGet(DS1337_DOW, true) + + +// library interface description +class DS1337 +{ + // user-accessible "public" interface + public: + /** + * clockExists: keeps track of the whether or not the RTC exists + **/ + bool clockExists; + + /** + * Class constructor + **/ + DS1337(); + + /** + * Init: initializes the clock + * If the I2C scan mod is available, it'll verify the RTC is reachable + **/ + int8_t Init(void); + + /** + * checkClock: verifies the clock integrity + * Returns false when the integrity check fails + **/ + boolean checkClock(); + + /** + * setRegister: sets a register bit fromt he register number and bitmask + **/ + void setRegister(uint8_t, uint8_t); + + /** + * unsetRegister: unsets a register bit fromt he register number and bitmask + **/ + void unsetRegister(uint8_t, uint8_t); + + /** + * getRegister: returns the specified register + **/ + uint8_t getRegister(uint8_t); + + /** + * clockGet: fills an array with the current time data + **/ + void clockGet(uint16_t *); + + /** + * clockGet: gets a specific item from the clock buffer + * use the second param to specify a buffer refresh + **/ + uint16_t clockGet(uint8_t, boolean); + + /** + * clockSet: Set the clock time using integer values + * Does not do any GMT or DST correction + **/ + #ifdef DS1337_USE_BCD_CLOCKSET + void clockSet(uint8_t, uint16_t); + #endif + + /** + * calculateUTS: returns the time as a unix time stamp + * This function doesn't take into account having DST set or not! + * + * Use the macro getUTS macro to access this function! + **/ + #ifdef DS1337_USE_GET_UTS + uint32_t calculateUTS(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec); + #endif + + /** + * clockSetWithUTS: sets the date & time from a unix time stamp + * pass the second param as true to skip DTS and GMT calculation + * + * Use the clockSet macro to access this function! + **/ + void clockSetWithUTS(uint32_t, boolean); + + /** + * Prints all of the DS1337 registers + **/ + + void printRegisters(void); + #ifdef DS1337_USE_ALARMS + /** + * alarmSelect: allows selection of the DS1337 alarm 1 or 2 + * false for alarm 1 and true for alarm 2 + **/ + void alarmSelect(boolean); + + /** + * Allows setting an alarm's date and time using integers + **/ + void alarmSet(uint8_t, uint8_t); + + /** + * alarmCheck: checks if an alarm flag was set and reset the flag + * set param to true to check for both registers false (or void) to check for the selected alarm + **/ + boolean alarmCheck(boolean); + boolean alarmCheck(void); // Same as above using false + #endif + private: + /** + * Hold a unix time stamp + **/ + #if defined(DS1337_USE_SET_UTS) || defined(DS1337_USE_GET_UTS) + uint32_t tt; + #endif + + /** + * Holds the RTC BCD time buffer + **/ + uint8_t rtc_bcd[8]; + + /** + * Writes a value to a clock register + **/ + void writeRegister(uint8_t, uint8_t); + + /** + * Write the RTC BCD buffer to the clock + **/ + void clockSave(void); + + /** + * Read the RTC BCD buffer to the clock + **/ + void clockRead(void); + + /** + * Converts a BCD to a binary integer + **/ + uint8_t bcdToBin(uint8_t, uint8_t); + + /** + * Converts a binary integer to BCD + **/ + uint8_t binToBcd(uint8_t); + + #ifdef DS1337_USE_ALARMS + /** + * Hold the buffer for alarm manipulation + **/ + uint8_t rtc_alarm[4]; + + /** + * alarmId: keeps track of which alarm we are working with + **/ + boolean alarmId; + + /** + * Writes the alarm buffer to the RTC + **/ + void alarmSave(void); + #endif +}; + +/** + * Define the Object's name +**/ +extern DS1337 RTC; + +#endif diff --git a/ds1624/ds1624.cpp b/ds1624/ds1624.cpp new file mode 100644 index 0000000..53cba46 --- /dev/null +++ b/ds1624/ds1624.cpp @@ -0,0 +1,61 @@ +extern "C" { + #include +} + +#include "../global.h" +#include "ds1624.h" + +DS1624::DS1624() +{ +#ifdef WIRE_LIB_SCAN_MOD + /*if (!Wire.isStarted())*/ Wire.begin(); +#else + Wire.begin(); +#endif +} + +DS1624 TEMP = DS1624(); + +void DS1624::Init(void) +{ + Wire.beginTransmission(DS1624_ADDR); + Wire.send(DS1624_CONFIG); + Wire.send(DS1624_CONFIGS); + Wire.endTransmission(); + + delay(10); + + Wire.beginTransmission(DS1624_ADDR); + Wire.send(DS1624_CONFIG); + Wire.endTransmission(); + + Wire.requestFrom(DS1624_ADDR, 1); + + Wire.beginTransmission(DS1624_ADDR); + Wire.send(DS1624_SMPL_START); + Wire.endTransmission(); + +#ifdef DS1624_HANDLE_BOOT_DELAY + delay(1500); +#endif +} + +uint16_t DS1624::readTemp(void) +{ + uint16_t res = 0; + Wire.beginTransmission(DS1624_ADDR); + Wire.send(DS1624_READ_TEMP); + Wire.endTransmission(); + + Wire.requestFrom(DS1624_ADDR, 2); + + while (!Wire.available()); + + res = (uint8_t) (Wire.receive())<<8; + + while (!Wire.available()); + + res |= (uint8_t) Wire.receive(); + + return res; +} diff --git a/ds1624/ds1624.h b/ds1624/ds1624.h new file mode 100644 index 0000000..930f2cb --- /dev/null +++ b/ds1624/ds1624.h @@ -0,0 +1,57 @@ +#ifndef DS1624_H +#define DS1624_H + +// include types & constants of Wiring core API +#include +#include + +// include types & constants of Wire ic2 lib +#include + +/** + * Comment this out if you don't want the + * init function to account for the ~1S startup + * delay for the first temperature sample! +**/ +#define DS1624_HANDLE_BOOT_DELAY + +/** + * Address byte selection + * Select 0 for low and 1 for high +**/ +#define DS1624_A0 0 +#define DS1624_A1 0 +#define DS1624_A2 0 + +#define DS1624_BASE_ADDR B01001000 +#define DS1624_ADDR DS1624_BASE_ADDR | (DS1624_A0 * B00000001) | (DS1624_A1 * B00000010) | (DS1624_A2 * B00000100) + +/** + * Registers and bit mask definition +**/ +#define DS1624_CONFIG 0xAC +#define DS1624_CONFIG_DONE B10000000 +#define DS1624_CONFIG_1SHOT B00000001 +#define DS1624_CONFIG_CONT B00000000 + +// Select your config here! +#define DS1624_CONFIGS DS1624_CONFIG_CONT + +#define DS1624_READ_TEMP 0xAA +#define DS1624_SMPL_START 0xEE +#define DS1624_SMPL_STOP 0x22 +#define DS1624_ACCESS_MEM 0x17 + +class DS1624 +{ + public: + DS1624(); + void Init(void); + uint16_t readTemp(void); + private: + +}; + +extern DS1624 TEMP; + +#endif diff --git a/ds1803/ds1803.cpp b/ds1803/ds1803.cpp new file mode 100644 index 0000000..a09c5ef --- /dev/null +++ b/ds1803/ds1803.cpp @@ -0,0 +1,46 @@ +extern "C" { + #include +} + +#include "../global.h" +#include "ds1803.h" + +DS1803::DS1803() +{ +#ifdef WIRE_LIB_SCAN_MOD + /*if (!Wire.isStarted())*/ Wire.begin(); +#else + Wire.begin(); +#endif +} + +/** + * Instantiate the object +**/ +DS1803 DPOT = DS1803(); + +void DS1803::setWiper(uint8_t value, uint8_t wiperAddr) +{ + if (!Wire.checkAddress(DPOT_WADDR)) return; + + Wire.beginTransmission(DPOT_WADDR); + Wire.send(wiperAddr); // Send the wiper address + + Wire.send(value); + + Wire.endTransmission(); +} +/* +uint8_t DS1803::getValue() +{ + if (!Wire.checkAddress(DPOT_WADDR)) return; + + Wire.requestFrom(DPOT_RADDR, 2); + + while (Wire.available()) { + Serial.println((uint8_t)Wire.receive(), DEC); + } + + return 0; +} +*/ diff --git a/ds1803/ds1803.h b/ds1803/ds1803.h new file mode 100644 index 0000000..e0856dd --- /dev/null +++ b/ds1803/ds1803.h @@ -0,0 +1,44 @@ +#ifndef DS1803_H +#define DS1803_H + +#include + +#define DPOT_WADDR 0x28 +#define DPOT_RADDR DPOT_WADDR | 0x01 + +/** + * The number of available potentiometer wipers +**/ +#define DPOT_NBR_WIPERS 0x02 + +/** + * Digital pot selection commands +**/ +#define DPOT_WIPERS B10101111 +#define DPOT_WIPER_0 B10101001 +#define DPOT_WIPER_1 B10101010 + +/** + * Macros +**/ +#define setWiper1(value) setWiper(value, DPOT_WIPER_0) +#define setWiper2(value) setWiper(value, DPOT_WIPER_1) +#define setWipers(value) setWiper(value, DPOT_WIPERS) + +/** + * DS1803 I2C Dual Digital Pot. +**/ +class DS1803 +{ + public: + DS1803(); + void setWiper(uint8_t, uint8_t); + //uint8_t getValue(); +}; + +/** + * Define the object's name +**/ +extern DS1803 DPOT; + +#endif diff --git a/global.h b/global.h new file mode 100644 index 0000000..7b9d230 --- /dev/null +++ b/global.h @@ -0,0 +1,45 @@ +#ifndef GLOBAL_H +#define GLOBAL_H + +extern "C" { + #include + #include + #include + #include + #include + + #include "wiring.h" + #include "WConstants.h" + + #include +} + +#include "staticPrint/staticPrint.h" + +#ifndef BV + #define BV(bit) (1<<(bit)) +#endif + +#ifndef cbi + #define cbi(reg,bit) reg &= ~(BV(bit)) +#endif +#ifndef sbi + #define sbi(reg,bit) reg |= (BV(bit)) +#endif + +#ifndef CI + #define CI(reg,bit) (reg & ~(bit)) +#endif +#ifndef SI + #define SI(reg,bit) (reg | bit) +#endif + + +#ifndef cli + #define cli() __asm__ __volatile__ ("cli" ::) +#endif +#ifndef sei + #define sei() __asm__ __volatile__ ("sei" ::) +#endif + +#endif diff --git a/twiLCD/twiLCD.cpp b/twiLCD/twiLCD.cpp new file mode 100644 index 0000000..d804fa8 --- /dev/null +++ b/twiLCD/twiLCD.cpp @@ -0,0 +1,427 @@ +extern "C" { + #include +} + +#include "../global.h" +#include "../configs/LCD/lcd.h" +#include "twiLCD.h" + +#ifdef TWI_LCD_DPOT_CTRL +#include "../ds1803/ds1803.h" +#endif + +twiLCD::twiLCD() +{ +#if defined(__AVR_ATmega168__) && !defined(TWI_LCD_SMALL) + #if defined(TWI_LCD_CTRL) && !defined(TWI_LCD_BL_PWM) + backlightStatus = 0; + #endif + + #ifdef TWI_LCD_BL_PWM + pinMode(TWI_LCD_BACKLIGHT, HIGH); + #endif + + displayStatus = false; +#endif + +#ifdef WIRE_LIB_SCAN_MOD + /*if (!Wire.isStarted())*/ Wire.begin(); +#else + Wire.begin(); +#endif +} + +twiLCD LCD = twiLCD(); + +void twiLCD::Init() { +#ifdef TWI_LCD_CTRL + backlightOff(); +#ifdef TWI_LCD_DPOT_CTRL + setBrightness(0); +#endif +#endif + delay(20); +/////////// 4 pin initialization + writeCommand(0x03); // function set: 4 pin initialization + delay(5); + writeCommand(0x03); // function set: 4 pin initialization + delay(1); + writeCommand(0x03); // function set: 4 pin initialization + delay(1); + writeCommand(0x02); // function set: 4 pin initialization +/////////// end of 4 pin initialization + + + writeCommand(LCD_FUNCTION_SET); // function set: 4-bit interface, 1 display lines, 5x7 font + writeCommand(LCD_ENTRY_MODE); + writeCommand(LCD_CURSOR); + clearScreen(); + + writeCommand(LCD_CLOSE_INIT); + +#if defined(__AVR_ATmega168__) && !defined(TWI_LCD_SMALL) +#ifdef TWI_LCD_CTRL + #if defined(TWI_LCD_BL_PWM) || defined(TWI_LCD_DPOT_CTRL) + #ifdef TWI_LCD_DPOT_CTRL + setBrightness(); + #endif + backlightOn(TWI_LCD_BL_LEVEL); + #else + backlightOn(); + #endif +#endif + + displayStatus = true; +#endif +} + +boolean twiLCD::checkLCDBusy(void) +{ + Wire.requestFrom(PCF8574_RADDR, 1); + + while (!Wire.available()); + + return (Wire.receive() & TWI_LCD_BUSY ? true : false); +} + +void twiLCD::writeCommand(uint8_t value) +{ + int value1 = 0; + int control = 0; // stores RS and RW + +#ifdef TWI_LCD_USE_TIMEOUT + previousMillis = millis(); +#endif + + control = value >> 8; // get the control signals RS and RW + control >>= 5; // shift the control signals to the left + + Wire.beginTransmission(PCF8574_WADDR); + + value1 = value; + cbi(value1, TWI_LCD_DATAL); // Turn off LByte + + cbi(value1, TWI_LCD_RS); + cbi(value1, TWI_LCD_RW); + + sendPulse(value1); + + delay(1); + + cbi(value, TWI_LCD_DATAH); // Turn off HByte + value <<= 4; + + cbi(value, TWI_LCD_RS); + cbi(value, TWI_LCD_RW); + + sendPulse(value); + + Wire.endTransmission(); + + delay(1); +} + +void twiLCD::writeData(uint8_t value) +{ + int value1 = 0; + int control = 0; // stores RS and RW + + // Wait for the LCD to be ready + +#ifdef TWI_LCD_USE_TIMEOUT + previousMillis = millis(); +#endif + + control = value >> 8; // get the control signals RS and RW + control >>= 5; // shift the control signals to the left + + value1 = value; + cbi(value1, TWI_LCD_DATAL); // Turn off LByte + sbi(value1, TWI_LCD_RS); + cbi(value1, TWI_LCD_RW); + + while (checkLCDBusy()); + + Wire.beginTransmission(PCF8574_WADDR); + sendPulse(value1); + + delay(1); + + cbi(value, TWI_LCD_DATAH); // Turn off HByte + value <<= 4; + + sbi(value, TWI_LCD_RS); + cbi(value, TWI_LCD_RW); + + sendPulse(value); + Wire.endTransmission(); +} + +void twiLCD::sendPulse(int value) +{ + cbi(value, TWI_LCD_ENABLE); + writeToPCF(value); + + sbi(value, TWI_LCD_ENABLE); + writeToPCF(value); + + cbi(value, TWI_LCD_ENABLE); + writeToPCF(value); +} + +void twiLCD::writeToPCF(int value) +{ +#if defined(TWI_LCD_CTRL) && !defined(TWI_LCD_BL_PWM) + if (backlightStatus) + sbi(value, TWI_LCD_BACKLIGHT); + else + cbi(value, TWI_LCD_BACKLIGHT); + + Wire.send(value); +#else + Wire.send(value); +#endif +} + +void twiLCD::clearScreen(void) +{ + writeCommand(LCD_CLEAR); + delay(100); + +#if defined(__AVR_ATmega168__) && !defined(TWI_LCD_SMALL) + currentLine = 1; +#endif + +#ifdef LCD_USE_CLRSCREEN_CALLBACK + onClearScreen(); +#endif +} + +void twiLCD::printString_P(const char *data) +{ + int ch; + + for (;;) { + ch = pgm_read_byte( data++ ); + if ( !ch ) return; + writeData(ch); + } +} + +#if defined(__AVR_ATmega168__) && !defined(TWI_LCD_SMALL) +#ifdef TWI_LCD_USE_TIMEOUT +bool twiLCD::checkTimeout(void) +{ + if (displayStatus && millis() - previousMillis > TWI_LCD_TIMEOUT) { + turnOff(); + return true; + } + + return false; +} +#endif + +#ifdef TWI_LCD_CTRL +#ifdef TWI_LCD_BL_PWM +void twiLCD::backlightOn(void) +{ + digitalWrite(TWI_LCD_BACKLIGHT, HIGH); +} + +void twiLCD::backlightOn(uint8_t value) +{ + analogWrite(TWI_LCD_BACKLIGHT, value); +} + +void twiLCD::backlightOff(void) +{ + digitalWrite(TWI_LCD_BACKLIGHT, LOW); +} +#else +#ifdef TWI_LCD_DPOT_CTRL +void twiLCD::backlightOn(void) +{ + DPOT.setWiper2(TWI_LCD_BL_LEVEL); +} + +void twiLCD::backlightOn(uint8_t value) +{ + DPOT.setWiper2(value); +} + +void twiLCD::backlightOff(void) +{ + DPOT.setWiper2(0); +} + +void twiLCD::setBrightness(void) +{ + DPOT.setWiper1(TWI_LCD_DB_LEVEL); +} + +void twiLCD::setBrightness(uint8_t value) +{ + DPOT.setWiper1(value); +} + +#else +void twiLCD::backlightOn(void) +{ + int val = 0; + backlightStatus = 1; + sbi(val, TWI_LCD_BACKLIGHT); + + Wire.beginTransmission(PCF8574_WADDR); + Wire.send(val); + Wire.endTransmission(); +} + +void twiLCD::backlightOff(void) +{ + int val = 0; + backlightStatus = 0; + cbi(val, TWI_LCD_BACKLIGHT); + + Wire.beginTransmission(PCF8574_WADDR); + Wire.send(val); + Wire.endTransmission(); +} +#endif +#endif +#endif + +void twiLCD::turnOff(void) +{ + writeCommand(LCD_TURN_OFF); +#if defined(TWI_LCD_CTRL) + backlightOff(); +#ifdef TWI_LCD_DPOT_CTRL + setBrightness(0); +#endif +#endif + displayStatus = false; +} + +/** + * This function needs a rewrite +**/ +void twiLCD::setCursor(int index) +{ + //0-79, index for one line display, 8 bit mode + //0-39 and 64-103 for lines one and two of two line display, not implemented yet + int cmd = 128+index; + writeCommand(cmd); +} + +/** + * This function needs a rewrite +**/ +void twiLCD::moveToXY(uint8_t row, uint8_t column) +{ + int position; + + // Determine the new position + position = (row * 20) + column; + + // Send the correct commands to the command register of the LCD + if(position < 20) + writeCommand(0x80 | position); + else if(position >= 20 && position < 40) + writeCommand(0x80 | (position % 20 + 0x40)); + else if(position >= 41 && position < 60) + writeCommand(0x80 | (position % 40 + 0x14)); + else if(position >= 20 && position < 40) + writeCommand(0x80 | (position % 60 + 0x54)); +} + +uint8_t twiLCD::getCurrentLine(void) +{ + return currentLine; +} + +void twiLCD::goToLine(uint8_t line) +{ + if (line > LCD_ROWS) return; + moveToXY(line - 1, 0); + currentLine = line; +} + +void twiLCD::goToNextLine(void) +{ + if (currentLine+1 > LCD_ROWS) { + goToLine(1); + } else { + goToLine(currentLine+1); + } +} + +void twiLCD::goHome(void) +{ + writeCommand(LCD_GO_HOME); // set cursor position to zero + currentLine = 1; +} + +void twiLCD::clearLine(void) +{ + int ii; + moveToXY(currentLine-1, 0); + + for (ii=0;ii 0) writeData(thousands + 0x30); + + uint8_t hundreds = (integer - thousands*1000) / 100; + if (hundreds > 0 || thousands > 0) + writeData(hundreds + 0x30); + + uint8_t tens = (integer - thousands*1000 - hundreds*100 ) / 10; + if (tens || hundreds > 0 || thousands > 0) + writeData(tens + 0x30); + + uint8_t ones = (integer - thousands*1000 - hundreds*100 - tens*10); + writeData(ones + 0x30); +} + +#endif diff --git a/twiLCD/twiLCD.h b/twiLCD/twiLCD.h new file mode 100644 index 0000000..86aabd7 --- /dev/null +++ b/twiLCD/twiLCD.h @@ -0,0 +1,220 @@ +#ifndef twiLCD_H + #define twiLCD_H + + #include + + #include "twiLCDConfig.h" + + #define PCF8574_WADDR 0x20 + #define PCF8574_RADDR PCF8574_WADDR | 0x01 + + #define TWI_LCD_RS 0 /* RS pin */ + #define TWI_LCD_RW 1 /* RW pin */ + #define TWI_LCD_ENABLE 2 /* Enable pin */ +#ifdef TWI_LCD_CTRL +#ifdef TWI_LCD_BL_PWM + #define TWI_LCD_BACKLIGHT 9 /* This is an Arduino pin number! */ +#else + #define TWI_LCD_BACKLIGHT 3 /* Backlight pin */ +#endif +#endif + + #define TWI_LCD_CONTROL B00000111 /* Mask for the 3 control bits (E, RS, RW) */ + #define TWI_LCD_DATA B11110000 /* Mask for the 4 bit word */ + #define TWI_LCD_DATAH B11110000 + #define TWI_LCD_DATAL B00001111 + #define TWI_LCD_BUSY B00001000 + +#ifndef printString + #define printString(str) printString_P(PSTR(str)) +#endif + + class twiLCD { + public: + /** + * Constructor: initializes this class + **/ + twiLCD(); + + /** + * LCD Initilization method + **/ + void Init(); + + /** + * writeData: write a byte of data to the LCD + * @param: value: the byte to write + **/ + void writeData(uint8_t value); + + /** + * clearScreen: clears the LCD and resets the cursor position to 0,0 + **/ + void clearScreen(void); + + /** + * printString_P: prints a program string to the LCD + * To call this function, use the LCD.printString() macro! + **/ + void printString_P(const char *data); + /** + * These function are only available on the mega168 for space reasons + **/ + #if defined(__AVR_ATmega168__) && !defined(TWI_LCD_SMALL) + + /** + * Methods for dealing with LCD timeout + * Returns true if the time is expired + **/ + #ifdef TWI_LCD_USE_TIMEOUT + bool checkTimeout(void); + #endif + + /** + * Backlight control functions + * Optionally enabled above + **/ + #ifdef TWI_LCD_CTRL + /** + * backlightOn: Turn on the backlight at full brightness + **/ + void backlightOn(void); + + /** + * backlightOff: turn off the LCD backlight + **/ + void backlightOff(void); + + // PWM Backlight Control + #if defined(TWI_LCD_BL_PWM) || defined(TWI_LCD_DPOT_CTRL) + /** + * backlightOn: turns on the backlight with a specific brightness + **/ + void backlightOn(uint8_t); + #endif + + #ifdef TWI_LCD_DPOT_CTRL + /** + * setBrightness: sets the brightness level using a digital pot + * If no param is passed TWI_LCD_DB_LEVEL is used + **/ + void setBrightness(void); + void setBrightness(uint8_t); + #endif + #endif + + /** + * setCursor: set cursor a position "index" + **/ + void setCursor(int); + + /** + * moveToXY: moves the cursor to position (row,column) + **/ + void moveToXY(uint8_t, uint8_t); + + /** + * Turn off the LCD (will turn off the backlight if control is enabled) + **/ + void turnOff(void); + + /** + * goToLine: Allows to move at the beginning of a specific line + **/ + void goToLine(uint8_t); + + /** + * goToNextLine: goes to the next line, wraps arround at the end + **/ + void goToNextLine(void); + + /** + * goHome: goes to position (0,0) + **/ + void goHome(void); + + /** + * clearLine: clears the current line + **/ + void clearLine(void); + + /** + * shiftDisplayLeft: shift all lines of the display one position to the left + **/ + void shiftDisplayLeft(void); + + /** + * shiftDisplayRight: shift all lines of the display one position to the right + **/ + void shiftDisplayRight(void); + + /** + * getCurrentLine: returns the current line + **/ + uint8_t getCurrentLine(void); + + /** + * getCurrentStatus: returns whether the display is on or off + **/ + bool getCurrentStatus(void); + + /** + * printInteger: writes an interger as text on the lcd + * The second version is only good for intergers < 99 and will add a leading zero + **/ + void printInteger(int16_t); + void printInteger(uint16_t integer, bool leadingZero); + #endif + private: + #if defined(__AVR_ATmega168__) && !defined(TWI_LCD_SMALL) + #ifdef TWI_LCD_USE_TIMEOUT + unsigned long previousMillis; + #endif + + #if defined(TWI_LCD_CTRL) && !defined(TWI_LCD_BL_PWM) + /** + * backlightStatus: used to keep track of the backlight status + **/ + uint8_t backlightStatus; + #endif + + /** + * currentLine: keeps track of the current line + **/ + uint8_t currentLine; + + /** + * displayStatus: keeps track of whether the display is on or off + **/ + bool displayStatus; + #endif + /** + * sendPulse: sends a byte of data with the appropiate Enable pulse + **/ + void sendPulse(int); + + /** + * writeToPCF: writes a new byte of data using twi + * This function is used to preserve some data through writes + * such as when bit3 of the expander is used to control the backlight + **/ + void writeToPCF(int); + + /** + * writeCommand: Writes an LCD command + * @param: value: the value to write + **/ + void writeCommand(uint8_t value); + + /** + * checkLCDBusy: reads the busy state bit from the LCD + **/ + boolean checkLCDBusy(void); + }; + + /** + * Define the object's name + **/ + extern twiLCD LCD; + +#endif diff --git a/twiLCD/twiLCDConfig.h b/twiLCD/twiLCDConfig.h new file mode 100644 index 0000000..6ddf4dd --- /dev/null +++ b/twiLCD/twiLCDConfig.h @@ -0,0 +1,42 @@ +#ifndef TWI_LCD_CONF_H +#define TWI_LCD_CONF_H + +// Uncomment this to use minimal mode (less functions, not as big) +// #define TWI_LCD_SMALL + +#if defined(__AVR_ATmega168__) && !defined(TWI_LCD_SMALL) + // Uncomment this to enable use of a timeout after which the LCD turns off + #define TWI_LCD_USE_TIMEOUT + +#ifdef TWI_LCD_USE_TIMEOUT + #define TWI_LCD_TIMEOUT 5000 /* In milliseconds (30 sec) */ +#endif + + // Uncomment this to enable control of the backlight on pin 3 + #define TWI_LCD_CTRL + +#ifdef TWI_LCD_CTRL + // Uncomment this to use PWM for backlight control. + //#define TWI_LCD_BL_PWM + +#ifdef TWI_LCD_BL_PWM + // Set this to the default brightness for PWM controlled backlight + #define TWI_LCD_BL_LEVEL 255 +#endif + +#ifndef TWI_LCD_BL_PWM + // Uncomment this use the DS1803 digi-pot for display/backlight brightness + #define TWI_LCD_DPOT_CTRL + +#ifdef TWI_LCD_DPOT_CTRL + // Set this to the default value of the backlight (0 to 254) + #define TWI_LCD_BL_LEVEL 254 + + // Set this to the default value of the display brightness (0 to 254) + #define TWI_LCD_DB_LEVEL 225 +#endif +#endif +#endif +#endif + +#endif