'****************************************************************
'*  Name    : Reflow oven                                       *
'*  Author  : Stijn Coenen [Stynus]                             *
'*  Notice  : Copyright (c) 2010 Stijn Coenen [Stynus]          *
'*          : Licenced under Creative Commons                   *
'*          : Attribution-Noncommercial 2.0 Belgium Licence     *
'*          : http://creativecommons.org/licenses/by-nc/2.0/be/ *
'*  Date    : 08/05/2010                                        *
'*  Version : 1.32                                              *
'*  Notes   : http://www.elektronicastynus.be/                  *
'*          : Projecten/Gereedschap/Reflow_oven/index.php       *
'****************************************************************
Device  16F877A
Config  WDT_OFF, PWRTE_ON, HS_OSC, LVP_OFF
Xtal    20
All_Digital = true
'****************************************************************
'Declaraties pinnen en variabelen
    'Lcd
        Declare LCD_DTPin PORTD.4
        Declare LCD_ENPin PORTC.5
        Declare LCD_RSPin PORTC.4
        Declare LCD_Interface 4
        Declare LCD_Lines 2
    'Verwarmingsweerstanden
        Symbol Rboven       = PORTA.1 : PORTA.1 = 0
        Symbol Ronder       = PORTA.0 : PORTA.0 = 0
    'Case temp sensor       
        Symbol SDA          = PORTA.5
        Symbol SLC          = PORTA.3
        Dim CaseTemp        As Byte
    'Oven temp sensor
        Symbol ChipSelect   = PORTD.2 : TRISD.2 = 0
        Symbol Sck          = PORTD.1
        Symbol SO           = PORTD.3
        Dim    OvenTemp     As Word
    'RS232
        Hserial_Clear       = On
        Hserial_Baud        4800
        Hserial_RCSTA       = %10010000
        Hserial_TXSTA       = %00100000 
    'Keypad
        Declare Keypad_Port PORTB
        Dim    Toets        As Byte
        Dim    Toets_W      As Byte
        Dim    TempToets    As Byte
        Dim    InstelTemp   As Word
        Symbol Pijl_up      = 10
        Symbol Pijl_down    = 11
        Symbol Enter        = 12
        Symbol Back         = 13
    'Diverse
        Symbol fan          = PORTE.2 : TRISE.2 = 0
        Symbol zoemer       = PORTC.2 : PORTC.2 = 0 
    '************************************************************       
    'Menu
        Dim    Menu_Item    As Byte
    'PID interrupt
        Symbol GIE          = INTCON.7        'Global Interrupt Enable  
        Symbol T0IE         = INTCON.5        'TMR0 Overflow Interrupt Enable 
        Symbol T0IF         = INTCON.2        'TMR0 Overflow Interrupt Flag 
        T0IF                = 0    
        Symbol PS0          = OPTION_REG.0    'Prescaler bit-0         
        Symbol PS1          = OPTION_REG.1    'Prescaler bit-1         
        Symbol PS2          = OPTION_REG.2    'Prescaler bit-2  
        PS0                 = 1 
        PS1                 = 1
        PS2                 = 1  
        Symbol PSA          = OPTION_REG.3    'Prescaler Assignment  
        PSA                 = 0 
        Symbol T0CS         = OPTION_REG.5    'Timer0 Clock Source Select   
        T0CS                = 0              
        TMR0                = 0  
        On_Hardware_Interrupt GoTo interrupt_routine
        Dim    setpoint     As Dword          'Gewenste temperatuur
        Dim    tempnu       As Dword          'Huidige temperatuur
        Dim    Error_now    As Dword          'Huidige fout
        Dim    Error_last   As Dword          'Fout laatste cyclus
        Dim    P            As Dword          'P    waarde
        Dim    I            As Dword          'I    waarde
        Dim    D            As Dword          'D    waarde        
        Dim    PID          As Dword          'PID  waarde
        Symbol Kp           = 15              'Proportionele actie
        Symbol Ki           = 0               'Integratietijd
        Symbol Kd           = 5               'Differentiatietijd
        Dim    DoBit        As Bit            'Zorgt ervoor dat de pid lus niet kan uitge-
                                              'voerd worden als de pwm lus niet voltooid is
        Dim    pwm_teller   As Byte           'Teller voor de PWM lus
    'Programma variabelen
        Dim    teller       As Byte           'houd het menu item bij                 
        Dim    tijd         As Byte           'Stap in de programma's        
        Dim    chrono       As Byte           'timing in de programma's
        Dim    digit        As Byte           'Digit bij het instellen temperatuur
'****************************************************************
Clear           'Variabelen leeg maken
GoTo oversub    'Over de sub routines heen springen
'****************************************************************
'Subroutines
    '************************************************************  
    'Subroutine om de temperatuur van de controllerprint in te lezen
    CaseTempInlezen:
        I2Cin SDA, SLC,$91,[CaseTemp]
    Return
    '************************************************************  
    'Subroutine om de temperatuur van de oven in te lezen 
    OvenTempInlezen:
        Low ChipSelect 
        SHIn SO,Sck,0,[OvenTemp\16]  
        High ChipSelect
        OvenTemp = OvenTemp >> 5     
    Return
    '************************************************************  
    'Subroutine om de knoppen in te lezen  
    KnoppenInlezen:
        Toets_W = InKey                     'Toetsenbord inlezen
        'Opzoeken welke waarde deze toets heeft
        Toets   = LookUpL Toets_W, [13,12,11,10,255,9,6,3,0,8,5,2,255,7,4,1,255]
        If Toets < 15 Then                  'Als de toets lager is dan 15 hier 
           While Toets_W = InKey : Wend     'blijven hangen tot de toets is losgelaten
           DelayMS 10                       '10mS delay tegen contact dender
        EndIf 
    Return    
    '************************************************************  
    'Subroutine om data over de oven naar de pc te sturen via een RS232 interface
    RS_Uit:
        HSerOut ["Oven:'", Dec OvenTemp  , "' "]
        HSerOut ["Case:'", Dec CaseTemp  , "' "] 
        HSerOut ["Setp:'", Dec setpoint  , "' "]
        HSerOut ["P:'"   , SDec P        , "' "]
        HSerOut ["I:'"   , SDec I        , "' "]
        HSerOut ["D:'"   , SDec D        , "' "]
        HSerOut [13,10]
    Return  
    '************************************************************  
    'Subroutine die een biepje uit de zoemer geeft.
    Zoemen:
        Sound zoemer, [120,250] 
    Return  
    '************************************************************  
    'Subroutine die de pid bereken sub aanroept, vervolgens de setwaarde dat deze geeft
    'op het display zetten en de sub aanroepen die deze uitstuurt via de RS232 verbinding
    Regel:
        If DoBit = 1 Then
            GoSub Bereken_PID
            Print At 2,1, "T", Dec3 OvenTemp, "C S", Dec3 setpoint, "C ", Dec3 PID, "% " 
            GoSub RS_Uit  
        EndIf      
    Return
    '************************************************************  
    'Subroutine die de pid waardes berekent
    Bereken_PID:
        Error_now = setpoint - OvenTemp     'De huidige fout berekeken
        If Error_now < 0 Then               'Als de fout kleiner is dan 0 (overshoot)
            P = 0                           'dan de P waarde 0 maken anders de P
        Else                                'waarde berekenen
            P = Kp * Error_now  
        EndIf
        I = I + (Ki * Error_now)            'I waarde berekenen
        D = Kd * (Error_now - Error_last)   'D waarde berekenen        
        Error_last = Error_now              'fout van nu in error_last zetten voor de 
                                            'volgende keer de D waarde te berekenen
        PID = P + I + D                     'P, I en D actie optellen             
        If PID > 100 Then PID = 100         'Als PID groter is dan 100 > 100 maken
        If PID < 0 Then PID = 0             'Als PID kleiner is dan 0 > 0 maken
    Return                                                                         
    '************************************************************  
    interrupt_routine:                      
        If T0IF = 1 Then                    'Kijken of de interrupt wel van timer0 komt
            '****************************************************
            'Temperatuur sensoren inlezen
            Inc teller                      'Teller + 1
            If teller = 100 Then            'Bij de 100ste interrupt de oven temperatuur inlezen
                'OvenTempInlezen
                Low ChipSelect 
                SHIn SO,Sck,0,[OvenTemp\16]  
                High ChipSelect
                OvenTemp = OvenTemp >> 5
                DoBit = 1
            EndIf
            If teller = 200 Then            'Bij de 200ste interrupt de case temperatuur inlezen
                I2Cin SDA, SLC,$91,[CaseTemp]
                If CaseTemp > 29 Then       'Fan aanzetten indien nodig
                    Low fan                 'Low = aan
                EndIf                       
                If CaseTemp < 25 Then
                    High fan                'High = uit
                EndIf
            EndIf    
            '****************************************************
            'Pwm routine om de verwarmingsweerstanden aan te sturen
            If pwm_teller < PID Then
                High Rboven
                High Ronder   
            Else
                Low Rboven
                Low Ronder
            EndIf
            If pwm_teller = 100 Then
                pwm_teller = 0     
            Else
                Inc pwm_teller
            EndIf
            '****************************************************
            T0IF = 0                        'Timer 0 interrupt vlag terug uitzetten  
        EndIf
    Context Restore
'****************************************************************
oversub:
    Cls
    DelayMS 300

    Print At 1,1, "Reflow oven V1.3"
    Print At 2,1, "Elek Stynus 2010"
    HSerOut ["******************************", 13,10]
    HSerOut ["* ElektronicaStynus.be       *", 13,10]
    HSerOut ["* Reflow oven V1.32          *", 13,10]
    HSerOut ["* Laatste update: 08/05/2010 *", 13,10]
    HSerOut ["******************************", 13,10]
    
    DelayMS 1000

Menu:
    Cls
    Low Rboven
    Low Ronder
    Menu_Item = 0
    While 1 = 1
        'Tekst op lcd display zetten    
        Select Menu_Item
            Case 0            '1234567890123456
                Print At 1,1, "-> - Pre-heat   "
                Print At 2,1, "   - Reflow     "
            Case 1            '1234567890123456
                Print At 1,1, "-> - Reflow     "
                Print At 2,1, "   - Desolder   " 
            Case 2            '1234567890123456
                Print At 1,1, "-> - Desolder   "
                Print At 2,1, "   - Fixed temp "
            Case 3            '1234567890123456
                Print At 1,1, "-> - Fixed temp "
                Print At 2,1, "   - Pre-heat   "
        EndSelect                          
        'Knoppen inlezen
        GoSub KnoppenInlezen  
        'Bladeren in menu:
        If Toets = Pijl_down Then 
            DelayMS 20 
            If Menu_Item < 3 Then
                Inc Menu_Item
            Else 
               Menu_Item = 0
            EndIf 
        EndIf
        If Toets = Pijl_up Then 
            DelayMS 20 
            If Menu_Item > 0 Then
                Dec Menu_Item
            Else 
               Menu_Item = 3
            EndIf
        EndIf          
        'Menu item enteren
        If Toets = Enter Then 
            Select Menu_Item
                Case 0
                    GoTo Preheat
                Case 1
                    GoTo Reflow
                Case 2
                    GoTo Desolder
                Case 3
                    GoTo Fix_temp
            EndSelect  
        EndIf        
        DelayMS 100
    Wend 
GoTo Menu 
'****************************************************************   
Preheat: 
    Cls           '1234567890123456
    Print At 1,1, "  - Pre-heat -  "
    setpoint = 75
    T0IE = 1
    GIE  = 1
    While 1 = 1
        GoSub Regel 
        GoSub KnoppenInlezen 
        If Toets = Back Then
            T0IE = 0
            GIE  = 0
            GoTo Menu
        EndIf 
    Wend 
    GoTo Menu
'****************************************************************    
Reflow:
    Cls
    T0IE = 1
    GIE  = 1
    setpoint = 0
    For tijd = 0 To 38
                      '1234567890123456
        Print At 1,1, "- Reflow - ", Dec2 tijd, "/38"   
        setpoint = LookUpL tijd, [20,37,53,70,86,102,118,129,140,150,155,160,165,169,172,175,177,179,180,197,213,230,230,230,213,197,180,170,160,150,140,130,120,110,100,90,70,40,20]
        For chrono = 0 To 100
            GoSub Regel
            GoSub KnoppenInlezen 
            If Toets = Back Then
                GoTo Menu
            EndIf 
            DelayMS 100
        Next
    Next
    setpoint = 0
    GoSub Regel
    T0IE = 0
    GIE  = 0
    While 1 = 1 
        GoSub Zoemen
        DelayMS 250
        GoSub KnoppenInlezen
        If Toets = Back Then
            GoTo Menu
        EndIf  
    Wend
'****************************************************************
Desolder: 
    Cls
    T0IE = 1
    GIE  = 1
    setpoint = 0
    For tijd = 0 To 38
                      '1234567890123456
        Print At 1,1, "-Desolder- ", Dec2 tijd, "/38"   
        setpoint = LookUpL tijd, [20,37,53,70,86,102,118,129,140,150,155,160,165,169,172,175,177,179,180,197,213,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230]
        For chrono = 0 To 100
            GoSub Regel
            GoSub KnoppenInlezen 
            If Toets = Back Then
                GoTo Menu
            EndIf 
            DelayMS 100
        Next
    Next
    setpoint = 0
    GoSub Regel
    T0IE = 0
    GIE  = 0
    While 1 = 1 
        GoSub Zoemen
        DelayMS 250
        GoSub KnoppenInlezen
        If Toets = Back Then
            GoTo Menu
        EndIf  
    Wend
'****************************************************************
Fix_temp:   
    Cls           '1234567890123456
    Print At 1,1, " - Fixed temp - "
    digit = 1
    setpoint = 0
    While 1 = 1
       GoSub KnoppenInlezen 
       Print At 2,1, "Temp: ", Dec setpoint, "°C    "
       If Toets < 10 Then           
            Select digit
                Case 1
                    setpoint = Toets   
                    Inc digit  
                Case 2
                    setpoint = (setpoint * 10) + Toets 
                    Inc digit 
                Case 3
                    setpoint = (setpoint * 10) + Toets 
            EndSelect      
       EndIf
       If Toets = Enter Then
            Break
       EndIf                   
       If Toets = Back Then
            If digit = 0 Then
                GoTo Menu
            EndIf
            Dec digit 
            setpoint = setpoint / 10
       EndIf 
    Wend          '1234567890123456
    Print At 2,1, "     Start?     "
    While 1 = 1
       GoSub KnoppenInlezen 
       If Toets = Back Then
            GoTo Fix_temp
       EndIf
       If Toets = Enter Then
            Break
       EndIf
    Wend  
    
    T0IE = 1
    GIE  = 1
    While 1 = 1 
        GoSub Regel  
        GoSub KnoppenInlezen 
        If Toets = Back Then
            T0IE = 0
            GIE  = 0
            GoTo Menu
        EndIf
    Wend    
'****************************************************************
End