Ⅲ. 코드 및 구현 내용
#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define OC1A_WIDTH OCR1A
#define OC1_PERIOD ICR1
// 실제 동작 clock hz를 설정하고, 코드구현에 앞서 AVR 기본 입출력관련 헤더파일과 지연함수 관련 헤더파일과 인터럽트 관련 헤더파일을 선언했다.
//이후, OC1A_WIDTH와 OC1_PERIOD를 각각 OCR1A와 1CR1로 정의합니다.
enum tone_scale
{
No, Do, Rae, Mi, Pa, Sol, Ra, Si_P, Si, Do_5, Rae_5
};
uint16_t frequency_return(uint16_t fre);
void tone(uint8_t scale, uint16_t delay);
uint16_t tone_array[11] = {0,1046,1174,1318,1396,1567,1760,1864,1975,2093,2349};
//enum함수를 사용하여 5옥타브 ‘도’부터 6옥타브 ‘레’까지 열거했다.
//PWM period to frequency를 정하는 frequency_return 함수를 정의해주며,
//tone함수를 정의하여 주파수와 duration에 따라 다른 음을 출력하도록 설정하였다.
void delay_ms(int ms)
{
while(ms-- != 0)
_delay_ms(1);
}
//tone 함수 내에서 delay함수에 대한 오류가 발생하여 해결하기 위한 방법으로 구글링을 통해 선언.
void Forward(uint8_t speed);
void Backward(uint8_t speed);
void Turn_left(uint8_t speed);
void Turn_right(uint8_t speed);
//Tekbot의 방향을 함수로 선언한다. 직진, 후진, 좌로 돌기, 우로 돌기
void BuzzerN();
void BuzzerS();
void BuzzerL();
void BuzzerR();
void BuzzerB();
//출발 전 두개의 스위치가 눌릴 경우, 출발할 경우, 왼쪽 스위치가 눌릴경우, 오른쪽 스위치가 눌릴 경우, 두개의 스위치가 동시에 눌릴 경우에 따른 Buzzer음을 각각 함수로 선언
ISR(TIMER3_OVF_vect)
{
PORTB =0b00001000;
PORTD =0b00000100;
delay_ms(250);
TCNT3 = 0xffff - 7812; // Every 1 second
}
// 인터럽트 서비스 루틴으로 인터럽트가 발생 시 수행하는 코드이다. ISR이 실행될 경우 두 바퀴가 서로 반대로 돌게 설정하여 delay 시간 만큼 회전을 한 후에
//TCNT3을 이용하여 다시 카운팅을 시작하게 만들어준다.
int main()
{
DDRB = 0b10101100;
DDRD = 0b00000111;
DDRF = 0b11111100;
PORTF=0b00000011;
TCCR0A = 0b11110001;
TCCR0B = 0b00000100;
TCCR1A = 0b10000000;
TCCR1B = 0b00010010;
TCCR3A = 0b00000000;
TCCR3B = 0b00000101;
TIMSK3 = 0b00000001;
// 왼쪽 바퀴와 오른쪽 바퀴의 EN와 DIR_A, DIR_B에 해당하는 핀을 OUTPUT으로 설정해주며, 왼쪽 스위치와 오른쪽 스위치에 해당하는 핀을 INPUT으로 설정했다. 이 후, PORTF를 통해 각각의 스위치를 풀업저항으로 설정하고 TCCR(Timer/Counter Control Register)를 이용해 TCCR0과 TCCR1에는 PWM모드와 분주비에 대해 설정하며 TCCR3에는 인터럽트를 사용하기 위한 모드와 분주비를 설정했다. 마지막으로 TIMSK로 노말모드를 Enable로 Set 하였다.
sei(); //모든 인터럽트 활성화
while(1)
{
if(!(PINF &(1<<0)) &&!(PINF &(1<<1)))
{
BuzzerN();
Forward(100);
BuzzerS();
TCNT3 = 0xffff-9000;
// PINF연산에 의해 두개의 스위치가 모두 눌릴경우 if문을 실행하게 된다. 그 외의 경우에는 다른 문을 실행하지 않는다.
// if문안에서는 BuzzerN()함수에 의해 음이 출력이 된 후 Forward함수에 의해 100의 속도로 직진동작을 수행한다. 이때 BuzzerS()함수가 실행되며 음 출력이 끝난 후 부터 타이머/카운팅이 시작된다.
while(1)
{
// 최초 if문이 실행 후 if문 안의 while문으로 들어와 무한 반복을 하게 되는데 이때, 왼쪽 스위치가 눌렸을 경우를 if문, 오른쪽 스위치가 눌렸을 경우를 else if문 아무것도 눌리지 않았을 경우를 else문으로 설정했다.
if(!(PINF &(1<<0)))
{
if(!(PINF &(1<<1)))
{
TCNT3 = 0xffff-9000;
Backward(190);
BuzzerB();
PORTB =0b00001000;
PORTD =0b00000100;
_delay_ms(90);
Forward(100);
}
else
{
TCNT3 = 0xffff-9000;
Backward(190);
BuzzerL();
Turn_left(100);
_delay_ms(100);
}
}
// 왼쪽 스위치가 눌릴 경우 if문에 오른쪽 스위치가 눌릴 경우와 else문에 눌리지 않았을 경우를 설정하여 동시 검출과 왼쪽 스위치만 검출, 두 가지 경우를 설정했다.
// 왼쪽 스위치가 눌리고 오른쪽 스위치도 눌릴 경우 설정한 TCNT부터 카운팅이 시작되며 그 동안 190의 속도로 후진하며 Buzzer음을 출력하고 이후 delay시간 만큼 회전을 하고 직진동작을 수행한다.
// 왼쪽 스위치만 눌렸을 경우에는 마찬가지로 설정한 TCNT값 부터 카운팅이 시작되며 후진동작과 BuzzerL음이 출력되며 이후, 왼쪽으로 약 90도 회전동작을 수행한다
else if(!(PINF &(1<<1)))
{
if(!(PINF &(1<<0)))
{
TCNT3 = 0xffff-9000;
Backward(190);
BuzzerB();
PORTB =0b00001000;
PORTD =0b00000100;
delay_ms(90);
Forward(100);
}
else
{
TCNT3 = 0xffff-13000;
Backward(190);
BuzzerR();
Turn_right(100);
delay_ms(115);
}
} //else if문
// 오른쪽 스위치가 눌릴 경우 왼쪽 스위치가 눌렸을 때와 동일하게 if문과 else문에 동시검출과 한쪽 스위치 검출을 설정하여 동시검출시 위와 동일한 동작을 수행하며, 오른쪽 스위치만 눌렸을 경우 설정한 TCNT 값부터 타이머/카운팅이 시작된다.
// 타이머/카운팅이 시작된 후 PWM에 의해 190의 속도만큼 후진동작과 BuzzerR음이 출력되며 오른쪽으로 약 90도 회전동작을 수행한다. 이 과정에서 타이머/카운팅이 0xffff에서 0x0000이 될 경우 오버플로우가 발생하여 인터럽트 서비스 루틴(ISR)이 실행하여 하던 동작을 멈추고 ISR함수를 실행한다.
else
Forward(100);
// 출발 후 스위치가 눌리지 않을 경우 Forward()함수를 실행해 직진동작만을 수행한다. 이때에도 ISR함수 내에서 타이머/카운터를 초기화해주었기 때문에 일정 시간이 지나면 인터럽트함수를 수행하게 된다.
}
}
}
return 0;
}
void Forward(uint8_t speed)
{
PORTB =0b00001000;
PORTD =0b00000010;
OCR0A = speed+58;
OCR0B = speed+25;
}
void Backward(uint8_t speed)
{
PORTB =0b00000100;
PORTD =0b00000100;
OCR0A = speed+10;
OCR0B = speed;
}
void Turn_left(uint8_t speed)
{
PORTB = 0b00000000;
PORTD = 0b00000010;
OCR0A = speed+50;
OCR0B = speed;
}
void Turn_right(uint8_t speed)
{
PORTB = 0b00001000;
PORTD = 0b00000000;
OCR0A = speed+50;
OCR0B = speed;
}
void tone(uint8_t scale, uint16_t delay)
{
OC1_PERIOD = frequency_return(tone_array[scale]);
OC1A_WIDTH = frequency_return(tone_array[scale])/20;
delay_ms(delay);
}
uint16_t frequency_return(uint16_t fre)
{
int8_t period_1 = 2; // period 2us
int set_period = 0;
int16_t return_fre = 0;
set_period = 1000000 / fre;
return_fre = set_period /period_1;
return return_fre;
}
void BuzzerN()
{
int dulation = 100;
tone(Mi, dulation);
tone(0, 60);
tone(Mi, dulation);
tone(0, 60);
tone(Mi, dulation);
tone(0, 60);
tone(Do_5, dulation+50);
}
void BuzzerS()
{
int dulation = 100;
tone(Sol, dulation+30);
tone(Mi, dulation-50);
tone(Sol, dulation+50);
tone(0, 60);
}
void BuzzerL()
{
int dulation = 30;
tone(Mi, dulation);
tone(0, 20);
tone(Sol, dulation);
tone(0 , 20);
tone(Sol, dulation);
tone(0 , 20);
tone(Mi, dulation);
tone(0, 0);
tone(Sol, dulation+50);
tone(0 , 20);
tone(Ra, dulation);
tone(0 , 20);
tone(Ra, dulation);
tone(0 , 20);
tone(Sol, dulation);
tone(0 , 20);
}
void BuzzerR()
{
int dulation = 50;
tone(Pa, dulation);
tone(0, 5);
tone(Pa, dulation);
tone(0, 5);
tone(Ra, dulation);
tone(0, 5);
tone(Ra, dulation);
tone(0, 5);
tone(Si_P, dulation+10);
tone(Ra, dulation);
tone(0, 5);
tone(Si_P, dulation);
tone(0, 5);
tone(Rae_5, dulation);
tone(0,
tone(Do_5, dulation);
tone(0, 5);
tone(Si_P, dulation);
tone(0, 10);
}
void BuzzerB()
{
int dulation = 50;
tone(Si, dulation);
tone(0 , 5);
tone(Ra, dulation);
tone(0 , 5);
tone(Si, dulation);
tone(0 , 5);
tone(Ra, dulation);
tone(0 , 5);
}
※구현 내용
1. 양 쪽 스위치를 누를 경우 BuzzerN 함수 실행 후 주행 시작
2. 주행 시작 후 BuzzerS 함수가 실행되며 앞으로 전진
3. 왼쪽 스위치가 눌릴 경우 BuzzerL 함수 실행과 동시에 뒤로 느리게 이동 후 왼쪽으로 회전 후 전진
4. 오른쪽 스위치가 눌릴 경우 BuzzerR 함수 실행과 동시에 뒤로 느리게 이동 후 오른쪽으로 회전 후 전진
5. 스위치 두개가 동시에 눌릴 경우 BuzzerB 함수 실행과 동시에 뒤로 느리게 이동 후 반 바퀴 회전을 하여 전진
6. 특정 시간이 지나면 타이머 카운터 인터럽트 발생(한 바퀴 회전)
Ⅳ. 문제점과 해결 방안
1. Tekbots 조립을 완료한 후 직진과 후진의 속도에 차이를 주기위해 PWM을 사용했으나 올바르게 작동하지 않았다.
=> PWM을 이용해 후진의 속도를 늦추는 코드를 구현하였지만 왼쪽 바퀴는 올바르게 작동하지만 오른쪽 바퀴는 PWM의 영향을 받지 않는 것을 발견하였고, 이에 따라 오른쪽 바퀴의 PWM을 결정하는 핀들의 납땜상태를 확인하고 재납땜을 하였으나 실패하여 모터컨트롤러보드와 Teensy보드를 처음부터 새로 정성들여 납땜을 하여 결과적으로 PWM이 정상적으로 작동하게 만들었다.
2. 코드 상으로는 서로 같으나 모터와 전류주입의 차이로 양 바퀴의 속도가 일정하지 않다.
=> 코드 구현 후 시범 주행을 하였을 때, 왼쪽 바퀴가 오른쪽 바퀴보다 빠르게 돌아 직진 시 오른쪽으로 휘는 현상이 발생하였고, 이를 코드상에서 OCR0A의 값을 변경(Speed+)시켜 양 바퀴의 속도를 비슷하게 만들었다.
3. tone함수 에러
=> 소리를 출력하기 위해 tone함수를 사용했으나 해결할 수 있는 방안이 떠오르지 않아 구글링을 하였고, 구글링을 통해 delay의 문제가 있다는 것을 식별하였고, delay함수를 따로 정의를 해주어 문제를 해결했다.
4. 버저소리 문제
=> 버저를 통해 나오는 소리가 USB를 컴퓨터와 연결하였을 때는 청아한 소리가 났으나 USB를 제거하는 순간 초저음의 소리가 출력되어 음을 식별하기 어려웠다. 그래서 tone의 주파수를 한 옥타브 올려 음을 식별할 수 있는 상태로 만들었다.
5. 시범 구동을 할 때마다 속도 및 인터럽트 발생시간, delay시간 등이 달라진다.
=> 컴퓨터와 USB를 연결한 상태로 코드를 구현하고 속도 및 인터럽트 시간 제어를 완료한 상태로 USB를 제거한 후 시범 구동을 했을 시 올바르게 작동하지 않았다. 전류 주입의 차이라고 생각하여 배터리를 새로 사서 갈아 끼웠으나 큰 차이가 나지 않아 코드 상의 값을 처음부터 새로 설정하여 구동 시범에서 올바르게 작동할 수 있게 하였다.
'Project > Arduino' 카테고리의 다른 글
| Arduino를 이용한Tekbot 구현하기[2](소프트웨어part) (0) | 2020.05.24 |
|---|---|
| Arduino를 이용한Tekbot 구현하기[1](하드웨어 part) (0) | 2020.05.24 |























