Hallo!! Ich habe für ein Uni Projekt eine einfache Modbus RTU Schnittstelle auf einem Atmega 32 implementiert. Ich verwende lediglich zwei Funktionscodes, FC03 und FC16. Der AVR ist Modus Slave. Es gibt insgesamt 10 Register, von denen zwei beschrieben werden und 6 gelesen werden können. Das ganze funktioniert im Prinzip auch so wie ich es mir vorgestellt habe. Jedoch hab ich das Problem, dass sich der µC nach einer nicht definierter Anzahl von Polls resetet. Dabei spielt es keine Rolle ob ich mit 100ms oder 1s Befehle sende. Nach einiger Zeit kommt der reset. Der Testaufbau besteht aus dem Programm Modbus Poll, einem RS485 / USB Converter von In-Curcuit. Bus Treiber auf AVR Seite ist ein MAX485. Ich habe meinen Quellcode etliche Male überprüft, kann aber keinen Fehler finden welcher zu einem Reset führen könnte. Vielen Dank für eure Hilfe, Manuel
Manuel K. schrieb: > Ich habe meinen Quellcode etliche Male überprüft, kann aber keinen > Fehler finden welcher zu einem Reset führen könnte. Du müsstest auch noch deinen Aufbau zeigen. Einen Reset bekommt der AVR eventuell durch die offene (lange?) Leitung die zum ISP Connector führt. "Herumvagabundierende" Felder induzieren auf der Leitung eine Störspannung die den AVR resetten lässt. Unbedingt einen Pullup 2..10K vorsehen, evtl. noch einen Kondensator 10..100nF.
- ARef gehört nicht an Vcc! - C5 und C6 sind nahe an Vcc und AVcc? - C1 und C2 haben keinen Wert, sind die vorhanden?
Hab gerade gemerkt, dass der Schaltplan nicht mehr ganz up to date ist.... Kondensatoren sind überall direkt an den Pins vorhanden. Atmega 32: Reset - Vcc Vcc (10) - GND (11) Vcc (30) - GND (31) Aref (32) - GND (31) MAX485 Vcc - GND Der Pull Up mit 10k am Reset ist auch vorhanden. Die Leitungswege sind relativ kurz. Aref, okay. Aber wohin damit?? Aber das kann ja eigentlich nicht die Ursache sein. Du würdest also die Ursache für den Reset ehr in der Hardware als in der Software sehen? (Zum Aufbau, der Lastwiderstand war nur zum testen des Schaltreglers drin, ist entfernt. Von den Buchsen im Schaltplan ist nur eine bestückt und angeschlossen. Der Rest kommt später hat aber mit dem Modbus erstmal nichts zu tun.)
Hab gerade nochmal mit Oszi gemessen. Der Reset Eingang bleibt die ganze Zeit brav auf 5V. Es muss scheinbar doch am Programm liegen...
Manuel K. schrieb: > Der Reset Eingang bleibt die ganze Zeit brav auf 5V. Wobei es oft sehr schwierig sein kann so einen (vermuteten) Spike mit dem Oszilloskop aufzufangen. Es tritt ja genau einmal auf, kann sehr kurz sein, und dann ist wieder lange Zeit Ruhe. Manuel K. schrieb: > Es muss scheinbar doch am Programm liegen... Ja dein Buffer kann ja überlaufen, dann passieren die wildesten Dinge. Ich habe dein Programm nicht daraufhin überprüft.
Manuel K. schrieb: > Ich habe meinen Quellcode etliche Male überprüft, kann aber keinen > Fehler finden welcher zu einem Reset führen könnte. Typisch für sporadische Abstürze ist ein zu klein gewählter Stack. Vergrößere ihn mal probeweise um 0x10 Bytes.
Ich habs mal eben durch den Compiler geschoben: :\pocketcpp\avr-gcc-6.1.0-x86-mingw\avr\include\avr\signal.h:36:2: warning: #warning "This header file is obsolete. Use <avr/interrupt.h>." [-Wcpp] ../main.c:404:15: warning: iteration 32 invokes undefined behavior [-Waggressive-loop-optimizations] ../main.c:411:15: warning: iteration 32 invokes undefined behavior [-Waggressive-loop-optimizations] Die letzten beiden solltest du dir mal anschauen... Oliver
Du hast in deinem Code mehrere Fehler!
1 | #define rxbuffersize 32
|
2 | #define txbuffersize 32
|
3 | ...
|
4 | uint8_t rxbuffer[rxbuffersize]; |
5 | uint8_t txbuffer[txbuffersize]; |
6 | ...
|
7 | void cleanrxbuffer(void){ |
8 | for (int i = 0; i<=rxbuffersize; i++){ |
9 | rxbuffer[i] = 0; |
10 | }
|
11 | rxbyte = 0; |
12 | }
|
13 | |
14 | void cleantxbuffer(void){ |
15 | for (int i = 0; i<=txbuffersize; i++){ |
16 | txbuffer[i] = 0; |
17 | }
|
18 | |
19 | }
|
Generiert dir einen Array Overflow! richtig wäre wohl:
1 | void cleanrxbuffer(void){ |
2 | for (int i = 0; i < rxbuffersize; i++){ |
3 | rxbuffer[i] = 0; |
4 | }
|
5 | rxbyte = 0; |
6 | }
|
7 | |
8 | void cleantxbuffer(void){ |
9 | for (int i = 0; i < txbuffersize; i++){ |
10 | txbuffer[i] = 0; |
11 | }
|
12 | }
|
Zusätzlich musst du an diversen Orten noch die Buffer-Grösse Prüfen (ob wirklich so viele Bytes empfangen wurden...):
1 | volatile static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length) { |
2 | uint8_t crc_hi = 0xFF; // high CRC byte initialized |
3 | uint8_t crc_lo = 0xFF; // low CRC byte initialized |
4 | unsigned int i; // will index into CRC lookup |
5 | |
6 | if((buffer_length >= rxbuffersize) || |
7 | (buffer_length >= txbuffersize)) |
8 | {
|
9 | // ERROR
|
10 | return 0; |
11 | }
|
12 | else
|
13 | {
|
14 | //pass through message buffer
|
15 | while (buffer_length--) { |
16 | i = crc_hi ^ *buffer++; |
17 | crc_hi = crc_lo ^ table_crc_hi[i]; |
18 | crc_lo = table_crc_lo[i]; |
19 | }
|
20 | |
21 | return (crc_hi << 8 | crc_lo); |
22 | }
|
23 | }
|
24 | |
25 | ISR(USART_UDRE_vect ){ |
26 | if ((txposition < txbuffer_length) && |
27 | (txbuffer_length < txbuffersize)){ // |
28 | UDR = txbuffer[txposition]; |
29 | txposition++; |
30 | }
|
31 | else{ |
32 | UCSRB |= (1<<TXCIE); |
33 | UCSRB &= ~(1<<UDRIE); |
34 | }
|
35 | }
|
Weiter würde ich bei "dataprocessing" auf die minimale Frame-Länge prüfen! Bei Modbus gibt es ja mindestes Slave-ID, Function-Code, CRC (weiss jetzt nicht, ob noch ein Register mehr dabei ist). Das sind gerade die Dinge, die mir aufgefallen sind. Eventuell gibt's noch mehr Problemstellen.
:
Bearbeitet durch User
Erstmal vielen Dank für die ganzen Tips und Verbesserungsvorschläge. Habe versucht das meiste in meinem Code zu berücksichtigen. Leider hat es das Problem nicht gelöst. Ich hatte zwischenzeitlich das Netzteil in Verdacht, da sich die Reset Erscheinungen je nach Netzteil gehäuft haben. Letztendlich lag der Fehler doch ganz wo anders. Ich hatte vergessen die CKOPT Fuse zu setzten. Hatte mich zwar vorher schonmal damit auseinandergesetzt aber scheinbar aus versehen deaktiviert. Das Problem an der CKOPt Fuse ist das es ne ganze zeitlang funktioniert und dann aufeinmal nicht mehr. Naja wieder was gelernt, bei nächsten mal passiert mir das hoffentlich nicht mehr.
Warum nimmst für Modbus nicht einfach eine Library? Für den AVR gibt es viele Implementierungen (siehe Modbus-Artikel).
Hat drei Gründe. Es es nicht ausgeschlossen, dass das Projekt später kommerziell verwendet wird. Und ich habe keine Ahnung ob das wegen Lizenzen nicht schwierig werden könnte. Es ist ein sehr spezieller Slave der aus Sicherheitsgründen alleine am Bus hängt und auch nur zwei Funktionscodes benötigt. Fehlermeldungen können am Gerät auch nicht ausgelesen werden. Von daher sind die meisten Librarys zu aufgeblasen. Aber eigentlich war der Hauptgrund, dass ich es selbst machen wollte, zwecks Lerneffekt. Ich hab relativ viel Zeit für die Umsetzung von daher passt das schon. Und mittlerweile funktioniert es ja auch problemlos.
Du denkst es macht sich jemand die Arbeit, lädt die Firmware vom Controller runter und schaut sich den Hexcode an um festzustellen ob da Lizenzen vorhanden sind???
> ...Es ist ein sehr spezieller Slave
HUNDEBABIES, HUNDEBABIES :)
StromTuner
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.