PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : an Sub übergebene Werte



BoGe-Ro
05.08.2011, 09:59
Hallo Forum,

ich möchte mit 3 DA-Wandlern LTC1257 analoge Spannungen ausgeben.
Diese DA-Wandler hängen hintereinander, hinter Optokopplern und müssen daher mit invertierten Signalen angesteuert werden.

Ich habe dazu eine Sub Analog, welche die 3 Sollspannungen übergeben bekommt.
Um nun nicht laufend identische Werte in die DA-Wandler zu shiften, möchte ich einen Vergleich zwischen bereits geladenen Werten und neuen Werten durchführen und nur bei Differenz neu laden.

Testweise rufe ich die Sub zyklisch mit identischen Werten auf - dennoch werden unterschiedliche Parameter erkannt.

Wo ist hier der Fehler?

Hier eine Beispielausgabe aus dem Terminal:

1000 0 2000 0 3000 0
1000 1000 331 2000 3000 3000
1000 1000 2000 331 3000 3000
1000 1000 2000 2000 364 3000
1000 1000 2000 2000 3000 364
800 1000 2000 2000 3000 3000
1000 800 2000 2000 3000 3000
1000 1000 288 2000 3000 3000
1000 1000 2000 288 3000 3000
288 1000 2000 2000 3000 3000
1000 288 2000 2000 3000 3000
1000 1000 288 2000 3000 3000
1000 1000 2000 288 3000 3000
288 1000 2000 2000 3000 3000
1000 288 2000 2000 3000 3000
1000 1000 2000 2000 288 3000
1000 1000 2000 2000 3000 288
1000 1000 2000 2000 2848 3000
1000 1000 2000 2000 3000 2848
353 1000 2000 2000 3000 3000
1000 353 2000 2000 3000 3000
1000 1000 2000 2000 314 3000
1000 1000 2000 2000 3000 314
288 1000 2000 2000 3000 3000
1000 288 2000 2000 3000 3000
288 1000 2000 2000 3000 3000
1000 288 2000 2000 3000 3000
288 1000 2000 2000 3000 3000
1000 288 2000 2000 3000 3000
800 1000 2000 2000 3000 3000
1000 800 2000 2000 3000 3000
1000 1000 288 2000 3000 3000
1000 1000 2000 288 3000 3000
288 1000 2000 2000 3000 3000
1000 288 2000 2000 3000 3000
1000 1000 288 2000 3000 3000
1000 1000 2000 288 3000 3000
288 1000 2000 2000 3000 3000
1000 288 2000 2000 3000 3000
1000 1000 2000 2000 288 3000
1000 1000 2000 2000 3000 288
1000 1000 2000 2000 2848 3000
1000 1000 2000 2000 3000 2848
288 1000 2000 2000 3000 3000
1000 288 2000 2000 3000 3000
1000 1000 288 2000 3000 3000
1000 1000 2000 288 3000 3000
288 1000 2000 2000 3000 3000
1000 288 2000 2000 3000 3000


und nachfolgend der reduzierte Quellcode

mfG
BoGe-Ro




$regfile = "M32def.dat"
$crystal = 12288000
$hwstack = 128
$swstack = 64
$framesize = 64
$baud = 57600


'### LCD ################################################## #####################
Config Lcdpin = Pin , Db4 = Portb.2 , Db5 = Portb.3 , Db6 = Portb.4 , _
Db7 = Portb.5 , E = Portb.1 , Rs = Portb.0
Config Lcd = 20 * 4
Cursor Off Noblink
Initlcd
Lcd_enable Alias Portb.1 : Config Lcd_enable = Output
Dim Lcd_inhalt As String * 80 'Textpuffer für Displayausgabe
Dim Lcd_inhalt_byte(80) As Byte At Lcd_inhalt Overlay
Lcd_inhalt = Space(80)
Dim Lcd_cnt As Byte
Dim Lcd_text As String * 20 'Temp-Variable für String-Zusammenbau
Dim Lcd_text_char(20) As Byte At Lcd_text Overlay

Declare Sub Lcd_put(byval _x As Byte , Byval _reg As Byte)
Declare Sub Lcd_print(byval _x As Byte , Byval _y As Byte , Byval _text As String)
'################################################# ##############################


'### Timer0-Systemtakt ################################################## #######
Tccr0 = &B1000_1011 'ctc-mode, prescaler=64
Ocr0 = 191 '95=500µs / 191=1ms
Timsk.ocie0 = 1
On Oc0 Isr_timer0


'### DA-Wandler ################################################## ##############
A_latch Alias Portd.6 : Config A_latch = Output : Reset A_latch
A_clock Alias Portd.4 : Config A_clock = Output : Set A_clock
A_data Alias Portd.3 : Config A_data = Output
Declare Sub Analog(byval _w1 As Word , Byval _w2 As Word , Byval _w3 As Word , Byval _mamv As Byte)
'_w1 = p-soll
'_w2 = p-ist
'_w3 = 0-10V / 4-20mA
'_mav: 0=µA / 1=mV
Dim W1_alt As Word , W2_alt As Word , W3_alt As Word

Dim L_temp As Long
Dim B_temp As Byte
Dim W_temp As Word
Dim Beschleunigung As Word : Beschleunigung = 0


Enable Interrupts


Do
L_temp = 2000
Sreg.7 = 0
Lcd_text = "Kanal 3: " + Str(l_temp) + Space(2) : Call Lcd_print(1 , 3 , Lcd_text)
Sreg.7 = 1

If Beschleunigung = 0 Then Call Analog(1000 , 2000 , 3000 , 1)
Loop
End



'### ISR's ################################################## ###################
Isr_timer0:
If Beschleunigung > 0 Then Decr Beschleunigung
Incr Lcd_cnt 'nächstes Zeichen im Display-Puffer
If Lcd_cnt =< 80 Then Call Lcd_put(lcd_inhalt_byte(lcd_cnt) , 1) 'Zeichen ausgeben
If Lcd_cnt = 81 Then Call Lcd_put(2 , 0) 'Cursor at home (2ms)
If Lcd_cnt = 90 Then Lcd_cnt = 0
Return





'### Sub's ################################################## ###################

'### DA-Wandler ################################################## ##############
Sub Analog(_w1 , _w2 , _w3 , _mamv)
'invertierte Ansteuerung aufgrund Optokoppler
'_w1 = p-soll
'_w2 = p-ist
'_w3 = 0-10V / 4-20mA
'_mamv:0=10µA / 1=mV
Local _s1 As Single
Local _s2 As Single
Local _s3 As Single

'4095 1
'---- => --------
'10 V 2.442 mV

If _w1 <> W1_alt Or _w2 <> W2_alt Or _w3 <> W3_alt Then
Sreg.7 = 0
Print _w1 ; Chr(9) ; W1_alt ; Chr(9) ; _w2 ; Chr(9) ; W2_alt ; Chr(9) ; _w3 ; Chr(9) ; W3_alt
Sreg.7 = 1
W1_alt = _w1 : W2_alt = _w2 : W3_alt = _w3

_s1 = _w1 * 0.4095 : _s1 = _s1 + 0.5 : _w1 = _s1
_s2 = _w2 * 0.4095 : _s2 = _s2 + 0.5 : _w2 = _s2

If _mamv = 1 Then
_s3 = _w3 * 0.4095
_s3 = _s3 + 0.5
Else
If _w3 >= 400 Then
_s3 = _w3 * 2.559375
_s3 = _s3 - 1023.25 '-1023.75 + 0.5 für Rundung
Else
_s3 = 0
End If
End If
_w3 = _s3

Shift _w1 , Left , 4 : _w1 = _w1 Xor &HFFFF
Shift _w2 , Left , 4 : _w2 = _w2 Xor &HFFFF
Shift _w3 , Left , 4 : _w3 = _w3 Xor &HFFFF
Shiftout A_data , A_clock , _w3 , 0 , 12 , 10
Shiftout A_data , A_clock , _w2 , 0 , 12 , 10
Shiftout A_data , A_clock , _w1 , 0 , 12 , 10
Set A_latch : Waitms 1 : Reset A_latch
End If
End Sub


'### LCD ################################################## #####################
'
Sub Lcd_print(byval _x As Byte , Byval _y As Byte , _text As String * 20)
'Z1S1 = 1-20
'Z2S1 = 41-60
'Z3S1 = 21-40
'Z4S1 = 61-80
Local _position As Byte
Local _anzahl As Byte
Local _i As Byte
Select Case _y
Case 1 : _position = 0
Case 2 : _position = 40
Case 3 : _position = 20
Case 4 : _position = 60
End Select
_position = _position + _x
_anzahl = Len(_text)
' _i = Memcopy(_text , Lcd_inhalt_byte(_position) , _anzahl)
For _i = 1 To _anzahl
If Lcd_text_char(_i) = "ü" Then Lcd_text_char(_i) = $f5
If Lcd_text_char(_i) = "ö" Then Lcd_text_char(_i) = $ef
If Lcd_text_char(_i) = "ä" Then Lcd_text_char(_i) = $e1
If Lcd_text_char(_i) = "ß" Then Lcd_text_char(_i) = $e2
Lcd_inhalt_byte(_position) = Lcd_text_char(_i)
Incr _position
If _position = 81 Then Exit For
Next _i
End Sub


Sub Lcd_put(_x As Byte , _reg As Byte)
' _reg=1: Datenregister
' _reg=0: Befehlsregister
Local Lcd_data As Byte
Lcd_data = _x And &HF0 : Shift Lcd_data , Right , 2 'oberes Nibble
Portb = Lcd_data + _reg 'Datenbyte auf Bus legen
!nop
!nop
Lcd_enable = 1
!nop
!nop
Lcd_enable = 0

Lcd_data = _x And &H0F : Shift Lcd_data , Left , 2 'unteres Nibble
Portb = Lcd_data + _reg 'Datenbyte auf Bus legen
!nop
!nop
Lcd_enable = 1
!nop
!nop
Lcd_enable = 0
End Sub

BoGe-Ro
05.08.2011, 10:20
Der Fehler liegt offenbar an dem Funktionsaufruf der Sub Lcd_put(_x As Byte , _reg As Byte).
Werden beide Aufrufe in der Timer0-ISR auskommentiert, gibt es keine Differenzen bei der Analog-Sub.
Kommentiere ich dagegen nur den Inhalt der Sub Lcd_put(_x As Byte , _reg As Byte) aus, treten diese Fehler wiederum auf.

Wer kann helfen?

mfG
BoGe-Ro

peterfido
05.08.2011, 14:47
In einer ISR sollten keine LCD Ausgaben getätigt werden. Die Ausführzeit des Sub LCDPUTist evtl. länger als der Abstand zwischen 2 IRQ.

BoGe-Ro
05.08.2011, 17:07
Hallo peterfido,

die Antwort triffts leider nicht.
Die Sub Lcd_put ist sehr sehr kurz - daran liegt es ganz sicher nicht. Es wird ja lediglich an den Pins des LCD gewackelt, so dass pro ms ein Byte im 4-bit-Mode ans LCD übertragen wird.
Weiterhin tritt der Fehler sogar auf, wenn in der Sub gar nichts mehr steht.

Weiterhin wurde festgestellt:
- spring ich in die leere Sub Lcd_put und übergebe einen Byte-Wert für _x, ist es genau dieser Byte-Wert der im Fehlerfall an Stelle _w1 in der Sub Analog auftaucht.
- veränder ich den bei Lcd_put übergebenen Byte-Wert für _x in der Lcd_put-Sub, so taucht der veränderte Byte-Wert für _w1 in der Sub Analog auf
- sogar im Bascom-Simulator ließ sich der Fehler produzieren - allerdings scheint es hier unmöglich die Register zu beobachten, weil während einiger hundert Durchläufe der Hauptschleife nur ab und an der Fehler auftaucht.

Da ich das Testprogramm allerdings auf Arbeit vergessen habe, kann ich leider erst am Montag weiterforschen

mfG
BoGe-Ro

peterfido
07.08.2011, 08:03
Welche Bascom Version hast Du? Ich habe gestern einen Fehler im Code gesucht, den es gar nicht gab. Der Code lief schon einige Zeit zuverlässig und wurde mit einer älteren Bascom Version kompiliert. Gestern habe ich an anderer Stelle etwas geändert und anschließend kam nur Mist bei raus. Nach dem Update auf 2.0.7.0 war der Fehler wieder weg. So tippe ich auf ein Problem der 2.0.6.x

BoGe-Ro
08.08.2011, 08:41
Hallo,

also ich nutze die Version 1.11.9.3
Mir steht aktuell auch nur diese Version zur Verfügung.
Nachfolgend der aktuelle Testcode - welcher noch immer den Fehler mitbringt.

Sogar im Bascom-Simulator taucht die "55" aus der Sub Lcd_put in der Sub Analog auf.

Also die Variablen _w1, _w2 und _w3 haben manchmal den Wert 55 obwohl sie mit _w1=10 , _w2=20 und_w3=30 übergeben werden.




$regfile = "M32def.dat"
$crystal = 12288000
$hwstack = 128
$swstack = 96
$framesize = 64
$baud = 57600
'$sim


'### LCD ################################################## #####################
Dim Lcd_cnt As Byte
Declare Sub Lcd_put(byval _x As Byte , Byval _reg As Byte)
'################################################# ##############################


'### Timer0-Systemtakt ################################################## #######
On Oc0 Isr_timer0
Tccr0 = &B1000_1011 'ctc-mode, prescaler=64
Ocr0 = 191 '95=500µs / 191=1ms
Timsk.ocie0 = 1



'### DA-Wandler ################################################## ##############
Declare Sub Analog(byval _w1 As Byte , Byval _w2 As Byte , Byval _w3 As Byte )
Dim W1_alt As Byte , W2_alt As Byte , W3_alt As Byte



Enable Interrupts


Do
Call Analog(10 , 20 , 30 )
Loop
End



'### ISR's ################################################## ###################
Isr_timer0:
Incr Lcd_cnt 'nächstes Zeichen im Display-Puffer
If Lcd_cnt <= 80 Then Call Lcd_put(5 , 1) 'Zeichen ausgeben
If Lcd_cnt = 81 Then Call Lcd_put(2 , 0) 'Cursor at home (2ms)
If Lcd_cnt = 250 Then Lcd_cnt = 0
Return





'### Sub's ################################################## ###################

'### DA-Wandler ################################################## ##############
Sub Analog(_w1 , _w2 , _w3 )
If _w1 <> W1_alt Or _w2 <> W2_alt Or _w3 <> W3_alt Then
' If _w1 <> W1_alt Then
Sreg.7 = 0
Print _w1 ; Chr(9) ; W1_alt ; Chr(9) ; _w2 ; Chr(9) ; W2_alt ; Chr(9) ; _w3 ; Chr(9) ; W3_alt
Sreg.7 = 1
W1_alt = _w1
W2_alt = _w2
W3_alt = _w3
End If
End Sub


'### LCD ################################################## #####################
'
Sub Lcd_put(_x , _reg )
_x = 55
End Sub

peterfido
08.08.2011, 17:41
Da scheint der Softwarestack oder Framestack aus dem Takt zu kommen. Am besten Du postest direkt im mcselc Forum mit Deinem Beispiel Code. Mark Albert bereinigt solche Sachen immer recht schnell, wenn er sie denn kennt. Da eine Sub mit Parameter aufrufen immer eine Menge Stackschieberei nutzt, rufen die meisten Programmierer aus einer ISR keine SUB mit Parameter auf. Ich persönlich nutze so gut wie keine Subs, sondern verwende globale Variablen und springe per Gosub dahin und mit return zurück. Läuft wesentlich schneller, braucht aber mehr RAM als mehrere Subs mit lokalen Variablen. Aber auch da kann man sich helfen und Variablen einfach nur für solche Zwecke verwenden. Aber dann nicht aus einer ISR heraus...

PS: Ein Update auf die 2.0.7.0 lohnt sich in jedem Fall. Oft wird Code kürzer, sodass gefühlt mehr Programm in den MC passt.

BoGe-Ro
24.08.2011, 11:33
Hallo,

für mich hat sich herausgestellt, dass es offenbar bei Funktions- und Subaufrufen aus einer ISR heraus zu Differenzen zwischen übergebenen und ankommenden Werten kommt.

Bei Arbeit mit globalen Variablen und Verzweigung mit Gosub - Return traten derartige Fehler nicht auf


Danke
BoGe-Ro