- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
Ergebnis 1 bis 7 von 7

Thema: PIC Eieruhr asm

  1. #1

    PIC Eieruhr asm

    Anzeige

    Praxistest und DIY Projekte
    Klicke auf die Grafik für eine größere Ansicht

Name:	Eieruhr.JPG
Hits:	22
Größe:	102,8 KB
ID:	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

  2. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    03.09.2009
    Ort
    Berlin (Mariendorf)
    Beiträge
    1.023
    Hallo Schlapfi.

    Zunächst willkommen im Forum.
    Ist das dein Microcontroller-Erstlingswerk? Ein kleines feines Projekt!

    Zunächst ein ehrliches Lob: Du hast deine Source recht gut dokumentiert, sowohl die Zusammenhänge des Codes in sich selbst, als auch die Zuordnung zur Hardware.
    Man kann ein paar gute Anregungen aus deinem Code mitnehmen.

    Es sind aber auch einige Fallstricke eingebaut, die ich gerne einem anderen Anfänger ersparen würde.
    Ich liste ein paar auf, ohne Anspruch auf Wichtigkeit und Vollständigkeit:

    - Interrupts global freizugeben, ohne tatsächlich eine Interruptroutine zu implementieren ist nicht nötig und ein wenig riskant. Du verwendest das TMR0-Überlaufflag. Dieses wird unabhängig von einer Interruptfreigabe erzeugt, allein durch den Überlauf von TMR0.
    - Der Programmstart sollte mit einem Sprung zu einem 'sprechenden' Label beginnen, das den Startpunkt des Hauptprogramms erkennen lässt, also z.B. 'main' oder 'start'. Sprung deswegen, weil im Falle eines Interrupts das Hauptprogramm unterbrochen und die Befehlsausführung beim Programmspeicherplatz Nr. 4 fortgesetzt wird. Es ist sicherer, gleich von Anfang an diese Speicherzuordnung im Programm anzulegen, damit man nicht später beim Einstig in die Interruprprogrammierung genau deswegen auf die Nase fällt. Ein Rücksprung RETFIE an dieser Stelle schafft dann zusätzliche 'Sicherheit' gegen unliebsame Überraschungen bei weiteren Experimenten in der ASM-Programmierung. Die von Microchip mitgelieferten Programmrohlinge (Templates) bilden genau dieses sichere Grundgerüst auch ab.
    - Ein Sprung GOTO $-1 ist legitim, wenn es sich um ein quasi 'atomares' Programmelement zum Warten auf ein Flag handelt; da wird man nicht versehentlich einen weiteren Befehl einschieben und erspart sich das Erfinden eines Labelnamens. Anders dagegen ein GOTO $+9: Das birgt das Risiko, bei der Änderung des übersprungenen Codeabschnitts zu ungewollten Sprungzielen zu führen; hierfür gibt es benannte Sprungmarken (Labels). Die sollte man auch verwenden.
    - ganz böse Falle:
    Code:
    LED
            addwf    PCL,1
            retlw    D0    
            retlw   ...
    Dieses Konstrukt funktioniert nur so lange, bis bei der Manipulation von PCL ein Überlauf geschieht. Entweder muss dieser Fall abgefangen werden oder man platziert das Unterprogramm LED per org-Zeile so, dass es unverrückbar an sicherer Stelle im Programmspeicher steht, dann aber am besten gaaaaaanz weit hinten am Ende eines Codesegments! Jetzt funktioniert dein Programm zwar, aber jede Erweiterung birgt das Risiko, dass das UP 'LED' an eine gefährliche Stelle innerhalb des Codespeichers rutscht und der Programmablauf sich im Nirvana verirrt. Genaueres über die Table Read-Methodik findet sich in der App Note AN556 bei Microchip.

    Gruß
    Christian.

  3. #3
    Hallo RoboHolIc
    Möchte mich vorstellen:
    Bin Baujahr 1955 habe 2 handwerkliche Berufe erlernt,
    1987 eine Elektriker ausbildung absolviert, ( aber nie ausgeübt )
    kam vor einigen Jahren zu PIC-Controller, da ich eine Spezial-IC
    wollte und mein Elektroniker meinte "Die gibt es nicht mehr"
    er könne mir einen Mikrokontroller verkaufen.
    Daher kaufte ich mir ein PICkit 1 und wollte mir diese IC "selbermachen".
    Da ich der englischen Sprache nicht mächtig bin, fällt es mir seeeehr schwer
    diverse MICROCHIP Datenplätter zu Identifizieren,
    und habe mich mühhhhsam über deutschsprachige Bücher zu meinen wissen durchgekämpt.
    Da im Buch "PICs für Einsteiger" von Thorsten Mumm die Tabellen so beschrieben sind.
    Die Programmsprünge mit $+x habe ich in div anderen Bücher so gelesen zb.
    Franzis Buch "Programieren vom PIC-Mikrocontrollern" von Dieter Kohtz
    das dieses Fehlerbehaftet ist habe ich eventuell überlesen.
    Aber ich glaube ich bin nicht der einzige der mit PIC so seine anfängerproblemchen hat
    deswegen habe ich dieses Programm eingestellt , ohne 1000 call wo sich der anfänger
    nicht mehr durchblickt ( Sprut )
    Grüsse:
    Schlapfi

  4. #4
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    03.09.2009
    Ort
    Berlin (Mariendorf)
    Beiträge
    1.023
    Hallo Schlapfi.

    Da hast du in Sachen Microcontroller anscheinend eine echte Ochsentour durchgemacht! Leider hast du dabei auch eher schlechte Lehrbücher erwischt.

    Keinesfalls will ich dein Programm schlecht machen. Schließlich tut es ja, was es soll. Die Sache mit den Tabellen ist aber ein 'gutes' Beispiel für schlechte Lernbeispiele; das Springen mittels GOTO $+x ist gleich das nächste! Beides funktioniert so wie es dasteht, ist aber nicht zur Nachahmung zu empfehlen.

    Dass du aus verschiedenen Quellen Material verwendet hast, habe ich schon anhand der verschiedenen Schreibweisen für Konstanten vermutet (z.B. der konstante Wert '06' ist oktal, also auf der Basis von 8 zu interpretieren; diese Darstellungsform wird selten verwendet, hat kaum Nutzwert und kann leicht als dezimal missverstanden werden).

    Also nochmals: Ich will dich nicht abbürsten und dein Projekt schlechtmachen, sonden die Probleme aufzeigen, die dort angelegt sind.
    Microchip liefert - gut versteckt auf dem PC - für (nahezu) jeden Controller eine Muster-Programmdatei, mit der ich von Anfang an sehr gut gefahren bin.
    Das für deinen Controller passende Musterprogramm habe ich gleich hier reingestellt. Als Übung könntest du mal versuchen, dein Projekt in diesen Rahmen einzubauen.

    Code:
    ;**********************************************************************
    ;   This file is a basic code template for assembly code generation   *
    ;   on the PIC16F631. This file contains the basic code               *
    ;   building blocks to build upon.                                    *
    ;                                                                     *
    ;   Refer to the MPASM User's Guide for additional information on     *
    ;   features of the assembler (Document DS33014).                     *
    ;                                                                     *
    ;   Refer to the respective PIC data sheet for additional             *
    ;   information on the instruction set.                               *
    ;                                                                     *
    ;**********************************************************************
    ;                                                                     *
    ;    Filename:        xxx.asm                                           *
    ;    Date:                                                            *
    ;    File Version:                                                    *
    ;                                                                     *
    ;    Author:                                                          *
    ;    Company:                                                         *
    ;                                                                     *
    ;                                                                     *
    ;**********************************************************************
    ;                                                                     *
    ;    Files Required: P16F631.INC                                      *
    ;                                                                     *
    ;**********************************************************************
    ;                                                                     *
    ;    Notes:                                                           *
    ;                                                                     *
    ;**********************************************************************
    
    
        list        p=16f631    ; list directive to define processor
        #include    <p16f631.inc>    ; processor specific variable definitions
    
    
    ; '__CONFIG' directive is used to embed configuration data within .asm file.
    ; The labels following the directive are located in the respective .inc file.
    ; See respective data sheet for additional information on configuration word.
    
        __CONFIG    _FCMEN_ON & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT
    
    
    
    ;***** VARIABLE DEFINITIONS
    w_temp        EQU    0x7D        ; variable used for context saving
    status_temp    EQU    0x7E        ; variable used for context saving
    pclath_temp    EQU    0x7F        ; variable used for context saving
    
    
    ;**********************************************************************
        ORG     0x000             ; processor reset vector
    
        nop
          goto    main              ; go to beginning of program
    
    
        ORG     0x004             ; interrupt vector location
    
        movwf   w_temp            ; save off current W register contents
        movf    STATUS,w          ; move status register into W register
        movwf    status_temp       ; save off contents of STATUS register
        movf    PCLATH,w      ; move pclath register into w register
        movwf    pclath_temp      ; save off contents of PCLATH register
    
    ; isr code can go here or be located as a call subroutine elsewhere
    
        movf    pclath_temp,w      ; retrieve copy of PCLATH register
        movwf    PCLATH          ; restore pre-isr PCLATH register contents
        movf    status_temp,w     ; retrieve copy of STATUS register
        movwf    STATUS            ; restore pre-isr STATUS register contents
        swapf   w_temp,f
        swapf   w_temp,w          ; restore pre-isr W register contents
        retfie                    ; return from interrupt
    
    
    
    main
    
    ; remaining code goes here
    
    
    
    
    ; example of preloading EEPROM locations
    
        ORG    0x2100
        DE    5, 4, 3, 2, 1
    
        END                       ; directive 'end of program'
    Frag einfach, wenn du dort etwas nicht verstehst.

    Gruß
    Christian.

  5. #5
    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

    Klicke auf die Grafik für eine größere Ansicht

Name:	Voltmeter.jpg
Hits:	6
Größe:	24,3 KB
ID:	30101

  6. #6
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    03.09.2009
    Ort
    Berlin (Mariendorf)
    Beiträge
    1.023
    Hallo Schlapfi.

    Zitat Zitat von Schlapfi Beitrag anzeigen
    Ich dachte ich brauch org 0x00 und org 0x04 nur dann, wenn ich die ISR verwende.
    'org 0x00' ist beim PIC16F676 für den ersten ausführbaren Befehl implizit gegeben. 'org 0x04' wird nur in Verbindung mit Interrupts wirklich benötigt. Alles so richtig.
    Dann sollte man aber konsequenterweise auch das GIE-Bit nicht setzen!

    Zitat Zitat von Schlapfi Beitrag anzeigen
    Möchte meine Programme nicht unnötig verkomplizieren.
    Bei sehr kleinen Programmen (=am Anfang) wirkt die Strukturierung oft überflüssig, aufblähend. Das ändert sich mit steigender Codegröße sehr bald. Ein Gerücht sagt, dieser Effekt ziehe sich durch praktisch alle Programmiersprachen hindurch! Strukturierung macht Programme i.d.R. robuster gegenüber Änderungen, besser lesbar, pflegeleichter ... Der effektive Code im Controller wird dabei nicht oder nur unwesentlich größer, lediglich der Sourcecode nimmt an Umfang zu.

    Zitat Zitat von Schlapfi Beitrag anzeigen
    Der PIC fängt ja immer bei 0x00 an, oder sehe ich da etwas falsch.
    Ja, dieser PIC macht das so. Es gibt (gab) bei den PICs aber auch ganz andere Konzepte. Es ist gut und hilfreich, mittels org-Anweisungen das jeweilige Programmspeicherkonzept im ASM-Code abzubilden. So kann man beispielsweise die Codesegmente eines PIC16F876 mittels org 0x0000, org 0x0800, org 0x1000 und org 0x1800 im ASM-Programm bekannt machen und verschiedene Unterprogramme dort gezielt platzieren. Das hilft sehr im effizienten Umgang mit der Codesegmentierung und der Assembler hat die Möglichkeit, Adressüberschneidungen zu erkennen.

    Zitat Zitat von Schlapfi Beitrag anzeigen
    Wie kann ich das mit den Tabellen besser machen ?
    Ich kann das nicht besser erklären als die genannte App Note AN556. Grob und aus der Erinnerung heraus gesagt besteht das Problem darin, dass ein simples 'addwf PCL' nur die acht niederwertigsten der (maximal) dreizehn Adressbits beeinflusst! Tritt bei der Addition ein Überlauf von PCL auf, dann muss PCH inkrementiert werden. So ist die Tabellenfunktion wasserdicht programmiert. Insgesamt sind das etwa fünf oder sechs Codezeilen, die dir im Fall des Falles viele Haarbüschel auf deinem Kopf retten werden!

    Gruß
    Christian.

  7. #7
    Hallo RoboHolIC.

    Danke für deine Tips, werde mir das genauer ansehen.

    Grüsse Schlapfi

Ähnliche Themen

  1. Eieruhr
    Von crabtack im Forum Vorstellung+Bilder+Ideen zu geplanten eigenen Projekten/Bots
    Antworten: 18
    Letzter Beitrag: 08.07.2010, 13:56
  2. CAN Asm Code, wie muss ich den Pic ansteuern.?????
    Von frankdssd im Forum PIC Controller
    Antworten: 1
    Letzter Beitrag: 08.04.2010, 13:56
  3. Eieruhr
    Von Bluesmash im Forum Vorstellungen+Bilder von fertigen Projekten/Bots
    Antworten: 21
    Letzter Beitrag: 18.09.2009, 00:43
  4. Raw-Eieruhr
    Von SprinterSB im Forum Vorstellungen+Bilder von fertigen Projekten/Bots
    Antworten: 7
    Letzter Beitrag: 16.03.2009, 22:28
  5. Eieruhr
    Von SprinterSB im Forum Vorstellungen+Bilder von fertigen Projekten/Bots
    Antworten: 32
    Letzter Beitrag: 20.03.2007, 13:18

Berechtigungen

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

12V Akku bauen