전자회로실험
LED 속도 변화
어제 실험에서는 주기적인 시간에 따라 LED를 On/Off시키는 코드를 작성해 보았다. 오늘은 이 LED On/Off를 시간을 동적으로 바꾸어 보는 코드를 작성했다.
port.h파일
#define PINA (*(volatile unsigned int *)0x39)
#define DDRA (*(volatile unsigned int *)0x3A)
#define PORTA (*(volatile unsigned int *)0x3B)
#define PINB (*(volatile unsigned int *)0x36)
#define DDRB (*(volatile unsigned int *)0x37)
#define PORTB (*(volatile unsigned int *)0x38)
#define PINC (*(volatile unsigned int *)0x33)
#define DDRC (*(volatile unsigned int *)0x34)
#define PORTC (*(volatile unsigned int *)0x35)
#define PIND (*(volatile unsigned int *)0x30)
#define DDRD (*(volatile unsigned int *)0x31)
#define PORTD (*(volatile unsigned int *)0x32)
#define PINE (*(volatile unsigned int *)0x21)
#define DDRE (*(volatile unsigned int *)0x22)
#define PORTE (*(volatile unsigned int *)0x23)
#define PINF (*(volatile unsigned int *)0x20)
#define DDRF (*(volatile unsigned int *)0x61)
#define PORTF (*(volatile unsigned int *)0x62)
main.c파일
#include "port.h"
int main(void)
{
unsigned int us = 0; // 10^-6
unsigned int ms = 0; // 10^-3
int flag = 0;
int t = 2000; // 시간 변화를 주기 위한 변수
DDRC = 0xFF;
while(1)
{
us++;
if(us >= 1000)
{
ms++;
us = 0;
}
if(ms >= t)
{
if(flag)
{
PORTC = 0x00;
flag = 0;
}
else
{
PORTC = 0xFF;
flag = 1;
}
ms = 0;
t -= 100;
if(t == 0)
{
t = 2000;
}
}
}
return 0;
}
// 변수 t를
이용하여 LED가 on/off 할
때
마다 t값을
줄여줌으로써 on/off 주기가
점점
짧아진다. 변수 t가 0이
되면
다시 2000으로
초기화하고
다시
반복한다.
PINx
PINx 레지스터는 I/O핀이 입력으로 사용될 경우 핀에 입력된 데이터를 읽어 오는 레지스터이다. 이 PINx를 직접 사용해보았다.
main.c 파일
#include "port.h"
int main(void)
{
DDRC = 0x01; // C핀 01번을 출력으로 설정
PORTC = 0x01; // C핀 01번에 High 출력
DDRD = 0x00; // D핀을 입력으로 설정
PORTD = 0x00; // D핀 초기화
PORTF = 0x00; // F핀 초기화
while(1)
{
if(PIND & 0x01) // D핀 01번에 High신호가 들어오면
{
DDRF = 0xff; // F핀에 High 신호 출력
}
else
{
DDRF = 0x00; // F핀에 Low 신호 출력
}
}
return 0;
}
// F핀에는 LED를
연결시켜놓고, C핀 01번을 D핀 01번으로
연결시키면 F에서
출력이
나오므로 LED에
불이
들어오는
것을
알
수
있다.
switch누름에 따라 LED on개수변화
#include "port.h"
int main(void)
{
DDRC = 0x00; //switch input
PORTC = 0x00;
DDRF = 0xFF; //LED output
PORTF = 0xFF;
while(1)
{
if((~PINC) & 0x01) // 1번 스위치가 눌러 졌을 때
{
PORTF = ~(0x01);
}
else if((~PINC) & 0x02) // 2번 스위치가 눌러 졌을 때
{
PORTF = ~(0x03);
}
else if((~PINC) & 0x04) // 3번 스위치가 눌러 졌을 때
{
PORTF = ~(0x07);
}
else if((~PINC) & 0x08) // 4번 스위치가 눌러 졌을 때
{
PORTF = ~(0x0F);
}
else if((~PINC) & 0x10) // 5번 스위치가 눌러 졌을 때
{
PORTF = ~(0x1F);
}
else if((~PINC) & 0x20) // 6번 스위치가 눌러 졌을 때
{
PORTF = ~(0x3F);
}
else if((~PINC) & 0x40) // 7번 스위치가 눌러 졌을 때
{
PORTF = ~(0x7F);
}
else if((~PINC) & 0x80) // 8번 스위치가 눌러 졌을 때
{
PORTF = ~(0xFF);
}
else
{
PORTF = 0xFF;
}
}
return 0;
}
// switch 입력
받은핀 : PORTC // LED 출력핀 : PORTF
// switch 회로도를
보면
스위치가
눌려
졌을
때 Low 신호가
입력
된다. 그러므로 C핀
입력을
보수
연산을해서
어느
핀이
눌러
졌는가
확인하고, 이에
따라 LED On의
개수를
정하고 F핀으로
출력
하였다.
C언어
Big Endian & Little Endian
정수 0x12345678가 실제 메모리에 저장 되는 방식에는 Big-Endian과 Little-Endian방식이 있다. Big-Endian의 의미는 정수의 끝부분 메모리 주소가 크다는 의미이고, Little-Endian은 정수의 끝부분의 메모리 주소가 작다는 의미다.
일반적인 인텔x86계열 cpu들은 Little-Endian방식을 채택하고 있는데, Little-Endian 방식은 메모리 첫 부분에 바로 정수의 끝자리가 오기 때문에 산술연산이 간단해지는 장점이 있다. 반면 끝부분이 앞에 오기 때문에 대수비교에 약점이 있다.
main.c파일
#include <stdio.h>
int main()
{
int iNum = 0x12345678;
int *iP = &iNum;
printf("iNum address: %08x\n", &iNum);
printf("iP address: %08x\n", &iP);
printf("iNum value: %08x\n", iNum);
*iP = 0x77777777;
printf("iNum value: %08x\n", iNum);
*((int *)0x12ff7c) = 0x99;
printf("iNum value: %08x\n", iNum);
/* little endian을 확인하는 코드 */
*((char *)0x12ff7c) = 0x01;
*((char *)0x12ff7d) = 0x02;
*((char *)0x12ff7e) = 0x03;
*((char *)0x12ff7f) = 0x04;
printf("iNum value: %08x\n", iNum);
return 0;
}
// 인텔 x86계열 Little-Endian을 확인하는 코드로 결과 제일 밑을 보면 확인할 수 있다
Volatile 키워드
c컴파일러는 불필요한 코드를 자동적으로 최적화 시켜준다. 하지만 특수 역할을 하는 레지스터를 엑세스 해야 되는 경우 이 최적화가 문제를 일으킨다. 이를 방지하기 위해서 volatile키워드를 사용한다.