[SOLVED] VCO

ted
Wed Sep 05, 2018 1:32 pm
Hi
I am trying to make a VCO based on voltmeter and generator programs, what I need is control Overflow of the timer by voltage applied to PA7.

pwmtimer3.setOverflow(1000 - 1);


edogaldo
Wed Sep 05, 2018 9:33 pm
You should put the timer configuration in the loop, define the overflow value as a function of the input voltage and define the compare value as half of the overflow value.

Cheers, E.


ted
Wed Sep 05, 2018 10:27 pm
I did like this, no pulses on PB0

#include <LiquidCrystal.h>
LiquidCrystal lcd(PA0, PA1, PA2, PA3, PA4, PA5);
HardwareTimer pwmtimer3(3);
int i;
int volt;
void setup() {
pinMode(PA6, INPUT_ANALOG);
lcd.begin(16, 2);
pinMode(PB0, PWM);
/*
pwmtimer3.pause();
pwmtimer3.setPrescaleFactor(72); // Timer input clock Prescaler = 1MHz 72MHz
pwmtimer3.setOverflow(1000 - 1);
pwmtimer3.setCompare(TIMER_CH3, 500); // PWM High Pulse width is 50% duty (1:1)
pwmtimer3.refresh();
pwmtimer3.resume();
*/
}

void loop() {
pwmtimer3.pause();
pwmtimer3.setPrescaleFactor(72); // Timer input clock Prescaler = 1MHz 72MHz
pwmtimer3.setOverflow(i);
pwmtimer3.setCompare(TIMER_CH3, i / 2); // PWM High Pulse width is 50% duty (1:1)
pwmtimer3.refresh();
pwmtimer3.resume();
i == volt;
float volt = analogRead(PA6);
volt = (volt * 3.3) / 4095.0;
lcd.setCursor(0, 0);
lcd.print(volt);
delay(100);
}


RogerClark
Thu Sep 06, 2018 1:11 am
I’d recommend you go back to basics

I can’t remember if PB0 even has a timer attached to it, but I’d double check that first

Then just to an AnalogWrite to PB0 and check you get some PWM

After thats working, try setting up your own PWM at one frequency

When thats working and you can set various initial frequencies and check that works

Then in your main(), try setting an initial freq, waiting 250ms and then set a new freq

If at any stage things arent working as you expect, examine what you are doing and bug fix


ted
Thu Sep 06, 2018 1:53 am
Everything is working except last two lines, I tried in setup and in the loop.
Then in your main(), try setting an initial freq, waiting 250ms and then set a new freq

If at any stage things arent working as you expect, examine what you are doing and bug fix

#include <LiquidCrystal.h>
LiquidCrystal lcd(PA0, PA1, PA2, PA3, PA4, PA5);
HardwareTimer pwmtimer3(3);
//int i ;
void setup() {
pinMode(PA6, INPUT_ANALOG);
lcd.begin(16, 2);
pinMode(PB0, PWM);

pwmtimer3.pause();
pwmtimer3.setPrescaleFactor(72); // Timer input clock Prescaler = 1MHz 72MHz
pwmtimer3.setOverflow(1000 - 1);
pwmtimer3.setCompare(TIMER_CH3, 500); // PWM High Pulse width is 50% duty (1:1)
pwmtimer3.refresh();
pwmtimer3.resume();
delay(10);
pwmtimer3.pause();
pwmtimer3.setPrescaleFactor(72); // Timer input clock Prescaler = 1MHz 72MHz
pwmtimer3.setOverflow(100 - 1);
pwmtimer3.setCompare(TIMER_CH3, 50); // PWM High Pulse width is 50% duty (1:1)
pwmtimer3.refresh();
pwmtimer3.resume();

}

void loop() {
/*
pwmtimer3.pause();
pwmtimer3.setPrescaleFactor(72); // Timer input clock Prescaler = 1MHz 72MHz
pwmtimer3.setOverflow(1000 - 1);
pwmtimer3.setCompare(TIMER_CH3, 500); // PWM High Pulse width is 50% duty (1:1)
pwmtimer3.refresh();
pwmtimer3.resume();
delay(10);
pwmtimer3.pause();
pwmtimer3.setPrescaleFactor(72); // Timer input clock Prescaler = 1MHz 72MHz
pwmtimer3.setOverflow(100 - 1);
pwmtimer3.setCompare(TIMER_CH3, 50); // PWM High Pulse width is 50% duty (1:1)
pwmtimer3.refresh();
pwmtimer3.resume();
*/
/*
float volt = analogRead(PA6);
volt = (volt * 3.3) / 4095.0;
lcd.setCursor(0, 0);
lcd.print(volt);
delay(100);
*/
}


edogaldo
Thu Sep 06, 2018 7:23 am
Said that you are not waiting for 250ms but for 10, which is the outcome you see?

ted
Thu Sep 06, 2018 10:54 am
I put 250 – the same results, only one frequency appears on PB0, when I am using setup frequency is from the this line.
pwmtimer3.setOverflow(100 - 1);

edogaldo
Thu Sep 06, 2018 11:37 am
Try this:
#include <LiquidCrystal.h>
LiquidCrystal lcd(PA0, PA1, PA2, PA3, PA4, PA5);
HardwareTimer pwmtimer3(3);
//int i ;
void setup() {
pinMode(PA6, INPUT_ANALOG);
lcd.begin(16, 2);
pinMode(PB0, PWM);
}

void loop() {
pwmtimer3.pause();
pwmtimer3.setPrescaleFactor(72); // Timer input clock Prescaler = 1MHz 72MHz
pwmtimer3.setOverflow(1000 - 1);
pwmtimer3.setCompare(TIMER_CH3, 500); // PWM High Pulse width is 50% duty (1:1)
pwmtimer3.refresh();
pwmtimer3.resume();
delay(1000);
pwmtimer3.pause();
pwmtimer3.setPrescaleFactor(72); // Timer input clock Prescaler = 1MHz 72MHz
pwmtimer3.setOverflow(100 - 1);
pwmtimer3.setCompare(TIMER_CH3, 50); // PWM High Pulse width is 50% duty (1:1)
pwmtimer3.refresh();
pwmtimer3.resume();
delay(1000);
}


stevestrong
Thu Sep 06, 2018 11:38 am
There is already a Timer3 instance of the HardwareTimer(3) defined in the core, and I would suggest you to use that one, and do not declare a new one.
So replace in your code pwmtimer3 with Timer3.

Furthermore, you don’t need to stop and restart the timer each time you change the compare value.
You don’t have to set the prescale factor each time.
It is enough to set it once in the setup
//HardwareTimer pwmtimer3(3); // - not needed

// in setup:
Timer3.setPrescaleFactor(72);
...
// in loop, when you want to change the frequency and/or duty cycle.
...
Timer3.pause();
Timer3.setOverflow(TIMER_CH3, <2*value-1>);
Timer3.setCompare(TIMER_CH3, <value>);
Timer3.refresh();
Timer3.resume();
...


ted
Thu Sep 06, 2018 12:32 pm
@ edogaldo
It is working, two frequencies are switching every 1 sec.
blinking LED = blinking generator. :lol:
How this can be used for VCO ?

ted
Thu Sep 06, 2018 12:42 pm
@ stevestrong.
I did, like that, and have some errors. Your approach is similar to my in the first post, you changed “i” to “value”, I think will work after removing the errors.
The errors
vco_dc_-stevestrong:16: error: expected initializer before 'void'

void loop() {

^

C:\Users\OWNER\Desktop\vco_dc_-stevestrong\vco_dc_-stevestrong.ino: In function 'void loop()':

vco_dc_-stevestrong:23: error: 'value' was not declared in this scope

value == volt;

^

vco_dc_-stevestrong:26: error: expected primary-expression before '<' token

Timer3.setOverflow(TIMER_CH3, <2*value-1>);

^

vco_dc_-stevestrong:26: error: expected primary-expression before ')' token

Timer3.setOverflow(TIMER_CH3, <2*value-1>);

^

vco_dc_-stevestrong:27: error: expected primary-expression before '<' token

Timer3.setCompare(TIMER_CH3, <value>);

^

vco_dc_-stevestrong:27: error: expected primary-expression before ')' token

Timer3.setCompare(TIMER_CH3, <value>);

^

Multiple libraries were found for "LiquidCrystal.h"
Used: C:\Users\OWNER\AppData\Local\Arduino15\packages\stm32duino\hardware\STM32F1\2018.1.3\libraries\LiquidCrystal
Not used: C:\Users\OWNER\Documents\Arduino\libraries\Newliquidcrystal_1.3.5
Not used: C:\Users\OWNER\Desktop\183\arduino-1.8.3\libraries\LiquidCrystal
Using library LiquidCrystal in folder: C:\Users\OWNER\AppData\Local\Arduino15\packages\stm32duino\hardware\STM32F1\2018.1.3\libraries\LiquidCrystal (legacy)
exit status 1
expected initializer before 'void'


ted
Thu Sep 06, 2018 12:44 pm
[stevestrong – Thu Sep 06, 2018 11:38 am] –
how do you verify the resulting frequency on PB0? With a scope?

Yes.


stevestrong
Thu Sep 06, 2018 12:55 pm
You forgot to put semicolon to end of line with:
//int i ;
int value // --- missing ";" -----

edogaldo
Thu Sep 06, 2018 1:09 pm
Try this:
//http://www.stm32duino.com/viewtopic.php?f=19&t=4082
//edogaldo

#include <LiquidCrystal.h>
LiquidCrystal lcd(PA0, PA1, PA2, PA3, PA4, PA5);

int ain;
int ovfDiv2;
float volt;

void setup() {
pinMode(PA6, INPUT_ANALOG);
lcd.begin(16, 2);
pinMode(PB0, PWM);
Timer3.setPrescaleFactor(72);
}

void loop() {
ain = analogRead(PA6);
ovfDiv2 = map(ain,0,4095,50,5000); // freq between 100Hz and 10kHz: ain=0 -> freq=100Hz - ain=4095 -> freq=10kHz
Timer3.pause();
Timer3.setOverflow(2*ovfDiv2-1);
Timer3.setCompare(TIMER_CH3, ovfDiv2);
Timer3.refresh();
Timer3.resume();
volt = (ain * 3.3) / 4095.0;
lcd.setCursor(0, 0);
lcd.print(volt);
delay(100);
}


ted
Thu Sep 06, 2018 1:52 pm
Frequency changing for voltmeter input 0V to 3.3V
0V – 1.2V = 120Hz-30Hz.
1.2V – 2.7V = no pulses
2.7V – 2.8V = toy music -on speaker
2.8V -3.3V = 200 Hz – 40 Hz

ted
Thu Sep 06, 2018 2:26 pm
I changed this line.
//ovfDiv2 = map(ain,0,50,4095,5000); // freq between 10KHz and 100Hz
ovfDiv2 = ain; // freq between 10KHz and 100Hz

edogaldo
Thu Sep 06, 2018 2:31 pm
I changed the function later:
ovfDiv2 = map(ain,0,4095,50,5000); // freq between 100Hz and 10kHz: ain=0 -> freq=100Hz - ain=4095 -> freq=10kHz

edogaldo
Thu Sep 06, 2018 2:35 pm
Sorry:
ovfDiv2 = map(ain,0,4095,5000,50); // freq between 100Hz and 10kHz: ain=0 -> freq=100Hz - ain=4095 -> freq=10kHz

ted
Thu Sep 06, 2018 2:51 pm
0V- 1V = 100Hz, 1V-2V = 200Hz, 2.5V-3.3V 400hz -10000Hz.
Frequency is not much changing for input 0V to 2.5V

ted
Thu Sep 06, 2018 3:17 pm
edogaldo
Thanks
I play with the numbers and looks I can get proper response however the sound is not that pure as using VCO build on NE555.
Probably I need averaging “ain”.

stevestrong
Thu Sep 06, 2018 3:20 pm
The reversal function is not correct.
You should use this one:
ovfDiv2 = 5050 - map(ain,0,4095,50,5000); // freq between 100Hz and 10kHz: ain=0 -> freq=100Hz - ain=4095 -> freq=10kHz

ted
Thu Sep 06, 2018 3:55 pm
I did averaging, the last digit on LCD is stable, however this not affect yet quality of the sound.
//http://www.stm32duino.com/viewtopic.php?f=19&t=4082
//edogaldo

#include <LiquidCrystal.h>
LiquidCrystal lcd(PA0, PA1, PA2, PA3, PA4, PA5);

int ain;
int ovfDiv2;
float volt;
unsigned int total; // can hold max 64 readings

void setup() {
pinMode(PA6, INPUT_ANALOG);
lcd.begin(16, 2);
pinMode(PB0, PWM);
Timer3.setPrescaleFactor(72);
}

void loop() {
////////////////////
for (int x = 0; x < 64; x++) { // multiple analogue readings for averaging
total = total + analogRead(PA6); // add each value to a total
}
volt = (total / 64.0) * 3.3; // convert readings to volt
//////////////////////
ain = analogRead(PA6);
//ovfDiv2 = map(ain,0,50,4095,5000); // freq between 10KHz and 100Hz
//ovfDiv2 = map(ain,0,1000,10000,0); // freq between 100Hz and 10kHz: ain=0 -> freq=100Hz - ain=4095 -> freq=10kHz
// ovfDiv2 = map(total,0,1000,10000,0);
// ovfDiv2 = ain/5; // freq between 10KHz and 100Hz
ovfDiv2 = map( total,0,50,4095,5000); // freq between 10KHz and 100Hz

Timer3.pause();
Timer3.setOverflow(2*ovfDiv2-1);
Timer3.setCompare(TIMER_CH3, ovfDiv2);
Timer3.refresh();
Timer3.resume();
// volt = (ain * 3.3) / 4095.0;
volt = (total /64.0)* 3.3 / 4095.0;
lcd.setCursor(0, 0);
lcd.print(volt);
total = 0; // reset value
delay(10);
}


ted
Thu Sep 06, 2018 4:19 pm
for Uin 0V -1V = 100 Hz, changing the voltage is changing the pulse width not frequency, then frequency is doubled (1V-2V) and the same only pulse with is responding to voltage changes and so on. Frequency jumping steps are decreasing after 2V.
//http://www.stm32duino.com/viewtopic.php?f=19&t=4082
//edogaldo

#include <LiquidCrystal.h>
LiquidCrystal lcd(PA0, PA1, PA2, PA3, PA4, PA5);

int ain;
int ovfDiv2;
float volt;

void setup() {
pinMode(PA6, INPUT_ANALOG);
lcd.begin(16, 2);
pinMode(PB0, PWM);
Timer3.setPrescaleFactor(72);
}

void loop() {
ain = analogRead(PA6);
// ovfDiv2 = map(ain,0,4095,50,5000); // freq between 100Hz and 10kHz: ain=0 -> freq=100Hz - ain=4095 -> freq=10kHz
ovfDiv2 = 5050 - map(ain,0,4095,50,5000); // freq between 100Hz and 10kHz: ain=0 -> freq=100Hz - ain=4095 -> freq=10kHz
Timer3.pause();
Timer3.setOverflow(2*ovfDiv2-1);
Timer3.setCompare(TIMER_CH3, ovfDiv2);
Timer3.refresh();
Timer3.resume();
volt = (ain * 3.3) / 4095.0;
lcd.setCursor(0, 0);
lcd.print(volt);
delay(10);
}


edogaldo
Thu Sep 06, 2018 4:41 pm
Try to explain the relationship you would expect between the voltage and the frequency.

ted
Thu Sep 06, 2018 5:06 pm
@stevestrong
100Hz all the time, pulse duty is changing smoothly from 50% to 0%, nice and stable signal, now I need to change this to make frequency changes not the width ?

ted
Thu Sep 06, 2018 5:09 pm
[edogaldo – Thu Sep 06, 2018 4:41 pm] –
Try to explain the relationship you would expect between the voltage and the frequency.

smooth frequency changes


stevestrong
Thu Sep 06, 2018 5:22 pm
int ovfDiv = 5050 - ain;
Timer3.pause();
Timer3.setOverflow(ovfDiv-1);
Timer3.setCompare(TIMER_CH3, ovfDiv/2);
Timer3.refresh();
Timer3.resume();

ted
Thu Sep 06, 2018 5:53 pm
from 0V to 0.5V = 10000 Hz – 800 Hz, frequency is changing not bad, from 0.5V to 3.3V frequency is changing slower and the pulse width is more effective by voltage changes.

ted
Thu Sep 06, 2018 6:07 pm
from 0V to 1V only the width is changing, after that frequency is changing not bad ( 300 Hz-1000hz.)

edogaldo
Thu Sep 06, 2018 6:54 pm
try this:
ovfDiv2 = 500000/map(ain,0,4095,100,10000); // freq between 100Hz and 10kHz: ain=0 -> freq=100Hz - ain=4095 -> freq=10kHz
Timer3.pause();
Timer3.setOverflow(2*ovfDiv2-1);
Timer3.setCompare(TIMER_CH3, ovfDiv2);
Timer3.refresh();
Timer3.resume();

ted
Thu Sep 06, 2018 9:14 pm
@ edogaldo
Perfect, 100Hz-10 000Hz, starts responding @ 0.05V = very sensitive and accurate.
@ 0.05V , the first pulse is stable, next 3 pulses are shaking a little bit and the 4th is again stable, for another voltages similar, this is giving sound not very pure bat acceptable.
thanks guys for helping.

ted
Thu Sep 06, 2018 9:24 pm
what is it the magic number 500 000 ?

edogaldo
Thu Sep 06, 2018 10:23 pm
You set the timer clock to 1MHz so your period (in us) is 1000000/freq and half period (50% duty cycle) is (1000000/freq)/2=500000/freq.

Leave a Reply

Your email address will not be published. Required fields are marked *