PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Bascom: Schrittmotorsteuerung mit Drehencoder?



MrMiffy08
13.10.2012, 11:24
Hallo Leute ich hab mal wieder eine Frage, bin lausiger Programmier-Anfänger:

Ich will einen Schrittmotor steuern, der 48 S/U hat und per A3967 getrieben wird, also mit Enable, Dir und Step. Die Hardware steht und funktioniert, hab ein kl. Testprogramm damit laufen.

' Stepper_test1.bas - Testprogramm für A3967 Platine mit Dir Step und Enable

$regfile = "attiny2313.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 8000000 'Quarzfrequenz
$baud = 9600



Declare Sub Key_pressed
Dim I As Long
Config Timer1 = Timer , Prescale = 1
Enable Timer1
Timsk.toie1 = 1
Dim Timer1_reload As Word
Portd.4 = 1 ' Pullup Widerstand ein für Enable - ****Enable =0 bedeutet Motor On!!!! ****
Enable Interrupts

Config Pind.2 = Output
Stepper_takt Alias Portd.2

Config Pind.4 = Output
Stepper_enable Alias Portd.4
Portd.4 = 0 'sprich Motor ON

On Timer1 Isr_timer1

' Step/Takt auf PD.2 / Taster auf PD.3 / Enable auf PD4 / Richtung auf PD5 /

'***********Hauptschleife:**********

Do



Loop

End



Isr_timer1:
Timer1_reload = 45536 ' Vorgabe für 400 / sec
Timer1 = Timer1_reload
Toggle Stepper_takt
Return


Der Schrittmotor soll nun aber mittels eines Drehencoders langsamer und schneller gemacht werden, die Routine hab ich aus dem Hoffmann-Buch.


'-----Deklarationen fuer Drehimpulsgeber:
Config Portd.0 = Input : Encoder_a Alias Pind.0 'Encoder Signal B an Pin 2
Config Portd.1 = Input : Encoder_b Alias Pind.1 'Encoder Signal A an Pin 3
Config Pind.3 = Input : Taster1 Alias Pind.3

Pind.0 = 1 'Pullups für den Drehencoder
Pind.1 = 1
Pind.3 = 1
'LED-Outputs:
Config Portd.2 = Output : Portd.2 = 0 'das ist Pin 6 alles mit Pulldown
Config Portd.5 = Output : Portd.5 = 0 ' Pin 9
Config Portb.4 = Output : Portb.4 = 0 ' Pin 16
Led_gelb Alias Portd.2
Led_gruen Alias Portd.5
Led_rot Alias Portb.4

' BASCOM-Programm
' Stefan Hoffmann 2009
' Drehimpulsgeber/Encoder mit ENCODER-Befehl
'
' In: Drehimpulsgeber an d.0 und d.1 sowie Taster

Dim Wert As Word
Wert = 100
Dim Zustand As Byte

Do
Zustand = Encoder(pind.0 , Pind.1 , Linksroutine , Rechtsroutine , 1)

If Wert > 100 Then Led_rot = 1

If Wert < 100 Then Led_gruen = 1

If Taster1 = 0 Then Led_gelb = 1
'Zu Testzwecken
Loop
End

Linksroutine:
Decr Wert
Return

Rechtsroutine:
Incr Wert
Return


Ich schnall einfach nicht, wie ich diese Routine mit einer Timer-Takterzeugung verheiraten kann. Der Takt ist doch konstant, und die Encoder-Routine braucht das doch als Variable, oder?

Habt ihr eine Idee, wie man so was lösen kann?

Vielen Dank für Anregungen!

MM08

(PS: - ich hatte schon einen anderen Code in Arbeit - s. Link (https://www.roboternetz.de/community/threads/57451-Schrittmotor-Steuerung-mit-Drehencoder-u-Taster-Pollin-bitte-mal-draufschauen?highlight=Drehencoder) und wieder verworfen, weil ich da schließlich vor dem gleichen Problem stand und kein Takt rauskam. Jetzt will ich das Ganze mal abspecken und klein und möglichst einfach wieder anfangen.)

MrMiffy08
14.10.2012, 00:37
Hallo,

merkwürdig, in meinen Emails sehe ich dass HeXPloreR mir am Nachmittag zweimal geantwortet hat, aber im Forum sehe ich die Beiträge bis jetzt nicht. Hab schon mal aus- und eingeloggt, kpl. neu gestartet, mal sehen wann ich sie sehen kann.

Ich habe jedenfalls nach seinen Vorschlägen (im unteren Codeschnipsel) die Doppelpunkte weggenommen und eigene Zeilen für jeden Befehl gemacht und die Inputs mit PIN statt Port benannt.
Jetzt passiert hier schon mal etwas mehr und Reproduzierbares, aber so richtig glücklich bin ich damit noch nicht. Ich mache da morgen mal weiter mit, muss mal in die Heia.

Grüße MM08

HeXPloreR
14.10.2012, 08:02
ja richtig, aber ich habe sie wieder gelöscht weil ich einfach noch zu unsicher bin was die Port config betrfft. Und ich möchte mir abgewöhnen zu schnell und vorallem wenig hilfreiche Beträge ab zu geben ;)

Aber denke schon das es PinD.0 statt PortD.0, bei InPut heissen müsste. PortD (OHNE .x) benutzt man besser nur wenn man den ganzen Port als Input nutzen möchte.

Benutzt Du denn auch Drehimpulsgeber so wie im Beispiel gedacht (Hab das Buch seit gestern nachmittag auch ;) )
Taster extra oder im Geber?
Taster korrekt angeschlossen (Pullup/-down beachtet)?

Mehr weiß ich dazu momentan nicht.

Viel Erfolg

Rone
14.10.2012, 09:57
Ja, Super! Ihr seid klasse!

Mein 2.0.7.3 macht den Code so geändert jetzt auch!

Vielen, vielen Dank!

Wie schön, dass hier so viele hilfreiche Leute am Werk sind, die ihr Wissen mit anderen teilen.....


Diese Antwort in dem anderen Faden läßt allerdings den Schluß zu,
daß das Problem erledigt ist, oder?

MfG

MrMiffy08
14.10.2012, 10:59
Hallo zusammen,
@HeXPloreR - danke für den Hinweis mit Port und Pin, das half schon mal weiter. DIe mit : getrennten Anweisungen hatte ich mal irgendwo gesehen und sofort falsch zur Regel erklärt. Ich gewöhn mir das sofort wieder ab!

Ja, den Encoder nutze ich wie im BUch - mit der Änderung dass die Kontakte jeweils noch 100nF gegen GND als Entprellung bekommen haben. UNd Pullups sind im zweiten Code drin, ich benutze den eingebauten Taster auch, ebenfalls mit Pullup, die schalten ja alle gegen GND.

@Rone -
(PS: - ich hatte schon einen anderen Code in Arbeit - s. Link (https://www.roboternetz.de/community/threads/57451-Schrittmotor-Steuerung-mit-Drehencoder-u-Taster-Pollin-bitte-mal-draufschauen?highlight=Drehencoder) und wieder verworfen, weil ich da schließlich vor dem gleichen Problem stand und kein Takt rauskam. Jetzt will ich das Ganze mal abspecken und klein und möglichst einfach wieder anfangen.)
ist ja schon eine Weile her; das "erledigt" bezog sich auf die unklare Fehlermeldung des Compilers, die dann endlich weg war. Die grundsätzliche Problematik die sich danach stellte war, dass keine sinnvolle Funktion dabei herauskam. Ich mach dazu noch mal einen abschließenden Beitrag in dem anderen Thread.

Was hier jetzt übrig ist, ist dass die beiden Teilcodes funktionieren, aber ich noch keine Ahnung habe wie ich den Drehencoder Code mit dem Rest so verknüpfe dass der Takt für den Schrittmotor im ersten Teil sich dadurch regeln läßt. Dazu eine Idee? Ich bin mit Variablen &Co nicht sehr erfahren, was man da so anstellen kann.

Vielen Dank für weitere Hilfe!

dussel07
15.10.2012, 08:35
Ich habe mal ein Board (http://www.daselektronikerforum.de/viewtopic.php?f=27&t=2496&sid=52d2fc66ddb2d944f7c28e74d9505439) geroutet da hat es mit den Kondensatoren am Encoder nicht geklappt - ohne dann schon.
Meine Idee war das im encoder Befehl ein entprellen schon integriert ist?

MrMiffy08
15.10.2012, 23:39
Hallo dussel,

das wäre schön und würde zwei Teile einsparen. Ich habe den selben Encoder (ALPS STEC12E) mit und ohne 100nF ausprobiert, beides hat die gleiche Wirkung. Ich versuche morgen mal das dezidiert zu beschreiben.

Wichtiger wäre mir allerdings die Problematik der "Verheiratung" der beiden Code-Stücke zu etwas sinnvollem. Dazu jmd Anregungen?

HeXPloreR
16.10.2012, 05:22
Wie wäre es denn wenn Du die Codestücke ordnest - also die Teile der Encoderabfrage dort hin schreibst wo zum beispiel die Ports und Subs definiert/deklariert werden...deine Encoderabfrage mit in die do loop der (leeren) Hauptschleife kopieren oder ausschneiden. Die do loop vom encoder vorher im einzelprogramm kann man komplett auskommentieren ( '( ...auskommentierter codetext... ') oder normal mit ' ) oder entfernen. Die Subs bleiben wo sie sind.

MrMiffy08
16.10.2012, 22:10
Ok, ich versuch's mal.




' Testprogramm für A3967 Platine mit Dir Step und Enable

$regfile = "attiny2313.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 8000000 'Quarzfrequenz
$baud = 9600


Config Timer1 = Timer , Prescale = 1
Enable Timer1
Timsk.toie1 = 1
Dim Timer1_reload As Word
Portd.4 = 1 ' Pullup Widerstand ein für Enable - ****Enable =0 bedeutet Motor On!!!! ****
Enable Interrupts

' Inputs: Drehimpulsgeber an d.0 und d.1 sowie Taster an d.3
'-----Deklarationen fuer Drehimpulsgeber:
Config Pind.0 = Input
Encoder_a Alias Pind.0 'Encoder Signal B an Pin 2
Config Pind.1 = Input
Encoder_b Alias Pind.1 'Encoder Signal A an Pin 3
Config Pind.3 = Input
Taster1 Alias Pind.3

Pind.0 = 1 'Pullups für den Drehencoder
Pind.1 = 1
Pind.3 = 1
'LED-Outputs stellvertretend für Step, Dir, Enable
' In der endgültigen Hardware liegen: Step/Takt auf PD.2 / Taster auf PD.3 / Enable auf PD4 / Richtung auf PD5 /
Config Portd.2 = Output
Portd.2 = 0 'das ist Pin 6 - alles mit Pulldown - steht für Step/Takt
Config Portd.5 = Output
Portd.5 = 0 ' Pin 9 - der hier steht für Dir
Config Portb.4 = Output
Portb.4 = 0 ' Pin 16 - diese Led steht für Enable

Led_gelb Alias Portd.2
Led_gruen Alias Portd.5
Led_rot Alias Portb.4


On Timer1 Isr_timer1 'Deklaration der Timerroutine


Dim Wert As Word
Wert = 100 'willkürlich gewählter Startwert
Dim Zustand As Byte

'***********Hauptschleife:**********
Do

Zustand = Encoder(Pind.0 , Pind.1 , Linksroutine , Rechtsroutine , 0)

If Wert > 100 Then Led_rot = 1

If Wert < 100 Then Led_gruen = 1

Loop

End


Isr_timer1:
Timer1_reload = 45536 'Vorgabe für 400 / sec
Timer1 = Timer1_reload
Toggle Led_gelb '= Stepper_takt
Return


Linksroutine:
Decr Wert
Return

Rechtsroutine:
Incr Wert
Return




So, und beim Starten dieses Codes leuchtet zunächst die gelbe Led (ist klar, Timer1), und beim Drehen je eine Raste leuchtet grün und in die andere rot, gehen aber nicht wieder aus. Dies jeweils egal mit Encoder mit 100nF gegen GND oder ohne und ebenso mit dem Pollin-Drehencoder ohne Kondensatoren, der hier schon mehrfach angesprochen wurde und der mehr oder weniger Ärger macht.
Ich habe an der Encoder-Routine mal hinten die 1 auf 0 geändert, weil ich ja das Prog ja weiter laufen lassen will. Mit 1 stoppt es hier wohl.

Wie bekomme ich es hin dass rot und grün wieder ausgehen?
Uind eben das Grundproblem - wie bekomme ich schnelleren/langsameren Takt an D2/Led_Gelb aufgrund Links/Rechtsdrehung hin?

Vielen Dank für Eure Anregungen!

HeXPloreR
17.10.2012, 08:47
die LEDs gehen nicht aus weil Du sie nur einschaltest wenn > oder < ... einfach noch ne bedingung mit dazu schreiben die ausschaltet wenn > oder < jeweils dazu. leider wenig zeit grade...

EDIT: Kann es sein, das unter jedes IF auch ein END IF muss?

MrMiffy08
17.10.2012, 23:38
Hallo HeXPlore (https://www.roboternetz.de/community/members/35937-HeXPloreR)!

Vielen Dank für Deine Hinweise! Ich habe mal eine Else eingefügt und den Timer Takt mal auf sichtbar korrigiert. das takkert jetzt mit 1Hz und die Led's gehen an und aus wie sie sollen. Also dieser Teil funktioniert jetzt schonmal. Super!
Der Gesamte Code sieht jetzt so aus:


$regfile = "attiny2313.dat"
$crystal = 8000000
$hwstack = 32
$swstack = 10
$framesize = 40
$baud = 9600
' BASCOM-Programm
' Stefan Hoffmann 2009
' Drehimpulsgeber/Encoder mit ENCODER-Befehl
'
' In: Drehimpulsgeber an d.0 und d.1 sowie Taster

'-----Deklarationen fuer Drehimpulsgeber:


' Testprogramm für A3967 Platine mit Dir Step und Enable

$regfile = "attiny2313.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 8000000 'Quarzfrequenz
$baud = 9600


Config Timer1 = Timer , Prescale = 256
Enable Timer1
Timsk.toie1 = 1
Dim Timer1_reload As Word
Portd.4 = 1 ' Pullup Widerstand ein für Enable - ****Enable =0 bedeutet Motor On!!!! ****
Enable Interrupts

' Inputs: Drehimpulsgeber an d.0 und d.1 sowie Taster an d.3
'-----Deklarationen fuer Drehimpulsgeber:
Config Pind.0 = Input
Encoder_a Alias Pind.0 'Encoder Signal B an Pin 2
Config Pind.1 = Input
Encoder_b Alias Pind.1 'Encoder Signal A an Pin 3
Config Pind.3 = Input
Taster1 Alias Pind.3

Pind.0 = 1 'Pullups für den Drehencoder
Pind.1 = 1
Pind.3 = 1
'LED-Outputs stellvertretend für Step, Dir, Enable
' In der endgültigen Hardware liegen: Step/Takt auf PD.2 / Taster auf PD.3 / Enable auf PD4 / Richtung auf PD5 /
Config Portd.2 = Output
Portd.2 = 0 'das ist Pin 6 - alles mit Pulldown - steht für Step/Takt
Config Portd.5 = Output
Portd.5 = 0 ' Pin 9 - der hier steht für Dir
Config Portb.4 = Output
Portb.4 = 0 ' Pin 16 - diese Led steht für Enable

Led_gelb Alias Portd.2
Led_gruen Alias Portd.5
Led_rot Alias Portb.4


On Timer1 Isr_timer1 'Deklaration der Timerroutine


Dim Wert As Word
Wert = 100 'willkürlich gewählter Startwert
Dim Zustand As Byte

'***********Hauptschleife:**********
Do

Zustand = Encoder(pind.0 , Pind.1 , Linksroutine , Rechtsroutine , 0)

If Wert > 100 Then
Led_rot = 1
Else
Led_rot = 0
End If

If Wert < 100 Then
Led_gruen = 1
Else
Led_gruen = 0
End If

Loop

End


Isr_timer1:
Timer1_reload = 34286 'Vorgabe für 400 / sec
Timer1 = Timer1_reload
Toggle Led_gelb '= Stepper_takt
Return


Linksroutine:
Decr Wert
Return

Rechtsroutine:
Incr Wert
Return


Wie könnte ich nun weiter kommen mit der "Verheiratung" der Funktionen?

Vielen Dank wieder für alle Hinweise!

MrMiffy08
18.10.2012, 12:01
Hallo zusammen,

ich hatte heute morgen beim Grübeln über mein Problem eine Erleuchtung: ist das was ich da brauche für die Ansteuerung nicht eigentlich PWM? Also ich will ja mit dem Encoder langsamer/schneller steuern, der Takt soll sich dabei verändern. Kann man denn so langsames PWM erzeugen? Oder ist es besser, PWM schneller zu machen und sw-mäßig runterzuteilen? Ist der Gedanke überhaupt korrekt?

Danke für Eure Hilfe!

EF_Arcturus
18.10.2012, 12:36
Hallo MrMiffy08,

dies ist meine erste Antwort hier im Forum, also bitte nicht gleich mit Steinen werfen, wenn von mir nicht alles korrekt geschildert wurde.

Nun zu deinem Anliegen. Nein, Drehzahlaenderungen durch PWM geht so nicht bei einem Schrittmotor.

Aber folgendes moechte ich dir mit auf den Weg geben:
Im Code fuer den Motortakt verwendest du den Timer1, ist ja auch Ok. Mit der gegebenen Einstellung hast du eine errechnete Drehzahl von 500 U/min.
Vorgabe war 400 T/sec, das ergibt 24000 T/min, der Moter benoetigt 48 T/Umdrehung, also macht er 24000T/min / 48T/U = 500 U/min.

Soweit ist alles klar.

Im Code fuer die Encoder-Abfrage benutzt du auch den Timer1, fuer sich allein ok, aber fuer die Drehzahlsteuerung kannst du den dann nicht mehr verwenden,
da er ja schon fuer den Motortakt verwendet wird.

Benutze also fuer den Encoder den Timer0 und konfiguriere den auf 1msec für die Abfrage.

So und nun ein Denkanstoss fuer das "Verheiraten" der beiden Code-Schnitzel:
Der Startwert fuer 400 T/sec (400Hz) ist ja 45536, der Encoder kann mit dem Timer0 einen Wert zwischen 0 und 255 haben.
Wenn du nun den Encoderwert zu dem Startwert addierst oder subtrahierst, so aendern sich doch die T/sec, also auch die Drehzahl.

Uebrigens ich selber verwende den Pollin-Drehencoder und bin sehr zufrieden.

Gruß EF_Arcturus

MrMiffy08
18.10.2012, 23:46
Hallo EF_Arcturus

vielen Dank für Deine Hinweise! Ich habe das mal umgesetzt, mit langsamerem Takt, weil ich will ja auch was sehen an der LED.
Kann man ja später für den Schritti wieder hochdrehen.
Der Encoder ist übrigens mit dem Bascom-Encoder-Befehl dekodiert, da kommt kein Timer zum Zug.
Den Timer für die Takterzeugung habe ich mal mit Timer0 gemacht, und dann noch die zwei Led's - eigentlich DIR und Enable - auskommentiert, damit mein Schrittmotor mal läuft. Die Idee mit der Verknüpfung durch Aufaddieren ist klasse, mit Timer 0 und max 255 sowie aufaddiertem Wert 100 macht in der Tat schneller und langsamer, genau was ich will.

Damit sieht man schon mal, dass da was sinnvolles passiert. Was mich allerdings wundert:
Trotzdem ich da die Timerwerte nach unten und oben begrenze, läuft der Timer über wenn ich den DE über den Wert hinaus drehe. Wie kann ich das verhindern?

Der aktuelle Code sieht so aus:


$regfile = "attiny2313.dat"
$crystal = 8000000
$hwstack = 32
$swstack = 10
$framesize = 40
$baud = 9600
' BASCOM-Programm
' Stefan Hoffmann 2009
' Drehimpulsgeber/Encoder mit ENCODER-Befehl
'
' In: Drehimpulsgeber an d.0 und d.1 sowie Taster

'-----Deklarationen fuer Drehimpulsgeber:

' Testprogramm für A3967 Platine mit Dir Step und Enable

$regfile = "attiny2313.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 8000000 'Quarzfrequenz
$baud = 9600


Config Timer0 = Timer , Prescale = 1024 'Timer1 Deklarationen für den Takt des Steppers
Enable Timer0
Timsk.toie0 = 1
Dim Timer0_reload As Word
Portd.4 = 1 ' Pullup Widerstand ein für Enable - ****Enable =0 bedeutet Motor On!!!! ****
Enable Interrupts
On Timer0 Isr_timer0 'Deklaration der Timerroutine


' Inputs: Drehimpulsgeber an d.0 und d.1 sowie Taster an d.3
'-----Deklarationen fuer Drehimpulsgeber:
Config Pind.0 = Input
Encoder_a Alias Pind.0 'Encoder Signal B an Pin 2
Config Pind.1 = Input
Encoder_b Alias Pind.1 'Encoder Signal A an Pin 3
Config Pind.3 = Input
Taster1 Alias Pind.3 'Taster

Pind.0 = 1 'Pullups für den Drehencoder
Pind.1 = 1
Pind.3 = 1
'LED-Outputs stellvertretend für Step, Dir, Enable
' In der endgültigen Hardware liegen: Step/Takt auf PD.2 / Taster auf PD.3 / Enable auf PD4 / Richtung auf PD5 /
Config Portd.2 = Output
Portd.2 = 0 'das ist Pin 6 - alles mit Pulldown - steht für Step/Takt
Config Portd.5 = Output
Portd.5 = 0 ' Pin 9 - der hier steht für Dir
Config Portb.4 = Output
Portb.4 = 0 ' Pin 16 - diese Led steht für Enable

Led_gelb Alias Portd.2
Led_gruen Alias Portd.5
Led_rot Alias Portb.4


Dim Wert As Word
Wert = 100 'willkürlich gewählter Startwert
Dim Zustand As Byte

'***********Hauptschleife:**********
Do


Led_rot = 0 'Enable ein
Zustand = Encoder(pind.0 , Pind.1 , Linksroutine , Rechtsroutine , 0)

'If Wert > 100 Then 'mal wegkommentiert für den Test mit dem Schritti
'Led_rot = 1
'Else
'Led_rot = 0
'End If

'If Wert < 100 Then
'Led_gruen = 1
'Else
'Led_gruen = 0
'End If

Loop

End


Isr_timer0:
Timer0_reload = 100 'Vorgabe für 50 / sec
Timer0 = Timer0_reload + Wert

If Timer0 = 25 Then 'Wertbegrenzung nach unten
Timer0 = 25
End If

If Timer0 = 255 Then 'Wertbegrenzung nach oben
Timer0 = 255
End If

Toggle Led_gelb '= Stepper_takt
Return


Linksroutine:
Decr Wert
Return

Rechtsroutine:
Incr Wert
Return



Bis hierhin bin ich schon mal ganz glücklich.

Habt Ihr Ideen, wie ich dieses "Überlaufen" weg bekomme?

Searcher
19.10.2012, 06:23
Isr_timer0:
Timer0_reload = 100 'Vorgabe für 50 / sec
Timer0 = Timer0_reload + Wert

If Timer0 = 25 Then 'Wertbegrenzung nach unten
Timer0 = 25
End If

If Timer0 = 255 Then 'Wertbegrenzung nach oben
Timer0 = 255
End If

Toggle Led_gelb '= Stepper_takt
Return


Linksroutine:
Decr Wert
Return

Rechtsroutine:
Incr Wert
Return



Wie Dein Programm im Ganzen funktioniert, hab ich jetzt nicht nachvollzogen aber Folgendes fiel mir auf:

In der Isr_Timer0 wird erst der Timer0 gesetzt und dann abgefragt und eventuell nochmal gesetzt. Man könnte erst Timer0_reload und Wert verrechnen und dann abhängig vom errechneten Wert in der Bedingung den Timer0 nur einmal setzen und verhindert somit unnötiges "Hüpfen" des Timers. Timer0 ist ja keine Variable, sondern eine Hardwareeinheit im µC deren Veränderung ja auch gleich Auswirkung auf die HW hat.


läuft der Timer über wenn ich den DE über den Wert hinaus drehe. Wie kann ich das verhindern?

In der Links-, Rechtsroutine kannst Du den Wert doch auch begrenzen? Je nachdem wie groß er ist, eben nicht mehr decrementieren oder incrementieren?

Gruß
Searcher

EF_Arcturus
19.10.2012, 21:19
Hallo MrMiffy08 und auch alle anderen,
ich bin auch ein Neuling bei der AVR-Programmierung und
beschaeftige mich seit ca. einem Monat mit BASCOM. Hab mir das myAVR-MK2 und das LCD-Add_on
zugelegt und probiere und lerne damit die Programmierung.
Zusätzlich habe ich den DE von Pollin gekauft und mich in den verschiedenen Foren umgesehen.
Dort habe ich auch die DE-Routinen von Screwdriver gefunden und für sehr gut befunden.
Eine dieser DE-Routinen habe ich dann übernommen und verwende diese nun immer.

Habe deine Code-Schnipsel und deine Anforderungen zusammen gewuerfelt und mal ein Prog
dafuer erstellt. Auf meiner HW funzt es einwandfrei. Im Anhang mein Code.

Wichtiger Hinweis:
Kann so nicht fuer die Ansteuerung eines Schrittmotors uebernommen werden! Es sind diverse
Aenderungen/Anpassungen noetig, aber die geforderte Funktion eine LED schnell bzw. langsam
blicken zu lassen ist gegeben. Damit man den DE nicht ständig drehen muss um etwas zu sehen,
habe ich eine Schrittweitenanpassung benutzt. So ist es jetzt moeglich in 20 Schritten
die Blinkfrequenz zu veraendern. Solltest du den Bereich erweitern, so achte darauf,
dass der neu erstellte Timer1_start-wert nicht über die Grenze von 2hoch16 überschreitet,
denn dann funzt Timer1 nicht!

Nun noch ein Hinweis an Alle die dieses lesen: Es mag sein dass man das Ergebnis dieses
Prog einfacher und schneller und besser und kuerzer hinbekommt.
Doch bedenkt bitte, ich bin, wie oben schon angemerkt, noch ein Anfaenger.

Achja, die Aussage von Searcher kann ichnur bestätigen.

So, hier nun mein Bascom-Programm:
23505

Hoffe es hilft dir weiter.

Gruss
EF_Arcturus (Wolfgang)

MrMiffy08
20.10.2012, 00:32
Hallo Wolfgang,

vielen Dank für deinen anregenden Beitrag! Die Routine von Screwdrivver hatte ich auch schon mal am Wickel, aber einfach zu wenig verstanden und daher wieder beiseite gelegt. Mit Deinen Anpassungen sieht das schon recht interessant aus, aber ich glaube ich werde mit meiner Einfach.- Version erst einmal weiter machen, bis das so läuft wie ich es brauche.
Dann will ich mich gerne reinstürzen und Deinem Vorschlag folgen, dazu reicht aber mein momentaner Gehirnschmalz nicht.
Außerdem bin ich auf mittlerweile bestehende Hardware angewiesen, mit einem Tiny2313, also das Umfiedeln ist nicht die Welt aber ich stelle das mal an zweite Stelle. Im Moment bastele ich an dem o.a. Code weiter, komme morgen wieder rein.
LG MM

MrMiffy08
22.10.2012, 00:46
Hallo zusammen,

so, ich habe jetzt mal ein bisschen an den Werten geschraubt (mein Schrittmotor kam beim schnellsten Turn nicht mehr mit) und habe versucht die Begrenzung in die Inc/Dec Routine einzubinden. Bin aber etwas ratlos, denn das hat nun gar nichts gebracht, obwohl ich rein rechnerisch weit vor dem höchsten Timerwert ende (bei 50+155 = 205) - was ist denn das? Wieso läuft da der TImer immer noch über statt bei 205 zu stoppen? Versteh ich nicht. Was mache ich falsch?

Und zum Thema -

In der Isr_Timer0 wird erst der Timer0 gesetzt und dann abgefragt und eventuell nochmal gesetzt. Man könnte erst
Timer0_reload und Wert verrechnen und dann abhängig vom errechneten Wert in der Bedingung den
Timer0 nur einmal setzen und verhindert somit unnötiges "Hüpfen" des Timers.
ist das in meinem Code jetzt so richtig? Oder muss ich an anderer Stelle noch was ändern?

Vielen Dank für weitere Hilfe!

Aktueller Stand:

$regfile = "attiny2313.dat"
$crystal = 8000000
$hwstack = 32
$swstack = 10
$framesize = 40
$baud = 9600
' BASCOM-Programm
' Stefan Hoffmann 2009
' Drehimpulsgeber/Encoder mit ENCODER-Befehl
'
' In: Drehimpulsgeber an d.0 und d.1 sowie Taster

'-----Deklarationen fuer Drehimpulsgeber:


' Testprogramm für A3967 Platine mit Dir Step und Enable

$regfile = "attiny2313.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 8000000 'Quarzfrequenz
$baud = 9600


Config Timer0 = Timer , Prescale = 1024 'Timer1 Deklarationen für den Takt des Steppers
Enable Timer0
'Timsk.toie0 = 1 'hab ich mal wegkommentiert.....
Dim Timer0_reload As Word
Portd.4 = 1 ' Pullup Widerstand ein für Enable - ****Enable =0 bedeutet Motor On!!!! ****
Enable Interrupts
On Timer0 Isr_timer0 'Deklaration der Timerroutine


' Inputs: Drehimpulsgeber an d.0 und d.1 sowie Taster an d.3
'-----Deklarationen fuer Drehimpulsgeber:
Config Pind.0 = Input
Encoder_a Alias Pind.0 'Encoder Signal B an Pin 2
Config Pind.1 = Input
Encoder_b Alias Pind.1 'Encoder Signal A an Pin 3
Config Pind.3 = Input
Taster1 Alias Pind.3 'Taster

Pind.0 = 1 'Pullups für den Drehencoder
Pind.1 = 1
Pind.3 = 1
'LED-Outputs stellvertretend für Step, Dir, Enable
' In der endgültigen Hardware liegen: Step/Takt auf PD.2 / Taster auf PD.3 / Enable auf PD4 / Richtung auf PD5 /
Config Portd.2 = Output
Portd.2 = 0 'das ist Step/Takt - Pin 6 - alles mit Pulldown + LEd_gelb
Config Portd.5 = Output
Portd.5 = 0 ' Pin 9 - der hier steht für Dir
Config Portb.4 = Output
Portb.4 = 0 ' Pin 16 - diese Led steht für Enable

Led_gelb Alias Portd.2
Led_gruen Alias Portd.5
Led_rot Alias Portb.4

Dim Wert As Word
Wert = 50 'willkürlich gewählter Startwert
Dim Zustand As Byte

'***********Hauptschleife:**********
Do

Led_rot = 0 'Enable ein
Led_gruen = 1 'Dir
Zustand = Encoder(pind.0 , Pind.1 , Linksroutine , Rechtsroutine , 0)

Loop

End

Isr_timer0:
Timer0_reload = 50 'Vorgabe für 38 / sec
Timer0 = Timer0_reload + Wert

Toggle Led_gelb '= Stepper_takt

Return


Linksroutine:
Decr Wert
If Wert = 10 Then
Wert = 10
End If
Return

Rechtsroutine:
Incr Wert
If Wert = 155 Then
Wert = 155
End If
Return

Searcher
22.10.2012, 10:30
Wieso läuft da der TImer immer noch über statt bei 205 zu stoppen? Versteh ich nicht. Was mache ich falsch?
Ich weis nicht genau, was Du mit Timerüberlauf meinst, weil ich vielleicht auch immer noch nicht wirklich die Ansteuerung des Steppers verstehe - was Du eigentlich genau erwartest - wie Du auf einen Timerüberlauf schließt.

Der Timer0 läuft immer bis 255 und macht dann den Overflow Interrupt. In der ISR wird der TCNT0 nun auf 50 + Wert gesetzt. Läuft also von da aus wieder bis 255 usw.



Isr_timer0:
Timer0_reload = 50 'Vorgabe für 38 / sec
Timer0 = Timer0_reload + Wert
Toggle Led_gelb '= Stepper_takt
Return

Linksroutine:
Decr Wert
If Wert = 10 Then
Wert = 10
End If
Return

Rechtsroutine:
Incr Wert
If Wert = 155 Then
Wert = 155
End If
Return


ist das in meinem Code jetzt so richtig? Oder muss ich an anderer Stelle noch was ändern?

Hatte ich im Prinzip so gemeint.

If wert = 10 then Wert = 10 bringt nichts. Wenn Wert auf 9 ist, bleibt er auf 9.
besser
If Wert <= 10 Then Wert = 10
Natürlich auch in der Rechtsroutine beachten

Aber wie gesagt: Was erwartest Du genau und was tut Dein Programm nicht richtig? Wie stellst Du den Timerüberlauf fest?

Gruß
Searcher

MrMiffy08
22.10.2012, 13:41
Hallo Searcher,

vielen Dank für Deine Antwort!
Also das Programm soll eigentlich so funktionieren:
Der Timer soll einen Takt machen, der mit Hilfe des Drehencoders in der Frequenz veränderbar ist, dieses Taktsignal soll auf den Stepperchip (Allegro A3967) gehen und für ihn das Step-Signal darstellen. Daneben braucht der Chip noch Enable (B.4 auf Low gesetzt) und Dir (an D.5), was ich noch gar nicht implementiert habe, das kommt noch. (Da möchte ich, dass der Stepper auf Tastendruck am DE einige volle Umdrehungen rechts herum, dann links herum macht.)

Diese Takterhöhung/-erniedrigung geht ja nun schon mal, allerdings macht der Takt bei Erreichen des niedrigsten oder höchsten Wertes einen Sprung (das meinte ich mit Überlauf, ist unglücklich ausgedrückt) und geht auf die höchste bzw. niedrigste Taktrate. Ich möchte, dass der Takt bei der jeweils höchsten/niedrigsten Frequenz stehenbleibt und nicht zu einer anderen Geschwindigkeit wechselt.

Ja, ich sehe schon, als Anfänger benutzt man Vokabeln, die eigentlich was anderes meinen ohne zu ahnen dass das missverständlich ist. Ich komme aber mit Eurer Hilfe so langsam weiter...

LG MrMiffy

Searcher
22.10.2012, 14:12
Diese Takterhöhung/-erniedrigung geht ja nun schon mal, allerdings macht der Takt bei Erreichen des niedrigsten oder höchsten Wertes einen Sprung (das meinte ich mit Überlauf, ist unglücklich ausgedrückt) und geht auf die höchste bzw. niedrigste Taktrate. Ich möchte, dass der Takt bei der jeweils höchsten/niedrigsten Frequenz stehenbleibt und nicht zu einer anderen Geschwindigkeit wechselt.
Das war/ist vermutlich jetzt noch die Abfrage in der Links- Rechtsroutine. Da kann "Wert" überlaufen. Schau meinen letzten Beitrag zu der Abfrage darin.


Ja, ich sehe schon, als Anfänger benutzt man Vokabeln, die eigentlich was anderes meinen ohne zu ahnen dass das missverständlich ist.
Null Problemo. Wir waren alle mal Anfänger und solange Du dran bleibst wird das schon. Auch ich zähle mich nicht zu den Nichtanfängern :-)

Gruß
Searcher

MrMiffy08
22.10.2012, 21:13
Hallo zusammen,
noch mal Dank an Searcher für die Hinweise!
Ich habe das > und < eingefügt und siehe da: Jetzt funktioniert es endlich wie es soll: Der Schritti dreht - mit gedrosseltem Tempo los, kann schneller durch den DE gesteuert werden und bleibt nun auhc bei der jeweiligen Max. und Min.- Geschwindigkeit stehen. Super!
Etwas Feintuning an den Werten für den Timer und dem Wert asus dem Drehencoder, und jetzt passt alles.

Ich werde nun noch das Enable für gesteuerten Stop und das Dir für eine Hin und Her-Bewegung implementieren. Wahrscheinlich brauche ich dann noch mal Hilfe, aber ich schraube erst mal ein wenig herum, will ja auch was lernen...

Aktueller Code:


$regfile = "attiny2313.dat"
$crystal = 8000000
$hwstack = 32
$swstack = 10
$framesize = 40
$baud = 9600
' BASCOM-Programm
' Stefan Hoffmann 2009
' Drehimpulsgeber/Encoder mit ENCODER-Befehl
'
' In: Drehimpulsgeber an d.0 und d.1 sowie Taster

' Testprogramm für A3967 Platine mit Dir Step und Enable

$regfile = "attiny2313.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 8000000 'Interner Osz. 8 MHz
$baud = 9600


Config Timer0 = Timer , Prescale = 1024 'Timer1 Deklarationen für den Takt des Steppers
Enable Timer0
Dim Timer0_reload As Word
Portd.4 = 1 'Pullup Widerstand ein für Enable - ****Enable =0 bedeutet Motor On!!!! ****
Enable Interrupts
On Timer0 Isr_timer0 'Deklaration der Timerroutine

' Inputs: Drehimpulsgeber an d.0 und d.1 sowie Taster an d.3
'-----Deklarationen fuer Drehimpulsgeber:
Config Pind.0 = Input
Encoder_a Alias Pind.0 'Encoder Signal B an Pin 2
Config Pind.1 = Input
Encoder_b Alias Pind.1 'Encoder Signal A an Pin 3
Config Pind.3 = Input
Taster1 Alias Pind.3 'Taster

Pind.0 = 1 'Pullups für den Drehencoder
Pind.1 = 1
Pind.3 = 1
'LED-Outputs stellvertretend für Step, Dir, Enable
' In der endgültigen Hardware liegen: Step/Takt auf PD.2 / Taster auf PD.3 / Enable auf PD4 / Richtung auf PD5 /
Config Portd.2 = Output
Portd.2 = 0 'das ist Step/Takt - Pin 6 - alles mit Pulldown + LEd_gelb
Config Portd.5 = Output
Portd.5 = 0 ' Pin 9 - Dir - Richtungssignal
Config Portd.4 = Output
Portd.4 = 0 ' Pin 16 - Enable - generelles Ein-Ausschaltsignal

Motor_step Alias Portd.2
Led_gruen Alias Portd.5
Chip_enable Alias Portd.4

Dim Wert As Word
Wert = 2 'willkürlich gewählter Startwert
Dim Zustand As Byte

'***********Hauptschleife:**********
Do

Chip_enable = 0 'Enable ein
Led_gruen = 1 'Dir
Zustand = Encoder(pind.0 , Pind.1 , Linksroutine , Rechtsroutine , 0)

Loop

End

Isr_timer0:
Timer0_reload = 4 'Vorgabe für 38 / sec
Timer0 = Timer0_reload + Wert
Toggle Motor_step '= Stepper_takt
Return

Linksroutine:
Decr Wert
If Wert <= 1 Then
Wert = 1
End If
Return

Rechtsroutine:
Incr Wert
If Wert >= 230 Then
Wert = 230
End If
Return

Searcher
23.10.2012, 10:41
noch mal Dank an Searcher für die Hinweise!
:Strahl

Diesmal noch eine kostenlose:-) Bemerkung.

Jeder schreibt sein Programm irgendwie anders als andere und wenn es zur eigenen Zufriedenheit funktioniert, ist alles gut.
Deine Linksroutine würde ich jetzt zB so machen:


Linksroutine:
if Wert > 1 then Decr Wert
Return

Da wird Wert nur dekrementiert, wenn es notwendig ist. Ob das dann auch wirklich OK ist in Zusammenarbeit mit dem restlichen Programm ist müßte man dann natürlich wieder testen.
Wenn nach dem Then nur eine Anweisung für die If Abfrage folgt, kann man das alles in eine Zeile schreiben und sich das end if sparen. Es darf sogar noch ein else mit einer folgenden Anweisung folgen. Ausprobieren und wenn der Compiler nicht meckert ist es gut.

Bei Deiner

Linksroutine:
Decr Wert
If Wert <= 1 Then
Wert = 1
End If
Return

wird Wert immer dekrementiert und wenn es notwendig ist auf 1 gesetzt. Das ist mehr Arbeit für den µC und braucht deshalb länger. Man sollte, allgemeine Regel, die Interrupt Routinen von der Laufzeit her so kurz wie möglich halten.

Viel Spaß und Erfolg noch
Gruß
Searcher

MrMiffy08
27.10.2012, 00:52
Hallo Searcher,

danke für die Feinheiten, das = habe ich noch entfernt. Soweit so gut.

Nun habe ich noch eine Routine für die Tastenabfrage des Drehencoders eingefügt, buchstabengenau aus dem S. Hoffmann-Buch. Die hatte ich vorher schon mal getestet mit LED's, das funktionierte gut. Ich brauche davon momentan nur Kurz- und Langdruck, um zu stoppen und hin-und her zu fahren.
Wenn ich jetzt das Programm so laufen lasse, muss ich feststellen dass der Schrittmotor sich Verschluckt: er macht vielleicht fünf sechs Schritte, stoppt dann kurz und macht wieder fünf sechs Schritte. Ein normales Durchlaufen ist das jedenfalls nicht. Das verstehe ich nicht. Wo mag das denn her kommen? Werden die Interrupts des Timer0 vom Programm gestört? Wenn ja wo denn?

Der aktuelle Code:

$regfile = "attiny2313.dat"
$crystal = 8000000
$hwstack = 32
$swstack = 10
$framesize = 40
$baud = 9600
' BASCOM-Programm
' Stefan Hoffmann 2009
' Drehimpulsgeber/Encoder mit ENCODER-Befehl
'
' In: Drehimpulsgeber an d.0 und d.1 sowie Taster

' Testprogramm für A3967 Platine mit Dir Step und Enable

$regfile = "attiny2313.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 8000000 'Interner Osz. 8 MHz
$baud = 9600


Config Timer0 = Timer , Prescale = 1024 'Timer1 Deklarationen für den Takt des Steppers
Enable Timer0
Dim Timer0_reload As Word
Portd.4 = 1 'Pullup Widerstand ein für Enable - ****Enable =0 bedeutet Motor On!!!! ****
Enable Interrupts
On Timer0 Isr_timer0 'Deklaration der Timerroutine

' Inputs: Drehimpulsgeber an d.0 und d.1 sowie Taster an d.3
'-----Deklarationen fuer Drehimpulsgeber:
Config Pind.0 = Input
Encoder_a Alias Pind.0 'Encoder Signal B an Pin 2
Config Pind.1 = Input
Encoder_b Alias Pind.1 'Encoder Signal A an Pin 3
Config Pind.3 = Input
Taster1 Alias Pind.3 'Taster

Pind.0 = 1 'Pullups für den Drehencoder
Pind.1 = 1
Pind.3 = 1
'LED-Outputs stellvertretend für Step, Dir, Enable
' In der endgültigen Hardware liegen: Step/Takt auf PD.2 / Taster auf PD.3 / Enable auf PD4 / Richtung auf PD5 /
Config Portd.2 = Output
Portd.2 = 0 'das ist Step/Takt - Pin 6 - alles mit Pulldown + LEd_gelb
Config Portd.5 = Output
Portd.5 = 0 ' Pin 9 - Dir - Richtungssignal
Config Portd.4 = Output
Portd.4 = 0 ' Pin 16 - Enable - generelles Ein-Ausschaltsignal
Config Portb.0 = Output
Portb.0 = 0 'Pin 9 - LED_DE - am Drehencoder Anzeige

Motor_step Alias Portd.2
Chip_dir Alias Portd.5
Chip_enable Alias Portd.4

Dim Wert As Word
Wert = 2 'experimentell ermittelter Startwert für den Drehencoder
Dim Zustand As Byte
'*****************Deklarationen für den Taster - am DE - für die Lang-kurz- und Doppelklickroutine
Dim Zaehler As Byte
Const Langzaehler = 100 'Danach gilt die Taste als lange gedrueckt
Const Doppelzaehler = 20 'Innerhalb dessen muss zweiter Klick erfolgen
Dim Gedrueckt As Byte 'Art des Drueckens (Kurz/Lang/Doppel)
Const Kurz = 1
Const Lang = 2
Const Doppel = 3
Dim I As Byte


'***********Hauptschleife:**********
Do

Chip_enable = 0 'Enable ein
Chip_dir = 1 'Dir


Zustand = Encoder(pind.0 , Pind.1 , Linksroutine , Rechtsroutine , 0)


Debounce Taster1 , 0 , Tastenauswertung , Sub

Select Case Gedrueckt 'Hier koennen beliebige Anweisungen erfolgen
Case Kurz: 'Es wurde einmal kurz gedrueckt
Toggle Chip_enable
Waitms 100
Case Lang: 'Die Taste wurde lange gedrueckt
For I = 1 To 6
Toggle Chip_dir
Next I
Wait 1

Case Doppel: 'Die Taste wurde doppelt gedrueckt
Waitms 500
End Select

Portd.2 = 0
Portd.5 = 0
Portb.4 = 0


Loop

End

'**********************Interrupt-Routine Timer0 ************************************
Isr_timer0:
Timer0_reload = 4 'Vorgabe für 38 / sec
Timer0 = Timer0_reload + Wert
Toggle Motor_step '= Stepper_takt
Return

'***********************Sub-Routinen Drehencoder ***********************************
Linksroutine:
Decr Wert
If Wert < 1 Then
Wert = 1
End If
Return

Rechtsroutine:
Incr Wert
If Wert > 230 Then
Wert = 230
End If
Return

'*****************Subroutine Tasterauswertung *****************************
Tastenauswertung:
Zaehler = 0
Do
Incr Zaehler
Waitms 10
Loop Until Taster1 = 1 Or Zaehler = Langzaehler

If Zaehler = Langzaehler Then 'lange gedrueckt
Gedrueckt = Lang
Else 'einmal kurz gedrueckt
Zaehler = 0
Do
Incr Zaehler
Waitms 10
Loop Until Taster1 = 0 Or Zaehler = Doppelzaehler

If Zaehler = Doppelzaehler Then 'bleibt bei einmal kurz
Gedrueckt = Kurz
Else
Gedrueckt = Doppel 'zweites Mal kurz gedrueckt
End If
End If
Return




Vielen Dank wieder für Hinweise!

LG MM

Searcher
27.10.2012, 09:05
Hi,





Pind.0 = 1 'Pullups für den Drehencoder
Pind.1 = 1
Pind.3 = 1


Um die Pullups einzuschalten muß es Portd.0, Portd.1 und Portd.3 = 1 heißen.

Weis nicht, ob es das Problem behebt und hab sonst erstmal keine Idee. Wenn die Pullups nicht eingeschaltet sind (wie bei dir) und die Außenbeschaltung nicht dementsprechend ist (externe Pullups), können sich die Eingänge Störimpulse einfangen, insbesondere vielleicht von dem Taster.

Was genau für ein Encoder ist das und wie ist er an dem µC angschlossen?

Gruß
Searcher

MrMiffy08
27.10.2012, 12:17
Hallo Searcher,

die Pullup-Bezeichnung habe ich umbenannt, das Phänomen ist wie zuvor. Ruckelnder Schrittmotor, aber gleichmäßig, sieht nicht nach Störungen aus sondern wie was rhythmisches.
Der ALPS Drehencoder (STEC12E08 (http://www.reichelt.de/Drehimpulsgeber/STEC12E08/3/index.html?;ACTION=3;LA=2;ARTICLE=73923;GROUPID=37 14;artnr=STEC12E08;SID=28xO05TKwQARwAAEzgAcE20b9f2 1fae70d6f7b56189d574aa3b9a)) ist auf einem kleinen Platinchen verlötet mit einer LED, ich habe eine Version mit 100nF X7F an den Impulskontakten und eine ohne Kondensatoren, verbunden über 10 cm Flachbandkabel, beide verhalten sich gleich.
Von der Motor Hardware habe ich auch zwei Versionen zum Gegenprüfen, einmal die mit dem Allegro A3967 und einmal eine mit dem kleinen Pololu Board md09b (http://www.watterott.com/de/Pololu-A4983-Schrittmotortreiber) mit dem A4983, beide machen identische Zuckungen (alles im Vollschrittbetrieb, aber selbst Achtelstep sieht komisch aus...) mit dem Programm. Ich hab das mal auf Youtube eingestellt: Link (http://youtu.be/9pbgNcI0jck)

Was haltet Ihr davon?

Searcher
27.10.2012, 12:53
Das sieht ja echt so aus, als wenn der Stepper manchmal nicht wüßte wohin :-)
Auf die Schnelle würd ich sagen, könnte es in der Case Bedingung liegen.

Die Variable Gedrueckt hat ja immer einen Wert und demzufolge wird immer was getoggelt. Da müßte man eindeutige Verhältnisse schaffen. Also Wenn Kurz, dann Chip_enable = ein (und nicht Toggeln) oder so. Hab jetzt keinen konkreten Vorschlag dafür, aber sollte man vielleicht mal genauer unter die Lupe nehmen.

Denke nicht:confused:, daß der Timer gestört wird.

Gruß
Searcher

Searcher
27.10.2012, 13:25
Hi, mein Verdacht erhärtet sich.
Wenn Gedrueckt den Wert Lang enthält und der Taster nicht betätigt wird, wird 6 mal ganz kurz hintereinander Chip_dir getoggelt.
Danach eine Sekunde Pause und danach wieder von vorne.

Um das zu überprüfen, statt Toggle das Chip_dir einfach mit einem festen Wert versorgen und schauen was passiert. Also in der Case Bedingung "Chip_dir = 0" und am besten auch gleich "Chip_enable = 0" (Chip_enable = 1 je nachdem, damit der Motor läuft)

Wenn der Motor dann wieder ruhig läuft, muß man sich die ganze Tastenabfrage/-auswertung vornehmen

PS:



Case Lang:
For I = 1 To 6
Toggle Chip_dir
Next I
Wait 1 'Sollte dieses Wait nicht innerhalb der For Next stehen:confused:
Case Doppel:

Gruß
Searcher

Searcher
27.10.2012, 16:21
Und nochmal :-)
$hwstack muß auf mindestens 34 erhöht werden.
Die ISR verlangt 32 und ein Unterprogramm nochmal 2, weil während der Abarbeitung eines Unterprogrammes die Timer-ISR auftreten kann.
http://halvar.at/elektronik/kleiner_bascom_avr_kurs/speicher_hwstack_swstack_frame/

PS: Sollte aber nichts mit dem Problem zu tun haben. Hab es gerade simuliert und danach würden 32 auch ausreichen.

Gruß
Searcher

MrMiffy08
27.10.2012, 17:41
Hallo Searcher,

ich hab jetzt wie Du vorschlägst den hwstack erhöht, dann den Langdrück-Kram mal kpl. auskommentiert und die beiden Waits bei Kurz und Doppel rausgenommen, der Schritti verhält sich immer noch so komisch mit den Zuckungen. Das ist doch äußerst suspekt, oder?
Es muss in der Tastenabfrage stecken, denn ohne diese ist der Motor einwandfrei gelaufen.
Ich hab diese erste Version noch extra gesichert um die Änderungen gegenzuprüfen.

So läuft er einwandfrei:


$regfile = "attiny2313.dat"
$crystal = 8000000
$hwstack = 34
$swstack = 32
$framesize = 40
$baud = 9600
' BASCOM-Programm
' Stefan Hoffmann 2009
' Drehimpulsgeber/Encoder mit ENCODER-Befehl
'
' In: Drehimpulsgeber an d.0 und d.1 sowie Taster

' Testprogramm für A3967 Platine mit Dir Step und Enable

$regfile = "attiny2313.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 8000000 'Interner Osz. 8 MHz
$baud = 9600


Config Timer0 = Timer , Prescale = 1024 'Timer0 Deklarationen für den Takt des Steppers
Enable Timer0
Dim Timer0_reload As Word
Portd.4 = 1 'Pullup Widerstand ein für Enable - ****Enable =0 bedeutet Motor On!!!! ****
Enable Interrupts
On Timer0 Isr_timer0 'Deklaration der Timerroutine

' Inputs: Drehimpulsgeber an d.0 und d.1 sowie Taster an d.3
'-----Deklarationen fuer Drehimpulsgeber:
Config Pind.0 = Input
Encoder_a Alias Pind.0 'Encoder Signal B an Pin 2
Config Pind.1 = Input
Encoder_b Alias Pind.1 'Encoder Signal A an Pin 3
Config Pind.3 = Input
Taster1 Alias Pind.3 'Taster

Portd.0 = 1 'Pullups für den Drehencoder
Portd.1 = 1
Portd.3 = 1
'LED-Outputs stellvertretend für Step, Dir, Enable
' In der endgültigen Hardware liegen: Step/Takt auf PD.2 / Taster auf PD.3 / Enable auf PD4 / Richtung auf PD5 /
Config Portd.2 = Output
Portd.2 = 0 'das ist Step/Takt - Pin 6 - alles mit Pulldown + LEd_gelb
Config Portd.5 = Output
Portd.5 = 0 ' Pin 9 - Dir - Richtungssignal
Config Portd.4 = Output
Portd.4 = 0 ' Pin 16 - Enable - generelles Ein-Ausschaltsignal
Config Portb.0 = Output
Portb.0 = 0 'Pin 9 - LED_DE - am Drehencoder Anzeige

Motor_step Alias Portd.2
Chip_dir Alias Portd.5
Chip_enable Alias Portd.4

Dim Wert As Word
Wert = 2 'experimentell ermittelter Startwert für den Drehencoder
Dim Zustand As Byte
'*****************Deklarationen für den Taster - am DE - für die Lang-kurz- und Doppelklickroutine


'***********Hauptschleife:**********
Do

Chip_enable = 0 'Enable ein
Chip_dir = 1 'Dir


Zustand = Encoder(pind.0 , Pind.1 , Linksroutine , Rechtsroutine , 0)




Loop

End


'*****************Subroutine Tasterauswertung *****************************


'**********************Interrupt-Routine Timer0 ************************************
Isr_timer0:
Timer0_reload = 4 'Vorgabe für 38 / sec
Timer0 = Timer0_reload + Wert
Toggle Motor_step '= Stepper_takt
Return


'***********************Sub-Routinen Drehencoder ***********************************
Linksroutine:
Decr Wert
If Wert < 1 Then
Wert = 1
End If
Return

Rechtsroutine:
Incr Wert
If Wert > 230 Then
Wert = 230
End If
Return



Und so, mit Deinen Änderungen, läuft er mit Zuckungen:

$regfile = "attiny2313.dat"
$crystal = 8000000
$hwstack = 32
$swstack = 10
$framesize = 40
$baud = 9600
' BASCOM-Programm
' Stefan Hoffmann 2009
' Drehimpulsgeber/Encoder mit ENCODER-Befehl
'
' In: Drehimpulsgeber an d.0 und d.1 sowie Taster

' Testprogramm für A3967 Platine mit Dir Step und Enable

$regfile = "attiny2313.dat"
$framesize = 32
$swstack = 32
$hwstack = 34
$crystal = 8000000 'Interner Osz. 8 MHz
$baud = 9600


Config Timer0 = Timer , Prescale = 1024 'Timer1 Deklarationen für den Takt des Steppers
Enable Timer0
Dim Timer0_reload As Word
Portd.4 = 1 'Pullup Widerstand ein für Enable - ****Enable =0 bedeutet Motor On!!!! ****
Enable Interrupts
On Timer0 Isr_timer0 'Deklaration der Timerroutine

' Inputs: Drehimpulsgeber an d.0 und d.1 sowie Taster an d.3
'-----Deklarationen fuer Drehimpulsgeber:
Config Pind.0 = Input
Encoder_a Alias Pind.0 'Encoder Signal B an Pin 2
Config Pind.1 = Input
Encoder_b Alias Pind.1 'Encoder Signal A an Pin 3
Config Pind.3 = Input
Taster1 Alias Pind.3 'Taster

Portd.0 = 1 'Pullups für den Drehencoder
Portd.1 = 1
Portd.3 = 1
'LED-Outputs stellvertretend für Step, Dir, Enable
' In der endgültigen Hardware liegen: Step/Takt auf PD.2 / Taster auf PD.3 / Enable auf PD4 / Richtung auf PD5 /
Config Portd.2 = Output
Portd.2 = 0 'das ist Step/Takt - Pin 6 - alles mit Pulldown + LEd_gelb
Config Portd.5 = Output
Portd.5 = 0 ' Pin 9 - Dir - Richtungssignal
Config Portd.4 = Output
Portd.4 = 0 ' Pin 16 - Enable - generelles Ein-Ausschaltsignal
Config Portb.0 = Output
Portb.0 = 0 'Pin 9 - LED_DE - am Drehencoder Anzeige

Motor_step Alias Portd.2
Chip_dir Alias Portd.5
Chip_enable Alias Portd.4

Dim Wert As Word
Wert = 2 'experimentell ermittelter Startwert für den Drehencoder
Dim Zustand As Byte
'*****************Deklarationen für den Taster - am DE - für die Lang-kurz- und Doppelklickroutine
Dim Zaehler As Byte
Const Langzaehler = 100 'Danach gilt die Taste als lange gedrueckt
Const Doppelzaehler = 20 'Innerhalb dessen muss zweiter Klick erfolgen
Dim Gedrueckt As Byte 'Art des Drueckens (Kurz/Lang/Doppel)
Const Kurz = 1
Const Lang = 2
Const Doppel = 3
Dim I As Byte


'***********Hauptschleife:**********
Do

Chip_enable = 0 'Enable ein
Chip_dir = 1 'Dir


Zustand = Encoder(pind.0 , Pind.1 , Linksroutine , Rechtsroutine , 0)


Debounce Taster1 , 0 , Tastenauswertung , Sub

Select Case Gedrueckt 'Hier koennen beliebige Anweisungen erfolgen
Case Kurz: 'Es wurde einmal kurz gedrueckt
Chip_enable = 1 'Motor stoppen

Case Lang: 'Die Taste wurde lange gedrueckt
' For I = 1 To 6
' Toggle Chip_dir
'Next I
'Wait 1

Case Doppel: 'Die Taste wurde doppelt gedrueckt
Chip_enable = 0 'Motor wieder an

End Select

Portd.2 = 0
Portd.5 = 0
Portb.4 = 0


Loop

End

'**********************Interrupt-Routine Timer0 ************************************
Isr_timer0:
Timer0_reload = 4 'Vorgabe für 38 / sec
Timer0 = Timer0_reload + Wert
Toggle Motor_step '= Stepper_takt
Return

'***********************Sub-Routinen Drehencoder ***********************************
Linksroutine:
Decr Wert
If Wert < 1 Then
Wert = 1
End If
Return

Rechtsroutine:
Incr Wert
If Wert > 230 Then
Wert = 230
End If
Return

'*****************Subroutine Tasterauswertung *****************************
Tastenauswertung:
Zaehler = 0
Do
Incr Zaehler
Waitms 10
Loop Until Taster1 = 1 Or Zaehler = Langzaehler

If Zaehler = Langzaehler Then 'lange gedrueckt
Gedrueckt = Lang
Else 'einmal kurz gedrueckt
Zaehler = 0
Do
Incr Zaehler
Waitms 10
Loop Until Taster1 = 0 Or Zaehler = Doppelzaehler

If Zaehler = Doppelzaehler Then 'bleibt bei einmal kurz
Gedrueckt = Kurz
Else
Gedrueckt = Doppel 'zweites Mal kurz gedrueckt
End If
End If
Return



(Die Schleife bei "Lang" soll übrigens dazu dienen den Motor 6 sec. lang in die eine und dann in die andere Richtung laufen zu lassen. Geht das überhaupt so?)

Aber zuerst zum Problem des Zuckens. Das tritt auch auf wenn die Taste gar nicht gedrückt wurde, also die Sub selbst kann es wohl nicht sein, aber wo klemmt es denn dann? Sehr merkwürdig.

Danke für Deine Hilfe!

LG MM

Searcher
27.10.2012, 18:19
Und so, mit Deinen Änderungen, läuft er mit Zuckungen:

$regfile = "attiny2313.dat"
$crystal = 8000000
$hwstack = 34
$swstack = 10
$framesize = 40
$baud = 9600
' BASCOM-Programm
' Stefan Hoffmann 2009
' Drehimpulsgeber/Encoder mit ENCODER-Befehl
'
' In: Drehimpulsgeber an d.0 und d.1 sowie Taster

' Testprogramm für A3967 Platine mit Dir Step und Enable

$regfile = "attiny2313.dat"
$framesize = 32
$swstack = 32
$hwstack = 34
$crystal = 8000000 'Interner Osz. 8 MHz
$baud = 9600


Config Timer0 = Timer , Prescale = 1024 'Timer1 Deklarationen für den Takt des Steppers
Enable Timer0
Dim Timer0_reload As Word
Portd.4 = 1 'Pullup Widerstand ein für Enable - ****Enable =0 bedeutet Motor On!!!! ****
Enable Interrupts
On Timer0 Isr_timer0 'Deklaration der Timerroutine

' Inputs: Drehimpulsgeber an d.0 und d.1 sowie Taster an d.3
'-----Deklarationen fuer Drehimpulsgeber:
Config Pind.0 = Input
Encoder_a Alias Pind.0 'Encoder Signal B an Pin 2
Config Pind.1 = Input
Encoder_b Alias Pind.1 'Encoder Signal A an Pin 3
Config Pind.3 = Input
Taster1 Alias Pind.3 'Taster

Portd.0 = 1 'Pullups für den Drehencoder
Portd.1 = 1
Portd.3 = 1
'LED-Outputs stellvertretend für Step, Dir, Enable
' In der endgültigen Hardware liegen: Step/Takt auf PD.2 / Taster auf PD.3 / Enable auf PD4 / Richtung auf PD5 /
Config Portd.2 = Output
Portd.2 = 0 'das ist Step/Takt - Pin 6 - alles mit Pulldown + LEd_gelb
Config Portd.5 = Output
Portd.5 = 0 ' Pin 9 - Dir - Richtungssignal
Config Portd.4 = Output
Portd.4 = 0 ' Pin 16 - Enable - generelles Ein-Ausschaltsignal
Config Portb.0 = Output
Portb.0 = 0 'Pin 9 - LED_DE - am Drehencoder Anzeige

Motor_step Alias Portd.2
Chip_dir Alias Portd.5
Chip_enable Alias Portd.4

Dim Wert As Word
Wert = 2 'experimentell ermittelter Startwert für den Drehencoder
Dim Zustand As Byte
'*****************Deklarationen für den Taster - am DE - für die Lang-kurz- und Doppelklickroutine
Dim Zaehler As Byte
Const Langzaehler = 100 'Danach gilt die Taste als lange gedrueckt
Const Doppelzaehler = 20 'Innerhalb dessen muss zweiter Klick erfolgen
Dim Gedrueckt As Byte 'Art des Drueckens (Kurz/Lang/Doppel)
Const Kurz = 1
Const Lang = 2
Const Doppel = 3
Dim I As Byte


'***********Hauptschleife:**********
Do

Chip_enable = 0 'Enable ein
Chip_dir = 1 'Dir


Zustand = Encoder(pind.0 , Pind.1 , Linksroutine , Rechtsroutine , 0)


Debounce Taster1 , 0 , Tastenauswertung , Sub

Select Case Gedrueckt 'Hier koennen beliebige Anweisungen erfolgen
Case Kurz: 'Es wurde einmal kurz gedrueckt
Chip_enable = 0 'Motor stoppen, 0 für starten ?

Case Lang: 'Die Taste wurde lange gedrueckt
For I = 1 To 6
Chip_dir = 0
Wait 1
Next I

Case Doppel: 'Die Taste wurde doppelt gedrueckt
Waitms 500 'ursprüngliches Programm, Motor wieder an

End Select

Portd.2 = 0
Portd.5 = 0
Portb.4 = 0


Loop

End

'**********************Interrupt-Routine Timer0 ************************************
Isr_timer0:
Timer0_reload = 4 'Vorgabe für 38 / sec
Timer0 = Timer0_reload + Wert
Toggle Motor_step '= Stepper_takt
Return

'***********************Sub-Routinen Drehencoder ***********************************
Linksroutine:
Decr Wert
If Wert < 1 Then
Wert = 1
End If
Return

Rechtsroutine:
Incr Wert
If Wert > 230 Then
Wert = 230
End If
Return

'*****************Subroutine Tasterauswertung *****************************
Tastenauswertung:
Zaehler = 0
Do
Incr Zaehler
Waitms 10
Loop Until Taster1 = 1 Or Zaehler = Langzaehler

If Zaehler = Langzaehler Then 'lange gedrueckt
Gedrueckt = Lang
Else 'einmal kurz gedrueckt
Zaehler = 0
Do
Incr Zaehler
Waitms 10
Loop Until Taster1 = 0 Or Zaehler = Doppelzaehler

If Zaehler = Doppelzaehler Then 'bleibt bei einmal kurz
Gedrueckt = Kurz
Else
Gedrueckt = Doppel 'zweites Mal kurz gedrueckt
End If
End If
Return


(Die Schleife bei "Lang" soll übrigens dazu dienen den Motor 6 sec. lang in die eine und dann in die andere Richtung laufen zu lassen. Geht das überhaupt so?)

Aber zuerst zum Problem des Zuckens. Das tritt auch auf wenn die Taste gar nicht gedrückt wurde, also die Sub selbst kann es wohl nicht sein, aber wo klemmt es denn dann? Sehr merkwürdig.


Die Änderungen hab ich mehr so gemeint: Rot = Änderungen
[edit] gerade entdeckt, blau ist doppelt
Hab wenig Hoffnung daß es dann wirklich rund läuft.
Zum 6 sec rechts oder links Lauf muß das wait 1 in der For Next Schleife stehen - siehe die rote Änderung.

Nur noch eine eine Idee für heute: Das ursprüngliche Programm mit dem Debounce - Tastenabfrage bei dem es nicht rund läuft: Was passiert, wenn Du nur die Debounce Zeile auskommentierst?

Ich weis nicht, ob das Debounce den Timer beeinflußt - in der Doku ist nichts zu finden. Vom Video her scheint die Laufrichtung zu wechseln :confused: :confused: :confused:

Gruß
Searcher

MrMiffy08
27.10.2012, 18:54
Hallo Searcher,

danke für Deine Geduld. Habe jetzt noch Deine Änderungen versucht:
der blaue Doppel-Quatsch weg, die roten Änderungen rein: Gleiches Verhalten. und nein, auch mit dem auskommentieren der Debounce-Zeile alleine ist das gleiche Zucken da, nur wenn die Sub mit weg ist läuft er gleichmäßig. Zum Haareraufen, ich mach jetzt auch erst mal Schluss, Dir einen schönen und erholsamen Abend, ein lecker Bierchen vielleicht und ein schöner Film! Ich geh mit meinem Jüngsten noch bisschen Basteln...

LG MM

Searcher
27.10.2012, 18:58
OK, ich merke auch, wie ich den Überblick verliere, falls ich ihn gehabt habe :-)
Mal drüber schlafen und schönen Abend noch.

Vielleicht hat hier noch jemand anderes eine Eingebung.

Ansonsten hilft alles verwerfen und ein anderes Konzept/ Aufbau des Programms.

Gruß
Searcher

Searcher
28.10.2012, 09:23
Alles frisch? Ich hab das Pech, daß ich mich immer verbeißen muß und habe heute noch mal ein bißchen simuliert (im BASCOM Simulator :-) )

Ausgehend von Deinem Programm vom 28.10., 1:52h (https://www.roboternetz.de/community/threads/59523-Bascom-Schrittmotorsteuerung-mit-Drehencoder?p=562617&viewfull=1#post562617) habe ich das Zucken zunächst eliminiert - hoffe ich. Verantwortlich war das "Portd.5 = 0" kurz vor Ende der Hauptschleife.

Dann noch ein paar Änderungen nach meinem Gutdünken eingebracht. Siehe Remarks im Programm.

Die Tastensteuerung und auch die Drehzahlsteuerung ist ungut, da sie immer haupsächlich auf die Richtungswechsel warten muß. Die Richtungswechsel würd ich als erstes wieder rausnehmen, da ich mir kaum vorstellen kann, daß man das gut steuern kann. Soll nur eine Demo sein.

Hoffe, daß endlich das Zucken weg ist. Bin auf Erfahrungbericht gespannt und bitte gerne Nachfragen.


' BASCOM-Programm
' Stefan Hoffmann 2009
' Drehimpulsgeber/Encoder mit ENCODER-Befehl
'
' In: Drehimpulsgeber an d.0 und d.1 sowie Taster

' Testprogramm für A3967 Platine mit Dir Step und Enable
' Modifiziert von Searcher

$regfile = "attiny2313.dat"
$framesize = 32
$swstack = 32
$hwstack = 34 '1. 32 nach 43 geändert
$crystal = 8000000 'Interner Osz. 8 MHz
$baud = 9600

' Inputs: Drehimpulsgeber an d.0 und d.1 sowie Taster an d.3
'-----Deklarationen fuer Drehimpulsgeber:
Config Pind.0 = Input
Encoder_a Alias Pind.0 'Encoder Signal B an Pin 2
Config Pind.1 = Input
Encoder_b Alias Pind.1 'Encoder Signal A an Pin 3
Config Pind.3 = Input
Taster1 Alias Pind.3 'Taster

Portd.0 = 1 'Pullups für den Drehencoder
Portd.1 = 1 '2. pind nach portd geändert
Portd.3 = 1
'LED-Outputs stellvertretend für Step, Dir, Enable
' In der endgültigen Hardware liegen: Step/Takt auf PD.2 / Taster auf PD.3 / Enable auf PD4 / Richtung auf PD5 /
Config Portd.2 = Output
Portd.2 = 0 'das ist Step/Takt - Pin 6 - alles mit Pulldown + LEd_gelb
Config Portd.5 = Output
Portd.5 = 0 ' Pin 9 - Dir - Richtungssignal
Config Portd.4 = Output
Portd.4 = 0 ' Pin 16 - Enable - generelles Ein-Ausschaltsignal
Config Portb.0 = Output
Portb.0 = 0 'Pin 9 - LED_DE - am Drehencoder Anzeige

Motor_step Alias Portd.2
Chip_dir Alias Portd.5
Chip_enable Alias Portd.4

Dim Wert As Word
Wert = 2 'experimentell ermittelter Startwert für den Drehencoder
Dim Zustand As Byte
'*****************Deklarationen für den Taster - am DE - für die Lang-kurz- und Doppelklickroutine
Dim Zaehler As Byte
Const Langzaehler = 100 'Danach gilt die Taste als lange gedrueckt
Const Doppelzaehler = 20 'Innerhalb dessen muss zweiter Klick erfolgen
Dim Gedrueckt As Byte 'Art des Drueckens (Kurz/Lang/Doppel)
Const Kurz = 1
Const Lang = 2
Const Doppel = 3
Dim I As Byte

Chip_enable = 1 'Motor aus 'Enable ein raus aus der Hauptschleife
Chip_dir = 1 'Dir raus aus der Hauptschleife

'Timer und ISR erst loslaufen lassen, wenn mit Chip_enable Motor aus ist
Config Timer0 = Timer , Prescale = 1024 'Timer1 Deklarationen für den Takt des Steppers
Dim Timer0_reload As Word
'Portd.4 = 1 'Pullup Widerstand ein für Enable - ****Enable =0 bedeutet Motor On!!!! ****
On Timer0 Isr_timer0 'Deklaration der Timerroutine
Enable Timer0 'Enable Timer0 nach "On Timer0 Isr..."
Enable Interrupts

'***********Hauptschleife:**********

Do

Zustand = Encoder(pind.0 , Pind.1 , Linksroutine , Rechtsroutine , 0)

Debounce Taster1 , 0 , Tastenauswertung , Sub

Select Case Gedrueckt 'Hier koennen beliebige Anweisungen erfolgen
Case Kurz: 'Es wurde einmal kurz gedrueckt
Chip_enable = 0 'Motor ein bei einmal kurz gedrückt
Waitms 100
Case Lang: 'Die Taste wurde lange gedrueckt
For I = 1 To 6
Toggle Chip_dir
Wait 6 'Wenn lang gedrückt, wechselt Motor alle 6 Sekunden die Laufrichtung
Next I

Case Doppel: 'Die Taste wurde doppelt gedrueckt
Chip_enable = 1 'Motor aus wenn doppelt gedrückt
Waitms 500
End Select


' Portd.2 = 0 'das ist Motorstep
' Portd.5 = 0 'das ist Chip_dir, Verursacher vom Zappeln !!!
' Portb.4 = 0 'das ist ???


Loop

End

'**********************Interrupt-Routine Timer0 ************************************
Isr_timer0:
Timer0_reload = 4 'Vorgabe für 38 / sec
Timer0 = Timer0_reload + Wert
Toggle Motor_step '= Stepper_takt
Return

'***********************Sub-Routinen Drehencoder ***********************************
Linksroutine:
Decr Wert
If Wert < 1 Then
Wert = 1
End If
Return

Rechtsroutine:
Incr Wert
If Wert > 230 Then
Wert = 230
End If
Return

'*****************Subroutine Tasterauswertung *****************************
Tastenauswertung:
Zaehler = 0
Do
Incr Zaehler
Waitms 10
Loop Until Taster1 = 1 Or Zaehler = Langzaehler

If Zaehler = Langzaehler Then 'lange gedrueckt
Gedrueckt = Lang
Else 'einmal kurz gedrueckt
Zaehler = 0
Do
Incr Zaehler
Waitms 10
Loop Until Taster1 = 0 Or Zaehler = Doppelzaehler

If Zaehler = Doppelzaehler Then 'bleibt bei einmal kurz
Gedrueckt = Kurz
Else
Gedrueckt = Doppel 'zweites Mal kurz gedrueckt
End If
End If
Return

Gruß
Searcher

MrMiffy08
28.10.2012, 13:14
Hallo Searcher,

Du bist genial!!! In der Tat war es wohl dieses Setzen von Chip_dir und Chip_enable in der Hauptschleife das diese Zuckungen verursacht. Ich hab jetzt nur mal Deinen letzten Code reingeschossen und damit läuft der Schritti jetzt wunderbar weich und regelmäßig und wird genau nach meinen Vorstellungen gestoppt, hin und her gedreht und wieder gestartet - einfach klasse!
Allerdings ist jetzt die Geschwindigkeitsregelung abhanden gekommen, ich schau mir das noch mal an, komme heute abend wieder rein.

Searcher
28.10.2012, 16:34
Das genial überhöre ich mal;) aber trotzdem Danke. Nach den ganzen Versuchen kann ich das gar nicht glauben.

Allerdings ist jetzt die Geschwindigkeitsregelung abhanden gekommen
Sollte gehen, wenn der Stepper nicht in dem Laufrichtungswechselmodus ist :confused:

Nochmal was zum reinschießen:). Die Zeiten und Anzahl der Laufrichtungsumschaltungen wird nun in einer neuen ISR von Timer1 gemacht. Vorteil soll sein, daß die Hauptschleife nicht von "wait" aufgehalten wird und die Taster-/Encoderabfragen öfter dran kommen. Das Grüne ist neu gegenüber der letzten Version. Kann ich leider kaum testen, da ich keine HW dafür hab.

' BASCOM-Programm
' Stefan Hoffmann 2009
' Drehimpulsgeber/Encoder mit ENCODER-Befehl
'
' In: Drehimpulsgeber an d.0 und d.1 sowie Taster

' Testprogramm für A3967 Platine mit Dir Step und Enable
' Modifiziert von Searcher die zweite mit zusätzlichem Timer1

$regfile = "attiny2313.dat"
$framesize = 32
$swstack = 32
$hwstack = 34 '1. 32 nach 34 geändert
$crystal = 8000000 'Interner Osz. 8 MHz
$baud = 9600

' Inputs: Drehimpulsgeber an d.0 und d.1 sowie Taster an d.3
'-----Deklarationen fuer Drehimpulsgeber:
Config Pind.0 = Input
Encoder_a Alias Pind.0 'Encoder Signal B an Pin 2
Config Pind.1 = Input
Encoder_b Alias Pind.1 'Encoder Signal A an Pin 3
Config Pind.3 = Input
Taster1 Alias Pind.3 'Taster

Portd.0 = 1 'Pullups für den Drehencoder
Portd.1 = 1 '2. pind nach portd geändert
Portd.3 = 1
'LED-Outputs stellvertretend für Step, Dir, Enable
' In der endgültigen Hardware liegen: Step/Takt auf PD.2 / Taster auf PD.3 / Enable auf PD4 / Richtung auf PD5 /
Config Portd.2 = Output
Portd.2 = 0 'das ist Step/Takt - Pin 6 - alles mit Pulldown + LEd_gelb
Config Portd.5 = Output
Portd.5 = 0 ' Pin 9 - Dir - Richtungssignal
Config Portd.4 = Output
Portd.4 = 0 ' Pin 16 - Enable - generelles Ein-Ausschaltsignal
Config Portb.0 = Output
Portb.0 = 0 'Pin 9 - LED_DE - am Drehencoder Anzeige

Motor_step Alias Portd.2
Chip_dir Alias Portd.5
Chip_enable Alias Portd.4

Dim Wert As Word
Wert = 2 'experimentell ermittelter Startwert für den Drehencoder
Dim Zustand As Byte
'*****************Deklarationen für den Taster - am DE - für die Lang-kurz- und Doppelklickroutine
Dim Zaehler As Byte
Const Langzaehler = 100 'Danach gilt die Taste als lange gedrueckt
Const Doppelzaehler = 20 'Innerhalb dessen muss zweiter Klick erfolgen
Dim Gedrueckt As Byte 'Art des Drueckens (Kurz/Lang/Doppel)
Const Kurz = 1
Const Lang = 2
Const Doppel = 3
Dim I As Byte

Chip_enable = 1 'Motor aus 'Enable ein raus aus der Hauptschleife
Chip_dir = 1 'Dir raus aus der Hauptschleife

'Timer und ISR erst loslaufen lassen, wenn mit Chip_enable Motor aus ist
Config Timer0 = Timer , Prescale = 1024 'Timer1 Deklarationen für den Takt des Steppers
Dim Timer0_reload As Word
On Timer0 Isr_timer0 'Deklaration der Timerroutine
Enable Timer0 'Enable Timer0 nach "On Timer0 Isr..."

Const Anz_umschaltungen = 6 'Hier Anzahl der Laufrichtungsumschaltungen festlegen, mindestens 2
Dim Umschaltungen As Byte 'Zählt Laufrichtungsumschaltungen
Umschaltungen = 0 'initialiesieren (ist aber an dieser Programmstelle sowieso = 0)
Dim Sekunden As Byte 'Dient zum Abzählen von Sekunden in der Isr_Sekunden_takt
Sekunden = 1 'initialisieren
Config Timer1 = Timer , Prescale = 256 , Clear Timer = 1 'Clear Timer on Compare Match
Compare1a = 31249 'Wert für eine Sekunde, Timer fängt nach einer Sekunde wieder bei 0 an
On Compare1a Isr_sekunden_takt
'Compare1a Interrupt wird erst in der Haupschleife enabled

Enable Interrupts

'***********Hauptschleife:**********

Do
Zustand = Encoder(pind.0 , Pind.1 , Linksroutine , Rechtsroutine , 0)

Debounce Taster1 , 0 , Tastenauswertung , Sub

Select Case Gedrueckt 'Hier koennen beliebige Anweisungen erfolgen
Case Kurz: 'Es wurde einmal kurz gedrueckt
Chip_enable = 0 'Motor ein bei einmal kurz gedrückt
Case Lang: 'Die Taste wurde lange gedrueckt
If Timsk.ocie1a = 0 Then 'Wenn Comparematchinterrupt nicht enabled, dann..
Toggle Chip_dir 'Sofort Laufrichtung umschalten
Incr Umschaltungen 'Zähler für Laufrichtungsumschaltungen erhöhen
Timer1 = 0 'Timercounter von Beginn an laufen lassen
set Tifr.Ocf1a 'vorsorglich interruptflag löschen
Enable Compare1a 'ISR für Sekundenzählen und Chip_dir Toggle einschalten
Else
If Umschaltungen = Anz_umschaltungen Then 'Wenn genug Umschaltungen, dann aufhören
Disable Compare1a 'Isr für Chip_dir toggle abschalten
Sekunden = 1 'Für nächsten Gebrauch initialisieren
Umschaltungen = 0 'Für nächsten Gebrauch initialisieren
Gedrueckt = Kurz 'Flicken wg. vermuteter Macke
End If
End If
Case Doppel: 'Die Taste wurde doppelt gedrueckt
Chip_enable = 1 'Motor aus wenn doppelt gedrückt
Disable Compare1a 'Isr für Chip_dir toggle abschalten
Sekunden = 1 'Für nächsten Gebrauch initialisieren
Umschaltungen = 0 'Für nächsten Gebrauch initialisieren
End Select
Loop

End

'**********************Interrupt-Routine Timer1 Sekundentakt ***********************
Isr_sekunden_takt: 'ISR toggelt alle 6 Sekunden den Chip_dir
If Sekunden < 6 Then 'solange noch keine 6 Mal durchlaufen ...
Incr Sekunden '...nur inkrementieren
Else 'sonst ...
Sekunden = 1 'Sekundenzähler zurücksetzten und ...
Toggle Chip_dir '... Laufrichtung umschalten
Incr Umschaltungen 'Zähler für Laufrichtungsumschaltungen erhöhen
End If
Return

'**********************Interrupt-Routine Timer0 ************************************
Isr_timer0:
Timer0_reload = 4 'Vorgabe für 38 / sec
Timer0 = Timer0_reload + Wert
Toggle Motor_step '= Stepper_takt
Return

'***********************Sub-Routinen Drehencoder ***********************************
Linksroutine:
Decr Wert
If Wert < 1 Then
Wert = 1
End If
Return

Rechtsroutine:
Incr Wert
If Wert > 230 Then
Wert = 230
End If
Return

'*****************Subroutine Tasterauswertung *****************************
Tastenauswertung:
Zaehler = 0
Do
Incr Zaehler
Waitms 10
Loop Until Taster1 = 1 Or Zaehler = Langzaehler

If Zaehler = Langzaehler Then 'lange gedrueckt
Gedrueckt = Lang
Else 'einmal kurz gedrueckt
Zaehler = 0
Do
Incr Zaehler
Waitms 10
Loop Until Taster1 = 0 Or Zaehler = Doppelzaehler

If Zaehler = Doppelzaehler Then 'bleibt bei einmal kurz
Gedrueckt = Kurz
Else
Gedrueckt = Doppel 'zweites Mal kurz gedrueckt
End If
End If
Return

Gruß
Searcher

MrMiffy08
28.10.2012, 20:58
Hallo searcher,
doch genial!
Diese neue Kombination macht jetzt haargenau was ich mir ausgedacht hatte. Abgesehen von ein paar Verschluckern, wenn man ihn hochregelt, das scheint aber mit Resonanzfrequenzen des verwendeten Motors zu tun zu haben, ein anderer Motor macht das nicht.
Ich werde noch mit den Timerwerten für die Umschaltung experimentieren, aber im Prinzip bin ich gerade wunschlos glücklich! Vielen, vielen Dank für Dein "Durchbeißen" mit diesem Stück Programm, das hätte ich nie zum Laufen gebracht!
Man lernt allerdings daraus auch, dass man nicht alles verstehen muss (warum im vorletzten Stück Code das Regeln der Geschwindigkeit weg ist...), vielleicht knie ich mich da auch noch mal rein. Für den Moment ist es jedenfalls mal gut.

Dir einen schönen Sonntag noch, Searcher, und bis dann mal wieder!

LG MM

Searcher
29.10.2012, 08:46
Freut mich, daß es für Dich paßt. Im Programm kann man aber noch viele Verbesserungen und Optimierungen vornehmen.


Man könnte zB versuchen den Takt für den Stepper HW-mäßig auszugeben.
Dazu den zB den OC0A Pin als Ausgang zum Stepper nutzen. Da ließe sich die Isr_Timer0 sparen
Mit erstem kurzen Tastendruck den Motor einschalten, wie jetzt und mit anderem kurzem Druck den Laufrichtungswechselmodus wieder ausschalten, wenn dieser eingeschaltet ist. Motor läuft weiter nur in eine Richtung.
Programmlesbarkeit/-übersichtlichkeit verbessern
usw.
aber siehe auch meine Signatur :-)



Theorie zur verloren gegangenen Geschwindigkeitsregelung in den alten Versionen:

Debounce und Encoder werden pro Hauptschleifendurchlauf einmal aufgerufen.
Gerade wenn der Laufrichtungswechselmodus läuft, hat der Hauptschleifendurchlauf eine sehr lange Verzögerung in dem entsprechenden Case.

Der Alps liefert an seinen beiden Ausgängen vier verschiedene Zustände.
Die Encoder Funktion vergleicht den Zustand in einem Durchlauf mit dem folgenden Zustand im nächsten Durchlauf.

Vergeht dazwischen viel Zeit, kriegt die Encoder Funktion Zustandswechsel nicht mit, weil von einem Aufruf zum anderen 4 Wechsel stattgefunden haben und könnte dann keine Betätigung erkennen.

Es könnte auch zu falschen Auswertungen kommen; Rechtsdrehung statt Linksdrehung, wenn die Zustände zu weiteren ungünstigen Zeitpunkten erfaßt werden.


Ich bin doch auch nur ein Hobbyprogrammierer und fand in Deinem Problem eine dankbare Aufgabe. Also eigentlich müßte ich Dir danken ;)


PS. Noch eine vermutliche Macke entdeckt und Änderung im letzten Code rot markiert.
Grund: Gedrueckt speichert immer den letzten Zustand und ändert sich erst, wenn
Taste neu betätigt wird. Ohne Änderung wird immer ein neuer Richtungswechselmodus eingeschaltet.

Gutes Gelingen bei Deinem Projekt und
Gruß
Searcher

MrMiffy08
31.10.2012, 20:12
Hallo Searcher, ich komme doch noch mal rein. ICh habe jetzt noch Deinen zuletzt geänderten Code benutzt und dabei stelle ich fest dass es zwei Frequenzen gibt, wo der Steppermotor wieder zuckt, und zwar kurz vor der schnellsten Drehzahl. Die Code Variante wo es sauber lief, habe ich leider nicht mehr, so dass ich auch nicht rauskriege wo es da klemmt. Ich stelle noch mal ein Video rein:

Link zu Youtube.com (http://youtu.be/vOQmfTOc2n0)

Deine Idee mit dem Hardware- Out am 2313 ist interessant, da wird die ISR überflüssig, aber der Timer wird ja trotzdem gebraucht oder? Läuft der dann per Output Compare Modus? Da muss ich mich noch mal reinlesen.

Hast Du zu dem Zappeln im Aktuellen Code noch eine Idee?


Danke wieder für alle Hinweise!

LG MM

(Verflixt, jetzt ist mir heute beim Testen meine Hardware abgeraucht, muss erstmal wieder löten....)

- - - Aktualisiert - - -

Noch mal zurück auf Null:
Das Zappeln scheint an meiner Hardware zu liegen - ich habe mal testweise mein Ansteuerboard mit dem Pololu breakout Board angestöpselt und siehe da: An diesem treiber läuft der erste Stepper und auch der andere den ich daran betreibe wie ne Eins!
Jetzt muss ich mal auf die Suche gehen.
Die Hardware-Ausgabe wird mich noch beschäftigen, das ist in der Tat eine gute Idee.

Schönen Abend noch!

Searcher
01.11.2012, 10:23
Danke für die Rückmeldung. Mit Steppern habe ich nun überhaupt keine Erfahrung. Wenn es um Resonanzen geht, fiel mir im Video auf, daß der fixiert werden könnte.

Ich hatte schon mal ein wenig über Taktausgabe über die HW nachgedacht. Ist gar nicht so einfach, alles ohne ISR zu machen, da die Frequenz des Timers in kleinen Schritten durch den Alps verändert werden soll. Das kann man über Register machen, muß aber aufpassen, daß man nicht zufällig zu bestimmten Zeiten Extremwerte da reinschreibt.

Vielleicht fällt mir noch was ein... mal sehen. Die Aufgabe intressiert mich selber. Schreib ruhig, wenn es was Neues gibt.

Gruß
Searcher

Searcher
02.11.2012, 05:39
So, nach gefühlten 30 days of night war es am Ende doch nicht so schwierig, den Takt über HW auszugeben :?

Dafür wird der Timer0 im fast PWM Modus mit OCRA als Top betrieben. Bei Comparematch wird der Ausgang OC0A getoggelt. UMVERDRAHTEN von PD2 nach PB2
Der Drehgeber verändert mit seinen Impulsen aus der Links-/Rechtsroutine heraus das OCRA Register und ändert damit die Frequenz. Wahrscheinlich hat sich die Wirkung der Drehrichtung geändert. Die Wahl fiel auf PWM Modus, da hier das Update des OCRA nicht sofort geschieht, sondern nur zu einem bestimmten TCNT0 Stand.

Da hatte ich auch gewisse Schwierigkeiten. Nach Datenblatt für Tiny2313 findet der Update bei Zählerstand Top statt. Nun ist OCRA aber Top. Was passiert, wenn getoggelt wird und "gleichzeitig" OCRA verändert wird. Konnte ich dem Datenblatt nicht entnehmen.

Den Fall wird es selten geben, aber er ist vorhanden und wird deshalb auch eintreten (nach Murphy - und nach Drehencoderbetätigung). Vielleicht macht es nichts - Ausprobieren.

Bei zB einem Mega88 wird das OCRA nach Datenblatt bei Bottom upgedated. Da hätte ich überhaupt keine Bedenken.

Ganz sicher bin ich mir wie immer nicht, ob ich den Rest richtig umgeschrieben habe.

Wenn Du ein langes Wochenende hast, könnte es jetzt gelaufen sein ;):)



' BASCOM-Programm
' Stefan Hoffmann 2009
' Drehimpulsgeber/Encoder mit ENCODER-Befehl
'
' In: Drehimpulsgeber an d.0 und d.1 sowie Taster

' Testprogramm für A3967 Platine mit Dir Step und Enable

' Modifiziert von Searcher die dritte mit zusätzlichem Timer1
' Timer0 für HW-Step Ausgabe auf PB2(OC0A) im fast PWM genutzt !!!
' UMVERKABELN: Taktausgabe nun auf PB2 statt PD6

$regfile = "attiny2313.dat"
$framesize = 32
$swstack = 32
$hwstack = 34 '1. 32 nach 34 geändert
$crystal = 8000000 'Interner Osz. 8 MHz
'*** $baud = 9600 aktivieren nur wenn UART auch genutzt wird.

' Inputs: Drehimpulsgeber an d.0 und d.1 sowie Taster an d.3
'-----Deklarationen fuer Drehimpulsgeber:
Config Pind.0 = Input
Encoder_a Alias Pind.0 'Encoder Signal B an Pin 2
Config Pind.1 = Input
Encoder_b Alias Pind.1 'Encoder Signal A an Pin 3
Config Pind.3 = Input
Taster1 Alias Pind.3 'Taster

Portd.0 = 1 'Pullups für den Drehencoder
Portd.1 = 1 '2. pind nach portd geändert
Portd.3 = 1
'LED-Outputs stellvertretend für Step, Dir, Enable
'In der endgültigen Hardware liegen: Step/Takt auf PD.2(PB.2) / Taster auf PD.3 / Enable auf PD4 / Richtung auf PD5 /

Config Portb.2 = Output '!!!!!von PD2 nach PB2(OC0A) geändert !!!!!!!!!!!!

Config Portd.5 = Output
Portd.5 = 0 ' Pin 9 - Dir - Richtungssignal
Config Portd.4 = Output
Portd.4 = 0 ' Pin 16 - Enable - generelles Ein-Ausschaltsignal
Config Portb.0 = Output
Portb.0 = 0 'Pin 9 - LED_DE - am Drehencoder Anzeige

Chip_dir Alias Portd.5
Chip_enable Alias Portd.4

Dim Wert As Byte 'statt word als byte declariert
Wert = 127 'Mit mittlerer Geschwindigkeit anfangen, Startwert für den Drehencoder
Dim Zustand As Byte
'*****************Deklarationen für den Taster - am DE - für die Lang-kurz- und Doppelklickroutine
Dim Zaehler As Byte
Const Langzaehler = 100 'Danach gilt die Taste als lange gedrueckt
Const Doppelzaehler = 20 'Innerhalb dessen muss zweiter Klick erfolgen
Dim Gedrueckt As Byte 'Art des Drueckens (Kurz/Lang/Doppel)
Const Kurz = 1
Const Lang = 2
Const Doppel = 3
Dim I As Byte

Chip_enable = 1 'Motor aus
Chip_dir = 1 'Dir

'************************************************* ******************************
'Neue Timer0 Konfiguration. Hab kein BASCOM Kommando für Timer0 - Fast PWM und OC0A Toggle gefunden
'deshalb "zu Fuß"
Tccr0a = Bits(com0a0 , Wgm01 , Wgm00) 'toggle OC0A, fast PWM
Tccr0b = Bits(wgm02 , Cs02 , Cs00) 'fast PWM - top OCR0A, prescale 1024
'************************************************* ******************************

Const Anz_umschaltungen = 6 'Hier Anzahl der Laufrichtungsumschaltungen festlegen, mindestens 2
Dim Umschaltungen As Byte 'Zählt Laufrichtungsumschaltungen
Umschaltungen = 0 'initialiesieren (ist aber an dieser Programmstelle sowieso = 0)
Dim Sekunden As Byte 'Dient zum Abzählen von Sekunden in der Isr_Sekunden_takt
Sekunden = 1 'initialisieren
Config Timer1 = Timer , Prescale = 256 , Clear Timer = 1 'Clear Timer on Compare Match
Compare1a = 31249 'Wert für eine Sekunde, Timer fängt nach einer Sekunde wieder bei 0 an
On Compare1a Isr_sekunden_takt
'Compare1a Interrupt wird erst in der Haupschleife enabled

Enable Interrupts

'***********Hauptschleife:**********

Do
Zustand = Encoder(pind.0 , Pind.1 , Linksroutine , Rechtsroutine , 0)

Debounce Taster1 , 0 , Tastenauswertung , Sub

Select Case Gedrueckt 'Hier koennen beliebige Anweisungen erfolgen
Case Kurz: 'Es wurde einmal kurz gedrueckt
Chip_enable = 0 'Motor ein bei einmal kurz gedrückt
Case Lang: 'Die Taste wurde lange gedrueckt
If Timsk.ocie1a = 0 Then 'Wenn Comparematchinterrupt nicht enabled, dann..
Toggle Chip_dir 'Sofort Laufrichtung umschalten
Incr Umschaltungen 'Zähler für Laufrichtungsumschaltungen erhöhen
Timer1 = 0 'Timercounter von Beginn an laufen lassen
Set Tifr.ocf1a
Enable Compare1a 'ISR für Sekundenzählen und Chip_dir Toggle einschalten
Else
If Umschaltungen = Anz_umschaltungen Then 'Wenn genug Umschaltungen, dann aufhören
Disable Compare1a 'Isr für Chip_dir toggle abschalten
Sekunden = 1 'Für nächsten Gebrauch initialisieren
Umschaltungen = 0 'Für nächsten Gebrauch initialisieren
Gedrueckt = Kurz 'In Normallauf schalten
End If
End If
Case Doppel: 'Die Taste wurde doppelt gedrueckt
Chip_enable = 1 'Motor aus wenn doppelt gedrückt
Disable Compare1a 'Isr für Chip_dir toggle abschalten
Sekunden = 1 'Für nächsten Gebrauch initialisieren
Umschaltungen = 0 'Für nächsten Gebrauch initialisieren
End Select
Loop

End

'**********************Interrupt-Routine Timer1 Sekundentakt *******************
Isr_sekunden_takt: 'ISR toggelt alle 6 Sekunden den Chip_dir
If Sekunden < 6 Then 'solange noch keine 6 Mal durchlaufen ...
Incr Sekunden '...nur inkrementieren
Else 'sonst ...
Sekunden = 1 'Sekundenzähler zurücksetzten und ...
Toggle Chip_dir '... Laufrichtung umschalten
Incr Umschaltungen 'Zähler für Laufrichtungsumschaltungen erhöhen
End If
Return

'***********************Sub-Routinen Drehencoder ******************************
Linksroutine:
If Wert > 21 Then Decr Wert
Ocr0a = Wert
Return

Rechtsroutine:
If Wert < 250 Then Incr Wert
Ocr0a = Wert
Return

'*****************Subroutine Tasterauswertung **********************************
Tastenauswertung:
Zaehler = 0
Do
Incr Zaehler
Waitms 10
Loop Until Taster1 = 1 Or Zaehler = Langzaehler

If Zaehler = Langzaehler Then 'lange gedrueckt
Gedrueckt = Lang
Else 'einmal kurz gedrueckt
Zaehler = 0
Do
Incr Zaehler
Waitms 10
Loop Until Taster1 = 0 Or Zaehler = Doppelzaehler

If Zaehler = Doppelzaehler Then 'bleibt bei einmal kurz
Gedrueckt = Kurz
Else
Gedrueckt = Doppel 'zweites Mal kurz gedrueckt
End If
End If
Return


PS: Und was ich gerade noch entdeckt habe: Mit der Angabe $baud initialisiert BASCOM die Register für UART. Du hast den Encoder auf RX und TX hängen. Hat anscheinend bisher nichts ausgemacht. Um Verwicklungen zu vermeiden könnte man das auskommentieren. Hab ich gerade noch im Code oben gemacht.

Gruß
Searcher