'Steuerprogramm für Andreas Dittrichs Akkulader $regfile = "m8def.dat" '####################################### individuelle Parameter ############### Const Quarz = 4000000 'CPU-Takt $crystal = Quarz 'Quarzfrequenz $baud = 19200 'Baudrate UART Const Reload = Quarz / 8 / 50 'Timer-Reload 50Hz VT 1:8 Const Ifa = 667 'Skalier-Faktor Ist-Strom Const Isofa = 130 'Skalier-Faktor Soll-Strom Const Ufa = 20 'Skalier-Faktor Spannung Const Bifa = 1011 'Korrektur-Faktor Big-Volt Const Akkus = 4 'Anzahl der Ladeschächte Const Ausmskd = &B11000001 'AND-Maske zum Rel. Ausschalten Port D Const Ausmskb = &B11000000 'AND-Maske zum Rel. Ausschalten Port B T26taste Alias Portc.4 'Steuerpin Tiny26-Taste Bitmuster: 'Bitmuster der Relais Data 2 , 0 , 4 , 0 , 8 , 0 , 16 , 0 '4 Relais an PortD Positionen: 'LCD-Anzeigeposition je Akku Data &H11 , &H19 , &H21 , &H29 Prefixe: 'Anzeigetexte zum Wert Data " C=" , "U0=" , "U1=" , " I=" , " t=" Config Lcd = 16 * 2 Config Lcdpin = Pin , E = Portd.7 , Rs = Portd.6 , Db4 = Portc.0 , Db5 = Portc.1 , Db6 = Portc.2 , Db7 = Portc.3 'Ende individuelle Parameter '####################################### Unterprogrammliste ################### Declare Sub Neutelegramm 'neues Telegramm auswerten Declare Sub Gibaus 'Ausgabe der Daten am LCD Declare Sub Lcd_4 'Ausgabe von 4 gleichartigen Werten Declare Sub Relais_ein 'schaltet Relais ein Declare Sub Relais_aus 'schaltet Relais aus Declare Sub Next_akku 'schaltet Akku um '$sim '####################################### Deklaration von Variablen ############ Dim Rx_buf(10)as Byte 'Empfangsbuffer Dim Rix As Byte 'RX-Index Dim W1 As Word 'Wert 1 Dim W2 As Word 'Wert 2 Dim W3 As Word 'Wert 3 Dim Lmo As Byte 'Lade-Modus (Status des Tiny26) Laden Alias Lmo.7 'Statusbit Laden Langsam Alias Lmo.6 'Statusbit langsam laden Ubig Alias Lmo.5 'Statusbit Spannungsteiler Dim Lbi As Byte 'Ladestatus-Bits Dim Lst As Byte 'Ladestufe Dim Ix As Byte 'Index auf Array Dim Cks As Word 'Checksumme Dim Merker As Byte 'einige Merker Fehler Alias Merker.0 'Merker "Fehler" Neuwert Alias Merker.1 'Merker "neuer Wert" Neutext Alias Merker.2 'neuer Text ist auszugeben Fertig Alias Merker.3 'Ladevorgang beendet Tame Alias Merker.4 'Taste "Menü" Tago Alias Merker.5 'Taste "Go" Blif Alias Merker.6 'Blinkflag LCD Dim Umil As Word 'Ladespannung (in mV) Dim Imil As Word 'Ladestrom (in mA) Dim Imax As Word 'Maximalwert Strom Dim Isol As Word 'eingestellter Sollstrom Dim Ladesek As Word 'bisherige Ladezeit (in Sekunden) Dim Masek As Long 'bereits geladene mAs Dim Mastu As Word 'geladene Kapazität (in mAh) Dim Tmp32 As Long 'temporär zum 32-Bit-Rechnen Dim Tmp As Byte 'temporär Dim Mp As Byte 'Menüpunkt 'Mp: 0=Fazit, 1=Schnelladen, 2=langsamladen, 3=Stromeinstellung, 5,6=aktiv Dim Weka As Byte 'Wert-Kategorie für Ausgabe (1..5) 'Weka: 1=Kapazität, 2=U_Start, 3=U_End, 4=Ladestrom, 5=Ladezeit Dim Pfx(5)as String * 3 'Präfix Anzeigewerte Dim Anu As Byte 'Akku-Nummer Dim U0(akkus)as Word 'Startspannung aller Akkus in mV Dim U1(akkus)as Word 'Endspannung aller Akkus in mV Dim I0(akkus)as Word 'max. Ladestrom aller Akkus in mA Dim Kap(akkus)as Word 'geladene Kapazität aller Akkus in mAh Dim Zeit(akkus)as Word 'Ladezeit aller Akkus in Sek. Dim Bimub(akkus)as Byte 'Relais-Bitmuster PortB Dim Bimud(akkus)as Byte 'Relais-Bitmuster PortD Dim Xy(akkus)as Byte 'Ausgabeposition je Akkuwert Dim Timout As Byte 'Timeout Telegrammabstand Dim Prz As Byte 'Prellzähler Tasten Dim Tao As Byte 'Tastenwert alt Dim Tas As Byte 'gültiger Tastenwert Dim Taz(3) As Byte 'Tastendruckzeit für Tiny26 Dim Tazz As Byte 'Zähler für Tastendruckzeit Tiny26 Dim Lawe(4)as Word 'LCD-Ausgabewerte Dim Wartez As Byte 'Warte-Zähler für Akku-Umschaltung Dim Telez As Byte 'Telegrammzähler für Scan in Bereitschaft '####################################### Interrupt-Vektoren ################### On Urxc Onrxd 'UART-Empfangs-Interrupt On Oc1a Zeittakt 'Timer-Compare1A-Interrupt '####################################### Initialisierung ###################### Admux = &B01100101 'ADC_5 linksbündig gegen Vcc messen Adcsra = &B11100110 'ADC freilaufend mit Vorteiler 1:64 Ocr1a = Reload 'Timer1-Zählumfang für 20ms Tccr1b = &B00001010 'CTC-Modus mit Vorteiler 1:8 Enable Oc1a 'Timer1-CompareA-Interrupt freigeben Enable Urxc 'UART-RXC-Interrupt freigeben Enable Interrupts 'Interrupts global freigeben Ddrd = &HFE 'außer RXD alles Ausgänge Portd = 0 'und auf L-Pegel Ddrb = &HFF 'alles Ausgänge Portb = 0 'und auf L-Pegel Ddrc = 31 'außer ADC5 alles Ausgänge Portc = 0 'und erstmal auf L-Pegel Restore Bitmuster 'Relais-Bitmuster For Anu = 1 To Akkus 'für jeden Ladeschacht/Ladeanschluss Read Bimud(anu) 'Bitmuster PortD ins Array holen Read Bimub(anu) 'Bitmuster PortB ins Array holen Next Anu Restore Positionen 'Ausgabepositionen am LCD For Anu = 1 To Akkus 'für jeden Ladeschacht/Ladeanschluss Read Tmp 'Bitmuster PortD holen Xy(anu) = Tmp 'und im Array sichern Next Anu Anu = 1 'sauberer Start Mp = 1 'sauberer Start Taz(1) = 25 'Tastendruckzeit Schnelladen in 20ms Taz(2) = 200 'Tastendruckzeit Langsamladen in 20ms Taz(3) = 10 'Tastendruckzeit Stromeinstellung in 20ms Restore Prefixe 'LCD-Fix-Texte For Weka = 1 To 5 'für 5 Ergebnistypen Read Pfx(tmp) 'ins Array einlesen Next Weka Weka = 2 'Startspannungen anzeigen Initlcd Cls '####################################### Hauptprogramm ######################## Do 'Hauptschleife If Rix > 9 Then Neutelegramm 'neues Telegramm eingetroffen? - ja... If Neutext = 1 Then Gibaus 'Textausgebe erforderlich? - ja... If Tame = 1 Then 'Menütaste gedrückt? Reset Tame 'Tastendruck entwerten Incr Mp 'Menüpunkt hoch Mp = Mp And 3 'und auf 0..3 begrenzen If Mp = 3 Then Relais_aus 'Akku entfernen um Strom einzustellen End If If Tago = 1 Then 'Go-Taste gedrückt? Reset Tago 'Tastendruck entwerten Select Case Mp 'in Menüpunkt Case 0 '"Fazit" Incr Weka 'Wert-Kategorie hoch If Weka > 5 Then Weka = 1 'und begrenzen Case 1 To 2 'Schnelladen Anu = 1 'Start mit Akku 1 Set Mp.2 'Laden aktivieren (Mp= 5 oder 6) Case 3 'Strom einstellen Tazz = Taz(mp) 'Tastendauer Tiny26-Taste Set T26taste 'Tiny26-Taste einschalten End Select End If Loop '####################################### Interrupt-Service-Routinen ########### Onrxd: 'ISR, UART-Byte eingetroffen Incr Rix 'Schreibposition im Array erhöhen Rx_buf(rix) = Udr 'Empfangsbyte in Buffer legen Return 'fertig, zurück... Zeittakt: 'ISR, Timer1CompareA (20ms) Dim Itmp As Byte 'temp in ISR Dim Taste As Byte 'Tasten-Nummer If Timout <> 0 Then 'wenn Telegramm-Timeout aktiv ist, Decr Timout 'Timeout herunterzählen If Timout = 0 Then Set Fertig 'abgelaufen? - ja, melden End If Itmp = Adch 'ADC 8bittig lesen Select Case Itmp 'welche Taste? Case 120 To 136 'Menü-Taste Taste = 1 Case 160 To 180 'Go-Taste Taste = 2 Case Else 'keine gültige Taste Taste = 0 End Select If Taste <> Tas Then 'wenn Tastendruck anders If Taste = Tao Then 'ist Taste = vorheriger Wert Incr Prz 'Prellzähler hoch If Prz > 5 Then 'Prellzeit erreicht? Tas = Taste 'ja, Taste übernehmen If Taste = 1 Then Set Tame 'Menü-Taste If Taste = 2 Then Set Tago 'Go-Taste End If Else Prz = 0 'Prellzähler löschen Tao = Taste 'akt. Taste als Vorwert übernehmen End If End If If Tazz <> 0 Then 'wenn Tiny26-Tastenzeit läuft Decr Tazz 'Tastenzeit herunterzählen If Tazz = 0 Then Reset T26taste 'abgelaufen? - ja, Taste aus End If If Wartez <> 0 Then 'Akku-Umschaltung Decr Tazz 'Wartezeit herunterzählen If Wartez = 0 Then Relais_ein 'abgelaufen? - ja, Relais ein End If Return 'fertig, zurück... '####################################### Unterprogramme ####################### Sub Neutelegramm 'Neues Telegramm eingetroffen If Rx_buf(1) = &HED Then 'Stimmt das Startbyte? If Rx_buf(10) = &H4D Then 'Stimmt auch das Stop-Byte? Cks = 0 'Checksumme Auf 0 For Ix = 2 To 8 'alle Datenbytes Cks = Cks + Rx_buf(ix) 'addieren Next Ix Ix = Cks And 255 'nur unteres Byte If Rx_buf(9) = Ix Then 'Stimmt die Prüfsumme? W1 = Rx_buf(3) * 256 'Wert 1 W1 = W1 + Rx_buf(2) 'kopieren W2 = Rx_buf(5) * 256 'Wert 2 W2 = W2 + Rx_buf(4) 'kopieren W3 = Rx_buf(7) * 256 'Wert 3 W3 = W3 + Rx_buf(6) 'kopieren Lmo = Rx_buf(8) 'Lademodus kopieren For Ix = 1 To 10 'Array Rx_buf(ix) = 0 'löschen Next Ix Rix = 0 'von vorn einlesen Set Neuwert 'neuen Wert melden Else 'Prüfsumme stimmt nicht Set Fehler 'Fehler melden End If Else 'Stop-Byte stimmt nicht Set Fehler 'Fehler melden End If Else 'Startbyte stimmt nicht Set Fehler 'Fehler melden End If 'Startbyte If Fehler = 1 Then 'bei Sync-Fehler For Ix = 1 To 9 'alle Bytes Rx_buf(ix) = Rx_buf(ix + 1) 'um eine Position Next Ix 'verschieben Decr Rix 'letztes Byte nochmal einlesen lassen Reset Fehler 'Fehlerflag löschen Exit Sub 'auf Anzeige verzichten... End If 'Wert1 enthält in beiden Telegrammtypen immer die Spannung am Akku. 'Ob sie als "small" oder "big" angezeit werden muss, steht in "Ubig". 'Wert2 enthält den Sekundenzähler. Wert3 enthält den Strom, in Bereitschaft 'als Summe von 32 Messungen, beim Laden als Einzelmessung. 'Lmo enthält Ladestromstufe, Spannungsteilerstatus Ubig und Ladestatus. If Neuwert = 1 Then 'wenn neue Werte da sind Reset Neuwert 'Merker entwerten Toggle Blif 'Blinkflag umkippen Tmp32 = W1 'Wert1 Tmp32 = Tmp32 * Ufa 'auf Millivolt Tmp32 = Tmp32 / 256 'skalieren Umil = Tmp32 'und übernehmen If Ubig = 1 Then 'Spannungsteiler aktiv? 'ja, Ladespannung "big" (R2 auf GND, Spannungsteiler R10/R2 wirksam) Tmp32 = Tmp32 * Bifa 'Spannungsteilerfaktor Tmp32 = Tmp32 / 256 'einrechnen Umil = Tmp32 'umil enthält jetzt die Akkuspannung End If 'Ladezeit ist in W2 Ladesek = W2 'Ladezeit in Sekunden 'Ladestrom (Iststrom) ist in W3 Tmp32 = W3 Tmp32 = Tmp32 * Ifa 'Ladestrom Tmp32 = Tmp32 / 256 'skalieren Imil = Tmp32 'und übernehmen 'Während des Ladens enthält W3 den Wert einer Strom-Messung 'im Ruhezustand enthält W3 aber 32 aufsummierte Strom-Messungen!! Lbi = Lmo And &HC0 'Ladebits isolieren If Lbi = 0 Then 'ist Ruhemodus aktiv? Imil = Imil / 32 'ja, dann durch 32 teilen Masek = 0 'Milliamp-Sekunden löschen U0(anu) = Umil 'Spannung als Startspannung sichern Imax = 0 'Strom-Schleppzeiger löschen If Mp = 5 Then 'wenn Schnelladen aktiv ist If Umil > 250 Then 'nur wenn Akku erkannt wird Tazz = Taz(1) 'Tastenzeit Tiny26-Taste zuweisen Set T26taste 'Taste am Tiny26 betätigen End If End If If Mp = 6 Then 'wenn Langsamladen aktiv ist Tazz = Taz(2) 'Tastenzeit Tiny26-Taste zuweisen Set T26taste 'Taste am Tiny26 betätigen End If If Mp = 1 Then Incr Telez 'im Leerlauf alle Akkus reihum If Mp = 2 Then Incr Telez 'scannen If Telez > 10 Then 'nach 10 empfangenen Telegrammen Telez = 0 'Zähler von vorn Next_akku 'nächsten Akku End If End If 'imil enthält den Iststrom 'Sollstrom (Ladestufe) ist in den unteren 4 Bit von Lmo Lst = Lmo And 15 'Ladestufe isolieren Isol = Lst * Isofa 'Ladestrom Schnelladen If Langsam = 1 Then 'langsames Laden aktiv? Isol = Isol / 10 'Anzeigewert dezimieren End If 'Bereits geladene Kapazität ermitteln If Laden = 1 Then 'wird der Akku geladen? Masek = Masek + Imil 'ja, Milliamperesekunden summieren Mastu = Masek / 3600 'durch s/h, um mAh zu bekommen U1(anu) = Umil 'Spannung als Endspannung sichern If Imil > Imax Then Imax = Imil 'Schleppzeiger Ladestrom I0(anu) = Imax 'max. Ladestrom sichern Kap(anu) = Mastu 'bereits geladene Kapazität sichern Zeit(anu) = Ladesek 'Ladezeit sichern End If 'in Mastu ist die geladene Kapazität End If 'Zur Ausgabe stehen jetzt folgende Variablen bereit: 'Umil (word) Ladespannung in Millivolt 'Imil (word) Istwert Ladestrom in Milliampere 'Isol (word) Sollwert Ladestrom laut Stromstufe in Milliampere 'Ladesek (word) bereits vergangene Ladezeit in Sekunden 'Mastu (word) bereits geladene Kapazität in Milliamperestunden End Sub Sub Gibaus 'Ausgabe der Daten am LCD Cls Select Case Mp 'je nach Menüpunkt Case 0 'Ergebnisanzeige Lcd_4 'lt. Weka ausgewählten Wert ausgeben Case 1 To 2 'Bereitschaft vor dem Laden If Blif = 1 Then 'abwechselnd Weka = 1 'Startspannung Lcd_4 'ausgeben Else If Mp = 1 Then 'Schnelladen Lcd "Schnelladen mit" Locate 2 , 1 Lcd Isol ; "mA" Else 'mp=2, Langsamladen Lcd "Langsamladen mit" Locate 2 , 1 Imil = Isol \ 10 Lcd Imil ; "mA" End If End If Case 3 'Stromeinstellung Locate 1 , 1 Lcd "Ladestufe:" ; Lst 'Ladestromstufe Locate 2 , 5 Lcd Isol ; "mA" 'Soll-Ladestrom in Milliampere Case 5 To 6 'Laden aktiv Locate 1 , 1 Lcd Anu ; " " 'Akku-Nummer Lcd Ladesek 'vergangene Sekunden Locate 1 , 9 Lcd "U=" ; Umil 'Spannung in Millivolt Locate 2 , 1 Lcd "I=" ; Imil 'Istwert Ladestrom Locate 2 , 9 Lcd "C=" ; Mastu 'Kapazität in Milliamperestunden End Select End Sub 'fertig, zurück... Sub Lcd_4 'Ausgabe von 4 Werten Dim Zei As Byte 'Zeile Dim Spa As Byte 'Spalte Select Case Weka 'welche Werte-Kategorie? Case 1 'geladene Kapazität For Tmp = 1 To 4 'aller Akkus Lawe(tmp) = Kap(tmp) 'zur Ausgabe kopieren Next Tmp Case 2 'Startspannung For Tmp = 1 To 4 'aller Akkus Lawe(tmp) = U0(tmp) 'zur Ausgabe kopieren Next Tmp Case 3 'Endspannung For Tmp = 1 To 4 'aller Akkus Lawe(tmp) = U1(tmp) 'zur Ausgabe kopieren Next Tmp Case 4 'max. Ladestrom For Tmp = 1 To 4 'aller Akkus Lawe(tmp) = I0(tmp) 'zur Ausgabe kopieren Next Tmp Case 5 'Ladezeit (in Sekunden) For Tmp = 1 To 4 'aller Akkus Lawe(tmp) = Zeit(tmp) 'zur Ausgabe kopieren Next Tmp End Select For Tmp = 1 To Akkus 'Datensatz ausgeben Spa = Xy(tmp)and 15 'Spalte ermitteln Zei = Xy(tmp) \ 16 'Zeile ermitteln Locate Zei , Spa 'Cursor positionieren Lcd Pfx(weka) 'Präfix ausgeben Lcd Lawe(tmp) 'Wert ausgeben Next Tmp 'nochmal... End Sub 'fertig, zurück... Sub Relais_ein 'schaltet Relais für Akku ein Dim Reltmp As Byte Reltmp = Portd And Ausmskd 'alle Relais an PortD aus Portd = Reltmp Or Bimud(anu) 'ein Relais einschalten Reltmp = Portb And Ausmskb 'alle Relais an PortB aus Portb = Reltmp Or Bimub(anu) 'ein Relais einschalten End Sub Sub Relais_aus 'schaltet alle Relais aus Portd = Portd And Ausmskd 'alle Relais an PortD aus Portb = Portb And Ausmskb 'alle Relais an PortB aus End Sub Sub Next_akku 'schaltet Akku um Incr Anu 'nächster Akku If Anu > Akkus Then 'letzter Akku fertig? If Mp.2 = 1 Then 'wenn Laden aktiv Mp = 0 'Ergebnisanzeige aktivieren Weka = 1 'Kapazität anzeigen Else 'wenn Leerlauf Anu = 1 'Ring schließen End If Else 'nein, noch ein Akku da Relais_aus 'alle Relais ausschalten Wartez = 250 '5 Sekunden Wartezeit, dann Rel.ein End If End Sub '