/ Trinket_Gemma_Blinky_Eyes / Trinket_Gemma_Blinky_Eyes.ino
Trinket_Gemma_Blinky_Eyes.ino
 1  // SPDX-FileCopyrightText: 2018 Mikey Sklar for Adafruit Industries
 2  //
 3  // SPDX-License-Identifier: GPL-3.0-or-later
 4  
 5  /* 
 6  Name: Blinking Eyes  - based on code by Brad Blumenthal, MAKE Magazine  
 7  License: GPLv3
 8  Modified for 8 MHz ATTiny85 and low light photocell
 9  October 2013 for Adafruit Learning System
10  */
11  
12  #define SENSITIVITY 550        // photocell sensitivity (changeable)
13  #define CELL_PIN    1          // CdS Photocell voltage divider on
14                                 //   Trinket GPIO #2 (A1), Gemma D1/A1
15  uint8_t eyes_open;
16  volatile uint8_t  blink_count; 
17  volatile uint8_t  blink_flag;
18  volatile uint8_t  tick_flag;
19  volatile uint8_t  getting_brighter = 0;
20  const uint8_t    min_bright=16;
21  const uint8_t    max_bright=128;
22  volatile uint8_t brightness;
23  uint8_t          lfsr;            // Linear Feedback Shift Register 
24  const uint8_t    min_blink = 64u; // don't blink more than once every 3 secs or so
25  
26  void setup() {
27    pinMode(0, OUTPUT);                                       // Eyes set as output
28    pinMode(2, INPUT);                                        // Photocell as input
29    analogWrite(0, max_bright);  analogWrite(1, max_bright);  // Light eyes
30    eyes_open = 1;
31    blink_flag = 0;
32    lfsr = random(100);                                       // initialize "blinking"
33    blink_count = max(blink_count, min_blink);
34    lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xF0u);              // pseudorandom blinking
35    
36    // Timer1 set to CK/1024  ~10 (8) hZ at 8 MHz clock rate for blinking action
37    TCCR1 |= _BV(CS13) | _BV(CS11) | _BV(CS10);  
38    TIMSK |= _BV(TOIE1);  // Enable Timer/Counter1 Overflow Interrupt
39  }
40  
41  void loop() {
42      uint16_t photocell;
43      photocell = analogRead(CELL_PIN);
44      if(photocell > SENSITIVITY) {  // if too light, shut down eyes until it gets darker on photocell
45         tick_flag=0;
46         analogWrite(0,0);  // Turn off eyes if too light out
47        }
48      if (tick_flag) {  // if too bright or we've counted enough ticks (clocks for blink)
49        tick_flag = 0;
50        if (blink_flag) {
51          blink_flag = 0;
52          if (eyes_open) {
53            eyes_open = 0;
54            analogWrite(0,0);  // Turn off eyes by stopping PWM
55            blink_count = (lfsr & 0x01) + 1; // off for 1-2 ticks
56            }
57          else {
58            eyes_open = 1;
59            analogWrite(0,brightness);  // Turn eyes on 
60            blink_count = max(blink_count, min_blink);
61            lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xF0u);  // regenerate pseudorandom blink
62            }
63        }
64        else { // One "tick,"  but we didn't blink...  work on brightness control
65          if (getting_brighter) {
66            brightness += 2;  // increase brightness
67            analogWrite(0, brightness);  
68            if (brightness >= max_bright) getting_brighter = 0;
69          } else {
70            brightness -= 2;  // decrease brightness
71            analogWrite(0, brightness); 
72            if (brightness <= min_bright) getting_brighter = 1;
73          }
74        }
75      }
76  }
77  
78  ISR (TIMER1_OVF_vect) {           // Every 64 times a second, check blink
79    noInterrupts();
80    tick_flag = 1;
81    blink_count--;
82    if (!blink_count) {
83      blink_flag = 1;
84    }
85    interrupts();
86  }