Forum: Mikrocontroller und Digitale Elektronik Brauche eure Hilfe zum Programmieren


von Ulrich W. (sandy49)


Angehängte Dateien:

Lesenswert?

Hallo Forum,

ich habe eine Akku-Lader Schaltung im web gefunden und habe sie 
nachgebaut.
Als LCD Anzeige habe ich DATAVISION DV-20208 von Pollin.
Die Hardware habe ich mehrmals sorgfältig überprüft,ob sich vlt. doch 
ein Fehler eingeschlichen hat.Ist aber nicht der Fall.Beim Layout habe 
ich schon darauf geachtet,dass alle Pin's vom Avr im Schaltplan mit 
meinem LCD-Modul übereinstimmen.
Trotzdem habe ich auf dem LCD Modul keine Anzeige beim Einschalten.
Das LCD-Modul ist mit dem Avr (ATtiny26) durch Flachbandkabel 
verbunden.Ziehe ich jetzt während es eingeschaltet ist den Stecker vom 
LCD-Modul ab und wieder drauf,erscheinen wirre Zeichen.
Nach betätigen des Tasters 1 erscheint teilweise der Text,den die 
Software vorgibt.
Allerdings in der falschen Zeile und dazwischen immer noch diese wirren 
Zeichen.
Da die Hardware aus meiner Sicht ok ist,vermute ich,dass die Software 
auf das LCD-Modul Datavision angepasst werden müsste.Die Software ist in 
Assembler und das sind für mich Böhmische Dörfer.

Jetzt hoffe ich,dass sich jemand damit auskennt und mir hilft.




;*********** [ Blei-Akku-Lader für 12 und 24 Volt  ********************
;
;   Datei     :  sla.asm
;   Autor    :  Hanno Gräff
;   Version    :  1.4
;   Datum    :  Februar 2010
;
;   Compiler    :  Atmel AVR Assembler
;
;  Änderungen  :  1.1 Tastenentprellung nach P. Dannegger
;           1.2 Strom auf 10 A erhöht, Timer0-Prescaler von 1024 auf 256 
geändert
;          1.3  Korrekurfaktor für LCD-Strommessung und Grenzwert bei 
Uo-Ladung
;          1.4  Softstart
;
;  Bemerkungen:
;
;
;*********************************************************************** 
*********************


; Include-Files
.include "tn26def.inc"
.include "def.inc"
.include "sla.inc"


.dseg
  .org RAMBEGIN

   Grenzwert:    .byte 1    ; Grenzwert für Uo-Abschaltung bei 1/5 bzw 
1/10 Kapazität
   Puffer:      .byte 8    ; Ringpuffer
  Ladestrom:    .byte 2



.cseg
  .org 0
   rjmp POWERON           ;Reset handler
   rjmp nix ;EXT_INT0      ;IRQ0 handler
   rjmp nix ;PIN-Change
   rjmp nix ;TIM1_CMP1A      ;Timer1 compare match
   rjmp nix ;TIM1_CMP1B    ;Timer1 compare Match
   rjmp nix ;TIM1_OVF       ;Timer1 overflow handler
   rjmp TIM0_OVF           ;Timer0 overflow handler
   rjmp nix ;USI_Start      ;USI Start handler
   rjmp nix ;USI_OVF           ;USI Overflow handler
   rjmp nix ;EE_RDY          ;EEPROM Ready handler
   rjmp nix ;ANA_COMP       ;Analog Comparator handler
   rjmp nix ;ADC_Complete    ;
nix:
   reti


txtAkku:
   .db  "Akku 12V:",0        ;10 Bytes
   .db  "Akku 24V:",0

txtMode:
   .db  " 1. Io",0,0        ;8 Bytes! muß gerade Zahl sein!
   .db  " 2. Uo",0,0        ;
   .db  " 3. Ut",0,0

txtAmpere:
   .db  " 2,0 A",0,0        ;8 Bytes!
   .db  " 2,5 A",0,0
   .db  " 3,0 A",0,0
   .db  " 3,5 A",0,0
   .db  " 4,0 A",0,0
   .db  " 4,5 A",0,0
   .db  " 5,0 A",0,0
   .db  " 5,5 A",0,0
   .db  " 6,0 A",0,0
   .db  " 6,5 A",0,0
   .db  " 7,0 A",0,0
   .db  " 7,5 A",0,0
   .db  " 8,0 A",0,0
  .db  " 8,5 A",0,0
  .db  " 9,0 A",0,0
  .db   " 9,5 A",0,0
  .db  "10,0 A",0,0

txtSonstiges:
  .db   "       ",0
  .db   "  Ende!",0


PowerOn:
  cli                  ; Interrupts ausschalten
  ldi    R16, RAMEND          ; Stack initialisieren
  out     SP,  R16


  ;PINB1 (PWM), lcd_enable und LCD_RS = Ausgang
  ldi   UL, (1<< PINB1) | (1<<PIN_LCD_ENABLE) | (1<<PIN_LCD_RS)
   out   DDRB, UL

  ;PIN_LCDs (Daten) = Ausgang
  ldi   UL, (1<<PIN_LCD_D4) | (1<<PIN_LCD_D5) | (1<<PIN_LCD_D6) | 
(1<<PIN_LCD_D7)
   out   DDRA, UL

  ldi    UL, (1 << PLLE)        ; PLL aktivieren d.h. asyncroner Takt 
bei PWM
  out    PLLCSR, UL          ; 1 Mhz * 64 = 64 Mhz


waitpll:                ; Takt setzen
  in     UL, PLLCSR
  sbrs  UL, PLOCK
  rjmp  waitpll

  in     UL,PLLCSR
  ldi    r17, (1 << PCKE)
  or    UL, r17
  OUT    PLLCSR, UL


  ;LCD initialisieren
  rcall  lcd_init
  rcall   lcd_clear


  ; Spannungen in Register einlesen
  ldi    UL, low(V_Charge_fast)    ; Ladeschlußspannung (12V) einlesen
  mov    FAST_V_L,UL          ; Wert in Registern speichern
  ldi    UL, high(V_Charge_fast)
  mov    FAST_V_H,UL

  ldi    UL, low(V_Charge_Trickle)  ; Erhaltungsladespannung einlesen
  mov    TRICKLE_V_L, UL        ; in Registern speichern
  ldi    UL, high(V_Charge_Trickle)
  mov    TRICKLE_V_H, UL

  ;Timer initialisieren
  ldi    UL, (1<<CS02)         ; Timer/Counter0, prescaler auf 1/256
  out    TCCR0, UL
  ldi    UL, (1<<TOIE0)        ; Timer-Overflow0 setzen
  out    TIMSK,UL          ;


  ;PWM-initialisieren
  ldi    UL, 159              ; OCR1C setzen 159 = 25khz/50khz
  out    OCR1C, UL
  ldi    UL, 10            ; unten anfangen
  out    OCR1A,UL


  ;"Akku:" ausgeben
  ldi     ZL,Low(txtAkku*2)        ; Label "Akku 12 V: "
   ldi     ZH,High(txtAkku*2)
   rcall  lcd_home
  rcall   lcd_print

  ldi     ZL,Low(txtAmpere*2)      ; Label "Stromladen: "
   ldi     ZH,High(txtAmpere*2)
  ldi    AL,0xA            ; 1.Zeile 11. Stelle
  rcall  lcd_cursor          ; Cursor setzen
  rcall   lcd_print


  ser    UL              ; Flags setzen
  clr    UH
  clr    Key_Old
  clr    Key_State
  clr    Key_Press

  sei                  ; Interrupts ermöglichen


;*********************************************************************** 
***************************************
; Wenn Taste 1 gedrückt, dann wenn Akku an ist, starten
; Wenn Taste 1 gedrückt und kein Akku an, dann Volt hochsetzen
; Wenn Taste 2 gedrückt, Strom hochsetzen
;*********************************************************************** 
***************************************

start:
  push  UL
  push  UH
  rcall   get_voltage          ; Spannung messen
  pop    UH
  pop    UL
  ldi    AL,100            ; willkürlicher Startwert, ob eine Spannung
  clr    AH
  cp    AV_L,AL            ; gemessen werden kann <=> 3 Volt
  cpc    AV_H,AH
  brsh  akku_on
  rcall  print_voltage

  cli                  ; Interrupts ausschalten
  sbrc  Key_Press, Taste1      ; Taste1 gedrückt?
  rcall   voltage            ; Akku-Spannung einstellen
  sbrc  Key_press, Taste2
  rcall  strom            ; Akku-Strom einstellen
  sei                  ; Interrupts wieder zulassen
  rjmp  start            ; zurück

; In erster LCD-Zeile Akkutyp 12 od. 24 V anzeigen
voltage:
  clr    Key_press          ; Taste löschen
  rcall  lcd_home          ; Cursor setzen
  ldi     ZL,Low(txtAkku*2)        ; Label "Akku 12 V: " adressieren
  ldi     ZH,High(txtAkku*2)
  tst    UL              ; Ist Flag = 0
  breq  v1              ; dann 12 Volt ausgeben
  adiw  ZH:ZL,10          ; sonst Adressierung auf 24 V
v1:  rcall   lcd_print          ; auf LCD ausgeben
  com    UL              ; Flag 'umdrehen'
  ret

; und gewählten Ladestrom
strom:
  clr    key_press          ; Taste löschen
  ldi    AL,0xA            ; 1.Zeile 11. Stelle
  rcall  lcd_cursor          ; Cursor setzen
  ldi     ZL,Low(txtAmpere*2)      ; Label "Stromladen: "
   ldi     ZH,High(txtAmpere*2)

  cpi    UH,16            ; Ist Max erreicht (=10,0 Amp) ?
  brlo  s0              ; wenn nein, weiter bei s0
  clr    UH              ; wenn ja, Flag = 0
  rjmp  s3              ; Wert ausgeben

s0:  inc    UH              ; sonst Tastendruck UH=UH+1

    mov    AL,UH
s2: adiw  ZH:ZL,8            ; pro Zählwert in UH
  dec    AL              ; zur Speicherstelle
  brne  s2              ; 8 Bytes addieren

s3:  rcall  lcd_print          ; Ausgabe
  ret


;  Akku angeschaltet, d. h. auf Start warten
akku_on:
  push  UL
  push  UH
  rcall  get_voltage          ; Spannung messen
  pop    UH
  pop    UL
  rcall  print_voltage        ; Spannung ausgeben
  ldi    AL,100            ; ist Spannung immer noch größer wie 
Hysterese
  clr    AH
  cp    AV_L,AL
  cpc    AV_H,AH
  brlo  start            ; wenn kleiner, ganz zurück zu Anfang
  cli                  ; Interrupts aus
  sbrc  Key_Press, Taste1      ; wenn Taste1 gedrückt zum Laden
  rjmp  laden
  sei                  ; Interrupts zulassen
  rjmp  akku_on            ; und zurück


;*********************************************************************** 
**************************
;
; 1. Initialisierung 12 oder 24 Volt
;
;*********************************************************************** 
**************************

laden:
  clr    Key_press          ; Key_press löschen


;LCD-Strom-Korrekturwert ausrechnen
  push  UH              ; UH zwischenspeichern
  ldi    AL,4            ; für die ersten 4 Stufen
  add    UH,AL            ; bei UH=0 = 4*500mA = 2Amp
  ldi    AL,I_Korr          ; Korrekturfaktor(I_Korr) laden
  tst    Al              ; Ist AL =>0 dann weiter
  brge  j2              ; bei <0 Zweierkomplement
  neg    AL              ; aus -1 wird +1
j2:
  lsl    AL              ; Faktor * 4
  lsl    AL

  clr    BL              ; BL löschen
j1: add    BL,AL            ; pro Zähler in UH, Faktor addieren
  dec    UH              ; UH=UH-1
  tst    UH              ; wenn UH<>0
  brne  j1              ; zurück
  mov    I_Adjust,BL          ; und BL in I_Adjust speichern
  pop    UH              ; UH wieder vom Stack holen


;1. Strom / Startwert bei 2000mA steht in I_charge, pro 500mA mehr 
I_Step addieren
  ldi    AL, low(I_Charge)      ; Startwert holen
  ldi    AH, high(I_Charge)
  ldi    BL, I_Step

  mov    I_Charge_l,AL        ; Anfangsstrom = 2 A
  mov    I_Charge_h,AH

  tst    UH              ; ist Flag UH (Strom) = 0 = 2 Amp
  breq  i2              ; dann gleich weiter mit Laden

i1:  add    AL, BL            ; sonst pro Zähler I_Step addieren
  adc    AH, ZERO          ; ggf. Carry addieren
  dec    UH              ; Zähler dekrementieren
  brne  i1              ; in AH:AL steht nun der gewählte Ladestrom

i2:  ldi    ZL,Low(Ladestrom)      ; Max. Ladestrom im DSEG speichern
  ldi    ZH,High(Ladestrom)
  st    Z+,AH
  st    Z, AL

;Grenzwert für 2. Ladestufe festlegen
  push  UL
  rcall  div8            ; AH:AL / 10 = BL
  sts    grenzwert, BL        ; BL im SDRAM speichern
  pop    UL


;2. Spannung
  mov    V_FLAG, UL          ; Spannung in Register sichern >0=12V 0=24V
  tst    UL              ; ist Flag (Spannung) <> 0 dann gleich zum 
Laden
  brne  c1              ; zum Laden

; Anpassung bei 24 Volt
  lsl    FAST_V_L          ; Spannung verdoppeln:
  rol    FAST_V_H          ; Ladeschlußspannung
  lsl    TRICKLE_V_L          ; Erhaltungsladung
  rol    TRICKLE_V_H

  ldi    ZL,Low(Ladestrom)      ; Strom halbieren
  ldi    ZH,High(Ladestrom)
  ld    UH,Z+
  ld    UL,Z
  lsr    UL
  ror    UH
  ldi    ZL,Low(Ladestrom)      ; zurückschreiben
  ldi    ZH,High(Ladestrom)
  st    Z+,UH
  st    Z, UL

  lsr    I_Charge_H          ; Strom halbieren
  ror   I_CHARGE_L

  lsr    BL              ; Stromlade-Grenzwert halbieren
  sts    Grenzwert, BL
  lsr    I_Adjust          ; LCD-Korrekturfaktor halbieren


;*********************************************************************** 
**************************
;
; 1. Laden mit konstantem Strom bis Spannung bei 14,8 V bzw. 29,6 V
;
;*********************************************************************** 
**************************


  ; "1. Stufe:" ausgeben
c1:
  ldi    AL,0xA            ; 1.Zeile 11. Stelle
  rcall  lcd_cursor
   ldi     ZL,Low(txtMode*2)        ; Label "Stromladen: "
   ldi     ZH,High(txtMode*2)
   rcall  lcd_print

  clr    Zero            ; Zähler setzen, alle 256 Durchläufe ...
  clr    BL              ; Additionsregister
  clr    BH              ; für Strommesswerte
  clr    CL
  clr    CH              ; CH als Zähler verwenden
  sei                  ; Interrupts zulassen

  rcall   start_pwm          ; PWM starten

c2:  rcall   get_current          ; Strom messen, Rückgabe in AV_H:AV_L
  add    BL, AV_L          ; aufaddieren
  adc    BH, AV_H
  adc    CL, Zero          ; Null + Carry addieren

  mov    UL, I_CHARGE_L        ; Vergleichswerte und
  mov    UH, I_CHARGE_H
  rcall  adj_pwm            ; AV_H:AV_L an Reglung übergeben

  dec    CH              ; Zähler = Zähler -1
  tst    CH
  brne  c2              ; wenn nicht 0, zurück zu c2

  mov    AV_L,BH            ; Durchschnittswert aus 256 Durchläufen
  mov    AV_H,CL            ; BL fällt weg = Division durch 256

  rcall  print_current        ; LCD-Ausgabe Strom

  rcall  stop_pwm          ; PWM aus
  rcall    get_voltage          ; Spannung messen
  rcall  start_pwm          ; PWM wieder ein

  rcall  print_voltage        ; und LCD-Ausgabe Spannung

  cp    AV_L, FAST_V_L        ; Spannung = 14,8V bzw. 29,6V
  cpc    AV_H, FAST_V_H
   brsh  vcf              ; wenn >=, dann nächste Stufe

  clr    BL              ; Additionsregister wieder auf 0
  clr    BH
  clr    CL
  clr    CH              ; Zähler neu setzen

  sbrc  Key_Press, Taste1      ; Wenn Taste gedrückt,
  rjmp  ende            ; Programm abbrechen

c4:  rjmp  c2              ; und zurück


;*********************************************************************** 
**************************
;
; 2. Weiterladen für 60 min mit konstanter Spannung bei 14,8 V
;
;*********************************************************************** 
**************************

vcf:
  ;2. Stufe auf LCD ausgeben
  ldi    AL,0xA            ; 1.Zeile 11. Stelle
  rcall  lcd_cursor
   ldi     ZL,Low(txtMode*2)        ; Label
   ldi     ZH,High(txtMode*2)
  adiw  ZH:ZL,8
   rcall  lcd_print

  ldi     AL,0x49           ; Cursor von LCD auf 2. Zeile 9. Stelle
   rcall   lcd_cursor
  ldi     ZL,Low(txtSonstiges*2)    ; Leerstring zur Überdeckung
   ldi     ZH,High(txtSonstiges*2)    ; der bisherigen Stromanzeige
  rcall  lcd_print

  clr    T_Msec            ; Zeit-Zähler Milli-Sekunden
  clr    T_Sec            ; Zeit-Zähler Sekunden
  clr    T_Min            ; Zeit-Zähler Minuten

  clr    BL              ; Additionsregister
  clr    BH              ; auf 0 setzen
  clr    CL
  clr    CH              ; Zähler auf 0 setzen
  clr    ZL

vcf1:
  rcall  get_voltage          ; Spannung messen, Rückgabe AV_L, AV_H

  add    BL, AV_L          ; aufaddieren
  adc    BH, AV_H
  adc    CL, Zero          ; Null + Carry addieren

  mov   UL, FAST_V_L        ; Max-Werte holen Fast-Volt (14,8 V)
  mov    UH, FAST_V_H         ; Low-und High-byte
  rcall   adj_pwm            ; an Regelung übergeben

  dec    CH              ; Zähler = Zähler -1
  tst    CH
  brne  vcf1            ; wenn nicht 0, zurück zu vcf1

  mov    AV_L,BH            ; Durchschnittswert aus 256 Durchläufen
  mov    AV_H,CL            ; BL fällt weg = Division durch 256
  rcall  print_voltage        ; 1/Sek Spannung ausgeben
  cpi    t_min,60          ; wenn 60 Minuten um
  breq  vct              ; weiter mit Trickle-Charge

  rcall  print_minutes        ; Minutenanzeige

  cp    ZL,t_min          ; Ist ZL gleich Minuten? d.h. nur 1 mal/Minute
  breq  vcf2            ; dann weiter

  rcall  get_current          ; wenn neu, dann Strom messen
  rcall  tab_shr            ; Puffer schieben, Rückgabe Durchschnitt in 
AH:AL
  sts    Puffer+1,AV_L        ; letzten Wert in Puffer speichern
  sts    Puffer,AV_H

  mov    ZL,t_min          ; Zeitwert in ZL speichern
  cpi    ZL,5            ; erst nach 5 Minuten zum ersten Mal
  brlo  vcf2            ; Durchschnitt mit aktuellem Wert vergleichen

  lds    BL,Grenzwert        ; Grenzwert holen
  cp    AL,BL            ; Vergleich aktueller Wert (AH:AL)
  cpc    AH,Zero               ; wenn Grenzwert größer als Durchschnitt
  brlo  vct              ; dann Ende und weiter mit Trickle-Charge


vcf2:
  clr    BL              ; Additionsregister wieder auf 0
  clr    BH
  clr    CL
  clr    CH              ; Zähler neu setzen

  sbrc  Key_Press, Taste1      ; Wenn Taste gedrückt,
  rjmp  ende            ; Programm abbrechen

  rjmp  vcf1            ; sonst zürück


;*********************************************************************** 
**************************
;
; 3. Erhaltungsladung min mit konstanter Spannung bei 13,8 V/27,6V für 
alle Ewigkeit
;
;*********************************************************************** 
**************************

vct:
  ldi    AL,0xA            ; 1.Zeile 11. Stelle
  rcall  lcd_cursor
   ldi     ZL,Low(txtMode*2)        ; Label
   ldi     ZH,High(txtMode*2)
  adiw  ZH:ZL,16
   rcall  lcd_print

  ldi     AL,0x49           ; Cursor von LCD auf 2. Zeile 9. Stelle
   rcall   lcd_cursor
  ldi     ZL,Low(txtSonstiges*2)    ; Leerstring zur Überdeckung
   ldi     ZH,High(txtSonstiges*2)    ; der bisherigen Stromanzeige
  adiw  ZL:ZH,8            ; "Ende!" ausgeben
  rcall  lcd_print

  clr    BL              ; Additionsregister
  clr    BH              ; auf 0 setzen
  clr    CL
  clr    CH

vct1:
  rcall  get_voltage          ; Spannung messen, Rückgabe AV_L, AV_H

  add    BL, AV_L          ; aufaddieren
  adc    BH, AV_H
  adc    CL, Zero          ; Null + Carry addieren

  mov   UL, TRICKLE_V_L        ; Max-Werte holen Trickle-Volt (13,8 
V/27,6 V)
  mov    UH, TRICKLE_V_H       ; Low-und High-byte
  rcall   adj_pwm            ; an Regelung übergeben

  dec    CH              ; Zähler = Zähler -1
  tst    CH
  brne  vct1            ; wenn nicht 0, zurück zu vct1

  mov    AV_L,BH            ; Durchschnittswert aus 256 Durchläufen
  mov    AV_H,CL            ; BL fällt weg = Division durch 256
  rcall  print_voltage        ; Spannung ausgeben

  clr    BL              ; Additionsregister wieder auf 0
  clr    BH
  clr    CL
  clr    CH              ; Zähler neu setzen

  sbrc  Key_Press, Taste1      ; Wenn Taste gedrückt,
  rjmp  ende            ; Programm abbrechen

  rjmp  vct1


;*********************************************************************** 
**************************
;
; 4. Ende
;
;*********************************************************************** 
**************************
ende:
  rcall  stop_pwm
  rjmp  poweron



;*********************************************************************** 
**************************
;
; Timer0-Interrupt
;
;*********************************************************************** 
**************************


TIM0_OVF:                ; Zählt bis 10 Minuten
  push  UL
  push  UH
  push  BL
  push  ZH
  push  ZL
  in    R21,SREG          ; Inhalt von SREG zwischenspeichern
  mov    UL,Key_old
  in    Key_old, Key_Port
  eor    UL, Key_Old
  com    Key_old
  mov    UH, Key_State
  or    Key_State, UL
  and    UL, Key_Old
  eor    Key_State,UL
  and   UH, UL
  or    Key_Press, UH

  inc   T_Msec            ; Milli-Sek. erhöhen
  cpi    T_Msec,16          ; sind es 15
  brlo  t0_end            ; wenn nein, dann Schleife
  clr    T_Msec            ; Millisekunden auf 0
  inc    T_Sec            ; und Sekunden erhöhen (1049 ms)

  ;Vergleich aktueller Strom mit Sollstrom
  ldi    ZL, low(Ladestrom)
  ldi    ZH, high(Ladestrom)
  ld    UH,Z+
  ld    UL,Z
  cp    I_Charge_l, Ul
  cpc    I_Charge_h, UH
  brge  TO_0            ; wenn >= dann zu TO_0
  ldi    BL,6
  add    I_Charge_l,BL        ; sonst pro Sekunde um ca. 100 mA
  adc    I_Charge_h,Zero        ; erhöhen
  rjmp  TO_1
TO_0:
  mov    I_Charge_l,UL        ; falls UL und UH größer waren
  mov    I_Charge_h,UH        ; hier auf gleich setzen

TO_1:
  cpi    T_Sec,58          ; sind es 60 Sekunden?
  brlo  t0_end            ; wenn nicht, dann Schleife
  clr    T_Sec            ; Sekunden auf 0
  inc    T_Min            ; und Minute erhöhen (59752 ms)
T0_end:
  out    SREG, R21          ; Inhalt von SREG wieder herstellen
  pop    ZL
  pop    ZH
  pop    BL
  pop    UH
  pop    UL
  reti


;*********************************************************************** 
**************************
;
; ADC-Handler, Eingabe: ADMUX = UL Rückgabe: AV_H:AV_l
;
;*********************************************************************** 
**************************

get_current:
  ldi    UL, ADC_Diff_Channel
  rjmp  get_measure

get_voltage:
  ldi    UL, ADC_V_Channel

get_measure:
  cli                  ; Während Messung, Interrupts verhindern
  out    ADMUX, UL          ; ADC Channel setzen
  rcall  wait1ms            ; warte 1ms
  clr    AV_L
  clr    AV_H            ; Additionsregister löschen

  ldi    UL, (1<< ADEN)         ;
  out    ADCSR,UL

  sbi    ADCSR,ADSC          ; 1. Start = Dummymessung
m_dummy:
  sbis  ADCSR,ADIF
  rjmp  m_dummy

  ldi    UH,32             ; Schleifenzähler auf 32

m_start:
  sbi    ADCSR, ADSC          ; 2. Start

m_wait:
  sbic  ADCSR, ADSC
  rjmp  m_wait            ; Warte bis Messung erfolgt ist (ADSC wird 0)

  in    UL, ADCL          ; Messungen zwischenspeichern
  add    AV_L, UL          ; und
  in    UL, ADCH
  adc    AV_H, UL          ; Werte aufaddieren

  dec    UH
  brne  m_start            ; wiederholen bis Zähler=0

  ldi    UH, 5             ; Zähler für's Schieben, 5 mal schieben = 
geteilt durch 32
m_avg:
  lsr    AV_H
  ror    AV_L            ;
  dec    UH              ; Zähler=Zähler-1
  brne  m_avg            ;

  cbi    ADCSR,ADEN
  sei                  ; Interrupts wieder zulassen
  ret                  ;


;*********************************************************************** 
**************************
;
; PWM-Handler: Eingabe Spannung in AV_H:AV_l und Vergleichswert in UH:UL
;
;*********************************************************************** 
**************************

;PWM-Regelung
adj_pwm:
  cp    AV_L,UL            ; Vergleich Register, Register
  cpc    AV_H,UH            ; Vergleich Register, Register + Carry
  breq  f_end            ; wenn gleich, dann Ende
  cp    AV_L,UL            ; nochmal vergleichen
  cpc    AV_H,UH
  brsh  f_dec            ; springe bei größer zu dec

f_inc:                  ; ansonsten erhöhen
  in    UL, OCR1A          ; aktuellen Wert einlesen
  inc    UL              ; UL=UL+1
  cpi    UL, 159            ; ist UL>= OCR1C
  brsh  f_end            ; dann Ende
  out    OCR1A, UL          ; sonst UL nach OCR1A
  rjmp   f_end

f_dec:
  in    UL, OCR1A          ; aktuellen Wert einlesen
  dec    UL              ; OCR1A > 0 ?
  cpi    UL,1
  brlo  f_end            ; wenn Carry 0 dann vorher zu ende
  out    OCR1A, UL

f_end:
  ret


; Start and Stop PWM
start_PWM:
  sbi    PORTB,PWM_PIN
  sbi    DDRB, PWM_PIN
  ldi   UL, (1<< COM1A1)|(1 << PWM1A)
  out   TCCR1A, UL
  tst    V_Flag            ; wenn V_FLAG = 0 dann 24V
  breq  p1

  ; bei 12 V 50 khz
  ldi   UL,   (1 << CS12)      ; bei 12 = 64 Mhz/ 8/159=50 khz
  out   TCCR1B, UL
  ret

p1: ; bei 24V 25 khz
  ldi   UL,   (1 << CS12)|(1<<CS10)  ; 12+10  = 64 Mhz/16/159=25 khz
  out   TCCR1B, UL
  ret


stop_PWM:
  cbi    PORTB, PWM_PIN
  sbi    DDRB,  PWM_PIN
  ldi    UL, (0 << PWM1A)
  out    TCCR1A, UL          ; PWM1A auf null setzen
  ret


;*********************************************************************** 
**************************
;
; vier Werte in Puffer nach rechts schieben, vorher aufaddieren und 
Durchschnitt berechnen
; Rückgabewert in AH:AL
;
;*********************************************************************** 
**************************

tab_shr:
  lds    UL, Puffer+7    ; 1.Wert (Low-Byte) lesen
  mov    AL,UL        ; in AL speichern
  lds    UL, Puffer+6    ; 1. Wert(high-Byte lesen)
  mov    AH,UL        ; in AH speichern

  lds    UL, Puffer+5    ; 2.Wert (low) lesen
  sts    Puffer+7,UL      ; und an 1. Stelle (low) speichern
  add    AL,UL        ; zu AL addieren

  lds    UL, Puffer+4    ; 2.Wert (high) lesen
  sts    Puffer+6,UL      ; und an 1. Stelle (high) speichern
  adc    AH,UL        ; zu AH addieren

  lds    UL, Puffer+3    ; usw.
  sts    Puffer+5,UL
  add    AL,UL

  lds    UL, Puffer+2
  sts    Puffer+4,UL
  adc    AH,UL

  lds    UL, Puffer+1
  sts    Puffer+3,UL
  add    AL,UL

  lds    UL, Puffer
  sts    Puffer+2,UL
  adc    AH,UL

  lsr    AH          ; Durchschnitt der 4
  ror    AL          ; Werte durch 2 mal
  lsr    AH          ; rechtsschieben
  ror    AL
  ret


;*******************[ Warteschleifen 
]*******************************************************

wait1s: ;1002,54
  push    UL
  ldi      UL,10
n1:  rcall    wait100ms
  dec      UL
  brne    n1
  pop      UL
  ret

wait100ms:; 100,54ms
  push    UL
  ldi      UL,10
n2:  rcall    wait10ms
  dec      UL
  brne    n2
  pop      UL
  ret


wait5ms:; 5,03ms
  push    UL
  ldi      UL,5
  rjmp    n3
wait10ms: ;10,04ms
  push    UL
  ldi      UL,10
n3:  rcall    wait1ms
  dec      UL
  brne    n3
  pop      UL
  ret

wait1ms:
  push    UL
  ldi      UL,9
n4:  rcall    wait100us
  dec      UL
  brne    n4
  pop      UL
  ret

wait50us:  ;48us
  push    UL
  ldi      UL,14
  rjmp    n5
wait100us:;  100us
  push    UL
  ldi      UL,32
n5:  dec      UL
  brne    n5
  pop      UL
  ret


;*********************************************************************** 
*********
; Spannung auf LCD ausgeben
; Werte AV_H:AV_L
; 2. Zeile 1. Stelle
;*********************************************************************** 
***********

Print_voltage:

  ldi     AL,0x40              ; Cursor von LCD auf 2. Zeile 1 Stelle
   rcall   lcd_cursor

   mov     AL, AV_L            ; Messung speichern
   mov     AH, AV_H
   add    AL, AV_L
   adc    AH, AV_H
   add    AL, AV_L
   adc    AH, AV_H            ; jetzt ist der dreifache Wert in AH:AL

  rcall   bin2ascii            ; Wert in AH:AL in Ascii umrechnen

  push   AL                ; zuerst 1er Stelle sichern
   push  AH                              ; 10er Stelle
   push  BL                ; 100er Stelle
   mov     AL,BH              ; in BH steht 1000er Stelle
   rcall  lcd_data            ; ausgeben
   pop   AL                ; 100er Stelle holen
   rcall   lcd_data                       ; ausgeben
   ldi     AL,','              ; ein Komma zwischensetzen
   rcall   lcd_data                       ; ausgeben
   pop     AL                            ; 10er Stelle holen
   rcall   lcd_data                       ; ausgeben
   pop     AL                ; 1er Stelle holen
   rcall   lcd_data                       ; ausgeben
   ldi     AL,' '              ; Leerstelle dranhängen
   rcall   lcd_data                       ; ausgeben
   ldi     AL,'V'              ; V für Volt dranhängen
   rcall   lcd_data                       ; ausgeben
  ret


;*********************************************************************** 
***********
; Strom auf LCD ausgeben 2A = 124 Steps = ca. 124 * 16 = 1984
; Werte AV_H:AV_L
;*********************************************************************** 
***********

Print_Current:

  ldi     AL,0x49             ; Cursor von LCD auf 2. Zeile 8. Stelle
   rcall   lcd_cursor

   mov    AL, AV_L            ; Messung speichern
  mov     AH, AV_H

pc2:
  lsl    AL                ; 4 mal linksschieben = mal 16
  rol    AH
  lsl    AL
  rol    AH                ;
  lsl    AL
  rol    AH                ;
  lsl    AL
  rol    AH                ;

  ldi    UL, I_Korr            ; Korrekturfaktor (signed!) nach UL
  tst    UL                ; >0 oder <0 ?
  brge  pc3                ; wenn UL >=0 weiter bei pc3
  sub    AL, I_Adjust          ; Korrekturwert (unsigned!) subtrahieren
  sbc    AH, Zero            ; ggf. Carry-Flag
  rjmp  pc4                ; weiter mit Ausgabe

pc3:
  add    AL, I_Adjust          ; Korrekturwert (unsigned!) addieren
  adc    AH, Zero            ; ggf. Carry-Flag addieren

pc4:                    ; Ausgabe
  ;in AV_H:AV_L steht jetzt der Wert in mA
  rcall   bin2ascii            ; Wert in AH:AL in Ascii umrechnen
                       ; 1er Stelle in Al wird verworfen
   push  AH                              ; 10er Stelle
   push  BL                ; 100er Stelle
   ldi    AL, '0'              ; 1000 Stelle immer mit 0 ausgeben
  rcall  lcd_data            ; ausgeben
  mov     AL,BH              ; in BH steht 1000er Stelle
   rcall  lcd_data            ; als 100 ausgeben
   ldi     AL,','              ; ein Komma zwischensetzen
   rcall   lcd_data                       ; ausgeben
  pop   AL                ; 100er Stelle vom Stack holen nach AL
   rcall   lcd_data                       ; ausgeben
   pop     AL                            ; 10er Stelle vom Stack holen
   rcall   lcd_data                       ; ausgeben
   ldi     AL,' '              ; Leerstelle dranhängen
   rcall   lcd_data                       ; ausgeben
   ldi     AL,'A'              ; A für Ampere dranhängen
   rcall   lcd_data                       ; ausgeben
  ret


;*********************************************************************** 
***********
; Zeit auf LCD ausgeben
; Werte AV_H:AV_L
;*********************************************************************** 
***********

Print_Minutes:

   ldi     AL,0x4A             ;Cursor von LCD auf 2. Zeile 10. Stelle
   rcall   lcd_cursor

   ldi    AL, 60
   sub     AL, t_min
  clr    AH

  ;in AL steht jetzt die verbeibende Zeit
  rcall   bin2ascii            ; Wert in AH:AL in Ascii umrechnen
                       ; 1er Stelle in Al wird verworfen
   push  AL
   mov    AL, AH              ; 10 Stelle ausgeben
  rcall  lcd_data            ; ausgeben
  pop   AL                ; 1er Stelle holen
   rcall   lcd_data                       ; ausgeben
   ldi     AL, ' '                        ; Leerzeichen
   rcall   lcd_data                       ; ausgeben
   ldi     AL,'m'              ; und min
   rcall   lcd_data                       ; anfügen
   ldi     AL,'i'              ;
   rcall   lcd_data
   ldi     AL,'n'              ;
   rcall   lcd_data
  ret


;*********************************************************************** 
**
; Binärwert in Ascii-Code wandeln
; Eingabe: AH:AL, Rückgabe in  CL, BH:BL, AH:AL = 5 digits (ASCII)
;*********************************************************************** 
**

bin2ascii:
  ldi    CL, -1 + '0'
bcd1:
  inc    CL
    subi   AL, low(10000)
    sbci   AH, high(10000)
    brcc   bcd1
    ldi    BH, 10 + '0'

bcd2:
  dec    BH
    subi   AL, low(-1000)
    sbci   AH, high(-1000)
    brcs   bcd2
    ldi    BL, -1 + '0'

bcd3:
  inc    BL
    subi   AL, low(100)
    sbci   AH, high(100)
    brcc   bcd3
    ldi    AH, 10 + '0'

bcd4:
  dec    AH
    subi   AL, -10
    brcs   bcd4
    subi   AL, -'0'

  ret



;*********************************************************************** 
****
;*
;* LCD-Routinen  4-Bit
;*
;* PIN_LCD_Enable  = PB5
;* PIN_LCD_RS    = PB6
;* PIN_LCD_D4    = PA4
;* PIN_LCD_D5    = PA5
;* PIN_LCD_D6     = PA6
;* PIN_LCD_D7    = PA7
;*
;*********************************************************************** 
*****


;sendet Datenbyte an das LCD
lcd_data:

  sbi    PortB, PIN_LCD_RS
  push  AL                       ;"Sicherungskopie" 2.Nibble
    andi    AL, 0b11110000             ; unteres Nibble auf Null setzen
  out    PORTA,AL
  rcall   lcd_enable                 ; Enable-Routine aufrufen
    pop     AL                         ; 2. Nibble
    swap    AL                    ; untere 4 bits (Nibble) nach oben
    andi    AL, 0b11110000             ; untere Hälfte auf Null setzen
  out    PORTA,AL
  rcall   lcd_enable                 ; Enable-Routine aufrufen
    rcall   wait50us                  ; warte
    ret                                ; zurück zum Hauptprogramm


 ;sendet einen Befehl an das LCD
lcd_command:                            ; wie lcd_data, nur ohne RS zu 
setzen

  cbi    PORTB, PIN_LCD_RS
  push  AL
    andi  AL, 0b11110000
  out    PORTA,AL
  rcall  lcd_enable
    pop    AL
  swap  AL
  andi  AL, 0b11110000
  out    PORTA,AL
  rcall  lcd_enable
    rcall  wait50us
    ret


 ;erzeugt den Enable-Puls
lcd_enable:

   sbi   PORTB, PIN_LCD_Enable      ; Enable high
    nop                              ; 3 Taktzyklen warten
  nop
  nop
  cbi    PORTB, PIN_LCD_Enable       ; Enable wieder low
  ret                              ; und wieder zurück


 ;Initialisierung
lcd_init:
    rcall    wait1s

  ldi      AL, 0b0011000             ;
    out    PORTB, AL                  ;
  rcall  lcd_enable                 ; 1. muss 3mal hintereinander 
gesendet
    rcall  wait5ms            ;    werden zur Initialisierung
    rcall  lcd_enable                 ; 2.
    rcall  wait5ms
    rcall  lcd_enable                 ; und 3!
    rcall  wait5ms

  ldi    AL,  0b00100000        ; 4bit Modus einstellen
  out    PORTB,AL
  rcall  lcd_enable
  rcall  Wait5ms

  ldi      AL, 0b00101000             ; 4bit-Modus, 2 Zeilen
    rcall  lcd_command          ; Befehl senden
  ldi    AL, 0b00001100             ; LCD on
    rcall  lcd_command          ; Befehl senden
  ldi    AL, 0b00000100             ; Entry mode
    rcall  lcd_command
    ret

 ;Sendet den Befehl zur Löschung des Displays
lcd_clear:
    ldi    AL, 0b00000001             ; Display löschen
    rcall  lcd_command
    rcall  Wait5ms
    ret
 ;Setzt Cursor-Position auf Anfang
lcd_home:
  ldi    AL, 0b00000010             ; Cursor an Anfang
     rcall  lcd_command
     rcall  wait5ms
     ret

; Erwartet die Position in AL
lcd_cursor:
  sbr    AL, 0b10000000             ; Bit 7 setzen
  rcall  lcd_command
  rcall  wait5ms
    ret

lcd_print:
  lpm                  ; Laden
  tst    R0              ; ist Zeichen =0
  breq  lcd_pend          ; gehe zu end
  mov    AL,R0            ; sonst Zeichen nach AL
  rcall  lcd_data          ; Ausgabe
  adiw  ZL,1                    ; Zeiger in ZL = ZL + 1(word)
  rjmp  lcd_print
lcd_pend:
   ret


;*********************************************************************** 
**
; Dividiert 16Bit-Zahl durch 8Bit-Zahl
; Eingabe:  AH:AL, Rückgabe in  BH:BL, CL = Divisor
; Hilsregister UL, UH
;*********************************************************************** 
**


div8:

  ldi    CL,10      ; Divisor
  ldi    BL,1      ; zählt von 1 an
  clr    UL        ; Hilfs-
  clr    BH        ; und Ergebisregister löschen

div8a:
  clc            ; löscht Carry
  rol    AL        ; höchstes Bit
  rol    AH        ; ins
  rol    UL        ; Hilfsregister rollen
  brcs  div8b      ; wenn Überlauf vorhanden zu div8b
  cp    UL,CL      ; Ergebnis 1 oder 0?
  brcs  div8c      ; wenn kleiner keine Subtraktion

div8b:
  sub    UL,Cl      ; subtrahiere Divisor
  sec            ; setze Carry
  rjmp  div8d      ; schiebe das Ergebnis

div8c:
  clc            ; löscht Carry

div8d:
  rol    BL        ; rotiere Carry ins Ergebnis
  rol    BH
  brcc  div8a      ; mach weiter, solange Carry = 0

  cpi    UL,5      ; Rest steht in UL, ist UL<5,
  brlo  div8e      ; dann weiter
  inc    BL        ; sonst 1 addieren
  adc    BH, Zero

div8e:
  ret

von Ulrich W. (sandy49)


Angehängte Dateien:

Lesenswert?

...und hier noch das Datenblatt vom LCD Modul

von Ulrich W. (sandy49)


Lesenswert?

Ich bin überwältigt von soooviel Hilfe.
Aber vlt. weiß doch jemand,wie das LCD Modul richtig initialisiert wird 
in dieser Assembler Software.
...oder doch nicht?
Uli

von Joe (Gast)


Lesenswert?

Wirre Zeichen beim LCD deuten auf fehlerhafte Impulse hin.

Die Versorgungsspannung am LCD muss unbedingt mit eigenen Kondensatoren 
geschützt werden.

Stimmt deine Taktfrequenz ?

Hast du deine Hardware und LCD schon mit einem anderen Programm und 
"Hello World" getestet ?

von WernerSch (Gast)


Lesenswert?

"Ich bin überwältigt von soooviel Hilfe."

Ich denke eine gute Hilfestellung deinerseits wäre, den Code ein wenig 
gekürzt zu veröffentlichen und nur auf die LCD Routinen zu reduzieren.
Dann müssten der Leser weniger lesen, auf den ersten Blick hatte ich 
keine Lust mich einzulesen. Tut mir leid.

Grüße

werner

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Ulrich W. schrieb:
> ...und hier noch das Datenblatt vom LCD Modul

Das ist die Anschlussbelegung und kein Datenblatt.

Ulrich W. schrieb:
> Ich bin überwältigt von soooviel Hilfe.

Wenn es das Originalprogramm ist, welches mit einem anderen Display 
funktioniert, wird ein solches Display auch richtig initialisiert.

Möglichkeiten
- Dein Display ist nicht kompatibel,
- Deine Bastelei ist fehlerhaft,
- Du hast etwas am Programm verändert,
- Das Display ist kaputt,
- Das Timing stimmt nicht (falscher Quarz, falsche Fuses)
- Du sammelst Dir Störungen ein (Flachbandkabel zu lang? D0..D3 hängen 
in der Luft?)

Die Initialisierung kann niemand überprüfen, da niemand das Timing 
Deines Displays kennt.

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

Das Umstecken des LCD im laufenden Betrieb ist nicht gesund für das LCD. 
Dass dabei wirre Zeichen kommen ist erklärbar (=> Joe).

Kontrolliere im Original diese Zeilen
> lcd_init:
>   rcall   wait1s
>   ldi     AL, 0b0011000
>   out     PORTB, AL

Ich sehe da 2-3 Probleme. Im Anhang ist ein Minimalprogramm mit 
Änderungen. Es wird wiederholt im 3s Takt nur ein Text ausgegeben. Kommt 
der Text und stimmen die Pausen?

Die Änderungen betreffen die Erweiterung der Konstante 0b0011000 auf 
8-Bit (0b00110000), Runterziehen von RS, und die Ausgabe auf die 
Datenleitungen (PORTA) statt auf E/RS Leitung auf PORTB. Die Änderungen 
orientieren sich am Code in AVR-Tutorial: LCD.

von Ulrich W. (sandy49)


Lesenswert?

Hallo,

es ist mein erstes Projekt mit einem LCD Modul und bin seit 3 Wochen 
damit beschäftigt.
Soft.-und Hardware funktionieren definitiv,aber mit dem richtigen LCD 
Modul.

@Joe
>>Hast du deine Hardware und LCD schon mit einem anderen Programm und
"Hello World" getestet ?

Bis jetzt nicht,aber den Gedanke hatte ich schon,nur noch nichts 
passendes gefunden.Ich werde weiter suchen und testen!

>>Stimmt deine Taktfrequenz ?
Falls Du die vom AVR meinst,die ist 1 Mhz.



@ WernerSch

>>Ich denke eine gute Hilfestellung deinerseits wäre, den Code ein wenig
gekürzt zu veröffentlichen und nur auf die LCD Routinen zu reduzieren.
Dann müssten der Leser weniger lesen, auf den ersten Blick hatte ich
keine Lust mich einzulesen. Tut mir leid.

Das muss Dir nicht Leid tun,sondern ich muss Dir Recht geben!
Ich kann zwar einen µC programmieren,aber mit der Software kenne ich 
mich nicht aus.Weder in Bascom, Assembler noch in C,C++ und was es noch 
alles gibt.
Natürlich hätte ich es kürzen können,aber bloss was? Nur nicht zuviel 
wegmachen dachte ich.Naja,das wird schon noch...


@ Christian H
>>Das ist die Anschlussbelegung und kein Datenblatt.

...auch richtig,aber das einzige was es von diesem Modul gibt.Es ist 
HD44780 kompatibel und habe mir eben von diesem Controller das 
Datenblatt besorgt.Ich hoffe, es hilft weiter.


>>Möglichkeiten
- Dein Display ist nicht kompatibel,
- Deine Bastelei ist fehlerhaft,
- Du hast etwas am Programm verändert,
- Das Display ist kaputt,
- Das Timing stimmt nicht (falscher Quarz, falsche Fuses)
- Du sammelst Dir Störungen ein (Flachbandkabel zu lang? D0..D3 hängen
in der Luft?)

1. doch,ist es.
2. definitiv ist die Hardware ok.
3. natürlich habe ich einige Einstellungen zu Testzwecken verändert,die 
aber keine Besserung brachten.Das Upload ist die Originaldatei und daran 
habe ich nichts verändert.
4. Das Display ist neu,trotzdem habe ich ein anderes 
angeschlossen...immer dasselbe.
5. Es werden keine Fuses eingestellt,es bleibt bei der 
Standardeinstellung.
6. Flachbandkabel ist 12cm lang,dürfte keine Probleme geben.
7. D0..D3 hatte ich mit GND verbunden,kein Erfolg.


@ Stefan B.

Ich werde die Software compilieren und testen.Melde mich dann wieder.

Bedanke mich für eure Hilfe.

von Ulrich W. (sandy49)


Lesenswert?

@ Stefan B.

C:\Download\Lader\Lader(neu)\sla.asm(49): error: Undefined symbol: 
txtHello
C:\Download\Lader\Lader(neu)\sla.asm(50): error: Undefined symbol: 
txtHello
Assembly failed, 2 errors, 8 warnings

Ich weiß (noch)nicht,wie man diesen Fehler korrigieren kann.


Uli

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Sorry da habe ich geschlampt und beim Labelnamen ist das Denglisch mit 
mir durchgegangen.

Relativ weit oben im Quellcode steht:
1
txtHallo:
2
  .db  "Hello world!",0,0

Etwas weiter unten im Quellcode steht
1
start:
2
  ;3s Text ausgeben
3
  rcall lcd_home
4
  ldi   ZL,Low(txtHello*2)
5
  ldi   ZH,High(txtHello*2)

Die Fehlermeldung besagt, dass der Assembler das Symbol txtHallo kennt 
(Umkehrschluss weil keine Fehlermeldung) aber das Symbol txtHello 
nicht...

Wie man das beheben kann, müsstest du selbst rausbekommen, so viel Grips 
hast du! Tipp: Es gibt genau zwei Möglichkeiten!

von Ulrich W. (sandy49)


Lesenswert?

Hi Stefan,

ja, natürlich hab ich es rausbekommen und es funzt perfekt!
In der 1.Zeile steht Hallo!
Demnach ist das Display und die Hardware also ok.

aber:
Ein neustart der Schaltung reicht nicht,(neu anlegen der 
Spannung)sondern  ich habe mal wieder den Stecker vom Display abgezogen 
(verzeih mir) und erst dann zeigte es " Hallo! "an.
Währenddessen blinkt der Cursor (viereckiges Quadrat)und wandert ständig 
von der 1.Zeile bis in die 2.Zeile.

Nachdem wir das bewältigt haben müssten wir doch auch das Original 
Programm zum Laufen bekommen,oder?
Danke Dir,Du machst mir wieder Hoffnung!
Währenddessen bin ich aber nicht untätig und versuche die 
Assemblersprache besser zu verstehen.


Gruß Uli

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Tja, dann schau dir die eigentliche Änderung in ulrich_lcd.asm mal 
genauer an. Es geht um die ersten paar Zeilen in der Routine ab dem 
Label lcd_init:

Ich denke in deiner Fassung wird kein richtiger Software-Reset des LCDs 
gemacht, weil die lcd_init wohl fehlerhaft ist. Der Fehler in den ersten 
Zeilen wirkt sich dann auf die Umschaltung in den 4-Bit Ansteuermodus 
aus. Deshalb scheitern die folgenden Ausgaben.

Wenn du das LCD brutal von der Versorgung trennst und wieder 
anstöpselst, macht das LCD einen Hardware-Reset beim Power-Up 
(Spannungsversorgung wieder da). Das LCD ist dann im Werksmodus und es 
sieht so aus, als ob der zufällig etwas besser funktioniert als der 
fehlerhaft initialisierte 4-Bit-Modus (teilweise richtige Ausgabe).

Dein Ziel muss allerdings sein, einen korrekten Software-Reset 
hinzubekommen und das LCD korrekt in den 4-Bit-Ansteuermodus zu bringen. 
Ich würde im nächsten Schritt aus ulrich_lcd.asm die geänderten Zeilen 
beim lcd-init: Label mal in das Ladeprogramm übertragen.

EDIT: Ich gehe gleich in die Falle also mehr ggf. morgen!

EDIT2: Darüber muss ich noch brüten:

> Ein neustart der Schaltung reicht nicht,(neu anlegen der
> Spannung)sondern  ich habe mal wieder den Stecker vom Display abgezogen
> (verzeih mir) und erst dann zeigte es " Hallo! "an.

Es scheint so, dass auch ulrich_lcd.asm das LCD noch nicht richtig 
resettet. Ich schaue mal, was ich an Hardware hier habe, um die 
Situation nachzustellen.

von Ulrich W. (sandy49)


Lesenswert?

Hallo Stefan,

gestern Abend noch ein kleines Erfolgserlebnis.Ich habe die 
ulrich_lcd.asm insoweit verändert,dass in der 1.Zeile "Hallo !"
und in der 2.Zeile "Guten Tag" angezeigt wurde.Hat mich gefreut,denn von 
wirren Zeichen war nichts mehr zu sehen.

Heute habe ich das Originalprogramm etwas verändert und es wird wie 
vorgesehen in der 1.Zeile "Akku 12V" angezeigt.Nach Tastendruck erfolgt 
Umschaltung auf "Akku 24V".

Das Programm bleibt allerdings an der Stelle stehen.Nach Eingabe des 
Akku Typs sollte dahinter die Ampere (beim Start auf 2A eingestellt) 
angezeigt und auch verändert werden können.

Direkt nach dem ich den µC neu programmiert habe,läuft das Programm 
normal an.Ist die Spannung einmal unterbrochen und wird neu 
angelegt,bleibt die Anzeige leer.
Deine Vermutung mit dem Reset könnte zutreffen.Wie kann man das in der 
Software einstellen?

Uli

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Uli, ich habe zufällig das gleiche LCD in der Bastelkiste gefunden und 
baue die Hardware (nur µC/Attiny2313 und LCD) jetzt am Wochenende auf. 
Mal sehen, ob ich das von dir beobachtete Verhalten nachstellen und ggf. 
beheben kann.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Beim Debuggen aufgefallen:
1
lcd_init:
2
; ### Alt ###
3
;  rcall  wait1s
4
;  ldi    AL, 0b0011000
5
;  out    PORTB, AL
6
7
; ### NEU ###
8
  cbi    PORTB, PIN_LCD_RS    ; Sicher ist sicher
9
  rcall  wait1s
10
  ldi    AL, 0b00110000
11
  out    PORTA, AL            ; Datenleitungen des LCD!
12
13
; Weiter im Originalcode
14
  rcall  lcd_enable           ; 1. muss 3mal hintereinander gesendet
15
  rcall  wait5ms              ;    werden zur Initialisierung
16
  rcall  lcd_enable           ; 2.
17
  rcall  wait5ms
18
  rcall  lcd_enable           ; und 3!
19
  rcall  wait5ms
20
  ldi    AL,  0b00100000      ; 4bit Modus einstellen
21
  out    PORTA,AL             ; ### Falsch PORTB richtig PORTA ####
22
  rcall  lcd_enable
23
  rcall  Wait5ms
24
  ldi    AL, 0b00101000       ; 4bit-Modus, 2 Zeilen
25
  rcall  lcd_command          ; Befehl senden
26
  ldi    AL, 0b00001100       ; LCD on
27
  rcall  lcd_command          ; Befehl senden
28
  ldi    AL, 0b00000100       ; Entry mode
29
  rcall  lcd_command
30
  ret

von Stefan B. (stefan) Benutzerseite


Lesenswert?

So jetzt auch auf dem Steckbrett aufgebaut und getestet. Es bestätigte 
sich das Problem aus dem Simulator/Debugger. Mit der Änderung oben, also 
statt:
1
  ldi    AL,  0b00100000      ; 4bit Modus einstellen
2
  out    PORTB,AL
3
  rcall  lcd_enable

das:
1
  ldi    AL,  0b00100000      ; 4bit Modus einstellen
2
  out    PORTA,AL             ; ### Falsch PORTB richtig PORTA ####
3
  rcall  lcd_enable

funktioniert das LCD auch nach Power-On und Reset des AVR - ohne 
Umstöpseln :-)

von Ulrich W. (sandy49)


Lesenswert?

Beim anlegen der Spannung ist die Anzeige nicht mehr "Akku 12V" , 
sondern es wird nur noch " 00,21VV: " ausgegeben.

Das Reset ist also erfolgt und scheinbar behoben.
Die Anzeige von "Akku " bzw. "Ampere" geht nur noch,wenn ich "rcall 
wait1s" eingebe.Aber kein Umschalten auf 24V möglich.
Ich arbeite derzeit an dem Original,bekomme es aber nicht hin.
Vielen Dank für deine Mühe.

Uli

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich verstehe deine Antwort nicht bzw. kann deine Aktionen aus der Ferne 
nicht nachvollziehen.

1/ Funktioniert das Minimalprogramm (plus der Änderung aus 
Beitrag "Re: Brauche eure Hilfe zum Programmieren") auch bei dir 
fehlerfrei?

Fehlerfrei würde bedeuten:

Die Anzeige
1
+--------------------+
2
|Hello world!        |
3
|                    |
4
+--------------------+
und
1
+--------------------+
2
|                    |
3
|                    |
4
+--------------------+
wechseln sich alle 3s ab. Tipp: 3s wie Pulsschlag abpassen. Anzahl der 
Wechsel in z.B. 1 Min. zählen.

2/ Mit welchem Quellcode und welchem Experiment kam die Anzeige "Akku 
12V"?

3/ Welche Spannung hast du dann wo angelegt?

4/ Änderte sich die Anzeige dann von "Akku 12V" auf " 00,21VV: " oder 
kam nur " 00,21VV: "? Wenn ersteres - wieviel Zeit ist da ungefähr 
vergangen? Hattest du eine Eingabe an den Tasten gemacht? Die Anzeige 
bleibt jetzt auf " 00,21VV: " stehen?

5/ Wo machst genau du die Änderung mit rcall wait1s?

Ich habe inzwischen auch den Thread gefunden, in dem der Bleilader 
beschrieben ist: Beitrag "Bleiakku-Lader 12/24V"

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bin jetzt am Debuggen der Firmware 1.41

Assembler meldet
> Firmware141.asm(508) : error : Illegal argument type or count
der Zeile
> adiw  ZL:ZH,8 ; "Ende!" ausgeben

und er hat Recht. Ändere
1
vct:
2
  ...
3
  ldi   ZL,Low(txtSonstiges*2)  ; Leerstring zur Überdeckung
4
  ldi   ZH,High(txtSonstiges*2) ; der bisherigen Stromanzeige
5
  adiw  ZL:ZH,8                 ; "Ende!" ausgeben

in
1
vct:
2
  ...
3
  ldi   ZL,Low(txtSonstiges*2)  ; Leerstring zur Überdeckung
4
  ldi   ZH,High(txtSonstiges*2) ; der bisherigen Stromanzeige
5
  adiw  ZH:ZL,8                 ; "Ende!" ausgeben

von Ulrich W. (sandy49)


Lesenswert?

Fehlerfrei bedeutet,dass das Minimalprogramm (plus der Änderung) 
"ulrich_lcd.asm" ohne Fehler abläuft.

>>2/ Mit welchem Quellcode und welchem Experiment kam die Anzeige "Akku
12V"?<<

Mit dem unendlich langen Quellcode am Anfang des Threads
(Firmware 1.41).
Ich wäre überglücklich,wenn dieser Quellcode ebenso Fehlerfrei laufen 
würde.

>>3/ Welche Spannung hast du dann wo angelegt?<<

damit meinte ich die Betriebsspannung von 5V auf der Platine.


>>4/ Änderte sich die Anzeige dann von "Akku 12V" auf " 00,21VV: " oder
kam nur " 00,21VV: "? Wenn ersteres - wieviel Zeit ist da ungefähr
vergangen? Hattest du eine Eingabe an den Tasten gemacht? Die Anzeige
bleibt jetzt auf " 00,21VV: " stehen?<<

Anfangs kam nur die Anzeige auf dem Display " 00,21VV " .An gleicher 
Stelle sollte stattdessen " Akku 12V" stehen.
Bis ich den anzuzeigenden Text " Akku 12V" in der Firmware 1.41 so 
abgeändert habe:

start:
  ;3s Text ausgeben
  rcall lcd_home
  ldi   ZL,Low  (txtAkku*2)
  ldi   ZH,High (txtAkku*2)
  rcall lcd_print
  rcall wait1s
  rcall wait1s
  rcall wait1s

Der Text "Akku" wurde 3 sec. angezeigt und danach nur noch " 00,21VV: "
Die Anzeige 00,21VV soll die gemessene Akkuspannung in der 2.Zeile des 
Display's darstellen.

>>Assembler meldet
> Firmware141.asm(508) : error : Illegal argument....<<

Im AVR Studio4 hatte ich keine Probleme beim kompilieren zu einer .hex 
Datei.
Ich werde auch die Änderung "adiw  ZH:ZL,8"  testen.

Brauchst Du evtl. die hex?

von Ulrich W. (sandy49)


Lesenswert?

Hallo Stefan,

die Firmware 1.41 habe ich nun komplett auf das o.a. LCD Modul 
umgeschrieben und es funktioniert ohne Fehler.

An der Stelle bedanke ich mich herzlich für deine Hilfe.

Uli

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Super, case closed! Wenn du noch einen Minibug erlegen willst, schau dir 
noch diese Stelle an:
1
wait1ms:
2
  push UL
3
  ldi  UL,9 ; <=== ?
4
n4:  rcall wait100us
5
  dec  UL
6
  brne n4
7
  pop  UL
8
  ret

Dort sollte eine 10 statt einer 9 stehen: 1ms = 10*100µs

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.