Mi proyecto de fin del ciclo superior Electronica

Pues resulta que he acabado la parte teórica del ciclo formativo de grado superior: "Desarrollo de productos electrónicos". Ahora estoy con las FCTs. Y para una de las asignaturas nos plantearon un proyecto para el fin de curso:

Se trata de un programador de riego: Poder especificar a que hora se debe empezar a regar y a qué hora debe acabar (ajustable con precisión de minutos), en cada uno de los 7 dias de la semana.

Empleando los siguientes componentes:
    Imagen
    "Display LCD 2x16 carácteres"

    Imagen
    "Microcontrolador PIC 16F876"
    Se debe programar en C

    Imagen
    "Reloj de tiempo real i2c DS1307"

    Mas los pulsadores/interruptores que consideráramos necesarios para su control.

Se debía diseñar la interfaz de usuario. Y puntuaba en consideración la facilidad de uso y el minimo coste en componentes (pulsadores e interruptores).

Resumen de funcionalidades de mi versión final:
    - Configurable de Lunes a Domingo una hora de inicio y de fin (con precisión de minutos).
    - Software controlable desde 2 botones (Up & Right) hasta 4 (Up, Right, Down, Left).
    - Interfaz intuitiva.
    - Configuración guardada en memoria EEPROM.
    - Testeo de hardware / memoria (con comprobación contra corrupción de configuración) al inicio.
    - Ajuste del reloj.
    - Información del riego de hoy en la pantalla de espera.
    entre otras...

Lo publicaré en otro momento que ahora se me ha hecho tarde. Será una versión digital en formato para el programa "Proteus ISIS". Sólo os digo que el programa está escrito en C y son 1456 líneas de código.

A ver si con esto consigo inspirar a varios de por aqui [beer] y así hablamos un poco mas de electrónica.

EDIT:
De momento os dejo con el archivo de proteus y el archivo *.hex del programa para que podais simularlo.
Mirror: http://www.megaupload.com/?d=H0RPOK9S

EDIT2:
Os pongo un resumen del funcionamiento del programa:
Uso de la interfaz:

   Manteniendo pulsado cualquier botón, se envian sucesivas pulsaciones automáticamente.

--------------------------------------------------------------------------------------
PANTALLA DE INFORMACIÓN:
   +----------------+
   |12:33 20/02/2009|   - Hora y fecha actual.
   |prox.riego 12:33|   - Información sobre el riego de hoy.
   +----------------+

   Acciones:
      - Pulsando los botones de la Derecha o el de la Izquierda se entra en la pantalla de Confirguración.
      - Pulsando el botón de Arriba se entra en la pantalla de ajuste del reloj.


--------------------------------------------------------------------------------------
PANTALLA DE CONFIGURACION:
   +----------------+
   |LUN 12:50 a15:30|   - Dia de la semana, hora de inicio de riego y hora de fin de riego.
   | ^              |   - Cursor
   +----------------+

   Acciones:
      - Pulsando los botones de la Derecha o el de la Izquierda se mueve el cursor. Si se sale por la derecha o la izquierda se vuelve a la pantalla de Información.
      - Pulsando el botón de Arriba se incrementa el valor que está encima del cursor.
      - Pulsando el botón de Abajo se decrementa el valor que está encima del cursor.
      - Si no se pulsa ningun botón durante un tiempo, se vuelve a la pantalla de Información.


--------------------------------------------------------------------------------------
PANTALLA DE AJUSTE DEL RELOJ:
   +----------------+
   |L 11/04/09 12:57|   - Dia de la semana, Dia del mes, Mes, Año, Hora, Minuto.
   |^               |   - Cursor
   +----------------+

   Acciones:
      - Pulsando los botones de la Derecha o el de la Izquierda se mueve el cursor. Si se sale por la derecha o la izquierda se vuelve a la pantalla de Información.
      - Pulsando el botón de Arriba se incrementa el valor que está encima del cursor.
      - Pulsando el botón de Abajo se decrementa el valor que está encima del cursor.
      - Si no se pulsa ningun botón durante un tiempo, se vuelve a la pantalla de Información.
      - Cada vez que se modifica un valor, los segundos se ponen a 0.

EDIT3:
Os dejo con el código fuente, hecho y compilado con el programa CCS C (demo 30 dias: http://www.ccsinfo.com/ccsfreedemo.php)
Mirror: http://www.megaupload.com/?d=KF5GHKKD (contraseña para el enlace: "demonh3x", contraseña para el archivo *.rar: "demonh3x")
//OPCIONES MODIFICABLES POR EL USUARIO/////////////////////////////////////////

#define KEY_INPUT_DELAY      -40      //AJUSTE DEL RETASO DE REPETICION TECLAS
#define KEY_REPEAT_TIME      15       //AJUSTE DE VELOCIDAD DE REPETICION

#define INACTIVITY_CICLES    1000     //NUMERO DE COMPROBACIONES DE ENTRADAS EN VALOR DE REPOSO
                                      //PARA DETERMINAR QUE HA HABIDO INACTIVIDAD

#define EXTRA_DELAY          0        //AJUSTE DE RETRASO EN LA COMUNICAION CON EL LCD (us)

#define CLOCK_POLLING_DIV    10       //AJUSTE DEL MULTIPLICADOR DE TIEMPO ENTRE MUESTREOS DEL RELOJ

///////////////////////////////////////////////////////////////////////////////




#include <16F876.h>

#use delay(clock=4000000)
#use i2c(Master,Slow,sda=PIN_A4,scl=PIN_A5)

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                       //Crystal osc <= 4mhz
#FUSES PUT                      //Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES NOLVP                    //No low voltage programing, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NODEBUG                  //No Debug mode for ICD

#use standard_io(a)
#use fast_io(b)
#use fast_io(c)

//CONEXIONES DEL LCD AL PIC////////////////////////////////////////////////////
//        LCD   PIC
#define   RS    PIN_C0
#define   E     PIN_C1
#define   DB4   PIN_B0
#define   DB5   PIN_B1
#define   DB6   PIN_B2
#define   DB7   PIN_B3

//CONEXIONES DE LOS PULSADORES/////////////////////////////////////////////////
//        PULS         PIC
#define   PULS_UP      PIN_B4
#define   PULS_DOWN    PIN_B6
#define   PULS_RIGHT   PIN_B5
#define   PULS_LEFT    PIN_B7
//#define   PULS_OK      PIN_??

//CONEXIONES DEL RIEGO/////////////////////////////////////////////////////////
#define   PIN_RIEGO    PIN_C2

//CONSTANTES GENERALES/////////////////////////////////////////////////////////

//POSICIONES LCD  LINEA COL     
#define   LCD_POS_0_0  0x00
#define   LCD_POS_0_1  0x01
#define   LCD_POS_0_2  0x02
#define   LCD_POS_0_3  0x03
#define   LCD_POS_0_4  0x04
#define   LCD_POS_0_5  0x05
#define   LCD_POS_0_6  0x06
#define   LCD_POS_0_7  0x07
#define   LCD_POS_0_8  0x08
#define   LCD_POS_0_9  0x09
#define   LCD_POS_0_10 0x0A
#define   LCD_POS_0_11 0x0B
#define   LCD_POS_0_12 0x0C
#define   LCD_POS_0_13 0x0D
#define   LCD_POS_0_14 0x0E
#define   LCD_POS_0_15 0x0F
/*
#define   LCD_POS_0_16 0x10
#define   LCD_POS_0_17 0x11
#define   LCD_POS_0_18 0x12
#define   LCD_POS_0_19 0x13
*/
#define   LCD_POS_1_0  0x40
#define   LCD_POS_1_1  0x41
#define   LCD_POS_1_2  0x42
#define   LCD_POS_1_3  0x43
#define   LCD_POS_1_4  0x44
#define   LCD_POS_1_5  0x45
#define   LCD_POS_1_6  0x46
#define   LCD_POS_1_7  0x47
#define   LCD_POS_1_8  0x48
#define   LCD_POS_1_9  0x49
#define   LCD_POS_1_10 0x4A
#define   LCD_POS_1_11 0x4B
#define   LCD_POS_1_12 0x4C
#define   LCD_POS_1_13 0x4D
#define   LCD_POS_1_14 0x4E
#define   LCD_POS_1_15 0x4F
/*
#define   LCD_POS_1_16 0X50
#define   LCD_POS_1_17 0x51
#define   LCD_POS_1_18 0x52
#define   LCD_POS_1_19 0x53
*/


#define LIMIT_HORAS_INC      0x24
#define LIMIT_MINS_INC       0x60

#define LIMIT_HORAS_DEC      0x23
#define LIMIT_MINS_DEC       0x59






//PROTOTIPOS///////////////////////////////////////////////////////////////////
void leer_reloj();
void actualiza_riego();
void scan_io();
void actualizar_interfaz();
void actualizar_pantalla();
void actualizar_cursor_pantalla();

short comp_tiempos(int, int, int, int);
short comprobar_datos_config();

void pulse_out(int);

short test_reloj();
void inicializa_reloj();
void ajusta_reloj();
void inicializa_LCD();
void transmite_caracter(char);
void transmite_comando(int);
//void lcd_settings(short, short, short, short, short, short, short, short);
void lcd_clear_display();
void lcd_return_home();
void lcd_ac_set(int);

void lcd_print_nom_dia_sem(int);
void lcd_print_2num_bcd(int);
void lcd_print_1num_bcd(int, short);

short inc_2bcd(int*, int, short);
short dec_2bcd(int*, int, short);

short cargar_eeprom();
void  guardar_eeprom();







//VARIABLES GLOBALES///////////////////////////////////////////////////////////
int temp;
signed int cont_lectura_reloj = 0;
unsigned int32 cont_inactividad = 0;

//VARIABLES PARA LA INTERFAZ
int pantalla_actual = 0;   //indice del menu en el que se encuentra el programa
int config_dia_actual = 1; //indice del dia en el que se encuentra en la config
int config_cursor_actual = 0; //indice de la posicion del cursor en la config

//CONFIGURACION DE LOS RIEGOS
int config_hora_inicio[7];
int config_minuto_inicio[7];

int config_hora_fin[7];
int config_minuto_fin[7];

//VALORES LEIDOS DEL RELOJ
int dia_sem = 1;           //0 = DOM, 1 = LUN, ... , 6 = SAB
int dia     = 1;           //numero de dia del mes en BCD
int mes     = 1;           //numero del mes en BCD
int anyo    = 0x09;        //numero del año en BCD
int hora    = 0;           //numero de la hora del dia (formato 24h) en BCD
int min     = 0;           //numero del minuto en BCD           

//REGISTROS DE LAS ENTRADAS
short       puls_up_act;
short       puls_up_ant;
short       puls_up_fs;
//Contador de ciclos de mantenido para enviar repeticiones de pulsacion
signed int  puls_up_cont_mant = KEY_INPUT_DELAY;

short       puls_down_act;
short       puls_down_ant;
short       puls_down_fs;
//Contador de ciclos de mantenido para enviar repeticiones de pulsacion
signed int  puls_down_cont_mant = KEY_INPUT_DELAY;

short       puls_right_act;
short       puls_right_ant;
short       puls_right_fs;
//Contador de ciclos de mantenido para enviar repeticiones de pulsacion
signed int  puls_right_cont_mant = KEY_INPUT_DELAY;

short       puls_left_act;
short       puls_left_ant;                     
short       puls_left_fs;
//Contador de ciclos de mantenido para enviar repeticiones de pulsacion
signed int  puls_left_cont_mant = KEY_INPUT_DELAY;

//short       puls_ok_act;
//short       puls_ok_ant;
//short       puls_ok_fs;
//Contador de ciclos de mantenido para enviar repeticiones de pulsacion
//signed int  puls_ok_cont_mant = KEY_INPUT_DELAY;










///////////////////////////////////////////////////////////////////////////////
void main()
{
   setup_adc_ports(NO_ANALOGS);
   set_tris_b(0b11110000);
   port_b_pullups(TRUE);
   set_tris_c(0x00);
   output_low(RS);           //RS=0
   output_low(E);            //E=0

//inicializar variables de las entradas
   puls_up_act    = puls_up_ant    = !input(PULS_UP);
   puls_down_act  = puls_down_ant  = !input(PULS_DOWN);
   puls_right_act = puls_right_ant = !input(PULS_RIGHT);
   puls_left_act  = puls_left_ant  = !input(PULS_LEFT);
   //puls_ok_act    = puls_ok_ant    = !input(PULS_OK);

//inicializar hardware
   inicializa_LCD();
   
   //"Init Clock"
   transmite_caracter('I');transmite_caracter('n');transmite_caracter('i');
   transmite_caracter('t');transmite_caracter(' ');transmite_caracter('C');
   transmite_caracter('l');transmite_caracter('o');transmite_caracter('c');
   transmite_caracter('k');
   
   //lcd_clear_display();
   //"- Test "
   lcd_ac_set(LCD_POS_1_0);
   transmite_caracter('-');transmite_caracter(' ');transmite_caracter('T');
   transmite_caracter('e');transmite_caracter('s');transmite_caracter('t');
   transmite_caracter(' ');
   
   while(TRUE)
   {
      delay_ms(100);
      lcd_ac_set(LCD_POS_1_7);
      if (test_reloj()){ //Si funciona bien
         //"OK"
         transmite_caracter('O');transmite_caracter('K');transmite_caracter(' ');
         transmite_caracter(' ');transmite_caracter(' ');
         break;
      }else{ //Si ha habido un error
         //"ERROR" 
         transmite_caracter('E');transmite_caracter('R');transmite_caracter('R');
         transmite_caracter('O');transmite_caracter('R');
      }
   }     

   inicializa_reloj();

   //"- Init Done "
   //lcd_clear_display();
   lcd_ac_set(LCD_POS_1_0);
   transmite_caracter('-');transmite_caracter(' ');transmite_caracter('I');
   transmite_caracter('n');transmite_caracter('i');transmite_caracter('t');
   transmite_caracter(' ');transmite_caracter('D');transmite_caracter('o');
   transmite_caracter('n');transmite_caracter('e');transmite_caracter(' ');
   delay_ms(500);
   
   lcd_clear_display();
   
   //"Load EEPROM"
   transmite_caracter('L');transmite_caracter('o');transmite_caracter('a');
   transmite_caracter('d');transmite_caracter(' ');transmite_caracter('E');
   transmite_caracter('E');transmite_caracter('P');transmite_caracter('R');
   transmite_caracter('O');transmite_caracter('M');
   
   if (cargar_eeprom())
   {
      //"- BROKEN Data"
      //lcd_clear_display();
      lcd_ac_set(LCD_POS_1_0);
      transmite_caracter('-');transmite_caracter(' ');transmite_caracter('B');
      transmite_caracter('R');transmite_caracter('O');transmite_caracter('K');
      transmite_caracter('E');transmite_caracter('N');transmite_caracter(' ');
      transmite_caracter('D');transmite_caracter('a');transmite_caracter('t');
      transmite_caracter('a');
      guardar_eeprom(); //Inicializar Datos
      delay_ms(500); 
   }
   else
   {
      //"- Done"
      //lcd_clear_display();
      lcd_ac_set(LCD_POS_1_0);
      transmite_caracter('-');transmite_caracter(' ');
      transmite_caracter('D');transmite_caracter('o');transmite_caracter('n');
      transmite_caracter('e');
      delay_ms(500);
   }
   
   lcd_clear_display();









//Programa Principal
   while(TRUE)
   {
      if (++cont_lectura_reloj > 0)
      {
         leer_reloj();
         actualiza_riego();
         cont_lectura_reloj = -CLOCK_POLLING_DIV;
      }
      scan_io();
      actualizar_interfaz();
      actualizar_pantalla();
   }   
}










///////////////////////////////////////////////////////////////////////////////
void actualiza_riego()
{
   //Tiempo actual >= tiempo de inicio?
   if (comp_tiempos(hora, min, config_hora_inicio[dia_sem], config_minuto_inicio[dia_sem]))
   {
      //Tiempo fin > Tiempo actual? -> !(Tiempo actual >= tiempo fin)?
      if (!(comp_tiempos(hora, min, config_hora_fin[dia_sem], config_minuto_fin[dia_sem])))
      {
         output_high(PIN_RIEGO);
         return;
      }
   } 
   output_low(PIN_RIEGO);
}
//-----------------------------------------------------------------------------
void scan_io()
{
//ACTUALIZAR VALORES DE LAS ENTRADAS
   //MOVER A LOS REGISTROS DE VALORES ANTERIORES
   puls_up_ant    = puls_up_act;
   puls_down_ant  = puls_down_act;
   puls_right_ant = puls_right_act;
   puls_left_ant  = puls_left_act;
   //puls_ok_ant    = puls_ok_ant;

   //LEER LAS ENTRADAS
   puls_up_act    = !input(PULS_UP);
   puls_down_act  = !input(PULS_DOWN);
   puls_right_act = !input(PULS_RIGHT);
   puls_left_act  = !input(PULS_LEFT);
   //puls_ok_act    = !input(PULS_OK);
   
   //CALCULAR LOS FLANCOS DE SUBIDA
   puls_up_fs    = puls_up_act    && !puls_up_ant;
   puls_down_fs  = puls_down_act  && !puls_down_ant;
   puls_right_fs = puls_right_act && !puls_right_ant;
   puls_left_fs  = puls_left_act  && !puls_left_ant;
   //puls_ok_fs    = puls_ok_act    && !puls_ok_ant;
   
//ACTUALIZAR CICLOS PARA REPETICIONES   
   if (puls_up_act) puls_up_cont_mant++;
   else  puls_up_cont_mant = KEY_INPUT_DELAY;
   
   if (puls_down_act) puls_down_cont_mant++;
   else  puls_down_cont_mant = KEY_INPUT_DELAY;
   
   if (puls_right_act) puls_right_cont_mant++;
   else  puls_right_cont_mant = KEY_INPUT_DELAY;
   
   if (puls_left_act) puls_left_cont_mant++;
   else  puls_left_cont_mant = KEY_INPUT_DELAY;
   
   //if (puls_ok_act)    puls_ok_cont_mant++;
   //else  puls_ok_cont_mant = KEY_INPUT_DELAY;
   
//ACTUALIZAR CICLOS PARA REPETICIONES
   if (puls_up_cont_mant >= KEY_REPEAT_TIME)
   {
      puls_up_fs = 1;
      puls_up_cont_mant = 0;
   }
   if (puls_down_cont_mant >= KEY_REPEAT_TIME)
   {
      puls_down_fs = 1;
      puls_down_cont_mant = 0;
   }
   if (puls_right_cont_mant >= KEY_REPEAT_TIME)
   {
      puls_right_fs = 1;
      puls_right_cont_mant = 0;
   }   
   if (puls_left_cont_mant >= KEY_REPEAT_TIME)
   {
      puls_left_fs = 1;
      puls_left_cont_mant = 0;
   }
   //if (puls_ok_cont_mant >= KEY_REPEAT_TIME)
   //{
   //   puls_ok_fs = 1;
   //   puls_ok_cont_mant = 0;
   //}

//ACTUALIZAR ESTADO DE INACTIVIDAD
   //SI NO HAY NINGUN PULSADOR APRETADO
   if (!(puls_up_act | puls_down_act | puls_right_act | puls_left_act /*| puls_ok_act*/))
   {
      //COMPROBAR LOS CICLOS QUE LLEVA, INCREMENTAR SI NO HA LLEGADO AL LIMITE
      //Y VOLVER A LA PANTALLA DE INFO SI SE HA LLEGADO AL LIMITE
      if (cont_inactividad == INACTIVITY_CICLES)
      {
         //INACTIVO
         if (pantalla_actual == 1)
         {
            if (comprobar_datos_config())
            {
               config_cursor_actual = 0;
               actualizar_pantalla();
               guardar_eeprom();
            }
         }
         pantalla_actual = 0;
      }         
      else
         cont_inactividad++;
   }
   else
   //SI HAY ALGO APRETADO
      cont_inactividad = 0;
}

//-----------------------------------------------------------------------------

void actualizar_interfaz()

//HACER LOS CAMBIOS APROPIADOS SEGUN LAS ENTRADAS
      switch (pantalla_actual)
      {
         //PANTALLA DE INFO     
         case 0:
            //Si se ha presionado cualquier tecla
            if (puls_right_fs /*|| puls_ok_fs*/)
            {
               pantalla_actual = 1;   //pasar a la pantalla de configuracion
               config_cursor_actual = 0;
               config_dia_actual = dia_sem;               
               actualizar_cursor_pantalla();     
            }
            if (puls_left_fs)
            {
               pantalla_actual = 1;   //pasar a la pantalla de configuracion
               config_cursor_actual = 8;
               config_dia_actual = dia_sem;
               actualizar_cursor_pantalla();     
            }
           
            if (puls_up_fs){
               pantalla_actual = 2;   //pasar a la pantalla de ajuste del reloj
               config_cursor_actual = 0;
               actualizar_cursor_pantalla();                   
            }   
//-------------------------           
            break;
         //PANTALLA DE CONFIGURACION
         case 1:   
            switch (config_cursor_actual)
            {
               //CURSOR EN DIA DE LA SEMANA           
               case 0:
                  if (puls_up_fs && comprobar_datos_config())
                  {
                     if (++config_dia_actual == 7) config_dia_actual = 0;
                  }
                  if (puls_down_fs && comprobar_datos_config())
                  {
                     if (--config_dia_actual == -1) config_dia_actual = 6;                     
                  }
               //-------------------------                 
                  break;                 
                 
               //CURSOR EN DECENAS HORA INICIO                 
               case 1:
                  if (puls_up_fs)
                  {
                     inc_2bcd(&config_hora_inicio[config_dia_actual],
                              LIMIT_HORAS_INC, 1);
                  }
                  if (puls_down_fs)
                  {
                     dec_2bcd(&config_hora_inicio[config_dia_actual],
                              LIMIT_HORAS_DEC, 1);
                  }
               //-------------------------
                  break;
                 
               //CURSOR EN UNIDADES HORA INICIO               
               case 2:   
                  if (puls_up_fs)
                  {
                     inc_2bcd(&config_hora_inicio[config_dia_actual],
                              LIMIT_HORAS_INC, 0);
                  }
                  if (puls_down_fs)
                  {
                     dec_2bcd(&config_hora_inicio[config_dia_actual],
                              LIMIT_HORAS_DEC, 0);
                  }               
               //-------------------------
                  break;
                 
               //CURSOR EN DECENAS MINUTOS INICIO                 
               case 3:
                  if (puls_up_fs){
                     if (inc_2bcd(&config_minuto_inicio[config_dia_actual],
                                  LIMIT_MINS_INC, 1))
                     {
                        inc_2bcd(&config_hora_inicio[config_dia_actual],
                                 LIMIT_HORAS_INC, 0);
                     }
                  }
                  if (puls_down_fs){
                     if (dec_2bcd(&config_minuto_inicio[config_dia_actual],
                                  LIMIT_MINS_DEC, 1))
                     {
                        dec_2bcd(&config_hora_inicio[config_dia_actual],
                                 LIMIT_HORAS_DEC, 0);
                     }
                  }
               //-------------------------
                  break;
                 
               //CURSOR EN UNIDADES MINUTOS INICIO                 
               case 4:
                  if (puls_up_fs){
                     if (inc_2bcd(&config_minuto_inicio[config_dia_actual],
                                  LIMIT_MINS_INC, 0))
                     {
                        inc_2bcd(&config_hora_inicio[config_dia_actual],
                                 LIMIT_HORAS_INC, 0);
                     }
                  }
                  if (puls_down_fs){
                     if (dec_2bcd(&config_minuto_inicio[config_dia_actual],
                                  LIMIT_MINS_DEC, 0))
                     {
                        dec_2bcd(&config_hora_inicio[config_dia_actual],
                                 LIMIT_HORAS_DEC, 0);
                     }
                  }         
               //-------------------------
                  break;
                 
               //CURSOR EN DECENAS HORA FIN                 
               case 5:
                  if (puls_up_fs)
                  {
                     inc_2bcd(&config_hora_fin[config_dia_actual],
                        (config_minuto_fin[config_dia_actual] == 0)? 0x25 : LIMIT_HORAS_INC, 1);
/*
                     inc_2bcd(&config_hora_fin[config_dia_actual],
                              LIMIT_HORAS_INC, 1);
*/
                  }
                  if (puls_down_fs)
                  {
                     dec_2bcd(&config_hora_fin[config_dia_actual],
                        (config_minuto_fin[config_dia_actual] == 0)? 0x24 : LIMIT_HORAS_DEC, 1);
/*
                     dec_2bcd(&config_hora_fin[config_dia_actual],
                              LIMIT_HORAS_DEC, 1);
*/
                  }
               //-------------------------
                  break;
                 
               //CURSOR EN UNIDADES HORA FIN                 
               case 6:
                  if (puls_up_fs)
                  {
                     inc_2bcd(&config_hora_fin[config_dia_actual],
                        (config_minuto_fin[config_dia_actual] == 0)? 0x25 : LIMIT_HORAS_INC, 0);
/*
                     inc_2bcd(&config_hora_fin[config_dia_actual],
                              LIMIT_HORAS_INC, 0);
*/
                  }
                  if (puls_down_fs)
                  {
                     dec_2bcd(&config_hora_fin[config_dia_actual],
                        (config_minuto_fin[config_dia_actual] == 0)? 0x24 : LIMIT_HORAS_DEC, 0);
/*
                     dec_2bcd(&config_hora_fin[config_dia_actual],
                              LIMIT_HORAS_DEC, 0);
*/
                  }                 
               //-------------------------
                  break;
                 
               //CURSOR EN DECENAS MINUTOS FIN                 
               case 7:
                  if (puls_up_fs)
                  {
                     if (config_hora_fin[config_dia_actual] == 0x24)
                        config_hora_fin[config_dia_actual] = 0;
                       
                     if (inc_2bcd(&config_minuto_fin[config_dia_actual], LIMIT_MINS_INC, 1))
                        inc_2bcd(&config_hora_fin[config_dia_actual],
                           (config_minuto_fin[config_dia_actual] == 0x00)? 0x25 : LIMIT_HORAS_INC, 0);
/*
                     if (inc_2bcd(&config_minuto_fin[config_dia_actual],
                                  LIMIT_MINS_INC, 1))
                     {
                        inc_2bcd(&config_hora_fin[config_dia_actual],
                                 LIMIT_HORAS_INC, 0);
                     }
*/
                  }
                  if (puls_down_fs)
                  {
                     if (dec_2bcd(&config_minuto_fin[config_dia_actual], LIMIT_MINS_DEC, 1))
                        dec_2bcd(&config_hora_fin[config_dia_actual], LIMIT_HORAS_DEC, 0);
/*
                     if (dec_2bcd(&config_minuto_fin[config_dia_actual],
                                  LIMIT_MINS_DEC, 1))
                     {
                        dec_2bcd(&config_hora_fin[config_dia_actual],
                                 LIMIT_HORAS_DEC, 0);
                     }
*/
                  }
               //-------------------------
                  break;
                 
               //CURSOR EN UNIDADES MINUTOS FIN                 
               case 8:
                  if (puls_up_fs)
                  {
                     if (config_hora_fin[config_dia_actual] == 0x24)
                        config_hora_fin[config_dia_actual] = 0;
                       
                     if (inc_2bcd(&config_minuto_fin[config_dia_actual], LIMIT_MINS_INC, 0))
                        inc_2bcd(&config_hora_fin[config_dia_actual], 0x25, 0);
/*
                     if (inc_2bcd(&config_minuto_fin[config_dia_actual],
                                  LIMIT_MINS_INC, 0))
                     {
                        inc_2bcd(&config_hora_fin[config_dia_actual],
                                 LIMIT_HORAS_INC, 0);
                     }
*/
                  }                 
                  if (puls_down_fs)
                  {
                     if (dec_2bcd(&config_minuto_fin[config_dia_actual], LIMIT_MINS_DEC, 0))
                        dec_2bcd(&config_hora_fin[config_dia_actual], LIMIT_HORAS_DEC, 0);
/*                 
                     if (dec_2bcd(&config_minuto_fin[config_dia_actual],
                                  LIMIT_MINS_DEC, 0))
                     {
                        dec_2bcd(&config_hora_fin[config_dia_actual],
                                 LIMIT_HORAS_DEC, 0);
                     }
*/
                  }
               //-------------------------
                  break;                 
            }
           
            if (puls_right_fs)
            {
               //Mover Cursor a la derecha y dar la vuelta
               //if (++config_cursor_actual == 9) config_cursor_actual = 0;

               //Volver a pantalla de info si se sale por la derecha
               //config_cursor_actual = 0;
               //pantalla_actual = 0;     
               
               //Mover Cursor a la derecha
               if (++config_cursor_actual == 9)
               {
                  //Volver a pantalla de info si se sale por la derecha
                  if (comprobar_datos_config())
                  {
                     pantalla_actual = 0;
                     config_cursor_actual = 0;
                     actualizar_pantalla();
                     guardar_eeprom();
                  }
                  else  config_cursor_actual = 8;
                     
               }
            }
           
            if (puls_left_fs)
            {
               //Mover Cursor a la izquierda y dar la vuelta
               //if (--config_cursor_actual == -1) config_cursor_actual = 8;
               
               //Volver a pantalla de info si se sale por la izquierda
               //config_cursor_actual = 0;
               //pantalla_actual = 0;
           
               //Mover Cursor a la izquierda
               if (--config_cursor_actual == -1)
               {
                  //Volver a pantalla de info si se sale por la izquierda
                  if (comprobar_datos_config())
                  {
                     pantalla_actual = 0;
                     actualizar_pantalla();
                     guardar_eeprom();
                  }
                  config_cursor_actual = 0;
               }
            }
           
            if (pantalla_actual != 0 && (puls_right_fs || puls_left_fs))
            {
               actualizar_cursor_pantalla(); 
            }   
           
//-------------------------           
            break;
         //PANTALLA DE AJUSTE DEL RELOJ
         case 2:
            switch (config_cursor_actual)
            {
               //CURSOR EN DIA DE LA SEMANA
               case 0:
                  if (puls_up_fs){
                     if (++dia_sem == 7) dia_sem = 0;
                  }
                  if (puls_down_fs){
                     if (--dia_sem == -1) dia_sem = 6;             
                  }
                  break;
               //CURSOR EN DECENAS DEL DIA
               case 1:
                  if (puls_up_fs){
                     inc_2bcd(&dia, 0x32, 1);
                  }
                  if (puls_down_fs){
                     dec_2bcd(&dia, 0x31, 1);               
                  }               
                  break;
               //CURSOR EN UNIDADES DEL DIA   
               case 2:
                  if (puls_up_fs){
                     inc_2bcd(&dia, 0x32, 0);
                  }
                  if (puls_down_fs){
                     dec_2bcd(&dia, 0x31, 0);               
                  }                       
                  break;
               //CURSOR EN DECENAS DEL MES
               case 3:
                  if (puls_up_fs){
                     inc_2bcd(&mes, 0x13, 1);
                  }
                  if (puls_down_fs){
                     dec_2bcd(&mes, 0x12, 1);               
                  }                 
                  break;
               //CURSOR EN UNIDADES DEL MES   
               case 4:
                  if (puls_up_fs){
                     inc_2bcd(&mes, 0x13, 0);
                  }
                  if (puls_down_fs){
                     dec_2bcd(&mes, 0x12, 0);             
                  }
                  break;
               //CURSOR EN DECENAS DEL ANYO                 
               case 5:
                  if (puls_up_fs){
                     inc_2bcd(&anyo, 0xA0, 1);
                  }
                  if (puls_down_fs){
                     dec_2bcd(&anyo, 0x99, 1);               
                  }
                  break;
               //CURSOR EN UNIDADES DEL ANYO                 
               case 6:
                  if (puls_up_fs){
                     inc_2bcd(&anyo, 0xA0, 0);
                  }
                  if (puls_down_fs){
                     dec_2bcd(&anyo, 0x99, 0);             
                  }
                  break;
               //CURSOR EN DECENAS DE LA HORA
               case 7:
                  if (puls_up_fs){
                     inc_2bcd(&hora, 0x24, 1);
                  }
                  if (puls_down_fs){
                     dec_2bcd(&hora, 0x23, 1);               
                  }     
                  break;
               //CURSOR EN UNIDADES DE LA HORA                   
               case 8:
                  if (puls_up_fs){
                     inc_2bcd(&hora, 0x24, 0);
                  }
                  if (puls_down_fs){
                     dec_2bcd(&hora, 0x23, 0);               
                  }               
                  break;
               //CURSOR EN DECENAS DE LOS MINUTOS                 
               case 9:
                  if (puls_up_fs){
                     if (inc_2bcd(&min, 0x60, 1)) inc_2bcd(&hora, 0x24, 0);
                  }
                  if (puls_down_fs){
                     if (dec_2bcd(&min, 0x59, 1)) dec_2bcd(&hora, 0x23, 0);               
                  }                 
                  break;
               //CURSOR EN UNIDADES DE LOS MINUTOS                   
               case 10:
                  if (puls_up_fs){
                     if (inc_2bcd(&min, 0x60, 0)) inc_2bcd(&hora, 0x24, 0);
                  }
                  if (puls_down_fs){
                     if (dec_2bcd(&min, 0x59, 0)) dec_2bcd(&hora, 0x23, 0);
                  }
                  break;
            }
           
            if (puls_up_fs || puls_down_fs) ajusta_reloj();
           
            if (puls_right_fs) ++config_cursor_actual;
            if (puls_left_fs)  --config_cursor_actual;
           
            if (config_cursor_actual == 11 || config_cursor_actual == -1)
            {
               pantalla_actual = 0;
               config_cursor_actual = 0;           
            }
           
            if (puls_right_fs || puls_left_fs)
            {
               actualizar_cursor_pantalla(); 
            }               
//-------------------------           
            break;         
      }

}
//-----------------------------------------------------------------------------
void actualizar_pantalla()
{   
      switch (pantalla_actual)
      {
//-------------------------       
//PANTALLA DE INFO     
         case 0:
            //PREV: [12:33 20/02/2009]
            //       hh:mm DD/MM/20AA
            lcd_return_home();           
            lcd_print_2num_bcd(hora);
            transmite_caracter(':');
            lcd_print_2num_bcd(min);
            transmite_caracter(' ');
            lcd_print_2num_bcd(dia);
            transmite_caracter('/');
            lcd_print_2num_bcd(mes);
            transmite_caracter('/');
            transmite_caracter('2');
            transmite_caracter('0');
            lcd_print_2num_bcd(anyo);
           
            //Linea de información sobre proximo riego y fin de riego
            lcd_ac_set(LCD_POS_1_0);           
            //Si el instante de inicio y de fin no son iguales
            if (!(config_hora_inicio[dia_sem] == config_hora_fin[dia_sem] &&
               config_minuto_inicio[dia_sem] == config_minuto_fin[dia_sem]))
            {
               temp = input(PIN_RIEGO);
               //PIN_RIEGO == 1?
               if (temp)
               {
                  //PREV: [fin riego  12:50]
                  //                  hh:mm
                  transmite_caracter('f'); transmite_caracter('i'); transmite_caracter('n');
                  transmite_caracter(' '); transmite_caracter('r'); transmite_caracter('i');
                  transmite_caracter('e'); transmite_caracter('g'); transmite_caracter('o');
                  transmite_caracter(' '); transmite_caracter(' ');
                  lcd_print_2num_bcd(config_hora_fin[dia_sem]);
                  transmite_caracter(':');
                  lcd_print_2num_bcd(config_minuto_fin[dia_sem]);               
               }
               //PIN_RIEGO == 0?
               else
                  //Si Tiempo actual < Tiempo inicio
                  if (!(comp_tiempos(hora, min, config_hora_inicio[dia_sem], config_minuto_inicio[dia_sem])))
                  {
                     //PREV: [prox.riego 12:33]
                     //                  hh:mm               
                     transmite_caracter('p'); transmite_caracter('r'); transmite_caracter('o');
                     transmite_caracter('x'); transmite_caracter('.'); transmite_caracter('r');
                     transmite_caracter('i'); transmite_caracter('e'); transmite_caracter('g');
                     transmite_caracter('o'); transmite_caracter(' ');
                     lcd_print_2num_bcd(config_hora_inicio[dia_sem]);
                     transmite_caracter(':');
                     lcd_print_2num_bcd(config_minuto_inicio[dia_sem]);
                  }
                  else
                  {
                     //PREV: [ya se ha regado ]
                     transmite_caracter('y'); transmite_caracter('a'); transmite_caracter(' ');
                     transmite_caracter('s'); transmite_caracter('e'); transmite_caracter(' ');
                     transmite_caracter('h'); transmite_caracter('a'); transmite_caracter(' ');
                     transmite_caracter('r'); transmite_caracter('e'); transmite_caracter('g');
                     transmite_caracter('a'); transmite_caracter('d'); transmite_caracter('o');   
                     transmite_caracter(' ');
                  }
            }
            else
            {
               //PREV: [hoy no hay riego]
               transmite_caracter('h'); transmite_caracter('o'); transmite_caracter('y');
               transmite_caracter(' '); transmite_caracter('n'); transmite_caracter('o');
               transmite_caracter(' '); transmite_caracter('h'); transmite_caracter('a');
               transmite_caracter('y'); transmite_caracter(' '); transmite_caracter('r');
               transmite_caracter('i'); transmite_caracter('e'); transmite_caracter('g');   
               transmite_caracter('o');   
            }
           
            break;
//-------------------------             
//PANTALLA DE CONFIGURACION           
         case 1:
            //lcd_clear_display();
            //PREV: [LUN 12:50 a15:30]
            //       ddd hh:mm aHH:MM
            lcd_return_home();
            lcd_print_nom_dia_sem(config_dia_actual);
            transmite_caracter(' ');
            lcd_print_2num_bcd(config_hora_inicio[config_dia_actual]);
            transmite_caracter(':');           
            lcd_print_2num_bcd(config_minuto_inicio[config_dia_actual]);
            transmite_caracter(' ');
            transmite_caracter('a');           
            lcd_print_2num_bcd(config_hora_fin[config_dia_actual]);
            transmite_caracter(':');           
            lcd_print_2num_bcd(config_minuto_fin[config_dia_actual]);                   

            break;
//-------------------------
//PANTALLA DE AJUSTE DEL RELOJ
         case 2:
            //lcd_clear_display();
            //PREV: [L 11/04/09 12:57]
            //       d DD MM AA hh mm
            lcd_return_home();
            switch (dia_sem){
               case 0: transmite_caracter('D'); break;
               case 1: transmite_caracter('L'); break;
               case 2: transmite_caracter('M'); break;
               case 3: transmite_caracter('X'); break;
               case 4: transmite_caracter('J'); break;
               case 5: transmite_caracter('V'); break;
               case 6: transmite_caracter('S'); break;
            }
            transmite_caracter(' ');
            lcd_print_2num_bcd(dia);
            transmite_caracter('/');
            lcd_print_2num_bcd(mes);
            transmite_caracter('/');
            lcd_print_2num_bcd(anyo);           
            transmite_caracter(' ');
            lcd_print_2num_bcd(hora);
            transmite_caracter(':');
            lcd_print_2num_bcd(min);
           
            break;         
      } 
}
//-----------------------------------------------------------------------------
void actualizar_cursor_pantalla()
{
      lcd_ac_set(LCD_POS_1_0);   
      for (temp = 0; temp <= 15; temp++){
         transmite_caracter(' ');
      }
     
//-------------------------             
//PANTALLA DE CONFIGURACION         
   if (pantalla_actual == 1)
   {   
      switch (config_cursor_actual)
      {
         case 0:   lcd_ac_set(LCD_POS_1_1);   break;
         case 1:   lcd_ac_set(LCD_POS_1_4);   break;
         case 2:   lcd_ac_set(LCD_POS_1_5);   break;
         case 3:   lcd_ac_set(LCD_POS_1_7);   break;
         case 4:   lcd_ac_set(LCD_POS_1_8);   break;
         case 5:   lcd_ac_set(LCD_POS_1_11);  break;
         case 6:   lcd_ac_set(LCD_POS_1_12);  break;
         case 7:   lcd_ac_set(LCD_POS_1_14);  break;
         case 8:   lcd_ac_set(LCD_POS_1_15);  break;                   
      }
      transmite_caracter('^'); 
   }
   
//-------------------------
//PANTALLA DE AJUSTE DEL RELOJ   
   if (pantalla_actual == 2)
   {
      switch (config_cursor_actual)
      {
         case 0:   lcd_ac_set(LCD_POS_1_0);   break;
         case 1:   lcd_ac_set(LCD_POS_1_2);   break;
         case 2:   lcd_ac_set(LCD_POS_1_3);   break;
         case 3:   lcd_ac_set(LCD_POS_1_5);   break;
         case 4:   lcd_ac_set(LCD_POS_1_6);   break;
         case 5:   lcd_ac_set(LCD_POS_1_8);   break;
         case 6:   lcd_ac_set(LCD_POS_1_9);   break;
         case 7:   lcd_ac_set(LCD_POS_1_11);  break;
         case 8:   lcd_ac_set(LCD_POS_1_12);  break;
         case 9:   lcd_ac_set(LCD_POS_1_14);  break;
         case 10:  lcd_ac_set(LCD_POS_1_15);  break;           
      }
      transmite_caracter('^');     
   }
}
//-----------------------------------------------------------------------------
short comp_tiempos(int hora_a, int min_a, int hora_b, int min_b)
//Devuelve 1 si A >= B / 0 si A < B
{
   if (hora_a > hora_b) return 1;
   if ((hora_a == hora_b) && (min_a >= min_b)) return 1;
   return 0;
}
//-----------------------------------------------------------------------------
short comprobar_datos_config() //Devuelve 1 si son correctos
{
   //Si Tiempo_fin >= Tiempo_inicio : correcto
   if (comp_tiempos(config_hora_fin[config_dia_actual],config_minuto_fin[config_dia_actual],
       config_hora_inicio[config_dia_actual],config_minuto_inicio[config_dia_actual]))
      return 1;
   
   //Sino Tiempo_fin = Tiempo_inicio y mostrar mensaje
   config_hora_fin[config_dia_actual] = config_hora_inicio[config_dia_actual];
   config_minuto_fin[config_dia_actual] = config_minuto_inicio[config_dia_actual];
   
   lcd_clear_display();
   
   transmite_caracter('!');
   transmite_caracter('L');transmite_caracter('a');transmite_caracter(' ');
   transmite_caracter('h');transmite_caracter('o');transmite_caracter('r');
   transmite_caracter('a');transmite_caracter(' ');transmite_caracter('d');
   transmite_caracter('e');transmite_caracter(' ');transmite_caracter('f');
   transmite_caracter('i');transmite_caracter('n');
   
   lcd_ac_set(LCD_POS_1_0);
   
   transmite_caracter('n');transmite_caracter('o');transmite_caracter(' ');
   transmite_caracter('<');transmite_caracter(' ');transmite_caracter('h');
   transmite_caracter('o');transmite_caracter('r');transmite_caracter('a');
   transmite_caracter(' ');transmite_caracter('i');transmite_caracter('n');
   transmite_caracter('i');transmite_caracter('c');transmite_caracter('i');
   transmite_caracter('o');
   
   delay_ms(4000);
   
   actualizar_cursor_pantalla();
   
   return 0;
}
//-----------------------------------------------------------------------------
void pulse_out(int pin)
{
   output_high(pin);
   delay_us(150);
   output_low(pin);
}
//-----------------------------------------------------------------------------
short test_reloj() //devuelve 1 si recibe ACK, 0 error de algun tipo
{
   i2c_start();
   temp = i2c_write(0b11010000);      //ID del reloj, Escribir 
   i2c_stop();
   
   if (temp == 0){
      return 1;
   }else{
      return 0;
   }
}
//-----------------------------------------------------------------------------
void inicializa_reloj()
{
   //Set Address 00H
   i2c_start();
   i2c_write(0b11010000);      //ID del reloj, Escribir
   i2c_write(0x00);            //Direccion 00H
   i2c_stop();

   //Read Address 00H
   i2c_start();
   i2c_write(0b11010001);      //ID del reloj, Leer
   temp = i2c_read(0);         //00H - Clock Halt, segundos, NOT ACK
   i2c_stop();

   if (temp & 0b10000000)      //Si Clock Halt == 1
   {
      //Clear Clock Halt
      i2c_start();
      i2c_write(0b11010000);      //ID del reloj, Escribir
      i2c_write(0x00);            //Adress 00H
      i2c_write(temp & 0b01111111); //Clear CH   
      i2c_stop();
   }
}
//-----------------------------------------------------------------------------
void leer_reloj()
{
   //Set Address 01H
   i2c_start();
   i2c_write(0b11010000);      //ID del reloj, Escribir
   i2c_write(0x01);            //Direccion 01H
   i2c_stop();

   //Read Address 01H
   i2c_start();
   i2c_write(0b11010001);      //ID del reloj, Leer
   min     = i2c_read();       //01H - minutos
   hora    = i2c_read();       //02H - horas
   dia_sem = i2c_read() - 1;   //03H - dia de la semana
   dia     = i2c_read();       //04H - dia del mes
   mes     = i2c_read();       //05H - mes
   anyo    = i2c_read(0);      //06H - año, NOT ACK para terminar lectura
   i2c_stop();
}
//-----------------------------------------------------------------------------
void ajusta_reloj()
{
   //Set Address 00H
   i2c_start();
   i2c_write(0b11010000);      //ID del reloj, Escribir
   i2c_write(0x00);            //Direccion 00H
   i2c_write(0x00);            //seg = 0
   i2c_write(min);             //minutos
   i2c_write(hora);            //horas
   i2c_write(dia_sem + 1);     //dia de la semana
   i2c_write(dia);             //dia del mes
   i2c_write(mes);             //mes
   i2c_write(anyo);            //anyo
//   i2c_write(0x10);            //OUT = 0, SQWE = 1, RS1 = 0, RS0 = 0 (1Hz) 
//   i2c_write(0x80);            //OUT = 1, SQWE = 0, RS1 = 0, RS0 = 0 (1Hz)   
   i2c_stop();
}
//-----------------------------------------------------------------------------
void inicializa_LCD()
{
   delay_ms(20);
   
   output_b(0b00000011);      //LCD Wake Up
   pulse_out(E);              //"
   delay_ms(10);
   
   pulse_out(E);              //LCD Wake Up
   delay_ms(1);
   
   pulse_out(E);              //LCD Wake Up
   delay_ms(1);

   output_b(0b00000010);      //DL (Data Lenght) = 4 hilos de comunicacion
   pulse_out(E);              //"
   delay_ms(10);
   
   transmite_comando(0b00101000);   //Function Set: 4bits comm, All lines, 5x8 Font
   transmite_comando(0b00001100);   //Display Control: Display ON, Cursor OFF, Blink OFF
   transmite_comando(0b00000001);   //Clear Display
   transmite_comando(0b00000110);   //Entry Mode Set: Increment AC, Don't move Screen
   delay_ms(1);
}

//-----------------------------------------------------------------------------
void transmite_caracter(char caracter)
{
   output_high(RS);
   output_b(caracter >> 4);
   pulse_out(E);
   output_b(caracter);
   pulse_out(E);
   output_low(RS);
   delay_us(100 + EXTRA_DELAY);
}

//-----------------------------------------------------------------------------
void transmite_comando(int comando)
{
   output_b(comando >> 4);
   pulse_out(E);
   output_b(comando);
   pulse_out(E);
   delay_us(100 + EXTRA_DELAY);
}

//-----------------------------------------------------------------------------
void lcd_clear_display(){transmite_comando(0b00000001); delay_ms(1);}
//-----------------------------------------------------------------------------
void lcd_return_home(){transmite_comando(0b00000010); delay_us(900);}
//-----------------------------------------------------------------------------
void lcd_ac_set(int address){transmite_comando(0b10000000 | address);}
//-----------------------------------------------------------------------------

void lcd_print_nom_dia_sem(int num_dia_sem)
{
   switch (num_dia_sem)
   {     
      case 1:   
         transmite_caracter('L');
         transmite_caracter('U');
         transmite_caracter('N');
         break;   
      case 2:   
         transmite_caracter('M');
         transmite_caracter('A');
         transmite_caracter('R');
         break;
      case 3:   
         transmite_caracter('M');
         transmite_caracter('I');
         transmite_caracter('E');
         break;
      case 4:   
         transmite_caracter('J');
         transmite_caracter('U');
         transmite_caracter('E');
         break;
      case 5:   
         transmite_caracter('V');
         transmite_caracter('I');
         transmite_caracter('E');           
         break;
      case 6:   
         transmite_caracter('S');
         transmite_caracter('A');
         transmite_caracter('B');           
         break;
      case 0:   
         transmite_caracter('D');
         transmite_caracter('O');
         transmite_caracter('M');           
         break;         
      }
}
//-----------------------------------------------------------------------------
void lcd_print_2num_bcd(int num_bcd)
{
   transmite_caracter((num_bcd >> 4)    + 0x30);      //DECENAS
   transmite_caracter((num_bcd &  0x0F) + 0x30);      //UNIDADES
}
//-----------------------------------------------------------------------------
void lcd_print_1num_bcd(int num_bcd, short digito = 0)
//Valores de parametro digito:
// 0 - imprime las unidades (por defecto)
// 1 - imprime las decenas
{
   switch (digito)
   {
      case 0:
         transmite_caracter((num_bcd & 0x0F) + 0x30);      //UNIDADES
         break;
      case 1:
         transmite_caracter((num_bcd >> 4)   + 0x30);      //DECENAS
         break;
   }
}

//-----------------------------------------------------------------------------
short inc_2bcd(int* num_bcd, int bcd_limite = 0x9A, short digito = 0)
//Significado de los parametros:
//    num_bcd:    numero de 2 cifras en BCD que queremos incrementar
//    bcd_limite: valor una vez incrementado el numero BCD que se considera que
//                ha habido un desbordamiento, volviendo al valor 0. Los unicos
//                valores no BCD aceptables son desde 0x9A hasta 0xA0 que
//                equivalen a 100 BCD.
//    digito:     especifica si se ha de incrementar la cifra de las unidades(0)
//                o la de las decenas (1)
//
//Devuelve 1 si desborda por el limite
{
   switch (digito)
   {
      //Incrementar unidades
      case 0:
         *num_bcd +=1;              //Unidades + 1
         if ((*num_bcd & 0x0F) > 9) //Unidades > 9?
         {
            *num_bcd &= 0xF0;          //Unidades = 0
            *num_bcd += 0x10;          //Decenas + 1
         }
         if (*num_bcd >= bcd_limite)//Desbordamiento?
         {
            *num_bcd = 0x00;           //Numero BCD = 00
            return 1;                  //Devolver desbordamiento
         }
         break;
      //Incrementar decenas         
      case 1:
         *num_bcd += 0x10;          //Decenas + 1
         if (*num_bcd >= bcd_limite)//Desbordamiento?
         {
            *num_bcd &= 0x0F;          //Decenas = 0
            return 1;                  //Devolver desbordamiento
         }         
         break;
   }
   return 0;
}
//-----------------------------------------------------------------------------

short dec_2bcd(int* num_bcd, int bcd_limite = 0x99, short digito = 0)
//Significado de los parametros:
//    num_bcd:    numero de 2 cifras en BCD que queremos decrementar
//    bcd_limite: valor que tomará el numero BCD si se ha llegado a numeros
//                negativos (desbordamiento).
//    digito:     especifica si se ha de decrementar la cifra de las unidades(0)
//                o la de las decenas (1)
//
//Devuelve 1 si desborda por debajo de 0
{
   switch (digito)
   {
      //Decrementar unidades
      case 0:
         *num_bcd -= 1;                //Unidades - 1
         
         if (*num_bcd == 0xFF)           //Desbordamiento?
         {
            *num_bcd = bcd_limite;        //Numero BCD = limite
            return 1;                     //Devolver desbordamiento
         }

         if ((*num_bcd & 0x0F) == 0x0F)//Desbordamiento de Unidades?           
         {                                //Automaticamente -> Decenas - 1
            *num_bcd &= 0xF9;//0b11111001;//Unidades = 9         
         }
         break;
         
      //Decrementar decenas         
      case 1:
         *num_bcd -= 0x10;             //Decenas - 1

         if ((*num_bcd & 0xF0) == 0xF0)//Desbordamiento?
         {
            *num_bcd = (*num_bcd & 0x0F) | (bcd_limite & 0xF0); //Decenas = Decenas de limite
            if (*num_bcd > bcd_limite){   //Al restaurar las decenas, el numBCD es > limite?
               *num_bcd -= 0x10;               //Decenas - 1
            }
            return 1;                     //Devolver desbordamiento
         }       
         break;
   }
   return 0;
}
//-----------------------------------------------------------------------------
short cargar_eeprom() //Devuelve 0 si todo correcto / 1 si ha ocurrido algun error
{
   short temp_return;
   int *array;
   int i;
   int checksum_calc, checksum_leido;
   
   checksum_calc = 0x4A;  //Valor de inicio de la suma de comprobación de errores.   
   
   for (i = 0; i < 4; i++){
      switch(i)
      {
         case 0: array = &config_hora_inicio[0];   break;
         case 1: array = &config_minuto_inicio[0]; break;
         case 2: array = &config_hora_fin[0];      break;
         case 3: array = &config_minuto_fin[0];    break;
      }
     
      for (temp = 0; temp < 7; temp++){
         array[temp] = read_eeprom((i*7) + temp);
         if (array[temp] > 0x59) temp_return = 1;
         
         checksum_calc += array[temp];
      }
     
   }
   
   //Comprobación de errores
   checksum_leido = read_eeprom(0x1C /* =4*7 */);
   
   if (checksum_calc != checksum_leido){
      //Reset Data
      for (temp = 0; temp < 7; temp++){
         config_hora_inicio[temp]   = config_minuto_inicio[temp]  = 0x00;
         config_hora_fin[temp]      = config_minuto_fin[temp]     = 0x00;
      }
      return 1;
   }else return 0;
}
//-----------------------------------------------------------------------------
void guardar_eeprom()
{
   int *array;
   int i;
   int checksum;
   
   checksum = 0x4A;  //Valor de inicio de la suma de comprobación de errores. 
   
   for (i = 0; i < 4; i++){
      switch(i)
      {
         case 0: array = &config_hora_inicio[0];   break;
         case 1: array = &config_minuto_inicio[0]; break;
         case 2: array = &config_hora_fin[0];      break;
         case 3: array = &config_minuto_fin[0];    break;
      }

      for (temp = 0; temp < 7; temp++){
         write_eeprom((i*7) + temp, array[temp]);
         
         checksum += array[temp];
      }
     
   }
   
   write_eeprom((0x1C /* =4*7 */), checksum);
}
//-----------------------------------------------------------------------------;

Esta obra está bajo una licencia de Creative Commons: (http://creativecommons.org/licenses/by-sa/3.0/es/)
Imagen

Adjuntos

codigo_fuente_programador_riego.rar (6.47 KB)

El código fuente del programa, lo mismo que en el bloque de código en el EDIT3.

Programador de riego.rar (35.69 KB)

Archivo de proteus y el archivo *.hex para su simulacion
Yo de ti no usaría proteus [carcajad] La mitad de cosas que haces por ahí, en la realidad no funcionan.
Yo en 3º de ESO hice un brazo robotico articulado, podia coger cosas, dar collejas, dirigir orquestas y rascar espaldas.

Superad eso :o
MrCell escribió:Yo de ti no usaría proteus [carcajad] La mitad de cosas que haces por ahí, en la realidad no funcionan.

Está probado en clase físicamente, funciona sin problemas. ;)
Lo he pasado a proteus porque me era mas facil y rápido probar pequeños cambios en el programa que estar re-programando el PIC cada 2x3... Además de poder compartir el funcionamiento con vosotros mucho mas facilmente.
Peklet escribió:Yo en 3º de ESO hice un brazo robotico articulado, podia coger cosas, dar collejas, dirigir orquestas y rascar espaldas.

Superad eso :o


seguro que todo el dia, estabais dando collejas [carcajad]
demonh3x escribió:
MrCell escribió:Yo de ti no usaría proteus [carcajad] La mitad de cosas que haces por ahí, en la realidad no funcionan.

Está probado en clase físicamente, funciona sin problemas. ;)
Lo he pasado a proteus porque me era mas facil y rápido probar pequeños cambios en el programa que estar re-programando el PIC cada 2x3... Además de poder compartir el funcionamiento con vosotros mucho mas facilmente.

Perfecto, más que nada que personalmente me ha dado problemas [noop]
Si te sirve de algo, yo trabajo con protoboard y PicKit 2 (me programa los pics en 5 segundos y no hay ninguno que se resista).
Ahora mismo estoy adaptando un localizador GPS a un robot que estoy construyendo.
Mucha suerte con tu proyecto [oki]
MrCell escribió:personalmente, proteus me ha dado problemas [noop]

A mi tambien me ha dado algunos problemas en ciertos diseños, por ejemplo el ultimo: no permite los comandos de lectura de un LCD Gráfico con chipset KS0108. Y no quiero comprarme la pantalla física aun. [decaio]

MrCell escribió:yo trabajo con protoboard y PicKit 2 (me programa los pics en 5 segundos y no hay ninguno que se resista).

Así es como trabaja el profesor de esta asignatura, la verdad es que mola bastante, pero tienes que aflojar pasta para él. Nosotros, en clase, probabamos con protoboard y un clon del programador TE-20 pero que le añadimos un socket para los PICs de 28 pines (en nuestro caso, para el PIC 16F876, hecho en otra asignatura del mismo modulo: Construcción de Prototipos Eelectrónicos).

Con el PicKit puedes depurar el programa en tiempo real (instrucciones paso a paso, monitorizar RAM, etc...)? Sería una opción muy interesante.

MrCell escribió:Ahora mismo estoy adaptando un localizador GPS a un robot que estoy construyendo.

Mola!, cuando lo acabes o hagas funcionar, estaría muy bien que lo compartieras ;)

MrCell escribió:Mucha suerte con tu proyecto [oki]

Gracias, pero el proyecto ya está acabado y entregado; Nota: 10 XD
demonh3x escribió:Gracias, pero el proyecto ya está acabado y entregado; Nota: 10 XD

Enhorabuena!
Hace un tiempo lei de un aparato que programaba las horas de riego, era mediante USB una cosa rarisima XD.
Pues creo que ya está todo subido y actualizado en el 1er post.

Me gustaría escuchar vuestras opiniones y/o mejoras ;)
Y lo llegaste a esamblar?, a fabricar? o solo era codigo?,

^.^, para ver una foto del bicho.
muad_did escribió:Y lo llegaste a esamblar?, a fabricar? o solo era codigo?,

^.^, para ver una foto del bicho.

Está hecho en proto-board, pero igualmente te subiré una foto ;)
Imagen
Perdona la malísima calidad, pero es lo que tiene mi movil. No está en funcionamiento porque mi PIC murió el otro dia cuando intentaba grabarle otro programa [buuuaaaa].
Saludos amigo, tremendo proyecto, lo he ojeado y se ve que trabajastes arduamente en el, yo le hice solo un cambio y lo utilizo para encender una luces de alumbrado exterior. te felicito !! y te deseo mucho exito en tu carrera
Hola!!
Primero k nada felicidades!!! [oki] wou k padre!!!
segundo:yo estoy en la prepa,en 4to semestre,y me he decidido por la electronica,me facina,armar,crear,etc..
wou,me gustaria k nos explicaras a los k nos intereza la electronica,un poco de lo k se ve,y algun proyecto facil de realizar,para ir empezando,y no llegar a la universidad desde cero,te lo agradeceria bastante.
Yo he empezado,con unos cursillos de internet,a programar en C,pero no se como controlar el harware k le agregas a tu proyecto,no se si se deve de utilizar alguna libreria de reloj XD o no se,por eso te pido k escribas mucho,o lo k tu quieras de la electronica.
Grasias y saludos!!!
lotex77 escribió:Saludos amigo, tremendo proyecto, yo le hice solo un cambio y lo utilizo para encender una luces de alumbrado exterior.

Estoy muy feliz de que alguien haya podido utilizar mi trabajo para algo util [beer]
Veo que solo tienes un mensaje posteado, te has registrado solo para comentarme esto? me alaga! ;)
Por cierto; que cambio le has hecho? estoy interesado en ver como has adaptado mi trabajo para esa finalidad...
lotex77 escribió:lo he ojeado y se ve que trabajastes arduamente en el

Hombre... si que le he dedicado bastante tiempo, pero no ha sido nada del otro mundo. Perseverancia y conocimientos ;)
lotex77 escribió:te felicito !! y te deseo mucho exito en tu carrera

Gracias! [chulito] No estaba haciendo una carrera precisamente, estaba haciendo un curso de "Formación Profesional" o FP de nivel superior (sistema educativo Español). Y ya casi lo he terminado.


pinopop escribió:Hola!!
Primero k nada felicidades!!! [oki] wou k padre!!!
segundo:yo estoy en la prepa,en 4to semestre,y me he decidido por la electronica,me facina,armar,crear,etc..
wou,me gustaria k nos explicaras a los k nos intereza la electronica,un poco de lo k se ve,y algun proyecto facil de realizar,para ir empezando,y no llegar a la universidad desde cero,te lo agradeceria bastante.
Yo he empezado,con unos cursillos de internet,a programar en C,pero no se como controlar el harware k le agregas a tu proyecto,no se si se deve de utilizar alguna libreria de reloj XD o no se,por eso te pido k escribas mucho,o lo k tu quieras de la electronica.
Grasias y saludos!!!

Por lo que veo, no has estudiado apenas nada de electronica, el problema que veo es que te faltan muchos conocimientos.
Por poder... podrias llegar a aprender a hacer cosas similares pero te encontrarias con muchos problemas por el camino y algunos quizá no puedas llegar a solucionar por falta de base...
Si quieres llegar a entender correctamente este proyecto deberias empezar estudiando "electronica digital" para luego centrarte mas en la parte de Microcontroladores y programacion, tanto en ensamblador (codigo maquina del microcontrolador) con en un lenguaje de mas alto nivel (por ejemplo; C o Basic)
Para empezar a entender todo el tema del hardware deberias buscarte un libro de electronica digital e ir trasteando con los ejercicios y ejemplos con el programa Proteus ISIS (muy bueno para este fin). La programacion la dejaría para mas tarde.
Piensa que este proyecto es el resultado de un curso de 2 años y varias asignaturas. No es algo que se pueda hacer para dentro de 6 meses habiendote saltado muchos conceptos por enmedio...
Ya se eso,pero algo muy basico k hayas hecho,y explicarlo un poco,estaria super XD
Saludos!!
REHome está baneado por "Ya hemos tenido suficiente, búscate otro foro para trollear por favor"
Muy bueno el proyecto, pensé que usaste el ASM.

Se puede hacer mil cosa con los PIC.

Ver vídeo.

http://electronica-pic.blogspot.com

Saludo.
15 respuestas