Go Down

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

winner10920

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

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 outputs
int 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

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

Quote
There are many roads to jerusalem!

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

winner10920

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

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
Read this
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

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

Hi GM,
   I thought the ATMega328 has toggle on output compare ?

Duane B

Read this
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

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

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

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 pm Last 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 OCR1A
const int  outPin = 9;

long period = 1;     // the period in microseconds
long pulseWidth = 0.5; // width of a pulse in microseconds

int prescale[] = {0,1,8,64,256,1024}; // range of prescale values

void 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

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


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

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