Output signal modulation

Hi everyone

For my master's thesis in visible light communication, I am using an LED as a transmitter and using an Adafruit feather nrf52840 to generate the signal. I am working with frequencies ranging from 2khz to 16khz.

There are 2 specific methods I want to explore:

  1. modulating the frequency, i.e. generating a simple on-off signal at a frequency of my choosing, and being able to change this frequency at a rapid pace,
  2. On-Off keying, i.e. generating on and off signals based on a bit array which represents the signal that has to be transmitted. This would happen at a set frequency, either 4khz or 8khz. (if I want to send [1 0 0 1], I want the output signal to be high for 125 microseconds (1s/8000), then low for 250 micros, then high again for 125 micros).

This is a question about the programming part.
I have been messing around with simple "micros()" in the loop function, but I get some strange behavior. I am now investigating ways to implement some interrupt routine.

I believe I can fill out most details on my own, but need some guidance about the best way to go. What is the best way to implement the things that I want with good accuracy (that is, if my pulse width needs to be 125 microseconds it shouldn't deviate too much)? And if interrupt-based programming is the answer, could you refer me to some kind of tutorial/documentation? (I already messed around with interrupts on an Arduino Uno, but I don't know what changes when switching to an Adafruit board.)

Thank you very much
Kind greetings
Emile

emilioho2020:
This is a question about the programming part.
I have been messing around with simple "micros()" in the loop function, but I get some strange behavior. I am now investigating ways to implement some interrupt routine.

That provides no useful information with which to help you.

If you post the program and describe in detail what the strange behaviour is then we may be able to suggest a solution.

...R

The reason I am struggling with this is that I have no reliable way to analyze the output. I actually need to build this setup in order to develop and test my receiver. To clarify "strange behaviour", I can only say that my toggling frequency is capped at about 1 khz, i.e., increasing the frequency further doesn't show any change in the receiver.

Here is the basic code I am using

int frequency = 2*4000;
long period_interval = (long) 1000000/frequency;
long currentMicros;
long previousMicros;
bool toggle;


// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(9, OUTPUT);
  previousMicros = micros();
}

// the loop function runs over and over again forever
void loop() {
// start timing interval

 currentMicros = micros();  // sample the time
 if (currentMicros - previousMicros >= period_interval) // more than our interval?
 {
   // save the last time we okayed time updates
   previousMicros = currentMicros; // save the current time for next comparison
   toggle = 1-toggle;  // results in 0 1 0 1 ...
   digitalWrite(9, toggle);
 }
}

I also set up some counters to monitor the time between each execution of the loop function, and I get quite different results on the Adafruit than on the Arduino Uno (I just made the switch because my old Uno was too slow to accommodate my needs); I got this result: for about 20 iterations, the loop function runs in almost instant time, then halts for +- 1ms (which is far too long in my application) (no idea what it is doing, running a kernel process or something), then resumes. This would explain why the LED would toggle only every ms or so.

I am sorry, but I can't provide a full analysis of the output signal as I don't have an oscilloscope at my disposal. Thanks for your help!

Emile

[Here is your code output on a Duemilanove - Moderator]

I would expect that code to work fine on an Uno or Mega but I don't know what the maximum frequency would be without testing. On an Uno or Mega I would use the digitalWriteFast library for improved performance.

Using a Hardware Timer I have a program on a Mega that produces stepper motor pulses at up to 25kHz.

I have no experience with the Adafruit feather.

...R

Try this simple code, toggles D19 (A5) at 20 KHz.
Easy to adjust by writing to a different input port, or changing the half period duration.
Will see a little jitter on a 'scope with the micros/millis interrupts.

byte triggerOut = 19;

unsigned long currentMicros;
unsigned long nextMicros;
unsigned long elapsedMicros;

unsigned long duration = 25UL; // flip every 50uS = 20KHz pulse

void setup() {
  pinMode (triggerOut, OUTPUT);
}
void loop() {
  while (1) {
    currentMicros = micros();
    elapsedMicros = currentMicros - nextMicros;
    if (elapsedMicros >= duration) {
      nextMicros = nextMicros + duration;
      PINC = 0b00100000; // toggle D19 output by writing to input port.
    }
  }
}

Odd - falling edge to falling edge looks like 50uS, rising edge to rising edge not so much.

"There are 2 specific methods I want to explore:

  1. modulating the frequency, i.e. generating a simple on-off signal at a frequency of my choosing, and being able to change this frequency at a rapid pace,
  2. On-Off keying, i.e. generating on and off signals based on a bit array which represents the signal that has to be transmitted. This would happen at a set frequency, either 4khz or 8khz. (if I want to send [1 0 0 1], I want the output signal to be high for 125 microseconds (1s/8000), then low for 250 micros, then high again for 125 micros)."..

Perhaps your problem stems from not being completely clear in what you want to do.
You want to modulate the frequency, but you seem to be wanting to change the pulse repetition rate which is in reality already an on-off signal, a square wave.
Do you already have devices that can detect your "signal", so you can see if you are getting the results you want?
Paul

Hi ?emilio

I played with this in the late 80's. I found the main problem was at the receiver, with ambient light. It varies hugely in intensity and may be modulated.
I used a large area photodiode as the receiver, as they can respond over a huge range of intensities.

For the transmitter, I go with the previous answers - keep it simple and get a useful square wave, you can modulate it later.

emilioho2020:
Hi everyone

There are 2 specific methods I want to explore:

  1. modulating the frequency, i.e. generating a simple on-off signal at a frequency of my choosing, and being able to change this frequency at a rapid pace,

modify Blink code = replace digitalWrite by tone, 1000Hz SOS

int piezoPin = 8;
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
 
//   S
  tone(piezoPin, 1000, 30);// 1000Hz
  delay(200);
  tone(piezoPin, 1000, 30);
  delay(200);
  tone(piezoPin, 1000, 30);
  delay(500);
//   O
  tone(piezoPin, 1000, 200);
  delay(500);
  tone(piezoPin, 1000, 200);
  delay(500);
  tone(piezoPin, 1000, 200);
  delay(500);
 //  S 
 tone(piezoPin, 1000, 30);
  delay(200);
  tone(piezoPin, 1000, 30);
  delay(200);
  tone(piezoPin, 1000, 30);
  delay(2000);

}                      // wait for a second
}

Modulating the frequency is quite easy: use the PWM output. Read the ATmega328p datasheet on details on how to set specific frequencies, you should be able to generate just about any frequency you want, and very easily change frequency or switch the signal on/off entirely. With the waveform generation itself all done in hardware, you have much more freedom in doing the actual programming.

Here's a revised version of the code from post #2:

unsigned long frequency = (long) 2*16000;
unsigned long period_interval = (long) 1000000/frequency;
unsigned long currentMicros;
unsigned long nextMicros;
bool toggle;

void setup() {
  // initialize digital pin 9 as an output.
  pinMode(9, OUTPUT);
  nextMicros = micros();
}

void loop() {
// start timing interval

 currentMicros = micros();  // sample the time
 if (currentMicros >= nextMicros) // more than our interval?
 {
   nextMicros = nextMicros + period_interval ; // calculate next toggle time
   toggle = !toggle;  // results in 0 1 0 1 ...
   digitalWrite(9, toggle);
 }
}

Changes include the following:

  • All the time variables are defined as unsigned since that is what micros() returns and because time only moves one direction.
  • "frequency" is defined as a long to prevent issues for values larger than 32k for a signed int which may have been the root cause of the "strange behavior" noted in post #2.
  • Time interval logic is rearranged to be uniform intervals rather than offset from currentMicros. The rational for this is discussed at length in the "several things at the same time" thread.
  • Logical "!" is used to change state of "toggle" variable, because arithmetic on Boolean values isn't obvious, even though it probably compiles to the same thing.

One issue with this approach is that Arduino "micros()" on an Uno has a time resolution of 4 uS, so there is clock jitter of that level on the generated signal, which becomes particularly apparent at higher frequencies. That said, this code runs at better than 32 kHz on an Uno. One could use fast I/O and play games with the word length of the time variables to speed to go faster, but the jitter problem will become more apparent.

While oscilloscopes may be a bit pricey, a cheap USB logic analyzer is nearly as useful for working with digital signals like this and they are very inexpensive.

Sorry, but a master's thesis that explores modulation techniques that have been thoroughly beaten to death for 100 years? I don't see it. What's the challenge? What I see here is on the level of a CET final year project. I suggest exploring digital modulation techniques such as spread spectrum technologies, with your thesis advisor.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.