program palesz
' Description:   Pálinkafőző, 3 hőérzékelővel
' Copyright:     izifer          Date:   2015.05.01
' Configuration: MCU: PIC16F1829  Osc.:  16 MHz
'                CONFIG1($8007) = 0x2F84   |   CONFIG2($8008) = 0x1613
'                SW:   mikroBasic Pro v6.5.0 & Proteus v7.9
' ************ symbols & variables *********************************************
' D7 = C.7 | D6 = C.6 | D5 = C.5 | D4 = C.4 | EN = C.3 | RS = C.2 | x | x |
symbol lcd_port = LATC
symbol lcd_RS  = $04       symbol lcd_EN  = $08
symbol RSbit   = LATC.2    symbol Ebit    = LATC.3
symbol OKb     = PORTA.3   symbol UPb     = PORTA.4   symbol DOb    = PORTA.5
symbol FG      = LATB.4    symbol HG      = LATB.5    symbol ZC     = LATB.6
symbol man     = flag.7    symbol BSen    = flag.0    symbol newdat = flag.1
dim
  txt16  as char[16]
  txt4   as char[4]
  txt3   as char[3]

  BSpeed, dt               as byte         'dt=érték változtatási késlelt.
  flag     as byte         absolute $20    'flag bitek
  BWait    as byte         absolute $21    'ButtonWait
  power    as byte         absolute $22    'kézi fűtőteljesítmény
  PID_num  as byte         absolute $23
  menun    as byte         absolute $24    'menű sorszáma
  i        as byte         absolute $25    'Fij i sorszáma
  j        as byte         absolute $26    'Fij j sorszáma
  Ktemp    as short        absolute $27    'Kazán  számolt C° érték
  Ttemp    as short        absolute $28    'Torony számolt C° érték
  Htemp    as short        absolute $29    'Hűtő   számolt C° érték
  HGd      as word         absolute $2A    'Hűtő TRIAC gate késleltetés
  ms10num  as byte         absolute $2C    '10ms számláló
  temp     as short        absolute $2D    'átmeneti tároló
  Ksum     as word         absolute $2E    'összegzett AD értékek
  Tsum     as word         absolute $30
  Hsum     as word         absolute $32
  min      as short        absolute $34    'min. érték a változtatás procban
  max      as short        absolute $35    'max. érték a változtatás procban
  Aij      as short [4][2] absolute $36    '8 byte-os tömb
  F1BE     as short        absolute $36    '= Aij[0][0]
  F1KI     as short        absolute $37    '= Aij[0][1]
  F2BE     as short        absolute $38    '= Aij[1][0]
  F2KI     as short        absolute $39    '= Aij[1][1]  ¬ [x]=hőmérséklet

const 
  BWmax = 11              ' BWmax = max. várakozási idő = 10s (11-1 = 10)
  ptr    as ^byte         ' kiírandó byte címét mutatja
  adat    = "ADAT"
  ment    = "ELMENTVE!"
  noment  = "ELVETVE!"
  cg     as byte[64] = (2, 4,14, 1,15,17,15,0, ' /8  á (0=end karakter)
                        2, 4,14,17,31,16,14,0, '1/9  é
                        2, 4,14,17,17,17,14,0, '2/10 ó
                        5,10,14,17,17,17,14,0, '3/11 ő  ö van => $EF (239)
                        2, 4, 0,17,17,17,14,0, '4/12 ú
                        5,10, 0,17,17,17,14,0, '5/13 ű  ü van => $F5 (245)
                        4, 4,31, 4, 4, 0,31,0, '6/14 +-
                        7, 5, 7, 0,12,16,12,0) '7/15 c°
                      '  P   á   l   i   n   k   a   f   ő   z   ő
  palin as byte [12] = ($50,$08,$6C,$69,$6E,$6B,$61,$66,$03,$7A,$03,0)
                      '  K   i   l   é   p   é   s   ?
  kilep as byte [9]  = ($4B,$69,$6C,$09,$70,$09,$73,$3F,0)
                      '  V   i   s   z   l   á   t   .   .   .
  viszl as byte [11] = ($56,$69,$73,$7A,$6C,$08,$74,$2E,$2E,$2E,0)
                       '  K   a   z   á   n   :
'  kazan  as byte [7]  = ($4B,$61,$7A,$08,$6E,$3A,0)
'************* delay u1 * 1us procedure ****************************************
sub procedure delayus(dim u1 as word)
  While u1   <> 0   
    delay_us(1)   
    dec(u1)   
  Wend
end sub
'************* delay u100 * 100us procedure ************************************
sub procedure delay100us(dim u100 as byte)
  While u100 <> 0   
    delay_us(100)   
    dec(u100)   
  Wend
end sub
'************* delay m1 * 1ms procedure ****************************************
sub procedure delayms(dim m1 as word)
  While m1 <> 0
    delay_ms(1)   
    dec(m1)   
  Wend
end sub
'************* toggle E bit procedure ******************************************
sub procedure chEbit()  
  Ebit = 1   
  delayus(10)
  Ebit = 0   
end sub
'************* LCD COMMAND OUT procedure ***************************************
sub procedure lcd_com (dim cmd as byte)
  RSbit = 0   
  lcd_port = (lcd_port and $0F) or (cmd and $F0)  
  chEbit
  lcd_port =  (lcd_port and $0F) or (cmd << 4)                
  chEbit
  If cmd > 2 Then delayus(40) Else delayms(2) End If
end sub
'************* LCD SET POSITION procedure **************************************
sub procedure lcd_pos(dim sor, osz as byte )
  lcd_com($80 + (64 * (sor-1)) + (osz - 1))
end sub
'************* LCD CLEAR procedure *********************************************
sub procedure lcd_clear()  
  lcd_com(1)   
end sub
'************* LCD HOME procedure **********************************************
sub procedure lcd_home()   
  lcd_com(2)   
end sub
'************* LCD LEFT procedure **********************************************
sub procedure lcd_left()   
  lcd_com($10)  
end sub
'************* LCD DISPLAY, CURSOR, BLINK ON/OFF procedure *********************
sub procedure lcd_display (dim d, c, b as byte)
  lcd_com($08+(4*d)+(2*c)+b)          ' d=display; c=cursor; b=blink on/off
end sub                               ' 1=ON; 0=OFF
'************* LCD INIT procedure **********************************************
sub procedure lcd_init()
  RSbit = 0   
  Ebit = 0   
  delayms(50)
  lcd_port = $30
  chEbit  
  delayms(5)  'reset
  chEbit  
  delayms(1)
  chEbit  
  delayms(1)
  lcd_port.4 = 0
  chEbit  
  delayms(1)          '             |
  lcd_com($28)        ' | 0| 0| 1|DL| N| F| x| x| => DL=0 4bit, N=1 2 sor
  lcd_com($0C)        ' | 0| 0| 0| 0| 1| D| C| B| => Display ON, cur & bl OFF
  lcd_com($01)        ' lcd clear
  lcd_com($06)        ' | 0| 0| 0| 0| 0| 1|ID| S| => DDRAM auto inc., no shift
end sub
'************* LCD ONE BYTE OUT procedure **************************************
sub procedure lcd_byte (dim dat as byte)
  RSbit = 1  
  lcd_port = (lcd_port and $0F) or (dat and $F0)      
  chEbit
  lcd_port = (lcd_port and $0F) or (dat << 4)                    
  chEbit
  delayus(40)
  RSbit = 0
end sub
'************* LCD BYTE's STRING OUT procedure *********************************
sub procedure lcd_bytes(dim sor, osz as byte)
  lcd_pos(sor, osz)                    ' @txt   = a txt címe
  RSbit = 1                            ' ptr^  = ptr cím tartalma
  while (ptr^ <> 0)                    ' ... while byte = 0
    lcd_byte(ptr^)
    inc(ptr)
  wend
  RSbit = 0
end sub
'************* LCD ONE CHARACTER OUT to (s, o) position procedure **************
sub procedure lcd_ch (dim sor, osz, chout as byte)
  lcd_pos(sor, osz)
  lcd_byte(chout)
end sub
'************* LCD TEXT STRING OUT to (s, o) position procedure ****************
sub procedure lcd_txt (dim s, o as byte, dim byref outstr as string)
  lcd_pos(s, o)
  RSbit = 1
  FSR0  = @outstr
  While INDF0 <> 0   
    lcd_byte(INDF0)   
    inc(FSR0)   
  Wend
  RSbit = 0
end sub
'************* ADC read ********************************************************
sub function ADread(dim ch as byte) as word
  ch = ch << 2
  ADCON0 = (ADCON0 and $01) or ch      'select AN chanel
  delay_us(5)                          'acquisition time delay
  ADCON0.1 = 1                         'start ADC
  while ADCON0.1 = 1 wend              'wait to finish ADC
  lo(result) = ADRESL
  hi(result) = ADRESH
end sub
'************* Hőfok számítás **************************************************
sub function hofok (dim ADsum as word) as integer
  ADsum = ADsum >> 6                   'osztás 64-el
  result = ADsum * 0.2 - 50            'Ta=(0,2 * AD) - 50
end sub
'************* interrupt procedure *********************************************
sub procedure interrupt                'IOC (ZC) interrupt every 10 ms
  i = LATB
  asm
    movlw 0xff
    xorwf IOCBF, W
    andwf IOCBF, F
  end asm
  IOCBF = 0                            'clear IOC bit
  Ksum = Ksum + ADread(0)              'Kazán hőérzékelője
  Tsum = Tsum + ADread(1)              'Torony hőérzékelője
  Hsum = Hsum + ADread(2)              'Hűtő hőérzékelője
  if inc(ms10num) = 64 then            '640 ms telt el
    Ktemp = hofok(Ksum)                'MCP -> Vout=500mV + (10mV/C° * TaC°)
    Ttemp = hofok(Tsum)                'Uref = 2046mV,; LSB = 2mV
    Htemp = hofok(Hsum)                'Ta[C°] = (AD * 2mV - 500mV) / 10[mV/C°]
    newdat = 1
  end if
  if ms10num = 100 then                '1000 ms (1 sec) telt el
    ms10num = 0                        'set for next one sec
    inc(BWait)                         'ButtonWait increment every second
    if BSen then inc(BSpeed) end if    'ButtonSpeed increment if enabled
    Ksum = 0 Tsum = 0 Hsum = 0
   'else exit'return 'exit
  end if
end sub
'************* menü_0 = STATIC STATE procedure *********************************
'sub procedure menu_0()
'    lcd_clear
'    lcd_display(1,0,0)
'    ptr = @kazan                       'ptr  = "Kazán:" címe
'    lcd_txt(1,15,"Cß")                 'C°
'    lcd_bytes(1,3)
'    lcd_txt(2,2, "Bojler:      Cß")
'end sub
'************* menü_1 = F1 (BOYLER) ON/OFF procedure ***************************
sub procedure menu_1()
    lcd_clear   '1234567890123456
    lcd_txt(1,1,"F1BE: [B]     Cß")
    lcd_txt(2,1,"F1KI: [B]     Cß")
    shorttostr(Aij[0][0],txt4)  lcd_txt(1,10,txt4)     'F1BE
    shorttostr(Aij[0][1],txt4)  lcd_txt(2,10,txt4)     'F1KI
end sub
'************* menü_2 = F2 (RADIÁTOR) ON/OFF procedure *************************
sub procedure menu_2()
    lcd_clear   '1234567890123456
    lcd_txt(1,1,"F2BE: [K]     Cß")
    lcd_txt(2,1,"F2KI: [K]     Cß")
    shorttostr(Aij[1][0],txt4)  lcd_txt(1,10,txt4)     'F2BE
    shorttostr(Aij[1][1],txt4)  lcd_txt(2,10,txt4)     'F2KI
end sub
'************* menü_3 = MINBE/HISZTERÉZIS változtatás procedure ****************
sub procedure menu_3()
    lcd_clear   '1234567890123456
    lcd_txt(1,1,"MINBE:        Cß")
    lcd_txt(2,1,"HISZT:        Cß")
    shorttostr(Aij[2][0],txt4)  lcd_txt(1,10,txt4)     'MINBE
    shorttostr(Aij[2][1],txt4)  lcd_txt(2,10,txt4)     'HISZTERÉZIS
end sub
'************* menü_4 = [K] és [B] korrekció procedure *************************
sub procedure menu_4()
    lcd_clear   '1234567890123456
    lcd_txt(1,1,"[K] korr:     Cß")
    lcd_txt(2,1,"[B] korr:     Cß")
    shorttostr(Aij[3][0],txt4)  lcd_txt(1,10,txt4)     '[K] korrekció
    shorttostr(Aij[3][1],txt4)  lcd_txt(2,10,txt4)     '[B] korrekció
end sub
'************* menü_5 = KILÉPÉS procedure **************************************
sub procedure menu_5()
    lcd_clear   ptr = @kilep    lcd_bytes(1,2)         'ptr  = "Kilépés?" címe
end sub
'************* menü kiiratás procedure *****************************************
sub procedure menu_kiir(dim menun as byte)
    lcd_display(1,0,0)
    select case menun
       case 1   menu_1()               'F1 ON/OFF
       case 2   menu_2()               'F2 ON/OFF
       case 3   menu_3()               'MINBE/HISZTERÉZIS
       case 4   menu_4()               '[K]/[B] korrekció; [x]=hőmérséklet
       case 5   menu_5()               'kilépés
    end select
end sub
'************* EEPROM WRITE procedure ******************************************
sub procedure epromw(dim i,j as byte)
    eeprom_write(2*i+j, Aij[i][j])
end sub
'************************** FILL LCD CGRAM *************************************
sub procedure fill_cgram()
   lcd_com($40)  RSbit = 1   FSR0  = @cg   
   for i = 0 to 63      lcd_byte(INDF0)      inc(FSR0)   next i   RSbit = 0
end sub
'************* INCREMENT BYTE procedure ****************************************
sub procedure inc_b (dim byref temp, min, max as short, dim s, o as byte)
    BSen = 0 Bspeed = 0 dt = 255       '255ms Up/Down speed
    while UPb = 0
       BSen = 1 BWait = 0              'enable ButtonSpeed counter on IT
       if BSpeed > 1 then dt=50 end if '80ms Up/Down speed
       inc(temp)   if temp > max then temp = min end if
       shortToStr(temp, txt4)   lcd_txt(s,o,txt4)
       delayms(dt)                     '255/80 ms léptetési sebesség
    wend
end sub
'************* DECREMENT BYTE procedure ****************************************
sub procedure dec_b (dim byref temp, min, max as short, dim s, o as byte)
    BSen = 0 Bspeed = 0 dt = 255       '255ms Up/Down speed
    while DOb = 0
       BSen = 1 BWait = 0              'enable ButtonSpeed counter on IT
       if BSpeed > 1 then dt=50 end if '80ms Up/Down speed
       dec(temp)   if temp <= min then temp = max end if
       shortToStr(temp, txt4)   lcd_txt(s,o,txt4)
       delayms(dt)                     '255/80 ms léptetési sebesség
    wend
end sub
'************* adat változtatása procedure *************************************
sub procedure change (dim menun, i as byte)
   BWait = 0   lcd_display(1,0,1)   temp = Aij [i][0] 'temp = Fij[menun - 1] [0]
   while BWait < BWmax
      lcd_pos(j+1,14)
      if UPb = 0 then                  'adat növelése
         inc_b (temp, min, max, j+1, 10)
      end if
      if DOb = 0 then                  'adat csökkentése
         dec_b (temp, min, max, j+1, 10)
      end if
      if OKb = 0 then                  'kilépés! mentés is?
         BWait = 0
         while OKb = 0 wend
         lcd_clear   lcd_display(1,0,0)
         lcd_txt(1,7,adat)             'adat = ADAT
         if BWait > 1 then             'mentés!
            Aij[i][j] = temp
            epromw(i, j)
            lcd_txt(2,5,ment)          'ment = MENTVE!
          else                         'nincs mentés!
            lcd_txt(2,5,noment)        'noment = ELVETVE!
         end if
         delayms(1000)
         inc(j)                        'j=0 --> első érték változtatása
         BWait = 0                     'j=1 --> második érték változtatása
         if  j = 2 then exit end if    'j=2 --> ez a menű kész ...
         temp  = Aij[i][j]             'temp = Aij[menun - 1][1] ; j = 1
         menu_kiir(menun)
         lcd_display(1,0,1)            'villogtatás
      end if
   wend
end sub
'************* main program ****************************************************
main:
TRISA      = %00111111                 'RA5-0 port are input
ANSELA     = %00000111                 'AN2-AN0 are analog input
WPUA       = %00111000                 'Pull up on RA5-3 pin
IOCAF      = 0

LATB       = %00000000
TRISB      = %11000000                 'RB7-6 input; RB5-4 digital output
ANSELB     = 0                         'upper ports are digital
WPUB       = 0
IOCBP      = %01000000                 'for ZC; rising edge on RB6
IOCBN      = %01000000                 'for ZC; falling edge
IOCBF      = 0

LATC       = 0
TRISC      = %00000011                 'RC7-2 port are output
ANSELC     = 0

INTCON.IOCIF = 0
INTCON.GIE = 1
INTCON.IOCIE = 1                       'IOCIE enabled
FVRCON     = %10000010                 'FVR enable, temp disable, ADCref=2048mV
ADCON0     = %00000001                 'AD enable
ADCON1     = %10100011                 'right jus; Fosc/32; V- = VSS; V+ = FVR
OPTION_REG = %01111111                 'Weak Pull-up Enable
OSCCON     = %01111010                 'no PLL, 16MHz, internal osc.
T1CON      = %00100000                 'Fosc/4; 1:4 prescale; TMR1 disable

Ksum = 0   Tsum   = 0
Hsum = 0   newdat = 0                  'set variables
FG   = 0   HG     = 0  ms10num  = 0
man  = 1   power  = 0                  'kézi mód, fűtés kikapcsolva


'************* EPROM reads *****************************************************
'for i = 0 to 3                         '[i][j]              [i][j]
'   for j = 0 to 1                      '[0][0] = F1BE;      [0][1] = F1KI
'      Aij[i][j] = eeprom_read(2*i+j)   '[1][0] = F2BE;      [1][1] = F2KI
'   next j                              '[2][0] = MINBE;     [2][1] = HISZT
'next i                                 '[3][0] = [K] korr;  [3][1] = [B] korr
lcd_init
lcd_display(1,0,0)
fill_cgram()
ptr = @palin                           'ptr  = "Pálinkafőző" címe
lcd_bytes(1,3)                         'ptr^ = ptr cím tartalma
lcd_txt(2,2,"made by IZIFER")
delayms(3000)
lcd_clear()
lcd_txt(1,1,"M %  Kaß Toß H ß")        'ß = °
lcd_ch(1,15,5)                         'ű betű

'************* setup & run for ever ********************************************
while true
   if IOCBF.6 then
     IOCBF.6 = 0
   end if
   if man then
     PID_num = power 
   end if
   for i = 1 to PID_num
     FG = 1
     delayms(10)
   next i
   for i = 1 to (100 - PID_num)
     FG = 0
     delayms(10)
   next i
  if Htemp >= 30 then
    HG = 1                             'Hűtő TRIAC be, ha a hűtő min. 30C°-os
   else
    HG = 0
    if Htemp > 20 then                 'Htemp = 29 ÷ 21 C°
      HG = 0
      HGd = 100 * (30 - Htemp)         'HGd (HG delay) = 100 ÷ 900
      HGd = 65535 - HGd                'HGd =
      TMR1H = hi(HGd)
      TMR1L = lo(HGd)
      T1CON.0 = 1                      'start TMR1
      if PIR1.0 = 1 then               'TMR1F=1 > letelt a 100÷900 us várakozás
       HG = 1                          'a TRIAC indítása 50us-os pulzussal
       delay_us(50)
      end if
      HG = 0
    end if
  end if
'   PID_num=60 Ktemp=82 Ttemp= 70 Htemp= 20
   if newdat then                      'új hőértékek frissítése az LCD-n
      newdat = 0
      shorttostr (PID_num, txt3)   lcd_txt(2,0,txt3)
      shorttostr (Ktemp,   txt3)   lcd_txt(2,4,txt3)
      shorttostr (Ttemp,   txt3)   lcd_txt(2,8,txt3)
      shorttostr (Htemp,   txt3)   lcd_txt(2,12,txt3)
   end if
   if OKb = 0 then                     'menűk:
      BWait = 0                        '1 = F1 BE/KI;      2 = F2 BE/KI
      while OKb = 0 wend               '3 = MINBE/HISZT;   4 = [K][B] korrekció
      if (BWait > 1) then              '5 = kilépés
         menun = 1                     'menun = 1 --> F1 BE/KI
         menu_kiir(menun)
         BWait = 0
         while BWait < BWmax           'lépegetés a menűkben
         if UPb = 0 then
            while UPb = 0 wend
            BWait = 0
            inc(menun)
            if menun = 6 then menun = 1 end if
               menu_kiir(menun)
            end if
            if DOb = 0 then
               while DOb = 0 wend
               BWait = 0
               dec(menun)
               if menun = 0 then menun = 5 end if
               menu_kiir(menun)
            end if
            if OKb = 0 then            'beállítások változtatása
               while OKb = 0 wend
               BWait = 0
               if menun = 5 then       'kilépés, ha menun=5 és OKb
                  lcd_clear 
                  ptr = @viszl         'ptr  = "Viszlát..." címe
                  lcd_bytes(1,2)
                  delayms(1000)
                  break
               end if
               j = 0    i = menun - 1
               select case menun
                  case 1,2,3 min =   0   max = 120
                  case 4     min = -50   max =  50
               end select
               change (menun, i)
               inc(menun)       menu_kiir(menun)
            end if
         wend
'         lcd_clear      lcd_display(1,0,0)       menu_0
      end if
   end if
wend
end.                                   'MŰKÖDÉS, KEZELÉS egy word dokuban!