Attiny13A, programmieren von verschiedenen abläufen

OP #5545933
Lesenswert?

Hallo zusammen,
vorweg... ich bin blutiger Anfänger... habe auch schon viel gesucht, 
aber finde einfach nicht so richtig die Hilfe die ich brauche.

Folgendes, ich möchte mir gerne eine Individuelle Lichtsteuerung bauen 
mit einem Attiny13A
Was soll er können?
Verschiende Programme ablaufen lassen
Programme durch schalten mittels Taster
Das aktuelle Programm speichern. Damit er mit dem Programm wieder 
startet, wenn man Ihn wieder einschaltet...

Das habe ich bisher als minimal-version mir zusammen gebastelt.
1
#define F_CPU 4800000UL //4,8MHz
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <avr/eeprom.h>
5

6
uint8_t eeFooByte EEMEM;                              //Variable eeFooByte im EEPROM anlegen.
7
uint8_t Setting_Write;                            //Variable myWByte anlegen und den Wert 1 laden. (Wird später in EEPROM geschrieben)
8
uint8_t Setting_Read;                                 //Variable für den Wert der dann aus EEPROM gelesen wird.
9

10
int main(void)
11
{
12
  #define EEPROM_DEF 0xFF
13
  int x;
14
  
15
  
16
  
17
  Setting_Read = eeprom_read_byte (&eeFooByte);
18
  x = Setting_Read;
19
  if (x < 1) {x = 1;}
20
  
21
  //int x = 1;
22
  int k = 0;
23
  int i = 0;
24
  
25
    DDRB = 0b00000001; //PB0 als Ausgang deklarieren
26
    PORTB = 0b00000010;
27
  
28
  while (1) 
29
    {
30
    k++;
31
    i++;
32
    
33
    if (!(PINB & (1<<1))) {x++; Setting_Write = x; eeprom_write_byte(&eeFooByte, Setting_Write);  _delay_ms(500);} // Invertiert mit (!...) Taster abfragen! Wert aus Variable Setting_Write in eeFooByte (EEPROM) schreiben
34
    
35
    if (x == 1)
36
    {
37
      if (k==10) {PORTB |= (1 << PB0);}
38
      if (k==20) {PORTB &= ~(1 << PB0);}
39
      if (k==30) {PORTB |= (1 << PB0);}
40
      if (k==40) {PORTB &= ~(1 << PB0);}
41
        
42
      if (k==80) {PORTB |= (1 << PB0);}
43
      if (k==90) {PORTB &= ~(1 << PB0);}
44
      if (k==100) {PORTB |= (1 << PB0);}
45
      if (k==110) {PORTB &= ~(1 << PB0);}
46
        
47
      if (k==150) {k = 0;}
48
      
49
    }
50
    if (x == 2)
51
    {
52
      if (k==1) {PORTB |= (1 << PB0);}
53
      if (k==6) {PORTB &= ~(1 << PB0);}
54
      if (k==11) {PORTB |= (1 << PB0);}
55
      if (k==16) {PORTB &= ~(1 << PB0);}
56
      
57
      if (k==26) {PORTB |= (1 << PB0);}
58
      if (k==31) {PORTB &= ~(1 << PB0);}
59
      if (k==36) {PORTB |= (1 << PB0);}
60
      if (k==41) {PORTB &= ~(1 << PB0);}
61
      
62
      if (k==51) {k = 0;}
63
    }
64
    if (x >= 3) {x = 1;}
65
    
66
    
67
    if (i==1000) {i = 0;}  
68
    _delay_ms(25);
69
    }
70

71
}

Probleme: Er schaltet nicht zuverlässig die Programme durch, er bleibt 
hängen, so das eine LED konstant an bleibt oder gar nicht erst leuchtet.
Das Byte in den eeprom schreiben funktioniert wohl auch nicht so 
zuverlässig.

Könnt ihr mit bitte helfen??


Vielen lieben Dank

Tobias
Gast #5545942
Lesenswert?

k, x, i sind nicht gerade aussagekräftige Dateinamen. Nutze den Platz 
für längere Namen.

Auch die Port-Zugriffe kann man mit Hilfe von Definitionen und 
Funktionen lesbarer machen. Beispiele:
1
#define BEREITSCHAFTS_LED PB3
2
PORTB |= (1<<BEREITSCHAFTS_LED);   // ein schalten
3
PORTB &= ~ (1<<BEREITSCHAFTS_LED); // aus schalten
4

5
#define Bereitschafts_LED_Ein PORTB |= (1<<PB3);
6
#define Bereitschafts_LED_Aus PORTB &= ~(1<<PB3);
7
Bereitschafts_LED_Ein;
8
Bereitschafts_LED_Aus;
9

10
static inline void Bereitschafts_LED_Ein()
11
{
12
    PORTB |= (1<<PB3);
13
}
14

15
static inline void Bereitschafts_LED_Aus()
16
{
17
    PORTB |= &= ~(1<<PB3);
18
}
19

20
Bereitschafts_LED_Ein();
21
Bereitschafts_LED_Aus();

Anstelle dieser langen "if"-Ketten halte ich "switch" für eleganter.

Bist du sicher dass die Stromversorgung Ok ist? Hast du 
Abblock-Kondensatoren? Zeige mal den Schaltplan und Fotos.

Wozu dient die Variable i?
Gast #5545958
Lesenswert?

Ich sehe da ein Problem:

Wenn k zum Beispiel gerade 14 ist und due dann von Programm X=1 nach x=2 
umschaltest, wird es ziemlich lange dauern, bis der Zähler k überläuft 
und bei 0 beginnt. Ich würde entweder bei jedem Umschalten des Programms 
k auf 0 setzen oder den letzten if Ausruck ändern.

anstatt: if (k==51) {k = 0;}
besser: if (k>=51) {k = 0;}

oder noch besser mit switch:
1
switch(k)
2
{
3
    case 1:  PORTB |=  (1 << PB0); break;
4
    case 6:  PORTB &= ~(1 << PB0); break;
5
    case 11: PORTB |=  (1 << PB0); break;
6
    case 16: PORTB &= ~(1 << PB0); break;     
7
    case 26: PORTB |=  (1 << PB0); break;
8
    case 31: PORTB &= ~(1 << PB0); break;
9
    case 36: PORTB |=  (1 << PB0); break;
10
    case 41: PORTB &= ~(1 << PB0); break;
11
    default: k = 0;
12
}
Beitrag #5545959 wurde von einem Moderator gelöscht.
Gast #5545960
Lesenswert?

Tobias B. schrieb:
> Da mir der letzte Spannungsteiler hops gegangen ist

Stromversorgung über einen Spannungsteiler ist schon mal ein riesen 
Fehler. Verwende entweder einen aktiven Spannungsregler (wie den LM7805) 
oder schließe den Mikrocontroller direkt ans Netzteil/Batterie an, falls 
die Spannung passt.

Und nie vergessen: 100nF direkt an jedem IC von VCC nach GND.

Zeige mal den Schaltplan und Fotos.
OP #5545975
Lesenswert?

Vielen Dank schonmal,
jetzt hab ich das etwas angepasst.
Mit dem Case blieb auf einmal die LED Konstant an... komisch,

Das Programme umschalten funktioniert nun reibungslos (vorerst :-)) aber 
irgendwo hab ich noch den Wurm drinnen mit dem Abspeichern und Auslesen 
des "aktiven" Programms? Wenn ich die Spannung unterbreche, dann fängt 
er wieder mit "1" an.

D.h. entweder speichert oder liest den Wert nicht, das immer mein
1
if (x < 1) {x = 1;}
 greift.


Spannungsregler ist notiert, suche mir da die passenden SMD Bauteile 
raus, 0,1µF hab ich drangehangen an VCC/GND.

Was meint ihr? Ist der 100µF übertrieben? Der ist als SMD Bauteil doch 
recht groß.

Grüße
Tobias
1
#define F_CPU 4800000UL //4,8MHz
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <avr/eeprom.h>
5

6
uint8_t eeFooByte EEMEM;                              //Variable eeFooByte im EEPROM anlegen.
7
uint8_t Setting_Write;                            //Variable myWByte anlegen und den Wert 1 laden. (Wird später in EEPROM geschrieben)
8
uint8_t Setting_Read;                                 //Variable für den Wert der dann aus EEPROM gelesen wird.
9

10
int main(void)
11
{
12
  #define EEPROM_DEF 0xFF
13
  int x;
14
  
15
  
16
  
17
  Setting_Read = eeprom_read_byte (&eeFooByte);
18
  x = Setting_Read;
19
  if (x < 1) {x = 1;}
20
  
21
  //int x = 1;
22
  int k = 0;
23
  int i = 0;
24
  
25
    DDRB = 0b00000001; //PB0 als Ausgang deklarieren
26
    PORTB = 0b00000010;
27
  
28
  while (1) 
29
    {
30
    k++;
31
    i++;
32
    
33
    if (!(PINB & (1<<1))) {x++; Setting_Write = x; eeprom_write_byte(&eeFooByte, Setting_Write); k = 0; i = 0;  _delay_ms(500);} // Invertiert mit (!...) Taster abfragen! Wert aus Variable myWriteByte in eeFooByte (EEPROM) schreiben
34
    
35
    if (x == 1)
36
    {
37
      if (k==10) {PORTB |= (1 << PB0);}
38
      if (k==20) {PORTB &= ~(1 << PB0);}
39
      if (k==30) {PORTB |= (1 << PB0);}
40
      if (k==40) {PORTB &= ~(1 << PB0);}
41
        
42
      if (k==80) {PORTB |= (1 << PB0);}
43
      if (k==90) {PORTB &= ~(1 << PB0);}
44
      if (k==100) {PORTB |= (1 << PB0);}
45
      if (k==110) {PORTB &= ~(1 << PB0);}
46
        
47
      if (k>=150) {k = 0;}
48
      
49
    }
50
    if (x == 2)
51
    {
52
      if (k==1) {PORTB |= (1 << PB0);}
53
      if (k==6) {PORTB &= ~(1 << PB0);}
54
      if (k==11) {PORTB |= (1 << PB0);}
55
      if (k==16) {PORTB &= ~(1 << PB0);}
56
      
57
      if (k==26) {PORTB |= (1 << PB0);}
58
      if (k==31) {PORTB &= ~(1 << PB0);}
59
      if (k==36) {PORTB |= (1 << PB0);}
60
      if (k==41) {PORTB &= ~(1 << PB0);}
61
      
62
      if (k>=51) {k = 0;}
63
    }
64
    if (x >= 3) {x = 1;}
65
    
66
    
67
    if (i==1000) {i = 0;}  
68
    _delay_ms(25);
69
    }
70

71
}
Gast #5545989
Lesenswert?

Tobias B. schrieb:
> Was meint ihr? Ist der 100µF übertrieben? Der ist als SMD Bauteil doch
> recht groß.

Schau ins Datenblatt des Spannungsregler. Da wird immer ein konkreter 
Wert empfohlen und manchmal ein maximale erlaubter Wert angegeben.

Ich glaube, dass Schlüsselwort EEMEM soll vor dem Namen der Variable 
stehen.

Warum benutzt du für x eine 16 Bit (int) Variable, kopierst sie aber zum 
Speichern von und zu 8 Bit um? Vermutlich ist das jetzt nicht die 
Problemursache, aber es ist zumindest merkwürdig.

Wenn du diese EEprom Zelle aufgrund vorheriger falscher Versuche schon 
tausende male beschrieben hast, ist sie vielleicht einfach schon 
verschlissen. Probiere mal einen anderen Speicherplatz. Anstelle der 
EEMEM Variable kannst du bei eeprom_write_byte() und eeprom_read_byte() 
einfach die Nummer (=Adresse) der Speicherzelle angeben.

Zeige den Quelltext mit switch/case.
Benutze längere Variablen Namen.
Benutze #define und/oder Funktionen um den Code besser lesbar zu machen.

Ich habe keine Lust, diese Wirrwarr noch öfter analysieren zu müssen.
Gast #5545992
Lesenswert?

> Da immer das if (x < 1) {x = 1;} greift.

Woher weißt du, dass genau diese Zeile greift? Hast du einen Debugger 
verwendet, oder wie analysierst du das? Ich würde das gerne wissen, weil 
man die weitere Vorgehensweise darauf aufsetzen kann.

Noch ein möglicher Fehler:

Beim Programmstart aktivierst du den internen Pull-Up Widerstand vom 
Taster und fragst in ohne nennenswerte Verzögerung danach ab.

Je nachdem, wie hoch die parasitäre Kapazität vom Steckbrett, Leitungen 
und Taster sind, ist der pin dann noch dabei, von Low nach High hoch zu 
kommen.

Benutze einen externen Pull-Up Widerstand mit 1 bis 4,7k Ohm und baue 
eine kleine Warteschleife ein, bevor du den Taster zum ersten mal 
abfragst.
Gast #5546009
Lesenswert?

> default: k = 0;

Das war falsch. Das greift ja schon bei all den Zwischenständen von k, 
wo NICHTS passieren soll. So müsste es gehen:
1
switch(k)
2
{
3
    case 1:  PORTB |=  (1 << PB0); break;
4
    case 6:  PORTB &= ~(1 << PB0); break;
5
    case 11: PORTB |=  (1 << PB0); break;
6
    case 16: PORTB &= ~(1 << PB0); break;     
7
    case 26: PORTB |=  (1 << PB0); break;
8
    case 31: PORTB &= ~(1 << PB0); break;
9
    case 36: PORTB |=  (1 << PB0); break;
10
    case 41: PORTB &= ~(1 << PB0); break;
11
    case 51: k = 0;
12
}
Dann aber nicht vergessen, k zurück auf 0 zu setzen, wenn der Taster zum 
Programmwechsel gedrückt wird.
OP #5546015
Lesenswert?

Hallo,

nein ich habe kein Debugger, live zu sehen was der Attiny macht wäre 
schon schön...

So ich hab jetzt das EEMEM davor gesetzt, das Beispiel hatte ich von 
http://avr-programmieren-rh.de/

Desweiteren habe ich das
1
_delay_ms(25);
 nach oben geholt, um ein wenig verweilzeit zu haben um den Taster ab zu 
fragen.

desweiteren hab ich "int" durch "uint8_t" ersetzt.

Jetzt klappt alles! VIELEN DANK EUCH! :-)


Wie meint ihr das, den Code lesbarer zu machen? Sorry für diese Frage..

Grüße
Tobias
Gast #5546068
Lesenswert?

Tobias B. schrieb:
> nein ich habe kein Debugger, live zu sehen was der Attiny macht wäre
> schon schön...

Also hast du das nur vermutet. Das solltest du auch deutlich 
hinschreiben, sonst führt deine (Fehl-)Diagnose die Helfer in die Irre.

Es ist immer Hilfreich, solche Vermutungen durch zusätzliche LED 
Anzeigen oder serielle Ausgaben zu verifizieren. Dafür brauchst du nur 
einen freien Pin. Siehe http://stefanfrings.de/avr_hello_world/

> Wie meint ihr das, den Code lesbarer zu machen? Sorry für diese Frage..

Habe ich doch geschrieben. Versuche es mal so (ungetesteter Code):
1
#define F_CPU 4800000UL //4,8MHz
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <avr/eeprom.h>
5

6
// Die LED ist an PB0 und GND angeschlossen
7
#define LED_EIN { PORTB |= (1 << PB0); }
8
#define LED_AUS { PORTB &= ~(1 << PB0); }
9

10
// Der Taster ist an PB1 und GND angeschlossen (erfordert Pull-Up)
11
#define TASTER_GEDRUECKT (!(PINB & (1<<PB1)))
12

13
uint8_t eeBlinkMusterNr EEMEM;  // Um das Blinkmuster im EEprom zu speichern
14
uint8_t blinkMusterNr;          // Aktuell laufendes Blinkmuster (1 oder 2)
15
uint8_t step=0;                 // Schrittzähler für die Blinkmuster
16

17

18
void setup()
19
{
20
    // I/O Pins initialisieren
21
    DDRB  = 0b00000001; // PB0=Ausgang für die LED
22
    PORTB = 0b00000010; // PB1=Eingang mit Pull-Up für den Taster
23
    
24
    // Konfiguration aus EEprom lesen
25
    blinkMusterNr = eeprom_read_byte(&eeBlinkMusterNr);
26
}
27

28

29
void blinkmuster_1()
30
{
31
    switch (step)
32
    {
33
        case 10:  LED_EIN; break;
34
        case 20:  LED_AUS; break;
35
        case 30:  LED_EIN; break;
36
        case 40:  LED_AUS; break;
37
        case 80:  LED_EIN; break;
38
        case 90:  LED_AUS; break;
39
        case 100: LED_EIN; break;
40
        case 110: LED_AUS; break;
41
        case 150: step=0;
42
    }
43
}
44

45

46
void blinkmuster_2()
47
{
48
    switch (step)
49
    {
50
        case 1:   LED_EIN; break;
51
        case 6:   LED_AUS; break;
52
        case 11:  LED_EIN; break;
53
        case 16:  LED_AUS; break;
54
        case 26:  LED_EIN; break;
55
        case 31:  LED_AUS; break;
56
        case 36:  LED_EIN; break;
57
        case 41:  LED_AUS; break;
58
        case 51: step=0;
59
    }
60
}
61

62

63
int main(void)
64
{
65
    setup();
66
    
67
    // Main loop, repeats every 25ms
68
    while(1)
69
    {
70
        _delay_ms(25);
71
        
72
        // Wenn Taste gedrückt...
73
        if (TASTER_GEDRUECKT)
74
        {
75
            // dann auf das nächste Blinkmuster umschalten
76
            blinkMusterNr++;  
77
            step=0;          
78
            
79
            // Neue Blinkmuster Nr im EEprom speichern
80
            eeprom_write_byte(&eeBlinkMusterNr, blinkMusterNr);
81
            
82
            // Ein bisschen warten 
83
            // Anm. stefanus: das würde ich etwas "intelligenter" machen
84
            _delay_ms(500);
85
        }
86
        
87
        // Blinkmuster anzeigen    
88
        switch (blinkMusterNr)
89
        {
90
            case 1: blinkmuster_1(); break;
91
            case 2: blinkmuster_2(); break;
92
            default: blinkMusterNr=1;
93
        }
94
        step++;
95
    }
96
}
Gast #5546106
Lesenswert?

Das Programm hat eine unschöne Stelle:

Wenn blinkMusterNr=2 aktiv ist und du dann die Taste drückst, wird die 
Variable auf 3 erhöht und das dann auch so im EEprom gespeichert.

3 ist ungültig, deswegen wird das direkt danach von den default case auf 
1 geändert.

Letztendlich wird im EEprom immer 2 oder 3 stehen, obwohl in 
Wirklichkeit die Blinkmuster 2 oder 1 aktiv sind. Ist egal, oder?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren