Forum: Mikrocontroller und Digitale Elektronik UART Funktioniert nicht wenn PWM Aktiv ist (Bascom)


von Peter K. (pker)


Angehängte Dateien:

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

von Klaus D. (kolisson)


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

von Steffen W. (derwarze)


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.

von Klaus D. (kolisson)


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

von Peter K. (pker)



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??

von Klaus D. (kolisson)


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.

von Peter K. (pker)


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.

von Klaus D. (kolisson)


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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.