Untitled

mail@pastecode.io avatar
unknown
c_cpp
2 years ago
4.7 kB
12
Indexable
Never
/* Defines */

#define LED PORTA.F0
#define BTN PORTB.F0
#define OUTPUT LED                                  /* Output is the LED */

#define enable_interrupts()   INTCON.GIE = 1        /* Enable global interrupts   */
#define disable_interrupts()  INTCON.GIE = 0        /* Disable global interrupts  */

#define BTN_TIME              (32/TIMESTEP)         /* 32ms button debounce  */
#define TMR0_PRELOAD          131                   /* Timer 0 preload */
#define TIMESTEP              8                     /* 8ms step        */
#define DELAY_TIME            (10000/TIMESTEP)      /* 10s delay       */
#define UP_TIME               (30000/TIMESTEP)      /* 30s up time     */
#define DOWN_TIME             (30000/TIMESTEP)      /* 30s down time   */


/* Variables */

struct{
  volatile unsigned int timer0;         // volatile because it's modified inside an interrupt
  volatile unsigned int button;
  unsigned int output;
  unsigned int now;
}count;

union{
  unsigned char data;
  struct{
    unsigned enable:1;
    unsigned button:1;
    unsigned output:1;
    unsigned delay:1;
  };  
} status;


/* Functions */

void clearTimer0(void){
  disable_interrupts();
  count.timer0 = 0;                     // Clear Timer0 counter
  enable_interrupts();
}

void initTimer0(void){                  // Default internal clock = 4MHz, (1 MIPS, CLKOUT=1MHz)
  OPTION_REG = 0x05;                    // TMR0 source = CLKOUT, 1:64, WDT = 1:32. Timer0 clock = 15625Hz
  INTCON = 0b10110000;                  // GIE=1, T0IE=1, RB0/INT=1
  TMR0 = TMR0_PRELOAD;                  // 15625Hz / ((255-131)+1) = 125Hz = 8ms
  clearTimer0();
}

void toggle_state(void){ 
  clearTimer0();         
  if(status.output){
    status.output = 0;                  // Clear state
    OUTPUT = 0;                         // Disable output
  }
  else{
    status.output = 1;                  // Set state
    OUTPUT = 1;                         // Enable output            
  }
}


/* ISR */
void Interrupt(void){
  if (TMR0IF_bit)
  {
     TMR0 = TMR0_PRELOAD;
     TMR0IF_bit	 = 0;
     count.timer0++;
     count.button++;
  }
}


/* Main */
void main() {
  TRISA.F0=0;
  TRISB.F0=1;
  TRISB.F1=0;
  TRISA.F1=0;
  PORTA.F1=0;
  LED=0;
  
  InitTimer0();                         // Init and start Timer0
  
  while(1) {
      
    /* Read Timer0 counter at the start of the loop */   
    
    disable_interrupts();               // Interrupts must be paused when handling timer0 and button counters
    count.now = count.timer0;           // Save counter status
    enable_interrupts();
        
        
    /* Handle button update and debouncing */
    
    if(status.button != BTN){           // If button changed from last stored state
      if(count.button >= BTN_TIME){     // If button debounce time elapsed 
        status.button = BTN;            // Update stored state and take action          
        if(!status.button){             // Stop state?
          count.out = count.now;        // Save counter status into output counter variable
          status.enable = 0;            // Disabled state
          OUTPUT = 0;                   // Disable output
        }
        else{                           // Run state?
          clearTimer0();                // Clear timer
          status.enable = 1;            // Enabled state
          status.delay = 1;             // Enable delay          
        }
      }
    }
    else{                               // Button didn't change
      disable_interrupts();
      count.button = 0;                 // Clear button counter
      enable_interrupts();        
    }      
    
    
    /* If enabled, handle delay and output signal */
    
    if(status.enable){
      if(status.delay){
        if(now >= DELAY_TIME {          // If counter >= delay time
          status.delay = 0;             // Delay done, clear flag
          disable_interrupts();
          count.timer0 = count.out;     // Restore counter status from output counter variable
          enable_interrupts();
          if(status.output){            // Restore output state
            OUTPUT = 1;
          }
        }
      }
      else{                             // Running
        if(status.output){              // If output high
          if(count.now >= UP_TIME) {    // Check for elapsed up time
            toggle_state();            
          }
        }
        else{                           // If output low
          if(count.now >= DOWN_TIME) {  // Check for elapsed down time
            toggle_state();
          }
        }
      }
    }
  }
}