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
Lesezeichen