Hello! I am making this high powered inverter that will be able to change the frequency, amplitude and switching frequency of the output "sinne" wave, to power a welder.......
I have integrated this code in my project somewhat successfully, because I find it much easier to learn by scripting and deducing, but this is way too advanced for me. I can somewhat understand the internal timer control and math.
(SPWM Timing Issue [SOLVED])
What I wanted to ask you about is this form of writing variables: int setSwitchFreq(int sfreq); and how would one go about changing or displaying them without a workaround.
I found out to use normal variable for setting For example: int Output , and then writing setAmp(Output); in the loop to then set it. In the project I need the Output variable due to other parts of the code (pid library for the most part) but I would like to avoid writing two more just for setting the frequencies...
Like I said I am pretty noobish at coding, but I need to learn, and best is by doing
#include <avr/io.h>
#include <avr/interrupt.h>
#define LookupEntries (512)
static int microMHz = 16; // clock frequency in MHz
static int freq, amp = 1024;// Sinusoidal frequency
static long int period; // Period of PWM in clock cycles. 1600 gives 10KHz.
static unsigned int lookUp[LookupEntries];
static char theTCCR1A = 0b10000010; //varible for TCCR1A
static unsigned long int phaseinc, switchFreq;
static double phaseincMult;
int setFreq(int freq); //set in Hertz
int setSwitchFreq(int sfreq); //set in Hertz
int setAmp(float _amp); //set in % (0 - 100)
void makeLookUp(void);
void registerInit(void);
void setup(){
Serial.begin(9600);
makeLookUp();
setSwitchFreq(10000);
setFreq(50);
setAmp(100);
registerInit();
}
void loop(){
/*
The code in the loop reads analog values from pins A1 and A2 so that potentiometers can be connected.
These values are used to vary the amplitude and frequency of the sine wave.
The switching frequency also toggles between 5 and 15Khz.
*/
}
ISR(TIMER1_OVF_vect){
static unsigned long int phase, lastphase;
static char delay1, trig = LOW;
phase += phaseinc;
if(delay1 == 1){
theTCCR1A ^= 0b10100000;// Toggle connect and disconnect of compare output A and B.
TCCR1A = theTCCR1A;
delay1 = 0;
}
else if((phase>>31 != lastphase>>31) && !(phase>>31)){
delay1++;
trig = !trig;
digitalWrite(13,trig);
}
lastphase = phase;
OCR1A = OCR1B = ((lookUp[phase >> 23]*period) >> 12)*amp >> 10;
}
int setFreq(int _freq){
if(_freq < 0 || _freq > 1000){ // returns -1 if the frequency value is invalid
return 0;
} else {
freq = _freq;
phaseinc = (unsigned long int) phaseincMult*_freq;
return 1;
}
}
int setSwitchFreq(int sfreq){
double temp;
if(sfreq <= 0 || sfreq > 20000){
return 0;
} else {
switchFreq = sfreq;
period = microMHz*1e6/sfreq;
//sindevisions*decimalbits/1MHz =
//1024*2^23/1e6 = 8,589.934592
phaseincMult = (double) period*8589.934592/microMHz;
phaseinc = (unsigned long int) phaseincMult*freq;
ICR1 = period;
}
}
int setAmp(float _amp)
{
if(_amp < 0 || _amp > 100){
return 0;
} else {
amp = map(_amp,0,100,0,1024);
return 1;
}
}
void makeLookUp(void){
double temp;
cli(); //disable global interupts while lookup table is made
TCCR1A = 0b00000010; //disconnect compare A and B while lookup table is generated
for(int i = 0; i < LookupEntries; i++){ // Generating the look up table.
temp = sin(i*M_PI/LookupEntries)*4096;
lookUp[i] = (int)(temp+0.5); // Round to integer.
}
TCCR1A = theTCCR1A; // reconnect compare outputs
sei(); //re-enable interupts now that table has been made
}
void registerInit(void){
// Register initilisation, see datasheet for more detail.
TCCR1A = theTCCR1A; // 0b10000010;
/*10 clear on match, set at BOTTOM for compA.
00 compB disconected initially, toggled later to clear on match, set at BOTTOM.
00
10 WGM1 1:0 for waveform 15.
*/
TCCR1B = 0b00011001;
/*000
11 WGM1 3:2 for waveform 15.
001 no prescale on the counter.
*/
TIMSK1 = 0b00000001;
/*0000000
1 TOV1 Flag interrupt enable.
*/
sei(); // Enable global interrupts.
// Set outputs pins.
DDRB = 0b00000110; // Set PB1 and PB2 as outputs.
pinMode(13, OUTPUT); // Set trigger pin to output
}
well there's a lot of abstract stuff to read, and I need to get this done for a college project, I'm expected to reference and compile, It just needs to work for now, I will learn everything eventualy.
so basically I would need to print values from the function definition? will that slow down the process more or less then to write variables for the main loop and just transfer them like I did
I am running about 85% uno ram as it is
You did not share your complete sketch, so we cannot see where freq is stored... or where it is comming from...
Edit: you did share that...
My guess is that the setFreq() function sets some registers based on the argument freq.
You could read those registers and derive the set frequency... but why not use or store the freq value that is sent to this function???
const int freq = 50;
setFreq(freq);
Serial.println(freq);
but If i was to edit it in loop, I would need to make another variable, set it and then repeat the comand from setup, with said variable instead of numbers, i did that with frequancy actually, but I can't find the one for switching, and i figured if i did that then a part of the function here would be useless since I already got the constraints for setting it=?
I can't ie LCD.print(setFreq) sais its not declared
but i can ie int X
then do whatever I want with that
and in loop
setFreq(x);
or i can change the freq, but would that ignore a part of the function that includes setFreq
also if thats ok, do I just declare sfreq together with freq for switching frequency, as that one is i think not global
right, I managed to do that, so the variable here is freq while sfreq is Function prototype, then i just have to declare sfreq for switching frequency as global variable and its done
I linked it, SathvikHegde posted it here, need to thank him when i get my welder to work, also I'm gonna post the full code when I fix it, it's a mess now...
Just figured out about building menus with strings, might drop half that ram usage...
lol right, then I just remove constraints, cos i got them already for button action
this is actually way simpler then I thought, just unfamiliar syntax since I never used function prototypes before, might make probe reading and averaging simmilar while I'm at it
Function prototypes are necessary in standard C++ to tell the compiler that the function exists and what type of parameters it needs. Later in the program the function is defined with the code that it contains as well as the parameters
The Arduino environment hides the process from you by creating function prototypes if they have not been included explicitly. This was one of the things done to make the Arduino environment more friendly than the standard C++ framework for non programmers
SUMMARY :
Function prototypes are not generally necessary in Arduino sketches (except in some special cases) but it does no hard to include them if you want to
Y actually looking at the whole thing now, I wont even need much of it since it was done here just to translate analog inputs from pots, i wont need to map because I will be setting everything with buttons, afraid to mess with the unknown I guess, how stupid of me
thanks guys
this might do the trick:
#include <avr/io.h>
#include <avr/interrupt.h>
#define LookupEntries (512)
static int microMHz = 16; // clock frequency in MHz
static int freq=50, amp = 0;// Sinusoidal frequency,set in Hertz, Sinusoidal amplitude set 0-100
static long int period; // Period of PWM in clock cycles. 1600 gives 10KHz.
static unsigned int lookUp[LookupEntries];
static char theTCCR1A = 0b10000010; //varible for TCCR1A
static unsigned long int phaseinc, switchFreq=10000; //set in Hertz
static double phaseincMult;
int setFreq(int freq);
int setSwitchFreq(int sfreq);
void makeLookUp(void);
void registerInit(void);
void setup(){
makeLookUp();
registerInit();
}
void loop(){
/*
The code in the loop reads buttons and runns display
*/
}
ISR(TIMER1_OVF_vect){
static unsigned long int phase, lastphase;
static char delay1, trig = LOW;
phase += phaseinc;
if(delay1 == 1){
theTCCR1A ^= 0b10100000;// Toggle connect and disconnect of compare output A and B.
TCCR1A = theTCCR1A;
delay1 = 0;
}
else if((phase>>31 != lastphase>>31) && !(phase>>31)){
delay1++;
trig = !trig;
digitalWrite(13,trig);
}
lastphase = phase;
OCR1A = OCR1B = ((lookUp[phase >> 23]*period) >> 12)*amp >> 10;
}
int setFreq(int _freq){
phaseinc = (unsigned long int) phaseincMult*freq;
return 1;
}
int setSwitchFreq(int sfreq){
double temp;
period = microMHz*1e6/switchFreq
//sindevisions*decimalbits/1MHz =
//1024*2^23/1e6 = 8,589.934592
phaseincMult = (double) period*8589.934592/microMHz;
phaseinc = (unsigned long int) phaseincMult*freq;
ICR1 = period;
}
void makeLookUp(void){
double temp;
cli(); //disable global interupts while lookup table is made
TCCR1A = 0b00000010; //disconnect compare A and B while lookup table is generated
for(int i = 0; i < LookupEntries; i++){ // Generating the look up table.
temp = sin(i*M_PI/LookupEntries)*4096;
lookUp[i] = (int)(temp+0.5); // Round to integer.
}
TCCR1A = theTCCR1A; // reconnect compare outputs
sei(); //re-enable interupts now that table has been made
}
void registerInit(void){
// Register initilisation, see datasheet for more detail.
TCCR1A = theTCCR1A; // 0b10000010;
/*10 clear on match, set at BOTTOM for compA.
00 compB disconected initially, toggled later to clear on match, set at BOTTOM.
00
10 WGM1 1:0 for waveform 15.
*/
TCCR1B = 0b00011001;
/*000
11 WGM1 3:2 for waveform 15.
001 no prescale on the counter.
*/
TIMSK1 = 0b00000001;
/*0000000
1 TOV1 Flag interrupt enable.
*/
sei(); // Enable global interrupts.
// Set outputs pins.
DDRB = 0b00000110; // Set PB1 and PB2 as outputs.
pinMode(13, OUTPUT); // Set trigger pin to output
}
If you do not call those functions, your sketch will not work, as the parameters are not set.
I.e. ICR1 and phaseinc.
It seems you really need to learn how to read a program.
A prototype or function will do nothing if they are not called in setup or loop...
Also this sketch is 'spaghetti code'...
It is, but it works , sry, I posted bit wrong, setSwitchFreq(0); setFreq(0); is still called in setup but I change variables directly now instead of setting them from call, so here is just 0, probably will change them to functions later because I don't like it this way.
I just jumbled prototype name with variable, because I never seen it in arduino, and I'm far from a C++ programmer, glad I got it cleared up, also progmemed the menu, and dropped the ram from 87% to 60.
SPWM code that can change amplitude is very hard to find, and critical for the type of inverter I built
and this is the second arduino project I ever did, first one was a triac controller using 0 cross for interrupt, very good for resistive, not so good for inductive load, I feel like I learned more about electronics and programming in a month doing solo work then in highscool and college combined, shitty theory only school system you can never see how it all comes together or the different applications of the stuff you recite...