PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Komisches Drehgeberverhalten!



EDatabaseError
06.11.2006, 17:43
Ich habe folgenden Code um einen Drehgeber auszuwerten (Wird bei jedem Change des Channels A ausgelöst.):



Isr_incremental_encoder:
If Phase_b <> Phase_a Then
Decr Ist
Else
Incr Ist
End If

If Dira = 1 Then
If Ist => 1000 Then
Dira = 0
Dirb = 1
End If
End If

If Dirb = 1 Then
If Ist =< 0 Then
Dira = 1
Dirb = 0
End If
End If

Print Ist
Return

das ganze geht auch ne weile gut aber plötzlich springt er auf >10000 Ink hoch und macht nur noch misst.

Auszug aus Protokoll:

508
509
510
511
512
12846
12846
12846
12847
...

an was kann das liegen und wie kann man das Problem am besten beseitigen?


tobi


edit1: ich hab das ganze auch mal ohne die Motoransteuerung getestet sondern den Motor direkt ans netzteil gehängt. Bringt nix - gleiches Problem

edit2: könnte es vllt an der PWM im hintergrund auf timer0 liegen?

PicNick
06.11.2006, 18:45
If Phase_b <> Phase_a Then
Decr Ist
Else
Incr Ist
End If

Versteh' ich nicht ganz. Meist macht man ISR bei einer bestimmte Flanke von channel-A, und je nachdem ob channel B dann oben oder unten ist, gehts rauf oder runter.

Andere Frage; wie sind die variablen definiert ? mit vorzeichen ? ohne ?

Edit1 Natürlich kann ein wilder Funkenflug stören. Glaub ich aber erstmal eher nicht.
Edit2 Den Zusammenhang seh ich so nicht.

EDatabaseError
06.11.2006, 18:54
der code vergleicht bei jeder flanke von Channel A die Channels und operiert dann. Dies funktioniert auch im großen und ganzen. Ich häng morgen mal den oszi dazu und mal schaun.

Was mich wundert: der selbe algorythmus ist schon mal bei einer anderne Platine verwendet worden die nur zählen musste - also nix arbeiten musste außer plus und minus. und da hat er 1a funktioniert.

da ich mit bascom arbeite und bascom den timer0 gern missbraucht und ich die PWM durch registersetzen auf timer0 gelegt hab frage ich mich ob das das Problem sein könnte?

funkenflug schließ ich mal aus, da er von 512 auf 12846 hochgeflogen ist.

tobi

pongi
06.11.2006, 19:00
Erklär mir bitte den Zusammenhang zwischen Timer0, PWM, und Zähler, daran könnte es liegen. Zb wenn du die Timerintterupts auswertest, kann es da eine Kollision geben. Hast du bei den Interrupts vorher die Arbeitsregister auch alle brav in den Stack hinterlegt, und alle brav -in umgekehrter Reihenfolge- zurückgeladen?

EDatabaseError
06.11.2006, 19:06
ich hab hier mal ein bisschen code:


'--- [ Inizialize compiler ] ---------------------------------------------------
$regfile = "m168def.dat"
$crystal = 16000000
$baud = 9600
$framesize = 32
$swstack = 32
$hwstack = 32

'--- [ Config devices and timers ] ---------------------------------------------

Config Pind.6 = Output
Pwm_out Alias Pind.6

Config Portc.0 = Output
Dira Alias Portc.0

Config Portc.1 = Output
Dirb Alias Portc.1

Audio Alias Portd.5

Config Scl = Portc.5
Config Sda = Portc.4

Config Pinc.3 = Input
Inp_start Alias Pinc.3

Config Pinc.2 = Input
Inp_libelle Alias Pinc.2

Config Portb.0 = Output
Led_red Alias Portb.0

Config Portb.1 = Output
Led_yellow Alias Portb.1

Config Portb.2 = Output
Led_green Alias Portb.2

Inp_stop Alias Pind.2

Phase_a Alias Pind.3
Phase_b Alias Pind.4

'Timer0 as PWM
Tccr0a = &B11000001
Tccr0b = &B00000001
Tcnt0 = &B00000000
Timsk0 = &B00000000
Tifr0 = &B00000000
Ocr0a = 255

'Timer1 as clock
Config Timer1 = Timer , Prescale = 256
Const Clock = 3036

'--- [ Declare SUBs ] ----------------------------------------------------------

Declare Sub Direction(byval Var As Byte)
Declare Sub Speed(byval Var As Byte)
Declare Sub Engine(byval Var As Integer)
Declare Sub Snd(byval Freq As Integer)

'--- [ Declare variables ] -----------------------------------------------------

Dim Daten(30) As String * 19 'Messdaten

Dim Soll As Integer 'Sollwert
Dim Nextsoll As Integer 'Nächster Sollwert
Dim Ist As Integer 'Ist Position
Dim Hits As Byte 'Anschläge
Dim Libelle As Bit 'Libelle
Dim Result As Bit 'Messungsergebnis

Dim Action As Byte 'Aktuelle Aktion
Dim Adminmode As Bit 'Administrationsmodus

Dim Buffer As String * 5 'RS232 Buffer

Dim Year As Integer 'Jahr
Dim Month As Integer 'Monat
Dim Day As Integer 'Tag
Dim Hour As Integer 'Stunde
Dim Minute As Integer 'Minute
Dim Second As Integer 'Sekunde
Dim Tresult As String * 5 'Zeitstring
Dim Dresult As String * 8 'Datumstring

Dim B1 As Byte 'HV
Dim I1 As Integer 'HV
Dim I2 As Integer 'HV
Dim S1 As String * 1 'HV
Dim S2 As String * 1 'HV

Dim Start_setted As Bit 'S_HV

'--- [ Inizialize variables and constants ] ------------------------------------

Const Fwd = 1
Const Bwd = 0

Const Limit = 9900
Const Cm_ink = 44

Const Volhigh = 500
Const Volmiddle = 800
Const Vollow = 1500

Start_setted = 0

Soll = 0
Nextsoll = 0
Ist = 0
Hits = 0
Libelle = 0
Result = 0

Action = 0
Adminmode = 0

Buffer = ""

Year = 2000
Month = 1
Day = 1
Hour = 0
Minute = 0
Second = 0
Tresult = ""
Dresult = ""

'--- [ Inizialize Interrupts ] -------------------------------------------------

Sreg.7 = 0

On Int0 Isr_stop 'On Rising Edge
On Int1 Isr_incremental_encoder 'On Pinchange
On Pcint1 Isr_pc1
On Timer1 Isr_clock 'On Timer1
On Urxc Isr_data 'On Urxc

Eicra = &B00000111
Eimsk = &B00000011
Eifr = &B00000011

Pcicr = &B00000010
Pcifr = &B00000010
Pcmsk2 = &B00000000
Pcmsk1 = &B00001100
Pcmsk0 = &B00000000

Enable Timer1
Enable Urxc

Sreg.7 = 1

'--- [ Start secuence ] --------------------------------------------------------

Echo Off

Gosub Clrdata

Ist = 0

Dira = 1
Dirb = 0
Call Speed(0)
'--- [ Main loop ] -------------------------------------------------------------

Do
nop
Loop
End

'--- [ Interrupt service routine ] ---------------------------------------------

Isr_incremental_encoder:
If Phase_b <> Phase_a Then
Decr Ist
Else
Incr Ist
End If

If Dira = 1 Then
If Ist => 1000 Then
Dira = 0
Dirb = 1
End If
End If

If Dirb = 1 Then
If Ist =< 0 Then
Dira = 1
Dirb = 0
End If
End If

Print Ist
Return

schaut bitte mal drüber

wegen meinem vorredner
da bascom ja allenmöglichen schrott mit timer0 anstellt und dann der chip intern crasht? ka? ich kenn das Problem nicht, aber ich muss es finden......

tobi

pongi
06.11.2006, 19:10
Leider kenn ich mich mit Bascom nicht aus, da ich kleinere uC-s (AtMega8) in Assembly größere in C progge.... Ich seh aber da keine Hinterlegung im Stack bei der Interruproutine.... Ausserdem müssen bei zugriffen auf die Timer-Register vorher die Interrupts gesperrt werden, auch bei den OCRx Registern für dei PWM Grenze

EDatabaseError
06.11.2006, 19:22
ah, ok...
also bevor ich das ocr register ändre muss ich das sreg.7 auf 0 setzen. aber ich schätze das das nicht die ursache für den crash ist.

gibt es noch andere mögliche ursachen?

tobi

EDatabaseError
08.11.2006, 20:25
Also, ich hab mal alles auf ne RNControl 1.4 ausgelagert (16 MHz) die nur für das Zählen zuständig ist.
Das Drehgeberrad benötig 3 sekunden für 1 umdrehung (eine Umdrehung hat laut datenblatt 512 ink)
(das Rad dreht sich nicht konstant sondern "wackelt")

ich hab mal den Oszi drangehängt und auf 10 µS eingestellt.
In dieser Auflösung bekomme ich 14 Flanken die der Chip verwalten muss.
Ich weiss leider nicht wie das bei nem oszi ist? ist dann die ganze breite 10 µS oder ein Rasterkästchen? WIe ist das in der regel.
Denn wenn 10µS eine Breite sind dann:
14 flanken = 10 µS
14 flanken = 0,000001 S
1 S = 1400000 flanken!!!!!!!!!!
wenn meine befürchtung stimmt bekomme ich 1,4 MHz impulse.

ich habe noch eine logs gemacht. also das springen auf 12000 ist nun weg. leider bekomme ich eben bei der Geschwindigkeit eine zu große differenz. Statt 0 eben -100 oder so in meinem fall ist das zu viel.

der basic code steht ja oben.

wäre es möglich das ganze in assembler zu schreiben das es schneller ist und es wieder in das basic zu implementieren?

wäre echt nett wenn ihr mir helft!

mfg
tobi

EDatabaseError
08.11.2006, 21:31
Ich habe jetzt meine Hex Datei decompiliert. Im Anhang habe ich meine Basic und Assembler Datei.
Die Basic datei hat ca. 30 effektive zeilen
die assembler datei >200!

kann einer der assemblerprofies die datei mal schnauen?

tausend dank!

Mfg
tobi

pongi
09.11.2006, 08:02
Wenn dein Rad wackelt, kann es ja sein, dass es einmal kurz "zurückwackelt" nicht? Und daher können ja so grosse Zahlen kommen. Wenn dein Rad aber in 3 Sek 360° macht, und du 512 Positionen hast, bekommst du jede 3/512=0.005856s also 58.56ms einen Interrupt. Das ist für ein uC mit 16MHz eine Ewigkeit. In dieser Zeit macht es fast 100.000 Zyklen, also sprich 100.000 Befehle werden verarbeitet.... Ich verstehe also ehrlich gesagt nicht, was du mit dem Oszi gemacht hast. Ausserdem wir von den Flanken meistens nur eine verarbeitet (steigend oder fallend), aber es stimmt auch so nicht.
Assemby hat selbstverständlich mehr Zeilen, das ist ja fast reine Computercode. Leider hab ich jetzt keine Zeit, dir das durchzuschauen.

EDatabaseError
09.11.2006, 12:31
ja es "wackelt"

ne was mich wundert. das programm besteht darin:
Wenn int0 eine pinchange event hat bekomme ich einen interrupt der:
eine if abfrage beeinhaltet
ein incr oder decr
ein senden an den rs232 port

das ist das programm.
mich wundert eben das es in assembler "sooooooooo" viel ist.

zu dem oszi nochmal:
bei oszi auf delay 10 µS wurden 14 flanken gemessen

JuergenHrob
12.11.2006, 10:15
Hallo EDatabaseError,

schau dir mal dieses Datenblatt eines Drehimpulsgebers an:

http://www.altron.de/_pdf/ddm/427z1.pdf

Auf der letzten Seite rechts ist ein Flussdiagramm, wie man die Zustände des Drehgebers decodieren kann, wenn man einen konfigurierbaren Interrupt hat. Wichtig ist offensichtlich das Umschalten zwischen steigender und fallender Flanke.

Ich hatte eine ganze Weile gebraucht, das für einen 8051er-Controller umzusetzen. Das waren wesentlich mehr als ein paar Zeilen...

Gruß

Jürgen