Appendix A: Code Listing
    
 digi-lev.c
#include <mega32.h>
#include <math.h>
#include <stdio.h>
#include <delay.h>
#asm
.equ __lcd_port=0x15
#endasm
#include <lcd.h>
#define TIME_BUT 30
#define TIME_ACC 10
#define TIME_LCD 100
unsigned char but_cnt=TIME_BUT;
unsigned char acc_cnt=TIME_ACC;
unsigned char lcd_cnt=TIME_LCD;
char measure_position = 0; unsigned char channels[2][2] = {{0,1},{2,3}};
unsigned int num_avg = 15;
unsigned int sensitivity = 15;
int accel[2] = {0,0};
unsigned int avg_cnt = 0;
float pitch_avg = 0.0f;
float roll_avg = 0.0f;
int old_pitch_avg = 0;
int old_roll_avg = 0;
int old_plum_avg = 0;
unsigned int num_avg_msk = 0;
unsigned int num_avg_hlf = 0;
int p_1 = 0;
int r_1 = 0;
int pitch_avg = 0;
int pitch_avg_2 = 0;
int roll_avg = 0;
int roll_avg_2 = 0;
int plum_avg_1 = 0;
char p_level = 1;
char r_level = 1;
char old_bubble=0;
char new_bubble=0;
#define CAL_AVG 1000
eeprom int mid_cal_store[2][2] = {{766, 732}, {694, 725}};
unsigned int mid_cal[2][2] = {{766, 732}, {694, 725}};
unsigned int read_adc(unsigned char);
void tsk_poll_accelerometers(void);
void tsk_buttons(void);
void tsk_lcd_update(void);
void calibrate_midpoint(char);
void calibrate_gravity(char);
unsigned int adc_data;
#define ADC_VREF_TYPE 0x00
#pragma savereg-
interrupt [ADC_INT] void adc_isr(void)
{
#asm
push r30
push r31
#endasm
adc_data=ADCW;
#asm
pop r31
pop r30
#endasm
}
#pragma savereg+
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
if (but_cnt > 0) but_cnt--;
if (acc_cnt > 0) acc_cnt--;
if (lcd_cnt > 0) lcd_cnt--;
}
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input|ADC_VREF_TYPE;
#asm
in r30,mcucr
cbr r30,__sm_mask
sbr r30,__se_bit
out mcucr,r30
sleep
cbr r30,__se_bit
out mcucr,r30
#endasm
return adc_data;
}
void tsk_poll_accelerometers(void)
{
char to_output = 0; unsigned char c_0, c_1;
acc_cnt = TIME_ACC;
c_0 = channels[measure_position][0];
c_1 = channels[measure_position][1];
accel[0] = (read_adc(c_0)-mid_cal[measure_position][0]); accel[1] = (read_adc(c_1)-mid_cal[measure_position][1]);
avg_cnt++;
avg_cnt%=num_avg;
pitch_avg += accel[0];
roll_avg += accel[1];
if(!avg_cnt) {
p_1 = pitch_avg;
p_1 = abs(p_1);
if((p_1>>sensitivity) < 1) {
p_1 &= num_avg_msk; if(p_1 >= num_avg_hlf) p_level = 0; else
p_level = 1; }
else
p_level = 0;
r_1 = roll_avg;
r_1 = abs(r_1);
if((r_1>>sensitivity) < 1)
{
r_1 &= num_avg_msk;
if(r_1 >= num_avg_hlf)
r_level = 0;
else
r_level = 1;
}
else
r_level = 0;
if(!p_level)
to_output |= (pitch_avg < 0) ? 0b10000000 : 0b00010000;
if(!r_level)
to_output |= (roll_avg < 0) ? 0b00100000 : 0b01000000;
if(to_output == 0)
to_output = 0b00001000;
to_output = ~to_output | 0b00000111;
PORTB = to_output;
if(abs(pitch_avg>>sensitivity) > 60)
measure_position = abs(measure_position-1);
old_pitch_avg = pitch_avg;
old_roll_avg = roll_avg;
pitch_avg = 0;
roll_avg = 0;
}
}
char lcd_select=0;
char prev_press = 0;
char eep_press_1 = 0;
char eep_press_2 = 0;
void tsk_buttons(void)
{
but_cnt = TIME_BUT;
if(!PINB.0) {
if (!prev_press)
{
lcd_select++;
lcd_select%=2;
prev_press = 1;
}
}
else prev_press = 0;
if (!PINB.1) {
calibrate_midpoint(0);
calibrate_midpoint(1);
}
if (!PINB.2) {
PORTB = 0b00000111;
mid_cal_store[0][0] = mid_cal[0][0];
mid_cal_store[0][1] = mid_cal[0][1];
mid_cal_store[1][0] = mid_cal[1][0];
mid_cal_store[1][1] = mid_cal[1][1];
delay_ms(2000);
}
sensitivity = ((read_adc(5) & 0xfffc)>>6)+3;
num_avg_hlf = ((unsigned int)1) << (sensitivity);
num_avg_msk = (num_avg_hlf << 1) - 1;
num_avg = ((unsigned int)1)<<sensitivity;
}
void tsk_lcd_update(void)
{
lcd_cnt = TIME_LCD;
switch(lcd_select)
{
case 0:
lcd_gotoxy(14,1);
lcd_putchar('R');
new_bubble = (old_roll_avg>>sensitivity)/6+7;
break;
case 1:
lcd_gotoxy(14,1);
lcd_putchar('P');
new_bubble = (old_pitch_avg>>sensitivity)/6+7;
break;
}
lcd_gotoxy(10,1);
lcd_putchar(' ');
lcd_gotoxy(10,1);
lcd_putchar(sensitivity+46);
lcd_gotoxy(1,1);
if(measure_position)
lcd_putchar('V');
else
lcd_putchar('H');
lcd_gotoxy(old_bubble,0);
if (old_bubble == 6 || old_bubble == 8)
lcd_putchar('|');
else
lcd_putchar(' ');
if(new_bubble < 0)
{
old_bubble = 0;
lcd_gotoxy(0,0);
lcd_putchar('o');
}
else if(new_bubble > 15)
{
old_bubble = 15;
lcd_gotoxy(15,0);
lcd_putchar('o');
}
else
{
lcd_gotoxy(new_bubble, 0);
lcd_putchar('o');
old_bubble = new_bubble;
}
}
void calibrate_midpoint(char channel)
{
unsigned int i; float mid = 0;
for (i=0; i<CAL_AVG; i++)
mid += read_adc(channels[measure_position][channel]);
mid_cal[measure_position][channel] = floor(0.5f + mid/((float)CAL_AVG));
printf("Midpoint Cal: %d: %u\r", channel, mid_cal[measure_position][channel]);
}
void main(void)
{
PORTB=0xFF;
DDRB=0xF8;
PORTD=0xFF;
DDRD=0x00;
TCCR1A=0x00;
TCCR1B=0b00001011;
OCR1A=250; OCR1B=0x0000;
TIMSK=0x10;
UCSRA=0x00;
UCSRB=0x18;
UCSRC=0x06;
UBRRH=0x00;
UBRRL=0x67;
ACSR=0x80;
SFIOR=0x00;
ADMUX=ADC_VREF_TYPE;
ADCSR=0x8F;
lcd_init(16);
lcd_clear();
lcd_gotoxy(6,0);
lcd_putsf("| |");
lcd_gotoxy(0,1);
lcd_putsf("- - sense:");
lcd_gotoxy(13,1);
lcd_putsf("- -");
mid_cal[0][0] = mid_cal_store[0][0];
mid_cal[0][1] = mid_cal_store[0][1];
mid_cal[1][0] = mid_cal_store[1][0];
mid_cal[1][1] = mid_cal_store[1][1];
#asm("sei")
while (1)
{
if(acc_cnt == 0) tsk_poll_accelerometers();
if(but_cnt == 0) tsk_buttons();
if(lcd_cnt == 0) tsk_lcd_update();
};
}