Advertisement
Jaimelito_

Jaimelito 2 LED

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