자작 조종기.. 소스 코드

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>

#define sbi(PORT,BIT)  PORT|=_BV(BIT)  //set bit
#define cbi(PORT,BIT)  PORT&=~_BV(BIT)  //clear bit



#include "lcd.h"

#define PARAM_LENGTH  4
typedef struct _eepromdata {
int8_t trim1;
int8_t trim2;
int8_t rev1;
int8_t rev2;
} EEP_data;

volatile EEP_data g_param;


volatile uint8_t g_timer = 0;

#define CHANNEL_NUM 8




#define  MINIMUM_VOLT  100



volatile uint8_t send_state = 0;
volatile uint16_t ch[CHANNEL_NUM];
volatile int16_t ch1,ch2,ch3;


volatile uint8_t g_model = 1;
volatile uint8_t g_buff1[10] = "M1,00.0V ";
volatile uint8_t g_buff2[10] = "000v000v ";



void DefaultParam()
{
g_param.trim1 = 0;
g_param.trim2 = 0;
g_param.rev1 = 0;
g_param.rev2 = 0;
}

volatile uint16_t g_volt = 37;

#define MAX_VAL (200)
#define MIN_VAL (-200)

void ReadADC()
{
uint16_t tmp;

int16_t t;
int16_t tmp1;
int16_t tmp2;
int16_t tmp3;

// control1, control2
ADMUX = 0x40;
ADCSR |= 0x40;
while((ADCSR&0x10)== 0x00);
ADCSR |= 0x10;
tmp = (ADCL+(ADCH<<8));
tmp1 = (tmp>>1) - 255 + g_param.trim1*2;




ADMUX = 0x41;
ADCSR |= 0x40;
while((ADCSR&0x10)== 0x00);
ADCSR |= 0x10;
tmp = (ADCL+(ADCH<<8));
tmp2 = (tmp>>1) - 255 + g_param.trim2*2;



ADMUX = 0x42;
ADCSR |= 0x40;
while((ADCSR&0x10)== 0x00);
ADCSR |= 0x10;
tmp = (ADCL+(ADCH<<8));
tmp3 = (tmp>>1)  - 255;




ADMUX = 0x43; // WATCH power
ADCSR |= 0x40;
while((ADCSR&0x10)== 0x00);
ADCSR |= 0x10;
tmp = (ADCL+(ADCH<<8));
g_volt = tmp /100 * 115 / 6;


if(g_model == 4) { // elevon 
t = tmp1 + tmp2;
if(t > MAX_VAL) ch1 = MAX_VAL;
else if(t < MIN_VAL) ch1 = MIN_VAL;
else ch1 = t;

t = tmp1 - tmp2;
if(t > MAX_VAL) ch2 = MAX_VAL;
else if(t < MIN_VAL) ch2 = MIN_VAL;
else ch2 = t;


} else {
if(tmp1 > MAX_VAL) ch1 = MAX_VAL;
else if(tmp1 < MIN_VAL) ch1 = MIN_VAL;
else ch1 = tmp1;

if(tmp2 > MAX_VAL) ch2 = MAX_VAL;
else if(tmp2 < MIN_VAL) ch2 = MIN_VAL;
else ch2 = tmp2;

}

if(g_param.rev1) ch1 = ch1*(-1);
if(g_param.rev2) ch2 = ch2 * (-1);


ch3 = tmp3;


ch[0] = 0xffff - 1500 + (ch1) * 3;
ch[1] = 0xffff - 1500 + (ch2) * 3;
ch[2] = 0xffff - 1500 + (ch3) * 3;

ch[3] = 0xffff - 1500;
ch[4] = 0xffff - 1500;
ch[5] = 0xffff - 1500;
ch[6] = 0xffff - 1500;
ch[7] = 0xffff - 1500;
}

#define TIMER3_ON sbi(ETIMSK,TOIE3)
#define  TIMER3_OFF cbi(ETIMSK,TOIE3)



SIGNAL(SIG_OVERFLOW1)
{
asm volatile("cli"); 
TCNT1 = 0xffff - 20000; // 20ms
send_state = 0;
TCNT3 = 0xfffe; // imediately
TIMER3_ON;
PORTA = 1;

asm volatile("sei"); 

if(g_timer) g_timer--;
}




SIGNAL(SIG_OVERFLOW3)
{
TCNT3 = ch[send_state];
PORTA = 0;
delay_us(50); // wait 100us
PORTA = 1;

send_state++;
if(send_state == CHANNEL_NUM) {
send_state = 0;
TIMER3_OFF;
}
}





void DisplayInfo()
{
g_buff1[1] = g_model + '0';

g_buff1[3] = g_volt/100 + '0';
g_volt = g_volt % 100;
g_buff1[4] = g_volt/10 + '0';
g_buff1[6] = g_volt%10 + '0';
LCD_puts(LCD_LINE1,(uint8_t*)g_buff1);

g_buff2[0] = ch1/100 + '0';
ch1 = ch1 % 100;
g_buff2[1] = ch1/10 + '0';
g_buff2[2] = ch1%10 + '0';

g_buff2[4] = ch2/100 + '0';
ch2 = ch2 % 100;
g_buff2[5] = ch2/10 + '0';
g_buff2[6] = ch2%10 + '0';
LCD_puts(LCD_LINE2,(uint8_t*)g_buff2);
}


volatile uint8_t g_buff3[10] = "CHN INFO ";
volatile uint8_t g_buff4[10] = "1N T:    ";


void DisplayChannel(int ch)
{
int8_t t;
if(ch == 1) {
g_buff4[0] = '1';
if(g_param.rev1) g_buff4[1] = 'R';
else g_buff4[1] = 'N';

if(g_param.trim1 < 0) {
g_buff4[5] = '-';
t = g_param.trim1 * -1;
} else {
g_buff4[5] = ' ';
t = g_param.trim1;
}

} else {
g_buff4[0] = '2';
if(g_param.rev2) g_buff4[1] = 'R';
else g_buff4[1] = 'N';

if(g_param.trim2 < 0) {
g_buff4[5] = '-';
t = g_param.trim2 * -1;
} else {
g_buff4[5] = ' ';
t = g_param.trim2;
}

}

g_buff4[6] = t/10 + '0';
g_buff4[7] = t%10 + '0';
LCD_puts(LCD_LINE1,(uint8_t*)g_buff3);
LCD_puts(LCD_LINE2,(uint8_t*)g_buff4);
}



int main()
{
uint8_t button;
asm volatile("cli"); 


sbi(TCCR1B,CS11); // clk/8 -> 1Mhz 1us timer..
sbi(TCCR3B,CS31);



TIMSK = 0X04; // timer1, overfow

DDRA = 0x01;
DDRB = 0Xff; // output for alarm
DDRC = 0Xff;
DDRG = 0x07;
DDRD = 0x2;
DDRE = 0x00;
PORTA = 0x1;

ADCSR = 0X84; 

LCD_init();
LCD_puts(LCD_LINE1,(uint8_t*)"3Ch v0.2 ");
LCD_puts(LCD_LINE2,(uint8_t*)"Kim Hyuk ");
delay_ms(250);
// EIFR |= 0X03;

g_model = eeprom_read_byte((void*)0);

if((uint8_t)g_model == 0xff) { // never read before..
g_model = 1;
}

if((PINE & 0Xf0) == 0x10){ // setup model 1
g_model = 1;
eeprom_write_byte((uint8_t*)0,g_model);
while((PINE & 0Xf0) == 0); // wait until button release..
}else if((PINE & 0Xf0) == 0x20)  { // 
g_model = 2;
eeprom_write_byte((uint8_t*)0,g_model);
while((PINE & 0Xf0) == 0); // wait until button release..
}else if((PINE & 0Xf0) == 0x40)  { // 
g_model = 3;
eeprom_write_byte((uint8_t*)0,g_model);
while((PINE & 0Xf0) == 0); // wait until button release..
}else if((PINE & 0Xf0) == 0x80)  { //  elevon mixing
g_model = 4;
eeprom_write_byte((uint8_t*)0,g_model);
while((PINE & 0Xf0) == 0); // wait until button release..
}




eeprom_read_block((void*)&g_param,(void*)(g_model*PARAM_LENGTH),PARAM_LENGTH);

if((uint8_t)(g_param.trim1) == 0xff) DefaultParam(); // never read before



ReadADC();
DisplayInfo();

asm volatile("sei");


TCNT1 = 0xffff - 20000; // 50Hz


while(1) { // start routine..

ReadADC();

if(PINE&0xf0) { // memorize when button pushed..
button |= (PINE & 0xf0);


} else { // handle when button released..

if(button != 0) {
if((button & 0xf0) == 0x10) { // button1
g_param.trim1++;
if(g_param.trim1 > 40) g_param.trim1 = 40; // MAXIMUM
DisplayChannel(1);
} else if((button & 0xf0 )== 0x20) { // BUTTTON 2
g_param.trim1--;
if(g_param.trim1 < -40) g_param.trim1 = -40; // MINIMUM
DisplayChannel(1);
} else if((button & 0xf0) == 0x40) { // BUTTON 3
g_param.trim2++;
if(g_param.trim2 > 40) g_param.trim2 = 40;
DisplayChannel(2);
} else if((button & 0xf0) == 0x80) { // BUTTON 3
g_param.trim2--;
if(g_param.trim2 < -40) g_param.trim2 = -40;
DisplayChannel(2);

} else if((button & 0xf0) == 0x30) { // both button 1,2
g_param.rev1 = 1 - g_param.rev1;
DisplayChannel(1);

} else if((button & 0xf0) == 0xC0) { // both button 3,4
g_param.rev2 = 1 - g_param.rev2;
DisplayChannel(2);
}

button = 0;
g_timer = 100; // show during 3 sec..
// eeprom_write_block((void*)&g_param,(void*)(g_model*PARAM_LENGTH),PARAM_LENGTH);

}

if(g_volt < MINIMUM_VOLT) { // low batter allert
if(g_timer == 0) {
cbi(PORTB,3); // turn on alaram during 1 sec
} else if(g_timer == 50) {
sbi(PORTB,3); // turn off alaram during 1 sec
}
}

if(g_timer == 1) {
DisplayInfo();
}
}
}
return 0;
}