'RC조종기자작-완성'에 해당되는 글 4건

  1. 2012.03.01 자작 조종기..
  2. 2012.03.01 자작 조종기 완성..
  3. 2010.07.31 추천 RF 모듈 - 코로나 2.4g DSSS V2
  4. 2010.07.31 자작 조종기.. 소스 코드

자작 조종기..

버드류의 2채널 델지를 날리다 보니, 한손에 쏙 들어오는 조그마한 조종기가 있었으면 좋겠다는 생각을 하게 됐네요.

 

더군다나 요즘처럼 날씨가 추운경우에 도라에몽처럼 손 하나를 감싸는 털뭉치 안에 조종기가 들어오면 손이 시렵지도 않겟지요.

 

어쨌든 웹질중에 찾아낸 rf 모듈입니다.

 

http://www.hobbycity.com/hobbycity/store/uh_viewItem.asp?idProduct=9770&Product_Name=Corona_2.4Ghz_DIY_Module_&_RX_(DSSS)_

 

수신기가 23불 정도이므로 송신 모듈은 그야말로 저렴 그 자체군요.

 

게다가 ppm 신호만 넣어주면 된답니다.

 

그래서 한번 제작해봣습니다 ㅎㅎ

 




얼마전에 지른 키캠을 입에 물고 찍었네요; 많이 흔들립니다.

 

칩은 가장 만만한 atmega128 을 사용햇네요.

 

컨트롤은 3개이나 6채널까지 지원되구요. (모터 달린 델타익기 정도? 혹은 이지스타 정도..?)

 

믹싱을 마음껏 할 수 있습니다;

 

아직 프로그래밍을 끝낸 상태는 아니고 틈틈히 20 프로 정도 했습니다.

 

신호 잘가는지 확인만 한 정도 인데,, 요즘 영 취미를 위한 시간 내기가 어렵네요.

 

연말이라 일이 바쁩니다. ㅎㅎ

 

자작 조종기 완성..

네이버 카페에 쓴글인데 블로그에 없어서 퍼온다.

연초에 시작했던걸 질질 끌어오다가 어떻게든 마무리해야겠다는 마음에
오늘 잠깐 짬을 냈습니다. 생업이 바쁘다보니....



3채널이고.. 대략 20미터까진 테스트해봤습니다. 실내라서 더이상 테스트는 못하구요..
필드에 한번 가져가봐야죠.
버드에 탑재해볼 예정입니다.
   

추천 RF 모듈 - 코로나 2.4g DSSS V2



2.4G 주파수! 8채널 수신기 및 안테나와 함께 가격은 단돈 29 달러.(와! 싸다!)

 

이 모듈은 7pin 의 in-out 을 갖는다.

 

바인딩용 4채널 커넥터 : led1, led2, tack-switch,gnd

ppm 용 3채널 커넥터 : vcc,gnd,ppm

 

다만 전원은 대략 리폴 3셀을 물려주면 되며,

ppm 레벨 또한 전원 레벨과 같아야한다.

다시 말해 1 : vcc, 0 : gnd 로 넣어줘야 한다.

 

어쨌든 가장 복잡한 부분이 쉽게 해결되었다.

 

다만 모듈에 안테나를 땜질해줘야 하므로 적어도 인두와 땜납이 필요하며 간단한 인두질은 할 줄 알아야 하겠다.

 

자작 조종기.. 소스 코드

#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;
}
prev 1 next