UART Funktioniert nicht wenn PWM Aktiv ist (Bascom)

OP #3021695
Lesenswert?

Hallo!

Habe hier ein Problem bei meiner Lüftersteuerung.

Die Steuerung sammelt Temperaturdaten, Drehzahldaten vom Lüfter und 
regelt diese.

Soweit funktioniert auch alles aber die Ausgabe über die UART 
Schnittstelle funktioniert nicht wenn ich zb. compare1a=150 einstelle.

Schaltplan im Anhang.

Und hier der Code:

Siehe Abschnitt "Lüfter regeln" und "Ausgabe über UART"
1
'###############################################################################
2
'Lüftersteuerung v1.0 @ P.K.er
3
'###############################################################################
4
$regfile = "m8def.dat"
5
$crystal = 8000000
6
$baud = 19200
7

8

9
'ADC Config'####################################################################
10
Config Adc = Single , Prescaler = Auto , Reference = Avcc
11
Start Adc
12

13

14
'Port Config'###################################################################
15
Config Portb.1 = Output                                     'fan1 PWM
16

17
Config Portd.2 = Output                                     'fan2 PWM
18

19
Config Pind.2 = Input                                       'fan1 INT
20
Portd.2 = 1
21

22
Config Pind.3 = Input                                       'fan2 INT
23
Portd.3 = 1
24

25

26
'Timer, PWM und Interupts##########################################
27
Config Timer0 = Timer , Prescale = 1024                     'timer für zeit erfassung
28
On Timer0 Isr_timer0
29
Enable Timer0
30

31
Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Up , Compare B Pwm = Clear Up , Prescale = 1       'timer für pwm lüfter
32

33
Config Int0 = Falling
34
Config Int1 = Falling
35
On Int0 Isr_int0
36
On Int1 Isr_int1
37
Enable Int0
38
Enable Int1
39
Enable Interrupts
40

41
'Variablen für Drehzahlerfassung'##########################################################
42
Dim Rpm1 As Word
43
Dim Rpm2 As Word
44
Dim Rpm1_temp As Word
45
Dim Rpm2_temp As Word
46
Dim X As Byte
47
Dim Soft_timer As Byte
48
Dim Rpm_runden As Byte
49
Dim Rpm_runden1 As Word
50
Dim Rpm_runden2 As Word
51

52
'Variablen für Lüfterregelung'#######################################################
53
Dim Pwm01 As Single
54
Dim Pwm02 As Single
55
Dim Min_temp1 As Single
56
Dim Soll_temp1 As Single
57
Dim Min_temp2 As Single
58
Dim Soll_temp2 As Single
59

60
'CPU
61
Min_temp1 = 45                                              'unterer Temperaturwert
62

63
Soll_temp1 = 50                                             'Oberer temperaturwert
64

65
'Umgebung
66
Min_temp2 = 30                                              'unterer Temperaturwert
67

68
Soll_temp2 = 35                                             'Oberer temperaturwert
69

70

71

72
'Variablen für Temperaturmessung'###################################################
73
Dim Wert1 As Single
74
Dim Mittel_wert1 As Single
75
Dim Temp1 As Single
76
Dim Raw1 As Word
77
Dim Wert2 As Single
78
Dim Mittel_wert2 As Single
79
Dim Temp2 As Single
80
Dim Raw2 As Word
81

82
Dim A As Byte
83
A = 0
84

85
Dim Uref As Single                                          'Referencespannung
86
Uref = 5.12
87

88

89
'Variablen für Ausgabe##########################################################
90
Dim Temp1_str As String * 5
91
Dim Temp2_str As String * 5
92
Dim Rpm1_str As Word
93
Dim Rpm2_str As Word
94
Dim Zeit As Byte
95
Dim Pwm01_str As Word
96
Dim Pwm02_str As Word
97

98

99
'Hauptprogramm##################################################################
100
Do
101
Zeit = Zeit + 1
102

103
'Temperaturdaten holen##########################################################
104

105
'Temperatur in Grad = ((ADC x Avcc) / 1024) x 100) - 273.1
106

107
   Raw1 = Getadc(0)
108
   Waitms 20
109
   Temp1 = Raw1 * Uref
110
   Temp1 = Temp1 / 1024
111
   Temp1 = Temp1 * 100
112
   Temp1 = Temp1 - 273.15
113

114

115
   Raw2 = Getadc(1)
116
   Waitms 20
117
   Temp2 = Raw2 * Uref
118
   Temp2 = Temp2 / 1024
119
   Temp2 = Temp2 * 100
120
   Temp2 = Temp2 - 273.15
121

122
   A = A + 1
123

124
   Mittel_wert1 = Mittel_wert1 + Temp1
125

126
   Mittel_wert2 = Mittel_wert2 + Temp2
127

128
   If A = 20 Then
129

130
      A = 0
131

132
      Wert1 = Mittel_wert1 / 20
133
      Wert2 = Mittel_wert2 / 20
134

135
      Wert1 = Wert1 - 4
136
      Wert2 = Wert2 - 4
137

138
      Mittel_wert1 = 0
139
      Mittel_wert2 = 0
140

141
      Temp1_str = Fusing(wert1 , "#.#")
142

143
      Temp2_str = Fusing(wert2 , "#.#")
144

145

146
   End If
147

148
'Lüfter regeln##################################################################
149

150
Compare1a = 150
151
Compare1b = 150
152

153
Wait 5
154

155
Compare1a = 255
156
Compare1b = 255
157

158
Wait 5
159

160
'Drehzahlerfassung##############################################################
161
If X = 1 Then
162
   X = 0
163

164
   'rpm werte runden
165
   Rpm_runden1 = Rpm_runden1 + Rpm1
166
   Rpm_runden2 = Rpm_runden2 + Rpm2
167

168
   Rpm_runden = Rpm_runden + 1
169

170
   If Rpm_runden = 5 Then
171

172
      Rpm1 = Rpm_runden1 / 5
173
      Rpm2 = Rpm_runden2 / 5
174

175
      Rpm_runden1 = 0
176
      Rpm_runden2 = 0
177

178
      Rpm_runden = 0
179

180
      'rpm werte berechnen
181
      Rpm1_str = Rpm1 * 30                                  'rpm * 30sek. (weil 2 imputse pro umdrehung)
182
      Rpm2_str = Rpm2 * 30                                  'rpm * 30sek. (weil 2 imputse pro umdrehung)
183

184
   End If
185

186
End If
187

188

189
'Ausgabe über UART##############################################################
190
If Zeit = 20 Then
191

192
   Zeit = 0
193

194
   Pwm01_str = Pwm01 / 2.55
195
   Pwm02_str = Pwm02 / 2.55
196

197
   Print "98765"                                            'Prüfnummer
198

199
   Waitms 50
200

201
   Print Rpm1_str
202

203
   Waitms 50
204

205
   Print Rpm2_str
206

207
   Waitms 50
208

209
   Print Pwm01_str
210

211
   Waitms 50
212

213
   Print Pwm02_str
214

215
   Waitms 50
216

217
   Print Temp1_str
218

219
   Waitms 50
220

221
   Print Temp2_str
222

223
End If
224

225
Loop
226

227

228
'isr von timer0#################################################################
229
Isr_timer0:                                                 'aller 1/30.5175 Sekunden
230

231
   Soft_timer = Soft_timer + 1
232

233
   If Soft_timer = 30 Then
234

235
      Rpm1 = Rpm1_temp
236
      Rpm2 = Rpm2_temp
237

238
      Rpm1_temp = 0
239
      Rpm2_temp = 0
240

241
      Soft_timer = 0
242
      X = 1
243

244
   End If
245

246
Return
247

248

249
'isr von int0###################################################################
250
Isr_int0:
251

252
   Rpm1_temp = Rpm1_temp + 1
253

254
Return
255

256

257
'isr von int1###################################################################
258
Isr_int1:
259

260
   Rpm2_temp = Rpm2_temp + 1
261

262
Return
263

264
End
Angehängte Dateien:
#3021705
Lesenswert?

Hi Du,
ohne jetzt wirklich den ganzen Code durchdacht zu haben fällt mir auf,
dass die Ausdrucksform
'Ausgabe über 
UART##############################################################
If Zeit = 20 Then

sowieso zu einem Problem führen wird, weil es ja nur ausgefürt wird wenn 
exact 20 bestehen. Sollte dein programm also irgendwie länger brauchen 
ist vielleicht schon 21 erreicht und du wartest bis zum nächsten 
Overflow der Var.

versuch mal:
'Ausgabe über 
UART##############################################################
If Zeit >= 20 Then

Gruss Klaus
#3021720
Lesenswert?

Habe nur mal kurz durchgescrollt.
Mir fällt auf das bei 'Lüfterreglen' 2x 5 Sekunden gewartet wird, sehr 
ungünstig da dann die Programmschleife nur 1x in 10Sek durchlaufen wird.
Weiter ungünstig sind die Berechnungen mit Singlevariablen, ist bei 
Bascom grottenlahm, speicherintensiv und in fast allen Fällen, so auch 
hier, unnötig.
Bei der UART-Ausgabe sind auch wieder völlig unnötige Waitbefehle und 
auch wieder 2 Kommarechnungen. Da das aber Wordvariablen in der Rechnung 
sind geht das in die Hose.

Bisher habe ich es immer geschaft Gleitkommarechnungen zu vermeiden. Für 
die Datenanzeige lässt sich das Komma gut nachträglich einfügen wenn man 
den Umweg über Stringvariablen nimmt, ist auf jeden Fall weniger ZEit 
und Speicherintensiv.
#3021759
Lesenswert?

Steffen Warzecha schrieb:
> Bisher habe ich es immer geschaft Gleitkommarechnungen zu vermeiden. Für
> die Datenanzeige lässt sich das Komma gut nachträglich einfügen wenn man
> den Umweg über Stringvariablen nimmt, ist auf jeden Fall weniger ZEit
> und Speicherintensiv.

Da hast du meines Erachtens nach auch einen der Nägel auf den Kopf 
getroffen.
Als ich vor Jahren mal mit uC anfing habe ich auch "single" geschworen.
Als dann die Unzulänglickeiten hervortraten ging ich auf "Double" was 
wieder neue Probleme erzeugte.

Im Finale schaffe ich nun alles mit Integer (oder long) Arithmetik.
Leider ist das Gehirn so aufgebaut dass man gerne Kommastellen sehen 
möchte um dem Ergebnis mehr zu trauen.

wenn man es jedoch mit dem taschenrechner mal rückwärts rechnet erkenn 
man dann sehr leicht warum die Ergebnisse nicht den erwartungen 
entsprechen.

Ich erinnere mich gerne an den Hype mit den Apfelmännchen, der in den 
1980gern gab. Da waren komplizierte Formeln in der CT mit Realteil und 
Imaginäranteil drinne. Jeder hat das dann programmiert und tatsächlich 
kam ein solches Apfelmännlein heraus. Als ich das alte pascal-Programm 
vor ein paar Jahren mal wieder herausgekramt hatte und die Formel 
einfach duch
die Formel :
 dim differenz as whatever
x=10
do
y=x / 3
z = y * 3
differenz = z-x
loop until differenz has overflow

.. und siehe da, es ist das gleiche Apfelmännchen.
Vielleicht nicht so bunt aber es geht schon.

das Apfelmännchen ist also keine geheime Information sondern eher der 
Bereich der möglichen Rundungsfehler den man vermeiden sollte.

Gruss Klaus
OP #3022166
Lesenswert?

Klaus De lisson schrieb:
> versuch mal:
> 'Ausgabe über
> UART##############################################################
> If Zeit >= 20 Then

das hat geholfen DANKE

Hab da noch ne andere Frage.
Und zwar übertrage ich ja Daten über den Serialport vom AVR zum PC.
Drehzahlen Temperaturen und PWM-stufe siehe Bild.
PWM-Stufe in ProgressBar 1 und 2 (die oberen 2)
der Rest ist eigentlich zu erkennen auf dem Bild.
Um die Reinfolge der Daten zu gewährleisten musste ich wie folgt 
vorgehen.

Bascom Code:
1
 Print "98765"
2

3
   Waitms 50
4

5
   Print Rpm1_str
6

7
   Waitms 50
8

9
   Print Rpm2_str
10

11
   Waitms 50
12

13
   Print Pwm01
14

15
   Waitms 50
16

17
   Print Pwm02
18

19
   Waitms 50
20

21
   Print Temp1_str
22

23
   Waitms 50
24

25
   Print Temp2_str

VB2010 Code:
1
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
2
        Try
3
            comein = SerialPort1.ReadLine
4
            Me.Invoke(New EventHandler(AddressOf auswertung))
5
        Catch ex As Exception
6

7
        End Try
8

9
    End Sub
10

11
    Private Sub auswertung()
12
        If a = 0 Then
13

14
            If comein = "98765" Then                 'Prüfnummer 98765
15
                a = 1
16
            Else
17
                a = 0
18
            End If
19

20
        ElseIf a = 1 Then
21
            a = 2
22

23
            Label1.Text = "FAN CPU:  " & comein & " RPM"
24

25
        ElseIf a = 2 Then
26
            a = 3
27

28
            Label2.Text = "FAN Umgebung:  " & comein & " RPM"
29

30
        ElseIf a = 3 Then
31
            a = 4
32

33
            If comein > 100 Then
34
                comein = 100
35
            ElseIf comein < 0 Then
36
                comein = 0
37
            End If
38

39
            ProgressBar1.Value = comein
40
            Label5.Text = "PWM " & comein
41

42
        ElseIf a = 4 Then
43
            a = 5
44

45
            If comein > 100 Then
46
                comein = 100
47
            ElseIf comein < 0 Then
48
                comein = 0
49
            End If
50

51
            ProgressBar2.Value = comein
52
            Label6.Text = "PWM " & comein
53

54

55
        ElseIf a = 5 Then
56
            a = 6
57

58
            Label7.Text = comein
59
            comein = comein / 10
60
            Label3.Text = "Temperatur CPU:  " & comein & "°C"
61

62
            If comein >= 100 Then
63
                comein = 100
64
            ElseIf comein <= 0 Then
65
                comein = 0
66
            End If
67

68
            ProgressBar3.Value = comein
69

70
        ElseIf a = 6 Then
71
            a = 0
72

73
            Label8.Text = comein
74
            comein = comein / 10
75
            Label4.Text = "Temperatur Umgebung:  " & comein & "°C"
76

77
            If comein >= 100 Then
78
                comein = 100
79
            ElseIf comein <= 0 Then
80
                comein = 0
81
            End If
82

83
            ProgressBar4.Value = comein
84

85
        End If
86

87
    End Sub

Jetzt haut das aber nicht hin so wie ich es will.
Ich bekomme manchmal komische Werte angezeigt und manchmal auch die 
Prüfnummer in der Temperatur angezeigt.

Wo liegt mein Problem hier oder wie kann man das anders machen??
#3022208
Lesenswert?

hallo Autor: Peter K. (pker) ,

ich hab wirklich nicht die Lust deinen VB Code zu lesen und diesen noch 
verstehen zu wollen. Allerdings erinnere ich mich dass ich diese Dinge 
auch schon mal gemacht habe (allerdings verwende ich Vbasic 2006 ohne 
den .net Syntax)

selbst bei Vb6 ist es so, dass sich Probleme bei der sychronisation 
einstellen wenn man viele Print-Befehle hintereinander absetzt zumal 
eben VB und Windows nicht gerade ein Echtzeit-system ist.
wenn du jedoch im AVR zunächst eine String mit bekannter Länge bildest 
wird es besser.
z.B.

Dim sendstring as String * 200
*****  hier hast du also einen String mit 200 zeichen
Print sendstring
******  sendet 200 Zeichen am Stück
dim rpm1string as string * 5 (für word variablen oder *3 für byte)
rpm1string = str(rpm1wert)


nun müssen wir überlegen was wir senden.
Da könnte man z.B. sagen das der Präfix eines Eintrages immer 4 zeichen 
lang ist (also immer die gleiche Länge)

sendstring="Rpm1"+ rpm1string+ "Rpm2"+rpm2str"

dann bekommst du auf dem PC eine einzige Sendung mit dem kompletten 
Telegramm

Nun wollen wir das Telegramm auch wieder zerlegen und fügen ein 
Trennzeichen ein. Dies könnte z.B. ein Semikolon sein
Der Sendstring wäre dann:

sendstring="Rpm1"+ rpm1string+ ";" +"Rpm2"+rpm2str"
abgeschlossen wird der String mit VBLF und VBCR

nun kannst du im VB (und da hast du viel mehr rechenleistung) den String 
wieder zerpflücken.
Du triigerst den VB Empfang mit dem VBLF und VBCR und prüfst die länge 
des String. Stimmt die Länge nicht hast du Fehlerhaften Empfang gehabt.
Simmt die Länge kannstt du in VB mit instring das Ganze wieder zerlegen.

Ich hoffe du verstehst das soweit.

Gruss Klaus

p.s.
wenn dein uC keinen Quarz verwendet sondern den internen RC wird es noch 
schwieriger zu synchen.
OP #3022797
Lesenswert?

Klaus De lisson schrieb:
> Ich hoffe du verstehst das soweit.

Das Prinzip leuchtet mir ein!

Nur an der Umsetzung habert es noch.


Ich habe jetzt 6 werte in Strings umgewandelt mit "string=str(wert)".
Die Strings haben alle 5 Stellen (string * 5).
Habe alle Strings zusammen gefügt mit 
"ausgabe_string=string1+string2..." und in einen Ausgabe String 
geschrieben (dieser hat 50 Stellen (ausgabe_string * 50)).
Jetzt gebe ich mit "Print ausgabe_string" die Werte aus.

Laut deiner Aussage müssten jetzt 50 Zeichen Übertragen werden.
die ersten 30 mit meinen werten.

Soweit Korrekt?

Ich nehme mal an das nicht genutzte Zeichen in einem Terminal nicht 
angezeigt werden aber trotzdem übertragen werden.
Dann Würde soweit auch alles hin hauen.



Klaus De lisson schrieb:
> nun kannst du im VB (und da hast du viel mehr rechenleistung) den String
> wieder zerpflücken.
> Du triigerst den VB Empfang mit dem VBLF und VBCR und prüfst die länge
> des String. Stimmt die Länge nicht hast du Fehlerhaften Empfang gehabt.

Da bin ich etwas unerfahren und habe keine Ahnung wie ich das machen 
soll.

> Simmt die Länge kannstt du in VB mit instring das Ganze wieder zerlegen.

Da Bräuchte ich auch etwas Hilfe.
#3023071
Lesenswert?

Peter K. schrieb:
> Laut deiner Aussage müssten jetzt 50 Zeichen Übertragen werden.
> die ersten 30 mit meinen werten.
>
> Soweit Korrekt?

Nein!
(ausgabe_string * 50) bedeutet ja nur das dein "Ausgabeeimer" das 
Fassungsvermögen von 50 hat. wenn du aber nur 30 in dem Eimer füllst 
kommen auch nur 30 heraus. Zusätzlich aber durch den Printbefehl noch 
<CR> und ein <LF> angehängt. (siehe chr(10) und chr (13))

Beim Enpfang musst du halt in VB proggen das ein CR und/oder ein LF das 
Ende einer Übertragung ist. Dann musst du den Empfangsstring bereinigen 
indem du am Ende 1 oder 2 Zeichen abschneiden um die CR und LF sofern 
vorhanden zu entfernen.

String = left(string, len(string-2))  z.b.

dann schneidest du den rest wieder in Stücke so dass deine 
Ursprungsstrings wieder entstehen.

z.B
string1 = mid(empfangsstring,1,5)
string2 = mid(empfangsstring,6,5)
u.s.w.

bitte nagel mich nicht auf die Syntax fest da ich ja sowieso ne andere 
VB Version habe.

Ich schätze aber, das du mit dem Begriffen sehr gut goolen kannst.

Gruss Klaus

ps.:
lad dir mal HTERM runter und schau dir dann an was du empfängst bevor du 
in VB anfängst zu proggen

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren