안녕하세요.
DC Motor를 PWM으로 제어를 하고자 하여 OCRB, OOCRC을 이용하여 제어를 하고 있습니다.
원하는 PWM이 출력이 되어 모터의 가감속과 방향을 바꾸어 가면서 제어가 되는데.
이상하게 Delay_ms()함수를 사용을 하면 전혀 동작을 하지 않네요.
혹 PWM의 time와 Delay_ms()와의 관계가 있는지 다른 설정이 필요한지에 대하여
고수님의 의견을 듣고자 합니다.
관련 소스와 회로도를 첨부 하여 드립니다.
프로그램이 다운로드 되지 않는 분을 위해 소스를 아래 추가 하여 드립니다.
#include <avr/io.h>
#include <avr/interrupt.h> #define F_CPU 8000000UL //CPU clock 설정 : 8MHz
#define PULSE_DUTY 1500000UL // 1500000ns = 1.5 ms (ns단위)
#define PULSE_WIDTH 20000000UL // 20000000ns = 20ms (ns 단위)
#define PULSE_CNT 50 // Pulse count. 한 번 command안에서 실행되는 펄스 갯수 volatile unsigned long clk_period = (uint16_t) (1000000000UL/F_CPU) * 8; // clkio/8 사용하므로 period는 x8
volatile uint8_t pulse_count = PULSE_CNT; volatile char nStopCheck = 0;
SIGNAL(TIMER3_COMPB_vect)
{
cli();
pulse_count--;
if(pulse_count == 0)
{
TCCR3A = 0x00;
TCCR3B = 0x00;
nStopCheck = 1;
}
sei();
} void init_CNT3()
{
DDRE |= 0x10; // PE4/OC3B output
DDRE |= 0x20; // PE4/OC3C output TCCR3A = 0x2B; // Counter 3, Channel B, Channel C, Compare Output Mode, Fast PWM
TCCR3B = 0x1A; // Waveform generation mode 15. clkio/8 clock 사용. OCR3A = (uint16_t) (PULSE_WIDTH/clk_period); // 20ms 주기 설정
OCR3B = (uint16_t) (PULSE_DUTY/clk_period); // default로 1.5ms 가운데
OCR3C = (uint16_t) (PULSE_DUTY/clk_period); // default로 1.5ms 가운데 ETIMSK = 0x0A; // Timer/Counter3, Output Compare B, Compare C Match Interrupt Enable sei();
} //////////////////////////////////////////////////////////////////////////////////////////////////
// Funtion : DCMove
//
// Description : DC 모터를 구동 시키는 함수
// (OCR3B, OCR3C를 이용하여 PWM을 출력하여 모터를 구동 시킴)
// Parameter :
// . nLeftMotorSpeed : Left DC motor 이동 속도 ( 0: 정지, 1~19 까지 가감속 지정 가능)
// . nLeftMotorDirection : Left DC motor 방향 설정 (1: Forward, 2: Backward)
// . nRightMotorSpeed : Right DC motor 이동 속도 ( 0: 정지, 1~19 까지 가감속 지정 가능)
// . nRightMotorDirection : Right DC motor 방향 설정 (1: Forward, 2: Backward)
//////////////////////////////////////////////////////////////////////////////////////////////////
void DCMove(char nLeftMotorSpeed, char nLeftMotorDirection,
char nRightMotorSpeed, char nRightMotorDirection)
{
if( nLeftMotorSpeed != 0 )
{
// 방향 설정 : DCMOTOR01_DIR (1<<5)
if( nLeftMotorDirection == 1 ) PORTA |= (1<<5); //Left DC Motor High(Forward)
else if( nLeftMotorDirection == 2 ) PORTA &= ~(1<<5); //Left DC Motor Low(Backward) OCR3B = (uint16_t) (1000000UL/clk_period) * nLeftMotorSpeed; // 1ms * Speed
} if( nRightMotorSpeed != 0 )
{
// 방향 설정 : DCMOTOR02_DIR (1<<7)
if( nRightMotorDirection == 1 ) PORTA |= (1<<7); //Right DC Motor High(Forward)
else if( nRightMotorDirection == 2 ) PORTA &= ~(1<<7); //Right DC Motor Low(Backward) OCR3C = (uint16_t) (1000000UL/clk_period) * nRightMotorSpeed; // 1ms * Speed
}
} void Delay_us(unsigned char time_us)
{
register unsigned char i; for(i = 0; i < time_us; i++) // 4 cycle +
{
asm volatile(" PUSH R0 "); // 2 cycle +
asm volatile(" POP R0 "); // 2 cycle +
asm volatile(" PUSH R0 "); // 2 cycle +
asm volatile(" POP R0 "); // 2 cycle +
asm volatile(" PUSH R0 "); // 2 cycle +
asm volatile(" POP R0 "); // 2 cycle +
}
} void Delay_ms(unsigned int time_ms)
{
register unsigned int i; for(i = 0; i < time_ms; i++)
{
Delay_us(250);
Delay_us(250);
Delay_us(250);
Delay_us(250);
}
}
int main(void)
{ init_CNT3(); DDRA = 0xFF; // PA4 ~ PA7 : (1<<4) | (1<<5) | (1<<6) | (1<<7)
PORTA = 0xFF; // DCMOTOR01_EN (1<<4), DCMOTOR02_EN (1<<6) DDRE |= (1<<PE4); // PE4 Output pin 설정
DDRE |= (1<<PE5); // PE5 Output pin 설정
PORTE &= ~0x10; // 초기 Low로 설정 하여 긴급 동작을 방지
PORTE &= ~0x20; // 초기 Low로 설정 하여 긴급 동작을 방지 pulse_count = PULSE_CNT; DDRD = 0xff;
OCR3B = 0;
OCR3C = 0; /*
// DCMove()함수가 않되어 일반적으로 LED를 On/Off하도록 하여 보았지만 아래 코드도
// 동작을 하지 않네요.
while(1)
{
PORTD = 0x00;
Delay_ms(500);
PORTD = 0xff;
Delay_ms(500);
}
*/
while(1)
{
DCMove(10, 1, 10, 2);
Delay_ms(500);
DCMove(10, 2, 10, 1);
Delay_ms(500);
} return 0;
}
DC Motor를 PWM으로 제어를 하고자 하여 OCRB, OOCRC을 이용하여 제어를 하고 있습니다.
원하는 PWM이 출력이 되어 모터의 가감속과 방향을 바꾸어 가면서 제어가 되는데.
이상하게 Delay_ms()함수를 사용을 하면 전혀 동작을 하지 않네요.
혹 PWM의 time와 Delay_ms()와의 관계가 있는지 다른 설정이 필요한지에 대하여
고수님의 의견을 듣고자 합니다.
관련 소스와 회로도를 첨부 하여 드립니다.
프로그램이 다운로드 되지 않는 분을 위해 소스를 아래 추가 하여 드립니다.
#include <avr/io.h>
#include <avr/interrupt.h> #define F_CPU 8000000UL //CPU clock 설정 : 8MHz
#define PULSE_DUTY 1500000UL // 1500000ns = 1.5 ms (ns단위)
#define PULSE_WIDTH 20000000UL // 20000000ns = 20ms (ns 단위)
#define PULSE_CNT 50 // Pulse count. 한 번 command안에서 실행되는 펄스 갯수 volatile unsigned long clk_period = (uint16_t) (1000000000UL/F_CPU) * 8; // clkio/8 사용하므로 period는 x8
volatile uint8_t pulse_count = PULSE_CNT; volatile char nStopCheck = 0;
SIGNAL(TIMER3_COMPB_vect)
{
cli();
pulse_count--;
if(pulse_count == 0)
{
TCCR3A = 0x00;
TCCR3B = 0x00;
nStopCheck = 1;
}
sei();
} void init_CNT3()
{
DDRE |= 0x10; // PE4/OC3B output
DDRE |= 0x20; // PE4/OC3C output TCCR3A = 0x2B; // Counter 3, Channel B, Channel C, Compare Output Mode, Fast PWM
TCCR3B = 0x1A; // Waveform generation mode 15. clkio/8 clock 사용. OCR3A = (uint16_t) (PULSE_WIDTH/clk_period); // 20ms 주기 설정
OCR3B = (uint16_t) (PULSE_DUTY/clk_period); // default로 1.5ms 가운데
OCR3C = (uint16_t) (PULSE_DUTY/clk_period); // default로 1.5ms 가운데 ETIMSK = 0x0A; // Timer/Counter3, Output Compare B, Compare C Match Interrupt Enable sei();
} //////////////////////////////////////////////////////////////////////////////////////////////////
// Funtion : DCMove
//
// Description : DC 모터를 구동 시키는 함수
// (OCR3B, OCR3C를 이용하여 PWM을 출력하여 모터를 구동 시킴)
// Parameter :
// . nLeftMotorSpeed : Left DC motor 이동 속도 ( 0: 정지, 1~19 까지 가감속 지정 가능)
// . nLeftMotorDirection : Left DC motor 방향 설정 (1: Forward, 2: Backward)
// . nRightMotorSpeed : Right DC motor 이동 속도 ( 0: 정지, 1~19 까지 가감속 지정 가능)
// . nRightMotorDirection : Right DC motor 방향 설정 (1: Forward, 2: Backward)
//////////////////////////////////////////////////////////////////////////////////////////////////
void DCMove(char nLeftMotorSpeed, char nLeftMotorDirection,
char nRightMotorSpeed, char nRightMotorDirection)
{
if( nLeftMotorSpeed != 0 )
{
// 방향 설정 : DCMOTOR01_DIR (1<<5)
if( nLeftMotorDirection == 1 ) PORTA |= (1<<5); //Left DC Motor High(Forward)
else if( nLeftMotorDirection == 2 ) PORTA &= ~(1<<5); //Left DC Motor Low(Backward) OCR3B = (uint16_t) (1000000UL/clk_period) * nLeftMotorSpeed; // 1ms * Speed
} if( nRightMotorSpeed != 0 )
{
// 방향 설정 : DCMOTOR02_DIR (1<<7)
if( nRightMotorDirection == 1 ) PORTA |= (1<<7); //Right DC Motor High(Forward)
else if( nRightMotorDirection == 2 ) PORTA &= ~(1<<7); //Right DC Motor Low(Backward) OCR3C = (uint16_t) (1000000UL/clk_period) * nRightMotorSpeed; // 1ms * Speed
}
} void Delay_us(unsigned char time_us)
{
register unsigned char i; for(i = 0; i < time_us; i++) // 4 cycle +
{
asm volatile(" PUSH R0 "); // 2 cycle +
asm volatile(" POP R0 "); // 2 cycle +
asm volatile(" PUSH R0 "); // 2 cycle +
asm volatile(" POP R0 "); // 2 cycle +
asm volatile(" PUSH R0 "); // 2 cycle +
asm volatile(" POP R0 "); // 2 cycle +
}
} void Delay_ms(unsigned int time_ms)
{
register unsigned int i; for(i = 0; i < time_ms; i++)
{
Delay_us(250);
Delay_us(250);
Delay_us(250);
Delay_us(250);
}
}
int main(void)
{ init_CNT3(); DDRA = 0xFF; // PA4 ~ PA7 : (1<<4) | (1<<5) | (1<<6) | (1<<7)
PORTA = 0xFF; // DCMOTOR01_EN (1<<4), DCMOTOR02_EN (1<<6) DDRE |= (1<<PE4); // PE4 Output pin 설정
DDRE |= (1<<PE5); // PE5 Output pin 설정
PORTE &= ~0x10; // 초기 Low로 설정 하여 긴급 동작을 방지
PORTE &= ~0x20; // 초기 Low로 설정 하여 긴급 동작을 방지 pulse_count = PULSE_CNT; DDRD = 0xff;
OCR3B = 0;
OCR3C = 0; /*
// DCMove()함수가 않되어 일반적으로 LED를 On/Off하도록 하여 보았지만 아래 코드도
// 동작을 하지 않네요.
while(1)
{
PORTD = 0x00;
Delay_ms(500);
PORTD = 0xff;
Delay_ms(500);
}
*/
while(1)
{
DCMove(10, 1, 10, 2);
Delay_ms(500);
DCMove(10, 2, 10, 1);
Delay_ms(500);
} return 0;
}