- Akku Tests und Balkonkraftwerk Speicher         
Ergebnis 1 bis 10 von 10

Thema: Timer1 Uhr

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.05.2006
    Alter
    35
    Beiträge
    122

    Timer1 Uhr

    Anzeige

    Praxistest und DIY Projekte
    Hallo Leute

    Ich übe jetzt schon seit mehreren Wochen an meinem "Projekt" herum, doch es will einfach nicht funktionieren.
    Ich möchte mit einem PIC16F88 (20Mhz) mit dem Timer 1 eine Uhr konstruieren, die dann die Zeit auf einem LCD ausgibt. Die Genauigkeit der Zeit sowie andere "Erweiterungen" spielt hier noch eine sehr untergeordnete Rolle (kein Auto-Reload von TMR1L/TMR1H...), da ich zuerst einmal das ganze zum Laufen bringen will. Das Programm gibt mir jedoch erst die Grundstellung für die Uhr (00:00:00) und irgendwelche ungewollte, ungeordnete Zeichen auf dem LCD aus => auf gut Deutsch: Chaos. Kann mir jemand hier weiterhelfen und sagen, was ich im nachfolgenden Code falsch gemacht habe? Der Vollständigkeit halber habe ich den ganzen Quellcode incl. Lcd-Ansteuerung etc aufgelistet.

    Wäre sehr dankbar.

    Code:
    	list 	p=16F88
    #include 	<p16f88.inc>
    
    
    	__CONFIG    _CONFIG1, _CP_OFF & _LVP_OFF & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _HS_OSC
    
     
    ; variables
    LcdDaten	Equ	0x22
    LcdStatus	Equ	0x23
    loops		Equ	0x24
    loops2		Equ	0x25
    stde		Equ	0x27
    stdz		Equ 0x2C
    mine		Equ 0x2D
    minz		Equ 0x30
    seke		Equ	0x31	; einerstelle sekunden
    sekz		Equ	0x32	;zehnerstelle sekunden
    w_copy		Equ	0x33
    s_copy		Equ 0x34
    copyw		Equ	0x20
    copys		Equ 0x21
    
    ; constants
    PORTC		Equ	PORTB
    PORTD		Equ	PORTB
    
    ;pins LCD
    #define	LcdE		PORTB, 0
    #define	LcdRw		PORTB, 3
    #define	LcdRs		PORTB, 2
    
    
    	
    	
    	org		0x00
    	goto Main
    
    	org 	0x04
    
    ISR						;interupt service routine
    	movwf	copyw
    	swapf	STATUS, W
    	bcf		STATUS, RP0
    	movwf	copys
    
    	incf	seke, f			;seke +1
    	movfw	seke		
    	sublw	.10				;seke -10 ;result negativ => z=0
    	btfss	STATUS, Z		;test z, if z=1 => skip next order
    	call 	printseke	
    	call	clearseke
    	incf	sekz, f
    	movf	sekz, w
    	sublw	.6
    	btfss	STATUS, Z
    	call	printsekz
    	call	clearsekz
    	incf	mine, f
    	movf	mine, w
    	sublw	.10
    	btfss	STATUS, Z
    	call	printmine
    	call	clearmine
    	incf	minz, f
    	movf	minz, w
    	sublw	.6
    	btfss	STATUS, Z
    	call	printminz
    	call	clearminz
    	incf	stde, f
    	movf	stde, w
    	sublw	.10
    	btfss	STATUS, Z
    	call	printstde
    	call	clearstde
    	incf	stdz, f
    	movf	stdz, w
    	sublw	.10
    	btfss	STATUS, Z
    	call	printstdz
    	call	clearstdz
    	goto	clearstdz
    
    	
    ISRend						;interupt end routine
    	bcf		STATUS, RP0
    	bcf		PIR1, TMR1IF	;clear interupt flag
    	swapf	copys, w
    	movwf	STATUS
    	swapf	copyw, f
    	swapf	copyw, w
    	retfie
    	
    
    
    
    Init
    
    	bcf		INTCON, GIE
    	bcf		INTCON, PEIE
    	bsf		STATUS, RP0
    	movlw	B'00000000'
    	movwf	TRISB
    	movlw	B'00000000'
    	movwf	ANSEL
    	bcf		STATUS, RP0
    	return
    
    InitTimer
    	bcf		STATUS, RP0
    	movlw	B'00110101'	;prescaler:  1:8; internal clock; not synchronize; Timer1 enabled
    	movwf	T1CON
    	bsf		STATUS, RP0
    	bsf		PIE1, TMR1IE	
    	bcf		STATUS, RP0
    	bsf		INTCON, GIE	
    	bsf		INTCON, PEIE
    	return
    
    	Main
    	call Init
    	call InitLCD
    	call InitTimer
    
    WAIT
    wai		movlw	.249
    		movwf	loops2
    wai2	nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    	nop
    		decfsz	loops2, F
    		goto	wai2
    		
    		decfsz	loops, F
    		goto 	wai
    		return
    
    InitLCD
    	movlw	D'25'		
    	movwf	loops	
    	call	WAIT		
    
    	movlw	B'00110000'	
    	movwf	PORTB
    	bsf		LcdE
    	nop	
    	bcf		LcdE
    	
    	movlw	D'10'
    	movwf	loops
    	call	WAIT
    	
    	movlw	B'00110000'
    	call	Control8Bit
    	movlw	B'00110000'
    	call 	Control8Bit
    	movlw	B'00100000'
    	call 	Control8Bit
    
    	movlw	B'00000001'
    	call	OutLcdControl	
    	movlw	B'00101000'
    	call	OutLcdControl	
    	movlw	B'00001000'
    	call	OutLcdControl
    	movlw	B'00000110'
    	call	OutLcdControl
    	movlw	B'00000011'
    	call	OutLcdControl
    	movlw	B'00001111'
    	call	OutLcdControl
    	movlw	B'11000100'
    	call	OutLcdControl
    	movlw	'0'
    	call	OutLcdDaten
    	movlw	'0'
    	call	OutLcdDaten
    	movlw	':'
    	call	OutLcdDaten
    	movlw	'0'
    	call	OutLcdDaten
    	movlw	'0'
    	call 	OutLcdDaten
    	movlw	':'
    	call	OutLcdDaten	
    	movlw	'0'
    	call	OutLcdDaten
    	movlw	'0'
    	call 	OutLcdDaten
    
    	return
    
    Control8Bit
    	movwf	PORTB
    	bsf		LcdE
    	nop
    	bcf		LcdE
    	movlw	D'10'
    	movwf	loops
    	call 	WAIT
    	return
    
    LcdBusy
        bsf     STATUS, RP0
    	movlw	B'11110000'
    	iorwf   TRISB, f 
            bcf     STATUS, RP0
    BusyLoop		
    	bcf		LcdRs
    	bsf		LcdRw
    	bsf		LcdE
    	nop
    	movf	PORTD, w
    	movwf	LcdStatus
    	bcf		LcdE
    	nop
    	bsf		LcdE
    	nop
    	bcf		LcdE
    	btfsc	LcdStatus, 7
    	goto 	BusyLoop
    	bcf		LcdRw
        bsf     STATUS, RP0	
    	movlw	B'00001111'
    	andwf   TRISB, f    
        bcf     STATUS, RP0
    	return	
    
    OutLcdControl
    	movwf	LcdDaten
    	call	LcdBusy
    	movf	LcdDaten, w
    	andlw	H'F0'
    	movwf	PORTD	
    	bsf		LcdE
    	nop
    	bcf		LcdE	
    	swapf	LcdDaten, w
    	andlw	H'F0'
    	movwf	PORTD	
    	bsf		LcdE
    	nop
    	bcf		LcdE	
    	return
    
    OutLcdDaten
    	movwf	LcdDaten
    	call	LcdBusy
    	movf	LcdDaten, w
    	andlw	H'F0'
    	movwf	PORTD	
    	bsf		LcdRs	
    	bsf		LcdE	
    	nop
    	bcf		LcdE	
    	swapf	LcdDaten, w
    	andlw	H'F0'
    	movwf	PORTD		
    	bsf		LcdRs	
    	bsf		LcdE
    	nop
    	bcf		LcdE	
    	bcf		LcdRs		
    	return
    
    clearseke	;ausgabe von seke, mit reset der stelle auf 0
    	movlw	b'11001011'
    	call 	OutLcdControl
    	clrf	seke
    	movfw	seke
    	iorlw	'0'
    	call	OutLcdDaten
    	goto 	ISRend
    	
    clearsekz
    	movlw	b'11001010'
    	call 	OutLcdControl
    	clrf	sekz
    	movfw	sekz
    	iorlw	'0'
    	call	OutLcdDaten
    	goto	ISRend
    
    clearmine
    	movlw	b'11001000'
    	call	OutLcdControl
    	clrf	mine
    	movfw	mine
    	iorlw	'0'
    	call 	OutLcdDaten
    	goto	ISRend
    	
    clearminz
    	movlw	b'11000111'
    	call	OutLcdControl
    	clrf	minz
    	movfw	minz
    	iorlw	'0'
    	call 	OutLcdDaten
    	goto	ISRend
    
    clearstde
    	movlw	b'11000101'
    	call	OutLcdControl
    	clrf	stde
    	movfw	stde
    	iorlw	'0'
    	call	OutLcdDaten
    	goto	ISRend
    	
    clearstdz
    	movlw	b'11000100'
    	call	OutLcdControl
    	clrf	stdz
    	movfw	stdz
    	iorlw	'0'
    	call	OutLcdDaten
    	goto	ISRend
    	
    	
    	
    printseke	; ausgabe von seke & beenden der ISR
    	movlw	b'11001011'
    	call	OutLcdControl
    	movfw	seke
    	iorlw	'0'
    	call	OutLcdDaten
    	goto	ISRend
    	
    printsekz
    	movlw	b'11001010'
    	call	OutLcdControl
    	movfw	sekz
    	iorlw	'0'
    	call	OutLcdDaten
    	goto	ISRend
    	
    printmine
    	movlw	b'11001000'
    	call	OutLcdControl
    	movfw	mine
    	iorlw	'0'
    	call	OutLcdDaten
    	goto	ISRend
    	
    printminz
    	movlw	b'11000111'
    	call	OutLcdControl
    	movfw	minz
    	iorlw	'0'
    	call	OutLcdDaten
    	goto	ISRend
    
    printstde
    	movlw	b'11000101'
    	call	OutLcdControl
    	movfw	stde
    	iorlw	'0'
    	call	OutLcdDaten
    	goto	ISRend
    	
    printstdz
    	movlw	b'11000100'
    	call	OutLcdControl
    	movfw	stdz
    	iorlw	'0'
    	call	OutLcdDaten
    	goto	ISRend
    
    	end
    (Sorry für die lückenhaften Kommentare im Code.)

    Auch einen Link zu einem funktionnierenden Programm, das Timer1 verwendet, wäre sehr hilfreich, damit ich vergleichen könnte und so ev. den Fehler finden könnte. (bei google habe ich nichts gefunden)

    Greez orph

  2. #2
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.10.2004
    Ort
    ferd. Waldmüllerg. 7/2
    Alter
    39
    Beiträge
    456
    Hum, grundsächlich wär mein Ansatz für eine Lösung für diese Aufgabe ein wenig anders ausgefallen, aber dies ist natürlich auch eine Möglichkeit.

    Was wir als erstes auffällt, du hast call-Befehle in deinem Programm, die aber mit einem goto enden. Das ist seeehr ungesund, weil ein call immer ein Eintrag in der Stack zu folge hat und erst das "return" in der Unterfunktion lässt den Stack-Pointer eine Ebene höher springen und bringt den PCL zurück an den Punkt, von wo der call-Befehl aufgerufen wurde. Existiert dieser aber nicht, so wird schafft der nächste call einen weiteren Sprung tiefer im Stack und der nächste noch einen, etc. und irgendwann ist dein Call-Stack voll. Abhängig vom µC führt das wiederrum zu einem reset, oder einfach dazu, dass dein Programm plözlich nicht mehr in die Hauptfunktion "zurückfindet".
    Also nie ein call ohne ein return benutzen. Wenn du ein goto am Ende der Funktion hast, dann spring auch mit einem goto hinein . Das erspart Frustrationen bei der Fehlersuche (weil es ein Laufzeitfehler ist, schreibt der Compiler auch nicht).

    call clearstdz
    Die Zeile ist unnütz, da du ja danach auch ein aufruf auf die gleiche Funktion hast

    call LcdBusy
    Das ist der Befehl, der wahrscheinlich für deine Misere verantwortlich ist. Den da ist eine Schleife drin und du kannst nicht sagen, wie lang sie durchlaufen wird. Deshalb könnte es theoretisch sein, dass der Timer1 überläuft, noch bevor der Interrupt vollends beendet wurde. Auch wenn es vom PIC her nicht möglich ist ein Interrupt in einem Interrput auszulösen schmeißt es jeden Versuch von Genauigkeit hin.

    Also das inclusive or mit '0' (also 0x30) ist natürlich auch eine Möglichkeit, wobei ich persönlich eher einfach 0x30 oder '0' zu dem Arbeitsregister hinzuaddiert hätte.
    MfG
    Mobius

    P.S.: Ich seh grad, dass du ja in deiner Hauptfunktion nichts zu tun hast ^_^. Es schadet dem armen Interrupt sicher nicht, wenn du die Ausgabe der Zahlen in diesem ausführen würdest, weil ein Interrupt ist eiegntlich dafür da, dass es schnell (betont) eine kleine Aufgabe ausführt.

    Code:
      Hauptprogramm            Interrupt
    -------------------      ------------
    
    Inintialisierung           Timer 1
          |                       |
          |                       |
          V                       V
    Uhrzeit auslesen<-+    Sekunde berechnen
          |           |           |
          |           |           |
          V           |           V
    LCD auffrischen   |     Minute berechnen
          |           |           |
          |           |           |
          +-----------+           V
                            Stunde berechnen
                                  |
                                  |
                                  |
                                  V
                            Daten Abspeichern

  3. #3
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.12.2005
    Ort
    Euskirchen-Großbüllesheim
    Alter
    74
    Beiträge
    2.063
    Hallo orph,
    in all meinen Programmen ist ein Timer-Interrupt, der jede Millisekunde die Interrupt-Service-Routine aufruft. Aus diesem 1ms-Int generiere ich 10ms, 100ms, 1Sek und was ich sonst noch so benötige. Damit erhalte ich jede Menge Software-Timer.
    Aus dem 1Sek-Zähler noch Minuten, Stunden, Tage, Monate .... zu generieren, dürfte kein Problem sein.
    Unter http://www.domnick-elektronik.de/picasm.htm findest Du Beispiele in Assembler, auch für die Uhr. Welchen Timer Du für den 1ms-Int verwendest, ist Deine Entscheidung.
    Wenn 1 Sekunde abgelaufen ist, setze ich ein Bit / Flag, daß der Haupschleife signalisiert: bitte die Anzeige aktualisieren. Das Hauptprogramm kann dann in aller Ruhe das Display updaten, ohne daß auch nur eine Millisekunde verloren geht.
    MfG Karl-Heinz
    HobbyElektronik hier klicken ....

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.05.2006
    Alter
    35
    Beiträge
    122
    hallo

    wieder zurück.
    Ich habe mein Prog nun so umfunktionniert, dass bei jedem Interrupt-Durchlauf das Bit UPDLCD gesetzt wird. Im Hauptprogramm wird das Bit getestet und wenn es gesetzt ist, wird das Lcd erneuert.

    Doch diese Sche.... läuft noch immer nicht. Ich bekomme nur ein leeres Display. Ich werde hier nochmals den Code abdrucken, vielleicht erkennt ja jemand, wo der Hacken ist. (Das Prob mit den returns und co. sollte auch behoben sein.)

    greez,

    Code:
    ;------------------------------------------------------------------------------
    ; LCD-Uhr
    ;										
    ;	Pic 16F88, 20Mhz, LCD an PORTB				
    ;------------------------------------------------------------------------------
    
    	list 	p=16F88
    #include 	<p16f88.inc>
    
    
    	__CONFIG    _CONFIG1, _CP_OFF & _LVP_OFF & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _HS_OSC
    
     
    ; variables
    LcdDaten	Equ	0x22
    LcdStatus	Equ	0x23
    loops		Equ	0x24
    loops2		Equ	0x25
    stde		Equ	0x27
    stdz		Equ 0x2C
    mine		Equ 0x2D
    minz		Equ 0x30
    seke		Equ	0x31	; einerstelle sekunden
    sekz		Equ	0x32	;zehnerstelle sekunden
    w_copy		Equ	0x33
    s_copy		Equ 0x34
    copyw		Equ	0x20
    copys		Equ 0x21
    Flags		Equ	0x40
    
    ; constants
    PORTC		Equ	PORTB
    PORTD		Equ	PORTB
    
    ;pins LCD
    #define	LcdE		PORTB, 0
    #define	LcdRw		PORTB, 3
    #define	LcdRs		PORTB, 2
    #define UPDLCD		Flags, 0
    
    
    	
    	
    	org		0x00
    	goto Main
    
    	org 	0x04
    
    ISR						;interupt service routine
    	movwf	copyw
    	swapf	STATUS, W
    	bcf		STATUS, RP0
    	movwf	copys
    
    	incf	seke, f			;seke +1
    	movfw	seke		
    	sublw	.10				;seke -10 ;result negativ => z=0
    	btfss	STATUS, Z		;test z, if z=1 => skip next order
    	goto 	ISRend	
    	clrf	seke
    	incf	sekz, f
    	movf	sekz, w
    	sublw	.6
    	btfss	STATUS, Z
    	goto	ISRend
    	clrf	sekz
    	incf	mine, f
    	movf	mine, w
    	sublw	.10
    	btfss	STATUS, Z
    	goto	ISRend
    	clrf	mine
    	incf	minz, f
    	movf	minz, w
    	sublw	.6
    	btfss	STATUS, Z
    	goto	ISRend
    	clrf	minz
    	incf	stde, f
    	movf	stde, w
    	sublw	.10
    	btfss	STATUS, Z
    	goto	ISRend
    	clrf	stde
    	incf	stdz, f
    	movf	stdz, w
    	sublw	.10
    	btfss	STATUS, Z
    	goto	ISRend
    	clrf	stdz
    	goto	ISRend
    
    	
    ISRend						;interupt end routine
    	bcf		STATUS, RP0
    	bcf		PIR1, TMR1IF	;clear interupt flag
    	swapf	copys, w
    	movwf	STATUS
    	swapf	copyw, f
    	swapf	copyw, w
    	bsf		UPDLCD
    	retfie
    
    Init
    
    	bcf		INTCON, GIE
    	bcf		INTCON, PEIE
    	bsf		STATUS, RP0
    	movlw	B'00000000'
    	movwf	TRISB
    	movlw	B'00000000'
    	movwf	ANSEL
    	bcf		STATUS, RP0
    	return
    
    InitTimer
    	bcf		STATUS, RP0
    	movlw	B'00110101'	;prescaler:  1:8; internal clock; no synchronize; Timer1 enabled
    	movwf	T1CON
    	bsf		STATUS, RP0
    	bsf		PIE1, TMR1IE	
    	bcf		STATUS, RP0
    	bsf		INTCON, GIE	
    	bsf		INTCON, PEIE
    	return
    
    	Main
    	btfsc	UPDLCD
    	goto	WriteLcd
    	call	Init
    	call	InitLCD
    	call	InitTimer
    	sleep
    	
    WriteLcd
    	bcf		UPDLCD
    	call	printseke
    	call	printsekz
    	call	printmine
    	call	printminz
    	call	printstde
    	call	printstdz
    	sleep
    
    WAIT
    wai		movlw	.249
    		movwf	loops2
    wai2	nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    	nop
    		decfsz	loops2, F
    		goto	wai2
    		
    		decfsz	loops, F
    		goto 	wai
    		return
    
    InitLCD
    	movlw	D'15'		
    	movwf	loops	
    	call	WAIT		
    
    	movlw	B'00110000'	
    	movwf	PORTB
    	bsf		LcdE
    	nop	
    	bcf		LcdE
    	
    	movlw	D'5'
    	movwf	loops
    	call	WAIT
    	
    	movlw	B'00110000'
    	call	Control8Bit
    	movlw	B'00110000'
    	call 	Control8Bit
    	movlw	B'00100000'
    	call 	Control8Bit
    
    	movlw	B'00000001'
    	call	OutLcdControl	
    	movlw	B'00101000'
    	call	OutLcdControl	
    	movlw	B'00001000'
    	call	OutLcdControl
    	movlw	B'00000110'
    	call	OutLcdControl
    	movlw	B'00000011'
    	call	OutLcdControl
    	movlw	B'00001111'
    	call	OutLcdControl
    	movlw	B'11000100'
    	call	OutLcdControl
    	movlw	'0'
    	call	OutLcdDaten
    	movlw	'0'
    	call	OutLcdDaten
    	movlw	':'
    	call	OutLcdDaten
    	movlw	'0'
    	call	OutLcdDaten
    	movlw	'0'
    	call 	OutLcdDaten
    	movlw	':'
    	call	OutLcdDaten	
    	movlw	'0'
    	call	OutLcdDaten
    	movlw	'0'
    	call 	OutLcdDaten
    	return
    
    Control8Bit
    	movwf	PORTB
    	bsf		LcdE
    	nop
    	bcf		LcdE
    	movlw	D'10'
    	movwf	loops
    	call 	WAIT
    	return
    
    LcdBusy
        bsf     STATUS, RP0
    	movlw	B'11110000'
    	iorwf   TRISB, f 
        bcf     STATUS, RP0
    BusyLoop		
    	bcf		LcdRs
    	bsf		LcdRw
    	bsf		LcdE
    	nop
    	movf	PORTD, w
    	movwf	LcdStatus
    	bcf		LcdE
    	nop
    	bsf		LcdE
    	nop
    	bcf		LcdE
    	btfsc	LcdStatus, 7
    	goto 	BusyLoop
    	bcf		LcdRw
        bsf     STATUS, RP0	
    	movlw	B'00001111'
    	andwf   TRISB, f    
        bcf     STATUS, RP0
    	return	
    
    OutLcdControl
    	movwf	LcdDaten
    	;call	LcdBusy
    	movf	LcdDaten, w
    	andlw	H'F0'
    	movwf	PORTD	
    	bsf		LcdE
    	nop
    	bcf		LcdE	
    	swapf	LcdDaten, w
    	andlw	H'F0'
    	movwf	PORTD	
    	bsf		LcdE
    	nop
    	bcf		LcdE	
    	return
    
    OutLcdDaten
    	movwf	LcdDaten
    	;call	LcdBusy
    	movf	LcdDaten, w
    	andlw	H'F0'
    	movwf	PORTD	
    	bsf		LcdRs	
    	bsf		LcdE	
    	nop
    	bcf		LcdE	
    	swapf	LcdDaten, w
    	andlw	H'F0'
    	movwf	PORTD		
    	bsf		LcdRs	
    	bsf		LcdE
    	nop
    	bcf		LcdE	
    	bcf		LcdRs		
    	return
    	
    printseke	; ausgabe von seke
    	movlw	b'11001011'
    	call	OutLcdControl
    	movfw	seke
    	iorlw	'0'
    	call	OutLcdDaten
    	return
    	
    printsekz
    	movlw	b'11001010'
    	call	OutLcdControl
    	movfw	sekz
    	iorlw	'0'
    	call	OutLcdDaten
    	return
    	
    printmine
    	movlw	b'11001000'
    	call	OutLcdControl
    	movfw	mine
    	iorlw	'0'
    	call	OutLcdDaten
    	return
    	
    printminz
    	movlw	b'11000111'
    	call	OutLcdControl
    	movfw	minz
    	iorlw	'0'
    	call	OutLcdDaten
    	return
    
    printstde
    	movlw	b'11000101'
    	call	OutLcdControl
    	movfw	stde
    	iorlw	'0'
    	call	OutLcdDaten
    	return
    	
    printstdz
    	movlw	b'11000100'
    	call	OutLcdControl
    	movfw	stdz
    	iorlw	'0'
    	call	OutLcdDaten
    	return
    	
    	end

  5. #5
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.10.2004
    Ort
    ferd. Waldmüllerg. 7/2
    Alter
    39
    Beiträge
    456
    Code:
       Main
       btfsc   UPDLCD
       goto   WriteLcd
       call   Init
       call   InitLCD
       call   InitTimer
       sleep <-----
    Hier ist ein Fehler, den ich gefunden habe. Bzw. nach diesem Befehl . Das Sleep-Commando versetzt den µC in den "Stand-By". Bei einem PIC bedeutet das nichts anderes, als das das Crystal abgeschalten wird und der µC bis zu einem externen-Interrupt in diesem Modus verweilt. Im Datenblatt kann man nachsehen, welches der Interrupts den PIC aus dem sleep-Mode holen können. Das wären bei einem 16F:
    -) PortB-Interrupts
    -) Watchdog-Overflow (wobei das eigentlich kein Interrupt auslöst)
    -) Timer1, wenn es durch einen externen Clock gespeist wird
    -) Flanke an dem INT-Pin (meist RB0)
    Also ist es nicht verwunderlich, dass der PIC nichts macht, du schickst ihn schlafen und er wird nicht aufwachen .

    Ansonsten, beim rückkehr aus dem Sleep wird ein Befehl übersprungen (bzw. die ISR-Routine gestartet) und anschließend nimmt der PIC die Verarbeitung der Befehle nach dem Sleep wieder auf, was bei dir dazu führt, dass er in die "WriteLcd"-Funktion springt.
    Code:
    main-loop:
        sleep
        nop                  ;PIC aufgewacht
        btfsc UPDLCD   ;Timer 1 overflow?
        call WriteLcd     ;Ausgabe
        goto main-loop
    
    WriteLcd
        ...
        return
    Du müsstest solch eine Schleife einbauen. Aber wie gesagt, wenn du keinen externen Quarz an dem Timer1 dran hast (oder es nicht dran geben kannst), dann wird das mittels sleep nicht funtionieren können. Was dir dann zum Stromsparen bleiben kann ist, den PIC langsamer zu takten und die unbenutzten I/O-Pins auf Input zu setzten.

    MfG
    Mobius

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.05.2006
    Alter
    35
    Beiträge
    122
    Hallo

    Vielen Dank für deine Antwort.
    Ich habe jetzt alle sleeps ausgetauscht, und tatsächlich, es erscheint etwas aufm LCD, dass in Richtung von Zählen geht, jedoch noch immer ein Chaos von ungewollten Zeichen ist.
    Code:
    	list 	p=16F88
    #include 	<p16f88.inc>
    
    
    	__CONFIG    _CONFIG1, _CP_OFF & _LVP_OFF & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _HS_OSC
    
     
    ; variables
    copyw		Equ	0x20
    copys		Equ 0x21
    LcdDaten	Equ	0x22
    LcdStatus	Equ	0x23
    loops		Equ	0x24
    loops2		Equ	0x25
    stde		Equ	0x27
    stdz		Equ 0x2C
    mine		Equ 0x2D
    minz		Equ 0x30
    seke		Equ	0x31	; einerstelle sekunden
    sekz		Equ	0x32	;zehnerstelle sekunden
    Flags		Equ	0x40
    charge		Equ	0x41
    
    
    ; constants
    PORTC		Equ	PORTB
    PORTD		Equ	PORTB
    
    ;pins LCD
    #define	LcdE		PORTB, 0
    #define	LcdRw		PORTB, 3
    #define	LcdRs		PORTB, 2
    #define UPDLCD		Flags, 0
    
    
    	
    	
    	org		0x00
    	goto Main
    
    	org 	0x04
    
    ISR						;interupt service routine
    	movwf	copyw
    	swapf	STATUS, W
    	bcf		STATUS, RP0
    	movwf	copys
    
    	incf	charge, f
    	movfw	charge
    	sublw	.10
    	btfss	STATUS, Z
    	goto	ISRendCharge
    	incf	seke, f			;seke +1
    	movfw	seke		
    	sublw	.10				;seke -10 ;result negativ => z=0
    	btfss	STATUS, Z		;test z, if z=1 => skip next order
    	goto 	ISRend	
    	clrf	seke
    	incf	sekz, f
    	movf	sekz, w
    	sublw	.6
    	btfss	STATUS, Z
    	goto	ISRend
    	clrf	sekz
    	incf	mine, f
    	movf	mine, w
    	sublw	.10
    	btfss	STATUS, Z
    	goto	ISRend
    	clrf	mine
    	incf	minz, f
    	movf	minz, w
    	sublw	.6
    	btfss	STATUS, Z
    	goto	ISRend
    	clrf	minz
    	incf	stde, f
    	movf	stde, w
    	sublw	.10
    	btfss	STATUS, Z
    	goto	ISRend
    	clrf	stde
    	incf	stdz, f
    	movf	stdz, w
    	sublw	.10
    	btfss	STATUS, Z
    	goto	ISRend
    	clrf	stdz
    	goto	ISRend
    
    	
    ISRend						;interupt end routine
    	bcf		STATUS, RP0
    	bcf		PIR1, TMR1IF	;clear interupt flag
    	swapf	copys, w
    	movwf	STATUS
    	swapf	copyw, f
    	swapf	copyw, w
    	bsf		UPDLCD
    	retfie
    	
    ISRendCharge				;interupt end routine
    	bcf		STATUS, RP0
    	bcf		PIR1, TMR1IF	;clear interupt flag
    	swapf	copys, w
    	movwf	STATUS
    	swapf	copyw, f
    	swapf	copyw, w
    	retfie
    
    Init
    
    	bcf		INTCON, GIE
    	bcf		INTCON, PEIE
    	bsf		STATUS, RP0
    	movlw	B'00000000'
    	movwf	TRISB
    	movlw	B'00000000'
    	movwf	ANSEL
    	bcf		STATUS, RP0
    	clrf	stde
    	clrf	stdz
    	clrf	mine
    	clrf	minz
    	clrf	seke
    	clrf	sekz
    	clrf	LcdDaten
    	clrf	LcdStatus
    
    	return
    
    InitTimer
    	bcf		STATUS, RP0
    	movlw	B'00110101'	;prescaler:  1:8; internal clock; no synchronize; Timer1 enabled
    	movwf	T1CON
    	bsf		STATUS, RP0
    	bsf		PIE1, TMR1IE	
    	bcf		STATUS, RP0
    	bsf		INTCON, GIE	
    	bsf		INTCON, PEIE
    	return
    
    	Main
    	btfsc	UPDLCD
    	goto	WriteLcd
    	call	Init
    	call	InitLCD
    	call	InitTimer
    	
    WriteLcd
    	bcf		UPDLCD
    	call	printseke
    	call	printsekz
    	call	printmine
    	call	printminz
    	call	printstde
    	call	printstdz
    	movlw	D'10'
    	movwf	loops
    	call	WAIT
    	goto WriteLcd
    
    WAIT
    wai		movlw	.249
    		movwf	loops2
    wai2	nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    		nop
    	nop
    		decfsz	loops2, F
    		goto	wai2
    		
    		decfsz	loops, F
    		goto 	wai
    		return
    
    InitLCD
    	movlw	D'15'		
    	movwf	loops	
    	call	WAIT		
    
    	movlw	B'00110000'	
    	movwf	PORTB
    	bsf		LcdE
    	nop	
    	bcf		LcdE
    	
    	movlw	D'5'
    	movwf	loops
    	call	WAIT
    	
    	movlw	B'00110000'
    	call	Control8Bit
    	movlw	B'00110000'
    	call 	Control8Bit
    	movlw	B'00100000'
    	call 	Control8Bit
    
    	movlw	B'00000001'
    	call	OutLcdControl	
    	movlw	B'00101000'
    	call	OutLcdControl	
    	movlw	B'00001000'
    	call	OutLcdControl
    	movlw	B'00000110'
    	call	OutLcdControl
    	movlw	B'00000011'
    	call	OutLcdControl
    	movlw	B'00001111'
    	call	OutLcdControl
    	movlw	B'11000100'
    	call	OutLcdControl
    	movlw	'0'
    	call	OutLcdDaten
    	movlw	'0'
    	call	OutLcdDaten
    	movlw	':'
    	call	OutLcdDaten
    	movlw	'0'
    	call	OutLcdDaten
    	movlw	'0'
    	call 	OutLcdDaten
    	movlw	':'
    	call	OutLcdDaten	
    	movlw	'0'
    	call	OutLcdDaten
    	movlw	'0'
    	call 	OutLcdDaten
    	return
    
    Control8Bit
    	movwf	PORTB
    	bsf		LcdE
    	nop
    	bcf		LcdE
    	movlw	D'10'
    	movwf	loops
    	call 	WAIT
    	return
    
    LcdBusy
        bsf     STATUS, RP0
    	movlw	B'11110000'
    	iorwf   TRISB, f 
        bcf     STATUS, RP0
    BusyLoop		
    	bcf		LcdRs
    	bsf		LcdRw
    	bsf		LcdE
    	nop
    	movf	PORTD, w
    	movwf	LcdStatus
    	bcf		LcdE
    	nop
    	bsf		LcdE
    	nop
    	bcf		LcdE
    	btfsc	LcdStatus, 7
    	goto 	BusyLoop
    	bcf		LcdRw
        bsf     STATUS, RP0	
    	movlw	B'00001111'
    	andwf   TRISB, f    
        bcf     STATUS, RP0
    	return	
    
    OutLcdControl
    	movwf	LcdDaten
    	;call	LcdBusy
    	movf	LcdDaten, w
    	andlw	H'F0'
    	movwf	PORTD	
    	bsf		LcdE
    	nop
    	bcf		LcdE	
    	swapf	LcdDaten, w
    	andlw	H'F0'
    	movwf	PORTD	
    	bsf		LcdE
    	nop
    	bcf		LcdE	
    	return
    
    OutLcdDaten
    	movwf	LcdDaten
    	;call	LcdBusy
    	movf	LcdDaten, w
    	andlw	H'F0'
    	movwf	PORTD	
    	bsf		LcdRs	
    	bsf		LcdE	
    	nop
    	bcf		LcdE	
    	swapf	LcdDaten, w
    	andlw	H'F0'
    	movwf	PORTD		
    	bsf		LcdRs	
    	bsf		LcdE
    	nop
    	bcf		LcdE	
    	bcf		LcdRs		
    	return
    	
    printseke	; ausgabe von seke
    	movlw	b'11001011'
    	call	OutLcdControl
    	movfw	seke
    	addlw	'0'
    	call	OutLcdDaten
    	return
    	
    printsekz
    	movlw	b'11001010'
    	call	OutLcdControl
    	movfw	sekz
    	addlw	'0'
    	call	OutLcdDaten
    	return
    	
    printmine
    	movlw	b'11001000'
    	call	OutLcdControl
    	movfw	mine
    	addlw	'0'
    	call	OutLcdDaten
    	return
    	
    printminz
    	movlw	b'11000111'
    	call	OutLcdControl
    	movfw	minz
    	addlw	'0'
    	call	OutLcdDaten
    	return
    
    printstde
    	movlw	b'11000101'
    	call	OutLcdControl
    	movfw	stde
    	addlw	'0'
    	call	OutLcdDaten
    	return
    	
    printstdz
    	movlw	b'11000100'
    	call	OutLcdControl
    	movfw	stdz
    	addlw	'0'
    	call	OutLcdDaten
    	return
    	
    	end
    Ich habe jetzt weiter noch eine "Warteschelife" mit Faktor 10 eingeführt. (zu Beginn der ISR)
    Meine Rechnung ist nun folgende:
    ((20000000Hz/(4*8*65535))^(-1))*10=1.04 sek.

    Zudem wird die Aktualisierung des LCD nur noch alle 10ms durchgeführt:

    Code:
    WriteLcd
    	bcf		UPDLCD
    	call	printseke
    	call	printsekz
    	call	printmine
    	call	printminz
    	call	printstde
    	call	printstdz
    	movlw	D'10'
    	movwf	loops
    	call	WAIT
    	goto WriteLcd
    Aber das ganze will noch immer nicht funktionnieren. Wieviele Fehler kann man denn hier noch machen???

    Ne weitere Frage: Was stehet im Stack Level 1 nach einem "retfie", respektive wohin springt das Programm nach einem "return from interrupt"?

    gruss orph

  7. #7
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.10.2004
    Ort
    ferd. Waldmüllerg. 7/2
    Alter
    39
    Beiträge
    456
    http://www.sprut.de/electronic/pic/int/int.htm
    Da steht es super drin, wie ein Interrupt abläuft .

    Ja, schon murphy hat gesagt, "All non trivial programms have at least one bug" und "The number of error in a programm is always greater than 0".

    Hum, hast du eigentlich deine Ausgabe-Funktion getestet??? Also dass er die richtigen Zeichen an die richtige Schreibt? Weil wenn nicht, dann tausch mal dein Main zu diesem aus:
    Code:
    Main:
       call   Init
       call   InitLCD
    
       movlw 0x01
       movwf stdz
       movlw 0x02
       movwf stde
       movlw 0x03
       movwf minz
       movlw 0x04
       movwf mine
       movlw 0x05
       movwf sekz
       movlw 0x06
       movwf seke
    
    ; damit müsste die Ausgabe jetzt lauten 12:34:56
       
    WriteLcd
       bcf      UPDLCD
       call   printseke
       call   printsekz
       call   printmine
       call   printminz
       call   printstde
       call   printstdz
       movlw   D'10'
       movwf   loops
       call   WAIT
       goto WriteLcd
    Da der Timer nun nicht aktiviert worden ist, müsste die Ausgabe statisch gleiben. Wenn sie das nicht ist, ist der Fehler irgendwo in deinen print-Funktionen zu suchen.

    MfG
    Mobius

  8. #8
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.05.2006
    Alter
    35
    Beiträge
    122
    und.... es funktionniert

    (sieht jemand den Fehler, den ich allzu oft übersehen habe?)

    Code:
    OutLcdControl 
       movwf   LcdDaten 
       ;call   LcdBusy 
       movf   LcdDaten, w
    Aber was solls, war ja nicht der einzige Fehler...

    Jetzt hätte ich nur noch eine Frage: Beim Display bleibt der Cursor einfach auf der Einerstelle der Stundenanzeige (Datenbyte nr. 69) und blinkt dort. Kann man den irgendwie verschieben? (sieht etwas unästhetisch aus, und dort macht er auch nicht wirklich Sinn)

  9. #9
    Erfahrener Benutzer Lebende Robotik Legende Avatar von PICture
    Registriert seit
    10.10.2005
    Ort
    Freyung bei Passau in Bayern
    Alter
    73
    Beiträge
    11.077
    Hallo orph!

    Wenn Du kein Cursor brauchst, kannst ihn mit dem Befehl "Display on/off control" Bit D1 entweder erst nach der Ausgabe oder schon bei der Initialisierung des Displays ausschalten !

    Die anderen Bits in dem Befehl sollten unverändert bleiben.

    MfG

  10. #10
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    13.07.2004
    Ort
    bei Stuttgart
    Alter
    42
    Beiträge
    760
    hi,
    ich habe das programm jetzt nicht genau angeschaut, allerdings sollte das nicht alzu schwer sein.
    ich würde mit dem timer jede sekunde einen interrupt auslösen, und dann einfach sekunden, minuten und stunden in der interrupt routine neu berechnen, und im hauptprogramm immer nur die werte auf lcd schreiben lassen.
    mfg jeffrey

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen