'LED'에 해당되는 글 3건

  1. 2016.11.23 Timer 3개 모두사용하는 예제
  2. 2016.11.14 AVR LED 2개 제어
  3. 2016.11.09 Linux 에서 AVR 컴파일 및 프로그래밍
2016. 11. 23. 22:53

ATMega328P 에는 총 3개의 타이머가 있습니다.


타이머0 - 8비트

타이머1 - 16비트

타이머2 - 8비트


모드는 모두 CTC 모드로 작성 했습니다.


Clear Timer on Compare match


CTC모드는 TCNT 값이 0부터 증가 해서 OCR 에 정의된 값 까지 갑니다.

(여기서 8비트는 최대 255 까지 밖에 ㅜㅜ)


1초를 구하기 위해 16비트는 설정만으로 가능하지만, 8비트는 모두 세지 못합니다.


그래서 타이머 인터럽트 내에 몇번 반복 시켜서 1초를 구하게 됩니다.



8비트로 1초 구하는 방법...

CPU가 16 MHz 로 동작을 가정합니다.


1. 1초에 16000000 Hz 진동합니다.

2. prescale 256 으로 셋팅했으므로 256 Hz 당 1 타이머 count 가 증가합니다.

    즉, 16000000 / 256 = 0.000016 초에 1 Hz씩  ( 1 hz / 16 us)

3. OCR에 정의된 값까지 증가하고 0으로 되돌아 갑니다.

    125번 반복하면 걸리는 시간 = 0.000016 x 125 = 0.002  125번 반복에 0.002초 ( 2 ms) 

    125번 이지만 0 부터 시작하므로 -1을 하여 124를 설정합니다.

4. 타이머 인트럽트가 2ms 당 1번씩 호출되므로 500번 마다 작동하도록 설정하면 1초 마다 동작하도록 설정 됨.


복잡한 것 같지만... 차근차근 읽어보면 그냥 산수 입니다. ^__^


16비트 타이머의 경우 OCR 에 정의할 수 있는 값이 거대해서 인트럽트에서 별도 반복 없이도 1초 구하는 것이 가능합니다.



동작영상



타이머 3개 모두 동작시킨 풀 소스코드

예제는 16비트 1초, 8비트 1/2초, 8비트 1/4초 로 세팅되어 있습니다.

https://github.com/haebi/AVRExample/blob/master/atmega328p/timer2/timer2.cpp


#define F_CPU 16000000UL // Set CPU Frequency 16 MHz


#define setbit(PORTX, BitX) PORTX |= (1 << BitX) // set bit to 1

#define clrbit(PORTX, BitX) PORTX &= ~(1 << BitX) // clear bit


#include <avr/io.h>

#include <util/delay.h>

#include <avr/interrupt.h>


int count0 = 0;

int tick0  = 0;


int count1 = 0;


int count2 = 0;

int tick2  = 0;


void setTimer0()

{

// 1sec for 8-bit

// 1 / 16000000 = 0.0000000625 * 256 (prescale) = 0.000016 (usec)

// 0.000016 (usec) * 125 (multiplier) = 0.002 * 1000 = 2 (ms)

// 2 (ms) * 500 (count) = 1 (sec)


TCNT0   = 0;

// Set CTC compare value with a prescaler of 256

OCR0A   = 124; // 125 -1 


// 0 1 0 - Configure timer 0 for CTC mode [p.106]

clrbit(TCCR0B, WGM02); // 0

setbit(TCCR0A, WGM01); // 1

clrbit(TCCR0A, WGM00); // 0


// 1 0 0 - Start timer at Fcpu/256 [p. 108]

setbit(TCCR0B, CS02); // 1

clrbit(TCCR0B, CS01); // 0

clrbit(TCCR0B, CS00); // 0

// Enable CTC interrupt

setbit(TIMSK0, OCIE0A);

}


void setTimer1()

{

// OCR1A =  OCR1AH + OCR1AL = (8 + 8 = 16 bit)

// Dec 15624 : repeat 0 ~ 15624 (15625 = 0)

OCR1A = 0x3D08; 


// Page 171-172

// Waveform Generation Mode : (TCCR1B:4,  TCCR1B:3, TCCR1A:1, TCCR1A:0)

// 0 1 0 0 - Set to TOP OCR1A

setbit(TCCR1B, WGM12); // Configure timer 1 for CTC mode


// Page 173

// Clock Select Bit ( CS12 CS11 CS10 )

// 0 1 0 - clock I/O / 1024 (From prescaler)

setbit(TCCR1B, CS12);

setbit(TCCR1B, CS10);


// Page 135

// TIMSK1 – Timer/Counter1 Interrupt Mask Register

setbit(TIMSK1, OCIE1A); // Enable CTC interrupt

}


void setTimer2()

{

// 1sec for 8-bit

// 1 / 16000000 = 0.0000000625 * 256 (prescale) = 0.000016 (usec)

// 0.000016 (usec) * 125 (multiplier) = 0.002 * 1000 = 2 (ms)

// 2 (ms) * 500 (count) = 1 (sec)


TCNT2   = 0;

// Set CTC compare value with a prescaler of 256 

OCR2A   = 124; // 125 -1 


// 0 1 0 - Configure timer 2 for CTC mode [p.155]

clrbit(TCCR2B, WGM22); // 0

setbit(TCCR2A, WGM21); // 1

clrbit(TCCR2A, WGM20); // 0


// 1 1 0 - Start timer at Fcpu/256 [p.156-157]

setbit(TCCR2B, CS22); // 1

setbit(TCCR2B, CS21); // 1

clrbit(TCCR2B, CS20); // 0


// Enable CTC interrupt

TIMSK2 |= (1 << OCIE2A);

}


// Main Function

int main(void)

{

setTimer0(); //  8 bit timer (TCNT0)

setTimer1(); // 16 bit timer (TCNT1)

setTimer2(); //  8 bit timer (TCNT2)


sei(); // Enable global interrupts


setbit(DDRD, DDD6); // Set output PD6

setbit(DDRD, DDD7); // Set output PD7

setbit(DDRB, DDB0); // Set output PB0


while (1)

{


}

}


// Timer0 interrupt

ISR (TIMER0_COMPA_vect)

{

tick0++;


// if (!(tick0 == 500)) // 1 sec

if (!(tick0 == 125)) // 1/4 sec

return;


tick0 = 0;


if (count0 == 0)

{

count0++;

clrbit(PORTB, PORTB0);

}

else

{

setbit(PORTB, PORTB0);

count0 = 0;

}

}


// Timer1 interrupt

ISR (TIMER1_COMPA_vect)

{

// already 1 sec


if (count1 == 0)

{

count1++;

clrbit(PORTD, PORTD6);

}

else

{

setbit(PORTD, PORTD6);

count1 = 0;

}

}


// Timer2 interrupt

ISR (TIMER2_COMPA_vect) 

{

tick2++;


// if (!(tick2 == 500)) // 1 sec

if (!(tick2 == 250)) // 1/2 sec

return;


tick2 = 0;


if (count2 == 0)

{

count2++;

clrbit(PORTD, PORTD7);

}

else

{

setbit(PORTD, PORTD7);

count2 = 0;

}

}




Posted by 해비
2016. 11. 14. 01:03

LED 1개 에 이어 2개 ...


운영체제 올라가면 별도 쓰레드로 올리고 sleep 주면 되겠지만... 여긴 그런게 없다...


while 문의 타이밍 주기를 1ms 로 세팅하고 LED 켜고 꺼지는 주기는 설정한 간격에 의해 별도 함수 내에서 처리하도록 프로그램 하였다.


time이 계속 증가만 하는데 이거 상관 없는지는 확인 이 필요할 것 같다.



사진



작동영상



소스코드

#define F_CPU 16000000UL


#include <avr/io.h>

#include <util/delay.h>


void PPD6(int time, int interval)

{

if ((time %  (2 * interval)) == 0)

{

PORTD &= ~(1<<PORTD6);

}

else if ((time %  interval) == 0)

{

PORTD |= (1<<PORTD6);

}

}


void PPD7(int time, int interval)

{

if ((time %  (2 * interval)) == 0)

{

PORTD &= ~(1<<PORTD7);

}

else if ((time %  interval) == 0)

{

PORTD |= (1<<PORTD7);

}

}


int main(void)

{

int time = 0;


DDRD |= (1<<DDD6); // PD6 Out

DDRD |= (1<<DDD7); // PD7 Out

while(1)

{

PPD6(time, 125);

PPD7(time, 500);


time++;

_delay_ms(1);

}




Posted by 해비
2016. 11. 9. 23:18

윈도우 에서 삽질하다 포기하고 리눅스로 넘어왔다.


첨부터 리눅스로 할껄...;;


필요한 프로그램 설치

apt install gcc-avr avr-libc avrdude 


다른 곳에서는 binutils 와 uisp 까지 설치 하라고 되있는 곳도 있던데...

일단 테스트 결과 네모 안에 있는 3개만 설치해도 빌드 및 프로그램이 가능함을 확인 하였다.

avr-gcc, avrdude 만 있음 되는 거 같다... 일단은 -_-


음영으로 표시된 부분이 명령창에서 입력하는 부분이다.



1. 소스 작성 (cpp)

2. Makefile 작성

3. 컴파일 -> hex 파일 생성

4. 프로그램 -> hex 파일 을 ATMega328p 에 전송 (USBASP 2.0 사용)

5. 퓨즈비트 세팅 -> 내장클릭 1Mhz 를 사용하지 않고 외부의 16 MHz 크리스탈을 사용하여 동작하도록 설정



잊어먹기 전에 정리.... -_-;;


안되서 맨날 시방시방 하다가 되니까... 이 기분을 어찌 표현해야 할지... ㅎㅎㅎ


펌웨어 버젼 어쩌고 경고 뜨는데, 현재로서는 모르겠다능 -_-;;

펍업 하다 USBASP 해먹으면... 진행을 못하니까... 열댓개 사서 시도를 해보던가 해야겠다.



ledblink.cpp

#define F_CPU 16000000UL

#include <avr/io.h>

#include <util/delay.h>

int main(void)

{

DDRB |= (1<<DDB5); //Set the 6th bit on PORTB (i.e. PB5) to 1 => output

while(1)

{

PORTB |= (1<<PORTB5);    //Turn 6th bit on PORTB (i.e. PB5) to 1 => on

_delay_ms(1000);        //Delay for 1000ms => 1 sec

PORTB &= ~(1<<PORTB5);    //Turn 6th bit on PORTB (i.e. PB5) to 0 => off

_delay_ms(1000);        //Delay for 1000ms => 1 sec

}



Makefile

ledblink.o: dummy

avr-gcc -mmcu=atmega328p -Os ledblink.cpp -o ledblink.o


ledblink: ledblink.o

avr-objcopy -j .text -j .data -O ihex ledblink.o ledblink.hex


dummy: 



compile

$ make ledblink

avr-gcc -mmcu=atmega328p -Os ledblink.cpp -o ledblink.o

avr-objcopy -j .text -j .data -O ihex ledblink.o ledblink.hex 



program

$ avrdude -c usbasp -p m328p -e -U flash:w:ledblink.hex


avrdude: warning: cannot set sck period. please check for usbasp firmware update.

avrdude: AVR device initialized and ready to accept instructions


Reading | ################################################## | 100% 0.00s


avrdude: Device signature = 0x1e950f (probably m328p)

avrdude: erasing chip

avrdude: warning: cannot set sck period. please check for usbasp firmware update.

avrdude: reading input file "ledblink.hex"

avrdude: input file ledblink.hex auto detected as Intel Hex

avrdude: writing flash (176 bytes):


Writing | ################################################## | 100% 0.15s


avrdude: 176 bytes of flash written

avrdude: verifying flash memory against ledblink.hex:

avrdude: load data flash data from input file ledblink.hex:

avrdude: input file ledblink.hex auto detected as Intel Hex

avrdude: input file ledblink.hex contains 176 bytes

avrdude: reading on-chip flash data:


Reading | ################################################## | 100% 0.13s


avrdude: verifying ...

avrdude: 176 bytes of flash verified


avrdude: safemode: Fuses OK (E:FF, H:DE, L:FF)


avrdude done.  Thank you. 



fuse-bit setting

$ avrdude -c usbasp -p m328p -C /etc/avrdude.conf -U lfuse:w:0xFF:m -U hfuse:w:0xDE:m -U efuse:w:0x05:m


avrdude: warning: cannot set sck period. please check for usbasp firmware update.

avrdude: AVR device initialized and ready to accept instructions


Reading | ################################################## | 100% 0.00s


avrdude: Device signature = 0x1e950f (probably m328p)

avrdude: reading input file "0xFF"

avrdude: writing lfuse (1 bytes):


Writing | ################################################## | 100% 0.00s


avrdude: 1 bytes of lfuse written

avrdude: verifying lfuse memory against 0xFF:

avrdude: load data lfuse data from input file 0xFF:

avrdude: input file 0xFF contains 1 bytes

avrdude: reading on-chip lfuse data:


Reading | ################################################## | 100% 0.00s


avrdude: verifying ...

avrdude: 1 bytes of lfuse verified

avrdude: reading input file "0xDE"

avrdude: writing hfuse (1 bytes):


Writing |                                                    | 0% 0.00s ***failed;  

Writing | ################################################## | 100% 0.03s


avrdude: 1 bytes of hfuse written

avrdude: verifying hfuse memory against 0xDE:

avrdude: load data hfuse data from input file 0xDE:

avrdude: input file 0xDE contains 1 bytes

avrdude: reading on-chip hfuse data:


Reading | ################################################## | 100% 0.00s


avrdude: verifying ...

avrdude: verification error, first mismatch at byte 0x0000

         0xd9 != 0xde

avrdude: verification error; content mismatch


avrdude: safemode: hfuse changed! Was de, and is now d9

Would you like this fuse to be changed back? [y/n] y

avrdude: safemode: and is now rescued

avrdude: safemode: Fuses OK (E:FF, H:DE, L:FF)


avrdude done.  Thank you. 








Posted by 해비