//____________________________________________________________________ // // Orologio di cartone charlieplexato // By Claudio Fin 2018 //____________________________________________________________________ /* Pin Funzione 2 -> LINE_A 3 -> LINE_B 4 -> LINE_C 5 -> LINE_D 6 -> LINE_E 7 -> LINE_F 8 -> LINE_G 9 -> LINE_H 10 -> LINE_I 11 <- PULS_SET_PIN (pull-up) 12 <- PULS_HOUR_PIN (pull-up) A0 <- PULS_MIN_PIN (pull-up) A3 -> SPKR */ //____________________________________________________________________ #include #define A_LINE 2 #define B_LINE 3 #define C_LINE 4 #define D_LINE 5 #define E_LINE 6 #define F_LINE 7 #define G_LINE 8 #define H_LINE 9 #define I_LINE 10 #define ANODE_ON_LEVEL HIGH #define CATHODE_ON_LEVEL LOW #define PULS_SET_PIN 11 #define PULS_HOUR_PIN 12 #define PULS_MIN_PIN A0 #define PULS_PRESS_LEVEL LOW #define DEBTIME 50 #define SPKR A3 //____________________________________________________________________ #define NOTE_B0 31 #define NOTE_C1 33 #define NOTE_CS1 35 #define NOTE_D1 37 #define NOTE_DS1 39 #define NOTE_E1 41 #define NOTE_F1 44 #define NOTE_FS1 46 #define NOTE_G1 49 #define NOTE_GS1 52 #define NOTE_A1 55 #define NOTE_AS1 58 #define NOTE_B1 62 #define NOTE_C2 65 #define NOTE_CS2 69 #define NOTE_D2 73 #define NOTE_DS2 78 #define NOTE_E2 82 #define NOTE_F2 87 #define NOTE_FS2 93 #define NOTE_G2 98 #define NOTE_GS2 104 #define NOTE_A2 110 #define NOTE_AS2 117 #define NOTE_B2 123 #define NOTE_C3 131 #define NOTE_CS3 139 #define NOTE_D3 147 #define NOTE_DS3 156 #define NOTE_E3 165 #define NOTE_F3 175 #define NOTE_FS3 185 #define NOTE_G3 196 #define NOTE_GS3 208 #define NOTE_A3 220 #define NOTE_AS3 233 #define NOTE_B3 247 #define NOTE_C4 262 // do #define NOTE_CS4 277 #define NOTE_D4 294 // re #define NOTE_DS4 311 #define NOTE_E4 330 // mi #define NOTE_F4 349 // fa #define NOTE_FS4 370 #define NOTE_G4 392 // sol #define NOTE_GS4 415 #define NOTE_A4 440 // la #define NOTE_AS4 466 #define NOTE_B4 494 // si #define NOTE_C5 523 #define NOTE_CS5 554 #define NOTE_D5 587 #define NOTE_DS5 622 #define NOTE_E5 659 #define NOTE_F5 698 #define NOTE_FS5 740 #define NOTE_G5 784 #define NOTE_GS5 831 #define NOTE_A5 880 #define NOTE_AS5 932 #define NOTE_B5 988 #define NOTE_C6 1047 #define NOTE_CS6 1109 #define NOTE_D6 1175 #define NOTE_DS6 1245 #define NOTE_E6 1319 #define NOTE_F6 1397 #define NOTE_FS6 1480 #define NOTE_G6 1568 #define NOTE_GS6 1661 #define NOTE_A6 1760 #define NOTE_AS6 1865 #define NOTE_B6 1976 #define NOTE_C7 2093 #define NOTE_CS7 2217 #define NOTE_D7 2349 #define NOTE_DS7 2489 #define NOTE_E7 2637 #define NOTE_F7 2794 #define NOTE_FS7 2960 #define NOTE_G7 3136 #define NOTE_GS7 3322 #define NOTE_A7 3520 #define NOTE_AS7 3729 #define NOTE_B7 3951 #define NOTE_C8 4186 #define NOTE_CS8 4435 #define NOTE_D8 4699 #define NOTE_DS8 4978 //____________________________________________________________________ int uscita[] = { NOTE_C5, NOTE_C5, NOTE_E5, NOTE_E5, NOTE_C5, NOTE_C5, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_C5, NOTE_E5, NOTE_G5, -999 }; byte uscita_durate[] = { 1, 2, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2, 1, 3, }; //____________________________________________________________________ int rancio[] = { NOTE_G4, NOTE_C5, NOTE_G4, NOTE_E5, NOTE_C5, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_E5, NOTE_C5, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_C5, NOTE_E5, NOTE_C5, NOTE_E5, NOTE_G5, NOTE_E5, NOTE_C5, NOTE_G4, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_E5, NOTE_C5, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_E5, NOTE_C5, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_C5, NOTE_E5, NOTE_C5, NOTE_E5, NOTE_C5, -999 }; byte rancio_durate[] = { 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2 }; //____________________________________________________________________ int adunata[] = { NOTE_G4, NOTE_C5, NOTE_C5, NOTE_C5, NOTE_E5, NOTE_C5, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_C5, NOTE_C5, NOTE_C5, NOTE_E5, NOTE_C5, NOTE_G4, -999 }; byte adunata_durate[] = { 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 2 }; //____________________________________________________________________ int adjustIn[] = { NOTE_G4, NOTE_C5, NOTE_E5, -999 }; byte adjustIn_durate[] = { 1, 1, 1 }; //____________________________________________________________________ int adjustOut[] = { NOTE_E5, NOTE_C5, NOTE_G4, -999 }; byte adjustOut_durate[] = { 1, 1, 1 }; //____________________________________________________________________ const uint8_t sectorAnode[8] = { A_LINE, B_LINE, C_LINE, D_LINE, E_LINE, F_LINE, G_LINE, H_LINE }; //____________________________________________________________________ const uint8_t sectorCathode[8][8] = { {B_LINE, C_LINE, D_LINE, E_LINE, F_LINE, G_LINE, H_LINE, I_LINE}, {A_LINE, C_LINE, D_LINE, E_LINE, F_LINE, G_LINE, H_LINE, I_LINE}, {A_LINE, B_LINE, D_LINE, E_LINE, F_LINE, G_LINE, H_LINE, I_LINE}, {A_LINE, B_LINE, C_LINE, E_LINE, F_LINE, G_LINE, H_LINE, I_LINE}, {A_LINE, B_LINE, C_LINE, D_LINE, F_LINE, G_LINE, H_LINE, I_LINE}, {A_LINE, B_LINE, C_LINE, D_LINE, E_LINE, G_LINE, H_LINE, I_LINE}, {A_LINE, B_LINE, C_LINE, D_LINE, E_LINE, F_LINE, H_LINE, I_LINE}, {A_LINE, B_LINE, C_LINE, D_LINE, E_LINE, F_LINE, G_LINE, I_LINE} }; //____________________________________________________________________ typedef struct { boolean press = false; boolean release = false; uint32_t t = 0; byte prec = !PULS_PRESS_LEVEL; } puls_t; //____________________________________________________________________ uint8_t vidmem[8] = { 128, 0, 0, 0, 0, 0, 0, 0 }; puls_t puls_set; puls_t puls_hour; puls_t puls_min; boolean increment = false; boolean adjust = false; byte minuti = 0; byte ore = 0; boolean error = false; boolean onPlay = false; int* note; byte* durate; //____________________________________________________________________ //******************************************************************** // LEVEL 3 //******************************************************************** byte BCDbin(byte n) { return ((n >> 4) * 10) + (n & 0x0F); } //____________________________________________________________________ byte binBCD(byte n) { return ((n / 10) << 4) | (n % 10); } //____________________________________________________________________ void clear_vidmem() { for(byte i=0; i<8; i++) vidmem[i] = 0; } //____________________________________________________________________ //******************************************************************** // LEVEL 2 //******************************************************************** void leggiRTC(){ Wire.beginTransmission(0x68); // <--- indirizzo RTC su bus i2c Wire.write(1); // <--- punta al registro 1 (minuti) if (Wire.endTransmission()) // <--- se errore di connessione { error = true; return; } Wire.requestFrom(0x68, 2); // <--- due registri da leggere if (Wire.available() != 2) { error = true; // <--- se errore di ricezione return; } minuti = BCDbin(Wire.read()); ore = BCDbin(Wire.read()); error = false; } //____________________________________________________________________ void impostaRTC(){ Wire.beginTransmission(0x68); // <--- indirizzo RTC su bus i2c Wire.write(0); // <--- punta al registro 0 (secondi) Wire.write(0); // <--- azzera secondi RTC Wire.write(binBCD(minuti)); // <--- imposta minuti RTC Wire.write(binBCD(ore)); // <--- imposta ore RTC Wire.endTransmission(); } //____________________________________________________________________ void inc_hour() { ore++; if(ore >= 19) ore -= 12; else if(ore <= 6) ore += 12; } //____________________________________________________________________ void inc_min() { minuti = (minuti + 1) % 60; } //____________________________________________________________________ void oraToVidmem() { static byte cnt = 0; byte i; clear_vidmem(); if(ore == 0) i = 0; else if(ore<12) i = ore; else i = ore - 12; if(i == 0) vidmem[0] |= 0b10000000; else if(i == 1) vidmem[0] |= 0b00000100; else if(i == 2) vidmem[1] |= 0b00100000; else if(i == 3) vidmem[1] |= 0b00000001; else if(i == 4) vidmem[2] |= 0b00001000; else if(i == 5) vidmem[3] |= 0b01000000; else if(i == 6) vidmem[3] |= 0b00000010; else if(i == 7) vidmem[4] |= 0b00010000; else if(i == 8) vidmem[5] |= 0b10000000; else if(i == 9) vidmem[5] |= 0b00000100; else if(i == 10) vidmem[6] |= 0b00100000; else if(i == 11) vidmem[6] |= 0b00000001; if(adjust) cnt = 0; // se adjust minuti sempre accesi if(cnt<5) vidmem[minuti >> 3] |= 1 << (7 - (minuti & 7)); cnt = (cnt + 1) % 10; } /* 7 6 5 4 3 2 1 0 --- --- --- --- --- --- --- --- 0 |*12| 1 | 2 | 3 | 4 |*1*| 6 | 7 | A_LINE --- --- --- --- --- --- --- --- 1 | 8 | 9 |*2*| 11| 12| 13| 14|*3*| B_LINE --- --- --- --- --- --- --- --- 2 | 16| 17| 18| 19|*4*| 21| 22| 23| C_LINE --- --- --- --- --- --- --- --- 3 | 24|*5*| 26| 27| 28| 29|*6*| 31| D_LINE --- --- --- --- --- --- --- --- 4 | 32| 33| 34|*7*| 36| 37| 38| 39| E_LINE --- --- --- --- --- --- --- --- 5 |*8*| 41| 42| 43| 44|*9*| 46| 47| F_LINE --- --- --- --- --- --- --- --- 6 | 48| 49|*10| 51| 52| 53| 54|*11| G_LINE --- --- --- --- --- --- --- --- 7 | 56| 57| 58| 59| | | | | H_LINE --- --- --- --- --- --- --- --- */ //____________________________________________________________________ void ruota() { vidmem[7] >>= 1; if(vidmem[6] & 1) vidmem[7] |= 128; vidmem[6] >>= 1; if(vidmem[5] & 1) vidmem[6] |= 128; vidmem[5] >>= 1; if(vidmem[4] & 1) vidmem[5] |= 128; vidmem[4] >>= 1; if(vidmem[3] & 1) vidmem[4] |= 128; vidmem[3] >>= 1; if(vidmem[2] & 1) vidmem[3] |= 128; vidmem[2] >>= 1; if(vidmem[1] & 1) vidmem[2] |= 128; vidmem[1] >>= 1; if(vidmem[0] & 1) vidmem[1] |= 128; vidmem[0] >>= 1; if(vidmem[7] & 8) { clear_vidmem(); vidmem[0] = 128; } } //____________________________________________________________________ void play_adunata() { note = adunata; durate = adunata_durate; onPlay = true; } //____________________________________________________________________ void play_rancio() { note = rancio; durate = rancio_durate; onPlay = true; } //____________________________________________________________________ void play_uscita() { note = uscita; durate = uscita_durate; onPlay = true; } //____________________________________________________________________ void play_adjustIn() { note = adjustIn; durate = adjustIn_durate; onPlay = true; } //____________________________________________________________________ void play_adjustOut() { note = adjustOut; durate = adjustOut_durate; onPlay = true; } //____________________________________________________________________ //******************************************************************** // LEVEL 1 //******************************************************************** void read_puls(::puls_t* self, byte pin) { self->press = false; self->release = false; byte in = digitalRead(pin); if(in == self->prec) self->t = millis(); else if(millis() - self->t >= DEBTIME) { if(in == PULS_PRESS_LEVEL) self->press = true; else self->release = true; self->prec = in; } } //____________________________________________________________________ void puls_logic() { static byte stat = 0; static uint32_t t; increment = false; switch(stat) { case 0: if(puls_set.press) { t=millis(); stat=1; } break; case 1: if(puls_set.release) stat = 0; else if(millis() - t >= 5000) { adjust=true; stat=2; } break; case 2: if(puls_set.press) { adjust=false; stat=0; } else if(puls_hour.press) { inc_hour(); increment = true; } else if(puls_min.press) { inc_min(); increment = true; t=millis(); stat=3; } break; case 3: if(puls_min.release) stat = 2; else if(millis() - t >= 1000) { inc_min(); increment = true; t=millis(); stat=4; } break; case 4: if(puls_min.release) stat = 2; else if(millis() - t >= 100) { inc_min(); increment = true; t=millis(); } } } //____________________________________________________________________ void vis_logic() { static uint32_t t = 0; static uint32_t t2 = 0; if(adjust) { if(increment) impostaRTC(); t = millis(); } else if(millis() - t >= 300) { t += 300; leggiRTC(); } int actTime = (int)ore*60 + minuti; boolean inTurno = actTime>=480 && actTime<=1019; if(adjust || inTurno) { if(millis() - t2 >= 100) { t2 += 100; oraToVidmem(); } } else { if(millis() - t2 >= 20) { t2 += 20; ruota(); } } } //____________________________________________________________________ void sound_logic() { static uint32_t t; static byte cnt; static byte stat = 0; static byte prec_min = minuti; switch(stat) { case 0: if(adjust) { play_adjustIn(); stat=1; } else if(minuti != prec_min) { prec_min = minuti; int actTime = (int)ore*60 + minuti; if(actTime == 480) play_adunata(); // 8:00 else if(actTime == 745) play_rancio(); // 12:25 else if(actTime == 993) { play_uscita(); cnt=3; stat=2; } //16:33 } break; case 1: if(!adjust) { play_adjustOut(); stat=0; } else if(increment) tone(SPKR, 1000, 20); break; case 2: if(!onPlay) { cnt--; if(cnt == 0) stat = 0; else { t=millis(); stat=3; } } break; case 3: if(millis() - t >= 500) { play_uscita(); stat=2; } } } //____________________________________________________________________ void charlie() // charlieplexa ogni 2ms (62.5Hz) { byte pin; byte i; static uint32_t t = 0; static byte sec = 0; if(micros() - t < 2000) return; t += 2000; byte n = vidmem[sec]; // blanking for(i=0; i<8; i++) pinMode(sectorAnode[i], INPUT); pinMode(I_LINE, INPUT); // imposta catodi accesi for(i=0; i<8; i++) if(n & (128>>i)) { pin = sectorCathode[sec][i]; pinMode(pin, OUTPUT); digitalWrite(pin, CATHODE_ON_LEVEL); } // accende anodo comune pin = sectorAnode[sec]; pinMode(pin, OUTPUT); digitalWrite(pin, ANODE_ON_LEVEL); // imposta numero prossimo anodo 0..7 sec = (sec + 1) % 8; } /* cathode table anode 0 1 2 3 4 5 6 7 --- --- --- --- --- --- --- --- 0 | b | c | d | e | f | g | h | i | a --- --- --- --- --- --- --- --- 1 | a | c | d | e | f | g | h | i | b --- --- --- --- --- --- --- --- 2 | a | b | d | e | f | g | h | i | c --- --- --- --- --- --- --- --- 3 | a | b | c | e | f | g | h | i | d --- --- --- --- --- --- --- --- 4 | a | b | c | d | f | g | h | i | e --- --- --- --- --- --- --- --- 5 | a | b | c | d | e | g | h | i | f --- --- --- --- --- --- --- --- 6 | a | b | c | d | e | f | h | i | g --- --- --- --- --- --- --- --- 7 | a | b | c | d | e | f | g | i | h --- --- --- --- --- --- --- --- */ //____________________________________________________________________ void play() { static byte stat = 0; static uint32_t t; static byte i; int n; switch(stat) { case 0: if(onPlay) { i=0; stat=1; } break; case 1: n = note[i]; if(n == -999) { onPlay=false; stat=0; } else { tone(SPKR, n); t=millis(); stat=2; } break; case 2: if(millis() - t >= durate[i]*150) { noTone(SPKR); t = millis(); stat = 3; } break; case 3: if(millis() - t >= 20) { i++; stat=1; } } } //____________________________________________________________________ //******************************************************************** // LEVEL 0 //******************************************************************** void setup() { pinMode(PULS_SET_PIN, INPUT_PULLUP); pinMode(PULS_HOUR_PIN, INPUT_PULLUP); pinMode(PULS_MIN_PIN, INPUT_PULLUP); pinMode(SPKR, OUTPUT); digitalWrite(SPKR, LOW); Wire.begin(); leggiRTC(); } //____________________________________________________________________ void loop() { read_puls(&puls_set, PULS_SET_PIN); read_puls(&puls_hour, PULS_HOUR_PIN); read_puls(&puls_min, PULS_MIN_PIN); puls_logic(); vis_logic(); sound_logic(); charlie(); play(); } //____________________________________________________________________