- 6개의 8비트 I/O 포트
- PA, PB, PC, PD, PE, PF
- 1개의 5비트 I/O 포트
- PG
- DDRx : 입출력 설정( 1 - 출력, 0 - 입력)
- PORTx : 출력될 값을 입력
PA포트에 1을 출력하여야 LED가 켜짐
먼저 LED는 출력이므로 DDRA 레지스터의 해당 비트에 '1'을 write하여 출력상태로 설정하고 PORTA 레지스터의 해당 비트에 '1'을 write하여 LED가 켜지도록한다.
#include <avr/io.h>
void main()
{
unsigned char value 128; 1000 0000
DDRA = 0xff; //포트A를 출력포트로 설정
for(;;){
PORTA = value;
_delay_ms(200);
value >> 1;
if(value == 0) value = 128;
}
#include <avr/io.h>
#define F_CPU 16000000UL
#include <util/delay.h>
unsigned char digit[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x7d, 0x27, 0x7f, 0x6f};
unsigned char fnd_sel[4] = {0x01, 0x02, 0x04, 0x08};
int main(){
int i = 0;
DDRC = 0xff; // C포트는 출력될 숫자는 모두 출력으로 사용
DDRG = 0x0f; // G포트는 4개만 출력으로 사용
while(1){
for (i = 0; i < 4; i++){
PORTC = digit[4-i]; //데이터 신호
PORTG = fnd_sel[i]; // FND 선택신호
_delay_ms(2);
}
}
}
스위치를 이해하긴 위한 빌드업 : 인터럽트
- Global Interrupt Enable : sei(), cli()
- SREG = 0x80;
- 우린 INT4(Swtich 1), INT5(Switch 2)를 쓸거라서 EIMSK는 0x30으로 설정
- 10이 하강 엣지에서의 인터럽트 발생
- EICRB = 0x0A(INT4, INT5쓴다고 가정)
ISR(Interrupt Service Routine)
ISR(인터럽트 이름){
인터럽트 서비스 루틴
}
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#include <util/delay.h>
unsigned char digit[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x7d, 0x27, 0x7f, 0x6f};
unsigned char fnd_sel[4] = {0x01, 0x02, 0x04, 0x08};
volatile int count = 0;
//switch1이 눌릴 때마다 count변수가 1씩 증가한다.
ISR(INT4_vect){
count++;
_delay_ms(100);
}
void display_fnd(int count){
int i, fnd[4];
fnd[3] = (count/1000)%10;
fnd[2] = (count/100)%10;
fnd[1] = (count/10)%10;
fnd[0] = count%10;
for(i = 0; i<4; i++){
PORTC = digit[fnd[i]];
PORTG = fnd_sel[i];
_delay_ms(2);
}
}
int main(){
DDRC = 0xff;
DDRG = 0x0f;
DDRE = 0xef; 0b11101111, (switch1-PE4만 입력)
EICRB = 0x02; //하강엣지 설정
EIMSK = 0x10; //INT4 인터럽트 활성화
SREG |= 1 << 7;
while(1) display_fnd(count)l
#include <avr/io.h>
#define F_CPU 16000000UL
#include <util/delay.h>
int main(){
DDRB = 0x10; //포트B의 4번째만 출력상태로 지정
while(1){
PORTB = 0x10;
_delay_ms(1);
PORTB = 0x00;
_delay_ms(1);
}
}
음을 울리기위해서는 주파수를 이용해야한다. 여기서 쓰이는 도의 주파수는 1046.6으로 1초에 1046.6.번의 주파수가 필요하므로 주기는 1/1046.6이므로 955us이다. 그러면 신호 1인 상태를 478us 유지하고 0인 상태를 478초 유지해야한다.
Timer의 주기를 설정하고 정해진 시간(위의 예로는 478us) 후 인터럽트가 발생해야하며 인터럽트 핸들러에서 on/off를 수행해야한다.
음을 내는 과정
TCCRn (제어,Prescaler를 이용한 클럭 주기 설정) TCNTn (카운터 값 세팅) TIMSK (인터럽트, 오버플로우 인터럽트 활성화)
2 | 1 | 0 | 설명 |
---|---|---|---|
0 | 1 | 1 | 32분주 |
1 | 0 | 0 | 64분주 |
1 | 0 | 1 | 128분주 |
타이머로 원하는 시간 세팅하는 법 (16MHz클럭, prescaler = 32)
타이머 클럭의 주기 = (1/(161000000))32 = 2us
100us의 지연시간을 얻으려면 100/2 50클럭이 필요하므로
TCNT = 256 - 50 = 206
Overflow 인터럽트 활성화
#include <avr/io.h>
#include <avr/interrupt.h>
#define ON 1
#define OFF 0
#define DO 17
volatile int state = OFF;
ISR(TIMER0_OVF_vect){
if (state == ON){
PORTB = 0x00;
state = OFF;
}
else{
PORTB = 0x10;
state = ON;
}
TCNT0 = DO;
}
int main(){
DDRB = 0x10;
TCCR0 = 0x03; //32분주
TIMSK = 0x01; //Overflow 인터럽트 활성화
TCNT0 = DO;
sei();
while(1);
}