Untitled

mail@pastecode.io avatar
unknown
c_cpp
2 years ago
5.6 kB
19
Indexable
Never
/*
 * File:   main.c
 * Author: David
 *
 * Created on 23 de marzo de 2022, 8:55
 */


#include <xc.h>

#define LED RA0
#define BTN RB0
#define OUTPUT LED                                                  /* Output is the LED */

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

/* Values in ms  */
#define BTN_TIME              20                                    /* 20ms button debounce, set 0 to disable */
#define DELAY_TIME            10000                                 /* 10s delay       */
#define UP_TIME               30000                                 /* 30s up time     */
#define DOWN_TIME             30000                                 /* 30s down time   */

/* Variables */

struct{
  volatile unsigned int ms;         // volatile because it's modified inside an interrupt
  volatile unsigned char button;
  unsigned char tmr;
  unsigned int out;
  unsigned int now;
}count;

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


/* Functions */

void clearTimer(void){
  disable_interrupts();
  TMR2 = 0;                             // Clear Timer counter
  count.ms = 0;                         // Clear ms counter
  enable_interrupts();
  count.now = 0;                        // Also clear now value
}

void readTimer(void){
    disable_interrupts();               // Interrupts must be paused when handling timer0 counters
    count.now = count.ms;               // Save counter status
    enable_interrupts();
}

void saveTimer(void){
    count.tmr = TMR2;                   // Save timer counter
    disable_interrupts();
    count.out = count.ms;               // Save ms counter
    enable_interrupts();
}

void restoreTimer(void){    
    TMR2 = count.tmr;                   // Restore timer counter
    disable_interrupts();
    count.ms = count.out;               // Restore ms counter
    enable_interrupts();
    count.now = count.ms;               // Update now time
}

void initTimer(void){                   // Default internal clock = 4MHz, (1 MIPS, CLKOUT=1MHz)
  PR2 =  249;                           // Period match =  249+1 = 250
  T2CON = 0b101;                        // TMR2 on, pre=1:4, post=1:1    1MHZ/(4*250) = 1KHz  
  PIE1bits.TMR2IE = 1;                  // Enable Timer2 interrupt
  clearTimer();                         // Clear Timer counter
  PIR1bits.TMR2IF = 0;                  // Clear flag
  INTCON = 0b11000000;                  // GIE=1, PIE=1 (Enable global and peripheral interrupts)  
}

/* ISR */
void __interrupt() Interrupt(void){
  if (PIR1bits.TMR2IF) {
     PIR1bits.TMR2IF = 0;
     count.ms++;
     count.button++;
     RA1 = !RA1;                        // Toggle test signal (500Hz), just to detect it's working     
  }  
}


/* Main */
void main() {
  TRISA0=0;
  TRISB0=1;
  TRISB1=0;
  TRISA1=0;
  RA1=0;
  OUTPUT=0;
  status.output = 1;
  
  initTimer();                         // Init and start Timer0
  
  while(1) {
      
    /* Read Timer0 counter at the start of the loop */   
    readTimer();
    
    /* 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){             // Input low?
          if(!status.delay && status.enable){   // If not in delay and enabled
            saveTimer();                // Save timer
            status.enable = 0;          // Disabled
            OUTPUT = 0;                 // Disable output
          }
        }
        else{                           // Input high?
          clearTimer();                 // Clear timer
          status.enable = 1;            // Enabled
          status.delay = 1;             // Enable delay          
        }
      }
    }
    else{                               // Button didn't change or bounced back to original position
      count.button = 0;                 // Clear button counter
    }                                   // No need to stop interrupts because it's atomic
    
    
    /* If enabled, handle delay and output signal */
    
    if(status.enable){                  // Enabled?
      if(status.delay){                 // Delay active?
        if(count.now >= DELAY_TIME) {   // If counter >= delay time
          status.delay = 0;             // Delay done, clear flag
          restoreTimer();               // Restore previous counter
          if(status.output){            // Restore output state
            OUTPUT = 1;
          }
        }
      }
      else{                             // Running?
        if(status.output){              // If output high
          if(count.now >= UP_TIME) {    // Check for elapsed uptime
            clearTimer();
            OUTPUT = 0;
            status.output = 0;
          }
        }
        else{                           // If output low
          if(count.now >= DOWN_TIME) {  // Check for elapsed downtime
            clearTimer();
            OUTPUT = 1;
            status.output = 1;
          }
        }
      }
    }
  }
}