task scheduler and handlers implemented (basics)

This commit is contained in:
King Kévin 2013-10-15 13:20:49 +02:00
parent 72182dc780
commit 95910b32fa
1 changed files with 108 additions and 30 deletions

View File

@ -18,19 +18,33 @@ volatile uint8_t input_i = 0; /* user input index */
volatile uint8_t pwr_ok; /* is power ok */
volatile uint8_t fan; /* fan signal state, to measure tachometer */
volatile uint8_t timer2_ovf = 0; /* to measure fan speed using timer 2 */
static const uint16_t TIMER2_PRESCALE[8] = {0,1,8,32,64,128,256,1024}; /* timer 2 CS2[2:0] values */
uint16_t TIMER2_PRESCALE[8] = {0,1,8,32,64,128,256,1024}; /* timer 2 CS2[2:0] values */
volatile uint16_t tachometer = 0; /* the tachometer time (from timer) */
volatile uint8_t ir; /* IR signal state, to measure IR code */
static const uint16_t TIMER1_PRESCALE[8] = {0,1,8,64,256,1024,0,0}; /* timer 1 CS1[2:0] values */
uint16_t TIMER1_PRESCALE[8] = {0,1,8,64,256,1024,0,0}; /* timer 1 CS1[2:0] values */
volatile uint16_t ir_tick; /* number of counter ticks per millisecond */
volatile uint8_t pulse = 0; /* pulse index within the burst */
#define PULSE_MAX 128 /* maximum number of pulses to save */
uint16_t burst[PULSE_MAX]; /* pulse times forming a burst (from timer) */
/* channel variables */
#define LEVELS 10 /* the number of PWM levels */
uint8_t ch_tick = 0; /* the tick counter for the channel PWM */
#define OUTPUTS_1 5 /* the number of outputs for channel 1 */
#define OUTPUTS_2 5 /* the number of outputs for channel 2 */
volatile uint8_t* PORTS_1[OUTPUTS_1] = {&PORTC,&PORTC,&PORTC,&PORTC,&PORTC}; /* channel 1 output ports */
volatile uint8_t* PORTS_2[OUTPUTS_2] = {&PORTD,&PORTD,&PORTD,&PORTD,&PORTD}; /* channel 2 output ports */
uint8_t BITS_1[OUTPUTS_1] = {PC0,PC1,PC2,PC3,PC4}; /* channel 1 output bits */
uint8_t BITS_2[OUTPUTS_2] = {PD2,PD3,PD4,PD5,PD7}; /* channel 2 output bits */
uint8_t ch_1[OUTPUTS_1]; /* the level value for the channel 1 outputs */
uint8_t ch_2[OUTPUTS_2]; /* the level value for the channel 2 outputs */
/* flags, set in the interrupts and handled in the main program */
volatile bool input_flag = false;
volatile bool power_flag = false;
volatile bool ir_flag = false;
volatile bool uart_flag = false; /* an incoming activity on the UART */
volatile bool power_flag = false; /* a change in the power or fan */
volatile bool ir_flag = false; /* to process a burst */
volatile bool pwm_flag = false; /* to trigger a PWM tick */
volatile bool channel_flag = false; /* indicate a change in the channel PWM values */
/* UART receive interrupt */
ISR(USART_RX_vect) {
@ -39,7 +53,7 @@ ISR(USART_RX_vect) {
if (input_i<INPUT_MAX) { /* next character, if space is available */
input_i++;
}
input_flag = true; /* set flag */
uart_flag = true; /* set flag */
}
/* power ok interrupt */
@ -92,6 +106,12 @@ ISR(TIMER1_COMPA_vect) { /* timer 1 OCR1A match interrupt vector */
}
}
/* timer 0 interrupt used generate a PWM for the channels */
ISR(TIMER0_COMPA_vect) { /* timer 0 OCR0A match interrupt vector */
ch_tick = (ch_tick+1)%LEVELS;
pwm_flag = true;
}
static void ioinit(void)
{
/* configure power */
@ -105,18 +125,7 @@ static void ioinit(void)
/* configure LED (on PD6/OC0A) */
DDRD |= (1<<LED); /* LED is output */
/* use timer 1 to produce a PWM */
/* use phase correct PWM mode (because fast PWM is always on for at least 1 cycle) */
TCCR0A &= ~(1<<WGM01);
TCCR0A |= (1<<WGM00);
TCCR0B &= ~(1<<WGM02);
/* /64 prescale timer */
TCCR0B &= ~(1<<CS02);
TCCR0B |= (1<<CS01)|(1<<CS00);
/* clear on match, because the pin is used as sink */
TCCR0A |= (1<<COM0A1)|(1<<COM0A0);
/* start with LED on */
OCR0A = 0xff;
PORTD &= ~(1<<LED); /* switch LED on */
/* configure FAN */
DDRC &= ~(1<<FAN); /* FAN (PC5/PCINT13) is input */
@ -153,8 +162,8 @@ static void ioinit(void)
ir_tick = F_CPU/(1000*prescale); /* ticks per ms */
OCR1A = (uint32_t)(15*F_CPU)/(1000*prescale); /* set clear time to 15 ms (no IR toggle should be longer) */
}
TIFR1 &= ~(1<<OCF1A); /* clear timer 1 overflow interrupt flag */
TIMSK1 |= (1<<OCIE1A); /* enable timer 1 overflow interrupt */
TIFR1 &= ~(1<<OCF1A); /* clear timer 1 compare interrupt flag */
TIMSK1 |= (1<<OCIE1A); /* enable timer 1 compare interrupt */
/* configure channels (used for powering LEDs using an nMOS) */
DDRC |= (1<<CH1_1)|(1<<CH1_2)|(1<<CH1_3)|(1<<CH1_4)|(1<<CH1_5); /* CH1_x is output */
@ -162,6 +171,18 @@ static void ioinit(void)
DDRD |= (1<<CH2_1)|(1<<CH2_2)|(1<<CH2_3)|(1<<CH2_4)|(1<<CH2_5); /* CH2_x is output */
PORTD &= ~((1<<CH2_1)|(1<<CH2_2)|(1<<CH2_3)|(1<<CH2_4)|(1<<CH2_5)); /* switch off CH2_x */
/* use timer 0 as source for the channel PWM */
/* use CTC mode */
TCCR0A |= (1<<WGM01);
TCCR0A &= ~(1<<WGM00);
TCCR0B &= ~(1<<WGM02);
/* /64 prescale timer */
TCCR0B &= ~(1<<CS02);
TCCR0B |= (1<<CS01)|(1<<CS00);
OCR0A = 0xff; /* set PWM speed */
TIFR0 &= ~(1<<OCF0A); /* clear timer 0 compare interrupt flag */
TIMSK0 |= (1<<OCIE0A); /* enable timer 0 compare interrupt */
/* use UART as terminal */
uart_init();
stdout = &uart_output;
@ -182,10 +203,72 @@ int main(void)
ir_data.command = 0;
uint8_t ir_repeat = 0; /* number of times the IR data has been repeated */
/* initialize channel output PWM values */
for (uint8_t i=0; i<OUTPUTS_1; i++) {
ch_1[i] = 0;
}
for (uint8_t i=0; i<OUTPUTS_2; i++) {
ch_2[i] = 0;
}
uint8_t on_1[5] = {0,0,0,0,0}; /* times when to switch on the outputs for channel 1 */
uint8_t on_2[5] = {0,0,0,0,0}; /* times when to switch on the outputs for channel 2 */
uint8_t off_1[5] = {0,0,0,0,0}; /* times when to switch off the outputs for channel 1 */
uint8_t off_2[5] = {0,0,0,0,0}; /* times when to switch off the outputs for channel 2 */
channel_flag = true; /* calculate above values later */
puts("LED dimmer up & running");
while (true) {
/* handle user input */
while (input_flag) {
/* calculated PWM values */
while (channel_flag) {
uint8_t start = 0;
for (uint8_t i=0; i<OUTPUTS_1; i++) {
on_1[i] = (start)%LEVELS;
off_1[i] = (on_1[i]+ch_1[i])%LEVELS;
start = (start+ch_1[i])%LEVELS;
}
start = 0;
for (uint8_t i=0; i<OUTPUTS_2; i++) {
on_2[i] = (start)%LEVELS;
off_2[i] = (on_2[i]+ch_2[i])%LEVELS;
start = (start+ch_2[i])%LEVELS;
}
channel_flag = false;
}
/* generate PWM for channel */
while (pwm_flag) {
if (pwr_ok) {
for (int i=0; i<OUTPUTS_1; i++) {
if (on_1[i]==ch_tick) {
if (on_1[i]!=off_1[i]) {
*(PORTS_1[i]) |= (1<<BITS_1[i]);
} else if (ch_1[i]==0) {
*(PORTS_1[i]) &= ~(1<<BITS_1[i]);
} else {
*(PORTS_1[i]) |= (1<<BITS_1[i]);
}
} else if (off_1[i]==ch_tick) {
*(PORTS_1[i]) &= ~(1<<BITS_1[i]);
}
}
for (int i=0; i<OUTPUTS_2; i++) {
if (on_2[i]==ch_tick) {
if (on_2[i]!=off_2[i]) {
*(PORTS_2[i]) |= (1<<BITS_2[i]);
} else if (ch_2[i]==0) {
*(PORTS_2[i]) &= ~(1<<BITS_2[i]);
} else {
*(PORTS_2[i]) |= (1<<BITS_2[i]);
}
} else if (off_2[i]==ch_tick) {
*(PORTS_2[i]) &= ~(1<<BITS_2[i]);
}
}
PIND |= (1<<LED);
}
pwm_flag = false;
}
/* handle UART input */
while (uart_flag) {
/* echo back */
char c = 0;
while (command_i<input_i) {
@ -193,7 +276,7 @@ int main(void)
putchar(c);
}
uart_action(c);
input_flag = false;
uart_flag = false;
}
/* handle power state */
while (power_flag) {
@ -264,13 +347,8 @@ static void uart_action(char c)
}
break;
case '1':
PINC |= (1<<CH1_1);
printf("CH1_1: ");
if (PINC&(1<<CH1_1)) {
puts("on");
} else {
puts("off");
}
ch_1[0] = (ch_1[0]+1)%(LEVELS+1);
channel_flag = true;
break;
case '2':
PINC |= (1<<CH1_2);