Forum: Mikrocontroller und Digitale Elektronik Atmega328P Batterie, Bewegungsmelder, LED, Fotowiderstand, Farbwechsel Taster


von Michael (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich hatte schon einen Beitrag hier im Forum, aber meine Anforderungen an 
meine Wunschlösung haben sich, wie es so oft der Fall ist im Laufe der 
Zeit doch noch weiter verändert.

Entschuldigt den Schaltplan. Mit Eagle bin ich noch relativ neu und ich 
habe keine Elektroniker Ausbildung. Also auch das Zeichnen eines 
Schaltplans ist nicht meine tägliche Arbeit. Ich hoffe man kann das 
halbwegs verstehen.

Kurz der Hintergrund.
Ich möchte ein kleines Nachtlicht bauen, das ich für verschiedene Zwecke 
verwenden kann, aber die Basis ist immer die gleiche.

- Bewegungsmelder PIR Modul mit AM312 Sensor und 3 Anschlüssen (Vin, 
Out, GND)
- Mikrocontroller (hier Atmega328P)
- Helligkeitssensor / Fotowiderstand (Dunkel??? LED an?, sonst bleibt 
LED aus)
- Drucktaster (Für den Farbwechsel)
- 3xAA Batterien

Zum Aufbau:
Die Batterien (3xAA -> V_Supply: 4.8V...2.7V) versorgen:
- PIR Sensor
- Mikrocontroller
- MT3608 Boost Wandler auf 8.5V

Die LEDs sind mit Vorwiderständen an den 8.5V Ausgangsspannung des 
MT3608 verbunden.
Es handelt sich um High Power LEDs. Diese werden aber nur mit ca.10mA 
betrieben, aber liefern damit schon deutlich mehr Licht als Standard 
LEDs.

Der Fotowiderstand (im Layout noch 3 Stück, da ich mich nicht 
entscheiden kann) wird mittels einem Pin des uC beim Aufwachen mit 
Spannung versorgt und so über ADC die Helligkeit gemessen.

Zu meinen Messdaten:
Stromverbrauch bei 4V Eingangsspannung:
Nur der PIR / Bewegungsmelder: 0.025mA
Nur der MT3608 mit ENABLE auf LOW: 0.07mA

LED Durchlassspannung bei I = ca. 10mA:
3x Rot: 5.49 V
3x Grün: 7.00 V
3x Blau: 7.63 V
3x Weiss: 7.93 V

Anbei mal noch der Code.
Was darin bis jetzt passiert:
- PIR Sensor erkennt Bewegung und weckt den uC mittels PinInterrupt auf
- Wert des Fotowiderstand wird ausgelesen
- Entscheidung ob LED an oder aus
- Zeit Zählen bis ausschalten, wenn neue Bewegung dann wieder bei 0 
anfangen mit Zählen.
- Beim Drücken des Tasters wird die Farbe gewechselt.
- Dann legt sich der uC wieder schlafen.


Was ich noch machen muss.
A) Beim Tastendruck, muss ich die Zeit bis zum Ausschalten wieder auf 0 
setzten bzw. das passiert vermutlich eh, da der Sensor eine Bewegung 
erkennt
B) Wenn es bei erkannter Bewegung Hell war und dann Dunkel wird, sollte 
die LED sich einschalten, das habe ich bis jetzt nicht hinbekommen. Ich 
bekomme es nur beim Aufwachen hin das ich es dort einmal überprüfe.
C) Bin ich mir nicht sicher ob es Sinn macht den MT3608 dauerhaft mit 
Spannung zu versorgen. Könnte ich diesen nicht auch mit einem Transistor 
erst mit Spannung versorgen, so wie ich es beim Fotowiderstand mache?
Wenn ja, was für ein Transistor und wo müsste dieser hin?


Und jetzt bin ich gespannt, was die Experten hier sagen.
Bin ich komplett auf dem falschen weg mit meiner Lösung oder kann man 
damit arbeiten?

Ich danke euch schonmal im voraus für euren Input.

Gruss
1
/*
2
 * Am Ende muss Serial kommentiert werden, um den Stromverbrauch zu senken
3
 */
4
5
#include <avr/sleep.h>
6
#include <avr/power.h>
7
#include <EEPROM.h>
8
//#include <LowPower.h>
9
long val;
10
int ref0, ref1;
11
12
const byte LED_R = 5; const byte LED_G = 6; const byte LED_B = 10; const byte LED_W = 9;
13
14
const byte ALS_POWER_PIN = 4;
15
//int ALS_PIN = A4;
16
int ALS_PIN = 18;
17
int buttonPin = 8;
18
int ALS_value = 0;
19
int addressR = 0; int addressG = 1; int addressB = 2; int addressW = 4;
20
21
const long Ausschaltverzoegerung = 5000;
22
23
byte R=0; byte G=0; byte B=0; byte W=0;
24
25
unsigned long previousMillis = 0;
26
const long intervalON = 1000;  
27
const long intervalOFF = 4000;
28
29
int ResetTimeStart = 0;
30
unsigned long TimeSinceButtonPressed = 0;
31
unsigned long TimeStart = 0;
32
int WaitTimeLedColor = 750; // time in ms
33
34
int WakeUpTrue = 0;
35
unsigned long WakeUpTime = 0;
36
37
unsigned long TimeSinceLastPirTracking = 0;
38
39
int counterButton = 0;
40
41
int RUN = 1;
42
43
int buttonPushCounter = 0;   // counter for the number of button presses
44
int buttonState = 0;         // current state of the button
45
int lastButtonState = 0; 
46
47
int InSituStableTrue = 0;
48
49
50
void ActivateIOs()
51
{
52
  Serial.println("WAKE-Activate IOs");
53
  pinMode(LED_R, OUTPUT); analogWrite(LED_R, 0);
54
  pinMode(LED_G, OUTPUT); analogWrite(LED_G, 0);
55
  pinMode(LED_B, OUTPUT); analogWrite(LED_B, 0);
56
  pinMode(LED_W, OUTPUT); analogWrite(LED_W, 0);
57
  pinMode(A4,INPUT);
58
  pinMode(ALS_POWER_PIN, OUTPUT);
59
  digitalWrite(ALS_POWER_PIN, HIGH);
60
  digitalWrite(13, HIGH);
61
  delay(200);
62
}
63
void DeactivateIOs()
64
{
65
  pinMode(LED_R, INPUT); digitalWrite(LED_R, LOW);
66
  pinMode(LED_G, INPUT); digitalWrite(LED_G, LOW);
67
  pinMode(LED_B, INPUT); digitalWrite(LED_B, LOW);
68
  pinMode(LED_W, INPUT); digitalWrite(LED_W, LOW);
69
  digitalWrite(ALS_POWER_PIN, LOW); pinMode(ALS_POWER_PIN, INPUT); digitalWrite(ALS_POWER_PIN, LOW);
70
  digitalWrite(13, LOW);
71
}
72
73
void SetLEDColor(int R, int G, int B, int W)
74
{
75
  analogWrite(LED_R, R);
76
  analogWrite(LED_G, G);
77
  analogWrite(LED_B, B);
78
  analogWrite(LED_W, W);
79
  if (R != EEPROM.read(addressR)) {EEPROM.write(addressR, R);Serial.println("R - Saved");
80
  } else {Serial.println("R - no change");
81
    }
82
  
83
  if (G != EEPROM.read(addressG)) {EEPROM.write(addressG, G);
84
  Serial.println("G - Saved");
85
  } 
86
  else {Serial.println("G - no change");
87
    
88
  }
89
  if (B != EEPROM.read(addressB)) {EEPROM.write(addressB, B);Serial.println("B - Saved");
90
  } else {Serial.println("B - no change");
91
    }
92
  if (W != EEPROM.read(addressW)) {EEPROM.write(addressW, W);Serial.println("W - Saved");
93
  } else {Serial.println("W - no change");
94
    }
95
}
96
97
void ReadLEDColor()
98
{
99
  R = EEPROM.read(addressR);
100
  G = EEPROM.read(addressG);
101
  B = EEPROM.read(addressB);
102
  W = EEPROM.read(addressW);
103
}
104
105
void ShowLEDColor()
106
{
107
  analogWrite(LED_R, R);
108
  analogWrite(LED_G, G);
109
  analogWrite(LED_B, B);
110
  analogWrite(LED_W, W);
111
}
112
113
void LEDsOff()
114
{
115
  analogWrite(LED_R, 0);
116
  analogWrite(LED_G, 0);
117
  analogWrite(LED_B, 0);
118
  analogWrite(LED_W, 0);
119
}
120
121
void wake()
122
{
123
  sleep_disable(); // cancel sleep as a precaution
124
  Serial.println("-------WAKE UP-------");
125
  detachInterrupt (0); // precautionary while we do other stuff
126
  //detachInterrupt (1); // precautionary while we do other stuff
127
  power_all_enable();
128
  ADCSRA |= (1 << ADEN);
129
  WakeUpTrue = 1; Serial.println("-------WakeUpTrue TRUE-------");
130
  ReadLEDColor();
131
  TimeSinceLastPirTracking = 0;
132
  WakeUpTime = millis();
133
  ActivateIOs();
134
}  // end of wake
135
136
void setup() 
137
  {
138
    Serial.begin(9600);
139
    Serial.println("Start");
140
    ReadLEDColor();
141
    Serial.print("R: ");Serial.print(R);Serial.print(" - G: ");Serial.print(G);Serial.print(" - B: ");Serial.print(B);Serial.print(" - W: ");Serial.println(W);
142
    Serial.print("EEPROM Place 10: ");Serial.println(EEPROM.read(10));
143
    delay(100);
144
145
    pinMode(13, OUTPUT);
146
    digitalWrite(13, HIGH); delay(1000); digitalWrite(13, LOW); Serial.println("LED LOW");
147
    
148
    pinMode(LED_R, OUTPUT);
149
    pinMode(LED_G, OUTPUT);
150
    pinMode(LED_B, OUTPUT);
151
    pinMode(LED_W, OUTPUT);
152
    analogWrite(LED_R, 0);
153
    analogWrite(LED_G, 0);
154
    analogWrite(LED_B, 0);
155
    analogWrite(LED_W, 0);
156
  }  // end of setup
157
158
void loop() 
159
{
160
    while (WakeUpTrue == 1)
161
      {
162
      //delay(500);
163
      ALS_value = analogRead(A4);
164
      Serial.print("-----");
165
      Serial.print(ALS_value);
166
      Serial.println("-----");
167
        if (ALS_value <= 300)
168
          {
169
          Serial.println("Dark - Turn LED ON");
170
          ReadLEDColor();
171
          ShowLEDColor();
172
          }
173
        else
174
          {
175
          Serial.println("Bright - Keep LED OFF");
176
          //ActivateLight = 0;
177
          }
178
      while (TimeSinceLastPirTracking < Ausschaltverzoegerung)
179
        {
180
        Serial.println(TimeSinceLastPirTracking);
181
        if (digitalRead(2) == HIGH) //war 3 wegen InterruptPin 1
182
          {
183
          TimeSinceLastPirTracking = 0;
184
          WakeUpTime = millis();
185
          }
186
        else
187
          {
188
          TimeSinceLastPirTracking = millis() - WakeUpTime;
189
          }
190
        ChangeColorByButton();
191
        
192
        }
193
      
194
      LEDsOff();
195
      WakeUpTrue = 0;
196
      }
197
        
198
      WakeUpTrue = 0;
199
      ADCSRA = 0;  // disable ADC
200
      Serial.println("Go Sleeping ..."   );
201
        
202
203
        Serial.println("AAAAA");
204
        DeactivateIOs();
205
        delay(100);
206
        ADCSRA = 0;  // disable ADC
207
        set_sleep_mode (SLEEP_MODE_PWR_DOWN); 
208
        sleep_enable();
209
        noInterrupts (); // Do not interrupt before we go to sleep, or the ISR will detach interrupts and we won't wake.
210
        attachInterrupt (0, wake, RISING); // will be called when pin D2 goes high  
211
        //attachInterrupt (1, wake, RISING); // will be called when pin D2 goes high  
212
        EIFR = bit (INTF0);  // clear flag for interrupt 0
213
        MCUCR = bit (BODS) | bit (BODSE); //turn off brown-out enable in software BODS must be set to one and BODSE must be set to zero within four clock cycles
214
        MCUCR = bit (BODS);  // The BODS bit is automatically cleared after three clock cycles
215
  
216
        // We are guaranteed that the sleep_cpu call will be done
217
        // as the processor executes the next instruction after
218
        // interrupts are turned on.
219
        interrupts ();  // one cycle
220
        sleep_cpu ();   // one cycle
221
        sleep_disable ();
222
        ActivateIOs();
223
        }
224
 // end of loop
225
226
227
void ChangeColorByButton()
228
{
229
  buttonState = digitalRead(buttonPin);
230
        if (buttonState != lastButtonState) {
231
            // if the state has changed, increment the counter
232
            if (buttonState == 1) {
233
              // if the current state is HIGH then the button went from off to on:
234
              buttonPushCounter++;
235
            } else {
236
              // if the current state is LOW then the button went from on to off:
237
            }
238
            if (buttonPushCounter == 1)
239
            {R=50; G=0; B=0; W=0; SetLEDColor(R, G, B, W);
240
            Serial.println("Red");
241
            }
242
            else if (buttonPushCounter == 2)
243
            {R=0; G=50; B=0; W=0; SetLEDColor(R, G, B, W);
244
            Serial.println("Green");
245
            }
246
            else if (buttonPushCounter == 3)
247
            {R=0; G=0; B=50; W=0; SetLEDColor(R, G, B, W);
248
            Serial.println("Blue");
249
            }
250
            else if (buttonPushCounter == 4)
251
            {R=0; G=0; B=0; W=50; SetLEDColor(R, G, B, W);
252
            Serial.println("White");
253
            }
254
            else if (buttonPushCounter == 5)
255
            {buttonPushCounter = 1;}
256
            // Delay a little bit to avoid bouncing
257
            delay(50);
258
          }
259
        lastButtonState = buttonState;
260
}

von Bastler (Gast)


Lesenswert?

Bitte noch mehr Leerzeilen in den Code einbauen

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Du möchtest sicher keine Spannungteiler mit Faktor 2 an den MOSFet Gates 
haben. Der Pulldown kann ja bei 10k bleiben, aber der Gatewiderstand ist 
mit 10k viel zu hoch. Mach da 100 Ohm oder kleiner rein, dann werden die 
MOSFet auch durchgesteuert.
Ändere mal den Wert der Speicherdrossel von 22µF auf 22µH. Das passt für 
Spulen einfach besser :-P
Für Programme in 'Arduino' bin ich zu blöd, dazu kann ich nichts sagen.

: Bearbeitet durch User
von Georg M. (g_m)


Lesenswert?

Bastler schrieb:
> Bitte noch mehr Leerzeilen in den Code einbauen

Das geht automatisch:

97
98
99
10
0
10
1
10
2
10
3
10
4

von Brain 2.0 (Gast)


Lesenswert?

Und ich vermisse die 100nF an jedem VCC des Atmega328, sowie einen 10k 
Widerstand am Reset-Pin gegen VCC.
Was ist mit einem Quarz, oder kommt da der interne Taktgeber zum tragen 
?

von Drago S. (mratix)


Lesenswert?

Michael schrieb:
> C) Bin ich mir nicht sicher ob es Sinn macht den MT3608 dauerhaft mit
> Spannung zu versorgen. Könnte ich diesen nicht auch mit einem Transistor
> erst mit Spannung versorgen, so wie ich es beim Fotowiderstand mache?
> Wenn ja, was für ein Transistor und wo müsste dieser hin?
Sein Enable hängt doch schon an AIN1/PD7. Ergo verbraucht er nur den 
kleinen Iq Ruhestrom.
Wenn dir das Sorgen bereitet, könntest du es komplett mit einem 
davorgeschalteten P-ch MOSFET abhängen. Und über den GPIO dann das Gate 
statt den Enable steuern.
Schau mal hier, ob das in Frage kommt: 
[https://github.com/RalphBacon/Arduino-Auto-Switch-Off]

> B) Wenn es bei erkannter Bewegung Hell war und dann Dunkel wird, sollte
> die LED sich einschalten, das habe ich bis jetzt nicht hinbekommen. Ich
> bekomme es nur beim Aufwachen hin das ich es dort einmal überprüfe.
Wenn das ganze nur als Nachtlicht arbeiten soll, könnte man den 
Interrupt zum Aufwachen noch ein wenig verbessern.
z.B. nur nach einem positivem PIR-signal und entsprechendem LDR Wert. 
Den LDR dann nach vorne ziehen. Je nach Signal beides mit einem 
einfachen AND Gatter oder eben Komparator/OPV zum INT0/PD2 führen. Die 
Variante würde zugleich das Problem B) lösen. Es sein denn in der 
Software fährst du die Abfrage nicht ab (noch nicht angeschaut).

Im Tiefschlaf begibt sich der uC eh schon, nur der Reset-Pin braucht 
einen definierten Pegel, Pullup. Und die Gate-Widerstände wurden schon 
erwähnt.

Für den PIR glaube ich gab es auch noch ein paar Mods. Seinen internen 
LDO eliminieren. Das würde sich positiv auf die Batterielaufzeit 
auswirken.

von Peter D. (peda)


Lesenswert?

Georg M. schrieb:
> Das geht automatisch:

Aber nur bei überlangem Code, den man besser als Anhang posten sollte.

von Georg M. (g_m)


Lesenswert?

Peter D. schrieb:
> Aber nur bei überlangem Code

Trotzdem ist das ein Gestaltungsfehler:
1
.rouge-gutter {
2
    width: 4ex;

von Drago S. (mratix)


Lesenswert?

Michael schrieb:
> Anbei mal noch der Code.
Ist schon ziemlich frech, den Hauptteil des Codes zu verschweigen und 
Header zu entfernen. Auch keine Erwähnung dass die Projektidee von 
https://github.com/RalphBacon/PIR-ATMega328P-Deep-Sleep stammt. Ebenso 
wurden weitere fertige Teile zusammenkopiert. Aber hier nach Hilfe, Rat 
und Lösung fragen.

Ich habe den Code überarbeitet und ergänzt. Auch neu strukturiert, in 
Funktionen verpackt und gesäubert. Nur sehe ich aus o.g. Gründen unter 
diesen Umständen, es nicht ein ihn einfach so fertig zu präsentieren.

Sorry, zum ersten Mal muss ich Nein sagen.

von Michael (Gast)



Lesenswert?

Ich möchte mich schonmal bedanken für eure Hinweise.

Das ich den Code aus verschiedenen Stellen zusammengesucht und angepasst 
habe ist richtig. Ich wollte nicht verheimlichen, dass ich den Deep 
Sleep Teil von Ralph Bacon habe. Ich hatte versucht mir das in der 
Arduino IDE etwas übersichtlicher zu gestalten. Ich gebe es gerne zu. 
Der Code stammt zum grössten Teil von dort. Auch richtig. Ich hätte die 
Quelle angeben sollen bzw. in meinem langen Text oben darauf hinweisen 
sollen. Ich bitte hiermit um Entschuldigung.

Ich habe mir das Video von Ralph Bacon, welches hier verlinkt wurde mit 
dem N- und P- Mosfet angeschaut und versucht das in meinen Schaltplan zu 
integrieren, aber ob das nun so funktioniert weiss ich natürlich nicht.

Die Dunkelschaltung habe ich von hier:
https://elektro.turanis.de/html/prj131/index.html

Vom Prinzip hoffe ich jetzt, dass folgendes passiert.

- Nur der PIR Sensor zieht dauerhaft Strom.
- Wenn das Signal des PIR auf High schaltet, wird das AND-GATE und der 
Komparator dadurch mit Spannung versorgt.
Ist es dunkel genug, sollten jetzt der MT3608 und der Atmega mit 
Spannung versorgt werden.
Um die Spannung aufrecht zu erhalten wird Pin PD2 am Atmega auf HIGH 
gesetzt und hält die Spannung somit aufrecht.

Könnte das so funktionieren oder habe ich da jetzt einen Fehler 
eingebaut?

Und nochmals Entschuldigung. Quellen werde ich in Zukunft angeben.

von Helmut L. (helmi1)


Lesenswert?

Michael schrieb:
> Könnte das so funktionieren oder habe ich da jetzt einen Fehler
> eingebaut?

Nur auf die Schnelle:
Dein Q2 wird niemals sperren, da fehlt der Pullupwiderstand zwischen 
Gate und Source.

Dein UND Gatter wird niemals einen Highpegel sehen, da fehlt der Pullup 
vom LM393 Komparator.

Fuer die 4 MOSFETS auf der rechten Seite ist der Gatewiderstand mit 10K 
viel zu gross.

von Michael (Gast)



Lesenswert?

Helmut L. schrieb:
> Dein Q2 wird niemals sperren, da fehlt der Pullupwiderstand zwischen
> Gate und Source.

Danke. Habe ich übersehen. War ja in dem Video von Ralph Bacon, welches 
"mister A." verlinkt hatte so eingezeichnet.

Helmut L. schrieb:
> Dein UND Gatter wird niemals einen Highpegel sehen, da fehlt der Pullup
> vom LM393 Komparator.

Danke. Habe ich mit 4k7 eingebaut.

Helmut L. schrieb:
> Fuer die 4 MOSFETS auf der rechten Seite ist der Gatewiderstand mit 10K
> viel zu gross.

Danke. Das wurde in einem vorherigen Post auch schon angesprochen. Ich 
habe es jetzt mit 100 Ohm Widerständen ersetzt.

von Georg M. (g_m)



Lesenswert?

Irgendwie scheint alles unnötig zu kompliziert zu sein.
Normalerweise sind PIR-Nachtlichter ziemlich einfache Konstruktionen.

Auf dem Foto ist das PCB von diesem PIR-Nachtlicht:
https://s7g10.scene7.com/is/image/aldi/202009160147

von Michael (Gast)


Lesenswert?

Georg M. schrieb:
> Irgendwie scheint alles unnötig zu kompliziert zu sein.
> Normalerweise sind PIR-Nachtlichter ziemlich einfache Konstruktionen.
>
> Auf dem Foto ist das PCB von diesem PIR-Nachtlicht:
> https://s7g10.scene7.com/is/image/aldi/202009160147

Da hast du wahrscheinlich recht.
Leider komme ich auf keine andere Lösung.

Ich denke hier wäre genau die Schaltung darin die ich benötige

https://de.aliexpress.com/item/32789207449.html

Das leuchtet scheinbar 2 Minuten nach und man kann auch die Farbe 
wechseln.
Vielleicht bestelle ich mal so eins ;-)

von Drago S. (mratix)


Lesenswert?

Der Reset ist nun falsch umgesetzt.

Ein /RST als low-active sollte so sein:
Vcc -> 10k -> RST
RST <- Taster <- GND

OT: spinnt die Forumsoftware wieder oder ist nur bei mir die Darstellung 
(fehlender Zeilenumbruch) kaputt?

: Bearbeitet durch User
von Drago S. (mratix)


Lesenswert?

Zum Problem B solltest du den code umschreiben.

Du hast nur eine einmalige (Ab)Schaltung als Verzögerung drinnen. Einen 
einfachen Countdown ohne retrigger.
Damit wurden die Bedingungen nicht weiter geprüft und das Licht ging 
aus.

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.