Forum: Mikrocontroller und Digitale Elektronik Zeitabhängige Spannungssteuerung


von AtroCty (Gast)


Lesenswert?

Guten Morgen,

ich habe ein kleines Problem mit einer Schaltung:

Ich habe eine Solar-Steuerung über einen Mikrokontroller realisiert. 
Dazu wird die Ausgangsspannung nach einem DC-DC-Wandler zu einer 
bestimmten Zeit über ein Relais an den Endverbraucher zugeschaltet. 
Dabei ruft der µC über einen TWI (DS1307) die aktuelle Zeit ab, und soll 
je nachdem das Relais schalten.

Sobald ich die Zeit neu einstelle läuft das Programm eine Zeit lang so, 
wie es soll. (Das Relais wird pünktlich geschaltet, und schaltet auch 
pünktlich zum gewünschten Zeitpunkt wieder ab)

Jedoch bleibt der µC nach einer Zeit verweilen am aktuellen Zustand, bis 
er neu eingestellt wird. Ich vermute, dass der µC sich aufhängt. Ich 
schätze, dass es am Code liegt, ich habe bereits 3 µC getestet, alle mit 
dem gleichem Ergebnis.

Mein Code:
1
#define   F_CPU   3686400
2
#include <avr\io.h>
3
//---------------------------------------------------------------------------------
4
// TWI-Funktionssammlung
5
#ifndef TWI_CLOCK
6
#define TWI_CLOCK 100000 // Geschwindigkeit des TWI-Busses
7
#endif
8
// TWCR - Control-Register-Bits
9
#define _TWINT 0b10000000
10
#define _TWEA 0b01000000
11
#define _TWSTA 0b00100000
12
#define _TWSTO 0b00010000
13
#define _TWWC 0b00001000
14
#define _TWEN 0b00000100
15
#define _TWIE 0b00000001
16
uint8_t   twiAdr = 0xD0;
17
void twiInitMaster(uint8_t twiAdr);
18
#include <util\delay.h>
19
#include <util\delay.h>
20
21
//------------------------------------------------------------------------
22
// twiInitMaster
23
//------------------------------------------------------------------------
24
void twiInitMaster(uint8_t twiAdr)
25
{
26
  // Clock
27
  TWBR=((F_CPU/TWI_CLOCK)-16)*2;
28
  // TWI-Status-Register (Vorteiler)
29
  TWSR=0;
30
  // Bus-Addr
31
  TWAR=twiAdr;
32
  // Enable
33
  TWCR=_TWINT|_TWEN;
34
}
35
//------------------------------------------------------------------------
36
// Start TWI (ohne Interrupt)
37
//------------------------------------------------------------------------
38
void twiStart()
39
{
40
  uint8_t x=TWCR;
41
  x&=_TWEN|_TWIE;    // nur Beibehalten von Enable und InterruptJ/N 
42
  TWCR=x|_TWINT|_TWSTA;
43
  // warten bis fertig
44
  while( !(TWCR & _TWINT))
45
  {}
46
}
47
//------------------------------------------------------------------------
48
// Stopp TWI (ohne Interrupt)
49
//------------------------------------------------------------------------
50
void twiStop()
51
{
52
  uint8_t x=TWCR;
53
  x&=_TWEN|_TWIE;    // nur Beibehalten von Enable und InterruptJ/N 
54
  TWCR=x|_TWINT|_TWSTO;
55
}
56
//------------------------------------------------------------------------
57
// Write Byte per TWI (ohne Interrupt)
58
// PE: data = zu sendende Daten
59
//     ackn = wenn !=0 wird Acknowledge (=TWEA) gesetzt
60
//------------------------------------------------------------------------
61
void twiWriteByte(uint8_t data, uint8_t ackn)
62
{
63
  TWDR=data;      // Daten bereitlegen
64
  // Befehl zusammenstellen
65
  uint8_t x=TWCR;
66
  x&=_TWEN|_TWIE;      //nur Beibehalten von Enable und InterruptJ/N 
67
  x|=_TWINT;
68
  if(ackn)   
69
    x|=_TWEA;   // evt. TWEA setzen, für Datenanforderung
70
  TWCR=x;         // senden
71
  // warten bis fertig
72
  while( !(TWCR & _TWINT))
73
  {}
74
}
75
//------------------------------------------------------------------------
76
// Read Byte per TWI (ohne Interrupt)
77
// PE: ackn = wenn !=0 wird Acknowledge (=TWEA) gesetzt
78
// PA: Data
79
//------------------------------------------------------------------------
80
int twiReadByte(uint8_t ackn)
81
{
82
  // Befehl zusammenstellen
83
  uint8_t x=TWCR;
84
  x&=_TWEN|_TWIE;      //nur Beibehalten von Enable und InterruptJ/N 
85
  x|=_TWINT;
86
  if(ackn)   
87
    x|=_TWEA;   // evt. TWEA setzen, für Datenanforderung
88
  TWCR=x;         // senden
89
  // warten bis fertig
90
  while( !(TWCR & _TWINT))
91
  {}
92
  return TWDR;
93
}
94
95
//-------------------------------------------------------------------------
96
// rtcGetRtcData
97
//-------------------------------------------------------------------------
98
uint8_t rtcGetRtcData(uint8_t Register)
99
{
100
  // Adresse senden   
101
  twiStart();
102
  twiWriteByte(twiAdr,0);
103
  twiWriteByte(Register,1);
104
  // Daten lesen
105
  twiStart();
106
  twiWriteByte(twiAdr+1,1);
107
  uint8_t b = (uint8_t)twiReadByte(0);
108
  twiStop();
109
  return b;
110
}
111
//-------------------------------------------------------------------------
112
// rtcGetSeconds
113
//-------------------------------------------------------------------------
114
uint8_t rtcGetSeconds()
115
{
116
  return rtcGetRtcData(0) & 0x7F;
117
}
118
//-------------------------------------------------------------------------
119
// rtcGetMinute
120
//-------------------------------------------------------------------------
121
uint8_t rtcGetMinute()
122
{
123
  return rtcGetRtcData(1);
124
}
125
//-------------------------------------------------------------------------
126
// rtcGetHour
127
//-------------------------------------------------------------------------
128
uint8_t rtcGetHour()
129
{
130
  return rtcGetRtcData(2) & 0x3F;
131
}
132
//-------------------------------------------------------------------------
133
// rtcWaitMs
134
//-------------------------------------------------------------------------
135
void rtcWaitMs(int miliSec)
136
{
137
  _delay_loop_2( 1*(F_CPU/(1000/4)) * miliSec);   // 4 Zyklen warteschleife
138
}
139
140
//--------------------------------------------------------------------
141
// myWait_ms - Warte-Routine für x-Millisekunden (0-255)
142
// ein Millisekundenzyklus dauert 1,052 ms
143
// PE: Anzahl der zu wartenden Milisekunden
144
//--------------------------------------------------------------------
145
void myWait_ms(uint8_t dauer_ms)
146
{
147
  __asm__ volatile (
148
    "myWait_ms_0%=:\n"
149
    "push   %0\n"
150
    "ldi   %0,1\n"
151
    "myWait_ms_3%=:\n"
152
    "push   %0\n"
153
    "ldi   %0,5\n"
154
    "myWait_ms_2%=:\n"
155
    "push   %0\n"
156
    "ldi   %0,255\n"
157
    "myWait_ms_1%=:\n"
158
    "dec   %0   \n"
159
    "brne   myWait_ms_1%=\n"
160
    "pop   %0   ; Register wiederherstellen\n"
161
    "dec   %0   \n"
162
    "brne   myWait_ms_2%=\n"
163
    "pop   %0   ; Register wiederherstellen\n"
164
    "dec   %0   \n"
165
    "brne   myWait_ms_3%=\n"
166
    "pop   %0   ; Register wiederherstellen\n"
167
    "dec   %0   \n"
168
    "brne   myWait_ms_0%=\n"
169
    :
170
    :"d" (dauer_ms)
171
    );
172
}
173
174
//---------------------------------------------------------------------------
175
void waitMs(int miliSec)
176
{
177
  _delay_loop_2( 1*(F_CPU/(1000/4)) * miliSec);   // 4 Zyklen warteschleife
178
}
179
180
//------------------------------------------------------------------------
181
// Initialisierungen
182
//------------------------------------------------------------------------
183
void init()
184
{
185
  twiInitMaster(twiAdr);
186
}
187
188
//------------------------------------------------------------------------
189
// Zahlensystem-Wandler
190
//------------------------------------------------------------------------
191
192
int dectobcd(int dec)
193
{
194
  int BCD;
195
  BCD = (((dec / 10) * 16) + (dec % 10));
196
  return BCD;
197
}
198
199
int bcdtodec(int BCD)
200
{
201
  int dec;
202
  dec = ((((BCD >> 4)&0b111)*10)+(BCD&0b1111));
203
  return dec;
204
}
205
206
//------------------------------------------------------------------------
207
// Einstellung der Zeit
208
//------------------------------------------------------------------------
209
210
void define_time(int stunde, int minute, int sekunde)
211
{
212
  twiStart();
213
  twiWriteByte(twiAdr,0);
214
  twiWriteByte(0,1);
215
  sekunde = dectobcd(sekunde);
216
  twiWriteByte(sekunde,1);
217
  minute = dectobcd(minute);
218
  twiWriteByte(minute,1);
219
  stunde = dectobcd(stunde);
220
  twiWriteByte(stunde,1);
221
  twiStop();
222
}
223
224
//------------------------------------------------------------------------
225
// Ein/Ausschalten des Relais
226
//------------------------------------------------------------------------
227
228
int switcher(int stunde_on, int stunde_off)
229
{
230
  int stunde = 0;
231
  stunde = rtcGetHour();
232
  stunde = bcdtodec(stunde);
233
  if ((stunde>=stunde_on) && (stunde<stunde_off))
234
  {
235
    PORTC = 0x08;
236
  }
237
  else
238
  {
239
    PORTC = 0x00;
240
  }
241
}
242
243
/////////////////////////////////////////////////////////////////////////////
244
// Main-Funktion
245
/////////////////////////////////////////////////////////////////////////////
246
main()
247
{
248
  //Variablen-Initialisierung
249
  int zeit1,zeit2;
250
251
  init();               // Initialisierungen
252
253
  //Zur Zeiteinstellung Kommentare entfernen!
254
  /*zeit1 = rtcGetHour();
255
  zeit2 = rtcGetMinute();
256
257
  
258
  if ((zeit1==0)&&(zeit2==0))
259
  {
260
    define_time(8,19,31);          
261
  }*/
262
  
263
  // Alternativ: direkte Überschreibung
264
  // define_time(10,10,15);
265
  
266
  DDRC = 0x08;
267
268
  while (true)              // Mainloop-Begin
269
  {
270
    switcher(11,13);
271
    _delay_ms(1000);
272
  }

Das ganze wurde zunächst mit dem Code-Wizard von myAVR erstellt, da ich 
die gleichen Bauteile der AVR-Boards verwendet habe.

Weiß jemand Rat?

Grüße

von Karl H. (kbuchegg)


Lesenswert?

> Ich vermute, dass der µC sich aufhängt.

Wär möglich.
Relais-Spulen können schon ordentlich Schmutz auf den 
Versorgungsspannungen erzeugen, wenn sie schalten.



Hast du ein Anzeigeelement, wie zb in LCD im System?
Dann könntest du dir dort laufend Ausgaben machen und zb auch die 
Uhrzeit von der RTC ausgeben lassen, dann würde man schon mehr sehen.

Wenn nicht, dann hilft es auch, sich eine LED an einen Port zu verkabeln 
und die in der Hauptschleife blinken zu lassen. Wenn das Blinken 
aufhört, dann ist der µC höchst wahrscheinlich abgeschmiert.
Aber um ehrlich zu sein würde ich mir als allererstes in ein neues 
Projekt eine Möglichkeit für Ausgaben einbauen. UART ist gut, LCD ist 
meistens besser. Ohne eine Chance sich auch mal Variablenwerte life und 
in Farbe direkt am Objekt ansehen zu können, ist alles andere immer ein 
Stochern im Nebel.

von Anon Y. (anonymous)


Lesenswert?

Hallo  AtroCty,

mir gefallen deine delays nicht. Verwende doch die eingebauten 
Funktionien.

Ich habe in meinem Code in grauer Vorzeit die i2c Funktionien 
umgeschrieben. Der Code blockt nämlich für immer, wenn etwas bei der i2c 
Kommunikation nicht stimmt. D.h. alle while(!blahh); habe ich ersetzt 
durch
while{!blahhh){
if(!timeout--) break;
}

Der Sinn ist ein ungenaues timeout (weil abhängig von der 
Ausführungszeit der Schleife). Wenn die entsprechend vorinitialisierte 
Variable abgelaufen ist wird im Code weiter gemacht. Das hat sich als 
sehr sinnvoll erwiesen, weil manchmal einfach i2c Nachrichten verloren 
gehen / sinnlose states angenommen werden.

von AtroCty (Gast)


Lesenswert?

@Buchegger:

Beim Relais habe ich eine Freilaufdiode verbaut, der sollte diese 
Schmutzspannungen eigentlich abfangen...

Nein, ich habe kein LCD verbaut, und ja, es ist leider ein "stochern", 
weil dies eigentlich nur eine simple Funktion bieten sollte ohne weitere 
Modifikationen.

@Anon Ymous:

Wie genau würde der Code dann oben aussehen?
Ich weiß leider nicht genau wie du das meinst...

von Karl H. (kbuchegg)


Lesenswert?

Du hast zb hier
1
int twiReadByte(uint8_t ackn)
2
{
3
  // Befehl zusammenstellen
4
  uint8_t x=TWCR;
5
  x&=_TWEN|_TWIE;      //nur Beibehalten von Enable und InterruptJ/N 
6
  x|=_TWINT;
7
  if(ackn)   
8
    x|=_TWEA;   // evt. TWEA setzen, für Datenanforderung
9
  TWCR=x;         // senden
10
  // warten bis fertig
11
  while( !(TWCR & _TWINT))
12
  {}
13
  return TWDR;
14
}

mit dem while eine potentielle Endlosschleife, wenn aus irgendeinem 
Grund _TWINT nicht so tut, wie es soll.

Ich kenn jetzt das Timing nicht, aber man kann mit Sicherheit ein 
zeitliche Obergrende festlegen, nach der diese Schleife und damir der 
Read als gescheitert zu betrachten ist (jetzt mal unabhängig von der 
Ursache warum das so ist). Ich sach jetzt einfach mal als Hausnummer: 
wenn sich nach 100 Millisekunden da noch nichts getan hat, dann ist da 
was schief gelaufen.
Also macht man sich eine Beschränkung rein, die diese Schleife auf jeden 
Fall nach 100ms abwürgt.
1
int twiReadByte(uint8_t ackn)
2
{
3
  // Befehl zusammenstellen
4
  uint8_t x=TWCR;
5
  x&=_TWEN|_TWIE;      //nur Beibehalten von Enable und InterruptJ/N 
6
  x|=_TWINT;
7
  if(ackn)   
8
    x|=_TWEA;   // evt. TWEA setzen, für Datenanforderung
9
  TWCR=x;         // senden
10
 
11
 // warten bis fertig
12
  uint8_t timeout = 100;
13
  while( !(TWCR & _TWINT) && timeout > 0)
14
  {
15
    _delay_ms( 1 );
16
  }
17
18
  // warum gings aus der Schleife raus. Hat es etwa zu lange
19
  // gedauert?
20
  if( timeout == 0 )
21
    return 0;
22
23
  // Nö. Alles ok. TWDR enthält das Ergebnis
24
  return TWDR;
25
}
wie du dann weiter mit dem Fehlerfall umgehst, das musst du selbst 
entscheiden. Sicherheitshalber solltest du ihn aber auf jeden Fall 
melden! Zb. in dem eine LED an geht!

> weil dies eigentlich nur eine simple Funktion bieten sollte ohne weitere

Es ist NIE einfach nur 'simpel'. Sobald man reale Projekte machen will, 
abseits vom Übungstisch, kommt man um eine Ausgabemöglichkeit nicht rum. 
In einfachsten Fall sind das ein paar LED, dann braucht man aber immer 
noch Phantasie um sich zu überlegen, wie man die jetzt sinnvoll 
einsetzen kann um sich besondere Zustände anzeigen zu lassen. Oder aber 
im einfachsten Fall eine UART oder ein LCD. Eine UART kann man fast 
immer nachrüsten, sofern die Pins frei sind. Das muss ja nicht schön 
sein - es muss zweckmässig sein. 2 fliegend verlötete Drähte auf eine 
kleine Hilfsplatine mit einem MAX232 (oder einem FT232) und von dort 
weiter zum PC und schon ist man im Geschäft.

Und im übrigen:
Wie stellst du eigentlich die Schaltzeiten ein? Wie handhabst du die 
Sommer/Winterzeit Umstellung. Was machst du, wenn bei der RTC mal die 
Batterie leer ist?

von AtroCty (Gast)


Lesenswert?

Sollte ich den timeout nicht dekrementieren, wie Ano Nymus gesagt hatte?

Schaltzeiten etc. sind egal, ebenso wenn Batterie leer ist.

von Karl H. (kbuchegg)


Lesenswert?

AtroCty schrieb:
> Sollte ich den timeout nicht dekrementieren, wie Ano Nymus gesagt hatte?

Ja, natürlich.
Bitte schreib das dem Umstand zu, dass ich den Code hier direkt 
eintippe.

von AtroCty (Gast)


Lesenswert?

An welcher Stelle sollte ich dies denn am besten tun?
 Sollte ich den timeout nicht auch zurücksetzen?

von Karl H. (kbuchegg)


Lesenswert?

1
 // warten bis fertig
2
  uint8_t timeout = 100;
3
  while( !(TWCR & _TWINT) && timeout-- > 0)
4
  {
5
    _delay_ms( 1 );
6
  }

und kauf dir ein C-Buch.
Das ist ja furchtbar. Mit Code zusammenkopieren wirst du nicht weit 
kommen.

von AtroCty (Gast)


Lesenswert?

Ich besitze eins, bin mir nur im unklaren im Zusammenhang mit 
Mikrokontrollern, da ich bisher nur reine Anwendungsentwicklung gemacht 
habe.

von MaWin (Gast)


Lesenswert?

> und kauf dir ein C-Buch.
> Das ist ja furchtbar. Mit Code zusammenkopieren wirst du nicht weit
> kommen.

Was bitte gefällt dir an dem Code nicht ?
Daß er nicht wie dein BASCOM aussieht ?

von AtroCty (Gast)


Lesenswert?

Ich kann so den Zusammenhang dieser Schleife mit der Arbeitsprozedur des 
µC nicht wirklich erkennen. Ich weiß gerade nicht wirklich, was diese 
Schleifenabhängigkeit des timeouts bewirkt.

von AtroCty (Gast)


Lesenswert?

Und zusammenkopiert ist es nicht wirklich, das meiste des Codes kommt 
aus eigener Hand bis auf die Teile des twi's, die sind vom CodeWizard 
vorgegeben. Und da es genau an dem Teil anscheinend hapert würde ich 
schon eine Erklärung bevorzugen, da ich schon gerne die Funktionsweise 
erkennen können würde, jedoch ist mir die Arbeitsweise des µC noch ein 
wenig schleierhaft...

von Karl H. (kbuchegg)


Lesenswert?

MaWin schrieb:
>> und kauf dir ein C-Buch.
>> Das ist ja furchtbar. Mit Code zusammenkopieren wirst du nicht weit
>> kommen.
>
> Was bitte gefällt dir an dem Code nicht ?
> Daß er nicht wie dein BASCOM aussieht ?

Ich verwende kein BASCOM.
UNd mit 'furchtbar' war eigentlich gemeint, dass man in einem Vorschlag, 
der sich über 3 Zeilen Code hinzieht nicht selbst die Stelle findet, an 
der man ein -- einfügen kann bzw. muss, um eine bereits vorgegebene 
Funktionalität (Timeout einer potentiellen Endlosschleife) zu 
realisieren.

von AtroCty (Gast)


Lesenswert?

Ich verstehe die Wirkungsweise dieses timeouts einfach nicht. Wenn ich 
an einer Stelle den Timer wieder resete würde mir das einleuchten, denn 
da ist die Position der Dekrementierung klar.

€DIT: Ich könnt mich selber für meine Blödheit schlagen g
Hatte das einfach nicht gerallt, dass das damit einfahc verhindert wird, 
dass die Schleife aufhören soll zu wirken sobald er keine Daten 
empfängt.

So ergibt das natürlich wieder Sinn. Ist einfach zu heiß hier in der 
Werkstatt ;)

von AtroCty (Gast)


Lesenswert?

kleines Update: Ich habe jetzt eine LED's an einem Ausgang verbaut, 
diese soll bei einem Fehler an dieser Stelle aufleuchten. Jedoch 
leuchtet die LED nicht, noch hat der µC seine gewünschte Funktionsweise 
konstant. (nach 30 Minuten hing er sich auf, die Zeit blieb auf dem 
Display stehen, das Relais blieb geschaltet.)

von Karl H. (kbuchegg)


Lesenswert?

Dann würde ich an deiner Stelle zum Testen jetzt erst mal das Relais 
weglassen :-)

von AtroCty (Gast)


Lesenswert?

Schon getan, liegt am µC.

von AtroCty (Gast)


Lesenswert?

Der µC schaltet ja nur einen Transistor, nicht das Relais direkt, weil 
das der µC nicht aushalten würde.

von Michael A. (Gast)


Lesenswert?

AtroCty schrieb:
> Der µC schaltet ja nur einen Transistor, nicht das Relais direkt, weil
> das der µC nicht aushalten würde.

Und was ändert das? Wenn das Relais auf der Versorgungsspannung rumsaut, 
ist das ganz egal, ob in der Ansteuerung noch ein Transistor sitzt.

Wie sieht es denn mit Abblockkondensatoren auf VCC bei µC und 
Relais/Diode aus?

von AtroCty (Gast)


Lesenswert?

Sind vorhanden, aber wie gesagt, ich habe es bereits auch mit einer 
externen Platine ohne Relais getestet mit gleichem Ergebnis.

Kann vom aktuellem Netz keine Bilder hochladen, aber ja, 
Stützkondensatoren sind vorhanden für die IC's (µC & TWI), sowie 
Freilaufdiode für das Relais. Spannung wird aus einem DC-DC-Wandler 
bezogen.

von AtroCty (Gast)


Lesenswert?

!Bump!

Bin mittlerweile echt ratlos, da der Fehler wohl definitiv am Code/µC 
aufzufinden ist...

Was ist denn an den delay-Funktionen auszusetzen?

Ebenfalls kann ich am Code keine Stelle feststellen, die den Speicher 
overflown... Würde es an den Spannungen liegen würde der µC abstürzen 
und nicht stehen bleiben.

von AtroCty (Gast)


Lesenswert?

Nochmal !BUMP!

bin gerade wieder dabei mich daran zu setzen, doch mir gehen die Ideen 
aus...

von AtroCty (Gast)


Lesenswert?

Haben das Problem endlich gelöst: Die Fuse-Bits waren nicht richtig 
eingestellt.

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.