Labornetzteil

BASCOM-Quellcode Hauptprogramm

Im ersten Teil des Hauptprogrammes werden zuerst die beiden Taster abgefragt und bei Betätigung eine Unterroutine angesprungen. Danach erfolgt die Abfrage der Strom- und Spannungswerte. Ich beschreibe hier nur beispielgebend die Bearbeitung des ersten Kanals für die Spannung von 3,3 Volt. Die beiden anderen Kanäle sind identisch aufgebaut. Zuerst wird in einem Unterprogramm der Wert der Spannung von dem jeweiligen Strom-/Spannungswandler INA219 abgefragt. Dazu werden die Schreib- und Leseadresse, sowie das Register 02 hex in die Variablen übernommen und so dem Unterprogramm übergeben. Der Rückgabewert muss drei Bit nach rechts geschoben werden. Anschließend addiere ich einen Offset, um Toleranzen auszugleichen. Die Auflösung des Wandlers beträgt 4 mV pro Bit. Um auf eine Spannungsanzeige in Volt zu kommen, wird der Wert durch 250 geteilt. Danach erfolgt das Auslesen des Wertes für den Strom in Register 04 hex. Auch hier erfolgt wieder eine Offset-Korrektur. Bei der gewählten Konfiguration des Schaltkreises beträgt die Auflösung des Wandlers 50 µA pro Bit. Für eine Anzeige in Milliampere wird dieser Wert demzufolge mit 20 dividiert. In der nächsten Zeile wird ein Bit einer Variablen gesetzt, falls der gemessene Strom größer als 1 Ampere ist. Diese Variable wird später ausgewertet, um die Warn-LED anzusteuern. In den folgenden beiden Zeilen wird der Maximal- und Minimalwert des Stromes erfasst. Die Berechnung des Durchschnittstromes geschieht nach folgendem Muster: Zuerst wird der aktuell gemessene Strom zu einer Variablen addiert. Solange der Zähler noch nicht den Maximalwert von 32768 erreicht hat, wird dieser erhöht. Den Durchschnitt erhält man anschließend bei der Division der Variablen mit dem Zähler. Wenn der Maximalwert des Zählers erreicht ist, wird statt der Erhöhung des Zählers einmal der Durchschnittswert subtrahiert. Der Maximalwert für den Zähler wurde so gewählt damit die Variable des Durchschnittes nicht überläuft. Bei ca. 15 Messungen pro Sekunde erhält man damit einen Durchschnitt über ca. 36 Minuten. Die Berechnung des Durchschnitts für die serielle Ausgabe erfolgt analog. Eine getrennte Erfassung erfolgt deshalb, weil ich dort den Durchschnitt zwischen zwei Ausgaben haben wollte.

'########################   H A U P T P R O G R A M M    #######################
Do
   'Tastaturabfrage
   Debounce Pind., 0 , Taste_o , Sub                      ' Taster oben
   Debounce Pind., 0 , Taste_u , Sub                      ' Taster unten

   Warning = 0
   'Ausgang 3,3 Volt Spannung messen
   Ina219_adr_w = Ina219_3_adr_w                            ' Schreibadresse INA219 Ausgang 3,3 Volt
   Ina219_adr_r = Ina219_3_adr_r                            ' Leseadresse INA219 Ausgang 3,3 Volt
   Ina219_reg = &H02                                        ' Bus Voltage
   Gosub Ina219_reg_read_w                                  ' Register INA219 lesen
   Shift W , Right , 3                                      ' must bee shifted right by three bits
   W = W + 6                                                ' Offset
   U_3 = W / 250                                            ' Spannung Ausgang 3,3 Volt (4 mV pro Bit)
   'Ausgang 3,3 Volt Strom messen
   Ina219_reg = &H04                                        ' Current
   Gosub Ina219_reg_read_i                                  ' Register INA219 lesen
   I = I - 2                                                ' Offset
   I_3 = I / 20                                             ' Strom Ausgang 3,3 Volt in mA (50 µA pro Bit)
   If I_3 > 1000 Then : Warning.= 1 : End If              ' Strom zu hoch
   If I_3 > I_3_max Then : I_3_max = I_3 : End If           ' Maximalstrom
   If I_3 < I_3_min Then : I_3_min = I_3 : End If           ' Minimalstrom
   'Durchschnitt Strom für lokale Anzeige
   I_3_avg1 = I_3_avg1 + I_3                                ' aktuellen Messwert f r Durchschnitt addieren
   If I_avg_count < 32768 Then                              ' maximal 32768 Messwerte
      Incr I_avg_count                                      ' Zähler für Durchschnitt erhöhen
   Else
      I_3_avg1 = I_3_avg1 - I_3_avg                         ' Durchschnitt subtrahieren
   End If
   I_3_avg = I_3_avg1 / I_avg_count                         ' Durchschnitt Ausgang 3,3 Volt errechnen
   'Durchschnitt Strom für serielle Ausgabe
   I_3_avg_s = I_3_avg1_s / I_avg_count_s                   ' Durchschnitt Ausgang 3,3 Volt errechnen
   I_3_avg1_s = I_3_avg1_s + I_3                            ' aktuellen Messwert für Durchschnitt addieren
   If I_avg_count_s < 32768 Then                            ' maximal 32768 Messwerte
      Incr I_avg_count_s                                    ' Zähler für Durchschnitt erhöhen
   Else
      I_3_avg1_s = I_3_avg1_s - I_3_avg_s                   ' Durchschnitt subtrahieren
   End If
   I_3_avg_s = I_3_avg1_s / I_avg_count_s                   ' Durchschnitt Ausgang 3,3 Volt errechnen

Im Anschluss an die Messungen der Spannungen und Ströme erfolgt die Messung der Kühlkörpertemperatur und Steuerung des Lüfters abhängig von dieser. Der Temperaturwert wird in einem Unterprogramm aus dem Thermometerschaltkreis DS1621 gelesen und umgerechnet. Wenn die Temperatur höher als 45 °C ist, soll der Lüfter anlaufen. Der Wert für die Pulsweitenmodulation wird in Schritten von 5 pro 0,1 °C erhöht. Der Lüfter erreicht seine maximale Drehzahl dadurch bei 60 °C. Der errechnete Wert wird anschließend an Timer 2 übergeben. Bei Temperaturen größer als 50 °C wird noch ein Bit der Variablen "Warning" gesetzt, dadurch wird später die rote LED angesteuert und die Anzeige auf dem Display beginnt zu blinken.

   'Temperatur messen und Lüfter regeln
   Gosub Ds1621_read                                        ' Werte DS1621 auslesen und umrechnen
   If Temperatur >= 450 Then                                ' Lüfterregelung Beginn bei 45 C
      If Temperatur >= 500 Then                             ' ab 50 °C Warnung ausgeben
         Warning.= 1                                      ' LED rot blinkt
      End If
      W = Temperatur - 449                                  ' 1-
      If W <= 50 Then
         Fan_pwm = W * 5                                    ' 0,1 °C - 5,0 °C = 5 - 250
      Else
         Fan_pwm = 255                                      ' volle Drehzahl
      End If
   Else
      Fan_pwm = 0                                           ' Lüfter aus
   End If
   Pwm2b = Fan_pwm                                          ' PWM Timer 2

Den Aufbau der Anzeige und die Menüsteuerung werde ich anhand zweier Menüpunkte beschreiben. Die komplette Struktur ist ist auf der Seite "Menüstruktur" zu sehen. Menüpunkt 0 ist der Ausgangspunkt beim Einschalten des Netzteils und zeigt Spannungen und Ströme aller drei Kanäle an. In der If-Bedingung wird abgefragt, ob ein Neuaufbau der Anzeige nach Menüwechsel notwendig ist. Ist das der Fall, wird das Display gelöscht und bis zum Ausschalten der Hintergrundbeleuchtung nach 30 Sekunden in der ersten Zeile ein Pfeil nach rechts angezeigt. Dies soll anzeigen, das bei Betätigung der oberen Taste zum nächsten Menüpunkt gewechselt wird. Bei jedem Durchlauf der Hauptprogrammschleife wird anschließend die Anzeige der Spannungen und Ströme aktualisiert.

   Select Case Menu
      Case 0                                                ' Anzeige Spannung und Strom
         If Lcd_refresh = 1 Then
            Lcd_refresh = 0 : Cls
            If Lcd_light = 1 Then
               Locate 1 , 40 : Lcd "{199}"                  ' Pfeil nach rechts
            End If
         End If
         'Spannungen anzeigen
         Str6 = Fusing(u_3 , "#.##")                        ' Spannung 3,3 Volt runden und formatieren
         Locate 1 , 4 : Lcd Str6 ; " V"                     ' Spannung Ausgang 3,3 Volt anzeigen
         Str6 = Fusing(u_5 , "#.##")                        ' Spannung 5 Volt runden und formatieren
         Locate 1 , 18 : Lcd Str6 ; " V"                    ' Spannung Ausgang 5 Volt anzeigen
         Str6 = Fusing(u_25 , "#.##")                       ' Spannung 1,25-25 Volt runden und formatieren
         Locate 1 , 31
         If U_25 < 10 Then : Lcd " " ; : End If             ' Leerzeichen anzeigen
         Lcd Str6 ; " V"                                    ' Spannung Ausgang 1,25-25 Volt anzeigen
         'Strom anzeigen
         Lcd_zeile = 2                                      ' Anzeige Zeile
         S = I_3 : Lcd_pos = 2 : Z = 0 : Gosub Lcd_i        ' Strom Ausgang 3 Volt anzeigen
         S = I_5 : Lcd_pos = 16 : Z = 1 : Gosub Lcd_i       ' Strom Ausgang 5 Volt anzeigen
         S = I_25 : Lcd_pos = 30 : Z = 2 : Gosub Lcd_i      ' Strom Ausgang 1,25-25 Volt übernehmen

Beispielgebend hier der Menüpunkt 12 für die Einstellung der Übertragungsrate der seriellen Schnittstelle. Bei Wechsel in diesen Menüpunkt wird in der oberen Zeile die Bedeutung angezeigt und ganz rechts Pfeile nach rechts und darunter nach oben für die Funktion der beiden Tasten. Danach wird in die Variable "Wert" der aktuelle Index der Einstellung übernommen. In der Variablen "Wertmax" wird die obere Grenze, die der Wert annehmen darf, festgelegt. In der folgenden If-Abfrage wird ermittelt, ob eine Taste betätigt wurde. In der Tastaturabfrage wurde die Variable "Wert" verändert und wird anschließend in "Ser_baudindex" übernommen. Dieser Index bestimmt, welcher String anschließend aus der Datentabelle "Table_ser_baud" geladen wird. Der Textstring wird danach in der unteren Zeile des Displays angezeigt. Bei Änderung dieses Index gegenüber dem im EEPROM gespeicherten wird der neue Wert dauerhaft im EEPROM gesichert. Dadurch können beim Neustart des Netzteils die gespeicherten Einstellungen wieder hergestellt werden. Zum Schluss wird noch die serielle Schnittstelle mit dem neuen Wert in einer Unterroutine eingestellt.

      Case 12                                               ' Einstellung Geschwindigkeit serielle Schnittstelle
         If Lcd_refresh = 1 Then
            Lcd_refresh = 0 : Cls
            Upperline : Lcd "Geschwindigkeit serielle Schnittstelle"
            Gosub Lcd_pfeil_lo                              ' Anzeige Pfeil nach rechts und oben
            Wert = Ser_baudindex                            ' Wert übernehmen
            Wertmax = 6                                     ' Einstellwerte Index 0-6
         End If
         If Wert_refresh = 1 Then
            Wert_refresh = 0                                ' nur einmal ausführen
            Ser_baudindex = Wert
            Str6 = Lookupstr(ser_baudindex , Table_ser_baud)
            Lowerline : Lcd Str6
            Locate 2 , 6                                    ' Cursorposition
            If Ser_baudindex <> Ser_baudindex_eram Then
               Ser_baudindex_eram = Ser_baudindex           ' Einstellungen speichern
               Gosub Ser_set_baud                           ' Einstellung Übertragungsrate serielle Schnittstelle
            End If
         End If

Im folgenden Teil werden Warnungen bei zu hoher Stromentnahme oder Übertemperatur ausgewertet. Die rote LED blinkt im Takt von einer halben Sekunden gesteuert von Timer 1. Solange die Warnungen noch nicht durch eine Tastenbetätigung bestätigt wurden, werden in Abhängigkeit der Höhe der Warnmeldung die Menüpunkte 0 oder 10 aktiviert. Die Bits 0 bis 2 der Variablen "Warning" werden durch Überstrom aktiviert und Bit 3 durch Übertemperatur. Der Summer wird wiederum durch Timer 1 aktiviert. Sollte die Temperatur größer als 54,9 °C sein, so wird ein Warnton ausgegeben.

   If Warning >= 1 Then
      If Led_rt <> Blinken.Then
         Led_rt = Blinken.0                                 ' Led rot blinkt
      End If
      If Quittung = 0 Then
         If Warning < 8 Then                                ' Strom zu hoch
            If Menu <> 0 Then : Menu = 0 : Lcd_refresh = 1 : End If       ' Spannung und Strom anzeigen
         End If
         If Warning >= 8 Then                               ' Temperatur zu hoch
            If Menu <> 10 Then : Menu = 10 : Lcd_refresh = 1 : End If       ' Temperatur anzeigen
         End If
         If Summer >= 1 Then
            Summer = 0
            If Temperatur >= 550 Then                       ' ab 55 °C
               Sound Piezo , 100 , 768                      ' 100 mS, 1 kHz
            End If
         End If
      End If
   Else
      Reset Led_rt                                          ' Led rot aus
      Quittung = 0
   End If

Der nachfolgende Teil des Programmes ist zuständig für die Auswertung der über die serielle Schnittstelle empfangenen Daten. Bei jedem empfangenem Zeichen wird die Variable "Interrupt" auf den Wert 1 gesetzt und dadurch die Auswertung gestartet. Bei Empfang der Ziffern 0 bis 7 wird das Intervall der Ausgabe an der seriellen Schnittstelle eingestellt. Ein "C" startet die Ausgabe im CSV-Format. Bei Empfang eines "S" wird die Ausgabe für "Logview" (universelles Visualisierungs-Tool um Daten aufzuzeichnen und auszuwerten) eingeleitet. Dazu wird zuerst ein Header gesendet, der zur Konfiguration des Programmes dient. Danach wird die Ausgabe der Daten gestartet. Dieses Programm sendet bei Aufzeichnungsende eine "E" an das Netzteil um die Übertragung zu beenden. Nach Empfang eines "T" startet das Netzteil die Ausgabe im Textformat. Mit "H" kann eine kleine Hilfe in Form einer Auflistung aller Befehle angefordert werden.

   'Empfang serielle Schnittstelle
   If Interrupt = 1 Then                                    ' Zeichen von UART empfangen
      Set Led_rt                                            ' LED rot einschalten
      Select Case Rxchar_uart                               ' Auswahl nach empfangenem Zeichen
         Case "0"
            Ser_intervall = 0
         Case "1"
            Ser_intervall = 1
         Case "2"
            Ser_intervall = 2
         Case "3"
            Ser_intervall = 5
         Case "4"
            Ser_intervall = 10
         Case "5"
            Ser_intervall = 15
         Case "6"
            Ser_intervall = 30
         Case "7"
            Ser_intervall = 60
         Case "C"
            Ser_format = 2                                  ' CSV
            Ser_ausgabe_kanal = 15                          ' alle Kanäle ein
            Sec_count_l = 0                                 ' Sekundenzähler zurück setzen
         Case "S"
            Incr Ofz_nr : Ofz_nr_eram = Ofz_nr : Str6 = Str(ofz_nr)
            Print "$N$;LNT15 #" ; Format(str6 , "000")
            Print "$C$;";
            If Ser_ausgabe_kanal.= 1 Then                 ' Ausgang 3,3 Volt
               Print "U_3[V,U];I_3[mA,I]" ;                 ' Spannung und Strom
               If Ser_ausgabe_kanal >= 2 Then
                  Print ";" ;
               Else
                  Print                                     ' keine weitere Ausgabe
               End If
            End If
            If Ser_ausgabe_kanal.= 1 Then                 ' Ausgang 5 Volt
               Print "U_5[V,U];I_5[mA,I]" ;                 ' Spannung und Strom
               If Ser_ausgabe_kanal >= 4 Then
                  Print ";" ;
               Else
                  Print                                     ' keine weitere Ausgabe
               End If
            End If
            If Ser_ausgabe_kanal.= 1 Then                 ' Ausgang 1,25-25 Volt
               Print "U_25[V,U];I_25[mA,I]" ;               ' Spannung und Strom
               If Ser_ausgabe_kanal >= 8 Then
                  Print ";" ;
               Else
                  Print                                     ' keine weitere Ausgabe
               End If
            End If
            If Ser_ausgabe_kanal.= 1 Then                 ' Temperatur
               Str6 = Str(temperatur)                       ' Temperatur übernehmen
               Print "T[ C,T];Fan[PWM,D]"                   ' Temperatur und PWM Lüfter
            End If
            Ser_format = 3                                  ' LogView Studio OpenFormat Zero
            Ser_ausgabe_kanal = 15                          ' alle Kanäle ein
            Sec_count_l = 0                                 ' Sekundenzähler zurück setzen
            Ofz_start = 1                                   ' serielle Ausgabe beginnen
         Case "E"
            Ofz_start = 0                                   ' serielle Ausgabe beenden
            Ser_format = 0                                  ' serielle Ausgabe beenden
         Case "T"
            Ser_format = 1                                  
Text
            Ser_ausgabe_kanal = 15                          ' alle Kanäle ein
            Sec_count_l = 0                                 ' Sekundenzähler zurück setzen
         Case "H"
            Print "________________________________________"
            Print "Befehle Labornetzteil LNT 15:"
            Print "C - Start Ausgabe CSV-Format"
            Print "S - Start Ausgabe OpenFormat Zero"
            Print "T - Start Ausgabe Textformat"
            Print "E - Ende Ausgabe seriell"
            Print "0 - kontinuierliche Ausgabe"
            Print "1 - Intervall 1 Sekunde"
            Print "2 - Intervall 2 Sekunden"
            Print "3 - Intervall 5 Sekunden"
            Print "4 - Intervall 10 Sekunden"
            Print "5 - Intervall 15 Sekunden"
            Print "6 - Intervall 30 Sekunden"
            Print "7 - Intervall 60 Sekunden"
      End Select
      Interrupt = 0 : Rxchar_uart = ""                      ' zurück setzen
      Lcd_refresh = 1 : Wert_refresh = 1
   End If                                                   ' ########## Ende Empfang seriell ##########

Die Ausgabe der Daten an der seriellen Schnittstelle ist in drei Formaten möglich: Text, CSV und Logview. Jedes Senden von Daten signalisiert die rote LED mit kurzem Aufleuchten. Im Textformat werden Spannung und Strom der in den Einstellungen gewählten Kanäle ausgegeben, auch die Ausgabe von Temperatur und PWM-Wert des Lüfters ist möglich. Die Ausgaben im Format CSV und Logview sind im Prinzip gleich und werden deshalb von einem Unterprogramm abgearbeitet.

   'Senden serielle Schnittstelle
   If Ser_format >= 1 Then
      If Sec_count >= Ser_intervall Then
         Sec_count = 0
         Set Led_rt                                         ' LED rot einschalten
         Select Case Ser_format
            Case 1                                          ' Textausgabe
               Print "------------------------------------"
               If Ser_ausgabe_kanal.= 1 Then              ' Ausgang 3,3 Volt
                  Str6 = Fusing(u_3 , "#.##")               ' Spannung 3,3 Volt runden und formatieren
                  Str8 = Fusing(i_3_avg_s , "#.##")         ' Strom runden und formatieren
                  If Str8 = "-0.00" Then : Str8 = "0.00" : End If
                  Print "U_3:  " ; Str6 ; " V   I_3:  " ; Str8 ; " mA"
               End If
               If Ser_ausgabe_kanal.= 1 Then              ' Ausgang 5 Volt
                  Str6 = Fusing(u_5 , "#.##")               ' Spannung 5 Volt runden und formatieren
                  Str8 = Fusing(i_5_avg_s , "#.##")         ' Strom runden und formatieren
                  If Str8 = "-0.00" Then : Str8 = "0.00" : End If
                  Print "U_5:  " ; Str6 ; " V   I_5:  " ; Str8 ; " mA"
               End If
               If Ser_ausgabe_kanal.= 1 Then              ' Ausgang 1,25-25 Volt
                  Str6 = Fusing(u_25 , "#.##")              ' Spannung 1,25-24 Volt runden und formatieren
                  Str8 = Fusing(i_25_avg_s , "#.##")        ' Strom runden und formatieren
                  If Str8 = "-0.00" Then : Str8 = "0.00" : End If
                  Print "U_24: " ; Str6 ; " V   I_24: " ; Str8 ; " mA"
               End If
               If Ser_ausgabe_kanal.= 1 Then              ' Temperatur
                  Str6 = Str(temperatur)                    ' Temperatur übernehmen
                  Print "Temp: " ; Format(str6 , "0.0") ; "  C  PWM:  " ; Fan_pwm
               End If
               I_3_avg_s = 0 : I_5_avg_s = 0 : I_25_avg_s = 0
               I_3_avg1_s = 0 : I_5_avg1_s = 0 : I_25_avg1_s = 0
               I_avg_count_s = 0
            Case 2                                          ' CSV
               Str2 = ","
               Print Sec_count_l ; ",";                     ' Sekundenzähler ausgeben
               Gosub Ser_ausgabe                            ' serielle Ausgabe Daten CSV oder OFZ
            Case 3
               If Ofz_start = 1 Then                        ' LogView Studio OpenFormat Zero
                  If Warning = 0 Then : Set Led_rt : End If ' LED rot ein
                  Str2 = ";"
                  Print "$" ;
                  Gosub Ser_ausgabe                         ' serielle Ausgabe Daten CSV oder OFZ
               End If
         End Select
      End If
   End If
Loop

End

Hiermit endet die Hauptprogrammschleife. Die Beschreibung der Interrupt- und Unterroutinen erfolgt im dritten Teil der Programmbeschreibung.