Forum: Mikrocontroller und Digitale Elektronik ATtiny13 verstehe Verhalten nicht


von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Hallo,

verstehe das Verhalten meines ATtiny13 nicht. Sieht jemand meinen 
Denkfehler?

Bin am Experimentieren, um externe Interrupts kennen zu lernen.

Habe folgenden Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
5
volatile uint8_t int0_flag = 0;
6
7
int main (void) {
8
    /* enable output pin, set low */
9
    DDRB |= (1<<PB4);
10
11
    /* enable pullup on interrupt pin */
12
    PORTB |= (1<<PB1);
13
    
14
    /* allow logic level to rise */
15
    _delay_ms(500);
16
    
17
    /* set interrupt flag for INT0 extern int. */
18
    GIMSK |= (1<<INT0);
19
    
20
    /* enable interrupts globally */
21
    //sei();
22
23
    while(1){
24
        if (int0_flag) {
25
            PORTB |= (1<<PB4);
26
        }
27
    }
28
29
    return 0;
30
}
31
32
ISR(INT0_vect) {
33
    int0_flag = 1;
34
}

Der PB4-Pin wird high, obwohl ich erwarten würde, dass er low bleibt.

sei() habe ich auskommentiert, um auszuschließen, dass int0_flag vom 
Interrupt manipuliert wird.

Warum wird der Pin trotzdem high? Wo ist mein Denkfehler?

Liebe Grüße,

Lukas

von Karl H. (kbuchegg)


Lesenswert?

Lukas P. schrieb:

> Warum wird der Pin trotzdem high? Wo ist mein Denkfehler?

Der Mechanismus, der Interrupts trackt ist bereits nach Anlegen der 
Versorgungsspannung aktiv. Egal ob du später dann einen Pullup 
dazuschaltest oder nicht. Egal ob du den Interrupt dann frei gibst oder 
nicht. Egal ob du die Interrupts insgesamt frei gibst oder nicht.

Erst mal (noch ehe dein Programm überhaupt eine Chance hat loszulegen), 
ist der Pin ein Eingang. Und je nachdem, was du da extern angeschlossen 
hast, kann das auch ein offener Eingang sein, der sich alles mögliche 
einfängt. Unter anderem auch Pegel, die du zu diesem Zeitpunkt nicht 
haben willst. Das ist aber dem µC egal. Er sieht dort einen Pegel 
und/oder Flanke und setzt dementsprechend das 'Ereignis aufgetreten 
Bit'. Es ist daher sinnvoll, dieses Bit erst mal zurückzusetzen, ehe du 
dann mit einem sei() alles scharf schaltest.

von Jim M. (turboj)


Lesenswert?

Lukas P. schrieb:
> Der PB4-Pin wird high, obwohl ich erwarten würde, dass er low bleibt.

Wiso? Den setzt niemand auf Low.

Könntest Du aber selbst machen:
1
/* enable pullup on interrupt pin */
2
    PORTB = (1<<PB1);
3
// ------^^

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Karl H. schrieb:
> Es ist daher sinnvoll, dieses Bit erst mal zurückzusetzen, ehe du
> dann mit einem sei() alles scharf schaltest.

Vielen Dank für den Hinweis, das werde ich einarbeiten.

von Karl H. (kbuchegg)


Lesenswert?

Karl H. schrieb:

> Bit'. Es ist daher sinnvoll, dieses Bit erst mal zurückzusetzen, ehe du
> dann mit einem sei() alles scharf schaltest.

Die Rede ist vom INT0F im Register GIFR
(musste erst mal im Datenblatt nachsehen)

: Bearbeitet durch User
von Karl M. (Gast)


Lesenswert?

Lukas P.,

und nicht vergessen die globalen Interrupts frei zu schalten, das hatte 
Karl Heinz schon angemerkt.

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Karl H. schrieb:
> Die Rede ist vom INT0G im Register GIFR
> (musste erst mal im Datenblatt nachsehen)

Hatte ich verstanden - trotzdem danke fürs extra Nachschauen!

von Karl H. (kbuchegg)


Lesenswert?

AChtug: Dieses Bit wird durch Einschreiben einer 1 gelöscht
Also
1
   ...
2
   GIFR = (1 << INT0F );  // eventuell bisher aufgetretene Interrupts löschen
3
   sei();
4
5
   while( 1 )
6
     ....

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Jim M. schrieb:
> Den setzt niemand auf Low.

Aber auch niemand auf high. So wie ich das Datenblatt verstehe und 
meinen Tests nach ist der Inhalt von PORTB nach dem Start 0x00.

Wenn ich die while-schleife leer lasse, dann bleibt der Pin brav low.


Karl M. schrieb:
> und nicht vergessen die globalen Interrupts frei zu schalten

Die sind grade absichtlich aus.
Ich will verstehen, warum der Pin ohne Interrupt high wird.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Wenn du keinen sei() hast, dann kann der nicht high werden. Denn dann 
kann die  Variable auch nie 1 werden.

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Karl H. schrieb:
> Wenn du keinen sei() hast, dann kann der nicht high werden. Denn dann
> kann die  Variable auch nie 1 werden.

Das hätte ich auch gedacht, wird er aber.

Habe nochmal kompiliert, geflasht und gemessen, Pin wird high.

Mist :(

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Durchcompiliert?

änder mal 1 Zeichen im Programm und achte drauf, dass auch wirklich 
alles compiliert und gelinkt wird.

richtiges Hex-File geflasht?

von WebDeveloper (Gast)


Lesenswert?

Du könntest das Programm mal wie folgt abändern und dann ausprobieren:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
5
volatile uint8_t int0_flag = 0;
6
7
int main (void) {
8
    /* enable output pin, set low */
9
    DDRB = (1<<PB4);
10
11
    /* enable pullup on interrupt pin */
12
    PORTB = (1<<PB1);
13
    
14
    /* allow logic level to rise */
15
    _delay_ms(500);
16
    
17
    /* set interrupt flag for INT0 extern int. */
18
    if (GIFR != 0) {
19
        GIFR = (1<<INTF0);
20
    }
21
    GIMSK |= (1<<INT0);
22
23
    int0_flag = 0;
24
    
25
    /* enable interrupts globally */
26
    sei();
27
28
    while(1){
29
        if (int0_flag) {
30
            PORTB |= (1<<PB4);
31
        }
32
    }
33
34
    return 0;
35
}
36
37
ISR(INT0_vect) {
38
    int0_flag = 1;
39
}

von Beobachter #42 (Gast)


Lesenswert?

so mal testen:

DDRB |= (1<<PB4);
PORTB &= ~(1<<PB4);

g
#42

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

@ WebDeveloper & 42:

habe eure Vorschläge eingepflegt, leider ohne Erfolg.

Der Pin wird trotzdem high.

Wenn ich die Zeile
1
PORTB |= (1<<PB4);
 in der while-Schleife auskommentiere, bleibt er low.

Diese Zeile wird also ausgeführt. Aber warum?

von WebDeveloper (Gast)


Lesenswert?

Poste doch mal das .lss-File.

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Der Vollständigkeit halber hier nochmal der Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
5
volatile uint8_t int0_flag = 0;
6
7
int main (void) {
8
    /* enable output pin, set low */
9
    DDRB = (1<<PB4);
10
    PORTB &= ~(1<<PB4);
11
12
    /* enable pullup on interrupt pin */
13
    PORTB = (1<<PB1);
14
    
15
    /* allow logic level to rise */
16
    _delay_ms(500);
17
    
18
    /* set interrupt flag for INT0 extern int. */
19
    if (GIFR != 0) {
20
        GIFR = (1<<INTF0);
21
    }
22
    GIMSK |= (1<<INT0);
23
24
    int0_flag = 0;
25
    
26
    /* enable interrupts globally */
27
    sei();
28
29
    while(1){
30
        if (int0_flag) {
31
            //PORTB |= (1<<PB4);
32
        }
33
    }
34
35
    return 0;
36
}
37
38
ISR(INT0_vect) {
39
    int0_flag = 1;
40
}

und das Makefile
1
BINARY=klotimer
2
OBJS=main.o
3
4
PREFIX  = avr
5
CC    = $(PREFIX)-gcc
6
LD    = $(PREFIX)-gcc
7
OBJCOPY    = $(PREFIX)-objcopy
8
OBJDUMP    = $(PREFIX)-objdump
9
10
CFLAGS    += -Os -Wall -Wextra -mmcu=attiny13 -DF_CPU=1200000UL -fdata-sections -ffunction-sections -Wl,-gc-sections
11
LDFLAGS    = 
12
13
.SUFFIXES: .elf .bin .hex .list
14
15
all: flash
16
17
images: $(BINARY).images
18
flash: $(BINARY).flash
19
20
%.images: %.bin %.hex %.list
21
  @#echo "*** $* images generated ***"
22
23
%.bin: %.elf
24
  $(OBJCOPY) -Obinary $(*).elf $(*).bin
25
26
%.hex: %.elf
27
  $(OBJCOPY) -Oihex -j .text -j .data $(*).elf $(*).hex
28
29
%.list: %.elf
30
  $(OBJDUMP) -S $(*).elf > $(*).list
31
32
%.elf: $(OBJS)
33
  $(LD) -o $(*).elf $(OBJS) $(LDFLAGS)
34
35
%.o: %.c Makefile
36
  $(CC) $(CFLAGS) -o $@ -c $<
37
38
clean:
39
  rm -f *.o
40
  rm -f *.elf
41
  rm -f *.bin
42
  rm -f *.hex
43
  rm -f *.list
44
45
%.flash: %.hex
46
  avrdude -P usb -p t13 -c usbtiny -v -B 10 -U flash:w:$(*).hex
47
48
.PHONY: images clean

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

WebDeveloper schrieb:
> Poste doch mal das .lss-File.

Jenes?
1
cat klotimer.list 
2
3
klotimer.elf:     file format elf32-avr
4
5
6
Disassembly of section .text:
7
8
00000000 <__ctors_end>:
9
   0:  20 e0         ldi  r18, 0x00  ; 0
10
   2:  a0 e6         ldi  r26, 0x60  ; 96
11
   4:  b0 e0         ldi  r27, 0x00  ; 0
12
   6:  01 c0         rjmp  .+2        ; 0xa <.do_clear_bss_start>
13
14
00000008 <.do_clear_bss_loop>:
15
   8:  1d 92         st  X+, r1
16
17
0000000a <.do_clear_bss_start>:
18
   a:  a1 36         cpi  r26, 0x61  ; 97
19
   c:  b2 07         cpc  r27, r18
20
   e:  e1 f7         brne  .-8        ; 0x8 <.do_clear_bss_loop>
21
22
00000010 <main>:
23
  10:  80 e1         ldi  r24, 0x10  ; 16
24
  12:  87 bb         out  0x17, r24  ; 23
25
  14:  c4 98         cbi  0x18, 4  ; 24
26
  16:  82 e0         ldi  r24, 0x02  ; 2
27
  18:  88 bb         out  0x18, r24  ; 24
28
  1a:  2f eb         ldi  r18, 0xBF  ; 191
29
  1c:  84 ed         ldi  r24, 0xD4  ; 212
30
  1e:  91 e0         ldi  r25, 0x01  ; 1
31
  20:  21 50         subi  r18, 0x01  ; 1
32
  22:  80 40         sbci  r24, 0x00  ; 0
33
  24:  90 40         sbci  r25, 0x00  ; 0
34
  26:  e1 f7         brne  .-8        ; 0x20 <main+0x10>
35
  28:  00 c0         rjmp  .+0        ; 0x2a <main+0x1a>
36
  2a:  00 00         nop
37
  2c:  8a b7         in  r24, 0x3a  ; 58
38
  2e:  88 23         and  r24, r24
39
  30:  11 f0         breq  .+4        ; 0x36 <main+0x26>
40
  32:  80 e4         ldi  r24, 0x40  ; 64
41
  34:  8a bf         out  0x3a, r24  ; 58
42
  36:  8b b7         in  r24, 0x3b  ; 59
43
  38:  80 64         ori  r24, 0x40  ; 64
44
  3a:  8b bf         out  0x3b, r24  ; 59
45
  3c:  10 92 60 00   sts  0x0060, r1
46
  40:  78 94         sei
47
  42:  80 91 60 00   lds  r24, 0x0060
48
  46:  fd cf         rjmp  .-6        ; 0x42 <__SREG__+0x3>
49
50
00000048 <__vector_1>:
51
  48:  1f 92         push  r1
52
  4a:  0f 92         push  r0
53
  4c:  0f b6         in  r0, 0x3f  ; 63
54
  4e:  0f 92         push  r0
55
  50:  11 24         eor  r1, r1
56
  52:  8f 93         push  r24
57
  54:  81 e0         ldi  r24, 0x01  ; 1
58
  56:  80 93 60 00   sts  0x0060, r24
59
  5a:  8f 91         pop  r24
60
  5c:  0f 90         pop  r0
61
  5e:  0f be         out  0x3f, r0  ; 63
62
  60:  0f 90         pop  r0
63
  62:  1f 90         pop  r1
64
  64:  18 95         reti

von WebDeveloper (Gast)


Lesenswert?

Dein Compiler tut da scheinbar etwas, was du nicht möchtest. Poste bitte 
mal das .lss-File, in dem man nachsehen kann, was vom Code geblieben und 
was entfernt wurde.

von WebDeveloper (Gast)


Lesenswert?

Genau das. Leider wird dein C-Code nicht eingebaut, aber ich schaue mal, 
ob ich was finde.

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Oh Mist, das war mit dem Auskommentierten if-Inhalt (
1
PORTB |= (1<<PB4);
).

Hier nochmal richtig:
1
cat klotimer.list                       
2
3
klotimer.elf:     file format elf32-avr
4
5
6
Disassembly of section .text:
7
8
00000000 <__ctors_end>:
9
   0:  20 e0         ldi  r18, 0x00  ; 0
10
   2:  a0 e6         ldi  r26, 0x60  ; 96
11
   4:  b0 e0         ldi  r27, 0x00  ; 0
12
   6:  01 c0         rjmp  .+2        ; 0xa <.do_clear_bss_start>
13
14
00000008 <.do_clear_bss_loop>:
15
   8:  1d 92         st  X+, r1
16
17
0000000a <.do_clear_bss_start>:
18
   a:  a1 36         cpi  r26, 0x61  ; 97
19
   c:  b2 07         cpc  r27, r18
20
   e:  e1 f7         brne  .-8        ; 0x8 <.do_clear_bss_loop>
21
22
00000010 <main>:
23
  10:  80 e1         ldi  r24, 0x10  ; 16
24
  12:  87 bb         out  0x17, r24  ; 23
25
  14:  c4 98         cbi  0x18, 4  ; 24
26
  16:  82 e0         ldi  r24, 0x02  ; 2
27
  18:  88 bb         out  0x18, r24  ; 24
28
  1a:  2f eb         ldi  r18, 0xBF  ; 191
29
  1c:  84 ed         ldi  r24, 0xD4  ; 212
30
  1e:  91 e0         ldi  r25, 0x01  ; 1
31
  20:  21 50         subi  r18, 0x01  ; 1
32
  22:  80 40         sbci  r24, 0x00  ; 0
33
  24:  90 40         sbci  r25, 0x00  ; 0
34
  26:  e1 f7         brne  .-8        ; 0x20 <main+0x10>
35
  28:  00 c0         rjmp  .+0        ; 0x2a <main+0x1a>
36
  2a:  00 00         nop
37
  2c:  8a b7         in  r24, 0x3a  ; 58
38
  2e:  88 23         and  r24, r24
39
  30:  11 f0         breq  .+4        ; 0x36 <main+0x26>
40
  32:  80 e4         ldi  r24, 0x40  ; 64
41
  34:  8a bf         out  0x3a, r24  ; 58
42
  36:  8b b7         in  r24, 0x3b  ; 59
43
  38:  80 64         ori  r24, 0x40  ; 64
44
  3a:  8b bf         out  0x3b, r24  ; 59
45
  3c:  10 92 60 00   sts  0x0060, r1
46
  40:  78 94         sei
47
  42:  80 91 60 00   lds  r24, 0x0060
48
  46:  88 23         and  r24, r24
49
  48:  e1 f3         breq  .-8        ; 0x42 <__SREG__+0x3>
50
  4a:  c4 9a         sbi  0x18, 4  ; 24
51
  4c:  fa cf         rjmp  .-12       ; 0x42 <__SREG__+0x3>
52
53
0000004e <__vector_1>:
54
  4e:  1f 92         push  r1
55
  50:  0f 92         push  r0
56
  52:  0f b6         in  r0, 0x3f  ; 63
57
  54:  0f 92         push  r0
58
  56:  11 24         eor  r1, r1
59
  58:  8f 93         push  r24
60
  5a:  81 e0         ldi  r24, 0x01  ; 1
61
  5c:  80 93 60 00   sts  0x0060, r24
62
  60:  8f 91         pop  r24
63
  62:  0f 90         pop  r0
64
  64:  0f be         out  0x3f, r0  ; 63
65
  66:  0f 90         pop  r0
66
  68:  1f 90         pop  r1
67
  6a:  18 95         reti

Bei 0x46 ist jetzt halt noch die Abfrage hinzugekommen, die war vorher 
leer, also wegoptimiert.

: Bearbeitet durch User
von WebDeveloper (Gast)


Lesenswert?

Also wie folgt:
1
00000000 <__ctors_end>:
2
   0:  20 e0         ldi  r18, 0x00  ; 0
3
   2:  a0 e6         ldi  r26, 0x60  ; 96
4
   4:  b0 e0         ldi  r27, 0x00  ; 0      // Lade Adresse int0_flag in X-Register
5
   6:  01 c0         rjmp  .+2        ; 0xa <.do_clear_bss_start>
6
7
00000008 <.do_clear_bss_loop>:
8
   8:  1d 92         st  X+, r1      // Speicher Wert aus r1 (ist nicht gesetzt?) in int0_flag und erhöhe Adresse in X um 1
9
10
0000000a <.do_clear_bss_start>:
11
   a:  a1 36         cpi  r26, 0x61  ; 97
12
   c:  b2 07         cpc  r27, r18
13
   e:  e1 f7         brne  .-8        ; 0x8 <.do_clear_bss_loop>
14
15
00000010 <main>:
16
  10:  80 e1         ldi  r24, 0x10  ; 16  
17
  12:  87 bb         out  0x17, r24  ; 23  // DDRB4 auf Ausgang
18
  14:  c4 98         cbi  0x18, 4  ; 24    // PORTB4 auf low
19
  16:  82 e0         ldi  r24, 0x02  ; 2
20
  18:  88 bb         out  0x18, r24  ; 24   // PORTB1 auf high
21
  1a:  2f eb         ldi  r18, 0xBF  ; 191
22
  1c:  84 ed         ldi  r24, 0xD4  ; 212
23
  1e:  91 e0         ldi  r25, 0x01  ; 1
24
  20:  21 50         subi  r18, 0x01  ; 1
25
  22:  80 40         sbci  r24, 0x00  ; 0
26
  24:  90 40         sbci  r25, 0x00  ; 0
27
  26:  e1 f7         brne  .-8        ; 0x20 <main+0x10>
28
  28:  00 c0         rjmp  .+0        ; 0x2a <main+0x1a>
29
  2a:  00 00         nop
30
  2c:  8a b7         in  r24, 0x3a  ; 58      // GIFR einlesen
31
  2e:  88 23         and  r24, r24
32
  30:  11 f0         breq  .+4        ; 0x36 <main+0x26>    // Springe wenn Zero
33
  32:  80 e4         ldi  r24, 0x40  ; 64          // Sonst setze INTF0 auf 1
34
  34:  8a bf         out  0x3a, r24  ; 58
35
  36:  8b b7         in  r24, 0x3b  ; 59          // Lese GIMSK
36
  38:  80 64         ori  r24, 0x40  ; 64          // Verodere mit (1<<INT0)
37
  3a:  8b bf         out  0x3b, r24  ; 59
38
  3c:  10 92 60 00   sts  0x0060, r1
39
  40:  78 94         sei              // Ints aktriv
40
  42:  80 91 60 00   lds  r24, 0x0060        // Lade Daten aus Speicheradresse 0x0060 
41
  46:  88 23         and  r24, r24          // Ist der Wert 0?
42
  48:  e1 f3         breq  .-8        ; 0x42 <__SREG__+0x3>    // Loope
43
  4a:  c4 9a         sbi  0x18, 4  ; 24        // Setze PORTB2  ????
44
  4c:  fa cf         rjmp  .-12       ; 0x42 <__SREG__+0x3>

In der folgenden ISR wird eine 1 in die Adresse 0x0060 (int0_flag) 
geschrieben.

Dein Assemblercode sieht logisch genauso aus wie er C-Code.


:-(.

von WebDeveloper (Gast)


Lesenswert?

4a:  c4 9a         sbi  0x18, 4  ; 24

Ist naturlich PORTB4

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Gut, so verstehe ich das auch.

Dann werde ich mal einen anderen tiny13 und eine andere Spannungsquelle 
testen, irgendwo muss der Fehler ja sein.

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Lukas P. schrieb:
> Dann werde ich mal einen anderen tiny13 und eine andere Spannungsquelle
> testen, irgendwo muss der Fehler ja sein.

Ergebnis:

Beim neuen Tiny geht die LED nicht an, auch nicht, wenn ich PB1 mit 
einem Taster low ziehe.

Beim alten geht nachwievor die LED an. Wenn ich PB1 low ziehe, geht sie 
aus und geht nach dem loslassen von PB1 mit einer kleinen Verzögerung 
wieder an.
Beides nicht, wie es sein sollte ...

Muss jetzt leider weg, Ideen und Erleuchtungen sind weiterhin willkommen 
;)

Vielen Dank für eure bisherige Hilfe!

: Bearbeitet durch User
von WebDeveloper (Gast)


Lesenswert?

Ich schätze mal:

deine LED geht an, wenn PB4 low ist und sie geht aus, wenn PB4 high ist. 
Wenn du den Taster betätigst und PB1 auf Masse gezogen wird, wird PB4 
high gesetzt und die LED geht aus, weil dann in deine If-Abfrage 
gesprungen wird.

Ein Zurück setzen ist nicht vorgesehen in der Schleife, passiert aber 
trotzdem. Das Teil macht nicht zufällig ständig Resets?

Bei nächster Gelegenheit wären ein Schaltplan und/oder zumindest 
ein/zwei gute Bilder vom Aufbau toll ;-).

von Lukas P. (fuzzhead) Benutzerseite


Angehängte Dateien:

Lesenswert?

WebDeveloper schrieb:
> Bei nächster Gelegenheit wären ein Schaltplan und/oder zumindest
> ein/zwei gute Bilder vom Aufbau toll ;-).

Ich gelobige Besserung :)

WebDeveloper schrieb:
> deine LED geht an, wenn PB4 low ist und sie geht aus, wenn PB4 high ist.
> Wenn du den Taster betätigst und PB1 auf Masse gezogen wird, wird PB4
> high gesetzt und die LED geht aus, weil dann in deine If-Abfrage
> gesprungen wird.

Die Pegel sind mit dem Multimeter gemessen, die LED ist gegen GND 
geschaltet.

Evtl habe ich beim Fummeln dem ersten Tiny den PORTB zerzappt (ESD) und 
der resetted wirklich durch den an PB1 hängenden Taster.

Aber der neue Tiny lässt garnichts leuchten, das ist auch faul. Ist der 
INT0-Taster gedrückt, wird der Pin auf 0.2V = 0.04*VCC runtergezogen. 
Laut Datenblatt sind für low nur 0.1*VCC nötig. Der Interrupt sollte 
also auslösen.

Ist doch alles haarig ...

: Bearbeitet durch User
von Marco G. (grmg2010)


Lesenswert?

WebDeveloper schrieb:
> if (int0_flag) {
>             PORTB |= (1<<PB4);
>         }

Müsste dies nicht anders lauten: if (int0_flag != 0)... oder wird in 
dieser Form auf 1 abgefragt?

Nutze testweise mal einen externen Pullup am !Reset-Pin.

von Dennis S. (eltio)


Lesenswert?

Marco G. schrieb:
> Müsste dies nicht anders lauten: if (int0_flag != 0)... oder wird in
> dieser Form auf 1 abgefragt?

Nein (oder fast): die Form testet auf "ungleich 0".

: Bearbeitet durch User
von WebDeveloper (Gast)


Lesenswert?

Als Lebenszeichentest könntest du mal die LED nach deinen 500ms Delay 
anschalten und dann testen, ob der Reset(taster) funktioniert. Danach 
kann man dann weiter überlegen, was das noch sein kann.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Lukas P. schrieb:
> Beim neuen Tiny ...
> Beim alten ...
Watchdog unterschiedlich eingestellt?
Oszillator verbogen?
Tut der uC überhaupt noch was?
Ich würde während der Entwicklung auch immer in der Mainloop eine LED 
vor sich hinblinken lassen. Wenn die mal nicht mehr blinkt, dann hängt 
das Programm...

BTW: wenn das tatsächlich ein "Klotimer" werden soll, wozu sind dann 
Interrupts nötig?

Marco G. schrieb:
> Müsste dies nicht anders lauten: if (int0_flag != 0)...
if() testet seinen Parameter sowieso schon auf 0. Und so wird der Code 
in der if-Bedingung nur dann ausgeführt, wenn der Parameter ungleich 0 
ist. Ergo ergibgt "if (irgendwas!=0){}" genau das selbe wie "if 
(irgendwas){}"

Das kann man dann auch gut für leserliche Programme verwenden:
1
if (daten_da) {
2
  daten_auswerten();
3
  if (!bereit_zum_senden) {
4
     daten_vorbereiten();
5
  else
6
     daten_senden();
7
  }
8
}

von Holger L. (max5v)


Angehängte Dateien:

Lesenswert?

Habe es gerade eben aufgebaut und getestet. Der einzige mögliche Fehler 
der mir am Aufbau aufgefallen ist wäre der Taster, den kann man leicht 
mal falsch verdrahten. Ein 100nF zwischen VCC+GND kann nicht schaden 
ebenso wie ein 10k Pullup am Resetpin.

Die Software (die letzte Version) lief sofort Problemlos. Das einzige 
was fehlte war #define F_CPU 1200000.
Die .hex ist angehängt, wenn du es damit versuchen möchtest.
(9.6MHz + Ckdiv8 = 1.2 MHz)

: Bearbeitet durch User
von Ingo L. (corrtexx)


Lesenswert?

Ich hatte mal mangels Lust auf nem Steckbrett keinen 100nF an der 
Versorgung und das Ding machte was es wollte, nur nicht was es sollte. 
100nF dran und alles lief einwandfrei...

mach mal:
1
while(1){
2
        if (int0_flag) {
3
            PORTB |= (1<<PB4);
4
            int0_flag--;
5
            _delay_ms(200);
6
        }else{
7
            PORTB &= ~(1<<PB4);
8
        }
9
}
10
11
ISR(INT0_vect) {
12
    int0_flag = 10;
13
}

EDIT:
Die 1k Vorwiderstand sind schon grenzwertig, eher weniger
Die 1k in Reihe zum Taster würde ich eher so auf 100R setzen

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Lukas P. schrieb:
> Ist doch alles haarig ...

Du hast den 100nF Kerko (Abblockkondensator) vergessen. Deine 
geschilderten Probleme (der eine ATTiny123 funktioniert, der andere 
nicht) passen wie Topf auf Deckel.

Löte ihn an und schon werden Deine Probleme verschwinden.

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Heureka!

Abblockkondensator hinzugefügt, Holgers Firmware geflashed -> kein 
Erfolg.

Alles vom Steckbrett gerissen und neu verkabelt -> jetzt läufts.

Komme mir grade doof vor…

Jetzt arbeite ich mal alle Vorschläge ein und poste dann den 
resultierenden Code.

Vielen, vielen Dank für eure große Hilfsbereitschaft und Geduld - 
wirklich toll hier :)

von Ingo Less (Gast)


Lesenswert?

Ein Steckbrett hat auch seine Tücken

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Jaja ... es war anscheinend nicht das Steckbrett alleine.

Ich bekomme den Code nachwievor nicht funktionstüchtig compiliert.

Flashe ich Holgers hex-file, läufts. Nehme ich mein eigenes, läufts 
nicht.

Habe ihm schon eine PN geschrieben und um die Befehle gebeten, die er 
benutzt.

von Lukas P. (fuzzhead) Benutzerseite


Angehängte Dateien:

Lesenswert?

Der Wurm steckte im Makefile.

Habe dem Linker nicht -mmcu=attiny13 übergeben. Jetzt läufts.

kopfgegenwandhau


Implementierte Änderungsvorschläge:

- zusätzliche LED in der Main-Schleife blinken lassen, um zu sehen, ob 
die läuft (Lothar)

- 100nF Abblockkondensator eingebaut. Die Lektion habe ich mir gemerkt … 
(Holger, Ingo und Frank)

- 10k Pullup am Reset-Pin (Holger)

- F_CPU hatte und habe ich im Makefile als Compileroption definiert. Ist 
das unsauber? (Holger)

- Codefragment eingefügt. (Ingo)

- LED-Vorwiderstand 1k habe ich gelassen, weil die LED sonst sehr 
blendet. Ist eine klare, blaue, fließen ca. 3mA. (Ingo)

Hier der resultierende Code:
1
cat main.c
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
5
volatile uint8_t int_flag = 0;
6
7
int main (void) {
8
    /* enable output pin, set low */
9
    DDRB = (1<<PB2) | (1<<PB4);
10
11
    /* enable pullup on interrupt pin */
12
    PORTB = (1<<PB1);    
13
    /* allow logic level to rise */
14
    _delay_ms(500);
15
    
16
    /* clear INT0 interupt flag if set*/
17
    if (GIFR != 0) {
18
        GIFR = (1<<INTF0);
19
    }
20
    /* set interrupt enable flag for INT0 extern int. */
21
    GIMSK |= (1<<INT0);
22
    
23
    /* reset interrupt signaling variable */
24
    //int_flag = 0;
25
    
26
    /* enable interrupts globally */
27
    sei();
28
29
    while(1){
30
        _delay_ms(200);
31
        
32
        if (int_flag) {
33
            PORTB ^= (1<<PB4);
34
            int_flag--;
35
        } else {
36
            PORTB &= ~(1<<PB4);
37
        }
38
39
        /* blink LED to monitor execution */
40
        PORTB ^= (1<<PB2);
41
    }
42
43
    return 0;
44
}
45
46
ISR(INT0_vect) {
47
    int_flag = 10;
48
}
1
cat Makefile
1
BINARY=klotimer
2
OBJS=main.o
3
4
PREFIX  = avr
5
CC    = $(PREFIX)-gcc
6
LD    = $(PREFIX)-gcc
7
OBJCOPY    = $(PREFIX)-objcopy
8
OBJDUMP    = $(PREFIX)-objdump
9
# Uncomment this line if you want to use the installed (not local) library.
10
11
CFLAGS    = -Os -Wall -Wextra -mmcu=attiny13 -DF_CPU=1200000UL
12
LDFLAGS    = -mmcu=attiny13
13
14
.SUFFIXES: .elf .bin .hex .list
15
16
all: flash
17
18
images: $(BINARY).images
19
flash: $(BINARY).flash
20
21
%.images: %.bin %.hex %.list
22
  @#echo "*** $* images generated ***"
23
24
%.bin: %.elf
25
  $(OBJCOPY) -Obinary $(*).elf $(*).bin
26
27
%.hex: %.elf
28
  $(OBJCOPY) -Oihex $(*).elf $(*).hex
29
30
%.list: %.elf
31
  $(OBJDUMP) -S $(*).elf > $(*).list
32
33
%.elf: $(OBJS)
34
  $(LD) -o $(*).elf $(OBJS) $(LDFLAGS)
35
36
%.o: %.c Makefile
37
  $(CC) -c $(CFLAGS) -o $@ $<
38
39
clean:
40
  rm -f *.o
41
  rm -f *.elf
42
  rm -f *.bin
43
  rm -f *.hex
44
  rm -f *.list
45
46
%.flash: %.hex
47
  avrdude -P usb -p t13 -c usbtiny -v -B 10 -U flash:w:$(*).hex
48
49
.PHONY: images clean

Jetzt zur allentscheidenden Frage, warum man für einen Klotimer 
Interrupts benötigt:

Habe vor einem Monat eine WG mitgegründet. Wir haben ein recht kleines 
Bad, man muss nach dem Duschen lüften. Jetzt ist es uns schon ein paar 
mal vorgekommen, das wir das Fenster vergessen haben und erst eine 
Stunde später in ein klapperkaltes Bad mit rödelnder Heizung kamen.

Der „Klotimer“ soll das verhindern. An Fensterrahmen und Fenster kommen 
Kontakte aus Alu-Tape als kruder Taster. Wird das Fenster geöffnet, so 
wird der Kontakt unterbrochen, was den ATtiny aus dem Stromsparschlaf 
wecken soll. Dieser startet einen 1 Sek. Timer, nach dessen Ablauf er 
überprüft, ob der Kontakt immernoch unterbrochen ist. Trifft dies zu, 
wird ein 5min Timer gestartet, nachdem ein lauter Alarm ertönt. Wird in 
der Zwischenzeit das Fenster wieder geschlossen, bricht der Timer ab und 
der ATtiny legt sich wieder schlafen. Das Ganze kommt in das Gehäuse 
eines defekten Rauchmelders, wird von einer 3V Lithium-Batterie versorgt 
und benutzt die Lärmerzeugungsmaschinerie des Rauchmelders. Mit dem 
Stummschaltungsknopf des Rauchmelders kann man den Alarm pausieren.

Der aktuelle Code ist dabei nur um grundlegende Funktionen zu testen, 
nicht Versuch einer Implementation.

Sobald das Projekt fertig ist, stelle ich hier den vollständigen 
Schaltplan, Code und Fotos ein.

Liebe Grüße,

Lukas

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Lukas P. schrieb:
> Wird in der Zwischenzeit das Fenster wieder geschlossen, bricht der
> Timer ab und der ATtiny legt sich wieder schlafen.
Was du brauchst ist ein simples Monoflop (oder auch zwei). Da hättest du 
dann auch keinerlei Probleme mit dem Batterieverbrauch.

Und wenn es unbedingt ein uC sein muss: weil die "5 min." absolut 
unkritisch sind, würde ich da allein mit dem Watchdog arbeiten. Der löst 
z.B. alle 5 sec. einen Reset aus, du siehst nach dem Kontakt und zählst 
in einem Zählerbyte das offene Fenster mit. Wenn dieser Zähler auf 60 
ist, schaltest du die Hupe ein (und nach 5 min. wieder aus, sonst hupt 
das ding die ganze Nacht, bis morgens um halb 6 der erste wieder nach 
Hause torkelt)...

: Bearbeitet durch Moderator
von Holger L. (max5v)


Lesenswert?

Schönes Projekt.

Nur falls du es noch nicht gelesen haben solltest (Electrical 
Characteristics im Datenblatt):
Die 1.2 MHz oder sogar 9.6 MHz sollten für dieses Projekt ein wenig 
übertrieben sein, man kann den Tinny intern mit 128kHz betreiben  was 
noch ein wenig Strom spart. (http://www.engbedded.com/fusecalc/)
Allerdings sollte man vorher kontrollieren ob das Programmiergerät das 
noch stemmen kann, die ISP-Frequenz sollte immer 1\4 des Cpu-Taktes 
betragen.

Das mit der Aluminiumfolie als Taster ist eine tolle Idee.
Man kann übrigens mit einem einfachen Kondensator, oder einem Transistor 
und weiteren einfachen Bauteilen eine Temperaturmessung durchführen, nur 
falls die Alufolie sich nicht beweisen sollte.

Lukas P. schrieb:
> - F_CPU hatte und habe ich im Makefile als Compileroption definiert. Ist
> das unsauber? (Holger)

Ich persönlich schreibe es immer direkt in den Code, das ist einfach 
übersichtlicher. Nach einem halben Jahr weiß man meißt nicht mehr was 
man dort für Einstellungen hatte, dann ist es auf einen Blick 
ersichtlich.
Nutze allerdings auch nur das AtmelStudio, dadurch muß man sich um das 
Makefile nicht kümmern.

: Bearbeitet durch User
von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> Lukas P. schrieb:
>> Wird in der Zwischenzeit das Fenster wieder geschlossen, bricht der
>> Timer ab und der ATtiny legt sich wieder schlafen.
> Was du brauchst ist ein simples Monoflop (oder auch zwei). Da hättest du
> dann auch keinerlei Probleme mit dem Batterieverbrauch.

Interessante Idee, damit habe ich noch nie gearbeitet. Habe etwas 
überlegt und glaube, eine Monoflop&Flipflop-Lösung gefunden zu haben. 
Schreibe den Schaltplan die Tage auf und poste ihn, dann kannst Du 
kommentieren.

Fürs fertige 'Produkt' würde ich immernoch den uC bevorzugen, weil ich 
so nur einen IC verbauen muss und viel flexibler bin. Schön wäre zum 
Beispiel ein kurzes 'Pieps' alle 20s, als 'Fenster-offen-Indikator'. 
Beim hastigen Verlassen des Bades und Hauses auf dem Weg zur Party merkt 
man es dann vllt. grade noch.

> Und wenn es unbedingt ein uC sein muss: weil die "5 min." absolut
> unkritisch sind, würde ich da allein mit dem Watchdog arbeiten. Der löst
> z.B. alle 5 sec. einen Reset aus, du siehst nach dem Kontakt und zählst
> in einem Zählerbyte das offene Fenster mit. Wenn dieser Zähler auf 60
> ist, schaltest du die Hupe ein.

Wird das Zählerbyte vom Reset nicht gelöscht? Oder meinst Du im EEPROM?

Werde das mal so und mal mit Timerinterrupts implementieren und den 
Verbrauch messen. Sobald ich mir nach Weihnachten ein Speicherscope 
gekauft habe, versteht sich. ;) Mutmaße aber, dass es keinen 
nenneswerten Unterschied für die Batterielaufzeit machen wird, da der 
Piezo-Treiber im zeitlichen Mittel um Größenordnungen mehr Leistung 
verbraucht.

Dessen reverse'den Schaltplan gibts auch die Tage.

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Holger L. schrieb:
> Schönes Projekt.
>
> Nur falls du es noch nicht gelesen haben solltest (Electrical
> Characteristics im Datenblatt):
> Die 1.2 MHz oder sogar 9.6 MHz sollten für dieses Projekt ein wenig
> übertrieben sein, man kann den Tinny intern mit 128kHz betreiben  was
> noch ein wenig Strom spart. (http://www.engbedded.com/fusecalc/)
> Allerdings sollte man vorher kontrollieren ob das Programmiergerät das
> noch stemmen kann, die ISP-Frequenz sollte immer 1\4 des Cpu-Taktes
> betragen.

Werde ich ausprobieren. Danke für den Hinweis!

> Das mit der Aluminiumfolie als Taster ist eine tolle Idee.
> Man kann übrigens mit einem einfachen Kondensator, oder einem Transistor
> und weiteren einfachen Bauteilen eine Temperaturmessung durchführen, nur
> falls die Alufolie sich nicht beweisen sollte.

Ok, ist notiert :)

von chris_ (Gast)


Lesenswert?

Bei 128kHz brauch der Attiny wirklich sehr wenig Strom. Wenn ich mich 
recht erinnere ca. 50uA ( wenn die meiste Peripherie aus ist ).

Ich hatte das für die Solarvögel verwendet. Die laufen schon bei sehr 
schwachem Licht los:

http://www.hobby-roboter.de/forum/viewtopic.php?f=5&t=43

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Interessantes Projekt! Vielen Dank für den Hinweis.

Das werd ich auch mal zusammenwerfen :)

: Bearbeitet durch User
von Holger L. (max5v)


Lesenswert?

Lukas P. schrieb:
> Wird das Zählerbyte vom Reset nicht gelöscht? Oder meinst Du im EEPROM?

Der Watchdog kann so programmiert werden das er statt einem Reset einen 
ISR-Aufruf durchführt, in dem kann dann eine volatile Variable erhöht 
werden.

Lukas P. schrieb:
> Mutmaße aber, dass es keinen
> nenneswerten Unterschied für die Batterielaufzeit machen wird, da der
> Piezo-Treiber im zeitlichen Mittel um Größenordnungen mehr Leistung
> verbraucht.

Der muß doch nicht die ganze Zeit über an der Versorgung hängen, den 
könnte man mit einem Transistor zuschalten wenn er benötigt wird.

von Lukas P. (fuzzhead) Benutzerseite


Lesenswert?

Holger L. schrieb:
> Der Watchdog kann so programmiert werden das er statt einem Reset einen
> ISR-Aufruf durchführt, in dem kann dann eine volatile Variable erhöht
> werden.

Cool!

Holger L. schrieb:
>Lukas P. schrieb:
>> Mutmaße aber, dass es keinen
>> nenneswerten Unterschied für die Batterielaufzeit machen wird, da der
>> Piezo-Treiber im zeitlichen Mittel um Größenordnungen mehr Leistung
>> verbraucht.
> Der muß doch nicht die ganze Zeit über an der Versorgung hängen, den
> könnte man mit einem Transistor zuschalten wenn er benötigt wird.

So ist es auch implementiert. Aber wenn er mal piept (und das wird er), 
verbraucht er bestimmt auf einen Schlag so viel Energie wie der uC in 
zwei Wochen.

: Bearbeitet durch User
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.