; ******************************************************************* ; * Include Routine fuer Akkuload, Berechnungs- und Anzeigeroutinen * ; * (C)2005 by Gerh.Schmidt, info@avr-asm-tutorial.net * ; ******************************************************************* ; ; ************** EEPROM Init, Lesen und Schreiben ****************** ; ; Initiiert den EEPROM-Speicher und stellt gespeicherte Id's fest ; EpInit: clr ZH ; Z ist EEPROM-Lesezeiger clr ZL clr R0 ; R0 ist Z�ler EpInit1: sbic EECR,EEWE ; Warte auf Schreib-Ende rjmp EpInit1 ; Warte weil Schreib-Bit gesetzt inc R0 ; n�hste Akku-Id ldi rmp,cEepMax+1 ; Maximalanzahl Id's cp R0,rmp ; vergleiche brcc EpInit4 ; Ende erreicht out EEARL,ZL ; EEPROM-Leseadresse setzen out EEARH,ZH sbi EECR,EERE ; EEPROM-Lesebit setzen EpInit2: sbic EECR,EERE ; warte auf Lesen ok rjmp EpInit2 ; warte weiter in rmp,EEDR ; Lese Akku-Id-Nummer cp rmp,R0 ; vergleiche mit aktueller Nummer brne EpInit4 ; nicht richtig, beende adiw ZL,1 ; n�hstes Byte im EEPROM out EEARL,ZL ; EEPROM-Lese-Adresse setzen out EEARH,ZH sbi EECR,EERE ; Read Enable setzen EpInit3: sbic EECR,EERE ; warte auf Lesen ok rjmp EpInit3 ; warte weiter in rmp,EEDR ; Lese Typangabe cpi rmp,0xA0 ; muss zwischen hex A0 und A3 sein brcs EpInit4 ; kleiner als A0, beenden cpi rmp,0xA4 ; gr�er als A3? brcc EpInit4 ; gr�er als A3, beenden adiw ZL,15 ; n�hste EEPROM-Position rjmp EpInit1 ; weiter EpInit4: dec R0 ; speichere Anzahl korrekter Akku-Id's sts sEaNm,R0 ret ; ; Lese den EEPROM-Inhalt der Akku-Id in rmp in den SRAM-Puffer ; EpRead: dec rmp ; Startet mit Id=1 mov ZL,rmp ; Kopiere nach Z clr ZH ; MSB auf Null, Adresse mit 16 multiplizieren lsl ZL ; *2 rol ZH lsl ZL ; *4 rol ZH lsl ZL ; *8 rol ZH lsl ZL ; *16 rol ZH ldi XH,HIGH(sEepB) ; X ist SRAM-Puffer-Zeiger ldi XL,LOW(sEepB) EpRead1: sbic EECR,EEWE ; warte auf Schreibende rjmp EpRead1 out EEARH,ZH ; gib EEPROM-Adresse aus out EEARL,ZL sbi EECR,EERE ; Setze Read Enable EpRead2: sbic EECR,EERE ; Warte auf Lese-Ende rjmp EpRead2 in rmp,EEDR ; Lese Byte st X+,rmp ; Speichere im SRAM-Puffer adiw ZL,1 ; n�hstes Byte im EEPROM mov rmp,ZL ; Teste auf Ende andi rmp,0x0F ; letzte vier Bits = Null? brne EpRead1 ; Lese weiteres Byte ret ; ; Schreibe den Pufferinhalt im SRAM in das EEPROM ; EpWrite: ldi XH,HIGH(sEepB) ; X ist der SRAM-Puffer-Zeiger ldi XL,LOW(sEepB) ld rmp,X ; Lese die ID-Nummer dec rmp ; Id's starten mit Id=1 mov ZL,rmp ; Kopiere nach Z clr ZH ; MSB leeren, EEPROM-Adresse mit 16 multiplizieren lsl ZL ; *2 rol ZH lsl ZL ; *4 rol ZH lsl ZL ; *8 rol ZH lsl ZL ; *16 rol ZH EpWrite1: sbic EECR,EEWE ; warte auf Schreibende rjmp EpWrite1 out EEARH,ZH ; gib EEPROM-Schreibadresse aus out EEARL,ZL ld rmp,X+ ; Lese Byte aus SRAM-Puffer out EEDR,rmp ; Schreibe ins EEPROM-Datenregister cli ; Stop Interrupts sbi EECR,EEMWE ; Setze Schreibmode Enable sbi EECR,EEWE ; Setze Write Enable sei ; erm�liche Interrupts wieder adiw ZL,1 ; n�hste Adresse im EEPROM mov rmp,ZL ; Test auf Ende andi rmp,0x0F ; Letzte vier Bits = Null? brne EpWrite1 ; Schreibe noch weiter Bytes ret ; ; Prfe Akku-Id und addiere die Ladekapazit� zur gespeicherten Id im EEPROM ; R0 ist der Kanal, erh�t denm Inhalt von R0 und R1! ; EpStore: rcall GetAkkuId ; Lese die Id des aktuellen Kanals tst rmp ; Id=0? breq EpStore4 ; ja, beende lds ZL,sEANm ; Lese die Anzahl Id's im EEPROM sec ; setze Carry-Flagge cpc rmp,ZL ; vergleiche mit (Anzahl der Id's+1) brcc EpStore4 ; gr�er als die Anzahl der gespeicherten Id's rcall EpRead ; lese die gew�lte Id in das SRAM ldi ZH,HIGH(sAdcC) ; Zeiger auf die gemessene Ladekapazit� in mAh ldi ZL,LOW(sAdcC) add ZL,R0 ; addiere Kanal zur Adresse add ZL,R0 ld XL,Z+ ; gemessene Ladekapazit� in X lesen ld XH,Z lds ZL,sENRL ; Restkapazit� vom Puffer nach Z lesen lds ZH,sENRM add ZL,XL ; gemessene Ladekapazit� addieren adc ZH,XH lds XL,sENCL ; Nennkapazit� des Akkus in X lds XH,sENCM clr rmp ; Z�ler fr Anzahl Volladungen leeren EpStore1: cp ZL,XL ; Restkapazit� in Z mit Nennkapazit� in X vergleichen cpc ZH,XH brcs EpStore2 ; Restkapazit� kleiner als Nennkapazit� sub ZL,XL ; subtrahiere Nennkapazit� sbc ZH,XH inc rmp ; Erh�e Anzahl der Volladungen rjmp EpStore1 ; weiter EpStore2: ; Anzahl der Volladungen ist in rmp, Restkapazit� in Z sts sENRL,ZL ; Restkapazit� im SRAM-Puffer speichern sts sENRM,ZH tst rmp ; eine volle Ladung oder mehr? breq EpStore3 ; nein lds ZL,sENLL ; Lese Anzahl Volladungen aus SRAM-Puffer add ZL,rmp ; addiere zur Anzahl Volladungen sts sENLL,ZL ; Speichere LSB der Anzahl Volladungen brcc EpStore3 ; kein �ertrag lds ZL,sENLM ; erh�e MSB der Anzahl Volladungen inc ZL sts sENLM,ZL ; speichere MSB der Anzahl Volladungen EpStore3: ; SRAM-Puffer ist komplett, speichere rcall EpWrite ; Schreibe den Puffer ins EEPROM EpStore4: ret ; ; *** Wandle die gemessenen Spannungen in dezimal und berechne Strom dezimal *** ; ; Wandle die Summe aus 32 ADC-Messungen in bin�e Spannung um ; Die Summe sd32e ist in R3:R2, das Ergebnis in R3:R2, verwendet R6:R5:R4 ; Referenzspannung ist 5V, Umrechnung: U[mV] = s32e * 39 / 256 ; Adc2mV: mov R4,R2 ; Kopiere s32e nach R6:R5:R4 und multipliziere mit 8 mov R5,R3 clr R6 lsl R4 ; * 2 rol R5 rol R6 lsl R4 ; * 4 rol R5 rol R6 lsl R4 ; * 8 rol R5 rol R6 mov R0,R4 ; Kopiere Zwischenergebnis in rmp:R1:R0, multipliziere mit 32 mov R1,R5 mov rmp,R6 lsl R4 ; * 16 rol R5 rol R6 lsl R4 ; * 32 rol R5 rol R6 add R4,R0 ; * 40, addiere 8-fach und 32-fach = 40-fach adc R5,R1 adc R6,rmp clr rmp sub R4,R2 ; * 39, ziehe Ausgangswert einmal ab = 39-fach sbc R5,R3 sbc R6,rmp mov R2,R5 ; / 256, Kopiere die beiden obersten Bytes ins Ergebnis (=/256) mov R3,R6 ldi rmp,0x80 ; runde das Ergebnis add rmp,R4 clr rmp adc R2,rmp adc R3,rmp ret ; ; Negativen in positiven bzw. positiven in negativen Wert umwandeln (R3:R2) ; Negative: neg R2 ; Zweierkomplement clr rmp sbc rmp,R3 mov R3,rmp ret ; ; Umrechnung der Differenzspannung ber dem Widerstand (in mV) in Strom (mA) ; mV Differenz in R3:R2, Ergebnis in R3:R2 ; ADC Referenzspannung ist 5V ; Umrechnung: mA = 11.84 * (s32ungerade - s32gerade) / 256 ; mV2mA: ldi rmp,0x80 ; teste ob Spannungsdifferenz negativ and rmp,R3 mov R0,rmp ; Speichere Vorzeichen breq mV2mA1 ; nicht negativ ; wandle negativ in positiv um rcall negative mV2mA1: mov R4,R2 ; kopiere nach R6:R5:R4 mov R5,R3 clr R6 lsl R4 ; * 2, multipliziere mit zwei rol R5 rol R6 add R4,R2 ; * 3, addiere Ausgangswert = * 3 adc R5,R3 clr rmp adc R6,rmp lsl R4 ; * 6, multipliziere mit zwei = * 6 rol R5 rol R6 lsl R4 ; * 12, multipliziere mit zwei = * 12 rol R5 rol R6 lsr R3 ; R3:R2 / 2, dividiere Ausgangswert / 8 ror R2 lsr R3 ; R3:R2 / 4 ror R2 lsr R3 ; R3:R2 / 8 ror R2 sub R4,R2 ; * 11.88, subtrahiere ein Achtel sbc R5,R3 sbc R6,rmp mV2mA3: mov R2,R5 ; kopiere Ergebnis nach R3:R2, teilen durch 256 mov R3,R6 ldi rmp,0x80 ; runde Ergebnis add rmp,R4 clr rmp adc R2,rmp adc R3,rmp tst R0 ; prfe negativ breq mV2mA4 ; nein rjmp negative ; wandle in negativ um mV2mA4: ret ; ; Rechne Strom in mA in Kapazit� in mAh um ; Anfang: R6:R5:R4 enth�t den Strom als 256*I(mA) ; Ende: R3:R2 ist die Ladekapazit� ber 4 Sekunden als 256*mAh ; mA2mAh: mov R1,R4 ; Kopiere den Ausgangswert nach R3:R2:R1 mov R2,R5 mov R3,R6 lsr R3 ; dividiere den Strom durch 2 ror R2 ror R1 lsr R3 ; ... durch 4 ror R2 ror R1 ; Der Strom in mA, multipliziert mit 64, ist jetzt in R3:R2:R1 clr rmp add R1,R5 ; addiere den Original-Strom, um 65 * I zu erhalten adc R2,R6 adc R3,rmp ; Der Strom in mA, multipliziert mit 65, ist jetzt in R3:R2:R1 lsl R4 ; Multiplikation des Ausgangsstroms mit 8 rol R5 rol R6 lsl R4 ; * 4 rol R5 rol R6 lsl R4 ; * 8 rol R5 rol R6 clr rmp ; Runden rol R4 ; oberstes Bit ins Carry adc R5,rmp adc R6,rmp add R1,R5 ; addiere 8*I zu 65*I = 73*I adc R2,R6 adc R3,rmp ; Das Ergebnis von 73*I/256 ist jetzt in R3:R2 ; Diese Zahl ist gleich der Ladekapazit� in mAh, multipliziert mit 256, ; die in den vergangenen vier Sekunden in den Akku geladen wurden ret ; ; ********* 32 Messungen der Spannung sind komplett ******* ; ; ADC hat 32 Messungen durchgefhrt und aufsummiert ; Adc32m: cbr rFlg,1<0 Monitor2: ; Status = Clear, nichts ausgeben lsr R1 ; n�hster Kanal lsr R1 inc R5 ; Kanalzahl ldi rmp,4 cp R5,rmp ; Ende? brcs Monitor1 ; nein, weiter ret Monitor3: ; Status > 0, ausgeben ldi rmp,'1' ; Sende Kanalnummer add rmp,R5 rcall UartSendChar ldi rmp,':' ; Sende : rcall UartSendChar ldi rmp,' ' rcall UartSendChar ldi rmp,'N' ; Sende Id rcall UartSendChar ldi rmp,'=' rcall UartSendChar ldi ZH,HIGH(sAdcAI1) ; Z auf Id ldi ZL,LOW(sAdcAI1) add ZL,R5 add ZL,R5 ld R2,Z clr R3 rcall UartSendNmbr ldi rmp,',' rcall UartSendChar ldi rmp,' ' rcall UartSendChar ldi rmp,'S' ; Sende Status rcall UartSendChar ldi rmp,'=' rcall UartSendChar mov rmp,R1 andi rmp,0x03 subi rmp,-'0' rcall UartSendChar ldi rmp,',' rcall UartSendChar ldi rmp,' ' rcall UartSendChar ldi ZH,HIGH(sAdcU) ; Sende Spannung, Z auf Spannung ldi ZL,LOW(sAdcU) add ZL,R5 add ZL,R5 ld R2,Z+ ; lese Spannung ld R3,Z+ rcall UartSendNmbr ldi rmp,'m' rcall UartSendChar ldi rmp,'V' rcall UartSendChar ldi rmp,',' rcall UartSendChar ldi rmp,' ' rcall UartSendChar ldi ZH,HIGH(sAdcI) ; Sende Strom, Z auf Strom ldi ZL,LOW(sAdcI) add ZL,R5 add ZL,R5 ld R2,Z+ ld R3,Z mov rmp,R3 ; negativ? rol rmp brcc Monitor4 rcall Negative ldi rmp,'-' rcall UartSendChar Monitor4: rcall UartSendNmbr ldi rmp,'m' rcall UartSendChar ldi rmp,'A' rcall UartSendChar ldi rmp,',' rcall UartSendChar ldi rmp,' ' rcall UartSendChar ldi ZH,HIGH(sAdcC) ; Sende Kapazit�, Z auf Kapazit� ldi ZL,LOW(sAdcC) add ZL,R5 add ZL,R5 ld R2,Z+ ld R3,Z rcall UartSendNmbr ldi rmp,'m' rcall UartSendChar ldi rmp,'A' rcall UartSendChar ldi rmp,'h' rcall UartSendChar ldi rmp,cCr rcall UartSendChar ldi rmp,cLf rcall UartSendChar rjmp Monitor2 ; n�hster Kanal ; ; Zeit auf LCD ausgeben ; DisplTimeL: sbrs rFlg,bLcdOk ; Lcd ok? ret sbrs rFlgD,bLcd3 ; Zeile 4 verfgbar? ret ldi rmp,3 ; Zeile 4 setzen mov R1,rmp ; drei Zahlen darzustellen rcall LcdLine ; Line 4 ldi XH,HIGH(sTimeD+1) ; X auf Zeit in Tagen ldi XL,LOW(sTimeD+1) DisplTimeL1: ld R2,-X ; Zeit lesen clr R3 ; MSB l�chen mov R0,R1 ; fhrende Nullen anzeigen rcall LcdDec2 ; zwei Digits ausgeben mov rmp,R1 cpi rmp,1 ; : ausgeben? breq DisplTimeL2 ; nein ldi rmp,':' ; : anzeigen rcall LcdChar DisplTimeL2: dec R1 ; alle gesendet? brne DisplTimeL1 ; nein, n�hste Zahl ldi rmp,' ' ; Leerzeichen anh�gen rcall LcdChar rjmp LcdCursor ; Cursor setzen ; ; Zeit prfen und ber UART ausgeben ; DispTimeU: ldi rmp,cUartTime ; Minutenintervall der Ausgabe mov R0,rmp lds rmp,sTimeM ; Minuten lesen DispTimeU1: tst rmp ; Null? breq DispTimeUd sub rmp,R0 ; subtrahiere Intervall brcc DispTimeU1 ; nicht Null, weiter prfen ret ; nicht ausgeben ; ; Zeitausgabe ber UART ; DispTimeUd: ldi rmp,'T' ; Zeit ausgeben rcall UartSendChar ldi rmp,'=' rcall UartSendChar ldi rmp,3 ; drei Werte mov R1,rmp ldi ZH,HIGH(sTimeD+1) ; Z auf Tage ldi ZL,LOW(sTimeD+1) DispTimeUd1: ld R2,-Z ; Zahl lesen clr R3 mov R0,R1 ; fhrende Nullen nicht unterdrcken rcall UartDec2 mov rmp,R1 ; : ausgeben? cpi rmp,1 breq DispTimeUd2 ; nein ldi rmp,':' rcall UartSendChar DispTimeUd2: dec R1 brne DispTimeUd1 ; n�hste Zahl ldi rmp,cCr ; Wagenrcklauf rcall UartSendChar ldi rmp,cLf ; Zeilenvorschub rjmp UartSendChar ; ; Eine Minute ist vergangen, Ausgabe wenn enabled ; Minute: cbr rFlg,1<