'조종기'에 해당되는 글 1건
- 2010.07.31 자작 조종기.. 소스 코드
자작 조종기.. 소스 코드
RC조종기자작-완성 2010. 7. 31. 12:50
#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;
}