Atlantis
Guest
Thu May 09, 2019 6:04 am
Szukam, ale jakoś znaleźć nie mogę...
Potrzebuję przykładów poprawnych ramek DCF77, wraz z informacją na temat
tego, jaki czas jest w nich zakodowany. Chodzi mi po prostu o ciąg bitów.
Pracuję obecnie nad własną biblioteką do obsługi modułów DCF77
(częściowo opierając się na kodzie Arduino). Niby działa, jednak od
czasu do czasu pojawiają się problemu i dekodowany czas różni się od
poprawnego. Chciałem teraz zrobić krok w tył i sprawdzić poprawność
działania poszczególnych funkcji, kompilując je na PC, karmiąc
spreparowanymi danymi i obserwując wynik.
Niby protokół jest opisany, jednak chcę mieć pewność, że i podczas
preparowania ramki nie popełnię błędu...
Piotr GaĹka
Guest
Thu May 09, 2019 8:48 am
W dniu 2019-05-09 o 08:04, Atlantis pisze:
Quote:
Pracuję obecnie nad własną biblioteką do obsługi modułów DCF77
(częściowo opierając się na kodzie Arduino). Niby działa, jednak od
czasu do czasu pojawiają się problemu i dekodowany czas różni się od
poprawnego.
Może Ci się przyda.
Dawno, dawno temu (lata 95..97) zrobiłem odbiornik DCF podłączony pod
COM komputera (zasilanie też z COM). Odbiornik wystawiał sygnał z DCF na
którejś z linii RS232 i z tej linii go czytałem.
Trochę się naszukałem w starych plikach, ale znalazłem. Poniżej źródła.
Zauważyłem, że odwołuję się do doneinfo.h. Poszukałem co to takiego -
jakaś forma linijki pokazującej postęp procesu - nie ma związku z samym DCF.
Nie chce mi się wczytywać w szczegóły. Na pierwszy rzut oka widzę, że:
- RS232 obsługuję po adresach - tak się robiło pod DOS
- do odmierzania czasu używam wysyłania w koło czegoś po RS232
Przy ^C^V program pocztowy pozawijał niektóre linijki.
============================= plik DCF77.H ============================
// dcf77.h
// DCF77 class - odbior sygnalu DCF77 przez port RS232
#ifndef __DCF77_H
#define __DCF77_H
#ifndef __DONEINFO_H
#include "doneinfo.h"
#endif
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
class DCF77
{
DWORD blo; // bufory na zbierane bity
WORD bhi;
int addr; // adres portu
enum {DLL=0, // Divisor Latch Low byte
DLH = 1, // Divisor Latch High byte
IER = 1, // Interrupt Enable Register - zezw. na przerwania
IIR = 2, // Interrupt Identification Register
LCR = 3, // Line Control Register - tryb transmisji
MCR = 4, // Modem Control Register - set innych linii
LSR = 5, // Line Status Register - stan transmisji
MSR = 6}; // Modem Status Register - stan innych linii
int parity(WORD w); // sprawdzenie parzystosci slowa
public:
DCF77(int com); // konstruktor
int read(DoneInfo *d=0); // odbior DCF77 ret:n imp (<0-bledy)
int gettime(struct time *t); // odczytany czas ret:0-ok,1-err
int getdate(struct date* d); // odczytana data ret:0-ok,1-err
};
#endif // __DCF77_H
============================ plik DCF77.CPP ============================
// dcf77.cpp
// DCF77 class - odbior sygnalu DCF77 przez port RS232
#include <dos.h>
#include <conio.h>
#include "dcf77.h"
DCF77::DCF77(int com):blo(0),bhi(0)
{
static int adrt[4]={0x3F8,0x2F8,0x3E8,0x2E8}; // adresy COM-ow
int div=48; // predkosc 2400
int lcr=3; // format 8N1
int mcr=1; // DTR=1
addr=adrt[com];
outportb(addr+LCR,0x80); // Divisor Latch Access
outportb(addr,div&0xFF); // Divisor Latch low byte
outportb(addr+DLH,div>>

; // high byte
outportb(addr+LCR,lcr); // Line Control Register
outportb(addr+MCR,mcr); // Modem Control Register
outportb(addr+IER,0); // Interrupt Enable Register
inportb(addr); // wyczyszczenie bufora
outportb(addr,0); // zapelnienie bufora nadawczego
outportb(addr,0);
}
int DCF77::parity(WORD w)
{
w^=w>>8;w^=w>>4;w^=w>>2;w^=w>>1;
return w&1;
}
// zwraca:
// nb = liczba odebranych impulsow, powinno byc co najmniej 39 impulsow
// -1 = brak impulsow przez 5 sekund
// -2 = nie podlaczony odbiornik - szum zamiast impulsow
// -3 = brak konca
// -4 = klawisz
int DCF77::read(DoneInfo *d) // odbior DCF77
{
int b,b0=0x10,b1=0x10; // 0x10 -> dodatnie zbocze bedzie prawdziwe
int valid=0; // na poczatku pracy
int dn=0; // licznik petli w sekundzie DCF77
int lock=0; // blokowanie analizy linii wejsciowej
int down=0; // bylo ujemne zbocze
int nb=0; // licznik odebranych bitow
int ns=0; // licznik zmian stanu w czasie blokowania
// w jednej sekundzie miesci sie 240 nadan 2400B:8N1
static const
lockT=234, // blokada dla calego okresu (0.975s)
lockt=18, // blokada dla impulsu (0.075s)
lim2s=420, // czas dla znacznika konca (1.75s)
lim01=31, // prog rozroznienia 0/1 (0.13s)
lim5s=1200; // czas dla braku impulsow (5s)
bhi=0; // zeruje bufory wynikowe
blo=0;
if(d)d->limit(60); // po 59 impulsie czeka jeszcze 2s
while(1){
if(inportb(addr+LSR)&0x20){
outportb(addr,0); // teraz mamy troche czasu bez naruszania dn
if(down){ // bylo ujemne zbocze - przetwarzanie i info
blo>>=1;
if(bhi&1L)blo|=0x80000000L; // przeniesienie bitu
bhi>>=1;
if(dn>lim01)bhi|=0x8000; // wpisanie aktualnego bitu
nb++; // liczba odebranych bitow
if(d)d->done(nb); // to moze zajac czas (dlatego down)
down=0; // obsluzone
}
dn++; // licznik wyslanych przez RS232 bajtow w impulsie DCF
if(dn>lim5s)return -1; // brak impulsow
if(nb>60)return -3; // za duzo impulsow
if(kbhit()){getch();return -4;} // nacisniety klawisz
}
b=inportb(addr+MSR)&0x10; // sprawdzenie linii wejsciowej
if(dn>lock){ // tylko gdy nie ma blokady
if(b!=b0){ // zmiana stanu
b0=b; // nowy stan
if(valid){ // juz bylo pierwsze dodatnie zbocze
if(b){ // dodatnie zbocze
if(dn>lim2s)return nb; // koniec minuty (dn>1.75s)
lock=lockt; // blokada do 0.075s
}
else{ // ujemne zbocze
down=1; // flaga ujemnego zbocza
lock=lockT; // blokada do 0.975 s
}
}
if(b){valid=1;dn=0;}// juz bylo dodatnie zbocze i licznik od 0
b1=b;
ns=0;
}
}
if(b!=b1){ // nieoczekiwana zmiana stanu
b1=b;
if(++ns>9)return -2; // szum - nie podlaczony odbiornik
}
}
}
int DCF77::gettime(struct time *t) // odczytany czas ret:0-ok,1-err
{
int h,l;
if((blo&0x200)==0 || // nie ma bitu startu
parity(WORD((blo>>10)&0xFF)) || // parzystosc minut
parity(WORD((blo>>1

&0x7F)) )return 1; // parzystosc godzin
h=int((blo>>14)&7);l=int((blo>>10)&0xF);t->ti_min=h*10+l;
if(h>5 || l>9)return 1; // zle wartosci dla minut
h=int((blo>>22)&3);l=int((blo>>1

&0xF);t->ti_hour=h*10+l;
if(h>2 || l>9 || t->ti_hour>23)return 1; // zle wartosci dla godzin
t->ti_sec=0;
t->ti_hund=0;
return 0;
}
int DCF77::getdate(struct date* d) // odczytana data ret:0-ok,1-err
{
int h,l,y;
if((blo&0x200)==0 || // nie ma bitu startu
parity(WORD(blo>>25))^parity(bhi) )return 1;// parzystosc daty
h=int((blo>>29)&3);l=int((blo>>25)&0xF);d->da_day=h*10+l;
if(l>9 || d->da_day>31)return 1; // zle wartosci dnia
h=(bhi>>6)&1;l=(bhi>>2)&0xF;d->da_mon=h*10+l;
if(l>9 || d->da_mon>12)return 1; // zle wartosci miesiaca
h=(bhi>>11)&0xF;l=(bhi>>7)&0xF;y=h*10+l;
if(h>9 || l>9)return 1;
d->da_year=(y<9

?2000+y:1900+y; // prawidlowo do 2097 roku
return 0;
}
Atlantis
Guest
Thu May 09, 2019 10:36 am
On 09.05.2019 08:09, Mateusz Viste wrote:
Quote:
To pewnie dla ciebie oczywistość, ale podczas transmisji mogą występować
błędy... Zaufanie do pojedynczej ramki powinno być mocno ograniczone, a
czas ustawiony tylko wówczas, kiedy ciąg kilku ramek konsekwentnie
wskazuje bardzo zbliżony czas.
Tak. Biblioteka na której się opieram zawiera kilka "sanity checks".
Problem polega na tym, że błędy nie są wynikiem problemy nie są efektem
przekłamania w transmisji, ale jakiegoś błędu w kodzie. Przez to są one
powtarzalne i występują w kolejnych ramkach, prowadząc do zaakceptowania
błędnego czasu.
Próbuję ustalić w którym miejscu się tak dzieje. A ponieważ zmęczyło
mnie debugowanie na "żywym" układzie, w środku nocy, gdy propagacja się
podnosi, chcę to zrobić w sposób opisany powyżej.