Forum: Compiler & IDEs Tasterabfrage


von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich wollte mich wieder zu dem leidigen Thema Taster melden. Und zwar 
wäre es mein Endziel meine Feuchtemesserschaltung mit einem Taster in 
den Power-Down Modus zu befördern. Ich habe jetzt aber erst mal ein 
kleines Programm für mich etwas "angepasst". Ich habe versucht möglichst 
viele Kommentare einzubringen, damit man meinen Gedankengang sieht. Ich 
bin ja wie hier schon paar Mal erwähnt totaler Anfänger bei der 
C-Programmierung. Als Controller verwende ich den ATTINY24V.
Um die ganze Sache zu entprellen habe ich mit Delay gearbeitet. Ich 
könnte mir vorstellen, dass ich das Unterprogramm taster_abfrage genauso 
auch in mein eigentliches Programm übernehmen kann. Unterschiede werden 
wohl nur im Main auftauchen, da ich ja keine Lämpchen ausschalten will 
sondern den ATTINY. Die ISR wird sich dann ja wohl nach dem Main 
wiederfinden. Jetzt aber erst mal zu diesem einfacheren Programm.
Nach meiner Theorie hätte ich ja am Anfang insgesamt 4 mal eine 
if-Abfrage machen können (müssen) damit die Schaltung entprellt ist:

1. wenn Taster gedrückt
2. Wartezeit 40 - 80 ms dass der Zustand stabil ist (Diesen Tip habe ich 
von einem Studienkollegen bekommen mit den 40 ms. Damit spare ich mir 
angeblich eine Entprellung. Zusätzlich könnte ich auch 100nF parallel zu 
meinem Taster schalten wurde mir gesagt)
3. Abfragen ob Taster immer noch gedrückt ist nach der Wartezeit
4. Abfragen ob Taster ausgelassen ist (Die Reaktion soll ja erst nach 
dem Auslassen erfolgen. Sprich solange einer seinen Finger da drauf hat 
passiert gar nichts)
5. wieder eine Wartezeit zur Stabilisierung
6. Abfragen ob Taster immer noch ausgelassen ist

Soetwas mit 4 if-Abfragen scheint mir aber doch zu kompliziert zu sein. 
Keine Ahnung ob mir die while Schleife da weiterhilft, damit es 
einfacher wird!
Dieses Programm funktioniert auch. Wobei der SMD-Taster nicht auf jede 
Aktion reagiert. Da ist die Frage ob das rein mechanisch bedingt ist, 
oder ob das mit meinem Programm und z.B. dem Delay zusammenhängt.
Würde mich über euren Support freuen!

Gruß
Thomas

von Karl H. (kbuchegg)


Lesenswert?

Dein Fehler könnte damit zusammen hängen, dass hier
1
  if(!(PINB & (1 << PINB2)))      // wenn Taster gedr�ckt
2
    {
3
      _delay_ms(80);        // Wartezeit 80ms
4
      if(!(PINB & (1 << PINB2)))  // wenn Taster immer noch gedr�ckt
5
      {
6
        while(!(PINB & (1 << PINB2)))  //solange Taster gedr�ckt (log 0)
7
8
        if(zustand == 1)    // wenn Zustand EIN ausschalten
9
        zustand = 0;

nach der while Schleife ein ; fehlt

1
  if(!(PINB & (1 << PINB2)))      // wenn Taster gedr�ckt
2
    {
3
      _delay_ms(80);        // Wartezeit 80ms
4
      if(!(PINB & (1 << PINB2)))  // wenn Taster immer noch gedr�ckt
5
      {
6
        while(!(PINB & (1 << PINB2)))  //solange Taster gedr�ckt (log 0)
7
          ;                            // MACHE NICHTS
8
9
        if(zustand == 1)    // wenn Zustand EIN ausschalten
10
        zustand = 0;

von Bastler (Gast)


Lesenswert?

Danke! Ja das schaut schon mal viel besser aus. Hältst du den 
Kondensator parallel zum Taster für sinnvoll? Eigentlich sieht mir ja 
die Gesamtstruktur des ganzen relativ kompliziert aus mit den 
if-Abfragen.

Gruß
Thomas

von Karl H. (kbuchegg)


Lesenswert?

Bastler schrieb:
> Danke! Ja das schaut schon mal viel besser aus. Hältst du den
> Kondensator parallel zum Taster für sinnvoll?

Nein.

> Eigentlich sieht mir ja
> die Gesamtstruktur des ganzen relativ kompliziert aus mit den
> if-Abfragen.

Wenn du das kompliziert nennst, dann warte mal ab, bis du anfängst 
richtige Programme zu schreiben. :-)

Und arbeite an deiner Code-Formatierung.
Die hat einen Zweck und sollte daher immer und überall gleich sein.

Es ist nicht akzeptabel, wenn du die öffnende { eines Blocks einmal um 2 
Zeichen einrückst und ein ander mal nicht. Wobei du dich fagen solltest, 
welchen Zweck es hat, die { einzurücken um dann gleich nocheinmal den 
Teil der innerhalb des Blockes steht ebenfalls um 2 Zeichen einzurücken.

Auch die Einrückung hat einen Zweck, wenn du das nicht konsequent 
durchziehst, führst du den Zweck ad absurdum. Zweck einer Einrückung ist 
es anzuzeigen, dass ein Codeteil zb in einer Abhängigkeit zu einem 
anderen Codeteil steht. D.h. Wenn zb bei einem if der then Teil nur aus 
einer Anweisung besteht und du daher keine {} drumherum machst, dann 
wird diese eine Anweisung eingerückt!
1
unsigned char taster_abfrage(void)
2
{
3
  static unsigned char zustand = 0;
4
  unsigned char ret = 2;        // ret auf definierten "undefinierten" Zustand
5
6
  if(!(PINB & (1 << PINB2)))      // wenn Taster gedr�ckt
7
  {
8
    _delay_ms(80);        // Wartezeit 80ms
9
    if(!(PINB & (1 << PINB2)))  // wenn Taster immer noch gedr�ckt
10
    {
11
      while(!(PINB & (1 << PINB2)))  //solange Taster gedr�ckt (log 0)
12
        ;
13
14
      if(zustand == 1)    // wenn Zustand EIN ausschalten
15
        zustand = 0;
16
17
      else          // wenn Zustand AUS einschalten
18
        zustand = 1;      // ret wird zur�ckgegeben
19
20
      ret = zustand;
21
    }
22
  }
23
24
  return ret;
25
}

Über jeder } muss es in der gleichen Codespalte eine { geben. Die { 
steht in derselben Spalte, in der auch die Anweisung beginnt, die den 
Block erzwingt (bei dir das 'i' von 'if'). Nach einer { wird der 
abhängige Codeteil um 2 Zeichen eingerückt. Die schliessende } wird 
wieder um 2 Zeichen ausgerückt und die nächsten Codeteile beginnen dann 
ebenfalls in dieser Spalte.
Wenn sich mit konsequenter Anwendung dieser Regel die schliessende } der 
Funktion nicht in Spalte 1 befindet, dann ist in der Funktion in der { } 
Hierarchie irgendetwas durcheinander gekommen.

von Bastler (Gast)


Lesenswert?

Ich glaube dieses Durcheinander kommt daher weil ich von einem Textfile 
in das AVR Studio eingefügt habe. Ich habe es bis jetzt immer mit Tab 
gemacht. Die zwei Leerzeichen kommen irgendwie durch das *.c oder 
*.txt-File.
Trotzdem nochmal herzlichen Dank für die Erklärung. Ja wie gesagt für 
mich als Anfänger ist das extrem schwer da plötzlich wie ein Profi alles 
zu machen. Daher sieht das kompliziert aus für mich. Würdest du sagen 
ich entprelle die Taste mit dem Delay? Ich habe ja jetzt immer ein 
Warning seit dem ich das mit dem Delay mache:

"F_CPU not defined for <util/delay.h>"

Alternativ würde das ja wohl mit for gehen wo ich ja immer eine 
bestimmte Zeit abwarte. Da könnte ich dann ja wohl den CPU-Takt 
heranziehen dafür. Alternativ wäre ja auch ein Timerinterrupt möglich 
vermute ich. Nur dann wird es wieder sehr kompliziert für mich da ich ja 
ohnehin einen Interrupt benötige um dieses Ding wieder aufzuwecken.
Evt. werde ich nochmal Hilfe in Anspruch nehmen wenn ich das mit dem 
Power-Down umsetzen will. Hatte da schon einmal Probleme weil er nicht 
eingeschlafen ist. Möchte da aber zunächst selber rumprobieren.
Gibt es eigentlich nur beim aufwachen den Interrupt?? Also wird die 
Interruptserviceroutine nur dann aufgerufen wenn ich meinen Externen 
Interrupt durch den Taster erzeuge? Einschlafen wird er wohl rein durch 
den Power-Down Befehl wobei ich nicht vergessen darf die Interrupts zu 
enablen und keine Flankenänderung da es ja keinen Takt mehr gibt. Das 
dürfte wohl so richtig sein?!

Gruß
Th.

von Karl H. (kbuchegg)


Lesenswert?

Bastler schrieb:

> Warning seit dem ich das mit dem Delay mache:
>
> "F_CPU not defined for <util/delay.h>"

Die delay Funktionen arbeiten nach dem Prinzip in einer Schleife solange 
Instruktionen abzuarbeiten, bis die Zeit vergangen ist.
Um die Zeit berechnen zu können, müssen sie daher auch wissen, wie 
schnell dein µC getaktet ist. Denn klarerweise werden 100 Instruktionen 
bei doppelter Taktfrequenz doppelt so schnell abgearbeitet.

das F_CPU Makro macht genau das. Es instruiert die delay Funktionen (und 
andere) darüber wie schnell dein µC getaktet wird.

einfach ganz am Anfang, noch bevor all den Includes

#define F_CPU   4000000   // 4 Mhz

oder welche Taktfrequenz du auch immer hast.

von Bastler (Gast)


Lesenswert?

Hallo

Also das mit dem #define F_CPU    1000000 hab ich gemacht. Mein 
Controller soll ja mit 1 MHz laufen. Allerdings habe ich genau diese 
Zeile wieder entfernt da der Takt durch die Fuses ja ohnehin auf 1 MHz 
festgelegt ist. Er bringt jetzt auch drei Warnings:

1. F_CPU not defined for <util/delay.h>
2. F_CPU redefined
3. this is the location of the previous definition

Wo liegt hier der Fehler?

Gruß
Thomas

von Karl H. (kbuchegg)


Lesenswert?

Bastler schrieb:
> Hallo
>
> Also das mit dem #define F_CPU    1000000 hab ich gemacht. Mein
> Controller soll ja mit 1 MHz laufen. Allerdings habe ich genau diese
> Zeile wieder entfernt da der Takt durch die Fuses ja ohnehin auf 1 MHz
> festgelegt ist.

Falsch.

Das F_CPU stellt nichts an der Hardware ein.
Aber woher soll denn der Compiler wissen, wie schnell dein µC getaktet 
ist? Der kann ja nicht hellsehen.

#define F_CPU 1000000

ist die Information für alle die es wissen wollen, welche Taktfrequenz 
der µC hat.

 Er bringt jetzt auch drei Warnings:
>
> 1. F_CPU not defined for <util/delay.h>
> 2. F_CPU redefined
> 3. this is the location of the previous definition
>
> Wo liegt hier der Fehler?

Reihenfolge!
delay.h will wissen, wie hoch die Taktfrequenz ist. Daher muss die F_CPU 
vor dem delay.h vereinbart werden
1
#define F_CPU 1000000
2
#include <util/delay.h>
3
...

von Bastler (Gast)


Lesenswert?

Ok. Danke. Es funktioniert jetzt auch ohne Warnings.
Kann ich jetzt aus der Tasterabfrage relativ leicht auch eine Power-Down 
Routine entwerfen?
Ich hätte jetzt gesagt dass man dem switch weiter kommen müßte. Nur dass 
man hald bei case Lampe aus irgendwie was reinbringen muss mit:

sei()    //ISR aktivieren
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_mode();

Geht das so in die Richtung?

Gruß
Thomas

von Karl H. (kbuchegg)


Lesenswert?

Bastler schrieb:

> Geht das so in die Richtung?

In den sleep schicken ist nicht das grosse Problem. So wie du das hast 
müsste das schon gehen. Die Frage ist eher: Wodurch wird der µC wieder 
aufgeweckt?

von Bastler (Gast)


Lesenswert?

Wenn ich das bis jetzt so richtig mitbekommen habe erfolgt das Aufwecken 
des Controllers durch eine ISR. Mein Problem ist jetzt nur wie die 
Anordnung ist.
Die ISR ist ja quasi eine eigene Unterfunktion. Nur wie das mit dem case 
gehen soll ist mir noch schleierhaft. Ich versuche jetzt mal was 
zusammenzuschreiben. Habe noch nie eine ISR geschrieben geschweige denn 
den Controller in Power Down geschickt.
Vermute aber mal dass wenn mans einfach macht auch hier nur wenige 
Zeilen fällig sind.

Gruß
Thomas

von Uwe (Gast)


Lesenswert?

Der Taster muss an einem Pin des MC hängen, mit dem man einen externen 
Interrupt auslösen kann (z.B. INT0 oder INT1). Die Interruptroutine 
definierst du einfach in deinem Programm, im Prozedur-Body muss nichts 
drin stehen.

In deinem entsprechenden Case-Zweig schaltest du Interrupt ein, 
definierst und gehst in den entsprechenden Sleep-Modus. Genau da bleibt 
das Programm stehen. Mit dem "Ein-Taster" (am Interrupt-Pin) wird wieder 
aus dem Sleep-Modus gegangen und genau an dieser Programmstelle 
weitergemacht. Wenn du Ein/Aus mit dem gleichen Taster machen möchtest 
musst du noch etwas Logik schreiben, dass der MC nicht gleich wieder 
nach dem Aufwecken einschläft...

Grüße Uwe

von Bastler (Gast)


Lesenswert?

Also hardwaremäßig hängt ein Taster am Pin 5 meines ATTINY 24V. Das 
sollte der INT0-Pin sein. Kann eine LED damit ein und ausschalten. Das 
funktioniert.
Habe ich die Möglichkeit nach dem Aufwachen automatisch einen Reset 
auszulösen? Geht das? Im Moment produziere ich irgendwie nur Fehler. Ich 
habe

set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_mode();

eingebaut aber da meckert er ja auch schon. Außerdem einen Interrupt bei 
pegelwechsel da ja kein Takt im Power-Down Modus. Kann mir da jemand 
helfen wie die Struktur da aussieht?

Gruß
Thomas

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe jetzt versucht einen Code zusammenzustellen für den Power Down. 
Ich habe keine Fehlermeldungen aber ich bezweifle dass dieser Code 
wirklich das tut was er soll. LED geht nach wie vor an und aus. Nur 
glaube ich nicht dass der Controller einschläft und wieder aufwacht.
Könntet ihr mir Tips geben was ich verändern muss.
Danke!

Gruß
Thomas

von Peter D. (peda)


Lesenswert?


von Bastler (Gast)


Lesenswert?

Habe ich mir zunächst angeschaut. Allerdings muss ich sagen dass ich 
hier nicht alles verstehe. Ja ich weiss man soll power-down nicht 
verwenden! Darum habe ich ja erst mit dem sleep_cpu gearbeitet. Die 
Frage ist ja auch ob das innerhalb von dem case funktioniert. Das 
einschalten müßte dann ja irgendwie auf die ISR verweisen. Keine Ahnung 
wie das dann nur von der groben Form dann aussehen könnte. Habe hald 
versucht hier alles logisch zusammenzufassen. Ich weiss auch nicht so 
genau was alles in der ISR stehen muss. Das soll ja möglichst kurz sein.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Ich weiss auch nicht so
> genau was alles in der ISR stehen muss. Das soll ja möglichst kurz sein.

Dann mache das doch. Im Extremfall steht einfach nix in der ISR.

Geschickter ist es in der ISR nach dem Aufwecken den Wecker abzustellen, 
damit irgendwelche im Wachzustand einlaufenden Interrupts keine 
Peozessorzeit fressen. Also heisst das den Weckinterrupt zu disablen, 
bis er das nächste mal gebraucht wird. Das nächste Mal ist in dem Fall 
die Stelle vor dem Schlafenlegen und dann wird der Weckinterrupt wieder 
enabled.

von Bastler (Gast)


Lesenswert?

Das habe ich ja glaube ich gemacht:

ISR ( INT0_vect )    // externer Interrupt 0
{
    GIMSK &= ~(1 << INT0);    // externer Interrupt deaktiviert
  cli();
}

Zunächst der externe Interrupt deaktiviert dann noch die restlichen. 
Müßte mein LED eigentlich erlöschen wenn mein Controller in Power-Down 
ist? Ich denke mal nicht da die LED bei 0 aktiv ist und das ja wohl der 
default-Wert sein dürfte. Also werde ich den Power-Down Zustand nur am 
Stromverbrauch erkennen. Kann mir auch nicht so ganz vorstellen dass es 
so funktioniert. Ich habe jetzt zwar wohl alles in meinem Programm drin 
was man brauchen könnte aber ob die Reihenfolge so wirklich stimmt sei 
dahingestellt!

Gruß
Th.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das ist tatsächlich so lange dahingestellt, wie du nur Codefetzen 
zeigst.

1. Stromverbrauch messen geht, wenn der Rest der unbekannten Schaltung 
das zulässt. Einen Tropfen Wasser in einem Eimer Wasser zu messen ist 
schwer.

Aber es ist trivial eine Debug-LED zu toggeln, wenn ein Ereignis 
auftritt z.B. Schlafmodus oder Wecken. Eine LED muss auch nicht 
Active-Low betrieben werden. Im Sinn deines stromsparenden Gerätes sind 
Active-Low angeschlossene LEDs eher kontraproduktiv.

2. Das cli() in der ISR ist mindestens überflüssig und u.U. fehlerhaft.

Es fehlt:

3. Wie und wo wird der INT0 eingestellt? Flanke oder Level? Welcher 
Level? Wird eine eventuell noch anstehende INT0 Bedingung gelöscht 
(GIFR)?

4. Ist im Programm ein sei() enthalten und wo?

5. Wie ist die Hardware am INT0-Pin angeschlossen? Was hält den HIGH 
Pegel (nicht aufwachen)? Der interne Pullup dieses Pins? Wo wird der 
geschaltet/initialisiert?

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Ok dann zeige ich hier nochmal meinen Code. Mir ist klar dass die Sache 
so nicht funktionieren kann. Alleine schon die Reihenfolge geht wohl 
nicht. Ich habe meine LED auf Active-High umgebaut. Es ist also im 
Moment nur der Controller mit dementsprechender 3 V Spannungsversorgung, 
Schnittstelle und eine LED angeschlossen. Ja ok natürlich noch der 
zukünftige Power-Down Taster. Der Taster ist an Pin3 gegen GND 
angeschlossen (also INT0).
Ich hoffe diese Infos sind ausreichend.

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Sieht doch schon gut aus. Ich schlage zwei Änderungen vor:

1. Synchronisiere den Zustand vom EIN/AUS Taster mit dem Wecktaster

2. Schau dir die Makros von 
http://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html an
1
#include <avr/io.h>
2
#include <stdint.h>
3
#define F_CPU   1000000
4
#include <util/delay.h>
5
#include <avr/sleep.h>
6
#include <avr/interrupt.h>
7
8
#define UNDEF 2
9
#define EIN 1
10
#define AUS 0
11
12
#define LED_EIN() (PORTB |= (1 << PB1))   // Port B1 auf 1 - LED leuchtet
13
#define LED_AUS() (PORTB &= ~(1 << PB1))  // Port B1 auf 0 - LED erlischt
14
15
// EIN/AUS Taster muss später auf WECKTASTER synchronisiert werden
16
// daher zustand als globale Variable verwenden.
17
unsigned char zustand = EIN; // AVR rennt zunächst
18
19
20
ISR ( INT0_vect )    // externer Interrupt 0
21
{
22
  GIMSK &= ~(1 << INT0);    // externer Interrupt deaktiviert
23
}
24
25
26
unsigned char taster_abfrage(void)
27
{
28
  if(!(PINB & (1 << PINB2)))    // wenn Taster gedrückt
29
  {
30
    _delay_ms(80);              // Wartezeit 80ms 
31
    if(!(PINB & (1 << PINB2)))  // wenn Taster immer noch gedrückt
32
    {
33
      // warten solange Taster gedrückt ist (log 0)
34
      while(!(PINB & (1 << PINB2)));  
35
36
      // Taster losgelassen
37
      if(zustand == EIN)
38
        zustand = AUS;
39
      else              
40
        zustand = EIN;    
41
    }
42
  } 
43
  return zustand;
44
}
45
46
47
int main(void)
48
{
49
  DDRB |= (1 << PB1);   // LED von Portpin auf GND; Ausgang
50
  DDRB &= ~(1 << PB2);  // Bit löschen; damit PB2 Eingang
51
  PORTB |= (1 << PB2);  // Taster an PB2 mit internem Pull-up (auf GND)
52
53
  // Debuganzeige: AVR rennt
54
  LED_EIN();
55
56
  while(1)
57
  {
58
    unsigned char schalter;  
59
60
    schalter = taster_abfrage();
61
    switch(schalter)
62
    {
63
      case EIN:
64
        LED_EIN();
65
        break;
66
      case AUS:
67
        // Debuganzeige: AVR pennt (gleich)
68
        LED_AUS();
69
        // Wecker stellen
70
        GIMSK |= (1<<INT0);    // Externer Interrupt enabled
71
        // Noch anstehende INT0 löschen (durch 1 schreiben)
72
        GIFR |= (1<<INTF0);
73
        // Schlafmodus vorbereiten und ausführen
74
        set_sleep_mode(SLEEP_MODE_PWR_DOWN); 
75
        sleep_enable();
76
        sei();
77
        sleep_cpu();
78
        // Hier geht es nach dem Aufwecken weiter
79
        zustand = EIN; // EIN/AUS Taster auf WECKTASTER synchronisieren
80
        sleep_disable();
81
        break;
82
      case UNDEF:
83
      default:
84
        break;
85
    }
86
  }      
87
88
  return 0;  
89
}
90
/* EOF */

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Die Manipulation von zustand in main() ist unschön. Deine Idee zustand 
in taster_abfrage() zu kapseln ist schöner. Man könnte beides erreichen, 
wenn man die globale Variable wieder durch die statische ersetzt und 
taster_abfrage() etwas ergänzt...
1
unsigned char taster_abfrage(unsigned char neuer_zustand)
2
{
3
  static unsigned char zustand = EIN; // AVR rennt zunächst
4
5
  if (neuer_zustand == UNDEF)
6
  {
7
    // Originalcode von oben
8
  }
9
  else
10
    zustand = neuer_zustand; // Synchronisieren
11
12
  return zustand;
13
}


Und in main() dann
1
     schalter = taster_abfrage(UNDEF);
2
        ...
3
        // EIN/AUS Taster auf WECKTASTER synchronisieren
4
        taster_abfrage(EIN);

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Stefan B. schrieb:

>
1
>         // Wecker stellen
2
>         GIMSK |= (1<<INT0);    // Externer Interrupt enabled
3
>         // Noch anstehende INT0 löschen (durch 1 schreiben)
4
>         GIFR |= (1<<INTF0);
5
>

Wenn du testest dann so:
1
         // Wecker stellen
2
         // Noch anstehende INT0 löschen (durch 1 schreiben)
3
         GIFR |= (1<<INTF0);
4
         GIMSK |= (1<<INT0);    // Externer Interrupt enabled

Das verhindert ein sofortiges Killen des zu stellenden Weckers bei noch 
anstehenden INT0s (z.B. durch prellendern Wecktaster)

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Zunächst mal Danke für diese Hilfe. Ich habe wieder meinen Code 
angehängt. Ich hoffe dass ich alles so weit richtig übernommen habe. 
Leider funktioniert die Sache immer noch nicht. Ich weiss ehrlich gesagt 
nicht wo das Problem liegt. Es hat schon funktioniert. Man spürt den 
Power-Down ja nur durchs Amperemeter. Im Power-Down Zustand war der 
Stromverbrauch aber immer noch bei 1mA!!!!! Das ist enorm viel wenn das 
denn stimmt!

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Du hast Teile anders übernommen als ich beabsichtigt habe:
1
#include <avr/io.h>
2
#include <stdint.h>
3
#define F_CPU   1000000
4
#include <util/delay.h>
5
#include <avr/sleep.h>
6
#include <avr/interrupt.h>
7
8
#define UNDEF 2
9
#define EIN 1
10
#define AUS 0
11
12
#define LED_EIN() (PORTB |= (1<<PB1))    // Port B1 auf 1 - LED leuchtet
13
#define LED_AUS() (PORTB &= ~(1<<PB1))  // Port B1 auf 0 - LED erlischt
14
15
ISR(INT0_vect)    // externer Interrupt 0
16
{
17
  GIMSK &= ~(1<<INT0);    // externer Interrupt deaktiviert
18
}
19
20
unsigned char taster_abfrage(unsigned char neuer_zustand)
21
{
22
  static unsigned char zustand = EIN;
23
24
  if(neuer_zustand == UNDEF)
25
  {
26
    if(!(PINB & (1 << PINB2)))    // wenn Taster gedrückt
27
    {
28
      _delay_ms(80);              // Wartezeit 80ms
29
      if(!(PINB & (1 << PINB2)))  // wenn Taster immer noch gedrückt
30
      {
31
        while(!(PINB & (1 << PINB2)));  //solange Taster gedrückt (log 0)
32
33
        if(zustand == EIN)        // wenn Zustand EIN ausschalten
34
          zustand = AUS;
35
        else                      // wenn Zustand AUS einschalten
36
          zustand = EIN;          // ret wird zurückgegeben
37
      }
38
    }
39
  }
40
  else
41
    zustand = neuer_zustand;      // Synchronisieren
42
  return zustand;
43
}
44
45
int main(void)
46
{
47
  DDRB |= (1 << PB1);   // LED von Portpin auf GND; Ausgang
48
  DDRB &= ~(1 << PB2);  // Bit löschen; damit PB2 Eingang
49
  PORTB |= (1 << PB2);  // Taster an PB2 mit internem Pull-up (auf GND)
50
51
  LED_EIN();
52
53
  while(1)
54
  {
55
    unsigned char schalter;
56
57
    schalter = taster_abfrage(UNDEF);
58
    switch(schalter)
59
    {
60
      case EIN:
61
        LED_EIN();
62
        break;
63
      case AUS:
64
        LED_AUS();
65
        // Wecker stellen
66
        MCUCR &= ~((1 << ISC01)|(1 << ISC00));  // low level interrupt
67
        GIFR |= (1 << INTF0);  // noch anstehende INT0 löschen
68
        GIMSK |= (1<<INT0);    // Externer Interrupt aktiviert
69
        // Einschlafen
70
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
71
        sleep_enable();
72
        sei();
73
        sleep_cpu();
74
        // Nach Aufwachen geht es an dieser Stelle weiter
75
        sleep_disable();
76
        taster_abfrage(EIN); // Synchronisieren auf Wecktaster
77
        break;
78
      default:
79
        break;
80
    }
81
  }      
82
  return 0;  
83
}

Gut dass du noch eingefügt hast:
>        MCUCR &= ~((1 << ISC01)|(1 << ISC00));  // low level interrupt
Das hatte ich fälschlicherweise zuviel rausgeworfen, als ich die Makros 
reingebracht hatte. Es funktioniert zwar ohne die Zeile (Bits sind per 
default gelöscht), schöner ist es mit der Zeile.

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Ok!
Diese Zeile kann man ja wohl weglassen:

//MCUCR |= (1<<SM1);  // Wahl des Power-down Modes (SM2 = 0)

Das wird ja von

set_sleep_mode(SLEEP_MODE_PWR_DOWN);

übernommen oder?
Ich habe nur das Problem dass er mir nicht immer aufwacht. Beim ersten 
schlafen gehen geht das. Dann nicht mehr. Könnte aber auch an der 
Entprellung liegen. Im Power-Down zieht er jetzt noch 10 µA Strom. Das 
scheint mir eigentlich so weit in Ordnung zu sein oder?
Ich habe den Code auch nochmals verfälscht. Ohne das sei() wo er nach 
dem Aufwachen hinspringen soll ging auch nichts. Aber das macht 
eigentlich wenig Sinn finde ich!
Kann man eigentlich zum Aufwachen einen Reset auslösen automatisch?

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das klingt dann doch verdächtig nach den Problemen, die Peter Dannegger 
in seinem Beitrag "AVR-GCC Power-Down Tutorial" anspricht 
und auch Lösungen dafür anbietet.
1
#include <avr/io.h>
2
#include <stdint.h>
3
#define F_CPU   1000000
4
#include <util/delay.h>
5
#include <avr/sleep.h>
6
#include <avr/interrupt.h>
7
#include <util/atomic.h>   // ####
8
9
...
10
11
int main(void)
12
{
13
  ...
14
15
  LED_EIN();
16
  sei();                   // ####
17
18
  while(1)
19
  {
20
    unsigned char schalter;
21
22
    schalter = taster_abfrage(UNDEF);
23
    switch(schalter)
24
    {
25
      case EIN:
26
        LED_EIN();
27
        break;
28
      case AUS:
29
        LED_AUS();
30
31
        ATOMIC_BLOCK(ATOMIC_FORCEON){                 // = CLI
32
          // Wecker stellen
33
          MCUCR &= ~((1 << ISC01)|(1 << ISC00));  // low level interrupt
34
          // GIFR |= (1 << INTF0);  // noch anstehende INT0 löschen
35
          // Überflüssig. This flag is always cleared when INT0 
36
          // is configured as a level interrupt. (d.h. Zeile MCUCR...)
37
          GIMSK |= (1<<INT0);    // Externer Interrupt aktiviert
38
          // Einschlafen
39
          sleep_enable();
40
          set_sleep_mode(SLEEP_MODE_PWR_DOWN);
41
        }                                             // == SEI
42
        sleep_cpu();
43
44
        // Nach Aufwachen geht es an dieser Stelle weiter
45
        sleep_disable();
46
        taster_abfrage(EIN); // Synchronisieren auf Wecktaster
47
        break;
48
      default:
49
        break;
50
    }
51
  }      
52
  return 0;  
53
}

von Gast (Gast)


Lesenswert?

>Kann man eigentlich zum Aufwachen einen Reset auslösen automatisch?

Ach was!

"Ich suche dringend einen Controller, der folgendes kann. Beim Aufwachen 
soll automatisch ein Reset ausgelöst werden, wobei der Controller 
selbsttätig seine Taktfrequenz verdoppeln und einige Bytes seines 
eigenen Programmspeichers ändern soll. Außerdem soll er während des 
Resets den Tx- mit dem Rx-Pin vom UART hardwaremäßig vertauschen sowie 
an einen zweiten Controller, der sich nur um die Abfrage eines einzigen 
Tasters kümmert, ein Signal schicken. Das Ganze soll unbedingt mehr als 
1000 mal pro Sekunde möglich sein."

So lautet eine richtige Anfängerfrage! ;-)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

@ Thomas
Ich bin vom Schreibtischtäter zum Stromer mutiert. D.h. ich habe gerade 
die Source oben auf mein Pollin-Funk-AVR-Board mit dem Attiny2313 
portiert und an dessen LED und Taster angepasst.

Mit den Hinweisen von Peter funktioniert das Schlafen/Wecken mehrmals 
hintereinander. Ohne ATOMIC_BLOCK(ATOMIC_FORCEON){ } geht es aber auch.

Wenn das bei deinem Aufbau nicht funktioniert, schreibe mal was zum 
Anschluss des Wecktasters - wo bekommt der im inaktiven Zustand (nicht 
gedrückt) den HIGH-Pegel her? Ich habe dafür bei der Initialisierung am 
INT0-Pin den internen Pullup gesetzt (Attiny2313: PORTD |= (1 << PD2);)

von Bastler (Gast)


Lesenswert?

Hallo!!

Also das scheint zu funktionieren. Konnte es jetzt 5 Mal hintereinander 
ein und ausschalten. Danach hat es zwar gestockt aber vielleicht liegt 
das ja an den SMD Tastern. Mich würde jetzt nur noch interessieren was 
dieses Atomic macht. Das habe ich ja auch nicht kappiert wo ichs mir 
angesehen habe.
Der Wecktaster ist an PB2 (INT0) angeschlossen. Ich habe keine Ahnung wo 
der im inaktiven Zustand den HIGH Pegel herbekommt. Ich stelle mir hald 
vor dass der Pull-Up am Eingang für den externen Interrupt aktiv ist. 
Und durchs VCC bekommt der Pin dann High. Wissen tu ich es nicht. Habe 
mit Microcontroller fast nie was zu tun gehabt. Achso lese gerade 
weiter. Du wolltest darauf raus. Also der Pullup ist bei mir aktiviert 
und Pin ist auf Eingang. Dadurch erklärt sich das wohl. Könntest du mir 
nochmals mit paar Kommentaren helfen damit ich das ganze Programm 
nachvollziehen kann.
Der schwierige Teil kommt ohnehin noch. Das war ja jetzt nur ein 
Beispiel um das mal zu testen. Meine eigentliche Schaltung ist ein 
Betauungsmesser den man ein und ausschalten kann. In diese Software muss 
ich das jetzt irgendwie implementieren. Also das mit LED aus und ein 
kann man da ja rauslassen. Da meine LEDs jetzt highactiv sind wird ihnen 
die defaultmäßige 0 nichts mehr anhaben. Also sprich ich brauche meine 
LEDs beim ausschalten nicht extra ausschalten. Da werde ich sicher noch 
Hilfe brauchen!

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Mich würde jetzt nur noch interessieren was
> dieses Atomic macht. Das habe ich ja auch nicht kappiert wo ichs mir
> angesehen habe.

Es sorgt dafür, dass die Anweisungen innerhalb der {} Klammer nicht 
durch Interrupts unterbrochen werden. Das ist wichtig, wenn Register in 
mehreren Einzelschritten manipuliert werden. Beispiel 16-Bit-Register 
oder Register lesen, Bits manipulieren und Register zurückschreiben. 
Ohne den Schutz künnten bei einer Unterbrechung falsche Daten in ein 
Register gelangen und/oder andere unerwünschte Sachen passieren.

Beispiel:

Interrupts seien aktiviert (sei). Der INT0 wird enabled aber das Sleep 
noch nicht. Jetzt tritt ein zufälliger INT0 auf. Die ISR wurde den INT0 
disablen. Dann käme das Sleep... und prompt würde der AVR nicht mehr 
aufwachen, weil der INT0 disabled ist. Möglicherweise ist genau das beim 
2. Durchlauf in 
Beitrag "Re: Tasterabfrage" 
passiert.

Also darf der Code zwischen dem INT0 enable und dem Sleep nicht 
unterbrochen werden! Das stellt die Atomic-Klammer sicher.

> Könntest du mir
> nochmals mit paar Kommentaren helfen damit ich das ganze Programm
> nachvollziehen kann.

Frag konkreter. Im Tutorialschreiben bin ich nicht gut.

> Der schwierige Teil kommt ohnehin noch. Das war ja jetzt nur ein
> Beispiel um das mal zu testen.

So verläuft i.A. Entwicklung. Splitten in Teilaufgaben. Lösen der 
Teilaufgaben und dann Zusammenführen zum Gesamtprojekt.

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Guten Morgen!

Also das mit Atomic scheint mir schon geholfen zu haben. Ich habe jetzt 
mal versucht mein Programm mit der Tasterabfrage in mein eigentliches 
Programm zur Feuchtemessung einzufügen. Außerdem habe ich das Programm 
umgeändert damit die LEDs nicht mehr lowactive sind.

Ich habe jetzt folgende Fehlermeldungen.
stray '\356' in program
und viele Warnings.

Für mein Programm wäre es ja besser wenn das Einschalten einen Reset 
auslösen würde. Das dürfte sogar zwingend notwendig sein, weil alle 
andere Funktionen wohl sonst nicht mehr funktionieren dürften.
Auch die Funktion mit dem Blinken der LEDs funktioniert nicht mehr so 
wie es mal war...
Ob man die while(1) Schleife von Schalter onoff benötigt weiss ich 
ehrlich gesagt auch nicht. Es würde da ja nie mehr wieder rauskommen. 
Nur ohne Schleife weiss ich auch nicht ob das dementsprechend abgedeckt 
wird alles

Gruß
Thomas

von Bastler (Gast)


Lesenswert?

Stop. Fehler gefunden. Ich habe

return zustand;

vergessen. Allerdings macht er jetzt irgendwie gar nichts mehr!!"g" Alle 
LEDs leuchten. Kein Power-Down. Ein Fehler dürfte wohl sein, dass diese 
while(1) Schleife fehlt die im anderen ist.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Es fehlt die {} Klammerung bei dem if-Anweisungsblock, der hier beginnt:
1
  if((trigger % 61)==0)
2
    //LED_EIN();
3
    sei();
4
    unsigned char schalter;

dadurch wird nur eine Anweisung nämlich das sei() ausgeführt, wenn 
(trigger % 61) == 0 erfüllt ist. Das ist bestimmt nicht beabsichtigt.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Die Abfrage if((trigger % 61)==0) würde ich an deiner Stelle auch 
überdenken.

Mit der Abfrage würde die EIN/AUS-Taste nur in knapp 2% der Umläufe von 
trigger ausgeführt (Bedingung ist 5 mal wahr bei 256 Schritten). Das 
wäre mir für eine interaktive Eingabe deutlich zu wenig.

Also in einem ersten Test würde ich dieses if rauswerfen und die Zeilen

    sei();
    unsigned char schalter;

vor das while(1) ziehen.

Logisch betrachtet würde ich die Messaktionen in den case EIN: Fall des 
switch stecken. Dort ist ja die Aktion bei eingeschaltetem Gerät...

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Guten Morgen!

Danke für deine neuen Tips. Du hast wohl recht dass man die Sache mit 
on/off öfter abfragen sollte. Seitdem ich aber das mit dem on/off in 
meinem Code habe funktioniert die Feuchtemessung nicht mehr so ganz. Die 
gelbe LED leuchtet da nur noch ganz schwach.
Ich habe jetzt auch den Aufruf feuchtemessung() in Main unter case EIN 
geschrieben. Das müßte wohl so funktionieren. Ein- und Ausschalten ist 
leider in dieser Schaltung immer noch nicht möglich. Ich mußte ja die 
while(1)-Schleife die ursprünglich auch für mein on/off eingebaut war 
weglassen da ja auch für die feuchtemessung und das mit der Batterie 
eine while(1) Schleife vorgesehen ist. Ebenso wäre es doch auch sinnvoll 
dass mit dem Einschalten ein Reset ausgelöst wird oder? Dann würde er 
alles wieder neu übernehmen.
Bin im Moment in der geringen Zeit die mir fürs Programmieren zur 
Verfügung steht dazu übergegangen zu testen ob nicht auch ein 
kapazitiver Feuchtesensor einzufügen ist. Man kann über die Ladezeit ja 
die Kapazität bestimmen. Da brauche ich ja normal keinen PWM oder so. 
Komparator wird wohl schon reichen. Die Frage ist nur ob das mit meinen 
3V Batteriespannung so einfach geht. Hast du hierbei Erfahrung? Gibt 
auch einen tollen Beitrag hier im Forum zum Thema Kapazitätsbestimmung. 
Da ist auch eine Schaltung dabei. Schwierig dürfte hald sein 0,3 pF pro 
% rel. Feuchte zu messen befürchte ich. Wobei das bei mir ja nicht so 
genau sein muss da ich ja eh nur eine grüne, gelbe und rote LED habe.
Wichtig wäre aber jetzt erstmal dass die Schaltung mit dem 
Betauungssensor funktioniert.

Danke!
Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Seitdem ich aber das mit dem on/off in
> meinem Code habe funktioniert die Feuchtemessung nicht mehr so ganz. Die
> gelbe LED leuchtet da nur noch ganz schwach.
> Ich habe jetzt auch den Aufruf feuchtemessung() in Main unter case EIN
> geschrieben. Das müßte wohl so funktionieren.

Weil du jetzt die feuchtemessung() zu oft aufrufst - jetzt jedesmal 
statt alle 16tes Mal. Dadurch toggelt die LED zu häufig und du siehst 
insgesamt eine dunklere LED.
1
    // ### FRÜHER jedes 16.tes Mal ###
2
    // z.B. jedes 16. Mal      // wenn Trigger ist 16, 32, 48 usw.
3
    //if((trigger % 16) == 0)
4
    //  feuchtemessung();
5
6
    schalter = taster_abfrage(UNDEF);
7
    switch(schalter)
8
    {
9
      case EIN:
10
        feuchtemessung(); // ### JETZT JEDESMAL! ###
11
        //LED_EIN();
12
        break;

Ändere es mal versuchsweise in (hier ist der Block batterieüberwachung() 
auch in den Wachzustand gezogen worden)
1
    schalter = taster_abfrage(UNDEF);
2
    switch(schalter)
3
    {
4
      case EIN:
5
        if(trigger == 0)           // jedes 256.te Mal
6
          batterieueberwachung();
7
        if((trigger % 16) == 0)    // jedes 16.te Mal
8
          feuchtemessung();
9
        break;

> Ein- und Ausschalten ist
> leider in dieser Schaltung immer noch nicht möglich. Ich mußte ja die
> while(1)-Schleife die ursprünglich auch für mein on/off eingebaut war
> weglassen da ja auch für die feuchtemessung und das mit der Batterie
> eine while(1) Schleife vorgesehen ist.

Weil die Feuchtemessung() ausserdem auf das ADC Ergebnis wartet, erwarte 
ich eine gewisse Trägheit bei der Reaktion auf den ein/aus Taster, wenn 
wie in deinem Code jedesmal die Funktion aufgerufen wird. Das sollte 
sich mit obigem Vorschlag mit seltenerem Aufruf deutlich verbessern.

Die jetzt vorhandene while(1) Schleife ist die Hauptarbeitsschleife und 
die kann (und sollte) alle Aufgaben übernehmen: feuchtemessung, 
batteriemessung, ein/aus Abfrage, schlafen/aufwachen und trigger zählen.

trigger zählen kann man später sinnvoll durch einen Timer ersetzen 
(Batteriemessung alle x Stunden, Feuchtemessung alle x Minuten, 
dazwischen pennen und Strom sparen). Wie oft die Feuchte gemessen werden 
muss/soll hängt von deiner Anwendung ab. Wozu verwendest du das 
Messgerät eigentlich?

> Ebenso wäre es doch auch sinnvoll
> dass mit dem Einschalten ein Reset ausgelöst wird oder? Dann würde er
> alles wieder neu übernehmen.

Das ist ja trivial zu lösen: Den Einschalter legst du auf den Resetpin.

Es gibt Anwendungen bei denen man die Initialisierung auf den 
Grundzustand nicht haben will. Beispiele: Es läuft eine Uhr mit und die 
Uhrzeit soll nicht verloren gehen. Es läuft eine 
Mittelwertbildung/Messwertglättung und die soll nicht vorloren gehen...

> Bin im Moment in der geringen Zeit die mir fürs Programmieren zur
> Verfügung steht dazu übergegangen zu testen ob nicht auch ein
> kapazitiver Feuchtesensor einzufügen ist. Man kann über die Ladezeit ja
> die Kapazität bestimmen. Da brauche ich ja normal keinen PWM oder so.
> Komparator wird wohl schon reichen. Die Frage ist nur ob das mit meinen
> 3V Batteriespannung so einfach geht. Hast du hierbei Erfahrung? Gibt
> auch einen tollen Beitrag hier im Forum zum Thema Kapazitätsbestimmung.
> Da ist auch eine Schaltung dabei. Schwierig dürfte hald sein 0,3 pF pro
> % rel. Feuchte zu messen befürchte ich. Wobei das bei mir ja nicht so
> genau sein muss da ich ja eh nur eine grüne, gelbe und rote LED habe.
> Wichtig wäre aber jetzt erstmal dass die Schaltung mit dem
> Betauungssensor funktioniert.

Sorry habe ich keine Erfahrung. Wenn es die Sensoren bei Conrad gibt, 
schreib mal die Artikelnummern dazu. Ich würde mir mindestens die 
Datenblätter mal ansehen. Und wenn du einen Link zu dem Beitrag hast, 
gib den bitte auch an.

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Ja der Tip das alles mit in case Ein einzubauen ist schon mal gut. Das 
mit dem Reset nach dem Einschalten dachte ich hald nur weil ich nicht 
weiss ob du ganzen Werte vor der while(1) Schleife erhalten bleiben. 
Keine Ahnung ob das bei mir nötig ist.
Die Schaltung funktioniert leider immer noch nicht. Speziell die gelbe 
LED ist sehr dunkel. Kann ja auch nicht hardwaremäßig zusammenhängen 
weil es ohne Power Down ja auch ging. Power Down geht leider immer noch 
nicht wieder. Keine Ahnung an welcher Stelle noch etwas falsch ist.
Der kapazitive Sensor ist von der Firma Hygrosens Instruments und heißt 
und heißt KFS140-MSMD (Conrad Art.-Nr.: 156508 - 62). Der Link zu der 
Seite auf der das mit dem kapazitivem Sensor beschrieben ist lautet:

http://elm-chan.org/works/cmc/report.html

Gruß
Th.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Ja der Tip das alles mit in case Ein einzubauen ist schon mal gut. Das
> mit dem Reset nach dem Einschalten dachte ich hald nur weil ich nicht
> weiss ob du ganzen Werte vor der while(1) Schleife erhalten bleiben.
> Keine Ahnung ob das bei mir nötig ist.

Da bleibt nix erhalten. Durch einen RESET fängt das Programm ganz von 
vorne an, d.h. alle globalen Variablen werden auf 0 initialisiert und 
die Ports sind im Zustand nach dem RESET (Eingang, Tristate).

> Die Schaltung funktioniert leider immer noch nicht. Speziell die gelbe
> LED ist sehr dunkel. Kann ja auch nicht hardwaremäßig zusammenhängen
> weil es ohne Power Down ja auch ging. Power Down geht leider immer noch
> nicht wieder. Keine Ahnung an welcher Stelle noch etwas falsch ist.

Ich kenne deine Schaltung nur teilweise. Es wäre hilfreich, wenn du ein 
Schaltbild zeichnest und in den Anhang steckst. Handskizze reicht, muss 
nichts fein ausgetüfteltes sein.

Bei dem Aufbau der Tastersoftware wurde ja die Portinitialisierung 
geändert. Man muss jetzt nachsehen, ob das nach dem Einfügen der 
eigentlichen Messroutinen aus der Messsoftware in das Gesamtprogramm 
Taster+Messsoftware noch passt.

> Der kapazitive Sensor ist von der Firma Hygrosens Instruments und heißt
> und heißt KFS140-MSMD (Conrad Art.-Nr.: 156508 - 62).

Den hast du zur Zeit aber nicht in die Schaltung eingebaut oder? Ich 
glaube es war mal von einem resistiven Betauungssensor die Rede.

Mich würde beim KFS140-MSMD dieser Satz aus dem Datenblatt (und der 
Preis von 26€/Stk.) abschrecken:

"Der Sensor ist nicht für manuelles löten geeignet, da der Sensor mit 
hoher Sicherheit überhitzt und beschädigt wird."

> Der Link zu der
> Seite auf der das mit dem kapazitivem Sensor beschrieben ist lautet:
> http://elm-chan.org/works/cmc/report.html

Das sieht gut aus. Der Messbereich ist für deinen Zweck geeignet.

von Karl H. (kbuchegg)


Lesenswert?

Sollte es hier
1
    else if((messwert > 0x32) && (messwert < 0x70))  //96
2
    {
3
        PORTA |= (1<<PA2);    // gelbe LED toggeln
4
        PORTA &= ~(1<<PA1);    // restl. LEDs aus
5
    PORTA &= ~(1<<PA2);
6
    }

nicht
    PORTA &= ~(1<<PA3);

heissen?
(Jetzt rein aus Symetriegründen und ohne das Programm analysiert zu 
haben)

Du kannst dich vor solchen Kinkerlitzchenfehlern ein wenig besser 
schützen, wenn du dir ein paar #define dafür machst
1
#define LED_ROT   (1<<PA1)
2
#define LED_GELB  (1<<PA2)
3
#define LED_GRUEN (1<<PA3)

dann steht da (und an anderer Stelle ebenso)
1
    else if((messwert > 0x32) && (messwert < 0x70))  //96
2
    {
3
      PORTA |= LED_GELB;
4
      PORTA &= ~LED_ROT;
5
      PORTA &= ~LED_GRUEN;
6
    }

womit die Kommentare überflüssig sind und man leichter sieht, welche 
Funktion die Port-Umschaltung hat bzw. auch was da eigentlich passiert 
und ob man sich beim Copy&Paste vertan hat.

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Ja genau. Das war ein Fehler. Jetzt funktioniert die Messung wieder ganz 
einwandfrei. Jetzt ist nur noch die Frage warum das ein- und ausschalten 
noch nicht so funktioniert. Ich dachte mir jetzt dass ich die LEDs kurz 
vor dem einschlafen nochmal separat deaktivieren muss. Habe euch das im 
Code mitgeschickt. Das hat einmal funktioniert. Dann nicht mehr. Kann 
natürlich auch mechanisch bedingt sein. Ich verwende so SMD Taster. Evt 
hat sich der inzwischen ja schon so abgenutzt?! Oder meine 
Entprellroutine ist nicht so perfekt.
Ebenso ist ja auch die Frage bei den blinkenden LEDs. Ich habe das auch 
mit delay gemacht. Ist sicher nicht so sauber. Gibt es da Störungen 
untereinander?

Stefan:
Das mit dem löten wäre gar kein Problem weil bei mir andere Technologien 
zum Einsatz kommen. Es wird nur im Probeaufbau gelötet dann nicht mehr. 
Du müßtest mir nur noch ausdeutschen warum der in seiner Schaltung 4 
Pins des Controllers benötigt bei diesem Link. Der Sensor ist bei 
Reichelt um ca. 12 Euro erhältlich. Keine Ahnung woher der große 
Unterschied kommt. Im Moment ist der resistive Betauungssensor eingebaut 
und ich bin froh wenn das alles so funktioniert. Die Zugabe wäre die 
Schaltung mit kapazitivem Sensor. In meiner Arbeit ist fürs 
programmieren keine Zeit vorgesehen da es um Technologiethemen geht. 
Daher ist es auch ein Zeitproblem. 3 V meiner Batterie wären also 
ausreichend. Auch der Stromverbrauch würde wohl durch das dauernde laden 
nicht größer sein als mit dem Spannungsteiler bei mir vermute ich mal.
Stromlaufplan im Anhang. Kleiner Fehler dass LED4 an PA7 statt an PB1 
hängt.

Gruß
Thomas

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Hier noch der aktualisierte Code. Ich habe beim einschalfen noch die 
LEDs deaktiviert. Müßte aber wohl vor dem endgültigen einschlafen sein 
denke ich.

Gruß
Th.

von Karl H. (kbuchegg)


Lesenswert?

Bastler schrieb:
> Hier noch der aktualisierte Code. Ich habe beim einschalfen noch die
> LEDs deaktiviert.

Nein, hast du nicht.
Du hast die LEDs deaktiviert, wenn die CPU wieder aufwacht :-)

Die CPU schläft ein, wenn du sleep_cpu() aufrufst. Wenn dieser Aufruf 
zurückkommt, ist die CPU aus dem Schlafen schon wieder aufgewacht.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Hier noch der aktualisierte Code. Ich habe beim einschlafen noch die
> LEDs deaktiviert. Müßte aber wohl vor dem endgültigen einschlafen sein
> denke ich.
1
      case AUS:
2
      {
3
        // Speicher für aktuellen LED Zustand 
4
        unsigned char gerettetes_porta; 
5
6
        // LED Zustand retten 
7
        gerettetes_porta = PORTA;
8
        // Alle LEDs ausschalten
9
        PORTA &= ~(LED_ROT | LED_GELB | LED_GRUEN | LED_BAT);
10
       
11
        ATOMIC_BLOCK(ATOMIC_FORCEON)
12
        {
13
          // "Wecker" stellen
14
          MCUCR &= ~((1<<ISC01)|(1<<ISC00));  // low level interrupt
15
          GIMSK |= (1<<INT0);      // ext. interrrupt aktiviert
16
          
17
          // Einschlafen
18
          sleep_enable();
19
          set_sleep_mode(SLEEP_MODE_PWR_DOWN);
20
        }
21
        sleep_cpu();
22
23
        // Nach Aufwachen geht es an dieser Stelle weiter
24
        sleep_disable();
25
        PORTA = gerettetes_porta; // LEDs wieder ein
26
        taster_abfrage(EIN);  //Synchronisieren auf Wecktaster
27
      }
28
      break;

Obacht mit LED_BAT!

Im Code von batterieueberwachung() hast du die Batterie-LED noch an 
PORTB hängen und in deiner Ausschaltroutine manipulierst du PORTA. 
Kontrolliere das in batterieueberwachung(). Und die DDRA Initialisierung 
auch!

von Bastler (Gast)


Lesenswert?

Hallo!

Ja das sieht jetzt schon besser aus irgendwie. Allerdings habe ich

unsigned char gerettetes_porta;

aus der while(1) Schleife rausgezogen. So funktioniert es ja auch. Sinn 
ist also die Bits von PORTA so wie sie gerade sind in der Variable zu 
sichern. Nur wenn ich sie dann lösche im nächsten Schritt steht dann in 
der Variable nicht 0x00?? Ich habe ja alles auf 0 gesetzt.
Gerät läßt sich jetzt aussschalten.
Kann mir jemand diese Schaltung erklären die oben zur Auswertung des 
kapazitiven Sensors im Anhang ist. Ich brauche da wohl nur bisschen 
umdimensionieren weil ich ja nur 3V Vcc habe oder? Welche Portpins 
brauche ich da von meinem ATTINY24V dafür. Passt ja nicht analog.

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Hallo!
>
> Ja das sieht jetzt schon besser aus irgendwie. Allerdings habe ich
>
> unsigned char gerettetes_porta;
>
> aus der while(1) Schleife rausgezogen. So funktioniert es ja auch. Sinn
> ist also die Bits von PORTA so wie sie gerade sind in der Variable zu
> sichern. Nur wenn ich sie dann lösche im nächsten Schritt steht dann in
> der Variable nicht 0x00?? Ich habe ja alles auf 0 gesetzt.

Nö. Der alte Zustand von PORTA steht in gerettetes_porta und der neue 
Zustand (LEDs aus) wird neu nach PORTA geschrieben. gerettetes_porta ist 
eine eigene Speicherstelle im RAM und wird nicht durch die Zuweisung an 
eine andere Speicherstelle (PORTA) beeinflusst - gerettetes_porta ist ja 
kein Zeiger o.ä.

> Gerät läßt sich jetzt aussschalten.
> Kann mir jemand diese Schaltung erklären die oben zur Auswertung des
> kapazitiven Sensors im Anhang ist. Ich brauche da wohl nur bisschen
> umdimensionieren weil ich ja nur 3V Vcc habe oder? Welche Portpins
> brauche ich da von meinem ATTINY24V dafür. Passt ja nicht analog.

Du meinst http://elm-chan.org/works/cmc/report.html ?

Elm Chan erklärt das doch sehr gut.

Er verwendet AIN0 und AIN1 um Vc mit der halben Versorgungsspannung (0,5 
* 5V) zu vergleichen und dabei wird die Zeit gemessen, bis das von 0 
ansteigende Vc und halbe Versorgungsspannung gleich sind. Die gemessene 
Zeit geht dann in die Formel zur Berechnung von C ein.

Für den Vergleich wird der Analog Comparator des µC benutzt. Auch der 
Attiny24V hat den. Vc geht auf AIN0 (PA1) und die halbe 
Versorgungsspannung auf AIN1 (PA2). Leider hast du da schon LEDs 
geplant. Die LEDs müsstest du an andere Pins hängen, weil du den Analog 
Comparator für die C-Messung brauchst!

Um die Messung genauer zu machen macht Elm Chan zwei Messungen mit 
Vc/Vcc = 0,5 und 0,17. Er stellt über PB2 ein, welche Spannung an AIN1 
reinkommen soll (0,17 * Vcc bzw. 0,5 * Vcc) je nachdem wie PB2 
geschaltet wird: PB2 Tristate Input AIN0 ist 0,5Vcc und PB2 LOW Output 
(=GND) AIN1 ist 0,17Vcc.

Zu der geringeren Vcc bei deinem System fällt mir spontan wenig ein. Die 
Formeln bzw. das Messprinzip sollte auch bei geringerem Vcc 
funktionieren, weil es auf das Verhältnis Vc/Vcc ankommt und weil das 
exakt auf 0,5 bzw. 0,17 eingestellt wird.

Elm Chan benutzt auch noch den Transistor Q1 und sich weiss nicht wie 
sich der mit seinem Basiswiderstand bei Vcc = 3V verhält. Soweit ich 
sehe ist der Q1 aber nur dazu da, um den unbekannten Kondensator ggf. 
mit mehr Saft zu laden, d.h. er spielt eine Rolle bei grossen C, wenn 
das Laden mit R5 zu lange dauern würde. Bei deinem sehr kleinen C im 
hundert pF Bereich kann dieser Schaltungsteil wohl wegfallen.

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Das wäre ja relativ einfach zu realisieren. Habe nochmals versucht die 
Schaltung aufzuzeichnen wie sie bei mir ungefähr aussehen müßte. Durch 
das Durchschalten des Transistors Q1 in der Ursprungsschaltung wird ja 
praktisch nur der Widerstand verkleinert. Dadurch fließt wohl mehr Strom 
in Cx. Folge: Die Ladezeit wird geringer wie du auch schon gesagt hast.
PA1 und PA2 könnte ich relativ Problemlos freimachen. Den Kontakt zum 
Umschalten kann ich ja dann ganz einfach z.B. auf PA3 legen. PA3 ist 
dann ein Eingang. Wenn ich dann 0 anlege verändert sich der 
Spannungsteiler und ich habe für das Spannungsverhältnis 0.169... also 
0,17. Was ist das aber dann für ein Zustand wenn ich das 
Spannungsverhältnis 0,5 benötige? Da müßte der 10k in der Luft hängen.
Welche Möglichkeiten siehst du noch den Stromverbrauch zu reduzieren. 
Ich würde meine Widerstände gerne viel größer machen. Also R7, R8 und 
R9. Habe ja nur eine Batterie (CR2032) mit einer Kapazität von 200mAh 
und der Spannungsteiler zieht ja dauernd Strom egal ob ich im Power Down 
Modus bin oder nicht. Habe mal so bisschen gerechnet. Bei Vcc/2 fließen 
um die 38µA. Da ist aber der Controller noch gar nicht dabei. Das Teil 
würde dann ja maximal ein halbes Jahr oder so intakt sein. Ist das aber 
wohl der Preis den ich dafür zahle dass ich nur so eine "kleine" 
Batterie verwende? Was ist für eine Lebensdauer normal für so Lithium 
Batterien wenn ich irgendein anderes Gerät habe? Es könnte nämlich 
passieren dass die Technologie dazu zwingt dass ein Batterietausch nicht 
mehr möglich ist.
Tut mir leid dass ich mich in diesen Bereichen doch etwas dumm anstelle.

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Was ist das aber dann für ein Zustand wenn ich das
> Spannungsverhältnis 0,5 benötige? Da müßte der 10k in der Luft hängen.

Genau, das müsste er. Geht. Den Pin als Eingang schalten und den 
internen Pullup-Widerstand ausgeschaltet lassen. Dann ist der Pin 
Tristate 
([[http://www.mikrocontroller.net/articles/Ausgangsstufen_Logik-ICs#Tristate]]) 
- so hochohmig, dass man meint der 10k bambelt in der Luft.

> Welche Möglichkeiten siehst du noch den Stromverbrauch zu reduzieren.

Ich würde zweistufig vorgehen. Zunächst die Schaltung so wie sie ist 
aufbauen und testen bzw. die Software entwickeln. Dann optimieren und 
zwar in Hardware und in Software.

> Ich würde meine Widerstände gerne viel größer machen. Also R7, R8 und
> R9. Habe ja nur eine Batterie (CR2032) mit einer Kapazität von 200mAh
> und der Spannungsteiler zieht ja dauernd Strom egal ob ich im Power Down
> Modus bin oder nicht.

Vielleicht kann man auch in Hardware den Spannungsteiler und die 
Versorgung des Sensors von einem Outputpin aus betreiben statt von Vcc 
aus. Diesen Versorgungspin kann man vorm Schlafengehen Tristate oder LOW 
schalten, um den Dauerstrom im externen Schaltungsteil im Schlafzustand 
zu minimieren.

Bei den Anzeige-LEDs forschen, ob es Methoden gibt, die mit weniger als 
deinen 1,5mA zu betreiben, z.B. gepulst statt kontinuierlich 
(http://members.misty.com/don/ledlocu.html#ckt bei deinem System dann 
pulsen per Software).

In Software kommt es enorm darauf an, wie oft die Messungen gemacht 
werden sollen. Nur pro Usereingabe oder auch regelmäßig alle x 
Sekunden/Minuten/Stunden/Tage... Das alles geht in die Energiebilanz 
rein.

Hinweise zum Energiesparen sind ja im Datenblatt angegeben. Abschalten 
was geht... Vielleicht kannst du auch noch in der Taktrate runter gehen. 
Habe auch nicht nachgesehen - ist der attiny24v bereits ein besonders 
energiesparender µC von Atmel oder gibt es geeignetere?

> Habe mal so bisschen gerechnet. Bei Vcc/2 fließen
> um die 38µA. Da ist aber der Controller noch gar nicht dabei. Das Teil
> würde dann ja maximal ein halbes Jahr oder so intakt sein. Ist das aber
> wohl der Preis den ich dafür zahle dass ich nur so eine "kleine"
> Batterie verwende? Was ist für eine Lebensdauer normal für so Lithium
> Batterien wenn ich irgendein anderes Gerät habe?

1-2x im Jahr Batteriewechsel wäre für mich als Anwender OK. Ich habe 
aber auch Uhren u.ä. Geräte, deren vergleichbare Batterie deutlich 
länger als 1 Jahr hält.

> Es könnte nämlich
> passieren dass die Technologie dazu zwingt dass ein Batterietausch nicht
> mehr möglich ist.

Wurde schon überlegt, alternative Energiequellen anzuzapfen? Vielleicht 
geht was mit Solarzelle, Thermolelement? Oder kann ein Akku eingebaut 
werden, der vom Anwender regelmäßig aufgeladen wird? Ist das zumutbar?

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Guten Morgen!

Jetzt habe ich zunächst mal nochmal mit meinem Code ein Problem. Das mit 
der Batterieüberwachung funktioniert jetzt plötzlich nicht mehr. Hat 
aber schon mal funktioniert. Kann mir nur vorstellen dass es irgendwie 
nicht mehr angewählt wird aber keine Ahnung warum. Habe auch mal das 
ganze Blinken auskommentiert. Reicht aber immer noch nicht. Ich wollte 
ja dass wenn die Batterie schwach ist alle 4 Sekunden so ein kurzes 
Flashen zu sehen ist. Habe nur irgendwie das Gefühl dass sich die beiden 
Delays der roten Led und der Bat LED stören. Wo es noch funktioniert hat 
war plötzlich die Geschwindigkeit eine andere. Kann das sein?
Ok. Das mit dem Tristate ist mir jetzt klar.
Ich habe die Bauteile aus meiner aufgezeichneten Schaltung soeben 
bestellt. Allerdings hat mein Attiny nicht mehr genug Pins frei. Naja 
obwohl wenn ich den resistiven Sensor abhänge dann würde es schono 
funktionieren. Dann habe ich genau drei Pins. Wenn ich allerdings einen 
Pin suche an den ich den Spannungsteiler hinhänge wirds schwer. Da 
könnte man aber glaube ich jederzeit einien Pin der ISP Schnittstelle 
verwenden glaube ich.
Bei den LEDs sehe ich keine andere Möglichkeit. Ich verwende bereits 
Low-Power SMD LEDs. 2mA. Da werde ich glaube ich kaum noch günstiger 
fahren. Allerdings dürte das kein Problem sein. Sie leuchten eh nur beim 
einschalten. Die rote blinkt recht schnell und die Bat-LED blinkt nur 
alle 4 Sekunden kurz.
Ich denke meine Taktrate ist mit 1Mhz eh schon relativ gering. Habe da 
wenig Erfahrung muss ich sagen.
Ok also ich denke mit der Batterie die 200mAh Stunden Kapazität besitzt 
sollte das dann doch so weit funktionieren. Weiss jetzt auswendig nicht 
was der Attiny an Strom zieht aber grob überschlagen müßte das für ein 
halbes Jahr reichen. Man kann ja auch noch einen richtigen Onoff 
Schalter einbauen bei Bedarf.
Ein Controllerwechsel wäre aus Zeitgründen völlig unmöglich. Auch an 
sowas hätte ich gedacht. Klappt aber wohl nicht mehr.
Alternative Quellen kommen wohl nicht in Frage. Es soll ja alles winzig 
klein sein. Diese Batterie scheint mir eine der kleinsten Energiequellen 
zu sein die verfügbar sind.
Dann werde ich mich jetzt mal schlau machen wie man mit dem Comparator 
umgeht. Habe ich auch noch nie gemacht geschweige denn gezählt wie lange 
es dauert bis er die andere Spannung erreicht hat. Sind also zwei 
Messungen. Laden bis 0,17 der VCC erreicht und laden bis 0,5 VCC 
erreicht oder? Wird das Ding dann wieder entladen eigentlich?

Gruß
Thomas

von Peter D. (peda)


Lesenswert?

Bastler schrieb:

> Ich habe die Bauteile aus meiner aufgezeichneten Schaltung soeben
> bestellt. Allerdings hat mein Attiny nicht mehr genug Pins frei.

???

Du hast 4 LEDs, 2 Taster, ein Sensor, macht 7 Pins.
Dann sind von den 12 IOs also noch 5 übrig.


Peter

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Jetzt habe ich zunächst mal nochmal mit meinem Code ein Problem. Das mit
> der Batterieüberwachung funktioniert jetzt plötzlich nicht mehr. Hat
> aber schon mal funktioniert. Kann mir nur vorstellen dass es irgendwie
> nicht mehr angewählt wird aber keine Ahnung warum.

Ich hatte schon geschrieben, dass die Batterie-LED am falschen Port 
hängt. Schaltplan und Code passen nicht zusammen.

Was anderes zu der Batteriegeschichte... Die LEDs haben bestimmte 
Durchflussspannungen und zwar unterschiedliche je nach Farbe 
(Halbleitermaterial). Wenn deine Batteriespannung mit der Zeit sinkt, 
ist irgendwann kein Betrieb der LEDs mehr möglich; sie leuchten einfach 
nicht mehr, weil die Durchflussspannung unterschritten ist bzw. der 
Strom nicht mehr ausreicht (Remember (I_led = 
(U_batt-U_led)/Vorwiderstand). Vielleicht hast du Glück und die CR2032 
hat eine flache Entladungskurve so dass (Ubatt-Uled) lange annähernd 
konstant ist...

> Habe auch mal das
> ganze Blinken auskommentiert. Reicht aber immer noch nicht. Ich wollte
> ja dass wenn die Batterie schwach ist alle 4 Sekunden so ein kurzes
> Flashen zu sehen ist. Habe nur irgendwie das Gefühl dass sich die beiden
> Delays der roten Led und der Bat LED stören. Wo es noch funktioniert hat
> war plötzlich die Geschwindigkeit eine andere. Kann das sein?

Definitiv kann das sein. So ein exaktes Blinken würde man mit einem 
Timer implementieren und nicht mit einer Softwareverzögerung, die nicht 
mehr stimmt sobald man neue Funktionen (Tastenabfrage, ggf. anderes 
Messprinzip) implementiert oder den Code refaktoriert (umstrickt).

> Allerdings hat mein Attiny nicht mehr genug Pins frei.

LEDs kann man multiplexen. Mit drei Pins kann man sechs LEDs betreiben 
(http://en.wikipedia.org/wiki/Charlieplexing). Deine active-high 
angeschlossene LEDs kann man auch problemlos an den Pins betreiben, die 
für ISP benutzt werden; sie flackern dann beim ISP-Programmieren. Zum 
Betrieb mit angeschlossenem ISP-Programmer: 
http://www.mikrocontroller.net/articles/AVR_In_System_Programmer#ISP-Pins_am_AVR_auch_f.C3.BCr_andere_Zwecke_nutzen

> Bei den LEDs sehe ich keine andere Möglichkeit. Ich verwende bereits
> Low-Power SMD LEDs. 2mA. Da werde ich glaube ich kaum noch günstiger
> fahren.

Die Idee in dem Link oben ist: Die LEDs müssen nicht dauernd leuchten, 
um was zu sehen. Wenn die LED 1s leuchten soll, reicht vielleicht auch 
1/10tel der Zeit oder 10x 1/100tel der Zeit...

> Ich denke meine Taktrate ist mit 1Mhz eh schon relativ gering. Habe da
> wenig Erfahrung muss ich sagen.

Ausprobieren. Man kann durch eine Fuse die internen 1 MHz noch mal durch 
8 teilen.

> Dann werde ich mich jetzt mal schlau machen wie man mit dem Comparator
> umgeht. Habe ich auch noch nie gemacht geschweige denn gezählt wie lange
> es dauert bis er die andere Spannung erreicht hat.

Kannst du ausrechnen anhand der Formel, die Elm Chan angegeben hat. Das 
Laden wird bei dem angegebenen Widerstandswert 3M3 ca. 0,1 bis 0,4ms 
dauern. so gesehen ist es wahrscheinlich kontraproduktiv den Takt unter 
1 MHz zu senken, weil das an der erreichbaren Auflösung knabbert. Ist 
aber nur ein Bauchgefühl ohne grosse Fehlerrechnung.

> Sind also zwei
> Messungen. Laden bis 0,17 der VCC erreicht und laden bis 0,5 VCC
> erreicht oder?

Habe mir den Quellcode von Elm Chan noch nicht angesehen. Aus der 
Beschreibung lese ich, dass dazwischen der C wieder entladen wird. Es 
werden zwei Zeiten gemessen t(0,17V laden) und t(0,5V laden)

> Wird das Ding dann wieder entladen eigentlich?

Selbstverständlich wird der C wieder entladen und zwar über R7 zur 
Strombegrenzung und über PB0 = Output LOW.

von Bastler (Gast)


Lesenswert?

Habe mir nochmal die Datenblätter der 4 verwendeten LEDs durchgelesen. 
Bei allen ist forward voltage typisch 1,8 (min. 1,7V und max 2,2V). Bei 
einem Strom von 2mA. Das ist bei allen gleich. Ich habe ja auch schon 
die Spannung bis auf 2.3 V runtergeregelt damit ich sehe ob meine 
Batterieled leuchtet. Da arbeitet alles einwandfrei. Erst bei 2 - 2,1 V 
wirds kritisch mit dem Leuchten. Ich habe ja als Vorwiderstand jeweils 
680 Ohm gewählt. Das heißt bei gewünschten 2mA fällt dort 1,36V ab. Im 
Idealfall habe ich 3V Batteriespannung. Ok stimmt. Das heißt für die LED 
bleiben eigentlich nur noch 1,64V. Das bedeutet meine Rs müssen kleiner 
werden. Hatte hald mit den 680ern bis jetzt keine Probleme. Evt. versuch 
ichs ja mal mit den 620ern. Wobei das ja auch noch zu groß ist. Wenn 
maximal 2,2 V an den LEDs ok sind dann kann ich sogar irgendwas mit 500 
Ohm verwenden.
Ok das heißt es würde wieder kompliziert werden weil ich ja dann einen 
Timer brauche fürs Blinken. Schade. Hatte gehofft ich kann das ganz 
einfach mit den delays machen. Brauche ja für de kapazitiven Sensor auch 
einen Timer.
  Das mit dem Multiplexen scheint ja auch nicht so schwer zu sein. 
Direkt programmieren brauche ich da ja nichts. muss nur sagen welche 
Leitung auf Ausgang und High oder welche auf Ausgang und low gezogen 
wird.
Naja meinen Takt hätte ich jetzt schon auf 1MHz belassen. Das mit dem 
Entladen ist mir jetzt auch klar. Werde morgen die Schaltung mal 
aufbauen.
Also von meiner ISP Schnittstelle könnte ich Miso Mosi und SCL auch noch 
für LEDs benutzen. Sprich wenn ich auf meinen Betauungssensor verzichte 
habe ich erst mal 3 Pins nur für den kap. Sensor und dann könnte ich auf 
6 LEDs erweitern für die Anzeige.
Naja ich werde mir wohl jetzt erst mal überlegen wie ich das mit dem 
Blinken hinbekomme. Das gleichmäßige Blinken der roten LED dürfte ja ok 
sein. Da taucht kein delay auf. Störend ist ja wohl eher das delay beim 
Bat LED. Da wollte ich ja dieses kurze flaschen alle 4 s.

Gruß
Th.

von Peter D. (peda)


Lesenswert?

Bastler schrieb:
> Also von meiner ISP Schnittstelle könnte ich Miso Mosi und SCL auch noch
> für LEDs benutzen.

Besser nur MISO, die anderen könnten durch die LEDs zu stark belastet 
werden. Hängt von Deinem Programmer ab, was der treiben kann.
Aber Du könntest sie für Tasten nehmen.

Wenn Du alle 12 IO nehmen willst, kannst Du nen Bootloader reinbrennen, 
der braucht dann nur einen Pin (z.B. ein Tasterpin).


Wenn Du es elegant machen willst, steuere die LEDs spannungsabhängig per 
Software-PWM. Dann brauchen sie nicht zuviel Strom bei voller Batterie 
und sind noch hell genug bei schwacher Batterie.

Ich würde die LEDs eh nicht übers ganze Programm verteilt schalten, da 
verliert man schnell den Überblick.

Ich würde ne Statemaschine machen und am Ende des Main werden dann die 
LEDs entsprechend dem aktuellen Zustand geschaltet.
Dann siehts Du auch sofort logische Fehler in Deinem Programmablauf, 
d.h. wenn verschiedee States gegeneinander kämpfen (Es gewinnt immer der 
letzte).
Wenn aber direkt eine Funktion ne LED einschaltet und eine andere aus, 
siehts Du das nicht.


Die Task zum Batterietest muß erstmal 16 Dummy-Wandlungen wegschmeißen, 
da die Bandgap sehr hochohmig ist:

http://wap.taur.dk/bandgap.png

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=80458&start=all&postdays=0&postorder=asc


Peter

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

Mal sehen, ob es im Netz eine Entladekurve einer CR2032 gibt. 
Interessiert mich jetzt doch, wieviel Energie bei welcher 
"Abschaltspannung" noch nicht rausgesuckelt ist. Da gibt es sicher auch 
gute/schlechte Hersteller. Kann mir nicht vorstellen, dass die 
Billigsortimenter und Qualitätshersteller identische Batterien haben.

> Ok das heißt es würde wieder kompliziert werden weil ich ja dann einen
> Timer brauche fürs Blinken. Schade. Hatte gehofft ich kann das ganz
> einfach mit den delays machen.

Richtig gemacht wird es mit Timer sogar deutlich eleganter.

Du hast dann eine Variable und dort steht drin welche LEDs an/aus sind 
und der Timer-Interrupt lässt die automatisch blinken! Im Programm 
fütterst du bloss die Variable mit dem aktuellen Zustand.

Und du hast eine Uhr laufen und kannst z.B. X Sekunden nach der 
Usereingabe den AVR automatisch schlafen legen und so Energie sparen, 
wenn der User "vergisst" das Gerät auszuschalten.

Der Vorschlag von Peter mit der state machine ist sehr gut. Den würde 
ich sofort umsetzen. Passt super in obiges Konzept!

> Brauche ja für de kapazitiven Sensor auch
> einen Timer.

Für die C-Messung benutzt du eine andere Art Timer. Der /Analog 
Comparator/ kann so konfiguriert werden, dass die Input Capture 
Function in Timer/Counter1 getriggert wird. Das gibt dir einen 
Zeitstempel für den Zeitpunkt, an dem 0,17V bzw. 0,5V erreicht werden. 
Die Differenz zum Start-Zeitstempel ist dann die jeweils verstrichene 
Ladezeit.

Soweit ich das oberflächlich im Datenblatt sehe, müsste beides (Timer 
als Uhr und Timer als Zeitstempler) sogar zusammen auf dem Hardware 
Timer1/Counter1 gehen. Alternativ Timer0 für die 1s-Uhr nehmen und 
Timer1 für die C-Messung.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Stefan B. schrieb:

> Mal sehen, ob es im Netz eine Entladekurve einer CR2032 gibt.
> Interessiert mich jetzt doch, wieviel Energie bei welcher
> "Abschaltspannung" noch nicht rausgesuckelt ist.

Ist gar nicht so schwer zu finden


http://sigma.octopart.com/141245/datasheet/Sanyo-CR2032.pdf
http://www.gpbatteries.com/pic/GPCR2032_DS.pdf
http://www.proton.com.pl/pdf/CR2032%280%29.pdf
http://www.renata.com/pdf/3vlithium/DBCR2032.05.pdf
http://www.sztlg.com/upload/File/CR2032.pdf
http://www.beck-elektronik.de/fileadmin/templates/beck_folder/batterien/maxell/CR2032.pdf
http://www.greatpower.net/product/product_images/t/cn_t__212.pdf

Bei der Suche ist auch das Thema "Maximaler Entladestrom, der für die 
Batterie gut ist" aufgetaucht. Auch mal drüber nachdenken...

http://forums.freescale.com/freescale/board/message?board.id=8BITCOMM&message.id=8294

Die dort angesprochene CR2450 hat 3V 560mAh und mehr

http://www.houseofbatteries.com/pdf/CSY-CR2450

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Zunächst mal wieder herzlichen Dank für eure Unterstützung. Ich habe 
jetzt mal versucht einen Stromlaufplan mit meinem Sensor zu zeichnen. 
Habe auch die VCC Versorgung für die Sensorschaltung auf einen Portpin 
gelegt. Ist das so weit korrekt? Wenn ich aber jetzt nur noch MISO 
benutzen darf dann kann ich auf die konventionelle Art nur 3 LEDs + das 
Bat LED anschließen. Meint ihr wirklich dass ich an MOSi, SCK nichts 
mehr ranhängen darf? Alle Lampen werden ja nie auf einmal leuchten. Ich 
glaube mein Controller kann 20 mA. Die LEDs funktionieren mit 2mA.
Also das mit der Statemachine betrache ich für mich speziell als viel zu 
komplex. Ich habe das einmal gehört habe aber keinen blassen Schimmer 
was dahintersteckt. Und natürlich wieder das alte Problem. Ursprünglich 
war diese Arbeit eine reine Technologiearbeit. Dann sollten irgendwann 
mal die Lämpchen blinken und dann habe ich mich schweren Herzens dazu 
entschlossen mit dem programmieren zu beginnen. HAbe programmieren immer 
gehasst und bin dem ausgewichen wo es nur geht. Ich weiss jetzt durch 
eure Hilfe inzwischen sehr viel nur kann ich mich hald gar nicht so 
reinlesen und reinarbeiten weil einfach keine Zeit dafür da ist. Darum 
stelle ich ja auch oft Fragen die für jemanden der es kann sehr trivial 
sind! Es hieß damals eine halbe Seite Code... Jetzt sind wir bei 
ungefähr 4-5 Seiten!!! Das mit dem Timer würde ich mir noch zutrauen. 
Das mit dem Comparator auch noch für den kapazitiven Sensor. Nur auch 
hier ist es ja jetzt wieder so dass ich zunächst mal keine Ahnung habe. 
Ich weiss hald jetzt viel besser was man mit den ganzen Registern usw 
macht.
Das mit dem Bootloader habe ich nicht verstanden... Das mit dem PWM 
glaube ich da brauche ich nicht anzufangen... Würde zu lange dauern. Das 
einzige wäre jetzt noch das mit dem Timer mit dem Blinken und dass mein 
Spannungsteiler an nem Portpin liegt um im Power Down Strom zu sparen.
Stefan: Der Timer über den du bei der C-Messung sprichst der ist aber 
auf meinem ATTINY 24 schon drauf oder? Wäre eigentlich für die Sache mit 
dem kap. Sensor ein digitaler Komparator nicht besser? Der Ausgang des 
analogen Komparators endet ja quasi irgendwo intern im Controller. Also 
ich muss den softwaremäßig verschalten dass bei einem dementsprechenden 
Ausgang was auch immer passiert.
Also meine Batterie hält jetzt wirklcih schon sehr lange. ICh glaube 
200mAh sind wirklich eine ganze Menge und voll und ganz ausreichend. 
Kann ja auch den Strom im Betrieb messen und den Strom im Power Down. 
Dann kann man ja ne ungefähre Abschätzung machen wie lang das Ding hält. 
Kommt natürlich auch immer drauf an wie lange es eingeschaltet bleibt. 
Bei 2,4 V Batteriespannung ist ja auch noch nicht aller Tage Abend. Dann 
leuchtet mein BatterieLED und man weiss dann Achtung es wird ungenau!

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

'n Abend ;-)

> Habe auch die VCC Versorgung für die Sensorschaltung auf einen Portpin
> gelegt. Ist das so weit korrekt?

Sieht für mich OK aus. Kannst ja im Prototypen einen Jumper vorsehen, so 
dass du entweder auf Vcc oder auf PA0 gehen kannst.

> Wenn ich aber jetzt nur noch MISO
> benutzen darf dann kann ich auf die konventionelle Art nur 3 LEDs + das
> Bat LED anschließen. Meint ihr wirklich dass ich an MOSi, SCK nichts
> mehr ranhängen darf? Alle Lampen werden ja nie auf einmal leuchten. Ich
> glaube mein Controller kann 20 mA. Die LEDs funktionieren mit 2mA.

Hängt wie Peter geschrieben hat vom ISP-Programmer ab; genauer, was der 
"treiben" kann, also wie viel Strom der liefern kann. Wenn an den 
Programmierleitungen deine LEDs hängen, fliesst dort ein Teil des 
Programmierstroms ab.

Typische 74HC/HCT244 (http://www.nxp.com/pip/74HC_HCT244_3.html) wie im 
Atmel-ISP STK200 können 6mA (HCT) bis 7,8mA (HC) treiben. Bei 
Nicht-Low-Current LEDs mit ILed typ. 10-20 mA gäbe es schon Probleme. 
Mit deinen Low-Current-LEDs mit ILed <2mA würde ich es im Prototypen 
riskieren. ggf. beim Prototypen die Leitung zwischen LED und 
Vorwiderstand mit Jumper trennbar machen oder bei dem Serienmodel die 
Vorwiderstände nach dem ISP-Programmieren einlöten.

Mit anderen ISP-Programmeradaptern kann das ganz anders aussehen. Z.B. 
wenn statt dem Buffer 74HC/HCT244 ein AVR Dienst schiebt, kann der ja 
deutlich mehr treiben!

> Also das mit der Statemachine betrache ich für mich speziell als viel zu
> komplex. Ich habe das einmal gehört habe aber keinen blassen Schimmer
> was dahintersteckt. Und natürlich wieder das alte Problem. Ursprünglich
> war diese Arbeit eine reine Technologiearbeit. Dann sollten irgendwann
> mal die Lämpchen blinken und dann habe ich mich schweren Herzens dazu
> entschlossen mit dem programmieren zu beginnen. HAbe programmieren immer
> gehasst und bin dem ausgewichen wo es nur geht. Ich weiss jetzt durch
> eure Hilfe inzwischen sehr viel nur kann ich mich hald gar nicht so
> reinlesen und reinarbeiten weil einfach keine Zeit dafür da ist. Darum
> stelle ich ja auch oft Fragen die für jemanden der es kann sehr trivial
> sind! Es hieß damals eine halbe Seite Code... Jetzt sind wir bei
> ungefähr 4-5 Seiten!!! Das mit dem Timer würde ich mir noch zutrauen.
> Das mit dem Comparator auch noch für den kapazitiven Sensor. Nur auch
> hier ist es ja jetzt wieder so dass ich zunächst mal keine Ahnung habe.
> Ich weiss hald jetzt viel besser was man mit den ganzen Registern usw
> macht.

Die Gefahr sich zu verzetteln besteht immer; man nennt das Featuritis. 
dagegen hilft bei Projektbeginn genau zu beschreiben, was man bis wohin 
haben will. Z.B. deine erste Version mit dem Betauungssensor.

Klar ist es schöner, wenn man mehrere Messpunkte haben kann, so wie es 
mit dem kap. Sensor möglich ist. ABER man öffnet leicht eine Büchse der 
Pandora., weil neue Voraussetzungen und nötiges Wissen dazu kommen.

Ich weiss nicht, ob ich dir erzählen darf, dass du noch an die 
Kalibrierung des kap. Sensors denken musst. Also wie hängt die gemessene 
Kapazität mit dem Messwert rel. Feuchte zusammen. Man kann das mit dem 
bekannten Wasserdampfgehalt über bestimmten Salzlösungen machen. Die 
Kurve im Datenblatt sind ja nur typ. Werte und der aktuelle Aufbau muss 
kalibriert werden. Genaugenommen muss vielleicht jedes gebaute Gerät 1x 
"im Werk" kalibriert werden. Bei einer grossen Serie kommt dann 
natürlich die Frage auf, wie macht man das schnell und wo speichert man 
dauerhaft den individuellen Kalibrierwert für die Umrechnung Kapazität 
nach rel. Feuchte... ROM, d.h. im Programm? Würde bedeuten pro Gerät 1 
Kompilerlauf... Oder im EEPROM? Da ist der nächste Wissensbaustein: Wie 
geht man mit EEPROM um?

> Das mit dem Bootloader habe ich nicht verstanden... Das mit dem PWM
> glaube ich da brauche ich nicht anzufangen... Würde zu lange dauern.

Bootloader ist IMHO ein Feature... Software-PWM auch, aber ein nicht so 
schwer zu lösendes (s.u.)

> Das
> einzige wäre jetzt noch das mit dem Timer mit dem Blinken und dass mein
> Spannungsteiler an nem Portpin liegt um im Power Down Strom zu sparen.
> Stefan: Der Timer über den du bei der C-Messung sprichst der ist aber
> auf meinem ATTINY 24 schon drauf oder?

Ja im AVR sind mehrere Timer drin. Die wahrscheinlich einfachste Lösung 
ist folgende:

Timer0 ist als allg. durchlaufende Uhr geschaltet. Die Interruptroutine 
kontrolliert die Zustandsvariablen für die LEDs und übernimmt die 
Aufgabe, die LEDs AN/AUS/Blinkend zu schalten.

Die Zustandvariablen für die LEDs werden im Userprogramm gesetzt. Ist 
der Wert 0, ist die betreffende LED aus. Hat sie einen Wert, toggelt der 
Timer0 die LED mit XOR, d.h. die LED blinkt. Die Zahl der Blinkaktionen 
wird um eins vermindert und der Timer0 wartet auf den nächsten 
Interrupt. Wenn die Interrupts im 1s Abstand kommen, hast du ein 1Hz 
Blinken.

Für die bessere Energiebilanz kann man per Software in der Timer-ISR 
auch leicht einrichten, dass ein 1 Hz Blinken gemacht wird, bei dem die 
LED nur z.B. 10% leuchtet und 90& dunkel ist statt 50:50 wie üblich. Ist 
aber ein Feature...

Umgekehrt geht natürlich auch - Batterie ist voll => 10:90, 
Batteriespannung sinkt dann Verhältnis steigern bis wegen mir 90:10 - 
das ist die Software-PWM, die Peter meint. Durch die unterschiedliche 
Leuchtdauer bleibt der Helligkeitseindruck trotz sinkender 
Batteriespannung gleich. Ist aber ein Feature...

Durch die Zahl kannst du mehr Infos aus dem AVR rausschaffen. Bsp. 1 
Blinken für je 10 rel. Feuchte (oder je gemessene 10pF). Oder eine 
Kombination von 2 LEDs für die Ausgabe eines Binärwertes oder 
Zehner+Einer Stellen oder Zehner+Fünfer-Stellen. Ist aber ein Feature...

Timer1 wäre nur für Input Capture zuständig. Hier werden die Ladezeiten 
gemessen.

> Wäre eigentlich für die Sache mit
> dem kap. Sensor ein digitaler Komparator nicht besser? Der Ausgang des
> analogen Komparators endet ja quasi irgendwo intern im Controller. Also
> ich muss den softwaremäßig verschalten dass bei einem dementsprechenden
> Ausgang was auch immer passiert.

Im Prinzip hast du einen digitalen Komparator mit Aussage Vkap < Vref 
oder Vkap >= Vref. Der Zeitpunkt des Wechsels (Flankentyp ist 
konfigurierbar) wird über den Input Capture gemessen. Komplett in 
AVR-interner Hardware! Du musst "nur" den AC und Timer1 des AVRs intern 
passend konfigurieren, die Messung starten (Strom per Outputpin ins 
Messsystem geben) und wirst per Interrupt benachrichtigt, wenn das 
Ereignis eingetreten ist. Dann den Zeitwert abholen.

> Also meine Batterie hält jetzt wirklcih schon sehr lange. ICh glaube
> 200mAh sind wirklich eine ganze Menge und voll und ganz ausreichend.
> Kann ja auch den Strom im Betrieb messen und den Strom im Power Down.
> Dann kann man ja ne ungefähre Abschätzung machen wie lang das Ding hält.
> Kommt natürlich auch immer drauf an wie lange es eingeschaltet bleibt.

Genau hier kann der Timer0 oben auch helfen. Z.B. wenn der x Sekunden 
gelaufen ist (Ausprobieren was praktikabel ist), schickt der den AVR in 
den Power Down, indem er eine Anweisung taster_abfrage(AUS); macht, die 
beim nächsten Durchlauf von while(1) zum Schlafen führt. Ist aber ein 
Feature...

> Bei 2,4 V Batteriespannung ist ja auch noch nicht aller Tage Abend. Dann
> leuchtet mein BatterieLED und man weiss dann Achtung es wird ungenau!

Kann man mit leben. Baue den Prototypen. Einen funktionierenden. Und die 
weiteren Features stellst du dann als Erweiterungen vor. Den Zeitaufwand 
dafür kannst du abschätzen und - jetzt das coole - es ist keine 
Hardwareänderung mehr nötig: Die Erweiterungen sind reine 
Firmwareupdates!

Und da käme wieder der Bootloader wieder ins Spiel ;-) Wenn der 
Endanwender die Updates machen soll, kann er keinen ISP-Adapter 
benutzen, das ist aus verschiedenen Gründen unpraktikabel. ABER einen 
einfachen Adapter (serielle Übertragung mit Sende-LED auf PC-Seite und 
Empfangs-Fotodiode auf µC-Seite) um den Bootloader zu füttern, das habe 
ich bei verschiedenen Konsumergeräten bereits gesehen. Ist aber ein 
Feature...

von Peter D. (peda)


Lesenswert?

Bastler schrieb:
> Also das mit der Statemachine betrache ich für mich speziell als viel zu
> komplex. Ich habe das einmal gehört habe aber keinen blassen Schimmer
> was dahintersteckt.

Ist eigentlich eine einfache Methode, um Klarheit in den Programmablauf 
zu bekommen, d.h. den Überblick zu behalten.
Jeder Zustand entspricht einer Nummer (0...n). Und zu jedem Zustand gibt 
es eine Routine (case), die etwas macht. Diese Routine beinhaltet dann 
auch die Abfragen, um in einen anderen Zustand zu wechseln.

Das ganze bedingt natürlich, daß man sich erstmal einen 
Programmablaufplan macht, d.h. welche Zustände gibt es und wie sind die 
Beziehungen zueinander.


> Ursprünglich
> war diese Arbeit eine reine Technologiearbeit. Dann sollten irgendwann
> mal die Lämpchen blinken und dann habe ich mich schweren Herzens dazu
> entschlossen mit dem programmieren zu beginnen.

Wie ist denn überhaupt so Dein Zeitplan?

Ich will Dir ja Deinen Optimismus nicht nehmen, aber die 
Kapazitätsmessung halte ich für einen Anfänger als sehr kompliziert.

Ich würde dann erstmal eine SW-UART vorsehen, um Debugausgaben 
darstellen zu können, d.h. Zahlenwerte in einem Terminalprogramm auf dem 
PC.
Die Meßwerte lassen sich schlecht nur mit LEDs darstellen, Du mußt aber 
irgendwie feststellen, welche Werte Deine Kapazitätsmessung liefert, ob 
die eingermaßen linear und stabil sind.


Peter

von Bastler (Gast)


Lesenswert?

Ok. Also ich habe meinen Prototypen aufgebaut. Auch ein Jumper habe ich 
vorgesehen damit man zwischen VCC und Portpin wechseln kann. Habe diesen 
Pin jetzt mal auf PA0 gelegt. Ich vermute ja mal dass dafür die ISP-Pins 
von Haus aus ausscheiden. Ich gehe auch davon aus dass ich meinen Kap 
Sensor (über 3,3M) und meinen "Referenzspannungsteiler" an das Gleiche 
Potential anschließen muss weil es sonst ungenau ist. Dann vermute ich 
muss dieser Pin als Ausgang konfiguriert werden wie bei den LEDs und auf 
High gelegt werden. Damit liegt ungefähr VCC an diesem ausgewählten 
Portpin an und ich kann ihn vorm einschlafen deaktivieren. Das wird 
analog auch bei meinem Betauungssensor funktionieren nur kann ich dann 
nicht als Referenz VCC angeben sondern muss irgendwie sagen dass des 
über den Port rauskommt. Ist das so richtig?
Also ich habe als ISP Programmer den AVRISP MKII. Habe mir auch schon 
das Manual durchgelesen allerdings stoße ich nirgends auf etwas was den 
zu treibenden Strom betrifft. Kann mich auch erinnern dass ich irgendwo 
schon mal was gelesen habe dass man die ISP Pins mitbenutzen kann. 
Ausgeschlossen ist wohl VCC GND und Reset vermute ich. Warum kann man 
gerade den MISO mitnutzen? Peter meinte ja auch für Taster geht das 
eher. Ich könnte also meinen Power Down Taster z.B. auf MOSI legen. Muss 
den Pin hald als Eingang konfigurieren und Pull Up setzen. Dann hätte 
ich mir ja wieder einen der anderen Pins gespart.
Also das mit der Statemachine würde ich mal nach dieser Arbeit privat 
versuchen wenn ich einfach auch die Zeit zum rumprobieren habe. Davon 
würde ich also schon gerne Abstand nehmen.
Das mit dem kalibrieren hört sich natürlich schon etwas an wie 
Alptraum!! Mir war es aber schon klar weil ichs ja auch gelesen habe. 
Ich denke mal ich werde 0 und 100 % rel Feuchte kalibrieren und alles 
andere ist dann in gleichen Abständen dazwischen. Das ist natürlich eine 
gigantische Arbeit. Würde aber dann wohl die Werte vom Prototypen auf 
die anderen Teile übernehmen.
Ich kann diesen Timer0 also auch mehrfach verwenden oder? Also nehmen 
wir an das Bat-Led flasht alle 4 Sekunden auf. Dann bleibt das Programm 
ja nicht da drin "hängen". Kann ich dann gleichzeitig sagen so jetzt 
blinke mit der roten LED wenn es gerade so nass ist? Oder muss ich da 
dann wieder einen anderen Timer vorsehen? Genauso ist das ja auch bei 
meiner Tastenentprellung. Auch da habe ich ja delay verwendet. Also im 
ungünstigsten Fall könnten drei Ereignisse gleichzeitig auftreten wo ich 
einen Timer benötige. Also Batterie schwach, so nass dass rot blinkt und 
ich möchte das Gerät ausschalten.
Also das mit dem Timer 1 betrifft dann meinen kap. Feuchtesensor. Der 
macht also genau das richtige und ist irgendwie mit meinem Comparator 
"getriggert".
Es gibt bereits jeweis nen Prototyp. Also eine Europlatine mit dem 
Betauungssensor und eine mit dem kap. Sensor. Das gute ist dass jede 
Schaltung auch einen ISP Stecker hat. Sprich ich kann im Nachhinein auch 
noch die Software abändern. Auch meine mit der anderen Technologie 
aufgebauten Schaltungen werden diesen Stecker beinhalten da es ja schwer 
ist die SMD Attinys auf einer anderen Platine zu programmieren.
Ich sehe schon irgendwie stelle mich ziemlich dumm da meine Beiträge in 
diesem Forum immer die längsten werden!!!"gg" Dabei sind die Probleme 
die ich habe ja wohl die einfachsten die es nur geben kann.

Gruß
Th.

von Bastler (Gast)


Lesenswert?

Zu Peters Beitrag:

Mein Zeitplan besagt eigentlich dass keine Zeit mehr fürs programmieren 
ist. Ich suche mir immer wieder freie Minuten wo ich damit ein wenig 
arbeiten kann. Bei meinem Betauungssensor sieht es ja eigentlich ned so 
schlecht aus. Das einzige wäre noch das mit dem Timer dass des  mit dem 
Blinken und der Tasterentprellung noch sicherer funktioniert. Das mit 
dem Kondensator ist eine reine Zugabe. Wenn ich das schaffe ist es gut. 
Wenn nicht dann ist es auch gut. Mir ist schon klar dass der 
hardwaremäßige Aufbau noch das geringste Problem ist. Die software ist 
ja mein Hauptproblem weil ich davon ja praktisch keine Ahnung hab. Ich 
muss mir ja auch erst mal über die Abläufe im klaren sein. Dass ein 
Timer Zeit zählt ist mir schon klar. Nur wie man das natürlich 
verarbeitet und was dann der Timerinterrupt macht und so das weiss ich 
nicht. Da werde ich mir erst nochmal das Tutorial durchlesen und dann 
nach ähnlichen Beispielen in diesem Forum suchen. Vielleicht ist es auch 
erstmal gut wenn ich einfach mal so probiere eine LED zum blinken zu 
bringen mit Timer. Ohne Sensor, Taster und was auch immer.

Gruß
Th.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Ok. Also ich habe meinen Prototypen aufgebaut. Auch ein Jumper habe ich
> vorgesehen damit man zwischen VCC und Portpin wechseln kann. Habe diesen
> Pin jetzt mal auf PA0 gelegt. Ich vermute ja mal dass dafür die ISP-Pins
> von Haus aus ausscheiden. Ich gehe auch davon aus dass ich meinen Kap
> Sensor (über 3,3M) und meinen "Referenzspannungsteiler" an das Gleiche
> Potential anschließen muss weil es sonst ungenau ist. Dann vermute ich
> muss dieser Pin als Ausgang konfiguriert werden wie bei den LEDs und auf
> High gelegt werden. Damit liegt ungefähr VCC an diesem ausgewählten
> Portpin an und ich kann ihn vorm einschlafen deaktivieren. Das wird
> analog auch bei meinem Betauungssensor funktionieren nur kann ich dann
> nicht als Referenz VCC angeben sondern muss irgendwie sagen dass des
> über den Port rauskommt. Ist das so richtig?

Weiss ich nicht aus dem Stegreif. Dazu müsste ich mir erst den Sinn 
dieser Zeile wieder heraussuchen:

  messwert = adcmessung((0<<REFS1)|(0<<REFS0)|(0<<MUX5)|(0<<MUX0));

Und überlegen, wo/wie der Betauungssensor angeschlossen war. In dem 
aktuellen Schaltbild ist der ja nicht eingezeichnet. Tipp: Kommentare im 
Programm schaden nicht. Schreib rein, was wichtig ist, wie z.B. der 
passenede Hardwareanschluss zum aktuellen Code!

Die Zeile bedeutet, dass als Vref Vcc benutzt wird und PA0 als Eingang 
für den ADC benutzt wird. Das beisst dich mit dem Schaltplan für das 
Gerät mit dem kap. Sensor, wenn dort PA0 als Ausgang für die 
Messspannungen (Sensor und Vergleich) benutzt wird.

> Also ich habe als ISP Programmer den AVRISP MKII. Habe mir auch schon
> das Manual durchgelesen allerdings stoße ich nirgends auf etwas was den
> zu treibenden Strom betrifft.

Im Userguide des AVRISP MKII steht, dass Pull-Ups an den 
Programmierleitungen not stronger than 820 Ohm sein sollen. stronger 
heisst hier kleinere Widerstandswerte. Das wären bei 5V 6mA - passt zu 
den obigen Überlegungen mit den HC/HCT ICs.

> Kann mich auch erinnern dass ich irgendwo
> schon mal was gelesen habe dass man die ISP Pins mitbenutzen kann.

Es gibt eine Appnote von Atmel Hardware Considerations in der was zu ISp 
und SPI-Bus steht. Vielleicht meinst du die?

> Ausgeschlossen ist wohl VCC GND und Reset vermute ich. Warum kann man
> gerade den MISO mitnutzen? Peter meinte ja auch für Taster geht das
> eher.

MISO wird von zum programmierenden AVR betrieben. Dessen Pin kann mehr 
Saft liefern. Mehr als die Logikbausteine/Levelkonverter/Buffer in den 
ISP-Programmieradaptern.

> Ich könnte also meinen Power Down Taster z.B. auf MOSI legen. Muss
> den Pin hald als Eingang konfigurieren und Pull Up setzen. Dann hätte
> ich mir ja wieder einen der anderen Pins gespart.

Du brauchst eigentlich nur einen Taster max. zwei.

Wichtig zum Aufwecken ist, dass ein Taster an dem Pin mit INT0 hängt. 
Den darfst du nicht wo anders hin legen. Die Ausnahme ist nur die 
Variante mit dem Rausschmeissen aus dem Schlaf per RESET. Ein 
RESET-Taster als Eingabetaster zu verwenden ist aber sehr unpraktisch.

PS: Usereingaben kann man auch über die Zahl der Tastendrücke, Dauer der 
Tastendrücke ("lang", "kurz") und Kombinatioen (alias "Morsen") 
machen...

> Also das mit der Statemachine würde ich mal nach dieser Arbeit privat
> versuchen wenn ich einfach auch die Zeit zum rumprobieren habe. Davon
> würde ich also schon gerne Abstand nehmen.

> Das mit dem kalibrieren hört sich natürlich schon etwas an wie
> Alptraum!! Mir war es aber schon klar weil ichs ja auch gelesen habe.
> Ich denke mal ich werde 0 und 100 % rel Feuchte kalibrieren und alles
> andere ist dann in gleichen Abständen dazwischen. Das ist natürlich eine
> gigantische Arbeit. Würde aber dann wohl die Werte vom Prototypen auf
> die anderen Teile übernehmen.

Hängt von der Fertigung der Sensoren ab. Bei guter Reproduzierbarkeit 
könnte das gehen. Wenn du Pech hast, kommen die Sensoren aus 
unterschiedlichen Chargen und sind zu stark unterschiedlich, um mit 
einer "Kennlinie" behandelt zu werden.

> Ich kann diesen Timer0 also auch mehrfach verwenden oder? Also nehmen
> wir an das Bat-Led flasht alle 4 Sekunden auf. Dann bleibt das Programm
> ja nicht da drin "hängen". Kann ich dann gleichzeitig sagen so jetzt
> blinke mit der roten LED wenn es gerade so nass ist? Oder muss ich da
> dann wieder einen anderen Timer vorsehen? Genauso ist das ja auch bei
> meiner Tastenentprellung. Auch da habe ich ja delay verwendet. Also im
> ungünstigsten Fall könnten drei Ereignisse gleichzeitig auftreten wo ich
> einen Timer benötige. Also Batterie schwach, so nass dass rot blinkt und
> ich möchte das Gerät ausschalten.

Ja ein Timer würde per Interrupt alle LEDs bedienen. Stell dir den als 
"Hintergrundprogramm" vor, der parallel zu deinem Userprogramm läuft.

> Es gibt bereits jeweis nen Prototyp. Also eine Europlatine mit dem
> Betauungssensor und eine mit dem kap. Sensor. Das gute ist dass jede
> Schaltung auch einen ISP Stecker hat. Sprich ich kann im Nachhinein auch
> noch die Software abändern. Auch meine mit der anderen Technologie
> aufgebauten Schaltungen werden diesen Stecker beinhalten da es ja schwer
> ist die SMD Attinys auf einer anderen Platine zu programmieren.

Bei SMD AVRs muss es nicht unbedingt der fette ISP Stecker sein. Es gibt 
hier im Forum Diskussionen, wo Leute nach alternativen 
Kontaktmöglichkeiten gefragt haben und z.B. Pads am Platinenende genannt 
wurden, die mit temporären Clips oder Federpins kontaktiert wurden. Man 
kann auch direkt an die Pins gehen... Meine Überlegungen von damals 
(Beitrag "Re: Challenger-Clip Miniatur(SMD)-Klemmprüfspitzen?") sind inzwischen im 
Kauf geendet ;-)

> Ich sehe schon irgendwie stelle mich ziemlich dumm da meine Beiträge in
> diesem Forum immer die längsten werden!!!"gg" Dabei sind die Probleme
> die ich habe ja wohl die einfachsten die es nur geben kann.

So sehe ich das nicht. Du bringst eine interessante aber - für meinen 
Level als Hobbyist - nicht zu exotische/schwierige Fragestellung auf, 
kannst sie verständlich formulieren, nimmst Rat an, bist bereit selbst 
zu denken/arbeiten... dann mag man/ich auch antworten. Der Platz 
"kostet" nix; da muss man nix sparen.

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Hallo

Also ich habe jetzt für meinen kapazitiven Sensor folgenden Schaltplan 
angefertigt. Ich habe jetzt die Möglichkeit 6 LEDs zum leuchten zu 
bringen. Gibt es eigentlich hier auch die Möglichkeit über #define so zu 
konfigurieren dass man nur noch LED_1on oder wie auch immer schreiben 
kann. Wenn ich z.B. LED1 anschalten will sieht ja der Code 
folgendermaßen aus:

DDRB |= (1<<PB0);  // Ausgang
DDRA |= (1<<PA7);       // Ausgang
DDRA &= ~(1<<PA5);  // Eingang
PORTB |= (1<<PB0);      // PB0 auf High
PORTA &= ~(1<<PA7);     // PA7 auf GND
PORTA &= ~(1<<PA5);     // PA5 Tristate (hängt quasi in der Luft)

Das ist natürlich extrem lästig wenn man immer diesen ganzen Schrott 
schreiben muss. Wie kann ich mir da behelfen weil ich ja mit #define 
immer nur z.B. einen Port bearbeiten kann. Oder kann man da verunden???
Als nächstes nochmal zu dem Problem in meiner Schaltung mit dem 
Betauungssensor. Ich möchte ja den Spannungsteiler statt an VCC auf 
einen Portpin legen. Dadurch erhoffe ich mir eine gewaltige 
Stromersparnis im Zustand Power-Down. Habe jetzt einfach mal gesagt dann 
leg ich den Spannungsteiler an Pin 10. Das ist PA3. Da war früher in 
meiner alten Schaltung eine LED dran. Der ist aber jetzt frei.
Es war ja die Frage was die Zeile

 messwert = adcmessung((0<<REFS1)|(0<<REFS0)|(0<<MUX5)|(0<<MUX0));

bedeutet. REFS1 und REFS0 auf 0 bedeutet VCC als analoge Referenz. Ich 
sehe gerade dass  mit 01 für REFS1 und REFS0 die externe AREF an PA0 
angesprochen werden kann. Ist das quasi schon die Lösung. Sprich der 
Spannungsteiler zieht die Spannung aus PA0. Mit MUX5:0 auf 0 wähle ich 
den Eingang PA0 für meine zu wandelnde Spannung (also zwischen 
Vorwiderstand und res. Sensor auf Gnd). Das müßte ich dann z.B. auf PA1 
legen damit der PA0 als Spannungsversorgung frei wird. Ist das so 
richtig?
NOCH WAS: Es ist selbstverständlich immer nur EIN Sensor in Betrieb. 
Also es gibt jetzt nen Prototypen für den Betauungssensor und einen für 
den kap. Sensor. Wobei bei dem Prototypen mit dem kap. Sensor auch der 
Betauungssensor drauf ist. Mit Jumper hald dass man umswitchen kann.
Damit hat sich die Sache mit der Benutzung von MOSI erledigt. Ich 
benutze nur noch Miso wie im Schaltplan zu sehen für die Ansteuerung der 
LEDs. Es dürfte ja kein Problem geben wenn ich den auf Ein- oder Ausgang 
ziehe oder? Könnte ja sein dass die Schnittstelle gestört wird. 
Funktionieren tuts prima. Kann jede LED ansteuern.
Leider kann ich meinen Schnittstellenstecker nicht vermeiden da mein 
Basissubstrat kein FR4 ist. Alle Schaltungen haben andere Formen also 
funktioniert auch die Möglichkeit mit dem Nadeladapter nicht.
Nochmal zum TIMER. Ich versuche im Moment mit Timer0 meine LEDs zum 
blinken zu bringen. Das sollte recht einfach sein. Also sprich pro 
Prozessor Takt wird ein Timer um eins erhöht. Ich habe mich entschlossen 
bei 1MHz Taktung den 1024 Vorteiler zu benutzen. Das bedeutet bis der 
Timer 1 mal überläuft vergehen 0,262144 Sekunden. Wenn ich mein LED also 
alle Sekunde ein und nach einer Sekunde wieder ausschalten will könnte 
ich den Interrupt bei Overflow verwenden. Allerdings löst der doch bei 
jedem Überlauf aus. Wie kann ich dem klarmachen dass er erst beim 4. 
Überlauf den Interrupt auslösen soll? Werde gegebenenfalls morgen den 
Code den ich bis jetzt habe auch noch hier reinstellen. Der Timer wäre 
ja für mich quasi der Schlüssel damit alles funktioniert. Möchte den ja 
auf der Schaltung vom Betauungssensor für die Tastenentprellung 
verwenden. Da habe ich ja das delay mit 80ms. Außerdem für das blinken 
der roten LED und vor allem für das alle 4 Sekunden aufblinken der 
Batterie LED.
So wie ich das verstanden habe kann ich da ein und denselben Timer 
benutzen. Ich muss dann praktisch nur in der Interruptserviceroutine für 
die drei verschiedenen Ereignisse etwas festlegen. Ist diese Überlegung 
richtig?

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Also ich habe jetzt für meinen kapazitiven Sensor folgenden Schaltplan
> angefertigt. Ich habe jetzt die Möglichkeit 6 LEDs zum leuchten zu
> bringen.

Es wäre deutlich einfacher, wenn du die LEDs nur an einem PORT hängen 
hättest. Dann könnte man prima den Zustand einlesen, verrechnen 
(verUNDen/verODERn) und in einem Rutsch setzen. Bei der jetzigen 
Variante musst du teuflisch aufpassen, was mit den übrigen LEDs 
passiert, wenn du eine LED schaltest.

Generell Du kannst die Grobarbeit "verstecken" und für einen 
Anweisungsblock ein mehrspaltiges #define benutzen, wenn du den 
Funktionsoverhead nicht möchtest
1
// LED1_ON: 
2
//   PB0 Output HIGH
3
//   PA7 Output LOW
4
//   PA5 Input  Z (int. Pull-up aus)
5
#define LED1_ON()      \
6
 do {                  \
7
   DDRA  |= (1<<PA7);  \
8
   PORTA &= ~(1<<PA7); \
9
   DDRA  &= ~(1<<PA5); \
10
   PORTA &= ~(1<<PA5); \
11
   DDRB  |= (1<<PB0);  \
12
   PORTB |= (1<<PB0);  \
13
 } while(0)

oder eine Inline-Funktion, wenn wenige Aufrufe der Funktion kommen
1
// LED1_ON: 
2
//   PB0 Output HIGH
3
//   PA7 Output LOW
4
//   PA5 Input  Z (int. Pull-up aus)
5
static inline void LED1_ON(void)
6
{
7
   DDRA  |= (1<<PA7);
8
   PORTA &= ~(1<<PA7);
9
   DDRA  &= ~(1<<PA5);
10
   PORTA &= ~(1<<PA5);
11
   DDRB  |= (1<<PB0);
12
   PORTB |= (1<<PB0);
13
}

oder eine reguläre Funktion, wenn viele Aufrufe im Programm verstreut 
sind
1
// LED1_ON: 
2
//   PB0 Output HIGH
3
//   PA7 Output LOW
4
//   PA5 Input  Z (int. Pull-up aus)
5
static void LED1_ON(void)
6
{
7
   DDRA  |= (1<<PA7);
8
   PORTA &= ~(1<<PA7);
9
   DDRA  &= ~(1<<PA5);
10
   PORTA &= ~(1<<PA5);
11
   DDRB  |= (1<<PB0);
12
   PORTB |= (1<<PB0);
13
}

Beim Umschalten von LEDs sollten Blitzer der anderen LEDs vermieden 
werden. Deshalb würde ich zuerst alles abschalten (fehlt oben) und dann 
die Anschaltfunktionen so schreiben, dass das Anschalten der jeweiligen 
Versorgungsspannung der letzte Befehl ist.

Die Abschaltfunktion dafür könnte man bei allen LEDs an einem Port 
wunderschön universell halten und z.B. die betreffenden PORTx auf LOW 
setzen - unabhängig von der DDRx Stellung!

> Als nächstes nochmal zu dem Problem in meiner Schaltung mit dem
> Betauungssensor. Ich möchte ja den Spannungsteiler statt an VCC auf
> einen Portpin legen. Dadurch erhoffe ich mir eine gewaltige
> Stromersparnis im Zustand Power-Down. Habe jetzt einfach mal gesagt dann
> leg ich den Spannungsteiler an Pin 10. Das ist PA3. Da war früher in
> meiner alten Schaltung eine LED dran. Der ist aber jetzt frei.

Siehe oben! Überlege dir dringend, was an PA3 und PB0 hängt zu tauschen!

> Es war ja die Frage was die Zeile
>  messwert = adcmessung((0<<REFS1)|(0<<REFS0)|(0<<MUX5)|(0<<MUX0));

Die Frage hatte ich im gleichen Posting beantwortet ;-) Mir war der Teil 
bei dem kapazitiven Sensor nicht klar. Die Funktion zur Feuchtemessung 
muss dort komplett anders aussehen. Der Code für den Betauungssensor hat 
in dem Programm für den kapazitiven Sensor eigentlich nichts zu suchen.

> NOCH WAS: Es ist selbstverständlich immer nur EIN Sensor in Betrieb.
> Also es gibt jetzt nen Prototypen für den Betauungssensor und einen für
> den kap. Sensor. Wobei bei dem Prototypen mit dem kap. Sensor auch der
> Betauungssensor drauf ist. Mit Jumper hald dass man umswitchen kann.

Wie soll das fertige Gerät aussehen - auch beide Sensoren oder nur 
einer? Zeichne das unbedingt in deinen Stromlaufplan ein! Nur wenn man 
alle Fakten kennt, kann man Änderungsvorschläge oder Kontrollen machen.

> Nochmal zum TIMER. Ich versuche im Moment mit Timer0 meine LEDs zum
> blinken zu bringen.
> Wie kann ich dem klarmachen dass er erst beim 4.
> Überlauf den Interrupt auslösen soll?

Statische Zählervariable in der ISR hochzählen lassen und nur bei jedem 
vierten Mal die Aktion ausführen.

> Ich muss dann praktisch nur in der Interruptserviceroutine für
> die drei verschiedenen Ereignisse etwas festlegen. Ist diese Überlegung
> richtig?

Beschreibe vorher in einfachen Worten die Funktion der LEDs bzw. die 
Ereignisse. Welche sind Nurleuchter? Welche sind Blinker? Welche können 
zusammen leuchten oder blinken? Wenn mehrere blinken - gleichzeitig oder 
wechselseitig oder egal?

Z.B.
Batteriecheck:
Batterie low => LED6 blinkt 4x im 1Hz Takt
Batterie nicht low => LED6 aus

Feuchtemessung:
Feuchte zu hoch => LED1 (rot) leuchtet dauernd
Feuchte normal  => LED2 (grün) blinkt im 1Hz Takt dauernd
Feuchte zu niedrig => LED3 (gelb) leuchtet dauernd
Jeweils eine LED ist aktiv!

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Mahlzeit!

Also die Schaltung für den kap. Feuchtemesser ist umgebaut. Die LEDs 
liegen jetzt an PA3, PA5 und PA7. Für den Betauungssensor lasse ich die 
Schaltung mit 3 LEDs weil das ja ohnehin sehr ungenau ist.
Ich glaube so weit ich das selbst beurteilen kann dass ich das über 
define Regeln möchte. Allerdings funktioniert das leider so nicht wie 
ich es mir dachte. Habe den Code mitgeschickt. Mir geht es im ersten 
Schritt nur darum die 6 LEDs möglichst einfach zum leuchten zu bringen. 
Im zweiten Schritt möchte ich dann wie man sieht versuchen über den 
Timer0 OVF ein Blinken herbeizuführen.
Es kann sein dass mein Fehler sehr einfach ist. Er erwartet jedenfalls 
einen identifier oder ein ( vor dem do und jeweil vor allen whiles. 
Keine Ahnung ob ich das jetzt immer noch so kompliziert machen muss wenn 
alle LEDs am gleichen Port hängen. Man könnte deine Ausführungen auch so 
verstehen dass ich nur DDR definen soll und Spannung oder nicht dann im 
Programm. Ist natürlich schon seeehr unübersichtlich wenn das define 
über mehrere Zeilen geht!
Das mit dem Ausschalten müßte ja passen dass ich die Ports auf 0 setze. 
Man könnte das aber wohl auch außerhalb von Main machen.
Nochmal zu den Problemen mit dem Betauungssensor. Eine spätere fertige 
Schaltung besteht entweder aus dem Betauungssensor oder dem kap. 
Feuchtesensor. Wie es aussieht werde ich den Betauungssensor dann auch 
mit 3 LEDs belassen. Wenn ich das also richtig verstanden habe gehört 
der Spannungsteiler des Betauungssensors an PA0 gehängt. Da steht ja 
auch AREF. Die eigentliche Auswertung zwischen dem "Vorwiderstand" und 
dem veränderlichen Widerstand könnte ich ja mit MUX5:0 auf PA7 legen. 
Sprich dann sollte dort die AD Wandlung stattfinden und nicht mehr auf 
PA0. Und genauso wie ich die LEDs vorm einschlafen ausschalte muss ich 
dann den PIN PA0 (mit AREF) wohl auf 0 legen. Dieser Pin wird wohl auch 
als Ausgang geschaltet werden müssen.
Der kapazitive Sensor wäre die Kür wenn ichs schaffe. Der soll dann mit 
den 6 LEDs an PA3, Pa5 und PA7 betrieben werden. Mir ist klar dass der 
Code vom Betauungssensor beim kap Sensor null verloren hat. Die 
Auswertung passiert ja über den Comparator mit dem Timer1 wie du schon 
geschrieben hast.
FÜr den Anfang möchte ich mich aber einfach mal damit begnügen 
herauszufinden wie ich die 6 LEDs steuern kann und wie man mit Timer0 
und dem OVF Timerinterrupt umgeht. In der Anfängermethode bringe ich die 
LEDs ja schon zum leuchten und habe mit dem im Anhang befindlichen Code 
ein Lauflicht realisiert.
Das mit dem Timer muss ich wirklich erst noch verstehen.

Gruß
THomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

In dem Code fehlen bei den #define die A\ Zeichen am Ende der Zeile. 
Zeilen mit \ am Zeilenende werden vom C-Präprozessor als eine Zeile 
behandelt. Fehlen die \ zählen die Zeilen als (sinnloser) Code.

Wenn alle LED am gleichen Port hängen, ist es wesentlich einfacher!
1
#define MASKE (~((1<<PA3) | (1<<PA7) | (1<<PA5)))
2
3
#define LED_OFF()
4
  do              \
5
  {               \
6
     PORTA &= MASKE; /* alle LEDs aus */ \
7
  } while (0)
8
9
//
10
// LED1_ON
11
//   PA3 Output HIGH
12
//   PA7 Output LOW
13
//   PA5 Input Z
14
//
15
#define LED1_ON() \
16
  do              \
17
  {               \
18
     uint8_t tmp; \
19
     /* hier LED_OFF() bzw. am Anfang der ISR */ \
20
     tmp = DDRA & MASKE; \
21
     tmp |= (1<<PA3) | (1<<PA7) | (0<<PA5); \
22
     DDRA = tmp; \
23
     PORTA |= (1<<PA3); \
24
  } while (0)

Bei der Multiplex-Schaltung kannst zu einem Zeitpunkt immer nur eine LED 
leuchten lassen. Damit es aussieht, als ob mehrere LEDs leuchten 
(Batterie+Feuchte z.B.), musst du umschalten.

Du musst also die ISRs häufiger aufrufen lassen und die Aktionen für die 
LEDs schneller durchführen. Durch die Trägheit des Auges verschmilzt das 
Flackern bei genügend schnellen Wechseln zu einem konstanten Leuchten.

Die Möglichkeiten für den Prescaler sind begrenzt. Rechne mal mit 
verschiedenen Werten. Ganzzahlen kann man durch Tunen der Schritte 256-x 
bekommen. Und wenn du EXAKT eine Sekunde haben willst, dann gibt es 
dafür einen ausführlichen Artikel im Wiki ([[AVR - Die genaue Sekunde / 
RTC]]).

1.000.000  1024  256 => 3,x Aufrufe zu 262,x ms. Bei Bei 6 LEDs kommen 
3 überhaupt nicht an die Reihe!

1.000.000  64  256 => 61,x Aufrufe zu je 16,x ms. Bei 6 LEDs kommt 
jede LED ca. 10 mal an die Reihe. Das flackert wahrscheinlich noch. 
Ausprobieren.

1.000.000  8  256 => 488,x Aufrufe zu je 2,x ms. Bei 6 LEDs bekommt 
jede LED ca. 80 mal die Möglichkeit jeweils für ca. 2ms zu leuchten. 
Zusammen dann etwa 160ms. Das ist 1/6tel Leuchtzeit einer 
nichtgemultiplexten LED.

Und noch schneller - Prescaler 1... Bereits Prescaler 8 geht deutlich 
auf Kosten der Zeitverteilung Userprogramm / Interruptprogramm. 
Irgendwann bekommt das Userprogramm seine Arbeit nicht mehr erledigt. 
Und noch schlimmer: bei zuviel Code in der ISR und zu kurzen Abständen 
gehen Interrupts verloren - es wird ungenau!

Wenn du ein Mittelding zwischen Prescaler 64 und Prescaler 8 haben 
willst, dann kannst du noch mit dem Startwert des Timers arbeiten. Statt 
die vollen 256 Schritte bis zum nächsten Overflow, dürfen es ja auch 
weniger sein. Hier kommen die verschiedenen Betriebsmodi des Timers ins 
Spiel, die den Startwert bzw. den Wert bei dem der Interrupt auftritt 
nutzen und ggf. automatisch nachladen.

OK. Das war jetzt das Dauerleuchten der LEDs. Jetzt zum Blinken z.B. mit 
1s an und 1s aus (1 Hz). Du kannst das in der ISR machen. Bei 
Prescalerfall 8 488 Aufrufe LED im Multiplex halten und brav anschalten. 
Dann 488 Aufrufe lang nicht anschalten! Dann muss aber die ISR wissen, 
welche LED Blinken sollen und welche Dauerleuchten und welche Aus sind. 
Das sind 3 Zustände und das passt nicht schön zu dem was unten noch 
kommt ;-)

Oder du kannst das im Userprogramm machen. Die ISR zählt nur Sekunden 
hoch (alle 488 Aufrufe Sekundenzähler um eins erhöhen) und im 
Userprogramm setzt du bei geraden Sekunden BLINKEN_AN und bei ungeraden 
Sekunden BLINKEN_AUS.

Das bringt das Thema Kommunikation zwischen ISR und Userprogramm auf. 
Woher weiss die ISR welche LEDs an und welche aus sein sollen? Hier gibt 
es den Weg über gemeinsame volatile definierte Variablen. Für An und Aus 
bietet sich eine Bitvariable an, weil das Platz spart.

volatile uint8_t led_zustand;

Im Userprogramm (im grossen while(1)) setzt du dann für eine LED die in 
der ISR über Multiplex angeschaltet werden soll das betreffende Bit in 
der Bitvariablen hier am Beispiel Blinken:

volatile uint8_t sekunden;

#define LED1 1

// Userprogramm
if (!(sekunden & 1)) // gerade Sekunden
  led_zustand |= (1<<LED1); // AN
else
  led_zustand &= ~(1<<LED1); // AUS

Oder wenn du das Blinken komplett in der ISR behandeln willst, dann 
kannst du zwei solche Bitvariablen nehmen. Ich rate aber davon ab, weil 
die dann notwendige Fallunterscheidung den Code in der ISR deutlich 
aufbläht.

#define LED1 1
#define LED2 2
volatile uint8_t led_daueran;
volatile uint8_t led_blinken;

// Userprogramm
led_daueran |= (1<<LED2); // LED2 an
led_blinken |= (1<<LED1); // LED1 blinken;

OK. die Aufgabe der ISR ist jetzt grob umrissen. Jetzt die Feinheiten. 
Beim Einstieg in die ISR werden zunächst alle LEDs ausgeschaltet.

Dann wird geschaut, welche von den 6 LEDs grundsätzlich beim Multiplexen 
dran ist. Hier wird mit einem statischen Zähler gearbeitet, der die 
Nummer der LED angibt. Die Nummer der LED kann man aus dem Zähler über 
den Modulo-Operator bekommen (zähler % 6 ergibt die Zahlen 5,4,...,1,0)

Für die betreffende LED wird geschaut, ob sie laut led_zustand leuchten 
soll. Soll sie, wird sie angeschaltet. Das kann man schön in ein switch 
packen.

Jetzt noch an die Sekunden fürs Blinken denken. Wenn der zähler 488 
erreicht hat, ist eine Sekunde verstrichen. Ups das sind mehr als 8-Bit! 
Also zahler 16 Bit gross machen ODER einfach halbesekunden zählen, d.h. 
244 Durchläufe... Fertig in der ISR.

Und der Fall oben mit den halbesekunden:
#define LED1 1
// Userprogramm
if (!(halbesekunden & 2)) // 0,0 bis 0,5 bis <1,0
  led_zustand |= (1<<LED1); // AN
else // // 1,0 bis 1,5 bis <2,0...
  led_zustand &= ~(1<<LED1); // AUS

von Bastler (Gast)


Lesenswert?

Hallo!!

Oje da hatte ich jetzt wieder zu kämpfen. Naja ich lerne dazu. Jetzt 
wird der Beitrag glaube ich bald geschlossen bei so vielen 
Einträgen!!“g“ Für diesen „Crashkurs“ könntest du ja wirklich Geld 
verlangen!!“g“
Zunächst nochmal zu den „\“ Zeichen. Ich habe da in meinem C-Buch auf 
die Schnelle nichts gefunden. Ich versteh das einfach mal so dass es das 
Gleiche wäre wenn ich alles in eine Zeile schreiben würde. Verstehen tu 
ich das nur nicht warum das so zusammenhängend sein muss. Kann ich da 
einfach sagen weil es in einer do/while Schleife einfach so ist dass des 
in einer Zeile sein muss? Do/while frägt ja im Unterschied zu while erst 
am Ende ab ob es weitergeht. Ich vermute mal das while(0) heißt dass es 
immer weiter geht…?  Andererseits sieht es mir unlogisch aus dass man 
hierfür überhaupt eine Schleife braucht. Rein von der Logik hätte ich 
gesagt könnte ich doch schreiben

#define LED_OFF (PORTA &= ~((1<<PA3)|(1<<PA7)|(1<<PA5)))

Unabhängig davon ergeben ja dann meine ganze #define-Befehle eine halbe 
bis ganze Seite. Ist das normal in der Programmierung???
Zu #define LED1_ON():
Ich definiere zunächst die Variable tmp. tmp = DDRA & MASKE; wird die 
LEDs wohl löschen. Warum muss da aber DDRA dabei sein??  Dann schreibe 
ich die Bits für die Datenrichtung in tmp und schreibe dies dann 
wiederrum in DDRA. Das letzte ist dann dass ich PORTA3 auf high setze. 
Nur den Anfang verstehe ich dabei eben nicht.
Zu dem mit do … while(0) habe ich jetzt gefunden dass man das macht wenn 
man mehrere Anweisungen in ein Makro packen möchte. Und while(0) heißt 
scheinbar einmal ausgeführt. Also sprich bei jedem Aufruf im Programm 
einmal. Ist das richtig?
Also ich bekomme jetzt alle LEDs so nacheinander zum leuchten. Das war 
mir klar dass immer nur eine leuchten kann. Das ist auch voll in 
Ordnung. Für die Batterie habe ich ein 7. LED vorgesehen. Das hat dann 
auch eine andere Farbe.
Also wegen dem Vorteiler. Ich brauche sicher nicht exakt eine Sekunde. 
Es wird keiner mit der Stopuhr da sitzen und schaun ob die LED exakt 
alle 4 Sekunden ein und ausgeht. Also bei dem 1024-Teiler könnte ich gut 
mit den 0,26.. Sekunden leben. Und für die 4 Sekunden nehme ich das hald 
mal 16. Also quasi 16 Überläufe. Wenn ich den Timer für Unterschiedliche 
Anwendungen benutze muss ich ja immer den gleichen Prescaler verwenden 
oder? Meinen Taster habe ich ja z.B. mit 80ms entprellt. Sprich hier 
könnte ich dann 3 Überläufe verwenden. Nur wie weiss der Timer dann wo 
er gerade steht?? Sagen mir das LED-Bat leuchtet. Dann wird der Taster 
Power Down betätigt. Dann muss er ja wissen wo muss ich einsteigen. 
Steigt er dann erst beim nächsten Überlauf mit 0 ein???
Das mit dem CTC Mode brauche ich dann wohl für den kap. Sensor. Da kann 
ich ja einen bestimmten Wert eingeben. Sprich die Spannung die erreicht 
werden soll oder? Und wenn er die erreicht hat dann weiss ich die Zeit. 
Das kann aber doch Timer0 auch. Du hast ja gemeint dazu benötige ich 
Timer1.
Also du würdest mir keinen 1024er-Vorteiler empfehlen. Sehe ich das 
richtig oder war das nur wegen dem Missverständnis dass 2 LEDs 
gleichzeitig leuchten sollen was ja nicht der Fall ist.
Also die ganzen Dinge mit dem Multiplexen kann ich dann wohl 
vernachlässigen wenn immer eine LED leuchten soll? So wie ich das 
verstanden habe steht dann in der ISR ganz wenig. Das wird ja wohl 
besser sein wenn ich das so löse weil ja auch noch das Entprellen dazu 
kommt. Dann mach ich die ISR nicht so voll.
Allerdings habe ich jetzt noch ein Denkproblem. Also angenommen ich 
nehme den Teiler 8. Was bedeutet das mit den 488,x Aufrufen?? Ich komme 
nie auf diese Zahl. Ich dachte immer bei dem Overflow muss ich die 
Anzahl der Überläufe zählen??? Sprich nach dem 4. Überlaufen oder was 
auch immer. Das kann man ja über TOV0 zählen lassen. Ich vermute mal 
wenn es zum ersten Mal überläuft dann steht da ne 1 drin. Durch die ISR 
wird’s dann wieder gelöscht. Ich dachte ich zähle da bis da 4 mal eine 1 
drinstand. Also werde ich der ISR auch noch sagen müssen mache beim 1., 
2. und 3. Überlauf nichts oder. Die ISR wird ja grundsätzlich ausgelöst 
beim Überlauf. Außer ich definiere des außerhalb so. Man kann doch den 
Teiler gar ned so groß machen dass ich eine Sekunde ohne Überlauf 
realisieren kann!! Bei 1024 komme ich ja auf 262,144ms. Also zunächst 
1000000 / 1024. Das Ergebnis als Kehrwert dann hab ich die Zeit für 1 
Erhöhung. Ich glaub Inkrement ist das. Bei mir sind das 1,024ms. Also 
immer alle Milisekunde wird der Timer eins mehr. Und das dann mal 256 = 
0,262144 s. Das mit den halben Sekunden verstehe ich nicht.
Ok. Also jetzt habe ich die 2,048ms. Sprich: Takt: 1MHz. Teiler =8. Nach 
genau 2,048ms läuft der Timer über. Das verstehst du jetzt wohl unter 
Aufrufen. Ok und die 488,28 habe ich jetzt auch. Wobei ich die noch ned 
ganz verstehe. Den Timertakt verstehe ich das ist der normale Clock 
durch den Vorteiler. Aber warum das dann geteilt durch 256??? Da Herz ja 
1/s ist heißt das quasi 488 mal ein Interrupt pro Sekunde!!! 
OKKKKKKKKKKKKKKK. Jetzt hab ichs geschnallt auch wenn es lange gedauert 
hat.
Naja erst noch mal Danke für die Erklärung. Ich werde jetzt versuchen da 
was zu basteln auch wenn es sich immer noch unglaublich schwer anhört.

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Zunächst nochmal zu den „\“ Zeichen. Ich habe da in meinem C-Buch auf
> die Schnelle nichts gefunden. Ich versteh das einfach mal so dass es das
> Gleiche wäre wenn ich alles in eine Zeile schreiben würde. Verstehen tu
> ich das nur nicht warum das so zusammenhängend sein muss. Kann ich da
> einfach sagen weil es in einer do/while Schleife einfach so ist dass des
> in einer Zeile sein muss? Do/while frägt ja im Unterschied zu while erst
> am Ende ab ob es weitergeht. Ich vermute mal das while(0) heißt dass es
> immer weiter geht…?  Andererseits sieht es mir unlogisch aus dass man
> hierfür überhaupt eine Schleife braucht. Rein von der Logik hätte ich
> gesagt könnte ich doch schreiben
>
> #define LED_OFF (PORTA &= ~((1<<PA3)|(1<<PA7)|(1<<PA5)))

Du könntest es so schreiben. Es wird aber bei grösseren Sachen leicht 
unübersichtlich und da ist es in mehreren Zeilen angenehmer zu lesen.

Das Verhalten von \ am Ende von Zeilen ist z.B. im folgenden PDF in 
Abschnitt 5.1.1.2 Translation phases beschrieben. Dort wird beschrieben, 
wie ein C-Quellcode übersetzt wird.
http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1124.pdf

"Each instance of a backslash character (\) immediately followed by a 
new-line character is deleted, splicing physical source lines to form 
logical source lines. Only the last backslash on any physical source 
line shall be eligible for being part of such a splice. A source file 
that is not empty shall end in a new-line character, which shall not be 
immediately preceded by a backslash character before any such splicing 
takes place."

Das müsste aber auch in üblichen C-Büchern drin stehen.

Der Grund für die do...while(0) Klammer in den Makros ist z.B. hier 
erklärt: http://www.rtems.com/ml/rtems-users/2001/august/msg00086.html

> Unabhängig davon ergeben ja dann meine ganze #define-Befehle eine halbe
> bis ganze Seite. Ist das normal in der Programmierung???

ja. Wenn das stört, kann man die Makros in eine Headerdatei stecken.

> Zu #define LED1_ON():
> Ich definiere zunächst die Variable tmp. tmp = DDRA & MASKE; wird die
> LEDs wohl löschen.
> Warum muss da aber DDRA dabei sein??  Dann schreibe
> ich die Bits für die Datenrichtung in tmp und schreibe dies dann
> wiederrum in DDRA. Das letzte ist dann dass ich PORTA3 auf high setze.
> Nur den Anfang verstehe ich dabei eben nicht.

Noch nicht. Nachlesen kannst du die Technik mit der Maske in 
Bitmanipulation

Die Zeile ist da, um den Zustand von DDRA zu holen und um mit der Maske 
die LED-Pins in DDR0 auf 0 zu setzen und die Nicht-LED-Pins zu schützen 
(so zu lassen wie sie sind). In den folgenden Anweisungen wird in tmp 
der wunschzustand für DDR der LED-Pins reingeodert. Dann wird DDRA *in 
einem Rutsch* gesetzt. Die Konstruktion mit der Hilfsvariable tmp ist 
dafür da, dass man DDRA (bzw. später PORTA) in einem Rutsch setzen kann.

> Zu dem mit do … while(0) habe ich jetzt gefunden dass man das macht wenn
> man mehrere Anweisungen in ein Makro packen möchte. Und while(0) heißt
> scheinbar einmal ausgeführt. Also sprich bei jedem Aufruf im Programm
> einmal. Ist das richtig?

Ja siehe oben.

> Also ich bekomme jetzt alle LEDs so nacheinander zum leuchten. Das war
> mir klar dass immer nur eine leuchten kann. Das ist auch voll in
> Ordnung. Für die Batterie habe ich ein 7. LED vorgesehen. Das hat dann
> auch eine andere Farbe.

Ich glaube du hast akute Featuritis. Ist aber nicht schlimm ;-)

> Also wegen dem Vorteiler. Ich brauche sicher nicht exakt eine Sekunde.
> Es wird keiner mit der Stopuhr da sitzen und schaun ob die LED exakt
> alle 4 Sekunden ein und ausgeht. Also bei dem 1024-Teiler könnte ich gut
> mit den 0,26.. Sekunden leben. Und für die 4 Sekunden nehme ich das hald
> mal 16. Also quasi 16 Überläufe. Wenn ich den Timer für Unterschiedliche
> Anwendungen benutze muss ich ja immer den gleichen Prescaler verwenden
> oder?

Wie gesagt, ich denke mit Prescaler 1024 funktioniert das Multiplexen 
der vielen LEDs nicht.

> Meinen Taster habe ich ja z.B. mit 80ms entprellt. Sprich hier
> könnte ich dann 3 Überläufe verwenden. Nur wie weiss der Timer dann wo
> er gerade steht??

Der Timer kann doch in der ISR eine Variable hochzählen, die du anlegst. 
Im Programm schaust du in der Variablen nach, wieviele Aufrufe der Timer 
hat, dann wartest du bis x weitere Aufrufe stattgefunden haben.

> Sagen mir das LED-Bat leuchtet. Dann wird der Taster
> Power Down betätigt. Dann muss er ja wissen wo muss ich einsteigen.
> Steigt er dann erst beim nächsten Überlauf mit 0 ein???

Auf Power Down reagiert dein Userprogramm, d.h. der Teil in dem while(1) 
in main(). Die ISR vom Timer hat damit zunächst nichts zu tun.

Im Userprogramm weisst du du musst schlafen gehen. Dann schaltest du die 
LEDs aus und lässt den µC pennen gehen. Nach dem Wecken setzt du wieder 
den LED-Zustand von vor dem Pennen und weiter geht es.

> Das mit dem CTC Mode brauche ich dann wohl für den kap. Sensor. Da kann
> ich ja einen bestimmten Wert eingeben. Sprich die Spannung die erreicht
> werden soll oder? Und wenn er die erreicht hat dann weiss ich die Zeit.
> Das kann aber doch Timer0 auch. Du hast ja gemeint dazu benötige ich
> Timer1.

Nein, das ist noch eine komplett andere Geschichte.

Im Moment bist du noch am Timer0 am bauen. Und der ist nur als Zeitgeber 
für das Multiplexen der LEDs und ggf. als Ticker für 
Sekunden/Halbsekunden o.ä. am arbeiten.

Die Messung der Kapazität des Sensors ist eine Sache vom Analog 
Comparator und der Input Capture Unit eines anderen Timers. Da ist noch 
Hirnschmalz gefordert. So weit bin ich auch noch nicht; muss ich mir bei 
Elm Chan ansehen. Ich hatte ja geschrieben, dass ich sowas noch nie 
gemacht habe.

> Also du würdest mir keinen 1024er-Vorteiler empfehlen. Sehe ich das
> richtig oder war das nur wegen dem Missverständnis dass 2 LEDs
> gleichzeitig leuchten sollen was ja nicht der Fall ist.

Auch wegen dem Bedienen von >3 LEDs überhaupt und weil flackerndes 
Dauerleuchten hässlich wäre.

> Also die ganzen Dinge mit dem Multiplexen kann ich dann wohl
> vernachlässigen wenn immer eine LED leuchten soll? So wie ich das
> verstanden habe steht dann in der ISR ganz wenig. Das wird ja wohl
> besser sein wenn ich das so löse weil ja auch noch das Entprellen dazu
> kommt. Dann mach ich die ISR nicht so voll.

Du darfst nicht die Menge an Code in der ISR mit der Zeitdauer in der 
ISR verwechseln. Es wird nicht bei jedem Interrupt der komplette Code in 
der ISR ausgeführt! Es gibt einen gemeinsamen Teil und einen Teil für 
die jeweilige LED. Die Auswahl der jeweiligen LED kann man z.B. mit dem 
switch sehr schnell auswählen. Der Code für die restlichen LED kommt in 
den folgenden Aufrufen an die Reihe.

> Allerdings habe ich jetzt noch ein Denkproblem. Also angenommen ich
> nehme den Teiler 8. Was bedeutet das mit den 488,x Aufrufen?? Ich komme
> nie auf diese Zahl. Ich dachte immer bei dem Overflow muss ich die
> Anzahl der Überläufe zählen??? Sprich nach dem 4. Überlaufen oder was
> auch immer. Das kann man ja über TOV0 zählen lassen. Ich vermute mal
> wenn es zum ersten Mal überläuft dann steht da ne 1 drin. Durch die ISR
> wird’s dann wieder gelöscht. Ich dachte ich zähle da bis da 4 mal eine 1
> drinstand. Also werde ich der ISR auch noch sagen müssen mache beim 1.,
> 2. und 3. Überlauf nichts oder. Die ISR wird ja grundsätzlich ausgelöst
> beim Überlauf. Außer ich definiere des außerhalb so. Man kann doch den
> Teiler gar ned so groß machen dass ich eine Sekunde ohne Überlauf
> realisieren kann!! Bei 1024 komme ich ja auf 262,144ms. Also zunächst
> 1000000 / 1024. Das Ergebnis als Kehrwert dann hab ich die Zeit für 1
> Erhöhung. Ich glaub Inkrement ist das. Bei mir sind das 1,024ms. Also
> immer alle Milisekunde wird der Timer eins mehr. Und das dann mal 256 =
> 0,262144 s.

Und wenn du deine Rechnung mit anderen Prescalerwerten machst?

1.000.000 / 8 dann Kehrwert: Zeit für eine Erhöhung 0,000008 Sekunden (8 
µs). Das mal 256 sind dann 0,002048 s (2,048 ms) zwischen den 
Overflow-Interrupts.

1s sind 1000ms. Durch 2,048 ms sind... 488,28125 Overflow-Interrupts in 
1einer Sekunde!

Wenn du mit Ganzzahlen rechnest (wie oben mit den 4) also mit 488 statt 
488,28125, dann ist deine ungenaue "Sekunde" 0,999424 s lang, also etwas 
zu kurz.

> Das mit den halben Sekunden verstehe ich nicht.

Um in der ISR Sekunde zu zählen, muss man dort bis 488 zählen. Die 
Halbesekunde ist nur eine Hilfskonstruktion, damit in der ISR keine 
Zählvariable gebraucht wird, in die 488 reinpasst. Um Halbesekunden zu 
zählen muss man nur bis 244 zählen. Und das passt in ein Byte.

Man könnte auch wesentlich feiner zählen z.B. in 80ms Schritten (=ca. 40 
Overflows). Vielleicht fällt dir auf, wo man die 80ms gut gebrauchen 
könnte...

> Ok. Also jetzt habe ich die 2,048ms. Sprich: Takt: 1MHz. Teiler =8. Nach
> genau 2,048ms läuft der Timer über. Das verstehst du jetzt wohl unter
> Aufrufen. Ok und die 488,28 habe ich jetzt auch. Wobei ich die noch ned
> ganz verstehe. Den Timertakt verstehe ich das ist der normale Clock
> durch den Vorteiler.

Mist hätte ich mal weiterlesen sollen, bevor ich erkläre. Zweites Mal 
reingefallen.

> Aber warum das dann geteilt durch 256???

Um von den Timertakten auf die Abstände der Overflow-Interrupte zu 
kommen. Nach 256 Timertakten kommt der Oberflow-Interrupt. Bzw. kann man 
durch Vorbelegung des Timerzählers weniger als 256 Timertakte erhalten.

> Da Herz ja
     ^^^^ Hertz!
> 1/s ist heißt das quasi 488 mal ein Interrupt pro Sekunde!!!
> OKKKKKKKKKKKKKKK. Jetzt hab ichs geschnallt auch wenn es lange gedauert
> hat.

Siehst du!

von Bastler (Gast)


Lesenswert?

Guten Morgen!

Ok jetzt habe ich wieder was gelernt mit den Masken. Ich kann ja 
Kommentare auch nicht nach dem "\" schreiben sondern nur innerhalb.
Ok das mit der Variablen temp ist mir auch klarer geworden. Ich habe 
jetzt für jede LED eine andere Variable temp benutzt also temp1 temp2 
temp3 usw. Ist das nötig. Doch eigentlich nicht weil ja immer nur eine 
LED aufgerufen wird und dann keine Verwechslungsgefahr besteht oder? 
Noch eine Sache zu
tmp=DDRA & MASKE. Also DDRA kann ja theoretisch irgendein Zustand sein. 
MASKE da sind definitiv alle Zustände der LED PORTs auf 0. Wenn ich 
verunde und eine Null dabei ist habe ich als Ergebnis immer 0. Klar. Ich 
schreibe das in tmp. Dann müßte ich doch aber erst sagen DDRA|= tmp;. 
Dann ist tmp auf DDRA drauf. In der nächsten Zeile wird ja tmp schon 
wieder mit dem Wunschzustand der LEDs beschrieben. Sprich es wird nur 
tmp "gelöscht" aber nicht die LEDs an DDRA. Ist das richtig? Also Ziel 
war nicht die LEDs erst mal abzuschalten. Das kommt dann erst anfangs in 
Main oder?
Jetzt noch mal zu der Sache mit dem Multiplexen. Also darunter verstehst 
du das Blinken der roten Lampe? Oder die Sache dass 6 LEDs an 3 
Leitungen hängen (dieses Problem ist ja aber über define gelöst und kann 
dann ja immer zuordnen und kann sagen LED2_ON bei diesem Wert usw? Oder 
verstehst du unter Multiplexen dass die LEDs nicht dauernd an sind 
sondern in einer ganz hohen Frequenz leuchten und das Auge des als 
Dauerleuchten ansieht. Also auf letzteres zum Stromsparen glaube ich 
könnte man verzichten. Und es müssen auch keine 2 LEDs gleichzeitig 
leuchten immer nur eine. Also der Übergang so wie mit den 3 LEs. Ganz 
einfach also.
Was den Vorteiler betrifft habe ich aber trotzdem auf Vorteiler 8 
umgedacht so wie du angedacht hast. Das werde ich machen.
Also die Information wo der Timer gerade steht bekommt die LED und der 
Taster durch die ISR. Läuft der Timer dann erst an wenn er das erste mal 
gefordert wird? Also sagen wir mal es ist so nass das rot leuchtet (rot 
soll ja blinken). Genau dann wenn rot gefordert ist läuft mein Timer los 
und erzeugt mir hier ein blinken mit 1 Mal pro Sekunde. Angenommen wenn 
jetzt genau in dem Moment die Batterie schwach wird dann sieht die 
Routine für die BatterieLED in der ISR nach und sieht ok mein Timer 
steht auf sagen wir mal 111 (von 255). Die Batterieled weiss aber sie 
braucht x-Aufrufe und die Aufrufe beziehen sich ja darauf dass der Timer 
von 0 wegläuft. Also kommt der erste Aufruf bei 111 ja schon nach glaube 
ich 144. Sprich er muss nach dem x-ten Umlauf kappieren es fehlt ja noch 
was weil der Timer ja bei 111 stand wo es losging. Sprich er müsste nach 
meiner Theorie dann nochmal bis 144 zählen dass er genau die x-Aufrufe 
erreicht. Analog dazu dann natürlich der Taster Power Down mit der 
Entprellung. Wo liegt der Fehler in meinem Denkprozess wenn es denn 
einen gibt?
OK. Das mit dem CTC vergesse ich erstmal. War nur ein Geistesblitz weil 
ich dachte des braucht man da.
Tut mir leid. Ich lese oft was frage dann und verstehe es nachträglich. 
Erst denken dann schreiben! Werde ich mir merken.
Also der ganze Spass mit dem Timmer einstellen. Startwert des Timers, 
select interrupt passiert wie ichs gemacht habe in meinem main.
Mal sehen wie ich das jetzt hinbekomme. Das in der ISR ist noch bisschen 
ein Problem. Allerdings hilft mir das mit switch case und dass es etwas 
gibt was für alle Komponenten ist und dann für die einzelnen.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:
> Guten Morgen!

Mahlzeit ;-)

>
> Ok jetzt habe ich wieder was gelernt mit den Masken. Ich kann ja
> Kommentare auch nicht nach dem "\" schreiben sondern nur innerhalb.
> Ok das mit der Variablen temp ist mir auch klarer geworden. Ich habe
> jetzt für jede LED eine andere Variable temp benutzt also temp1 temp2
> temp3 usw. Ist das nötig. Doch eigentlich nicht weil ja immer nur eine
> LED aufgerufen wird und dann keine Verwechslungsgefahr besteht oder?


Die Variable ist innerhalb des do ... while im Makro angelegt und nur 
dort belegt sie auch Platz auf dem Stack oder einem Register (jenachdem 
was der Compiler frei hat). Wie die heisst, ist piepegal.

> Noch eine Sache zu
> tmp=DDRA & MASKE. Also DDRA kann ja theoretisch irgendein Zustand sein.
> MASKE da sind definitiv alle Zustände der LED PORTs auf 0. Wenn ich
> verunde und eine Null dabei ist habe ich als Ergebnis immer 0. Klar. Ich
> schreibe das in tmp. Dann müßte ich doch aber erst sagen DDRA|= tmp;.
> Dann ist tmp auf DDRA drauf. In der nächsten Zeile wird ja tmp schon
> wieder mit dem Wunschzustand der LEDs beschrieben. Sprich es wird nur
> tmp "gelöscht" aber nicht die LEDs an DDRA. Ist das richtig? Also Ziel
> war nicht die LEDs erst mal abzuschalten. Das kommt dann erst anfangs in
> Main oder?

Das Makro zeilenweise erklärt...

#define MASKE (~((1<<PA3) | (1<<PA7) | (1<<PA5)))

Die MASKE sieht jetzt so aus:
PA:76543210
   01010111

#define LED_OFF()
  do              \
  {               \
     PORTA &= MASKE; /* alle LEDs aus */ \
  } while (0)

Bsp:
PORTA  #x#x#xxx
MASKE  01010111
Ergeb. 0x0x0xxx

D.h. Nur die Pins PA3, PA5, PA7 werden gelöscht. In diesem Zustand 
leuchtet keine der LEDs die mit Charliemultiplex angeschlossen sind.

//
// LED1_ON
//   PA3 Output HIGH
//   PA7 Output LOW
//   PA5 Input Z
//
#define LED1_ON() \
  do              \
  {               \
     uint8_t tmp; \

Das ist die zeitweilige Hilfsvariable. Sie ist nur zwischen dem 
umschliessenden {} gültig (s. oben)

     /* hier LED_OFF() bzw. am Anfang der ISR */ \

Man kann alle LED hier beim Code für die einzelne LED ausschalten oder 
zentral einmal bevor die Codestücke für die einzelnen LEDs aktiv sind. 
Letztes spart Code.

     tmp = DDRA & MASKE; \

Bsp:
DDRA   #x#x#xxx
MASKE  01010111
tmp    0x0x0xxx
DDRA   #x#x#xxx

DDRA ist noch nicht geändert!

     tmp |= (1<<PA3) | (1<<PA7) | (0<<PA5); \

Hier bauen wir das den neuen Wert für DDRA auf, der später gesetzt wird

     DDRA = tmp; \

Da ist das Setzen in einem Rutsch

     PORTA |= (1<<PA3); \

Und zum Abschluss Vcc auf einen Pin geben. Die anderen PORTA Pins für 
diese LED sind vom Löschen er noch 0 und brauchen hier nicht 
berücksichtigt zu werden. Ab jetzt leuchtet die LED.

  } while (0)

> Jetzt noch mal zu der Sache mit dem Multiplexen. Also darunter verstehst
> du das Blinken der roten Lampe?

Das nicht. Das Blinken wird anders gelöst.

> Oder
> verstehst du unter Multiplexen dass die LEDs nicht dauernd an sind
> sondern in einer ganz hohen Frequenz leuchten und das Auge des als
> Dauerleuchten ansieht.

Letzeres und mehr, nämlich überhaupt in einer gegebenen Zeit alle LEDs 
bedienen zu können.

1,2,3,... steht für die jeweilige LED
# steht für Ende/Beginn ISR
Die Zeit läuft von links nach rechts
------------------- Zeit ---------------------->

Man kann die LEDs so leuchten lassen
11111111111#22222222222#33333333333#44444444444#55555555555#66666666666. 
..

Oder so
1#2#3#4#5#6#1#2#3#4#5#6#1#2#3#4#5#6#1#2#3#4#5#6#1#2#3#4#5#6#1#2#3#4#5#6. 
..

Angenommen der Zeitstrahl ist eine 1s lang (260ms * 4), dann schaffst du 
bei Methode 1 nur ein Leuchten bei LED1 bis LED4. Die LED5 und LED6 
kommen nicht an die Reihe bzw. kommen in der folgenden Sekunde dran, 
knappsen aber Zeit von zwei anderen LEDs ab. Beobachtet man die LED1, 
sieht man in 1s ein 260ms Hell und 3*260ms Dunkel. Also Blinken, obwohl 
man vielleicht ein Dauerleuchten wollte! Das Blinken ist systembedingt 
beim Multiplexen da!

bei Methode 2, dort wo die ISR häufiger aufgerufen wird (kleinerer 
Prescaler), kommen a. alle LEDs an die Reihe und b. die Zeit zwischen 
dem Drankommen einer LED ist deutlich kürzer. Bei geeignete schnellem 
Wechsel verschmilzt das schnelle Blinken im Auge zu einem Dauerleuchten!

Bei dieser einfachen Darstellung sieht man auch gut noch was anderes! 
Der Overhead # für das Anspringen/Beenden der ISR ist mei Methode 2 
deutlich grösser. Die nutzbare Rechenzeit (Anzahl Systemtakte) ist 
insgesamt geringer. Eine beliebige Steigerung der Frequenz der ISR 
Aufrufe ist nicht möglich.

Jetzt zur Arbeitsweise von ISR und Userprogramm:

------------------------- Zeit (1s) --------------------------------->
Das Userprogramm macht beim 0,5sAN / 0,5s AUS Blinken von LED3 alleine:
Wenn 1. Halbsekunde: led_zustand |= (1<<LED3);  // AN
Wenn 2. Halbsekunde: led_zustand &= ~(1<<LED3); // AUS

Der Inhalt von Bit LED3 in led_zustand ist also:
11111111111111111111111111110000000000000000000000000000000000000000000

Die ISR macht generell:
1#2#3#4#5#6#1#2#3#4#5#6#1#2#3#4#5#6#1#2#3#4#5#6#1#2#3#4#5#6#1#2#3#4#5#6. 
..

Die Aktion für LED3 wird jetzt nur durchgeführt, wenn der Inhalt von 
Inhalt von Bit LED3 in led_zustand 1 ist

1#2#3#4#5#6#1#2#3#4#5#6#1#2#3#4#5#6#1#2#3#4#5#6#1#2#3#4#5#6#1#2#3#4#5#6. 
..
    1           1           1           0           0           0
          "Leuchtzeit"                          "Dunkelzeit"

> Also auf letzteres zum Stromsparen glaube ich
> könnte man verzichten. Und es müssen auch keine 2 LEDs gleichzeitig
> leuchten immer nur eine. Also der Übergang so wie mit den 3 LEs. Ganz
> einfach also.

Es ist nicht zum Stromsparen gedacht, abwohl das ein positiver 
Nebeneffekt sein kann (den man auch per grösseren Vorwiderstand 
erreichen könnte).

> Was den Vorteiler betrifft habe ich aber trotzdem auf Vorteiler 8
> umgedacht so wie du angedacht hast. Das werde ich machen.
> Also die Information wo der Timer gerade steht bekommt die LED und der
> Taster durch die ISR. Läuft der Timer dann erst an wenn er das erste mal
> gefordert wird? Also sagen wir mal es ist so nass das rot leuchtet (rot
> soll ja blinken). Genau dann wenn rot gefordert ist läuft mein Timer los
> und erzeugt mir hier ein blinken mit 1 Mal pro Sekunde.

Kommt darauf an, was du dem Timer an Aufgaben zuteilst und wie dein 
Messablauf bzw. die Gerätefunktion aussieht.

Man könnte die Gerätefunktion grob strukturieren:

1. Einschalten
2. Batterie checken
3. Batteriecheck anzeigen
4. Tasteneingabe (EIN/AUS) prüfen
5. Feuchte messen
6. Feuchte anzeigen
7. Option: Laufzeit prüfen
8. ggf. Wecker stellen und Schlafen legen
9. wiederholen bei 4. oder 2.

Wenn der Timer nur die LED Anzeige macht, braucht er nur bei 3 und 6 zu 
laufen.

Wenn der Timer zusätzlich die 80ms für die Entprellung abpasst, wird er 
zusätzlich bei 4. laufen.

Wenn der Timer optional die Laufzeit überwacht, wird er zusätzlich bei 
7. laufen; ja im Prinzip während des gesamten Programms ausser 
vielleicht bei den eigentlichen Messungen. man würde dann auch die 
"Trigger"-Konstruktion rauswerfen und mit der hochgezählten Zeit des 
Timers arbeiten. Beispiel: Batteriecheck immer einmal beim Einschalten 
und dann alle 60 Sekunden. Feuchtemessung nach dem Einschalten und dann 
alle 2 Sekunden. Länger als 5 Min. starrt keiner auf das Gerät, deshalb 
nach 5 Min. automatisch abschalten (Schlafen).

> Angenommen wenn...

Diese Frage vielleicht noch mal stellen, wenn die Gerätefunktion / der 
Ablauf festgelegt ist.

> OK. Das mit dem CTC vergesse ich erstmal. War nur ein Geistesblitz weil
> ich dachte des braucht man da.

CTC kann man vorteilhaft nutzen, wenn man nicht mit 256 Schritten 
zwischen den ISRs leben will. Man könnte zwar ohne CTC den Timerzähler 
statt bei 0 z.B. bei 127 loslaufen lassen. Dann hat man 128 Schritte bis 
zum nächsten Timer-Overflow. Dafür müsste man in der ISR eine Anweisung 
Timerzähler = 127; schreiben. ODER man füllt ein Hardwareregister des 
Timers mit dem Wunschwert bei dem der Interrupt kommen soll (der Vektor 
heisst dann nur anders) aber ab dann ist keine extra Anweisung in der 
ISR notwendig! Das ist der CTC Modus.

Fang einfach an. Schreib zunächst dein obiges Testprogramm für die LEDs 
weiter. Das ergänzen mit Taster/Messung/Schlafen kommt dann im zweiten 
Schritt.

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Guten Morgen!

Also ehrlich gesagt bin ich mir immer noch nicht sicher ob wir beide das 
richtige meinen. Ich möchte da nochmal darauf zurückkommen. Also der 
Betauungssensor hat ja nur 3 LEDs die an 3 Ports hängen. Bei diesen LEDs 
soll nur die rote blinken. Also ganz einfach.
Der kapazitive Sensor hat 6 LEDs weil der ja hoffentlich genauer ist. 2 
rote 2 gelbe und 2 grüne LEDs. Die grünen sollen in ihrem Bereich 
jeweils Dauerleuchten. Also ganz trocken 1. grüne. Bei vielleicht 20 
%rel. Feuchte die 2. grüne LED. Das blinken soll erst bei den gelben 
beginnen. SAgen wir mal bei der 4. LED. Die erste gelbe soll Dauerlicht 
sein. Die 4. gelbe soll vielleicht mit 1Hz blinken. Die erste rote mit 
doppelt so schnell und die letzte rote LED wieder doppelt so schnell. 
Das wäre meine theoretische Vorstellung. Darum dachte ich man kann da so 
ne allgemeine Blinkroutine entwerfen und kann die dann jeweils bisschen 
abgeändert auf diese drei LEDs anwenden.
Du bist ja glaube ich immer noch bei dem Multiplexen. Dass alle LEDs 
quasi "blinken" nur dass man es hald nicht bei allen sieht. Ich weiss 
hald nicht ob das für mich dann zu kompliziert wird fürn Anfang.
Bei 1111111#2222222# usw. vergeht also mehr Zeit. Unglaublich wie 
untalentiert ich dabei bin. Ich kann mir das einfach sehr schwer 
vorstellen was da abgeht. Würde es ohne Multiplexen leichter???? Also 
sprich LED 1-3 Dauerleuchten und nur LED 4-6 Blinken??? Das mit dem 
Strom sollte ja kein Problem sein weil man das Gerät ja nach Benutzung 
in den Power Down versetzt. Vielleicht habe ich das auch noch nicht so 
gesagt. Das wären ja auch alles gleich lange Abläufe oder??? Kann man 
das varieren. Es sollen ja nicht alle LEDs gleichschnell blinken dann. 
Ich vermisse hald in allen ISR das Flag wo der Überlauf eingetragen 
wird. Habe mir das tutorial angeschaut und noch zwei Bücher. Irgendwie 
scheint ja das volatile sowas ähnliches zu machen. Da wird ja irgendwas 
hochgezählt oder eingetragen was in diese Richtung geht.
Nochmal zum Ablauf der Lampenfolge
Es geht von LED 1 auf 6 und dann natürlich wieder zurück von 6 auf 1 
wenn es trockener wird. ICh denke mal das hast du ja auch gedacht.
Moment das ist nicht zum Stromsparen?????????????????? Wofür dann?? Weil 
das sauberes programmieren ist??? Oder weil der Übergang fließender 
ist????? Warum macht man das so???
Also das mit der Gerätefunktion ist jetzt wieder klarer. Das ist jetzt 
auch allgemeiner.


1. Einschalten
2. Batterie checken
3. Batteriecheck anzeigen
4. Tasteneingabe (EIN/AUS) prüfen
5. Feuchte messen
6. Feuchte anzeigen
7. Option: Laufzeit prüfen
8. ggf. Wecker stellen und Schlafen legen
9. wiederholen bei 4. oder 2.


Ideal wäre es natürlich wenn der Timer alles machen würde. Das Blinken 
der LED beim Batteriecheck. Das Blinken der Sensor LEDs und das 
Tasterentprellen. DAs gilt für Betauungssensor und kap. Sensor.
Ich bin jetzt erstmal stolz dass ich ein Programm habe das keine Fehler 
bringt auch wenn ich nur ein Dauerleuchten von LED5 erziehlt habe!!"g" 
Der Code ist im Anhang oben. Habe da auch bissl rumprobiert aber das ist 
wieder auskommentiert. Vielleicht kannst du mir ja sagen ob das mit dem 
Timer einstellen in main so in Ordnung ist


Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

Morschen!

> Also ehrlich gesagt bin ich mir immer noch nicht sicher ob wir beide das
> richtige meinen. Ich möchte da nochmal darauf zurückkommen. Also der
> Betauungssensor hat ja nur 3 LEDs die an 3 Ports hängen. Bei diesen LEDs
> soll nur die rote blinken. Also ganz einfach.

> Der kapazitive Sensor hat 6 LEDs weil der ja hoffentlich genauer ist. 2
> rote 2 gelbe und 2 grüne LEDs. Die grünen sollen in ihrem Bereich
> jeweils Dauerleuchten.
> Also ganz trocken 1. grüne.
> Bei vielleicht 20 %rel. Feuchte die 2. grüne LED.
> Die erste gelbe soll Dauerlicht sein.
> Die 4. gelbe soll vielleicht mit 1Hz blinken.
> Die erste rote mit doppelt so schnell und
> die letzte rote LED wieder doppelt so schnell.
> Das wäre meine theoretische Vorstellung. Darum dachte ich man kann da so
> ne allgemeine Blinkroutine entwerfen und kann die dann jeweils bisschen
> abgeändert auf diese drei LEDs anwenden.

Ich versuche in deinen Fragen rauszulesen, um welche Hardware es jeweils 
gehen soll. Vielleicht machst du es mir einfacher und schreibst jeweils 
in getrennten Beiträgen nur zu einer Hardware (und dem jeweiligen 
Programm). Oder du trennst in einem Beitrag mit fetten Überschriften.

> Du bist ja glaube ich immer noch bei dem Multiplexen. Dass alle LEDs
> quasi "blinken" nur dass man es hald nicht bei allen sieht. Ich weiss
> hald nicht ob das für mich dann zu kompliziert wird fürn Anfang.
> Bei 1111111#2222222# usw. vergeht also mehr Zeit. Unglaublich wie
> untalentiert ich dabei bin. Ich kann mir das einfach sehr schwer
> vorstellen was da abgeht. Würde es ohne Multiplexen leichter????

Es geht auch ohne das Multiplexen im Timer. IMHO ist es uneleganter, 
aber es geht, wenn nie mehr als eine der über Charlieplexing 
angeschlossenen LEDs gleichzeitig aktiv sein müssen.

> Also
> sprich LED 1-3 Dauerleuchten und nur LED 4-6 Blinken??? Das mit dem
> Strom sollte ja kein Problem sein weil man das Gerät ja nach Benutzung
> in den Power Down versetzt. Vielleicht habe ich das auch noch nicht so
> gesagt. Das wären ja auch alles gleich lange Abläufe oder??? Kann man
> das varieren. Es sollen ja nicht alle LEDs gleichschnell blinken dann.
> Ich vermisse hald in allen ISR das Flag wo der Überlauf eingetragen
> wird.
> Habe mir das tutorial angeschaut und noch zwei Bücher. Irgendwie
> scheint ja das volatile sowas ähnliches zu machen. Da wird ja irgendwas
> hochgezählt oder eingetragen was in diese Richtung geht.

Das "Flag" ist eine von dir angelegte Zählvariable. Die muss global und 
volatile sein, wenn in der ISR und im Userprogramm z.B. in main() darauf 
zugegriffen wird.

> Nochmal zum Ablauf der Lampenfolge
> Es geht von LED 1 auf 6 und dann natürlich wieder zurück von 6 auf 1
> wenn es trockener wird. ICh denke mal das hast du ja auch gedacht.

Die Entscheidung welche LED geschaltet wird macht das Userprogramm. 
Entweder die feuchtemessung() selbst oder die aufrufende Routine über 
den Rückgabewert von feuchtemessung().

> Moment das ist nicht zum Stromsparen?????????????????? Wofür dann?? Weil
> das sauberes programmieren ist??? Oder weil der Übergang fließender
> ist????? Warum macht man das so???

Weil es "eleganter" ist und um alle Optionen zu haben. Bsp. statt 6 
Stufen beim kap. Messgerät, hättest du so 11 Stufen:

LED1
LED1 + LED2
LED2
LED2 + LED3
...
LED5 + LED6
LED6

> Ich bin jetzt erstmal stolz dass ich ein Programm habe das keine Fehler
> bringt auch wenn ich nur ein Dauerleuchten von LED5 erziehlt habe!!"g"
> Der Code ist im Anhang oben.

Ich simuliere es mal heute abend im AVR Studio...

> Habe da auch bissl rumprobiert aber das ist
> wieder auskommentiert. Vielleicht kannst du mir ja sagen ob das mit dem
> Timer einstellen in main so in Ordnung ist

Hier ein Tipp: Statt Codeteile wie in
1
  /*if(count == 1)
2
  {
3
  ...

mit /* */ auszukommentieren, mache das z.B. so
1
#if 0
2
  if(count == 1)
3
  {
4
  ...
5
#endif

Das ist übersichtlicher und weniger fehlerträchtig, besonders wenn im 
auskommentieren Codeteil selbst noch /* */ Kommentare stehen.

Du kannst auch Makros verwenden und die am Quellcodeanfang je nach zu 
testender Funktion schalten:
1
// 1 für zu prüfenden Codeteil an / 0 für aus
2
#define TESTVERSION 0 
3
4
...
5
6
#if TESTVERSION
7
  if(count == 1)
8
  {
9
  ...
10
#endif /* TESTVERSION */

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!!

So in meiner ersten Mail erstmal wieder ein paar Codes die aber nur 
teils funktionieren. Habe es so konfiguriert wie du vorgeschlagen hast. 
Testversion 3 läuft zumindest schon mal so weit dass nach ca.3 Sekunden 
die LED angeht und nach weiteren 3 Sekunden wieder erlischt. Allerdings 
funktioniert das mit while(1) auch nicht dauern. Ich kann mir nur 
vorstellen dass Zeit oder takt nicht zurückgesetzt wird und der Zähler 
immer weiter hochläuft. Aber rein von der Sache ist das ja schon mal 
ganz ok.
Ich werde in der nächsten Email auch gleich den Stromlaufplan schicken. 
Eigentlich unterscheiden sich meine beiden Hardwares ja nur durch die 
LEDs bzw die spätere Schaltung für den kap. Feuchtesensor. Ich bin 
derzeit nur noch an der Platine am spielen die auch die 6 LEds enthält. 
Für den Betauungssensor den ich jetzt auch nochmal hier aufgebaut habe 
werde ich hald nur 3 LEDs ansteuern. Ist ja nur ein Prototyp.
Bei meinem Talent werde ich wohl auf die Sache mit dem Multiplexen erst 
mal verzichten. Es muss ja wirklich nur immer eine LED leuchten und da 
ist mir der Übergang auch nicht so wichtig. Schließlich kann ich hier 
einiges vereinfachen wenn ich das erstmal ausspare. Und auch so ist der 
Zweck für mich erst einmal erfüllt.
Die Initialisierung des Timers habe ich jetzt in einem eigenem 
unterprogramm erledigt weil ich mir dachte das ist eleganter. 
Testversion 3 benützt außerdem anstatt des 8er Teilers den 64er Teiler.
Wäre froh wenn du des mal testen könntest und mir sagen könntest warum 
da nur einmal ein blinken stattfindet. Heißt ja wohl dass meine 
Überläufe schon mal funktionieren.
Ebenso stellt sich noch die Frage wie ich LED1_ON() verneine. Mit 
~LED1_ON() geht es nicht. Was geht ist LED_OFF(). Aber das sieht wieder 
komplizierter aus dann...
Das mit #if und #endif ist eingearbeitet und funktioniert bei mir auch. 
Das ist eine wunderbare Funktion weil ich jetzt schön umschalten kann 
ohne doofe Kommentare zu machen!

Gruß
Thomas

von Bastler (Gast)


Lesenswert?

Eine Berichtigung. Der Stromlaufplan ist noch nicht fertig umgeändert. 
Die LEDs über R1 hängen jetzt nicht mehr an PB0 sondern an PA3. Das was 
an PA3 angeschlossen war (vom kap. Sensor) hängt dafür an PB0. Die 
Widerstände von den LEDs habe ich jetzt halb so groß dimensioniert wie 
davor mit den 680Ohm Widerständen da ja hin und rückweg da ist. Damit 
komme ich ja auch wieder auf 680 Ohm.
Der kap. Sensor ist nur für später auch schon auf diesem Board. Ich habe 
aber noch keine Absichten den hier irgendwie anzusprechen. Stattdessen 
hängt noch mit Jumper der Betauungssensor dran damit ich beides mit 
dieser Platine testen kann. Das ist allerdings fürs Lampen blinken 
erstmal unerheblich. Mein Ziel ist ja die LEDs4, 5, 6 und 7 zum blinken 
zu bringen und den Taster S1 zu entprellen. Dann werde ich versuchen das 
in das Programm vom Betauungssensor einzuarbeiten.
Wenn das dann funktioniert möchte ich mich an die Herausforderung mit 
dem kap. Sensor und evt dem multiplexen machen.

Gruß
Th.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> So in meiner ersten Mail erstmal wieder ein paar Codes die aber nur
> teils funktionieren. Habe es so konfiguriert wie du vorgeschlagen hast.
> Testversion 3 läuft zumindest schon mal so weit dass nach ca.3 Sekunden
> die LED angeht und nach weiteren 3 Sekunden wieder erlischt.

Ausschnitt aus Testversion3:
1
/****************/
2
#if Testversion3
3
/****************/
4
5
#define F_CPU 1000000
6
7
// Aufrufe pro Sekunde bei 64er-Teiler für Testversion3
8
// 
9
// 1. Makros schreibe ich gerne GROSS, dann kann man sie im Code 
10
// schnell von Variablen und Funktionen unterscheiden.
11
// 2. Klammern kann man bei Makros nie zu viel haben.
12
//
13
#define ANZAHL_OVERFLOWS_PRO_SEKUNDE (F_CPU/(64*256))
14
15
volatile uint8_t takt;     // Initalisierung auf 0 macht GCC
16
volatile uint8_t sekunde;  // Lesbarere Schreibweise
17
18
ISR(TIM0_OVF_vect)
19
{
20
  takt--;
21
  if(takt == 0)
22
  {
23
    takt = ANZAHL_OVERFLOWS_PRO_SEKUNDE;
24
    sekunde++;
25
    /* 
26
       Abfrage und Schalterei wurde ins Userprogramm verlagert 
27
       Die ISR läuft "unabhängig" vom Userprogramm und weiss
28
       nicht, welche LED vom Programmablauf her blinken soll.
29
30
       Man kann eine Zusatzvariable zwischen ISR und Userprogramm
31
       vereinbaren, die der ISR diesen Sachverhalt mitteilt. Dann
32
       kann man den Blinkcode hier rein ziehen. Vorher nicht.
33
     */
34
  }
35
}
36
37
void init(void)
38
{
39
  // Timer einstellen
40
  // WGM01 und WGM00 auf für Normalbetrieb
41
  // Vorteiler 64; 1 Overflow - 16,384ms
42
  // 1s = 61,03515625 Aufrufe oder Überläufe
43
  // 40ms = 2,44140625 Aufrufe
44
  TCCR0B |= (1<<CS01)|(1<<CS00);  
45
  TIMSK0 |= (1<<TOIE0);    // Timeroverflow Interrupt ein
46
  TCNT0 = 0;               // Startwert des Timers bei 0
47
  takt = ANZAHL_OVERFLOWS_PRO_SEKUNDE;
48
  sekunde = 0;
49
}
50
51
int main(void)
52
{
53
  LED_OFF();
54
  init();
55
  sei();
56
57
  while(1)        // for(;;) {} geht scheinbar auch??? Ja!
58
  {
59
    /*
60
       Sekunde:      0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...
61
       Sekunde & 6:  0 1 2 3 4 5 0 1 2 3 4  5  0  1  2  ...
62
       Schaltaktion: Aus   An    Aus   An      Aus      ...
63
    */
64
    switch((sekunde & 6)) // & ist der MODULO-Operator
65
    {
66
       case 3: 
67
               LED5_ON();
68
               break;
69
       case 0:
70
               LED_OFF();
71
               break;
72
    }
73
  }
74
}
75
#endif /* Testversion3 */

> Bei meinem Talent werde ich wohl auf die Sache mit dem Multiplexen erst
> mal verzichten.

Du lernst das auch. Das haben schon andere geschafft ;-) Das Gute ist: 
Die spätere Änderung ist nur eine Firmwareänderung. Auf dem gleichen 
Prototypen kannst du auch die elegantere Firmware laufen lassen.

> Die Initialisierung des Timers habe ich jetzt in einem eigenem
> unterprogramm erledigt weil ich mir dachte das ist eleganter.

Ist es!

> Testversion 3 benützt außerdem anstatt des 8er Teilers den 64er Teiler.
> Wäre froh wenn du des mal testen könntest und mir sagen könntest warum
> da nur einmal ein blinken stattfindet. Heißt ja wohl dass meine
> Überläufe schon mal funktionieren.

Siehe oben. Wenn bei deiner Version sekunde > 3 ist wird nie mehr 
eingeschaltet und wenn sekunde > 6 ist wird nie mehr ausgeschaltet. Bzw. 
doch, wenn uint8_t sekunde überläuft, d.h. in ca. 4 Min. 19s Abstart 
geht die LED5 wieder an...

> Ebenso stellt sich noch die Frage wie ich LED1_ON() verneine. Mit
> ~LED1_ON() geht es nicht. Was geht ist LED_OFF(). Aber das sieht wieder
> komplizierter aus dann...

LED_OFF() schaltet alle LEDs aus, in dem alle Portpins für die LEDs auf 
LOW gesetzt werden. Vcc wird dadurch ausgeschaltet. Man bräuchte nur den 
einem Portpin auf LOW zu schalten, der im Moment Vcc für die eine LED 
liefert. Dafür bräuchte man aber 6 Makros LED1_OFF(),... , LED6_OFF(). 
Um das zu vermeiden, die Holzhammermethode und alle drei Portpins LOW.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

>     switch((sekunde & 6)) // & ist der MODULO-Operator

Stimmt nicht ;-)

% ist der MODULO-Operator. Ich brauch' dringend einen Kaffee! Die 
korrekte Zeile lautet:

     switch((sekunde % 6)) // % ist der MODULO-Operator

von Bastler (Gast)


Lesenswert?

Hallo!

Erst nochmal herzlichen Dank. Ich habe jetzt mein erstes Timerblinken 
erzielt! Eine tolle Sache. Also ich kann das Lämpchen minimal mit 1Hz 
blinken lassen. Also 1 s an und wieder 1 s aus. Für ein halbes Herz 
brauche ich dann das define mit Overflows pro 500ms oder sogar pro 
250ms. Kann ich wenn ich alles gleichzeitig will das dann auch in einer 
ISR Routine abhandeln vermute ich mal.
Dann stellt sich für mich nur noch die Frage wie ich es dann schaffe die 
jeweiligen Blinkrythmen in meinem main anzuwählen. Oder soll ich dann 
für jedes Lämpchen ein eigenes Unterprogramm machen? Wäre ja auch für 
später sinnvoll wenn ich den AD-Wandler auswerte. Habe ja jeweils gesagt 
in dem Bereich rote LED. In dem Bereich gelbe LED und in dem Bereich 
grüne LED. Dann würde ich da nur noch die Unterfunktionen aufrufen oder?
Jetzt kann ich mich zum ersten Mal wieder kurz fassen! :-)

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Sehr schön, dass das jetzt klappt!

Du kannst neben sekunde ja auch halbesekunde oder viertelsekunde 
zählen. Schau dir den MODULO Operator an. Grob gilt (ungenau wg. 
Ganzzahlrechnung):

(takt % ANZAHL_OVERFLOWS_PRO_SEKUNDE == 0) => sekunde++, takt 
zurücksetzen
(takt % (ANZAHL_OVERFLOWS_PRO_SEKUNDE/2) == 0) => halbesekunde++
(takt % (ANZAHL_OVERFLOWS_PRO_SEKUNDE/4) == 0) => viertelsekunde++
usw.

"Ein Unterprogramm für jede LED", das würde ich auch erst mal so machen.

Hier noch eine kleine Änderung, um unnötige Aufrufe für das An- und 
Ausschalten zu vermeiden:
1
    static uint8_t letzte_sekunde = ~0; // damit if bei sekunde==0 wahr ist
2
    if (letzte_sekunde != sekunde) 
3
    {
4
      letzte_sekunde = sekunde;
5
      switch((letzte_sekunde % 6))
6
      {
7
         case 3: 
8
               LED5_ON();
9
               break;
10
         case 0:
11
               LED_OFF();
12
               break;
13
      }
14
    }

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Jetzt versuche ich gerade mehrere verschiedene Blinktakte zu 
programmieren. Allerdings habe ich da wieder ein Problem. Mit einmal 
Variable takt werde ich das ja wohl nicht schaffen. Ich werde ja wohl 
für alle 3 LEDs eine Variable benötigen. Die Bedinung (also if) wann die 
LEDs blinken sollen steht wohl wieder in der ISR. Dann ist nur noch die 
Frage wie ich das dann in main für die einzelnen LED anwählen kann. Wohl 
auch wieder mit einer neuen switch case Abfrage.
Für die Batterie LED kann ich wohl wieder das mit den Überläufen pro 1 
Sekunde verwenden vermute ich mal. Muss hald dann 4 mal passieren.
Grundsätzlich kann ich jedes Lampenblinken anwählen. Also auch das mit 
0,5 Hz und 0,25 Hz wenn ich das jeweilige define für Takt eintrage.

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bei mehreren Blinkraten macht es Sinn wieder vom Switch/Case wegzugehen. 
Man müsste sich sonst einen "Zeitstrahl basteln" und überlegen, wie man 
die einzelnen Aktionen darauf anordnet.

Mit deinen Hz Angaben komme ich nicht zurecht. 0,5 Hz blinkt langsamer 
als 1 Hz. Dann passen die ...500MS und ...250MS Makros nicht. Ich 
vermute du willst einfach hektischeres und doppelt hektischeres Blinken 
also 2 Hz und 4 Hz, oder?

Das Basteln des Zeitstrahls, kann man in die Timer-ISR verlagern. Auf 
die Schnelle hingeschrieben aber nicht getestet:
1
// LED4 orange; Blinktakt 1 Hz
2
#define ANZAHL_OVERFLOWS_PRO_SEKUNDE (F_CPU/(64*256))    
3
4
// LED5 rot; Blinktakt 2 Hz
5
#define ANZAHL_OVERFLOWS_PRO_500MS ((F_CPU/(64*256))/2)    
6
7
// LED6 rot; Blinktakt 4 Hz
8
#define ANZAHL_OVERFLOWS_PRO_250MS ((F_CPU/(64*256))/4)    
9
10
// für spätere Tastenentprellung
11
// Anm. Stefan: Noch nicht angeschaut
12
#define ANZAHL_OVERFLOWS_PRO_80MS (0.08/(F_CPU/(64*256)^-1))  
13
14
/*********************/
15
#if TESTVERSION3
16
/*********************/
17
18
volatile uint8_t takt;
19
volatile uint8_t sekunde;
20
21
// Angabe für: Wie lange soll die entsprechende LED blinken?
22
// Bsp: 
23
//      LED4 soll 3 s lang mit 1 Hz blinken 
24
//      => 3 s * 1 Hz * 2 Pegelwechsel/Hz = 6 mal
25
//      bei uint8_t max. 127s Blinken möglich
26
// 
27
//      LED5 soll 8 s lang mit 2 Hz blinken 
28
//      => 8 s * 2 Hz * 2 Pegelwechsel/Hz = 32 mal
29
//      bei uint8_t max. 63s Blinken möglich
30
// 
31
//      LED6 soll 6 s lang mit 4 Hz blinken 
32
//      => 6 s * 4 Hz * 2 Pegelwechsel/Hz = 48 mal
33
//      bei uint8_t max. 31s Blinken möglich
34
//
35
volatile uint8_t takt_LED4;
36
volatile uint8_t takt_LED5;
37
volatile uint8_t takt_LED6;
38
volatile uint8_t takt_LED7;
39
40
ISR(TIM0_OVF_vect)
41
{
42
  takt--;
43
44
  // Die LEDs haben eine Vorrangreihenfolge 
45
  // LED4 vor LED5 vor LED6! 
46
47
  if((takt % ANZAHL_OVERFLOWS_PRO_250MS) == 0)
48
  {
49
    if (takt_LED6)
50
    {
51
      LEDS_OFF();
52
      if ((takt_LED6 & 1) == 0)
53
        LED6_ON();
54
      takt_LED6--;
55
    }
56
  } /* 4 Hz Aktionen */
57
58
  if((takt % ANZAHL_OVERFLOWS_PRO_500MS) == 0)
59
  {
60
    if (takt_LED5)
61
    {
62
      LEDS_OFF(); 
63
      if ((takt_LED5 & 1) == 0) 
64
        LED5_ON();
65
      takt_LED5--;
66
    }
67
  } /* 2 Hz Aktionen */
68
69
  if((takt % ANZAHL_OVERFLOWS_PRO_SEKUNDE) == 0)
70
  {
71
    if (takt_LED4)
72
    {
73
      LEDS_OFF();
74
      if ((takt_LED4 & 1) == 0)
75
        LED4_ON();
76
      takt_LED4--;
77
    }
78
79
    // Sonderfall LED7 (Batterie)
80
    // Hängt nicht am Charlieplexing, d.h. LED7 kann parallel 
81
    // zu anderen LED Blinken. Braucht aber eigene AN/AUS Makros!
82
    if (takt_LED7)
83
    {
84
      LED7_OFF();
85
      if (!(takt_LED7 & 1))
86
        LED7_ON();
87
      takt_LED7--;
88
    }
89
90
    sekunde++;
91
    takt = ANZAHL_OVERFLOWS_PRO_SEKUNDE; // nur hier!
92
  } /* 1 Hz Aktionen */
93
}
94
95
void init(void)
96
{
97
  // Timer einstellen
98
  // Vorteiler 64; 1 Overflow - 16,384ms
99
  // 1s = 61,03515625 Aufrufe oder Überläufe
100
  // 0,5 s = 30.51757813 Aufrufe
101
  // 0,25 s = 15,25878906
102
  // 80ms = 4,8828125 Aufrufe
103
  TCCR0B |= (1<<CS01)|(1<<CS00);    
104
  TIMSK0 |= (1<<TOIE0); // Timeroverflow Interrupt ein
105
  TCNT0 = 0;            // Startwert des Timers bei 0
106
  takt = ANZAHL_OVERFLOWS_PRO_SEKUNDE;
107
}
108
109
void warte(uint8_t wartezeit)
110
{
111
  uint8_t stoppzeit;
112
113
  stoppzeit = sekunde + wartezeit;
114
  while(sekunde != stoppzeit);
115
}
116
117
int main(void)
118
{
119
  LED_OFF();
120
  init();
121
  sei();      // Interrupts aktivieren
122
123
  while(1)      
124
  {
125
    // Kleines Blinkdemo mit obigen Werten...
126
    takt_LED7 = 4 * 1 * 2;
127
    warte(2);
128
    takt_LED4 = 3 * 1 * 2;
129
    warte(10);
130
    takt_LED5 = 8 * 2 * 2;
131
    warte(10);
132
    takt_LED7 = 4 * 1 * 2;
133
    takt_LED6 = 6 * 4 * 2;
134
    warte(10);
135
  }
136
}
137
#endif /* TESTVERSION3 */

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Ups. Jetzt war ich zu schnell! ;-) Bin im Moment dabei das zu verstehen 
was ich da genau programmiert habe. Ich glaube ich habe ja eine 
Ungenauigkeit drin weil ich ja keine Kommazahlen habe. Sprich bei 
61,.... irgendwas Überläufe wird meine Maschine 61 benutzen vermute ich.
Aber jetzt noch mal zur Funktion meines Programmes. Ich beginne mal mit 
der ISR. Der takt der in init belegt wurde wird zunächst in der ISR um 
eins verringert. Also bei 1 Sekunde 61 Überläufe da das nach dem Komma 
wegfällt. Wenn es dann von 61 bis auf null runtergezählt hat wird die 
if-Schleife in der ISR aufgerufen. warum man hier aber nochmal takt = 
ANZAHL_.... schreibt ist mir nicht klar. Und dann wird das gleiche für 
die nächste Sekunde gemacht weil man die Sekunden in init ja wieder 
zurücksetzt. Ist meine Annahme richtig?
Bei dem neuen Programmteil habe ich aber ein Problem. Also zunächst mal 
wieder eine neue variable (letzte Sekunde) die alles (von 1 - 255) sein 
darf aber nicht 0. Wenn letzte_sekunde dann ungleich Sekunde ist wird 
die if-Abfrage ausgeführt. Jetzt ist für mich die Frage wann ist das 
ungleich? Eigentlich ja immer oder? Dann sagst du letzte Sekunde = 
Sekunde???? Dann das mit dem Modulo. Also switch. letzte_Sekunde geteil 
durch 2. Wenn Rest null alle LEDs aus und wenn Rest 1 LED6 an.
Ist das jetzt so einigermaßen richtig gedacht?

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Ich glaube ich habe ja eine
> Ungenauigkeit drin weil ich ja keine Kommazahlen habe.
> Sprich bei
> 61,.... irgendwas Überläufe wird meine Maschine 61 benutzen vermute ich.

Genau. Deine sekunde auf deinem AVR-Gerät ist dadurch etwas kürzer als 
eine Sekunde auf deiner Uhr.

> Aber jetzt noch mal zur Funktion meines Programmes. Ich beginne mal mit
> der ISR. Der takt der in init belegt wurde wird zunächst in der ISR um
> eins verringert. Also bei 1 Sekunde 61 Überläufe da das nach dem Komma
> wegfällt.

> Wenn es dann von 61 bis auf null runtergezählt hat wird die
> if-Schleife in der ISR aufgerufen. warum man hier aber nochmal takt =
> ANZAHL_.... schreibt ist mir nicht klar.

Um takt auf den Startwert zu stellen, damit du eine Periode von 
ANZAHL_OVERFLOWS_PRO_SEKUNDE Takten bekommst. Würdest du das nicht 
machen, würde takt im nächsten Umlauf von 0 bei takt-- auf 255 
springen (8-Bit Unterlauf) und die nächste Sekunde wäre gut viermal so 
lang!

> Und dann wird das gleiche für
> die nächste Sekunde gemacht weil man die Sekunden in init ja wieder
> zurücksetzt. Ist meine Annahme richtig?

Nein. init() läuft nur einmal am Programmanfang, vor der Endlosschleife. 
Das Initialisieren von sekunde auf 0 ist dort überflüssig, weil es für 
globale Variable im C-Startupcode (vor main) bereits gemacht wurde.

> Bei dem neuen Programmteil habe ich aber ein Problem. Also zunächst mal
> wieder eine neue variable (letzte Sekunde) die alles (von 1 - 255) sein
> darf aber nicht 0. Wenn letzte_sekunde dann ungleich Sekunde ist wird
> die if-Abfrage ausgeführt. Jetzt ist für mich die Frage wann ist das
> ungleich? Eigentlich ja immer oder? Dann sagst du letzte Sekunde =
> Sekunde????

Exakt nicht. Das ist der Clou an volatile Variablen und der ISR. Die 
parallel laufende ISR erhöht ja sekunde regelmäßig. Und im 
Userprogramm wird durch die Kennzeichnung volatile immer der frische 
Wert genommen und in den Vergleich einbezogen!

> Dann das mit dem Modulo. Also switch. letzte_Sekunde geteil
> durch 2. Wenn Rest null alle LEDs aus und wenn Rest 1 LED6 an.
> Ist das jetzt so einigermaßen richtig gedacht?

Jo. Statt MODULO 2 kann man auch das letzte Bit abfragen mit dem BIT-UND 
Operator &. Das ist in der frischen Source so.

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Zunächst Danke für die Erklärung und das Blinkprogramm. Ich habe jetzt 
auch wieder einen Code angehängt. Kurz zur Erklärung:
Testversion 1 ist das Programm welches die rote LED mit 1Hz blinken 
läßt. Natürlich meinte ich bei schnellerem Blinken auch nicht mit 0,5 Hz 
sondern mit 2 und 4 Hz. Also quasi 2 bzw. 4 mal pro Sekunde.
Testversion 2 ist dein Programm. Es waren ein paar Fehler drin die ich 
inzwischen aber soweit herausbekommen haben. Also 0 Warnings. Allerdings 
leuchtet da irgendwie alles durcheinander. Zuerst mal LED4 und 5 
miteinander. Dann LED1 und6. Und dann wieder 4 und 5 ganz schnell. Weiss 
nicht ob meine ganzen defines inzwischen stören.
Testversion 3 ist wieder mein eigentlicher Betauungssensor. Ich habe das 
Programm umgeschrieben damit ich es mit dem Prototypen mit den 6 LEDs 
benutzen kann. Allerdings werde ich auch hier nur 3 LEDs nutzen nämlich 
LED2, 4 und 6. Da habe ich die Ansteuerung korrigiert. LEDBat kann man 
lassen. Was interessant ist: Power-Down funktioniert. grüne LED leuchtet 
auch ganz normal am Anfang. Batterie LED funkitoniert aber nicht. Und 
wenn ich den Sensor anhauche dann leuchten plötzlich das grüne und das 
rote LED gleichzeitig!!! Also irgendwie scheint da ein Timer 
mitreinzuspielen. Evt von einem anderen define oder so?? Normal soll ja 
grün, gelb und rot sein. Keine Ahnung. Meine Vermutung ist hald dass 
sich da was stört. Aja nach dem Rot und grün gleichzeitig geleuchtet 
haben verlöschen die beiden und es passiert nichts mehr. Erst wieder 
nach einem Reset!
Evt. wäre eine Programmtrennung doch wieder sinnvoll? Hier hätte ich 
hald alles drin gehabt. Zum probieren und für den Betauungssensor.
Kannst du dir eigentlich vorstellen dass man den Betauungssensor auch 
eichen muss? Wohl ja befürchte ich oder??

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Mittlerweile drei Programme für zwei unterschiedliche Hardwares in 
einen Quellcode zu stecken, das ist etwas zu viel. Willst du die alle 
behalten und pflegen?

Testversion1 würde ich rausschmeissen. Die interessiert nicht mehr.

Testversion2 ist das Demoprogramm für die Ansteuerung der LEDs im 
Charlieplexing ohne irgendeine andere Funktion. Diese Version setzt auf 
den Timer0, um das abgestufte Blinken zu ermöglichen.

Das Blinken über Testversion3 zu machen, d.h. ohne den Timer, das wird 
schwer, weil die Laufzeit von Codestücken die Blinkzeiten beeinflusst. 
Das geht in einfachen Demos, um die grundsätzliche Funktion zu zeigen, 
aber ich halte den Weg für eine Sackgasse im Endgerät.

Die wilde Blinkerei der LEDs im Demoprogramm ist vielleicht zu viel 
gewesen. Es kann auch sein, dass ich mir ein falsches Demo ausgedacht 
habe; ich kann es derzeit auch nicht testen, weil ich erst löten müsste. 
Du kannst in main() Zeilen auskommentieren und sehen, was dann passiert.

Testversion2 kann man rel. einfach um die eigentlichen Funktionen 
erweitern.

Welche Varianten sind denn jetzt im Rennen?

Variante1 Betauungssensor auf dem Einfachboard

> Also der
> Betauungssensor hat ja nur 3 LEDs die an 3 Ports hängen. Bei diesen LEDs
> soll nur die rote blinken. Also ganz einfach.

Diese Hardware wird im Moment nicht mehr eingesetzt. Die Teile fliegen 
aus dem Sourcecode raus.

Variante2 Betauungssensor auf dem Board mit dem kapazitive Sensor

> Testversion 3 ist wieder mein eigentlicher Betauungssensor. Ich habe das
> Programm umgeschrieben damit ich es mit dem Prototypen mit den 6 LEDs
> benutzen kann. Allerdings werde ich auch hier nur 3 LEDs nutzen nämlich
> LED2, 4 und 6.

Charlieplex LED1 = GRUN = Ohne Funktion (aus)
Charlieplex LED2 = GRUN = Dauerleuchten
Charlieplex LED3 = GELB = Ohne Funktion (aus)
Charlieplex LED4 = GELB = Dauerleuchten
Charlieplex LED5 = ROT = Ohne Funktion (aus)
Charlieplex LED6 = ROT = Dauerleuchten
Solo LED7 = LED_BAT = ROT = Blinken (1 Hz?, Wie lange?)

Variante3 kapazitiver Sensor

> Der kapazitive Sensor hat 6 LEDs weil der ja hoffentlich genauer ist. 2
> rote 2 gelbe und 2 grüne LEDs. Die grünen sollen in ihrem Bereich
> jeweils Dauerleuchten.
> Also ganz trocken 1. grüne.
> Bei vielleicht 20 %rel. Feuchte die 2. grüne LED.
> Die erste gelbe soll Dauerlicht sein.
> Die 4. gelbe soll vielleicht mit 1Hz blinken.
> Die erste rote mit doppelt so schnell und
> die letzte rote LED wieder doppelt so schnell.

Charlieplex LED1 = GRUN = Dauerleuchten
Charlieplex LED2 = GRUN = Dauerleuchten
Charlieplex LED3 = GELB = Dauerleuchten
Charlieplex LED4 = GELB = Blinken 1 Hz (bis nächste Messung?)
Charlieplex LED5 = ROT = Blinken 2 Hz (bis nächste Messung?)
Charlieplex LED6 = ROT = Blinken 4 Hz (bis nächste Messung?)
Solo LED7 = LED_BAT = ROT = Blinken (1 Hz?, Wie lange?)

Man sieht, dass hier und in der Variante1 vorher noch die Funktion für 
das Dauerleuchten zu schreiben ist.

Da sich der Einsatz von LED4, LED5 und LED6 bei den beiden Varianten 
unterscheiden, sieht der Inhalt der ISR bei beiden Varianten 
unterschiedlich aus. Im Moment ist er für Variante3 (nur Blinken) 
geschrieben. Wenn du jetzt zu Variante2 wechseln willst, kann man das 
machen.
1
#define VARIANTE2 1
2
#define VARIANTE3 0
3
4
#if VARIANTE3
5
volatile uint8_t takt_LED1;
6
volatile uint8_t takt_LED3;
7
volatile uint8_t takt_LED5;
8
#endif /* VARIANTE3 KAP.SENSOR */
9
10
volatile uint8_t takt_LED2;
11
volatile uint8_t takt_LED4;
12
volatile uint8_t takt_LED6;
13
volatile uint8_t takt_LED7;
14
15
ISR(TIM0_OVF_vect)
16
{
17
  takt--;
18
19
  // Die LEDs haben eine Vorrangreihenfolge 
20
  // LED1 vor LED2 vor LED3 vor LED4 vor LED5 vor LED6! 
21
22
#if VARIANTE2
23
  if((takt % ANZAHL_OVERFLOWS_PRO_SEKUNDE) == 0)
24
  {
25
    // Sonderfall LED7 (Batterie)
26
    // Hängt nicht am Charlieplexing, d.h. LED7 kann parallel 
27
    // zu anderen LED Blinken. Braucht aber eigene AN/AUS Makros!
28
    if (takt_LED7)
29
    {
30
      PORTB &= ~LED7_ON;
31
      if (!(takt_LED7 & 1))
32
      PORTB |= LED7_ON; // ### ACHTUNG: nicht &= ###
33
      takt_LED7--;
34
    }
35
36
    sekunde++;
37
    takt = ANZAHL_OVERFLOWS_PRO_SEKUNDE; // nur hier!
38
  } /* 1 Hz Aktionen */
39
40
  // Dauerleuchter
41
  if (takt_LED6)
42
  {
43
    LED_OFF();
44
    LED6_ON();
45
  }
46
47
  // LED5 keine Funktion
48
49
  // Dauerleuchter
50
  if (takt_LED4)
51
  {
52
    LED_OFF();
53
    LED4_ON();
54
  }
55
56
  // LED3 keine Funktion
57
58
  // Dauerleuchter
59
  if (takt_LED2)
60
  {
61
    LED_OFF();
62
    LED2_ON();
63
  }
64
65
  // LED1 keine Funktion
66
#endif /* VARIANTE2 Betauungssensor */
67
68
#if VARIANTE3
69
  /*
70
   * Blinken von LED4, LED5 und LED6
71
   */
72
  if((takt % ANZAHL_OVERFLOWS_PRO_250MS) == 0)
73
  {
74
    if (takt_LED6)
75
    {
76
      LED_OFF();
77
      if ((takt_LED6 & 1) == 0)
78
      LED6_ON();
79
      takt_LED6--;
80
    }
81
  } /* 4 Hz Aktionen */
82
83
  if((takt % ANZAHL_OVERFLOWS_PRO_500MS) == 0)
84
  {
85
    if (takt_LED5)
86
    {
87
      LED_OFF(); 
88
      if ((takt_LED5 & 1) == 0) 
89
        LED5_ON();
90
      takt_LED5--;
91
    }
92
  } /* 2 Hz Aktionen */
93
94
  if((takt % ANZAHL_OVERFLOWS_PRO_SEKUNDE) == 0)
95
  {
96
    /*
97
     * Blinken von LED4, LED5 und LED6
98
     */
99
    if (takt_LED4)
100
    {
101
      LED_OFF();
102
      if ((takt_LED4 & 1) == 0)
103
        LED4_ON();
104
      takt_LED4--;
105
    }
106
107
    // Sonderfall LED7 (Batterie)
108
    // Hängt nicht am Charlieplexing, d.h. LED7 kann parallel 
109
    // zu anderen LED Blinken. Braucht aber eigene AN/AUS Makros!
110
    if (takt_LED7)
111
    {
112
      PORTB &= ~LED7_ON;
113
      if (!(takt_LED7 & 1))
114
      PORTB |= LED7_ON; // ### ACHTUNG: nicht &= ###
115
      takt_LED7--;
116
    }
117
118
    sekunde++;
119
    takt = ANZAHL_OVERFLOWS_PRO_SEKUNDE; // nur hier!
120
  } /* 1 Hz Aktionen */
121
122
  // Dauerleuchter
123
  if (takt_LED3)
124
  {
125
    LED_OFF();
126
    LED3_ON();
127
  }
128
129
  // Dauerleuchter
130
  if (takt_LED2)
131
  {
132
    LED_OFF();
133
    LED2_ON();
134
  }
135
136
  // Dauerleuchter
137
  if (takt_LED1)
138
  {
139
    LED_OFF();
140
    LED1_ON();
141
  }
142
#endif /* VARIANTE3 KAP.SENSOR */
143
}

Und noch die Verwendung im Programm:
1
#define DAUERFEUER_EIN 1
2
#define DAUERFEUER_AUS 0
3
#define BLINKEN_4S_1HZ (4*1*2) 
4
#define BLINKEN_AUS 0
5
6
  // Dauerleuchter anschalten (dauert max. 16ms bis zu nächsten ISR)
7
  takt_LED2 = DAUERFEUER_EIN;
8
9
  // Dauerleuchter ausschalten (dauert max. 16ms bis zu nächsten ISR)
10
  takt_LED2 = DAUERFEUER_AUS;
11
12
  // Blinker einschalten (dauert max. 16ms bis zu nächsten ISR)
13
  takt_LED7 = BLINKEN_4S_1HZ;
14
15
  // Blinker ausschalten (dauert max. 16ms bis zu nächsten ISR)
16
  takt_LED7 = BLINKEN_AUS;

Wenn die weiteren Funktionen in Testversion2 eingebaut werden, muss man 
beim Schlafen gehen etwas aufpassen: Die LEDs sind über takt_LEDx und 
LED_OFF() auszuschalten. Dann wird der Timer0 disabled. Nach dem 
Aufwachen wird der Timer0 wieder enabled. Die LEDs braucht man nach dem 
Aufwachen nicht den Vorschlafzustand zu setzen; lieber macht man frische 
Messungen (trigger passend auf 0-1 setzen)!

Testversion3 hat die eigentlichen Funktionen und hast bereits versucht 
das Charlieplexing hier einzubauen.

Die Ursache für die komische Reaktion der LEDs muss ich mir genauer 
ansehen; mit dem hier nicht vorhandenen Timer können die nichts zu tun 
haben.

Mir fällt auf, dass du kein einziges LED_OFF() in feuchtemessung() hast! 
Die Makros leben davon, dass zuvor ein LED_OFF() gemacht wird. Das 
LED_OFF() setzt die Pins, die auf LOW gehen sollen; die LEDx_ON() Makros 
schalten ja nur die Vcc dazu! Wenn das anders laufen soll, kann man 
die LED_OFF() Funktionalität in die LEDx_ON() Makros reinziehen:
1
#define LED1_ON()              \
2
   do                    \
3
   {                    \
4
     uint8_t tmp; /* unsigned integer 8bit 0-255 */         \
5
     PORTA &= MASKE; /* alle LEDs aus */  \
6
     tmp = DDRA & MASKE; /* holt Zustand von DDRA und setzt ihn auf 0 */   \
7
     tmp |= (1<<PA3)|(1<<PA7)|(0<<PA5); /* Wunschzustand LED */       \
8
     DDRA |= tmp;            \
9
     PORTA |= (1<<PA3);          \
10
   } while (0)

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Nene diese Software ist für den neuen Prototypen. Ich kann jedes dieser 
drei Programme mit der gleichen Hardware betreiben. Dieser Prototyp 
gehört ja für die spätere Kapazitätsmessung. Wie ich aber schon sagte 
habe ich jetzt auch noch meinen Betauungssensor mit Jumer drangehängt. 
Das heißt ich kann beide Sensoren mit einem Board auswerten. Diese 
Leiterplatte ist nicht das Endprodukt. Das Endprodukt wird nicht auf FR4 
Material entstehen und wird auch nicht gelötet. Also das auf FR4 ist 
rein zum testen ob das Programm und die Hardware funktioniert. Es ist 
schon richtig es gibt auch noch die alte Hardware. Da war nur der 
Betauungssensor. Das war mit den 3 LEDs. Ich hätte auch einen Schaltplan 
von dem neuen Prototypen mit den Jumpern falls es nötig sein sollte.
Klar. Testversion 1 war einfach für mich mal zu sehen wie funktioniert 
der Timer. Habe damit noch nie was gemacht.
Mein Ziel ist ja jetzt in Testversion drei dieses Blinken auch mit Timer 
zu machen. Habe es nur einfach mal hier rein gezogen damit man sich 
stückchenweise ranarbeiten kann an des gewünschte Ziel. Also ich 
beabsichtige nicht das Blinken ohne Timer zu machen. Das einzige was ich 
mir vorstellen könnte dass man die Tastenentprellung mit dem delay 
beibehält. Aber das blinken der roten LED und der BAT LED soll mit Timer 
gemacht werden (also rote LED beim Betauungssensor wo nur 3 LEDs 
verwendet werden!!)
Achso das heißt es kann zu störungen kommen? Dachte mit dem #if kann man 
das quasi rauslöschen oder es ist so als würde es gar nicht dortstehen?

Nochmals zu den Varianten die existieren:

Variante 1:
Betauungssensor auf dem alten Prototypen. 3 LEDs. Jedes an einem eigenen 
Port. PowerDown. Keine Timer. Nur delay die sich zu stören scheinen.

Variante 2:
Neues Board. Kleiner leichter. Gebaut um das mit dem kap. Sensor zu 
überprüfen. 6 LEDs an drei Ports. Jetzt erweitert mit Jumper damit ich 
auch den res. Sensor damit testen kann. Allerdings muss ich dann die 
Software die für Prototyp 1 geschrieben wurde umschreiben weil sonst 
keine Lampe leuchtet. Klar weil ich das mit den LEDs jetzt anders habe. 
Nicht mehr jede LED an eigenem Portpin. Warum ich das gemacht habe dass 
ich das so nochmal aufbau. Weiss auch nicht. Ich hab es einfach nochmal 
sauberer verdrahtet dass das Board ansehnlich ist. Sprich vom 
Betauungssensor muss es zwei verschiedene Programme geben. Eines für das 
alte Board und eines für den neuen Prototypen. Wobei für meine 
revolutionäre Technologie werde ich Software und Schaltung des alten 
Boards verwenden. Natürlich erweitert um das mit dem Timerblinken. In 
der besonderen Technologie werden also nur 3 LEDs realisiert weil es eh 
sehr ungenau ist. Das mit dem kap. Sensor ist nur noch die Zugabe. Wenn 
es klappt wunderbar. Testversion 3 ist der Code von dem alten Board. Ich 
habe aber schon versucht die Teile zu entfernen wo ich meine dass ich 
sie auf dem neuen Board nicht mehr benötige.
JAAAAAAAAAAAAAAAA. Ganz genau. Fast richtig. Bei Variante 2.
Charlieplex. ist das eigentlich der offizielle Name?? Oder kann man auch 
sagen gemultiplext?? Wobei das passt ja auch nicht...
LED1, 3 und 5 auf neuem Board für Betauungssensor unerheblich
LED2 und 4 (grün und gelb) mit Dauerleuchten
LED 6 rot mit blinken. Wobei man auch für das gelbe LED ein blinken 
verwenden könnte. Dann ist es noch ähnlicher zum kap. Sensor. Also sagen 
wir um es zu vereinfachen. LED4 blinkt wie bei kap. Sensor mit 1 Hz und 
LED6 blinkt doppelt so schnell. Also für den Betauungssensor. Hoffe ich 
habe das jetzt verständlich geschrieben was der Plan ist.
LED_BAT oder LED7 je nachdem soll alle 4Sekunden kurz aufflashen. Also 
ich kann da jetzt praktisch keine Frequenz sagen.
4 Sekunden gar nichts und sagen wir mal 0,5 Sekunden aktiv und immer 
weiter so. Batterieled immer gleich. Ist bei beiden Boards am gleichen 
Pin. Also hier dürfte sich absolut nichts verändern.

STOP!!!

Also ich glaube des wird jetzt wirklich zu kompliziert dann. Da ich ja 
einerseits auch die Schaltung des alten Prototyps verwende macht es ja 
keinen Sinn das für den neuen zu programmieren beim Betaungssensor. Im 
Anhang nochmal der Schaltplan und der Code für das alte Board. Also 
Betauungssensor. Und die allererste Variante. Ziel: Timer 0 zum blinken 
von LED2 und LED3 sowie LED_BAT und evt Tasterentprellung. Außerdem wie 
in Stromlaufplan 4: Spannungsteiler an PA7 um Strom zu sparen. Das müßte 
ja relativ leicht sein hoffe ich.

Ich schreibe mir gerade etwas zusammen. Also vergessen wir erstmal das 
mit dem Prototypen 2. Da werde ich rangehen sobald der Prototyp 1 seine 
wirklich endgültige Funktion hat. Werde mir aber da paar Codestücke 
rausnehmen. Werde das dann wieder hier reinstellen wenn ich schneller 
bin als du!

Gruß
Thomas

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

So. Ich habe jetzt schon mal versucht ein Stück vorzuarbeiten. Habe 
allerdings immer noch ein Problem wie das dann bei dem LED_BAT und dem 
Tasterentprellen geht. Keine Ahnung irgendwie. Das Timerinit dürfte ja 
eh passen. Und die ISR habe ich auch schon mal geschrieben so weit wie 
möglich. Spannungsteiler an Portpin das habe ich noch nicht gemacht.
Das ganze bisherige Zeug mit dem Blinken kann man ja alles vergessen. 
DAs ahbe ich erst mal auskommentiert. Ich habe auch noch eine Frage 
wegen der Abfrage in der ISR.

z.B.
if((takt % ANZAHL_OVERFLOWS_PRO_500MS) == 0)

takt sind meine 61 Überläufe pro Sekunde die ich ihm in Timerinit 
gegeben habe. ANZAHL_OVERFLOWS_PRO_500MS ist wohl 30 (genau: 
30,51757813). Der Modulo Operator sagt mir ja den Rest. Also sprich die 
If Schleife wird ausgeführt wenn Rest 0 ist. Der Takt wird von 61 
runtergezählt. Ups. Stimmt das ist dann einmal. 61 dürfte ne Primzahl 
sein. ABER: Ich kann mit dene 61 Überläufe aus dem Timerinit ja jetzt 
nicht die für ne halbe Sekunde oder 80ms Sekunden steuern. Bei 80ms sind 
es 4 Überläufe und bei 500ms wie gesagt 30. Moment. Also das mit 30 
funktioniert. ABer das mit den 4 Überläufen. Z.B. 60 geteilt durch 4 ist 
auch Rest 0 und 40 geteilt durch 4 auch. Das heißt für die 80 ms 
Sekunden braucht man was spezielles und für das LED_BAT auch oder??

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

Vielleicht sowas wie im Anhang. Achtung, das war noch nicht im Compiler, 
kann also noch Schreibfehler haben und logische Fehler sowieso.

Beim Entprellen ist im Moment nur das _delay_ms() durch einen Zähler 
ersetzt, der von der Timer0 ISR gefüttert wird. Gleiches Prinzip wie die 
warte() vorher mit Sekunden.

Eingefügt ist noch die Behandlung des Timers beim Schlafen/Wecken. Die 
Zustände der LEDs werden jetzt auch nicht gerettet, sondern nach dem 
Aufwecken wird neu gemessen. Im Moment unmittelbar beim nächsten 
Durchlauf durch das grosse while(1).

Die Schalterei der LEDs siehst du in der Source. Alles wird dem Timer 
überlassen. dadurch kann es max. 500ms dauern, bis eine LED an geht. Am 
"ehesten" wäre das bei der gelben LED zu beoabchten.

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

Ups, mir war nicht aufgefallen, dass der Aufruf von init() bereits in 
Test3.c fehlte. Das habe ich nachgetragen und ein paar Änderungen für 
den Simulator habe ich auch eingefügt.

von Peter D. (peda)


Lesenswert?

Bastler schrieb:
> Charlieplex.

Das geht nur mit speziellen ICs (Maxim), die interne 
Konstantstromquellen haben oder wenn Deine VCC kleiner als die 2-fache 
LED-Spannung ist.
Ansonsten kriegst Du Geister-LEDs.


> Also ich glaube des wird jetzt wirklich zu kompliziert dann.

Das sehe ich schon länger so.

Du mußt aufhören, drauflos zu programmieren und Dir erstmal nen 
Programmablaufplan machen.

Und mal verbal beschreiben, welche Zustände es überhaupt gibt und wann 
welche LED wie schnell zu blinken hat.

Ich bleibe dabei, ohne Statemaschine wirst Du das Chaos nicht 
beherrschen können.
Dein Gefrickel wird nie vollständig funktionieren. Du drehst an einer 
Schraube, damit etwas geht und dafür geht aber was anderes nicht mehr.


Peter

von Bastler (Gast)


Lesenswert?

Hallo!

Zunächst mal wieder danke für die Unterstützung. Also ein und 
ausschalten funktioniert und die Feuchtemessung grundsätzlich auch. 
Allerdings blinkt LED Gelb und LED Rot ziemlich ungleichmäßig. DAs 
Batterie LED leuchtet nur durchgängig aber grundsätzlich geht das ja 
schon ganz gut.
Das mit dem define der Schwellwerte finde ich super weil es einfach 
übersichtlicher ist.
Das mit den Testfällen im Simulator dürfte ja für das Programm keine 
Rolle spielen da ja 0 dahinter steht oder?
Also das mit der State Machine wäre wohl einfach nicht mehr möglich von 
der Zeit her...

Gruß
Th.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Leider konnte ich am Wochenende keinen Attiny24 auftreiben, sonst hätte 
ich die Schaltung mal aufgebaut.

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Guten Morgen!

Kein Problem. Die Frage ist ja ob da alle liebe Mühe umsonst ist weil es 
fast nur mit der Statemashine zu realisieren ist oder ob man das mit dem 
Timer hinbekommt. Bin gerade dabei zu verstehen wann der wo rumspringt. 
Ist hald gerade etwas verwirrend mit dem Lampendurcheinander. Ich glaube 
schon dass des unangenehm ist wenn man die Schaltung nicht vor sich. Vor 
allem wird jetzt das langsam zum Problem dass debuggen nicht möglich ist 
mit dieser ICP Schnittstelle. Habe ja leider keine JTAG Schnittstelle. 
Die Beschaffung von dem ATTINY24 scheint bisschen schwer zu sein ja. 
Habe ihn beim Reichelt bestellt. Beim Conrad gibts den nicht. Habe 
trotzdem nochmal den Code mitangehängt. Der Code liefert auf jeden Fall 
keine Fehler mehr.

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bei der Statemachine käme sicher auch der Timer zur Anwendung. 
Sobald du ein Projekt hast, bei dem Zeit eine Rolle spielt und bei dem 
Aktionen annähernd parallel ablaufen sollen bsp. Blinken, ist es 
geschickt einen Timer einzusetzen.

Die state machine hätte den Vorteil, dass du 1. zu jedem Zeitpunkt 
exakt und leicht nachvollziehbar weisst, in welchem Zustand sich dein 
Programm befindet und wie die Übergänge dazwischen passieren und 2. dass 
es keine ungültigen/unvorhergesehenen Zustände und Übergänge gibt (bei 
richtiger Planung und Umsetzung).

Die grosse Gefahr bei der Implementierung ohne state machine ist die 
Verzettelung. Bei jeder Änderung kann es passieren, dass das fragile 
Projekt zusammenstürzt, weil plötzlich Nebeneffekte auftreten bsp. 
längere Laufzeit in einem Codeteil A zerbricht einen feingetunten 
Codeteil B. Und diese Gefahr steigt mit jedem Tag an, an dem du 
vergisst, was du vorher programmiert hast. Solche Programme zu debuggen 
und zu warten oder an Dritte zu übergeben ist der Horror.

Bei dem grossen Zeitdruck den du beschreibst, würde ich zuerst eine 
funktionierende 0.1 Version der Firmware festklopfen. Später kannst du 
in einer ruhigen Stunde die Firmware deines Projekts auf eine /state 
machine/ umschreiben. Du wirst sicher wertvolles für die nächsten 
Projekte lernen. Die Hardware braucht ja - µC sei Dank - nicht geändert 
zu werden.

von Bastler (Gast)


Lesenswert?

Also dann dürfte des praktisch zu schwer werden ohne Statemachine einen 
vernünftigen Code hinzubekommen oder? Hat mich ja auch gewundert dass 
die Tasterentprellung scheinbar funktioniert hat. Aber die LEDs machen 
wirklich die lustigsten Sachen. Wäre hald schön zu wissen was im 
Controller in den einzelnen Registern und Variablen steht. So dürfte es 
ja fast unmöglich sein den Fehler zu finden. Könnte natürlic das Blinken 
der einen LED nach wie vor mit dem delay erledigen. Wie gehe ich da dann 
weiter am besten vor außer den Fehler im vorhandenen Code suchen?

Gruß
Th.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Du kannst systematisch an die Sache rangehen und ein Problem nach dem 
anderen lösen. (#)

Betrifft das Problem die Batterie-LED, dann lasse die Steuerung der 
anderen LEDs mal weg (Stelle in feuchtemessung() auskommentieren). Bei 
der Batterie-LED auch darüber nachdenken, dass sich ein "Kurzes 
Aufblitzen dann 4s Pause" mit der derzeitigen Praxis beisst, die 
Batteriemessung zu machen, wenn trigger gleich 0 ist. Letzteres ist 
nämlich deutlich schneller als die 4s. Deshalb wird es hier garantiert 
eine lustige Sache geben.

Ähnliches kann bei den Feuchte-LEDs passieren. Die Routine zum Setzen 
einer Feuchte-LED ist die Timer-ISR. Die wird alle 16,x ms aufgerufen. 
Die Feuchtemessung selber wird aufgerufen, wenn trigger durch 16 teilbar 
ist.

Letzteres ist

a) wohl schneller als 16 ms, d.h. die Anzeige ist verzögert zur Messung. 
Hier ist zu entscheiden, wie kurz hintereinenader gemessen werden 
muss/soll. IMHO ist es nicht sinnvoll das Messintervall kürzer als das 
Anzeigeintervall zu machen.

Und b) - mein Fehler! - die Setzerei der drei Werte für die Flags, 
welche LED an und welche aus sein soll, ist nicht atomar, d.h. die 
Timer-ISR kann (und wird nach Murphys Gesetz) irgendwann nicht 
konsistente Werte sehen, wenn die Timer-ISR die drei Zeilen unterbricht, 
die beim Setzen des LED Zustands verwendet werden.

Man kann das z.B. auf zwei Arten lösen:

1. ATOMIC-Makro um die jeweils drei Zeilen mit dem Setzcode in 
feuchtemessung(). Das kennst du aus der Hauptschleife.

Oder

2. Verkürzung des Codes auf eine atomare Anweisung z.B. Verwendung von 
Bit-Flags statt uint8_t Flags. Dabei muss man im vom GCC erzeugten 
Assemblercode die Annahme prüfen, ob tatsächlich eine Anweisung erzeugt 
wurde...

Also:
1
// Eine globale (Bit-)Variable für drei LEDS
2
volatile uint8_t takt_LED_FEUCHTE;

Dann in feuchtemessung():
1
    if(messwert >= SCHWELLE_ROT)          
2
    {
3
      takt_LED_FEUCHTE = LED_ROT; // atomar?
4
    }
5
    else if((messwert > SCHWELLE_GELB) && (messwert < SCHWELLE_ROT))  //70
6
    {
7
      takt_LED_FEUCHTE = LED_GELB; // atomar?
8
    }
9
    else if(messwert <= SCHWELLE_GELB)     
10
    {
11
      takt_LED_FEUCHTE = LED_GRUEN; // atomar?
12
    }

Und in der ISR (Teilcode):
1
  if((takt_LED_FEUCHTE & LED_GRUEN) == AUS)
2
  // oder: if( !(takt_LED_FEUCHTE & LED_GRUEN) )
3
    PORTA &= ~LED_GRUEN;
4
  
5
  /* Einschalter */
6
  if((takt_LED_FEUCHTE & LED_GRUEN) == LED_GRUEN)
7
  // oder: if( (takt_LED_FEUCHTE & LED_GRUEN) )
8
    PORTA |= LED_GRUEN;

# Developing a good bedside manner
http://www.embedded.com/design/testissue/220100899?printable=true
http://www.troubleshooters.com/tuni.htm

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!!

Ok dann vergessen wir einfach mal dieses 4sekündige aufblitzen. Nur die 
Feuchteleds sollen blinken und der Taster soll entprellt sein. Ist das 
dann bei der Feuchtemessung ein Problem mit den Aufrufen alle 16 ms. 
Könnte ja sagen alle 19 oder so. Also wenn trigger geteilt durch 19 
teilbar ist oder?
Also das mit dem was du falsch gemacht haben sollst verstehe ich noch 
nicht. Du sagst also dass das

volatile uint8_t takt_LED1_GRUEN;
volatile uint8_t takt_LED2_GELB;
volatile uint8_t takt_LED3_ROT;

nicht funktioniert und man mit einer Variablen für alle LEDs arbeiten 
muss richtig? Theoretisch ist mir das klar. Da ja nie alle LEDs 
gleichzeitig blinken müssen kann man das wohl mit etwas Zeitverlust so 
machen.
Das mit dem takt_LED_FEUCHTE bedeutet man wählt Möglichkeit 2. Was 
bedeutet das mit dem Bit-Flag??
Ich habe jetzt versucht das umzuschreiben alles und es zu durchdenken. 
Grundsätzlich funktioniert die Feuchtemessung auch noch. Allerdings 
blinkt jetzt gar nichts mehr und LED gelb verlischt nicht wenn rot 
angeht. Bzw. rot und gelb bleiben ein wenn schon wieder grün leuchten 
sollte.
Das dürfte wohl dadurch kommen dass ich ja bei der Anwahl der LEDs die 
anderen nicht mehr deaktiviere oder?
Ich versuche im Moment auch noch die Abläufe in meinem Timer zu 
verstehen. Mein Power Down funktioniert auch allerdings kann ich mir 
nicht vorstellen dass da was entprellt ist. Also vermute ich dass mein 
Taster derzeit ohne Entprellung arbeitet.
Wann platzt dieser Beitrag im Forum eigentlich???"g"

Gruß
Th.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Allerdings
> blinkt jetzt gar nichts mehr und LED gelb verlischt nicht wenn rot
> angeht. Bzw. rot und gelb bleiben ein wenn schon wieder grün leuchten
> sollte.

Auf den ersten Blick: Klar bei diesem Code...
1
  if((takt_LED_FEUCHTE & LED_GRUEN) == AUS)
2
    PORTA &= ~LED_GRUEN;
3
  if((takt_LED_FEUCHTE & LED_GELB) == AUS)
4
    PORTA &= ~LED_GRUEN;
5
  if((takt_LED_FEUCHTE & LED_ROT) == AUS)
6
    PORTA &= ~LED_GRUEN;
da wird immer nur die grüne LED geschaltet! Ich schaue mir den Rest an 
und laden dann den neuen Code hoch.

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

Bastler schrieb:

> Ok dann vergessen wir einfach mal dieses 4sekündige aufblitzen. Nur die
> Feuchteleds sollen blinken und der Taster soll entprellt sein.

Dazu ist jetzt ein #if 0 #endif in batteriemessung(). Daran denken, das 
später wieder rauszuholen.

> Ist das
> dann bei der Feuchtemessung ein Problem mit den Aufrufen alle 16 ms.
> Könnte ja sagen alle 19 oder so. Also wenn trigger geteilt durch 19
> teilbar ist oder?

Es kommt auf die Anwendung an, die ich nicht kenne. Ändert sich die rel. 
Luftfeuchte bei deiner Anwendung tatsächlich so schnell oder würde es 
reichen in grösseren Abständen zu messen. Von der Anzeige her, bekommt 
keiner mit, ob die LED 16ms später an- oder ausgeht.

> Also das mit dem was du falsch gemacht haben sollst verstehe ich noch
> nicht. Du sagst also dass das
>
> volatile uint8_t takt_LED1_GRUEN;
> volatile uint8_t takt_LED2_GELB;
> volatile uint8_t takt_LED3_ROT;
>
> nicht funktioniert und man mit einer Variablen für alle LEDs arbeiten
> muss richtig? Theoretisch ist mir das klar. Da ja nie alle LEDs
> gleichzeitig blinken müssen kann man das wohl mit etwas Zeitverlust so
> machen.

Wenn du wie im alten Code drei Anweisungen hast, um einen Anzeigezustand 
einzustellen, kann dir zwischen die drei Anweisungen ein Interrrupt 
reinfunken und du endest mit einem teilweise vor und teilweise nach dem 
Interrupt gesetzten Zustand. Das kann hier dazu führen, dass kurzzeitig 
nicht nur eine LED leuchtet oder gar keine LED leuchtet. Deshalb die 
Suche nach einer Möglichkeit mit einem ununterbrechbaren Maschinenbefehl 
einen Anzeigezustand einzustellen.

> Das mit dem takt_LED_FEUCHTE bedeutet man wählt Möglichkeit 2. Was
> bedeutet das mit dem Bit-Flag??

Diese Möglichkeit bietet eine Variable, deren einzelne Bits als Schalter 
benutzt werden. Alle Bits können bei einer 8-Bit Variablen in einer 
Zuweisung an die Variable zugewiesen werden. Die C-Anweisung wird 
(prüfen!) in einen Maschinenbefehl übersetzt und der wird dann ohne 
Unterbrechung durch einen Interrupt abgearbeitet.

> Ich versuche im Moment auch noch die Abläufe in meinem Timer zu
> verstehen.

Die Timer-ISR wird alle 16.x ms aufgerufen.

61 Aufrufe heisst 1s sind rum. Bei jedem Aufruf wird daher ein mit 61 
vorbelegter Zähler (takt) runtergezählt. Wenn der Zähler bei 0 landet, 
wird ein zweiter Zähler (sekunde) hochgezählt. Das ist die Funktion 
"Uhr"

In der Timer-ISR wird bei jedem Durchlauf nachgesehen, ob das 
Userprogramm angegeben hat, dass bestimmte LEDs AUSgeschaltet werden 
sollen. Die Variable dazu sind die Variablen takt_LED_FEUCHTE und 
takt_LED_BAT. Wenn in takt_LED_FEUCHTE bestimmte Bits 0 sind, wird die 
entsprechende LED ausgeschaltet. Wenn takt_LED_BAT = AUS ist, wird die 
Batterie LED ausgeschaltet. Das ist die Funktion "Ausschalter".

In der Timer-ISR wird bei jedem Durchlauf nachgesehen, ob das 
Userprogramm angegeben hat, dass bestimmte LEDs EINgeschaltet werden 
sollen. Die Variable dazu sind die Variablen takt_LED_FEUCHTE und 
takt_LED_BAT. Wenn in takt_LED_FEUCHTE bestimmte Bits 1 sind, wird die 
entsprechende LED eingeschaltet. Wenn takt_LED_BAT = EIN ist, wird die 
Batterie LED ausgeschaltet. Das ist die Funktion "Einschalter".

Als Besonderheit gilt hier, dass die gelbe und rote Feuchte-LED und die 
Batterie-LED blinken sollen.

Bei den blinkenden Feuchte-LEDs (1 Hz und 2 Hz) erfolgt das durch 
Abpassen des richtigen Moments (takt % ...) und Toggeln des Ports an dem 
die LED hängt (^=).

Bei der blinkenden Batterie-LED erfolgt das durch getrennte AN/AUS 
Schalterei, weil der Rhythmus "kurz aufblitzen, dann 4s Ruhe" sein soll.

Die 4s werden dadurch realisiert, dass takt_LED_BAT hochgesetzt wird und 
eine bestimmte Anzahl von Durchläufen mit Runterzählen verstreichen 
müssen, bis die LED wieder angeschaltet wird.

> Mein Power Down funktioniert auch allerdings kann ich mir
> nicht vorstellen dass da was entprellt ist. Also vermute ich dass mein
> Taster derzeit ohne Entprellung arbeitet.

Die Entprellung des EIN/AUS-Tasters wird in tastenabfrage() dadurch 
sichergestellt, dass eine bestimmte Zahl (80/16) von Timer-ISRs 
verstrichen sein müssen und der Pegel am Pin dann gleich dem zuerst 
abgefragten Pegel sein muss. Es wurde nur das _delay_ms(80) ersetzt.

Der Taster an INT0 zum Aufwecken ist nicht entprellt. Hier wird auf den 
ersten ankommenden LOW-Pegel reagiert.

> Wann platzt dieser Beitrag im Forum eigentlich???"g"

Das Forum ist sehr stabil. Ich habe noch nie einen Thread platzen sehen. 
Und wir brauchen nur noch 4 Fragen/Antworten dann sind wir bei 100

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

So, ich hatte heute abend etwas Zeit und habe dein Programm auf den 
Attiny2313 portiert, weil ich den zu Hause hatte.

In der Source ist dazu am Anfang ein #define für mein POLLIN... Board 
mit dem Attiny2313 bei 8 MHz, was auch einen anderen Vorteiler verlangt. 
Das #define lässt du für den Attiny24 einfach auskommentiert stehen.

Da beim Wechsel vom Attiny24 zum Attiny2313 alle Pins anders verstrippt 
werden mussten, habe ich dafür Makros eingeführt. Der Attiny2313 hat 
auch keinen ADC, deshalb arbeite ich hier mit künstlichen Prüfwerten. Du 
kannst ja die echte Messung machen.

Beim Praxistest ist mir als erstes der Schluckauf beim Blinken 
aufgefallen. Ursache war, dass der Hilfszähler takt nicht 
zurückgesetzt wurde, wenn er 0 erreicht hatte. Wo der Codeschnippsel in 
der langen Diskussion verloren ging, weiss ich nicht. Er war mal da.

Im Moment gibt es auch nur einen aktiven Taster - den Wecktaster an dem 
INT0 Pin. Damit schaltet man den AVR EIN (wecken) und AUS (schlafen). 
Dafür wurde auch die Entprellung etwas sorgfältiger behandelt, aber 100% 
optimal ist es noch nicht. Man kann das einfach auf zwei Taster (1xAUS 
und 1xWecken) ändern, wenn dir das lieber hast.

Ich hoffe du kommst mit dem Code zurecht. Wenn nicht frag einfach.

von Test (Gast)


Lesenswert?

Guten Morgen!!

Nochmal herzlichen Dank. Ich bin bis jetzt noch nicht dazu gekommen mir 
deine erste Mail anzuschauen und alles auszuwerten. Ich hoffe aber dass 
ich es heute noch schaffen werde!!

Gruß
Thomas

von Bastler (Gast)


Lesenswert?

Hallo!

Zunächst mal zum Code deiner ersten Email. Es funktioniert schon mal 
wesentlich besser. Allerdings scheint das schnelle Blinken der LED doch 
manchmal etwas hektisch. Man könnte also durchaus damit es einfacher 
wird für gelb und rot den gleichen Blinktakt wählen. Also 1 Hz. Das 
sollte die Sache dann wohl noch einfacher gestalten. Das blinken ist 
allerdings unregelmäßig.
Ok also das #if 0 #endif ist so wie wenn ich "/*......*/" mache. Das ist 
mir schon klar. Mit #if 1 aktiviere ich diesen Teil des Codes. Wozu 
gehört dann dass #ifdef und #else??
Es reicht leicht in größeren Abständen zu messen weil es eh immer dauert 
und die Messung ja von Haus aus sehr ungenau ist. Was bedeutet größere 
Abstände?? Halbe Sekunde??
Ok das mit den 61 Aufrufen pro Sekunde ist mir klar. Also grundsätzlich 
wird mein Timer Interrupt alle 16,.. ms aufgerufen. Es sind auch 
wirklich 16 ms weil das nach dem Komma wegfällt. Dann arbeitet er da 
durch und schaut ob er was zu blinken oder was auch immer hat. Wenn 
nicht springt er wieder ins Programm zurück. Richtig? Ja das mit dem 
takt-- ist klar. Also jeden Aufruf -1. Am Ende der ISR ist dann ja noch 
takt_Taster ++. Das wird also hochgezählt oder wie? Funktion Ausschalter 
ist klar. Ja genau mit dem ^= habe ich auch noch meine Probleme. &= ist 
mir klar und |= ist mir auch klar.
Zum Aufwecken wird eine Entprellung ja wohl nicht nötig sein oder??

Zweiter Eintrag von dir:
Das sieht ja schon mal völlig anders aus irgendwie.... Also zwei Taster 
wäre schlecht wegen meiner Technologie. Es sollte schon bei einem 
bleiben. Ok nochmal zu dem #if. Also wenn #if 0 dort steht und danach 
#else wird in dem Fall der else teil ausgeführt oder?

WOW!! Ich glaube jetzt klappt das wirklich alles. Mein LED Bat LED 
leuchtet wie gewünscht und das andere klappt auch super. So jetzt werde 
ich aber erst mal heimgehen!!"g" Da stürze ich mich morgen wieder drauf.
Nochmals vielen Dank. Normal würd ich sagen des kost a Mass!!!"g"

Gruß
Th.

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Und hier mal der Ansatz mit Statemachine.

Ich hab aber nur nen ATmega48 gehabt, der ATtiny24 paßt nicht aufs 
STK500.
Die Messungen werden mit 4 Tasten simuliert.
Ich hoffe mal, ich hab die Blinkmuster richtig aus Deinem Code 
interpretiert.

Das Power-Down ist noch nicht drin. Das sollte man auch besser zum 
Schluß machen, wenn alles andere richtig funktioniert.
Im Anhang sind alle nötigen Files.
1
#include <util\atomic.h>                        // need "--std=c99"
2
#include <avr\power.h>
3
#include <avr\interrupt.h>
4
#include "humidity.h"
5
#include "getkey.h"
6
7
8
enum {
9
        MEASURE,
10
        WET,
11
        NORMAL,
12
        DRY,
13
        LOWBATT,
14
        OFF
15
};
16
17
18
uint8_t state = MEASURE;
19
20
21
void init( void )
22
{
23
  LED_WET_DDR = 1;
24
  LED_NORMAL_DDR = 1;
25
  LED_DRY_DDR = 1;
26
  LED_LOWBATT_DDR = 1;
27
28
  get_key_init();
29
  clock_prescale_set( clock_div_8 );            // 1MHz
30
}
31
32
33
void power_on_off( void )
34
{
35
  if( get_key_press( 1<<KEY_OFF )){
36
    if( state == OFF )
37
      state = MEASURE;
38
    else
39
      state = OFF;
40
  }
41
}
42
43
44
void low_bat( void )
45
{
46
  if( get_key_press( 1<<KEY_SIMULATE_LOWBATT ))
47
    state = LOWBATT;
48
}
49
50
51
void meas_humidity( void )
52
{
53
  if( get_key_press( 1<<KEY_SIMULATE_WET ))
54
    state = WET;
55
  if( get_key_press( 1<<KEY_SIMULATE_NORMAL ))
56
    state = NORMAL;
57
  if( get_key_press( 1<<KEY_SIMULATE_DRY ))
58
    state = DRY;
59
}
60
61
62
int main( void )
63
{
64
  init();
65
  sei();
66
67
  for(;;){
68
69
    meas_humidity();
70
    low_bat();
71
    power_on_off();
72
73
    switch( state ){
74
75
      case MEASURE:
76
                LED_WET     = LED_ON;
77
                LED_NORMAL  = LED_ON;
78
                LED_DRY     = LED_ON;
79
                LED_LOWBATT = LED_OFF;
80
                break;
81
82
      case WET:
83
                LED_WET     = LED_ON ^ !!(flasher & 0x20);      // 1s
84
                LED_NORMAL  = LED_OFF;
85
                LED_DRY     = LED_OFF;
86
                LED_LOWBATT = LED_OFF;
87
                break;
88
89
      case NORMAL:
90
                LED_WET     = LED_OFF;
91
                LED_NORMAL  = LED_ON;
92
                LED_DRY     = LED_OFF;
93
                LED_LOWBATT = LED_OFF;
94
                break;
95
96
      case DRY:
97
                LED_WET     = LED_OFF;
98
                LED_NORMAL  = LED_OFF;
99
                LED_DRY     = LED_ON ^ !!(flasher & 0x10);      // 0.5s
100
                LED_LOWBATT = LED_OFF;
101
                break;
102
103
      case LOWBATT:
104
                LED_WET     = LED_OFF;
105
                LED_NORMAL  = LED_OFF;
106
                LED_DRY     = LED_OFF;
107
                LED_LOWBATT = LED_ON ^ !!(flasher & 0xF0);      // 4s
108
                break;
109
110
      case OFF:
111
                LED_WET     = LED_OFF;
112
                LED_NORMAL  = LED_OFF;
113
                LED_DRY     = LED_OFF;
114
                LED_LOWBATT = LED_OFF;
115
                break;
116
    }
117
  }
118
}


Peter

von Stefan B. (stefan) Benutzerseite


Lesenswert?

AAARRRRRGGGHHHH - Jetzt schnappt sich der Peter die 100 ;-)

Bastler schrieb:

> Ok also das #if 0 #endif ist so wie wenn ich "/*......*/" mache. Das ist
> mir schon klar. Mit #if 1 aktiviere ich diesen Teil des Codes. Wozu
> gehört dann dass #ifdef und #else??

#if, #ifdef, #else, #endif... sind Anweisungen für den C-Präprozessor. 
Wenn du mehr in C programmierst, brauchst du die und du solltest dir das 
in einem C Buch anschauen.

> Es reicht leicht in größeren Abständen zu messen weil es eh immer dauert
> und die Messung ja von Haus aus sehr ungenau ist. Was bedeutet größere
> Abstände?? Halbe Sekunde??

Weiss nicht, du musst ein Gefühl dafür bekommen, wie dein Gerät 
eingesetzt wird und wie geduldig/ungeduldig die Anwender sind. Wenn der 
Prototyp einsatzbereit ist, gib ihn mal einem vollkommen unbedarften 
Anwender. Sag nix zur Bedienung und schau eine halbe Stunde zu...

> Ok das mit den 61 Aufrufen pro Sekunde ist mir klar. Also grundsätzlich
> wird mein Timer Interrupt alle 16,.. ms aufgerufen. Es sind auch
> wirklich 16 ms weil das nach dem Komma wegfällt.

Nein, überlege das nochmal durch.

Es sind exakt 16,384 ms von Überlauf zu Überlauf, ABER du zählst für 
die Sekunde ganzzahlig 61 mal diesen Überlauf statt exakt 61,03515625 
mal, d.h. deine "Pseudosekunde" ist nur 16,384*61 = 999,424 ms lang 
statt 16,384*61,03515625 = 1000 ms. Exakt heisst hier natürlich nur im 
Rahmen der Genauigkeit der Taktquelle.

> Ja genau mit dem ^= habe ich auch noch meine Probleme. &= ist
> mir klar und |= ist mir auch klar.

Steht auch in jedem C Buch unter dem Abschnitt Operatoren für 
Bitmanipulation (Bits invertieren).

> Zum Aufwecken wird eine Entprellung ja wohl nicht nötig sein oder??

Der INT0 ist ein extrem scharfer Wachhund. Sobald die Leitung vom Taster 
an den Pin LOW geht, schlägt der Interrupt zu. Da ist zunächst nix mit 
Entprellen, zumal der AVR ja noch pennt und für die Entprellung in 
Software erstmal aufwachen muss. Im Code fehlte aber das Warten auf das 
Loslassen der Aufwecktaste.

An der Stelle müsste man noch etwas sorgfältiger arbeiten und die 
Tasterabfrage aufräumen. Ich könnte mir vorstellen, dass die Timer-ISR 
auch regelmäßig den Tastenzustand abfragt und entprellt und die 
tasterabfrage() nur das Ergebnis bekommt. Wahrscheinlich hat Peter im 
Code oben das so gemacht; seine bewährte Routine zur Tastenentprellung 
arbeitet mit dem Timer.

> Zweiter Eintrag von dir:
> Das sieht ja schon mal völlig anders aus irgendwie.... Also zwei Taster
> wäre schlecht wegen meiner Technologie. Es sollte schon bei einem
> bleiben.

Ja, mit den zwei Tastern war ein Mistverständnis von mir.

> Nochmals vielen Dank. Normal würd ich sagen des kost a Mass!!!"g"

Gerngeschehen. Das Maß gönne ich mir am Wochenende.

von Bastler (Gast)


Lesenswert?

Hallo!

Also überblicksmäßig sieht das ja toll aus mit der Statemachine. Das ist 
ja wirklich viel einfacher. Da ist der Code ja nur noch 2 Seiten lang 
anstatt meinen 8 oder 9 Seiten.
Im Endcode kommen die ganzen #if Kommentare dann ja raus vermute ich 
oder? Das wäre ja ein unsauberer Stil.
Gefällt mir alles so weit gut. Also mein gelbes LED blinkt jetzt 
praktisch mit 1Hz. Das heißt 0,5s an und 0,5s aus. Das rote ist 0,25s an 
und 0,25s aus. Naja beides auf 1Hz setzen das schaffe ich auch noch. Was 
mir nur auffällt ist dass wenn dass Bat-LED blitzt und rot oder gelb 
blinkt dann zuckt das hin und wieder. Das ist nicht schlimm wird sich 
auch so nicht beheben lassen vermute ich.
Naja jetzt steht nur noch an dass man den Spannungsteiler nicht an VCC 
hängt sondern an einen Portpin. Das geht wohl über die REFS1 und REFS2 
Bits oder?

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Im Endcode kommen die ganzen #if Kommentare dann ja raus vermute ich
> oder? Das wäre ja ein unsauberer Stil.

Wieso wäre das unsauber? "Legale" Anwendung solcher #if..#endif Klammern 
ist z.B. die Konfiguration auf unterschiedliche Hardware oder als 
Unterscheidung von Debug/Release-Code.

Beides wird oben verwendet. Einmal als Unterscheidung zwischen dem 
unterschiedlichen Anschluss an einen Attiny24 von dir und einen 
Attiny2313 von mir. Und einmal als Debugcode mit bestimmten Testwerten 
statt aktueller Hardware und dem Releasecode mit der tatsächlichen 
Messung.

Wenn etwas unsauber ist, dann die Stellen bei denen lediglich ein #if 0 
oder #if 1 steht. Die sollte man sauber dokumentieren oder streichen, 
wenn es alter nicht mehr benutzter Testcode ist.

> Gefällt mir alles so weit gut. Also mein gelbes LED blinkt jetzt
> praktisch mit 1Hz. Das heißt 0,5s an und 0,5s aus. Das rote ist 0,25s an
> und 0,25s aus. Naja beides auf 1Hz setzen das schaffe ich auch noch.

Ähm, du wolltest doch extra, dass Gelb langsam blinkt und Rot doppelt so 
schnell. Jetzt willst du das wieder nicht?

> Was
> mir nur auffällt ist dass wenn dass Bat-LED blitzt und rot oder gelb
> blinkt dann zuckt das hin und wieder. Das ist nicht schlimm wird sich
> auch so nicht beheben lassen vermute ich.

Ist mir so nicht aufgefallen, werde ich mal darauf achten. Ich betreibe 
die Schaltung aber auch an einem Netzteil mit genügend Saft und nicht an 
einer Batterie. (Batterie-)betrieb mit <5V (>=9V vor 
Festspannungsregler) ist dort nicht möglich.

> Naja jetzt steht nur noch an dass man den Spannungsteiler nicht an VCC
> hängt sondern an einen Portpin. Das geht wohl über die REFS1 und REFS2
> Bits oder?

Du hast doch schon den Jumper JP1 drin, um entweder Vcc oder die 
Spannung von PA7 auf den Spannungsteiler zu geben. Wenn der Jumper JP1 
auf Versorgung durch PA7 gesetzt wird, muss vor der Feuchtemessung PA7 
einen HIGH-Pegel ausgeben und am besten direkt nach der Feuchtemessung, 
aber spätestens vor dem Schlafengehen einen LOW-Pegel (Stromsparen).

Die Einstellung der ADC-Referenz kann gleich bleiben. Als ADC-Referenz 
kann immer die im AVR intern geführte Vcc benutzt werden oder im 
Spezialfall die iM AVR interne Bandgap-Referenz von 1.1V, wenn die 
erwartete Maximalspannung an dem Messeingang ADC0 kleiner 1.1V ist. 
Welche von beiden du benutzt, wird über REFS1 und REFS2 eingestellt.

Wenn du die Referenz von Vcc auf 1.1V umstellst, weil vielleicht die 
max. Messspannung bei Versorgung durch PA7 kleiner als 1.1V wird, dann 
denk daran, dass sich die SCHWELLE_... Werte bei der Feuchte ändern. Die 
Batteriemessung ist davon nicht betroffen.

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

So, hier jetzt mal mit kompletter Funktion.

Du mußt nur noch die Anpassungen an Deine Schaltung machen.
Die Pinanpassungen sind ja einfach zu machen.
Der Timer0 müßte beim ATtiny24 sogar gleich sein (mal prüfen).
Unterschiede könnten noch beim ADC sein (MUX).

Die einzelnen Spannungsschwellen mußt Du einfach nur eintragen.
Für die Messung muß ja an den Bereichsgrenzen ne Hysterese erfolgen, 
damit die LEDs nicht flackern.

Die Bandgap ist sehr hochohmig, d.h. die ersten 8 Messungen stimmen 
nicht. Daher werden erstmal 16 Dummymessungen gemacht.
Den Sensor habe ich mit einem Poti simuliert und die 
Unterspannungserkennung mit dem STK500 (Einstellen der Targetspannung).
Wurde Unterspannung erkannt, kommt man erst wieder durch an/aus in den 
Meßmodus. Es kann also auch da kein Flackern passieren.

Bei mir funktioniert somit alles einwandfrei.
Als letzter Schritt ist dann nur noch das Stromsparen übrig (sollte man 
ja immer als letztes machen).
1
#include <util\atomic.h>                        // need "--std=c99"
2
#include <avr\power.h>
3
#include <avr\interrupt.h>
4
#include "humidity.h"
5
#include "getkey.h"
6
7
8
enum {
9
        MEASURE,
10
        WET,
11
        NORMAL,
12
        DRY,
13
        LOWBATT,
14
        OFF
15
};
16
17
18
uint8_t state = MEASURE;
19
20
21
static inline void init( void )
22
{
23
  LED_WET_DDR = 1;
24
  LED_NORMAL_DDR = 1;
25
  LED_DRY_DDR = 1;
26
  LED_LOWBATT_DDR = 1;
27
  MEAS_PWR_DDR = 1;
28
29
  get_key_init();
30
  clock_prescale_set( clock_div_8 );            // 1MHz
31
}
32
33
34
static inline void power_on_off( void )
35
{
36
  if( get_key_press( 1<<KEY_ON_OFF )){
37
    if( state == OFF )
38
      state = MEASURE;
39
    else
40
      state = OFF;
41
  }
42
}
43
44
45
uint16_t read_adc( uint8_t channel )
46
{
47
  uint16_t val = 0;
48
49
  ADMUX = channel;
50
  for( uint8_t i = 16; i; i-- ){
51
    ADCSRA = 1<<ADEN                    // ADC on
52
           | 1<<ADSC                    // ADC start
53
           | 1<<ADIF                    // clear ADIF
54
           | 1<<ADPS1 | 1<<ADPS0;       // 1MHz / 8 = 125kHz (50..200kHz)
55
    while( !(ADCSRA & 1<<ADIF) );       // wait until conversion done
56
    val += ADC;
57
  }
58
  return val >> 4;                      // average over 16 samples
59
}
60
61
62
static inline void low_bat( void )
63
{
64
                                        // Bandgap need dummy measurement !!!
65
      read_adc( 1<<REFS0                        // VCC as reference
66
              | 0<<ADLAR                        // ADC = 10 bit value
67
              | 14 );                           // input 14 = 1.1V Bandgap
68
69
  if( read_adc( 1<<REFS0                        // VCC as reference
70
              | 0<<ADLAR                        // ADC = 10 bit value
71
              | 14 ) > THRESHOLD_LOWBATT )      // input 14 = 1.1V Bandgap
72
    state = LOWBATT;
73
}
74
75
76
static inline void meas_humidity( void )
77
{
78
  MEAS_PWR = 1;                                 // sensor power on
79
  switch( read_adc( 1<<REFS0                    // VCC as reference
80
                  | 0<<ADLAR                    // ADC = 10 bit value
81
                  | MEAS_IN )){                 // input ADC1
82
83
    case 0 ... THRESHOLD_WET1:
84
                        state = WET;            // wet
85
                        break;
86
87
    case THRESHOLD_WET1 + 1 ... THRESHOLD_WET2:
88
                        if( state == WET )      // hysteresis (stay wet/normal)
89
                          break;
90
91
    case THRESHOLD_WET2 + 1 ... THRESHOLD_DRY1:
92
                        state = NORMAL;         // normal
93
                        break;
94
95
    case THRESHOLD_DRY1 + 1 ... THRESHOLD_DRY2:
96
                        if( state == NORMAL )   // hysteresis (stay normal/dry)
97
                          break;
98
99
    default:
100
                        state = DRY;            // dry
101
  }
102
  MEAS_PWR = 0;                                 // sensor power off
103
}
104
105
106
int main( void )
107
{
108
  init();
109
  sei();
110
111
  for(;;){
112
113
    power_on_off();
114
    switch( state ){
115
116
      case MEASURE:
117
      case WET:
118
      case NORMAL:
119
      case DRY:
120
                meas_humidity();
121
                low_bat();
122
    }
123
    switch( state ){
124
125
      case WET:
126
                LED_WET     = LED_ON ^ !!(flasher & 0x20);      // 1s
127
                LED_NORMAL  = LED_OFF;
128
                LED_DRY     = LED_OFF;
129
                LED_LOWBATT = LED_OFF;
130
                break;
131
132
      case NORMAL:
133
                LED_WET     = LED_OFF;
134
                LED_NORMAL  = LED_ON;
135
                LED_DRY     = LED_OFF;
136
                LED_LOWBATT = LED_OFF;
137
                break;
138
139
      case DRY:
140
                LED_WET     = LED_OFF;
141
                LED_NORMAL  = LED_OFF;
142
                LED_DRY     = LED_ON ^ !!(flasher & 0x10);      // 0.5s
143
                LED_LOWBATT = LED_OFF;
144
                break;
145
146
      case LOWBATT:
147
                LED_WET     = LED_OFF;
148
                LED_NORMAL  = LED_OFF;
149
                LED_DRY     = LED_OFF;
150
                LED_LOWBATT = LED_ON ^ !!(flasher & 0xF0);      // 4s
151
                break;
152
153
      case OFF:
154
                LED_WET     = LED_OFF;
155
                LED_NORMAL  = LED_OFF;
156
                LED_DRY     = LED_OFF;
157
                LED_LOWBATT = LED_OFF;
158
                break;
159
    }
160
  }
161
}


Wenn Du was nicht verstehst, frag ruhig.


Peter

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

So, hier nun die fertige Version.

Für das Schlafen habe ich den Pin-Change Interrupt genommen.
Das hat den Vorteil, daß man bereits beim Drücken schlafen gehen kann 
und man ist außerdem flexibler mit der Pin-Wahl.

Für das Schlafen habe ich noch ne extra Funktion in die Get-Key Routine 
geschrieben. Mit dieser kann man testen, ob das Entprellen der 
Aufwachtaste schon beendet ist. Erst dann darf man schlafen gehen.

An der Schlaffunktion ist nichts besonderes. Sobald mit der Taste der 
Zustand "OFF" ausgewählt wurde, wird sie aufgerufen und versucht 
schlafen zu gehen. Da die Taste prellt, wird mehrmals sofort wieder 
aufgewacht, aber das stört überhaupt nicht.
Durch die Trennung von Schlaffunktion und Entprellfunktion gibt es keine 
unerwünschten Zustandswechsel. Die Schlaffunktion kümmert sich nur um 
das Stromsparen und die Entprellfunktion nur um die Statemachine.

Die Blinkfunktionen habe ich noch etwas verständlicher geschrieben 
(if/else).

Ich denke, an den 3 Schritten sieht man auch schön eine sinnvolle 
Vorgehensweise:

1. Grundgerüst mit Dummyfunktionen
2. Ersetzen der Dummyfunktionen mit den Meßfunktionen
3. Stromsparen

Besonders für den 3.Schritt ist es wichtig, daß die Entprellung schon 
einwandfrei funktioniert, sonst wird das nix.


Der Code ist insgesamt auf 676 Byte angewachsen.


Peter

von Bastler (Gast)


Lesenswert?

Guten Morgen!!

Zunächst wieder mal herzlichen Dank für eure umfangreiche Hilfe...!

Zu Stefans Nachricht:
Wußte ich nicht dass man dieses #if ... #endif so verwendet. Ist aber 
umso besser wenn das möglich ist!! Solang es mit der Codegröße kein 
Problem ergibt. Weiss ja nicht wieviel mein Attiny 24 schluckt. 
Irgendwann wird der Kanal wohl mal zu sein?!
Ja ich weiss ich wollte die verschiedenen Blinkfrequenzen. Ich werde da 
auch nochmals nachfragen was gewünscht wird. Ich wollte es hald nur mal 
testen ob ich das auch anders machen kann mit gleicher 
Blinkgeschwindigkeit!
Meinst du das hängt mit der Batterie zusammen dieses "überblinken"?? Es 
ist nur immer wenn das Ereignis doppelt auftritt.
Ja. Also hardwaremäßig brauche ich nichts mehr verändern um den 
Spannungsteiler an einen Portpin zu hängen. Sprich des sieht dann so aus 
wie bei meinem Power Down Taster. Referenz kann gleich bleiben auch wenn 
ich das nicht verstehe. Ich lege den Portpin auf Eingang und auf High. 
Dann hat er wohl Vcc - x als Versorgungsspannung. Vorm schlafen gehen 
setze ich das dann auf 0 und nach dem aufwachen wieder auf 1 vermute ich 
mal. Glaubst du dass an dem Portpin unter 1,1 V anliegen. Da sollte doch 
annähernd mein Vcc sein? Kann man ja leicht messen da beim PowerDown 
Taster.


Zu Peters Nachricht:
Also mit einer State Machine (Zustandsautomat) bin ich wohl auf der 
sicheren Seite vermute ich mal?! Ich werde auch den Code mal 
ausprobieren. Die ersten 8 Messungen stimmen nicht. Dürfte ja kein 
Problem sein da mein Sensor grundsätzilch schon ungenau ist. Ich 
verwende ja auch kein Display sondern nur die 3 LEDs. Ok. Bei mir waren 
es ja die 4 Dummymessungen und jetzt sind es hald 16.
Was meinst du mit Stromsparen? Beim PowerDown dass alles ausgeschaltet 
wird?? Das Problem für mich wird ja nur sein den Code in meiner 
Facharbeit dementsprechend zu beschreiben!!"g" Da ich natürlich erst mal 
immer viele Seiten schreiben möchte wäre natürlich der "normale" Code 
besser weil man da wohl mehr beschreiben kann so weit ich das bewerten 
kann. State Machine wäre hald wohl die professionelle Lösung so wie ich 
das jetzt deinen Aussagen entnehme.
Den pin-Change Interrupt hast du benutzt. Mir wurde aber doch gesagt 
dass das mit dem Taster mehrere Zustände sind. Drücken, der Zustand wo 
Taster gedrückt und dann der Zustand wo Taster ausgelassen wird. Und 
sollte nicht dann erst was passieren??? Habe ich da was falsch 
verstanden?
Das mit der Schlaffunktion verstehe ich noch nicht. Die Taste prellt hat 
aber eine Entprellung???? Das widerspricht sich doch oder??
676 Byte muss ich da beim Attiny 24 Angst haben?? Schafft er das noch???

Danke!

Gruß
Th.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Meinst du das hängt mit der Batterie zusammen dieses "überblinken"?? Es
> ist nur immer wenn das Ereignis doppelt auftritt.

Das weiss ich nicht. Viele Gedanken habe ich mir da nicht gemacht, weil 
ich die Situation nicht komplett nachstellen kann.

> Ja. Also hardwaremäßig brauche ich nichts mehr verändern um den
> Spannungsteiler an einen Portpin zu hängen. Sprich des sieht dann so aus
> wie bei meinem Power Down Taster.

Ich verstehe nicht was der Power Down Taster mit der Spannungsversorgung 
des Spannungsteilers zu tun hat.

> Referenz kann gleich bleiben auch wenn
> ich das nicht verstehe.

Aus dem Portpin PA7 käme maximal Vcc raus (in der Praxis etwas weniger, 
Datenblatt), d.h. wenn deine Messung mit der Vcc-Versorgung und der 
Referenz Vcc funktioniert, wird die Messung auch mit der 
Portpin-Versorgung und der Referenz Vcc funktionieren.

> Ich lege den Portpin auf Eingang und auf High.
> Dann hat er wohl Vcc - x als Versorgungsspannung. Vorm schlafen gehen
> setze ich das dann auf 0 und nach dem aufwachen wieder auf 1 vermute ich
> mal.

So sieht es aus. Und: Wenn gerade keine Feuchtemessung läuft, braucht 
der Spannungsteiler auch keinen Strom... Abgesehen davon könnte es für 
den Sensor auch gesund sein, wenn er nicht dauernd stromführend ist, 
auch wenn es sich um sehr kleine Ströme handelt (Datenblatt).

> Glaubst du dass an dem Portpin unter 1,1 V anliegen. Da sollte doch
> annähernd mein Vcc sein? Kann man ja leicht messen da beim PowerDown
> Taster.

Die Messung würde nichts bringen. Hier ist ein anderen Portpin gemeint: 
Der Messeingang der Spannung des Spannungsteilers, also deine 
Signalspannung an PA0. Nicht der Portpin zur Spannungsversorgung des 
Spannungsteilers!

Wenn die Signalspannung an PA0 immer kleiner als 1.1V ist, könntest du 
statt der Referenz Vcc die Referenz 1.1V einsetzen und so die Auflösung 
(Auflösung und Genauigkeit) erhöhen.

von Bastler (Gast)


Lesenswert?

Hallo!

Der Power Down hat nichts mit der Spannungsversorgung für den 
Spannungsteiler zu tun. Mir ging es da nur um die Pinbeschreibung. Ich 
werde für meine Spannungsversorgung die gleichen Werte benötigen wie für 
den Power-Down Taster. Also auf Eingang und High für Pull-Up. Ok das mit 
dem Portpin PA7 ist auch klar.
Dann werde ich das mal versuchen. Werde mich diesbezüglich wohl bald 
wieder melden!

von Peter D. (peda)


Lesenswert?

Bastler schrieb:
> Die ersten 8 Messungen stimmen nicht. Dürfte ja kein
> Problem sein da mein Sensor grundsätzilch schon ungenau ist.

Nö, das betrifft nur die Bandgap-Messung, ich hatte oben schonmal Links 
dazu gepostet.

> Das Problem für mich wird ja nur sein den Code in meiner
> Facharbeit dementsprechend zu beschreiben!!"g"

Vielleicht kann ja mal Stefan drüberschauen, ob er ihn versteht.

> Da ich natürlich erst mal
> immer viele Seiten schreiben möchte wäre natürlich der "normale" Code
> besser weil man da wohl mehr beschreiben kann

Ich glaub, zu der Statemachine gibts auch genug zu schreiben.
Der Vorteil ist, daß man die Funktionen getrennt beschreiben kann, da 
sie voneinander unabhängig sind.


> Mir wurde aber doch gesagt
> dass das mit dem Taster mehrere Zustände sind. Drücken, der Zustand wo
> Taster gedrückt und dann der Zustand wo Taster ausgelassen wird. Und
> sollte nicht dann erst was passieren???

Genau daher eben die Trennung zwischen Power-Down und Entprellen.
Die Entprellfunktion wurde schon woanders beschrieben:

http://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29


> 676 Byte muss ich da beim Attiny 24 Angst haben?? Schafft er das noch???

Schau mal ins Datenblatt, da stehts drin.


Peter

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Ich
> werde für meine Spannungsversorgung die gleichen Werte benötigen wie für
> den Power-Down Taster. Also auf Eingang und High für Pull-Up. Ok das mit
> dem Portpin PA7 ist auch klar.
> Dann werde ich das mal versuchen. Werde mich diesbezüglich wohl bald
> wieder melden!

Tu das, mich interessiert, ob die Vorsorgung durch einen *Inputpin mit 
Pull-Up* funktioniert.

Du hast eine Vcc abhängige und auf wenige µA begrenzte Versorgung durch 
den internen 20k bis 50k Pull-Up (Abschnitt 21.6 Pin Pull-up im 
Datenblatt).

Als zweiten, aber kleinen Stromabnehmer hast du neben dem 
Spannungsteiler den sehr hochohmigen Inputpin (im Bereich von typ. 
<0.05µA bis max. 1µA bei Vcc 5V, Input Leakage Current I/O Pin in Table 
20-1. DC Characteristics).

Ich bin gespannt, ob der Spannungteiler (1M5 bis 2M5 Ohm tot. je nach 
Feuchte) dann ausreichend befeuert wird.

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Anbei das Programm an Deine Schaltung angepaßt und für den ATtiny24 
compiliert.


Peter

von Bastler (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!!

Peter:
Zunächst mal danke für das Programm. Werde es testen sobald es mir 
möglich ist.

Stefan:
Bin gerade dabei am Programm paar Änderungen vorzunehmen. Hardwaremäßig 
habe ich meinen Prototyp 1 umgebaut. Ich habe den Spg.teiler an PA7 
hängen und es scheint zu funktionieren. Im Power-Down scheine ich jetzt 
noch viel weniger Strom zu verbrauchen. Kann man das so schreiben wie 
ich es in Test 13 gemacht habe?? Der Ausgang an PA7 ist fast Vcc. Nur 
paar mV weniger.
Außerdem habe ich versucht für die rote LED noch eine Definition auf 1 
Hz zu machen. Sprich dass rot genauso schnell blinkt wie gelb. 
Funktioniert aber nicht. Kann das ja mit dem #define beliebig 
umschalten!

Gruß
Th.

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

Bei den Alternativen 1Hz/2Hz hast du zu viel Code genommen. Es reichen 
ein paar wenige Zeilen. Der Sekundenzähler (im 1Hz-Timerteil) und die 
Batterie-LED (im 2Hz-Timerteil) sind ja nicht betroffen.

Das Abschalten der Versorgung durch PA7 sollte IMHO direkt nach der 
Messung gemacht werden. Je früher, desto weniger Energie entfleucht 
nutzlos durch den Spannungsteiler. Und du sparst dadurch die 
Sonderbehandlung vor dem Schlafen und nach dem Wecken.

von Peter D. (peda)


Lesenswert?

Stefan B. schrieb:
1
  if(messwert >= SCHWELLE_ROT)
2
    takt_LED_FEUCHTE = LED_ROT;
3
  else if((messwert > SCHWELLE_GELB) && (messwert < SCHWELLE_ROT))  //70
4
    takt_LED_FEUCHTE = LED_GELB;
5
  else if(messwert <= SCHWELLE_GELB)
6
    takt_LED_FEUCHTE = LED_GRUEN;

Nur so als Anmerkung: Auch MCs müssen sich an Mathematikregeln halten:

Wenn (messwert >= SCHWELLE_ROT) falsch ist, brauchst Du nicht mehr auf
(messwert < SCHWELLE_ROT) testen.
Und wenn (messwert > SCHWELLE_GELB) falsch ist, bleibt dem Meßwert 
nichts anderes übrig, als (messwert <= SCHWELLE_GELB) zu sein.
Diese beiden Tests sind also überflüssig.

Ich finde auch ROT, GELB und GRUEN nicht sehr aussagekräftig. Es soll 
doch ne Feuchte geprüft werden, da wäre TROCKEN, NORMAL, FEUCHT viel 
verständlicher.

Ich glaub auch nicht, daß der Sensor super stabil ist, d.h. nahe den 
Umschaltwerten werden immer beide LEDs flackern. Das sieht unschön aus.
Schau mal in meinen Code, da habe ich ne Hysterese einprogrammiert.


> Bei den Alternativen 1Hz/2Hz hast du zu viel Code genommen.

Wenn ich so die Zeiten lese, 4s, 2s, 1s, 0.25s, da geht mir ein 
Seifensieder auf, daß das ja alles Teiler von 4s sind.
Man könnte also ein Byte bis 4s zählen lassen (4s = 15.6ms * 256) und 
dann sind die einzelnen Bits die gewünschten Zeitintervalle.
Dann je nach Blinktakt einfach nur das richtige Bit auf die LED geben.


Peter

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Peter, du hast bei allen Punkten Recht. Man könnte an dem Programm 
einiges verbessern.

Die Frage ist bei mir:
Wer schreibt das Programm, Thomas oder ein anderer?

Ich bin von Anfang an bei meinen Antworten mit dem Ziel vorgegangen, 
dass Thomas sein Programm selbst schreiben muss. Anders als manch 
anderer Fragesteller, war er ja auch dazu bereit und ist beharrlich 
dabei geblieben.

Klar, zu Beginn war fast nur das Abfragen einer Taste und das Leuchten 
lassen von LEDs da. Das hat sich aber mit der Zeit nach vielen Fragen, 
Recherchen und Antworten hier im Forum mit der Teilnahme einiger User 
gemausert. Dies ist ja nicht der einzige Thread dazu. Es ist inzwischen 
eine Sleep-Implementierung drin. Es ist ein Aufwecken per INT0 drin. Es 
ist eine Messung von Vcc per ADC drin (bei der ich einiges von euch 
lernte) und eine Messung des Sensors... viel fehlt nicht mehr und er 
wäre mit seinem Projekt das halbe Tutorial durch.

Gerade im letzten Monat hat Thomas mehrmals von Zeitdruck geschrieben. 
Und mir schien, dass eine Featuritis akut war und dass die Gefahr 
bestand, nicht mal eine Firmware 0.1 kurzfristig fertig zu bekommen.

Deinen ersten und zweiten Hinweis auf eine bessere Implementierung mit 
einer Statemachine habe ich frühzeitig unterstützt. Das hätte aus Sicht 
von Thomas aber auch bedeutet ein solala funktionierendes Programm 
komplett auf andere Füsse zu stellen. Egal, er hat die Hinweise damals 
nicht aufgegriffen und ich wollte das auch nicht erzwingen

Das Thema Timer war auch nicht verstanden und ich hielt den Timer für 
essentiell, um überhaupt eine Chance auf ein im Zeitablauf stabiles 
Programm zu haben.

Aus diesen Gründen habe ich mehr als anfangs beabsichtigt in die 
Programmierung an sich eingegriffen, indem ich irgendwann das Gerüst von 
Thomas für den Timer ergänzt habe. So gesehen habe ich geschummelt und 
es mir leichter gemacht. Statt noch mehr Diagramme zu zeichnen und zu 
erklären, habe ich die Nerven vorloren und Code vorgesetzt.

Und ich habe den Eindruck, dass genau der Programmteil Timer und damit 
die LED füttern bei Thomas noch die meiste Zeit beim Nachvollziehen und 
Dokumentieren braucht. Ich hoffte und hoffe noch, wenn der Druck "ich 
brauche eine funktionierende Firmware" gelöst ist, hat Thomas Ruhe und 
Muse diesen Teil zu verstehen.

SCHWELLE_ledfarbe habe ich genommen, um leichter Simulationswerte für 
die drei LEDs einzugeben. Denn um die inzwischen absehbare Firmware 0.1 
zu testen, habe ich mir an einem Abend einen Hardwaredummy ohne Sensor 
und mit einem gerade vorhandenen Attiny2313 aufgebaut. Was Trocken oder 
Nass bei dem Sensor und welcher LED bedeuten habe ich dabei nicht 
nachvollzogen. Mir war wichtig, beim Testen bestimmte LEDs zu schalten. 
Aber an der Namenswahl und dem Hysteresethema sieht man, dass fremde 
Codestücke, eine Simulation oder ein Hardwaredummy nicht die Realität 
und das Know-How des alten Hasen ersetzen können.

Ich hoffe Thomas stellt sein Projekt nach der Abgabe seiner Facharbeit 
nicht ein, sondern rekapituliert die Diskussion und macht aus den 
gesammelten Erkenntnissen eine bessere Firmware. Es würde ihn meiner 
Meinung nach im Bereich µC weiterbringen, wenn er dabei bleiben will.

Wie heisst es nach dem Programmieren einer Software? "Es läuft, jetzt 
müssten wir das eigentlich neu schreiben." Mit deiner Variante über 
Statemachine hat Thomas sicher eine sehr gute Ausgangsbasis und den 
direkten Vergleich.

In diesem Sinn
Stefan

von Peter D. (peda)


Lesenswert?

Stefan B. schrieb:
> Aus diesen Gründen habe ich mehr als anfangs beabsichtigt in die
> Programmierung an sich eingegriffen, indem ich irgendwann das Gerüst von
> Thomas für den Timer ergänzt habe. So gesehen habe ich geschummelt und
> es mir leichter gemacht. Statt noch mehr Diagramme zu zeichnen und zu
> erklären, habe ich die Nerven vorloren und Code vorgesetzt.

Ich hab schon viel früher aufgegeben. Ab ner bestimmten Anzahl von 
Problemstellen mag man sich nen Code nicht mehr weiter ansehen, auch 
wenn er funktioniert.

Ich habe auch als Anfänger drauflos programmiert und nie zuerst nen 
Programmablaufplan gemacht. Und wenn man dann vor dem absoluten Chaos 
steht und doch nen Plan macht, entwirren sich mindestens 90% der 
Probleme.

Was für nen Anfänger wohl schwer zu verstehen ist, ist die quasi 
Gleichzeitig von Aufgaben in der Mainloop. Die Mainloop läuft so schnell 
durch, daß es so aussieht, als mache sie viele Sachen gleichzeitig.
Ein Anfänger will immer alles streng der Reihe nach machen, bloß an der 
ersten Wartestelle wirds dann haarig.
Da hilft dann ein Plan: Aha, hier muß ich warten, da mache ich 
inzwischen mit den anderen Aufgaben weiter.

Letztendlich geht kein Programm ohne Plan, bloß macht man ihn als 
Erfahrener für solche kleine Aufgaben im Kopf.

Die Tastenentprellung konnte ich ja aus der Schublade ziehen und das 
Power-Down auch. Der Rest war dann fast nur Schreibarbeit.

Was ich hier das erste mal ausprobiert habe, ist die Switch-Anweisung 
mit Bereichen. Das ist deutlich übersichtlicher, als ne If-Kaskade und 
vermeidet automatisch unnütze Doppeltests.
Die Switchanweisung achtet nämlich streng darauf, daß kein Case doppelt 
auftritt, da gibts sofort die rote Karte (Error-Meldung).
Und der erzeugte Code ist sogar schön klein und schnell.

> Mit deiner Variante über
> Statemachine hat Thomas sicher eine sehr gute Ausgangsbasis und den
> direkten Vergleich.

Da würde mich mal interessieren, ob Du denkst, da könnte sich ein 
Anfänger durchwuseln oder ob es viel zu kompliziert ist.


Peter

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich denke für den fortgeschrittenen Anfänger ist dein Code 
nachvollziehbar. Aber es braucht Zeit, wie jeder fremde Code, den man 
sich anschaut. Die wesentlichen Unterschiede beim ersten Darüberblicken 
für mich waren:

1. Die Manipulation der Ports

Dein Verfahren arbeitet mit den SBIT Makros. Das habe ich bisher 
seltener gesehen als die direkten Anweisungen in der Source (PORT... = 
...) bzw. die darauf basierten dirkten Verfahren mit Makros. Keine 
grosse Hürde.

2. Die Entprellung

Hier muss man sich einlesen, wie zunächst das Warteschleifen-Verfahren 
durch ein Polling im Timer-Interrupt ersetzt wird. Und man muss den Dreh 
rausbekommen was die Masken und Statusvariablen etc. bedeuten. Deine 
anscheinend bevorzugte Manipulation von Bits z.B. mit ^ ist für den 
Anfänger anspruchsvoll. Weil der Code an sich knapp geschrieben ist und 
Kommentare selten sind, ist man aufs Tutorial angewiesen. Diese Stelle 
ist IMHO die grösste Hürde.

3. Das doppelte switch in main

Anschaulicher für mich wäre es gewesen, alle Zustände in einem switch zu 
behandeln. Man braucht aber eine schnelle Reaktion auf den OFF Zustand, 
d.h. man darf man die Messungen nicht durchführen, wenn die Abfrage der 
Taste OFF liefert. Ich hätte das mit einem if auf not OFF statt auf die 
anderen Zustände abgefragt oder den OFF Zustand aus dem switch raus und 
als if vor das switch gezogen.

4. Problemfall überschneidene Zustände

state ist eine Variable, die nur einen Zustand aufnehmen kann. Jetzt 
kann aber gleichzeitig die Situation vorliegen, dass man ein neues 
Ergebnis der Feuchtemessung hat und gleichzeitig das Ergebnis der 
Batteriemessung LOW_BAT. Vom Projekt her soll die Feuchte weiter 
gemessen werden, aber die Warnleuchte Batterie niedrig soll zusätzlich 
blitzen. Derzeit hat das Ergebnis der Batteriemessung Vorrang und das 
Ergebnis der aktuellen Feuchtemessung wird verworfen, was zur Anzeige 
eines nicht aktuellen und u.U. falschen Feuchtewertes führt, solange der 
LOW_BAT Zustand anhält.

5. Das Setzen der LEDs

Vorsicht: Geschmackssache! Die Manipulation vieler LEDs in den case 
Fällen hatte mich in dem alten Code von Thomas gestört, wo das Teil der 
Feuchtemessung war. Die Variante das zentral in einer Funktion (oder in 
der Timer-ISR) zu machen gefällt mir besser. Keine grosse Hürde.

6. power_down/sleep_cpu

Ich habe etwas Bauchweh, dass power_down und sleep_cpu getrennt wurden, 
weil ich eine Gefahr darin sehe, dass sich bei der Weiterentwicklung 
Code zwischen set_sleep_mode( SLEEP_MODE_PWR_DOWN ), "implizites sei()" 
und sleep_cpu(); schmuggelt.

7. Aufwecken mit WAKEUP_vect statt INT0_vect

Für mich war in der Source nicht offensichtlich, weshalb diese Änderung 
gemacht wurde. Das Nachlesen im Thread (Reaktion vor Loslassen möglich, 
freiere Pinwahl) hat das dann erklärt.

8. CTC Modus beim Timer

Hier muss man sich auf einen anderen Timermodus einlassen. Keine grosse 
Hürde.

von Peter D. (peda)


Lesenswert?

Stefan B. schrieb:
> 1. Die Manipulation der Ports
>
> Dein Verfahren arbeitet mit den SBIT Makros.

Ich finde diese Schreibweise deutlich besser lesbar.
Hauptsächlich gefällt mir aber daran, daß ich nicht extra Byteadresse 
und Bitnummer definieren muß.


> 2. Die Entprellung
>
> Deine
> anscheinend bevorzugte Manipulation von Bits z.B. mit ^ ist für den
> Anfänger anspruchsvoll.

Das EXOR ist hier notwendig, da die Entprellung auf einem Vertical 
Counter basiert.
Er ist natürlich nicht einfach zu verstehen, aber jeder, der ihn 
verstanden hat, ist froh darüber.


> 3. Das doppelte switch in main
>
Das erste Switch steuert die Meßaktionen (Eingabe), das 2. die Anzeige 
(Ausgabe). Die Trennung erfolgte der Übersichtlichkeit wegen.


> Vom Projekt her soll die Feuchte weiter
> gemessen werden, aber die Warnleuchte Batterie niedrig soll zusätzlich
> blitzen. Derzeit hat das Ergebnis der Batteriemessung Vorrang und das
> Ergebnis der aktuellen Feuchtemessung wird verworfen, was zur Anzeige
> eines nicht aktuellen und u.U. falschen Feuchtewertes führt, solange der
> LOW_BAT Zustand anhält.

Daran sieht man, wie wichtig es ist, erstmal überhaupt die 
Aufgabenstellung zu formulieren.

Ich hab daher aus dem Code heraus rückwärts die Aufgabenstellung 
rauslesen müssen und dabei können Fehler passieren.
Anbei die Funktion eingebaut. Die low-Batt Funktion braucht dann auch 
eine Hysterese.


> 5. Das Setzen der LEDs
>
> Vorsicht: Geschmackssache! Die Manipulation vieler LEDs in den case
> Fällen hatte mich in dem alten Code von Thomas gestört, wo das Teil der
> Feuchtemessung war. Die Variante das zentral in einer Funktion (oder in
> der Timer-ISR) zu machen gefällt mir besser.

Die LEDs werden auch bei mir zentral gesteuert, aber im Main.
Durch die Bitschreibweise wird aber ersichtlicher, wann welche LED 
leuchtet.


> 6. power_down/sleep_cpu
>
> Ich habe etwas Bauchweh, dass power_down und sleep_cpu getrennt wurden,
> weil ich eine Gefahr darin sehe, dass sich bei der Weiterentwicklung
> Code zwischen set_sleep_mode( SLEEP_MODE_PWR_DOWN ), "implizites sei()"
> und sleep_cpu(); schmuggelt.

Es kann sich ruhig was zwischenschmuggeln, wenn der Code so geschrieben 
ist, daß immer ein sicherer Zustand vorliegt.

Es wird einmal atomar der Power-Down-Modus und der Pin-Change-Interrupt 
enabled und andererseits im Pin-Change-Interrupt der Idle-Modus enabled 
und der Pin-Change disabled.
Der gefährliche Zustand, Power-Down enabled und Pin-Change disabled, 
kann also nirgends auftreten.
Es wird außerdem nicht das gefährliche Macro sleep_mode(), sondern das 
sichere Macro sleep_cpu() verwendet.
Der Code ist somit in der Ausführungsreihenfolge abgesichert.
Du kannst alle Funktionen im Main beliebig vertauschen, das Programm 
funktioniert immer.



Ich hab auchmal bei Atmel nachgefragt, was die Bemerkung im Datenblatt 
soll, auf der das sleep_mode() Macro basiert.
Es wurde mir bestätigt, daß es keinerlei Auswirkung hat, wann das 
Enable-Bit gesetzt wird.
Es muß nur irgendwann vor dem Sleep sein, daher ist im Init-Code der 
optimale Platz dafür.

Auch logisch betrachtet bringt es reinweg garnichts, wenn man das 
Enable-Bit nach dem Sleep löscht, da es ja immer vor dem nächsten Sleep 
wieder gesetzt wird. Das sleep_mode() Macro hat also keinerlei 
praktischen Nutzen.


Peter

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Ups, Anhang vergessen.


Peter

von Bastler (Gast)


Lesenswert?

Guten Morgen!!

Da habe ich ja jetzt ziemliche Diskussionen losgetreten in meinem 
Beitrag. Mir ist klar dass man sowas am besten in der Freizeit machen 
sollte. Da kann man rumprobieren und testen usw. Ich habe registriert 
dass der Code nicht das Optimum darstellt. Mir ist eigentlich nur 
wichtig dass des so weit einigermaßen funktioniert. Klar ich würde es 
auch sehr gerne perfekt machen allerdings habe ich ja schon zu Beginn 
gesagt ich bin Anfänger. So schnell von 0 auf 100 ist wohl schwer 
möglich noch dazu wenn es sich eigentlich um eine Technologiearbeit 
handelt. Ich bin froh dass ich von euch diese Hilfe erhalten habe weil 
ohne wäre es nicht gegangen. Anfangs habe ich ja mit einer halben Seite 
Code gerechnet. Inzwischen ist es ja doch sehr umfangreich. Wohl mehr 
als das 10fache weil man hald immer neue Ideen hat. Diese Ideen in 
knapper Zeit zu verwirklichen ist dann wohl fast unmöglich. Mir wurde 
beim programmieren ja auch gesagt "learning by doing"! Jetzt kommt ja 
beim zeitlichen auch noch dazu dass ich die Arbeit schreiben muss und am 
Do eine Vorlesung besuche. Jetzt wird die Sache natürlich noch 
schwieriger.
Mir ist natürlich auch klar dass die Sache mit dem kapazitiven Sensor 
bis Dezember nur noch schwer zu realisieren sein dürfte. Ich muss mich 
da ja auch selber erst hineindenken. Die Hardware dafür war ja noch das 
leichteste.
Wegen der Sache mit der Statemachine wollte ich mich nochmals 
informieren. Dieses Ding hat ja einen ständig defnieriten Zustand. Habe 
schon mit Informatikern gesprochen. Eine Statemachine kann man ja 
irgendwo mit case in verbindung bringen. Heißt das ich habe in Teilen 
eine oder gibt es da nur entweder ganz oder gar nicht?
Ich hoffe jedenfalls dass ich nach Dezember zum Ende meiner Arbeit die 
Zeit finde in meiner Freizeit programmieren zu können. Auch dann werde 
ich wohl noch suppport benötigen. Allerdings habe ich dann endlich mal 
die Zeit die in meinen Augen benötige! Möchte dann ja auch gerne mit 
JTAG Schnittstellen Erfahrungen sammeln. Genauso wie mit TI - 
Controllern. Ursprünglich war ja geplant meinen Sensor mit einem MSP430 
auszuwerten. Mechanische Gründe gaben schließlich den Ausschlag den 
ATTINY zu benutzen! Bin aber inzwischen ganz froh mit meiner Wahl!
Bis Dezember werde ich mich hald noch so damit durchschlagen müssen. Das 
wichtigste ist jedoch dass ich das Interesse am Programmieren gefunden 
habe. Das ist wohl unbezahlbar. Ok mich reißt Programme schreiben nach 
wie vor nicht total vom Hocker aber ich habe erkannt welche tolle Dinge 
man damit machen kann.
Evt. schaffe ich am Wochenende ja die Software mit der Statemachine zu 
testen.

Stefan:
Ich habe meine Software jetzt abgeändert. Vom Stromverbrauch im 
Power-Down bin ich schon sehr angetan. Sprich Spannungsteiler auf 
Portpin klappt wunderbar. Was mir jedoch auffällt ist dass meine 
Feuchteanzeige träger ist. Wenn ich meinen Sensor anhauche blinkt 
irgendwann die rote LED. Aber es dauert jetzt wesentlich länger bis 
wieder der Grundzustand mit dem grünen LED eintritt. Du hast ja davon 
gesprochen dass ich evt noch eine Verzögerung einbauen soll nach der 
Aktivierung des Spg.teilers. Sprich dieser Effekt würde dann ja wohl 
nochmal zusätzlich verstärkt werden oder? Ebenso gibt es noch Probleme 
die rote LED mit 1Hz Blinkfrequenz einzusetzen. Sie blinkt immer noch 
schneller obwohl ja die 250ms für rot keine Rolle mehr spielen dürften.

Eine weitere Frage. Code habe ich mir von einem Entwicklungsleiter einer 
Software-Firma sagen lassen erklärt man mittels Struktugrammen. Auch ich 
sollte das ja wohl so machen. Habe das ja auch schon mal gehört. 
Zeichnet man sowas am geschicktesten in Power-Point? Jedes Unterprogramm 
wird ja wohl eine Bubble darstellen. Bzw. if-Abfragen macht man ja mit 
Rauten und Abzweigungen für true und false. Was macht man bei case?? Das 
muss ich ja auch noch darstellen!


Gruß und sorry für die verspätete Antwort!
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Generell gefällt mir das Verfahren im Weck-Interrupt den Sleepmodus neu 
für das Userprogramm zu setzen. Das werde ich in Zukunft auch so machen.

Nicht einig bin ich damit, dass es nichts ausmachen soll, wenn sich Code 
zwischen das implizite sei (Abschluss der ATOMIC-Klammer) und das 
sleep_cpu schmuggelt bzw. dass man die Funktionen im main beliebig 
vertauschen kann.

Du hast insofern Recht, dass dein Verfahren die Zombies d.h. Pennen bei 
rausgezogenem Stecker am Wecker verhindert.

Ich sehe aber den Haken, dass Userinput verloren gehen kann, d.h. dass 
sich der µC beim Druck auf den EIN/AUS-Taster nicht Schlafen legt 
sondern wach bleibt.

Der Fall würde eintreten, wenn der Weckinterrupt zur Laufzeit des 
eingeschuggelten Codes aktiv wird. Das dann folgende sleep_cpu würde in 
den Schlafmodus des Weckinterrupts (IDLE) gehen und nicht in den des 
Userprogramms (POWER_DOWN).

Im Code von V3B habe ich nicht überprüft, welche Auswirkungen das hätte. 
Also ob ein gedrückt halten des EIN/AUS-Tasters automatisch beim 
nächsten Durchlauf ein POWER_DOWN auslöst, oder ob ein 2. Tastendruck 
nötig ist oder gar ein 2. (Pseudo-Wecken) und ein 3. (neues AUS).

von Stefan B. (stefan) Benutzerseite


Lesenswert?

@ Thomas

[Spekulation]
Strom durch einen Widerstand ist immer auch eine Heizung. Wenn du auf 
eine kältere Oberfläche hauchst, wird die Feuchte länger dort bleiben 
als auf einer wärmeren Oberfläche. Du kannst zwei Tests machen:

1. "Vorwärmzeit" vor der Messung mit einer kleinen Wartezeit vor der 
eigentlichen Messung.

2. Rückänderung des Codes: Spannungsversorgung für den Spannungsteiler 
bleibt immer an, nur vor dem Schlafen wird sie ausgeschaltet und beim 
Wecken an. Also so wie du es in Test_13.c hattest.

Ich würde zuerst 2. testen, um zu sehen, ob es überhaupt einen Effekt 
gibt.
[/Spekulation]

Und ich würde prüfen, ob die Schwellwerte mit der neuen 
Spannungsversorgung über PA7 (d.h. Vcc-X) noch die gleichen sind wie bei 
der alten Versorgung (Vcc).

Dazu würde ich mich langsam um die Kalibrierung des Sensors kümmern, 
weil ich nicht reproduzierbar hauchen kann ;-)

Das 2Hz Blinken der roten Feuchte-LED ist ja richtig so, denn in der 
Source Test_13.c und Test_13a.c steht:
#define TOGGLE_ROT_1HZ 0
#define TOGGLE_ROT_2HZ 1

Ein Programm für Flussdiagramme wäre z.B. die Freeware Diagram Designer. 
Die findet man auf Sourceforge, aber auf 
http://logicnet.dk/DiagramDesigner/ sieht man auch Screenshots. Ich habe 
allerdings keine praktische Erfahrung damit.

Struktogramme nach DIN 66261 sind was anderes 
(http://wwwlrh.fh-bielefeld.de/IN_Prak/inprak6.htm). Programme für 
Nassi-Shneiderman-Diagramme ("Struktogramme") sind bei 
http://de.wikipedia.org/wiki/Nassi-Shneiderman-Diagramm genannt. Ich 
habe allerdings keine praktische Erfahrung damit.

von Peter D. (peda)


Lesenswert?

Stefan B. schrieb:
> Ich sehe aber den Haken, dass Userinput verloren gehen kann, d.h. dass
> sich der µC beim Druck auf den EIN/AUS-Taster nicht Schlafen legt
> sondern wach bleibt.

Ne, das ist ja gerade das geniale an einer Statemachine.
Man kann unterscheiden zwischen Aktionen, die einen State setzen und 
welchen, die den State auswerten.

Das Powerdown wertet nur den State OFF aus, d.h. solange OFF ist, muß es 
die CPU schlafen legen.
Es stört überhaupt nicht, wenn durch Preller die CPU z.B. 10-mal wieder 
aufwacht. Nach einigen ms sind die Preller vorbei und die CPU bleibt 
schlafen.

Erst die Entprellroutine kann beim nächsten Tastendruck den State in WET 
ändern. Und erst dadurch hört die CPU auf, immer wieder in Power-down zu 
gehen.


Probleme beim Power-Down entstehen hauptsächlich nur dann, wenn man das 
Sleep/Wakeup mit dem Entprellen verwuselt.

Auch hier gilt deshalb: "Divide and Conquer".


Peter

von Bastler (Gast)


Lesenswert?

Guten Morgen!

So jetzt komme ich endlich mal wieder dazu meine Software zu 
begutachten. Also ich habe meinen Code jetzt wieder so verwendet wie in 
Test13.c! Sieht aber so aus als ob das ganze Teil träger ist als wenn 
ich direkt an VCC meinen Spannungsteiler habe. Könnte natürlich die 
Schwellwerte ändern.
Die Kalibrierung des Sensors stellt für mich immer noch ein Hindernis 
da. Ich hatte gehofft das rechnerisch zu bestimmen. Gestaltet sich aber 
schwer. Ich habe eine Kennlinie bei der es heißt rel. Feuchte bei dem 
Widerstand. Klar ich kann mit meinen Stufen des AD-Wandlers 
zurückrechnen. Ich kann dann sagen was für eine Spannung anliegt am 
Sensor. Ich könnte somit auch den Widerstand meines Sensors bestimmen. 
Ist ja ne ganz einfache Spg.Teilerberechnung. Allerdings bin ich hald 
immer noch unsicher weil ja quasi parallel zum Sensor die IC-Strecke 
liegt. Der "Vorwiderstand" hat bei mir ja 1,5 MOhm. Am liebsten wäre mir 
wenn man den Widerstand beim IC vernachlässigen könnte. Ansonsten ist 
das ja eine parallelschaltung von dem Sensor und dem 
Controllerwiderstand.
Mein rotese LED blinkt leider immer noch nicht mit 1Hz selbst wenn ich 
es richtig define.
Kann ich dir evt. wenn ich mein Flussdiagramm habe dieses zur Kontrolle 
schicken?

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Willst du der "trägeren Messung" nachforschen? Wenn ja, siehe die 
Überlegungen oben (Heizeffekt) plus diese Überlegungen zu der neuen 
Versorgung:

Die Input-PA7-Versorgung unterscheidet sich auf Hardwareebene von der 
Vcc-Versorgung durch den 20-50k Pull-Up Widerstand zwischen Vcc und dem 
Anschluss deines Spannungsteilers sowie durch den Leckstrom in den 
Eingang von PA7. Man könnte versuchen diese Situation bei der 
Vcc-Versorgung nachzustellen indem ein weiterer Spannungsteiler 
aufgebaut wird.

Du könntest als drittes die Variante testen, bei die Versorgung aus PA7 
bezogen wird, wobei aber PA7 als Outputpin betrieben wird 
(Output-PA7-Versorgung).

Eine Änderung der Schwellwerte hängt davon ab, was du messen willst bzw. 
wie du überhaupt auf die Schwellwerte gekommen bist. Es werden definitiv 
andere Spannungen am ADC anliegen, wenn entweder Vcc oder Vcc-X in den 
Spannungsteiler reingehen. Und bei gleichbleibendem Aref=Vcc müssen 
"hinten" andere Werte rauskommen.

Ich halte eine Kalibrierung für unverzichtbar. Das Berechnen aus der 
Kennlinie im Datenblatt ist ungenau. Die Kennlinie im Datenblatt ist 
eine typ. Angabe des Herstellers, wie sich die Sensoren typischerweise 
verhalten. Die kann man benutzen, um die Schaltung zu dimensionieren, 
aber nicht, um die Messwerte zu interpretieren.

Den konkreten Zusammenhang zwischen rel. Feuchte und Widerstandswert bei 
deinem konkreten Sensorexemplar musst du bestimmen, wenn dir was an 
Genauigkeit (Auflösung und Genauigkeit) liegt.

Im Moment stocherst du im Trüben. Könntest du ausschliessen, dass du bei 
Vcc-Versorgung zwar eine flinkere Messung aber mit ungenauen 
Feuchtewerten hast aber dass eine PA7-Versorgung träger ist aber genaue 
Feuchtewerte liefert?

Dieses Dilema kannst du nur lösen, wenn du dem Messsystem Umgebungen mit 
genau bekannten rel. Feuchten vorsetzt und dann eine eigene 
Kalibrierkurve machst. Am "wenigsten" Arbeit hast du, wenn du die rel. 
Feuchte bei den beiden Schwellwerten einstellen kannst.

Ein Verfahren zur Kalibrierung von Feuchtesensoren arbeitet mit 
gesättigten Salzlösungen bei bestimmten Temperaturen:
http://www.d-r-h.de/hilfstabellen/klima_def_luftfeuchte.html
http://www.umnicom.de/Elektronik/Sonstiges/Messtechnik/tmKap2/tmKap224/tmKap224.html

Das 2Hz-Blinken der roten Feuchte-LED kann ich aus der Betrachtung der 
Source test_13a.c im Moment nicht nachvollziehen. Leider sind in der 
Source alle Anpassungen für meinen Attiny2313 Hardwaremockup 
verschwunden und ich müsste die erst wieder neu einbauen, um das auf 
Hardwareebene zu debuggen.

Sei mir nicht böse, aber bitte schick mir kein Flussdiagramm. Das würde 
deutlich die Hilfe zur Selbsthilfe übersteigen. Das ist essentieller 
Bestandteil deiner Facharbeit und ich möchte mich da nicht einmischen.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das Blinken habe ich jetzt auf dem Attiny2313 getestet. Die rote 
Feuchte-LED blinkt wie erwartet mit 1Hz. Nix von zu schnell (2Hz) zu 
sehen.

von Peter D. (peda)


Lesenswert?

Bastler schrieb:
> Die Kalibrierung des Sensors stellt für mich immer noch ein Hindernis
> da. Ich hatte gehofft das rechnerisch zu bestimmen. Gestaltet sich aber
> schwer. Ich habe eine Kennlinie bei der es heißt rel. Feuchte bei dem
> Widerstand. Klar ich kann mit meinen Stufen des AD-Wandlers
> zurückrechnen.

Wenn Du ne Kennlinie hast, würde ich die Schwellen danach einstellen und 
testen.
Du kannst die ADC-Werte selber ausrechnen oder die Formen hinschreiben 
und es den Compiler ausrechnen lassen.
Der Compiler rechnet gerne für Dich konstante Ausdrücke aus. Der 
Übersichtlichkeit halber kann man das in mehreren Schritten mit Defines 
machen. Man muß also keine Monsterformel hinschreiben.


> Der "Vorwiderstand" hat bei mir ja 1,5 MOhm.

In dem Fall kann man die Spannung zum Sensor nicht zwischen den 
Messungen abschalten sondern nur im Power-Down.
Außerdem muß ein Kondensator 100nF an den ADC-Eingang, der liefert dann 
genug Energie für die Sample&Hold-Stufe des ADC.


Peter

von Bastler (Gast)


Lesenswert?

Guten Morgen!

Mir ist hald aufgefallen dass meine Sensoren unterschiedlich sind. Ich 
habe ein und den gleichen Sensor bestellt nämlich den SHS-A2. Das 
Keramikplättchen war bei den ersten um ca. 1mm schmäler. Auch die 
Beschichtung sieht bisschen anders aus. Wenn ich den Sensor anhauche 
scheint er auch anders zu reagieren. Ich muss meine Schwellwerte 
wesentlich höher setzen damit ich eine Reaktion erzeugen kann. Habe 
jetzt auch die Spg.versorgung erstmal wieder auf VCC gesetzt um dieses 
Problem auszuschließen. Das mit den 20-50KOhm habe ich im Datenblatt 
gelesen. Bei VCC = 3V. Ich weiss nicht ob das dann so funktionieren 
wird. Als Referenz zählt ja immer noch meine VCC. Sagen wir mal 3V. 
Allerdings dürfte es theoretisch nichts ausmachen. Mit meinem PA7 kann 
ich dann ja nur die höheren Spannungen nicht "anfahren". Das würde mir 
ja nichts ausmachen weil ich mit meinem 1,5 MOhm Widerstand ohnehin 
dachte dass ich die Spannung am Sensor auf knapp 0,8V begrenzt habe. 
Beim anhauchen scheint es allerdings so als ob der Sensor einen 
Widerstand im MOhm Bereich erziehlt obwohl das Datenblatt einen 
maximalen Widerstand von ca. 500000 Ohm angibt. Sehr ominös. Ich bin 
natürlich auch kein Klimaspezialist. Bedeutet anhauchen einen so großen 
Unterschied wie die eigentliche Betauung. Wenn ich das Teil auf 
anhauchen einstelle dann reagiert er bei wirklichem Tau ja gar nicht 
mehr. Mir wurde damals ja auch von Hygrosens Instrument bestätigt dass 
ich den Sensor im Notfall mit 0,8 V Gleichspannung betreiben kann. Er 
ist dann zwar ungenau aber des ist meine Messung ja wohl auch.

Naja jetzt mal zu deiner Mail:
Das mit der Überlegung als Output Pin ist ja interessant. Glaubst du das 
geht??? Kann ich hierbei was zerstören? Also ne Treiberüberlastung ist 
ja ausgeschlossen da ich ja glaube ich max. 20mA Strom ziehen darf. Das 
würde wohl nie erreicht werden. Die Schwellwerte habe ich mir ungefähr 
hingerechnet. Bzw. ich habe erst probiert und mir dann berechnet wieviel 
mV die einzelnen Stufen sind. Mit dem ersten Sensor waren das 0,146 und 
0,439 V. Ich habe das jetzt versucht auf die Kennlinie hinzurechnen. 
Wenn ich sage dass mein AD Pin keinen Widerstand gegen Masse aufweißt 
dann wären diese Stufen ungefähr im Bereich von 70 und 90% relative 
Feuchte. Aber ist hald alles so ungefähr aber das wußte ich von Anfang 
an und damit wäre ich ja grundsätzlich zufrieden. Hab ja kein Display wo 
genau der Prozentwert stehn soll.
Was will ich? Ich möchte hald dass wenn man das Teil anhaucht die LEDs 
dementsprechend was machen. Ich werde das mit der Betauung wohl sicher 
nicht machen. Das wäre zu kompliziert. Da müßte man dann ja auch immer 
ein Therarium zur Verfügung haben um die Bedingungen zu erzeugen. Also 
fällt meiner Meinung nach so eine richtige Dimensionierung weg. Das ist 
mir bewußt. Ich werde andere Werte haben wenn ich VCC und VCC über PA7 
anliegen habe. Also bei dem ersten Sensor könnte ich dir sagen dass die 
VCC Versorgung "besser" ist. Meine Spannungswerte passen mit den 
Schwellenwerten zusammen. Und 70 und 90% rel Feuchte scheint mir auch 
sehr annehmbar bei anhauchen. Der neue Sensor bereitet mir noch Probleme 
aber ich werde später noch damit bisschen arbeiten.
Das mit dem Flussdiagramm ist voll in Ordnung. Verstehe ich. Kein 
Problem.
Moment. Neue Info. Das mit dem Kondensator an den ADC Eingang. Du meinst 
den 100nF parallel zum Sensor vom ADC Pin auf GND. Warum kann ich mit 
dem 1,5MOhm Widerstand die Spannungen zwischen den Messungen nicht 
abschalten. Hat das was mit dieser "Vorwärmzeit" zu tun weil der 
Widerstand so groß ist??? Ich habe den Code auch wieder so verändert wie 
du gemeint hast. Ich aktiviere den Spg.teiler bei der Feuchtemessung und 
deaktiviere ihn wieder wenn das Gerät ausschaltet. Das wäre auch ok da 
das Gerät eh nur immer kurz angeschaltet ist.
Sorry dass ich deine Softwareänderungen aus meinem Code entfernt habe 
und du nochmal diese Arbeit investieren mußtest! War nicht meine 
Absicht!

Gruß
Th.St.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Wenn du frei wählen kannst, was du misst und im Moment das System nur 
auf auf "Anhauchen" auslegst - warum nicht etwas Sinnvolles messen?

Beispielsweise die Luftfeuchte als Teil des Innenraumklimas:
http://www.gesundbauen.at/BER1-FEU.htm
http://www.tappeser.de/wissen/schadstoffe/schadstoffe/optimaleluftfeuchte.html
http://www.downloads.fgk.de/139__8_Frag_u_Antw_Raumluftfeuchte.pdf
http://www.schimmelpilz-sanieren.de/info/bt/bt12.htm

Deine neue untere Schwelle zeigt dann zu trockene Raumluft an, die zu 
Halsbeschwerden führen kann. Und die neue obere Schwelle zeigt zu 
feuchte Raumluft an, die z.B. zu Problemen mit Schimmel führen kann.

von Bastler (Gast)


Lesenswert?

Naja was heißt frei wählen. Das Teil wird unterwegs sein in der Zukunft. 
Genaueres kann ich dazu nicht sagen. Unterwegs weiss man hald nicht was 
man für Bedingungen vorfindet und so ist das Anhauchen die einfachste 
Variante etwas zu testen. Ich weiss das hört sich langsam wohl ominös an 
bei mir! ;-)

von Bastler (Gast)


Lesenswert?

Hallo!!

Mal wieder ich mit Problemen!! Und zwar. Auf meinen inzwischen fertigen 
Bauteilen muss ein Fehler sein. Am AVRISP MKII blinkt die orange LED. 
DAs heißt ja laut manual reversed target cable connection. Also wohl 
meine Belegung ist verdreht. Ich habe das aber jetzt ein paar mal 
kontrolliert da kann eigentlich nichts falsch sein. Jetzt meine Fragen: 
Könnte es am Widerstand liegen. Ich habe durch meine Technologie bedingt 
Widerstände <20 Ohm vom ICP Stecker auf meinen Controller. Ist das ein 
Problem? Ich habe am 10kOhm Reset Widerstand merkwürdigerweise 17 Ohm 
wenn ich im eingebauten Zustand messe. Sehr merkwürdig auf meiner 
Versuchsplatine ist das nicht. Dürfte aber auch keine Brücke da sein. 
Wenn ich auf meiner Versuchsplatine Reset R brücke um das Problem zu 
simulieren leuchtet mein LED nach wie vor grün. DAs verstehe ich jetzt 
gar nicht. Womit kann sowas noch zusammenhängen?? Könnte ich da ein paar 
Tips bekommen?? Was passiert z.B. wenn Miso, Mosi nicht angeschlossen 
wären?? Wenn VCC oder GND in der LUft hängt dann leuchtet ja das rote 
LED. Das ist nicht der Fall. Das heißt die beiden müssen passen und 
zwischen beiden ist auch kein Kurzschluss.

Gruß
Th.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Bastler schrieb:

> Mal wieder ich mit Problemen!! Und zwar. Auf meinen inzwischen fertigen
> Bauteilen muss ein Fehler sein. Am AVRISP MKII blinkt die orange LED.
> DAs heißt ja laut manual reversed target cable connection. Also wohl
> meine Belegung ist verdreht.

Sorry habe kein AVRISP MKII und quassele deshalb ab jetzt ins Blaue...

"Reversed target cable connection, OR NOT CORRECT PULL-UP ON THE RESET 
LINE."
http://support.atmel.no/knowledgebase/avrstudiohelp/mergedProjects/AVRISPmkII/HTML_Source/Hardware_Description.htm

> Ich habe das aber jetzt ein paar mal
> kontrolliert da kann eigentlich nichts falsch sein. Jetzt meine Fragen:
> Könnte es am Widerstand liegen. Ich habe durch meine Technologie bedingt
> Widerstände <20 Ohm vom ICP Stecker auf meinen Controller. Ist das ein
> Problem?

Ich vermute, du benutzt so was wie Leitkleber als Draht- und 
Lötmittelersatz.

Denke nicht, dass die 20R hier ein Problem sind. Kannst du aber am 
Prototypen prüfen, wenn du dort 20R Widerstände einschleifst. Du kannst 
auch einen Serienaufbau "opfern" und 0R Drähtchen parallel zu den 20R 
Verbindungen ziehen. Wird es dann besser?

> Ich habe am 10kOhm Reset Widerstand merkwürdigerweise 17 Ohm
> wenn ich im eingebauten Zustand messe. Sehr merkwürdig auf meiner
> Versuchsplatine ist das nicht.

Das ist eindeutig falsch bzw. die Situation "NOT CORRECT PULL-UP ON THE 
RESET LINE." Der Pull-Up darf laut Atmel nicht kleiner 4K7 sein. 
Kontrolliere mal, ob du unter dem Widerstand einen Kurzschluss gebaut 
hast z.B. Leitkleber zusammengelaufen.

> Dürfte aber auch keine Brücke da sein.
> Wenn ich auf meiner Versuchsplatine Reset R brücke um das Problem zu
> simulieren leuchtet mein LED nach wie vor grün. DAs verstehe ich jetzt
> gar nicht.

Ich auch nicht.

> Womit kann sowas noch zusammenhängen?? Könnte ich da ein paar
> Tips bekommen?? Was passiert z.B. wenn Miso, Mosi nicht angeschlossen
> wären??

Sorry, habe kein AVRISP MKII. Bei meinem STK200-Kompatiblen 
ISP-Programmieradapter würde das ISP Programmierprogramm (AVRDUDE) den 
µC nicht finden.

von Bastler (Gast)


Lesenswert?

Hallo!

Danke für deine Tips. Ich bin jetzt schon weiter. Habe Kurzschlüsse 
unter meinem Wannenstecker.
Jetzt noch paar Fragen.
Zum LED-Bat das blinkt wenn meine Batterie sich leert. Ich bemerke schon 
dass das Lämpchen blinkt aber es ist so schwach wie nochmal was. Woran 
könnte das liegen? Wenn ich ganz einfach in einem kleinen Programm 
ansteuere leuchtet es ganz normal. Ebenso habe ich ein Problem mit 
meinem Power-Down Taster. Habe alles durchgemessen. Der Taster zieht den 
Pin auf GND. Also kein Kurzschluss oder was auch immer. Man merkt auch 
dass die LEDs aus sind solange der Taster gedrückt ist. Er geht aber 
nicht in den Schlafmodus. Ich glaube nicht dass das an der Entprellung 
liegt weil alleine vom Zufallsprinzip müßte es hin und wieder gehen. 
Siehe ja auch PRototyp. Habe auch sicherheitshalber nochmal das mit dem 
delay ohne den Timer getestet auch das funktioniert nicht. Dass die LEDs 
erlöschen zeigt dass der Taster auch wirklich am Pin hängt. 1Hz und 2Hz 
blinken der Feuchte LEDs funktioniert. Mal wieder sehr ominös. Wenn 
nichts gehen würde wäre es wenigstens eindeutig. Dachte erst wegen 
meinem LED-BAt dass ich einen zu großen Übergangswiderstand habe. Das 
scheint es aber auch nicht zu sein weil es ja normal leuchtet wenn ich 
es ganz normal ansteuere. Da ist guter Rat teuer. Ich befürchte jetzt 
mal dass du mir da auch nicht helfen kannst oder?
Wir verstehen uns richtig. Das ist ein Bauteil das programmierbar ist 
nicht eines wo es am AVRISP orange blinkt...

Gruß
Thomas

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Da bin ich ziemlich ratlos. Software kann man einigermaßen ferndebuggen; 
Hardware eher schlecht.

Schwaches Leuchten einer LED kann verschiedene Ursachen haben.

Zu wenig Saft

Kann passieren, wenn der Vorwiderstand zu groß ist oder zum 
Vorwiderstand andere Serienwiderstände hinzu kommen. Dieser Fall liegt 
wohl nicht vor (Erfolgreicher Test mit LED-only Betrieb, wenn ansonsten 
gleicher Aufbau UND Spannungsversorgung, d.h. fast leere Batterie)

Bei einem µC mit I/O Pins kann es auch daran liegen, dass die LED durch 
einem Input-Pin versorgt wird statt mit einem Output-Pin. Ein Input-Pin 
als Stromsenke ist hochohmig, d.h. es kann nur wenig Strom abgeleitet 
werden. Der Input-Pin als Stromquelle setzt einen Pull-Up voraus. Die 
sind i.a. auch hochohmig, d.h. nur wenig Strom steht zur Verfügung. 
Diesen Fall kann ich mir auch nicht vorstellen, wenn du obiges Programm 
benutzt hast.

Es gibt LEDs mit unterschiedlichem Durchlassstrom. Verwechselungen 
passieren - Der Teufel ist ein Eichhörnchen und eine "normale" LED 
braucht 10x mehr Saft als eine Low-Current-LED. Dieser Fall liegt wohl 
nicht vor (Erfolgreicher Test mit LED-only Betrieb, wenn gleiche LED 
getestet).

Zu selten Saft

Das kann der Fall sein, wenn die LED nicht statisch mit Strom versorgt 
wird sondern mit einem periodischen AN/AUS Mechanismus. Je nach Dauer 
der AN/AUS Phase ist das dann heller oder dunkeler. Diesen Fall kann ich 
mir auch nicht vorstellen, wenn du obiges Programm benutzt hast und das 
Serienmuster mit (annähernd) gleicher Taktfrequenz wie der Prototyp 
läuft.

Bei dem Taster ist die Frage, ob der INT0-Eingang bei offenem Taster 
auf einem LOW Pegel liegt (schlecht) oder ob ein sauberer HIGH Pegel 
anliegt (gut). LOW heisst nicht gleich GND Potential (Datenblatt)!

von Peter D. (peda)


Lesenswert?

Bastler schrieb:
> Zum LED-Bat das blinkt wenn meine Batterie sich leert. Ich bemerke schon
> dass das Lämpchen blinkt aber es ist so schwach wie nochmal was.

Vermutlich schaltet Dein Programm schnell ein und aus.
Bewege mal die Platine mit der LED ganz schnell im dunklen Raum hin und 
her, damit sieht man das Flackern (bis mehrere kHz).

> Er geht aber
> nicht in den Schlafmodus. Ich glaube nicht dass das an der Entprellung
> liegt weil alleine vom Zufallsprinzip müßte es hin und wieder gehen.

Ich kann nur wiederholen, mach erstmal die Funktion, d.h. die Taste 
schaltet die LEDs ein/aus, ohne den CPU-Mode zu ändern!
Und erst, wenn das einwandfrei geht, kommt das Powerdown hinzu.

Zu versuchen, Powerdown und Funktion gleichzeitig zu programmieren, 
bringt selbst nen Profi zum Schwitzen.


Peter

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.