Forum: Mikrocontroller und Digitale Elektronik Merkwürdiger _delay_ms() reset


von Dirk S. (fusebit)


Lesenswert?

Moin,

ich stehe gerade vor einem für mich völlig unverständlichen Problem.
Bei mir verursacht die _delay_ms() Funktion plötzlich einen ständig 
wiederholten Reset am ATmega328.

Codeausschnitt:
1
lcd_init(LCD_DISP_ON);
2
  lcd_clrscr();
3
  lcd_gotoxy(0,0);
4
  lcd_puts("UI-Logger-Solar");
5
  //Warten damit der OpenLog initialisiert ist
6
  _delay_ms(250);
7
  lcd_gotoxy(15,0);  
8
  lcd_putc('9');
9
//  wdt_reset();  
10
  _delay_ms(250);
11
  lcd_gotoxy(15,0);
12
  lcd_putc('8');  
13
//  wdt_reset();
14
  _delay_ms(250);
15
  lcd_gotoxy(15,0);
16
  lcd_putc('7');

Das passiert aber nur wenn ich die Schaltung "frisch" an die Versorgung 
anklemme. Sobald ich einmal einen Reset auslöse, oder den Chip neu 
flashe funktioniert alles.
Nehme ich die delays raus geht es auch. Nun wird es besonders schräg:
Setze ich ein delay vor den obigen Bereich resettet das Programm bei dem 
delay. Lasse ich den Abschnitt wie oben, dann läuft der Zähler runter 
(geht bis 0) und dann erfolgt der Reset.
- WDT ist aus. Habe es aber auch mit WDT probiert.
- Der Wert für die Funktion spielt keine Rolle, habe ab 1ms vieles 
probiert.
- Verschieden Werte für die Optimierung habe ich auch probiert

Es hat die ganze Zeit funktioniert und plötzlich nicht mehr! Ich habe 
versucht möglichst genau die letzte Änderung auszukommentieren, aber der 
Reset bleibt. Leider weiß ich nicht genau ab welcher Änderung es 
angefangen hat, weil es beim neu flashen ja nicht auftritt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dirk S. schrieb:
> WDT ist aus. Habe es aber auch mit WDT probiert.

Bist du dir sicher?

Wenn der Wachhund einmal gebissen hat, muss man ihn explizit beim Booten 
bedienen (WDRF zurücksetzen), ansonsten bleibt er bis zum nächsten 
Powercycle aktiv.

von Karl M. (Gast)


Lesenswert?

Hallo,

42, was steht in den Fuse-Bits für aktivierte Hardwareeinheiten?

von Teo D. (teoderix)


Lesenswert?

Das Problem scheint wo anders zu liegen. Das ganze klingt schwer nach 
Buffer-Overflow.

von 1000V Dc (Gast)


Lesenswert?

delay_ms kann nicht mit beliebig großen werten aufgerufen werden...

von A. S. (Gast)


Lesenswert?

Wie arbeitet delay?
Wann tritt der reset auf? (Hast du ein oszi/LSA? Dann vorher Pin wackeln
Was passiert nach Zähler=0?
Was meinst Du mit "wenn ich reset auslöse"? Den delay-reset oder per 
Pin? Tritt es nur nach Power-on auf? -> Reset-Beschallung
Welche Funktionen triggern den wdt?
Stromaufnahme/Begrenzung?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

1000V Dc schrieb:
> delay_ms kann nicht mit beliebig großen werten aufgerufen werden...

Doch, schon seit vielen Jahren.

von Dirk S. (fusebit)


Lesenswert?

Das geht ja schnell.

Es tritt nur auf wenn die Versorgung weg war. Nach einem Reset per Pin, 
oder einem read vom programmer ist es weg. Das ist für mich ja der 
zentrale Knackpunkt. Weil ab dem Reset alles sauber läuft...

Der Wert des delay macht keinen Unterschied.

Ich habe nur eine minimale Programmierumgebung mit im Weihnachtsurlaub 
:-)
Oszi etc. sind zu Hause im Keller.

Auch wenn ich den WDT korrekt bediene tritt der Reset beim ersten Aufruf 
von _delay_ms() auf, allerdings nicht wenn die weiteren Aufrufe im 
oberen Code-Ausschnitt da sind.

Stromaufnahme ist okay, ein DMM habe ich dabei.

: Bearbeitet durch User
von Dirk S. (fusebit)


Lesenswert?

So, nun habe ich den WDT aktiviert und setze ihn in nicht zurück.

Nach dem flashen startet das Programm, geht sauber in die Hauptschleife 
und nach einiger Zeit löst der Wachhund aus. So soll es sein.

Trenne ich nun die Versorgung, dann läuft der Countdown durch und es 
erfolgt der Reset weit vor dem WDT.

Setzte ich nun wdt_reset() dazwischen ändert sich nichts!
1
int main(void)
2
{
3
     wdt_reset();
4
     /* Start timed sequence */
5
     WDTCSR |= (1<<WDCE) | (1<<WDE);
6
     /* Set new prescaler(time-out) value */
7
     WDTCSR = (1<<WDE) | (1<<WDP3);
8
     
9
    DDRB=0b00111111;
10
     DDRC=0b00110000;
11
  DDRD=0b11111110;
12
   
13
  SETBIT(PORTB,1);
14
  SETBIT(PORTB,2);
15
  
16
  SPCR = (1<<SPE) | (1<<MSTR);                    //Enable SPI Master
17
  
18
  UBRR0H = (unsigned char)(11>>8);                  //Baudrate setzen bei 3,6864 MHz: 23=9600; 11=19200
19
  UBRR0L = (unsigned char)11;                      //siehe Datenblatt
20
  UCSR0B |= (1<<RXCIE0) | (1<<RXEN0) | (1<<TXEN0);          //Receiver + Transmitter Enable
21
  UCSR0C |= (1<<UCSZ01)| (1<<UCSZ00);                  //1 Stop Bit/s, 8 Datenbits
22
  
23
  set_sleep_mode(6);                          //6: Standby, 3: Power-save, 2: Power-down, 1: ADC noise reduction, 0: idle
24
  sleep_enable();  
25
26
  //TWI setup
27
  TWBR = 0b00000000;                          //Taktfrequenz maximal, bei 3,68 MHz -> 230 kHz  
28
  if((RTC_read(RTCHOUR) & 0b01000000)) RTC_write(RTCHOUR,0b00000000);          //24 Stunden format
29
  
30
  /*Für das erte Mal und debugging*/
31
  //Datum festlegen, hier der
32
  //RTC_write(RTCYEAR,0b00011001);
33
  //RTC_write(RTCMTH,BCD(12));
34
  //RTC_write(RTCDATE,BCD(23));
35
  //RTC_write(RTCHOUR,BCD(19));
36
  //RTC_write(RTCMIN,BCD(27));  
37
  
38
    
39
  TCCR2B |= (1<<CS22) | (1<<CS21) | (1<<CS20);            //Timer 1 Prescaler 011 -> 64, 010 -> 8
40
  TIMSK2 |= (1<<TOIE0);                        //Overflow Interupt Enable
41
  TCNT2 = TIMER;
42
  
43
     
44
  lcd_init(LCD_DISP_ON);
45
  lcd_clrscr();
46
  lcd_gotoxy(0,0);
47
  lcd_puts("UI-Logger-Solar");
48
  lcd_gotoxy(0,1);
49
  lcd_puts("2019");
50
  //Warten damit der OpenLog initialisiert ist
51
  _delay_ms(250);
52
  lcd_gotoxy(15,0);  
53
  lcd_putc('9');
54
  wdt_reset();  
55
  _delay_ms(250);
56
  lcd_gotoxy(15,0);
57
  lcd_putc('8');  
58
  wdt_reset();
59
  _delay_ms(250);
60
  lcd_gotoxy(15,0);
61
  lcd_putc('7');  
62
  wdt_reset();
63
  _delay_ms(250);
64
  lcd_gotoxy(15,0);
65
  lcd_putc('6');  
66
//  wdt_reset();
67
  _delay_ms(250);
68
  lcd_gotoxy(15,0);
69
  lcd_putc('5');  
70
//  wdt_reset();    
71
  _delay_ms(250);
72
  lcd_gotoxy(15,0);
73
  lcd_putc('4');  
74
//  wdt_reset();
75
  _delay_ms(250);
76
  lcd_gotoxy(15,0);
77
  lcd_putc('3');  
78
//  wdt_reset();
79
  _delay_ms(250);
80
  lcd_gotoxy(15,0);
81
  lcd_putc('2');  
82
//  wdt_reset();
83
  _delay_ms(250);
84
  lcd_gotoxy(15,0);
85
  lcd_putc('1');  
86
//  wdt_reset();
87
  _delay_ms(250);
88
  lcd_gotoxy(15,0);
89
  lcd_putc('0');
90
//  wdt_reset();
91
  _delay_ms(250);        
92
93
  lcd_clrscr();    
94
95
  date_refresh();   
96
 
97
  //Titelzeile
98
  ausgabe("Datum");
99
  while (!(UCSR0A& (1<<UDRE0)));
100
  UDR0 = tab;
101
  ausgabe("Zeit");
102
  while (!(UCSR0A& (1<<UDRE0)));
103
  UDR0 = tab;  
104
  ausgabe("Spannung");
105
  while (!(UCSR0A& (1<<UDRE0)));
106
  UDR0 = tab;
107
  ausgabe("Strom");
108
  while (!(UCSR0A& (1<<UDRE0)));
109
  UDR0 = cr;
110
  while (!(UCSR0A& (1<<UDRE0)));
111
  UDR0 = lf;    
112
 
113
   sei(); 
114
   
115
    for(;;)
116
    {
117
      if(slow==1)                //Nur einmal pro Sekunde!
118
      {
119
        spannung=spannung/10;        //Mittelwert
120
        strom=strom/10;            //Mittelwert
121
        if(strom<NULLPUNKT) 
122
        {
123
          vorzeichen=0;
124
          strom=NULLPUNKT-strom;
125
        }
126
        if(strom>NULLPUNKT)
127
        {
128
          vorzeichen=1;
129
          strom=strom-NULLPUNKT;        
130
        }
131
        if(strom==NULLPUNKT) strom=0;
132
        strom=(strom*10)/4;          //In mA umrechnen
133
        
134
        
135
        if(sekunde<5) seite02();
136
        else seite01();
137
        
138
        
139
        //Sekundenwerte im Array speichern
140
        sek_u[a]=spannung;
141
        sek_i[a]=strom;
142
        a++;
143
        if(a==61) a=1;
144
  
145
        spannung=0;
146
        strom=0;
147
    
148
        CLRBIT(PORTB,1);
149
        _delay_ms(1);
150
        SETBIT(PORTB,1);
151
      }
152
    
153
    adc_i=adc_volt(0);
154
    strom=strom+adc_i;
155
    
156
    adc_u=((unsigned long)adc_volt(1)*TEILER)/1000;
157
    spannung=spannung+adc_u;
158
//    wdt_reset();
159
    sleep_cpu();
160
    }
161
}

von Karl M. (Gast)


Lesenswert?

Nochmal,

welche Fuse-Bits sind gesetzt, ist BOD Level eingestellt?
Alle Kondensatoren, i.A. 100nF verbaut?
Alle Vcc, AVcc und (AGnd) Gnd angeschlossen?
Wie weich ist die Versorgungsspannung an Vcc?

von Dirk S. (fusebit)


Angehängte Dateien:

Lesenswert?

Hier die Sicherungen...

von Karl M. (Gast)


Lesenswert?

Woher weißt Du das?
1
set_sleep_mode(6);                          //6: Standby, 3: Power-save, 2: Power-down, 1: ADC noise reduction, 0: idle

Da gibt es in den verschiedenen AVRs Bitnamen, die in Kombination das 
gewünschte bewirken.

Dann noch, ohne den passenden Einsprung?
1
TIMSK2 |= (1<<TOIE0);

Zum Glück lässt sich das Programm nicht Übersetzen, so dass niemand 
einen Test machen kann!

von Karl M. (Gast)


Lesenswert?

Nachfrage,

ist es ein ATmega328 oder ein ATmega328p?
Da gibt es Unterschiede.

von Dirk S. (fusebit)


Angehängte Dateien:

Lesenswert?

Sleep Einstellungen machen keinen Unterschied, hatte ich schon komplett 
auskommentiert.

Der Code ist derweil etwas wild, da ich am rumprobieren bin.

Anbei der Schaltplan.

Und wie gesagt: Es hat die ersten Tage funktioniert, heute habe ich 
weiter gemacht und nun tritt es auf. Da es nur bei einem Kaltstart 
passiert habe ich es erst im Laufe des Tages bemerkt.

Werde es jetzt weiter reduzieren...

von Holger L. (max5v)


Lesenswert?

Dirk S. schrieb:
> Trenne ich nun die Versorgung, dann läuft der Countdown durch und es
> erfolgt der Reset weit vor dem WDT.

Eventuell mal die Brownout Detection deaktivieren bzw. herabsetzen.
Es kann unter Umständen sein das das Display wenn es noch nicht 
initialisiert ist deutlich mehr Strom zieht als deine Versorgung 
hergibt?

von Dirk S. (fusebit)


Lesenswert?

Karl M. schrieb:
> Nachfrage,
>
> ist es ein ATmega328 oder ein ATmega328p?
> Da gibt es Unterschiede.

ATmega328, AtmelStudio ist mit der Signatur zufrieden...

von Karl M. (Gast)


Lesenswert?

Da sind noch Antworten ausstehend,

Und dann wird noch im Register UCSR0B der "RX Complete Interrupt Enable" 
und ich sehe keinen Interrupt Routine dafür.

Warum?

von Karl M. (Gast)


Lesenswert?

Dirk S. schrieb:
> Karl M. schrieb:
>> Nachfrage,
>>
>> ist es ein ATmega328 oder ein ATmega328p?
>> Da gibt es Unterschiede.
>
> ATmega328, AtmelStudio ist mit der Signatur zufrieden...

Das meine ich nicht, es gibt zwei Datenblätter!

von Dirk S. (fusebit)


Angehängte Dateien:

Lesenswert?

Mal sehen ob das klappt.

Ich versuche ein mp4-Video hochzuladen auf dem das Verhalten zu sehen 
ist.
Erst die Dauerschleife mit dem ungeklärtem Reset nach dem Countdown, 
dann ein "read" mit dem AtmelICE und es läuft (bis der Wachhund 
anbeisst).

Nach einem Kaltstart hängt es wieder...

von Dirk S. (fusebit)


Lesenswert?

Und für Karl:
1
/*
2
 * UI-Logger-Solar.c
3
 *
4
 * Created: 22.12.2019 16:26:01
5
 * Author : Dirk
6
 
7
 ATmega328 mit 16x2 LCD; LED und drei Tasten
8
 
9
 LCD:
10
 PORTD,2: E
11
 PORTD,3: RW
12
 PORTD,4: RS
13
 PORTB,0: D4
14
 PORTD,7: D5
15
 PORTD,6: D6
16
 PORTD,5: D7
17
 
18
 
19
  - WDT fertig implementieren
20
  - 5 min Mittelwerte
21
  - Tasten zum umschalten und Uhr einstellen
22
 
23
 */ 
24
25
26
#define BIT(x) (1<<(x))
27
#define SETBIT(p, b) (p) |=BIT(b)
28
#define CLRBIT(p, b) (p) &= ~BIT(b)
29
#define TOGGLE(p, b) (p) ^=BIT(b)
30
#define TIMER 76       
31
#define VREF 5000    //mV
32
#define TEILER 4092    //Spannungsteiler
33
#define NULLPUNKT 2493  //Nullpunkt Allegro
34
#define STEIGUNG 400  //mV/A für Allegro
35
#define cr 0x0D
36
#define lf 0x0A
37
#define tab 0x09
38
#define punkt 0x2E
39
#define dopu 0x3A
40
//#define F_CPU 1843200UL     //  In compiler symbols festgelegt
41
42
43
#include <avr/io.h>
44
#include <util/delay.h>
45
#include <lcd.h>
46
//#include <avr/sleep.h>
47
#include <avr/interrupt.h>
48
#include <stdlib.h>
49
#include <avr/wdt.h>
50
51
52
unsigned long zwischenwert, adc_u, adc_i,spannung, strom, mittel_u, mittel_i;
53
unsigned int jahr,  sek_i[60], sek_u[60], minute_i[60], minute_u[60], fuenfmin_u, fuenfmin_i;
54
char output[8];
55
unsigned char a,byte_eins, byte_zwei, slow, vorzeichen, flag01, data, dummy;
56
volatile unsigned char sekunde, minute, stunde, tag, monat;
57
volatile unsigned char byte00, byte01, byte02;
58
59
//TWI Variablen
60
char SLA_W=0b11010000;        //Adressierung und RTC register write
61
char SLA_R=0b11010001;        //RTC register read
62
char RTCSEC=0x00;          //RTC register address
63
char RTCMIN=0x01;
64
char RTCHOUR=0x02;
65
char RTCWKDAY=0x03;
66
char RTCDATE=0x04;
67
char RTCMTH=0x05;
68
char RTCYEAR=0x06;
69
char CONTROL=0x0E;          //Control register address
70
71
72
void RTC_write(char Address, char Data)
73
{
74
  TWCR = (1<<TWINT) | (1<<TWSTA) |(1<<TWEN);      //Start condition
75
  while (!(TWCR & (1<<TWINT)));
76
  //if ((TWSR & 0xF8) !=START) ERROR();
77
  
78
  //Byte senden (Adressierung)
79
  TWDR = SLA_W;
80
  TWCR = (1<<TWINT) | (1<<TWEN);
81
  while (!(TWCR & (1<<TWINT)));
82
  //if((TWSR & 0xF8) != MT_SLA_ACK) ERROR();
83
  
84
  //Byte senden (Daten)
85
  TWDR = Address;    //RTCSEC register address
86
  TWCR = (1<<TWINT) | (1<<TWEN);
87
  while (!(TWCR & (1<<TWINT)));
88
89
  //Byte senden (Daten)
90
  TWDR = Data;
91
  TWCR = (1<<TWINT) | (1<<TWEN);
92
  while (!(TWCR & (1<<TWINT)));
93
  
94
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);    //STOP condition
95
}
96
97
char RTC_read(char Address)    //UNFERTIG!!!
98
{
99
  char Data;
100
  
101
  //Hiermit wird die TWI nach dem schlafen wieder gestrtet
102
  TWCR &= ~((1 << TWSTO) | (1 << TWEN));
103
  TWCR |= (1 << TWEN);
104
105
106
107
  TWCR = (1<<TWINT) | (1<<TWSTA) |(1<<TWEN);      //Start condition
108
  while (!(TWCR & (1<<TWINT)));
109
  //if ((TWSR & 0xF8) !=START) ERROR();
110
  
111
  //Byte senden (Adressierung)
112
  TWDR = SLA_W;
113
  TWCR = (1<<TWINT) | (1<<TWEN);
114
  while (!(TWCR & (1<<TWINT)));
115
  //if((TWSR & 0xF8) != MT_SLA_ACK) ERROR();
116
  
117
  //Byte senden
118
  TWDR = Address;    // register address
119
  TWCR = (1<<TWINT) | (1<<TWEN);
120
  while (!(TWCR & (1<<TWINT)));
121
122
  TWCR = (1<<TWINT) | (1<<TWSTA) |(1<<TWEN);      //Rep. Start condition
123
  while (!(TWCR & (1<<TWINT)));
124
  //if ((TWSR & 0xF8) !=START) ERROR();
125
  
126
  //Byte senden
127
  TWDR = SLA_R;
128
  TWCR = (1<<TWINT) | (1<<TWEN);
129
  while (!(TWCR & (1<<TWINT)));
130
  //if((TWSR & 0xF8) != MT_SLA_ACK) ERROR();
131
  
132
  //Byte empfangen (Daten)
133
  
134
  TWCR = (1<<TWINT) | (1<<TWEN);
135
  while (!(TWCR & (1<<TWINT)));
136
  Data = TWDR;
137
  
138
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);    //STOP condition
139
  
140
  return Data;
141
}
142
143
void date_refresh(void)
144
{
145
  cli();
146
  sekunde=RTC_read(RTCSEC);
147
  //sekunde &= ~((1 << 7));              //ST bit loeschen
148
  sekunde= (sekunde/16*10) + (sekunde%16);
149
  minute=RTC_read(RTCMIN);
150
  minute=(minute/16*10)+(minute%16);
151
  stunde=RTC_read(RTCHOUR);
152
  //stunde &= ~((1 <<6));              //AM/PM bit loeschen
153
  stunde=(stunde/16*10) + (stunde%16);
154
  tag=RTC_read(RTCDATE);
155
  tag=(tag/16*10)+(tag%16);
156
  monat=RTC_read(RTCMTH);
157
  //monat &= ~((1<<5));                //Lapyear bit loeschen
158
  monat=(monat/16*10)+(monat%16);
159
  jahr=RTC_read(RTCYEAR);
160
  jahr=(jahr/16*10)+(jahr%16);
161
  jahr=jahr+2000;
162
  sei();
163
}
164
165
char BCD(char wert)      //Die BCD Codierung fuer die RTC erzeugen
166
{
167
  char temp=0;
168
  temp=((wert/10)<<4);
169
  temp=temp+wert%10;
170
  return(temp);
171
}
172
173
unsigned int adc_volt(uint8_t kanal)      //ADC Abfrage Funktion
174
{
175
  unsigned long berechnung, speicher=0;
176
  
177
  cli();
178
  byte00=1;                          //Beim MCP3002 für beige Känale gleich
179
  
180
  if(kanal==0) byte01=128;
181
  if(kanal==1) byte01=192;
182
  
183
  byte02=0;
184
  
185
  for(int n=0;n<8;n++)
186
  {
187
    CLRBIT(PORTB,2);                    //Start transmission
188
    SPDR = byte00;
189
    while (!(SPSR & (1<<SPIF)));
190
    SPDR = byte01;
191
    while (!(SPSR & (1<<SPIF)));
192
    
193
    byte_eins=SPDR;
194
    
195
    SPDR =byte02  ;
196
    while (!(SPSR & (1<<SPIF)));
197
    
198
    byte_zwei=SPDR;
199
    
200
    SETBIT(PORTB,2);                    //Stop transmission
201
    
202
    berechnung=(byte_eins<<8)+byte_zwei;          //Wert auslesen
203
    speicher+=berechnung;
204
  }
205
206
  
207
  berechnung=((speicher+4)/8)*VREF/4096;                  //Mittelwert der AD-Wandler Durchläufe
208
  
209
  sei();
210
  return(berechnung);
211
}
212
213
//serielle Ausgabe
214
void ausgabe(char text[16])
215
{
216
  
217
  for (unsigned char k=0;k<15;k++)    //max 16 Stellen
218
  {
219
    data=text[k];          //kte-Stelle übernehmen
220
    if(data==0) break;        //Nur Nutzdaten übertragen
221
    text[k] = dummy;        //kte-Stelle löschen
222
    while (!(UCSR0A& (1<<UDRE0)));
223
    UDR0=data;
224
  }
225
  
226
}
227
228
void datensatz(void)
229
{
230
  //Datum
231
  utoa(tag,output,10);
232
  ausgabe(output);
233
  while (!(UCSR0A& (1<<UDRE0)));
234
  UDR0 = punkt;
235
  utoa(monat,output,10);
236
  ausgabe(output);
237
  while (!(UCSR0A& (1<<UDRE0)));
238
  UDR0 = punkt;
239
  utoa(jahr,output,10);
240
  ausgabe(output);
241
  while (!(UCSR0A& (1<<UDRE0)));
242
  while (!(UCSR0A& (1<<UDRE0)));
243
  UDR0 = tab;
244
  
245
  //Uhrzeit
246
  utoa(stunde,output,10);
247
  ausgabe(output);
248
  while (!(UCSR0A& (1<<UDRE0)));
249
  UDR0 = dopu;
250
  utoa(minute,output,10);
251
  if(minute<10)
252
  {
253
    while (!(UCSR0A& (1<<UDRE0)));
254
    UDR0 = '0';  
255
  }
256
  ausgabe(output);
257
  while (!(UCSR0A& (1<<UDRE0)));
258
  UDR0 = dopu;
259
  utoa(sekunde,output,10);
260
  if(sekunde<10)
261
  {
262
    while (!(UCSR0A& (1<<UDRE0)));
263
    UDR0 = '0';
264
  }  
265
  ausgabe(output);
266
  while (!(UCSR0A& (1<<UDRE0)));
267
  UDR0 = tab;
268
  
269
  //Spannung
270
  utoa(mittel_u,output,10);
271
  ausgabe(output);
272
  while (!(UCSR0A& (1<<UDRE0)));
273
  UDR0 = tab;
274
  //Strom
275
  utoa(mittel_i,output,10);
276
  ausgabe(output);
277
  while (!(UCSR0A& (1<<UDRE0)));
278
  UDR0 = tab;
279
  
280
  
281
282
  while (!(UCSR0A& (1<<UDRE0)));
283
  UDR0 = cr;
284
  while (!(UCSR0A& (1<<UDRE0)));
285
  UDR0 = lf;
286
}
287
288
SIGNAL(TIMER2_OVF_vect)                          //Handler für Timer Interrupt
289
{
290
    slow++;
291
    TCNT2 = TIMER;
292
    if(slow==10)
293
    {
294
      slow=0;
295
      sekunde++;
296
      if(sekunde==60)
297
      {
298
        minute++;
299
        sekunde=0;
300
        if(minute%3==0) date_refresh();
301
        for(unsigned char i=1;i<60;i++)
302
        {
303
          mittel_u=mittel_u+sek_u[i];
304
          mittel_i=mittel_i+sek_i[i];  
305
        }  
306
        mittel_u=mittel_u/60;
307
        mittel_i=mittel_i/60;
308
        minute_u[minute]=mittel_u;
309
        minute_i[minute]=mittel_i;
310
311
        datensatz();
312
313
314
      }
315
    }
316
}
317
318
void seite01(void)
319
{
320
  //Erste Zeile
321
  lcd_gotoxy(0,0);
322
  lcd_puts("       ");
323
  utoa(tag,output,10);
324
  lcd_gotoxy(0,0);
325
  if(tag<10) lcd_putc('0');
326
  lcd_puts(output);
327
  lcd_putc('.');
328
  utoa(monat,output,10);
329
  lcd_gotoxy(3,0);
330
  if(monat<10) lcd_putc('0');
331
  lcd_puts(output);
332
  lcd_putc('.');
333
  utoa(stunde,output,10);
334
  lcd_gotoxy(8,0);
335
  if(stunde<10) lcd_putc('0');
336
  lcd_puts(output);
337
  lcd_putc(':');
338
  utoa(minute,output,10);
339
  lcd_gotoxy(11,0);
340
  if(minute<10) lcd_putc('0');
341
  lcd_puts(output);
342
  lcd_putc(':');
343
  utoa(sekunde,output,10);
344
  lcd_gotoxy(14,0);
345
  if(sekunde<10) lcd_putc('0');
346
  lcd_puts(output);  
347
  
348
  //Zweite Zeile
349
  lcd_gotoxy(0,1);
350
  lcd_puts("       ");
351
  utoa(spannung,output,10);
352
  if(spannung<10000) lcd_gotoxy(1,1);
353
  else lcd_gotoxy(0,1);
354
  lcd_puts(output);
355
  lcd_puts("mV");
356
  lcd_gotoxy(9,1);
357
  if(vorzeichen==0) lcd_putc('-');          
358
  else lcd_putc('+');
359
  utoa(strom,output,10);
360
  lcd_gotoxy(10,1);
361
  lcd_puts("     ");
362
  if(strom<1000) lcd_gotoxy(11,1);
363
  if(strom<100) lcd_gotoxy(12,1);
364
  if(strom<10)  lcd_gotoxy(13,1);
365
  lcd_puts(output);
366
  lcd_gotoxy(14,1);
367
  lcd_puts("mA");  
368
}
369
370
void seite02(void)
371
{
372
  //Erste Zeile
373
  lcd_gotoxy(0,0);
374
  lcd_puts("Seite 2");
375
376
  
377
  utoa(stunde,output,10);
378
  lcd_gotoxy(8,0);
379
  if(stunde<10) lcd_putc('0');
380
  lcd_puts(output);
381
  lcd_putc(':');
382
  utoa(minute,output,10);
383
  lcd_gotoxy(11,0);
384
  if(minute<10) lcd_putc('0');
385
  lcd_puts(output);
386
  lcd_putc(':');
387
  utoa(sekunde,output,10);
388
  lcd_gotoxy(14,0);
389
  if(sekunde<10) lcd_putc('0');
390
  lcd_puts(output);
391
  
392
  //Zweite Zeile
393
  lcd_gotoxy(0,1);
394
  lcd_puts("       ");
395
  utoa(mittel_u,output,10);
396
  if(mittel_u<10000) lcd_gotoxy(1,1);
397
  else lcd_gotoxy(0,1);
398
  lcd_puts(output);
399
  lcd_puts("mV");
400
  lcd_gotoxy(9,1);
401
  if(vorzeichen==0) lcd_putc('-');
402
  else lcd_putc('+');
403
  utoa(mittel_i,output,10);
404
  lcd_gotoxy(10,1);
405
  lcd_puts("     ");
406
  if(mittel_i<1000) lcd_gotoxy(11,1);
407
  if(mittel_i<100) lcd_gotoxy(12,1);
408
  if(mittel_i<10)  lcd_gotoxy(13,1);
409
  lcd_puts(output);
410
  lcd_gotoxy(14,1);
411
  lcd_puts("mA");
412
}
413
414
415
416
int main(void)
417
{
418
     wdt_reset();
419
     /* Start timed sequence */
420
     WDTCSR |= (1<<WDCE) | (1<<WDE);
421
     /* Set new prescaler(time-out) value */
422
     WDTCSR = (1<<WDE) | (1<<WDP3);
423
     
424
    DDRB=0b00111111;
425
     DDRC=0b00110000;
426
  DDRD=0b11111110;
427
   
428
  SETBIT(PORTB,1);
429
  SETBIT(PORTB,2);
430
  
431
  SPCR = (1<<SPE) | (1<<MSTR);                    //Enable SPI Master
432
  
433
  UBRR0H = (unsigned char)(11>>8);                  //Baudrate setzen bei 3,6864 MHz: 23=9600; 11=19200
434
  UBRR0L = (unsigned char)11;                      //siehe Datenblatt
435
  UCSR0B |= (1<<RXCIE0) | (1<<RXEN0) | (1<<TXEN0);          //Receiver + Transmitter Enable
436
  UCSR0C |= (1<<UCSZ01)| (1<<UCSZ00);                  //1 Stop Bit/s, 8 Datenbits
437
  
438
  //set_sleep_mode(6);                          //6: Standby, 3: Power-save, 2: Power-down, 1: ADC noise reduction, 0: idle
439
  //sleep_enable();  
440
441
  //TWI setup
442
  TWBR = 0b00000000;                          //Taktfrequenz maximal, bei 3,68 MHz -> 230 kHz  
443
  if((RTC_read(RTCHOUR) & 0b01000000)) RTC_write(RTCHOUR,0b00000000);          //24 Stunden format
444
  
445
  /*Für das erte Mal und debugging*/
446
  //Datum festlegen, hier der
447
  //RTC_write(RTCYEAR,0b00011001);
448
  //RTC_write(RTCMTH,BCD(12));
449
  //RTC_write(RTCDATE,BCD(23));
450
  //RTC_write(RTCHOUR,BCD(19));
451
  //RTC_write(RTCMIN,BCD(27));  
452
  
453
    
454
  TCCR2B |= (1<<CS22) | (1<<CS21) | (1<<CS20);            //Timer 1 Prescaler 011 -> 64, 010 -> 8
455
  TIMSK2 |= (1<<TOIE0);                        //Overflow Interupt Enable
456
  TCNT2 = TIMER;
457
  
458
     
459
  lcd_init(LCD_DISP_ON);
460
  lcd_clrscr();
461
  lcd_gotoxy(0,0);
462
  lcd_puts("UI-Logger-Solar");
463
  lcd_gotoxy(0,1);
464
  lcd_puts("     2019");
465
  //Warten damit der OpenLog initialisiert ist
466
  _delay_ms(250);
467
  lcd_gotoxy(15,0);  
468
  lcd_putc('9');
469
  wdt_reset();  
470
  _delay_ms(250);
471
  lcd_gotoxy(15,0);
472
  lcd_putc('8');  
473
  wdt_reset();
474
  _delay_ms(250);
475
  lcd_gotoxy(15,0);
476
  lcd_putc('7');  
477
  wdt_reset();
478
  _delay_ms(250);
479
  lcd_gotoxy(15,0);
480
  lcd_putc('6');  
481
  wdt_reset();
482
  _delay_ms(250);
483
  lcd_gotoxy(15,0);
484
  lcd_putc('5');  
485
  wdt_reset();    
486
  _delay_ms(250);
487
  lcd_gotoxy(15,0);
488
  lcd_putc('4');  
489
  wdt_reset();
490
  _delay_ms(250);
491
  lcd_gotoxy(15,0);
492
  lcd_putc('3');  
493
  wdt_reset();
494
  _delay_ms(250);
495
  lcd_gotoxy(15,0);
496
  lcd_putc('2');  
497
  wdt_reset();
498
  _delay_ms(250);
499
  lcd_gotoxy(15,0);
500
  lcd_putc('1');  
501
  wdt_reset();
502
  _delay_ms(250);
503
  lcd_gotoxy(15,0);
504
  lcd_putc('0');
505
  wdt_reset();
506
  _delay_ms(250);        
507
508
  lcd_clrscr();    
509
510
  date_refresh();   
511
 
512
  //Titelzeile
513
  ausgabe("Datum");
514
  while (!(UCSR0A& (1<<UDRE0)));
515
  UDR0 = tab;
516
  ausgabe("Zeit");
517
  while (!(UCSR0A& (1<<UDRE0)));
518
  UDR0 = tab;  
519
  ausgabe("Spannung");
520
  while (!(UCSR0A& (1<<UDRE0)));
521
  UDR0 = tab;
522
  ausgabe("Strom");
523
  while (!(UCSR0A& (1<<UDRE0)));
524
  UDR0 = cr;
525
  while (!(UCSR0A& (1<<UDRE0)));
526
  UDR0 = lf;    
527
 
528
   sei(); 
529
   
530
    for(;;)
531
    {
532
      if(slow==1)                //Nur einmal pro Sekunde!
533
      {
534
        spannung=spannung/10;        //Mittelwert
535
        strom=strom/10;            //Mittelwert
536
        if(strom<NULLPUNKT) 
537
        {
538
          vorzeichen=0;
539
          strom=NULLPUNKT-strom;
540
        }
541
        if(strom>NULLPUNKT)
542
        {
543
          vorzeichen=1;
544
          strom=strom-NULLPUNKT;        
545
        }
546
        if(strom==NULLPUNKT) strom=0;
547
        strom=(strom*10)/4;          //In mA umrechnen
548
        
549
        
550
        if(sekunde<5) seite02();
551
        else seite01();
552
        
553
        
554
        //Sekundenwerte im Array speichern
555
        sek_u[a]=spannung;
556
        sek_i[a]=strom;
557
        a++;
558
        if(a==61) a=1;
559
  
560
        spannung=0;
561
        strom=0;
562
    
563
        CLRBIT(PORTB,1);
564
        _delay_ms(1);
565
        SETBIT(PORTB,1);
566
      }
567
    
568
    adc_i=adc_volt(0);
569
    strom=strom+adc_i;
570
    
571
    adc_u=((unsigned long)adc_volt(1)*TEILER)/1000;
572
    spannung=spannung+adc_u;
573
//    wdt_reset();
574
    //sleep_cpu();
575
    }
576
}

von Karl M. (Gast)


Lesenswert?

Hallo,

Was passiert ist alles durch die Hardware, das gesamte Programm und 
dem aktivierten WDT per Fuse-Bit erklärbar.

Aber da Du nicht alles offenlegen möchtest und auch immer wieder von 
anderen Softwareversionen und Tests schreibst, weiß niemand - außer Dir 
- genau, was zusammen hängt.

Versuche mal deine Posts aus unserer Sicht (Informationsstand) zu sehen.

Das alles ist Vergleichbar mir eine Buchstabensuppe.

von Karl M. (Gast)


Lesenswert?

Hallo,

da fehlt mir noch eine Interrupt Routine, wie oben geschrieben.

Dann knallt es hier in der SIGNAL(TIMER2_OVF_vect):
1
if(minute%3==0) date_refresh();
Da man in einer ISR schon das globale Interruptflag wieder setzt.

SIGNAL(<handler>) ist doch nicht mehr gültig.

https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Alte_Quellen

von Thomas E. (thomase)


Lesenswert?

Karl M. schrieb:
> Das meine ich nicht, es gibt zwei Datenblätter!

Nein.

ATmega48A/PA/88A/PA/168A/PA/328/P sind in einem Datenblatt.

von Dirk S. (fusebit)


Lesenswert?

Hallo Karl,

was Du schreibst mag ja stimmen, aber bis dort kommt das Programm 
überhaupt nicht nach einem Kaltstart und nach einem Reset funktioniert 
es einwandfrei!

Auch wenn es mit Sicherheit alles andere als sauber programmiert ist.

von Karl M. (Gast)


Lesenswert?

Und hier knallt es entsprechend auch durch die unterschiedlichen 
Datentypen und einem Aufruf in einer Interrupt Service Routine.
1
void ausgabe(char text[16]);

von Karl M. (Gast)


Lesenswert?

Thomas E. schrieb:
> Karl M. schrieb:
>> Das meine ich nicht, es gibt zwei Datenblätter!
>
> Nein.
>
> ATmega48A/PA/88A/PA/168A/PA/328/P sind in einem Datenblatt.

Hallo,

in der Atmel Zeit war dies wie folgt:
Beitrag "Re: Atmega 328 oder 328P ?"

von Thomas E. (thomase)


Lesenswert?

Karl M. schrieb:
> in der Atmel Zeit war dies wie folgt:
> Beitrag "Re: Atmega 328 oder 328P ?"

Was willst du mit diesem uralten Thread aussagen? Dass du lange nicht 
mehr auf einen Kalender geguckt hast?

von Theor (Gast)


Lesenswert?

@ Dirk

Hm. Die Beschreibung ist leider wirklich sehr schwer verständlich, 
teilweise unverständlich und unklar. Schwierig da was Definitives zu 
sagen.

Allerdings gibt es diese Reset-Probleme in Zusammenhang mit dem delay 
immer wieder und - wenn ich mich recht entsinne - in den meisten Fällen 
liegt es nicht am delay selbst.
Ich weiß, dass ist schwer zu verstehen, wenn doch verschiedene Varianten 
mit und ohne delay unterschiedliches Verhalten zeigen. Dennoch ist es 
oft wahr. Lies mal ein paar von den erwähnten Threads.
Dummerweise kann man häufig nicht gleich den Finger auf den Punkt legen, 
der ausschlaggebend ist und in Verbindung mit dem delay ein Problem 
darstellt.

Daher die Hinweise auf sonstige Fehler, die scheinbar nichts damit zu 
tun haben, was Du als Ursache vermutest.

Wenn man nicht so recht weiß, dann ist das einer der beiden Erfolg 
versprechenden Ansätze.

1. Probleme beseitigen, auch wenn sie scheinbar abseitig sind - nichts 
mit der eigenen Vermutung zu tun haben. (Fehler sind ohnehin Fehler und 
müssen irgendwann sowieso beseitigt werden).

2. So viel wie möglich und detaillierte Information geben. Hier 
insbesondere Schaltplan, Beschreibung der Stromversorgung, 
Compileroptionen.
Manchmal waren es auch hohe Lasten, wie Relais, welche die 
Stromversorgung beeinflussten und die delays haben nur den zeitlichen 
Ablauf verändert - waren aber nicht selbst verantwortlich.

Schwierig die Sache, aber wenn Du es über Dich bringen kannst, dann 
folge einmal den Hinweisen, auch wenn sie Dir zuerst sinnlos vorkommen. 
Versprechen kann ich natürlich nichts, aber die Erfahrung zeigt, dass 
das in die richtige Richtung führt.

von Sascha W. (sascha-w)


Lesenswert?

@Dirk,

gib doch am Anfang mal das MCUSR aus, dann siehst du was den letzten 
Reset ausgelöst hat.

Sascha

von Dirk S. (fusebit)


Lesenswert?

Da ist wohl etwas Wahres dran.
Ich habe nun die UART Ausgabe auskommentiert und der Fehler ist weg.
Und das obwohl diese an der Problemstelle im Programm noch nicht 
aufgerufen wurde...

von Stefan F. (Gast)


Lesenswert?

Dirk S. schrieb:
> Und das obwohl diese an der Problemstelle im Programm noch nicht
> aufgerufen wurde...

Ist das tatsächlich so, oder glaubst du das nur?

Schalte zur Kontrolle innerhalb der Funktion eine LED an, dann bist du 
sicher.

von Dirk S. (fusebit)


Lesenswert?

Sobald ich diesen Bereich aktiviere ist der Fehler aktiv, auch wenn noch 
alle Zugriffe auf die Schnittstelle auskommentiert bleiben:
1
  UBRR0H = (unsigned char)(11>>8);                  //Baudrate setzen bei 3,6864 MHz: 23=9600; 11=19200
2
  UBRR0L = (unsigned char)11;                      //siehe Datenblatt
3
  UCSR0B |= (1<<RXCIE0) | (1<<RXEN0) | (1<<TXEN0);          //Receiver + Transmitter Enable
4
  UCSR0C |= (1<<UCSZ01)| (1<<UCSZ00);                  //1 Stop Bit/s, 8 Datenbits

von Sascha W. (sascha-w)


Lesenswert?

Dirk S. schrieb:
> Da ist wohl etwas Wahres dran.
> Ich habe nun die UART Ausgabe auskommentiert und der Fehler ist weg.
> Und das obwohl diese an der Problemstelle im Programm noch nicht
> aufgerufen wurde...

Wie ist RX extern beschalten? Da du den Pullup nicht aktiviert hast und 
den RX-Int aktiviert, aber keine ISR, hast könnte bei offenem Eingang 
schon mal was triggern.

Sascha

von Dirk S. (fusebit)


Lesenswert?

Genau, Sascha!

Ich Trottel!
Das Problem war der OpenLog, oder besser der Typ, der den OpenLog 
benutzt.

Und Karl hatte auch recht...

Der OpenLog initialisiert sich nur nach dem Trennen der Versorgung und 
gibt seinen Status aus. Mit der UART Konfiguration hat er einen 
Interrupt ausgelöst der keine ISR hat...

Euch einen guten Rutsch :-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dirk S. schrieb:
> Ich Trottel!

Nun, einfach zur Gewohnheit machen, dass du für jedes Interruptbit, was 
du irgendwo in einem Register aktivierst, sofort irgendwo eine 
(zumindest leere) ISR hinschreibst. Dann weißt du später, dass du da 
noch was ausfüllen musst.

Schön, dass ihr's gefunden habt.

von Rolf M. (rmagnus)


Lesenswert?

Jörg W. schrieb:
> Dirk S. schrieb:
>> Ich Trottel!
>
> Nun, einfach zur Gewohnheit machen, dass du für jedes Interruptbit, was
> du irgendwo in einem Register aktivierst, sofort irgendwo eine
> (zumindest leere) ISR hinschreibst. Dann weißt du später, dass du da
> noch was ausfüllen musst.

Ich würde es sogar umgekehrt machen: Den Interrupt überhaupt erst 
aktivieren, nachdem ich die dazugehörige ISR geschrieben habe. 
Schließlich habe ich dann erst ein Interesse daran, dass der Interrupt 
auch aktiv ist.

Karl M. schrieb:
> Und hier knallt es entsprechend auch durch die unterschiedlichen
> Datentypen und einem Aufruf in einer Interrupt Service Routine.
> void ausgabe(char text[16]);

ausgabe ist nicht reentrant, da es eine globale Variable beschreibt. 
Außerdem darf man keine Stringliterale übergeben, da es auch in den 
übergebenen String schreibt.
Die fehlende Reentranz kann dazu führen, dass bei gleichzeitiger 
Ausführung aus dem Hauptprogramm und der ISR über das Stringende hinaus 
geschrieben wird und damit andere Speicherinhalte überschrieben werden.

: Bearbeitet durch User
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.