PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer1 Uhr



orph
30.08.2006, 21:33
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.


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

Mobius
31.08.2006, 00:27
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.


Hauptprogramm Interrupt
------------------- ------------

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

kalledom
31.08.2006, 09:22
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.

orph
13.09.2006, 22:42
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,



;------------------------------------------------------------------------------
; 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

Mobius
14.09.2006, 09:46
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.


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

orph
14.09.2006, 19:20
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. ;-)


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:


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

Mobius
14.09.2006, 20:41
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:


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

orph
14.09.2006, 22:33
und.... es funktionniert

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


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)

PICture
16.09.2006, 13:02
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

jeffrey
16.09.2006, 15:44
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