// Hemerson David Pabon Martinez
// Erick Alejandro Vega Gomez
// Variables globales para el conteo del reloj
byte segundos;
byte segundos_unidades;
byte segundos_decenas;
byte minutos;
byte minutos_unidades;
byte minutos_decenas;
byte horas;
byte horas_unidades;
byte horas_decenas;
byte dias;
byte dias_unidades;
byte dias_decenas;
byte meses;
byte meses_unidades;
byte meses_decenas;
int years;
int years_unidades;
int years_decenas;
int years_centenas;
int years_miles;
//variable que establece el modo del reloj
byte modo = 0;
int valorPotenciometro;
//Variable para contar ciclos del programa, se usa en la funcion de sinRebote
//para generar el blink
long contador;
// Arreglos de la entrada a los 7 segmentos
byte numeros[] = {
0b11111100, //0
0b01100000, //1
0b11011010, //2
0b11110010, //3
0b01100110, //4
0b10110110, //5
0b10111110, //6
0b11100000, //7
0b11111110, //8
0b11100110, //9
};
// Arreglo para imprimir las letras
byte letras[] = {
0b11101110, //A 0
0b00111110, //B 1
0b10011100, //C 2
0b11111100, //D 3
0b10011110, //E 4
0b10001110, //F 5
0b11110010, //G 6
0b00001100, //I 7
0b01110000, //J 8
0b00011100, //L 9
0b11101100, //M 10
0b11101100, //N 11
0b11111100, //O 12
0b11001110, //P 13
0b10001100, //R 14
0b10110110, //S 15
0b00011110, //T 16
0b01111100, //U 17
0b01000110, //V 18
0b11100110, //Y 19
};
// alias para imprimir la combinacion necesaria para representar
// cada numeros
#define cero numeros[0]
#define uno numeros[1]
#define dos numeros[2]
#define tres numeros[3]
#define cuatro numeros[4]
#define cinco numeros[5]
#define seis numeros[6]
#define siete numeros[7]
#define ocho numeros[8]
#define nueve numeros[9]
// alias para los pines de carga serial, shift clock y latch clock
#define DS 5 // Entrada serial
#define STCP 6 // Latch clock
#define SHCP 7 // Shift clock
void setup(){
Serial.begin(115200);
// Asignar los pines DS, STCHP, SHCP como salidas
DDRD = set_HIGH(DDRD, DS);
DDRD = set_HIGH(DDRD, STCP);
DDRD = set_HIGH(DDRD, SHCP);
// pines para que controla los anodos de los 7 segmentos
DDRD = set_HIGH(DDRD, 2);
DDRD = set_HIGH(DDRD, 3);
DDRD = set_HIGH(DDRD, 4);
DDRB = set_HIGH(DDRB, 0);
DDRB = set_HIGH(DDRB, 1);
DDRB = set_HIGH(DDRB, 5);
}
void loop(){
int x;
if (presionaA(PINB) == 1){
x = comparar(++modo, 7);
modo *= x;
convierteuno();
}
if (modo != 0){
controlPotenciometro();
}
// El siguiente switch controla el estado del reloj:
// modo = 0 : El reloj cuenta normalmente
// modo = 1 : Programar segundos
// modo = 2 : Programar minutos
// modo = 3 : Programar horas
// modo = 4 : Programar dias
// modo = 5 : Programar meses
// modo = 6 : Programar años
switch(modo){
case 0:
reloj();
// Generar el latch clock
PORTD = set_HIGH(PORTD, STCP);
PORTD = set_LOW(PORTD, STCP);
mostrar();
break;
case 1:
// Esta condicional se encargar de generar el BLINK en la variable que
// se va a programar
if (contador_millis(++contador) == 1){
PORTD = set_HIGH(PORTD, 2);
}
else{
PORTD = set_LOW(PORTD, 2);
}
// Estos condicionales detectan si se presiono el boton azul
// o el boton Rojo y aumentan si se presiono azul o decrementa si se presiono rojo
if (presionaZ(PINB) == 1){
segundos++;
}
if (presionaR(PINB) == 1){
segundos--;
}
// Esta funcion convierte el valor completo de la variable que se programa
// a decenas, unidades y guarda esos valores y los parametro 2 y 3 de la funcion
convertir(segundos, segundos_decenas, segundos_unidades);
// Generar el latch clock
PORTD = set_HIGH(PORTD, STCP);
PORTD = set_LOW(PORTD, STCP);
// Condicional para que la variable tenga un limite al programarla
if (segundos > 59){
segundos = 0;
}
// Llamar la funcion mostrar parar cargar los valores en los displays
mostrar();
break;
case 2:
if (contador_millis(++contador) == 1){
PORTD = set_HIGH(PORTD, 3);
}
else{
PORTD = set_LOW(PORTD, 3);
}
if (presionaZ(PINB) == 1){
minutos++;
}
if (presionaR(PINB) == 1){
minutos--;
}
convertir(minutos, minutos_decenas, minutos_unidades);
PORTD = set_HIGH(PORTD, STCP);
PORTD = set_LOW(PORTD, STCP);
minutos = (minutos > 59) ? minutos = 1 : minutos = minutos;
mostrar();
break;
// caso 3, programa horas
case 3:
if (contador_millis(++contador) == 1){
PORTD = set_HIGH(PORTD, 4);
}
else{
PORTD = set_LOW(PORTD, 4);
}
if (presionaZ(PINB) == 1){
horas++;
}
if (presionaR(PINB) == 1){
horas--;
}
convertir(horas, horas_decenas, horas_unidades);
PORTD = set_HIGH(PORTD, STCP);
PORTD = set_LOW(PORTD, STCP);
horas = (horas > 23) ? dias = 1 : horas = horas;
mostrar();
break;
// caso 4, programa dias
case 4:
if (contador_millis(++contador) == 1){
PORTB = set_HIGH(PORTB, 0);
}
else{
PORTB = set_LOW(PORTB, 0);
}
if (presionaZ(PINB) == 1){
dias++;
}
if (presionaR(PINB) == 1){
dias--;
}
convertir(dias, dias_decenas, dias_unidades);
PORTD = set_HIGH(PORTD, STCP);
PORTD = set_LOW(PORTD, STCP);
dias = (dias == 0 | dias > 30) ? dias = 1 : dias = dias;
mostrar();
break;
//caso 5; programa mes
case 5:
if (contador_millis(++contador) == 1){
PORTB = set_HIGH(PORTB, 1);
}
else{
PORTB = set_LOW(PORTB, 1);
}
if (presionaZ(PINB) == 1){
meses++;
}
if (presionaR(PINB) == 1){
meses--;
}
PORTD = set_HIGH(PORTD, STCP);
PORTD = set_LOW(PORTD, STCP);
meses = (meses > 11) ? meses = 0 : meses = meses;
mostrar();
break;
// caso 6: programar años
case 6:
if (contador_millis(++contador) == 1){
PORTB = set_HIGH(PORTB, 5);
}
else{
PORTB = set_LOW(PORTB, 5);
}
if (presionaZ(PINB) == 1){
years++;
}
if (presionaR(PINB) == 1){
years--;
}
PORTD = set_HIGH(PORTD, STCP);
PORTD = set_LOW(PORTD, STCP);
years = (years > 9999) ? years = 0 : years = years;
mostrar();
break;
}
}
// La funcion cargar permite cargar un valor de 8 bits al registro serial
void cargar(byte valor){
PORTD = set_LOW(PORTD, DS);
PORTD = set_LOW(PORTD, STCP);
PORTD = set_LOW(PORTD, SHCP);
byte i = 0;
while (i <= 7){
if((valor & 0x01) == 0){
PORTD = set_LOW(PORTD, DS);
}
else{
PORTD = set_HIGH(PORTD, DS);
}
PORTD = set_HIGH(PORTD, SHCP);
PORTD = set_LOW(PORTD, SHCP);
valor >>= 1;
i++;
}
}
// Funciones para modificar bits en los registro :
// la función set_HIGH y set_LOW tiene como parametros el registro para modificar
// y la ubicación del bit a modificar, la función set_HIGH asigna uno y la
// función set_LOW asgina un cero.
byte set_HIGH(byte registro, byte nroBit){
return registro | (1 << nroBit);
}
byte set_LOW(byte registro, byte nroBit){
return registro & ~(1 << nroBit);
}
// Esta funcion compara el parametro var con el limite, si var es igual al limite
// retorna un 0, pero si es menor retorna valor 1
int comparar(int var, int limite){
int resta = var + ~(limite) + 1;
resta = (resta >> 31) & 0x01;
return resta;
}
// Esta funcion se encarga de carga 15 paquetes de datos de bits hacia los displays,
// cargar los valores de todas las variables de tiempo
void mostrar(){
cargar(numeros[segundos_unidades]);
cargar(numeros[segundos_decenas]);
cargar(numeros[minutos_unidades]);
cargar(numeros[minutos_decenas]);
cargar(numeros[horas_unidades]);
cargar(numeros[horas_decenas]);
cargar(numeros[dias_unidades]);
cargar(numeros[dias_decenas]);
// Esta funcion convierte el valor numerico a un valor en letras que
// corresponde al mes
convertir_meses(meses);
cargar(numeros[years_unidades]);
cargar(numeros[years_decenas]);
cargar(numeros[years_centenas]);
cargar(numeros[years_miles]);
separar(years, years_unidades, years_decenas, years_centenas, years_miles);
}
// esta funcion se encargar de convertir del dato numerico del mes,
// a un dato en forma de letras correspondiente a cada mes.
void convertir_meses(int mes){
switch(meses){
case 0:
cargar(letras[4]);
cargar(letras[11]);
cargar(letras[4]);
break;
case 1:
cargar(letras[1]);
cargar(letras[4]);
cargar(letras[5]);
break;
case 2:
cargar(letras[14]);
cargar(letras[0]);
cargar(letras[10]);
break;
case 3:
cargar(letras[14]);
cargar(letras[1]);
cargar(letras[0]);
break;
case 4:
cargar(letras[19]);
cargar(letras[0]);
cargar(letras[10]);
break;
case 5:
cargar(letras[11]);
cargar(letras[17]);
cargar(letras[8]);
break;
case 6:
cargar(letras[9]);
cargar(letras[17]);
cargar(letras[8]);
break;
case 7:
cargar(letras[12]);
cargar(letras[0]);
cargar(letras[6]);
break;
case 8:
cargar(letras[13]);
cargar(letras[4]);
cargar(letras[15]);
break;
case 9:
cargar(letras[16]);
cargar(letras[2]);
cargar(letras[12]);
break;
case 10:
cargar(letras[16]);
cargar(letras[12]);
cargar(letras[11]);
break;
case 11:
cargar(letras[2]);
cargar(letras[7]);
cargar(letras[3]);
break;
}
}
// Esta funcion es el reloj, va de años, meses, dias, horas, minutos y segundos.
void reloj(){
byte x;
x = comparar(++segundos, 60);
segundos *= x;
convertir(segundos, segundos_decenas, segundos_unidades);
minutos += !x;
x = comparar(minutos, 60);
minutos *= x;
convertir(minutos, minutos_decenas, minutos_unidades);
horas += !x;
x = comparar(horas, 24);
horas *= x;
convertir(horas, horas_decenas, horas_unidades);
dias += !x;
x = comparar(dias, 31);
// Este condicional sirve para que cuando se resetee el valor de dias,
// inmediatamente el valor vuelva a 1 ya que cuenta los dias
if (dias == 0){
dias = 1;
}
dias *= x;
convertir(dias, dias_decenas, dias_unidades);
meses += !x;
x = comparar(meses, 12);
meses *= x;
convertir(meses, meses_decenas, meses_unidades);
years += !x;
x = comparar(years, 9999);
years *= x;
separar(years, years_unidades, years_decenas, years_centenas, years_miles);
}
// La funcion convertir toma un valor de 2 digitos y los separa, se usa en las
// variables horas, dias, meses
void convertir(byte valor, byte &masSig, byte &menosSig){
if (valor < 10 ){
menosSig = valor;
masSig = 0;
}else{
menosSig = valor % 10;
masSig = valor / 10;
}
valor = (masSig * 10) + menosSig;
}
// Esta funcion realiza la misma tarea de la funcion convertir con la diferencia
// de que se usa sobre la variable de años y separa cuatro digitos
void separar(int numero, int &unidades, int &decenas, int ¢enas, int &miles){
unidades = numero % 10;
numero /= 10;
decenas = numero % 10;
numero /=10;
centenas = numero % 10;
numero /=10;
miles = numero % 10;
}
// Funciones para detectar si el usuario presiono alguna tecla:
// El boton amarillo sirve para cambiar el modo y la variable que se programa
// El boton azul incrementa la variable
// El boton rojo decrementa la variable
byte presionaA(byte pines){
long antiRebote;
delay(120);
return (((PINB & (1 << 4)) == 0) && (millis() - antiRebote) > 200);
}
byte presionaZ(byte pines){
long antiRebote;
delay(15);
return (((PINB & (1 << 3)) == 0) && (millis() - antiRebote) > 200);
}
byte presionaR(byte pines){
long antiRebote;
delay(15);
return (((PINB & (1 << 2)) == 0) && (millis() - antiRebote) > 200);
}
// Esta funcion es un contador que retorna 1 cada 2 ciclos, se usar para controlar
// el parpadeo de los displays
boolean contador_millis(long y){
boolean x = !(y % 2);
return x;
}
// Esta funcion asigna un cero a los pines que van conectados a los catodos
// de los displays
void convierteuno(){
PORTD = set_LOW(PORTD, 2);
PORTD = set_LOW(PORTD, 3);
PORTD = set_LOW(PORTD, 4);
PORTB = set_LOW(PORTB, 0);
PORTB = set_LOW(PORTB, 1);
PORTB = set_LOW(PORTB, 5);
}
// para controlar
void controlPotenciometro(){
valorPotenciometro = analogRead(0);
if ((valorPotenciometro >= 0) & (valorPotenciometro <= 170)){
modo = 6;
}
if ((valorPotenciometro >= 171) & (valorPotenciometro <= 340)){
modo = 5;
}
if ((valorPotenciometro >= 341) & (valorPotenciometro <= 510 )){
modo = 4;
}
if ((valorPotenciometro >= 511 ) & (valorPotenciometro <= 680 )){
modo = 3;
}
if ((valorPotenciometro >= 681) & (valorPotenciometro <= 850 )){
modo = 2;
}
if ((valorPotenciometro >= 851 ) & (valorPotenciometro <= 1022 )){
modo = 1;
}
if (valorPotenciometro == 1023){
modo = 0;
}
convierteuno();
}