Labornetzteil
BASCOM-Quellcode Interrupts, Unterroutinen und Tabellen
In diesem Teil der Dokumentation werden die Interruptroutinen und Unterprogrammeabschnitte beschrieben. Die erste Interruptroutine wird durch den Empfang eines Zeichens der seriellen Schnittstelle aufgerufen. Es wird nur das empfangene Zeichen in eine Variable übernommen und eine Variable gesetzt. Durch diese wird die Reaktion im Hauptprogramm auf den Empfang gestartet. Danach wird die Kontrolle wieder ans Hauptprogramm übergeben. Der zweite Interrupt wird ausgelöst durch Timer 1. Durch Vorladen des Timers mit dem Wert B9B0 hex geschieht dies im Takt von 0,5 Sekunden. Das umschalten der Variable "Blinken" bewirkt, das im Hauptprogramm, wenn erforderlich, die rote LED und die Anzeige blinkt. Die beiden Sekundenzähler werden benötigt für Intervall und Durchschnittsberechnung der seriellen Ausgabe. Falls die LCD-Hintergrundbeleuchtung eingeschaltet ist, wird ein weiterer Zähler erhöht. Nach Ablauf von 60 Sekunden wird die Beleuchtung abgeschaltet und zwei Variablen zur Steuerung der Anzeige werden gesetzt.
'#################### I N T E R U P T R O U T I N E N #################### Int_rx_uart: ' Empfang serielle Schnittstelle Rxchar_uart = Udr ' read UDR only once Interrupt = 1 ' Interrupt ausgelöst Return Tmr1_isr: ' Sekundentakt Timer1 = &HB9B0 ' Overflow nach 0,5 Sekunden Toggle Blinken Summer = 1 If Blinken = 0 Then ' 1 Sekunde Incr Sec_count ' Sekundenzähler für Abstand serielle Ausgabe Incr Sec_count_l ' Sekundenzähler für Durchschnitt und serielle Ausgabe If Lcd_light_off >= 1 Then Incr Lcd_light_off If Lcd_light_off >= 60 Then ' nach 60 Sekunden Lcd_light_off = 0 Reset Lcd_light ' LCD-Hintergrundbeleuchtung aus Lcd_refresh = 1 ' Anzeige 1 neu aufbauen Wert_refresh = 1 ' Anzeige 2 neu aufbauen End If End If End If Return |
Der nächste Programmabschnitt sorgt für die serielle Ausgabe der Messwerte im Format CSV und OpenFormatZero für Logview. Da die Ausgabe für jeden Kanal konfigurierbar ist, wird zuerst geprüft, ob das entsprechende Bit in der Variablen gesetzt ist. Wenn ja, dann wird zuerst die Spannung, danach der in Str2 gespeicherte String (ein Semikolon oder Komma, je nach Ausgabeformat) und abschließend der Durchschnittswert des Stromes gesendet. Danach erfolgt eine Prüfung, ob weitere Messwerte ausgegeben werden sollen. Je nach Größe der Variablen wird entweder wieder Str2 oder nur ein Zeilenende gesendet. Die Ausgabe der restlichen Kanäle erfolgt nach gleichem Schema, nur das beim letzten Kanal Temperatur und PWM-Wert ausgegeben werden. Zum Abschluss werden die Durchschnittswerte der Ströme und der Zähler zurück gesetzt.
'####################### U N T E R P R O G R A M M E ####################### Ser_ausgabe: ' serielle Ausgabe Daten CSV oder OFZ If Ser_ausgabe_kanal.0 = 1 Then ' Ausgang 3,3 Volt Print U_3 ; Str2 ; I_3_avg_s ; ' Spannung und Strom If Ser_ausgabe_kanal >= 2 Then Print Str2 ; Else Print ' keine weitere Ausgabe End If End If If Ser_ausgabe_kanal.1 = 1 Then ' Ausgang 5 Volt Print U_5 ; Str2 ; I_5_avg_s ; ' Spannung und Strom If Ser_ausgabe_kanal >= 4 Then Print Str2 ; Else Print ' keine weitere Ausgabe End If End If If Ser_ausgabe_kanal.2 = 1 Then ' Ausgang 1,25-25 Volt Print U_25 ; Str2 ; I_25_avg_s ; ' Spannung und Strom If Ser_ausgabe_kanal >= 8 Then Print Str2 ; Else Print ' keine weitere Ausgabe End If End If If Ser_ausgabe_kanal.3 = 1 Then ' Temperatur Str6 = Str(temperatur) ' Temperatur übernehmen Print Format(str6 , "0.0") ; Str2 ; Fan_pwm ' Temperatur und PWM Lüfter End If I_3_avg_s = 0 : I_5_avg_s = 0 : I_25_avg_s = 0 ' Durchschnitte Strom zurück setzen I_3_avg1_s = 0 : I_5_avg1_s = 0 : I_25_avg1_s = 0 ' Durchschnitte Strom zurück setzen I_avg_count_s = 0 ' Zähler für Durchschnitt zurück setzen Return |
Das folgende Unterprogramm setzt die Variable für die Übertragungsrate der seriellen Schnittstelle bei Auswahl des Index im Einstellungsmenü.
Ser_set_baud: ' Einstellung Übertragungsrate serielle Schnittstelle Select Case Ser_baudindex Case 0 Baud = 2400 Case 1 Baud = 4800 Case 2 Baud = 9600 Case 3 Baud = 19200 Case 4 Baud = 38400 Case 5 Baud = 57600 Case 6 Baud = 115200 End Select Return |
Die nächsten beiden Abschnitte steuern Anzeigen auf dem Display. Die erste Unterprozedur zeigt ganz rechts im Display oben einen Pfeil nach rechts und darunter einen Pfeil nach oben. Dies soll die Funktion der Tasten veranschaulichen: "Nach rechts" - einen Menüpunkt weiter, "Nach oben" - Einstellwert erhöhen. Wenn die Hintergrundbeleuchtung ausgeschaltet ist, werden die Symbole und der Cursor nicht angezeigt. Routine 2 zeigt bei Einstellungen, die nur "ein" oder "aus" erlauben den entsprechenden Text an. Eine Infozeile und Versionsnummer, sowie Erstellzeit und -Datum stellt die 3. Unterprozedur dar.
Lcd_pfeil_lo: ' Anzeige Pfeil nach rechts und oben If Lcd_light = 1 Then Locate 1 , 40 : Lcd "{199}" ' Pfeil nach rechts Locate 2 , 40 : Lcd "{197}" ' Pfeil nach oben Cursor On Blink Else Cursor Off End If Return Lcd_ein_aus: ' Anzeige ein/aus If X = 1 Then Lcd "ein" Else Lcd "aus" End If Return Lcd_info: ' Anzeige Version und Compilerzeit Upperline : Lcd "LNT 15 - ATmega 328P, INA219, DS1621" Lowerline : Lcd "Version: " ; Version(2) ; " " ; Version(1) Return |
Das erste Unterprogramm im folgenden Abschnitt zeigt die abgegebene Leistung des Kanals an. Der Rohwert wird in der Variablen "s" übergeben. Die erste Zeile sorgt für eine Rundung mit zwei Nachkommastellen und Übernahme in einen String. Da bei BASCOM die Formatierung leider nicht richtig funktioniert, wird anschließend die Länge des Strings ermittelt und daraufhin hin eine errechnete Anzahl Leerzeichen angezeigt. Erst jetzt erfolgt die Anzeige des Messwertes und der Maßeinheit. Das darauf folgende Unterprogramm beinhaltet die Anzeige des Stromes. Eine Prüfung des Wertes in der Variablen "S" entscheidet darüber, ob die Anzeige in Ampere oder mA erfolgt. Der eigentliche Messwert wird anschließend gerundet und formatiert in einen String übernommen. Hier muss auch wieder eine Eigenheit von BASCOM korrigiert werden: Die Variable könnte z.B. den Wert -0,00001 haben, nach der Formatierung auf zwei Nachkommastellen übernimmt BASCOM aber das negative Vorzeichen. Da ein Anzeigewert von "-0,00" unschön aussieht, wird das geändert. Anschließend wird auch wieder, wie bei der Ausgabe der Leistung, der String mit führenden Leerzeichen ergänzt. Die Anzeige erfolgt im Normalfall statisch und bei zu hoher Stromaufnahme blinkend.
Lcd_p: ' Anzeige Leistung Str6 = Fusing(s , "#.##") ' Leistung runden und formatieren X = Len(str6) : Y = 6 - X Locate 1 , Lcd_pos ' Anzeigeposition Lcd Space(y) ; Str6 ; " W" ' Leistung anzeigen Return Lcd_i: ' Anzeige Strom If S >= 1000 Then S = S / 1000 Str6 = " A " Else Str6 = " mA" End If Str8 = Fusing(s , "#.##") ' Strom runden und formatieren If Str8 = "-0.00" Then : Str8 = "0.00" : End If X = Len(str8) : Y = 6 - X Str12 = Space(y) Str12 = Str12 + Str8 ' Messwert Str12 = Str12 + Str6 ' Maßeinheit Locate Lcd_zeile , Lcd_pos If Warning.z = 0 Then ' keine Warnung Lcd Str12 ' Strom anzeigen Else ' Anzeige blinkt If Blinken = 0 Then Lcd Space(6) ' Leerzeichen anzeigen Else Lcd Str12 ' Strom anzeigen End If End If Return |
Der nächste Abschnitt zeigt drei Routinen zur Kommunikation mit dem Strom-/Spannungswandler INA219 über den I²C-Bus. Der erste Teil liest eine Word-Variable vom Schaltkreis, die in zwei Byte übermittelt wird. Dazu wird zuerst die Startsequenz auf dem Bus ausgegeben. Danach folgt die Schreibadresse des anzusprechenden Schaltkreises und die Registeradresse, die ausgelesen werden soll. Nach einem Repeat-Start mit anschließender Ausgabe der Leseadresse des Schaltkreises werden zwei Byte vom Bus gelesen. Anschließend wird die Stopp-Sequenz auf den Bus gegeben und zurück ins Hauptprogramm gesprungen. Im zweiten Teil passiert dasselbe, nur das diesmal eine Integer-Variable übermittelt wird. Der letzte Teil wird zum Schreiben der Konfigurationsregister verwendet. Auch hier wird wieder zuerst die Schreib- und Registeradresse auf den Bus gegeben. Darauf erfolgt sofort anschließend das Schreiben des High- und Low-Byte der temporären Word-Variable.
Ina219_reg_read_w: ' Register INA219 lesen I2cstart ' send start I2cwbyte Ina219_adr_w ' send write address I2cwbyte Ina219_reg ' send register pointer I2crepstart I2cwbyte Ina219_adr_r ' send read address I2crbyte W_high , Ack ' read MSB I2crbyte W_low , Nack ' read LSB I2cstop Return Ina219_reg_read_i: ' Register INA219 lesen I2cstart ' send start I2cwbyte Ina219_adr_w ' send write address I2cwbyte Ina219_reg ' send register pointer I2crepstart I2cwbyte Ina219_adr_r ' send read address I2crbyte I_high , Ack ' read MSB I2crbyte I_low , Nack ' read LSB I2cstop Return Ina219_reg_write: ' Register INA219 schreiben I2cstart ' send start I2cwbyte Ina219_adr_w ' send write address I2cwbyte Ina219_reg ' Calibration Register I2cwbyte W_high ' write MSB I2cwbyte W_low ' write LSB I2cstop Return |
Die Kommunikation mit dem Thermometer-IC DS1621 über den I²C-Bus verläuft ähnlich wie beim INA219. Zuerst wird der Temperatur-Wert in zwei Bytes gelesen. In diesen ist die Temperatur allerdings nur in Schritten zu 0,5 enthalten. Für eine höhere Auflösung werden zwei zusätzliche Variablen gelesen: COUNT_REMAIN und COUNT_PER_C. Mit diesen ist nach einer im Datenblatt angegeben Formel eine genauere Berechnung möglich. Ich verwende hier eine angepasste Variante, die ohne Gleitkomma-Berechnung auskommt. Übernommen wird dazu nur das MSB in eine Integer-Variable. Sollte die Temperatur negativ sein (Bit 7 = 1), so wird das obere Byte auf 255 gesetzt. Der Temperaturwert wird mit 100 multipliziert und 25 (statt 0,25) subtrahiert. Anschließend werden die beiden Count-Werte subtrahiert, mit 100 multipliziert und anschließend dividiert. Beide temporären Variablen addiert und anschließend mit 10 dividiert ergibt die Temperatur in einer Integer-Variablen. Die Darstellung mit Kommastelle erfolgt dann bei der Anzeige mit dem Befehl "Format".
Ds1621_read: I2cstart ' I2C-Kommunikation starten I2cwbyte Ds1621_adr_w ' Address of DS1621 Thermometer for write I2cwbyte &HAA ' Temperaturmessung Lesekommando I2crepstart ' I2C-Kommunikation starten I2cwbyte Ds1621_adr_r ' Address of DS1621 Thermometer for read I2crbyte Ds_msb , Ack ' MSB holen I2crbyte Ds_lsb , Nack ' LSB holen I2cstop I2cstart ' I2C-Kommunikation starten I2cwbyte Ds1621_adr_w ' Address of DS1621 Thermometer for write I2cwbyte &HA8 ' Count Remain anfordern I2crepstart ' I2C-Kommunikation starten I2cwbyte Ds1621_adr_r ' Address of DS1621 Thermometer for read I2crbyte C_r , Nack ' Count Remain holen I2cstop I2cstart ' I2C-Kommunikation starten I2cwbyte Ds1621_adr_w ' Address of DS1621 Thermometer for write I2cwbyte &HA9 ' Count per C anfordern I2crepstart ' I2C-Kommunikation starten I2cwbyte Ds1621_adr_r ' Address of DS1621 Thermometer for read I2crbyte C_p_c , Nack ' Count per C holen I2cstop I_low = Ds_msb If I_low.7 = 1 Then I_high = 255 Else I_high = 0 End If I = I * 100 : I = I - 25 I1 = C_p_c - C_r I1 = I1 * 100 I1 = I1 / C_p_c Temperatur = I + I1 Temperatur = Temperatur / 10 Return |
Die letzten beiden Unterprogramme werden bei Tastenbetätigung aufgerufen. Die obere Taste hat hauptsächlich die Funktion, die Menüpunkte bis zu einem Maximalwert zu erhöhen. Zuerst werden einige Variablen gesetzt, um dem Hauptprogramm zu vermitteln, das eine Taste betätigt wurde. Falls die LCD-Hintergrundbeleuchtung aus war, wird sie jetzt eingeschaltet und die Menünummer noch nicht erhöht. Außerdem wird Timer 1 gestartet, der nach einer bestimmten Zeit die Hintergrundbeleuchtung wieder abschaltet. Der nächste Tastendruck wechselt dann ins nächste Menu. Falls die Hintergrundbeleuchtung schon eingeschaltet war, wird die Zeit für die LCD-Beleuchtung wieder auf 1 zurück gesetzt. Auch die untere Taste ist mit diesen Funktionen für die Beleuchtung versehen. Ansonsten hat sie als Hauptfunktion den Wert in den Einstellungsmenüs bis zu einem Maximalwert zu erhöhen. Abweichend davon erfolgt in den Menüpunkten 1 und 2 das Rücksetzen der Minimal-, Maximal- und Durchschnittswerte der Ströme. In den Menüs 3, 10 und 11 erfolgt ein Sprung in eine andere Menüebene.
Taste_o: ' Taste oben Lcd_refresh = 1 : Wert_refresh = 1 : Quittung = 1 If Lcd_light = 0 Then Lcd_light = 1 ' LCD-Hintergrundbeleuchtung einschalten Lcd_light_off = 1 ' Timer LCD-Hintergrundbeleuchtung ein Else Incr Menu ' nächster Menüpunkt If Menu = 4 Then : Menu = 0 : End If ' letzter Menüpunkt Ebene 1 ist 3 If Menu >= 19 Then : Menu = 10 : End If ' letzter Menüpunkt Ebene 2 ist 18 Wertmax = 0 End If If Lcd_light_off >= 1 Then Lcd_light_off = 1 ' Timer LCD-Hintergrundbeleuchtung ein End If Return Taste_u: ' Taste unten Wert_refresh = 1 : Quittung = 1 If Lcd_light = 0 Then Lcd_light = 1 ' LCD-Hintergrundbeleuchtung einschalten Lcd_refresh = 1 Lcd_light_off = 1 ' Timer LCD-Hintergrundbeleuchtung ein Else If Wertmax >= 1 Then Incr Wert ' Wert erhöhen If Wertmax < Wert Then : Wert = 0 : End If End If Select Case Menu Case 1 ' Anzeige MIN/MAX Strom I_3_max = -99 : I_5_max = -99 : I_25_max = -99 I_3_min = 999 : I_5_min = 999 : I_25_min = 999 Case 2 ' Anzeige Durchschnitt Strom I_3_avg = 0 : I_5_avg = 0 : I_25_avg = 0 I_3_avg1 = 0 : I_5_avg1 = 0 : I_25_avg1 = 0 I_avg_count = 0 Sec_count_l = 0 Case 3 ' Anzeige Leistung Menu = 10 : Lcd_refresh = 1 ' Sprung in Menüebene 2 Case 10 Menu = 0 : Lcd_refresh = 1 ' Sprung in Ebene 0 Case 11 Menu = 0 : Lcd_refresh = 1 ' Sprung in Ebene 0 End Select End If If Lcd_light_off >= 1 Then Lcd_light_off = 1 ' Timer LCD-Hintergrundbeleuchtung ein End If Return |
Letzter Teil im Programm sind 3 Tabellen mit Daten. Die erste Tabelle beinhaltet Texte zur Anzeige des eingestellten Datenformates für die Ausgabe der Messwerte über die serielle Schnittstelle. Tabelle 2 enthält Anzeigestrings für die eingestellte Baudrate und die letzte Tabelle erfasst die Zeit der Intervalle der seriellen Ausgabe.
'#################### D A T E N #################### Table_ser_format: ' Ausgabeformat seriell Data "keine Ausgabe " ' keine Ausgabe Data "Text " ' Textformat Data "CSV (comma separated) " ' CSV Data "OpenFormat Zero (LogView Studio)" ' LogView Studio OpenFormat Zero Table_ser_baud: ' Baudrate seriell Data " 2400" , " 4800" , " 9600" , " 19200" Data " 38400" , " 57600" , "115200" Table_intervall: ' Intervall in Sekunden Data 0 , 1 , 2 , 5 , 10 , 15 , 30 , 60 |
Hiermit endet die Beschreibung des BASCOM-Quellcodes für das Labornetzteil. Insgesamt umfasst der Quellcode etwas über 1000 Zeilen. Hier und da könnte sicher noch etwas optimiert werden, aber irgendwann muss man ein Projekt auch mal abschließen.