TODOPIC
Microcontroladores PIC => Todo en microcontroladores PIC => Mensaje iniciado por: psykhon en 27 de Diciembre de 2007, 21:16:39
-
estoy jugando un poco con el tmr1 + un xtal de 32.768 con la idea de hacer un rtc por soft pero me gustaria saber de gente que ya lo a hecho y sus resultados en cuanto a la precision. Bien podria esperar y medir pero por ahi tengo la mala suerte de tener xtales de baja calidad. TXS
-
de que calidad estamos hablando?
-
a mi me fué mal (http://www.todopic.com.ar/foros/index.php?topic=15208.msg117964#msg117964).
Montado en un protoboard y usé uno de 32Khz, cuando tocaba la carcasa del cristal era que funcionaba :(
-
bueno a mi me fue mas o menos bien, pero con un 16f684, con los cristales de los mouses :mrgreen: que son de 32.768 KHz, ahora sobre la precision, como la mido??? me hago un codigo para una especie de reloj, lo sincronizo con el de windows digamos, o el de mi celular, jeje y despues de un tiempo veo cuanto se desplaza??
aca mi codigo:
#include <16f684.h>
#fuses INTRC,NOWDT,NOPROTECT,PUT,NOBROWNOUT,NOCPD,MCLR,NOFCMEN,NOIESO
#use delay (internal=8000000)
#use fast_io(a)
#use fast_io(c)
//#byte T1CON = 0x10
#INT_TIMER1
void tmr1_handler()
{
output_toggle(PIN_C2);
set_timer1(32767);
}
void main()
{
setup_oscillator(OSC_8MHZ);
SET_TIMER1(32767);
SETUP_ADC(ADC_OFF);
setup_adc_ports(NO_ANALOGS);
//T1CON=0x8f;
setup_timer_1(T1_EXTERNAL|T1_CLK_OUT|T1_DIV_BY_1); // Cristal=32.768 KHz
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
set_tris_a(0x2f);
set_tris_c(0x33);
do
{
output_low(PIN_C3);
delay_ms(500);
output_high(PIN_C3);
delay_ms(500);
}while(true);
}
el esquema es muy sencillo, el cristal con dos consensadores a tierra de 22pF y conectados a T1CKI y CLKOUT, dos leds, uno en C2 y otro en C3, C2 parpadea cada segundo segun lo diga el cristal, el C3 solo lo puse de prueba, jeje, porque al principio no me estaba dando, tambien tengo unos cristales nuevitos, comprados, y pues ahi los pruebo tb, haber como va la cosa, un saludo :mrgreen:
-
ok entiendo todo lo que dices, ahora, supongo que el cristal del mouse no es de tan baja calidad, asi que ustedes juzgaran, hice el codigo para un pequeño reloj, basandome en algo del codigo de vszener, aca el resultado:
#include <16f684.h>
#fuses INTRC,NOWDT,NOPROTECT,PUT,NOBROWNOUT,NOCPD,NOMCLR,NOFCMEN,NOIESO
#use delay (internal=8000000)
//#define DS1820_PIN PIN_A0
//#include <ds1820.c>
#define DEFINE_ONE_WIRE_PIN
#define ONE_WIRE_PIN PIN_A0
#include <1wire.c>
#include <2ds1820.c>
#define DEFINE_PINES_LCD
#define LCD_DB4 PIN_C0
#define LCD_DB5 PIN_C1
#define LCD_DB6 PIN_C2
#define LCD_DB7 PIN_C3
#define LCD_E PIN_C4
#define LCD_RS PIN_C5
#define LCD_RW PIN_A1
#include <lcd_flex.c>
#use fast_io(a)
#use fast_io(c)
int seg=0,min=0,hora=0;
int1 inc_min=0,inc_hora=0,mode=0;
float minstep;
void switch_seg()
{
switch(seg){ //limites...
case 0x0A: seg=0x10;break;
case 0x1A: seg=0x20;break;
case 0x2A: seg=0x30;break;
case 0x3A: seg=0x40;break;
case 0x4A: seg=0x50;break;
case 0x5A: {seg=0x00;inc_min=1;}
}
}
void switch_min()
{
switch(min){ //limites...
case 0x0A: min=0x10;break;
case 0x1A: min=0x20;break;
case 0x2A: min=0x30;break;
case 0x3A: min=0x40;break;
case 0x4A: min=0x50;break;
case 0x5A: {min=0x00;inc_hora=1;}
}
}
void switch_hora()
{
switch(hora){ //limites...
case 0x0A: hora=0x10;break;
case 0x1A: hora=0x20;break;
case 0x24: hora=0x00;
}
}
#INT_TIMER1
void tmr1_handler()
{
set_timer1(32767);
seg++;
switch_seg();
if(inc_min)
{
inc_min=0;
min++;
switch_min();
}
if(inc_hora)
{
inc_hora=0;
hora++;
switch_hora();
min=0;
}
}
void config_hora()
{
disable_interrupts(INT_TIMER1);
do
{
printf(lcd_putc,"\fConfigurar Hora");
printf(lcd_putc,"\nHora: %2X:%2X:%2X",hora,min,seg);
delay_ms(150);
if(input(PIN_A2))
{
while(input(PIN_A2)){}
hora++;
switch_hora();
}
}while(!input(PIN_A3));
do
{
delay_ms(20);
while(input(PIN_A3)){}
printf(lcd_putc,"\fConfig Minutos");
printf(lcd_putc,"\nHora: %2X:%2X:%2X",hora,min,seg);
delay_ms(150);
if(input(PIN_A2))
{
while(input(PIN_A2)){}
min++;
switch_min();
inc_hora=0;
}
}while(!input(PIN_A3));
do
{
delay_ms(20);
while(input(PIN_A3)){}
printf(lcd_putc,"\fConfig Segundos");
printf(lcd_putc,"\nHora: %2X:%2X:%2X",hora,min,seg);
delay_ms(150);
if(input(PIN_A2))
{
while(input(PIN_A2)){}
seg++;
switch_seg();
inc_min=0;
}
}while(!input(PIN_A3));
SET_TIMER1(32767);
enable_interrupts(INT_TIMER1);
delay_ms(80);
}
void main()
{
setup_oscillator(OSC_8MHZ);
SETUP_ADC(ADC_OFF);
setup_adc_ports(NO_ANALOGS);
setup_timer_1(T1_EXTERNAL|T1_CLK_OUT|T1_DIV_BY_1); // Cristal=32.768 KHz
enable_interrupts(GLOBAL);
lcd_init();
set_tris_a(0x2d);
set_tris_c(0);
config_hora();
while(true)
{
if(input(PIN_A3))
{
while(input(PIN_A3)){}
config_hora();
}
if(input(PIN_A2))
{
while(input(PIN_A2)){}
mode=!mode;
}
if(mode==0)
printf(lcd_putc,"\fHora: %2X:%2X:%2X",hora,min,seg);
else
{
minstep=ds1820_read();
printf(lcd_putc,"\fTemp :%3.2f C", minstep);
}
delay_ms(130);
}
}
al mismo tiempo este codigo con presionar un botoncillo cambia de ver la hora a ver la temperatura :mrgreen: jeje
y lo probe durante unas 4 a 5 horas y note que se ha retrasado 1seg al cabo de 3 horas, en cuanto a la temperatura creo que la ambiente estubo entre 20 y 23ºC
considerando esta medicion, ya que no creo que alguien posea un super laboratorio (porque yo no :mrgreen: jeje) para realizar estas mediciones (al menos creo que nos podemos basar en nuestras propias mediciones, claro considerando siempre que no son tan precisas, o talvez nada precisas :mrgreen: pero al menos tenemos un dato aproximado)
claro que no desmerezco todo lo que haz mencionado JCC40, ya que para determinar esos parametros se hace como tu mencionas :mrgreen:
pero como un dato de curioso picmaniaco :mrgreen: jeje, saqeu ello
eso daria digamos 8 segundos al dia, lo cual es bastante, talvez se pueda obtimizar algo mas en el codigo, puede ser que se me haya pasado alguna linea por ahi :D; por que eso quiere decir que tenemos como 4minutos de atraso al mes y unos 48minutos al año, es casi una hora, lo cual es demasiado :(
comparado con el anterior que mencionas de 1.7s/dia, que da 51s al mes y 10.2 minutos al año que es mas aceptable :mrgreen:
haber que les parece, un saludo :mrgreen:
este es mi primer post en el 2008!!!! :D feliz año para todos!!!!! :mrgreen:
-
si :D recuerdo haber visto en una clase de telecomunicaiones sobre relojes y si la memoria no me falla los de cesio o nose que otro componente quimico son los mas precisos, pero a la vez loos infinitamente mas caros, que se utilizan en relojes de los satelites, ya que requiere una precision excelente :mrgreen:
crees que si en mi codigo cuento tres horas y pasadas las 3 horas le sumo un segundin mas :D se mejoraria bastante el error al mes y al año :mrgreen:
un saludo
-
Hola amigos!
Evidentemente, viendo la precision alcanzada por Cryn (bravo por el experimento!) y los costos de los cristales mencionados por JCC40, resulta evidente que lo mejor es usar un RTC externo, o no? :?
Son pequeños, livianos, baratos y hasta donde se, mucho mas precisos que lo calculado por Cryn....
Saludos.
-
bueno, lo probe con unos crystalitos que no se que precision tendran y que dicen kds4k al costado, el tmr1 ajustado para interrumpir cada 0.125 de segundo y parece que adelantan 1 segundo mas o menos al dia a +/- 30 grados. Muy importante usar capacitores de 33pf como dice el datasheet de mchip. El rtc te resuelve todo pero esta alternativa es barata, consume muy poco y solo se sacrifican dos pines (con un rtc tambien, ya que hay que comunicarse con el mismo). El metodo que encontre por ahi para calibrarlo (y que no probe) es hacer que genere una señal de 512hz en una pata y con un frequencimetro de precision ajustar el "drift" para cada temperatura, muy complicado para la precision que ya dan. Como resumen me parece que para pequeñas cosas es una excelente alternativa
-
Evidentemente, viendo la precision alcanzada por Cryn (bravo por el experimento!) y los costos de los cristales mencionados por JCC40, resulta evidente que lo mejor es usar un RTC externo, o no? :?
Son pequeños, livianos, baratos y hasta donde se, mucho mas precisos que lo calculado por Cryn....
:mrgreen: jejeje, es que me dio curiosidad para ahcer el experimento :mrgreen: me puse a jugar Warcraft mientras esperaba las 3 horas :D
aunque como mencione talvez se me fue alguna(s) linea(s) de codigo y haga que se retarde un poquitin mas, pero si se pudiera pulir el codigo, talvez se logre una mejor precision :mrgreen:
lo que has conseguido psykhon, me parece muy bueno :mrgreen: haber si le vemos el codigo :-)
un saludote
-
muuuuuuuuuuuuuyyyyyyyyyyyyyy desprolijo, con rutinas y variables de depuracion huerfanas, en mkbasic y como pa ver si anda nomas asi que no me critique mucho jejeje
program RelojPulsera
symbol LCD_sclk = PORTA.1
symbol LCD_sda = PORTA.0
symbol LCD_cs = PORTA.7
symbol LCD_reset = PORTA.6
symbol TiempoAlerta = 30 'constante que indica cuanto tiempo suena la alarma
symbol overflows = 30517
const CMD = 0
const DTA = 1
'
const myFont5x7 as byte[455] =
(0x00, 0x00, 0x00, 0x00, 0x00 , '// sp ascii 32
0x00, 0x00, 0x2f, 0x00, 0x00 , '// !
0x00, 0x07, 0x00, 0x07, 0x00 , '// "
0x14, 0x7f, 0x14, 0x7f, 0x14 , '// #
0x24, 0x2a, 0x7f, 0x2a, 0x12 , '// $
0xc4, 0xc8, 0x10, 0x26, 0x46 , '// %
0x36, 0x49, 0x55, 0x22, 0x50 , '// &
0x00, 0x05, 0x03, 0x00, 0x00 , '// '
0x00, 0x1c, 0x22, 0x41, 0x00 , '// (
0x00, 0x41, 0x22, 0x1c, 0x00 , '// )
0x14, 0x08, 0x3E, 0x08, 0x14 , '// *
0x08, 0x08, 0x3E, 0x08, 0x08 , '// +
0x00, 0x00, 0x50, 0x30, 0x00 , '// ,
0x10, 0x10, 0x10, 0x10, 0x10 , '// -
0x00, 0x60, 0x60, 0x00, 0x00 , '// .
0x20, 0x10, 0x08, 0x04, 0x02 , '// /
0x3E, 0x51, 0x49, 0x45, 0x3E , '// 0
0x00, 0x42, 0x7F, 0x40, 0x00 , '// 1
0x42, 0x61, 0x51, 0x49, 0x46 , '// 2
0x21, 0x41, 0x45, 0x4B, 0x31 , '// 3
0x18, 0x14, 0x12, 0x7F, 0x10 , '// 4
0x27, 0x45, 0x45, 0x45, 0x39 , '// 5
0x3C, 0x4A, 0x49, 0x49, 0x30 , '// 6
0x01, 0x71, 0x09, 0x05, 0x03 , '// 7
0x36, 0x49, 0x49, 0x49, 0x36 , '// 8
0x06, 0x49, 0x49, 0x29, 0x1E , '// 9
0x00, 0x36, 0x36, 0x00, 0x00 , '// :
0x00, 0x56, 0x36, 0x00, 0x00 , '// ;
0x08, 0x14, 0x22, 0x41, 0x00 , '// <
0x14, 0x14, 0x14, 0x14, 0x14 , '// =
0x00, 0x41, 0x22, 0x14, 0x08 , '// >
0x02, 0x01, 0x51, 0x09, 0x06 , '// ?
0x32, 0x49, 0x59, 0x51, 0x3E , '// @
0x7E, 0x11, 0x11, 0x11, 0x7E , '// A
0x7F, 0x49, 0x49, 0x49, 0x36 , '// B
0x3E, 0x41, 0x41, 0x41, 0x22 , '// C
0x7F, 0x41, 0x41, 0x22, 0x1C , '// D
0x7F, 0x49, 0x49, 0x49, 0x41 , '// E
0x7F, 0x09, 0x09, 0x09, 0x01 , '// F
0x3E, 0x41, 0x49, 0x49, 0x7A , '// G
0x7F, 0x08, 0x08, 0x08, 0x7F , '// H
0x00, 0x41, 0x7F, 0x41, 0x00 , '// I
0x20, 0x40, 0x41, 0x3F, 0x01 , '// J
0x7F, 0x08, 0x14, 0x22, 0x41 , '// K
0x7F, 0x40, 0x40, 0x40, 0x40 , '// L
0x7F, 0x02, 0x0C, 0x02, 0x7F , '// M
0x7F, 0x04, 0x08, 0x10, 0x7F , '// N
0x3E, 0x41, 0x41, 0x41, 0x3E , '// O
0x7F, 0x09, 0x09, 0x09, 0x06 , '// P
0x3E, 0x41, 0x51, 0x21, 0x5E , '// Q
0x7F, 0x09, 0x19, 0x29, 0x46 , '// R
0x46, 0x49, 0x49, 0x49, 0x31 , '// S
0x01, 0x01, 0x7F, 0x01, 0x01 , '// T
0x3F, 0x40, 0x40, 0x40, 0x3F , '// U
0x1F, 0x20, 0x40, 0x20, 0x1F , '// V
0x3F, 0x40, 0x38, 0x40, 0x3F , '// W
0x63, 0x14, 0x08, 0x14, 0x63 , '// X
0x07, 0x08, 0x70, 0x08, 0x07 , '// Y
0x61, 0x51, 0x49, 0x45, 0x43 , '// Z
0x00, 0x7F, 0x41, 0x41, 0x00 , '// [
0x55, 0x2A, 0x55, 0x2A, 0x55 , '// 55
0x00, 0x41, 0x41, 0x7F, 0x00 , '// ]
0x04, 0x02, 0x01, 0x02, 0x04 , '// ^
0x40, 0x40, 0x40, 0x40, 0x40 , '// _
0x00, 0x01, 0x02, 0x04, 0x00 , '// '
0x20, 0x54, 0x54, 0x54, 0x78 , '// a
0x7F, 0x48, 0x44, 0x44, 0x38 , '// b
0x38, 0x44, 0x44, 0x44, 0x20 , '// c
0x38, 0x44, 0x44, 0x48, 0x7F , '// d
0x38, 0x54, 0x54, 0x54, 0x18 , '// e
0x08, 0x7E, 0x09, 0x01, 0x02 , '// f
0x0C, 0x52, 0x52, 0x52, 0x3E , '// g
0x7F, 0x08, 0x04, 0x04, 0x78 , '// h
0x00, 0x44, 0x7D, 0x40, 0x00 , '// i
0x20, 0x40, 0x44, 0x3D, 0x00 , '// j
0x7F, 0x10, 0x28, 0x44, 0x00 , '// k
0x00, 0x41, 0x7F, 0x40, 0x00 , '// l
0x7C, 0x04, 0x18, 0x04, 0x78 , '// m
0x7C, 0x08, 0x04, 0x04, 0x78 , '// n
0x38, 0x44, 0x44, 0x44, 0x38 , '// o
0x7C, 0x14, 0x14, 0x14, 0x08 , '// p
0x08, 0x14, 0x14, 0x18, 0x7C , '// q
0x7C, 0x08, 0x04, 0x04, 0x08 , '// r
0x48, 0x54, 0x54, 0x54, 0x20 , '// s
0x04, 0x3F, 0x44, 0x40, 0x20 , '// t
0x3C, 0x40, 0x40, 0x20, 0x7C , '// u
0x1C, 0x20, 0x40, 0x20, 0x1C , '// v
0x3C, 0x40, 0x30, 0x40, 0x3C , '// w
0x44, 0x28, 0x10, 0x28, 0x44 , '// x
0x0C, 0x50, 0x50, 0x50, 0x3C , '// y
0x44, 0x64, 0x54, 0x4C, 0x44) '// z
dim i as word
dim j as byte
dim texto as string[19] 'string para componer el texto que va a la pantalla
dim wtexto as string[19] 'string temporal
dim numero as string[3] 'para imprimir los numeros
dim temp as byte
dim temp2 as byte
dim Ticks as byte 'cuenta los ticks del sistema
dim Segundos as byte
dim Minutos as byte
Dim Horas as byte
dim Alarma as byte 'almacena si debe sonar la alarma o no
dim wtimer as word 'subdivisor del tmr0
Dim HoraAlarma as byte 'almacena la hora fijada para la alarma
Dim MinutoAlarma as byte 'almacena el minuto fijado para la alarma
sub procedure Write_lcd(dim dc , c as byte )
dim cx as char
'
' bytetostr(c,texto)
' lcd_out(1,1 ,texto)
' delay_ms(500)
LCD_sclk = 0
LCD_sda = dc
LCD_sclk = 1
'// enviar byte de control/dato
cx = 8
while cx > 0
LCD_sclk = 0
LCD_sda = c.(cx - 1)
LCD_sclk = 1
cx = cx - 1
wend
end sub
sub procedure Init_lcd
LCD_reset = 0
delay_ms(70)
LCD_reset = 1
Delay_ms(70)
Write_lcd(CMD,0x20) '// VOP
Write_lcd(CMD,0x90) '// EV
'
Write_lcd(CMD,0xA4) '// Display en modo normal
Write_lcd(CMD,0x2f) '// power control set
'Write_lcd(CMD,0xd2) '// MUX
' Write_lcd(CMD,0xC8) '// invertir filas
' Write_lcd(CMD,0xa1) '// invertir columnas
' Write_lcd(CMD,0xac)
' Write_lcd(CMD,0x07)
Write_lcd(CMD,0xac) '// ubicacion de imagen
Write_lcd(CMD,0x07)
Write_lcd(CMD,0xf9) '// activar modo icono (acelera encendido)
Write_lcd(CMD,0xaf)
Write_lcd(CMD,0x40)
Write_lcd(CMD,0xb0)
Write_lcd(CMD,0x10)
Write_lcd(CMD,0x0)
end sub
sub procedure Lcd_Write_Char( Dim Row as byte, Dim Col as byte,dim wChar as Char )
'dim i,j as byte
dim wNroChar as byte
dim CharPos as word
Write_lcd(CMD,0x40)
Write_lcd(CMD,(0xb0 + row))
Write_lcd(CMD,0x10)
Write_lcd(CMD,(col / 16) + 16 ) 'Table 23. Column address set tabla que muestra el dir. de col de acuerdo al manual
Write_lcd(CMD,( (Col mod 16))) '(D/C) D7 D6 D5 D4 D3 D2 D1 D0 Setting
' 0 0 0 0 1 * A6 A5 A4 Upper bit address * Disabled bit
' 0 A3 A2 A1 A0 Lower bit address
CharPos = (wchar - 32 ) * 5 'se resta 32 por ser el primer caracter imprimible de la lista
' _y se multiplica por cinco que es el ancho del caracter en la tabla
for j = 0 to 4
Write_lcd(dta, font5x7[charpos + j] )
next j
end sub
sub procedure Write_Lcd_String(Dim Row as char, Dim Col as char)
dim TextLength as byte
TextLength = STRLEN(texto) - 1
for i = 0 to (TextLength) 'hay un error del compilador pasando strings a funciones por lo que usamos una var global
Lcd_Write_Char(row,col + (i*5) ,texto[i])
next i
end sub
sub procedure Clear_Lcd
Write_lcd(CMD,0x40)
Write_lcd(CMD,0xb0)
Write_lcd(CMD,0x10)
Write_lcd(CMD,0x00)
for i = 0 to 864
Write_lcd(dta,0)
next i
end sub
sub procedure MostrarHora
ByteToStr(horas,texto)
Write_Lcd_String(4,0)
ByteToStr(minutos,texto)
Write_Lcd_String(4,16)
texto = ":"
Write_Lcd_String(4,16)
ByteToStr(segundos,texto)
Write_Lcd_String(4,32)
texto = ":"
Write_Lcd_String(4,32)
ByteToStr(ticks,texto)
Write_Lcd_String(4,48)
texto = "-"
Write_Lcd_String(4,48)
end sub
sub procedure IncrementarMinutos() 'Incremento los minutos, si son 60 los pongo en 0 _
minutos = minutos + 1 'e incremento las horas
if minutos = 60 then
minutos = 0 'Incremento las horas y si son 24 las pongo en 0
Horas = horas + 1
if horas = 24 then
horas = 0
end if
end if
end sub
sub procedure interrupt
tmr1h = $F0 'recargo para 1/8 segundo
pir1.tmr1if = 0 'borro el flag de la int
ticks = ticks + 1
if ticks = 8 then
segundos = segundos + 1
ticks = 0
end if
end sub
main:
osccon = %01110000
ansel = %00000000
cmcon = 0x07
OPTION_REG = %10000111 'desabilita pull-ups, prescale TMR0 by 256
TRISB = %00000000 ' configuro el puerto B como salida , pines 7 y 6 como entradas
PORTB = %0 ' pongo el puerto B en cero
TRISA = 0 ' configuro el puerto A como salida
PORTA = %0 ' pongo el puerto A en cero
T1CON = %00001111 'configuro tmr1 como oscilador para el rtc
TMR1H = $F0 'recargo para 1/8 segundo
TMR1l = $00
PIE1.TMR1IE = 1 'habilito la interrupcion de tmr1
INTCON = $C0
'INTCON = 0 'desabilita interrupciones
'inicializacion de variables
ticks = 0
segundos = 0
minutos = 0
horas = 0
horaalarma = 0
MinutoAlarma = 0
'registro = 1
alarma = 0 ' seteo la alarma como apagada
wtimer = overflows
Init_lcd()
Clear_Lcd
' texto = "GAROFALO"
' Write_Lcd_String(5,5)
' texto = "El Reloj..."
' Write_Lcd_String(6,0)
' texto = "del Ganador!!!"
' Write_Lcd_String(7,0)
ciclo:
while true
if segundos = 60 then 'Si los segundos = 60 incremento los minutos y pongo a 0 los segundos
segundos = 0
IncrementarMinutos
' Clear_Lcd ' limpio la pantalla
end if
MostrarHora
if Button(PORTB, 4, 0, 1) then 'mejorar el procesamiento de los botones
Minutos = Minutos + 1
end if
if Button(PORTB, 3, 0, 1) then
horas = horas + 1
end if
sleep
wend
end.
ah, es para un f88 con intrc y lcd nok1100 (lindo pero molesto como el que mas)
-
no hombre :mrgreen: ta muy bueno :-/
a todos se nos escapa una linea por ahi :D
-
por si alguno se pregunta algo raro del codigo :D :D :D :D
http://usuarios.arnet.com.ar/galak/alfredo/pirata.html (http://usuarios.arnet.com.ar/galak/alfredo/pirata.html)