Go Down

### Topic: 50% duty cycle square wave from 1hz to 1Mhz, easiest way? (Read 52830 times)previous topic - next topic

#### winner10920

##### Jul 27, 2012, 04:08 am
Like said in the subject what would be the easiest way to make an adjustable square wave(50% duty cycle) that can be adjusted from 1hz(doesn't have to be that low but it'd be nice) to 1Mhz(doesn't have to be that high maybe >750khz but it'd be nice), the precision doesn't have to be crazy but adjustable as much as possible so I can correct it
I used to have a function generator that did it but it broke and I need this as a separate solution anyway, also if it could be easily digitally adjusted that would be really awesome to exchange a potentiometer for an encoder for fine adjustments
I know there's a ton of ways of making oscillators and than just turning it into a good square wave, but what's the easiest best? It doesn't have to drive much of a load, its more for signal purposes
my current attempt is my 555 timer which is a pain to readjust everytime I want to change and it never turns out to be 50% duty cycle or even close enough, also the fastest I think I got was 300khz with a horrible duty cycle

#### Resinator

#1
##### Jul 27, 2012, 07:35 am
There are many roads to jerusalem!

A timed interrupt would probably be the best way, or use the onboard PWM not that I have ever used that as I always program PWM manually

Digital write takes about 4us so thats not an option for even moderate frequencies direct port addressing is what you need

But the easiest way is a program that does nothing else  like this

Code: [Select]
`void setup(){   DDRB = DDRB | B110000;} // Set digital pins 12 and 13 to outputsint T = 30;void loop(){          PORTB = B100000;         // Digital pin 13 high   delayMicroseconds(T);  //30 microsecond delay   PORTB = B000000;        // Digital pin 13 low    delayMicroseconds(T);   //30 microsecond delay      `
}

I am not sure it will produce a 1MHz wave though you will need to modify it so the delay is 0.5us

#### Grumpy_Mike

#2
##### Jul 27, 2012, 08:22 am
Put the output of your 555 through a divide by two to get a 1:1 duty cycle. Something like a 74LS74.

You will not get that range with a single capacitor so you will have to switch ranges.

#### AWOL

#3
##### Jul 27, 2012, 11:42 am
Quote
There are many roads to jerusalem!

So how come they all lead to Rome? (except the A57, which ends up in Worksop)

#### winner10920

#4
##### Jul 27, 2012, 12:53 pm
I was thinking about using an arduino timer but do thy have that kind of flexibility?
I know pwm wont work as I believe the max speed is 133khz but I don't need pwm, just 50% constant

#### DuaneB

#5
##### Jul 27, 2012, 01:14 pm
Hi,
If you see the thread I started a day or two back, the 555 is a horrible source of noise.

I would look to the the ATMega built in timers, your application is basically what they are there for.

You can configure the timers to automatically toggle a pin in the background, much faster and more accurate than trying to do it in software - there may be libraries already available that provide a nice interface to this functionality.

Duane B

rcarduino.blogspot.com
http://rcarduino.blogspot.com/2012/04/servo-problems-with-arduino-part-1.html
then watch this
http://rcarduino.blogspot.com/2012/04/servo-problems-part-2-demonstration.html

Rcarduino.blogspot.com

#### Grumpy_Mike

#6
##### Jul 27, 2012, 01:48 pm
Quote
I know pwm wont work as I believe the max speed is 133khz

No that is wrong it will go faster than that.

Quote
I don't need pwm, just 50% constant

The advantage of PWM is that it works without using any of the software CPU cycles.
If you follow the PWM output with a divide by two you get the square wave you are after.
Some processors have a toggle output pin on counter overflow, but not this one.
Doing it in software you have to arrange for the counter overflow ( or under flow ) to trigger an interrupt. In the ISR you simply toggle the pin.

#### DuaneB

#7
##### Jul 27, 2012, 02:23 pm
Hi GM,
I thought the ATMega328 has toggle on output compare ?

Duane B

http://rcarduino.blogspot.com/2012/04/servo-problems-with-arduino-part-1.html
then watch this
http://rcarduino.blogspot.com/2012/04/servo-problems-part-2-demonstration.html

Rcarduino.blogspot.com

#### winner10920

#8
##### Jul 27, 2012, 02:36 pm
I guess im gonna have to dive into the datasheet and figure this out
So the general consensus is that the arduino hardware can do this? I don't wanna spend 20 hours and realize it can't do what I want, ill be needing to dynamically change the frequency so I guess that means changing prescalers and counters on the fly?

#### Grumpy_Mike

#9
##### Jul 27, 2012, 04:32 pm
Quote
I thought the ATMega328 has toggle on output compare ?

Yes sorry you are right it does see section 17.5.1 and 14.7 of the data sheet.

#### Erni

#10
##### Jul 27, 2012, 05:53 pm
Maybe the easyest way would be to use the Timer1 library:

http://www.arduino.cc/playground/Code/Timer1

Quote
setPeriod(period)
Sets the period in microseconds. The minimum period or highest frequency this library supports is 1 microsecond or 1 MHz. The maximum period is 8388480 microseconds or about 8.3 seconds. Note that setting the period will change the attached interrupt and both pwm outputs' frequencies and duty cycles simultaneously

#### spcomputing

#11
##### Jul 27, 2012, 05:58 pmLast Edit: Jul 27, 2012, 06:00 pm by spcomputing Reason: 1
I used this sketch to time a Atmega1284p at 1MHz:

Edit - *With* another Uno.

Code: [Select]
`#include <TimerOne.h>#define pwmRegister OCR1Aconst int  outPin = 9;long period = 1;     // the period in microsecondslong pulseWidth = 0.5; // width of a pulse in microsecondsint prescale[] = {0,1,8,64,256,1024}; // range of prescale valuesvoid setup(){  Serial.begin(9600);  pinMode(outPin, OUTPUT);  Timer1.initialize(period);  //initialize timer1, 1000 microsec  setPulseWidth(pulseWidth);}void loop(){}bool setPulseWidth(long microseconds){  bool ret = false;    int prescaleValue = prescale[Timer1.clockSelectBits];  long precision = (F_CPU / 128000) * prescaleValue  ;  period = precision * ICR1 / 1000;  if( microseconds < period)    {      int duty = map(microseconds, 0, period, 0, 1024);      if(duty < 1)        duty = 1;      if( microseconds > 0 && duty < RESOLUTION)      {        Timer1.pwm(outPin, duty);        ret = true;      }    }    return ret;}`

Just need the Timer1 library.

#### winner10920

#12
##### Jul 28, 2012, 05:37 am
Solved XD
dig some digging in the datasheet for the past few hours and I can now set up pin 9 or ten to any frequency I want
thx for the help, using the arduino hardware is real easy once you figure it out

#### tejobr

#13
##### Aug 07, 2012, 12:58 am

Solved XD
dig some digging in the datasheet for the past few hours and I can now set up pin 9 or ten to any frequency I want
thx for the help, using the arduino hardware is real easy once you figure it out

And you can share your solution with us? I need to generate a wave of 1 MHz to recover a "Fuse brick";

Thanks

#### winner10920

#14
##### Aug 07, 2012, 01:43 pm
you'll be working with TCCR1A, TCCR1B, and OCR1A
first disable interupts,
set the wgm bits to CTC mode with OCR1A as top, calculate and set OCR1A,
set COM1A1,COM1A0 (or B depending if you want uno pin 9 or 10) then start the clock with prescaler /1,
If your in a rush you can probbly read the datasheet about these and figure it out,
ill post my code after work, I made a function that calculates the OCR1A and prescaler down to 4hz, but upwards of700khz the resolution is pretty bad, tho 1Mhz is fine I measured it with my uno @ .997Mhz which I guess is close enough,

Go Up