|
|
View previous topic :: View next topic |
Author |
Message |
Shaheers
Joined: 23 Sep 2013 Posts: 14
|
I got very slow response, help |
Posted: Sat Nov 30, 2013 2:53 pm |
|
|
Sir just make a solid state switch that switch over among two power sources while active source goes down,
The main problem is that i got a large enough delay to switch over,
REMEMBER plz there is two do-while loops, working for two sources, when i used only first loop. I can switch over Source A to B quickly,
but when i write a secound part of code for switch to Source B to A, it works but slow enough, i dont know what happens there.
here is a code
Code: |
#include <Static_sw.h>
#include "flex_lcd.c" //Mdified lcd file, only contained in project directory
int1 lcd_volt_flag=0;
//=========Timer0 intrupt====================
#define R1 1.7 //Range 1
#define R2 1.8 //Range 2
#define R3 1.9 //Range 3
#define R4 2.0 //Range 4
#define R5 2.1 //Range 5
#define R6 2.2 //Range 6
#define R7 2.3
#define R8 2.4
#define R9 2.5
#define R10 2.7
#define R11 2.8
#define R12 2.9
#define R13 3.0
#define R14 3.1
#define R15 3.2
#define R16 3.3
int range(float a)
{
if(a>R4 && a<=R5)
{
return 5;
}
else if(a>R5 && a<=R6)
{
return 6;
}
if(a<=R1 )
{
return 1;
}
else if(a>R1 && a<=R2)
{
return 2;
}
else if(a>R2 && a<=R3)
{
return 3;
}
else if(a>R3 && a<=R4)
{
return 4;
}
if(a>R4 && a<=R5)
{
return 5;
}
else if(a>R5 && a<=R6)
{
return 6;
}
else if(a>R6 && a<=R7)
{
return 7;
}
else if(a>R7 && a<=R8)
{
return 8;
}
else if(a>R8 && a<=R9)
{
return 9;
}
else if(a>R9 && a<=R10)
{
return 10;
}
else if(a>R10 && a<=R11)
{
return 11;
}
else if(a>R11 && a<=R12)
{
return 12;
}
else if(a>R12 && a<=R13)
{
return 13;
}
else if(a>R13 && a<=R14)
{
return 14;
}
if(a>R14 && a<=R15)
{
return 15;
}
else if(a>R15 && a<=R16)
{
return 16;
}
else if(a>R16)
{
return 17;
}
}
void main()
{
setup_adc_ports(AN0_AN1_AN3);
setup_adc(ADC_CLOCK_DIV_64);
set_adc_channel(Output); // Built-in A/D setup function
int16 sample;
int16 max=0;
int16 min=65335;
float value;
float maximum=0.0;
float volt=0.0;
unsigned int8 i=0;
int val[3]={10,11,12};
int1 inc=0;
int1 lcd_flag=0;
lcd_init(); // LCD initilized
lcd_putc("\fAslam-u-Alicum!");
delay_ms(500);
//==========Main Program============
for(;;)
{
do {
output_low(L2);
delay_ms(100);
output_high(L1);
if(lcd_flag==0)
{
lcd_gotoxy(1,1);
lcd_putc("Primery Supply:");
lcd_flag=1;
}
sample = read_adc(); // Built-in A/D read function
delay_us(400);
if(max<=sample)
{
max=sample;
}
else if(min>=sample)
{
min=sample;
}
value=sample*0.004887585532746823069403714565;
val[0]=range(value);
if(val[0]==val[1])
{
delay_us(100);
sample = read_adc();
value=sample*0.004887585532746823069403714565;
val[1]=range(value);
if(val[0]==val[1])
{
i++;
}}
else if(val[0]!=val[1])
{
val[1]=val[0];
i=0;
}
if(i>=3)
{
inc=1;
lcd_flag=0;
lcd_volt_flag=0;
break;
}
maximum=max*0.004887585532746823069403714565; // divide by 1023
volt=(2.5-maximum)*438.571428; // convert to mains voltages
lcd_gotoxy(1,2);
printf(lcd_putc, " %4.4f", volt);
}while(!inc);
do{
output_low(L1);
delay_us(100);
output_high(L2);
if(lcd_flag==0)
{
lcd_gotoxy(1,1);
lcd_putc("Alternate Supply:");
lcd_flag=1;
}
sample = read_adc(); // Built-in A/D read function
delay_us(400);
if(max<=sample)
{
max=sample;
}
else if(min>=sample)
{
min=sample;
}
value=sample*0.004887585532746823069403714565;
val[0]=range(value);
if(val[0]==val[1])
{
delay_us(100);
sample = read_adc();
value=sample*0.004887585532746823069403714565;
val[1]=range(value);
if(val[0]==val[1])
{
i++;
}}
else if(val[0]!=val[1])
{
val[1]=val[0];
i=0;
}
if(i>=3)
{
inc=0;
break;
}
maximum=max*0.004887585532746823069403714565; // divide by 1023
volt=(2.5-maximum)*438.571428; // convert to mains voltages
lcd_gotoxy(1,2);
printf(lcd_putc, " %4.4f", volt);
}while(inc);
}}
|
|
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
Simplify simplify, simplify. |
Posted: Sat Nov 30, 2013 4:44 pm |
|
|
It's difficult to tell what you're expecting the code to do.
There are no useful comments to help.
I don't care to work through it in detail.
You appear to be working though a series of tests using floats.
Floats are notoriously slow.
If you do a return after most of the tests you'll get a response which is much slower than if you return after only a few tests.
Use say MPLAB to find out how long the various paths through your tests take.
Then compare those times to what you get in practice.
You don't actually tell us what the delays are.
Above all I suggest you both simplify what you're doing and avoid floats.
Mike |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Sat Nov 30, 2013 6:15 pm |
|
|
Mike is right !
You're best to get rid of floating point math. Read up about 'scaled integers', a topic covered here several times.
You refer to 'mains voltage' which I assume is 240 volts.If you use an 8bit integer to be 'volts', it'll be good up to 255 volts, so 1 bit equals 1 volt.
8bit integer math is super fast compared to floats.
Also as you are using 'mains voltage' please be very,very careful with connections !!!
hth
jay |
|
|
Shaheers
Joined: 23 Sep 2013 Posts: 14
|
|
Posted: Sat Nov 30, 2013 11:04 pm |
|
|
Thanks for reply both of you,
actually i am measuring the AC voltages by using following arrangement
using op-amp i am down grading voltage to TTL level and after that measuring it, when mains power is off the output of op-amp output is 2.5volts
on power is available its about say 2.5+1 and 2.5-1 volts
series of test checks that weather the volts are varying or not
the hardware i use is describe in following link
http://www.paulmonigatti.com/2011/09/reading-ac-voltages-with-a-microcontroller/ |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Sun Dec 01, 2013 3:45 am |
|
|
Ongoing, a 'float', in CCS, has typically 6.5 digits of accuracy. You have values with like 20digits involved. Totally pointless. Worse, the values are just wrong as well. Do a bit of research on the transfer function of the PIC ADC, and find 'why' you do not want to divide by 1023.
Remember every float value test involves a float subtraction. Doing this against two values, two subtractions.
With a bit of thought, scaled integers will give you _better_ results, and a lot quicker too. Remember that unless you are paying a premium price, the odds are that every resistor in your division etc., is only 1% accurate, so trying to use huge accuracies is totally pointless.
Though not 'great', since it still involves one float multiplication, this should be a 'drop in' replacement for your 'range' function. Think about what it'll give:
Code: |
int range(float a)
{
int rnum;
signed int16 ival;
ival=a*10.4999;
ival-=17;
if (ival<=0) return 1;
for (rnum=2; rnum<17;rnum++)
{
ival--;
if (ival<=0) return rnum;
}
return rnum;
}
|
Preferably though redesign your maths throughout, to use integers from the start.
Best Wishes |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sun Dec 01, 2013 5:06 am |
|
|
The range() function now uses all regular intervals and can be simplified to: Code: | int range(float a)
{
if (a <= 1.7)
{
return 1;
}
if (a > 3.3)
{
return 17;
}
return (a - 1.7) * 10;
} |
Now, coming back to the earlier mentioned 'scaled integers' method you can improve the performance dramatically.
You are comparing the float values with only 1 digit after the dot. If you multiply all the float values by 10, then you have values with no important digits after the dot. Hey... that means you can remove all those digits and just use integer math! That's the 'scaled integer' method.
Only on presentation to the user you have to convert the multiplied integer value back to a float representation again. Think about it like calculating in dollars or in cents. $1.23 is a float value. 123 cents is an integer. Both are equal value but integer arithmetic is 100 times more efficient for the PIC processor. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Sun Dec 01, 2013 1:15 pm |
|
|
As a general comment, you need to rethink your basic approach.
You need something like a single loop, reading the ADC, and scaling it.
This then advances to a state machine. This decides what to 'do' with the value. For delays, start a timer, then advance a state. In the next state check for the timer having expired, and until this happens _keep looping_. The whole point is you don't actually 'delay' anywhere. As it's prime job, this machine tests for the events that need to make things happen _before_ doing anything else.
Either use custom timers, started as outlined, or have a single 'tick' interrupt at (say) 10mSec, then have a variable that is decremented until it is zero in this. So a 400mSec delay would be done by loading this variable with '40', and then looping waiting till this gets to 0.
The whole point is that checking for things that must happen quickly, happens all the time, whatever else is going on.
Best Wishes |
|
|
Shaheers
Joined: 23 Sep 2013 Posts: 14
|
|
Posted: Wed Dec 04, 2013 11:55 am |
|
|
Thank you very very much, one more point that can I count frequency from that arrangement, I mean by giving the stepdowned mains sinusoidal voltage at counter input or CCP module or I need it to convert to square wave first |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Wed Dec 04, 2013 12:07 pm |
|
|
You need to convert to a square wave first.
Also be sure to isolate the mains voltage from the PIC usually using an optocoupler ( typ: 4N35) fed into a comparator to get clean waveforms.
Have a 'Google' at typical circuits,some will just use transistors or opamps.
Since you already have an opamp, maybe a spare section can be used?
hth
jay |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|