Forum: Mikrocontroller und Digitale Elektronik AVR mit Modbus automatischer Reset


von Manuel K. (Gast)


Angehängte Dateien:

Lesenswert?

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

von Arduinoquäler (Gast)


Lesenswert?

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.

von Arduinoquäler (Gast)


Lesenswert?

- ARef gehört nicht an Vcc!

- C5 und C6 sind nahe an Vcc und AVcc?

- C1 und C2 haben keinen Wert, sind die vorhanden?

von Manuel K. (Gast)


Angehängte Dateien:

Lesenswert?

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.)

von Manuel K. (Gast)


Lesenswert?

Hab gerade nochmal mit Oszi gemessen. Der Reset Eingang bleibt die ganze 
Zeit brav auf 5V.
Es muss scheinbar doch am Programm liegen...

von Arduinoquäler (Gast)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Manuel K. schrieb:
> IMG_7590.JPG

Und wie sieht das von unten aus?

von Oliver S. (oliverso)


Lesenswert?

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

von Patrick B. (p51d)


Lesenswert?

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
von Manuel K. (Gast)


Lesenswert?

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.

von Tim Grunolf (Gast)


Lesenswert?

Warum nimmst für Modbus nicht einfach eine Library? Für den AVR gibt es 
viele Implementierungen (siehe Modbus-Artikel).

von Mathias O. (m-obi)


Lesenswert?

Genau. Ich nehme freemodbus. Läuft prima.

von Manuel K. (Gast)


Lesenswert?

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.

von Mathias O. (m-obi)


Lesenswert?

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

von Axel R. (Gast)


Lesenswert?

> ...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
Noch kein Account? Hier anmelden.