Untitled
unknown
c_cpp
4 years ago
5.6 kB
66
Indexable
/*
* 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;
}
}
}
}
}
}Editor is loading...