'############################################################################### '# # '# Dieses Programm dient zum automatischen Laden eines Akkupacks # '# # '############################################################################### '# # '# Änderungen # '# # '# - Ab dieser Version dient das Programm nicht mehr zur Aufnahme von # '# Kennlinien, sondern es wird das Programm zum automatischen Laden # '# implementiert. # '# # '############################################################################### $crystal = 16000000 $baud = 9600 Daccs Alias Portd.2 Adcs Alias Portc.2 Adsck Alias Portc.4 '################################# Prozessor ################################### 'ATMEGA8-16PI 'Externer Quarzpszillator mit 16 MHz '################################# Anschlüsse ################################## 'LEDs 'LED ROT --> Portd.5 'LED GELB --> Portd.6 'LED GRÜN --> Portd.7 'D/A-Wandler LTC1451 'CS --> Portd.2 'Chipselect 'SCK --> Portd.4 'Serial Clock 'SDI --> Portd.3 'Serial Data Input 'A/D-Wandler LTC2400 'CS --> Portc.2 'Chipselect 'SCK --> Portc.4 'Serial Clock 'SDO --> Portc.3 'Serial Data Output 'Temperatursensor DS1821 'DQ --> Portb.1 'Datenleitung '############################### Konstanten #################################### Const Read_temp = &HAA Const Startconvert_t = &HEE Const Stopconvert_t = &H22 Const Write_status = &H0C Const Read_status = &HAC Const Read_counter = &HA0 Const Load_counter = &H41 Const Reload = 62500 'Wert für Outputcompareregister. 1 Sekundenintervall Const Loadthreshold = 51118 'ADC-Wert, ab dem bei Unterschreitung der Ladevorgang beginnt. Const Grenzadcwert = 57803 'ADC-Wert, bei dessen Überrschreitung der Ladevorgang abgebrochen wird Const Grenztemp = 45 'Temperatur in °C, bei deren Überschreitung der Ladevorgang abgebrochen wird Const Maxschnellladezeit = 250 'Zeit in Minuten, bei deren Überschreitung der Schnellladevorgang abgebrochen wird Const Auswertschwelle_spannung = 8.6 'Spannung in Volt, bei deren Überschreitung die Gradientenfeinauswertung vorgenommen wird Const Auswertschwelle_gradt = 0.18 'Temperaturgradient in °C/min bei dessen Überschreitung die Gradientenfeinauswertung vorgenommen wird Const Gradientu_ladeschluss = 0.001 'Spannungsgradient in V/min, bei dessen Unterschreitung der Schnellladevorgang beendet wird Const Gradientt_ladeschluss = 0.62 'Temperaturgradient in °C/min bei dessen Überschreitung der Schnellladevorgang beendet wird Const Ugrenz_erhalt = 8.86 'Spannung in V, bei deren Überschreitung der Erhaltungsladevorgang beendet wird Const Tgrenz_erhalt = 45 'Temperatur in °C, bei deren Überschreitung der Erhaltungsladevorgang beendet wird '############################### Variablen ##################################### Dim Dummy As Byte Dim Mess_adcwert As Word Dim Sekunden As Byte Dim Minuten As Word Dim Messzaehler As Byte Dim Tempmesszaehler As Byte Dim Temperature(3) As Single Dim Adcwert(3) As Word Dim Flag1 As Byte Dim Status As Byte 'Diese Byte enthält informationen über den Status des Ladevorgangs 'Status = 0 --> Ende 'Status = 1 --> Schnellladen 'Status = 2 --> Erhaltungsladen '########################## Subroutinendeklaration ############################# Declare Sub Set_daconverter(byval Value As Word) Declare Function Get_adconverter() As Word Declare Sub Init_ds1821 Declare Function Get_temp() As Single Declare Sub Messwert_aufnahme Declare Sub Schnellladen Declare Sub Erhaltungsladen '########################### Ports & HArdware ################################## Config Portd = Output Portd = 0 Config Portc = Output Portc = 0 Config Portc.3 = Input Config 1wire = Portb.1 Config Timer1 = Timer , Prescale = 256 'Timerkonfiguration Ocr1ah = High(reload) Ocr1al = Low(reload) Tccr1a = 0 'Outputcopare von Ausgängen trennen Set Tccr1b.3 'Timer nach outputcompare zurücksetzen On Compare1a Timer1_isr: '############################### Initalisierung ################################ Daccs = 1 Adcs = 1 'Chip select auf high legen Adsck = 0 'SCK des A/D-Wandlers auf low legen Portd.5 = 1 'LEDs ausschaltrn Portd.6 = 1 Portd.7 = 1 Status = 0 Sekunden = 0 Minuten = 0 Messzaehler = 0 Init_ds1821 Print "Active"; Print Chr(13); 'Enable Compare1a 'Enable Interrupts '############################### Hauptprogramm ################################ Start: Wait 1 Mess_adcwert = Get_adconverter() 'Klemmspannung des Akkus messen If Mess_adcwert < Loadthreshold Then 'Wenn Klemmspannung unter bestimmter Schwelle, Print "Schnellladen"; Print Chr(13); Status = 1 'Schnellladen Portd.6 = 0 'gelbe LED an Sekunden = 0 Minuten = 0 Messzaehler = 0 Call Set_daconverter(2354) 'Strom 2400mA einstellen Enable Compare1a 'Interrupts für weiteren Ablauf aktivieren Enable Interrupts Else Print "Erhaltungsladen"; Print Chr(13); Status = 2 'Erhaltungsladen Portd.7 = 0 'grüne LED an Sekunden = 0 Minuten = 0 Messzaehler = 0 Call Set_daconverter(300) 'Strom 300mA einstellen Enable Compare1a 'Interrupts für weiteren Ablauf aktivieren Enable Interrupts End If While Status <> 0 ' in dieser Schleife verharren, bis Status auf Ende (0) gesetzt wird If Flag1 = 1 Then Flag1 = 0 Stop Timer1 Dummy = Dummy + 1 'Tempmesszaehler = Messzaehler + 1 'Temperature(tempmesszaehler) = Get_temp() 'einen Temperaturwert einlesen Wait 1 Start Timer1 End If Wend Disable Compare1a 'Interrupts deaktivieren Disable Interrupts Call Set_daconverter(0) 'Strom 0A einstellen Waitms 100 Call Set_daconverter(0) 'Strom 0A einstellen (Redundanz) End '############################## Subroutinen ################################### Sub Set_daconverter(byval Value As Word) 'Diese Subroutine dient zum Setzen des D/A-Wandlers 'mit der Variable Value wird ein Wert mit maximal 12 Bit übergeben, welcher 'dann an den D/A wandler geschickt wird Local Dacvalue As Word If Value < 4096 Then 'Prüfen, ob wert nicht längerals 12 bit ist Portd.4 = 0 Daccs = 0 'Chip select auf low legen Dacvalue = Value 'Wert übernehmen Shift Dacvalue , Left , 4 'MSB bis Bit15 von Dacvalue schieben Shiftout Portd.3 , Portd.4 , Dacvalue , 0 , 12 Daccs = 1 'Chip select auf high legen End If End Sub '**************************************************************************** Function Get_adconverter() As Word 'diese Funktion dient zum Auslesen des A/D-Wandlers. Die Funktion gibt den 'gelesenen Wert an die Variable zurück. Es werden von den 24 Bit nur 16 Bit benötigt 'Die letzten 8 Bit verfallen. Negative werte werden auf 0 aufgerundet Local Adcvalue As Word Local Adclauf As Byte Local Negativ As Byte Adcvalue = 0 Adsck = 0 'Setze SCKauf low, damit beim aktivieren des Wandlers 'der Chip in den externalSCK-Mode geht das SCK-Signal wird dann vom Prozessor generiert Adcs = 0 'CS auf low --> Chip aktivieren While Pinc.3 = 1 'warten bis EOC(EndOfConversion)-Bit auf 0 geht Wend Adsck = 1 Waitus 1 Adsck = 0 Waitus 1 'bit 30 überspringen Adsck = 1 Waitus 1 Adsck = 0 Waitus 1 'bit 29 takten Adsck = 1 Waitus 1 If Pinc.3 = 1 Then 'bit 29 (Vorzeichen) überprüfen Negativ = 0 Else Negativ = 1 End If Adsck = 0 Waitus 1 'bit 28 überspringen Adsck = 1 Waitus 1 For Adclauf = 1 To 16 '16 Bit einlesen MSB first Shift Adcvalue , Left , 1 'Bits nach links verschieben Adsck = 0 Waitus 1 'Taktimpuls Adsck = 1 Waitus 1 Adcvalue.0 = Pinc.3 'Bit eilesen Next Adcs = 1 'CS auf 1 Chip deaktivieren, nächste Wandlung starten If Negativ = 1 Then Get_adconverter = 0 'bei negativem Wert 0 zurückgeben Else Get_adconverter = Adcvalue 'bei positivem wert den Wert zurückgeben End If End Function '******************************************************************************* Sub Init_ds1821 'Diese Subroutine dient zur Einstellung des 1-Wire-Temperatursensors DS1821 'In dieser Version wird der Sensor im One-Shot Modus betrieben Local Wert As Byte 1wreset '1-Wire-Reset durchführen Print "ERRORFLAG: "; Print Err; 'Errorflag ausgeben Print Chr(13); 1wwrite Write_status 'Befehl zum Schreiben des Control/Statusregisters geben 1wwrite 1 'Zum Control/Statusregister schreiben (ONE SHOT AKTIVIERT!!!) Waitms 15 1wreset '1-Wire-Reset durchführen Print "ERRORFLAG: "; Print Err; 'Errorflag ausgeben Print Chr(13); 1wwrite Read_status 'Befehl zum Lesen des Control/Statusregisters geben Wert = 1wread() 'Statusregister lesen Print Wert; Print Chr(13); 1wreset '1-Wire-Reset durchführen 1wwrite Startconvert_t 'Befehl zum Start der Temperaturmessung geben 1wreset '1-Wire-Reset durchführen End Sub '******************************************************************************* Function Get_temp() As Single 'Diese Funktion liest den Temperatursensor DS1821 aus und rechnet die Temperatur 'ins Integer-Format um. Tritt ein Fehler auf, wird der Wert 0 zurückgegeben. Local Wert As Integer Local Rawdata As Byte Local Count_remain As Word Local Count_per_degree As Word Local Temperatur As Single Local Bruch As Single 1wreset '1-Wire-Reset durchführen If Err = 0 Then 'wenn kein Fehler aufgetreten ist 1wwrite Startconvert_t 'Befehl zur Temperaturmessung geben Rawdata = 0 While Rawdata.7 = 0 'Wiederholen, bis Ende der Temperaturmessung erkannt wird 1wreset '1-Wire-Reset durchführen 1wwrite Read_status 'Befehl zum lesen des Statusregisters senden Rawdata = 1wread() 'Statusregister einlesen Wend 1wreset '1-Wire-Reset durchführen 1wwrite Read_temp 'Befehl zum Temperaturlesen geben Rawdata = 1wread() 'Temperatur lesen 1wreset '1-Wire-Reset durchführen 1wwrite Read_counter 'Befel zum Lesen des Counterregister schicken Count_remain = 1wread(2) 'Counterregister lesen 1wreset '1-Wire-Reset durchführen 1wwrite Load_counter 'Befehl zum Laden des Slopeaccumulators in das Counterregister schicken 1wreset '1-Wire-Reset durchführen 1wwrite Read_counter 'Befel zum Lesen des Counterregister schicken Count_per_degree = 1wread(2) 'Counterregister lesen If Rawdata.7 = 1 Then 'Wenn negatives Vorzeichen vorliegt Rawdata = Rawdata + 2 '2-er-Komplement addieren Wert = Rawdata Wert = Wert * -1 'negatives Vorzeichen setzen Else Wert = Rawdata End If Bruch = Count_per_degree - Count_remain Bruch = Bruch / Count_per_degree If Wert < 0 Then 'Je nach Vorzeichen die Umrechnung durchführen Temperatur = Wert + 0.5 Temperatur = Temperatur - Bruch Else Temperatur = Wert - 0.5 Temperatur = Temperatur + Bruch End If Get_temp = Temperatur 'Temperaturwert zurückgeben Else 'Wenn Fehler aufgetreten ist Print "ERROR!"; 'Fehlermeldung ausgeben Print Chr(13); Get_temp = 0 End If End Function '****************************************************************************** Sub Schnellladen 'Diese Subroutine dient zum Durchführen der Schnellladung. Sie wird einmal pro 'Minute aufgerufen. Jede Minute wird je ein Meßwert für Temperatur und Spannung 'aufgenommen. Liegen diese nicht in bestimmten Grenzen, wird der Ladevorgang 'abgebrochen. Alle drei Minuten, wir aus den Meßwerten ein Mittelwert gebildet 'und die Gradienten ausgewertet. Anhand der Gradienten wird entschieden, ob der 'Ladevorgang beendet werden soll. Local Spannungsgradient As Single Local Temperaturgradient As Single Local Spannung As Single Local Temperatur As Single Local Flag As Byte 'Stop Timer1 If Minuten > Maxschnellladezeit Then 'Wenn Maximal Print "Error"; 'Fehlermeldung ausgeben Print Chr(13); Print "Timeout"; Print Chr(13); Portd.6 = 1 'gelbe LED aus Portd.5 = 0 'rote LED an Status = 0 'Ladevorgang abbrechen Else 'Wenn Zeit OK ist, dann normal den Ladevorgang bearbeiten '****************************************************************** Messzaehler = Messzaehler + 1 'Meßzähler um eins erhöhen If Messzaehler = 3 Then 'wenn Meßzähler=3 dann Messzaehler = 0 'Meßzähler zurücksetzen '************** Mittelwert des AD-Wandlerwertes ermitteln ********* Spannung = Adcwert(1) + Adcwert(2) Spannung = Spannung + Adcwert(3) Spannung = Spannung / 3 Spannung = Spannung / 65536 Spannung = Spannung * 10 '************** Mittelwert des Temperaturwertes ermitteln ********* Temperatur = Temperature(1) + Temperature(2) Temperatur = Temperatur + Temperature(3) Temperatur = Temperatur / 3 '************** Mittelwert des Spannungsgradienten ermitteln ********* Spannungsgradient = Adcwert(3) - Adcwert(1) Spannungsgradient = Spannungsgradient / 2 Spannungsgradient = Spannungsgradient / 65536 Spannungsgradient = Spannungsgradient * 10 '************** Mittelwert des Temperaturgradienten ermitteln ********* Temperaturgradient = Temperature(3) - Temperature(1) Temperaturgradient = Temperaturgradient / 2 '********************** Gradientenauswertung ************************** If Spannungsgradient < 0 Then 'Wenn Spannunsgradient<0 Status = 2 'Ladevorgang beenden, Erhaltungsladung einleiten Print "Schnellladung beendet"; Print Chr(13); Portd.6 = 1 'gelbe LED aus Portd.7 = 0 'grüne LED an Else 'Wenn Spannunsgradient nicht <0, dann weitere Auswertung '********************** Weitere Auswertung ************************* If Temperaturgradient > Gradientt_ladeschluss Then 'Wenn Spannunsgradient> bestimmte Schwelle Status = 2 'Ladevorgang beenden, Erhaltungsladung einleiten Print "Schnellladung beendet"; Print Chr(13); Portd.6 = 1 'gelbe LED aus Portd.7 = 0 'grüne LED an Else 'Wenn Temperaturgradient nicht > Schwelle, dann Feinauswertung '********************** Feinauswertung ***************************** Flag = 0 If Spannung > Auswertschwelle_spannung Then 'wenn die Klemmspannung über einer gewissen Schwelle liegt, Flag = 1 ' dann Flag für Feinauswertung setzen End If If Temperaturgradient > Auswertschwelle_gradt Then 'wenn Temperaturgradient über einer gewissen Schwelle liegt, dann Flag für Feinauswertung setzen Flag = 1 ' dann Flag für Feinauswertung setzen End If If Flag = 1 Then If Spannungsgradient < Gradientu_ladeschluss Then 'Wenn Spannungsgradient unter eine bestimmte Schwelle fällt, dann Status = 2 'Ladevorgang beenden, Erhaltungsladung einleiten Print "Schnellladung beendet"; Print Chr(13); Portd.6 = 1 'gelbe LED aus Portd.7 = 0 'grüne LED an End If End If End If End If Else Adcwert(messzaehler) = Get_adconverter() 'einen Adcwert einlesen ' Temperature(messzaehler) = Get_temp() 'einen Temperaturwert einlesen Wait 2 If Adcwert(messzaehler) > Grenzadcwert Then 'Wenn Überspannung erkannt wurde, dann Print "Error"; 'Fehlermeldung ausgeben Print Chr(13); Print "Ueberspannung"; Print Chr(13); Portd.6 = 1 'gelbe LED aus Portd.5 = 0 'rote LED an Status = 0 'Ladevorgang abbrechen End If If Temperature(messzaehler) > Grenztemp Then 'Wenn Übertemperatur erkannt wurde, dann Print "Error"; 'Fehlermeldung ausgeben Print Chr(13); Print "Uebertemperatur"; Print Chr(13); Portd.6 = 1 'gelbe LED aus Portd.5 = 0 'rote LED an Status = 0 'Ladevorgang abbrechen End If End If '********************************************************************* End If Call Set_daconverter(2354) 'Strom 2400mA wieder einstellen 'Start Timer1 End Sub '****************************************************************************** Sub Erhaltungsladen 'Diese Subroutine dient zum Durchführen der Erhaltungsladung. Sie wird einmal pro 'Minute aufgerufen. Jede Minute wird je ein Meßwert für Temperatur und Spannung 'aufgenommen. Liegen diese nicht in bestimmten Grenzen, wird der Ladevorgang 'beendet. Local Spannung As Single Local Temperatur As Single Local Adcvalue As Word Adcvalue = Get_adconverter() 'AD-Wandler auslesen Temperatur = Get_temp() 'Temperatur messen Spannung = Adcvalue / 65536 'Spannung ausrechnen Spannung = Spannung * 10 If Spannung > Ugrenz_erhalt Then 'Wenn Überspannung erkannt wurde, dann Print "Erhaltungsladung beendet"; 'Meldung ausgeben Print Chr(13); Print "Überspannung"; Print Chr(13); Portd.7 = 1 'grüne LED aus Status = 0 'Ladevorgang beenden End If If Temperature(messzaehler) > Tgrenz_erhalt Then 'Wenn Übertemperatur erkannt wurde, dann Print "Erhaltungsladung beendet"; 'Meldung ausgeben Print Chr(13); Print "Übertemperatur"; Print Chr(13); Portd.7 = 1 'grüne LED aus Status = 0 'Ladevorgang beenden End If Call Set_daconverter(300) 'Strom 300mA wieder einstellen End Sub '****************************************************************************** Timer1_isr: Print Sekunden; 'Nur zur Überwachungszwechen Print Chr(13); Sekunden = Sekunden + 1 'eine Sekunde dazuzählen If Sekunden = 59 Then Call Set_daconverter(0) 'Strom 0A einstellen (für Messung, die eine Sekunde später erfolgt) Flag1 = 1 End If If Sekunden = 60 Then 'Wenn eine Minute um ist, dann Sekunden = 0 'Sekundenzähler auf Null setzen Minuten = Minuten + 1 'Minutenstand um 1 erhöhen If Status = 1 Then 'wenn Status "Schnellladen" Erkannt Ist , Schnellladen 'Dann In Das Entsprechende Unterprogramm Springen End If If Status = 2 Then 'wenn Status "Erhaltungsladen" Erkannt Ist , Erhaltungsladen 'Dann In Das Entsprechende Unterprogramm Springen End If End If Return