'Terminal:
'обычный режим -   V>292 I>0 Pa>0 Pf>0 F>0
'нажата кнопка при старте - аналоговый SETUP. DC shift
'нажата кнопка в конце полосы - цифровой SETUP. Калибровка.

$regfile = "m8def.dat"                                      ' мега8
$crystal = 8000000
$baud = 4800
$hwstack = 32                                               ' default use 32 for the hardware stack
$swstack = 10                                               ' default use 10 for the SW stack
$framesize = 40                                             ' default use 40 for the frame space

Config Portb.3 = Output , Portb.4 = Output , Portc.3 = Input
Set Portc.3
Led1 Alias Portb.3 : Led2 Alias Portb.4 : Button1 Alias Pinc.3

'Const Uk = 800 : Const Ik = 216 : Const Ik2 = 5000   :period=25 : dmod.0=1-VAPFI(default):dmod.1=1-osc

Dim I(200) As Word , U(200) As Word
Dim N As Byte , Zzz As Word , A As Byte                     ', Xxx As Integer
Dim Result As Word At $0388 , L As Byte At $0388 Overlay , H As Byte At $0389 Overlay , K As Byte , Button1state As Byte , Dispmode As Byte
Dim Umax As Word , Umin As Word , Umid As Long , Chan As Byte
Dim Imax As Word , Imin As Word , Imid As Long
Dim Urms As Long , Irms As Long , Xl As Long , Pact As Long , Pl As Long , Ns As Word , Pfull As Long , Fi As Long , Icom As Long
Dim Uk As Word , Ik As Word , Ik2 As Word , Ur As Integer , Ir As Integer , Lin As String * 6
Dim Countmes As Long , Countsum As Long , Countdisp As Long
Dim Mmode As Byte , Sflag As Byte
Dim M As Byte , D As Byte , Digs As Byte , Dign As Byte , Digraz(4) As Byte , P1 As Word , J As Byte
Dim Period As Byte , Gumax As Byte , Gumin As Byte , Gimax As Byte , Dmod As Byte
Dim Uke As Eram Word , Ike As Eram Word , Ik2e As Eram Word , Periode As Eram Byte , Gumaxe As Eram Byte , Gumine As Eram Byte , Gimaxe As Eram Byte , Dmode As Eram Byte

Declare Sub Dval(byval Dsing As Long)

Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
Config Lcd = 20 * 2
Cursor Off
Deflcdchar 0 , 31 , 17 , 17 , 17 , 31 , 32 , 32 , 32        ' пустышка
Deflcdchar 1 , 31 , 17 , 21 , 17 , 31 , 32 , 32 , 32        ' 1 точка
Deflcdchar 2 , 31 , 31 , 27 , 31 , 31 , 32 , 32 , 32        ' черный квадрат
Deflcdchar 3 , 31 , 31 , 32 , 32 , 32 , 32 , 32 , 32        ' replace ? with number (0-7)
Deflcdchar 4 , 32 , 32 , 32 , 32 , 32 , 32 , 31 , 31        ' replace ? with number (0-7)
Deflcdchar 5 , 31 , 31 , 32 , 32 , 32 , 32 , 31 , 31        ' replace ? with number (0-7)
Deflcdchar 6 , 31 , 31 , 31 , 31 , 31 , 31 , 31 , 31        ' replace ? with number (0-7)

Cls
Config Adc = Single , Prescaler = 16 , Reference = Internal ' 0-Is 1-Ib 2-Uref(1.26) 5-U
On Adc Adc_int
Start Adc
Reset Led1 : Reset Led2
Button1state = Button1
Cls
'    1234567801234567890
Lcd "Power Meter  v2.0"
Print "PM 1.0"
Locate 2 , 1
For N = 1 To 20
   Lcd Chr(255)
   Waitms 100
Next

Gosub Init
If Button1 = 0 Then Gosub Setup
Set Led2
N = 1 : Countmes = 0 : Countsum = 0
Enable Adc
'Enable Timer1
Config Watchdog = 2048
Start Watchdog
Enable Interrupts
Mmode = 1
Dispmode = 1
Cls
Start Adc

Do
 Urms = 0 : Irms = 0 : Pact = 0 : Ns = 0
 For J = 1 To Period
   Reset Watchdog
   Admux = 197
   Do : Power Adcnoise : Loop Until Result < 500
   Do : Power Adcnoise : Loop Until Result > 500
   If Mmode = 1 Then
      Chan = 192                                            '0 channel
      Icom = Ik
    Else
      Chan = 193                                            '1 channel
      Icom = Ik2
   End If
   'Pk = Uk * Icom                                           'вычисление константы для мощности
   For N = 1 To 200
      Admux = Chan                                          'выбор ADC0 (192+номер ADC)
      Power Adcnoise                                        'замер
      I(n) = Result
      Admux = 197                                           'выбор ADC5 (192+номер ADC)
      Power Adcnoise                                        'замер
      U(n) = Result
      If N > 120 And Result > 500 Then Exit For
      For K = 1 To 4 : Next K
   Next N
   Ns = Ns + N                                              'all count
   Umax = 0 : Umin = 1023 : Umid = 0 : Imax = 0 : Imin = 1023 : Imid = 0
   For K = 1 To N
       If Umax < U(k) Then Umax = U(k)
       If Umin > U(k) Then Umin = U(k)
       Umid = Umid + U(k)
       If Imax < I(k) Then Imax = I(k)
       If Imin > I(k) Then Imin = I(k)
       Imid = Imid + I(k)
   Next K
   If Imin = 0 Or Imax = 1023 Then
      Set Led1
    Else
      Reset Led1
   End If

   Umid = Umid / N
   Imid = Imid / N

   If Dmod.1 = 1 Then                                       'osc
      For K = 1 To N
         Print K ; " " ; U(k) ; " " ; I(k)
         Reset Watchdog
      Next
   End If

   For K = 1 To N                                           'rms main calculation
      Ur = U(k) - Umid : Xl = Ur * Ur : Urms = Urms + Xl
      Ir = I(k) - 512 : Xl = Ir * Ir : Irms = Irms + Xl : Ir = -ir
      Pl = Ur * Ir : Pact = Pact + Pl
   Next K
   If Button1 = 0 Then
      Dispmode = 1 - Dispmode
      Waitms 300 : Cls
   End If
 Next J                                                     'end of measuring of 8 waves
   'calc
   Urms = Urms / Ns : Urms = Sqr(urms) : Urms = Urms * Uk : Urms = Urms / 1000       '  Urms - напряжение, реал
   Irms = Irms / Ns : Irms = Sqr(irms) : Irms = Irms * Icom : Irms = Irms / 1000       'Irms - ток*100
   Pact = Pact / Ns : Pact = Pact / 1000 : Pact = Pact * Uk : Pact = Pact * Icom : Pact = Pact / 10000 : If Pact < 0 Then Pact = 0       'активная
   Pfull = Urms * Irms : Pfull = Pfull / 10                 'полная*10
   Fi = Pact * 100 : Fi = Fi / Pfull
   If Dmod.0 = 1 Then Print "V>" ; Urms ; " I>" ; Irms ; " Pa>" ; Pact ; " Pf>" ; Pfull ; " F>" ; Fi
   If Mmode = 1 Then
        If Imax = 1023 Or Imin = 0 Then Mmode = 2
   End If
   If Mmode = 2 Then
        If Imax < 522 And Imin > 488 Then Mmode = 1
   End If
   Zzz = Irms / 100
   If Urms < Gumin Or Urms > Gumax Or Zzz > Gimax Then Reset Led2       'предохранитель
   Incr Countmes : Countsum = Countsum + Pact
   If Button1state = 0 Then
      Locate 1 , 1 : Lcd "U " ; Umin ; " " ; Umax ; " >" ; Umid ; " #" ; N ; "  "
      Locate 2 , 1 : Lcd "I " ; Imin ; " " ; Imax ; " >" ; Imid
      Locate 2 , 18 : Zzz = Getadc(2) : Lcd Zzz
    Else                                                    'основной режим ++++++++++++
      If Dispmode = 1 Then
         Gosub Dispdig
         Locate 1 , 17 : Lcd Urms
         Lin = Str(irms)
         Locate 2 , 17 : Lcd Format(lin , "0.00")           '\\\\\\\\\\\\\
      Else
         Locate 1 , 1
         Call Dval(pact)                                    ' отображаем активную мощность
         Lcd "W  " ; Urms ; "V "                            'V
         If Irms < 1000 Then Lcd " "
         Lin = Str(irms)
         Lcd Format(lin , " 0.00") ; "A "                   'A  \\\\\\\\\\\\\\\\
         Locate 2 , 1                                       'Full Power
         Call Dval(pfull)
         Lcd "VA " ;
         If Pact < 1 Then
            Lcd "    "
         Else
            If Fi > 100 Then Fi = 100
            Lin = Str(fi)
            Lcd Format(lin , "0.00")                        'Fi  \\\\\\\\\\\\\\\\\\\\
         End If
         Lcd " "
         Countdisp = Countsum / Countmes
         Locate 2 , 14
         Call Dval(countdisp)
         Lcd "avW"                                          ' Last Mode
      End If
   End If
      Locate 1 , 20
      If Sflag = 1 Then
         Lcd Chr(mmode)                                     'symbol
         Sflag = 0
      Else
         Lcd Chr(0)
         Sflag = 1
      End If


 Loop
'-------------------------------------------------------------------------------------------------------------------

Adc_int:
   L = Adcl                                                 'младший байт результата - считывать обязательно первым
   H = Adch                                                 'старший байт результата
Return

Sub Dval(byval Dsing As Long)                               'мощность*10
      Local L1 As String * 6
      If Dsing < 1000 Then
         L1 = Str(dsing)
         Lcd Format(l1 , " 0.0")
      Else
         Dsing = Dsing \ 10
         L1 = Str(dsing)
         Lcd Format(l1 , "   0")
      End If
End Sub

Dispdig:                                                    'xp
P1 = Pact \ 10
Zzz = P1 \ 1000 : Digraz(1) = Zzz
Zzz = P1 \ 100 : Digraz(2) = Zzz Mod 10
Zzz = P1 \ 10 : Zzz = Zzz Mod 10 : Digraz(3) = Zzz
Zzz = P1 Mod 10 : Digraz(4) = Zzz
If Digraz(1) = 0 Then
   Digraz(1) = 10
   If Digraz(2) = 0 Then
   Digraz(2) = 10
      If Digraz(3) = 0 Then
         Digraz(3) = 10
      End If
   End If
End If
For M = 0 To 3                                              'знакоместо
   For D = 1 To 3                                           'символ из трех клеток
      Dign = M * 4 : Dign = Dign + D
      Zzz = Digraz(m + 1) * 3 : Zzz = Zzz + D : Decr Zzz
      Locate 1 , Dign : Digs = Lookup(zzz , Digh) : Lcd Chr(digs)
      Locate 2 , Dign : Digs = Lookup(zzz , Digl) : Lcd Chr(digs)
   Next
Next
Return

Init:
If Periode = 255 Then
   Uke = 800 : Ike = 216 : Ik2e = 5000 : Periode = 25 : Gumine = 160 : Gumaxe = 245 : Gimaxe = 16 : Dmode = 1
End If
Uk = Uke : Ik = Ike : Ik2 = Ik2e : Period = Periode : Gumin = Gumine : Gumax = Gumaxe : Gimax = Gimaxe : Dmod = Dmode
Return

Setup:
Cls : Lcd "setup"
Print "Setup"
Do
Gosub Setup2
Input "Choice >" , Zzz
Print "> ";
If Zzz = 1 Then Input Uk
If Zzz = 2 Then Input Ik
If Zzz = 3 Then Input Ik2
If Zzz = 4 Then Input Period
If Zzz = 5 Then Input Gumin
If Zzz = 6 Then Input Gumax
If Zzz = 7 Then Input Gimax
If Zzz = 8 Then Input Dmod

Loop Until Zzz = 0
Uke = Uk : Ike = Ik : Ik2e = Ik2 : Periode = Period : Gumine = Gumin : Gumaxe = Gumax : Gimaxe = Gimax : Dmode = Dmod

Print " EXIT"
Return

Setup2:
Print "---"
Print "1.Uk " ; Uk
Print "2.Ik1 " ; Ik
Print "3.Ik2 " ; Ik2
Print "4.Period " ; Period
Print "5.Umin " ; Gumin
Print "6.Umax " ; Gumax
Print "7.Imax " ; Gimax
Print "8.Disp " ; Dmod
Print "0.Exit"

Return

'         0    |     1      |    2      |      3    |    4       |     5     |     6     |    7      |    8      |    9      | 10 pusto
Digh:
Data 6 , 3 , 6 , 3 , 6 , 32 , 5 , 5 , 6 , 3 , 5 , 6 , 6 , 4 , 6 , 6 , 5 , 5 , 6 , 5 , 5 , 3 , 3 , 6 , 6 , 5 , 6 , 6 , 5 , 6 , 32 , 32 , 32

Digl:
Data 6 , 4 , 6 , 4 , 6 , 4 , 6 , 4 , 4 , 4 , 4 , 6 , 32 , 32 , 6 , 4 , 4 , 6 , 6 , 4 , 6 , 32 , 32 , 6 , 6 , 4 , 6 , 4 , 4 , 6 , 32 , 32 , 32


'Setup
'---
'1.uk 800
'2.Ik1 216
'3.Ik2 5000
'4.Period 25
'5.Umin 160
'6.Umax 245
'7.Imax 16
'8.Disp 1  1-то же, что на дисплее 2-осциллограмма 3=1+2
'0.Exit
'Choice >