여기서는 프로그래밍 관점에서 I/O장치와 상호작용하는 기술을 다룬다.
가장 단순한 I/O는 컴퓨터가 읽거나 쓸 수 있는 비트에 물건을 연결한 형태의 I/O이다. 이런 형태의 I/O가 널리 쓰이는 과정에서 점점 더 복잡한 장치로 진화했다.
위 그림의 LED는 발광 다이오드다. 다이오드는 놀이동산 입구의 회전문 같은 역할울 하는 반도체 장치다. 즉, 다이오드는 전기를 회로도에 표시된 속이 빈 화살표 방향으로만 흐르도록 제한한다. LED는 다이오드 역할을 하면서 부수적으로 빛이 나는 장치이다.
LED와 저항을 직렬로 연결했다는 점에 유의해라. 저항을 연결한 이류는 LED에 흐르는 전류를 제한해서 PB0과 LED가 타버리는 일이 없도록 방지하기 위해서이다.
이때 예를 들어 V가 5볼트라고 해보자. 그러면 각층에 걸리는 전압이 0.7볼트다(트랜지스터의 특성에 따라). 그리고 AVR의 데이터시트를 보면 5볼트일때 대응하는 전압은 4.2볼트이다. 그리고 LED의 데이터시트에따르면 최대전류가 10mA가 되기를 원하고, AVR이 버티 수 있는 전류는 20mA이다. 그리고 옴의 법칙에 따르면 필요한 저항값은 350옴이다.
그리고 장치에 따라 전압 강하등이 달라지기 때문에 사용하려는 LED나 다른 구성요소에 따라 데이터시트를 참조해야한다.(데이터시트 :부품(전자부품 등) , 하부시스템(전원공급장치 등) , 소프트웨어등의 성능, 특성등을 모아놓은 문서)
포트B는 그림 6-2처럼 세가지 레지스터에 의해 제어된다. DDRB는 데이터 방향 레지스터다. 각 핀을 입력으로 쓸지 출력으로 쓸지 결정한다.
PORTB는 출력데이터를 저장하는 래치다. PINB는 핀의 값을 읽는다.
이 그림이 복잡해 보일수 있으나 단순히 구성요서들의 배치에 지나지 않는다(...고 하지만 나는 너무 복잡하다)
DDRB는 포트B에 대한 데이터 방향 레지스터다. 이 레지서터의 어느 비트에 1을 넣으면 그 비트 번호에 해당하는 포트B 비트가 출력에 쓰이게 된다. 0을 넣으면 입력이다. PORTB는 포트의 출력 부붙이다. PORTB의 어느 비트에 0이나 1을 넣으면 (해당비트가 출력 비트로 DDRB에 지정된 경우) 핀의 출력 전압이 0이나 1로 바뀐다. PINB를 읽으면 연관된 핀의 상태를 읽을 수 있다.
R은 풀업 저항이라고 부른다. 버튼이 눌리지 않은 경우 이 저항이 프로세서의 인터럽트 요청핀에 연결괸 선의 전압을 공급 전압 V까지 올려서 논리 1을 만들어 준다. 버튼이 눌리면 저한은 IRQ나 회로가 타지 않게 V에서 흘러온느 전류를 제한하면서 IRQ논리에 0을 공급한다.
왼쪽은 우리가 생각하는 그림, 오른쪽은 실제로 일어나는 상태
이런 일이 일어나는 이유는 버튼에 연결된 금속 조각이 접점에 닿으면 금속조각이 아주 잠깐 되튕겨져서 접점에서 떨어진다. 접촉면이 안정될 때까지 여려번 발생할 수 있다.
이러한 바운스 현상을 없애는 디바운스 방법은 간단하다
위 그림처럼 인터럽트 핸들러에 타이머를 설정하고 그 시간이 지나면 버튼을 감지하는 것이다. 이 접근 방식을 두 가지 방법으로 실현할 수 있다. 첫째는 최초 인터럽트 시 타이머를 설정하는 방법, 둘때는 인터럽트가 발생할 때마다 기존타이머를 새 타이머로 재설정하는 것이다.
이 방법은 효과적이지만 기계부품의 낡음에 따라 최선의 방식은 아니다. 회로를 따로 만드는 방법이 있지만 소프트웨어로 구현하는편이 싸게 먹힌다.
예시)
그림 6-1처럼 어떤 I/O포트에 연결된 버튼이 8개 있다고 가정하자.
이 I/O포트의 상태는 INB라는 8비트 unsigned char 변수를 통해 읽을 수 있다. 그러면 아래의 그림처럼 유한 임펄스 응답 필터(FIR)를 만들 수 있다.
FIR은 큐다. 타이머 틱이 발생할 때마다 가장 오래된 값을 버리고 새 값을 넣으면서 각 값을 하나씩 시프트한다. 그리고 배열 원소들을 OR 해서 상태를 만들어내고, 원소가 2개 있는 큐의 current.입력에 넣는다. current에 값을 넣기 직전에 기존 current값은 previous로 옮긴다. 이제 current와 previous의 상태를 XOR 하기만 하면 어떤 버튼이 상태가 바꼈는지 알 수 있다.
아래는 이과정을 c언어로 작성한 코드
어떤 장치든 디스플레이가 포함된 경우가 많다. 알람시계나 식기세척기, 전자레인지 등의 디스플레이 창을 말한다. 가장 흔한 유형이 아래의 7세그먼트 디스플레이이다.
이 디스플레이에는 7개의 LED가 숫자모양으로 있고 1개의 LED가 소숫점을 표시하는 형태로 붙어 있다.
이 디스플레이에 있는 LED를 처리하려면 16가지의 핀이 필요하다. 하지만 보통은 16개를 사용하지 않고, 각 LED마다 1개씩 핀을 연결하고, 핀하나에 모든 LED를 함께 연결한다.
이런 숫자 디스플레이를 제어하는 소프트웨어는 간단하다. 필요에 따라 어떤 LED를 켤지만 연관시켜주면된다.
그러나 기기에따라 사용방법은 복잡해 질수 있다. 예를 들어 전자 시계를 위의 숫자 LED를 이용하면 4개의 숫자가 필요하다. 각 디스플레이별 I/O포트를 별도로 연결 할 수 있지만 프로레서가 중춤한 수의 포트를 제공하지 못하는 경우가 흔하다. 이러면 해법은 한개의 I/O포트를 이용해서 사람의 시각의 잔상효과를 활용해서 1/24초 보다 짧은 간격으로 번갈아가며 깜박이는 방법이다.
어떤 장치든 버튼과 디스플레이가 함께있는 경우가 여럿 있다.
이런 경우 버튼과 디스플레이의 입력을 멀티플렉싱하면 필을 덜 써도 된다.
이는 버튼이 12개 있는 전화 스타일의 키패드와 숫자4개를 표시하는 디스플레이를 멀티 플렉싱했다 가정하는 그림이다.
네 자리 디스플레이 회로와 비교할때, 푸시 버튼을 12개 사용하기 위해 핀을 12개 추가하지 않고 단지 3개만 추가하면 된다. 모든 푸시 버튼은 풀업 저항에 의해 논리 1로 끌어 올려진다. 디스플레이가 선택되지 않은 경우 버튼을 눌러도 B출력이 모두 1이기 때문에 아무 효과가 없다. 가장 왼쪽 디스플레이가 선택된경우 B0가 로우이고, 맨윗줄의 버튼중 어느 하나를 누르면 그와 연결된 C입력이 로우가 된다. 디스플레이와 푸시버튼이 똑같은 신호에 의해 선택되기 때문에, 상태를 스캠하는 코드를 타이머 인터럽트핸들러에 함께 넣을 수 있다.
알랍 시계에는 디스플레이의 밝기를 조절하는 장치가 포함 될 수도 있다.
아래의 그림처럼 듀티사이클을 조절함으로써 밝기를 조절 할 수 있다.
그림의 왼쪽 부분에서 각 디스플레이는 전체시간의 1/4 동안 켜져 있다. 하지만 오른쪽의 각 디스플레이는 전체의 1/8만 켜져 있고, 오른쪽의 디스플레이는 왼쪽 디스플레이가 켜져 있는 시간의 절반동안은 꺼져있다. 결과적으로 오른쪽의 디스플레이는 왼쪽디스플레이보다 절반정도의 밝기로 보인다. '밝기'는 디스플레이가 켜져 있는 평균시간과 관련이 있다. 하지만 듀티사이클과 사람이 인지하는 밝기 사이의 관계는 선형이 아닐 것이다.
센서를 읽어 모터, 바퀴, 놉 같은 회전축의 위치를 알아내야하는 경우가 있다. 회전축에 수위치를 넣거나 광센서가 읽을 수 있는 검은색과 흰색 점을 사용해 위치를 알아 낼 수있다. 어떤 접근 방법을 선택하든 축의 위치를 2진수로 인코딩 해야한다. 우리가 여덟 가지 위치에 관심이 있다면 인코더는 아래 그림과 비슷한 형태일 것이다.
흰 부분이 0이고 검은 부분이 1이다.
그러면 아래와 같이 전파지연같은 문제로 인코더가 완벽히 그려지지않는 경우는 어떨까?
01234567이 읽히리라 예상했지만 실제로는 2010234567이 읽힌다.
이를 헤결하기위해 물리학자가 각도에따라 비트가 하나씩만 달라지는 개선된 방법을 발견했다. 이는 그레이 코드라고 부른다.