micooke / WWVB

Arduino WWVB Transmitter for Attiny85, nano, micro etc.
MIT License
30 stars 5 forks source link

AD9850 DDS as a RF generator #10

Closed RoLorenzoni closed 7 years ago

RoLorenzoni commented 7 years ago

Hi! I am new with programming, but I found your project really interesting. I live in a country that does not have the time signal available, so I have no other choice but constructing a transmitter. I tried your "minimal" project but it wasn't able to set my citizen watches. The Rx indicator shows some signal reception but it always fails. Then I got a AD9850 DDS RF generator and it's really easy to create a sine 60khz carrier. Changing a WWVB sample code from vinmarshall (https://github.com/vinmarshall/WWVB-Clock), I could generate a WWVB signal that was correctly received by the watches. Now, I'm trying to combine the ad9850 code with your wwvb library, but with no sucess. I would be very happy if you could help me with that, because I am new to programming. I am using an arduino nano, a ublox 6 GPS module to get acurate time and the AD9850 to broadcast it. Thanks in advance.

here is the code I used to generate the carrier.

/ WWVB Test Signal v 1.0

include

const int W_CLK_PIN = 7; const int FQ_UD_PIN = 8; const int DATA_PIN = 10; const int RESET_PIN = 11;

double freq = 60000; double trimFreq = 124999500;

int phase = 0;

/* WWVB time format struct - acts as an overlay on wwvbRxBuffer to extract time/date data.

struct wwvbBuffer { unsigned long long U12 :4; // no value, empty four bits only 60 of 64 bits used unsigned long long Frame :1; // framing unsigned long long Dst :2; // dst flags unsigned long long Leapsec :1; // leapsecond unsigned long long Leapyear :1; // leapyear unsigned long long U11 :1; // no value unsigned long long YearOne :4; // year (5 -> 2005) unsigned long long U10 :1; // no value unsigned long long YearTen :4; // year (5 -> 2050) unsigned long long U09 :1; // no value unsigned long long OffVal :4; // offset value unsigned long long U08 :1; // no value unsigned long long OffSign :3; // offset sign unsigned long long U07 :2; // no value unsigned long long DayOne :4; // day ones unsigned long long U06 :1; // no value unsigned long long DayTen :4; // day tens unsigned long long U05 :1; // no value unsigned long long DayHun :2; // day hundreds unsigned long long U04 :3; // no value unsigned long long HourOne :4; // hours ones unsigned long long U03 :1; // no value unsigned long long HourTen :2; // hours tens unsigned long long U02 :3; // no value unsigned long long MinOne :4; // minutes ones unsigned long long U01 :1; // no value unsigned long long MinTen :3; // minutes tens unsigned long long U00 :1; };

// We point the struct and the unsigned long long at the // same memory space so we can access the bits using // both paradigms. struct wwvbBuffer buffer = (struct wwvbBuffer ) malloc(sizeof(struct wwvbBuffer)); unsigned long long timeBits = (unsigned long long ) buffer;

/*

void setup() {

// Setup the Serial port out and the WWVB signal output pin

DDS.begin(W_CLK_PIN, FQ_UD_PIN, DATA_PIN, RESET_PIN); DDS.calibrate(trimFreq);

    // Preset the time struct 
    *timeBits = 0x0000000000000000;
    buffer->MinTen = 5;
    buffer->MinOne = 7; 
    buffer->HourTen = 2;
    buffer->HourOne = 3;
    buffer->DayHun = 3;
    buffer->DayTen = 6;
    buffer->DayOne = 5;
    buffer->OffSign = 5;  // 2 -> -  5 -> +
    buffer->OffVal = 3;
    buffer->YearTen = 1;
    buffer->YearOne = 0;
    buffer->Dst = 3; // 0 no dst, 1 dst ending, 2 dst starting, 3 dst
    buffer->Leapyear = 0;
    buffer->Leapsec = 0;

}

/*

void loop() {

// Print the Date & Time to the Serial port for debugging. int year = (buffer->YearTen 10) + buffer->YearOne; int day = (buffer->DayHun 100) + (buffer->DayTen 10) + buffer->DayOne; int hour = (buffer->HourTen 10) + buffer->HourOne; int minute = (buffer->MinTen * 10) + buffer->MinOne; char date[30]; sprintf(date, "%.2i:%.2i %.3i, 20%.2i\n", hour, minute, day, year); Serial.print(date);

// Step through each bit in this frame int position = 0; for (int i = 63; i >= 4; i--) { // Mask off all bits but the one in question. // This singles out one bit, moving from MSB to LSB unsigned long long mask = (unsigned long long) 1 << i; unsigned long long masked = (*timeBits) & mask;

// Determine if there was a 1 in that bit position
int bit = ((*timeBits) & mask)?1:0;

            // Determine if we're at a Marker position
            int mark = 0;
            if ( (position == 0) || 
                 ((position + 1) % 10 == 0) ) {
                   mark = 1;
            }
            position++;

// Rattle off each bit

// Debug output to the Serial port
// Print in groups of 4. Makes cross ref to hex easier
if ( (i+1) % 4 == 0) {
  Serial.println("");
} 

            if (mark) { 
              Serial.print("M"); 
              sendMark();
            } else if (bit == 0) {
              Serial.print("0");
              sendUnweighted();
            } else if (bit == 1) {
              Serial.print("1");
              sendWeighted();
            }

} Serial.println("");

// Increment the Time and Date if (++(buffer->MinOne) == 10) { buffer->MinOne = 0; buffer->MinTen++; }

if (buffer->MinTen == 6) { buffer->MinTen = 0; buffer->HourOne++; }

    if (buffer->HourOne == 10) {
            buffer->HourOne = 0;
            buffer->HourTen++;
    }

    if ( (buffer->HourTen == 2) && (buffer->HourOne == 4) ) {
            buffer->HourTen = 0;
            buffer->HourOne = 0;
            buffer->DayOne++;
    }

    if (buffer->DayOne == 10) {
            buffer->DayOne = 0;
            buffer->DayTen++;
    }

    if (buffer->DayTen == 10) {
            buffer->DayTen = 0;
            buffer->DayHun++;
    }

    if ( (buffer->DayHun == 3) && 
         (buffer->DayTen == 6) &&
         (buffer->DayOne == (6 + (int) buffer->Leapyear)) ) {
             // Happy New Year.
             buffer->DayHun = 0;
             buffer->DayTen = 0;
             buffer->DayOne = 1;
             buffer->YearOne++;
     }

     if (buffer->YearOne == 10) {
       buffer->YearOne = 0;
       buffer->YearTen++;
     }

     if (buffer->YearTen == 10) {
       buffer->YearTen = 0;
     }

}

/*

void sendMark() {

// Send low for 0.8 sec DDS.down(); delay(799);

// Send high for 0.2 sec DDS.setfreq(freq, phase); delay(199);

return; }

/*

void sendWeighted() {

// Send low for 0.5 sec DDS.down(); delay(499);

// Send high for 0.5 sec DDS.setfreq(freq, phase); delay(499);

return; }

/*

void sendUnweighted() {

// Send low for 0.2 sec DDS.down(); delay(199);

// Send high for 0.8 sec DDS.setfreq(freq, phase); delay(799);

return; }

micooke commented 7 years ago

Yeah im Australian, no wwvb here either!

Thanks for pointing me to that library, its actually a similar approach to what my new wwvb_jjy library is taking - but i use a union to access the bits as a buffer, jjy or wwvb. Interesting that it syncs on your watch, i will have to test it out against my clock (BALDR brand, same as @mr-sneezy) which arrived yesterday.

Also, i ordered that exact dds board a week ago so should be able to use the same test setup (when it eventually arrives). My library has worked with desk clocks, but not watches - i had been wondering if this is because the arduino outputs a 0 to 5v square wave instead of a -5 to 5v sine, looks like it may.

Ill have a look at that library and get back to you. In the meantime, if you wanted to test against an early release have a look at the tx example in my wwvb_jjy library. It requires my pwm library. Initialise the dds in setup, turn it off in the overflow isr and turn it on in the compare isr.

Cheers

micooke commented 7 years ago

Okay im dumb. Those updates failed, i should be able to fix it easily enough though. I tested last night and got my new library syncing my desk clock but haven't updated the changes yet - needs a tidy up of debug code.

Ive reopened this until the new library is tested and working, then ill transition to that.

Cheers

RoLorenzoni commented 7 years ago

Hello. As I'm not a good programmer, I'm testing the range of the signal from the ad9850. I connected an AM loop antenna on the analog1 output pin of the DDS. Even without a proper modulation, I could make a simple program that switches the 60khs carrier on and off in a regular half second interval. Of course, the watch doesn't sync, but, it listens to the signal and shows "strong" signal even 3 meters away from the antenna. An electronic technician told me that it's easy to extend the range even more by using a MOSFET transistor to amplify the signal. My idea is that one transmitter could have the range all over the house. cheers

RoLorenzoni commented 7 years ago

Oh, forgot to say... Differently from de PWM output at arduino board, you should connect the other end of the antenna to the gnd pin in order to have a good transmission.

micooke commented 7 years ago

Regarding the transmitter, you will need to check the applicable regulations on your country regarding transmit power. The example i use is current limited by grounding the antenna through a led - this is more to protect the arduino pin, although they are internally limited to 20mA anyways.

Generally you will be limited to 100mW ERP, which is Pt(av) × Gt. The max theoretical duty cycle is 73% over a 60s frame (7 markers at 20%, 53 low at 80%). Pt(av) = 5V × 20mA ×73% = 0.073W = 73mW. To keep under 100mW the max antenna gain would be 10×log10(100/73) = 1.36dB.

If you are not limited to 100mW you have a few options. You could use the arduino to switch in a higher voltage using a fet or op amp, or pull a higher current through a fet. The 2n2222 (800mA max) is a good common BJT which should work well, or a 2n7000 (200mA) if you wanted a mosfet (or BS170 - 500mA, a less common 2n7000 equivalent).

baradhili commented 7 years ago

remember the regs are always about ERP - effective radiated power.... at 60kHz - you will be more worried about planning regulations than transmitted power as the 1/4 length is huge....

Though careful matching is always a good idea to protect your transmitter driver..

micooke commented 7 years ago

You mean I can't install a 1.25km antenna out the back :smile:

Actually I did forget how terrible the gain of these antennas are. They are classified as being electrically small, and i make no effort at impedance matching so probably 'worse than -10dB' if my memory serves me correctly.

So @RoLorenzoni - ignore my warning. Also, @mr-sneezy tells me its 10mW, not 100mW.

baradhili commented 7 years ago

it depends where you live :).... you might have enough space if you are in aust.. :)

On 2 May 2017 at 15:45, Mark Cooke notifications@github.com wrote:

You mean I can't install a 1.25km antenna out the back 😄

Actually I did forget how terrible the gain of these antennas are. They are classified as being electrically small, and i make no effort at impedance matching so probably 'worse than -10dB' if my memory serves me correctly.

So @RoLorenzoni https://github.com/RoLorenzoni - ignore my warning. Also, @mr-sneezy https://github.com/mr-sneezy tells me its 10mW, not 100mW.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/micooke/WWVB/issues/10#issuecomment-298533122, or mute the thread https://github.com/notifications/unsubscribe-auth/AAotFOySFPyJ8ZyOxWPjcSCcOS8NadrHks5r1t8wgaJpZM4NMDkd .

micooke commented 7 years ago

Ill keep this open for a little bit - but the wwvb_jjy library is now working for a simple example so ill resolved this issue in that repo 🤞

RoLorenzoni commented 7 years ago

Oh thanks. I'll test the wwvb_jjy today. I found this app on the web. http://www.jrcomputing.com.au/Set_Watch/Set_Watch_Manual.html May be useful, specially for you, because it's JJY too.

micooke commented 7 years ago

Thanks for that, ill have to check it out. Im closing this as i have an (untested) example in the new wwvb_jjy library - https://github.com/micooke/wwvb_jjy/blob/master/examples/AD9850_WWVB_tx/AD9850_WWVB_tx.ino

micooke commented 7 years ago

Hey @baradhili did you end up getting a board from Wingsy?

https://forum.allaboutcircuits.com/threads/i-built-it-now-can-i-sell-it.130898/page-2#post-1089916

I wound be interested in the schematic and what antenna you are using.

Cheers

baradhili commented 7 years ago

Not me sorry

On 31 May 2017 at 15:25, Mark Cooke notifications@github.com wrote:

Hey @baradhili https://github.com/baradhili did you end up getting a board from Wingsy?

https://forum.allaboutcircuits.com/threads/i-built-it-now-can-i-sell-it. 130898/page-2#post-1089916

I wound be interested in the schematic and what antenna you are using.

Cheers

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/micooke/WWVB/issues/10#issuecomment-305107849, or mute the thread https://github.com/notifications/unsubscribe-auth/AAotFMOGETAQX6-0YbV0UD7fS7diLufXks5r_RXugaJpZM4NMDkd .