Cómo comparar números de hora del día almacenados en decimal codificado en binario en PIC

2

Estoy usando un PIC18f que tiene un reloj interno en tiempo real. Los valores del día, mes y año se almacenan en formato BCD. La hoja de datos dice que estos valores se almacenan en formato BCD en los registros.

Quiero comparar el tiempo. P.ej. if (time==10.20) // 10 hours twenty minutes

¿Debo realizar algunas conversiones a otro tipo de datos como int / char mientras trato con BCD en los registros?

    
pregunta Rookie91

3 respuestas

3

El decimal codificado en binario (BCD) simplemente significa que cada dígito decimal está codificado en 4 bits (0-9, o 0000 a 1001), con los seis valores restantes (10-15, o 1010 a 1111) sin usar. Por lo general, dos dígitos BCD se colocan lado a lado dentro de un byte de 8 bits, por lo que los valores de 0-99 se pueden codificar.

Por lo tanto, un valor de minutos de 59 se codificaría como:

0101 1001     0x05  0x09

en lugar de su representación binaria:

0011 1011    0x3B    (3*16 + 11 = 59)

Codificar los dígitos de esta forma hace que sea más fácil mostrarlos, ya que solo tiene que desplazarlos y enmascararlos, no es necesaria la conversión de binario a decimal. P.ej. Si tiene dos dígitos BCD en un byte BCDdigits (que podrían representar uno de los registros en el módulo RTCC), entonces

ones = BCDdigits & 0xf;
tens = BCDdigits >> 4;

Todos estos ejemplos asumen variables sin signo.

Se pueden comparar directamente dos números de varios dígitos ambos en formato BCD, siempre que estén alineados correctamente.

Por ejemplo, los registros en el PIC18 RTCC son todos de 8 bits. Así que tienes que hacer esto:

if ((HOURS == 0x10) && (MINUTES == 0x20))

o esto

if ((HOURS << 8) | MINUTES ) == 0x1020)

donde HORAS y MINUTOS son los registros de horas y minutos en el PIC18 RTCC.

Si el segundo número que se va a comparar no está en BCD, entonces deberá convertirlos a una base común, como minutos. Entonces, si tiene un byte que contiene minutos en BCD y otro que contiene horas en BCD, podría calcular:

unsigned short minutes;
minutes = 600*(HOURS >> 4) + 60*(HOURS & 0x0f)
         + 10*(MINUTES >> 4) + (MINUTES & 0x0f);

y luego compáralo con tu otro valor también convertido en minutos.

    
respondido por el tcrosley
2

Los literales BCD son los mismos que los hexadecimales, excepto que nunca usas los dígitos A-F.

Por ejemplo, para comparar horas y minutos, simplemente escribirías

if (time == 0x1020) { /* 10:20 in BCD */
  ...
}

Use los comentarios generosamente para indicar qué constantes son BCD, o escriba una macro que lo aclare.

    
respondido por el Dave Tweed
1

Los relojes BCD son una molestia con los que trabajar; No tengo idea de por qué son tan populares.

Si uno simplemente desea comparar dos horas o fechas, puede simplemente comparar las partes numéricas de los componentes en orden de menos significativo a más significativo; El año en que se envolvió de 99 a 00 puede haber sido un problema hace 15 años, pero ya no. Es importante tener cuidado con el hecho de que muchos chips BCD utilizan los bits superiores de los campos "decenas" para varios propósitos, por lo que es posible que haya que enmascarar los valores de lectura con 0x3F o 0x7F antes de hacer comparaciones. Además, uno debe asegurarse de que el dispositivo esté configurado para el modo "24 horas", o bien tratar con el hecho de que la mayoría, si no todos, los dispositivos que usan BCD tienen (y pueden por defecto) un modo "12 horas" que numera las horas 0x12, 0x01..0x09, 0x10, 0x11, 0x52, 0x41..0x0x49, 0x50, 0x51 [algunos dispositivos pueden poner el indicador AM / PM en el bit 7 en lugar del bit 6]; en tales dispositivos, las comparaciones numéricas simples no funcionarán desde las 12:00 am hasta las 11:00 am y la 1:00 pm, y las 12:00 pm se ordenarán después de las 11:00 pm.

Mi recomendación al usar cualquier tipo de chip RTC es convertir el tiempo en un número lineal de segundos. Convierta cada byte a un valor decimal haciendo algo como:

unsigned char bcd_to_dec(unsigned char bcd)
{
  return bcd - 3*(bcd >> 4);
}

Para las fechas posteriores al 1 de marzo de 2000, reste 3 del mes. Si eso es negativo o mayor que 12, sume 12 al mes y reste uno del año. Eso cambiará el calendario, de modo que el 1 de marzo es el primer día del mes 0 de cada año, por lo que el 29 de febrero será el último día del año.

Calcule el número del 1 de marzo del año (relativo al 1 de marzo de 2000) al calcular (year*365)+(year/4u) . Agregue un número de día para el mes actual usando una tabla de 12 entradas. Luego agregue (día actual - 1). Eso dará el número de días desde el 1 de marzo de 2000.

Multiplica eso por 24, suma las horas, multiplica eso por 60, suma los minutos, multiplica eso por 60 y suma los segundos.

Todo esto es un poco un poco molesto de trabajo, pero permitirá realizar cálculos con tiempos relativos mucho más fácilmente de lo que era posible con BCD. Se puede minimizar la cantidad de espacio de código requerido si se define un valor global del tipo unsigned long y un método:

void mul(unsigned char factor) { ulong_acc *= factor; }

Hacer eso reducirá cada paso de multiplicación para que no sea más que un movlw seguido de una llamada de función.

    
respondido por el supercat

Lea otras preguntas en las etiquetas