BASIC4MCU | 질문게시판 | atmega128 각종 센서와 블루투스 USART관련 질문입니다!
페이지 정보
작성자 seojc 작성일2020-09-07 22:42 조회6,290회 댓글0건본문
안녕하세요 컨트롤러를 이용하여 RC카를 제어하려고 하는 학생입니다!
컨트롤러에서 3개 스위치를 이용하여 RC카를 각각
1. MPU6050을 이용한 각도제어모드
2. 조이스틱을 이용한 제어모드
3. 초음파를 이용한 자율주행 모드
로 세가지 방법으로 스위치를 이용하여 블루투스로 신호를 보내어 나타내려합니다! (예를 들어 스위치1,2,3중 1을 누르면 1번모드 2를 누르면 2번모드 3을 누르면 3번모드식입니다)
여기서 문제가 생겼습니다
USART(블루투스)로 신호를 보내는데 신호가 처음에는 잘 가다가 몇번 신호를 보내면 막혀 컨트롤러에서 스위치와 CLCD가 멈춰버립니다..
원인을 찾다찾다 모르겠어서 질문을 올립니다ㅠㅠ 제 예상으로는 RC카 부분 USART에서 인터럽트를 쓰지 않고 while문에서 그대로 신호를 받다보니 이런 문제점이 생긴거같기도하고
USART문제가 아니라 switch문이나 스위치에 문제가 있는거 같기도 하고.. 아니면 하드웨어적으로 문제가 있는거 같기도하고..(스위치로 신호를 보내었을때 될때도 있고 안될때도 있어서 제일 가능성이 낮은 원인입니다)
도와주시면 감사하겠씁니다 ㅠㅠㅠ
----------------컨트롤러 부분 코딩입니다-------------------------------------
#define F_CPU 8000000UL
#define FS_SEL 16.4
#include
#include
#include
#include
#include
#include#include "clcd_D8 (4).h"
unsigned char twi_read(char addressr);
void twi_write(unsigned char address,unsigned char data);
void USART_Transmit(unsigned char tx_data);
void USART_Transmit_init4(int data);
//void USART_Transmit1(unsigned char tx_data) ;
//void USART_Transmit_init1(int data);
void get_raw_data();
void calibrate();
void function_1(int sw);
unsigned short read_adc();
void init_adc1();
void init_adc2();
volatile double dt = 0.000;
volatile int temp;
volatile unsigned char a_x_l,a_x_h,a_y_l,a_y_h,a_z_l,a_z_h;
volatile unsigned char g_x_l,g_x_h,g_y_l,g_y_h,g_z_l,g_z_h;
volatile double bas_a_x,bas_a_y,bas_a_z;
volatile double bas_g_x,bas_g_y,bas_g_z;
volatile double a_x,a_y,a_z;
volatile double g_x,g_y,g_z;
volatile double las_angle_gx,las_angle_gy,las_angle_gz;
volatile double angle_ax,angle_ay,angle_az;
volatile double angle_gx,angle_gy,angle_gz;
volatile double roll,pitch,yaw;
volatile double alpha;
int main()
{
DDRB=0x00;
//UART
UCSR0A = 0x00;
UCSR0B = 0b00011000;
UCSR0C = 0b00000110;
UBRR0H = 0;
UBRR0L = 51; //9600
//TWI(I2C)
TWCR = (1<);<>
TWBR = 12; //400khz
//TIMER0
TCCR0 = (1<)|(1<
TCNT0 = 256-62; //125 번 => 0.002s
TIMSK = (1<);<>
//MPU6050 init
twi_write(0x6B, 0x00); //sleep 끔
_delay_ms(10);
twi_write(0x1A, 0x05); //DLPF 10Hz
calibrate();
clcd_port_init();
clcd_init_8bit();
clcd_command(CMD_DISPLAY_OPTION5);
SREG = 0x80;
while(1)
{
get_raw_data();
las_angle_gx = roll; //최근값 누적
las_angle_gy = pitch;
las_angle_gz = yaw;
temp = (a_x_h<<8) | a_x_l;
a_x = - temp;
temp = (a_y_h<<8) | a_y_l;
a_y = - temp;
temp = (a_z_h<<8) | a_z_l;
a_z = temp;
temp = (g_x_h<<8) | g_x_l;
g_x = temp;
temp = (g_y_h<<8) | g_y_l;
g_y = temp;
temp = (g_z_h<<8) | g_z_l;
g_z = temp;
g_x = (g_x - bas_g_x)/FS_SEL;
g_y = (g_y - bas_g_y)/FS_SEL;
g_z = (g_z - bas_g_z)/FS_SEL;
a_x = (a_x -bas_a_x);
a_y = (a_x -bas_a_y);
a_z = (a_x -bas_a_z);
angle_ax = atan(-1.000*a_y/sqrt(pow(a_x,2) + pow(a_z,2)))*180/3.141592;
angle_ay = atan(a_x/sqrt(pow(a_y,2) + pow(a_z,2)))*180/3.141592;
angle_gx = g_x*dt + las_angle_gx;
angle_gy = g_y*dt + las_angle_gy;
angle_gz = g_z*dt + las_angle_gz;
dt = 0.000;
alpha = 0.98;
roll = alpha*angle_gx + (1.000 - alpha)*angle_ax;
pitch = alpha*angle_gy + (1.000 - alpha)*angle_ay;
yaw = angle_gz;
function_1(PINB); //스위치용 //이 부분에서 function_1이라는 함수를 통해 switch문으로 들어갑니다
_delay_ms(10);
}
}
void function_1(int sw)
{
unsigned short value;
switch(sw)
{
case 0x01: //MPU6050용 //첫번쨰 스위치가 눌렸을때는 mpu6050이 아래와 같이 반응합니다
{
clcd_position(0,1); clcd_str("MPU6050 START");
if (roll <= -20)
{ PORTG=0x00;
USART_Transmit('8');
clcd_clear();
clcd_position(1,5); clcd_str("GO");
}
if (roll >= 20 )
{
USART_Transmit('2');
clcd_clear();
clcd_position(1,5); clcd_str("BACK");
}
if (pitch <= -20 )
{
USART_Transmit('4');
clcd_clear();
clcd_position(1,5); clcd_str("");
}
if (pitch >=20 )
{
USART_Transmit('6');
clcd_clear();
clcd_position(1,5); clcd_str("Right");
}
roll = 0;
pitch = 0;
break;
}
case 0x02: ///조이스틱용 //조이스틱 용으로 2번 스위치가 눌렸을 경우 조이스틱으로 반응합니다
{
clcd_position(0,1); clcd_str("JOYSTICK START");
PORTG=0x00;
init_adc1();
value = read_adc();
if (value <=5)
{
USART_Transmit('2');
clcd_clear();
clcd_position(1,5); clcd_str("Back");
}
if (value >= 1000)
{
USART_Transmit('8');
clcd_clear();
clcd_position(1,5); clcd_str("GO");
}
init_adc2();
value=read_adc();
if (value <=5)
{
USART_Transmit('4');
clcd_clear();
clcd_position(1,5); clcd_str("LEFT");
}
if (value >= 1000)
{
USART_Transmit('6');
clcd_clear();
clcd_position(1,5); clcd_str("RIGHT");
}
break;
}
case 0x04: //자율주행용 //자율주행용으로 스위치3번이 눌렸을때 이용합니다
{
PORTG=0x00;
USART_Transmit('0');
clcd_clear();
clcd_position(0,1); clcd_str("AUTOMODE START");
break;
}
case 0x0A:
case 0x09: //mpu6050, 조이스틱 정지용
{
USART_Transmit('5');
clcd_clear();
clcd_position(1,0);clcd_str("STOP");
break;
}
case 0x03:
{
USART_Transmit('5');
clcd_clear();
clcd_position(0,1); clcd_str("DONT PUSH");
break;
}
case 0x05:
{
USART_Transmit('5');
clcd_clear();
clcd_position(0,1); clcd_str("DONT PUSH");
break;
}
case 0x06:
{
USART_Transmit('5');
clcd_clear();
clcd_position(0,1); clcd_str("DONT PUSH");
break;
}
case 0x07:
{
USART_Transmit('5');
clcd_clear();
clcd_position(0,1); clcd_str("DONT PUSH");
break;
}
default:
{
PORTG=0xff;
USART_Transmit('5');
clcd_clear();
clcd_position(0,1); clcd_str("CHOICE MODE");
}
}
}
ISR(TIMER0_OVF_vect) //0.002s -----------------------mpu6050관련 코딩함수들입니다!------------------------------
{
dt += 0.002;
TCNT0 = 256-62;
}
void calibrate() //초기값 읽기
{
int cal = 10;
for(int i=0; i;>
{
get_raw_data();
temp = (a_x_h<<8) | a_x_l;
a_x += - temp;
temp = (a_y_h<<8) | a_y_l;
a_y += - temp;
temp = (a_z_h<<8) | a_z_l;
a_z += temp;
temp = (g_x_h<<8) | g_x_l;
g_x += temp;
temp = (g_y_h<<8) | g_y_l;
g_y += temp;
temp = (g_z_h<<8) | g_z_l;
g_z += temp;
_delay_ms(10);
}
a_x /= cal;
a_y /= cal;
a_z /= cal;
g_x /= cal;
g_y /= cal;
g_z /= cal;
bas_a_x = a_x; //초기 값으로 저장
bas_a_y = a_y;
bas_a_z = a_z;
bas_g_x = g_x;
bas_g_y = g_y;
bas_g_z = g_z;
}
void get_raw_data()
{
a_x_h = twi_read(0x3B); //x축 가속도
_delay_us(10);
a_x_l = twi_read(0x3C);
_delay_us(10);
a_y_h = twi_read(0x3D);
_delay_us(10); //y축 가속도
a_y_l = twi_read(0x3E);
_delay_us(10);
a_z_h = twi_read(0x3F);
_delay_us(10); //z축 가속도
a_z_l = twi_read(0x40);
_delay_us(10);
g_x_h = twi_read(0x43);
_delay_us(10); //x축 각속도
g_x_l = twi_read(0x44);
_delay_us(10);
g_y_h = twi_read(0x45);
_delay_us(10);
g_y_l = twi_read(0x46);
_delay_us(10);
g_z_h = twi_read(0x47);
_delay_us(10);
g_z_l = twi_read(0x48);
_delay_us(10);
}
void twi_write(unsigned char address,unsigned char data)
{
TWCR = (1<)|(1<
while(!(TWCR & (1<)));>
while((TWSR&0xF8) != 0x08); //START 상태(08) 기다림
TWDR = 0b11010000; //AD(1101000)+W(0)
TWCR = (1<)|(1<
while(!(TWCR & (1<))); <>
while((TWSR&0xF8) != 0x18); //SLA+W ACK 상태(18) 기다림
TWDR = address; //register address
TWCR = (1<)|(1<
while(!(TWCR & (1<)));<>
while((TWSR&0xF8) != 0x28); //Data ACK 상태(28) 기다림
TWDR = data; //data
TWCR = (1<)|(1<
while(!(TWCR & (1<)));<>
while((TWSR&0xF8) != 0x28);
TWCR = (1<)|(1<
}
unsigned char twi_read(char address)
{
unsigned char data;
TWCR = (1<)|(1<
while(!(TWCR & (1<)));>
while((TWSR&0xF8) != 0x08); //START 상태(08) 기다림
TWDR = 0b11010000; //AD(1101000)+W(0)
TWCR = (1<)|(1<
while(!(TWCR & (1<))); <>
while((TWSR&0xF8) != 0x18); //SLA+W ACK 상태(18) 기다림
TWDR = address; //register address
TWCR = (1<)|(1<
while(!(TWCR & (1<)));<>
while((TWSR&0xF8) != 0x28); //Data ACK 상태(28) 기다림
TWCR = (1<)|(1<
while(!(TWCR & (1<)));<>
while((TWSR&0xF8) != 0x10); //Repeat START 상태(08) 기다림
TWDR = 0b11010001; //AD(1101000)+R(1)
TWCR = (1<)|(1<
while(!(TWCR & (1<)));<>
while((TWSR&0xF8) != 0x40); //SLA+R ACK 상태(40) 기다림
TWCR = (1<)|(1<
while(!(TWCR & (1<)));<>
while((TWSR&0xF8) != 0x58); //ACK 상태(58) 기다림
data = TWDR;
TWCR = (1< )|(1<-----------------------mpu6050관련 코딩함수들입니다!------------------------------
return data;
}
void USART_Transmit(unsigned char tx_data) //USART0번으로 블루투스 송신을 할때 사용하였습니다
{
while(!(UCSR0A & (1<)));<>
UDR0 = tx_data;
}
/*
--------------------조이스틱을 위한 ADC 함수입니다-----------------------------
void init_adc1() //----1번
{
ADMUX=0X40; //0b01000000 <---- AVCC사용 오른쪽정렬 ADC0번 사용 , 싱글채널 인풋
ADCSRA=0X87; // 0b10000111 <---- ADC실행 가능, 128분주 사용
}
void init_adc2()
{
ADMUX =0X41;
ADCSRA=0X87;
}
unsigned short read_adc()// ------2번
{
unsigned char adc_low, adc_high;
unsigned short value;
ADCSRA |=0x40; // ADC시작
while((ADCSRA & 0x10) != 0x10); //반복실행을 한 후 위한것으로 ADC가 끝나면 플래그가 1로 set되어서 반복 종료
adc_low =ADCL;
adc_high=ADCH;
value =(adc_high << 8 ) | adc_low; //short 변수인 value에 adc 하이 로우 값을 넣는다
return value;
}
---------------------------------------------------------
---------------------------------------------------------
---------------RC카 부분 코딩입니다!-------------------------
#define F_CPU 8000000UL
#define BAUD 9600
#define U2X_S 2 // U2X 1 or 2
#define MYUBRR ((F_CPU*U2X_S)/(16L*BAUD)-1)
#define sbi(reg, bit) reg |= (1<<(bit))
#define cbi(reg, bit) reg &= ~(1<<(bit))
#include
#include
#include
#include
#include "USART_ch0.h"
void timer0_init(void);
void timer2_init(void);
void Go_Straight (void);
void Turn_Left (void);
void Turn_Right (void);
void Back (void);
void Stop (void);
volatile unsigned int buf[8],dist[8],start=0,end=0;
volatile unsigned char cnt=0,flag[8]={0,};
char ch ;
ISR(INT0_vect){ if(EICRA==0x03)start=TCNT1; else{ end=TCNT1; buf[0]=end-start; EIMSK=0; flag[0]=1; } EICRA^=0x01; }
ISR(INT1_vect){ if(EICRA==0x0C)start=TCNT1; else{ end=TCNT1; buf[1]=end-start; EIMSK=0; flag[1]=1; } EICRA^=0x04; }
ISR(INT4_vect){ if(EICRB==0x03)start=TCNT1; else{ end=TCNT1; buf[4]=end-start; EIMSK=0; flag[4]=1; } EICRB^=0x01; }
ISR(TIMER1_COMPA_vect)
{
switch(cnt){
case 0: PORTA|=0x01; _delay_us(10); PORTA&=~0x01; EICRA=0x03; EICRB=0x00; EIFR=0xFF; EIMSK=0x01; break;
case 1: PORTA|=0x02; _delay_us(10); PORTA&=~0x02; EICRA=0x0C; EICRB=0x00; EIFR=0xFF; EIMSK=0x02; break;
case 4: PORTA|=0x19; _delay_us(10); PORTA&=~0x10; EICRA=0x00; EICRB=0x03; EIFR=0xFF; EIMSK=0x10; break;
}
if(++cnt>4)cnt=0;
}
int main(void)
{
DDRE = 0x00;//echo 초음파 센서에 관련된 초기값입니다
DDRA = 0xFF;//trig 초음파 센서에 관련된 초기값입니다
TCCR1B=0x0C; OCR1A=1840; TIMSK=0x10; //8000000/256/(1+ 1840)=16.9744.. 초음파 센서에 관련된 초기값입니다
timer0_init();
timer2_init();
USART0_Init ( MYUBRR );
SREG=0x80;
while(1)
{
ch = U0_RX(); // USART_recevie(); ch를 이용하여 while문에서 값을 받았습니다
/////////////////
if (ch == '0') //0값을 받았을때는 초음파를 이용한 자율주행을 합니다
{
Go_Straight();
if(flag[0])
{ flag[0]=0; dist[0]=(int)((float)buf[0]/1.8125);
if (dist[0]<=5)
{
Back(); _delay_ms(500);
Stop();_delay_ms(100);
Turn_Right(); _delay_ms(500);
}
}
if(flag[1])
{ flag[1]=0; dist[1]=(int)((float)buf[1]/1.8125);
if (dist[1]<=5)
{
Back();_delay_ms(500);
Stop(); _delay_ms(100);
Turn_Right();_delay_ms(500);
}
}
if(flag[4])
{ flag[4]=0; dist[4]=(int)((float)buf[4]/1.8125);
if (dist[4]<=5)
{
Back();_delay_ms(500);
Stop();_delay_ms(100);
Turn_Left();_delay_ms(500);
}
}
}
/////////////////
if (ch == '8'){Go_Straight();} //각각 다른 값을 받았을때 앞뒤 좌우로 움직입니다
if (ch == '2'){Back();}
if (ch == '4'){Turn_Left();}
if (ch == '6'){Turn_Right();}
if (ch == '5'){Stop();}
/////////////////
}
}
void timer0_init(void){TCCR0 = 0b01101100;}
void timer2_init(void){TCCR2 = 0b01101011;}
void Turn_Right(void)
{
sbi(PORTB,4);
sbi(PORTB,2);
cbi(PORTB,3);
sbi(PORTB,7);
cbi(PORTB,0);
sbi(PORTB,1);
MP3_send_cmd(0X12,0,4);
}
void Turn_Left(void)
{
sbi(PORTB,4);
cbi(PORTB,2);
sbi(PORTB,3);
sbi(PORTB,7);
sbi(PORTB,0);
cbi(PORTB,1);
MP3_send_cmd(0X12,0,4);
}
void Go_Straight(void)
{
sbi(PORTB,4);
cbi(PORTB,2);
sbi(PORTB,3);
sbi(PORTB,7);
cbi(PORTB,0);
sbi(PORTB,1);
MP3_send_cmd(0X12,0,4);
}
void Back(void)
{
sbi(PORTB,4);
sbi(PORTB,2);
cbi(PORTB,3);
sbi(PORTB,7);
sbi(PORTB,0);
cbi(PORTB,1);
MP3_send_cmd(0X12,0,4);
}
void Stop(void)
{
cbi(PORTB,4);
cbi(PORTB,2);
cbi(PORTB,3);
cbi(PORTB,7);
cbi(PORTB,0);
cbi(PORTB,1);
}
정리한다고하였는데 코딩이 지져분하여 죄송합니다 ㅠㅠㅠ
제가 문제라고 생각하는 switch 구문(함수)와 USART(블루투스 통신)부분만 표시하였습니다(mpu6050,조이스틱,초음파 등 센서들은 작동 문제가 없는것을 각각 확인하였고 스위치를 통해 동작하는 것을 확인하였습니다,, 일단 각 센서구현은 됩니다! )
개인적으로 RC카(수신쪽)에서 while문에서 블루투스 신호를 받은것이 문제라고 생각하는데 어떠신가요 ㅠㅠ
스위치를 누를때 처음에는 잘 되는가 싶다가 중간부터 아에 먹통이 되버립니다 ㅠㅠ
일단 내일 학교 가자마자 바로 인터럽트 구문으로 바꾸어볼 생각입니다!!
컨트롤러 사진입니다
https://cafe.naver.com/circuitsmanual전자공작이라는 카페에서 (전자공작 키트님) 초음파 관련 코딩입니다
https://blog.naver.com/speedprinse/221187451092
임베디드 시스템 네이버 블로그에서 faust님의 mpu6050각도 관련글입니다!
댓글 0
조회수 6,290등록된 댓글이 없습니다.