 |
www.elektronik.si Forum o elektrotehniki in računalništvu
|
Poglej prejšnjo temo :: Poglej naslednjo temo |
Avtor |
Sporočilo |
bigmedo Neznanec

Pridružen-a: Čet 04 Nov 2010 22:41 Prispevkov: 1 Aktiv.: 0.01 Kraj: Dobrepolje
|
Objavljeno: Čet Mar 28, 2013 10:30 pm Naslov sporočila: W-meter in števec porabe s PIC16F877A |
|
|
Za maturo sem se odločil izdelat W-meter in števec porabe. Tok merim z hallovo sondo, usmerim jo z OPAMP-om in integratorjem. To gre na 1. analogni vhod PIC-a.
Na 2. an. vhodu merim napetost preko trafo-greatz-2 kondija-2 enaka upora. Padec napetosti na enem izmed uporov peljem na PIC.
Zatakne se pri programu. Programiram v mikroC Pro. Če imam vse spremenljivke v unsigned int obliki potem sta 2 manjša problema. Če katera izmed vrednosti preseže 32000 se pred njo postavi "-" in se začne čudno odštevati. Poleg tega spremenljivla char zahteva vsaj 7 znakov in številke postavi na zadnja mesta (desno)..kako bi jih lahko premaknil na levo?
Večji zaplet nastane ko vključim v program izračune za dejanske vrednosti. Te spremenljivke zahtevajo obliko float. Ko postavim vse potrebne spremenljivke v float pa mi vse številčne vrednosti na LCD-ju pokaže na 0.
Npr.... MOC: 0
Vendar je sedaj ta "0" pomaknjena na levo stran.
Kako bi tisti, ki ste bolj vešči in izkušeni v tem to rešili?
Za razumevanje bom priložil napisan program. Upam, da je program dosti logično in jasno napisan. Izračun za energijo še ni čisto pravilen, saj bo ta morala biti v kWh. prikazujem na LCD-ju 20x4.
Hvala za vaš čas in odgovore.
Koda: |
sbit LCD_RS at RD2_bit; //DEKLARACIJA LCD-ja
sbit LCD_EN at RD3_bit;
sbit LCD_D4 at RD4_bit;
sbit LCD_D5 at RD5_bit;
sbit LCD_D6 at RD6_bit;
sbit LCD_D7 at RD7_bit;
sbit LCD_RS_Direction at TRISD2_bit; //DEKLARACIJA LCD-ja
sbit LCD_EN_Direction at TRISD3_bit;
sbit LCD_D4_Direction at TRISD4_bit;
sbit LCD_D5_Direction at TRISD5_bit;
sbit LCD_D6_Direction at TRISD6_bit;
sbit LCD_D7_Direction at TRISD7_bit;
//spremenljivke
/*float tok=0, tok1=0, tok2=0, tok3=0, //tok
nap=0, nap1=0, nap2=0, nap3=0, //napetost
moc=0, // moč
ene=0; //energija*/
float tok=0, nap=0, moc=0, ene=0;
unsigned int tok1=0, tok2=0, tok3=0, nap1=0, nap2=0, nap3=0;
char moctxt[14];
char enetxt[14];
char naptxt[14];
char toktxt[14];
int test=0;
char testtxt[7];
//začetek programa
void main() {
TRISA=7; //analogna vhoda in ledice
TRISC=0; //???
TRISD=0; //tipke
TRISE=0; //ledice
adcon1=0x02; //adc
PORTA=0;
PORTB=0;
PORTC=0;
PORTD=0;
PORTE=0;
Lcd_Init();
Lcd_Cmd(_LCD_CURSOR_OFF);
UART1_Init(9600);
while(1){
nap1=ADC_read(0); //1. branje
tok1=ADC_read(1);
delay_ms(300);
nap2=ADC_read(0); //2. branje
tok2=ADC_read(1);
delay_ms(300);
nap3=ADC_read(0); //3. branje
tok3=ADC_read(1);
delay_ms(300);
nap=(nap1+nap2+nap3)/3; //izračuni za napetost
nap=(5/1024)*nap;
nap=nap*52;
tok=(tok1+tok2+tok3)/3; //izračuni za tok
tok=(5/1024)*tok;
tok=tok*100;
tok=tok/50;
moc=nap*tok; //izračuna za moč in energijo
ene=ene+moc;
IntToStr(moc, moctxt);
IntToStr(ene, enetxt);
intToStr(tok, toktxt);
intToStr(nap, naptxt);
//LCD
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,1,"MOC:");
Lcd_Out(2,1,"ENERGIJA:");
Lcd_Out(1,6, moctxt);
Lcd_Out(2,11,enetxt);
Lcd_Out(3,1,"NAPETOST:");
Lcd_Out(4,1,"TOK:");
Lcd_Out(3,11, naptxt);
Lcd_Out(4,6,toktxt);
nap1, nap2, nap3, nap, tok1, tok2, tok3, tok, moc=0;
test++; //testiranje pravilnosti delayev(cikel mora biti dolg 1s)
IntToStr(test, testtxt);
Lcd_Out(1,14,testtxt);
Lcd_Out(1,20,"s");
|
|
|
Nazaj na vrh |
|
 |
dumr666 Član


Pridružen-a: Tor 31 Jan 2012 23:30 Prispevkov: 409 Aktiv.: 2.51 Kraj: Ljubljana
|
Objavljeno: Čet Mar 28, 2013 10:46 pm Naslov sporočila: |
|
|
na pice se spoznam natanko 0 ampak vseeno. Si mogoče poskusil z nepredznačeno celoštevilsko vrednostjo? |
|
Nazaj na vrh |
|
 |
hahalolek Član


Pridružen-a: Sob 29 Maj 2010 11:49 Prispevkov: 199 Aktiv.: 1.09 Kraj: Domžale
|
Objavljeno: Čet Mar 28, 2013 11:08 pm Naslov sporočila: |
|
|
Če rabiš večjo številko lahko uporabiš unsigned long int , ki zasede 4 byte.
Ali spremeniš IntToStr() v FloatToStr(), ko spremeniš spremenljivko v float? _________________ Lp Blaž
Prvi poklic na svetu je bil električar. Še preden je bog rekel naj bo luč, so oni že kable napeljevali. |
|
Nazaj na vrh |
|
 |
igo Član

Pridružen-a: Sre 11 Okt 2006 19:11 Prispevkov: 3641 Aktiv.: 16.01
|
Objavljeno: Čet Mar 28, 2013 11:30 pm Naslov sporočila: |
|
|
1. Računi so dosti natančnejši, če najprej množiš, nato deliš. Obraten vrstni red povzroči izgubo ločljivosti, saj se nižji biti nadomeščajo z ničlami.
2. Uporabi 4 tokove in napetosti. Ko četverice sešteješ, rezultat premakneš desno za 2 bita in dobiš deljenje s 4.
3. Četverice ciklaj, da bo rezultat manj nihal.
Tok4 = Tok3
Tok3 = Tok2
Tok2 = Tok1
Tok1 = getADC() /* Tok1 je vedno zadnja meritev
4. Vrstici tok = tok * 100 in tok = tok / 50 nadomesti s tok = tok * 2 , bo manj izgub spodnjih bitov.
5. V čem je sploh problem, če je rezultat ADC največ 10-biten, pri izračunih pa se ne preseže 16 bitov? Več kot 16-bitna števila rabiš samo pri moči in končnih števcih porabljene energije. _________________ Teoretično je praksa posledica teorije, praktično je pa ravno obratno. (igo 2001)
LP, Igor |
|
Nazaj na vrh |
|
 |
forest70 Član


Pridružen-a: Ned 20 Jul 2008 1:00 Prispevkov: 588 Aktiv.: 2.86 Kraj: Koper
|
Objavljeno: Čet Mar 28, 2013 11:38 pm Naslov sporočila: |
|
|
uporabi sprintf !
char buff[16];
sprintf(buff,"%f",moc);
Lcd_Out(1,6,buff ); |
|
Nazaj na vrh |
|
 |
. Neznanec

Pridružen-a: Pet 01 Okt 2004 1:17 Prispevkov: 1 Aktiv.: 0.00
|
Objavljeno: Pet Mar 29, 2013 12:36 am Naslov sporočila: |
|
|
Brisana vsebina odstranjenega uporabnika. |
|
Nazaj na vrh |
|
 |
lojzek Član



Pridružen-a: Pet 25 Jan 2008 8:00 Prispevkov: 3387 Aktiv.: 16.00
|
Objavljeno: Pet Mar 29, 2013 7:42 am Naslov sporočila: |
|
|
Jaz sem sicer AVR-jevec, ampak princip odgovora je za oba enak.
Jaz se problemov s floati na daleč izognem z drugim pristopom. Uporabim int ali pa tudi long, če so cifre zelo velike. Mislim, da sem namreč tudi pri AVRju zasledil, da se float in sprintf ne marata prav preveč.
Osnova je, da izračunam dejanske vrednosti povečane za faktor recimo 10, 100 ali tudi 1000. Potem pa najprej izračunam celi del cifre, iz preostanka pa še decimalke in nato izpišem na ekran.
Za prikaz principa ti prilagam nekaj izsekov mojega programa, ki počne to, kar ti želiš. Ampak nikakor ne bo direktno uporabno pri tebi. Merim namreč do 40V in 7A, pa še v AVRjevem C jeziku je pisano.
Koda: |
/to so deklaracije spremenljivk na začetku/
volatile unsigned long I; //Izmerjen tok
volatile unsigned int R; //Izračunana upornost
volatile unsigned int P; //Izračunana moč
volatile unsigned int Ah; //Nastavljena kapaciteta
volatile signed int uAh;
volatile char tekst[17]; //Niz za izpis na ekran
/tukaj imaš, kako izračunam napetost in tok/
//Izračun pravih vrednosti iz tistega, kar preberem iz ADC-ja
// I [mA]
I = I / 3; //povprečenje
I = I * 757; //množenje s konstanto
I = I / 100; //sprememba v mA (npr 1120 = 1,12A)
// U [V×100]
U = U / 3; //povprečenje
U = U * 300; //množenje s konstanto
U = U / 100; //sprememba v V * 100 (npr. 100 = 1,00V)
U = U - ((I * 33)/1000); //odštej napetost na merilnem uporu za tok
// 33 pomeni upornost upora *100 -> = 0,33ohm
void Izpis () //Spremenjena v ver1
{
unsigned int u = U; //pomožne spremenljivke
unsigned int i = I;
unsigned long a; //pomaga pri izračunu decimalk (sprintf ne izpiše long)
//Najprej izpiši U in I v prvo vrsto
if (I < 1000) // izpiši tok v mA
{
sprintf (tekst, "U=%.2d.%.2dV I=%.3dmA\n",
u/100, u%100, i);
}
else
{
sprintf (tekst, "U=%.2d.%.2dV I=%.1d.%.2dA\n",
u/100, u%100, i/1000, (i%1000)/10);
}
LCDstring(tekst, 0,0); //Izpis napetosti in toka na poz. 0,0
// po potrebi (usmernik) v drugo vrsto izpiši R in P
if (bit_is_set (Flag, 2))
{
if ((U > 10) && (I > 7)) //izračun, če U ali I nista 0
{
if (I < U) // izpiši R v ohm (večje upornosti)
{
a = (U*100)/I; //izračun upornosti R*10
i = a;
sprintf (tekst, "%.4d.%dô", i/10, i%10);
//prvi del vsake vrstice je izračun celega dela cifre, drugi pa decimalke upornosti/moči
//gornja vrstica lepo računa R
}
else
{ // manjše upornosti
a = U*10000/I; //izračun upornosti R*1000
i = a;
sprintf (tekst, "%.2d.%.3dô", i/1000, i%1000);
}
LCDstring(tekst, 0,1); //izpiši upornost
if (I * U < 100000) // izpiši moč v mW
{
sprintf (tekst, " %.3dmW\n", (U*I)/100);
//prvi del vsake vrstice je izračun celega dela cifre, drugi pa decimalke upornosti/moči
//gornja vrstica lepo računa R
}
else
{ // izpiši moč v W
a = (U/10)*(I/10)/100; //izračun moči v W*100
i = a;
sprintf (tekst, " %.3d.%.1dW\n", i/10, i%10);
}
LCDstring(tekst, 7,1); //Izpisi moč
}
else LCDstring("----.-ô ---.-W", 0,1); //napetost ali tok sta 0!!!!!
// znak ô pomeni simbol za ohm!
return;
}
// po potrebi (Polnilnik na čas) v drugo vrsto izpiši preostali čas
if (bit_is_set (Flag, 0))
{
sprintf (tekst, "%6.2d:%.2d:%.2d", ure,minute,sekunde);
LCDstring(tekst, 0,1); //Izpis časa na poz. 0,1
}
// po potrebi (Polnilnik na kapaciteto) v drugo vrsto izpiši preostalo kapaciteto
if (bit_is_set (Flag, 1))
{
signed int vmesni;
vmesni= (I/36);
if ((Ah==0) && (vmesni > uAh))
{
Flag &= ~(1<<1); //Zaključek polnenja- zbriši zastavico
Flag |= (1<<2); //prestavi na napajalnik
PORTB &= ~(1<<PB1); //tudi izklopi polnilnik
PORTB &= ~(1<<PB2); //izklopi lučko za vklopljen rele
}
else if (takt == 4) {
uAh = uAh - vmesni;
if (uAh < 0)
{
--Ah;
uAh = (10000-(uAh* (-1)));
}
}
sprintf (tekst, "Q=%.2d.%.3d%.4dAh", Ah/1000, Ah%1000, uAh);
LCDstring(tekst, 0,1); //Izpis napetosti in toka na poz. 0,1
}
}
|
|
|
Nazaj na vrh |
|
 |
lojzek Član



Pridružen-a: Pet 25 Jan 2008 8:00 Prispevkov: 3387 Aktiv.: 16.00
|
Objavljeno: Pet Mar 29, 2013 7:57 am Naslov sporočila: |
|
|
Še toliko bom dodal, da bo v takem principu sicer merilnik uporaben samo za merjenje navidezne moči, ali pa ohmskih bremen. |
|
Nazaj na vrh |
|
 |
xfce Član

Pridružen-a: Čet 28 Jul 2011 8:06 Prispevkov: 521 Aktiv.: 3.08
|
Objavljeno: Pet Mar 29, 2013 8:14 am Naslov sporočila: |
|
|
Ta stavek ti vrne vrednost 0.
Zato če deliš int in int dobiš int. Če je manjši od nič ti ga zaokroži na nič. To je vsa umetnost.
Drugače pa deli vedno nazadnje, kot so ti rekli predhodniki.
Če se pa držiš tega pa uporabi povsod to:
Koda: |
nap=(5.0/1024.0)*nap; |
in ti bo zadeva delala, ker po pač računal kot float.
Za pisanje na lcd uporabi sprintf()
Koda: |
char buff[17];
moc =(5.0/1024.0)*10;
sprintf(buff,"Poraba: %5.3fW",moc);}
Lcd_Out(1,1,buff); |
|
|
Nazaj na vrh |
|
 |
igo Član

Pridružen-a: Sre 11 Okt 2006 19:11 Prispevkov: 3641 Aktiv.: 16.01
|
Objavljeno: Pet Mar 29, 2013 11:21 am Naslov sporočila: |
|
|
V števec Porabljene energije prištevaj osnovni produkt povprečenih tok*nap (produkt ima največ 20 bitov, torej jih zadostuje 24). To je pri prevajalniško določenih tipih spremenljivk najbolj zgoščena in natančna oblika.
Vse nadaljnje izračune uporabljaj izključno za prikaz na lcd in/ali za pošiljanje na računalnik. Pri tem za osnovo spet uporabi tok*nap ki ju najprej pomnoži z vsemi nastopajočimi faktorji od obeh spremenljivk, nato pa še deli z vsemi delitelji.
Kasneje dodaš še malo "šminke" z obdobno porabo (zadnji dan/teden/mesec ... obdobje od reseta ...), z maksimalno močjo z datumom in časom vred ter z mesečno konico (maksimalna povprečna moč 15-minutnega dela ure) in še čim. Rabil boš še en mali RTC čip (PCF8385).
Če na 2 digitalna vhoda pripelješ ustrezno prilagojeni sinusoidi napetosti in toka, lahko zaznavaš razliko prehodov skozi 0 in izračunaš še cosFI in jalovo moč. _________________ Teoretično je praksa posledica teorije, praktično je pa ravno obratno. (igo 2001)
LP, Igor |
|
Nazaj na vrh |
|
 |
|
|
Ne, ne moreš dodajati novih tem v tem forumu Ne, ne moreš odgovarjati na teme v tem forumu Ne, ne moreš urejati svojih prispevkov v tem forumu Ne, ne moreš brisati svojih prispevkov v tem forumu Ne ne moreš glasovati v anketi v tem forumu Ne, ne moreš pripeti datotek v tem forumu Ne, ne moreš povleči datotek v tem forumu
|
Uptime: 492 dni
Powered by phpBB © 2001, 2005 phpBB Group
|