Labornetzteil

BASCOM-Quellcode Initialisierung Hardware und Deklaration Variablen

Zuerst werden die Compiler-Optionen festgelegt. Verwendet wird ein ATmega168P. Der Takt wird mit einem sog. Baudraten-Quarz mit einer Frequenz von 9,216 MHz erzeugt. Damit sind Übertragungsraten auf der seriellen Schnittstelle bis zu 115200 Baud möglich. Die Übertragungsrate der Schnittstelle wird erst einmal mit nur 38400 Baud initialisiert. Sie kann aber später in der Software verändert werden. Für den I²C-Bus wird die Hardwareschnittstelle verwendet. Bei AVR nennt sich das TWI (Two Wire Interface). Der Takt des Busses wird auf 400 kHz festgelegt.

$regfile = "m168pdef.dat"                                   ' ATMega 168p
$crystal = 9216000                                          ' used crystal frequency
$hwstack = 128                                              ' default use 32 for the hardware stack
$swstack = 128                                              ' default use 10 for the SW stack
$framesize = 128                                            ' default use 40 for the frame space
$baud = 38400                                               ' Baudrate UART 38400
$version 1 , 0 , 1

'we use the TWI pins of the Mega168P
$lib "i2c_twi.lbx"                                          ' we do not use software emulated I2C but the TWI
Config Scl = Portc.5                                        ' we need to provide the SCL pin name
Config Sda = Portc.4                                        ' we need to provide the SDA pin name
Config Twi = 400000
I2cinit

Als nächstes wird die serielle Schnittstelle eingerichtet. Bei Empfang eines Zeichens über die serielle Schnittstelle wird ein Interrupt "URXC" ausgelöst. Dadurch soll dann später die Interrupt-Service-Routine "Int_rx_uart" aufgerufen werden. Danach werden diverse Einstellungen aus dem EEPROM des AVR geladen und die Schnittstellen dementsprechend  eingestellt.

'serielle Schnittstelle
Dim Rxchar_uart As Byte                                     ' Keyboard data
On Urxc Int_rx_uart                                         ' define serial receive ISR
Enable Urxc                                                 ' enable Serial RX complete interrupt
Dim Interrupt As Byte                                       ' Interrupt ausgelöst
Dim Ser_baudindex As Byte                                   ' Geschwindigkeit serielle Ausgabe
Dim Ser_baudindex_eram As Eram Byte                         ' Geschwindigkeit serielle Ausgabe EEPROM
Ser_baudindex = Ser_baudindex_eram
If Ser_baudindex >= 7 Then                                  ' Fehler abfangen
   Ser_baudindex = 4 : Ser_baudindex_eram = 4               ' Startwert Geschwindigkeit seriell 38400
End If
Gosub Ser_set_baud                                          ' Einstellung Übertragungsrate serielle Schnittstelle
Dim Ser_format As Byte                                      ' Format serielle Ausgabe
Dim Ser_format_eram As Eram Byte                            ' Format serielle Ausgabe EEPROM
Ser_format = Ser_format_eram
If Ser_format >= 4 Then                                     ' Fehler abfangen
   Ser_format = 1 : Ser_format_eram = 1                     ' Startwert Ausgabeformat seriell
End If
Dim Ser_intervall As Byte                                   ' Intervall serielle Ausgabe
Dim Ser_intervall_index As Byte                             ' Index Intervall serielle Ausgabe
Dim Ser_intervall_index_eram As Eram Byte                   ' Index Intervall serielle Ausgabe EEPROM
Ser_intervall_index = Ser_intervall_index_eram
If Ser_intervall_index >= 8 Then                            ' Fehler abfangen
   Ser_intervall_index = 1 : Ser_intervall_index_eram = 1   ' Startwert Intervall 1 Sekunde
End If
Ser_intervall = Lookup(ser_intervall_index , Table_intervall)       ' Intervall in Sekunden aus Tabelle laden
Dim Ofz_nr As Byte                                          ' Nummer für Logview OpenFormat Zero
Dim Ofz_nr_eram As Eram Byte                                ' Nummer für Logview OpenFormat Zero EEPROM
Ofz_nr = Ofz_nr_eram
Dim Ofz_start As Byte                                       ' Ausgabe OpenFormat Zero gestartet
Dim Sec_count As Byte                                       ' Sekundenzähler für Abstand serielle Ausgabe
Dim Ser_ausgabe_kanal As Byte                               ' Kanal ausgeben ja/nein
Dim Ser_ausgabe_kanal_eram As Eram Byte                     ' Kanal ausgeben ja/nein EEPROM
Ser_ausgabe_kanal = Ser_ausgabe_kanal_eram
If Ser_ausgabe_kanal >= 16 Then                             ' Fehler abfangen
   Ser_ausgabe_kanal = 15 : Ser_ausgabe_kanal_eram = 1      ' Ausgabe alle Kanäle
End If

Im folgenden Abschnitt wird das LCD konfiguriert für Betrieb am 4-Bit breiten Bus und die Anschlüsse dafür werden festgelegt. Ich benutze ein HD44780-kompatibles Display mit 2 Zeilen je 40 Zeichen. Nach der Initialisierung und Deklaration einiger Variablen werden zwei Portanschlüsse als Ausgang für eine LED und die Steuerung der LCD-Hintergrundbeleuchtung definiert. Auf die Einrichtung von 2 Eingängen für die Taster und Einschaltung deren Pullup-Widerständen folgt noch ein Ausgang für einen Piezosummer. Im Anschluss daran werden zwei Timer initialisiert. Timer 1, ein 16-Bit-Timer, wird eingerichtet mit einem Takt von einer halben Sekunde für das Blinken der LED und die Ausgabe der seriellen Daten. Timer 2 wird für PWM konfiguriert. Output-Compare-Ausgang B steuert hierbei den Lüfter. Ich habe mit verschiedenen PWM-Frequenzen experimentiert, mit der Frequenz von 36 kHz funktioniert der gewählte Lüfter am besten.

'LCD 40x2
Config Lcdpin = Pin , Rs = Portb., E = Portb., Db4 = Portc., Db5 = Portc., Db6 = Portc., Db7 = Portc.3
Config Lcd = 40 * 2
Initlcd
Cursor Off Noblink
Cls                                                         ' clear the screen
Dim Lcd_refresh As Byte                                     ' Anzeige neu aufbauen
Dim Lcd_light_off As Byte                                   ' LCD-Hintergrundbeleuchtung
Lcd_light_off = 1                                           ' LCD-Hintergrundbeleuchtung Timer ein
Dim Lcd_zeile As Byte
Dim Lcd_pos As Byte

Config Portb.= Output : Led_rt Alias Portb.0              ' LED rot
Config Portd.= Output : Lcd_light Alias Portd.2           ' LCD-Hintergrundbeleuchtung
'Taster
Config Pind.= Input : Portd.= 1                         ' Taster oben, Pullup ein
Config Pind.= Input : Portd.= 1                         ' Taster unten, Pullup ein
'Piezo
Config Portd.= Output : Piezo Alias Portd.4               ' Piezo-Summer
Dim Summer As Byte
Dim Quittung As Byte

'Timer 1 für Sekundentakt
Config Timer1 = Timer , Prescale = 256                      ' Timer 1 als Zähler
Timer1 = &HB9B0                                             ' Overflow nach 0,5 Sekunden
On Timer1 Tmr1_isr                                          ' ISR
Enable Timer1 : Start Timer1
'Timer 2 für PWM-Lüfterdrehzahl, 36000.000 Hz
Config Timer2 = Pwm , Prescale = 1 , Compare_a_pwm = Clear_up , Compare_a = Disconnect , Compare_b = Clear
Dim Fan_pwm As Byte                                         ' PWM für Lüfter
Dim Bsec As Byte , Bmin As Byte , Bhour As Byte , Bday As Byte
Dim Sec_count_l As Long                                     ' Sekundenzähler für Durchschnitt und serielle Ausgabe

Hier erfolgt jetzt die Einrichtung der Konstanten und Variablen für den Thermometer-Schaltkreis DS1621. Danach wird die Temperaturmessung des Schaltkreises durch Schreiben des Befehlt "EE" gestartet. Nach einer Pause von einer Sekunde wird die rote LED und die LCD-Hintergrundbeleuchtung eingeschaltet, sowie eine Versionsinformation auf dem LCD ausgegeben. Falls als serielles Ausgabeformat "Text" ausgewählt ist, wird auch eine Info an die serielle Schnittstelle gesendet.

'DS1621 Thermometer
Const Ds1621_adr_w = &H90                                   ' Address of DS1621 Thermometer for write
Const Ds1621_adr_r = &H91                                   ' Address of DS1621 Thermometer for read
Dim Ds_lsb As Byte                                          ' LSB DS1621
Dim Ds_msb As Byte                                          ' MSB DS1621
Dim C_p_c As Byte                                           ' Count per C - Read Slope [A9h]
Dim C_r As Byte                                             ' Count Remain - Read Counter [A8h]
Dim Temperatur As Integer                                   ' Temperatur
I2cstart
I2cwbyte Ds1621_adr_w                                       ' Address of DS1621 Thermometer for write
I2cwbyte &HEE                                               ' Temperaturmessung starten
I2cstop

Wait 1
Set Led_rt                                                  ' LED rot ein
Set Lcd_light                                               ' LCD-Hintergrundbeleuchtung ein
Gosub Lcd_info                                              ' Anzeige Version und Compilierzeit
If Ser_format = 1 Then                                      ' serielle Ausgabe Textformat
   Print
   Print "------------------------------------"
   Print "LNT 15 - ATmega 328P, INA219, DS1621"
   Print "Version: " ; Version(2) ; ", " ; Version(1)
End If
Wait 2

Die Einrichtung der Variablen und Konstanten für die Strom- und Spannungssensoren INA219 sind etwas umfangreicher, da sie für 3 Schaltkreise definiert werden müssen. Die Konstanten der Hardware-Adressen sind bestimmt durch die Beschaltung der Adresseingänge der Schaltkreise. Die Variablen für Spannungen, Ströme, Leistungen, Durchschnitts-, Maximal- und Minimalströme werden jeweils als Gleitkommazahlen definiert.

'INA219 - CURRENT/POWER MONITOR
Dim Ina219_adr_w As Byte                                    ' Schreibadresse INA219
Dim Ina219_adr_r As Byte                                    ' Leseadresse INA219
Const Ina219_25_adr_w = &H80                                ' Schreibadresse INA219 Ausgang 1,25-25 Volt
Const Ina219_25_adr_r = &H81                                ' Leseadresse INA219 Ausgang 1,25-25 Volt
Const Ina219_3_adr_w = &H82                                 ' Schreibadresse INA219 Ausgang 3,3 Volt
Const Ina219_3_adr_r = &H83                                 ' Leseadresse INA219 Ausgang 3,3 Volt
Const Ina219_5_adr_w = &H88                                 ' Schreibadresse INA219 Ausgang 5 Volt
Const Ina219_5_adr_r = &H89                                 ' Leseadresse INA219 Ausgang 5 Volt
Dim Ina219_reg As Byte                                      ' Register
Dim U_3 As Single                                           ' Spannung Ausgang 3,3 Volt
Dim U_5 As Single                                           ' Spannung Ausgang 5 Volt
Dim U_25 As Single                                          ' Spannung Ausgang 1,25-25 Volt
Dim I_3 As Single                                           ' Strom Ausgang 3,3 Volt
Dim I_5 As Single                                           ' Strom Ausgang 5 Volt
Dim I_25 As Single                                          ' Strom Ausgang 1,25-25 Volt
'Durchschnitt Strom für lokale Anzeige
Dim I_3_avg As Single                                       ' Durchschnitt Strom Ausgang 3,3 Volt
Dim I_5_avg As Single                                       ' Durchschnitt Strom Ausgang 5 Volt
Dim I_25_avg As Single                                      ' Durchschnitt Strom Ausgang 1,25-25 Volt
Dim I_3_avg1 As Single                                      ' Durchschnitt Strom Ausgang 3,3 Volt
Dim I_5_avg1 As Single                                      ' Durchschnitt Strom Ausgang 5 Volt
Dim I_25_avg1 As Single                                     ' Durchschnitt Strom Ausgang 1,25-25 Volt
Dim I_avg_count As Word                                     ' Z hler f r Durchschnitt Strom
'Durchschnitt Strom für serielle Ausgabe
Dim I_3_avg_s As Single                                     ' Durchschnitt Strom Ausgang 3,3 Volt
Dim I_5_avg_s As Single                                     ' Durchschnitt Strom Ausgang 5 Volt
Dim I_25_avg_s As Single                                    ' Durchschnitt Strom Ausgang 1,25-25 Volt
Dim I_3_avg1_s As Single                                    ' Durchschnitt Strom Ausgang 3,3 Volt
Dim I_5_avg1_s As Single                                    ' Durchschnitt Strom Ausgang 5 Volt
Dim I_25_avg1_s As Single                                   ' Durchschnitt Strom Ausgang 1,25-25 Volt
Dim I_avg_count_s As Word                                   ' Zähler für Durchschnitt Strom
Dim I_3_max As Single                                       ' Maximum Strom Ausgang 3,3 Volt
Dim I_5_max As Single                                       ' Maximum Strom Ausgang 5 Volt
Dim I_25_max As Single                                      ' Maximum Strom Ausgang 1,25-25 Volt
Dim I_3_min As Single                                       ' Minimum Strom Ausgang 3,3 Volt
Dim I_5_min As Single                                       ' Minimum Strom Ausgang 5 Volt
Dim I_25_min As Single                                      ' Minimum Strom Ausgang 1,25-25 Volt
I_3_max = -10000 : I_5_max = -10000 : I_25_max = -10000
I_3_min = 10000 : I_5_min = 10000 : I_25_min = 10000
Dim P_3 As Single                                           ' Leistung Ausgang 3,3 Volt
Dim P_5 As Single                                           ' Leistung Ausgang 5 Volt
Dim P_25 As Single                                          ' Leistung Ausgang 1,25-25 Volt

Im folgenden werden zuerst einige Variablen für die Menu-Steuerung definiert. Im Anschluss daran folgen Variablen, die nur temporär verwendet werden. Das heißt, das diese nur vorübergehend für Schleifen oder Zwischenergebnisse bei Berechnungen verwendet werden. Das nächste Programmstück ist eigentlich für das Endprodukt nicht mehr erforderlich. Es scannt den I²C-Bus über alle möglichen Adressen und gibt diese aus. Man erkennt also, wenn irgendein I²C-Teilnehmer nicht mehr ansprechbar ist. Danach werden global die Interrupts eingeschaltet.

'Variablen für Menu
Dim Menu As Byte                                            ' Menunummer
Dim Menu_old As Byte
Dim Menuverlassen As Byte                                   ' Zähler um ins Hauptmenu zurück zu springen
Dim Wertmax As Word                                         ' maximal einstellbarer Wert
Dim Wert As Word                                            ' Wert hoch/runter
Dim Wert_refresh As Byte                                    ' Wert wurde geändert
Dim Warning As Byte                                         ' Warnung ein
Dim Blinken As Byte                                         ' LCD + LED blinkt

'temporäre Variablen
Dim X As Byte , Y As Byte , Z As Byte
Dim W As Word
Dim W_low As Byte At W Overlay : Dim W_high As Byte At W + 1 Overlay
Dim I As Integer , I1 As Integer
Dim I_low As Byte At I Overlay : Dim I_high As Byte At I + 1 Overlay
Dim S As Single
Dim L As Long
Dim Str2 As String * 2
Dim Str6 As String * 6
Dim Str8 As String * 8
Dim Str12 As String * 12
Dim Str40 As String * 40

Cls
Upperline : Lcd "I2C-Bus Scan"
Wait 1
Cls
Upperline : Lcd "INA219-1"
Locate 1 , 11 : Lcd "INA219-2"
Locate 1 , 21 : Lcd "INA219-3"
Locate 1 , 31 : Lcd "DS1621"
= 0 : Z = 1
For X = 2 To 254 Step 2                                     ' for all odd addresses
   I2cstart                                                 ' send start
   I2cwbyte X                                               ' send address
   If Err = 0 Then                                          ' we got an ack
      Locate 2 , Z
      Lcd "hex: " ; Hex(x)                                  ' Adresse anzeigen
      Incr Y : Z = Z + 10
   End If
   I2cstop                                                  ' free bus
Next
If Y = 0 Then
   Lowerline
   Lcd "I2C-Error, no Slave found!"
End If
Wait 2

Enable Interrupts

Als letztes vor dem Beginn der Hauptprogrammschleife erfolgt die Konfiguration der Strom- und Spannungssensoren INA219. Die Konfigurationsregister der ICs sind 16 Bit breit. Die Kommentare zu den Bits habe ich bewusst im Code gelassen. Der erste und zweite Ausgang (3,3 und 5 Volt) wird auf maximal 16  Volt Eingangsspannung konfiguriert. Möglich sind zwei Messbereiche: 16 oder 32 Volt. "PG" ist die Maximalspannung über dem Shunt zur Strommessung. Bei den gewählten Widerständen von je 0,1 Ohm entspricht dies einem Maximalstrom von 1,6 Ampere. Alle drei Wandler werden mit der maximal möglichen Auflösung von 12 Bit betrieben. Es werden 128 Samples (Messungen) durchgeführt und daraus ein Durchschnitt gebildet. Das dauert zwar 68 Millisekunden, liefert aber eine ruhige Anzeige. Ca. 15 Messwerte pro Sekunde reichen mir, das Hauptprogramm braucht ja sowieso noch seine Zeit um die Messwerte umzurechnen, anzuzeigen und evtl. seriell auszugeben. Mit dem Wert für "Optional Second Calibration"  können Ungenauigkeiten der Shunts ausgeglichen werden. Der 3. Kanal wird abweichend zu den anderen auf 32 Volt Eingangsspannung und 80 mV Maximalspannung über dem Shunt konfiguriert.

'W = &B 0 0 1 11 0011 0011 111 Default Configuration Register 00h
'       | | | || |||| |||| |||
'       | | | || |||| |||| +++- MODE 1-3
'       | | | || |||| ++++- SADC 1-4
'       | | | || ++++- BADC 1-4
'       | | | ++- PG 0-1
'       | | +- BRNG
'       | +- -
'       +- RST

'W = &B0011100110011111                                      ' Default Configuration Register 00h
'W = &B0011111111111111                                      ' Register 00h, 12 Bit, 128 Samples, Bus Voltage Range 32 V
'W = &B0001111111111111                                      ' Register 00h, 12 Bit, 128 Samples, Bus Voltage Range 16 V
'W = &B0001011111111111                                      ' Register 00h, 12 Bit, 128 Samples, Bus Voltage Range 16 V, Gain +4 (160 mV)

'Ausgang 3,3 Volt
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
= &B0001011111111111                                      ' Register 00h, 12 Bit, 128 Samples, Bus Voltage Range 16 V, PG 160 mV
Ina219_reg = &H00                                           ' Configuration Register
Gosub Ina219_reg_write                                      ' Register INA219 schreiben
'W = 8192                                                    ' Calibration Register Value
= 7880                                                    ' Optional second Calibration step
Ina219_reg = &H05                                           ' Calibration Register
Gosub Ina219_reg_write                                      ' Register INA219 schreiben

'Ausgang 5 Volt
Ina219_adr_w = Ina219_5_adr_w                               ' Schreibadresse INA219 Ausgang 5 Volt
Ina219_adr_r = Ina219_5_adr_r                               ' Leseadresse INA219 Ausgang 5 Volt
= &B0001011111111111                                      ' Register 00h, 12 Bit, 128 Samples, Bus Voltage Range 16 V, PG 160 mV
Ina219_reg = &H00                                           ' Configuration Register
Gosub Ina219_reg_write                                      ' Register INA219 schreiben
'W = 8192                                                    ' Calibration Register Value
= 7502                                                    ' Optional second Calibration step
Ina219_reg = &H05                                           ' Calibration Register
Gosub Ina219_reg_write                                      ' Register INA219 schreiben

'Ausgang 1,25-25 Volt
Ina219_adr_w = Ina219_25_adr_w                              ' Schreibadresse INA219 Ausgang 1,25-25 Volt
Ina219_adr_r = Ina219_25_adr_r                              ' Leseadresse INA219 Ausgang 1,25-25 Volt
= &B0010111111111111                                      ' Register 00h, 12 Bit, 128 Samples, Bus Voltage Range 32 V, PG 80 mV
Ina219_reg = &H00                                           ' Configuration Register
Gosub Ina219_reg_write                                      ' Register INA219 schreiben
'W = 40960                                                   ' Calibration Register Value
= 37654                                                   ' Optional second Calibration step
Ina219_reg = &H05                                           ' Calibration Register
Gosub Ina219_reg_write                                      ' Register INA219 schreiben

Reset Led_rt                                                ' LED rot aus

Cls

Nachdem die rote LED ausgeschaltet wurde, wird noch die Anzeige auf dem LCD gelöscht. Die Beschreibung der Hauptprogrammschleife erfolgt im nächsten Teil der Dokumentation.