NeuronC y RTC

En las redes Lonworks es necesario incluir un patrón de hora y puede que no se disponga de conexión a Internet para tomarla de un servidor o que no exista un gateway que pueda realizar esta función. Para ello es muy fácil conectar a una CPU de Echelon (FT3120 o FT3150) mediante el bus I2C un chip del tipo PCF8583 (RTC).

Mediante el código adjunto y la documentación técnica del fabricante del chip podremos dotar a la red de una hora fiable basada en un auténtico reloj / calendario. Esta es la versión base con las funciones mínimas. El código se puede completar con la inclusión de escenas, plug-in de ajuste de hora, conexión de sincronización via GPS, etc.

  1. //----------------------------------------------------
  2. // Software necesario para implementar un RTC en  
  3. // un nodo Lonworks con un chip I2C PCF8583
  4. // Este reloj sería el 'master' de horario
  5. // en ausencia de otras referencias externas
  6. //----------------------------------------------------
  7. // En versiones posteriores se incluye la gestión
  8. // automática del horario verano/invierno
  9. // así como la sincronización via GPS
  10. //-----------------------------------------------------  
  11. #define rtc_addr 0x50 // dirección del RTC  
  12. network output sd_string("Dia de la Semana")   SNVT_date_day   nvoDiaSema;
  13. network input sd_string("Entrada Ajuste Hora") SNVT_time_stamp nviTimeSet;  
  14. // Variables Errores I2C
  15. network output sd_string("Fallos bus I2C")SNVT_count I2CFails;  
  16. // Salidas RTC, como suele vincularse a decenas o cientos de nodos, se ajusta como
  17. unackd_rpt network output sd_string("Time Stamp propagado") SNVT_time_stamp bind_info(unackd_rpt) nvoTimeRef;
  18. network output sd_string("Day of Week") SNVT_count nvoDOW;  
  19. //////////////////////////////////////////////////////////////////
  20. // Funciones - Timers - Variables - I/O's - etc. //
  21. //////////////////////////////////////////////////////////////////
  22. int es_bisi(long ano);
  23. unsigned short dow(unsigned int d, unsigned int m, unsigned long a);  
  24. /////////////////////// Timers ///////////////////////////////////
  25. mtimer repeating lectura=250;  
  26. ////////////////////// I/O Objects //////////////////////////////
  27. IO_8 i2c io_i2c_bus;  
  28. ////////////////////// Vars ////////////////////////////////////
  29. far unsigned int rtcbuff[18];
  30. far unsigned int rtcset[7];
  31. far unsigned int rtc_cont;
  32. far unsigned long ano;
  33. far unsigned int ano_ant, ano_act, minut;
  34. unsigned int horas_adel;  
  35. // Variable interna para manejo reloj
  36. SNVT_time_stamp  nvoTimeSet;  
  37. /////////////////////////////////// Tasks ///////////////////////////////////
  38. // Reset task
  39. // This task is called whenever the node is reset.
  40. when(reset){   rtc_cont=0;  
  41.   // Lectura Inicial RTC
  42.   if (!io_out(io_i2c_bus,&rtc_cont,rtc_addr,1)) I2CFails++;
  43.   if (!io_in(io_i2c_bus,rtcbuff,rtc_addr,18)) I2CFails++;
  44.   // Si se desea se puede manejar la variable I2CFails aquí...
  45.   // No hay fallos nunca salvo avería directa del chip
  46.   ano_act=( (rtcbuff[5]&0xC0)>>6);
  47.   nvoTimeSet.second=(((rtcbuff[2]&0xF0)>>4)*10)+(rtcbuff[2]&0x0F);
  48.   nvoTimeSet.minute=(((rtcbuff[3]&0xF0)>>4)*10)+(rtcbuff[3]&0x0F);
  49.   nvoTimeSet.hour=(((rtcbuff[4]&0x30)>>4)*10)+(rtcbuff[4]&0x0F);
  50.   nvoTimeSet.day=(((rtcbuff[5]&0x30)>>4)*10)+(rtcbuff[5]&0x0F);
  51.   nvoTimeSet.month=(((rtcbuff[6]&0x10)>>4)*10)+(rtcbuff[6]&0x0F);
  52.   ano=(rtcbuff[16]*256)+rtcbuff[17]+ano_act;
  53.   nvoTimeSet.year=ano;
  54.   nvoDiaSema=(rtcbuff[6]&0xE0)>>5;
  55.   nvoTimeRef=nvoTimeSet;
  56.   }
  57. /////////////////////////////////////  
  58. //***************************************
  59. // Puesta en hora del Reloj desde SNVT's
  60. //***************************************
  61. when (nv_update_occurs(nviTimeSet)) {
  62.  unsigned int x, y, t;
  63.  unsigned long z;
  64.  x=dow(nviTimeSet.day,(unsigned int)nviTimeSet.month,nviTimeSet.year);
  65.  nvoDOW=x;
  66.  if (x==7) {y=0;}
  67.  else {y=x;}
  68.  rtcset[0]=2;
  69.  t=(unsigned int)(nviTimeSet.year % 4);
  70.  ano_act=t;
  71.  ano_ant=t;
  72.  z=nviTimeSet.year-t;
  73.  rtcset[1]=((nviTimeSet.second/10)*16)+(nviTimeSet.second%10);
  74.  rtcset[2]=((nviTimeSet.minute/10)*16)+(nviTimeSet.minute%10);
  75.  rtcset[3]=((nviTimeSet.hour/10)*16)+(nviTimeSet.hour%10);
  76.  rtcset[4]=((nviTimeSet.day/10)*16)+(nviTimeSet.day%10)+(t<<6);
  77.  rtcset&#91;5]=((nviTimeSet.month/10)*16)+(nviTimeSet.month%10)+(y*32);
  78.  if (!io_out(io_i2c_bus,&rtcset,rtc_addr,6)) I2CFails++;
  79.  rtcset&#91;0]=16;
  80.  rtcset&#91;1]=(unsigned int)(z / 256);
  81.  rtcset&#91;2]=(unsigned int)(z % 256);
  82.  if (!io_out(io_i2c_bus,&rtcset,rtc_addr,3)) I2CFails++;
  83.  nvoTimeRef=nviTimeSet;
  84.  nvoTimeSet=nviTimeSet;
  85.  // Nueva hora, propagar salida....
  86.  propagate(nvoTimeRef);
  87.  }
  88. //*************************************************************  
  89. /////////////////////////////////////////////////////////////////////////////
  90. // I/O event tasks //
  91. /////////////////////////////// Functions /////////////////////////////////  
  92. //--------------------------------------------------------------------------
  93. // Volver a leer el reloj... para otro ritmo, ajustar timer
  94. //--------------------------------------------------------------------------
  95. when (timer_expires(lectura)){
  96.   unsigned int sumador;
  97.   signed int z;
  98.   rtc_cont=0;
  99.   if (!io_out(io_i2c_bus,&rtc_cont,rtc_addr,1)) I2CFails++;
  100.   if (!io_in(io_i2c_bus,rtcbuff,rtc_addr,18)) I2CFails++;
  101.   // Ver posibilidad de comunicar error en caso de fallo en lectura reloj
  102.   ano_act=( (rtcbuff&#91;5]&0xC0)>>6);
  103.   if ( (ano_act!=ano_ant) && (ano_act==0) ){
  104.     sumador=4;
  105.     }
  106.   else {
  107.     sumador=0;
  108.   }
  109.   ano=(rtcbuff[16]*256)+rtcbuff[17]+ano_act+sumador;
  110.   ano_ant=ano_act;
  111.   // Igualar comparadores
  112.   nvoTimeSet.second=(((rtcbuff[2]&0xF0)>>4)*10)+(rtcbuff[2]&0x0F);
  113.   nvoTimeSet.minute=(((rtcbuff[3]&0xF0)>>4)*10)+(rtcbuff[3]&0x0F);
  114.   nvoTimeSet.hour=(((rtcbuff[4]&0x30)>>4)*10)+(rtcbuff[4]&0x0F);
  115.   nvoTimeSet.day=(((rtcbuff[5]&0x30)>>4)*10)+(rtcbuff[5]&0x0F);
  116.   nvoTimeSet.month=(((rtcbuff[6]&0x10)>>4)*10)+(rtcbuff[6]&0x0F);
  117.   nvoTimeSet.year=ano;
  118.   nvoDiaSema=(rtcbuff[6]&0xE0)>>5;
  119.   if (sumador==4) {
  120.     rtcset[0]=16;  
  121.     // Escribir a partir de dirección 16
  122.     rtcset[1]=(unsigned int)(nvoTimeSet.year / 256);
  123.     rtcset[2]=(unsigned int)(nvoTimeSet.year % 256);
  124.     if (!io_out(io_i2c_bus,&rtcset,rtc_addr,3)) I2CFails++;
  125.     sumador=0;
  126.     }
  127.   //********************************************************************//  
  128.   // Para no saturar la red, la hora se propaga cada minuto, suficiente
  129.   // para la mayoría de los sistemas de control
  130.   // Estamos en un nuevo minuto ?
  131.   if ( nvoTimeSet.minute != minut ) {
  132.     nvoTimeRef=nvoTimeSet;
  133.     minut=nvoTimeSet.minute;
  134.     }
  135.   //--------------------------------------------------------------------
  136. }
  137. //***************************//
  138. // Calcula dia de la Semana  //
  139. //***************************//
  140. // Lunes=1....Domingo=7
  141. unsigned short dow(unsigned short d, unsigned short m, unsigned long a) {
  142.  unsigned int an, dato;
  143.  an=(unsigned int)(a-1900);
  144.  if (m >= 3) m -= 3;
  145.  else {
  146.    m += 9;
  147.    an--;
  148.    }
  149.  dato=(an + an / 4 + (m * 13 + 2) / 5 + d + 3) % 7 + 1;
  150.  dato--;
  151.  if (dato==0) {dato=7;}
  152.  return (dato);
  153.  }
  154. //*****************************  
  155. //*************
  156. // Año bisiesto
  157. //*************
  158. // Devuelve '0' si es bisiesto y '1' si no lo es para restar a 29 dias de febrero...
  159. int es_bisi(long ano){
  160.  int a;
  161.  if ((ano % 4)!=0) {a=0;} else {a=1;};
  162.  return a;
  163. }
  164. //*************

Podría también gustarte...

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *