본문 바로가기
임베디드/Atmega128

atmega128 timer/counter0 위상정정 PWM 이용한 DC모터 속도제어

by sj0020 2021. 1. 9.

 

책 pdf 367

#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU             16000000UL
#define PRESCALE          256L
#define PULSE_PER_OVERFLOW    510L
#define MS_OVERFLOW_CYCLE    ((double)(PULSE_PER_OVERFLOW * PRESCALE)\
							/(double)((double)F_CPU/1000.0))
#define OC0      PB4
#define UP      PB7
#define DOWN   PB6
#define NUM_REQ    2
#define REQ_UP    0
#define REQ_DOWN 1
#define DEBOUNCE_CYCLE 50

volatile unsigned long   timer0;            //오버플로마다 1씩 증가 될 변수
volatile unsigned int   number;
unsigned char led[]={0x48,0x7D,0xC4,0x64,0x71,0x62,0x43,0x7C,0x40,0x70};

volatile unsigned long req[NUM_REQ]={0,0};
double   ms_ov_cycle;

// 타이머/카운터@ 인터럽트 서비스 루틴
ISR(TIMER0_OVF_vect)
{
	int i;
	timer0++;       // 오버플로마다 1씩 증가
	
	//오버플로 횟수가 짝수 일때 10자리, 홀수일때 1자리 디스플레이
	PORTC = (timer0 % 2 == 0) ? led[(number % 100) / 10] : led[number%10];
	PORTD = (PORTD | 0xC0) & ~(1<<((timer0 % 2 == 0) ? PD7 : PD6));
	
	for(i=0; i<NUM_REQ; i++)
	if( req[i] > 0)         //REQ 요청이 있을때만
	req[i]--;         //시간 지연 경과 응답
}

// ms_interval초 시간 지연을 위한 오버플로 횟수 계산 함수
unsigned long ms_req_timer0(unsigned long ms_interval)
{
	return (ms_interval <=0) ? 0 : \
	+(unsigned long)(ms_interval / ms_ov_cycle);
}

int main(void)
{
	DDRC = 0xFF;
	DDRD |= 1 << PD7| 1<<PD6;            //두 자리 7-세그먼트 LED를 켜기 위한 출력
	DDRB |= 1 << OC0;                  //OC0 = PB4 출력
	DDRB &= ~(1<<UP | 1<<DOWN);            //UP, DOWN 스위치 위치를 입력 방향으로
	PORTB |= 1<<UP | 1<<DOWN;            //UP, DOWN 풀업 저항
	
	TCCR0 = 1<<WGM00;                  //위상정정 PWM 파형 발생모드
	TCCR0 |= 1<<CS02 | 1<<CS01;            //프리스케일러 CS02:00 = (1,1,0) 256 분주
	TCCR0 |= 1<<COM01;                  //상승 중 OCR0와 일치 0, 하강 중 일치 1
	
	TIMSK |= 1<<TOIE0;                  //타이머/카운터0 인터럽트 활성화
	
	timer0 = 0;
	sei();
	
	ms_ov_cycle = MS_OVERFLOW_CYCLE;
	
	OCR0 = 0;
	number = OCR0*100/256;                //OCR0값과 number값을 일치
	
	while(1){
		if( (req[REQ_UP] == 0) && !(PINB & (1<<UP)) ){   //req[UP] 응답, UP 스위치 눌림 검사
			req[REQ_UP] = ms_req_timer0(DEBOUNCE_CYCLE);
			OCR0 = (OCR0 == 255) ? 255 : OCR0 + 1;
		}
		
		if((req[REQ_DOWN]==0) && !(PINB & (1<<DOWN))){ //req[DOWN] 응답, DOWN 스위치 검사
			req[REQ_DOWN] = ms_req_timer0(DEBOUNCE_CYCLE);
			OCR0 = (OCR0 == 0) ? 0 : OCR0 - 1;
		}
		
		number = OCR0 * 100/256;
	}
	return 0;
}

timercounter.pdsprj
0.02MB

7segment부분 제거한것

#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU             16000000UL
#define PRESCALE          256L
#define PULSE_PER_OVERFLOW    510L
#define MS_OVERFLOW_CYCLE    ((double)(PULSE_PER_OVERFLOW * PRESCALE) /(double)((double)F_CPU/1000.0))
#define OC0      PB4
#define UP      PB7
#define DOWN   PB6
#define NUM_REQ    2
#define REQ_UP    0
#define REQ_DOWN 1
#define DEBOUNCE_CYCLE 50

volatile unsigned long   timer0;            //오버플로마다 1씩 증가 될 변수


volatile unsigned long req[NUM_REQ]={0,0};
double   ms_ov_cycle;

// 타이머/카운터0 인터럽트 서비스 루틴
ISR(TIMER0_OVF_vect)
{
	int i;
	timer0++;       // 오버플로마다 1씩 증가
	
	
	for(i=0; i<NUM_REQ; i++)
	if( req[i] > 0)         //REQ 요청이 있을때만
	req[i]--;         //시간 지연 경과 응답
}

// ms_interval초 시간 지연을 위한 오버플로 횟수 계산 함수
unsigned long ms_req_timer0(unsigned long ms_interval)
{
	return (ms_interval <=0) ? 0 : +(unsigned long)(ms_interval / ms_ov_cycle);
}

int main(void)

{

	DDRB |= 1 << OC0;                  //OC0 = PB4 출력
	DDRB &= ~(1<<UP | 1<<DOWN);            //UP, DOWN 스위치 위치를 입력 방향으로
	PORTB |= 1<<UP | 1<<DOWN;            //UP, DOWN 풀업 저항
	
	//TCCR0 |= 1<<WGM00 | 1<<CS02 | 1<<CS01 | 1<<COM01;
	TCCR0 = 1<<WGM00;                  //위상정정 PWM 파형 발생모드 TCCR0 = 0b0110 0110;  = 0x66;  
	TCCR0 |= 1<<CS02 | 1<<CS01;            //프리스케일러 CS02:00 = (1,1,0) 256 분주
	TCCR0 |= 1<<COM01;                  // TCNT 값이 OCR0값보다 높을때는 0으로 clear, OCR0값보다 낮을때는 1로 set. 
										// 1<<COM00 | 0<<COM01 으로 setting 하면 TCNT 값이 OCR0값보다 높을때는 1로 set, OCR0값보다 낮을때는 0으로 clear.
	
	TIMSK |= 1<<TOIE0;                  //타이머/카운터0 인터럽트 활성화
	
	timer0 = 0;
	sei();
	
	ms_ov_cycle = MS_OVERFLOW_CYCLE;
	
	OCR0 = 0;

	
	while(1){
		if( (req[REQ_UP] == 0) && !(PINB & (1<<UP)) ){   //req[UP] 응답, UP 스위치 눌림 검사
			req[REQ_UP] = ms_req_timer0(DEBOUNCE_CYCLE);
			OCR0 = (OCR0 == 255) ? 255 : OCR0 + 1;
		} 
		
		if((req[REQ_DOWN]==0) && !(PINB & (1<<DOWN))){ //req[DOWN] 응답, DOWN 스위치 검사
			req[REQ_DOWN] = ms_req_timer0(DEBOUNCE_CYCLE);
			OCR0 = (OCR0 == 0) ? 0 : OCR0 - 1;
		}		
	}
	return 0;
}