Sida 4 av 6

Re: Göra ADC beräkningar med PIC 12F675

Postat: 7 januari 2012, 16:10:59
av sodjan
Menar du vilken skillnad i funktion det blir (alltså det som står i databladet)
eller när och hur man eventuellt vill ha de olika alternativen i praktiken ?

För båda aternativen gäller att :

- Processorn kör på den interna INTOSC oscillatorn.
- I/O pinnen GP5 fungerar som en vanlig I/O pinne och kan användas "som vanligt" av applikationen.

Det som skilljer är :

> 101 = INTOSC oscillator: CLKOUT function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN

- I/O pinnen GP4 på processorn har en klocksignal som kommer från INTOSC oscillatorn.

> 100 = INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN

- I/O pinnen GP4 fungerar som en vanlig I/O pinne och kan användas "som vanligt" av applikationen.

Klocksignalen kan t.ex användas om man har någon extern krets inkopplad som i sig behöver en "klocka".
Om jag minns rätt så är klocksignalen 1/4 av Fosc, d.v.s att om man kör processorn på t.ex
4 MHz, så har man en 1 Mhz klocksignal på GP4 (i det första alternativet).

Slutligen så är det kanske inte så vanligt att man behöver en extern klocksignal, så det
andra alternativet (med I/O funktion på GP4) är nog absolut vanligast.

OK ?

Re: Göra ADC beräkningar med PIC 12F675

Postat: 7 januari 2012, 17:55:48
av newbadboy
där satt den som ett smäck. tack

Re: Göra ADC beräkningar med PIC 12F675

Postat: 8 januari 2012, 19:24:56
av newbadboy
Nu har jag fler kuliga frågor. jag har gjort ett program som läser in en analog spänning och sparar undan det i en variabel. Sedan räknar jag ut hur mycket 90% av det inlästa värdet är och sparar det i en ny variabel. Både programmet och själva kretsen verkar funka fint men jag har fått en anmärkning att man inte kan göra på det sättet som jag har gjort för det blir fel.

Har en del av programmet här nedan. Det som jag sägs ha gjort fel är att jag inte kan multiplicera adc_rd värdet med 0.9 av ngn anledning som jag inte helt fattar.


Såhär har jag deklarerat variablerna

unsigned int adc_rd;
unsigned int trig_val;

Och såhär har jag gjort beräkningen

adc_rd=ADC_Read(2); // get ADC value from 2nd channel

trig_val=adc_rd*0.9; //trig_val is 90% of start value

Re: Göra ADC beräkningar med PIC 12F675

Postat: 8 januari 2012, 19:28:42
av eqlazer
Vet du vad flyttal är? 0.9 är ett sådant, alltså inte ett heltal/integer.

Re: Göra ADC beräkningar med PIC 12F675

Postat: 8 januari 2012, 19:46:35
av sodjan
Som vanligt gäller att inte försöka med egna tolkningar av olika (fel-) meddelanden.
Se till att kopiera in de *faktiska* meddelanden som du får.
Om det nu inte är så att det är solkart vad meddelandet betyder, men
du hade du ju inte behövt fråga från början... :-)

Felet är med stor sannolikhet att du blandar inkompatibla datatyper.
(Men helt säkra kan vi inte vara förrens de faktiska felmeddanderna finns.)

> trig_val=adc_rd*0.9;

trig_val = (adc_rd*9) / 10;

skulle sannolikt gå igenom kompilatorn.
Notera att det enbart är heltal ("int") i hela beräkningen.

Det hade gått göra effektivare om du skulle ha haft någon annan del
än just 90%, något som går jämt upp i en potens av 2. T.ex
trig_val = adc_rd - (adc_rd / 8 ). En delning med 8 är en enkel/snabb 3-bits
shift och det hade gett 87.5 % av mätvärdet i stället för 90 %.

Re: Göra ADC beräkningar med PIC 12F675

Postat: 8 januari 2012, 21:22:06
av newbadboy
Som sagt, kompileringen går genom utan problem. Och min krets verkar fungera som den ska... Det var på annat forum de påpekade att det är inte rätt att göra så.men det verkar ju funka :-/


Men jag antar att jag borde byta unsigned int mot float?

Re: Göra ADC beräkningar med PIC 12F675

Postat: 8 januari 2012, 21:37:05
av jesse
Det fungerar, men det blir problem av olika orsaker om du skulle ha ett större program med fler beräkningar.

Dina variabler är ju av heltalstyp. Och det är heltal som processorn är "bäst" på - den räknar det snabbare och det tar upp väldigt lite programminne (och även mindre RAM) att utföra heltalsberäkningar.

Precis som Sidjan säger, så kan du räkna ut det med enbart heltalsoperationer på det här sättet:

Kod: Markera allt

trig_val = (adc_rd*9) / 10;
Om du använder flyttal, dvs. tal med en decimalpunkt, t.ex. 0.9 så blir det mycket mer avancerat för processorn att räkna. Det går mycket långsammare.

Testa själv att först kompilera programmet med din beräkning

Kod: Markera allt

trig_val=adc_rd*0.9;
och se hur mycket programminne (Flash) det tar upp. Ändra nu till det Sodjan skrev och gör om kompileringen.

Ser du någon skillnad?

Du kan också testa att mäta tiden det tar för att utföra beräkningen. Det kan du göra på olika sätt. T.ex i simulator eller att du gör t.ex. 1000 beräkningar och sedan tänder en lysdiod - och kollar hur lång tid det tar.

Det går oftast att slippa att använda flyttal genom olika knep, som det ovan. Man måste bara vara noga med att man inte överskrider maxgränserna för heltalen - då blir det fel. Att multiplicera ett 16-bitars heltal med 9 och sedan dividera med 10 fungerar bra så länge talet inte är större än 3640. Ska man multiplicera med större tal får du använda fler bitar i heltalet, t.ex. ett 32-bitars tal.

Re: Göra ADC beräkningar med PIC 12F675

Postat: 9 januari 2012, 00:10:35
av sodjan
> Det var på annat forum de påpekade...

Jaha, och hur skulle vi/jag kunne veta det ? :-) Varför inte länka direkt till
det formumet/tråden så att vi kan se vad som skrevs ? Det är samma problem
med att försöka omtolka vad de skrev där som för ett felmeddelanden.
Vi vill se *originalet*, inte en tolkning. :-)

> ... att det är inte rätt att göra så.

Rätt och rätt. Om kompilatorn nu accepterade koden så har den i alla fall
genererat någon kod för att försöka hanterade det. Återstår att verifiera
det över hela det område som invärderna kan anta.

Men, man bör nog i alla fall förstå vad kompilatorn har gjort med det hela.
Eller så skriver man om koden så att man har bättre koll.

> Men jag antar att jag borde byta unsigned int mot float?

Det är den vanligaste nybörjarreaktionen och sannolikt också den sämsta lösningen!

Som jesse beskrev så ska du så långt det är möjligt undvika float och enbart använda
det då det är absolut nödvändigt, och det är det nog inte i detta fall. Det är alldeles
för små tal och ett för begränsat dynamiskt område för det. Det går utmärkt med int.

Hur givet är dessa 90%? Skulle 87.5% fungera lika bra? Det skulle underlätta beräkningen.

Re: Göra ADC beräkningar med PIC 12F675

Postat: 9 januari 2012, 09:10:24
av newbadboy
Som sagt jag är inte ngn avancerad hackare så det är bra man kan få en del förklarat. Jesse beskrev bra varför det fungerar trots att det inte är helt rätt skrivet. Noggrannheten är inte superhög så 87,5 går oxå att leva med.

Och här är originalet från det andra forumet. Orsaken att jag då och då frågar är just pga av att det är MikroC eget forum. Ibland kan det vara bra då man har ex syntax problem och kan fråga folk som direkt sitter med mikroc.

http://www.mikroe.com/forum/viewtopic.p ... 53#p177353

Re: Göra ADC beräkningar med PIC 12F675

Postat: 9 januari 2012, 09:57:31
av sodjan
Bra, det ger ju lite mer sammanhang till det hela. :-)
Sista förslaget var ju inte helt fel heller :
Hi,
I would multiply by 9, not by 0.9. In this case you don't need to use float or double. I did not think about the whole logic.

Kod: Markera allt

Select all
trig_val=adc_rd*9;   //trig_val is 90% of start value
...
if(adc_rd*10 < trig_val){     //if value is less then 90% of
...
}

> Noggrannheten är inte superhög så 87,5 går oxå att leva med.

Enda fördelen me det är att man kan trimma exekveringstiden lite
mer genom att det enbart blir beräkningar med potenser av 2.
Kanske inte helt nödvändigt här, int-beräkningar går rimligt snabbt
också, speciellt jämfört med float. Det var mer som ett exempel på
hur man, vid behov, kan trimma rutiner...

Re: Göra ADC beräkningar med PIC 12F675

Postat: 9 januari 2012, 10:01:17
av newbadboy
Hehe nää,, snabbheten är lågt prioriterat i detta fallet.

Re: Göra ADC beräkningar med PIC 12F675

Postat: 9 januari 2012, 10:25:22
av jesse
Ja, när man ser ursprunget av de olika värdena så kan man ofta förenkla ännu mer.

Din utgångsfråga i det här forumet var ju hur du ska multiplicera ett tal med 0.9 och du fick svaret multiplicera med 9 och dela med 10.

Men när man ser var inkommande data kommer ifrån och vad resultatet ska användas till kan man skala upp resultatet så som Sodjan citerade, och därmed slipper du helt divisionen.

Ibland ska man jämföra med en konstant och då blir det ännu lättare. Då justerar man konstanten istället - och processorn behöver inte räkna alls - bara jämföra rakt av med ett fast värde.

exempel:

Kod: Markera allt

// ADC 100% värde = 1024
// ADC  90% värde = 0.9*1024 = 922.
#define LIMIT 922

if (adc_rd < LIMIT) { ... }
EDIT:
letadyylko skrev:unsigned int trig_val;
trig_val=adc_rd*0.9;

trig_val is integer... where is float or double? You can not multiply integer and next number with a decimal comma without converting
Det där var ju ett felaktigt påstående. Visst går det, som du själv märkte. Konvertering i det här fallet förändrar inget. Eller, rättare sagt, adc_rd omvandlas till float i operationen för att kunna multipliceras med 0.9. När operationen är klar ska resultatet stoppas in i en heltalsvariabel igen, trig_val - då kapas eventuella decimaler bort och talet omvandlas tillbaks till heltal. Fungerar som sagt, men är väldigt klumpigt.

Det borde kanske ge en varning i kompilatorn att du omvandlar float till int? Man bör bli uppmärksammad på att här kan man förlora data om man inte ser upp (int rymmer inte lika stort intervall).

Re: Göra ADC beräkningar med PIC 12F675

Postat: 9 januari 2012, 11:04:10
av newbadboy
Det var lite därför jag ville ha ngn mer än jag som kollade lite på min kod då jag har känt mig osäker på om jag gjort verkligen rätt trots att det funkar. Men man ser ju vilka misstag man gör och förhoppningsvis inte gör dem igen.

Sedan är det intressant att se hur man kan göra samma beräkning på flera sätt.

Re: Göra ADC beräkningar med PIC 12F675

Postat: 9 januari 2012, 19:57:47
av newbadboy
Har lagt till en funktion, om man tappar kontakten med sensorn så dras adc ingången upp till 5V via en pullup. Relä ugången skall oxå trigga i detta fallet

Först hade jag två if satser efter varandra och en else sats sist men hur jag än gjorde vägrade den hoppa in i if satsen som känner av om adc värdet är över 5V, dvs m man tappat kontakten med sensorn. Till slut satte jag dit en else if sats och då funkar det. Kan ni hjälpa mig förstå vad det är jag gjort eg och om det är ok att göra såhär???

Kod: Markera allt

 while(IGNITION==0){                                //medan ignition är noll läs in adc värdet kontinuerligt
                                   adc_rd=ADC_Read(2);                           

                                    
                                    
                                    if(adc_rd > 0x39A){         // om man tappar kontakt till sensor blir adc värdet "pulluppat"                   
                                             delay_ms(1000);      //till 5V, dvs över 4,5V (39A), aktivera reläet.
                                             adc_rd=ADC_Read(2);    //delay satsen säkerställer bara att false trigg inte sker

                                             if(adc_rd > 0x39A){
                                                       RELAY_OUT=1;
                                                        DIAG_LED=1;
                                                        }
                                              }




                                   else if(adc_rd < trig_val){     //trig val är ett givet värde på ca 1V              
                                             delay_ms(1000);        //delay är mot false trigg som ovan           
                                             }
                                             adc_rd=ADC_Read(2);
                    
                                             if(adc_rd < trig_val){              
                                                       RELAY_OUT=1;              
                                                        DIAG_LED=1;
                                                        }
                                             }
    
                                   else{
                                        RELAY_OUT=0;     // om inte if satser ovan uppfylls se till att relä och diag är noll               
                                        DIAG_LED=0;        //samt om ngn if sats vairt uppfylld men inte längre säkerställ noll
                                        }
                                   }

Re: Göra ADC beräkningar med PIC 12F675

Postat: 9 januari 2012, 20:05:48
av sodjan
Lite mer kommenterar hade varit bra så att man förstår
lite enklare varför du läser ADC'n dubbelt. Verkar ha något
med "false trig" att göra (?).

Sen så är det lite oklart vad det var du frågade om egentligen.
Det finns baa en version av koden och inget att jämföra med.

"Spännande" formattering också, som dessutom verkar ändra
på sig lite då och då... :-)