Microchip/Atmel AVR ATtiny85, Pin-change interrupt (PCINT0) ) und Watchdog als Timer (WDT)

Gast #5907836
Lesenswert?

Der folgende Code läuft auf einem "Digispark" Klon mit ATtiny85 bei 5V 
extern (USB ist nicht verbunden).
Wenn ich INPUT mit NC2 low ziehe, schaltet OUTPUT für 204 ms ein - nicht 
für 8 Sekunden.
Stimmt etwas mit der Watchdog-Konfiguration nicht, oder woran kann's 
noch liegen?

1
// Microchip / Atmel AVR ATtinyx5
2
// 
3

4
//#define F_CPU 1000000 // 8MHz/8 CLKDIV8 (default, fuse sets prescaler in CLKPR, can be overwritten)
5
#define F_CPU 16500000 // 16.5 MHz: PLL overclocked by micronucleus USB bootloader (USB sync.)
6

7

8
// C types
9
#include <stdint.h>
10

11
// AVR-libc
12
#include <avr/io.h>
13
#include <avr/sleep.h>
14
#include <avr/interrupt.h>
15
#include <avr/wdt.h>
16
#include <util/delay.h>
17

18

19
// IO
20
//  #RESET PB5 1   8 VCC
21
//         PB3 2   7 PB2
22
//         PB4 3   6 PB1
23
//         GND 4   5 PB0
24
#define NC0       (1<<PB0)  // 5 (MOSI/DI/SDA/AIN0/OC0A/#OC1A/AREF/PCINT0)
25
#define LED       (1<<PB1)  // 6 (MISO/DO/AIN1/OC0B/OC1A/PCINT1)
26
#define NC2       (1<<PB2)  // 7 (SCK/USCK/SCL/ADC1/T0/INT0/PCINT2)
27
#define INPUT     (1<<PB3)  // 2 (PCINT3/XTAL1/CLKI/#OC1B/ADC3)
28
#define OUTPUT    (1<<PB4)  // 3 (PCINT4/XTAL2/CLKO/OC1B/ADC2)
29
//                          // 1 (PCINT5/#RESET/ADC0/dW)
30
//                             4 GND
31
//                             8 VCC
32

33

34
ISR(PCINT0_vect) {
35
  GIMSK = 0;          // stop PCIE
36
  PORTB |= (LED | OUTPUT);    // debug
37
  WDTCR = (1<<WDIE) | WDTO_8S;  // enable WDT
38
}
39

40

41
ISR(WDT_vect) {
42
  wdt_disable();      // stop WDT
43
  PORTB &= ~(LED | OUTPUT); // debug
44
  GIMSK = (1<<PCIE);    // enable interrupt
45
}
46

47

48
int main(void) {
49
   
50
  MCUSR = 0;  // reset status
51
  GIFR = 0xFF;  // clear interrupt flags
52
  
53
  // low power
54
  wdt_disable();    // stop WDT
55
  sleep_bod_disable();  // BOD
56
  ACSR |= (1<<ACD);    // analog comparator
57
  PRR |= (1<<PRTIM0) | (1<<PRTIM1) | (1<<PRUSI) | (1<<PRADC);
58

59
  // output(s)
60
  DDRB = (LED | OUTPUT | NC0 | NC2); //
61
  PORTB = 0;
62
  
63
  // hello world
64
  for (uint8_t n=0; n<6; n++) {
65
  PORTB ^= LED;
66
  _delay_ms(200);
67
  }
68

69
  // enable pin change interrupt
70
  GIFR |= (1<<PCIF);  // the flag can be cleared by writing a logical one to it
71
  GIMSK = (1<<PCIE);  // 
72
  PCMSK = (1<<PCINT3);  // 
73

74
  // power down
75
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
76
  sleep_enable();
77
  sei();
78
  while (1) {
79
    sleep_cpu();
80
  //sleep_disable();
81
  }
82
}
Beitrag #5907874 wurde von einem Moderator gelöscht.
Gast #5907916
Lesenswert?

1
  wdt_enable(WDTO_4S);      // enable WDT
2
  WDTCR |= (1<<WDIE);      // WDT for interrupt

8.8 s
1
  wdt_enable(WDTO_8S);      // enable WDT
2
  WDTCR |= (1<<WDIE);      // WDT for interrupt

17.5 s

Läuft er doppelt?
Gast #5907980
Lesenswert?

Also:
Fehler 1: WDT nicht korrekt konfiguriert (Schreibsequenz per Makro)
Fehler 2: WDT lief doppelt, weil der PCINT nach Ablauf von WDT sofort 
wieder ausgeführt wurde.
50..60 ms "Latenz" zwischen Flanke und Schalten des Ausgangs: PLL 
start-up time
Gast #5908046
Lesenswert?

Thomas E. schrieb:
> Auf das WDTCR kann nur in einer Timed Sequence zugegriffen werden. Mach
> das wie im Datenblatt beschrieben oder benutze die Makros.

Im Datenblatt steht dazu "keine Einschränkung", wenn WDTON nicht 
aktiviert ist.
Zum Löschen von WDE ist dagegen die Sequenz erforderlich.

Neuer Versuch, anderer Wert:
1
WDTCR |= (1<<WDIE) | WDTO_2S;

Geht. 8-D
Gast #5908197
Lesenswert?

Lasse Klingeln schrieb:
> Irgendwas stimmt hier wohl mit Atmel Studio nicht.

Vielleicht auch mit der Badehose :-)

Hier eine Variante mit der Arduino IDE.
Ein paar include hinzufügen, dann müsste es auch mit dem Atmel Studio im 
8 Sekunden Takt blinken.

Getestet mit einem 16,5MHz Digistump Klon.
Die Eingebaute LED hängt an PB1
1
#include <avr/wdt.h>
2

3

4
int main(void) 
5
{
6
  wdt_enable(WDTO_8S);  
7
  DDRB |= _BV(PB1);   // led output
8
  WDTCR |= 1<<WDIE;    
9
  sei();
10
  for(;;){}
11
}
12

13

14
ISR(WDT_vect) 
15
{
16
  WDTCR |= 1<<WDIE;  
17
  PINB = _BV(PB1); // toggle led
18
}
Gast #5908276
Lesenswert?

Thomas E. schrieb:
> Habe dir doch gesagt, daß das nicht geht.

Wie im vagen Datenblatt beschrieben, geht es leider auch nicht:

    wdt_reset();
    WDTCR |= (1<<WDCE) | (1<<WDE);
    WDTCR = (1<<WDIE) | WDTO_4S;


Es gibt kein Makro für den WDT als Timer.
Bislang funktioniert es bei mir nur so, wie um 11:55 geschrieben, also 
WDT enable Makro und dann umschalten auf Interrupt:

    wdt_enable(WDTO_4S);
    WDTCR |= (1<<WDIE);

Arduino Fanboy D. schrieb:
> Hier eine Variante mit der Arduino IDE.

Danke, so läuft's auch bei mir.

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