Liste der Anhänge anzeigen (Anzahl: 1)
PIC Eieruhr asm
Anhang 30094
Mit nur 2 CALL befehle habe ich ein lernprogramm geschrieben.
Ich hoffe es hilft auch jemanden.
lg
Schlapfi
Code:
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Dateiname: Eieruhr ( Lernprogramm )
; LED mit 3 x 7 Segment Multiplex betrieb
; Autor: Schlapfi
; Datum: Dez. 2013
; PIC 16F631
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Funktionsbeschreibung des Programms:
; Prozessor-Takt 8 MHz Intern
; Mit PAUSE wird gewartet bis Timer-0 überleuft, über ZAEHL wird diese Zeit erweitert
; auf 1,000999 Sec.( für Eierkochen ausreichend, Fehlmessung 0,6 Sec. in 10 Min.)
; und "einer" wird mit diesem Takt hochgezählt.
; Anoden sind RB6 = hundert , RB5 = zehner, RB4 = einer
; einer = Sekunde-einer
; zehner = Sekunde-zehner
; hundert = Minute
; 7-Segment mit gemeinsamer Anode.
; Katoden ausgänge sind: PORT-C
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
list p=16F631
#include <p16f631.inc>
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _CPD_OFF
ERRORLEVEL -302 ; Unterdrücken BANK SELECTION MESSAGES
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Deklaration der Variablen und Konstanten
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
einer EQU H'0022' ; Variable für die Einerstelle der Zahl
zehner EQU H'0023' ; Variable für die Zehnerstelle der Zahl
hundert EQU H'0024' ; Variable für die Hunderterstelle der Zahl
ZAEHL EQU H'0025' ; Zähler für Sekunde
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Masken für das Einschalten der LEDs
; Masken sind wegen besserer beschaltung so gwählt
; und können leicht verändert werden.
; gfedcba
#define D0 B'01000000' ; 0
#define D1 B'01111001' ; 1
#define D2 B'00100100' ; 2
#define D3 B'00110000' ; 3
#define D4 B'00011001' ; 4
#define D5 B'00010010' ; 5
#define D6 B'00000010' ; 6
#define D7 B'01111000' ; 7
#define D8 B'00000000' ; 8
#define D9 B'00010000' ; 9
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Startadresse des PIC-Controllers nach einem RESET oder Neustart
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
org 0x000 ; Startadresse des PICs
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; PIC Einstellungen
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
START
bsf STATUS,RP0 ; Auswahl Bank 1
movlw B'01110000' ; Int-Oszilator 8 MHz,
movwf OSCCON
movlw b'00000100' ; TMR0 vorbereiten (intern, Vorteiler 32,)
movwf OPTION_REG
movlw b'00000000' ; TRISC = Ausgang
movwf TRISC ; damit ist Port C = Ausgang
movwf TRISB ; und Port B
movwf TRISA ; und Port A
bcf STATUS,RP0 ; Auswahl Bank 0
; Interrupt
movlw b'10000000' ; alle
movwf INTCON ; Interrupts freigeben
movlw .250
movwf ZAEHL
clrf PORTA ; Löschen aller Ausgänge
clrf PORTB
clrf PORTC ; Löschen aller Ausgänge
clrf einer
clrf zehner ; Löschen
clrf hundert
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Hauptprogramm: LED Anzeigen 3x7 Segmente
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
LEDAnz
clrf PORTB ; Löschen aller Ausgänge
clrf PORTC
; führende null unterdrücken. ZEROPIT abfragen ob gesetzt.
movlw d'0' ; 0 nach " W " laden
addwf hundert,w ; inhalt von hundert dazu addieren, schreibe in " W "
btfsc STATUS,Z ; ist nicht null ? : überspringe nächste Zeile
goto $+9 ; wenn null, 9 Zeilen nach unten
movlw B'01000000' ; hunderter Katode
movwf PORTB ; und an PORTB ausgeben
movf hundert,w ; Laden der Variable "hundert" in das W-Register
call LED ; Sprung zum Laden der LED-Variablen
movwf PORTC ; und an PORTC ausgeben
call PAUSE
clrf PORTB ; Löschen aller Ausgänge
clrf PORTC
movlw B'00100000'
movwf PORTB
movf zehner,w ; Laden der Variablen "zehner" in das W-Register
call LED ; Sprung zum Laden der LED-Variablen
movwf PORTC
call PAUSE
clrf PORTB ; Löschen aller Ausgänge
clrf PORTC
movlw B'00010000'
movwf PORTB
movf einer,w ; Laden der Variablen "einer" in das W-Register
call LED ; Sprung zum Laden der LED-Variablen
movwf PORTC
call PAUSE
goto LEDAnz ; und wieder zu Anzeige
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Ab hier folgen die Unterprogramme
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; PAUSE:
; wartet bis Timer0 überleuft ( alle 4 mSec. ) und verringert ZAEHL bis null,
; 4 mSec ( Timer0 ) X 250 ( ZAEHL ) = Eine Sekunde
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
PAUSE
btfss INTCON,T0IF ; Pause von 4 ms Dauer
goto $-1 ; warten bis Interruptflag gesetzt ist
movlw 06 ; Timer-0 auf 250 stellen
movwf TMR0 ; W -> Timer-0
bcf INTCON,T0IF ; TMR0-Flag löschen
decfsz ZAEHL ; ZAEHL minus 1 bis 0
return ; ZAEHL > 0
movlw .250 ; ZAEHL = 0
movwf ZAEHL ; und wird neu geladen
; erhöht "einer" um 1 und alle weiteren stellen bei überlauf
incf einer,1 ; Erhöhen der Variablen "einer" um +1
movfw einer ; Laden der Variablen "einer" ins W-Register
sublw D'10' ; 10 in W laden und abziehen.
btfss STATUS,Z ; ergebnis = 0 : überspringe nächste Zeile
return ; rechenergebnis nicht 0 = return
; Ja, dann
incf zehner,1 ; Zählervariable für die zweite Stelle erhöhen
clrf einer ; einer löschen
movfw zehner ; Laden der Variablen "zehner" ins W-Register
sublw D'6' ; Maximaler Zählwert erreicht?
btfss STATUS,Z ; erreicht : überspringe nächste Zeile
return ; nicht 0 = return
; Ja, dann
incf hundert,1 ; Zhundert um 1 erhöhen
clrf zehner ; zehner löschen
movfw hundert ; Laden der Variablen "hundert" ins W-Register
sublw D'10' ; Maximaler Zählwert erreicht?
btfss STATUS,Z ; erreicht : überspringe nächste Zeile
return ; nicht 0 = return
clrf hundert ; Zählervariable löschen
return ; Rücksprung
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
LED
addwf PCL,1
retlw D0
retlw D1
retlw D2
retlw D3
retlw D4
retlw D5
retlw D6
retlw D7
retlw D8
retlw D9
END
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo RoboHolIc
Danke für deine Antwort.
Das hier war mein erstes richtiges Programm.
Voltmeter bis 15 Volt
Code:
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Dateiname: Voltmeter ( Lernprogramm )
; Autor: Schlapfi
; Datum: Sept. 2013
; Kontroller: 16F676
; Das Programm kann mit wenigen veränderungen auch für andere PIC's verwendet werden.
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Funktionsbeschreibung des Programms:
; Spannungsmessung bis 15.0 Volt. 3 stellige LED-anzeige mit Multiplex betrieb.
; An RA0 wird eine spannung gemessen und an RC0 - RC3 im BCD code ausgegeben
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; 10K 10K 10K
; - 0 V ____ ____ ____ + 15V
; ------|____|-----+-------|____|------------|____|------
; |
; ----------- || --+--- RA0 ->
; C 1µF
;
; Bordspsnnung ( Auto ) wird durch 3 geteilt,
; durch 3 Widerstände a,10 K Ohm.
; Von RA0 ( AD-Eingang ) einen Kondensator 1µF nach Masse stabilisiert
; die Anzeige. ( verhindert laufen )
; Der 5 Volt Messbereich des PIC entspricht dann 15 Volt.
; Das Ergebnis der Messung wird mit dem Faktor 3 Multipliziert
; und an RC1 bis RC4 im BCD code ausgegeben.
; Katoden sind RA5 = hundert ( 10 V ) ,
; RA1 / RA4 = zehner ( einerstelle ) und Dp.,
; RA2 = einer.( nachkommastelle )
; Die Katoden werden über Transistoren gesteuert der Dp. kann direkt gesteuert werden.
; BCD ausgänge sind: RC4 = 1 , RC1 = 2 , RC2 = 4 , RC3 = 8
; diese steuern einen CMOS-4511 7-Segment-Dekoder.
; Es können auch andere BCD zu 7 Segment decoder verwendet werden.( zb. 4513 oä.)
; Die Pinbelegung des PIC wurde wegen der Pinanordnung des 4511 so gewählt.
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
list p=16F676
#include <p16f676.inc>
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _CPD_OFF
ERRORLEVEL -302 ; Unterdrücken BANK SELECTION MESSAGES
;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Deklaration der Variablen und Konstanten
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
schleife EQU H'0020' ; Anzahl der "schleifen"
help EQU H'0021' ; Hilfsvariable für verschiedene Aufgaben.
einer EQU H'0022' ; Variable für die Einerstelle der Zahl
zehner EQU H'0023' ; Variable für die Zehnerstelle der Zahl
hundert EQU H'0024' ; Variable für die Hunderterstelle der Zahl
ADC_L EQU H'0026' ; -----------------""---------------------
ADC_H EQU H'0027' ; Variablen
ADC_L1 EQU H'0028' ; weden für rechenoperationen gebraucht
ADC_H1 EQU H'0029' ; -----------------""---------------------
count EQU H'002C' ; -----------------""---------------------
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Masken für das Einschalten der LEDs
; Masken sind wegen der Eingänge des C-MOS 4511 so gwählt,
; und können für andere zwecke leicht verändert werden.
#define D0_AN B'00000000' ; 0
#define D1_AN B'00010000' ; 1
#define D2_AN B'00000010' ; 2
#define D3_AN B'00010010' ; 3
#define D4_AN B'00000100' ; 4
#define D5_AN B'00010100' ; 5
#define D6_AN B'00000110' ; 6
#define D7_AN B'00010110' ; 7
#define D8_AN B'00001000' ; 8
#define D9_AN B'00011000' ; 9
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
w equ 0 ; w ist Zielregister
f equ 1 ; f ist Zielregister
org 0 ; Start bei Adresse 0
goto START
org 04 ; feste Interrupt-Service-Adresse
START
bsf STATUS,RP0 ; Auswahl Bank 1
call 0x3FF ; Laden des Kalibrierungswertes
movwf OSCCAL ; Schreiben des Kalibrierungswertes für den internen Takt
movlw B'00010001' ; FOCS 8 und AN0
movwf ANSEL
movlw b'00000001' ;setze RA0 als Eingang und den Rest als Ausgang
movwf TRISA
movlw b'00000000' ;alle Pins von Port C sind Ausgänge
movwf TRISC
movlw B'00000011' ; Pull-ups abschalten, interne clock, Teiler 1:16
movwf OPTION_REG ; Schreiben des OPTION-Registers
bcf STATUS,RP0 ; Zurück zu Bank 0
movlw B'10000001' ; Rechtsbündig, AN 0, AD an
movwf ADCON0
clrf PORTA ; Löschen aller Ausgänge
clrf PORTC ; Löschen aller Ausgänge
clrf einer
clrf zehner
clrf hundert
movlw d'20'
movwf count
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Hauptprogramm
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Hier wird der AD-Wandler 25 X abgefragt und zu ADC_L und ADC_H addiert.
; Entspricht einer multiplikation mit 25
Haupt
clrf ADC_L
clrf ADC_L1
clrf ADC_H
clrf ADC_H1
clrf help
movlw d'25' ; 25 in W laden
movwf help ; W in help laden
Prog call ADMess ; gehe zu unterprogramm ADMess
decfsz help,f ; 1 von help abziehen, prüfen ob null
goto Prog ; nicht null gehe zu Prog
bcf STATUS,C ; null erreicht lösche C bit
movfw ADC_L ; ADC_L in W laden
movwf ADC_L1 ; W in ADC_L1 kopieren
movfw ADC_H ; -"-
movwf ADC_H1
goto ADAD
ADMess
bsf STATUS,RP0 ; Auswahl Bank 1
clrf ADRESL ; niederwertigen Teil des AD-Ergebnisses löschen
bcf STATUS,RP0 ; Auswahl Bank 0
clrf ADRESH ; höherwertigen Teil des AD-Ergebnisses löschen
bsf ADCON0,GO ; A/D-Wandler starten
btfsc ADCON0,GO ; Ist der A/D-Wandler fertig?
goto $-1 ; Nein, weiter warten ( eine Zeile zurück )
movf ADRESH,w ; Dezimalwert aus ADH-Register in W schreiben
; movlw d'3' ; wird mit " NOP " überschrieben dient nur zur überprüfung
addwf ADC_H,f ; addiere W zu ADC_H und schreibe in F
bsf STATUS,RP0 ; Auswahl Bank 1
movf ADRESL,w ; Dezimalwert aus ADL-Register in W schreiben
bcf STATUS,RP0 ; Auswahl Bank 0
; movlw d'70' ; wird mit " NOP " überschrieben dient nur zur überprüfung
; ADC_H + ADC_L ergeben 12,3 Volt
bcf STATUS,C ; C löschen
addwf ADC_L,f ; addiere W zu ADC_L und schreibe in F
btfsc STATUS,C ; übertrag erfolgt ?
incf ADC_H,f ; addiere eins
return
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; ADC_L und ADC_H Werden mit 3 multipliziert
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ADAD clrf schleife ; lösche schleife
movlw d'2' ; 2 in W laden, einmal steht es schon im Speicher
movwf schleife ; wert aus W in schleife
ADD_3 bcf STATUS,C ; C löschen
movf ADC_L1,w ; ADC_L1 in W laden
addwf ADC_L,f ; addiere W zu ADC_L
btfsc STATUS,C ; überlauf erfolgt ? kein überlauf überspringe
incf ADC_H,F ; bei überlauf addiere 1 zu ADC_H
movf ADC_H1,w ; lade ADC_H1 in W
addwf ADC_H,f ; addiere W zu ADC_H und schreibe nach F
decfsz schleife,f ; eins von schleife abziehen bis null,
; wenn null überspringe nächsten befehl.
goto ADD_3 ; gehe zu
; normalerweise wird ADC_H und ADC_L jetzt durch 256 dividiert = 9 X durch 2 dividieren
; ADC_H ein mahl rechts ADC_L wird nicht mehr gebraucht.Das Messergebnis steht in ADC_H
rrf ADC_H,w ; dividiere durch 2 und schreibe nach W
; in ADC_H steht jetzt das endergebnis
movwf help ; gemessene Spannung ( ADC_H ) in help schreiben
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; auswertung des endergebnis von Hexa in Dezimahl
; help wird zerlegt in einer , zehner und hunderter
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
clrf schleife
bcf STATUS,C
movlw d'100' ; lade 100 in W Register
sub_H
subwf help,F ; 100 von help abziehen und in F schreiben
btfsc STATUS,C ; übertrag erfolgt ?
goto ergeb_Pos_H ; kein übertrag gehe zu ergeb_Pos_H
addwf help,f ; addiere W ( 100 ) zu help
movfw schleife ; schleife in W Register laden
movwf hundert ; anzahl der durchläufe ist jetzt hundert
clrf schleife ; lösche schleife
bcf STATUS,C ; Carryflag löschen
movlw d'10' ; lade 10 in W Register
goto sub_Z
ergeb_Pos_H
incf schleife,F ; schleife + 1
goto sub_H ; und noch einmal
sub_Z
subwf help,F ; 10 von help abziehen
btfsc STATUS,C ; übertrag erfolgt ?
goto ergeb_Pos_Z ; kein übertrag gehe zu ergeb_Pos_Z
addwf help,f ; addiere W ( 10 ) zu help
movfw schleife ; schleife in W Register laden
movwf zehner ; anzahl der durchläufe ist jetzt zehner
movfw help ; der rest
movwf einer ; ist einer
bcf STATUS,C
goto Anz
ergeb_Pos_Z
incf schleife,F ; schleife + 1
goto sub_Z
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Ansteuerung einer 3 X 7 Segment Anzeige ( Multiplex )
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anz
clrf PORTA ; Löschen aller Ausgänge
clrf PORTC
; führende null unterdrücken. ZEROPIT abfragen ob gesetzt.
movlw d'0' ; 0 nach " W " laden
addwf hundert,w ; inhalt von hundert dazu addieren, schreibe in " W "
btfsc STATUS,Z ; ist nicht null ? : überspringe nächste Zeile
goto An2 ; wenn null, 6 Zeilen nach unten
movlw B'00100000' ; hunderter Katode
movwf PORTA ; und auf PORTA ausgeben
movf hundert,w ; Laden der Variable "hundert" in das W-Register
call LED ; Sprung zum Laden der LED-Variablen
movwf PORTC ; und auf PORTC ausgeben
call PAUSE ; Pause 4 mSek.
An2
clrf PORTA ; Löschen aller Ausgänge
clrf PORTC
movlw B'00010010' ; zehner Katode
movwf PORTA
movf zehner,w ; Laden der Variablen "zehner" in das W-Register
call LED ; Sprung zum Laden der LED-Variablen
movwf PORTC
call PAUSE
clrf PORTA ; Löschen aller Ausgänge
clrf PORTC
movlw B'00000100'
movwf PORTA
movf einer,w ; Laden der Variablen "einer" in das W-Register
call LED ; Sprung zum Laden der LED-Variablen
movwf PORTC
call PAUSE
decfsz count ; count minus 1 bis 0
goto Anz ; count nicht 0
movlw d'20'
movwf count
goto Haupt ; count = 0, neue AD-Messung
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Ab hier folgen die Unterprogramme
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;Warteschleife Pause
PAUSE ; Label, wo die Standardwarteschleife beginnt
movlw d'199' ; Dezimalwert für die Zeitkonstante damit "PAUSE" = 1ms ist
movwf schleife ; Schieben des Wertes 199 in die Variable "schleife"
; Ende der Start-Eeinstellungen für "PAUSE1ms"
PAUSEE ; Einsprungstelle für Pausenschleife
nop
nop
decfsz schleife,1 ; Dekrementiere die Variable "schleife" um 1 und schreibe das Ergebnis zurück in "schleife"
goto PAUSEE ; Ist die Zeit verstrichen? Nein, dann springe zurück zu "PAUSEE"
; Neuer Durchlauf bis "schleife"= 0
return
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
LED
addwf PCL,1
retlw D0_AN
retlw D1_AN
retlw D2_AN
retlw D3_AN
retlw D4_AN
retlw D5_AN
retlw D6_AN
retlw D7_AN
retlw D8_AN
retlw D9_AN
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
END
Dieses arbeitet seit über einem Jahr zuverlässig.
Ich dachte ich brauch org 0x00 und org 0x04 nur dann,
wenn ich die ISR verwende. Möchte meine Programme
nicht unnötig verkomplizieren.
Der PIC fängt ja immer bei 0x00 an,
oder sehe ich da etwas falsch.
Wie kann ich das mit den Tabellen besser machen ?
Grüsse Schlapfi
Anhang 30101