Forum: Mikrocontroller und Digitale Elektronik Mikrocontroller Steuerung


von ansgar (Gast)


Lesenswert?

Hallo,

ich habe folgendes Problem. Ich möchte eine Schaltung mit einem Attiny 
realisieren welche nach jedem Neustart des Systems einen anderen Zustand 
einnimmt. Neustart heißt die Spannungsversorung wird komplett getrennt 
und anschließend wieder verbunden. Es gibt insgesamt 3 Zustände.

Nach dem ersten Einschalten soll Zustand 1 aktiviert werden.
Nach dem nächsten aus/einschalten Zustand 2, nach dem nächsten 
aus/einschalten Zustand 3.
Danach soll bei jedem weiteren aus/einschalten zwischen Zustand 2 und 3 
toggeln.

Das lässt sich ja noch gut mit einer Flag realsieren realsieren, ich 
hoffe nur dass der EEPROM wirklich an die 100k Schreibzyklen mitmacht.

Das eigentliche Problem ist nun folgendes. Ich möchte dass nach einer 
gewissen Zeit im ausgeschalteten Zustand, also zB. 5 Minuten der 
Mikrocontroller nach dem Einschalten wieder in den Zustand 1 wechselt.

Ich weiß nur nicht wie ich das Clever lösen kann.
Was mir einfallen würde:
Spannung an einem Kondensator messen-> nach gewisser Zeit bestimmter 
Pegel unterschritten.

Oder irgendwie den µC über einen Goldcap solange versorgen und einen 
Timer laufen lassen.

So recht gefällt mir das aber nicht.

Wie könnte ich Das am geschicktesten lösen? Ihr habt da hoffentliche 
bessere Vorschläge?

Allgemein ist nur wenig Platz für zusätzliche Bauteile vorhanden.

Danke schonmal

Gruß Ansgar

von holger (Gast)


Lesenswert?

>Wie könnte ich Das am geschicktesten lösen? Ihr habt da hoffentliche
>bessere Vorschläge?

Controller nicht wirklich ausschalten und neu starten sondern
in den Sleep Modus setzen. Ansonsten wird das wohl eher eklig.

von ansgar (Gast)


Lesenswert?

danke für deine Antwort. Leider ist das Gerät Batteriebetrieben, und ich 
kann/will aus verschiedenen Gründen das Umschalten zwischen den 
Zuständen nur durch den Reset mittels "Spannung weg" realisieren. Ein 
Taster kommt nicht in Frage.

Danke

von Hop Triceratop (Gast)


Lesenswert?

Was soll dieser tiny-Scheiss. Nimm einen richtigen Mega16 oder groesser. 
Die 2 Euro mehr koennen's nicht sein.

von Frank K. (fchk)


Lesenswert?

EEPROM durch einen MCP79410 EEPROM/RAM/RTC ersetzen.

Beim Power-Off solltest Du schauen, ob Du einen Power-Off Interrupt 
hinbekommst, bei dem Du den aktuellen Zeitstempel im SRAM des MCP 
speicherst. Wenn Du das nicht schaffst, machst Du das halt periodisch 
alle 15s.
Beim Wiederanschalten prüfst Du den Zeitstempel gegen die aktuelle Zeit 
und führst die entsprechende Aktion aus. Den letzten Zustand speicherst 
Du auch im gepufferten SRAM.

fchk

von ansgar (Gast)


Lesenswert?

Der Mehrpreis ist sicher nicht der Grund für den Tiny, sondern der nicht 
vorhandene Platz und der geringere Stromverbrauch.

Wie könnte denn ein Atmega mein Problem "lösen"?

Danke

Ansgar

von holger (Gast)


Lesenswert?

>Leider ist das Gerät Batteriebetrieben

Ist doch ok. Im Sleep Modus zieht der uC nur ein
paar uA. Wenn überhaupt.

von skyperhh (Gast)


Lesenswert?

Für den Zustandswechsel wie geschrieben das EEPROM nutzen... für den 
Rückfall nach 5min folgende Idee.

Mosfet der über den µC eingeschaltet werden kann und einen Kondensator 
lädt... im laufenden Betrieb evtl. immer mal wieder Nachladen, damit die 
Spannung am Kondensator nahe Betriebsspannung bleibt... wenn der µC 
abgeklemmt wird, entlädt sich der Kondensator langsam ... über den 
Widerstand/Kondensator kann man die Entladezeit festlegen. Ein 
Komperator oder Schmitt-Trigger vergleicht dann beim Einschalten die 
Spannung ...

von ansgar (Gast)


Lesenswert?

@Frank

Vielen Dank für Deine Antwort. Leider benötige ich dafür wieder einige 
zusätzliche Bauteile, Quarz usw.
Den MCP müsste ich dann wohl noch über einen Goldcap versorgen, oder 
gibts da was besseres?

@Holger
wie gesagt ich muss zum Wechseln zwischen den Zuständen die 
Spannungsversorung trennen.
Oder kann ich den Tiny 5 Minuten über einen Goldcap versorgen und einen 
Timer laufen lassen?

Danke

Ansgar

von ansgar (Gast)


Lesenswert?

@skyperhh

ja an sowas ähnliches hatte ich auch gedacht. Aber ich weiß nicht wie 
zuverlässig das Ganze funktionieren würde.

Danke

Ansgar

von holger (Gast)


Lesenswert?

>@Holger
>wie gesagt ich muss zum Wechseln zwischen den Zuständen die
>Spannungsversorung trennen.
>Oder kann ich den Tiny 5 Minuten über einen Goldcap versorgen und einen
>Timer laufen lassen?

Den kannst du im Sleep Modus ein paar Tage mit Goldcap laufen lassen.

von frame (Gast)


Lesenswert?

> Das lässt sich ja noch gut mit einer Flag realsieren realsieren, ich
> hoffe nur dass der EEPROM wirklich an die 100k Schreibzyklen mitmacht.

Die minimale Anzahl an Lösch/Schreibzyklen ist über den gesamten 
Temperaturbereich garantiert, in diesem Fall für die Maximaltemperatur.
Bei 25°C sind (nicht garantiert) 1...5 Mio. Zyklen drin.

Du könntest z.B. nach einem Ausschalten die EEPROM-Bytes sukzessive auf 
0 setzen, die Null-Bytes zählen und das Ergebnis der Modulo 3 - Division 
als Startzustandsindikator verwenden.

Das setzt voraus, daß du nach dem Abschalten noch genügend 'Saft' zum 
Schreiben und ggf. vollständigen Löschen des EEPROMs hast.
Meine Firma verwendet eine ähnliche Methode in Geräten, die in 
Millionenstückzahlen verkauft werden.

von skyperhh (Gast)


Lesenswert?

ansgar schrieb:
> ja an sowas ähnliches hatte ich auch gedacht. Aber ich weiß nicht wie
> zuverlässig das Ganze funktionieren würde.

Warum sollte das ganze nich funktionieren? Kleines C wählen, großer 
Widerstand...

von ansgar (Gast)


Lesenswert?

@ frame

könntest Du das Verfahren mal näher erleutern?

@skyperhh

bei einigen Versuchen hat der Kondensator die Spannung keine 5 Minuten 
gehalten.
Möglicherweiße muss ich da mal noch verschiedene Typen testen.

von Frank K. (fchk)


Lesenswert?

ansgar schrieb:
> @Frank
>
> Vielen Dank für Deine Antwort. Leider benötige ich dafür wieder einige
> zusätzliche Bauteile, Quarz usw.

1* 32kHz Quarz. 1* 100n Abblockkondensator 2* Pullup-R für den I2C
Das wars.

> Den MCP müsste ich dann wohl noch über einen Goldcap versorgen, oder
> gibts da was besseres?

Dein Gerät ist doch ohnehin batteriebetrieben, oder? Dann trenne nur die 
eigentliche Stromversorgung, nicht aber die Versorgung zu VBat vom MCP.

fchk

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Frank K. schrieb:
> 1* 32kHz Quarz. 1* 100n Abblockkondensator 2* Pullup-R für den I2C
> Das wars.

Ich weiß nicht, ich finde das reichlich kompliziert...

Für die gewünschte Funktion reicht ein ATtiny13A – ohne Quarz. Als 
Puffer für die Versorgungsspannung tuts für 5 Minuten im Sleepmode ein 
kleiner (!) Elko. EEPROM wird nicht benötigt.

Der ATtiny13A besitzt einen internen 128-kHz-Oszillator, den man per 
Vorteiler bis auf 500 Hz runtertakten kann. Dann braucht der 
Mikrocontroller eh kaum noch Strom.

Das Programm sollte kaum größer werden als ungefähr 30 Assembler-Zeilen.

Also, alles halb so wild, außer dem Mikrocontroller brauchst du 
eigentlich nur nen kleinen Elko, um die Spannung zu halten, und einen 
Kondensator in Reihe zum externen Interrupt-Eingang (mit Pulldown) – zum 
Aufwecken.

von frame (Gast)


Lesenswert?

> @ frame
> könntest Du das Verfahren mal näher erleutern?

Eigentlich ist die Methode ursprünglich für Flash ausgelegt, den man nur 
blockweise löschen kann. Dabei werden Datenblöcke sukzessive in den 
Flash geschrieben, bis ein Block voll ist. Dann wird der nächste 
begonnen, und der übernächste voreilend gelöscht. Beim letzten Block 
wird dann wieder am Anfang begonnen.

Für deinen Fall wäre das simpler, z.B.:
Flash ist im unbeschriebenen Zustand 0xFF. Beim allerersten Start sind 
alle (verwendeten) Zellen 0xFF. Beim ersten Ausschalten setzt du die 
erste Zelle auf 0x00. Beim zweiten Ausschalten setzt du die erste Zelle 
wieder auf 0xFF, und die zweite auf 0x00. Und so weiter. Nach der 
letzten Zelle beginnst du wieder von vorn.
Das verteilt die Schreibzyklen gleichmäßig auf die Zellen, die du dafür 
verwenden willst - was auch den einzigen Vorteil gegenüber einem Zähler 
in einer Zelle darstellt.
Aus der Position der 0x00-Zelle kannst du die Anzahl bisheriger Starts 
ableiten, z.B. durch Modulo-Division.

Aber, wie gesagt, meine Firma nutzt Controller mit für 100k 
spezifizierten EEPROM-Schreibzyklen, bisher ohne Probleme.
100.000 Starts sind schon relativ viel, rechne das doch mal mit deiner 
angesetzten Schalthäufigkeit nach.

von Vlad T. (vlad_tepesch)


Lesenswert?

frame schrieb:
> Das setzt voraus, daß du nach dem Abschalten noch genügend 'Saft' zum
> Schreiben und ggf. vollständigen Löschen des EEPROMs hast.

das brauchst du nicht.

folgender Ablauf:

Epprom inital nullen

startup: erste "nicht-0"-Zelle mit aktuellem Modus beschreiben.
irgendwann saft weg
nächster Startup. erste freie Zelle suchen, modus aus voriger Zelle 
berechnen und wieder wegschreiben.
Wenn ende des EEPROMS erreicht wieder komlett nullen und modus in erste 
Zelle schreiben.

so schreibt man immer nur ins eeprom, wenn man sicher Saft hat und 
verteilt die Schreibzugriffe auch optimal.

Das alles löst aber das 5min. Problem nicht.

Ich würde versuchen einen Kondensator zu nutzen.
wichtig ist, dass der µC den Spannungswegfall registriert und (zB per 
FET) sämtliche anderen Verbraucher vom Strom trennt. dann power down 
sleep aufsetzen und per Watchdog-Interupt weckenlassen und die ca 5min 
zählen. dannach einfach den internen Modus wieder auf Startwert setzen, 
falls vor dem irgendwann folgenden Brown-Out wieder angeschalten werden 
sollte.

Da braucht man auch gar kein eeprom.

von frame (Gast)


Lesenswert?

Das Verfahren kommt von einem Gerät, daß diverse Zustände erst bei 
Netz-Aus und nicht dauernd sichert, weil wegen sich permanent ändernder 
Daten sonst die garantierte Anzahl an Lösch/Schreibzyklen schnell 
erreicht wäre.
Das Gerät muß aber einen Standard erfüllen, der die persistente 
Abspeicherung dieser Daten beinhaltet.
Deswegen ist die Netzversorgung auch auf eine Stützzeit von >300ms 
ausgelegt, um alle Daten sicher speichern zu können.

In wie weit diese Umstände auf das diskutierte Gerät zutreffen, muß der 
Fragesteller entscheiden.

von Bernhard S. (b_spitzer)


Lesenswert?

Wenn eine Echtzeituhr (Batteriegepuffert mit kleinem RAM-Bereich) zu 
viel Aufwand ist, mach doch so:
Mach dem ersten einschalten läuft Betriebsart 1, danach legt sich der 
Controller schlafen und wird vom Timer regelmässig kurz geweckt. Wenn in 
der Zwischenzeit wieder Eingeschaltet wird, wechselt der Controller in 
Betriebsart 2/3/2/3 etc. Nach 5 min im Sleep/Aufwach-Betrieb schaltet 
sich der Controller aus und beim nächsten Einschalten ist daher wieder 
Betriebsart 1 dran. Dann brauchst Du eine Pufferung, die höchstens Strom 
für einige Minuten Sleep-Mode (5 Sleep plus Aufwachphasen) puffern muss.

von ansgar (Gast)


Lesenswert?

Hallo,

danke für eure Unterstützung. Ich habe die Anforderungen jetzt etwas 
geändert.

Es gibt nur noch zwei Zustände. Die Zustände sollen nur zwei Ports 
umschalten.

Dass Trennen der Versorgungsspannung wird durch den ext. Interrupt 
detektiert, da er auf die fallende Flanke reagiert.
Der Interrupt lässt dann den Mode wechseln.

Der Attiny wird während der Off Zeit aus einem Elko gepuffert. Damit der 
Elko reicht wird wechselt er in den Sleepmode Idle.

Jetzt möchte ich allerdings dass IMMER Mode 1 aktiviert wird wenn die 
Offzeit länger als 8 Sekunden dauert.
Dauert die Offzeit weniger als 8 Sekunden soll man durch 
trennen/wiederherstellen der Spannungsversorung die Stufen wechseln 
können.

Ich habe dazu noch den Timer aktiviert, und wollte das mit dem 
Timeroverflow Interrupt machen.

Leider bekomme ich es nicht hin dass die 8 Sekunden nur während der 
Offzeit gelten, sondern nur so dass er immer nach 8 Sekunden schaltet.

Ich kann leider keine zusätzlichen Bauteile mehr einbauen, und muss das 
über die Software hinbiegen.

Ich hoffe ihr könnt mir nochmal helfen.

Anbei mal mein letzter Codestand, so funktioniert der Timeroverflow 
natürlich gar nicht, war nur ein Versuch.


Vielen Dank

Ansgar
1
//Includes
2
#include <avr/io.h>
3
#include <stdint.h>
4
#include <avr/interrupt.h>
5
#include <avr/eeprom.h>
6
#include "defines.h"
7
#include <avr/sleep.h>
8
9
/**********************************************/
10
#define F_CPU 128000UL  // 128kHz CPU Takt
11
#include <util/delay.h>
12
13
/**********************************************/
14
//Variablen
15
volatile uint8_t Zaehler = 0;
16
volatile uint8_t Mode =1;
17
volatile uint8_t b = 0;
18
volatile bool Abbruch = true;
19
20
//uint8_t EStatus EEMEM = 0; //EEPROM
21
22
23
24
/***********************************************/
25
26
//Hauptprogramm
27
int main(void)
28
     {
29
  
30
  /*************Zuordnungen********************/
31
  
32
      
33
34
      DDRB = ( 1 << PB0 ) |  ( 1 << PB2 );// Ausgänge PB0 und PB2
35
      PORTB=0b00000000; //Ausgänge: LOW / Eingänge: Pullups deaktiviert
36
    
37
      TCCR0B= (1<<CS02) |(0<<CS01) |  (1<<CS00); // Prescaler 1024
38
      
39
      
40
      
41
      GIMSK   |=  (1<<INT0); //externer INT0 auf PB1 freigeben
42
      MCUCR |= (1<<ISC01) | (0<<ISC00); //Interrup INT0: fallende Flanke
43
      
44
  
45
     // Analogcomparator ausschalten
46
     
47
     ACSR = 0x80;
48
     
49
     //Interrupts zulassen
50
    sei();
51
52
    //Sleepmode "IDLE2" wählen
53
    set_sleep_mode(SLEEP_MODE_IDLE);
54
    
55
  
56
    while(1)
57
    {
58
       switch (Mode) 
59
    {
60
      case 1:  //100%
61
      
62
      {
63
        Abbruch = true;
64
       Mode = 2;
65
        while(Abbruch)    //Endlosschleife bis Abbruch durch Interrupt INTO
66
        {
67
          TIMSK0 &=~ (1<<TOIE0); //Timer Overflow Interrupt sperren 
68
69
          PORTB &= ~(1<<PB0); //Analogschalter 1 geschlossen
70
          PORTB |= (1<<PB2); //Analogschalter 2 geöffnet
71
72
             sleep_mode();  //schlafen
73
        }
74
            
75
      }
76
      
77
      break;
78
      
79
      
80
      
81
      
82
      
83
      
84
      
85
      case 2:     //25%
86
       {
87
         Abbruch = true;
88
         Mode = 1;
89
         while(Abbruch)  //Endlosschleife bis Abbruch durch Interrupt INTO
90
         {
91
           TIMSK0 &=~ (1<<TOIE0);  //Timer Overflow Interrupt sperren 
92
93
           PORTB |= (1<<PB0); //Analogschalter 1 geöffnet
94
           PORTB &= ~ (1<<PB2); //Analogschalter 2 geschlossen 
95
96
              sleep_mode(); //schlafen
97
         }
98
               
99
       }
100
       
101
       break;
102
      
103
      
104
      
105
      
106
      
107
      
108
      
109
      default:
110
                PORTB &= ~(1<<PB0); //Analogschalter 1 geschlossen
111
                PORTB |= (1<<PB2); //Analogschalter 2 geöffnet
112
      
113
      
114
    }
115
  
116
  }
117
  
118
return 0;
119
}
120
//Ende Hauptprogramm
121
122
123
124
125
/*****************************************************************/
126
//Interrupt Routine
127
128
ISR(TIM0_OVF_vect) // Timer0 Overflow Interrupt wird alle 2048ms aufgerufen
129
{
130
  //PORTB |=(1<<PB3);
131
  if (Zaehler < 3)  
132
  {
133
      Zaehler++; 
134
135
    }
136
  else {
137
    Zaehler = 0;
138
     Mode=1;    //nach 8s Mode 1 aktivieren
139
  }
140
  
141
142
143
  
144
}
145
146
147
ISR(INT0_vect)  //  Interrupt fallende Flanke PB1
148
{
149
  Abbruch = false;
150
  Zaehler = 0;
151
  _delay_ms(200);
152
  TCNT0 = 0;
153
  TIMSK0 |= (1<<TOIE0); //Overflow Interrupt zulassen
154
  
155
}

von ansgar (Gast)


Lesenswert?

Ich habe mir gerade überlegt dass ich nach dem Interrupt fallende 
Flanke, den Interrupt auf steigende Flanke umstelle.
Somit könnte ich feststellen ob ich wieder eingeschaltet habe oder 
nicht.

Was meint ihr?

Danke

Ansgar

von ansgar (Gast)


Lesenswert?

Hallo,

ich hab die Software jetzt so hinbekommen dass es scheinbar das macht 
was ich wollte.

Habt ihr noch Verbesserungsvorschläge?

Danke

Gruß Ansgar
1
//Includes
2
#include <avr/io.h>
3
#include <stdint.h>
4
#include <avr/interrupt.h>
5
#include <avr/eeprom.h>
6
#include "defines.h"
7
#include <avr/sleep.h>
8
9
/**********************************************/
10
#define F_CPU 128000UL  // 128kHz CPU Takt
11
#include <util/delay.h>
12
13
/**********************************************/
14
//Variablen
15
volatile uint8_t Zaehler = 0;
16
volatile uint8_t Mode =1;
17
volatile uint8_t b = 0;
18
volatile bool Abbruch = true;
19
20
//uint8_t EStatus EEMEM = 0; //EEPROM
21
22
23
24
/***********************************************/
25
26
  //Funktionen
27
  void mode1(void)   //Mode1
28
  {
29
    PORTB &= ~(1<<PB0); //Analogschalter 1 geschlossen
30
    PORTB |= (1<<PB2); //Analogschalter 2 geöffnet
31
  }
32
  
33
  void mode2(void)   //Mode2
34
  {
35
    PORTB |= (1<<PB0); //Analogschalter 1 geöffnet
36
    PORTB &= ~ (1<<PB2); //Analogschalter 2 geschlossen
37
  }
38
39
  void interruptchange(void) //Externen Interrupt umschalten fallende/steigende Flanke
40
  {
41
     if ( !( MCUCR & (1<<ISC00) ) ) //falls Interrupt fallende Flanke
42
    {
43
       MCUCR |= (1<<ISC00);  //Interrupt auf steigende Flanke umstellen
44
       Zaehler = 0;
45
       TCNT0 = 0;
46
       TIMSK0 |= (1<<TOIE0); //Overflow Interrupt zulassen
47
    }
48
    else if(MCUCR & (1<<ISC00) )  //falls Interrupt steigende Flanke
49
   {
50
     MCUCR &= ~ (1<<ISC00); //Interrupt auf fallende Flanke umstellen
51
     TIMSK0 &=~ (1<<TOIE0); //Timer Overflow Interrupt sperren 
52
     Abbruch = false;
53
   }
54
  }
55
  //Funktionen Ende
56
57
58
//Hauptprogramm
59
int main(void)
60
     {
61
  
62
  /*************Zuordnungen********************/
63
  
64
      
65
66
      DDRB = ( 1 << PB0 ) |  ( 1 << PB2 ) | (1<<PB3);// Ausgänge PB0 und PB2
67
      PORTB=0b00000000; //Ausgänge: LOW / Eingänge: Pullups deaktiviert
68
    
69
      TCCR0B= (1<<CS02) |(0<<CS01) |  (1<<CS00); // Prescaler 1024
70
      
71
      GIMSK   |=  (1<<INT0); //externer INT0 auf PB1 freigeben
72
      MCUCR |= (1<<ISC01) | (0<<ISC00); //Interrup INT0: fallende Flanke
73
      
74
  
75
     // Analogcomparator ausschalten
76
     
77
     ACSR = 0x80;
78
     
79
     //Interrupts zulassen
80
    sei();
81
82
    //Sleepmode "IDLE" wählen
83
    set_sleep_mode(SLEEP_MODE_IDLE);
84
    
85
  
86
    while(1)
87
    {
88
       switch (Mode) 
89
    {
90
      case 1:  //100%
91
      
92
      {
93
        Abbruch = true;
94
       Mode = 2;
95
        while(Abbruch)    //Endlosschleife bis Abbruch durch Interrupt INTO
96
        {
97
                  mode1();
98
                  sleep_mode();  //schlafen
99
        }
100
            
101
      }
102
      
103
      break;
104
      
105
      
106
      
107
      
108
      
109
      
110
      
111
      case 2:     //25%
112
       {
113
         Abbruch = true;
114
         Mode = 1;
115
         while(Abbruch)  //Endlosschleife bis Abbruch durch Interrupt INTO
116
         {
117
           mode2();
118
            sleep_mode(); //schlafen
119
         }
120
               
121
       }
122
       
123
       break;
124
      
125
      default:
126
                PORTB &= ~(1<<PB0); //Analogschalter 1 geschlossen
127
                PORTB |= (1<<PB2); //Analogschalter 2 geöffnet
128
      
129
      
130
    }
131
  
132
  }
133
134
  
135
  
136
return 0;
137
}
138
//Ende Hauptprogramm
139
140
141
/*****************************************************************/
142
//Interrupt Routinen
143
144
ISR(TIM0_OVF_vect) // Timer0 Overflow Interrupt wird alle 2048ms aufgerufen
145
{
146
  
147
  
148
  if (Zaehler < 3)  
149
  {
150
      Zaehler++; 
151
152
    }
153
  else {
154
    Zaehler = 0;
155
     
156
     PORTB |=(1<<PB3);
157
     Mode=1;    //nach 8s Mode 1 aktivieren
158
  }
159
  
160
161
162
  
163
}
164
165
166
ISR(INT0_vect)  //  Interrupt fallende/steigende Flanke PB1
167
{
168
  
169
  _delay_ms(200);
170
  interruptchange();
171
  
172
}

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.