Storing Cookies (See : http://ec.europa.eu/ipg/basics/legal/cookies/index_en.htm ) help us to bring you our services at overunity.com . If you use this website and our services you declare yourself okay with using cookies .More Infos here:
https://overunity.com/5553/privacy-policy/
If you do not agree with storing cookies, please LEAVE this website now. From the 25th of May 2018, every existing user has to accept the GDPR agreement at first login. If a user is unwilling to accept the GDPR, he should email us and request to erase his account. Many thanks for your understanding

User Menu

Custom Search

Author Topic: Arduino signal generator  (Read 31945 times)

gyulasun

  • Hero Member
  • *****
  • Posts: 4117
Re: Arduino signal generator
« Reply #30 on: May 04, 2018, 12:33:57 AM »
Hi Dann,

Good you managed to make it work, albeit with that unwanted issues.  Perhaps a 'dead bug' construction
instead of the protoboard may cure the problem.
You can think of spurious oscillations due to not enough decoupling on input pins and / or the 5V reference pin.
See this motor speed control circuit based on TL494 where the wiper of duty cycle control pot is shunted by
a 220 uF, rather unusual:  http://www.nawattakam.com/talk/index.php?topic=784.0  Also, the pin connections
around the duty cycle circuit are different from the schematics shown in this forum hence from what you built. 
Maybe it would be worth rewire your board for the changes because pin 4 (dead time control) is grounded
which is your duty cycle control input at present and receives varying DC voltage from the wiper of the potmeter.
The motor speed control circuit in the above link gives almost 100% duty control by combining the two out of phase
outputs for the motor via the two power MOSFETs, originally the TL494 gives duty control from 1% to 45% only, if I
understand correctly.  Good luck.

Gyula

madddann

  • Full Member
  • ***
  • Posts: 159
Re: Arduino signal generator
« Reply #31 on: May 04, 2018, 11:03:01 PM »
Hi Gyula.

Thanks for that schematic, I fiddled with the circuit some more time and got it to work (above certain frequency). It seems that below 30kHz the duty cycle anomaly on one of the outputs starts to happen.
Anyway I just realized this chip will not go below 1kHz, so it doesn't help me with what I'm experimenting right now.
I also have an SG3525, but the lowest it will go is 100Hz, which is still higher than I would like.

So now I came full circle, and learned something useful along the way.


@all.

Now back to the arduino plan.
I'll write down the specs needed here again:

-two phase PWM square wave generator
-variable frequency from 1Hz (or at least around 5Hz) up to whatever is possible - reasonable  (adjustable with pot.)
-variable duty cycle from 1% to 100%, resolution the more the better (adjustable with pot.)
-two outputs shifted (delayed) for half the total period (180°), (not inverted - same signal on both channels only shifted) like the signals PWM1 and PWM3 here: https://batchloaf.files.wordpress.com/2015/03/four_phase_pwm.png

I have an arduino nano 328p, V3.

Anyone that enjoys fiddelin with code Is welcome  :) .

Maybe somewhere on the net already exsists some code for a 4 phase or 6 phase PWM controller with adjustable frequency...
If anyone happens to know about it please post it here.
Any help is appreciated.

Thanks everyone!

gyulasun

  • Hero Member
  • *****
  • Posts: 4117
Re: Arduino signal generator
« Reply #32 on: May 05, 2018, 09:07:43 PM »
Hi Dann,

I understand your aim to use your Arduino chip. Hopefully the needed specifications you set out can be
achieved either by your chip or by a PIC chip (microcontroller).

Yet, I would again like to refer to an 'analog' way of producing shifted pulses. You surely heard about
modified sine wave inverters, these are basically DC to AC power converters and their output waveforms
try to mimic the needed sine wave shape as close as possible. And this involves the producing of shifted
pulses first. See such circuit here, with scope shot on the waveform you would need:
https://www.homemade-circuits.com/how-to-build-simplest-modified-sine/ 
Unfortunately, this circuit does not include duty cycle control.  It could be provided by using a dual monostable
multivibrator (say CD4538) which would stretch out or reduce the pulse width coming from IC2 (CD4017)
and you could control the pulse width by a double (stereo) potmeter or individually for the two channels.
Here is another circuit to produce the shifted pulses, with other than the CD4017:
http://www.instructables.com/id/Modified-Sine-Wave-Signal-Generator/  but it does not have duty cycle control either.
 
Good luck.
Gyula

madddann

  • Full Member
  • ***
  • Posts: 159
Re: Arduino signal generator
« Reply #33 on: May 06, 2018, 12:32:05 AM »
Hi! Thanks for the suggestions Gyula.

I think I have some of those SN74LSxx chips and I also have a variable frequency PWM (555 + comparator) that I used before,
so I may come up with some mix that works. Will try to play tomorrow in multisim.

Today I got some help from someone close and we did program (just few lines of code) the arduino nano to output two PWM signals shifted by 180°, at a fixed frequency.
So I did play a bit with my figuera setup and noticed that variable phase shift would come also handy  ;D .
I also think that the mosfets are cutting off almost half (top section) of the resonant wave, so will have to replace them with ordinary transistors.
The problems pile up one after another, but hopefully the solutions will outmatch them.

On the arduino forum I found some discussion and code that would do what I need, but it's for arduino mega: https://forum.arduino.cc/index.php?topic=482903.0
Maybe I'll ask there for some help.

Dann



kEhYo77

  • Full Member
  • ***
  • Posts: 247
Re: Arduino signal generator
« Reply #34 on: May 07, 2018, 06:41:08 PM »
YO!

I spent the whole weekend trying to figure this out and here it is!!!
3 controlling pots: Frequency / Duty / Range
Max operational frequency around 500 kHz
Min operational frequency around 1 Hz
The resolution of duty cycle goes down the higher you go up in given frequency range.


Enjoy!!!


Quote
// Dual pin PWM PUSH-PULL generator FOR Arduino UNO on pins 9&10
// by kEhYo77 2018


int user_cycles;
int user_duty;
int user_range;
int temp_cycles;
int temp_duty;
int temp_range;
int tuner;
unsigned long past = 0;


void set(int cycles, float duty) {
 
  char oldSREG;
 
  int dutyCycle = cycles * duty;
  if (dutyCycle < 6) {
    dutyCycle = 6; // Prevent duty cycle from being too short
  }

  oldSREG = SREG; // Save the registers
  cli(); // Disable interrupts for 16 bit register access
  ICR1 = cycles; // ICR1 is TOP in p & f correct pwm mode
  OCR1A = cycles-dutyCycle/2+1; //Pin 9 match
  OCR1B = dutyCycle/2-1; //Pin 10 match
 
  SREG = oldSREG; // Restore the registers
}


void setup() {
 
  pinMode(A0, INPUT); //analoque pot input Frequency
  pinMode(A1, INPUT); //analoque pot input DutyCycle
  pinMode(A2, INPUT); //analogue pot input Range
 
  bitClear(ADCSRA,ADPS0); //running analog pot input
  bitClear(ADCSRA,ADPS1); //with high speed clock
  bitSet(ADCSRA,ADPS2); //set prescaler to 16
   
  pinMode(9, OUTPUT); //output A
  pinMode(10, OUTPUT); //output B


  TCCR1A = 0; //clear timer1 registers
  TCCR1B = 0;
  TCNT1 = 0;


  TCCR1A |= _BV(COM1A1) | _BV(COM1A0);
  //Output A. Set OC1A/OC1B on Compare Match,
  //Clear OC1A/OC1B at BOTTOM (inverting mode)


  TCCR1A |= _BV(COM1B1);
  //Output B. Clear OC1A/OC1B on Compare Match when up-counting.
  //Set OC1A/OC1B on Compare Match when down-counting.


  TCCR1B |= _BV(WGM13); //PWM Phase Correcrt mode 10 to ICR1
  TCCR1A |= _BV(WGM11); //WGM13:WGM11 set 1010
  TCCR1B |= _BV(CS10); //set prescaler 1
}


void loop() {
  if ((millis() - past) >= 500) { //read pots every half second
  temp_cycles = analogRead(A0);
  temp_duty = analogRead(A1);
  temp_range = analogRead(A2);
  past = millis();
   
  if (temp_cycles != user_cycles || temp_duty != user_duty) {
    user_cycles = temp_cycles;
    user_duty = temp_duty;
    set(user_cycles * tuner, user_duty / 1024.0);
  }


  if (temp_range != user_range) {
  if (temp_range <= 250) { TCCR1B |= (1<<CS10); TCCR1B &= ~((1<<CS11) | (1<<CS12)); tuner = 1; } // prescaler 1 ( 8 kHz - 300 kHz )
  if (temp_range > 250 & temp_range <= 500) { TCCR1B |= _BV(CS11); TCCR1B &= ~((1<<CS10) | (1<<CS12)); tuner = 8; } //prescaler 8 ( 120 Hz - 40 kHz )
  if (temp_range > 500 & temp_range <= 750) { TCCR1B |= _BV(CS10) | _BV(CS11); TCCR1B &= ~(1<<CS12); tuner = 16; } //prescaler 64 ( 4 Hz - 1 kHz )
  if (temp_range > 750 & temp_range <= 1024) { TCCR1B |= _BV(CS12); TCCR1B &= ~((1<<CS10) | (1<<CS11));  tuner = 32; } //prescaler 256 ( 1 Hz - 60 Hz )
  user_range = temp_range;
  }


  }
}

forest

  • Hero Member
  • *****
  • Posts: 4076
Re: Arduino signal generator
« Reply #35 on: May 07, 2018, 08:31:40 PM »
Beautiful! Could you post two outputs on the same plane , because it looks a bit shifted in phase (not pure 180 degrees) ?

kEhYo77

  • Full Member
  • ***
  • Posts: 247
Re: Arduino signal generator
« Reply #36 on: May 07, 2018, 08:33:22 PM »
It is 100% 180 deg. shifted phase corrected mode.
The output looks distorted only at this max frequency.

forest

  • Hero Member
  • *****
  • Posts: 4076
Re: Arduino signal generator
« Reply #37 on: May 07, 2018, 08:46:05 PM »
I'm interested if there is possibility to change the slope rising time especially to make it more sinusoidal :-) by any eternal filter maybe ?

kEhYo77

  • Full Member
  • ***
  • Posts: 247
Re: Arduino signal generator
« Reply #38 on: May 07, 2018, 08:53:36 PM »
I am afraid not. This method uses hardware timer registers to do the magic using mainly hardware and no software.
You can try to adapt my previously posted code for Figuera in this thread where I use sine table values.
You can "draw" in this table any shape you want.

TinselKoala

  • Hero Member
  • *****
  • Posts: 13958
Re: Arduino signal generator
« Reply #39 on: May 08, 2018, 05:38:03 AM »
Nice work!

Tested and verified to work with Arduino UNO R3, so it will most likely work on all members of that family (nano, promini, etc.). I have not yet tested it on a MEGA.

Probably a good idea to specify that all 3 pots should be same value. 10K is good, 50k is probably better. The pots are effectively in parallel so they interact somewhat.

It might be interesting to eliminate the pots and just use the serial monitor to send values instead. But since this sketch depends on having the actual inputs at analog pins A0, A1 and A2 to work, instead of just arbitrary variable values, it might take a little fiddling to enable serial functionality.


kEhYo77

  • Full Member
  • ***
  • Posts: 247
Re: Arduino signal generator
« Reply #40 on: May 08, 2018, 04:53:38 PM »
This code should work on Mega but you have to change the OUTPUT pin numbers to 11 and 12 as 16bit counter Timer1 [/size]is assigned there differently.
I will improve on that code to make it work with an LCD/serial and a rotary encoder to automatically dial in desired frequency.
Another weekend off ;)
This one is fresh from the bakery and if someone wants to modify it feel free.



madddann

  • Full Member
  • ***
  • Posts: 159
Re: Arduino signal generator
« Reply #41 on: May 08, 2018, 07:12:18 PM »
OMG kEhYo77, I'm speechless, thank you soo much, I saw this just now.

TK, thanks for testing.

Dann

kEhYo77

  • Full Member
  • ***
  • Posts: 247
Re: Arduino signal generator
« Reply #42 on: May 13, 2018, 03:18:20 PM »
I came across this variable frequency! 3 phase! sine! generator code for Arduino UNO, hope you like it.


Quote
// 3 phase PWM sine
// (c) 2016 C. Masenas
// Modified from original DDS from:
// KHM 2009 /  Martin Nawrath


// table of 256 sine values / one sine period / stored in flash memory
PROGMEM const unsigned char sine256[]  = {
  127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
  242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
  221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
  76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
  33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124


};
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
         
int testPin = 7;
int enablePin = 6 ;


volatile  float freq=1;
const float refclk=122.549  ;     //  16 MHz/510/256


// variables used inside interrupt service declared as voilatile
volatile unsigned long sigma;   // phase accumulator
volatile unsigned long delta;  // phase increment
byte phase0, phase1, phase2 ;


void setup()
{
  Serial.begin(9600);        // connect to the serial port
  Serial.println("DDS Test");


  pinMode(enablePin, OUTPUT);      // sets the digital pin as output
  pinMode(testPin, OUTPUT);      // sets the digital pin as output
  pinMode(9, OUTPUT);     // pin9= PWM  output / frequency output
  pinMode(10, OUTPUT);     // pin10= PWM  output / frequency output
  pinMode(11, OUTPUT);     // pin11= PWM  output / frequency output


  Setup_timer2();
  Setup_timer1();
  digitalWrite(enablePin, HIGH);


// the waveform index is the highest 8 bits of sigma
// choose refclk as freq to increment the lsb of the 8 highest bits
//    for every call to the ISR of timer2 overflow
// the lsb of the 8 highest bits is 1<<24 (1LL<<24 for long integer literal)
  delta = (1LL<<24)*freq/refclk ; 
}
void loop(){
 
  changeFreq(20);
  delay(10000);
  changeFreq(25);
  delay(10000);
             
 }


void changeFreq(float _freq){
  cbi (TIMSK2,TOIE2);              // disable timer2 overflow detect
  freq = _freq;
  delta=(1LL<<24)*freq/refclk;  // update phase increment
  sbi (TIMSK2,TOIE2);              // enable timer2 overflow detect
}


//******************************************************************
// timer2 setup
// set prscaler to 1,  fast PWM
void Setup_timer2() {


// Timer2 Clock Prescaler to : 1
  sbi (TCCR2B, CS20);  // set
  cbi (TCCR2B, CS21);  // clear
  cbi (TCCR2B, CS22);


  // Timer2 PWM Mode
  cbi (TCCR2A, COM2A0);  // clear OC2A on Compare Match, PWM pin 11
  sbi (TCCR2A, COM2A1);


  // set to fast PWM
  sbi (TCCR2A, WGM20);  // Mode 1, phase correct PWM
  cbi (TCCR2A, WGM21);
  cbi (TCCR2B, WGM22);


  sbi (TIMSK2,TOIE2);              // enable overflow detect
 
}
// timer1 setup  (sets pins 9 and 10)
// set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer1() {


// Timer1 Clock Prescaler to : 1
  sbi (TCCR1B, CS10);
  cbi (TCCR1B, CS11);
  cbi (TCCR1B, CS12);


  // Timer1 PWM Mode set to Phase Correct PWM
  cbi (TCCR1A, COM1A0);  // clear OC1A on Compare Match, PWM pin 9
  sbi (TCCR1A, COM1A1);
  cbi (TCCR1A, COM1B0);  // clear OC1B on Compare Match, PWM pin 10
  sbi (TCCR1A, COM1B1);


  sbi (TCCR1A, WGM10);  // Mode 1  / phase correct PWM
  cbi (TCCR1A, WGM11);
  cbi (TCCR1B, WGM12);
  cbi (TCCR1B, WGM13);
}


//******************************************************************
// Timer2 Interrupt Service at 31372,550 KHz = 32uSec
// this is the timebase REFCLOCK for the DDS generator
// runtime : 8 microseconds ( inclusive push and pop)
// OC2A - pin 11
// OC1B - pin 10
// OC1A - pin 9
// https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
ISR(TIMER2_OVF_vect) {


  sbi(PORTD,testPin);         


  sigma=sigma+delta; // soft DDS, phase accu with 32 bits
  phase0=sigma >> 24;     // use upper 8 bits for phase accu as frequency information
                         // read value fron ROM sine table and send to PWM DAC
  phase1 = phase0 +85 ;
  phase2 = phase0 +170 ;


  OCR2A=pgm_read_byte_near(sine256 + phase0);  // pwm pin 11
  OCR1B=pgm_read_byte_near(sine256 + phase1);  // pwm pin 10
  OCR1A=pgm_read_byte_near(sine256 + phase2);  // pwm pin 9


  cbi(PORTD,testPin);           
 
}

Reiyuki

  • Full Member
  • ***
  • Posts: 133
Re: Arduino signal generator (Teensy)
« Reply #43 on: May 14, 2018, 03:44:13 PM »
Great thread, everyone. ;)


One issue I and others have run into is clock-rate.  At higher frequencies, many of the sketches posted lose granularity and become distorted.

Most Arduino run at 16mhz, but sketches using PWM or pulses are often only clean up to 50-200khz.

I've had good luck boosting this number by using higher clockrate Arduinos, specifically Teensy's:
https://www.pjrc.com/teensy/

The improvements are largely linear (sketches that become distorted at 100khz with 16mhz clock tend to reach 300khz with 48mhz clock.

Note: Some sketches (especially ones using interrupts) will need to be tweaked to work with the different chipset.  Also, many of the faster Teensy's are 3.3v and not 5v, so you may need to make changes elsewhere to accommodate.