个人资料
归档
正文

Atomic clock

(2020-09-04 11:58:05) 下一个

其实是接受长波电台的时钟,基站倒是Atomic时钟。其核心是美英60/中国68.5/德国77.5KHz的长波收音机,再数字译码。网上有人DIY。室内用比GPS方便一点。

我2006年左右买的圆形数显Skyscan,radio强度满格,现在还能用,但因DST改过几次因此它不适合现行标准。买的La Crosse其radio强度为0,退了。国产UMEXUS的样子还行,但液晶是第一代,可视角小。

https://en.wikipedia.org/wiki/WWVB

https://www.nist.gov/pml/time-and-frequency-division/radio-stations/wwvb

https://www.lloydm.net/Demos/wwvb.html  https://www.youtube.com/watch?v=zD_INHy3BBI 

https://www.youtube.com/watch?v=aUKLQaWvwXc src:https://github.com/KC7MMI/AVR-ASM-WWVB-Atomic-Clock

http://www.leapsecond.com/pages/sony-wwvb/

http://canaduino.ca/downloads/CANADUINO_Atomic_Clock_Receiver_Kit_SMD.pdf 这个用的是D10x60磁棒加固定电容调谐,MAS6180C芯片。https://www.sparkfun.com/products/retired/10060 

1MHz以下通常用Mn-Zn Ferrite锰锌铁氧体,其指标包括电感系数Al, L=Al*N^2;与空心线圈相比的实用导磁率uapp=L/L0和实用Q值,Qapp=Q/Q0。

信号不强时更新可能出错,许多人发现会快/慢一个小时,有的产品允许只更新分/秒。

我觉得不如用无线网接受网上的network time protocol,如PC和手机那样。

// here's the Arduino code  https://www.youtube.com/watch?v=OeZzNehKL_Y&t=3s

#include
#include          
#include
#include

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
// DO NOT use all zeros!
byte mac[] = {  
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

unsigned int localPort = 8888;      // local port to listen for UDP packets

IPAddress timeServer(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov NTP server
// IPAddress timeServer(132, 163, 4, 102); // time-b.timefreq.bldrdoc.gov NTP server
// IPAddress timeServer(132, 163, 4, 103); // time-c.timefreq.bldrdoc.gov NTP server

const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets 

// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

enum KEYS {
  ALLUP,
  SELECT,
  LEFT,
  DOWN,
  UP,
  RIGHT
};

char str[20];
int nStart,nEnd,nWid;
int nLastDecode;
int nBytes[6];
int nIndex, nMask;
int nMode;
int hour, minute, day, year, second;
int nPinState;
int keyVal, oldKey, curKey;

void setup()
{
  lcd.begin(16, 2); // start the library
  pinMode(3,INPUT);    // clock receiver input
  lcd.setCursor(0,0);
  lcd.print("Hello                                   ");
  lcd.setCursor(0,0);
      
  for(int i =0; i < 5; i++)
  {
    nBytes[i] = 0;
  }
  nIndex = 0;
  nMode = 0;
  nMask = 0x80;
  nStart = nEnd = millis();
  nPinState = digitalRead(3);
  oldKey = analogRead(0);
  hour = minute = second = day = year = 0;
  
  // start Ethernet and UDP
  if (Ethernet.begin(mac) == 0) {
    lcd.print("Failed DHCP");
    lcd.setCursor(0,0);
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }
  Udp.begin(localPort);
  
}


void loop()
{
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  delay(1000);  
  if ( Udp.parsePacket() )
  {  
    // We've received a packet, read the data from it
    Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);  
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;  

    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;     
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;  

    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print((epoch  % 86400L) / 3600); // print the hour (86400 equals secs per day)
    lcd.print(':');  
    if ( ((epoch % 3600) / 60) < 10 ) {
      // In the first 10 minutes of each hour, we'll want a leading '0'
      lcd.print('0');
    }
    lcd.print((epoch  % 3600) / 60); // print the minute (3600 equals secs per minute)
    lcd.print(':'); 
    if ( (epoch % 60) < 10 ) {
      // In the first 10 seconds of each minute, we'll want a leading '0'
      lcd.print('0');
    }
    lcd.print(epoch %60); // print the second
  }
  
  while(1)
  {
    readclock();
    keyboard();
  }
}

void readclock(void)
{
int nRead;
  nRead = digitalRead(3);
  if(nRead != nPinState)
  {
    nPinState = nRead;
    
    // we get here on every transition of the input signal (edge)
    if(nRead == HIGH)
    {
      // when sig goes high, just save the systenm clock
      nStart = millis();
      second++;
      if(second == 60) second = 0;
      lcd.setCursor(11,0);
      if(second < 10) lcd.print('0');
      lcd.print(second);
    }
    else if(nRead == LOW)
    {
      // when sig goes low, do all the work
      // this means we have a new bit from the receiver
      nEnd = millis();

      // nWid is our measurement of the pulse width in ms.
      // this can vary a bit, so we dice it up into three
      // very generous windows.
      nWid = nEnd - nStart;
      if(nWid > 725)  // > 725ms = sync pulse
      {
        if(nLastDecode == 2)
        {
          dsync();
          nLastDecode = 3;
         }
         else
         {
           sync();
           nLastDecode = 2;
         }
       }
       else if(nWid < 275)
       {
         its0();
         nLastDecode = 0;
       }
       else
       {
         its1();
         nLastDecode = 1;
       }
     }
  }
}

void keyboard(void)
{
  keyVal = analogRead(0);
  if(keyVal != oldKey)
  {
    if(keyVal < 70) curKey = RIGHT;
    else if(keyVal < 225) curKey = UP;
    else if(keyVal < 420) curKey = DOWN;
    else if(keyVal < 620) curKey = LEFT;
    else if(keyVal < 900) curKey = SELECT;
    else curKey = ALLUP;
//    lcd.setCursor(0,1);
//    lcd.print(curKey);
//    lcd.print("     ");
    oldKey = keyVal;
  }
}

void its1(void)
{
  nBytes[nIndex] |= nMask;
  nMask = nMask >> 1;
  lcd.setCursor(14,0);
  lcd.print("1");
}

void its0(void)
{
  nMask = nMask >> 1;
  lcd.setCursor(14,0);
  lcd.print("0");
}

void sync(void)
{
  nMask = 0x100;
  nIndex++;
  lcd.setCursor(14,0);
  lcd.print("S");
}

void dsync(void)
{
  second = 0;
  nMask = 0x80;
  nIndex = 0;
  showit();
  for(int i =0; i < 5; i++)
  {
    nBytes[i] = 0;
  }
  nMode = 1;
  lcd.setCursor(14,0);
  lcd.print("D");
  
}

void showit(void)
{
  int i;
      lcd.setCursor(0,0);
      lcd.print("                    ");
      lcd.setCursor(0,0);
      if(nMode == 1)
      {
        Decode();
        lcd.print("UTC: ");
        lcd.print(hour);
        lcd.print(":");
        if(minute <= 9) lcd.print("0");   // do I have to do everything?
        lcd.print(minute);
        lcd.print(":");
        lcd.setCursor(0,1);
        lcd.print("DAY: ");
        lcd.print(day);
        lcd.print(" YR: ");
        lcd.print(year);
      }
      else
      {
        lcd.print("In sync");
      }
}


void Decode(void)
{
  minute = nBytes[0] & 0x0f;
  minute += ((nBytes[0] >> 5) & 0x07) * 10;

  hour = nBytes[1] & 0x0f;
  hour += ((nBytes[1] >> 5) & 0x07) * 10;

  //  WWVB sends the time AFTER the time mark, so we need to add a minute
  //  for the correct time.
  minute++;
  if(minute >= 60)
  {
    minute = 0;
    hour++;
    if(hour >= 24)
    {
      hour = 0;
    }
  }
  
  day = (nBytes[3] >> 5) & 0x0f;
  day += (nBytes[2] & 0x0f) * 10;
  day += ((nBytes[2] >> 5) & 0x03) * 100;

  year = (nBytes[5] >> 5) & 0x0f;
  year += ((nBytes[4]) & 0x0f) * 10;
}


// send an NTP request to the time server at the given address 
unsigned long sendNTPpacket(IPAddress& address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE); 
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49; 
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:      
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket(); 
}

UMEXUS

[ 打印 ]
阅读 ()评论 (0)
评论
目前还没有任何评论
登录后才可评论.