#include #define SERIAL_DEBUG 0 // Remote controls #define RC6_CHM 0xFFA25D// CHANNEL - #define RC6_CH 0xFF629D// CHANNEL #define RC6_CHP 0xFFE21D// CHANNEL + #define RC6_PREV 0xFF22DD// |<< PREVIOUS #define RC6_NEXT 0xFF02FD// >>| NEXT #define RC6_PLAY 0xFFC23D// PLAY/PAUSE #define RC6_VM 0xFFE01F// VOLUME - #define RC6_VP 0xFFA857// VOLUME + #define RC6_EQ 0xFF906F// EQ #define RC6_0 0xFF6897// 0 #define RC6_100 0xFF9867// 100+ #define RC6_200 0xFFB04F// 200+ #define RC6_1 0xFF30CF// 1 #define RC6_2 0xFF18E7// 2 #define RC6_3 0xFF7A85// 3 #define RC6_4 0xFF10EF// 4 #define RC6_5 0xFF38C7// 5 #define RC6_6 0xFF5AA5// 6 #define RC6_7 0xFF42BD// 7 #define RC6_8 0xFF4AB5// 8 #define RC6_9 0xFF52AD// 9 #define AMP2540_VCDAUX 0x8FDBCE66 #define AMP2540_TUNERCD 0xC375A98B #define AMP2540_DVD 0xCC7372A6 #define AMP2540_TAPE 0xE917A076 #define AMP2540_SEARCH 0xE82D76B6 #define AMP2540_RESET 0x04D1A486 #define AMP2540_VM 0xAB95D276 #define AMP2540_VP 0x0217C346 #define MODE_NORMAL 0 #define MODE_SETTIME 1 #define MODE_SETALARM 2 #define PIN_BUTTON 3 #define PIN_BUZZER 8 #define PIN_IR 10 #define PIN_LED_DUTY A0 #define PIN_REG_CLOCK 7 #define PIN_REG_DATA 5 #define PIN_REG_LATCH 6 IRrecv irrecv(PIN_IR); decode_results ircode; unsigned long last_ir = 0; // Matrix state unsigned char matrix[8] = {0b10000001, 0, 0, 0, 0, 0, 0, 0b10000001}; unsigned char matrix_row_on = 0; // Interface mode unsigned char mode = MODE_NORMAL; // Selected number (0..4: None, Hour, Minute, Second) unsigned char number_selection = 0; // Time added to internal clock, to fit real time unsigned long time_offset = 0; unsigned char alarm = false; unsigned long alarm_time = 0; // Is alarm ringing unsigned char alarm_ringing = false; unsigned int led_duty; unsigned int led_duty_step = 3; // Bytewise reverse unsigned char reverse(unsigned char b) { b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; b = (b & 0xCC) >> 2 | (b & 0x33) << 2; b = (b & 0xAA) >> 1 | (b & 0x55) << 1; return b; } unsigned char fix_pixels(unsigned char b) { return (b << 1) | (b >> 7); } void shift_matrix() { if(led_duty_step == 0) { digitalWrite(PIN_REG_LATCH, LOW); shiftOut(PIN_REG_DATA, PIN_REG_CLOCK, MSBFIRST, ~(1 << matrix_row_on)); shiftOut(PIN_REG_DATA, PIN_REG_CLOCK, MSBFIRST, fix_pixels(matrix[(matrix_row_on+7)%8])); digitalWrite(PIN_REG_LATCH, HIGH); matrix_row_on = (matrix_row_on + 1) % 8; } else if(led_duty_step == 1) { digitalWrite(PIN_REG_LATCH, LOW); shiftOut(PIN_REG_DATA, PIN_REG_CLOCK, MSBFIRST, 255); shiftOut(PIN_REG_DATA, PIN_REG_CLOCK, MSBFIRST, 0); digitalWrite(PIN_REG_LATCH, HIGH); } led_duty_step ++; } void draw_time(unsigned long t) { unsigned char seconds = t/1000%60; unsigned char minutes = t/60000%60; unsigned char hours = t/3600000%24; matrix[1] = reverse(seconds) >> 1; matrix[2] = matrix[1]; matrix[3] = reverse(minutes) >> 1; matrix[4] = matrix[3]; matrix[5] = reverse(hours) >> 1; matrix[6] = matrix[5]; } void draw_mode() { switch(mode) { case MODE_NORMAL: matrix[0] = 0b10000001; break; case MODE_SETTIME: matrix[0] = 0b10011001; break; case MODE_SETALARM: matrix[0] = 0b10111101; break; } if(alarm) matrix[0] |= 0b01000010; } void draw_number_selection() { switch(number_selection) { case 1: matrix[1] |= 0b10000001; break; case 2: matrix[3] |= 0b10000001; break; case 3: matrix[5] |= 0b10000001; break; } } const unsigned char HEX_ALPHA[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; void send_hex(unsigned long val) { Serial.write(HEX_ALPHA[(val >> 28) & 0xf]); Serial.write(HEX_ALPHA[(val >> 24) & 0xf]); Serial.write(HEX_ALPHA[(val >> 20) & 0xf]); Serial.write(HEX_ALPHA[(val >> 16) & 0xf]); Serial.write(HEX_ALPHA[(val >> 12) & 0xf]); Serial.write(HEX_ALPHA[(val >> 8) & 0xf]); Serial.write(HEX_ALPHA[(val >> 4) & 0xf]); Serial.write(HEX_ALPHA[val & 0xf]); Serial.write('\n'); } void setup() { pinMode(PIN_REG_DATA, OUTPUT); pinMode(PIN_REG_CLOCK, OUTPUT); pinMode(PIN_REG_LATCH, OUTPUT); pinMode(PIN_BUZZER, OUTPUT); pinMode(PIN_BUTTON, INPUT_PULLUP); pinMode(PIN_LED_DUTY, INPUT); irrecv.enableIRIn(); pinMode(13, OUTPUT); digitalWrite(13, LOW); #if SERIAL_DEBUG Serial.begin(9600); #endif } void loop() { if(led_duty_step > led_duty) { led_duty_step = 0; led_duty = (1023-analogRead(PIN_LED_DUTY)) / 128; } if(irrecv.decode(&ircode)) { #if SERIAL_DEBUG send_hex(ircode.value); #endif unsigned long val = ircode.value; if(val == last_ir) { alarm_ringing = false; switch(val) { case AMP2540_VCDAUX: mode = (mode+1) % 3; break; case AMP2540_VP: change_selected_number(1); break; case AMP2540_VM: change_selected_number(-1); break; case AMP2540_SEARCH: number_selection = (number_selection+1) % 4; break; case AMP2540_TUNERCD: alarm = !alarm; break; } last_ir = 0; } else { last_ir = val; } irrecv.resume(); } if(alarm && !alarm_ringing) { unsigned long t = ((millis() + time_offset) / 1000) % 86400; if(alarm_time / 1000 == t) { alarm_ringing = true; } } if(alarm_ringing) { if(millis()%1000 < 100) { matrix[7] = 0b11111111; digitalWrite(PIN_BUZZER, HIGH); } else { matrix[7] = 0b10000001; digitalWrite(PIN_BUZZER, LOW); } if(digitalRead(PIN_BUTTON) == LOW) { digitalWrite(PIN_BUZZER, LOW); alarm_ringing = false; } } draw_mode(); if(mode == MODE_SETALARM) draw_time(alarm_time); else draw_time(millis() + time_offset); draw_number_selection(); shift_matrix(); } void change_selected_number(signed int nb) { switch(mode) { case MODE_SETTIME: change_time(&time_offset, nb); break; case MODE_SETALARM: change_time(&alarm_time, nb); break; } } void change_time(unsigned long *t, signed int mul) { switch(number_selection) { case 1: *t += mul * 1000; break; case 2: *t += mul * 60000; break; case 3: *t += mul * 3600000; break; } *t %= 86400000; }