Moin Leute, ich habe hier eine Schaltung mit einem Atmega 32U4. Letzterer kommuniziert mit einem PC. Die Schaltung und auch die Software habe ich hier tausendfach getestet und es gab keinerlei Schwierigkeiten. Nun bleibt der uC bei einem Kunden immer wieder hängen. Die Leiterplatte habe ich schon ausgetauscht, sodass ich etwa eine schlechte Lötstelle als Fehler ausschließen möchte. Leider scheint der Fehler wie zufällig aufzutreten. Ich kann keine Ursache ausmachen - auf keine zeitliche - einmal trat der Fehler hier nun auch auf aber ohne, dass ich eine Ursache erkennen konnte... Darum meine Frage: Weiß jemand eine Quelle für eine Art Checkliste was bei einem hängenden uC zu prüfen ist?
In Zeile 42 schreibst du über Arraygrenzen hinweg.
Ja ich seh's auch ganz deutlich.
Tim B. schrieb: > Darum meine Frage: Weiß jemand eine Quelle für eine Art Checkliste was > bei einem hängenden uC zu prüfen ist? - Resetbeschaltung - Abblockung - Versorgung gepuffert - Programmfehler (Atomic, Arraygrenzen z.B.) - Taktausfall (wegen "bleibt stehen") - Endlos-While-Schleifen die etwas pollen, Stichwort Timeout einbauen Kannst du "bleibt hängen" näher spezifierenz?
Hier mal ein Beispiel, wie man ein Timeout einbaut:
1 | static uint16_t WaitForFallingEdge ( void ) |
2 | {
|
3 | uint16_t Temp = 0; |
4 | while ( (TEMP_IO_PORT & (1<<TEMP_IO_PIN)) && Temp < TIMEOUT ) Temp++; |
5 | if ( Temp == TIMEOUT ) return TIMEOUT_ACCOURED; |
6 | return Temp; |
7 | }
|
Meine Glaskugel ist mir gestern explodiert und ist bei der Reparatur. deswegen veröffentliche hier bitte den Code der auf dem Controller läuft.
Manchmal ist es wirklich eine Strafe einen Eröffnungs-Beitrag hier lesen zu müssen. Leider merkt man das erst wenn man ihn gelesen hat sonst könnte man die Situation ja sogar vermeiden.
Vielen Dank. Also es ist so, dass ich nur sehr begrenzt progrtammieren kann, weshalb ich sowohl beim Arduino-Sketch sehr viel Hilfe hatte und an der PC-Software gar nicht beteiligt war. Den Arduino-Sketch werde ich mir wegen der Arraygrenzen gleich mal zur Brust nehmen aber soweit ich mich erinnere hat die PC-Software alle "Rechen- und Merkaufgaben" übernommen. Außerdem müsste die Software dann ja zeitlich immer nach einer bestimmten Anzahl von Schreibvorgängen - also auch nach einer bestimmten Zeit abstürzen. Die läuft aber mal über Nacht problemlos und stürzt dann wieder nach ein paar Minuten ab. Bemerkbar macht sich der Absturz dadurch, dass der uC nichts mehr schaltet und die PC-Software einfriert. Sobald der uC neu gestartet wird läufts wieder. Bevor ich jetzt lange suche: Ist vielleicht das Aktivieren des Watchdogs über die Fuses eine Lösung (Watchdog timer always on; [WDTON=0])? Wird der uC dann automatisch neu gestartet wenn er abstürtzt? Eigentlich würde ich erst mal checken, ob der uC auch dann abstützt, wenn er nicht mit dem PC verbunden ist um herauszufinden ob vielleicht etwas mit der Kommunikation nicht stimmt. Das ist aber natürlich schwierig, wenn sich der Fehler nicht reproduzieren lässt...
Dunkelseher schrieb: > Manchmal ist es wirklich eine Strafe einen Eröffnungs-Beitrag > hier lesen zu müssen. Wieso? Der TO hat doch nur nach einer allgemeinen Vorgehensweise gefragt. Also allgemein: - Den Fehler eingrenzen!
Beitrag #6386452 wurde von einem Moderator gelöscht.
Tim B. schrieb: > Ist vielleicht das Aktivieren des Watchdogs > über die Fuses eine Lösung (Watchdog timer always on; [WDTON=0])? Wird > der uC dann automatisch neu gestartet wenn er abstürtzt? Nein, der Watchdog ist das allerletzte Mittel, den µC wieder zu holen, wenn man selber keinen Einfluss mehr nehmen kann. Ein Programm, dass auf einen WDT angewiesen ist, damit es läuft ist ein schlechtes Programm.
Das ist der Arduino-Sketch:
1 | #include <EEPROM.h> /// zum speichern im EEPROM des Arduino |
2 | #include <OneWire.h> |
3 | #include "WS2812.h" |
4 | |
5 | ////////////////////////////////////////////////
|
6 | /// Ab hier kann wieder angepasst werden !!! ///
|
7 | ////////////////////////////////////////////////
|
8 | |
9 | /* Konstanten
|
10 | */
|
11 | #define UPDATE_TIME_CHECK 500 /// ms zwischen Signal + Avg + Schutz
|
12 | |
13 | #define NUM_READ_A 125 /// Anzahl der Messungen Haupt-Stromsensor
|
14 | #define UPDATE_TIME_A 4 /// ms zwischen den Messungen vom Haupt-Stromsensor
|
15 | |
16 | #define NUM_READ_U 20 /// Anzahl der Messungen Nutzer-Stromsensoren
|
17 | #define UPDATE_TIME_U 25 /// ms zwischen den Messungen vom Spannung(s-Teiler)
|
18 | |
19 | #define NUM_READ_V 20 /// Anzahl der Messungen Spannung(s-Teiler)
|
20 | #define UPDATE_TIME_V 25 /// ms zwischen den Messungen von Nutzer-Stromsensoren
|
21 | |
22 | #define OVP_MF_OFF_ID 767 /// ADC-Wert bei 15zu20V
|
23 | #define OVP_MF_ON_ID 716 /// ADC-Wert bei 14zu20V
|
24 | #define OVP_MF_TIME 10000 /// 10s nach aus darf ein
|
25 | |
26 | #define UVP_WR_OFF_ID 563 /// ADC-Wert bei 11zu20V
|
27 | #define UVP_WR_ON_ID 588 /// ADC-Wert bei 11,5zu20V
|
28 | #define UVP_WR_TIME 10000 /// 10s nach aus darf ein
|
29 | |
30 | #define OCP_MF_OFF_ID 2046 /// 2x 50A = 2x map(MAX_ADC_USER) = 2x 1023
|
31 | #define OCP_MF_ON_ID 1637 /// 80A
|
32 | #define OCP_MF_TIME 10000 /// 10s nach aus darf ein
|
33 | |
34 | #define OTP_MF_OFF 80.0 /// °C
|
35 | #define OTP_MF_ON 70.0 /// °C
|
36 | |
37 | #define ADC_NUM 12 /// Anzahl analoge Eingänge
|
38 | |
39 | #define PORT_A A0 /// (?) Stromsensor zwischen WR und Bat
|
40 | #define PORT_LED 13 /// 1x WS2812
|
41 | #define PORT_MF 11 /// Port um Mosfets zu schalten
|
42 | #define PORT_TEMP 7 /// Port vom Tempsensor DS18B20Z
|
43 | #define PORT_U0 A9 /// Stromsensor User 0
|
44 | #define PORT_U1 A8 /// Stromsensor User 1
|
45 | #define PORT_U2 A7 /// Stromsensor User 2
|
46 | #define PORT_U3 A11 /// Stromsensor User 3
|
47 | #define PORT_U4 A5 /// Stromsensor User 4
|
48 | #define PORT_U5 A4 /// Stromsensor User 5
|
49 | #define PORT_U6 A3 /// Stromsensor User 6
|
50 | #define PORT_U7 A2 /// Stromsensor User 7
|
51 | #define PORT_U8 A6 /// (?) Stromsensor User 8
|
52 | #define PORT_U9 A1 /// (?) Stromsensor User 9
|
53 | #define PORT_V A10 /// Spannungsteiler
|
54 | #define PORT_WR 5 /// Wechselrichter-Port fürs ein- und ausschalten
|
55 | #define TIME_MF_OFF_TO_ON 10000 /// ms → nach min. wieviel Zeit wieder ON
|
56 | #define TIME_WR_OFF_TO_ON 10000 /// ms → nach min. wieviel Zeit wieder ON
|
57 | |
58 | #define ALERT_USER_HIGH_W 100.0
|
59 | #define ALERT_USER_LOW_W 40.0
|
60 | #define BITBREITE 10
|
61 | #define BPS 115200 /// 115200 Bits_Per_Second (Serielle Kommunikation)
|
62 | #define COUNT_USER 8 /// Nutzeranzahl
|
63 | #define GAUGE_USER 100.00 /// W für Vollausschlag der Bargraphanzeige
|
64 | #define KWH_AUSSCHLAG 0.10 /// kWh für Vollausschlag nach jeder Seite der Bargraphanzeige Verbrauch bzw. Erzeugt
|
65 | #define MAX_ADC_A 921 /// bei +MAX_A_BATT
|
66 | #define MAX_ADC_V 1023 /// ADC_Wert bei MAX_V
|
67 | #define MAX_ADC_USER 614 /// (runtergerechneter) ADC_Wert inkl. Offset bei MAX_A_USER
|
68 | #define MAX_V 20.00 /// Maximale Sensorbereich (Hardware)
|
69 | #define MAX_A_USER 50.00 /// Maximale theoretische Sensorbereich (Hardware)
|
70 | #define MAX_A_BATT 100.00 /// Maximale theoretische Sensorbereich (Hardware)
|
71 | #define MIN_ADC_A 102 /// bei -MAX_A_BATT
|
72 | #define MIN_ADC_V 0 /// ADC_Wert bei 0 V
|
73 | #define MIN_ADC_USER 0 /// (runtergerechneter) ADC_Wert inkl. Offset
|
74 | #define NUTZER_ID "" /// Das ist die Lizenz
|
75 | #define OFFSET_A 0
|
76 | #define OFFSET_V 0
|
77 | #define OFFSET_USER 102 /// 102 rechnerisch (=0,5V)
|
78 | #define VERSION "2019.10.03" /// vom µC
|
79 | #define WR_DELAY 1000 /// Zeit jeweis zwischen Ausschalten, Kalibrieren, Einschalten des WR
|
80 | |
81 | /* Aufzählungen
|
82 | */
|
83 | enum OPT /// Option für Serial-Event |
84 | {
|
85 | Mf_On = 15, |
86 | Mf_Off = 14, |
87 | Wr_On = 13, |
88 | Wr_Off = 12, |
89 | Send_Conf = 11, |
90 | Kali = 10, |
91 | Send_Data = 9 |
92 | };
|
93 | |
94 | /* RGB-Code für diverse States
|
95 | */
|
96 | cRGB ALERT_PROTECT = {255, 255, 0 }; /// gelb → OCP || OTP || OVP || UVP ist 1 |
97 | cRGB NO_COLOR = {0, 0, 0 }; /// aus bzw. schwarz bzw. keine Farbe |
98 | cRGB NO_PROTECT = {0, 255, 0 }; /// grün → OCP && OTP && OVP && UVP ist >= 2 |
99 | cRGB OCP_OTP_OVP_UVP = {255, 0, 0 }; /// rot → OCP || OTP || OVP || UVP ist 0 |
100 | cRGB TIME_ALERT_PROTECT = {255, 0, 0 }; /// lila → Abklingzeit + ALERT_PROTECT |
101 | cRGB TIME_NO_PROTECT = {255, 0, 0 }; /// türkis → Abklingzeit + NO_PROTECT |
102 | |
103 | ////////////////////////////////////////
|
104 | /// Ab hier nichts mehr anpassen !!! ///
|
105 | ////////////////////////////////////////
|
106 | |
107 | struct Configuration{ /// Das was als Konfiguration über USB gesendet wird |
108 | //short Alert_High_V_Id = OVP_MF_ALERT_ID;
|
109 | //short Alert_Low_V_Id = UVP_WR_ALERT_ID;
|
110 | float Alert_User_High_W = ALERT_USER_HIGH_W; |
111 | float Alert_User_Low_W = ALERT_USER_LOW_W; |
112 | float Gauge_User = GAUGE_USER; |
113 | float KWh_Ausschlag = KWH_AUSSCHLAG; |
114 | float Max_A_Batt = MAX_A_BATT; |
115 | float Max_A_User = MAX_A_USER; |
116 | float Max_V = MAX_V; |
117 | short Mosfet_High_Id = OVP_MF_OFF_ID; |
118 | short Mosfet_Low_Id = OVP_MF_ON_ID; |
119 | uint8_t ADC_Bitbreite = BITBREITE; |
120 | uint8_t Count_User = COUNT_USER; |
121 | char Kinobox_Version[11] = VERSION; |
122 | char Nutzer_ID[150] = NUTZER_ID; |
123 | uint8_t dummy[17] = {0}; |
124 | };
|
125 | |
126 | struct Daten{ /// Alle analoge Ports |
127 | short adc[ADC_NUM]; /// Port A 0 bis A 11 |
128 | };
|
129 | |
130 | /* Variablen
|
131 | */
|
132 | byte Read_Index_A = 0; |
133 | byte Read_Index_V = 0; |
134 | byte Read_Index_U = 0; |
135 | short Reading_A[NUM_READ_A] = {0}; |
136 | short Reading_V[NUM_READ_V] = {0}; |
137 | short Reading_U[ADC_NUM-2][NUM_READ_U] = {0}; |
138 | long Total_A = 0; |
139 | long Total_V = 0; |
140 | long Total_U[ADC_NUM-2] = {0}; |
141 | unsigned long Last_Time_Check = 0; |
142 | unsigned long Last_Time_Read_A = 0; |
143 | unsigned long Last_Time_Read_V = 0; |
144 | unsigned long Last_Time_Read_U = 0; |
145 | unsigned long Last_Time_MF_Off = 0; |
146 | unsigned long Last_Time_WR_Off = 0; |
147 | unsigned long now = 0; |
148 | |
149 | OneWire ds(PORT_TEMP); /// an welchen Port ist der Temperatursensor |
150 | byte Temp_Addr[8]; /// Adresse des Temperatursensors |
151 | byte Temp_Data[12]; /// Daten des Temperatursensors |
152 | int16_t Temp_Raw = 0; |
153 | float Temperatur = 0.0; |
154 | short adc = 0; /// temporär für Berechnungen usw. |
155 | short tempAall = 0; /// gesamt für alle Nutzer für OCP-Schutz |
156 | int Analog_Port_Array[ADC_NUM] = {PORT_A, PORT_V, PORT_U0, PORT_U1, PORT_U2, PORT_U3, PORT_U4, PORT_U5, PORT_U6, PORT_U7, PORT_U8, PORT_U9}; |
157 | Daten Max_ADC = {MAX_ADC_A, MAX_ADC_V, MAX_ADC_USER, MAX_ADC_USER, MAX_ADC_USER, MAX_ADC_USER, MAX_ADC_USER, MAX_ADC_USER, MAX_ADC_USER, MAX_ADC_USER, MAX_ADC_USER, MAX_ADC_USER}; |
158 | Daten Min_ADC = {MIN_ADC_A, MIN_ADC_V, MIN_ADC_USER, MIN_ADC_USER, MIN_ADC_USER, MIN_ADC_USER, MIN_ADC_USER, MIN_ADC_USER, MIN_ADC_USER, MIN_ADC_USER, MIN_ADC_USER, MIN_ADC_USER}; |
159 | Daten Offset = {OFFSET_A, OFFSET_V, OFFSET_USER, OFFSET_USER, OFFSET_USER, OFFSET_USER, OFFSET_USER, OFFSET_USER, OFFSET_USER, OFFSET_USER, OFFSET_USER, OFFSET_USER}; |
160 | Daten Data = {0}; /// Das was über USB gesendet wird |
161 | Configuration Conf; |
162 | WS2812 LED(1); |
163 | cRGB LED_rgb = {0}; |
164 | byte OVP_State = 0; /// Überspannungsschutz |
165 | byte UVP_State = 0; /// Unterspannungsschutz |
166 | byte OCP_State = 0; /// Überstromstärkeschutz |
167 | byte OTP_State = 0; /// Temperaturschutz |
168 | |
169 | ////////////////////////////////////////
|
170 | /// Ab hier nichts mehr anpassen !!! ///
|
171 | ////////////////////////////////////////
|
172 | |
173 | /* Programmstart
|
174 | */
|
175 | void setup() |
176 | {
|
177 | init_default_led(); |
178 | init_default_mosfet(); |
179 | init_default_temp(); |
180 | init_default_wr(); |
181 | zero_reading_data(); |
182 | zero_total_data(); |
183 | zero_usb_data(); |
184 | Verbinden(); |
185 | //EEPROM_auslesen(); /// Ggf. in späteren Version aktivieren und erweitern
|
186 | }
|
187 | |
188 | /* Dauerschleife für regelmäßige Aktionen
|
189 | */
|
190 | void loop() |
191 | {
|
192 | now = millis(); |
193 | if( (now - Last_Time_Read_A) >= UPDATE_TIME_A ) /// Haupt-Stromsensor |
194 | {
|
195 | Last_Time_Read_A = now; |
196 | Total_A -= Reading_A[Read_Index_A]; |
197 | Reading_A[Read_Index_A] = (short)analogRead(Analog_Port_Array[0]); |
198 | Total_A += Reading_A[Read_Index_A]; |
199 | Read_Index_A++; |
200 | if( Read_Index_A >= NUM_READ_A ) { Read_Index_A = 0; } |
201 | }
|
202 | if( (now - Last_Time_Read_V) >= UPDATE_TIME_V ) /// Spannung(s-Teiler) |
203 | {
|
204 | Last_Time_Read_V = now; |
205 | Total_V -= Reading_V[Read_Index_V]; |
206 | Reading_V[Read_Index_V] = (short)analogRead(Analog_Port_Array[1]); |
207 | Total_V += Reading_V[Read_Index_V]; |
208 | Read_Index_V++; |
209 | if( Read_Index_V >= NUM_READ_V ) { Read_Index_V = 0; } |
210 | }
|
211 | if( (now - Last_Time_Read_U) >= UPDATE_TIME_U ) /// Nutzer_Stromsensoren |
212 | {
|
213 | Last_Time_Read_U = now; |
214 | for( byte i = 0 ; i < (ADC_NUM-2) ; i++ ) |
215 | {
|
216 | Total_U[i] -= Reading_U[i][Read_Index_U]; |
217 | Reading_U[i][Read_Index_U] = (short)analogRead(Analog_Port_Array[i+2]); |
218 | Total_U[i] += Reading_U[i][Read_Index_U]; |
219 | }
|
220 | Read_Index_U++; |
221 | if( Read_Index_U >= NUM_READ_U ) { Read_Index_U = 0; } |
222 | }
|
223 | if( (now - Last_Time_Check) >= UPDATE_TIME_CHECK ) /// Signal+Avg+Schutz |
224 | {
|
225 | Last_Time_Check = now; |
226 | /// Falls keine Verbindung, soll auch OHNE Befehl der
|
227 | /// Mittelwert in der USB-Struktur gespeichert werden,
|
228 | /// damit die LED weiterhin einen Status geben kann.
|
229 | if(!Serial) |
230 | {
|
231 | calc_save_avg(); |
232 | }
|
233 | temperaturschutz(); |
234 | ueberstromschutz(); |
235 | ueberspannungsschutz(); |
236 | unterspannungsschutz(); |
237 | update_states(); /// LED, WR und/oder MF beeinflussen |
238 | }
|
239 | }
|
240 | |
241 | /* USB-Data-Struktur mit den Mittelwert aus der
|
242 | * Gesamt_pro_Port-Data-Struktur speichern
|
243 | */
|
244 | inline void calc_save_avg() |
245 | {
|
246 | /// Stromstärke-Batterie-ADC-Wert
|
247 | adc = Total_A / NUM_READ_A; /// Mittelwert bilden |
248 | Data.adc[0] = (short)map(adc, Min_ADC.adc[0], Max_ADC.adc[0], -1023, 1023); /// Umwandeln per Verhältnis + speichern |
249 | /// Spannung-ADC-Wert
|
250 | adc = Total_V / NUM_READ_V; /// Mittelwert bilden |
251 | Data.adc[1] = (short)map(adc, Min_ADC.adc[1], Max_ADC.adc[1], 0, 1023); /// Umwandeln per Verhältnis + speichern |
252 | /// Stromstärke-Nutzer-ADC-Wert
|
253 | for( int i = 0 ; i < (ADC_NUM-2) ; i++ ) |
254 | {
|
255 | adc = Total_U[i] / NUM_READ_U; /// Mittelwert bilden |
256 | if(adc >= Offset.adc[i+2]) /// gemessenes größergleich Offset |
257 | {
|
258 | adc -= Offset.adc[i+2]; /// adc um offset erleichtern |
259 | Data.adc[i+2] = (short)map(adc, Min_ADC.adc[i+2], Max_ADC.adc[i+2], 0, 1023); /// Umwandeln per Verhältnis + speichern |
260 | }
|
261 | else /// gemessenes kleiner als Offset |
262 | {
|
263 | Data.adc[i+2] = (short)0; /// abspeichern → Strom/Spannung = 0 |
264 | }
|
265 | }
|
266 | }
|
267 | |
268 | /* Daten übertragen
|
269 | */
|
270 | inline void daten_senden() |
271 | {
|
272 | senden( (char*)&Data , (uint8_t)sizeof(Daten) ); |
273 | }
|
274 | |
275 | /* Grundeinstellung vom LED laden
|
276 | */
|
277 | inline void init_default_led() |
278 | {
|
279 | pinMode( PORT_LED , OUTPUT ); |
280 | set_port( PORT_LED , false ); |
281 | LED.setOutput(PORT_LED); |
282 | set_led(NO_COLOR); |
283 | LED.set_crgb_at(0, LED_rgb); /// Wert festlegen |
284 | LED.sync(); /// Werte an LEDs übertragen |
285 | }
|
286 | |
287 | /* Grundeinstellung vom Mosfet laden
|
288 | */
|
289 | inline void init_default_mosfet() |
290 | {
|
291 | pinMode( PORT_MF , OUTPUT ); |
292 | set_port( PORT_MF , true ); |
293 | }
|
294 | |
295 | /* Grundeinstellung vom LED laden
|
296 | */
|
297 | inline void init_default_temp() |
298 | {
|
299 | /// Suchen
|
300 | if ( ds.search(Temp_Addr) ) |
301 | {
|
302 | ds.skip(); |
303 | }
|
304 | else
|
305 | {
|
306 | ds.reset_search(); |
307 | }
|
308 | }
|
309 | |
310 | /* Grundeinstellung vom Wechselrichter laden
|
311 | */
|
312 | inline void init_default_wr() |
313 | {
|
314 | pinMode( PORT_WR , OUTPUT ); |
315 | set_port( PORT_WR, true ); |
316 | }
|
317 | |
318 | /* Konfiguration übertragen
|
319 | */
|
320 | inline void konfig_senden() |
321 | {
|
322 | /// die Konfiguration dem PC mitteilen
|
323 | senden( (char*)&Conf , (uint8_t)sizeof(Configuration) ); |
324 | }
|
325 | |
326 | /* Daten über USB senden und dabei den
|
327 | * Eingangspuffer leeren,
|
328 | * Daten byte-weise übertragen und
|
329 | * Ausgangspuffer leeren
|
330 | */
|
331 | inline void senden(char *structPointer, byte structLength) |
332 | {
|
333 | while( Serial.available() ) |
334 | {
|
335 | Serial.read(); |
336 | }
|
337 | for( int i = 0 ; i < structLength ; i++ ) |
338 | {
|
339 | Serial.write( structPointer[i] ); |
340 | }
|
341 | Serial.flush(); |
342 | }
|
343 | |
344 | /* Daten über USB empfangen und
|
345 | * dabei das Kommando auswerten und
|
346 | * passende Aktion ausführen
|
347 | */
|
348 | void serialEventRun() |
349 | {
|
350 | if (Serial.available()) |
351 | {
|
352 | switch(Serial.read()) |
353 | {
|
354 | case OPT::Mf_On : set_port( PORT_MF , true ); break; |
355 | case OPT::Mf_Off : set_port( PORT_MF , false ); break; |
356 | //case OPT::Wr_On : waiting(WR_DELAY); set_port( PORT_WR , true ); break;
|
357 | //case OPT::Wr_Off : waiting(WR_DELAY); set_port( PORT_WR , false ); break;
|
358 | case OPT::Send_Conf : konfig_senden(); |
359 | //case OPT::Kali : waiting(WR_DELAY); Strom_Kalibri_All(); break;
|
360 | case OPT::Send_Data : calc_save_avg(); daten_senden(); break; |
361 | }
|
362 | }
|
363 | }
|
364 | |
365 | /* Einen bestimmten digitalen Port einen Wert zuweisen
|
366 | */
|
367 | inline void set_port(int port , bool value) |
368 | {
|
369 | if( digitalRead( port ) != value ) { |
370 | digitalWrite( port , value ? HIGH : LOW ); |
371 | }
|
372 | }
|
373 | |
374 | /* Einer LED einen Farbwert zuweisen
|
375 | */
|
376 | inline void set_led(cRGB value) |
377 | {
|
378 | if( ( LED_rgb.r != value.r ) || ( LED_rgb.g != value.g ) || ( LED_rgb.b != value.b ) ) |
379 | {
|
380 | LED_rgb.r = value.r; |
381 | LED_rgb.g = value.g; |
382 | LED_rgb.b = value.b; |
383 | LED.set_crgb_at(0, LED_rgb); /// Wert festlegen |
384 | LED.sync(); /// Werte an LEDs übertragen |
385 | }
|
386 | }
|
387 | |
388 | /* Schutz: Mosfet und Wechselrichter sollen funktionieren, auch ohne PC
|
389 | */
|
390 | inline void temperaturschutz() |
391 | {
|
392 | /// ??????????
|
393 | ds.reset(); // RICHTIGE TEMP AKTUALISIERT NICHT |
394 | ds.select(Temp_Addr); // RICHTIGE TEMP AKTUALISIERT NICHT |
395 | /// start conversion (, with parasite power on at the end = ds.write(0x44, 1) )
|
396 | ds.write(0x44); // RICHTIGE TEMP AKTUALISIERT NICHT |
397 | ds.reset(); // FALSCHE TEMP AKTUALISIERT NICHT |
398 | ds.select(Temp_Addr); // FALSCHE TEMP AKTUALISIERT NICHT |
399 | /// Read Scratchpad
|
400 | ds.write(0xBE); // FALSCHE TEMP AKTUALISIERT NICHT |
401 | /// Lesen
|
402 | for (byte i = 0; i < 9; i++){ |
403 | Temp_Data[i] = ds.read();} |
404 | Temp_Raw = (Temp_Data[1] << 8) | Temp_Data[0]; |
405 | /// Sensortemperatur
|
406 | Temperatur = (float)Temp_Raw / 16.0; |
407 | /// Temp-Pegel prüfen
|
408 | if( Temperatur < OTP_MF_ON ) { |
409 | OTP_State = 2; } /// an + grün |
410 | else if( Temperatur > OTP_MF_OFF ) { |
411 | OTP_State = 0; } /// aus + rot |
412 | else { |
413 | OTP_State = 1; } /// gelb |
414 | }
|
415 | |
416 | /* Schutz: Mosfet soll funktionieren, auch ohne PC
|
417 | */
|
418 | inline void ueberspannungsschutz() |
419 | {
|
420 | if( Data.adc[1] < OVP_MF_ON_ID ) { |
421 | OVP_State = 2; } /// an + grün |
422 | else if( Data.adc[1] > OVP_MF_OFF_ID ) { |
423 | OVP_State = 0; } /// aus + rot |
424 | else { |
425 | OVP_State = 1; } /// gelb |
426 | }
|
427 | |
428 | /* Schutz: Mosfet soll funktionieren, auch ohne PC
|
429 | */
|
430 | inline void ueberstromschutz() |
431 | {
|
432 | tempAall = 0; |
433 | for(int i=2 ; i<ADC_NUM ; i++) |
434 | {
|
435 | tempAall += Data.adc[i]; |
436 | }
|
437 | if( tempAall < OCP_MF_ON_ID ) { |
438 | OCP_State = 2; } /// an + grün |
439 | else if( tempAall > OCP_MF_OFF_ID ) { |
440 | OCP_State = 0; } /// aus + rot |
441 | else { |
442 | OCP_State = 1; } /// gelb |
443 | }
|
444 | |
445 | /* Schutz: Wechselrichter soll funktionieren, auch ohne PC
|
446 | */
|
447 | inline void unterspannungsschutz() |
448 | {
|
449 | if( Data.adc[1] > UVP_WR_ON_ID ) { |
450 | UVP_State = 2; } /// an + grün |
451 | else if( Data.adc[1] < UVP_WR_OFF_ID ) { |
452 | UVP_State = 0; } /// aus + rot |
453 | else { |
454 | UVP_State = 1; } /// gelb |
455 | }
|
456 | |
457 | /* USB-Verbindung herstellen
|
458 | */
|
459 | inline void Verbinden() |
460 | {
|
461 | Serial.begin(BPS); |
462 | }
|
463 | |
464 | /* Eine bestimmte Dauer abwarten
|
465 | */
|
466 | inline void waiting(unsigned long dauer) |
467 | {
|
468 | unsigned long jetzt = millis(); |
469 | while( ( millis() - jetzt ) < WR_DELAY ){} |
470 | }
|
471 | |
472 | /* Mittelwert-Data-Struktur auf 0 setzen
|
473 | */
|
474 | inline void zero_reading_data() |
475 | {
|
476 | for( int i = 0 ; i < NUM_READ_A ; i++ ) { Reading_A[i] = 0; } |
477 | for( int i = 0 ; i < NUM_READ_V ; i++ ) { Reading_V[i] = 0; } |
478 | for( int i = 0 ; i < NUM_READ_U ; i++ ){ |
479 | for( int j = 0 ; j < (ADC_NUM-2) ; j++ ) { Reading_U[j+2][i] = 0; } |
480 | }
|
481 | }
|
482 | |
483 | /* Gesamt_pro_Port-Data-Struktur auf 0 setzen
|
484 | */
|
485 | inline void zero_total_data() |
486 | {
|
487 | Total_A = 0; |
488 | Total_V = 0; |
489 | for( int i = 0 ; i < (ADC_NUM-2) ; i++ ) { Total_U[i] = 0; } |
490 | }
|
491 | |
492 | /* USB-Data-Struktur auf 0 setzen
|
493 | */
|
494 | inline void zero_usb_data() |
495 | {
|
496 | for( int i = 0 ; i < ADC_NUM ; i++ ) |
497 | {
|
498 | Data.adc[i] = 0; |
499 | }
|
500 | }
|
501 | |
502 | /* Anhand der Protect_States die LED farblich gestalten und
|
503 | * Mosfet bzw. Wechselrichter schalten
|
504 | */
|
505 | void update_states() |
506 | {
|
507 | /// Mindest 1 der States ist 0 → Rot → WR bzw MF ausschalten
|
508 | if( !OCP_State || !OTP_State || !OVP_State || !UVP_State ){ |
509 | set_led(OCP_OTP_OVP_UVP); /// Rot festlegen |
510 | ////// Einer der WR-Relevanten States sind 0
|
511 | if( !UVP_State ) { |
512 | set_port( PORT_WR , false ); /// Wechselrichter ausschalten |
513 | Last_Time_WR_Off = now;} /// Zeit notieren für Einschaltverzögerung |
514 | ////// Einer der MF-Relevanten States sind 0
|
515 | else{ |
516 | set_port( PORT_MF , false ); /// Mosfet ausschalten |
517 | Last_Time_MF_Off = now;} } /// Zeit notieren für Einschaltverzögerung |
518 | /// Keins der States ist 0
|
519 | else{ |
520 | ////// Alle States sind mindest 2 → Grün üder Türkis
|
521 | if( ( OCP_State == 2 ) && ( OTP_State == 2 ) && |
522 | ( OVP_State == 2 ) && ( UVP_State == 2 ) ){ |
523 | if( ( ( now - Last_Time_WR_Off ) >= TIME_WR_OFF_TO_ON ) && |
524 | ( ( now - Last_Time_MF_Off ) >= TIME_MF_OFF_TO_ON ) ){ |
525 | ///////// Alle WR-Relevanten Stetes sind 2
|
526 | set_port( PORT_WR , true ); /// Wechselrichter ausschalten |
527 | ///////// Alle MF-Relevanten States sind 2
|
528 | set_port( PORT_MF , true ); /// Mosfet einschalten |
529 | ///////// Wartezeit für wieder einschalten abgelaufen
|
530 | set_led(NO_PROTECT); } /// Grün festlegen |
531 | else{ |
532 | ///////// Wartezeit für wieder einschalten noch nicht abgelaufen
|
533 | set_led(TIME_NO_PROTECT); } } /// Türkis festlegen |
534 | ////// Mindest 1 der States ist 1 → Gelb oder Lila → für Alarmanzeige
|
535 | else{ |
536 | if( ( ( now - Last_Time_WR_Off ) >= TIME_WR_OFF_TO_ON ) && |
537 | ( ( now - Last_Time_MF_Off ) >= TIME_MF_OFF_TO_ON ) ){ |
538 | ///////// Wartezeit für wieder einschalten abgelaufen
|
539 | set_led(ALERT_PROTECT); } /// Gelb festlegen |
540 | else{ |
541 | ///////// Wartezeit für wieder einschalten noch nicht abgelaufen
|
542 | set_led(TIME_ALERT_PROTECT); } } } /// Lila festlegen |
543 | }
|
544 | |
545 | /*
|
546 | * Funktionen für später
|
547 | */
|
548 | |
549 | /*
|
550 | void EEPROM_auslesen()
|
551 | {
|
552 | for(byte i=0; i<(ADC_NUM); i++)
|
553 | EEPROM.get(EEPROM_Kalibrierung+(2*i), ADC_Offset[i]);
|
554 | }
|
555 | */
|
556 | |
557 | /*
|
558 | void Strom_Kalibri_All(){}
|
559 | */
|
:
Bearbeitet durch Admin
Beitrag #6386472 wurde von einem Moderator gelöscht.
Macht das Programm zufällig nach ~50 Tagen Probleme?
Funkdeppjäger schrieb im Beitrag #6386472: > Sag mal glaubst du wirklich, dass sich einer deinen Schrott ansieht und > deine Hausaufgaben macht? Ausserdem gehört der Text in einen Anhang und nicht in den Beitrags-Textkörper! Siehe: Wichtige Regeln - erst lesen, dann posten! .... Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
Tim B. schrieb: > Nun bleibt der uC bei einem Kunden immer wieder hängen. Softwarefehler. Oder andersrum: die Software kommt nicht damit klar, dass da ein kleiner, fies kurzer Störimpuls kommt, wenn jemand das Licht ausschaltet. Tim B. schrieb: > Das ist der Arduino-Sketch: Sowas bitte als Anhang (wie in der Anleitung über jeder Texteditbox geschrieben]! Oder pack den C-Code wenigstens in [C] Tags. Dann gibts Syntax-Highlighting gratis. > short adc = 0; /// temporär für Berechnungen usw. Wenn du in einer Funktion eine temporäre Variable brauchst, warum deklarierst du die dann nicht dort, wo sie hingehört? > /// Das ist die Lizenz Netter Ansatz... ;-)
:
Bearbeitet durch Moderator
Tim B. schrieb: > Also es ist so, dass ich nur sehr begrenzt progrtammieren kann Tim B. schrieb: > bei einem Kunden Aha.
Ingo Less schrieb: > Macht das Programm zufällig nach ~50 Tagen Probleme? Leider schon wesentlich früher. Beim Kunden tritt das Problem anscheinen schon nach ein bis zwei Stunden auf.
Tim B. schrieb: > Außerdem müsste die Software dann ja zeitlich immer nach einer > bestimmten Anzahl von Schreibvorgängen - also auch nach einer bestimmten > Zeit abstürzen. Eben nicht unbedingt nach einer bestimmten Zeit: Es könnte z.B. sein, dass ein Interrupt, wenn er an einer bestimmten Stelle des Hauptprogramms auftritt, den Fehler produziert. Dann ist das ein Zufallsgenerator: Zeitpunkt des Interrupts und Laufzeit der Hauptschleife. Solche Fehler sind nur schwer zu finden. Da hilft oft nur Durcharbeiten aller kritischen Stellen im Programm. Und um zu wissen, welche Stellen kritisch sind, braucht dann schon Erfahrung.
Tim B. schrieb: > Die Schaltung Lass doch mal sehen. Und das Layout. Und den Aufbau. Nicht, dass da doch auch noch ein Problem drin ist... ;-)
Kommt evtl. so viel Noise über die serielle Schnittstelle, dass diese sich gestört fühlt und hier
1 | while( Serial.available() ) |
2 | {
|
3 | Serial.read(); |
4 | }
|
hängen bleibt?
Lothar M. schrieb: > Tim B. schrieb: >> Die Schaltung > Lass doch mal sehen. Und das Layout. Und den Aufbau. Nicht, dass da doch > auch noch ein Problem drin ist... ;-) Das ist das Layout. Das ist aber vermutlich so erst mal schwer zu verstehen...
Ingo Less schrieb: > Kommt evtl. so viel Noise über die serielle Schnittstelle, dass diese > sich gestört fühlt und hier
1 | > while( Serial.available() ) |
2 | > { |
3 | > Serial.read(); |
4 | > } |
5 | >
|
> hängen bleibt?
Das würde erklären warum das Ding beim Kunden abstürzt und bei mir
nicht. Aber we kann man dem begegnen? Kabel besser schirmen?
Ingo Less schrieb: > Tim B. schrieb: >> Ist vielleicht das Aktivieren des Watchdogs >> über die Fuses eine Lösung (Watchdog timer always on; [WDTON=0])? Wird >> der uC dann automatisch neu gestartet wenn er abstürtzt? > Nein, der Watchdog ist das allerletzte Mittel, den µC wieder zu holen, > wenn man selber keinen Einfluss mehr nehmen kann. Ein Programm, dass auf > einen WDT angewiesen ist, damit es läuft ist ein schlechtes Programm. Irgendwie habe ich die Tendenz das trotzdem so zu lösen. Zumindest dann, wenn der Fehler durch Störimpuse hervorgerufen wird. Dazu müsste ich aber die Ursache kennen...
Serial ist virtuell. Da reicht dann auch ein virtueller Schirm. ;-) Im Ernst: Ich kann das Programm kaum lesen und noch viel weniger verstehen. Das ist C++. Damit lässt sich viel schöner modularisieren, als es hier zu sehen ist. Auch behagen mit die Defines nicht so, die meisten lassen sich sicherlich ersetzen.
Ich vermute einfach mal dass ein EMV-Problem vorliegt. Die Schaltung in ein Gehäuse welches auch geerdet ist (Schukostecker) und eine gründlich entstörte Spannungsversorgung helfen dort fast immer. bzw. hast du die USB-Versorgung so wie in den Application Notes geschrieben, entstört? Den Plan haben wir ja nicht. Der Watchdog hilft den Gerät wieder auf die Beine, aber das ist eine sehr "dirty" Lösung, die man nur macht wenn wirklich nichts mehr geht. o/ Anselm
Sieht so aus als ob über die fetten Tracks richtig Strom fließt und die winzigen Leitungen quer dazu gehen dann vom/zum µC. Hm, ob das nicht Probleme macht ? Was sind das für dicke 10-polige Teile ? Shunts ? Gehört das zum oekotrainer.de ?
:
Bearbeitet durch User
Thomas W. schrieb: > Sieht so aus als ob über die fetten Tracks richtig Strom fließt > und die > winzigen Leitungen quer dazu gehen dann vom/zum µC. Hm, ob das nicht > Probleme macht ? > Was sind das für dicke 10-polige Teile ? Shunts ? An die Leisterplatte ist ein 40 Ah Akku und ein 1000 W Wechselrichter angeschlossen. Es fließt also tatsächlich ein sehr großer Strom. Der Akku wird über 10 Eingänge geladen. Die 4 MosFETs können die Eingänge im Fehlerfall trennen. Der Strom der 10 Eingänge wird jeweils über einen Hallsensor gemessen - ebenso der Strom zwischen Akku und Wechselrichter. Die Spannung für den uC wird mit einem LM317 erzeugt. Ich bin davon ausgegangen - dass der Akku mit dem niedrigen Innenwiederstand hier für stabilie Verhältnisse sorgt. Außerdem gibt es ja auch diverse Kondensatoren parallel zur Spannungsversorgung direkt am uC. Wenn es hier Schwierigkeiten gäbe würde der uC ja auch im Testlauf ständig abstützen. Das Problem tritt aber nur beim Kunden auf...
Ich würde die Reset Leitung des Micros (ISP Verbinder) ja nicht unbedingt durch die Hälfte der Strompfade mitten durchrouten. Für mich sieht das so aus. als ob da schön viele Antennen sind die Dir alle möglichen Signale einfangen...: - Ich würde die Filter für die HAL Sensoren direkt am Mikrocontroller plazieren - Die Eingänge groundseitig abzutrennen ist auch sehr mutig. Was passiert im Fehlerfall? Ist die Eingangsspannung irgendwie begrenzt? Denn nach dem Abtrennen fehlt ja die Last durch den Akku. - Bei solchen Strömen sollte man Leistungsteil und Steuerteil separieren. - In die HAL Sensoren koppeln die Magnetfelder der Nachbarleitungen und auch der eigenen Leitungen zusätzlich ein. Im Datenblatt steht wie man es richtig macht
Tim B. schrieb: > Das ist das Layout. Das ist aber vermutlich so erst mal schwer zu > verstehen... Es ist schon mal schwer zu erkennen. Poste das mal als PNG und möglichst großformatig. Da gibts auch eine Checkbox, dass das Bild nicht verkleinert werden soll. Zum Verständnis trägt dann der Schaltplan bei... ;-) Tim B. schrieb: > Aber we kann man dem begegnen? Kabel besser schirmen? Die Software fehlertolerant machen. Und die Hardware mal im Labor ein wenig mit EMV belasten. Du schreibst da auch was von USB. Das ist beim EMV-Test bei mir immer der erste Bus, der abkotzt. Ich habe für die Schaltungsinbetriebnahme für begleitende "EMV-Vortests" einfach einen Viehtreiber wie https://www.ebay.de/itm/Viehtreiber-HandyShock-Rind-Tier-Treiber-11215/381541741059 gekauft. Dazu brauche ich dann noch eine Metallplatte und eine Kunststoffplatte. Jetzt kommt das Metallblech auf den Labortisch, die Kunstoffplatte als Isolator drauf und auf diese Kunststoffplatte gut von der Metallplatte isoliert meine neue Schaltung. Die lasse ich laufen und zünde mit dem Viehtreiber auf die Metallplatte (einfach rein und gleich wieder raus, nicht in die Schaltung, die wäre sofort kaputt). Wenn meine Schaltung und die Software das überstehen, dann kann ich mich ins Feld trauen. Dieser Aufbau ist der "Burst-Test des kleinen Mannes"... ;-)
:
Bearbeitet durch Moderator
Tim B. schrieb: > Das ist das Layout. Das ist aber vermutlich so erst mal schwer zu > verstehen... So auf den ersten Blick wird das nie funzen. Du hast einfach zu hohe Schaltströme zu dicht an empfindlicher Elektronik. Besser auf zwei Leiterplatten verteilen. Softwarefehler kann man mit einem Zähler eingrenzen den man entweder nach dem Reset ausgibt oder bei Aufruf oder zwischen der Routinen.
Na wenn schon die schwindelige PC Software einfriert, weil sie durcheinanderkommt, dann wird der Arduino Profi sich wohl eher gar nicht um Fehlersituationen, deren Erkennung und Behandlung Gedanken gemacht haben. Das ist alles mit der heißen Nadel gestrickt, ausnahmslos....
Tim B. schrieb: > Das würde erklären warum das Ding beim Kunden abstürzt und bei mir > nicht. Aber we kann man dem begegnen? Kabel besser schirmen? besser wäre doch die empfangenen Daten auf Plausibilität zu prüfen kommen da Zeichen die man erwartet? isprint isnum isalpha wären mögliche Tests wenn unplausible Zeichen kommen, wird der Buffer geleert? werden unplausible Zeichen weiter eingelesen? Droht Bufferüberlauf?
Tim B. schrieb: > Also es ist so, dass ich nur sehr begrenzt progrtammieren kann, weshalb > ich sowohl beim Arduino-Sketch sehr viel Hilfe hatte und an der > PC-Software gar nicht beteiligt war. Tim B. schrieb: > Das Problem tritt aber nur beim Kunden auf... Klingt nach Volkswagen ;). Tu dir selbst einen gefallen und nimm das Produkt schnell vom Markt, bevor sich jemand die Bude damit abfackelt. Ich vermute mal deine Bastelei hat keine EMV Tests gesehen. Genausowenig Vertrauen erweckt dein Layout. Sprint Layout ist einfach mal nicht das Programm der Wahl wenn man kundenfähige Produkte entwicklen möchte. Wie hälst du Schaltplan und Layout syncron? Oder gibt es gar keinen Schaltplan und es wurde direkt drauf loslayoutet? Wenn ich lese, dass du 4 Mosfets schaltest im Fehlerfall... Wie wurde der Fehlerfall in der FMEA bewertet? Welches Performance Level soll deine Sicherheitsschaltung erfüllen? Wie hast du den Fall simuliert? Wie hast du den Fall getestet? Solche Sachen wie du habe ich vor 10 Jahren auch gebaut, ich hatte die gleichen Probleme und wäre nicht im Traum darauf gekommen das zu verkaufen, da ich wusste das es zwar halbwegs funktioniert, aber nicht die Zuverlässigkeit an den Tag legt, die ich von so einem Produkt erwarten würde. Aber zurück zum Problem. Schaltet dein Kunde während des Betriebs Leuchtstoffröhren? Wie sicher bist du dir, dass es der µC ist? Hängt sich evenutell die Schnittstelle am PC auf? (Hatte ich bei mir privat, da war das PC Netzteil billiger Kernschrott und die Spannungen waren sehr instabil) Es soll kein Bashing deines Produkts werden, bitte bleib unbedingt dran an der Elektronik. Aber das was du hier präsentiert hast ist weder tauglich noch sicher. Im Interesse deiner Kunden und deiner Freiheit: Nimm das Produkt vom Markt, entwickel es neu, teste und validiere es und dann vermarkte es. Nutze KICAD für das Layout (Open Source), lasse Prototypen fertigen und dann teste sie systematisch oder gib sie zu einem Softwaretester (ISTQB). Falls das finaziell nicht drin ist, dann teste du die Funktionen. Was passiert wenn deine serielle Schnittstelle Werte von 0 bis 10 erwartet, du aber ein "ü" sendest? Was passiert mit Funktionen die ein uint8_t erwarten, wenn stattdessen ein "-3" übergeben wird. Stichwort: Error Handling. VG Paul
Ich hatte auch mal ne Schaltung, ein Step-Down, bei dem bei zu viel Power die serielle Schnittstelle am PC abgestürzt ist... Also zu viel EM können die nicht vertragen. Bei meinem ST-Link verliere ich regelmäßig die Verbindung zum uC wenn ich ne Schaltung habe, die zu sehr sendet bzw. größere Ströme im Spiel sind!
Joachim B. schrieb: > besser wäre doch die empfangenen Daten auf Plausibilität zu prüfen > kommen da Zeichen die man erwartet? > > isprint > isnum > isalpha > > wären mögliche Tests > > wenn unplausible Zeichen kommen, wird der Buffer geleert? Falls die Zeichen nicht palausibel sind, kommt noch "ISNICHWAHR!" in Frage.
Ingo Less schrieb: > Nein, der Watchdog ist das allerletzte Mittel, den µC wieder zu holen, > wenn man selber keinen Einfluss mehr nehmen kann. Ein Programm, dass auf > einen WDT angewiesen ist, damit es läuft ist ein schlechtes Programm. Die große Frage ist das Betriebssystem. preemtiv oder kooperativ? Der Watchdog sollte nicht nur einen Wiederanlauf ermöglichen, sondern auch Debuginforationen sichern. Zu diesen Informationen zählt ein Schnappschuß der Register insbesondere des SP und PC. Der PC läßt auf die Stelle des Hängers schließen. Auch andere "Exceptions", z.B. Division durch Null, sollten so behandelt werden. Für die Implementierung macht preemtiv oder kooperativ einen großen Unterschied aus. Bei kooperativen BS löst jede Dauerschleife eine WD-Restart aus. Bei preemtiven BS, wie Linux, können einzelne Prozesse oder Threads hängen. Hier ist es sinnvoll Überwachungsprozesse zu implementieren, die die zu überwachenden Prozesse auf Plausibiltät bzw. korrekten Ablauf prüfen.
:
Bearbeitet durch User
ich persönlioch bin ja schon kein Fan davon eine schon grün leuchtende LED im nächsten "Arbeitsschritt" auf Grün zu schalten, ich finde "schalter" egal welche, ob LEDS der sonstige outputs sollte NUR geschaltet werden wenn sich der Zustand ändert. und sowas:
1 | void setup() |
2 | {
|
3 | ...
|
4 | Verbinden(); |
5 | }
|
6 | inline void Verbinden() |
7 | {
|
8 | Serial.begin(BPS); |
9 | }
|
finde ich auch fürchterlich nutzlos wenn eine funktion ausschliesslich einmalig im setup() aufgerufen wird, ist sie mMn zu entfernen und ihr code ins setup zu schreiben; insbesondere wenn es nur ein stumpfer Einzeler ist. Egal ich behaupte der Fehler taucht in der ds auf, die konvertierung via ds.write(0x44) kann ne Sekunde dauern, millis laufen weiter, schlimmer noch das Konversionsergebniss wird von Dir vollständig verworfen
1 | ds.reset(); // RICHTIGE TEMP AKTUALISIERT NICHT |
2 | ds.select(Temp_Addr); // RICHTIGE TEMP AKTUALISIERT NICHT |
3 | ds.write(0x44); // RICHTIGE TEMP AKTUALISIERT NICHT |
4 | ds.reset(); // FALSCHE TEMP AKTUALISIERT NICHT |
5 | ds.select(Temp_Addr); // FALSCHE TEMP AKTUALISIERT NICHT |
ist also mindestens 'übereilt'
1 | ds.reset(); // RICHTIGE TEMP AKTUALISIERT NICHT |
2 | ds.select(Temp_Addr); // RICHTIGE TEMP AKTUALISIERT NICHT |
3 | ds.write(0x44); // RICHTIGE TEMP AKTUALISIERT NICHT |
4 | delay(1000); |
5 | ds.reset(); // FALSCHE TEMP AKTUALISIERT NICHT |
6 | ds.select(Temp_Addr); // FALSCHE TEMP AKTUALISIERT NICHT |
wäre der sicherere weg. heisst aber dass alle "timer" die Du has immer auslösen MÜSSEN (alle kleiner einer Sekunde) deswegen solltest Du sie entsprechend anpassen. Apropos...
1 | #define UPDATE_TIME_A 4 /// ms zwischen den Messungen vom Haupt-Stromsensor
|
ist natürlich auch eher unsinnig Im Grunde kannst Du UPDATE_TIME_A fast genausogut komplett weglassen und den Code bei jedem Schleifendurchlauf ausführen, der braucht selbst in etwa 2.5-3ms würd ich schätzen. spielt aber keine Rolle, denn ab dem ersten triggern von temperaturschutz() ist jede folgende loop() eh komplett auf "max" und alle vergleiche triggern darunterliegenden Code Mach mal den Test wie folgt:
1 | void loop() |
2 | {
|
3 | now = millis(); |
4 | if(now > 1000 && now < 10000) |
5 | Serial.writeln(now); |
6 | ...
|
(sollte in den ersten zehn sekunden die Zweit zwischen zwei Loop durchläufen veranschaulichen) und achte mal darauf wie gross der Abstand zwischen den letzten paar durchläufen ist, ich möchte wetten, dass Du überhaupt nur 10 zeitangaben über den serial monitor bekommst, (alles andere würde mich bei dem oneWire protokoll echt wundern) 'sid
Leute, vielen lieben Dank für die vielen Beiträge und Tipps. Ich werde am Montag weiter machen. Jetzt raucht der Kopf. Eines konnte ich allerdings noch feststellen: Ich habe den Watchdog aktiviert und der uC ist trotzdem hängen geblieben. Ich habe darum nun die Kommunikation mit dem PC im Verdacht. Eure Tipps werde ich mir natürlich trotzdem anschauen - vieles davon betrifft ja auch diesen Punkt. Das doofe an dieser ganzen Sache ist, dass ich den Fehler nicht auslösen kann und darum immer Stunden lang warten muss bis der Fehler auftritt. EMV-Quälen habe ich mangels Weidezaungerät jetzt mal versucht wie hier beschrieben. Dabei habe ich mit dem Relais, der Leuchtstofflampe und einer alten Bohrmaschine direkt über dem uC rumhantiert. Das hat ihm alles nix ausgemacht :-)
Sowohl die Schaltung als auch das Programm sind komplex. Ich würde drei Dinge versuchen: a) Kläre, ob das Ding ohne große Lastströme zuverlässig funktioniert. b) Gebe jede Menge Logmeldungen auf einem zweiten seriellen Port aus und zeichne diese in eine Datei auf. Diese Meldungen sollten einen Hinweis darauf geben, an welcher Stelle das Programm hängen bleibt und was kurz vorher passierte. c) Reduziere das Programm auf weniger, um den Fehler einzukreisen. Man könnte sich da mal ganz dumm stellen und einfach mal jede Sekunde "Hallo" ausgeben. Dann mal schauen, ob das wenigstens stabil läuft. Danach könnte man Schaltvorgänge im Lastkreis manuell auslösen, um zu sehen, ob diese sich negativ auswirken. Was manchmal auch Wunder wirkt: Zur Stromversorgung eine Batterie verwenden. Muss ja nicht für immer so bleiben, sondern nur, um Probleme mit dem Netzteil oder Masseschleifen auszuschließen.
Hier wird die Variable "dauer" gar nicht benutzt:
1 | /* Eine bestimmte Dauer abwarten
|
2 | */
|
3 | inline void waiting(unsigned long dauer) |
4 | {
|
5 | unsigned long jetzt = millis(); |
6 | while( ( millis() - jetzt ) < WR_DELAY ){} |
7 | }
|
Ich wollte das gerne zum Test compilieren, aber dazu fehlt die WS2812.h.
Stefan ⛄ F. schrieb: > Ich wollte das gerne zum Test compilieren, aber dazu fehlt die WS2812.h. Vielleicht sollte später WR_DELAY durch dauer ersetzt werden.
Stefan ⛄ F. schrieb: > while( ( millis() - jetzt ) < WR_DELAY ){} Ich nehme an, mills() liefert den Wert des Systemtickers zurück und dieser ist auch vom Typ unsigned long. Was passiert nach einem Überlauf von 0xffffffff auf 0 ? Dann gibt es sehr lange Wartezeiten, oder?
:
Bearbeitet durch User
Gerald K. schrieb: > Was passiert nach einem Überlauf von 0xffffffff auf 0 ? > Dann gibt es sehr lange Wartezeiten, oder? Nein, die zeit stimmt nach einem Überlauf immer noch. Voraussetzung ist, dass man wie hier subtrahiert.
Gerald K. schrieb: > Was passiert nach einem Überlauf von 0xffffffff auf 0 ? > > Dann gibt es sehr lange Wartezeiten, oder? Da passiert gar nix (überraschendes). Das Prinzip heißt in der Arduinowelt "Blink without Delay". Zumindest wird in dem Beispiel das Prinzip implementiert. Und ja: Keine Problem beim Überlauf, wenn das Intervall kleiner als 49,x Tage ist
Vielleicht gibt es in der Nähe von oekotrainer.de einen Dienstleister, der sich das ganze mal anschauen möchte? Lothar M. schrieb: ... > Ich habe für die Schaltungsinbetriebnahme > für begleitende "EMV-Vortests" einfach einen Viehtreiber wie > https://www.ebay.de/itm/Viehtreiber-HandyShock-Rind-Tier-Treiber-11215/381541741059 > gekauft. Dazu brauche ich dann noch eine Metallplatte und eine > Kunststoffplatte. Jetzt kommt das Metallblech auf den Labortisch, die > Kunstoffplatte als Isolator drauf und auf diese Kunststoffplatte gut von > der Metallplatte isoliert meine neue Schaltung. Die lasse ich laufen und > zünde mit dem Viehtreiber auf die Metallplatte (einfach rein und gleich > wieder raus, nicht in die Schaltung, die wäre sofort kaputt). Wenn meine > Schaltung und die Software das überstehen, dann kann ich mich ins Feld > trauen. > Dieser Aufbau ist der "Burst-Test des kleinen Mannes"... ;-) Lothar, Du begeisterst mich. Damit wird die 61000-4-2 (ESD) ein Kinderspiel. Und auch die für die anderen Störempfindlichkeiten bekommt man ein besseres Gefühl. Ich halte gerne mal ein klingelndes Handy an Baugruppen. Gerade bei Analogschaltungen sieht man da schnell die Störempfindlichkeit. Und wenn die MCU abstürzt, bietet das Design noch viel Verbesserungspotential. Frage: weißt Du, was der Viehtreiber rausreicht? Ladespannung (1..15kV), Ladekapazität (150pF) und Ausgangsimpedanz (330R)? (Zum Vergleich, Werte aus der EN61000-4-2).
Beitrag #6387042 wurde vom Autor gelöscht.
Bananensoftware : Reift beim Kunden😂😂😂👍👍
Ich habe inzwischen versucht die Schaltung nochmal mit allen möglichen EMV-Störungen zu malträtieren (auch mit der Viehschockermethode mit echtem Viehschocker :-)) aber was ich auch mache, es hat keinen Einfluss auf die Schaltung. Außerdem habe ich den Code für den uC so geändert, dass er nur kuriose Zeichenketten an den PC sendet. Das hat nur dazu geführt, dass die PC-Software kurioses anzeigt (was hier nicht weiter schlimm ist) aber kein Absturz und kein Hänger. Ich habe das while (serial.available()aus dem Code entfernt und einen einfachen Watchdog eingebaut. Vielleicht hat ersteres das Problem ja auch tatsächlich schon behoben. Sicher weiß ich das nicht, weil ich den Fehler ja doofer weise ja durch nichts auslösen konnte. Als nächstes werde ich versuchen vom PC zum uC kuriose Zeichenketten zu senden. Anschließend werde ich mich nochmal mit der ds.write(0x44)-Sache beschäftigen. Ein delay einzubauen ist hier aber keine Lösung, weil das Programm weiterlaufen muss. Da würde ich dem Temp-Sensor eher komplett deaktivieren.
Wahrscheinlich liest ja keiner mehr aber vielleicht ja auch doch:
Inzwischen hat sich herrausgestellt, dass ein defekter Wechselrichter
die Störquelle war, der zwischen Eingang GND und PE eine Spannung von
mehreren hundert Volt produziert hat.
Eine Messelektronik wird über den Akku, an den auch der Wechselrichter
angeschlossen ist, gespeist. Ein PC nimmt die Signale der Messelektronik
über eine USB-Verbindung ab. Dadurch ist der PC über die USB-Verbindung
mit dem Minus-Pol eines Akkus verbunden. Der Wechselrichter ist defekt
und liefert darum (unter Last) gemessen zwischen Minus-Pol des Eingangs
und Schutzleiter des Ausgangs, impulsweise eine sehr hohe Spannung von
>500V. An den Wechselrichter ist ein Beamer angeschlossen und verbindet,
sobald er eingeschaltet wird den Schutzleiter mit dem Gehäuse des
HDMI-Steckers. Wenn nun der HDMI-Stecker am PC eingesteckt wird, liegt
die hohe Spannung zwischen Minus USB und Gehäuse HDMI Stecker an und
sorgt offensichtlich dafür, dass die Schutzschaltung des PCs den
USB-Port lahmgelegt. Mir ist das aufgefallen, weil der USB-Port, schon
nicht mehr funktioniert hat bevor ich den HDMI-Stecker ganz eingesteckt
habe. Als ich das dann näher beobachtet habe, habe ich bemerkt, dass
beim Kontakt des HDMI-Steckers mit der Buchse Funken zu sehen sind.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.