PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PIC 12F675 Tastendruckzeit auswerten in Assembler



DL4VAL
15.05.2013, 17:44
Hallo
Um einen Drehkondensator an einer Magnetantenne zu drehen, habe ich einen Schrittmotor eingesetzt.
Jetzt hatte ich das Problem, dass der Motor nicht über die beiden Endschalter fahren soll.
Mit einem PIC12F675 habe ich einen Impulsgeber "programmiert". War tagelange Arbeit und habe noch nicht so richtig verstanden, wie es funktioniert. Klappt aber, wie ich mir das vorstelle.
Jetzt möchte ich das ganze aber noch optimieren.

Meine Schaltung gibt z.Zeit Impulse ab von etwa 25ms Abstand. Das reicht um den Schrittmotor fein zu verfahren.
Der Motor hat 200 Schritte und ist 1:5 untersetzt.
Um vor einem Ende zum andern zu kommen, benötige ich etwa 500 Schritte.
(Halbe Umdrehung)
Das dauert nun schon etwas lange mit der Feinverstellung.

Durch längeres halten der Taste würde ich gerne die Geschwindigkeit erhöhen.
Habe mir das so vorgestellt, dass mit dem ersten Tastendruck ein Timer anläuft, der nach etwa 2 Sekunden Taste halten, ein anderes Unterprogramm aufruft, um dort schnellere Takte zu erzeugen. (Wait)

Hat einer einen Vorschlag für mich?
Wie realisiere ich im Assembler: Wenn Taste gedrückt call UP1, wenn Taste lange gedrückt call UP2?

Gruß Bernd

RoboHolIC
16.05.2013, 08:50
Hallo Bernd.

Es vereinfacht in vielen Fällen die Programmieraufgabe ungemein, wenn das Programm ein Nebeneinander von asynchronem Hauptprogramm und mit fester Frequenz aufgerufener Interruptroutine realisiert.
Der Controller prüft dann z.B. in festen Zeitabständen die Signale der Hardware, z.B. den Tastereingang und verdichtet diese Inputs zu Systemzuständen, z.B. 'Taste nicht gedrückt' oder 'Taste seit nn Millisekunden ununterbrochen gedrückt' oder noch weiter verdichtet zur Benutzereingabe 'Feinpositionierung' und 'Eilgang', jeweils abgeleitet aus nn.
Dazu wird bei jedem Durchlauf der ISR (Interrupt Service Routine) ein Zähler um eins erhöht, wenn die Taste gedrückt ist, oder aber ausgewertet und genullt, wenn sie nicht gedrückt ist. Zeiten <20 Millisekunden betrachtet man dann als Kontaktprellen, Werte größer xx als Feinpositionierung, größer yy als Eilgang; das alles passt i.d.R. locker in die ISR bei z.B. 1ms ISR-Zyklus und 4MHz Prozessortakt.
Auf diese Weise ist auch eine schnell reagierende Notabschaltung machbar, die selbst dann funktioniert, wenn das Hauptprogramm vielleicht gerade auf Daten von der seriellen Schnittstelle wartet, die langwierige Fütterung einer LCD-Anzeige abarbeitet oder gar in einer Endlosschleife hängt!

Die ISR kann auch gut die Erzeugung der Schrittmotorimpulse übernehmen. Feinpositionierung und Eilgang unterscheiden sich ja nur dadurch, dass ein 1ms-Interrupt (das ist mein Liebling) nur bei jedem 200sten oder jedem zweiten (Beispielwerte!) Aufruf einen Schrittmotorimpuls ausgibt. Dazu braucht es noch nicht mal ein Hauptprogramm.

Ist jetzt eine wenig klarer geworden, wie die Lösung aussehen kann? Wenn nicht, dann frag ruhig noch mal nach.

Gruß
Christian.

DL4VAL
16.05.2013, 13:49
Hallo Christian
Habe mein Grundprogramm mal angehängt:
25512

Sorry, habe gar nichts verstanden. :confused:
Bin Anfänger, Dummy ... Newbie

Der momentane Stand meiner Überlegungen ist:

main
Warte auf Eingang G0
G0 = low
Lösche Variable Counter und mache sonst nichts.

G0 = high
Springe in UPlinks
(Das gleiche für rechts)
goto main

UPlinks
Counter +1 wenn Counter <= 10
G4 = high ;Impuls Ausgang 1
call WAIT wenn Counter z.B. < 10 (Wenn das UP normal durchläuft 25ms, mal 10 dann käme der Counter auf 10
wenn bei 250ms)
Call WAITschnell wenn Counter > =10

G4 = low ;Impuls Ausgang 0
call WAIT wenn Counter z.B. < 10 (Wenn das UP normal durchläuft 25ms, mal 10 dann käme der Counter auf 10
wenn bei 250ms)
Call WAITschnell wenn Counter >= 10
return

Wait
Lange Schleife
z.B. 10ms
return

WAITschnell
Kurze Schleife
z.B 1ms
Return

So etwa habe ich mir das vorgestellt im Ablaufplan.
Nun will ich das umsetzen in Assembler.
Konstante festlegen: Counter und Endwert
Counter und Endwert(10) am Anfang festlegen.
MOVLW 10
MOWF Endwert

Dann in UPlinks:
Endwert in w laden
MOVLW Endwert
SUBLW Counter
Sobald das Flag Z auf 0 ist ist der Endwert erreicht und das Programm soll ab dann immer in WAITschnell springen, bis im Hauptprogramm der Eingang wieder auf Null geht.
BTFSC Status,Z
call WAIT
BTFSS Status,Z
call WAITschnell
Soll so funktionieren wie das verstellen einer Digitaluhr.
Genaue Zeiten sind nicht so wichtig.
Benötige zum Fein-Einstellen etwa 1 Impuls pro Sekunde und dann für schnell max 100 Hz damit ich keine Schritte verliere.
Kann ich aber an der Hardware testen.
Das Umsetzen auf einfache Weise im Assembler ist mein Problem.
Leider gibt es wenig Codeschnipsel mit anständigen Kommentaren um das zu lernen.
Habe mehrere Tage gebraucht um das Grundprogramm zum laufen zu bringen.
Anfangs-Probleme:Falsche config.., Analoge Eingänge statt Digitale, bfc statt bfs etc.

learning by doing

Jetzt muss ich halt rausfinden wie man das umsetzt, ohne zu kompliziert zu werden.
Natürlich kann man auch Timer1 und 2 einsetzen und genaue Zeiten ausrechnen.
Da zu braucht es aber noch mehr Wissen.
Aber warum mit Kanonen auf Spatzen schießen?

MfG Bernd

PICture
16.05.2013, 14:10
Hallo!

Fürs Lernen kann's nicht schaden: https://www.roboternetz.de/wissen/index.php/PIC_Assembler . Leider kann ich dir nicht helfen, weil ich die Mnemonics vom ASM Quellcode aus unnötigem Text zu "fischen" hasse. ;)

DL4VAL
16.05.2013, 14:15
Hallo!

Fürs Lernen kann's nicht schaden: https://www.roboternetz.de/wissen/index.php/PIC_Assembler . Leider kann ich dir nicht helfen, weil ich die Mnemonics vom ASM Quellcode aus unnötigem Text zu "fischen" hasse. ;)

Hallo
Danke für den link.
Was heißt das in Satz2 auf deutsch?
Wie kann ich das anders beschreiben?
VG Bernd

PICture
16.05.2013, 14:29
Falls du "Mnemonics" meinst, sind es zugeordnete englische Namen für Maschinenbefehle (z.B. "movf", "bcf", "bsf", usw.), die als Binärzahlen für Menschen sehr unverständlich sind.

Sorry, aber ich analisiere keine Quellcoden, wenn ich sie selber nicht brauche und fange immer mit Schaltplan + Zeitdiagrammen der Signale an.

DL4VAL
16.05.2013, 19:07
OK
Sorry.
Was ich nicht verstehe.Warum Antwortest Du, wenn Du nicht helfen willst und dich die Problemstellung nicht interessiert?

Für mich war das die Frage, ob man das so umsetzen kann?

Der "unnötige Text" sollte einfach nur erklären, was es bewirken soll.
Nee, ich wollte wissen, was unter unnötigem Text zu verstehen ist.

Schaltplan ist denke ich, hier nicht so relevant.
Ein Eingang für LINKS drehen, ein Eingang für RECHTS drehen.
Ein Ausgang für DIR, Ein Ausgang für Impuls.
Signalverlauf: Beide Eingänge AUS, beide Ausgänge AUS
Eingang LINKS bis etwa 5 Sekunden ein, Ausgang DIR AUS, Ausgang Impuls EIN/AUS 50ms Takt
Eingang LINKS größer 5 Sekunden ein, Ausgang DIR AUS, Ausgang Impuls EIN/AUS 10ms Takt

Das gleiche für RECHTS.
Nur der Vollständigkeit halber.
Falls sich noch jemand findet der mir da weiterhelfen will.
Danke.

Bernd

Höflichkeit ist eine Zier, weiter kommt man ohne Ihr. :(

PICture
16.05.2013, 19:16
Was ich nicht verstehe.Warum Antwortest Du, wenn Du nicht helfen willst und dich die Problemstellung nicht interessiert?

Ich habe beantwortet, weil ich jedem helfen will. Dafür muss ich mir jedoch das Problem vorstellen können, was aber bisher leider nicht möglich war.


Schaltplan ist denke ich, hier nicht so relevant.

Ich habe nur µC Beschaltung von Ein- und Ausgängen gemeint, möchte aber darüber nicht diskutieren.

Ausserdem anstatt "learning by doing" ist "learning befor doing" sicher effizienter.

RoboHolIC
17.05.2013, 00:28
Bevor die Diskussion weiter entgleitet: Ich denke, jeder wird mit der Zeit seine eigene bevorzugte Herangehensweise an neue Dinge entwickeln - und die scheinen nicht immer kompatibel zu einander zu sein. Vielleicht lässt man das einfach so stehen.

@DL4VAL
Ich selbst bin froh, wenn ich mich nach einem halben Jahr im Source-Konzept eines abgeschlossenen Hobbyprojekts wieder zurecht finde. Bis auf wenige Detaillösungen habe ich mir allen Sourcecode meiner Projekte Schritt für Schritt selbst erarbeitet und zum funktionieren gebracht.
Diesen Weg und die damit verbundenen Erfolgserlebnisse will ich dir gar nicht ersparen bzw. vorenthalten. (Wenn du da Faulheit herausliest, würde ich das nicht mal dementieren). :)

In den angehängten Quelltext mag ich mich nicht im Detail(siehe oben) einlesen. Allerdings hab ich nach dem org 0x00 ein 'goto Init' gesehen, da würde ich immer ein 'call Init' erwarten, damit der Programmfluss auch wieder zurück kommt und dann das 'goto main' ausführt (goto ist hier möglich aber unfein). Mich wunderts, dass überhaupt was halbwegs sinnvolles passiert.

Ich schlage stattdessen vor bzw. empfehle dir:
- fang mit der Einrichtung eines Timerinterrupts an, z.B. 1ms Zyklus.(d.h. Prescaler, Timer-Config, Preloadwert setzen, PIE & GIE-Register passend machen)
- dann lass je Durchlauf eine Zählervariable inkrementieren
- werte das Bit 7 der Zählervariable aus: wenn gesetzt, dann LED einschalten, andernfalls LED ausschalten
Fertig ist eine Blinkfunktionalität (wenngleich vermutlich zu hektisch)

Dann: baue eine Delayfunktion in der ISR, die den Controller nicht für andere Aufgaben blockiert:
- wenn restzeit > 0, dann dekrementiere restzeit
- wenn restzeit == 0, dann
- invertiere den Pegel auf der Steppertreiber-Pulsleitung ; das ist der eigentliche Nutzen
- setze restzeit auf den Startwert
Fertig ist die frequenzstabile Pulserzeugung für den Steppertreiber

Wenn die Pulserzeugung klappt, kannst du die Richtungssteuerung dazubauen

Dann vielleicht die Zeitmessung für die EIN-Zeit einer Taste (wie bereits beschrieben)
und so weiter ...

Spiele mit den Möglichkeiten, sammle Erfahrung und lass das Datenblatt nicht kalt werden.

Gruß
RoboHolIC

DL4VAL
17.05.2013, 11:59
Bevor die Diskussion weiter entgleitet: Ich denke, jeder wird mit der Zeit seine eigene bevorzugte Herangehensweise an neue Dinge entwickeln - und die scheinen nicht immer kompatibel zu einander zu sein. Vielleicht lässt man das einfach so stehen.

@DL4VAL
Ich selbst bin froh, wenn ich mich nach einem halben Jahr im Source-Konzept eines abgeschlossenen Hobbyprojekts wieder zurecht finde. Bis auf wenige Detaillösungen habe ich mir allen Sourcecode meiner Projekte Schritt für Schritt selbst erarbeitet und zum funktionieren gebracht.
Diesen Weg und die damit verbundenen Erfolgserlebnisse will ich dir gar nicht ersparen bzw. vorenthalten. (Wenn du da Faulheit herausliest, würde ich das nicht mal dementieren). :)

In den angehängten Quelltext mag ich mich nicht im Detail(siehe oben) einlesen. Allerdings hab ich nach dem org 0x00 ein 'goto Init' gesehen, da würde ich immer ein 'call Init' erwarten, damit der Programmfluss auch wieder zurück kommt und dann das 'goto main' ausführt (goto ist hier möglich aber unfein). Mich wunderts, dass überhaupt was halbwegs sinnvolles passiert.

Ich schlage stattdessen vor bzw. empfehle dir:
- fang mit der Einrichtung eines Timerinterrupts an, z.B. 1ms Zyklus.(d.h. Prescaler, Timer-Config, Preloadwert setzen, PIE & GIE-Register passend machen)
- dann lass je Durchlauf eine Zählervariable inkrementieren
- werte das Bit 7 der Zählervariable aus: wenn gesetzt, dann LED einschalten, andernfalls LED ausschalten
Fertig ist eine Blinkfunktionalität (wenngleich vermutlich zu hektisch)

Dann: baue eine Delayfunktion in der ISR, die den Controller nicht für andere Aufgaben blockiert:
- wenn restzeit > 0, dann dekrementiere restzeit
- wenn restzeit == 0, dann
- invertiere den Pegel auf der Steppertreiber-Pulsleitung ; das ist der eigentliche Nutzen
- setze restzeit auf den Startwert
Fertig ist die frequenzstabile Pulserzeugung für den Steppertreiber

Wenn die Pulserzeugung klappt, kannst du die Richtungssteuerung dazubauen

Dann vielleicht die Zeitmessung für die EIN-Zeit einer Taste (wie bereits beschrieben)
und so weiter ...

Spiele mit den Möglichkeiten, sammle Erfahrung und lass das Datenblatt nicht kalt werden.

Gruß
RoboHolIC

Hallo RoboHolIC
Danke für die Antwort.
Da ich schon seit Jahren Excel-VBA beruflich programmiere, weiß ich was Du meinst.
Nur habe ich mir verschiedene Funktionen geschrieben, die ich als Baustein immer wieder einsetzen kann.
Spart natürlich Arbeit.
Irgendwann habe ich auch das "unnötige" :) Kommentieren angefangen. (Sorry, sollte jetzt keine Anspielung auf vorhergehendes sein)
Das Kommentieren habe ich Anfangs aus Faulheit auch weggelassen. Nachträglich aber eingefügt, um wieder zu verstehen was abläuft.
Ich dachte für Assembler gibt es vielleicht auch so "Bausteine" die man einsetzen kann.
Im Codesys gibt es auch vordefinierte Bausteine und xxx.lib die man verwenden kann.

Zum Lernen:
PIC`s (Assembler) sind wie alle, einem selbst neu, neuen Programmiersprachen erst mal sehr unübersichtlich.(Befehle sind nicht in Kopf)
Einfache Beispiele zum Einarbeiten habe ich bei Sprut gefunden. Ich habe stundenlang verschiedene Sachen gelesen.
Ein einfaches Beispiel mit Kommentaren, in dem nur ein Eingang digital abgefragt wird und dann z.B. eine LED an einem Ausgang AN/AUS geht habe ich nicht gefunden. "Hallo Welt" für Assembler :-)
Die Informationen mit analog/digital Eingang und das man die am Anfang (INIT) umstellen muss, konnte ich nur mühsam finden.
Wie Sprut auf seiner Seite schreibt: Er hat noch kein gutes Buch zu PIC`s gefunden. Danke an Sprut seine Seiten sind super.
Wenn das Projekt fertig ist, stelle ich den kommentierten Quelltext ein. Habe gelesen, dass viele Anfänger mit solche Problemen kämpfen.

OK, wird jetzt alles zu lang.
Meine Schaltung funktioniert jetzt ja, soweit. Habe mir auch so meine Gedanken über Lösungen der schnelleren Taktausgabe gemacht.
Verschiedene Sachen aus meiner Siemens S5 Zeit, wie Merker etc. sind mir da wieder in den Sinn gekommen.


Ich werde auch noch googeln was die ISR ist. :-)
GOTO und REM aus meiner Basiczeit, werde ich dann auch durch Call und ; ersetzen. :-) Danke.
Das mit den Timern vom 12F675 werde ich ausprobieren, wenn das Teil über die Verzögerungs-Schleifen läuft.
Schön das man einen PIC mehrmals brennen kann.

Dann Danke mal vorerst.

Gruß Bernd

RoboHolIC
17.05.2013, 22:35
Dazu wird bei jedem Durchlauf der ISR (Interrupt Service Routine)ein Zähler um eins erhöht

PIC-typische Abkürzungen im Zusammenhang mit Interrupts:
IRQ = Interrupt Request = eine Anforderung zur Programmunterbrechung aufgrund eines Ereignisses, z.B. Timerüberlauf, externes Triggersignal am INT-Eingang, ...
ISR = Interrupt Service Routine = der Programmteil, der die angemessene Reaktion auf das jeweilige Ereignis bewirkt
xxxIF = Interrupt Flag = ein ereignisanzeigendes Signalbit, aufgrund dessen eine ISR gestartet wird, kann meist auch ohne Interruptfreigabe vom Hauptprogramm gelesen werden
GIE = Global Interrupt Enable = der Hauptschalter
PIE = Peripheral Interrupt Enable = je Bit eine Freischaltung eines Hardwareinterrupts (UART, Timer, I2C, INT-Eingang ...)

Zur Ersetzung des GOTO:

GOTO und REM aus meiner Basiczeit, werde ich dann auch durch Call und ; ersetzen.
GOTO braucht's bei den PICs fast an jeder Ecke für Verzweigungen; das Äquivalent zu CALL ( ) wäre GOSUB. Ich will das vorsichtshalber erwähnen, weil ich aus deinem letzten Posting eine Verdrehung diesbezüglich herausgelesen hatte. Nichts für ungut.

Ja, dass Kommentare wichtig sind, wird selten angezweifelt, keine Frage; die Geister scheiden sich gelegentlich am WIE.
Vielleicht hättest du mit meiner Art des Kommentierens und der vertikalen Gliederung der Sourcedateien ebenfalls Lesbarkeitsprobleme wie ich mit deiner beigefügten Datei; das ist auch eine Frage der Gewohnheit und daher (meist) kein Gegenstand für Kritik.

Zuletzt noch eine Sourcedatei von mir zur direkten Ansteuerung einer doppelten Vollbrücke (für einen (1) Schrittmotor) zum ankucken und evtl. abkupfern von Timer, Int. & Co.
Leider ist das unaufgeräumte Source aus einer ad hoc-Anpassung von bestehendem Code. Da sind noch einige Überbleibsel drin, aber es ist der assemblierfähige Code:



; ToDo:
; =====
; -
; -
; -
;
;
;************************************************* *********************
; *
; Filename: VORZRUCK.asm *
; Date: *
; File Version: *
; *
; Author: Christian *
; Company: *
; *
; *
;************************************************* *********************
; *
; Files Required: P16F876A.INC *
; *
;************************************************* *********************
; *
; Hardwarekonfiguration: *
; -- kein (!) LCD *
; -- 1x Taste f�r Steuereingriffe *
; -- 1x Diagnose-LED *
; -- 2x digitale Eing�nge: Referenz-/Endschalter beider Achsen *
; -- 1x analoger Eingang: CNY70 o.�. zur Pseudo-Wanderkennung *
; -- 2x je 4 digitale Ausg�nge: Schrittmotoransteuerung *
; -- 1x Schaltausgang: Stiftabsenkung *
; *
;************************************************* *********************


list p=16f876a ; list directive to define processor
#include <P16F876A.INC> ; processor specific variable definitions

__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC
; ACHTUNG: Ein 4MHz- oder 10MHz-Oszillator mit _LP_OSC-Config-Bits l�uft nicht an !!!

;************************************************* ****************************
; '__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.
;************************************************* ****************************



; STATUS-Bits
#define _C STATUS,0 ; f�r die Kurzschreibung von Bitpr�fungen: "BTFSS _C"
#define _Z STATUS,2 ;


; Hardware-Signale
#define LED buf_rc,0 ; Diagnose-LED
#define PENDWN buf_rc,7 ; Stiftabsenkung

#define SWX sta_rc,6 ; Endschalter X-Achse
#define SWY sta_rc,5 ; Endschalter Y-Achse
#define KEY sta_rc,1 ; Steuertaste


; Flag-Bits
#define DRIGGD flax,0 ; =1: fraenk. fuer "Taste betaetigt"
#define BUMPED flax,1 ; =1: an die Wand gesto�en
#define DIR_FWD flax,2 ; =1: vorw�rts bewegen
#define DIR_REV flax,3 ; =1: r�ckw�rts bewegen



;***** KONSTANTEN

;numerische Konstanten
SACHT EQU d'2' ; Motorschritte nach jeweils (SACHT*1ms)
LIMDUNK EQU d'180' ; unterhalb Kollisionsbit setzen
LIMHELL EQU d'200' ; oberhalb Kollisionsbit l�schen



;***** BANK(0)-EXKLUSIVE REGISTER 0x20..0x6F

;== 0x20 ===
scr1 EQU 0x20 ; Scratch-Bytes f�r Subroutinen
scr2 EQU 0x21 ;
scr3 EQU 0x22 ;
scr4 EQU 0x23 ;
par0 EQU 0x24 ; Ersatz f�r Stack-Parameter�bergabe
par1 EQU 0x25 ;
par2 EQU 0x26 ;
flax EQU 0x27 ; diverse Flags
x28 EQU 0x28 ;
x29 EQU 0x29 ;
restweg EQU 0x2A ; verbleibender Verfahrweg in Halbschritten
x2b EQU 0x2B ;
x2c EQU 0x2C ;
slowpe EQU 0x2D ;
indexx EQU 0x2E ; 2 Zeiger auf die Bitmuster-Arrays
indexy EQU 0x2F ; zur Stepper-Ansteuerung

;== 0x30 ===
x30 EQU 0x30 ;
x31 EQU 0x31 ;
x32 EQU 0x32 ;
x33 EQU 0x33 ;
x34 EQU 0x34 ;
x35 EQU 0x35 ;
x36 EQU 0x36 ;
x37 EQU 0x37 ;
x38 EQU 0x38 ;
x39 EQU 0x39 ;
x3a EQU 0x3A ;
x3b EQU 0x3B ;
x3c EQU 0x3C ;
x3d EQU 0x3D ;
x3e EQU 0x3E ;
x3f EQU 0x3F ;

;== 0x40 ===
;x40 EQU 0x40 ;
; hier kommen zwei Arrays zu je 8 Byte f�r die Ansteuerung der Stepper
; sie werden sp�ter mit den ben�tigten Bitmustern bef�llt
pattx1 EQU 0x40 ; BASIS: Array[8] der X-Pattern
pattx2 EQU 0x41 ; Ansteuerungssequenz X-Achse
pattx3 EQU 0x42 ; bis ...
pattx4 EQU 0x43 ; ...
pattx5 EQU 0x44 ; ...
pattx6 EQU 0x45 ; ...
pattx7 EQU 0x46 ; ...
pattx8 EQU 0x47 ; ... hierher !
patty1 EQU 0x48 ; BASIS: Array[8] der Y-Pattern
patty2 EQU 0x49 ; Ansteuerungssequenz Y-Achse
patty3 EQU 0x4A ; bis ...
patty4 EQU 0x4B ; ...
patty5 EQU 0x4C ; ...
patty6 EQU 0x4D ; ...
patty7 EQU 0x4E ; ...
patty8 EQU 0x4F ; ... hierher !

;== 0x50 ===
x50 EQU 0x50 ;
x51 EQU 0x51 ;
x52 EQU 0x52 ;
x53 EQU 0x53 ;
x54 EQU 0x54 ;
x55 EQU 0x55 ;
x56 EQU 0x56 ;
x57 EQU 0x57 ;
x58 EQU 0x58 ;
x59 EQU 0x59 ;
x5a EQU 0x5A ;
x5b EQU 0x5B ;
x5c EQU 0x5C ;
x5d EQU 0x5D ;
x5e EQU 0x5E ;
x5f EQU 0x5F ;


;== 0x60 ===
buf_rb EQU 0x60 ; PORTB-Pufferregister gegen die read-modify-write-Falle
buf_rc EQU 0x61 ; dito Port C
sta_rc EQU 0x62 ; Binärstatus von Port C
val_wall EQU 0x63 ; Meßwert des Wandsensors
x64 EQU 0x64 ;
x65 EQU 0x65 ;
x66 EQU 0x66 ;
x67 EQU 0x67 ;
x68 EQU 0x68 ;
x69 EQU 0x69 ;
x6a EQU 0x6A ;
iscr EQU 0x6B ; scratch in der ISR
x6c EQU 0x6C ;
x6d EQU 0x6D ;
x6e EQU 0x6E ;
x6f EQU 0x6F ;

;***** BANK(1)-EXKLUSIVE REGISTER 0xA0..0xEF
;== 0xA0 ===
;== 0xB0 ===
;== 0xC0 ===
;== 0xD0 ===
;== 0xE0 ===

;***** BANK(2)-EXKLUSIVE REGISTER 0x110..0x11F (Nische)
;== 0x110 ===

;***** BANK(2)-EXKLUSIVE REGISTER 0x120..0x16F
;== 0x120 ===
;== 0x130 ===
;== 0x140 ===
;== 0x150 ===
;== 0x160 ===


;***** BANK(3)-EXKLUSIVE REGISTER 0x190..0x19F (Nische)
;== 0x190 ===

;***** BANK(3)-EXKLUSIVE REGISTER 0x1A0..0x1EF
;== 0x1A0 ===
;== 0x1B0 ===
;== 0x1C0 ===
;== 0x1D0 ===
;== 0x1E0 ===

;***** GLOBALE VARIABLEN 0x70..0x7F
x70 EQU 0x70 ;
x71 EQU 0x71 ;
x72 EQU 0x72 ;
x73 EQU 0x73 ;
x74 EQU 0x74 ;
x75 EQU 0x75 ;
x76 EQU 0x76 ;
x77 EQU 0x77 ;
x78 EQU 0x78 ;
dlycnt EQU 0x79 ; Delay-Restzyklen zu je 1ms
ticker EQU 0x7A ; virtuelle Unruh; immerzu in Bewegung
hitick EQU 0x7B ; �berlaufz�hler f�r ticker
temp_w EQU 0x7C ; variable used for context saving
temp_status EQU 0x7D ; variable used for context saving
temp_pclath EQU 0x7E ; variable used for context saving
temp_fsr EQU 0x7F ; variable used for context saving








;************************************************* *********************
;************************************************* *********************
ORG 0x0000 ; Begin of 2k-Code Page #0 (1st)
; processor reset vector
;************************************************* *********************
;************************************************* *********************

nop ; nop required for icd
goto MAIN ; go to beginning of program
nop
nop















;************************************************* *********************
;************************************************* *********************
ORG 0x0004 ; interrupt vector location
;************************************************* *********************
;************************************************* *********************


;********** Kontext sichern **********
movwf temp_w ; save off current W register contents
movf STATUS,w ; move status register into W register
movwf temp_status ; save off contents of STATUS register
movf PCLATH,w ; move pclath register into w register
movwf temp_pclath ; save off contents of PCLATH register
movf FSR,w ;
movwf temp_fsr ;

; Lead-In
;bcf INTCON,GIE ; globales IRQ-Disable ;;; das geschieht schon automatisch bei der IRQ response
bcf STATUS,RP0 ;
bcf STATUS,RP1 ; Bank 0 als default
bcf PCLATH,4 ;
bcf PCLATH,3 ; Code Page #0


;********** ISR f�r den Timer0-Interrupt
ISR_TMR0
; IRQ-flag l�schen und preload
bcf INTCON,T0IF ; Timer0-IRQ
movlw d'8' ; 256-(250-2!) = 8 f�r 1000,0 Hz @ 4,00MHz !!! DIESEN WERT AUCH BEIM INIT SETZEN !!!
movwf TMR0 ; preload = verk�rzter Anlauf zum n�chsten �berlauf-IRQ

;ADC auslesen und speichern
ISR_ADC_1
; warten, dann ablesen
btfsc ADCON0,GO_DONE ; Wandlung fertig?
goto ISR_ADC_1 ; nein!
movf ADRESH,w ;
movwf val_wall ;

; A/D-Wandlung starten
bsf ADCON0,GO_DONE ; den ca. 1ms lange gesampleten Kanal jetzt wandeln

; Eing�nge lesen
movf PORTC,w ;
movwf sta_rc ; Port C in Abbildvariable einlesen


ISR_TMR0_1
; Millisekunden-Eieruhr
movf dlycnt,f ; Z-Flag generieren
btfss _Z ;
decf dlycnt,f ; dekr., wenn nicht null (Z=0)

; Millisekunden-Ticker (= virtuelle Unruh)
incf ticker,f ;

; langsamer Ticker (quasi: HighByte)
movf ticker,w ;
btfsc _Z ; = 0, d.h. �berlauf?
incf hitick,f ;


ISR_FLASH
; LED ansteuern
bcf LED ;
btfsc hitick,0 ;
bsf LED ;


ISR_BUMP
movlw LIMDUNK ; eindeutig keine Reflexion
subwf val_wall,w ;
btfss _C ;
bsf BUMPED ; ja !

movlw LIMHELL ; eindeutige Reflexion
subwf val_wall,w ;
btfsc _C ;
bcf BUMPED ; ja!


ISR_STEP

ISR_STEP_1
movf restweg
btfsc _Z ; kein Restweg
goto ISR_STEP_END ; ... daher �berspringen
decfsz slowpe,f ; Schrittfreq. auf 1000Hz/SACHT verlangsamen
goto ISR_STEP_END ; noch nicht null, daher �berspringen
; Schritt ausf�hren
btfsc DIR_FWD ; Unterscheidung der Bewegungsrichtung
; btfss BUMPED ; Unterscheidung der Bewegungsrichtung
incf indexx,f ; anhand der Richtungsflags.
; btfsc BUMPED ; Unterscheidung der Bewegungsrichtung
btfsc DIR_REV ; Auch Stillstand ist m�glich!
decf indexx,f ;
ISR_STEP_2
movlw b'00000111' ; Indizes normieren auf Wertebereich 0..7 (Bits 2..0)
andwf indexx,f ;
clrf buf_rb ; tabula rasa

movlw pattx1 ; Basisadresse (literal, d.h. Speicherstelle) der x-Pattern
addwf indexx,w ; plus Offset
movwf FSR ;
movf INDF,w ; Bitmuster, indirekt adressiert
iorwf buf_rb,f ; Bits in Puffer einpr�gen


ISR_STEP_TAIL
; Nacharbeiten nach einem Schritt
decf restweg,f
movlw SACHT ;
; movf val_wall,f
movwf slowpe ; Verz�g.zeit neu starten


ISR_STEP_END






; Hier sollten alle Pins f�r die aktuelle Runde ermittelt sein, daher ...


;Ausgabe-Puffervariablen an die Ausgangspins des Chips durchreichen
movf buf_rb,w ;
movwf PORTB ; PORTB-bits auf die Ausg�nge
movf buf_rc,w ;
movwf PORTC ; PORTC-bits auf die Ausg�nge




; !!!! AB HIER NICHT MEHR AUF DIE PORTS SCHREIBEN !!!!





ISR_RESTORE
; Kontext wiederherstellen
movf temp_fsr,w ;
movwf FSR ;
movf temp_pclath,w ; retrieve copy of PCLATH register
movwf PCLATH ; restore pre-isr PCLATH register contents
movf temp_status,w ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf temp_w,f ; Kniff, um W zu laden, ohne den Status zu verändern !
swapf temp_w,w ; restore pre-isr W register contents

retfie ; return from interrupt (impliziert ein "bsf INTCON,GIE")




















;************************************************* *********************
MAIN ; Das Hauptprogramm
;************************************************* *********************

; banksel <labelname> ; das ist die MAKRO-Sytax
; pagesel <labelname> ; das ist die MAKRO-Sytax
; pageselw <labelname> ; das ist die MAKRO-Sytax


clrf INTCON ; alle Interruptquellen sperren, alle IRQs verwerfen
clrf PORTA ;
clrf PORTB ;
clrf PORTC ;


; I/O-Leitungen konfigurieren
bsf STATUS,RP0 ; Bank 1
movlw b'11111111' ; 5..1: (noch Analog-)Eing�nge
movwf TRISA ;
movlw b'00000000' ; 7..0: 2x4 Ausg�nge f�r Stepper
movwf TRISB ;
movlw b'01100010' ; 7: Stiftabsenkung out; 6,5: Endschalter in;
movwf TRISC ; 1: Taste in 0: LED out. Rest OUT gegen floatende Inputs
bcf STATUS,RP0 ; Bank 0


; ADC konfigurieren
bsf STATUS,RP0 ; Bank 1
bcf ADCON1,ADFM ; 0= left justified
bsf ADCON1,ADCS2 ; 1= clock select -> 1/64 erm�glichen

bcf ADCON1,PCFG3 ; (1110: nur AN0, ratiometrisch zu Vdd,Vss; Rest digital)
bcf ADCON1,PCFG2 ; (011x: alles dig. I/O)
bcf ADCON1,PCFG1 ; 0000: alles analoge Inputs, ratiometrisch zu Vdd,Vss
bcf ADCON1,PCFG0 ;

bcf STATUS,RP0 ; Bank 0

bsf ADCON0,ADCS1 ; 10bin= clock select -> 1/64 erm�glichen
bcf ADCON0,ADCS0 ;
bsf ADCON0,ADON ; ADC einschalten

; Timer0 konfigurieren
bsf STATUS,RP0 ; Bank 1
clrwdt ; WDT-Register und implizit Prescaler l�schen, das geh�rt sich so!
movlw b'10000001' ; int sys clk, 1:4, prescale assg. to TMR0
movwf OPTION_REG ;
bcf STATUS,RP0 ; Bank 0
movlw d'8' ; Presetwert vgl. Timer0-ISR
movwf TMR0 ;




; Startzust�nde herstellen
clrf indexx
clrf indexy
movlw d'0' ;
movwf ticker ;
movwf hitick ;
movwf buf_rb ;
movwf PORTB ; I/O-Leitungen
movwf buf_rc ;
movwf PORTC ; I/O-Leitungen
movwf flax ; acht Flag-Bits


movlw b'01100010' ; die Einsen sind die low-aktiven Eing�nge (Taster)
movwf sta_rc ;

movlw SACHT ; Teilungsfaktor f_irq --> f_step
movwf slowpe ;

movlw b'00001010' ; Ansteuerpattern x-Achse
movwf pattx1 ; acht Zust�nde wegen Halbschrittbetrieb
movlw b'00000010' ; f� das LOW-Nibble des Portbytes
movwf pattx2 ;
movlw b'00000110' ;
movwf pattx3 ;
movlw b'00000100' ;
movwf pattx4 ;
movlw b'00000101' ;
movwf pattx5 ;
movlw b'00000001' ;
movwf pattx6 ;
movlw b'00001001' ;
movwf pattx7 ;
movlw b'00001000' ;
movwf pattx8 ;


bsf STATUS,RP0 ; Bank 1
clrf PIE1 ;
clrf PIE2 ;
bcf STATUS,RP0 ; Bank 0
clrf PIR1 ;
clrf PIR2 ;
clrf INTCON ; alle Quellen und IRQs disablen/r�cksetzen



; Anlaufsperre via "Reset"-Taste.
; F�r Entwicklungszwecke ab und an recht hilfreich,
; nicht aber f�r die primitive Funktionalit�t des Schlittens im Alltagsbetrieb
KLINKE
; btfsc PORTC,1
; goto KLINKE





; Interrupts enablen bzw. in Gang setzen
bsf INTCON,T0IE ; Timer 0 enable
;bcf INTCON,T0IE ; Timer 0 disable
bsf INTCON,PEIE ; Gruppe der Peripherals
bsf INTCON,GIE ; globales Enable





; das "eigentliche Hauptprogramm"



;Referenzpunkt (Endschalter) anfahren
; pagesel REFERENZ
; call REFERENZ



; und hier endlich die Hauptprogrammschleife

LOOOP ; die Schleife �ber alles

pagesel FAHRPROG
call FAHRPROG


pagesel LOOOP ;
goto LOOOP ;






;************************************************* *********************
P0_IDLE
; Prinzip: "Jeder Code Page ihre eigene Bummelfunktion"
; wartet stur, bis die ISR den Z�hler dlycnt bis Null heruntergez�hlt hat
movwf dlycnt ; Delayzeit wird im W-Register geliefert
P0_IDLE_1
movf dlycnt,f ; zero flag generieren
btfss _Z ; bei Z=1 ausbrechen
goto P0_IDLE_1 ;

return ;

;************************************************* *********************
FAHRPROG

; Hinweg
bcf DIR_REV
bsf DIR_FWD
movlw d'240'
movwf restweg

FAHRPROG_1
movf restweg
btfss _Z
goto FAHRPROG_1 ; so lange noch Restweg vorhanden ist

movlw d'240'
movwf restweg

FAHRPROG_2
movf restweg
btfss _Z
goto FAHRPROG_2 ; so lange noch Restweg vorhanden ist

; R�ckweg

bcf DIR_FWD
bsf DIR_REV
movlw d'240'
movwf restweg

FAHRPROG_3
movf restweg
btfss _Z
goto FAHRPROG_3 ; so lange noch Restweg vorhanden ist

movlw d'240'
movwf restweg

FAHRPROG_4
movf restweg
btfss _Z
goto FAHRPROG_4 ; so lange noch Restweg vorhanden ist


return

;************************************************* *********************
;************************************************* *********************
ORG 0x0800 ; Begin of 2k-Code Page #1 (2nd)
;************************************************* *********************
;************************************************* *********************

P1_IDLE
; Prinzip: "Jeder Code Page ihre eigene Bummelfunktion"
; wartet stur, bis die ISR den Z�hler dlycnt bis Null heruntergez�hlt hat
movwf dlycnt ; Delayzeit wird im W-Register geliefert
P1_IDLE_1
movf dlycnt,f ; zero flag generieren
btfss _Z ; bei Z=1 ausbrechen
goto P1_IDLE_1 ;

return ;

;************************************************* *********************
;************************************************* *********************
ORG 0x1000 ; Begin of 2k-Code Page #2 (3rd)
;************************************************* *********************
;************************************************* *********************

P2_IDLE
; Prinzip: "Jeder Code Page ihre eigene Bummelfunktion"
; wartet stur, bis die ISR den Z�hler dlycnt bis Null heruntergez�hlt hat
movwf dlycnt ; Delayzeit wird im W-Register geliefert
P2_IDLE_1
movf dlycnt,f ; zero flag generieren
btfss _Z ; bei Z=1 ausbrechen
goto P2_IDLE_1 ;

return ;

;************************************************* *********************
;************************************************* *********************
ORG 0x1800 ; Begin of 2k-Code Page #3 (4th)
;************************************************* *********************
;************************************************* *********************

P3_IDLE
; Prinzip: "Jeder Code Page ihre eigene Bummelfunktion"
; wartet stur, bis die ISR den Zhler dlycnt bis Null heruntergezhlt hat
movwf dlycnt ; Delayzeit wird im W-Register geliefert
P3_IDLE_1
movf dlycnt,f ; zero flag generieren
btfss _Z ; bei Z=1 ausbrechen
goto P3_IDLE_1 ;

return ;

;************************************************* *********************
;************************************************* *********************
END ; directive 'end of program'
;************************************************* *********************
;************************************************* *********************



Gruß
Christian.

oberallgeier
18.05.2013, 16:35
Hallo Bernd,

so etwas Ähnliches mache ich manchmal - oft auch ohne Timer.
... Wenn Taste gedrückt call UP1, wenn Taste lange gedrückt call UP2 ...Mein Vorschlag zu einer einfachen Lösung geht anders. Du holst ja die Information über die gedrückte Taste irgendwo ab. WENN Taste gedrückt, dann inkrementiere Tastenzählerstand . . . wenn nicht gedrückt, dann nicht inkrementieren - so etwas Ähnliches vermute ich auch bei Dir. Nun eine Erweiterung: wenn Taste gedrückt, inkrementiere eine zweite Variable - wenn Taste nicht gedrückt, dann setze diese Variable auf Null. WENN diese zweite Variable z.B. den Wert zehn oder zwanzig oder so übersteigt, dann inkrementiere Deine Schrittmotor-Verfahrweg-Routine eben statt um eins um ein Vielfaches: zehn, zwanzig oder so. Ne weitere Lösungsmöglichkeit besteht in einer progressiven Steigerung: Schrittmotor immer um so viel schneller weiter stellen, wie gerade Tastatur-Druck-Vorgänge AKTUELL gezählt wurden. Taste lösen führt immer zum Nullen dieses Progressiv-Zählers.

Ist grad ein bisschen wirr beschrieben sehe ich, aber ich glaube, Du weißt was ich meine.

Natürlich geht die Geschichte mit nem Timer eleganter . . .

DL4VAL
19.05.2013, 18:53
Danke Christian
Das sehe ich mir mal in Ruhe an.
Danke nochmals für den Tipp mit GOTO.
Das hat an anderer Stelle einen Fehler verursacht, dass der PIC gerade das gemacht hat, was ich Ihm gesagt habe: Wirres Zeug.:)
Hat keinen richtigen Ablauf mehr gegeben und der PIC hat sich undefiniert aufgehängt.
Gruß Bernd

- - - Aktualisiert - - -

Hallo oberallgeier
Danke für Deinen Vorschlag.
Habe das gestern etwa so gelöst, wie Du es beschrieben hast.(Hast sich für mich schlüssig gelesen :-) )
Taste losgelassen: Alle Variablen auf Start (ini)
Taste gedrückt:Steuere UP für langsames blinken an und vermindere bei jedem Durchlauf eine Variabel (Endwert)
Ist das ganze 10 mal Durchgelaufen, hat der Ausgang ja 10 langsame Impulse zum Feineinstellen gemacht.
(lasse ich die Taste zwischendurch, los beginnt das aufs neue)
Ist der Zähler auf NULL, dann springt der PIC in UP für schnelles Blinken und setzt dort einen Merker
damit das Teil weiß, dass es schon in UPschnell war und weiter dort arbeiten soll.
Das ist für meine Anwendung ausreichend. Wenn jetzt die Endschalter der Drehkondensators kommen wie DIR umgedreht,
FERTISCH. :)

Jetzt werde ich das ganze noch etwas übersichtlicher gestalten.
Habe das funktionierende Programm mal eingestellt.
Ab und an blinkt noch ohne Tastendruck die Impuls-LED auf.
Weiß aber nicht ob das vom Programm oder der Beschaltung des PIC kommt.
Habe die Eingänge mit 100nF auf Masse gelegt, aber kommt immer noch ab und an.
Falls noch einer drüber guckt und eine Verbesserung/Fehler findet, wäre nett mir eine Info zukommen zu lassen.
Danke.
Gruß Bernd



;************************************************* *********************
; *
; Filename: Impulsgeber_Neu.asm *
; Date: 11.05.2013 *
; File Version: 001 *
; *
; Author: Bernd Kunz *
; Company: private *
; *
; *
;************************************************* *********************
; *
; Files Required: P12F675.INC *
; *
;************************************************* *********************
; *
; Notes: Schrittmotor drehen mit Impulsen *
; Richtungssignal für links oder rechts Drehen. *
; Endschalter beendet Drehung am Ende des Verfahrweges *
; Halten des Tasters erhöht die Drehgeschindigkeit *
; Einsatz am Drehkondensator einer Magnetic-Loop *
;************************************************* *********************
;************************************************* *********************
;* Pinbelegung *
;* ---------------------------------- *
;* GP: 0 < ein links drehen *
;* 1 < ein rechts drehen *
;* 2 < ein linker Endschalter *
;* 3 < ein rechter Endschalter *
;* 4 > Ausgang Impulse *
;* 5 > Ausgang Richtungssignal *
;* *
;************************************************* *********************
list p=12f675 ; list directive to define processor
#include <p12f675.inc> ; processor specific variable definitions

errorlevel -302 ; suppress message 302 from list file

__CONFIG _MCLRE_OFF & _PWRTE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _BODEN_OFF
;******************************Wichtig************ *************************************

; Variablennamen vergeben
CBLOCK 0x20
w_temp ;variable used for context saving
status_temp ;variable used for context saving
loops ;Zähler für Warteschleife
loops2 ;Zähler für Warteschleife
Endwert ;Wieviele Impulse vergehen bis auf schnelle Warteschleife umgeschaltet wird.
Merker ;Endwert erreicht
Endwert2 ;Wieviele Impulse vergehen bis auf schnelle Warteschleife umgeschaltet wird.
Merker2 ;Endwert erreicht
links1gesetzt
rechts1gesetzt
ENDC


;************************************************* **********************
org 0x00
call Init
goto main ; go to beginning of program
org 0x4
goto main

;************************************************* **********************
; Initialisierung
Init
; IO-Pins
bcf STATUS, RP0 ; Bank 0 Im Register Status wird was? auf 0 gesetzt !!!!Umschaltung auf Bank 1
clrf GPIO ; aus! CLRF GPIO ;In das Register GPIO wird 0 geschrieben
movlw b'00111111' ;Set GP<5:0> to digital IO !!!!!!!WICHTIG!!!!!!! Digital setzen nicht analog
movwf CMCON ; Comparator aus CMCON — COMPARATOR CONTROL REGISTER setzen
;Ab hier die Aus- und Eingänge setzen.
bsf STATUS, RP0 ; Bank 1
clrf ANSEL ;Digital I/O
movlw b'00001111' ;Setze GP<3:2:1:0> als Eingang und setze GP<5:4> ist Ausgang
movwf TRISIO ;movwf TRISIO ;Schreibe das Trioregister mit den Werten
;Endwert setzen je höher um so länger wird gewartet bis es schneller geht
MOVLW 0xA ;Lade Wert dezimal 10 in W
MOVWF Endwert ;Lade W in Variable Endwert
MOVLW 0 ;Merker mit 0 intialisieren
MOVWF Merker ;Lade W in Variable Merker
MOVLW 0
MOVWF links1gesetzt
;************************************************
MOVLW 0xA ;Lade Wert dezimal 10 in W
MOVWF Endwert2 ;Lade W in Variable Endwert2
MOVLW 0 ;Merker mit 0 intialisieren
MOVWF Merker2 ;Lade W in Variable Merker2
MOVLW 10
MOVWF rechts1gesetzt

bcf STATUS, RP0 ; Bank0
; ; internen Taktgenerator kalibrieren
; bsf STATUS, RP0 ; Bank 1
; call 0x3FF
; movwf OSCCAL ; 4-MHz-Kalibrierung
; bcf STATUS, RP0 ; Bank 0
; Interrupt
bcf INTCON, GIE ; Int deaktiviert


; *****************************Unterprogramme******* ********************

prüfen ;Wie lange wurde die Taste gedrückt?
DECFSZ Endwert,f ;Endwert ist Anfangs mit 10 geladen subtrahiere 1
;Falls das 0 ergibt, dann ignoriere den nachfolgenden Befehl
INCF Merker,f ;Erhöhe Merker um 1 wenn Endwert nicht auf 0 ist
DECFSZ Merker,f ;Verringere den Wert von Merker um 1. Falls das 0 ergibt, dann ignoriere den nachfolgenden Befehl
call links1 ;Solange der Endwert zwischen 1 und 10 ist ist der Merker auf 0, Wenn der Merker auf 0 ist gehe links
;Springe da hin und nicht wie mit call wieder zurück
DECFSZ links1gesetzt,f
call links
;Hier muß eine initlinks hin Endwert auf 1 und Merker auf 0 damit das schnelle bleibt
return


inilinks ;********************************Rücksetzen wenn Eingang GPIO0 auf 0 geht*****************************
MOVLW 0xA ;Lade Wert dezimal 10 in W
MOVWF Endwert ;Lade W in Variable Endwert

MOVLW 0 ;Merker mit 0 intialisieren
MOVWF Merker ;Lade W in Variable Merker

MOVLW 0
MOVWF links1gesetzt
;BTFSC GPIO,0
;call links
return

inirechts ;********************************Rücksetzen wenn Eingang GPIO0 auf 0 geht*****************************
MOVLW 0xA ;Lade Wert dezimal 10 in W
MOVWF Endwert2 ;Lade W in Variable Endwert

MOVLW 0 ;Merker mit 0 intialisieren
MOVWF Merker2 ;Lade W in Variable Merker
MOVLW 0
MOVWF rechts1gesetzt
;BTFSC GPIO,0
;call links
return

prüfenrechts ;Wie lange wurde die Taste gedrückt?
DECFSZ Endwert2,1 ;Endwert ist Anfangs mit 10 geladen subtrahiere 1
;Falls das 0 ergibt, dann ignoriere den nachfolgenden Befehl
INCF Merker2,f ;Erhöhe Merker um 1 wenn Endwert nicht auf 0 ist
DECFSZ Merker2,1 ;Verringere den Wert von Merker um 1. Falls das 0 ergibt, dann ignoriere den nachfolgenden Befehl
call rechts1 ;Solange der Endwert zwischen 1 und 10 ist ist der Merker auf 0, Wenn der Merker auf 0 ist gehe links
;Springe da hin und nicht wie mit call wieder zurück
DECFSZ rechts1gesetzt,f
call rechts
;Hier muß eine initlinks hin Endwert auf 1 und Merker auf 0 damit das schnelle bleibt
return






; DECFSZ Verringere den Wert aus der Speicherzelle f um 1. Falls das 0 ergibt, dann ignoriere den nachfolgenden Befehl.
; Syntax: DECFSZ f,d
; Bedeutung: wenn d=0:
; Vom Wert in f wird 1 abgezogen, und das Ergebnis in W gespeichert.

; wenn d=1:
; Vom Wert in f wird 1 abgezogen, und das Ergebnis wieder in f gespeichert.

; Ist das Ergebnis der Subtraktion Null, dann wird der nächste Befehl im Programm übersprungen, und mit dem übernächsten weitergebacht.
; Beispiel: DECFSZ 0x20,1 ; Der Inhalt der Speicherzelle mit
; der Adresse 20h wird um 1 erniedrigt



links1 ;Schnelle Impulse
MOVLW 1 ;Lade Wert dezimal 1 in W Läd immer wieder Endwert mit 1 Um wieder hierhin zu springen.
MOVWF Endwert ;Lade W in Variable Endwert
MOVLW 0 ;Merker mit 0 intialisieren
MOVWF Merker ;Lade W in Variable Merker


bsf GPIO,5 ;PIN 5 ist auf Masse Richtungssignal
BTFSC GPIO,2 ;Endschalter abfragen (Wenn Eingang auf Masse dann übergehen)
bcf GPIO,5 ;PIN 5 ist auf PLUS, (Richtungssignal umkehren, wenn der Endschalter kommt)
;*******************
bsf GPIO,4 ; LED an
call warten1 ; 250 ms warten
bcf GPIO,4 ; LED aus
call warten1 ; 250 ms warten
MOVLW 1
MOVWF links1gesetzt
return

links ; langsame Impulse und Richtung links ein/aus-schalten
bsf GPIO,5 ;PIN 5 ist auf Masse Richtungssignal
BTFSC GPIO,2 ;Endschalter abfragen (Wenn Eingang auf Masse dann übergehen)
bcf GPIO,5 ;PIN 5 ist auf PLUS, (Richtungssignal umkehren, wenn der Endschalter kommt)
;*******************
bsf GPIO,4 ; LED an
call warten ; 250 ms warten
bcf GPIO,4 ; LED aus
call warten ; 250 ms warten
return

;************************************************* *********************
;Schnelle Impulse und Richtung rechts ein/aus-schalten
rechts1
MOVLW 1 ;Lade Wert dezimal 1 in W Läd immer wieder Endwert mit 1 Um wieder hierhin zu springen.
MOVWF Endwert2 ;Lade W in Variable Endwert
MOVLW 0 ;Merker mit 0 intialisieren
MOVWF Merker2 ;Lade W in Variable Merker

bcf GPIO,5 ;PIN 5 ist auf PLUS Richtungssignal
BTFSC GPIO,3 ;Endschalter abfragen (Wenn Eingang auf Masse dann übergehen)
bsf GPIO,5 ;PIN 5 ist auf Masse (Richtungssignal umkehren, wenn der Endschalter kommt)
;*****************
bsf GPIO,4 ; LED an
call warten1 ; 250 ms warten
bcf GPIO,4 ; LED aus
call warten1 ; 250 ms warten
;*****************
MOVLW 1
MOVWF rechts1gesetzt
return

rechts ;Langsame Impulse
bcf GPIO,5 ;PIN 5 ist auf PLUS Richtungssignal
BTFSC GPIO,3 ;Endschalter abfragen (Wenn Eingang auf Masse dann übergehen)
bsf GPIO,5 ;PIN 5 ist auf Masse (Richtungssignal umkehren, wenn der Endschalter kommt)
;*****************
bsf GPIO,4 ; LED an
call warten ; 250 ms warten
bcf GPIO,4 ; LED aus
call warten ; 250 ms warten
;*****************
return

;*****************************Neue Warteschleifen************************************ *********
warten1
;schnell
;************************************************* ***********
; Warteschleife 10 ms
movlw D'10' ; 100 ms Pause
movwf loops
goto Wai

warten
; Langsam
;************************************************* ********
; Warteschleife 250 ms
; Wait250
movlw D'250' ; 250 ms Pause
movwf loops
goto Wai

;************************************************* ********
Wai
movlw .110 ;Zeitkonstante für 1ms
movwf loops2 ;inizialisieren von loops2
Wai2 nop
nop
nop
nop
nop
nop
decfsz loops2, F ; 1 ms vorbei?
goto Wai2 ; nein, noch nicht
;
decfsz loops, F ; 250 ms vorbei?
goto Wai ; nein, noch nicht
retlw 0 ; das Warten hat ein Ende

;************************************************* ************************
;Hauptprogramm
main
; call 0x3FF ; retrieve factory calibration value
; bsf STATUS,RP0 ; set file register bank to 1
; movwf OSCCAL ; update register with factory cal value
; bcf STATUS,RP0 ; set file register bank to 0

; bcf GPIO,4 ;Erst mal alles Ausschalten
; bcf GPIO,5 ;Erst mal alles Ausschalten
clrf GPIO

BTFSC GPIO,2 ;Endschalter abfragen Wenn Eingang auf Masse dann übergehen
bcf GPIO,5 ;PIN 5 ist auf PLUS (Wenn Eingang auf 1 dann Pin 5 auf Plus)
BTFSC GPIO,3 ;Endschalter abfragen Wenn Eingang auf Masse dann übergehen
bsf GPIO,5 ;PIN 5 ist auf Masse (Wenn Eingang auf 1 dann Pin5 auf Masse)
;****************************links herum*********************************
BTFSC GPIO,0 ;wenn der Eingang 1 ist, Links herum einschalten
call prüfen
BTFSS GPIO,0 ;Wenn der Eingang 0 ist
call inilinks ;Endwert und Merker wieder auf Anfang setzen

;*************************** rechts herum *******************************
BTFSC GPIO,1 ;wenn der Eingang 1 ist, Rechts herum einschalten
call prüfenrechts
BTFSS GPIO,1 ;Wenn der Eingang 0 ist
call inirechts ;Endwert und Merker wieder auf Anfang setzen
goto main


; initialize eeprom locations

ORG 0x2100
DE 0x00, 0x01, 0x02, 0x03


END ; directive 'end of program'

PsiQ
13.06.2013, 15:46
Alsoooo.
Das ist evtl etwas ketzerisch jetzt die ganze schöne Software wieder zu entfernen, ABER:

Du gibst doch per Software die Drehrichtung vor, an Pin5.
Dann brauchst du keine 2 Eingänge für Endschalter verwenden, sondern kannst beide per (evtl mit 1k dazwischen) (o.ä.) auf einen Eingang legen.
Nehmen wir mal Pin2 = Stopp
Welcher Endschalter grad klingelt, weisst du ja von Pin5.

Wenn Pin5 LOW
und
"Stopp"signal => Rechtsrum stoppen

Wenn
Pin 5 HIGH
und
"Stopp"signal
=> Linksrum stoppen

Oder einfach den Ausgang 4 deaktiveren (bis taster losgelassen; subroutine intern zum Ende hin überspringen),
dann ist die Drehrichtung Pin5 egal und muss nicht ausgewertet werden.

Damit hast du Pin3 frei,
und kannst diesen als "Turboknopf" verwenden.

Gleiches spiel wäre bei Pin1+2 möglich:
Wenn es einen ADC oder "float*"(?) Pin gibt. *mit "float" meine ich, er hängt ohne signal oder per 10k:10k Spannungsteiler auf ca 2,5V und erkennt high oder low als signal)
Nimm einen Wechseltaster oder Schalter
(1)/0/(1) => ( ) = Tastfunktion; 0 = Ruhestellung
Wenn der Schalter in Mittelstellung ist liegen über einen 10k:10k Spannungsteiler 2,5V am Pin an.
Wenn er links oder rechts gedrückt wird brückt der Taster nach 0V oder 5V. => links/rechts drehen.

Wenn der Chip nen ADC hat, kannst du sogar ein Poti nehmen, und je nach Auslenkung aus der Mittelstellung (mit etwas totbereich 2V..3V),
und damit direkt die Geschwindigkeit proportional dem Ausschlag machen, wie bei ner Modellbausteuerung.

PS.: Quellcode:
Fehlt nach "call init" nicht in
"init"
ein return am Ende ??
Der rasselt da nach "init" doch ins unterprogramm "prüfen" weiter,
und dort steht dann (erst) ein "return", oder ist das Absicht?

Ich würde da
"call init" ... "return"
"call prüfen" ... "return"
[weiter im Programm]
machen.

Dann sieht man oben besser wie die einzelnen Schritte abgearbeitet werden.

Wenn du mit 100nF 100k gemeint hast, kannst du versuchen mal 20k als pulldown oder pullup zu verwenden.
oder ein Entstörglied als Kombination aus 1k + 100nF vor dem Eingangspin setzen.

Am µC hast du direkt nen 100nF ?








-------------------
Alternative ohne ADC / float:
Pin0 - Drehrichtung: HIGH = rechtsrum, LOW = linksrum => KippSCHALTER 1/1 (Pin0 + 20k Widerstand + daran den mittleren Pin vom Kippschalter)
Pin1 - langsam drehen : 20k Pulldown nach Gnd, Taster mit 1k nach +5V => LOW = nichtstun; HIGH (Taster gedrückt) = langsam drehen
Pin2 - schnell drehen : 20k Pulldown nach Gnd, Taster mit 1k nach +5V => Low = nichtstun; HIGH (Taster gedrückt) = schnell drehen
Pin3 - Beide Endschalter (HIGH oder LOW als Stoppsignal je nach Geschmack und el. Schaltung)
Pin4 - Ausgang Impulse (deaktiveren / subroutine übersrpingen bei "Stopp")
Pin5 - Ausgang Drehrichtung

edit: Pin0 und Pin5 haben hier das gleiche Signal! -Wenn du bei Pin0 einen Kippschalter 1/1 verwendest,
brauchst du Pin5 nichtmehr und der wäre frei!! (Für ultraschnell oder anfahren der mittelstellung odersowas)
Bisschen mehr Hardware...