Coffre au trésor
Un coffre à ouverture télécommandée avec un code. Le but de ce projet est de faire des énigmes pour les enfants. Ils doivent trouver un code. Si ils ont le bon code. Ils le composent sur une télécommande infrarouge et peuvent ouvrir le coffre.
Le code est reprogrammable avec un code administrateur, hard codé à 1234567 dans l'exemple. Pour reprogrammer le code il faut presser la touche CH- (tout en haut à gauche de la télécommande). Ensuite saisir le code 1 2 3 4 5 6 7 puis le code secret à trois chiffres. Celui-ci est sauvé dans l'EEPROM.
J'ai récupéré une carte prototino. Le circuit n'est pas aussi compliqué :)
En gros, il faut connecter le capteur infrarouge sur une pin capable d'avoir une interruption (la 2 par exemple). Et connecter le solénoïde derrière un transistor qui peut donner assez de courant. Sur ma carte prototino j'avais un H-Bridge alors j'en ai profité.
Il y aussi un beep, bien utile pour confirmer la pression des touches de la télécommande. Pendant mes tests j'utilisais des LED en plus du beep.
La version pour ATTiny n'est pas testée encore.
La télécommande utilisée ici utilise un code NEC.
#include <EEPROM.h>
#if defined (__AVR_ATtiny45__) || (__AVR_ATtiny85__)
//#include "PinChangeInterruptSimple.h" // mimics attachInterrupt() but a PCI for ATtiny
#define SDI PB0 // GREEN ON LED CHAIN
#define CLK PB2 // BLUE ON LED CHAIN
#define IR_PIN PB4 // IR SENSOR
#define MES_PIN PB3 // MESURE
#define DEBUG_PIN PB1 // DEBUG
#define BIT_DUR 880 // Full bit Duration Infrared reciever
#endif
#if defined (__AVR_ATmega328P__)
const int BRIDGE_EN_A = 3;
const int BRIDGE_A1 = 4;
const int BRIDGE_A2 = 5;
const int PROG_PIN = 13;
const int IR_PIN = 2;
const int IR_PIN_INT = INT0;
const int BIT_DUR = 888; // Full bit Duration Infrared reciever
const int WAITING_PIN = 9;
const int BEEP_PIN = A4;
#endif
const byte key_codes[] = { 69, 70, 71, 68, 64, 67, 7, 21, 9, 22, 25, 13, 12, 24, 94, 8, 28, 90, 66, 82, 74 };
const char key_chars[] = { 'A', 'B', 'C', 'D', 'E', 'F', '-', '+', '=', '0', '*', '#', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
char convKey(byte key_code) {
for(byte b=0;b<sizeof key_codes;b++){
if(key_code==key_codes[b]) return key_chars[b];
}
return 0;
}
//------------------------------------- Télécommande IR -------------------------------------------
volatile int ir_key = -1;
// MAX 180 us on ATTiny @ 1MHz
// 18 us on ATMega @ 16MHz
void irRemote_ISR() {
static unsigned long irq_micros = 0;
static byte address = 0;
static byte command = 0;
static byte buffer = 0;
static byte error = 0;
static char bit_cpt = -2;
unsigned long us = micros();
unsigned long elapsed = us - irq_micros;
irq_micros = us;
if(elapsed>6750) {
bit_cpt = -1;
}
else if(bit_cpt==-1 && digitalRead(IR_PIN)==LOW) {
if(elapsed>3500) {
bit_cpt = 0;
error = 0;
}
}
else if(bit_cpt>=0 && bit_cpt<32) {
if(digitalRead(IR_PIN)==LOW) {
buffer >>= 1;
if(elapsed>1125) buffer |= 0x80;
bit_cpt++;
if(bit_cpt==8) {
address = buffer;
}
else if(bit_cpt==16) {
buffer = ~buffer;
if(buffer!=address) error++;
}
else if(bit_cpt==24) {
command = buffer;
}
else if(bit_cpt==32) {
buffer = ~buffer;
if(buffer!=command) error++;
if(error==0) ir_key = command;
}
}
}
return;
}
//------------------------------------- CODE -------------------------------------------------
void open_chest() {
digitalWrite(BEEP_PIN, HIGH);
digitalWrite(BRIDGE_EN_A, HIGH);
delay(2000);
digitalWrite(BEEP_PIN, LOW);
digitalWrite(BRIDGE_EN_A, LOW);
}
void beep() {
digitalWrite(BEEP_PIN, HIGH);
delay(200);
digitalWrite(BEEP_PIN, LOW);
}
void error_beep() {
for(int i=0;i<4;i++) {
delay(100);
digitalWrite(BEEP_PIN, HIGH);
delay(100);
digitalWrite(BEEP_PIN, LOW);
}
}
boolean set_code() {
byte secure[] = { '1', '2', '3', '4', '5', '6', '7' };
byte buffer[] = { 0, 0, 0 };
byte mode = 0;
byte cpt=0;
for(;;) {
int key = readKey(2000);
if(key==-1) return false;
if(key>='0' && key<='9') {
beep();
switch(mode) {
case 0:
if(secure[cpt++] != key) return false;
if(cpt==7) {
cpt = 0;
mode = 1;
digitalWrite(WAITING_PIN, HIGH);
}
break;
case 1:
buffer[cpt] = key;
cpt++;
if(cpt==3) {
for(cpt=0;cpt<3;cpt++) EEPROM.write(cpt, buffer[cpt]);
return true;
}
}
}
}
}
byte try_code(byte key) {
byte buffer[] = { key, 0, 0 };
for(int cpt=1;;) {
int k = readKey(2000);
if(k>='0' && k<='9') {
beep();
buffer[cpt] = k;
cpt++;
if(cpt==3) {
for(cpt=0;cpt<3;cpt++) {
if(buffer[cpt] != EEPROM.read(cpt)) return false;
}
return true;
}
}
else return false;
}
}
int readKey(long timeout) {
unsigned long until = millis() + timeout;
for(;;) {
int key = ir_key;
if(key!=-1) {
ir_key = -1;
return convKey(key);
}
if(timeout==0) return -1;
if(millis()>until) {
Serial.println("TIMEOUT");
return -1;
}
}
}
void setup() {
#if defined (__AVR_ATmega328P__)
Serial.begin(9600);
#endif
digitalWrite(BRIDGE_EN_A, LOW);
digitalWrite(BRIDGE_A1, HIGH);
digitalWrite(BRIDGE_A2, LOW);
digitalWrite(BEEP_PIN, LOW);
digitalWrite(WAITING_PIN, LOW);
digitalWrite(PROG_PIN, LOW);
pinMode(BRIDGE_EN_A, OUTPUT);
pinMode(BRIDGE_A1, OUTPUT);
pinMode(BRIDGE_A2, OUTPUT);
pinMode(BEEP_PIN, OUTPUT);
pinMode(WAITING_PIN, OUTPUT);
pinMode(PROG_PIN, OUTPUT);
pinMode(IR_PIN, INPUT);
#if defined (__AVR_ATmega328P__)
attachInterrupt(IR_PIN_INT, irRemote_ISR, CHANGE);
#endif
#if defined (__AVR_ATtiny45__) || (__AVR_ATtiny85__)
attachPcInterrupt(IR_PIN, irRemote_ISR, CHANGE);
#endif
}
void loop() {
int key = readKey(0);
if(key!=-1) {
// EEPROM.write(0, key);
Serial.println(key);
beep();
if(key=='A') { // programmation
digitalWrite(PROG_PIN, HIGH);
if(!set_code()) error_beep();
else open_chest();
digitalWrite(PROG_PIN, LOW);
digitalWrite(WAITING_PIN, LOW);
}
else if(key>'0' && key<='9') { // tentative
digitalWrite(WAITING_PIN, HIGH);
if(try_code(key)) {
digitalWrite(WAITING_PIN, LOW);
delay(100);
open_chest();
}
else {
digitalWrite(WAITING_PIN, LOW);
error_beep();
}
}
}
}