406 lines
9.8 KiB
C++
406 lines
9.8 KiB
C++
/********************************************************
|
|
* Clock Library for Studuino mini
|
|
* 2016/3/29 ArTec Co.,Ltd.
|
|
* Software SPI
|
|
*
|
|
*
|
|
********************************************************/
|
|
#include "Clock.h"
|
|
|
|
volatile clockparams_t clockparams;
|
|
byte rFirst;
|
|
unsigned long lastUpdateTime;
|
|
unsigned long lastUpdateDate;
|
|
unsigned long lastUpdateAlarm;
|
|
unsigned long lastUpdateMode;
|
|
unsigned long lastUpdateTemp;
|
|
boolean fSending;
|
|
byte alarmState; // 0:off 1:on 2:snooze
|
|
boolean fOnAlarm; // false:off true:on
|
|
boolean pushMonitor;
|
|
boolean fBackLightOff;
|
|
unsigned long lastPushTime;
|
|
unsigned long t2counter;
|
|
|
|
|
|
//割り込み関数
|
|
// Pushボタン、Alarmボタンの監視をする
|
|
ISR(TIMER1_COMPB_vect)
|
|
{
|
|
if(pushMonitor) {
|
|
byte pushed = (clockparams.mode >> 6) & 0x01;
|
|
byte almode = (clockparams.mode >> 2) & 0x03;
|
|
|
|
if(pushed == 1) {
|
|
if(alarmState == 1) {
|
|
alarmState = 0;
|
|
if(fOnAlarm) {
|
|
noTone(8);
|
|
fBackLightOff = true;
|
|
fOnAlarm = false;
|
|
pushMonitor = false;
|
|
lastPushTime = clockparams.hour * 60 + clockparams.minute;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(almode == 0) {
|
|
alarmState = 0;
|
|
if(fOnAlarm) {
|
|
noTone(8);
|
|
fBackLightOff = true;
|
|
fOnAlarm = false;
|
|
pushMonitor = false;
|
|
lastPushTime = clockparams.hour * 60 + clockparams.minute;
|
|
}
|
|
}
|
|
} else {
|
|
if(fBackLightOff) {
|
|
byte data[3];
|
|
data[0] = 0xa5;
|
|
data[1] = 0;
|
|
data[2] = 0;
|
|
writeCommand(data, 3);
|
|
fBackLightOff = false;
|
|
}
|
|
}
|
|
if(lastPushTime != (clockparams.hour * 60 + clockparams.minute)) alarmState = 1;
|
|
}
|
|
|
|
ISR(TIMER2_OVF_vect)
|
|
{
|
|
t2counter++;
|
|
}
|
|
|
|
void writeCommand(byte* command, byte length) {
|
|
fSending = true;
|
|
rFirst = 1;
|
|
for(byte i = 0; i < length; i++) {
|
|
writeByteData(command[i]);
|
|
}
|
|
delayMicroseconds(DELAY1);
|
|
fSending = false;
|
|
}
|
|
|
|
byte writeByteData(byte _send) { // This function is what bitbangs the data
|
|
byte Read_Write_Count = 0;
|
|
|
|
for(Read_Write_Count = 0; Read_Write_Count < 8; Read_Write_Count++) { // There are 8 bits in a byte
|
|
PORTB |= B00100000; // SCK high
|
|
delayMicroseconds(DELAY_WRITE1); // Delay_2US(100);
|
|
if(_send & 0x80) {
|
|
PORTB |= B00001000; // MOSI high
|
|
} else {
|
|
PORTB &= B11110111; // MOSI low
|
|
}
|
|
delayMicroseconds(DELAY_WRITE2); // Delay_2US(30);
|
|
_send = (_send << 1);
|
|
PORTB &= B11011111; // SCK low
|
|
if(rFirst) {
|
|
rFirst = 0;
|
|
delayMicroseconds(DELAY_WRITE3); // Delay_2US(2000);
|
|
} else {
|
|
delayMicroseconds(DELAY_WRITE4); // Delay_2US(100);
|
|
}
|
|
}
|
|
|
|
PORTB |= B00101000; // MOSI, SCK high
|
|
return _send; // Return the received data
|
|
}
|
|
|
|
byte readByteData() { // This function is what bitbangs the data
|
|
byte Read_Write_Count = 0;
|
|
byte _receive = 0;
|
|
rFirst = 1;
|
|
|
|
for(Read_Write_Count = 0; Read_Write_Count < 8; Read_Write_Count++) { // There are 8 bits in a byte
|
|
PORTB |= B00100000; // SCK high
|
|
delayMicroseconds(DELAY_READ1); // Delay_2US(100);
|
|
PORTB &= B11011111; // SCK low
|
|
|
|
if(rFirst) {
|
|
rFirst = 0;
|
|
delayMicroseconds(DELAY_READ2); // Delay_2US(2000);
|
|
} else {
|
|
delayMicroseconds(DELAY_READ3); // Delay_2US(50);
|
|
}
|
|
_receive = _receive << 1;
|
|
if(digitalRead(MISO_pin))
|
|
_receive |= 0x01;
|
|
delayMicroseconds(DELAY_READ4); // Delay_2us(60);
|
|
PORTB |= B00100000; // SCK high
|
|
delayMicroseconds(DELAY_READ5); // Delay_2US(80);
|
|
}
|
|
|
|
delayMicroseconds(DELAY_READ6); // Delay_2US(200);
|
|
PORTB |= B00100000; // SCK high
|
|
return _receive; // Return the received data
|
|
}
|
|
|
|
// update functions
|
|
void updateTime() { // 0: hour 1: minute
|
|
if(!fSending) {
|
|
if(millis() - lastUpdateTime + T2CYCLE * t2counter > UPD_INTVAL_TIME) {
|
|
rFirst = 1;
|
|
writeByteData(0xb1);
|
|
byte buf = readByteData();
|
|
clockparams.hour = (buf / 16) * 10 + (buf % 16);
|
|
buf = readByteData();
|
|
clockparams.minute = (buf / 16) * 10 + (buf % 16);
|
|
lastUpdateTime = millis() + T2CYCLE * t2counter;
|
|
}
|
|
}
|
|
}
|
|
|
|
void updateDate() {
|
|
if(!fSending) {
|
|
if(millis() - lastUpdateDate + T2CYCLE * t2counter > UPD_INTVAL_DATE) {
|
|
rFirst = 1;
|
|
writeByteData(0xb2);
|
|
byte buf = readByteData();
|
|
clockparams.year = 2000 + (buf / 16) * 10 + (buf % 16);
|
|
buf = readByteData();
|
|
clockparams.month = (buf / 16) * 10 + (buf % 16);
|
|
buf = readByteData();
|
|
clockparams.day = (buf / 16) * 10 + (buf % 16);
|
|
lastUpdateDate = millis() + T2CYCLE * t2counter;
|
|
}
|
|
}
|
|
}
|
|
|
|
void updateMode() {
|
|
if(!fSending) {
|
|
if(millis() - lastUpdateMode + T2CYCLE * t2counter > UPD_INTVAL_MODE) {
|
|
rFirst = 1;
|
|
writeByteData(0xb3);
|
|
clockparams.mode = readByteData();
|
|
lastUpdateMode = millis() + T2CYCLE * t2counter;
|
|
}
|
|
}
|
|
}
|
|
|
|
void updateAlarm() {
|
|
if(!fSending) {
|
|
if(millis() - lastUpdateAlarm + T2CYCLE * t2counter > UPD_INTVAL_ALARM) {
|
|
rFirst = 1;
|
|
writeByteData(0xb4);
|
|
byte buf = readByteData();
|
|
clockparams.alhour = (buf / 16) * 10 + buf % 16;
|
|
buf = readByteData();
|
|
clockparams.alminute = (buf / 16) * 10 + buf % 16;
|
|
lastUpdateAlarm = millis() + T2CYCLE * t2counter;
|
|
}
|
|
}
|
|
}
|
|
|
|
void updateTemperature() {
|
|
if(!fSending) {
|
|
if(millis() - lastUpdateTemp + T2CYCLE * t2counter > UPD_INTVAL_TEMP) {
|
|
rFirst = 1;
|
|
writeByteData(0xb5);
|
|
byte data[2];
|
|
data[0] = readByteData();
|
|
data[1] = readByteData();
|
|
byte var = data[0] / 16;
|
|
clockparams.temperature = (data[0] % 16) * 100 + (data[1] / 16) * 10 + (data[1] % 16);
|
|
if(var != 0)
|
|
clockparams.temperature = 1000 - clockparams.temperature;
|
|
lastUpdateTemp = millis() + T2CYCLE * t2counter;
|
|
}
|
|
}
|
|
}
|
|
|
|
void updateAll() {
|
|
fSending = true;
|
|
updateTime();
|
|
delayMicroseconds(5000);
|
|
updateDate();
|
|
delayMicroseconds(5000);
|
|
updateAlarm();
|
|
delayMicroseconds(5000);
|
|
updateMode();
|
|
delayMicroseconds(5000);
|
|
fSending = false;
|
|
}
|
|
|
|
/***** Clock class function definitions *****/
|
|
Clock::Clock() {
|
|
}
|
|
|
|
// 液晶時計に使用するピンを初期化し、SCK_pinをHIGHに設定する
|
|
void Clock::initClockPinSet() {
|
|
pinMode(SCK_pin, OUTPUT);
|
|
pinMode(MISO_pin, INPUT);
|
|
pinMode(MOSI_pin, OUTPUT);
|
|
pinMode(BZR_pin, OUTPUT);
|
|
|
|
digitalWrite(SCK_pin, HIGH);
|
|
digitalWrite(MOSI_pin, HIGH);
|
|
|
|
// タイマー1コンペアB割り込みを使用する。
|
|
// Servoライブラリが使用するコンペアAの設定と合わせる。
|
|
TCCR1A = 0b00000000;
|
|
TCCR1B = 0b00000010;
|
|
OCR1BH = 0x00;
|
|
OCR1BL = 0xff;
|
|
TIMSK1 |= 0b00000100;
|
|
|
|
// タイマー2オーバーフロー割り込みを使用する
|
|
TCCR2A = 0;
|
|
TCCR2B = 7; // 分周比 1/1024
|
|
|
|
|
|
delay(2000);
|
|
|
|
TIMSK2 = 1;
|
|
alarmState = 1;
|
|
}
|
|
|
|
/* :::::::::::::: 設定用関数 ::::::::::::::::::::::::::: */
|
|
// 時間の設定
|
|
void Clock::setTime(byte hour, byte minute) {
|
|
byte data[3];
|
|
data[0] = 0xa1;
|
|
data[1] = (hour / 10) * 16 + (hour % 10);
|
|
data[2] = (minute / 10) * 16 + (minute % 10);
|
|
writeCommand(data, 3);
|
|
}
|
|
|
|
// 日付の設定
|
|
void Clock::setDate(byte year, byte month, byte day) {
|
|
byte data[4];
|
|
data[0] = 0xa2;
|
|
data[1] = (year / 10) * 16 + (year % 10);
|
|
data[2] = (month / 10) * 16 + (month % 10);
|
|
data[3] = (day / 10) * 16 + (day % 10);
|
|
writeCommand(data, 4);
|
|
}
|
|
|
|
// 12h/24h, C/Fの設定
|
|
void Clock::setTimeTempMode(byte mode) {
|
|
byte data[2];
|
|
data[0] = 0xa3;
|
|
data[1] = mode;
|
|
writeCommand(data, 2);
|
|
}
|
|
|
|
// アラーム時間の設定
|
|
void Clock::setAlarm(byte hour, byte minute) {
|
|
byte data[3];
|
|
data[0] = 0xa4;
|
|
data[1] = (hour / 10) * 16 + (hour % 10);
|
|
data[2] = (minute / 10) * 16 + (minute % 10);
|
|
writeCommand(data, 3);
|
|
}
|
|
|
|
// 液晶バックライトの設定
|
|
void Clock::setBackLight(boolean on, byte red, byte green, byte blue) {
|
|
byte data[3];
|
|
data[0] = 0xa5;
|
|
data[1] = on * 16 + red;
|
|
data[2] = blue * 16 + green;
|
|
writeCommand(data, 3);
|
|
delay(50); // Only for this function.
|
|
}
|
|
|
|
/* :::::::::::::: データ取得用関数 ::::::::::::::::::::::::::: */
|
|
// 時間取得
|
|
byte Clock::getHour() {
|
|
updateTime();
|
|
return clockparams.hour;
|
|
}
|
|
|
|
byte Clock::getMinute() {
|
|
updateTime();
|
|
return clockparams.minute;
|
|
}
|
|
|
|
// 日付取得
|
|
unsigned int Clock::getYear() {
|
|
updateDate();
|
|
return clockparams.year;
|
|
}
|
|
|
|
byte Clock::getMonth() {
|
|
updateDate();
|
|
return clockparams.month;
|
|
}
|
|
|
|
byte Clock::getDay() {
|
|
updateDate();
|
|
return clockparams.day;
|
|
}
|
|
|
|
// モード取得
|
|
byte Clock::getMode() {
|
|
updateMode();
|
|
return clockparams.mode;
|
|
}
|
|
|
|
byte Clock::getTimeMode() {
|
|
return getMode() % 2;
|
|
}
|
|
|
|
byte Clock::getTempMode() {
|
|
return (getMode() >> 1) % 2;
|
|
}
|
|
|
|
byte Clock::getAlarmMode() {
|
|
return (getMode() >> 2) & 0x03;
|
|
}
|
|
|
|
byte Clock::getPushed() {
|
|
return (getMode() >> 6) & 0x01;
|
|
}
|
|
|
|
// アラーム時間取得
|
|
byte Clock::getAlarmHour() {
|
|
updateAlarm();
|
|
return clockparams.alhour;
|
|
}
|
|
|
|
byte Clock::getAlarmMinute() {
|
|
updateAlarm();
|
|
return clockparams.alminute;
|
|
}
|
|
|
|
// 温度取得
|
|
int Clock::getTemperature() {
|
|
updateTemperature();
|
|
return clockparams.temperature;
|
|
}
|
|
|
|
boolean Clock::isAlarmTime() {
|
|
if(getAlarmMode() == 0) return false;
|
|
int delta = (getHour() - getAlarmHour()) * 60 + (getMinute() - getAlarmMinute());
|
|
if(getAlarmMode() == 1 && (delta != 0)) return false;
|
|
if(getAlarmMode() == 2 && ((delta % SNOOZE_TIME) != 0)) return false; // Snooze
|
|
if(alarmState == 0) return false;
|
|
|
|
//TIMSK1 |= 0b00000100; //アラーム時間になった時のみ、Timer1でプッシュボタンを監視する
|
|
pushMonitor = true;
|
|
fOnAlarm = true;
|
|
return true;
|
|
}
|
|
|
|
void Clock::buzzer(boolean on, unsigned int frequency) {
|
|
if(on) {
|
|
if(alarmState == 1) {
|
|
updateMode();
|
|
tone(BZR_pin, frequency);
|
|
}
|
|
} else {
|
|
noTone(BZR_pin);
|
|
}
|
|
}
|
|
|
|
void Clock::buzzer(unsigned int frequency, unsigned long duration) {
|
|
if(alarmState == 1) {
|
|
updateMode();
|
|
tone(BZR_pin, frequency);
|
|
delay(duration);
|
|
noTone(BZR_pin);
|
|
}
|
|
}
|
|
|