how to generate waveform

hi all,

I am a first time arduino and C++ user. I just bought the OSEPP Uno R3 Plus 201-kit and I test the Ultrasonic_Range_Finder example and I probe the Digital pin5 and saw 100us on time with 2.5s period.
Now, I try to generate the waveform based on the following specification:

step1:
output high 12us (A)
output low 13us (B)
repeat (A) and (B) for 20 times
output low 24ms

step2:
repeat step1 and loop forever.

note: "us" is microsecond and "ms" is milisecond
If anyone can help, please send the code to me. I appreciate your help very much.

Please take a look at the example code here: http://arduino.cc/en/Reference/DelayMicroseconds

It is almost word-for-word what you are looking for, except you must tweak some of the values. And you will also need to put a for() loop in to repeat 20 times.

For higher accuracy, disable interrupts before outputting your waveform using this function: detachInterrupt() - Arduino Reference

hi joshuabardwell,

thanks so much for your quick tip. I am be able to generate the waveform with frequency I want. I try to put the for loop to stop at 20 times, but it did not work. I am sorry for asking the very basic program question like this, but I am learning to program myself at the first time and with no C++ knowledge. Below is my code:

int outPin = 8; // digital pin 8

void setup()
{
pinMode(outPin, OUTPUT); // sets the digital pin as output
}

void loop()
{
for (int outPin=0; outPin <= 20; outPin++)
noInterrupts(); // turn interrupt off for timing accuracy
digitalWrite(outPin, HIGH); // sets the pin on
delayMicroseconds(7); // pauses for 7 (actual ontime 10us seen on scope) microseconds
digitalWrite(outPin, LOW); // sets the pin off
delayMicroseconds(10); // pauses for 10 (actual offtime 15us seen on scope) microseconds
}

again if you can help, appreicate very much.

for (int outPin=0; outPin <= 20; outPin++)
  noInterrupts();                            // turn interrupt off for timing accuracy
  digitalWrite(outPin, HIGH);

Don't you want the output on a single pin?

hi AWOL,

yes, I want the output on pin 8 only and waveform should goes high 7us, low 10us for 20 times and stay low for 24ms, then go high 7us, low 10us for 20 times and stay low for 24ms, and keep repeat the whole thing again forever.

if you can give me the code to implement this, it'd be great help.

thanks a lot in advance.

I want the output on pin 8 only

So why write to a different pin for each iteration?

hi AWOL,

my purpose is to repeat the waveform at pin8 for 20 times and stop for 24ms and do it again, but I don't know how to write the code to do this. I read the example of for() loop and try to apply into my code, but obviously like you said it goes different pins not repeating, not what's I want. Can you help to revise my code.

Thanks much.

Thanks for including your complete code. Please also put it inside "code" tags. It's the hash-mark (#) symbol in the editor.

int outPin = 8;                 // digital pin 8

void setup()
{
  pinMode(outPin, OUTPUT);      // sets the digital pin as output
}

void loop()
{
 for (int outPin=0; outPin <= 20; outPin++)
  noInterrupts();                            // turn interrupt off for timing accuracy
  digitalWrite(outPin, HIGH);     // sets the pin on
  delayMicroseconds(7);            // pauses for 7 (actual ontime 10us seen on scope) microseconds      
  digitalWrite(outPin, LOW);    // sets the pin off
  delayMicroseconds(10);        // pauses for 10 (actual offtime 15us seen on scope) microseconds      
}

Your use of the for() loop is incorrect. What you are doing is declaring a new variable "outPin" in the scope of the for() loop, which starts at the value 0 and increments by one each iteration of the loop until it reaches 20. Then you are writing to outPin. You have declared two copies of a variable named outPin--one in the global scope, which has value 8, and one in the scope of the for() loop, which goes from 0 to 20. This is known as variable overloading, and there are some cases when it can be a good thing, but mostly, it is a bad idea, and is confusing, and it is probably not what you meant to do.

Just to expound a bit more... what your loop is doing is this:

Write HIGH to pin 1 for 10 us.
Write LOW to pin 1 for 15 us.
Write HIGH to pin 2 for 10 us.
Write LOW to pin 2 for 15 uS
... pin 3
... pin 4
... pin 5
etc...
... pin 20

What you want is something like this:

for(int x = 0; x < 20; x++)
{
  digitalWrite(outPin, HIGH)
  ... etc...
}

In other words, use x as a temporary counter variable within the scope of the for() loop and leave outPin alone.

Another note: it would probably be better to call noInterrupts() just before the for() loop, rather than calling it multiple times from within the loop. Also, don't forget that you must re-enable interrupts using interrupts() as soon as possible, or things will get screwy. So I would suggest:

noInterrupts();
for(x = 0; x < 20; x++)
{
  // digitalWrites go here
}
interrupts();

hi joshuabardwell,

thank you so much for your helpful suggestion. I was be able to generate the waveform I need

Thanks again for your big help.

Merry Christmas and Happy New Year to you!!!

:stuck_out_tongue_closed_eyes:

Just would like to mention that I got square wave signal at 2.64V with 29.31kHz frequency based on given coding.
Could you share the final coding so that it beneficial for everybody here..

2.64V ?? How did that happen? If the output isn't close to 5V peak-to-peak (for a
5V supply) you are overloading the pin.

MarkT:
2.64V ?? How did that happen? If the output isn't close to 5V peak-to-peak (for a
5V supply) you are overloading the pin.

Yeah, it still showed the same value today. Anyway, its also notice that my circuit measured 4.73V instead of 5V..

Then something is overloading the pin - remember the absolute maximum current rating
for any pin is 40mA, in practice 20 to 25mA is a safe upper limit (even then you lose a volt
or so of drive).

MarkT:
Then something is overloading the pin - remember the absolute maximum current rating
for any pin is 40mA, in practice 20 to 25mA is a safe upper limit (even then you lose a volt
or so of drive).

Ops, sorry to mentioned that I'm measuring in rms value. So, its generate 4.90V with the same frequency..

hi NanoScaler,

sorry for very slow response because I spent Christmas and did not log in to see your question. Fortunately, I got the waveform with 4.9V output, that's great. Thanks MarkT to reply for me.

To joshuabardwell,

I am running into another problem that I try to read the analog voltage at pin A0 and map the analog range from 0, 1023 to digital range 255 to 0. When I apply the voltage to A0 and change it, the pulse width from pin 9 is changing accordingly, but it always give me 2ms period. I try to change the period longer, but I can't. I already changing the delay(2) to delay(200), but it does nothing. Could you please help? please see my code below:

int sensorValue = 0; // value read from the pot
int outputValue = 0; // value output to the PWM (analog out)

void setup() {

}

void loop() {

// read the analog in value at pin A0

sensorValue = analogRead(A0);

// map it to the range of the analog out:

outputValue = map(sensorValue, 0, 1023, 255, 0);

// change the analog out value:

analogWrite(9, outputValue);

// wait 2 milliseconds before the next loop
// for the analog-to-digital converter to settle after the last reading

delay(2);
}

As I said earlier, please put your code in "code" tags. It's the hash-mark (#) button in the editor. I'll take a look and see if anything jumps out.

int sensorValue = 0;        // value read from the pot
int outputValue = 0;        // value output to the PWM (analog out)

void setup() {

}

void loop() {

  // read the analog in value at pin A0
  sensorValue = analogRead(A0);   

  // map it to the range of the analog out:
  outputValue = map(sensorValue, 0, 1023, 255, 0);  

  // change the analog out value:
  analogWrite(9, outputValue);           

  // wait 2 milliseconds before the next loop
  // for the analog-to-digital converter to settle after the last reading
  delay(2);         
}

I am running into another problem that I try to read the analog voltage at pin A0 and map the analog range from 0, 1023 to digital range 255 to 0. When I apply the voltage to A0 and change it, the pulse width from pin 9 is changing accordingly, but it always give me 2ms period. I try to change the period longer, but I can't. I already changing the delay(2) to delay(200), but it does nothing. Could you please help? please see my code below:

The frequency of the PWM signal will always be the same, regardless of the frequency of your digitalWrites. As you have seen, changing the digitalWrite() value changes the duty cycle of the PWM signal, but the base PWM frequency is un-changed.

It's not clear to me what you're trying to accomplish by changing the delay() value. Maybe you could elaborate. Do you need a higher-frequency PWM signal to be output?

Another thing: you really should do pinMode(9, OUTPUT) in setup(). My understanding is that digital pins default to input, so I'm not sure how your analogWrite() is even working. Maybe analogWrite() explicitly sets the pin to OUTPUT or something. I don't know. Either way, you need to do pinMode() in setup just as a matter of good programming practice.

hi joshuabardwell,

never mind, I got it by changing the microcontroller timer.

Thanks,
Sonh

hi joshuabardwell,

Thanks so much for helpful inputs. I ran into another challenge one I'd like your help. The code below I try to generate the PWM signal to pin3 and changing its on time respect to voltage at pin A1 if Pin5 rising from low high (edge trigger). If pin5 low, then write digital signal low to pin3. And pin3 waveform has to goes high right away at pin5 rising edge and goes low when its on time finish (about 30ms). However, when I probe the waveform, I saw pin3 on and off randomly, not align with pin5 rising edge.

Thanks in advance.

int ultraValue = 0;                            
int ultraPwmValue = 0; 
int Pin5 = 5;
int readValue = 0;
int initialValue = 0;

void setup() {                
  pinMode(Pin5, OUTPUT);
 }


void loop() {
  

 
  TCCR2B = TCCR2B & 0b11111000 | 0x07;    // set up the timer2 to 30Hz clock

  digitalWrite(Pin5, HIGH);
  readValue = digitalRead(Pin5);

  if(readValue != initialValue){
    if(readValue == HIGH){
  
  int ultraValue = analogRead(A1); // read echo analog voltage at pin A1
  ultraPwmValue = map(ultraValue, 0, 1023, 235, 10);  // 0V map to 235 is equivalent to 90% (~30ms) on time of 33ms, 1023(~5V) map to 10 is 6.6% (~2ms) on time of 33ms  
  analogWrite(3, ultraPwmValue);
                          }
                               }
      

  else{digitalWrite(3, LOW);}
 
  delay(30);               
  digitalWrite(Pin5, LOW);  
  delay(30);  
}