Cálculo de milisegundos usando temporizadores en PIC y sincronizándolos con el tiempo DS1307

4

He usado DS1307 en mi proyecto que me da los valores de Hour, Min, Sec pero también se necesitan valores de Milliseconds . Estoy planeando usar temporizadores con 1 millisecond y luego sincronizarlos según los segundos de DS1307 .
He hecho el programa para 1 ms de retraso, pero el problema es que no estoy seguro de si está funcionando con 1 ms o no porque usé el parpadeo del led y no podemos ver el parpadeo del led a 1 ms. Mi primera pregunta es, ¿hay alguna manera de que pueda estar seguro de que está demorando 1 ms.?

Ahora digamos si su temporizador de 1 ms exacto. Ahora, cómo sincronizarlo con la sincronización DS1307 . Mi aplicación total es como si recibiera entradas, entonces tengo que mostrar qué entradas están activadas en UART con tiempos exactos (incluidos los milisegundos). Por ejemplo, si la entrada 4 está en ON, entonces:

/*
**some code
*/
 if(PORTEbits.RB5 == 1)
 {
   putsUART1("Input 4 ON, Time:  ");
   putsUART(TIME);
 }

Ahora, este TIME debería contener los valores de HH:MM:SS:MS . Hasta ahora puedo mostrar HH:MM:SS solamente. Tampoco puedo usar sqw/out porque su PCB hecho a medida y ese pin se deja en blanco. Por favor ayuda

EDIT:

He incluido count ++ en ISR que se incrementa a 1 ms. En while (1) estoy imprimiendo los valores de conteo después de leer sec en la función RTC_read

 while(1)
 {
    RTC_read();

    sprintf(TIME,"%s%s:%s%s:%s%s",hr2,hr1,min2,min1,sec2,sec1);
    putsUART1(TIME);
    putsUART1(" ");
    putsUART1(COUNT);
    putsUART1("\n");
 }

void __ISR(_TIMER_2_VECTOR, ipl3) Timer2Handler(void)
{
  mT2ClearIntFlag();
  count++;

}

función RTC_read:

/*
* some code
*/

 //read sec
   while(!I2CReceivedDataIsAvailable(RTC_I2C_BUS));
   Nop();
   sec = I2CGetByte(RTC_I2C_BUS); 
   AckI2C2();
   while (!I2CAcknowledgeHasCompleted(I2C2)); 

   /*
    * Milliseconds
    */
   if(count >= 999)
   {
       count = 0;
   }
   else
   {
       sprintf(COUNT,"%d",count);

   }
    
pregunta anna carolina

6 respuestas

6

Sugeriría que su idea para una resolución de milisegundos sea poco realista, ya que el tiempo que lleva leer HH: MM: SS fuera del chip RTC en las velocidades de datos típicas I 2 C tendrá tiempo. Variación de latencia superior a un milisegundo.

La resolución de informes en milisegundos también es discutible cuando su medio de informes es un puerto serie UART que opera a una velocidad de bits inferior a un milisegundo por bit.

Le animo a que, en cambio, tome su placa de circuito personalizada, desenrolle el chip DS1307 y sustitúyalo por un chip M41T81S compatible con patillas de ST Micro. (Paquete compatible también si ha implementado el dispositivo de tipo SO-8).

Este último dispositivo contiene convenientemente un registro de mantenimiento de tiempo adicional que le brinda conteos de resolución de décimas y centésimas de segundo. La lectura de HH: MM: SS.ss es compatible con la resolución neta de 10 mseg.

El M41T81S también tiene una muy buena función de calibración que permite que las funciones internas de tiempo se ajusten para ajustar las variaciones de frecuencia menores del cristal RTC de 32.768 kHz. Tengo una unidad prototipo aquí que tiene este chip utilizado que una vez calibrado ha continuado mostrando la hora correcta (en unos pocos segundos) durante casi un año. Dudo que pueda lograrlo con su DS1307 a menos que haya diseñado su circuito XTAL con capacidades de recorte.

    
respondido por el Michael Karas
4

Use la salida de onda cuadrada en el DS1307 (pin 7), configurada para generar una salida de 1Hz. Utilice el registro de control para habilitar esta salida como se describe en la página 9 de la hoja de datos de DS1307.

Cuando el PIC reciba el pulso, restablezca a cero el temporizador de milisegundos de su PIC.

Página 9 de la hoja de datos:

    
respondido por el BenAdamson
3

Este es un addendum para respuesta de Szidor . Solo quería esbozar algunos de los detalles en pseudocódigo.

Suponiendo que tiene una interrupción precisa del temporizador de 1 ms, puede sincronizar el contador ms con el RTC externo encuestando su registro de segundos desde dentro del ISR del Temporizador 1. Si configura el contador de ms en 999 al inicio del sistema, automáticamente sondeará el RTC continuamente para encontrar la primera vez que avanza el valor de los segundos, y luego lo hará al final de cada segundo para permanecer sincronizado.

int ms = 999;
int seconds;
int minutes;
int hours;

timer1_isr()
{
  static int prev_seconds;

  /* Advance the ms counter on every tick, but don't allow
   * it to overflow.
   */
  if (ms < 999) ++ms;

  /* If we're close to the end of a second, poll the RTC to
   * find the next boundary.
   */
  if (ms > 990) {
    seconds = read_ds1307(SECONDS_REG);
    if (seconds != prev_seconds) {
      ms = 0;
      minutes = read_ds1307(MINUTES_REG);
      hours = read_ds1307(HOURS_REG);
    }
    prev_seconds = seconds;
  )
}

Calibrar la interrupción (por ejemplo, a través de OSCCAL ) es una cuestión diferente. Tiene la opción de realizar una calibración manual (laboriosa y sujeta a variaciones debido a cambios de temperatura, envejecimiento, etc.) o permitir que el sistema se calibre automáticamente a través de un mecanismo de retroalimentación.

De cualquier manera, la forma más fácil de medir el error del oscilador interno del PIC es contar la cantidad de tics Timer1 que ocurren en 10 segundos, según lo mide el RTC. Para una calibración manual, podría usar el depurador para ejecutar el siguiente código.

int ms = 0;
int done_flag = 0;

timer1_isr()
{
  static int prev_seconds;
  int seconds;
  seconds = read_ds1307(SECONDS_REG);
  if (ms == 0) {
    /* wait for seconds value to advance from 0 to 1 */
    if (seconds == 1 && prev_seconds == 0) ms = 1;
  ) else if (done_flag == 0) {
    /* count ticks until seconds value advances from 10 to 11 */
    ++ms;
    if (seconds == 11 && prev_seconds == 10) done_flag = 1;
  }
  prev_seconds = seconds;
}

Puede encender un LED al mismo tiempo que establece done_flag . Ejecute el código hasta que el LED se encienda, y lea el valor de ms usando el depurador. Será un valor cercano a 10000; el valor exacto le dirá qué tan lejos está el reloj de su PIC, y puede usar esto para averiguar cómo ajustar OSCCAL .

Para obtener crédito adicional, averigüe cómo combinar estas dos ideas para que el valor de OSCCAL se pueda ajustar sobre la marcha (por ejemplo, una vez cada hora aproximadamente) para mantener el reloj PIC calibrado al reloj RTC continuamente.

    
respondido por el Dave Tweed
2

El siguiente es desordenado, poco ortodoxo, pero utilizo estas técnicas aquí y allá y creo que deberían darte más precisión.

Primero necesita un reloj preciso de 1 ms:

Puede usar una interrupción para hacer que parpadee el LED cada, por ejemplo, el 100º tilde, parpadeando el LED cada 1/10 de segundo y usarlo para ajustar su temporizador.

(Puedes contar, dependiendo de tu paciencia :) - muchos parpadeos y mides el tiempo, o usar un software de metrónomo para verificar si está sincronizado, etc. Si lo tiene casi preciso, puede configurar la interrupción para encender el LED en 100 minutos, luego sentarse después de 95, mirarla y verificar un reloj digital (teléfono inteligente) cuando se enciende.)

El ajuste real se puede hacer:

  • Con OSCTUNE cambiante.

  • Si no está ejecutando en FRC, entonces lo que puede hacer es tener una constante de "microsegundo por tick", agregarla a una variable en cada tick y derivar el ms de eso. Cambiar esta constante hacia arriba o hacia abajo desde 1000 ajustará su temporizador.

Determinar el punto cuando RTC está cambiando en segundo lugar:

Si solo consulta los segundos a 100 kHz, tomaría una fracción de ms. Además, el valor que obtiene es el valor en el punto en que el RTC detecta la condición de INICIO.

Entonces, en el encendido, puede consultar el segundo valor como loco, borrar el registro de TMR en cada INICIO y dejarlo solo cuando cambie el segundo. Opcionalmente, puede repetir eso de vez en cuando para volver a sincronizar el temporizador.

    
respondido por el Szidor
2

Si desea un reloj de ms, entonces un reloj en tiempo real (suponiendo que se trata de un DS1307 del contexto, no se vinculó a una hoja de datos) destinado a mostrar los segundos no es apropiado.

Ya tienes un PIC, aunque no dijiste cuál. Muchos PIC tienen hardware para manejar un cristal de reloj de 32768 Hz, y luego cuentan el tiempo. Si su PIC es un PIC tradicional 16, por ejemplo, entonces esto es parte del hardware del temporizador 1. El temporizador 1 con su controlador de cristal puede funcionar incluso mientras el resto del sistema está inactivo.

Al usar un cristal de baja velocidad y el temporizador 1, puede crear su propio reloj en tiempo real, pero también obtener relojes más rápidos, como 1 ms, del mismo cristal.

Si la energía no es un problema, entonces puede ejecutar el PIC desde un cristal normal, dividirlo para obtener una interrupción de 1 ms, y luego hacer todo el tiempo desde allí.

    
respondido por el Olin Lathrop
0

El problema del tiempo exacto es más fácil de lo que te preocupa. Utiliza un temporizador de hardware e interrumpe. Espera 600000 de eso y parpadea el led. ¿Hizo 600 segundos? Entonces no tienes que preocuparte por 1 ms. Esa medida no es para garantizar que es lo suficientemente precisa. Da una pista importante de que todo está bien y, por lo tanto, con una probabilidad muy alta de que finalmente dependa de la precisión del cristal del dispositivo, no tendrá problemas de software.

El problema de sincronización:

Digamos que lees el chip en cada 999 mS. En probabilidad media después de 500 segundos, su lectura se repetirá por el mismo valor que el anterior. Ese es el punto donde debes mantenerlo como punto de compensación. Si tiene que realizar mediciones inmediatamente, hágalas sin desplazamiento y modifíquelas más adelante. Básicamente, entonces. Puede hacer esto mucho más rápido mejorando el algoritmo, por ejemplo:

X = 500
inicio:
T0 = el tiempo desde el chip
wait_mS 1000-X
T1 = el tiempo desde el chip
si T0 == T1, entonces X = X * (- 1)
X = X / 2
a medida que la X se hace más pequeña, el punto de desplazamiento es más preciso.
Ir a inicio

    
respondido por el Ayhan

Lea otras preguntas en las etiquetas

Comentarios Recientes

se puede ver aquí. 3D Kernels Touch se encuentra en todos los núcleos, construido en PLICA 2012 (cuando está instalado) o PLICA 2013 en el directorio de proyectos ... muchos más BSP conocen los tipos. Se cargan diferentes módulos para diferentes características ARM del sitio de llamadas ... No se requiere siempre la generación del archivo .pnh si los desarrolladores se refieren a la 'nueva' autoridad 'sin un parámetro ... La generación del archivo .ps2wp. Se necesitan. El módulo de subprocesos para PlICA 2012... Lees verder