Ik gebruik een pic16f877A om:

* een ADC uit te lezen
* temperatuur te meten met een DS1820
* een fan aan te sturen (digitaal met een lm317)
* fan toerental uit te lezen (met pulsin commando)
* vervolgens het gemeten voltage, temperatuur en fan snelheid op een lcd te printen

Dit werkt in principe allemaal prima, alleen is het programma te traag.
De adc waarde verspringt maar langzaam op het lcd.
D.m.v weglaten van delen code heb ik het idee dat vooral het meten van het toerental met pulsin en de if statements voor het instellen van de fan snelheid veel tijd kosten.
Wie kan mij tips geven over het optimaliseren van het programma?


Device 16F877A 
'Config WDT_Off, PWRTE_Off, XT_OSC, LVP_off
Config WDT_OFF, PWRTE_Off, XT_OSC, LVP_OFF, CP_OFF, DEBUG_OFF, WRT_OFF, CPD_OFF, BODEN_ON

PORTB_PULLUPS On

XTAL 4 
ADIN_RES = 10 ;ADC resolutie
ADIN_TAD = FRC ;de clock voor de adc extern / intern
ADIN_STIME = 50;De conversie tijd
ALL_DIGITAL = True

Symbol EN1         = PORTC.7          ;Uitgang voor LCD Enable 1
Symbol EN2         = PORTD.5          ;Uitgang voor LCD Enable 2
Symbol dq          = PORTD.0          ; inlees poort ds1820
Symbol R0K         = PORTD.2          ; lm317 res to ground
Symbol R5K         = PORTD.3          ; lm317 res to ground
Symbol R1K         = PORTC.4          ; lm317 res to ground

        ;76543210
TRISA = %01000000
ADCON1= %11000001 ;adc instellen op de goede poorten
Print $FE,$40,$0E,$0A,$0E,$00,$00,$00,$00,$00                '' voor graden symbool

Clear
Cls

;Variabele declareren
Dim Waarde As Float
Dim VAR1 As Word
Dim VAR2 As Word
Dim TPL As Word
Dim Rpm As Float
Dim Rpm1 As Word
Dim Temp As Word              ' Holds the temperature value 
Dim C As Byte                 ' Holds the counts remaining value 
Dim CPerD As Byte             ' Holds the Counts per degree C value

Hoofdprogramma: 


;; TEMPERATURE MEASUREMENT
    
    OWrite dq, 1, [$CC, $44]      ' Send Calculate Temperature command 
    Repeat '
    ORead dq, 4, [C]              ' Keep reading low pulses until
    Until C <> 0                  ' the DS1820 is finished.
    OWrite dq, 1, [$CC, $BE]      ' Send Read ScratchPad command
    ORead dq, 2,[Temp.LowByte,Temp.HighByte, C, C, C, C, C, CPerD]
  ' Calculate the temperature in degrees Centigrade
    Temp = (((Temp >> 1) * 100) - 25) + (((CPerD - C) * 100) / CPerD)
 
;; FAN SPEED
    If  Temp < 3000  Then GoSub SPEED0
    If  Temp > 3000  Then GoSub SPEED1
    If  Temp > 4000  Then GoSub SPEED2
    If  Temp > 5000  Then GoSub SPEED3
  
    
 
; RPM MEASUREMENT
    VAR1 = PulsIn PORTC.5 , 0  
    VAR2 = PulsIn PORTC.5 , 1  
    TPL = (VAR1 * 2) + (VAR2 * 2)
    Rpm = 6000000/TPL 
    Rpm1 = Rpm
    If  TPL < 100  Then Rpm1=0

;; ADC uitlezen
    Waarde = ADIn 6
    Waarde = (Waarde * 5) / 341

 
;; Print op LCD
    GoSub Derde
    Print At 1, 1, "Heatsink Temp: ",  Dec Temp / 100, ".", DEC1 Temp," ", 0,"C " ;Zet tekst op regel 1  
    Print At 2,1, "Fan Speed:   ",  Dec Rpm1, " rpm       " 
    GoSub Eerste
    Print At 1,1, "Vout: ",DEC2 Waarde, " V " 

    GoTo Hoofdprogramma           ;Doe het voorbeeld steeds weer opnieuw

Derde:

    High EN1                             ;geef regel 1 en 2 vrij
    Low EN2                              ;blokkeer regel 3 en 4
    Return
 
Eerste:

    Low EN1                              ;blokkeer regel 1 en 2
    High EN2                             ;geef regel 3 en 4 vrij
    Return

SPEED0:

    DelayMS 1
    High R0K 
    High R5K 
    High R1K 
    DelayMS 1
    Return

SPEED1:

    DelayMS 1
    Low R0K 
    Low R5K 
    High R1K             
    DelayMS 1
    Return

SPEED2:

    DelayMS 1
    Low R0K 
    High R5K 
    Low R1K                 
    DelayMS 1
    Return

SPEED3:

    DelayMS 1
    Low R0K 
    Low R5K 
    Low R1K                 
    DelayMS 1
    Return

End        

Deze schiet niet echt op voor de snelheid: DelayMS 1000.
Daarnaast wat vretende berekeningen

DelayMS 1000 ' Wait until conversion is complete

Hier mis ik een until, want dat doet delayms niet: die wacht gewoon telkens een seconde.
Dus een rondje van je main kost minimaal 1 seconde: lekker traag ;)

[EDIT] te laat

oeps, foutje bij opschonen code voor het posten.
die had ik er (uiteraard :)) al tussenuit gehaald.
code blijft te traag naar mijn zin....

Die DS1820 is ook niet bepaald de snelste.

De DS1820 doet er ook iets van 750msec. over om tot een resultaat te komen. Misschien kun je beter de DS1820 pollen in plaats van wachten. Dus gewoon je rondje doen totdat hij klaar is, dan pas de temperatuur uitlezen en verwerken.

Persoonlijk zou ik al die tijdvretende dingen in een interrupt afhandelen.

Een sensor zoals de MCP980x is een wat makkelijkere keus. Heeft fast mode i2c interface.

Beter kan je one-wire sensoren zoals de DS1820 niet gebruiken, zijn traag en in combinatie met interrupts levert dit geheid problemen op.

Gebruik of I2C of AD (bijvoorbeeld de LM35 of de LM335AZ) sensoren.

De 16F877A heeft 8x 10-BIT ADC, dus daar kan je zo een LM35 aan hangen!

Je gebruikt ook tweemaal float, (daar ontkom je waarschijnlijk niet aan) maar daar wordt het niet echt sneller van.

De controller draaid nu op 4MHz, die kan ook naar 20MHz dat scheeld ook weer.

;; FAN SPEED
    If  Temp < 3000  Then GoSub SPEED0
    If  Temp > 3000  Then GoSub SPEED1
    If  Temp > 4000  Then GoSub SPEED2
    If  Temp > 5000  Then GoSub SPEED3

Bij een temp > 5000 gaat hij eerst naar SPEED1, dan SPEED2 en dan pas naar SPEED3

Ik zou het zo neerzetten:

    If  Temp > 5000  Then GoSub SPEED3
        elseif Temp > 4000  Then GoSub SPEED2
        elseif Temp > 3000  Then GoSub SPEED1
        else GoSub SPEED0
    Endif

En waarom zit er bij elke SPEED subroutine 2 maal een waitms 1 in?

I.p.v. High en Low, Aan en Uit gebruiken. wel even aan en uit definiëren.



symbol AAN = 1
symbol Uit = 0

Dit boven staande stukje code moet boven in je programma staan.

Edit, zo is het misschien duidelijker.


Derde:

    EN1 = Aan                             ;geef regel 1 en 2 vrij
    EN2 = Uit                             ;blokkeer regel 3 en 4
    Return
 
Eerste:

    EN1 = Uit                              ;blokkeer regel 1 en 2
    EN2 = Aan                             ;geef regel 3 en 4 vrij
    Return
 
SPEED0:

    DelayMS 1
    R0K = Aan 
    R5K = Aan 
    R1K = Aan 
    DelayMS 1
    Return
 
SPEED1:

    DelayMS 1
    R0K = Uit 
    R5K = Uit 
    R1K = Aan             
    DelayMS 1
    Return
 
SPEED2:

    DelayMS 1
    R0K = Uit 
    R5K = Aan 
    R1K = Uit                 
    DelayMS 1
    Return
 
SPEED3:

    DelayMS 1
    R0K = Uit 
    R5K = Uit
    R1K = Uit                 
    DelayMS 1
    Return
 
End

Of zo:


Select Temp
    Case < 3001
        GoSub SPEED0
    Case 3000 To 4000     
        GoSub SPEED1
    Case 4000 To 5000     
        GoSub SPEED2
    Case > 5000     
        GoSub SPEED3        
End Select

Waar waarom een snelheid via vaste waardes regelen en niet via PWM?

[Bericht gewijzigd door Stan1 op (13%)]

Op 30 oktober 2011 15:48:51 schreef Tinus016:
I.p.v. High en Low, Aan en Uit gebruiken. wel even aan en uit definiëren.



symbol AAN = 1
symbol Uit = 0

Dat is niet het enige, je moet dan ook TRIS instellen.

bedankt voor de hulp zover,
waarom is het beter aan uit te gebruiken dan high low?

Bij iedere HIGH en LOW wordt ook steeds de poort als uitgang gedefinieerd.
Het is beter om dit eenmalig bovenaan in je programma te doen met TRIS.

Lees hiervoor het begin van cursus deel 3:
www.picbasic.nl/beginners3.htm

Ik heb nu de tris gebruikt en de snelheid verhoogt naar 20 Mhz.
Dit scheelt al een stuk.

Richard,

om de meting van de ds te versnellen, heb ik de code voor het uitlezen in 2 gehakt!

 ' ****************** temp meting ds18s20 ******************************* 
  ds_1820:

 Output DQbin             			      ' maak Pin Output
 DQbin=0					              ' OneWire lijn Laag
 PauseUs 480                              ' 480 µS laag houden    
 Input DQbin                              ' Maak Pin Input
 PauseUs 70                               ' wacht 70 µS
 If DQbin=1 then                          ' geen pulzen van DS1820   
    v = 1200                              ' op display 20,0 graden
    Return
 EndIf
 OWOut DQbin, 1, [$CC, $44]       		  ' Start temperatuur conversie
 return
 
      
    Wachtlus_bin:

    led2 = 1 
    OWIn DQbin, 4, [resterend_tellen]	' controlle nog steeds bezig controleren
    If resterend_tellen = 0 Then wachtlus_bin      ' Bezig 
    
        OWOut DQbin, 1, [$CC, $BE]		          ' lees de temperatuur
    OWIn DQbin, 0, [Temperatuur.LowByte, Temperatuur.HighByte, Skip 4, resterend_tellen, tellen_per_C]
    Temperatuur = (((Temperatuur >> 1) * 100) - 25) + (((tellen_per_C - resterend_tellen) * 100) / tellen_per_C)
        if Temperatuur > 32767 then  '32767 controleer als bit 12=1
        Temperatuur= ~Temperatuur
        V= (10000 - Temperatuur )/10               ' 25 C = 1250  0 C= 1000  -10 C =900 
    else
        V= (10000 + Temperatuur)/10
    EndIf
    led2= 0
    Tekenbit_bin = $2b '2b="+"     
        If v >= 1000 then                     ' boven 0 C.      
            Temp_bin=V-1000                   
            Else                                   
            Temp_bin=1000-V                  ' onder 0 C. 
            Tekenbit_bin=$2d  '2d = -"
        EndIf
   return

ik gebruik een iets andere versie van picbasic maar ik vermoed dat het wel duidelijk is

Eerst met de sub ds_1820 de conversie starten, en ik ga 1 seconden later de sub Wachtlus_bin aanroepen en zodoende heb ik om de 2 seconden een nieuwe temperatuur en tussendoor kan de up andere dingen doen ! Dus hij zit niet te wachten todat de ds de temparatuur conversie heeft gedaan.

Succes Johan

Je kunt veel beter de timer interrupt gebruiken. Dat maakt het leven een stuk eenvoudiger...