Advertisement
Guest User

ATTINY85 2 led

a guest
Jun 9th, 2015
417
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.77 KB | None | 0 0
  1. #define F_CPU 4800000UL
  2. #define PHASE 0b00000001
  3. #define FAST  0b00000011
  4. #define BLINK_ON_POWER      
  5. #define VOLTAGE_MON        
  6. #define MODES           0,4,10,120,255    
  7. #define MODES2          0,2,32,125,255
  8. #define MODE_PWM        0,PHASE,FAST,FAST,PHASE
  9. #define MODE_PWM2        0,PHASE,FAST,FAST,PHASE
  10. #define ADC_LOW         130
  11. #define ADC_CRIT        120
  12. #define ADC_DELAY       188
  13. #define MOM_EXIT_DUR    128
  14. #define FULL_MODE  -1
  15. #include <avr/pgmspace.h>
  16. #include <avr/io.h>
  17. #include <util/delay.h>
  18. #include <avr/interrupt.h>
  19. #include <avr/wdt.h>  
  20. #include <avr/eeprom.h>
  21. #include <avr/sleep.h>
  22. //#include <avr/power.h>
  23. #define SWITCH_PIN  PB3    
  24. #define SWITCH_PIN2 PB4    
  25. #define PWM_PIN     PB1
  26. #define PWM_PIN2     PB0
  27. #define VOLTAGE_PIN PB2
  28. #define ADC_CHANNEL 0x01  
  29. #define ADC_DIDR    ADC1D  
  30. #define ADC_PRSCL   0x06  
  31.  
  32. #define PWM_LVL1     OCR0B  
  33. #define PWM_LVL2     OCR0A  
  34.  
  35. #define DB_PRES_DUR 0b00000001
  36. #define DB_REL_DUR  0b00001111
  37.  
  38.  
  39. #define LONG_PRESS_DUR   128
  40. #define LOCK_PRESS_DUR   600
  41. /*
  42.  * The actual program
  43.  * =========================================================================
  44.  */
  45.  
  46. /*
  47.  * global variables
  48.  */
  49. const uint8_t modes[]     = { MODES    };
  50. const uint8_t modes2[]     = { MODES2};
  51. const uint8_t mode_pwm[] = { MODE_PWM };
  52. const uint8_t mode_pwm2[] = { MODE_PWM2 };
  53. volatile int8_t mode_idx = 0;
  54. volatile int8_t mode_idx2 = 0;
  55. volatile uint8_t press_duration = 0;
  56. volatile uint8_t press_duration2 = 0;
  57. volatile uint8_t low_to_high = 1;
  58. volatile uint8_t in_momentary = 0;
  59.  
  60. // Debounce switch press value
  61.  
  62. int is_pressed()
  63. {
  64.     // Keep track of last switch values polled
  65.     static uint8_t buffer = 0x00;
  66.     // Shift over and tack on the latest value, 0 being low for pressed, 1 for pulled-up for released
  67.     buffer = (buffer << 1) | ((PINB & (1 << SWITCH_PIN)) == 0);
  68.      
  69.     return (buffer & DB_REL_DUR);
  70. }
  71.  
  72.  int is_pressed2()
  73.  {
  74.          // Keep track of last switch values polled
  75.          static uint8_t buffer2 = 0x00;
  76.          // Shift over and tack on the latest value, 0 being low for pressed, 1 for pulled-up for released
  77.          buffer2 = (buffer2 << 1) | ((PINB & (1 << SWITCH_PIN2)) == 0);
  78.          
  79.          return (buffer2 & DB_REL_DUR);
  80.  }
  81.  
  82.  inline void next_mode() {
  83.          if (++mode_idx >= sizeof(modes)) {
  84.                  // Wrap around
  85.                  mode_idx = 1;
  86.          }
  87.  }
  88.  
  89.  inline void prev_mode() {
  90.          if (mode_idx == 0) {
  91.                  // Wrap around
  92.                  mode_idx = sizeof(modes) - 1;
  93.                  } else {
  94.                  --mode_idx;
  95.          }
  96.  }
  97. inline void next_mode2() {
  98.         if (++mode_idx2 >= sizeof(modes2)) {
  99.                 // Wrap around
  100.                 mode_idx2= 1;
  101.         }
  102. }
  103.  
  104. inline void prev_mode2() {
  105.         if (mode_idx2 == 0) {
  106.                 // Wrap around
  107.                 mode_idx2 = sizeof(modes2) - 1;
  108.                 } else {
  109.                 --mode_idx2;
  110.         }
  111. }
  112.  
  113. inline void PCINT_on() {
  114.     // Enable pin change interrupts
  115.     GIMSK |= (1 << PCIE);
  116. }
  117.  
  118. inline void PCINT_off() {
  119.     // Disable pin change interrupts
  120.     GIMSK &= ~(1 << PCIE);
  121. }
  122.  
  123. // Need an interrupt for when pin change is enabled to ONLY wake us from sleep.
  124. // All logic of what to do when we wake up will be handled in the main loop.
  125. EMPTY_INTERRUPT(PCINT0_vect);
  126.  
  127. inline void WDT_on() {
  128.     // Setup watchdog timer to only interrupt, not reset, every 16ms.
  129.     cli();                          // Disable interrupts
  130.     wdt_reset();                    // Reset the WDT
  131.     WDTCR |= (1<<WDCE) | (1<<WDE);  // Start timed sequence
  132.     WDTCR = (1<<WDIE);               // Enable interrupt every 16ms
  133.     sei();                          // Enable interrupts
  134. }
  135.  
  136. inline void WDT_off()
  137. {
  138.     cli();                          // Disable interrupts
  139.     wdt_reset();                    // Reset the WDT
  140.     MCUSR &= ~(1<<WDRF);          // Clear Watchdog reset flag
  141.     WDTCR |= (1<<WDCE) | (1<<WDE);  // Start timed sequence
  142.     WDTCR = 0x00;                   // Disable WDT
  143.     sei();                          // Enable interrupts
  144. }
  145.  
  146. inline void ADC_on() {
  147.     ADMUX  = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
  148.     DIDR0 |= (1 << ADC_DIDR);                         // disable digital input on ADC pin to reduce power consumption
  149.     ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
  150. }
  151.  
  152. inline void ADC_off() {
  153.     ADCSRA &= ~(1<<7); //ADC off
  154. }
  155.  
  156. void sleep_until_switch_press()
  157. {
  158.     // This routine takes up a lot of program memory :(
  159.     // Turn the WDT off so it doesn't wake us from sleep
  160.     // Will also ensure interrupts are on or we will never wake up
  161.     WDT_off();
  162.     // Need to reset press duration since a button release wasn't recorded
  163.     press_duration = 0;
  164.     // Enable a pin change interrupt to wake us up
  165.     // However, we have to make sure the switch is released otherwise we will wake when the user releases the switch
  166.     while (is_pressed()||is_pressed2()) {
  167.         _delay_ms(16);
  168.     }
  169.     PCINT_on();
  170.     // Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command.
  171.     //set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  172.     // Now go to sleep
  173.     sleep_mode();
  174.     // Hey, someone must have pressed the switch!!
  175.     // Disable pin change interrupt because it's only used to wake us up
  176.     PCINT_off();
  177.     // Turn the WDT back on to check for switch presses
  178.     WDT_on();
  179.     // Go back to main program
  180. }
  181.  
  182. // The watchdog timer is called every 16ms
  183. ISR(WDT_vect) {
  184.  
  185.     static uint8_t  adc_ticks = ADC_DELAY;
  186.     static uint8_t  lowbatt_cnt = 0;
  187.  
  188.     if (is_pressed()) {
  189.         if (press_duration < 255) {
  190.             press_duration++;
  191.         }
  192.      if (is_pressed2()) {
  193.              if (press_duration2 < 255) {
  194.                      press_duration2++;
  195.              }
  196.          
  197.  
  198.         if (press_duration == LONG_PRESS_DUR) {
  199.             // Long press
  200.             if (mode_idx == 0) {
  201.                 // TODO: if we were off, enter strobe mode
  202.                 mode_idx = 4;
  203.             } else {
  204.                 // if we were on, turn off
  205.                 mode_idx = 0;
  206.             }
  207.         }
  208.          
  209.                 if (press_duration2 == LONG_PRESS_DUR) {
  210.                         // Long press
  211.                         if (mode_idx2 == 0) {
  212.                                 // TODO: if we were off, enter strobe mode
  213.                                 mode_idx2 = 4;
  214.                                 } else {
  215.                                 // if we were on, turn off
  216.                                 mode_idx2 = 0;
  217.                         }
  218.                 }
  219.         // Just always reset turbo timer whenever the button is pressed
  220.         //turbo_ticks = 0;
  221.         // Same with the ramp down delay
  222.         adc_ticks = ADC_DELAY;
  223.      
  224.     } else {
  225.          
  226.          
  227.          
  228.         // Not pressed
  229.         if (press_duration > 0 && press_duration < LONG_PRESS_DUR) {
  230.             // Short press
  231.             if (mode_idx == 4) {
  232.                 // short-press from strobe goes to second-highest mode
  233.                 mode_idx = sizeof(modes)-4;
  234.             }
  235.             else { // regular short press
  236.                 if (low_to_high) {
  237.                     next_mode();
  238.                 } else {
  239.                     prev_mode();
  240.                 }  
  241.             }
  242.                          if (press_duration2 > 0 && press_duration2 < LONG_PRESS_DUR) {
  243.                                  // Short press
  244.                                  if (mode_idx2 == 4) {
  245.                                          // short-press from strobe goes to second-highest mode
  246.                                          mode_idx2 = sizeof(modes2)-4;
  247.                                  }
  248.                                  else { // regular short press
  249.                                          if (low_to_high) {
  250.                                                  next_mode2();
  251.                                                  } else {
  252.                                                  prev_mode2();
  253.                                          }
  254.                                  }
  255.         } else {
  256.              
  257.             // Only do voltage monitoring when the switch isn't pressed
  258.         #ifdef VOLTAGE_MON
  259.             if (adc_ticks > 0) {
  260.                 --adc_ticks;
  261.             }
  262.             if (adc_ticks == 0) {
  263.                 // See if conversion is done
  264.                 if (ADCSRA & (1 << ADIF)) {
  265.                     // See if voltage is lower than what we were looking for
  266.                     if (ADCH < ((mode_idx == 1) ? ADC_CRIT : ADC_LOW)) {
  267.                         ++lowbatt_cnt;
  268.                     } else {
  269.                         lowbatt_cnt = 0;
  270.                     }
  271.                 }
  272.                  
  273.                 // See if it's been low for a while
  274.                 if (lowbatt_cnt >= 4) {
  275.                     prev_mode();
  276.                     lowbatt_cnt = 0;
  277.                     // If we reach 0 here, main loop will go into sleep mode
  278.                     // Restart the counter to when we step down again
  279.                     adc_ticks = ADC_DELAY;
  280.                 }
  281.                  
  282.                 // Make sure conversion is running for next time through
  283.                 ADCSRA |= (1 << ADSC);
  284.             }
  285.         #endif
  286.         }
  287.         press_duration = 0;
  288.                 }
  289.                                  }
  290.                          }
  291.                          }
  292. int main(void)
  293. {     // Set all ports to input, and turn pull-up resistors on for the inputs we are using
  294.     DDRB = 0x00;
  295.     PORTB = (1 << SWITCH_PIN) | (1 << SWITCH_PIN2);
  296.  
  297.     // Set the switch as an interrupt for when we turn pin change interrupts on
  298.     PCMSK = (1 << SWITCH_PIN) | (1 << SWITCH_PIN2);
  299.      
  300.     // Set PWM pin to output
  301.  
  302.     DDRB  = (1 << PWM_PIN) | (1 << PWM_PIN2);
  303.  
  304.     // Set timer to do PWM for correct output pin and set prescaler timing
  305.     TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
  306.     TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
  307.      
  308.     // Turn features on or off as needed
  309.     #ifdef VOLTAGE_MON
  310.     ADC_on();
  311.     #else
  312.     ADC_off();
  313.     #endif
  314.     ACSR   |=  (1<<7); //AC off
  315.      
  316.  
  317.      
  318. #ifdef BLINK_ON_POWER
  319.     // blink once to let the user know we have power
  320.     TCCR0A = PHASE | 0b00100000;  // Only use the normal output
  321.     PWM_LVL1 =60;
  322.     PWM_LVL2 = 60;
  323.     _delay_ms(3);
  324.     PWM_LVL1 = 0;
  325.         PWM_LVL2 = 0;
  326.     _delay_ms(1);
  327. #endif
  328.  
  329.     // Enable sleep mode set to Power Down that will be triggered by the sleep_mode() command.
  330.     set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  331.     sleep_until_switch_press();
  332.      
  333.     uint8_t last_mode_idx = 0;
  334.     int8_t real_mode_idx = 0;
  335.  uint8_t last_mode_idx2 = 0;
  336.          int8_t real_mode_idx2 = 0;
  337.      
  338.     while(1) {
  339.         // We will never leave this loop.  The WDT will interrupt to check for switch presses and
  340.         // will change the mode if needed.  If this loop detects that the mode has changed, run the
  341.         // logic for that mode while continuing to check for a mode change.
  342.         if (mode_idx != last_mode_idx) {
  343.             real_mode_idx = mode_idx;
  344.             // The WDT changed the mode.
  345.             if (mode_idx == FULL_MODE) {
  346.                 // strobe should use second-highest mode
  347.                 real_mode_idx = sizeof(modes) - 4;
  348.             } else if (mode_idx > 0) {
  349.                 // No need to change the mode if we are just turning the light off
  350.                 // Check if the PWM mode is different
  351.                 if (mode_pwm[last_mode_idx] != mode_pwm[mode_idx]) {
  352.                     TCCR0A = mode_pwm[mode_idx] | 0b10100000;  // Use both outputs      
  353.                 }
  354.             }
  355.             PWM_LVL1     = modes[real_mode_idx];
  356.             last_mode_idx = mode_idx;
  357.             // Handle strobe mode
  358.             if (mode_idx == FULL_MODE) {
  359.                 PWM_LVL1=255;
  360.                 TCCR0A=PHASE | 0b00100000;
  361.              
  362.       }
  363.                         if (mode_idx2 != last_mode_idx2) {
  364.                                 real_mode_idx2 = mode_idx2;
  365.                                 // The WDT changed the mode.
  366.                                 if (mode_idx2 == FULL_MODE) {
  367.                                         // strobe should use second-highest mode
  368.                                         real_mode_idx2 = sizeof(modes2) - 4;
  369.                                         } else if (mode_idx2 > 0) {
  370.                                         // No need to change the mode if we are just turning the light off
  371.                                         // Check if the PWM mode is different
  372.                                         if (mode_pwm2[last_mode_idx2] != mode_pwm2[mode_idx2]) {
  373.                                                 TCCR0A = mode_pwm2[mode_idx2] | 0b10100000;  // Use both outputs
  374.                                         }
  375.                                 }
  376.                                 PWM_LVL2     = modes2[real_mode_idx2];
  377.                                 last_mode_idx2 = mode_idx2;
  378.                                 // Handle strobe mode
  379.                                 if (mode_idx2 == FULL_MODE) {
  380.                                         PWM_LVL2=255;
  381.                                         TCCR0A=PHASE | 0b00100000;
  382.                                        
  383.                                 }
  384.  
  385.                         if (real_mode_idx && real_mode_idx2 == 0){
  386.                 _delay_ms(1); // Need this here, maybe instructions for PWM output not getting executed before shutdown?
  387.                 // Go to sleep
  388.                 sleep_until_switch_press();
  389.             }
  390.    
  391. }
  392.  
  393.                
  394.     return 0; // Standard Return Code
  395.         }
  396.         }
  397. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement