#include <mega128.h>
#include <stdio.h>
#asm //인터럽트 enable에 관련
.equ __lcd_port=0x12 ;PORTD
#endasm
#include <lcd.h>
#include <delay.h>
void Go_Ahead(int v, int p);
void Turn_Left(int v, int angle);
void Turn_Right(int v, int angle);
void Turn(int v,int angle);
void Stop(int delay);
void Key_Input(void);
void Run(void);
void Run_Test(void);
void Run_Run(void);
void Run_Servo_Motor(void);
void Run_DC_Motor(void);
void Test_Mode(void);
void Run_Mode(void);
int i, j, Velocity, Pulse, Angle; //속도, 펄스(펄스 ∝ 속도), 앵글 변수 선언
int switch1, switch2,switch3;
int switch1_cht, switch2_cht, switch3_cht;
interrupt [TIM1_COMPA] void step_motor_1(void) //timer interupt로 시간에 따라 호출 됨
{
i++;
}
interrupt [TIM3_COMPA] void step_motor_2(void)
{
j++; //외부 인터럽트로 j값을 증가시킴, j값의 초기화는 이루어 지나 제어문 등에는 사용되는 것이 보이지 않음.
}
interrupt [TIM1_COMPB] void servo_motor_1(void)
{
}
interrupt [EXT_INT5] void external_int5(void) //switch1 = 0 : Test Mode, switch1 = 1 : Run Mode,
{ //switch1 = 2 : Servo motor Mode, switch1 = 3 : DC motor Mode
switch1_cht++;
if (switch1_cht > 1)
{
switch1++;
switch1_cht = 0;
delay_ms(10);
}
if(switch1 == 4)
{
switch1 = 0;
}
}
interrupt [EXT_INT6] void external_int6(void)
{
switch2_cht ++;
if (switch2_cht > 1)
{
switch2++;
switch2_cht = 0;
delay_ms(10);
}
if(switch2 == 10)
{
switch2 = 0;
}
}
interrupt [EXT_INT7] void external_int7(void)
{
switch3_cht ++;
if (switch3_cht > 1)
{
switch3++;
switch3_cht = 0;
delay_ms(10);
}
if(switch3 == 2)
{
switch3 = 0;
}
}
void Go_Ahead(int v,int p)
{
OCR1A = v;//velocity와 pulse
OCR3AH = 0;
OCR3AL = v;
i=0;
while(1)
{
if(i>=p) // 인터럽트 증가에 따라 i가 증가, i에 따라 pulse 만큼 유지
{
i = 0;
break;
}
}
}
void Turn_Left(int v,int angle)
{
PORTA = 0b00000000;
OCR1A = v;
OCR3AH = 0;
OCR3AL = v;
i=0;
while(1)
{
if(i>=angle)
{
j = 0;
PORTA = 0b00000010;
break;
}
}
}
void Turn_Right(int v,int angle)
{
PORTA = 0b00000011;
OCR1A = v;
OCR3AH = 0;
OCR3AL = v;
i=0;
while(1)
{
if(i>=angle+2)
{
j = 0;
PORTA = 0b00000010;
break;
}
}
}
void Turn(int v, int angle)
{
PORTA = 0b00000000;
OCR1A = v;
OCR3AH = 0;
OCR3AL = v;
i=0;
while(1)
{
if(i >= angle * 2 + 4)
{
j = 0;
PORTA = 0b00000010;
break;
}
}
}
void Stop(int delay)
{
delay_ms(delay);
}
void Init_Port(void)
{
DDRA = 0b00000011;
DDRB = 0b00100000;
DDRE = 0b00001000;
PORTA = 0b00000010;
OCR1A = 0xFFFF;
OCR3AH = 0xFF;
OCR3AL = 0xFF;
}
void Init_Timer(void)
{
TIMSK = 0x10; //Timer/Counter1, Output Compare A Match Interrupt Enable
ETIMSK = 0x10; //Timer/Counter3, Output Compare A Match Interrupt Enable
TCCR1A = 0x40;
TCCR1B = 0x0d;
TCCR3A = 0x40;
TCCR3B = 0x0d;
}
void Init_ext_int(void)
{
EICRB = 0b10101000; //INT5,INT6,INT7을 falling edge로 설정
EIMSK = 0b11100000; //INT5,INT6,INT7 인에이블 설정
}
void Init_System(void) // 각 값 초기화
{
Init_Port();
Init_Timer();
Init_ext_int();
lcd_init(16);
delay_ms(10);
SREG = 0x80; // Global int enable
}
void Key_Input(void)
{
while(1)
{
lcd_gotoxy(0,13);
lcd_putchar(switch2 + 48);
if(switch1 == 0)
{
lcd_gotoxy(0,0);
lcd_putsf("Test Mode "); //값이 0이면, Test Mode 란 글자를 보여준다.
}
else if(switch1 == 1)
{
lcd_gotoxy(0,0);
lcd_putsf("Run Mode ");//값이 1이면, Test Mode 란 글자를 보여준다.
}
else if(switch1 == 2)
{
lcd_gotoxy(0,0);
lcd_putsf("Servo motor");//값이 2이면, Test Mode 란 글자를 보여준다.
}
else if(switch1 == 3)
{
lcd_gotoxy(0,0);
lcd_putsf("DC motor ");//값이 3이면, Test Mode 란 글자를 보여준다.
}
if(switch3 == 1)
{
break;
}
}
}
void Run_Run(void)
{
Velocity = 50;
Pulse = 4700 ;
Go_Ahead(Velocity,Pulse);
Turn_Left(Velocity,Angle);
Go_Ahead(Velocity,Pulse);
Turn_Left(Velocity,Angle);
Go_Ahead(Velocity,Pulse);
Turn_Left(Velocity,Angle);
Go_Ahead(Velocity,Pulse);
Turn(Velocity,Angle);
Go_Ahead(Velocity,Pulse);
Turn_Right(Velocity,Angle);
Go_Ahead(Velocity,Pulse);
Turn_Right(Velocity,Angle);
Go_Ahead(Velocity,Pulse);
Turn_Right(Velocity,Angle);
Go_Ahead(Velocity,Pulse+100);
DDRB = 0b00000000;
DDRE = 0b00000000;
}
void Run_Test(void)
{
while(1)
{
Go_Ahead(Velocity,Pulse); //속도와 펄스에 따라 실행
Turn_Left(Velocity,Angle); //속도와 앵글에 따라 실행
}
}
void Run_Mode(void) //switch2값에 따라 앵글을 지정한다
{
if (switch2 == 0)
{
Angle = 190;
}
else if(switch2 == 1)
{
Angle = 192;
}
else if(switch2 == 2)
{
Angle = 194;
}
else if(switch2 == 3)
{
Angle = 195;
}
else if(switch2 == 4)
{
Angle = 196;
}
else if(switch2 == 5)
{
Angle = 197;
}
else if(switch2 == 6)
{
Angle = 199;
}
else if(switch2 == 7)
{
Angle = 201;
}
else if(switch2 == 8)
{
Angle = 203;
}
else if(switch2 == 9)
{
Angle = 205;
}
}
void Run_Servo_Motor(void)
{
unsigned int sign = 0; // 0 -> (-) , 1 -> (+)
unsigned int dir = 0; // 0 : increse , 1 : decrease // 모터의 방향에 관한 변수
unsigned char sign_d = 0b00101101; // initialization = -
unsigned char ten_d = 0b00111001; // initialization = 9
unsigned char one_d = 0b00110000; // initialization = 0
DDRB = 0b01000000; //PB6
TIMSK = 0b00001000; //Timer/Counter1, Output Compare B Match Interrupt Enable
TCCR1A = 0b00100010; //Clear OCnA/OCnB/OCnC on compare match, set OCnA/OCnB/OCnC at BOTTOM(non-inverting mode)
//Fast PWM mode(Bit1,0)
TCCR1B = 0b00011011; //Fast PWM mode(Bit4,3)
//clkI/O/64 (From prescaler)
//16Mhz/64 = 250000 Hz
ICR1 = 5000; //Period(250000/5000 = 50 Hz)
OCR1B = 174; //initialization : Pulse Width(250000/175 = 1428.57 Hz = 0.7ms , -90degree)
lcd_init(16); // init 16*2 LCD
delay_ms(50);
lcd_gotoxy(0,0); //출력 좌표지정
lcd_putsf("HOMEWORK");
lcd_gotoxy(0,1);
lcd_putsf("Degree is = ");
lcd_gotoxy(12,1);
lcd_putchar(sign_d);
lcd_gotoxy(13,1);
lcd_putchar(ten_d);
lcd_gotoxy(14,1);
lcd_putchar(one_d);
delay_ms(50);
while(1) //PWM 파형으로 SEOVO MOTOR 제어
{
if (dir == 0) OCR1B = OCR1B + 11; //-90 to 90 , unit 5 degree increase
else OCR1B = OCR1B - 22; //90 to -90 , unit 5 degree decrease
if ( 370 >= OCR1B ) sign = 0; // sign : (-)
else sign = 1; // sign : (+)
if ( OCR1B <= 174 || OCR1B >= 570 ) ten_d = 0b00111001; //9
else if ( (OCR1B <= 196 && OCR1B >= 185) || (OCR1B <= 559 && OCR1B >= 548) ) ten_d = 0b00111000; //8
else if ( (OCR1B <= 218 && OCR1B >= 207) || (OCR1B <= 537 && OCR1B >= 526) ) ten_d = 0b00110111; //7
else if ( (OCR1B <= 240 && OCR1B >= 229) || (OCR1B <= 515 && OCR1B >= 504) ) ten_d = 0b00110110; //6
else if ( (OCR1B <= 262 && OCR1B >= 251) || (OCR1B <= 493 && OCR1B >= 482) ) ten_d = 0b00110101; //5
else if ( (OCR1B <= 284 && OCR1B >= 273) || (OCR1B <= 471 && OCR1B >= 460) ) ten_d = 0b00110100; //4
else if ( (OCR1B <= 306 && OCR1B >= 295) || (OCR1B <= 449 && OCR1B >= 438) ) ten_d = 0b00110011; //3
else if ( (OCR1B <= 328 && OCR1B >= 317) || (OCR1B <= 427 && OCR1B >= 416) ) ten_d = 0b00110010; //2
else if ( (OCR1B <= 350 && OCR1B >= 339) || (OCR1B <= 405 && OCR1B >= 394) ) ten_d = 0b00110001; //1
else ten_d = 0b00100000;
if (dir==0)
{
if (one_d == 0b00110000) one_d = 0b00110101; //one digit : repeat 0 and 5
else one_d = 0b00110000;
}
else one_d = 0b00110000;
if ( OCR1B >= 570 && dir == 0) dir = 1;
if ( OCR1B <= 174 && dir == 1) dir = 0;
if (sign == 0) sign_d = 0b00101101; //sign = 0 -> LCD -
else sign_d = 0b00100000; //sign = 1 -> LCD
lcd_gotoxy(0,0); //출력 좌표지정
lcd_putsf("HOMEWORK");
lcd_gotoxy(0,1);
lcd_putsf("Degree is = ");
lcd_gotoxy(12,1);
lcd_putchar(sign_d);
lcd_gotoxy(13,1);
lcd_putchar(ten_d);
lcd_gotoxy(14,1);
lcd_putchar(one_d);
delay_ms(500);
}
}
void Run_DC_Motor(void)
{
int g;
DDRB = 0b00100000;
TIMSK = 0b00010000; //Timer/Counter1, Output Compare A Match Interrupt Enable
TCCR1A = 0b10000010; //Clear OCnA/OCnB/OCnC on compare match, set OCnA/OCnB/OCnC at BOTTOM(non-inverting mode)
//Fast PWM mode(Bit1,0)
TCCR1B = 0b00011011; //Fast PWM mode(Bit4,3)
//clkI/O/64 (From prescaler)
//16Mhz/64 = 250000 Hz
ICR1 = 5000; //Period(250000/5000 = 50 Hz)
OCR1B = 174; //initialization : Pulse Width(250000/175 = 1428.57 Hz = 0.7ms , -90degree)
#asm("sei")//인터럽트 enable
while(1)
{
delay_ms(500);
for (g=0; g<50; g++) //속도 증가
{
OCR1A = OCR1A + 100;
delay_ms(100);
}
delay_ms(4000);
for (g=0; g<50; g++) /속도 감소
{
OCR1A = OCR1A - 100;
delay_ms(100);
}
delay_ms(5000);
}
}
void Run(void) // 각 값에 따라 각 함수 실행
{
while(1)
{
switch(switch1){
case 0: Test_Mode();
Run_Test();
break;
case 1: Run_Mode();
Run_Run();
break;
case 2: Run_Servo_Motor();
break;
case 3: Run_DC_Motor();
break;
}
}
}
void Test_Mode(void)
{
Velocity = 50; // 속도와 펄스 값 지정
Pulse = 300 ;
if (switch2 == 0) // switch2 값에 따른 각도 값 지정
{
Angle = 195;
}
else if(switch2 == 1)
{
Angle = 196;
}
else if(switch2 == 2)
{
Angle = 197;
}
else if(switch2 == 3)
{
Angle = 198;
}
else if(switch2 == 4)
{
Angle = 199;
}
else if(switch2 == 5)
{
Angle = 200;
}
else if(switch2 == 6)
{
Angle = 201;
}
else if(switch2 == 7)
{
Angle = 202;
}
else if(switch2 == 8)
{
Angle = 203;
}
else if(switch2 == 9)
{
Angle = 204;
}
}
void main(void)
{
Init_System();
while(1)
{
Key_Input(); // key값을 입력 받는다.
Run(); // Run함수 실행
}
}
서보 모터로 돌아가는 각도 표시하고 DC 모터로 순간 가속 시키고 스텝 모터로 2m 정사각형을 한번 돌고 다시 역순으로 돌아오는 프로그램이 |
댓글 달기