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

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.