Pimp wrote:Din beskrivning av problemdomänet är väldigt bristfällig och jag råder dig att uppdatera den med utförlig information som undviker att sätta dig i position där en potentiell lösning enbart kan leveras av någon som har direkt erfarenhet av mikrokontrollern du nämner.
Nu till ditt problem.
1. Om du studerar dina ekvationer lite närmare ser du nästan alltihop kan beräknas i förväg. Om jag har förstått det rätt så läser du direkt från en ADC, eller hur? Om så är fallet bör du åtminstone ha två steg i implementation:
(a) Avgör om sensorn är tillförlitig
(b) Beräkna ett medelvärde från ADC så att vi får ett stabiliserat värde
2. Ställ upp en array med n-element där n anger hur pass nogrann din "temperaturtabell" skall vara. Om jag vidare antar att detta är enkel labb som utförs inomhus kan du begränsa definitionsområdet till 15-30 grader. Nu måste du (utan min hjälp) beräkna i förväg vilket värde elementen i array motsvarar när du använder (ett stabiliserat) ADC värde som index till denna array. Alltså shifta ADC-värde ett par steg etc...
Den bästa optimeringen är att undvika behöva optimera.
Bristfällig? Vissa små detaljer hade jag inte med, men i det stora hela vill jag nog påstå att jag inte har missat speciellt mycket. Men om så önskas kan jag beskriva hela systemet.
Temperaturgivaren har tre pinnar, Vcc, Vss och Output. Givaren ger ut en fyrkantvåg mellan 1 och 4 kHz, men detta är inte speciellt intressant egentligen, eftersom det är
pulskvoten som är viktig. Den går ut på att desto högre temperatur det är, desto längre tid är perioden hög. Notera att både Th och Tl ändras, därför måste jag räkna hur länge den är hög samt låg.
Mikrokontrollern (uc) har en pinne/funktion som heter
Input Capture (IC), den används för att bland annat räkna ut frekvenser och pulskvoter. Den fungerar på så sätt att den genererar ett avbrott vid flankskifte. Alltså när insignalen går från hög till låg och vice versa. Jag bestämmer själv vilken av dem som uc:n ska söka efter.
Samtidigt i bakgrunden använder jag TIMER1, en räknare som varje klockcykel räknar upp ett 16-bits register. Vid overflow genereras ett avbrott och registret ställs på lämpligt tal igen. Detta tal väljs utifrån hur ofta jag vill ha interrupt såklart. Man använder den klocka som är kopplad till processorn (8MHz) och skalar ned den till lämpligt tal. Mitt önskemål är 200ms, men eftersom TIMER1 även används till IC får den inte vara för långsam då den blir lite okänslig - den hinner inte räkna så långt alltså. Jag är tvungen att ställa avbrottet på var 50:e ms (för då kan min prescaler vara 8 istället för 64. har jag den på 8 och väljer 200ms hinner den räkna runt i förväg), och sedan slå igång temperaturinhämtningen var fjärde gång.
När IC får interrupt kopieras automatisk värdet av TIMER1 till ett annat register, vilket jag använder mig av när jag ska räkna sedan. Detta register läser jag av och sparar sedan undan värdet. Eftersom det är 16-bitars register jag använder mig av så får jag ett tal mellan 0 och 64k. Min algoritm ser ut på följande sätt:
- Starta IC-avbrottsfunktionen
Vänta på att kunna börja räkna (väntar in en låg flank för att kunna känna av en hög)
Spara undan startvärdet (när avbrottet för IC kommer)
Ställ om och vänta på låg
Spara undan mellanvärdet (när avbrottet kommer)
Ställ om och vänta på hög
Spara undan slutvärdet (när avbrottet kommer)
Stäng av IC-avbrottsfunktionen
Nu har jag fått tre värden, start, växling och slut. Dags att börja räkna. Jag har fått fram värden för rumstemperatur (19 grader C just nu). Th = 63 (motsvarar 136 us), Ttot (Th+Tl) = 152 (motsvarar 196 us). Dessa värden växlar med någon siffra hit och dit, men är relativt stabila.
Det är alltså ingen ADC som jag läser av, utan en inkommande puls enbart. Eftersom insignalen är så pass stabil behöver jag inte räkna ut ett medelvärde. Jag vill bara använda de värden jag har och räkna ut min temperatur. Temperaturen kommer att variera mellan 5 och 50 grader gissar jag på. Men jag har inte kunnat testa vid denna temperatur och få fram värden att räkna på.
Grejen är nu så pass enkel att jag har två värden och en formel som jag vill räkna på. Jag vill helst inte byta datatyp till något större då de tar så mycket plats. Nu borde jag ha beskrivit problemet mer än nödvändigt...
Generella klassikern är ju att shifta värdena ett par steg uppåt (dvs *2, *4, *8 osv per shift)
och sen räkna på det, och precis innan du presenterar datat så shiftar du ner
det igen lika mycket, så får du fixed.point-decimaler.
Shifta vet jag hur man gör, men hur menar du att jag ska göra exakt...? Jag vet inte om jag hänger med riktigt. Principen låter som att jag flyttar värdesiffrorna, men blir inte det väldigt okänsligt och desktruktivt (liknande division med heltal)?
Förklara gärna. Jag går på lunch under tiden