기타2012. 1. 28. 09:24

버릴것이 하나없는 ATX 파워, 이번엔 납연제거기로 변신

 

 

 

제작시간 : 30분 이내

제작비용 : 5,000원

필요공구 : 인두, 납, + 드라이버, 커터, 브러쉬, 수축튜브, 글루건

 

 

  어제 납땜을 하면서 불현듯 납연제거기(납연기 빨아들이는 팬)이 있어야 겠다는 생각을 하게 되었습니다. 제가 담배를 피는데(자랑이네) 납땜할 때 나는 연기(납연기라기 보다는 주로 플럭스 연기인듯 합니다)를 들이마실때마다 항상 생각이 되는 것이, 건강은 둘째치고 후각에 어떤 영향을 끼치는 것이었습니다. 향수나 기름도 마찬가지이지만, 꼭 기름냄새 맡은뒤에 담배피는 느낌이랄까요?

 

  담배야 조만간 끊어야겠지만, 어찌되었든 납땜시 연기가 그다지 유쾌한 것이 아닌것은 분명합니다. 허나, 납연제거기가 생각보다 가격이 꽤 나갑니다. 시중제품은 뽀대도 있고, 성능도 좋겠지만, 사실 가격도 그러하지만, 크기도 그다지 끌리지가 않습니다. 납땜할 때 앞에 떡하니 있으면 정신집중이 잘 안된다고나 할까요? 그래서 이번 프로젝트는 작고 간단하고 비용이 거의 들지 않으며 실용적인 형태로 구상을 하게 되었습니다.

 

 

  팬을 떠올리게 되면 역시 PC에 덕지 덕지 달려있는 팬이 제일 먼저 연상되게 됩니다. CPU팬으로 120mm짜리를 가지고는 있지만, 그걸 사용하기엔 조금 아깝고, 거시기해서 ATX 파워서플라이를 재활용하기로 했습니다. 멀쩡한 파워 뜯기는 좀 그렇고 예전에 내부 쇼트가 나서 부품의 일부를 못쓰게 된 파워를 아는 분이 버린다고 하는 것을 줏어온게 하나 있었는데(사실은 고쳐 쓰려고 했습니다만 ㅡㅡ;;), 이참에 이녀석을 납연제거기로 만들기로 했습니다.

 

  아래 사진은 이번에 희생하실 ATX 파워입니다. 제 기억으로는 아마 이녀석이 내부쇼트가 나서 메인보드까지 태워먹었던 저주스러운 중국산 파워로 알고 있습니다. 원 소유주는 보드갈고 파워갈면서 이 파워를 아주 미워해서 망치로 뽀개려는걸 제가 줏어온겁니다. 그러고 보니 대략 3년전쯤 이야기로군요 ㅡㅡ;; 하여튼, 사진에서처럼 120mm 대형 팬이 달린 제품이라 풍량도 넉넉하고 이 제품을 세울때도 무난할것 같아서 아주 마음에 들었습니다. 스위치도 달렸겠다. 내부 공간도 넉넉하고 팬그릴도 달려있으니 금상첨화지요.

 

  그래도 혹시나, 문제가 없는 것일지도 모른다는 생각에 전원 연결하고 테스터로 전압을 재보았습니다. +5V VSB(케이블에서 보라색)에는 5V 전원이 이상없이 나옵니다만, 전원을 켜니 다른 전원출력부위는 원래 전압을 몇초정도 유지하더니 뚝뚝 떨어지고, 결국에는 0V가 되어 버리고 마는군요. 수리하는 노력이 아까울수 있으니 미련은 버립니다.

 

 

 

제작과정

 

STEP  1  부품소개

 

  부품이라고 해봐야 별것 없습니다. 사실 가장 중요한 점은 자유롭게 구부러지는 구리선과 클립이 핵심입니다. 구리선은 신경 쓴다고 썼지만, 제가 갖고 있는 선중에 눈에 먼저 띄인 것이 케이블TV용 동축케이블이었습니다. 어딘가에 더 두꺼운 선이 있던 것으로 기억되지만 찾기가 귀찮아서 그냥 이걸로 쓰기로 했습니다. 요새는 쓰임새가 전혀 없는 선이라 잘라써도 아깝지는 않더군요(사실 몇개 더 있어서...). 다음은 필요한 부품 리스트입니다.

 

1. 스펀지 또는 필터 : 필터역할을 할 스펀지입니다. 이외에도 다양한 것들을 필터로 쓰시면 됩니다.

2. 12V 어댑터 : 팬에 전원공급을 할 어댑터입니다. 플러그 타입보다 양쪽이 케이블로 된게 만들기 좋습니다.

3. 가변저항 : 옵션입니다. 팬속도를 조절하기 위해서 준비는 했습니다만, 달지 말지는 마지막에 결정합니다.

4. LED : 전원이 켜졌음을 알리는 LED입니다. 반드시 필요한것은 아닙니다.

5. 1K 저항 : LED 전류제한을 위한 저항입니다. LED에 따라서 용량이 달라져야 합니다.

6. 몰렉스 2핀 커넥터 : 팬과 어댑터를 연결하기 위한 용도입니다. 몰렉스 5045-02 타입입니다.

7. 고무발 4개 : 사진 찍는 시점에서 없어서 사진엔 없지만, 바닥받침용 고무다리입니다.

 

 

 

STEP  2  파워서플라이 분해

 

  납연제거기의 핵심은 팬이라고 해도 무방합니다. 중고 ATX 파워의 경우 내부에 먼지가 많이 쌓여 있을 확률이 높습니다. 따라서 내부 청소를 잘해주어야 기계적인 부분의 동작이 부드럽게 잘 됩니다. 게다가 청소를 제대로 안하면 시끄럽기도 합니다 ^^ 우선은 내부상황이 어떤지 한번 분해를 해보겠습니다.

 

1. 우측면부 : 사진에 보이는 면이 우측면부로 사용할 예정입니다. 전원입력, 스위치는 그대로 이용합니다.

2. 케이블들 : 원래 달려있는 케이블과 커넥터들은 나중에 또 DIY 할때 재활용을 할만하겠습니다.

3. 커버 제거 : 파워의 윗부분이나 아랫부분 귀퉁이에 보통 4개의 나사를 풀면 커버가 열립니다. 아휴 먼지~

4. 팬쪽 커버 : 커버를 열때 팬이 붙이 있으면 사진처럼 커넥터를 빼서 상하가 분리되도록 합니다.

 

 

  팬을 자세히 클로즈업해보았습니다. 오래된 묵은 먼지가 팬을 덮고 있습니다. 그런것은 청소하면 되므로 별 문제가 되지 않습니다만, 제일 중요한 문제는 역시 잘 구동되느냐 하는 점이지요. 12V에 인가를 해보니 토크가 딸려서 잘 돌지 않습니다. 손으로 몇번 돌려주니 그제서야 살살 돌아가는 군요. 정지해 있을때 손으로 돌려봐도 분명히 뻑뻑합니다.

 

  대부분 이러한 경우에는 팬을 버립니다만, 청소후 약간의 기름칠만 해줘도 처음 컨디션으로 어느정도 회복이 가능합니다. 경험상 괜찮은 것은 모기약과 같은 유성 스프레이 제품입니다. 점성이 낮아서 부담이 없고, 구하기가 쉬우니까요. 정 없으면 콩기름과 같은 것으로 기름칠을 해줘도 됩니다. 어쨌든 컨디션 복원은 뒤에서 다시 설명하겠습니다.

 

 

 

STEP  3  팬 분해

 

  앞으로 오랜동안 같이 동고동락할 공구가 될 녀석이므로 청소를 깨끗하게 해주는게 좋습니다. 조금 귀찮아도 팬나사 4개만 풀면 분해가 되므로, 꼭 분해를 해서 청소를 하시는게 좋습니다. 가급적 실외에서 하시는 것을 추천합니다. 먼지가 장난이 아닙니다 ^^;;

 

1. 팬나사 제거 : 팬이 있는 4개의 귀퉁이에 있는 팬나사 4개를 제거합니다. 보통 그릴과 같이 달려있습니다.

2. 분해 사진 : 설명안드려도 되겠죠? 나사 4개만 제거하면 사진처럼 분해가 됩니다.

3. 먼지 제거 : 브러쉬로 먼지를 최대한 깨끗하게 털어내줍니다. 걸레같은것으로 닦아주면 더 좋습니다.

4. 청소 도구 : 제가 사용하는 브러쉬들입니다. 컴프레샤로 잘 안털어지는 묵은 먼지는 칫솔이 아주 좋습니다.

 

 

 

STEP  4  팬에 기름칠하기

 

  최대한 깨끗한 상태로 복원을 시켰지만 역시 내부적으로는 여전히 뻑뻑합니다. 이럴때는 앞에서 말씀드렸듯이 기름성분이 있는 뭔가를 팬 내부에 흘려넣어주고 기름성분이 팬 내부에서 자리를 잡도록 적절하게 돌려주면 됩니다.사진에서처럼 팬은 한면에만 상표스티커가 있는데, 대부분 상표스티커를 살짝 들추면 모터 중심부가 보입니다. 그곳에 기름을 한두방울 떨어뜨려 주고 조금만 돌려주면 컨디션 회복은 끝납니다. 하지만, 어떤 팬의 경우는 그러한 중심홀이 없어서 측면의 틈새에 넣어주어야 하는 경우도 있습니다. 스포이드나 주사기를 이용해서 넣어주면 좋습니다.

 

1. 먼지청소 완료 : 아까와는 다르게 새제품에 근접한 상태입니다. 깨끗하니 좋군요.

2. 스티커 제거 : 100%는 아니지만, 스티커를 살짝 들어내면 모터 중앙홀이 나타닙니다.

3. 윤활유 삽입 : 저는 스티커제거제를 윤활유대신 사용합니다. 중요한점은 비전도성이어야 하는 점입니다.

4. 모터 회전 : 윤활유가 충분히 내부에 코팅이 되도록 돌립니다. 상태에 따라 다르지만, 최악의 경우 약 5분

                      이내에 회복이 되어집니다.

5. 모터상태 회복 : 스펙상으로는 12V 300mA라고 쓰여있지만, 약 180mA 정도의 전류소비를 하는군요.

6. 스티커 접착 : 아까 떼어낸 스티커 및 내부의 작은 고무커버를 모두 붙여서 원상복구 합니다.

 

 

  모터상태 회복에 대해서 추가적인 설명을 하면, 윤활유없이 테스트시 아예 돌지를 못했고, 손으로도 꽤 뻑뻑했습니다. 윤활유를 중앙홀에 넣고나서 돌렸을때도 아주 약간 부드러워졌을 정도였지만, 약 3~4도마다 걸리는 듯한 느낌과 속도도 여전히 빠르지 못해서 흡입하는 것도 약했습니다. 이러한 정도는 약간 심한 정도였습니다만, 약 2~3분을 그대로 돌도록 내버려두니, 갑자기 회전속도가 빨라지고 전류량도 줄어들면서 소리도 매우 부드러워졌습니다. 모터회전이 부드러워지면서 로드걸린게 풀어진것이죠.

 

  그래도 좀 더 적절하게 돌도록 약 5분정도 회전시킨 뒤 스티커를 원상복구 시켰습니다. 처음에 1초에 1회전도 못했을 당시 전류소모가 약 350mA 정도 였었습니다만, 지금은 매우 부드럽고, 조용하고 전류소모도 180mA로 낮아졌습니다. 흡입력은 선풍기를 만들어도 될정도록 바람의 세기가 꽤 강합니다. 어차피 연기 흡입용이고 배기부에 필터를 씌우게 되면 흡입력이 떨어지게 되므로 흡입력이 강할수록 좋겠지요.

 

 

STEP  5  파워서플라이 PCB 제거

 

  이제 파워서플라이의 PCB를 제거할 차례입니다. 전원공급은 어댑터를 사용할 예정이므로 보드제거는 필수입니다. 덩치도 크고 PCB가 그대로 노출되어 그대로 두면 뭔가 꺼림칙한 느낌도 들겠죠? 제거한 뒤에는 재활용을 해도 됩니다. 케이블이나 레귤레이터 및 쓸만한 부품들이 꽤 많이 들어있습니다 ^^

 

1. PCB 고정나사 제거 : 거의 100%로 PCB 네 귀퉁이에 나사가 있습니다. 이를 제거합니다.

2. 케이블 추출 : 케이스에 달린 케이블은 보통 고정용 플라스틱을 앞으로 빼고 밖으로 움직이면 빠집니다.

3. PCB 추출 : 케이블이 빠지면 파워PCB가 쉽게 빠집니다. 아직 몇몇 선이 남아있습니다.

4. 배선 절단 : 사진처럼 PCB에 연결된 배선들을 잘라줍니다.

5. PCB 제거 : 배선이 모두 잘리면 보드가 빠집니다. 끄집어 내면 됩니다.

6. 마무리 : 그 외 달린 조그만 보드도 떼어내고(납땜으로) 필요없는 배선들을 모두 떼어 정리해줍니다.

 

 

 

STEP  6  케이스 청소 및 팬조립

 

  팬도 청소가 되었으니 케이스도 청소를 할 차례입니다. 저는 보통 미지근한 물에 담궈서 빨래비누나 세제등을 솔에 뭍혀서 벅벅벅 닦아주는 방식을 선호합니다. PCB도 그렇게 청소하지만, 말릴때만 잘 말리면 별 문제는 없습니다. 아참 기계적인 부분이 있는 부품은 주의하셔야겠죠? ^^

 

1. 청소후 모습 : 깨끗하게 청소된 모습입니다. 빨리 말릴땐 드라이나 열풍기를 쓰면 됩니다.

2. 팬 조립 : 이제 부드럽게 움직이는 팬도 커버에 고정시켜 줍니다.

 

 

 

STEP  7  어댑터 개조

 

  어댑터를 손볼 차례입니다만, 가지고 있는 어댑터에 따라서 달라질 수 있습니다. 저는 플러그타입 어댑터가 아니라 양쪽이 모두 케이블로 연결된 타입입니다. 마침 뭘 할려고 한쪽이 끊어진 걸 가지고 있어서 재활용을 했습니다. 12V 제품이지만, SMPS 타입이 아니라 트랜스타입이라 무부하시 15~16V를 왔다갔다 합니다만, 모터는 전압에 덜 민감하기 때문에 그냥 써도 됩니다 ^^ 일반적으로 플러그타입이 많으실텐데, 저처럼 개조를 해도 되고, 그냥 플러그를 전원과 스위치에 선으로 연결해도 됩니다.

 

1. 커버 열기 : 어댑터마다 다르지만 보통 2~4개의 나사가 있습니다. 이를 제거하면 커버가 열립니다.

2. 팬단자 위치선정 : 팬의 케이블을 자를것이 아니므로 몰렉스2핀으로 단자를 케이스에 대봅니다.

3. 팬단자 고정 : 얇은 선쪽에 원래 구멍이 있어서 그곳에 끼운뒤 접착제로 고정을 했습니다.

4. 배선 정리 : 어댑터 내부 PCB의 전원케이블을 납땜으로 깨끗하게 정리해줍니다.

5. 배선 납땜 : 팬단자에 연결할 배선과 220V 단자 및 스위치에 연결할 배선들을 미리 납땜해줍니다.

6. 마무리 : 팬다자에 배선을 연결해주고 케이스를 닫으면 개조는 끝납니다.

 

 

 

STEP  8  케이스 내부 배선

 

  이제 만들어진 어댑터를 케이스에 장착하고 내부 배선만 하면 끝납니다. 대충 80% 정도의 진행도가 되겠네요. 다 완성되기 전에는 반드시 전원을 연결하지 마세요. 저는 이거하다가 모르고 잠깐 220V 전기쇼크 한번 먹었습니다. 알면서도 부주의하면 꼭 한번 당합니다.

 

1. 완성된 어댑터 : 앞단계에서 작업해서 적절하게 변화된 어댑터 모습입니다.

2. 어댑터 고정 : 전원케이블 위치로 무게 배분을 고려해서 왼쪽 아래쪽에 글루건으로 튼튼하게 고정했습니다.

3. 전원커넥터 연결 : 어댑터의 검은색(GND)를 전원커넥터의 GND에 연결하세요. 커넥터에 표시가 있습니다.

4. 스위치 연결 : 어댑터의 다른 한선을 스위치에 연결하고, 스위치의 다른 한쪽을 전원커넥터에 연결합니다.

               추가로 전원커넥터 왼편에 있는 220/110v 전환용 슬라이드 스위치는 제거합니다.

5. 임시 조립 : 잘 작동하는지 확인하기 위해서 커버를 일단 닫아보았습니다. 모양은 괜찮군요. 

6. 동작 확인 : 전원케이블을 연결하고, 스위치를 켜봅니다. 떨림은 없는지, 잘 작동하는지 확인합니다.

 

 

 

STEP  9  전원 LED 달기1

 

  이제 전원을 켜면 불이 들어오도록 전원LED를 달고, 배기부쪽에 필터를 달면 완성입니다. 전원LED는 그냥 모양새일뿐이니 반드시 필요한 것은 아닙니다. 그냥 DIY라고 해도 가급적 이쁘게 만드는게 제 주관이라서 저는 어지간하면 항상 전원LED는 달곤 합니다. 비용적으로도 큰 문제도 없고, 마치 화룡점정의 마침표를 찍는 느낌이랄까요?

 

1. LED 및 저항준비 : LED는 쉽게 구할수 있는 것으로 하시고, 저항은 1K 정도면 대부분 될겁니다.

2. 저항 납땜 : LED에 저항을 납땜합니다. 애노드(+)나 캐소드(-) 어느쪽도 상관없지만, 편의상 + 에 땜합니다.

                   전원을 공급받을 선도 이때 미리 연결을 해두시면 됩니다.

3. 수축튜브에 삽입 : 제품의 외부로 노출되거나 리드선째 작업할때는 가급적 사진처럼 수축튜트를 권합니다.

4. 수축튜브 가열 : 수축튜브는 라이터보다는 드라이기나 열풍기로 가열하면 깔끔하게 잘 됩니다.

5. LED 케이스 : 외부에 LED를 장착할 케이스입니다. DVI 모니터케이블 커넥터쪽 뚜껑을 사용했습니다.

6. ㄱ자로 꺾음 : LED 케이스내로 들어갈 정도로 적절한 위치에서 90로 꺾어줍니다.

 

 

 

STEP  10  전원 LED 달기2 및 필터 달기

 

  LED 작업을 마무리 할 차례입니다. 만든 LED 램프를 전원에 연결하면 끝납니다. 제가 한삽질을 하는 까닭에 내부의 충전기 선정리작업을 할때 미리 선을 넣어두고 글루건으로 붙였어야 했는데, 이미 붙이고 말았군요. 다시 뜯고서 하기엔 너무 귀찮고 의미없어 보여서 그냥 밖에 나와있는 몰렉스 커넥터 밑단에 납땜하였습니다^^ 필터는 가급적 달아주세요. 빨아들인 납연기(송진연기라고 해야겠지만)가 그대로 다시 배출되면 납연제거기의 의미가 없어지니까요 ^^

 

1. LED 케이스 조립 : 앞에서 작업한 90도 리드선을 꺾은 LED를 케이스에 넣고 글루건으로 붙입니다.

2. LED 케이스 접착 : 납연제거기 본체의 적절한 위치(아까 220/110v 전환스위치 위치)에 접착합니다.

3. LED 전원 납땜 : 위에서 말씀드린대로 삽질의 댓가로 몰렉스 커넥터 밑단에 납땜했습니다.

4. 내부선 정리 : 내부 배선을 적절하고 깔끔하게 정리합니다. 케이블타이를 쓰면 좋겠죠? ^^

5. 필터 준비 : 배기구에 크기를 잘 맞추어 자릅니다. 필터는 반드시 공기가 잘 통하는 형태로 준비하세요.

6. 필터 장착 : 나중에 교환이 가능하도록 네 귀퉁이에 3M 77 접착제를 뿌려서 붙였으나, 테이프나 기타 여러

                      방법으로 붙이시면 됩니다. 공기가 잘 통하도록 가급적 모서리쪽만 붙이세요 ^^

 

 

STEP  FIN  마무리 겸 테스트

 

  모든 작업이 마무리가 되었습니다. 뚜껑을 덮고, 고무다리가 있다면 모서리에 각각 붙이시면 좋습니다. 가변저항을 달아서 팬속도를 조절할 수 있도록 만들어도 좋습니다. 그에 대한 작업은 나중에 사진찍어서 추가하도록 하겠습니다. 이제 전원을 켜고 잘 동작하는지 확인해보세요 ^^ 아래 동영상은 가동테스트입니다.

 

 

Posted by 콩알은

댓글을 달아 주세요

기타2012. 1. 28. 09:23

간단하면서 실용적인 작업용 만능 거치대

 

 

제작시간 : 20분 이내

제작비용 : 1,000원

필요공구 : 롱로즈, 전기인두, 납, + 드라이버

 

  DIY 관련, 특히 납땜을 하다보면, 손이 2개가 아니라 4개였으면 할때가 많습니다. 한손에는 인두를 한손에는 납을 쥐고 해야 하는데, 기판이나 부품을 잡아야 할 때가 꽤 있어서 애를 쓰던 적이 한두번씩은 있으실 겁니다. 어느정도 숙달이 되면 사실 큰 고민없이 잘하시는 분도 많지만, 그래도 불편한 것은 사실입니다. 게다가 어쩔때는 테스터의 리드봉이나 전원을 임시로 연결하면서 다른 것도 잡아야 할 때도 있습니다.

  

  이번 프로젝트는 이러한 불편을 덜어주도록 만능손(?) 작업대를 만들어 보겠습니다. 이름만 거창할 뿐 실상은구리선에 클립만 붙인 정도일 뿐입니다. 실제로 이러한 제품을 전자부품 쇼핑몰에서 판매하지만, 사실 사용해 보니, 매우 불편하고 쓸모가 없었습니다. 오히려 아래의 제품이 보다 효율적이고, 저 비용이면서 쓸모가 많다 할 수 있을 것 같습니다.

 

 

  처음에는 아래와 같이 베이스가 나무판으로 된 것을 만들려고 했었습니다만, 제작과정에서 드릴을 사용하거나, 나사못을 사용해야 하는점, 무게가 가벼워서 약간 큰 보드나 작업물을 지탱하지 못한다는 점, 제작과정에서 하드디스크보다 만들기가 더 귀찮다는 점등을 들어서 나무판 버전은 포기하고, 하드디스크 버전으로 만들게 되었습니다.

 

 

 

 

 

제작과정

 

STEP  1  부품소개

 

  부품이라고 해봐야 별것 없습니다. 사실 가장 중요한 점은 자유롭게 구부러지는 구리선과 클립이 핵심입니다. 구리선은 신경 쓴다고 썼지만, 제가 갖고 있는 선중에 눈에 먼저 띄인 것이 케이블TV용 동축케이블이었습니다. 어딘가에 더 두꺼운 선이 있던 것으로 기억되지만 찾기가 귀찮아서 그냥 이걸로 쓰기로 했습니다. 요새는 쓰임새가 전혀 없는 선이라 잘라써도 아깝지는 않더군요(사실 몇개 더 있어서...). 다음은 필요한 부품 리스트입니다.

 

1. 고장난 하드디스크 : 어떤 것이든 상관없습니다(라벨위에 不 x 라고 써있네요 ^^;;)

2. 악어클립 4개 : 5Cm 짜리로 구했습니다. 너무 작으면 무는 힘이 없고, 너무 크면 부담되고 상처납니다.

3. 터미널 링단자 4개 : 구리선을 튼튼하게 지탱하려면 아무래도 이게 확실합니다.

4. 나사 4개 : 보통 컴퓨터에서 파워나 하드를 고정하는 나사입니다.

5. 구리선 : 가급적 두꺼운게 좋습니다. 저는 동축케이블을 사용했습니다.

 

 

 

STEP  2  하드디스크 분해

 

  사실, 하드디스크 분해과정은 큰 필요가 없습니다. 다만, 어차피 베이스로 쓸 거라면, 기판의 부품정도는 나중에 써먹을 수 있도록 빼두어야겠다는 생각으로 제거한 것입니다. 상판까지 분해하면 내부의 스핀들모터나, 플래터, 보이스코일, 헤드와 컨트롤 IC 정도가 더 나옵니다. 크게 활용도가 높은 부품은 아닌지라 그냥 두었습니다.

 

1. 하드디스크를 뒤집는다. : 두뇌(보드)를 분리할 것이므로 잠시 묵념정도는... ^^;;

2. 기판 분해 : 하드마다 약간씩 다르지만, 대체로 +나사를 사용합니다. 눈에 보이는대로 나사를 제거합니다.

3. 케이블 분리 : 보드에 1~2개 정도 케이블(보통 FPC타입)이 있습니다. 보이는대로 분리합니다.

4. 보드 분리 : 약하게 접착되어 있는 경우도 있지만, 살짝 힘을 주면 쉽게 떼어집니다. 스펀지도 떼주세요.

 

 

 

STEP  3  구리선 만들기

 

  이 부분은 제가 동축케이블로 작업했기 때문에 필요한 과정일뿐, 다른 선을 확보한 분들은 필요가 없는 부분이겠죠? ^^사실, 두꺼운 구리선을 일반사람이 구하는 것도 나름 쉬운 일이 아니더군요. 어쨌든 구리선이 두꺼우면 두꺼울수록 좋습니다. 물론 너무 두꺼우면 반대로 작업능률도 저하되므로 대충 구부려보시고 적당한 수준의 선을 사용하세요.

 

1. 분해된 하드사진 : 분해가 된 하드디스크 앞에 잠시 묵념을... ^^;;

2. 케이블 절단 : 동축케이블을 적당한 길이로 자릅니다. 저는 대충 20Cm 정도로 잘라냈습니다.

3. 피복 제거 : 케이블 내의 구리선을 꺼내려면 외피-쉴드-연선-쉴드-내피를 제거해야 합니다(사진참조).

4. 구리선 분리 : 피복을 제거하고 구리선만 남은 모습입니다.

 

 

 

STEP  4  작업용 클립 만들기

 

  부품 선택시 여러가지 악어클립과 지지용 단자를 놓고 조금 고민을 했습니다. 너무 작으면 무는 힘이 약해서 무게가 있는 것은 잘 빠질테고, 너무 크면 무는 힘으로 기판이나 물리는 부품에 손상을 줄 여지가 크기 때문이죠. 하부 지지용 단자도 너무 약하면 납땜으로만 하중을 버티게 되므로 쉽게 떨어져버릴 수 있습니다. 그래서 5Cm급 악어클립과 터미널 링단자를 선택한 이유입니다. 부품을 사러 가게 되면 여러가지 악어클립이 있지만, 악어이빨이 서로 잘 맞물리는지 꼭 확인하세요. 어긋난 제품도 많습니다.

 

1. 구리선을 구부린다. : 악어클립에 그냥 끼우기보다는 좀 튼튼하게 하기 위해서 구부립니다.

2. 클립과 구리선 결합 : 구리선을 악어클립에 끼웁니다. 끼워서 빠지지 않게 잘 마무리를 합니다.

3. 납땜 결합 : 구리선과 악어클립이 튼튼하게 붙도록 넉넉한 양의 납땜을 합니다. 플럭스를 쓰면 잘됩니다.

4. 작업 완료 : 악어 4마리가 회의중입니다. 4개 모두 만들어두시면 끝납니다.

 

 

 

STEP  5  하부 지지대 만들기 및 하드와 결합

 

  위에서 설명했듯이, 하부 지지대도 상당히 중요합니다. 납이 그냥 노출되는 경우 납땜부위가 쉽게 떨어집니다. 그래서 가급적 터미널 링단자와 비슷한 물체로 만드시는게 좋습니다. 이게 그냥 납땜이 어려우므로 미리 홀에다가 납을 넉넉하게 땜해서 밀어넣어둔후 구리선을 끼우는게 쉽습니다.

 

1. 하부 지지대 만들기 : 앞에서 만든 클립 반대편에 하부 지지대를 만듭니다. 색상은 큰 의미 없습니다.

2~4. 하드에 작업용 클립 장착 : 다 만든 작업용 클립을 하드 구멍에 대고 나사로 단단히 고정시킵니다.

 

 

 

 

STEP  FIN  마무리

 

  작업클립 4개를 모두 붙이면 끝납니다. 구리선을 적당히 S자나 원형으로 구부려 두면 작업하기가 한결 수월해집니다. 만일 구리선이 얇으면 약한 진동에도 클립쪽이 떨립니다(동축케이블의 경우 떨림). 그래도 물체를 물려놓으면 괜찮아 집니다. 2개로 진동이 안잡히면 4개의 클립을 물리면 됩니다. 이것과 함께 그래버 프로브(Grabber Probe)를 함께 만들면, 테스터기 사용때나, 오실로스코프 및 전원공급할 때 아주 유용하게 됩니다. 비용이나 시간적인 투자가 크지 않으므로 가급적 함께 꼭 사용하세요 ^^

 

Posted by 콩알은

댓글을 달아 주세요

기타2012. 1. 28. 09:22

쥐뿔도 몰라도 LCD는 내 입맛대로, PC에 LCD를 달아보자

 

 

제작시간 : 20분 이내

제작비용 : 3,000원~7,000원

필요공구 :  전기인두, 납, 니퍼, + 드라이버 (글루건, 전동드릴)

 

  LCD는 가장 대중적이면서도 가장 많이 사용되는 표시장치중 하나로, MCU 관련해서는 필수코스 중 하나입니다. 하지만, 전자회로에 대해 잘 모르는 사람들은 어떨까요? 완제품은 값도 비싸고 실상 달아두어도 별 쓸모가 없어 선뜻 구매하기 어렵기도 합니다. 그러면서도 컴퓨터본체는 왜들 LCD 달린것을 선호할까요? ^^;; 멋진것을 추구하는 것은 아무래도 누구에게나 마찬가지인가 봅니다.

 

  얼마전 당근카페에서 어느분께서 32x2짜리 청색 백라이트 제품을 파격적인 가격에 판매를 했습니다. 저도 몇개 샀는데 어제 저녁에 도착을 했네요. 이미 LCD는 상당히 많은 양을 가지고 있음에도 자꾸 저렴한 것에 손이 가는 것은 참... 절대강자 지름신을 누가 말리겠습니까 ^^ 이참에 다목적용으로 사용할 수 있는 LCD 디스플레이를 만들기로 했습니다. 화면 표시내용을 상당한 자유도로 여러가지를 표시할 수 있고 전자에 슈퍼 울트라 초보분도 20분 이내에 만들수 있는 LCD 표시장치입니다.

 

  2가지 버전으로 진행되는데, 하나는 PC 전면부에 장착할 수 있도록 만든 버전과, 또다른 하나는 외부에서 사용할 수 있는 버전으로 진행됩니다. 내부버전은 드라이브베이에 장착하면 유용할테고, 외부버전은 적절한 케이스나 천원샵에서 파는 천원짜리 액자에 붙여 놓으면 매우 멋있습니다. 지원운영체제는 윈도우즈 95이상이면 가능하며, 지원되는 LCD 포맷은 1x10, 1x16, 1x20, 1x24, 1x40, 2x16, 2x20, 2x24, 2x40, 4x16, 4x20, 4x40 입니다. 참고로 가급적이면 LCD 컨트롤러가 HD44780인 제품이 호환성이 좋습니다.

 

 

  회로는 아래의 사진을 참조하시면 됩니다. 일반적으로 캐릭터 LCD는 14핀의 전원/제어핀과 함께 2핀은 백라이트에 관련되어 있습니다. LCD에서 1번핀은 GND이고, 2번핀은 VCC입니다. 3번의 경우 LCD 콘트라스트 조정인데, 그냥 만들기 쉽고 기본 출력정도로 하기 위해서 GND에 묶었습니다. 5번은 R/W인데, LCD Read는 사용하지 않으므로 GND에 묶으면 됩니다.

 

  VCC의 경우도 15번과 묶은 이유는 이번에 사용할 LCD Smartie 프로그램에서 제어를 할 수는 있지만, 대부분 LCD 백라이트를 켜고 사용하는게 일반적이기 때문에 부품수를 하나라도 줄이기 위해서 삭제를 했습니다. 따라서 프린터에서 LCD로 가는 라인은 데이터라인 2개와 제어라인(RS, E) 2개로 총 10개 선으로 만들 수가 있습니다. 아쉽게도 LCD Smartie에서는 4비트 제어를 지원하지 않습니다.

 

 

 

제작과정

 

STEP  1  부품소개

 

  필요한 부품은 거의 없다시피 합니다. 따라서 초보자분들도 쉽게 따라하실 수 있습니다. 두가지 버전으로 진행되는데 첫번째 버전은 외장형입니다. 32x2짜리는 드라이버에서 지원을 하지 않으니 우선은 가장 대중적인 16x2짜리로 진행하면서 다른 LCD들에서도 테스트를 해보겠습니다.

 

1. LCD 모듈 : LCD 모듈입니다. 사진의 것은 32x2짜리입니다만, 앞서 말씀드렸듯이 진행은 16x2로 합니다.

2. 헤더핀 소켓 : 헤더핀 소켓으로 1x7짜리 2개이나 2x7짜리 1개로도 되며, LCD의 핀배열에 따라 1x14짜리를

                      써야하는 경우도 있습니다.

3. 프린터포트 케이블 : 패래럴포트 케이블이라고도 합니다. 마침 상태 안좋은 것이 있어서 쓰기로 했습니다.

4. USB 케이블 : LCD에 전원을 넣을 용도로 사용됩니다. 신호용도로는 사용하지 않습니다.

 

 

 

1. LCD 모듈 : 설명은 위와 같습니다.

2. 몰렉스 4핀 커넥터 : 내부에서 전원을 공급받아야 하기 위한 3.5" FDD용 전원용커넥터입니다.

3. 헤더핀 소켓 : 위와 같지만, 연결을 보드에 직접 하기 때문에 25핀 헤더핀이 더 필요합니다.

4. HDD 전원커넥터 : 2번과 같은 이유입니다. 2번을 사용할지 4번을 사용할지 결정하시면 됩니다.

5. 플랫 케이블 : 보드와 LCD를 연결할 데이터 케이블입니다. 5번이나 6번을 둘중 하나만 사용하면 됩니다.

6. 랜 케이블 : 전원문제는 해결되므로 랜선(8P)짜리로도 동작이 가능합니다. 5번이나 6번중 선택하세요.

  

 

 

STEP  2  LCD 모듈 준비

 

  위의 사진에는 헤더핀이 달려 있어서 미처 사진을 찍지 못했는데, 실제로는 안달려있는 것을 가지고 계신 분이 계셔서 만드는 법을 올립니다. 헤더핀이 달려있는 경우에는 건너 뛰셔도 됩니다.

 

1. 헤더핀 준비 : CLCD는 보통 14핀이므로 LCD에 따라서 7x2짜리나 14x1짜리를 준비합니다.

2. 헤더핀 장착 : 헤더핀을 LCD의 커넥터 위치에 끼웁니다. 위치나 배열모양은 LCD에 따라 다릅니다.

3. 납땜 : 헤더핀을 끼운뒤에는 납땜을 해줍니다. 끼운면의 반대편에서 납땜하는 것 다 아시죠?

4. 완성 사진 : 완성된 사진입니다. 1열로 된 LCD도 모양만 다를뿐 방법은 이와 다르지 않습니다.

 

 

 

STEP  3  USB 케이블 준비

 

  앞에서도 말씀드렸지만, 패래럴 포트는 LCD를 구동할만한 전원을 공급하지 못하기 때문에 본체 뒷면 프린터포트 근처에 있는 LCD에서 전원을 따오기 위한 USB 케이블이 필요합니다. 다른 방법도 있지만, 현재로서는 이 방법이 가장 무난하다고 말씀 드릴 수 있겠네요 ^^

 

1. 케이블 준비 : 잘려진 케이블이 없어서 더이상 사용하지 않는 구형 핸드폰 충전케이블을 사용했습니다.

2. 케이블 절단 : 적절한 길이로 잘라냅니다.

3. 절단 사진 : 절단된 사진입니다. 절단면 끝을 적절한 길이로 겉을 깝니다.

4. 완성 사진 : USB의 내부 선 색상은 규격이 정해져 있습니다. 적색이 Vcc, 흑색 및 쉴드선이 GND입니다.

 

 

 

STEP  4  패래럴 케이블 준비

 

  이제 LCD를 구동할 데이터가 오고가는 패래럴 케이블을 준비할 차례입니다. 사진처럼 프린터포트쪽이 커버가 달린 제품이 USB 전원을 연결하기 용이합니다. 정 없다면 프린터포트쪽 케이블을 벗겨내서 연결을 하거나, LCD까지 USB 케이블을 연결하거나 해야 해서 매우 불편합니다.

 

1. 커버 열기 : 컴퓨터와 연결하는 쪽 프린터커버를 엽니다.

2. 커버 내부 : 내부는 빼곡하게 선이 연결되어 있습니다. 포트쪽 테두리에 연결된 선은 GND입니다.

3. 케이블 절단 : 프린터에 연결하는 쪽 단자에 가까이에서 케이블을 절단합니다.

4. 절단 사진 : 안타깝기는 하지만, 해당 단자는 사용이 흔치 않은 부품이므로 묵념해줍니다.

5. 피복 벗기기 : LCD와 연결하기 위한 케이블을 꺼내기 위해 적절한 길이로 피복을 벗깁니다.

6. 피복 내부 : GND 선과 쉴드로 되어 있습니다. GND 선은 안써도 되나 일단 두고, 알루미늄 쉴드는 벗깁니다.

7. 내부 손질 : 안쪽에 케이블이 부드럽도록 무명실이 있는데 끊습니다. 없는 경우도 많습니다.

8. 테스터 준비 : LCD와 연결할 선이 어떤것인지 찾기 위해 테스터의 도통테스트를 사용합니다.

9. 포트 연결도 : 프린터포트와 LCD 연결도입니다. 중요한건 2~9번핀, 16번 핀입니다.

10. 핀배열 확인 : 프린터포트 핀과 반대쪽 케이블간 연결도를 테스터로 확인하고 결과를 적은 사진입니다.

                 주의하실점은, 제 데이터가 회원님들과 같지 않으므로 테스터로 꼭 확인을 하시는게 좋습니다.

 

 

 

STEP  5  프린터포트측 배선작업 1

 

  자, 이제 배선작업만 남았습니다. LCD측 배선작업과 프린터포트측 배선작업으로 나뉘어집니다. 뭐 그다지 어려운 것도 없고, 단지 그냥 개인적인 욕심에서 깔끔하게 만드는 것에 중점을 두는 정도일 것 같습니다. 포트를 감싸고 있는 사다리꼴 모양의 금속 테두리는 USB와 마찬가지로 GND에 연결되어 있습니다. 따라서 18~25번인 그라운드핀을 굳이 자를 필요없이 테두리에 납땜하시면 됩니다. 케이블내의 GND 배선도 미리 금속테두리에 납땜이 되어 있군요.

 

1. USB선 정리 : 검은색은 쉴드와 납땜을 했고(안해도 무방) 백색과 녹색은 데이터선이므로 무시합니다.

2. 1번핀 절단 : 프린터포트 쪽에서 사용하지 않는 15번을 과감하게 잘랐습니다. 마침 색상도 적색이군요.

3. VCC 연결 : 잘라낸 15번 적색선을 USB 케이블의 적색과 연결, 수축튜브로 마무리를 합니다(없어도 무방).

4. GND 연결 : 금속테두리 또는 아무 GND 선과 검은색(저는 쉴드선까지 했음)을 연결해줍니다.

 

 

 

STEP  6  프린터포트측 배선작업 2

 

  기본적인 배선은 끝났고, 일단 깔끔하게 마무리를 하려면 USB 전원선 처리를 좀 잘하면 좋을 것 같습니다. 저는 프린터케이블이 나가는 후면구멍 옆을 깎아서 USB 케이블도 그쪽으로 빠져나오도록 만들었습니다. 아참, USB선을 프린터케이블에 연결하기 전에 미리 가공을 해두었습니다.

 

1. 케이스 가공 : 미리 케이스를 가공합니다. 사진처럼 뒷부분에 홈을 뚫었습니다.

2. 가공상태 확인 : USB 케이블을 홈에 잘 들어 맞는지 대어 봅니다.

3. 케이스에 장착 : 작업한 포트를 프린터포트 후드에 장착합니다. 한방에 딱 들어 맞는군요.

4. 완성 사진 : 완성된 사진입니다. 저런 형태로 만드셔서 프린터포트와 USB 포트에 연결하면 됩니다.

 

 

  아래는 캐릭터 LCD의 일반적인 핀배치입니다(LCD가 보이는 면으로 위에서 봤을때). 2x7열의 형태도 있고, 1x14 또는 1x16의 형태도 있습니다. 보통 2x7의 형태의 경우 백라이트를 켜는 핀이 15/16에 달려 있지 않고, 반대쪽에 따로, A와 K로 표기되어 있습니다. A는 Anode로 + , K는 Cathode - 개념으로 생각하시면 됩니다. 즉, A는 Vcc, K는 GND를 의미합니다.

 

  1x14 또는 16열의 경우 왼쪽 첫번째 핀에 1이라고 적혀있으면 아래의 오른쪽 그림에 해당하는 것이고, 오른쪽 첫번째 핀에 1이라고 적혀있으면 맨 왼쪽이 14 또는 16이 되는 배열입니다. 14핀의 경우는 아래의 내용과 같지만, 16핀의 경우는 백라이트를 켜는 A와 K가 나란히 붙은 것으로 생각하시면 됩니다. 보통 15번이 A, 16번이 K입니다만, 자신이 가지고 있는 LCD의 데이터쉬트에 나와있는 핀배열을 가급적 꼭 한번씩 확인해보시기 바랍니다. 일반적일 뿐이지, 제조회사, 모델별로 다를 수도 있습니다.

STEP  7  LCD측 배선작업

 

  앞에서 작업한 케이블을 가지고 이제는 LCD에 연결할 포트를 만들어 보기로 하겠습니다. 납땜간격이 조밀한 편이라서 조금 어려울지 모르지만, 인내를 가지고 하시면 금방 만들 수 있습니다. 주의할점은 위의 배열을 참조하셔서 LCD에 끼울때의 극성을 잘 보셔야 합니다. 납땜하는 핀면으로 보면 좌우가 바뀌게 됩니다(당연히 마주보는 것이니 그렇겠죠?). 극성이 바뀌면 LCD가 고장날 수 있으니 꼭 주의하세요.

 

1. 헤더핀 소켓 준비 : LCD에 끼워질 헤더핀 소켓을 7핀짜리를 준비하거나 긴것에서 잘라서 만듭니다.

2. 접착 : 두개의 헤더핀 소켓을 접착제나 기타 다른 방법으로 붙입니다.

3. 선정리 : 선을 가지런하게 정리합니다. 좀 길게 나오거니 삐죽한 것은 길이가 맞도록 잘 잘라둡니다.

4. 납땜 및 고정 : 하나씩 납땜합니다. 납땜하기 전 해당 선에 수축튜브를 끼워두면 나중에 깔끔해집니다.

5. 수축튜브 : 납땜이 모두 끝나면 수축튜브 작업을 해서 깔끔하고 튼튼하게 붙도록 합니다.

6. 완성 : 완성된 사진입니다. 여기에 실리콘을 채우면 좋겠지만, 동작확인후에 하는게 좋습니다.

 

 

 

STEP  8  CLCD 백라이트 배선작업

 

  앞에서 설명을 드렸지만, 2x7열 제품의 경우 백라이트는 반대쪽에 2핀으로 따로 빠져나온 경우가 많습니다. 이걸 별도로 케이블화 할 수는 있지만, 사실 매우 번거롭습니다. 그래서 백라이트 컨트롤은 포기하기로 한 것입니다. 하고 싶으신 분은 별도로 하셔도 됩니다 ^^;; 저는 아예 A 는 Vcc, K는 GND에 연결했습니다. 연결시 선은 얇을수록 좋겠지만 절연성이 있어야 합니다. 저는 에나멜선을 사용했지만, 일반 래핑와이어를 사용하셔도 됩니다.

 

1. 백라이트 위치확인 : 사진의 왼쪽이 백라이트 단자, 오른쪽이 CLCD 단자입니다. 거리가 좀 있죠?

2. 단자 연결 : 백라이트측에 선을 붙입니다.

3. Vcc/GND 연결 : 백라이트측에서 빼온 선을 각각 A는 Vcc(2번), K는 GND(1번)에 연결합니다.

4. 완료 : 완료된 사진입니다.

 

 

 

STEP  FIN  마무리

 

  LCD 컨트롤 호스트 프로그램은 LCD Smartie 라고 하는 프로그램을 사용했습니다. 현재의 최신버전은 5.4버전인데, 유틸자료실이나 맨위의 링크에서 받으실 수 있습니다. 압축풀면 설치프로그램 없이 바로 폴더안에 LCDSmartie라는 프로그램을 실행하시면 조그마한 창이 뜹니다. 왼편 아래에 Setup에 가셔서 Screens 탭을 누르면 오른편에 디스플레이 세팅이 나옵니다.

 

  거기서 디스플레이 플러그인에 자신이 가지고 있는 LCD 모듈 종류를 고르시면 되는데 거의 대부분이 HD44780 컨트롤러를 사용할테니 HD44780.dll을 선택하시면 됩니다. 그 뒤에 바로 왼쪽의 Screen을 누르면 LCD 사이즈가 나오며 자신의 모듈의 크기를 입력하시면 됩니다. 그뒤 적용이나 OK를 누르면 끝납니다.

 

  아참, 그렇게 해도 화면이 뜨지 않는다면, 일단 해당 프로그램을 종료한 뒤 다시 실행하시면 거의 됩니다. 혹시나 안되시는 분들은, 연결상태를 잘 확인해보시는 것이 좋겠습니다. 이 외에도 다른 프로그램들도 많지만, 대체로 LCD Smartie가 제일 좋은 것 같습니다. Vista도 지원된다고 하니(편법) 쓸만합니다. 사용법은 개인적으로 알아보시는게 좋겠고, 해당 소프트웨어 홈페이지 주소는 http://lcdsmartie.sourceforge.net/ 입니다.

 

1. 완성된 전체사진 : 이번 프로젝트 완성사진입니다. 프로젝트라고 하기엔 너무 간단하죠? ^^

2. 테스트 1 : 하드용량 모니터링 화면입니다. 기본값으로 출력됩니다.

3. 테스트 2 : 메일확인 모니터링 화면입니다. 테스트 1과 마찬가지로 기본입니다.

4. 테스트 3 : 네트워크 모니터링 화면입니다. 마찬가지로 기본입니다.

 

 

 

  클로즈업해서 한 컷 찍었습니다. 나름 괜찮은 모양새를 가지고 있습니다. 기본 프로그램 외에도 해당 홈페이지에는 다양한 플러그인이 있어서 여러 어플리케이션과 맞물리도록 되어 있습니다. 필요한 것들을 받아서 멋지게 활용해보시기 바랍니다. 참고로 완료된 것은 아니고, 외장형이크로 투명아크릴로 된 케이스를 만드는 것이 마지막이 되겠습니다. 아참, 내장형 만드는 것도 케이블 만드는 부분만 게시할 예정입니다. 다른 부분은 같으니까요 ^^ 그럼 즐거운 DIY 되시기 바라면서 동영상 첨부합니다.

 

 

Posted by 콩알은

댓글을 달아 주세요

기타2012. 1. 28. 09:21

브레드보드용 소형 5v / 3.3v 전원장치 만들기

 

 

 

제작시간 : 20분 이내

제작비용 : 2,000원

필요공구 : 전기인두, 납, 니퍼, 글루건, 커터+아크릴커터, + 드라이버(방열판장착시)

 

 

  브레드보드에서 이런 저런 작업을 하다보면, 환경에 따라서 파워서플라이로 전원을 공급할 때도 있고, 전원어댑터등에서 따서 연결할 때도 있습니다. 그런데, 때로는 브레드보드 자체에 전원장치가 달렸으면 하는 때가 많습니다. 이것저것 하다보면 사무실/학교등에서 작업을 다 못해서 집에서 해야 하는데 집에서는 전원연결 환경이 부족하다던가 할 때는 더 절실해지겠죠.

 

  저도 이런 경우를 자주 느끼곤 해서 이번에 브레드보드용 전원장치를 만들기로 했습니다. LM317을 이용해서 3.3V와 5V를 공급하도록 하려고 합니다. 물론 약간 큰 보드들은 레귤레이터가 달려 있어서 거기에서 따오기도 하지만, 헤더핀으로 브레드보드에 장착되도록 된 모듈의 경우에는 전원장치가 대부분 달려 있지 않습니다. 결과적으로 약간의 돈과 시간만 투자하면, 여유롭게 작업을 할 수 있는 환경이 되는 것이지요. 물론, 이러한 것이 필요없는 분들도 계십니다만, 대다수 분들은 개발환경이 그렇게 좋지 못하다는 점을 미리 생각해주세요 ^^

  아래의 회로가 이번에 제작할 브레드보드용 소형 전원장치 회로도입니다. 3.3V와 5V가 동시에 공급되는 것이 아니라 공급전압을 선택하면 해당 전압으로만 전원이 공급됩니다. 둘다 동시에 사용해야 할 경우에 필요한 회로는 나중에 따로 또 계획해서 만들어 보겠습니다 ^^ 원래는 3.3v와 5v만 공급하려고 했지만, 12v도 쓰일 경우가 좀 있는듯 해서 약간 변경을 했습니다.

 

  단, 조건이 있는데, 어댑터는 SMPS 타입의 12v 어댑터를 사용할 것을 권해드립니다. 트랜스타입의 경우 12v가 정확하게 나오지 않는 이유에서입니다. 만일 12v를 사용하지 않을 경우는 회로도에서 12v 전원으로 빠진 부분을 생략하고 만들면 됩니다. 예를 들어 S1(스위치) 오른쪽의 12v를 없애고, J3 커넥터를 2핀으로 바꾸고, 3번의 12v를 빼면 됩니다. 첨부된 파일중 schematic.jpg를 다운받으시면 크게 보실수 있습니다.

 

 

  아래 그림은 만능기판 PCB로 만들때의 배치입니다. 첨부된 파일중 pcb.jpg는 실크가 없이 부품과 배선만 나와있는 것이고, pcb2.jpg는 아래와 같은 사진입니다. 만드실 때 만능기판 위치 참조용으로는 pcb.jpg가 좋습니다. 그리드가 교차하는 지점들이 만능기판 구멍에 해당됩니다. 추가로, 붉은색 선은 파란선과 교차되지 않도록 그냥 점퍼를 날리시면 됩니다(그냥 단선으로 이으시면 됩니다). 이 점에 대해서는 만드는 과정에서 다시 설명을 하도록 하겠습니다.

 

  부품을 이보다 더 적게 배치를 할 수 있지만, 그렇게 하면 모두 와이어링으로 만들어야 하므로, 일부러 적당한 배치를 했습니다. 대충 만능기판 칸갯수로 12x12 칸 정도 사이즈로 만들수 있습니다. 이정도만 되어도 가로세로 약 3~4cm 사이즈밖에 안되므로, 괜찮을듯 합니다. 회로도나, PCB에서 오류가 있는데, Molex 3P은 잘못된 표기입니다. 헤더핀소켓이나, 라운드소켓 3핀짜리를 사용하시면 됩니다.

 

 

 

제작과정

 

STEP  1  부품소개

 

  대부분 전자회로쪽에서 자주 사용되는 부품위주로 되어 있어서 부품수급에 어렵지 않겠지만, 240옴이나 390의 경우는 아주 자주 사용되는 것은 아니므로 없다면, 저항두개를 직렬로 이어서 사용하셔도 됩니다. 저항 두개를 직렬로 붙이면 저항두개의 저항값의 합이 됩니다. 그 외에, 슬라이드 스위치(비싸네요) 대신에 다른 스위치를 사용하셔도 무방합니다. 다만, 스위치에도 정격이 있고, 아주 작은 슬라이드 스위치의 경우 6V 정도의 저전압 제품도 있는데 이는 전원스위치로 부적당합니다.

 

1. LM317T Adjustable 레귤레이터 : 이번 프로젝트의 핵심이 되는 가변형 레귤레이터입니다.

2. 슬라이드 스위치 : 한개는 전원스위치, 다른 한개는 전압선택 스위치입니다. 크기가 작은 것이 편합니다.

3. 100uF 전해 캐패시터 : 전원입력단에 사용될 전해 캐패시터입니다. 사용될 어댑터보다 내압이 커야합니다.

4. 10uF 전해 캐패시터 : 전원출력단에 사용될 전해 캐패시터입니다. 입력/출렬단 모두 50V 제품입니다.

5. 헤더핀 2핀 : 브레드보드에 꽂을 헤더핀입니다. 2핀만 있으면 충분합니다.

6. 몰렉스 2핀 : 어댑터가 아닌 PC 파워나, 파워서플라이에서 전원을 가져올 경우 사용되는 커넥터입니다.

7. 0.1uF 세라믹 캐패시터 : 극성이 없는 세라믹 캐패시터입니다. 104라고 표기되어 있습니다.

8. 240옴 저항 : 색띠는 빨노갈, 오차는 5%입니다. FeedBack용 저항입니다.

9. 330옴 저항 x 2개 : 색띠는 등등갈(등색은 주황색), 오차는 5%입니다. LED 및 Adjustable용 저항입니다.

10. 390옴 저항 : 색띠는 등백갈, 오차는 5%입니다. Adjustable용 저항입니다.

11. 전원 LED : 전원이 ON 되었는지 알려주는 LED입니다. 일반적인 LED 사용하시면 됩니다.

12. 라운드소켓 3핀 : 와이어링으로 전원을 공급하기 위한 소켓입니다. 없으면 헤더핀소켓을 사용해도 됩니다.

13. 전원잭 : 어댑터를 연결할 전원잭입니다.

14. 만능기판 : 모든 부품이 장착될 만능기판 PCB입니다. 12x12칸만 있으면 됩니다.

 

 

 

STEP  2  PCB 준비

 

  저는 보통 PCB에서 필요한 만큼 잘라서 쓰는데, 패드와 패드 사이를 절단해서 사용합니다. 그래야 절단했을때 단면이 보기가 좋습니다. 절단시 보통 아크릴커터와 쇠자를 사용해서 양면으로 여러번 그어낸후 칼로 마무리를 하면, 깨끗하게 절단이 잘 됩니다.

  

1. PCB 크기 선정 : 필요한 만큼을 아크릴커터로 그어둡니다. 여러번 그어야 눈에 잘 보입니다.

2. PCB 절단 : 그어둔 부분을 양쪽 모두 아크릴커터로 여러번 그은후 칼로 몇번 그으면 깨끗하게 절단됩니다.

3. PCB 다듬기 : 일반 커터로 절단면을 다듬어서 매끄럽게 해줍니다. 보기도 좋고, 기능적으로도 좋습니다.

4. 완성 사진 : 완성된 사진입니다. 100원짜리 동전보다 약간 크군요. 정확히 12x12칸입니다.

 

 

 

STEP  3  부품 장착

 

  부품과 PCB가 모두 준비되었으면 기판에 부품을 실장할 차례입니다. 크기가 매우 작으므로, 위치선정에 주의하시고, 잘 모르시겠으면 위에서 보여준 기판도면을 보고 위치를 파악해서 장착하면 됩니다. 12V용 레귤레이터를 따로 사용하지 않으므로, 12V가 고르게 출력되는 SMPS 타입 어댑터를 사용하시면 좋습니다. 저는 마침 여유가 있어서 이를 사용하기로 했습니다.

 

1. 어댑터 확인 : 사용할 어댑터가 12V 출력이 맞게 되는지 테스터로 확인합니다. 꽤 양호한 출력이군요.

2. 방열판 장착 : LM317에 방열판을 장착합니다. 앞에서 소개를 못했지만, 레귤레이터의 경우 5V 이상의

               전압차의 입력전압이라면 방열판을 장착해주는 것이 좋습니다.

3. 위치 확인 : 부품위치 및 공간 파악을 위해서 가조립을 한번 해본 모습입니다.

4. 1차 부품 : 기준이 되는 위치로 저항과 몇가지 부품(100uF 캐패시터, 몰렉스 커넥터)을 장착후 납땝합니다.

5. 전원잭 준비 : 전원잭은 만능기판에 안들어 갑니다. 핀을 모두 잘라낸후 저항에서 남는 다리를 이어줍니다.

               전원잭은 3핀으로 되어 있고 사진에는 안보이지만, 앞쪽 2핀은 서로 이어주어야 전원이 들어옵니다.

6. 2차 부품 : 1차 이후 남은 10uF, 0.1uF 캐패시터와, 슬라이드 스위치, LED 및 전원잭을 장착후 납땜합니다.

7. 3차 부품 : 브레드 보드에 꼽힐 헤더핀과 라운드소켓 3핀을 추가로 장착후 납땜합니다. 

8. LM317 납땜 : 가운데에 비워둔 LM317과 방열판을 장착후 납땜합니다. 방열판에 있던 핀은 잘랐습니다.

 

 

 

STEP  4  배선작업

 

  이제 남은 것은 배선작업과 테스트 뿐이군요. 간단한 회로이지만, 가지고 있는 부품이나 개인 선호도에 따라서 배선이 달라질 수 있습니다. 저도 처음에 올린 것과 조금 다르게 부품배치를 하다보니, 배선이 약간 나빠지게 되었습니다. 그래서 점퍼가 두개인가 더 생겼는데, 쓸데없이 뜨게질하다보니 점프와이어가 많은 것처럼 보입니다.

 

  배선작업에 대해서는 회로도와 PCB 레이아웃을 보시면서 연습하시는 수밖에 없습니다. 한지점 한지점 연결하는 법을 작성하다가는 아마도 지금의 열배는 넘는 설명 분량이 될것 같습니다. 기본적으로 배선은 GND 배선을 먼저하면 편리합니다. 배선중 가장 많은 것이 역시 GND이기 때문이죠.

 

1. 배선 작업 : 우선 GND끼리 연결되는 배선을 먼저한 후에 VCC, 나머지 배선을 하는 것이 좋습니다.

2. 어댑터잭 고정 : 고정은 되어 있지만, 어댑터잭의 원래다리로 고정한게 아니므로, 글루건으로 보강합니다.

3. 고정 완료 : 글루건으로 추가로 보강한 모습입니다. 글루건은 아직 미흡하군요. ㅠㅠ

4. 완성 모습 : 모든 작업이 완성된 모습입니다. 작아서 예쁘군요. 

 

 

 

STEP  FIN  마무리

 

  만드는 작업이 끝났으니, 테스트를 해볼 차례입니다. 앞에서 이미 어댑터가 12V가 고르게 출력되는 것을 확인했으므로, 어댑터는 확인할 필요가 없겠네요. 브레드보드에 장착하기 전에 각 핀별 출력이 제대로 되는지 테스터기로 확인을 해봅니다. 저는 12.09v와 3.29v, 5.01v로 꽤 정확한 출력이 되는 것을 확인했습니다. 이후에 브레드보드에 장착한 모습입니다.

 

  전원 LED 및 전원 모두 양호하게 동작합니다. 브레드보드 상단의 가로부분에 장착을 해도 되고, 세로부분에 장착을 해서 사용해도 됩니다. 이외에도 보드에서 12v를 빼서 추가로 사용이 가능하기 때문에 편리합니다. 2천원정도의 비용을 들인 제품치고는 만족도가 꽤 좋습니다. 디바이스마트같은 곳에서 판매중인 전원장치보다도 훨씬 더 편리하고 예쁩니다. PCB를 만들어서 원하시는 카페회원분들에게 키트로 판매할 예정입니다.

 

 

  사용방법은 아래와 같습니다. 어댑터입력에 어댑터(12v)를 연결하거나, 외부전원 입력단자에 전원일 입력하고, 전원스위치를 켜면, 전원LED에 불이 들어오고, 3.3v / 5v 전환스위치 세팅에 따라서 브레드보드 장착용 헤더핀과 뒷면의 12v / GND / 3.3~5v 소켓이 전원이 들어옵니다. 뒷면의 12v는 전원입력에 따라서 달라지겠죠. 그래서 앞에서 가급적 SMPS 타입의 전원어댑터를 사용하라고 말했던 것입니다.

 

  전환스위치는 한쪽은 3.3v, 다른쪽은 5v이므로 용도에 맞춰서 조절해서 사용하면 헤더핀의 출력은 그에 맞춰 자동으로 전원이 출력되며, 후면의 포트중 맨 오른쪽 포트도 마찬가지로 스위치 설정에 맞게 전압이 변경됩니다. 아쉽지만, 3.3v와 5v 동시출력은 안됩니다.

 

Posted by 콩알은

댓글을 달아 주세요

AVR2012. 1. 19. 14:49

1. 채터링이란 어떤건가요? (통상 10ms이내 시간동안 발생하는 건가요?)

 

chattering :

 

사전에 나온 정의- 전자 회로 내의 스위치나 계전기의 접점이 붙거나 떨어질 때 기계적인 진동에 의해 실제로는 매우 짧은 시간

 

 안에 접점이 붙었다가 떨어지는 것을 반복하는 현상. 이는 회로에 나쁜 영향을 끼치므로 제거해야 한다.

 

실무- 스위치의 과도 현상에 의하여 나타나는 전류의 단속 현상

 

(기계식스위치는 접점을 스프링으로 유지하기 때문에 접점을 만들거나 끊을때 과도기적인 진동이 뒤따른다)

 

예하나 들면 제일 찾기 쉬운것이 리밋트 스위치 처럼 내부에 스프링이 내장되있는 타입입니다.

 

리밋트 스위치를 하나 들고 톡 건드리신 후 잘 보세요

 

자세히 보시면 떨림이 보일겁니다 -이게 채터링현상입니다

 

2. 채터링을 해결하기위해서 HW/SW적으로 어떤 방법이 사용이 되나요?

 

조치방법은 아래의 두가지 방법으로 가능합니다.

 

내부장치 :  리드 스위치(영구 자석 응용) ,  터치 스위치(가변 커패시턴스 응용)

 

외부회로 :  적분회로 + 파형 성형 회로(커피시터의 충방전 응용) , RS 플립플롭(기억 유지 응용)

 

 

 

 

 

 

3. 만약에 PLC SW적으로 해결한다면, 어떻게 하면 되나요?

 

   (타이머를 50ms정도 해서 해결할려고 했지만, 스위치 입력이 많은 경우 시간 딜레이 loss가 많이 생겨서 결코 바람직하지 안은

 

것 같습니다. 다른 좋은 방법이 있나요? 만약에 50개~100개 이상의 입력이 있는경우는 어떻게 하면 효율적으로 시간낭비 없이 입

 

력 채터링을 해결할수 있나요?)

 

프로그래밍으로 잡는것은 한계가 생깁니다.

 

타이머로 잡으면 시간의 loss가 생겨서 응답시간이 제대로 맞지 않기 때문에

 

응답시간이 중요한 프로그램에서는 사용 할 수가 없습니다.

Posted by 콩알은

댓글을 달아 주세요

AVR2012. 1. 17. 23:51

High-performance, Low-power AVR® 8-bit Microcontroller
(고성능, 저전력 8비트 마이크로컨트롤러)


Advanced RISC Architecture-확장 RISC 구조
- 133 Powerful Instructions-Most Single Clock Cycle Execution
(133개의 명령어를 제공 - 대부분의 명령이 한 클럭에 동작된다.)

- 32 x 8 General Purpose Working Registers + Peripheral Control Registers
(32개의 8bit 범용 작업 레지스터 + 주변장치 제어 레지스터)

- Fully Static Operration

- Up to 16 MIPS Throughput at 16 MHz
(16MHz에서 16MIPS 성능)

- On-chip 2-cycle Multiplier
(2사이클에 곱셈이 되는 곱셈기를 내장하고 있다.)


High Endurance Non-volatile Memory segments
- 128k bytes of in-system self-programmmable Flash program memory
(내부에 프로그램 가능한 128Kbyte의 Flash내장)

- 4Kbytes EEPROM

- 4kbytes internal SRAM

- Write/Erase cycles : 10,000 flash/100,000 EEPROM
(flash : 10,000번 쓰기/지우기 가능,  EEPROM : 100,000번 쓰기/지우기 가능)

- data retention : 20years at 85c / 100 years at 25c
(85도씨에서 20년, 25도씨에서 100년의 데이터 수명을 가진다.)

- Optional Boot Code Section with Independent Lock Bits
(독립적인 락비트를 가진 추가적인 부트 코드 영역을 가지고 있다)
     In-System Programming by On-chip Boot Program 
     (프로세서 내부의 부트프로그램에 의한 ISP 프로그램)
    True Read-While-Write Operation

- Up to 64Kbyte Optional External Memory Space
(64Kbyte까지 외부메모리 확장 가능)

- Programming Lock for Software Security
(소프트웨어 보안을 위한 프로그램가능한 락비트)

- SPI Interface for In-System Programming
(ISP프로그램을 위한 SPI 인터페이스 핀)


JTAG(IEEE std. 1149.1 Compliant) Interface
- Boundary-scan Capabilities According to the JTAG Standard

- Extensive On-chip Debug Support
(온칩 디버그를 가능)

- Programming of Flash, EEPROM, Fuses and Lock Bits through the JTAG Interface
(Flash, EEPROM를 쓰거나 Fuses 와 Lock bit 설정 가능)


Peripheral Features(주변장치 특징)
- Two 8-bit Timer/Counters with Separate Prescalers and Compare Modes
(2개의 8비트 타이머/카운터)

- Two Expanded 16-bit Timer/Counters with Separate Prescaler, Compare Mode and Capture Mode
(2개의 확장 16비트 타이머/카운터)

- Real Time Counter with Separate Oscillator
(분리된 오실레이터에 의한 Real Time Counter)

- Two 8-bit PWM channels
(2개의 8비트 PWM채널)

- 6 PWM Channels with Programmable Resolution from 2 to 16 Bits
(6개의 2~16비트로 설정할 수 있는 분해능을 가진 PWM채널)

- Output Compare Modulator

- 8-channel, 10-bit ADC(8채널, 10비트 ADC)
   8 Single-ended Channels
   (8개의 한개 단자 체널)
   7 Differential Channels
   (7개의  차동 채널)
   2 Differential Channels with Programmable Gain at 1x, 10x, or 200x
   (2개의 Gain설정 차동 채널)

- Byte-oriented Two-wire Serial Interface
   (2선을 이용한 시리얼 통신 (TWI))

- Dual Programmable Serial USARTs
   (2개의 전 이중 시리얼 통신포트)

- Master/Slave SPI Serial Interface
   (마스터/슬레이브 SPI 시리얼 인터페이스)

- Programmable Watchdog Timer with On-chip Oscillator
  (내부 오실레이터를 가진 프로그램 가능한 와치독 타이머)

- On-chip Analog Comparator
  (칩 내부 아날로그 비교기)

Special Microcontroller Features(특별한 마이크로 컨트롤러 특징)
- Power-on Reset and Programmable Brown-out Detection
(전원이 불안할때 Reset 하는 기능)

- Internal Calibrated RC Oscillator

- External and Internal Interrupt Sources
(내부 외부 인터럽트)

- Six Sleep Modes : Idle, ADC Noise Reduction, Power-save, Power-down,
 Standby, and ExtendedStandby
(6개의 슬립모드 : 아이들, ADC 노이즈 감소, 파워절약, 파워다운, 대기, 확장대기)

- Software Selectable Clock Frequency
(소프트웨어로 선택가능한 클럭 주파수)

- ATmega103 Compatibility Mode jSelected by a Fuse

- Global Pull-up Disable
(풀업 디스에이블 가능)

I/O and Packages
- 53 Programmable I/O Lines
(53개의 설정가능한 입출력(I/O)포트)

- 64-lead TQFP and 64-pad QFN/MLF
(64핀 TQFP와 64핀MLF)

Operating Voltages(동작 전압)
- 2.7 ~ 5.5V ATmega128L
- 4.5 ~ 5.5V ATmega128

Speed Grades(클럭 주파수)
- 0~8 MHz ATmega128L
- 0~16 MHz ATmega 128

Posted by 콩알은

댓글을 달아 주세요

AVR2012. 1. 16. 09:34

 

8 : AVR 프로세서로 외부 인터럽트를 제어해보자!


이 강좌는 2010-05-03 에 시작하여 2010-08-02 에 완료한 강좌입니다. ]

 

 

안녕하세요뻔뻔강사 입니다.

 

~ 8그토록 기다렸던 8강 입니다.

(* 이게 월드컵이라면 얼마나 좋았겠습니까흑흑아쉬워아쉬워.)

 

제가 알기로 이 8강을 목~~~ 빠지게 기다리던 통에 목 디스크 걸릴 뻔 하셨단 분들이 더러 계시다던데(-_-;;;) 차후에 혹술 자리에서 뵙게 되면 술 한잔 꼭 대접해 올리겠습니다. (_._)

 

여러분들이 기다리셨던 것만큼 저 역시 기다려왔던 8강입니다.

아시는 분들만 아신다는 제 책(-_-;;;)이 얼마 전에 출간되고 요즘 들어 아주 난리(?)가 난 안드로이드 강의와 몇 가지 외부 업체들과의 일들로 인해 차분하게 책상에 앉아 글을 쓸만한 여유를 갖지 못했었네요.

 

이제부터 조금씩 조금씩 마음의 여유를 갖고 다시금 강좌를 올려 드리려 하오니 그간 올려주셨던 수많은 덧글들처럼 따뜻한 격려의 덧글 많이 많이 부탁 드립니다. (_._)

(* 일일이 덧글들에 답변 드리지 못해 정말 죄송합니다그래도 모든 덧글들 빠짐없이 확인하고 있으니 앞으로도 많이 부탁 드려요그것만이 글을 쓰게 하는 힘이 됩니다. ^^;;)

 

지난 7강에서 다뤘던 “타이머/카운터” AVR의 첫 번째 고비였다면 이후 TWI(I2C)가 두 번째 고비로 다가 올 것입니다그때까지는 비교적 쉬운 편이오니 마음 편하게 읽어 주시면 감사하겠습니다.

 

시원한 아이스커피라도 한잔 옆에 놓고 시작해 볼까요? ^^;;;

 

! 8강에 들어가기 앞서 여러분들께 한가지 부탁을 드릴게요.

반드시 7강을 먼저 읽어 보시고 8강을 읽어주세요!

 

이미 7강에 인터럽트와 관련된 중요한 이야기들을 많이 해두었으므로 그러한 내용들을 8강에서 다시금 꺼내지는 않을 테니까요 7강을 먼저 읽고 8강을 읽어 주시면 감사하겠습니다. (_._)

 

 

외부 인터럽트(External Interrupt)?

 

이번 8강의 주제는 제목에서 보여지는 “외부 인터럽트(External Interrupt) 입니다.

 

사실 외부 인터럽트란 건 별거 없습니다.

말 그대로 CPU 외부, CPU 바깥 주변에 있는 하드웨어(디바이스)로부터 미리 약속된 특정 신호(?) 값이 CPU로 입력되면 그에 따른 인터럽트를 발생시키는 게 바로 외부 인터럽트입니다.

 

정말 쉽죠? ^^;;

 

그런데이제껏 제 글을 읽어주셨던 분들이라면 ‘뻔뻔강사가 이렇게 단순하게 끝내진 않겠지?’ 라고 기대하실지도 모르겠습니다.

 

바로 그렇습니다뻔뻔강사는 그냥 끝내지 않습니다. (^-^)@

 

지난 번 타이머/카운터 강좌에서는 인터럽트 서비스가 실행되는 과정에 대해 설명 드렸었다면이번 강좌에서는 ‘인터럽트그 자체에 대해 좀 더 깊게 살펴보려고 합니다.

 

먼저 이번 강좌의 제목인 ‘외부 인터럽트’ 란 말을 보면서외부 인터럽트그럼 내부 인터럽트도 있단 얘긴가라고 생각하셨던 분들은 공학도로서의 호기심 지수가 무척 높으신 분들이라고 생각됩니다. 그냥 넘어가지 않고 언제나 물음표(?)를 던지려는 공학도야말로 발전 가능성이 무척 높다라는 건 너무나 당연한 사실이지요.

 

그렇습니다외부 인터럽트처럼 내부 인터럽트도 있습니다다음 표를 볼까요?

 

< 8-1> 외부 인터럽트 vs 내부 인터럽트

내부 인터럽트 = 소프트웨어(SW) 인터럽트

외부 인터럽트 = 하드웨어(HW) 인터럽트

CPU 내부에서 실행되는 소프트웨어(SW) 요청에 의해 발생되는 인터럽트

타이머/카운터

CPU 외부에 있는 주변 하드웨어(HW) 요청에 의해 발생되는 인터럽트

네트워크 카드센서

 

< 8-1>에 보니 ‘내부 인터럽트의 대표적인 예로 지난 7강에서 배웠던 타이머/카운터가 나오는군요혹시 다음 그림 기억 나시나요?

 

<그림 8-1> ATmega128 타이머/카운터 내부 구조

 

타이머/카운터 강좌에서 설명 드렸다시피 타이머/카운터는 CPU Core가 요청한 시간이 되면, Prescaler가 적용된 클럭의 개수를 카운트 완료하면 이를 CPU Core에게 <그림 8-1>과 같이 인터럽트 방식으로 알려준다고 했었죠이때 사용되는 인터럽트가 Overflow 방식과 Output Compare Match 인터럽트 방식이 있었다고 설명 드렸습니다.

 

<그림 8-1>을 보면 인터럽트가 어디서 발생되고 있나요그렇습니다. ATmega128 내부에서, CPU 내부에서 발생되고 있죠이렇게 CPU 내부에서 발생되는 인터럽트를 내부 인터럽트라 합니다.

 

여기서 한 가지 더!

타이머/카운터 인터럽트는 왜 발생하게 되었을까요우리가 LED 1초마다 한번씩 켰다 껐다 하기 위해서, CPU Core에서 실행되는 소프트웨어(SW = AVR Firmware) 1초라는 시간을 측정하기 위해서 타이머/카운터에서 지원하는 인터럽트가 발생되었던 것입니다. 따라서, < 8-1>에서 적어놓은 것처럼 내부 인터럽트는 CPU 내부(= CPU Core)에서 실행되는 소프트웨어(SW) 요청 때문에 발생하는 인터럽트라 해서 일명 ‘소프트웨어 인터럽트’ 라고도 불립니다. 다음 그림을 볼까요?

 

<그림 8-2> 리눅스 내부 구조(Linux System Architecture)

 

<그림 8-2>는 요즘 스마트폰에 사용되는 안드로이드(Android)로 인해 다시금 제2의 전성기를 누리고 있는 리눅스(Linux)라는 운영체제(OS)의 내부 구조를 그린 그림입니다.

 

Linux  Windows 같은 Non-RTOS(= RTOS가 아닌 OS)들은 RTOS와 달리 가상 메모리를 사용하여 User Application이 동작하는 User Level  OS(= Kernel)가 동작하는 Kernel Level 이 구분되어 있습니다. 여기서 구분되어 있다는 말은 하드웨어적으로 구분되어 있다는 말입니다.

 

가령 AVR 프로세서에서는 CPU 동작 모드” 라는 말이 없습니다. Firmware RTOS는 인터럽트를 제외하곤 모든 태스크들이 전부 하드웨어적으로(= CPU 동작 모드가동일하게 실행되기 때문입니다그러나, Linux  Windows 같은 Non-RTOS 들은User Level 의 태스크들, User Application들과 Kernel Level의 태스크들디바이스 드라이버 등은 하드웨어적으로(= CPU 동작 모드가서로 다르게 동작된다는 말입니다조금 더 어렵게 얘기하자면 User Level에서 실행되는 CPU 동작 모드를User Mode, Kernel Level에서 실행되는 CPU 동작 모드를 Supervisor Mode라고 합니다조금 복잡하죠.

 

조금 더 자세하게 설명 드리고 싶지만 그러자니 한도 끝도 없을 듯 하여여기까지만 설명 드리고여기에서는 ‘내부 인터럽트’, , ‘소프트웨어 인터럽트에 좀 더 집중해 보도록 하죠.

 

<그림 8-2>에 보면 User Level  Kernel Level 사이에 Software Interrupt 라고 적혀진 부분이 보일 겁니다앞서 User Level  Kernel Level 은 서로 다른 CPU 동작 모드로 실행된다고 했는데이 말이 <그림 8-2> 에 보여진 Linux 내부 구조와 무슨 상관이 있는고 하니, Linux 에서는 User Application 을 실행시키는 User Level  CPU 동작 모드(= User Mode)에서는 절대로 OS(= Kernel) 가 동작되는 메모리 영역으로 접근할 수 없다는 말입니다다시 말해, User Application 에서 직접 OS 내부에 있는 디바이스 드라이버나 기타 OS 내부 서비스 함수를 직접 호출할 수 없다는 뜻입니다, User Level  Kernel Level 사이엔 넘지 못할 강이 있다는 거죠.

 

그러나 우리가 어떤 User Application들을 실행시키더라도 실제 실행이 되는 건 또 왜일까요가령 우리가 printf() 라는 함수를 실행시키면 OS 내부에는 이에 대한 대응 함수가 실행되게 될 텐데 도대체 어떻게 해서 User Application 에서 호출된 함수에 대한 정보가 OS 내부에 전달되게 될까요바로 Software Interrupt 에 해답이 있습니다다음 그림을 볼까요?

 

<그림 8-3> Linux 에서의 SW 인터럽트 처리 과정

 

<그림 8-3>을 앞서 보여드렸던 <그림 8-2>와 비교해 보면 User Application 에서 OS(= Kernel) 내부로 해당 함수의 정보가 전달되는 과정 중에 SW 인터럽트가 중요한 교량 역할을 하고 있음을 알 수 있습니다결코 건널 수 없던 강을 인터럽트란 방식으로 넘기도록 구현된 게 RTOS 가 아닌 OS, Non-RTOS 들이 User Application 들을 실행시켜 주는 방식이거든요.

 

여하간 이때 사용되는 Software Interrupt 역시 User Application 이라는 소프트웨어(SW) 요청 때문에 발생된 인터럽트이므로 타이머/카운터와 마찬가지로 내부 인터럽트라 할 수 있습니다.

 

반면 외부 인터럽트는 어떤 것들이 있을까요역시 다음 그림을 또 볼까요? ^^;;

 

<그림 8-4> 외부 인터럽트 예 : 네트워크 카드

 

<그림 8-4>은 우리가 흔히 사용하는 인터넷 메신저를 예로 들었습니다.

가령 다음과 같은 상황을 잠시 떠올려 보죠.

 

(뻔뻔강사)

어제 좋은 거 하나 다운 받았는데 보내줄까?

(친구)

당근이지어여 보내.

 

뻔뻔강사 님이 친구 님에게 파일을 전송합니다.

 

잠시 후

(친구)

이게 뭐야너 수준이 고작 이 정도였어?

(뻔뻔강사)

-_-;;;

(친구)

이거 보고 레벨 좀 높여라언제까지 그럴래?

(뻔뻔강사)

-_-;;;

 

친구 님으로부터 전송된 파일을 수신합니다.

 

잠시 후

(뻔뻔강사)

오오오오오~~~ 역시 넌 내 베스트 프렌드야.

(친구)

너도 내 베스트 프렌드 좀 되면 안되겠니레벨 좀 높여서…

(뻔뻔강사)

-_-;;;

첨언 : 단순한 예일뿐 오해하지 마세요! -_-;;;

 

위에 언급된 상황을 보고 어떤 생각이 드시나요?

(* 묻고 나서 질문을 보니 질문이 더 이상하군요. -_-;;; 쿨럭~)

 

위에서 중요한 건 내가 친구에게 파일을 보낼 때송신(TX)할 때와 친구로부터 파일을 수신(RX)할 때의 상황이 <그림 8-4>와 같을 수 있다는 얘기입니다.

(* 절대로 레벨 업..이나 그런 얘기가 중요한 게 아닙니다. -_-;;; 쿨럭~~~)

 

내가 파일을 보낼 때에는 이미 보내고자 하는 파일이 내 컴퓨터 안에 있으므로 보내는 데에는 그리 문제가 없어 보입니다그러나친구로부터 파일을 받고자 할 때엔 문제가 있을 수도 있어 보이는데 어떤 문제가 있을 수 있을까요?

 

가령 외부 인터넷의 연결 상태가 좋지 않을 경우엔 어떻게 될까요?

이 경우 두 가지 방법을 생각해 볼 수 있습니다.

 

첫 번째 방법은 네트워크 카드 내에 있는 수신 버퍼에 데이터가 꽉 찰 때까지 계속 수시로 CPU 쪽에서 물어보는 방법입니다.계속 물어보다가 수신 버퍼에 꽉 차게 되면 그때 CPU 쪽으로 데이터를 가져오면 되겠죠.

 

두 번째 방법은 CPU가 너무나 바빠서 수신 버퍼에 데이터가 꽉 찰 때까지 기다려줄 수 없으니 네트워크 카드에게 이렇게 말하는 겁니다“네트워크 카드야내가 너무 바빠서 너 다 찰 때까지 기다려 줄 수 없으니다 꽉 차게 되거들랑 나한테 좀 알려줘. 라고 말이죠그리고, CPU 쪽에서는 네트워크 카드 데이터 처리를 담당하고 있던 디바이스 드라이버란 소프트웨어를 잠시 재우고(sleep()나서 CPU 자신은 다른 바쁜 일들을 처리하게 됩니다그러던 중 네트워크 카드 쪽 수신 버퍼가 꽉 차게 되면 다른 일을 하고 있던 CPU에게 이를 알려주고자 네트워크 카드는 “인터럽트”를 발생시키게 되는 거죠인터럽트 신호를 받은CPU는 재워두었던 디바이스 드라이버를 깨우고(wake_up()나서 해당 데이터를 처리하게 됩니다.

 

어떻게 감이 살짝 오시나요? ^^;;

 

첫 번째 방법은 Firmware에서 많이 사용하는 “폴링(Polling) 방식” 이었습니다그리고두 번째 방법은 태스크 수가 매우 많은 운영체제(Non-RTOS)에서 주로 많이 사용하는 “인터럽트(Interrupt) 방식” 이었죠.

 

<그림 8-4>에서 알 수 있듯이 외부 인터럽트는 특성상 CPU 외부에서 신호를 받아 인터럽트 발생 여부를 판단하기 때문에,미리 어떤 신호가 들어왔을 때 인터럽트를 발생시킬 것인지 약속이 되어 있어야 합니다아무 신호나 다 인터럽트를 발생시켜주게 되면 시스템 자체가 제대로 동작하지 않을 테니까요.

 

이렇게 인터럽트를 발생시키겠다고 미리 사전에 약속(= 설정)한 신호를 “트리거(Trigger) 신호”라 하며 이번 강좌에서 여러분들이 배워야 할 것은 바로 이러한 트리거 신호를 AVR 프로세서에서는 어떻게 설정하는가 하는 점입니다.

 

그럼 어떻게 설정하는지 한번 알아 볼까요? ^^;;

 

 

2  AVR 외부 인터럽트 제어 관련 레지스터 분석

 

외부 인터럽트 제어에서의 핵심은 어떻게 트리거 신호를 설정하느냐 하는 것입니다.

머 당연한 얘기겠지만 관련된 레지스터들을 설정하는 것일 테니 관련된 레지스터들을 살펴보도록 합시다준비되셨죠? Go~ Go~ Go~ Move~ Move~ Move~~~

 

 

2.1 EICRA, EICRB : External Interrupt Control Register A, B

 

항상 그렇듯이 여러분들이 레지스터들 중에서 가장 먼저 살펴봐야 할 레지스터들은 언제나 제어(Control)와 관련된 레지스터입니다이번 강좌의 타겟으로 삼은 AVR ATmega128은 외부 인터럽트 제어용으로 INT0 ~ INT7 까지 총 8개의 핀을 할당해주고 있습니다다음 <그림 8-4>는 이러한 8개의 핀들을 나타내고 있는 그림입니다.

Posted by 콩알은

댓글을 달아 주세요

AVR2012. 1. 16. 09:29


7 : AVR 프로세서로 1msec를 측정해보자!

 

이 강좌는 2010-01-29 에 시작하여 2010-04-08 에 완료한 강좌입니다. ]

 

 

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />안녕하세요뻔뻔강사 입니다.

 

6강 이후 정말 정말 오랜만이네요오랜(?) 방황(?) 끝에 올리는 강좌라 저 개인적으로 가슴이 뭉클합니다미흡한 글이지만 편하게 읽어주시면 감사하겠습니다. (_._) 꾸벅~

 

참고로 7강 원고 작성을 완료하고 보니 A4 용지 기준으로 총 31 페이지 정도 나오네요. -_-

엄청난 스크롤 압박이 예상됩니다이번 강좌를 작성하는데 제가 마신 커피 만도 최소 30잔 이상 될 듯 싶으니여러분들도 마음 느긋하게 먹고 하나씩 찬찬히 읽어가시길 바랍니다.

 

아울러 이번 강좌는 워낙 내용이 길다 보니 별도 PDF 파일로 저장하여 올려 드리도록 하겠습니다많은 분들에게 도움이 되었으면 좋겠습니다. ^^

 

심호흡 하세요다시 말하지만 스크롤 엄청 날 겁니다.

이제 시작할까요? ^^;;;

 

 

1  AVR Timer/Counter 내부 구조 분석

 

지난 번 6강이 올라간 지 너무 오래되어 혹여 잊어 버리신 분들을 위해 간략하게 복습을 해보겠습니다.

 

사람은 시계를 보면서 시간을 측정할 수 있지만, AVR 프로세서와 같은 기계들은 당연히 그럴 수 없을 겁니다그럴 때 필요한 것이 바로 전원만 인가되면 무조건 정해진 주기마다 한번씩 특정 신호를 출력시키는 부품, Oscillator 였죠.

 

AVR 프로세서와 같은 기계는 비록 사람처럼 말을 하거나 눈으로 볼 수는 없지만 Oscillator 가 출력하는 전기적인 신호의 높낮이(H, L 신호)는 확인할 수 있습니다그래야 기계적으로 동작할 테니 말이죠따라서전기적으로 높은 신호(H)에서 시작했다가 낮은 신호(L)에서 끝나는혹은 그와 반대되는 하나의 주기를 한번의 Clock 으로 보고이러한 Clock 이 몇 번 확인되는지 그 수를 카운트하여 거꾸로 시간을 계산하게 됩니다중학교(?) 때 배웠을 [진동수 = 1/주기이라는 공식을 사용하면 한번 Clock이 발생할 때 걸리는 시간(1 Clock Time)을 계산할 수 있기 때문이죠. AVR 프로세서와 같은 기계들은 이와 같은 방법으로 시간을 계산하고 있습니다.

 

그러나이 방법에도 문제가 하나 있습니다.

 

AVR 프로세서가 하나씩 카운트한 Clock 의 횟수 값을 어딘가에 저장해 놓아야 할 텐데 프로세서 내부에는 그럴만한 공간이 다들 아시다시피 레지스터 밖에 없습니다. AVR 프로세서가 8비트 프로세서다 보니 레지스터 역시 8비트일 테고그러다 보니 최대 256번 밖에는 카운트할 수가 없는 것이 문제가 되었습니다따라서카운트해야 할 횟수를 줄여야 할 필요성이 생기게 되었죠.

 

여기서 또 하나 고민이 생깁니다. AVR 프로세서는 기계이기 때문에필요에 따라서 하나를 덜 카운트하고 할 수가 없습니다.전기적인 신호의 높낮이만 알 수 있기 때문에 다른 방법으로 카운트 횟수를 줄일 수 밖에 없었습니다그래서 나온 개념이Prescaler 입니다원리는 간단합니다. Clock 이 발생되는 시간주기를 늘리면 이와 반비례 개념인 진동수카운트 수가 줄어든다는 원리입니다.

 

이렇게 해서 완성된 공식이 바로 아래와 같은 공식입니다.

 

Œ 구하고자 하는 시간

 Original 1 Clock Time(주기)

Ž Prescaler 에 의해 길어진 1 Clock Time = 1 Count Time

  Count 

 

 

여기까지가 지난 6강에서 살펴 본 내용이며이를 기반으로 AVR 프로세서의 타이머/카운터(Timer/Counter)의 내부 구조를 제 나름대로 추측(?)하여 그림을 그려 본 것이 바로 아래 그림입니다.

 

<그림 7-1> AVR 프로세서의 타이머/카운터 내부 구조

 

<그림 7-1> 에서 ATmega128 로 표시했지만실제 어떤 프로세서든 거의 <그림 7-1>와 같은 구조로 타이머/카운터가 CPU Core 와 연결되어 있다고 보시면 됩니다. AVR Core 가 우리가 측정하고자 하는 시간을 위해 카운트 해야 할 n 값을 계산하여 타이머/카운터에게 입력하면타이머/카운터 내에 있는 카운터가 n 값만큼 카운트를 하게 됩니다카운터가 n 값을 모두 카운트 하면 이를 타이머에게 알려주고 타이머는 카운트를 요청했던 AVR Core 에게 이를 알려주기 위해 인터럽트” 를 발생시키게 됩니다.

 

이와 같은 과정을 순서대로 나열해 보자면다음과 같습니다.

 

AVR 프로세서로 1msec 를 측정하는 방법 및 순서

Œ 공식(2)에 맞춰 원하는 시간 1msec 를 측정하기 위해 필요한 n 값을 계산한다.

 만약 n 값이 256 보다 크다면 256 보다 작게 하기 위해 적절한 Prescaler 를 선택한다.

Ž 선택한 Prescaler를 적용하여 n 값을 계산한 후 이를 타이머/카운터에 적용한다.

 카운터가 n 값만큼 카운트하고카운트가 완료되면 이를 타이머에게 알린다.

 타이머는 n (= 1msec)만큼 시간이 지나면 이를 AVR Core에게 인터럽트로 알린다.

 다시 n (= 1msec)만큼 시간이 지나면 이를 인터럽트로 AVR Core 에게 알리는 작업이 (전원이 꺼질 때까지무한히 반복된다.

 

 

설명을 좀 더 드리자면 에서 Prescaler 를 선택한다고 했는데어떻게 선택하는 걸까요?

 

프로세서(CPU) 내부에 있는 어떤 것들을 설정할 때에는 결국 레지스터를 건들게 됩니다, Prescaler 역시 프로세서에서 미리 제공한 몇 가지 것들 중 하나를 선택하는 것이므로어느 특정 레지스터의 일부 비트 값들을 사용하여 사용자(개발자)들이 선택할 수 있도록 되어 있습니다.

 

 에서는 인터럽트로 알려준다고 했는데이런 인터럽트는 어떤 것들이 있고 어떻게 설정하는 걸까요다음 장에서 이를 알아보도록 합시다. ^^

 

뻔뻔강사의 한 마디!

처음 타이머/카운터 개념을 접하시는 분들이 가장 어렵고 헷갈려 하시는 부분이 바로 이 인터럽트 부분입니다개념적으로도 약간 아리송하지만 소스 코드 역시 그렇거든요제 모든 능력을 발휘하여 최대한 쉽게 강좌를 작성할 테니눈 크게 뜨고 잘 살펴보시기 바랍니다.

 

 

 

2  Overflow Interrupt vs Output Compare Match Interrupt

 

먼저 인터럽트부터 잠깐 알아보고 넘어가겠습니다.

 

인터럽트(Interrupt)란 어떤 특정 조건이 만족되면기존에 실행되던 태스크(Task)를 무조건 잠시 멈추고 무언가 다른 일을 하도록 하는 녀석입니다. 인터럽트가 하는 일을 좀 유식한 표현을 사용하여 인터럽트 서비스 루틴(ISR : Interrupt Service Routine)이라고 부릅니다이름이 어찌됐든 간에 인터럽트가 걸리기 전까지 실행되던 태스크는 인터럽트가 발생되면 일단 잠시 중지되고인터럽트 서비스 루틴이 종료되면 중지되었던 태스크는 다시금 실행이 됩니다.

 

타이머/카운터에서는 우리가 원했던 시간을 측정하는 방법이 타이머/카운터가 Prescaler 에 의해 변형된(주기가 늘어난) Clock 을 카운트하는 것이므로공식에 의해 계산된 n 값만큼 카운트가 완료되면 그때마다 타이머/카운터에 의한 인터럽트가 발생되는 것입니다, n 값만큼의 시간을 주기로 계속 인터럽트가 발생된다는 거죠.

 

타이머/카운터에서는 이렇게 발생시키는 인터럽트로 2가지 종류가 있습니다.

 

하나는 Overflow Interrupt 라고 불리는 인터럽트로타이머/카운터가 카운트하는 횟수를 저장하는 레지스터(AVR 프로세서에서는 이 레지스터를 “TCNT” 라고 이름지었습니다)에 Overflow (모든 레지스터의 비트 값이 “1”로 채워졌을 때 다시 “1” 을 더할 경우 발생하는 현상가 발생될 때마다 걸리는 인터럽트입니다.

 

드디어 AVR 프로세서에서 타이머/카운터(Timer/Counter)와 관련된 레지스터가 하나 튀어 나왔습니다타이머/카운터의 동작 원리가 Prescaler에 의해 변형된 Clock의 수를 카운트하는 것이므로 반드시 어딘 가에는 현재 카운트하고 있는 값을 저장했어야 하는데, AVR 프로세서와 같은 CPU 에서는 내부적으로 레지스터(Register) 공간 외에는 별 다른 공간이 없습니다물론AVR 프로세서는 EEPROM 이라는 특별한 메모리(ROM) 공간을 제공하지만 이는 일반적인 CPU의 사양이 아니므로 레지스터로 짐작(추측)하는 것이 타당해 보이네요. ^^

 

AVR ATmega128 에는 총 4개의 타이머/카운터를 제공하고 있습니다. 8비트 타이머/카운터 2, 16비트 타이머/카운터 2,이렇게 총 4개가 있으며이번 강좌의 주제처럼 단순히 시간을 측정하기 위해선 8비트 타이머/카운터 중 가장 첫 번째인Timer/Counter 0 을 사용하는 게 가장 쉬우므로 위에서 언급한 TCNT 레지스터의 정확한 이름은 TCNT0 가 될 것입니다첫 번째 타이머/카운터의 TCNT 레지스터란 뜻이죠.

 

조금 복잡해지기 시작하고 있습니다. TCNT 니 뭐니.. .

그래도 어쩌겠어요이 쪽 분야가 좀 그렇답니다.

그러다 찬찬히 몇 번 정도 읽다 보면 이해가 가실 거예요포기하지 마시고 끝까지 함께 하시길 바랍니다. (_._)

 

여러분들은 제 글을 보고 궁금해지신 사항이 생겼을 것입니다.

8비트 타이머/카운터와 16비트 타이머/카운터 간에는 어떤 차이가 있는가 하는 점이죠.

어떤 차이가 있을까요?

 

앞서 8비트 프로세서(CPU)에서 타이머/카운터가 n 값을 카운트하기 위해 (변형된) Clock 값을 레지스터에 저장한다고 설명한 바 있습니다. 8비트 타이머/카운터와 16비트 타이머/카운터와의 차이는 바로 이 카운트한 Clock 값을 저장하기 위한 레지스터의 비트 수가 서로 다릅니다, 8비트 타이머/카운터의 경우 당연히 8비트 레지스터로 되어 있고, 16비트 타이머/카운터의 경우 당연히 16비트 레지스터로 되어 있을 겁니다아래 그림을 보시면 이해가 되겠죠? ^^;;

 

<그림 7-2> 8비트 타이머/카운터의 TCNT : TCNT0

 

<그림 7-3> 16비트 타이머/카운터의 TCNT : TCNT1H, TCNT1L

 

 

단순 무식하게 생각해봐도 두 개 레지스터를 제어하는 것 보다는 하나의 레지스터를 제어하는 게 쉽고 편하겠죠? ^^;; 그래서단순히 시간만을 측정하기 위해선 8비트 타이머/카운터인 Timer/Counter0 를 사용하여 시간을 측정하는 것입니다그러나,모터의 속도를 제어하는 등의 PWM(Pulse Width Modulation) 같은 다소 어려운 제어를 해야 될 경우에는 16비트 타이머/카운터를 사용해야 할 경우도 있으니 일단 알고만 있으시면 되겠습니다.

 

앞서 언급한 Overflow Interrupt 인터럽트는 바로 TCNT0 레지스터에 Overflow 가 발생할 때마다 인터럽트 신호를 AVR Core 에 전송하여 AVR Core 가 인터럽트 발생 전까지 실행시키던 태스크를 중지시키고 Overflow Interrupt 인터럽트가 발생했을 때 실행되어야 할 인터럽트 서비스 루틴(ISR)을 실행시키도록 되어 있습니다.

 

이와 달리 Output Compare Match Interrupt 라고 불리는 인터럽트도 있습니다.

이름을 잘 보면 무언가를 비교하여 결과가 일치(Match)할 때 발생되는 인터럽트 같아 보입니다.

원리를 간단하게 설명 드리자면앞에서 설명했던 공식에서 n 값을 구한 후 Overflow Interrupt 인터럽트와 달리 이 값을 다른 어딘가에 일단 저장해 놓습니다그 어딘가는 당연히 레지스터가 되겠죠? AVR 프로세서는 이러한 레지스터를 OCR(Output Compare Register)라 부르며, 8비트 타이머/카운터에서 사용되는 정확한 이름은 OCR0 가 되겠습니다그런 다음 타이머/카운터가 (변형된) Clock 값을 카운트하여 그 값을 저장하는 TCNT0 레지스터와 서로 비교하여 값이 일치될 때 인터럽트를 발생시킨다는 개념이 Output Compare Match Interrupt 인터럽트 입니다.

 

이제부터 눈 크게 뜨고 잘 살펴봐야 할 대목들이 나옵니다눈 크게 뜨세요! @.@

 

앞서 Overflow Interrupt 인터럽트는 TCNT0 레지스터에 Overflow 가 발생할 때마다 인터럽트를 발생시킨다고 하였습니다.인터럽트가 발생되는 시점은 언제나 TCNT0 레지스터 값들이 모두 “1” 로 채워져 있을 경우가 됩니다여기서 주의해서 생각해야 할 점은 인터럽트가 발생한 이후부터 그 다음 번 인터럽트가 발생하는 데까지 걸리는 시간 이 내가 원하는 시간 이며결국 이 값이 앞서 공식에 의해 구한 “n  이 됩니다바로 이 “n  을 이해하는 게 중요한데“n   AVR 프로세서 내부에 있는 타이머/카운터란 하드웨어 컨트롤러가 입력되는 (변형된) Clock 값을 하드웨어적으로 카운트하는 횟수 값 입니다TCNT0 레지스터의 값을 의미하는 게 아니라 타이머/카운터가 카운트하는 횟수 값을 의미하고 있습니다이를 이해하는 게 중요합니다.

 

예를 하나 들어 설명해보죠.

 

가령 AVR ATmega128 프로세서에 16MHz 짜리 Oscillator 를 연결하여 16MHz 로 동작되는 보드에서 1msec 라는 시간을 측정하고 싶습니다이 경우 앞서 설명한 공식을 대입해 보면,

 

 

이 경우 Prescaler  1/64 Prescaler 를 선택했다고 가정한 경우입니다계산해 보니 n 값이 250 이 나왔습니다, 16MHz로 동작하는 ATmega128 에서 1/64 Prescaler 를 선택했다고 가정한 경우, 1msec 라는 시간은 타이머/카운터가 1/64 Prescaler 에 의해 변형된 Clock  250번 카운트하는 동안 걸린 시간을 의미합니다.

 

“n = 250” 이라는 값은 타이머/카운터가 하드웨어적으로 카운트해야 하는 값이므로 반드시 지켜줘야 하는 값입니다.

 

여러분들도 아시다시피 Overflow 가 발생하게 되면 해당 레지스터는 Overflow 에 의해 레지스터의 모든 값이 자연적으로“0” 값으로 채워지게 됩니다따라서Overflow Interrupt 인터럽트가 발생하고 별다른 조치”(?) 를 취해주지 않으면 TCNT0레지스터의 값은 자동적으로 “0” 값부터 시작하게 되고 이후 인터럽트가 발생되는 시점(= Overflow 발생)까지 타이머/카운터가 하드웨어적으로 카운트하는 횟수는 우리가 앞에서 계산했던 것처럼 “n = 250” 이 나오는 게 아니라 “n = 256” 이라는 값이 나오게 됩니다왜일까요? Overflow 인터럽트가 발생되고 난 이후TCNT0 레지스터가 “0” 일 때부터 타이머/카운터는 무조건 (변형된) Clock을 카운트하여 이 값들을 TCNT0 레지스터에 기록하게 됩니다TCNT0 레지스터가 “0” 일 경우 “n = 1”이 되는 거죠이렇게 진행되다가 TCNT0 레지스터의 모든 비트 값이 “1” 이 되게 되면 “n = 256” 이 되고 인터럽트 발생 조건에 의해 Overflow Interrupt 인터럽트가 발생되게 됩니다우리가 원했던 것은 “n = 250” 때마다 인터럽트를 발생시키는 것이었는데인터럽트가 발생된 후 아무런 조치를 취해주지 않았더니 “n = 256” 마다 인터럽트를 발생시키는 문제가 발생하였습니다원했던 시간을 측정할 수 없게 된 거죠.

 

이 문제를 해결하려면 어찌해야 할까요?

 

Overflow Interrupt 인터럽트의 경우 인터럽트가 발생되는 조건, Overflow 조건 자체를 변경할 수는 없습니다인터럽트와 인터럽트 사이 간격 중 끝나는 시점은 변경할 수 없기에 우리가 원하는 시간(= n )마다 인터럽트를 발생시켜 주기 위해서는 출발 시점을 변경할 수 밖에 없습니다. , Overflow Interrupt 인터럽트가 발생되고 나서 TCNT0 레지스터 값을 그대로 방치하는 게 아니라 “256 - n” 값을 초기 값으로 입력시키는 조치(?)를 취해주어야만 우리가 원하는 n 값 마다 인터럽트를 발생시킬 수 있습니다. “0” 부터 “255” 까지 8비트 레지스터로 표현할 수 있는 시간 간격은 “256” 이므로인터럽트가 발생되고 초기 값을 “256 - n” 부터 시작한다면 다음 번 인터럽트는 “n” 값 만에 발생될 수 있기 때문입니다이를 그림으로 그려보면 다음과 같습니다.

 

<그림 7-4> Overflow 인터럽트 시간 구간

 

우리가 원하는 시간(= n 마다 Overflow 인터럽트를 발생시키려면 <그림 7-4>에 보이듯이 반드시 “256 - n” 값을 초기 값으로 입력하여 “256 - n” 값부터 타이머/카운터가 카운트 할 수 있도록 해야 합니다이렇게 하기 위해선 인터럽트가 발생했을 때 실행되는 인터럽트 서비스 루틴(ISR) 내부에 반드시 “TCNT0 = (256 – n);” 과 같은 코드가 추가되어야겠죠이점이 굉장히 중요하므로 꼭 기억해 두도록 합시다!

 

Overflow 인터럽트와 달리 Output Compare Match Interrupt 의 경우엔 상황이 조금 다릅니다.

Output Compare Match Interrupt 는 공식에 의해 계산한 “n” 값을 별도의 OCR0 레지스터에 입력해 둔 후 타이머/카운터가 카운트하여 입력한 TCNT0 레지스터의 값과 서로 비교하여 일치되면 인터럽트를 발생시킨다고 앞에서 설명한 바 있죠?

 

앞에서 예로 들었던 “n=250” 값을 Output Compare Match Interrupt 의 경우로 가정하여 살펴보죠다시 말하지만 “n” 값은 카운트 횟수 값이지 레지스터 값이 아닙니다. 따라서TCNT0 레지스터 값과의 비교를 위해 OCR0 레지스터에 입력해야 할 값은 “250” 이 아닌 “249” 값이 되어야 합니다왜냐하면 레지스터는 “0” 값부터 시작되므로 레지스터의 모든 비트 값이 “0” 일 때 “n=1” 이 되므로우리가 원하는 “n=250” 값을 위해선 OCR0 레지스터에 “n-1” 값인 “249” 값을 입력해야 하는 것입니다.이 경우 TCNT0 레지스터 값이 하나씩 증가되어 마침내 OCR0 레지스터 값과 같은 “249” 값이 되었다면 당연히 우리가 원하는 대로 “n=250” 만에 Output Compare Match 인터럽트가 발생한 것이 됩니다여기까진 순조롭죠문제는 앞서 Overflow 인터럽트처럼 인터럽트가 발생하고 난 다음 시점입니다TCNT0 레지스터 값이 “249” 일 때 인터럽트가 발생했다면 인터럽트가 발생하고 난 이후 TCNT0 레지스터의 값은 당연히 “250” 이 될 겁니다그 이후 “251, 252, ...” 이렇게 증가하다가 “255” 가 될 거고 이후 Overflow 가 발생하여 다시 “0” 부터 카운트되기 시작하다가 결국 “249” 가 될 때 다시금 인터럽트가 발생하게 되겠죠인터럽트가 발생된 이후 “250” 부터 다음 번 “249” 가 될 때까지 걸리는 카운트 횟수는 “256” 이 됩니다이 역시 별다른 조치를 취하지 않으면 문제가 될 소지가 있습니다.

 

이러한 문제를 해결하기 위해선 앞서 Overflow 와는 달리 인터럽트가 발생된 이후 TCNT0 레지스터의 값을 초기화 상태인“0” 값으로 만들어줘야 합니다그래야 다시 “n=250” 만에 Output Compare Match 인터럽트가 발생할 테니까요한 가지 다행인 점은 AVR 프로세서에서는 이를 하드웨어적으로 자동 처리해준다는 점입니다다음 타이머/카운터 관련 레지스터를 살펴보면서 이에 대해 알아보도록 하죠. ^^

 

 

 

3  AVR 타이머/카운터 관련 레지스터 분석

 

드디어 길고 길었던 이번 7강의 종착역이 머지 않았습니다조금만 기운내세요!

 

여러분들은 왜 타이머와 카운터가 한데 묶여 같이 동작해야 하는지 그 원리에 대해 이해하셨고원하는 시간을 구하기 위해선 별도의 공식이 필요하며시간이 다 될 때마다 이를 AVR Core 상에서 실행되고 있는 소프트웨어에게 알려주기 위해 2가지의 인터럽트 제어가 필요하다는 사실도 이해하셨습니다.

 

이러한 타이머/카운터를 제어하기 위해 필요한 특별한 레지스터들(SFR)에 대해 살펴보고소프트웨어로 레지스터를 제어하기 위한 방법을 알아보도록 하겠습니다.

 

 

3.1 TCCR0 : Timer/Counter Control Register

 

가장 먼저 살펴봐야 할 레지스터는 타이머/카운터를 제어(Control)하는데 필요한 레지스터인 TCCR0 레지스터입니다끝에 붙은 “0”  4개의 타이머/카운터 중 첫 번째 타이머/카운터라는 의미입니다.

 

<그림 7-5> TCCR0 레지스터

 

각 비트에 대한 설명을 드리기 전에 한 가지 미리 얘기해둘 점은 이번 강좌의 목적이 시간을 측정하기 위해서이지 PWM 을 제어하기 위함이 아니라는 점입니다따라서각 비트들 중 PWM 관련 얘기들이 나오면 넘어가도록 하겠으니이번 강좌에서는 시간 측정에만 집중 하도록 하죠. ^^

 

1)    Bit 7 : FOC0 (Force Output Compare)

7번 비트(8번째 비트)는 이름에서도 유추가 가능하듯이 Output Compare 를 강요(?)할 때 사용되는 비트입니다데이터시트에 보면 특별한 경우가 아니고서는 “0” 값을 유지하라고 나오는군요따라서 패스~~~ 하겠습니다.

(* 실제 PWM 이 아닌 경우 중 Output Compare Match 인터럽트와 같은 효과를 보이기 위해 사용될 수 있으나 TCNT0레지스터 값을 자동으로 “0” 값으로 Clear 해주는 기능인 CTC 기능이 이 경우 지원되지 않기 때문에 실제로 거의 사용되지 않는 비트입니다.)

 

 

2)    Bit 6, 3 : WGM01, WGM00 (Waveform Generation Mode)

6번 비트(7번째 비트) 3번 비트(4번째 비트)는 타이머/카운터에 입력될 파형을 생성하는 용도로 사용되는 비트들이며,설정은 다음 표와 같이 해주면 됩니다.

 

 

 

위 표에서 우리가 신경 써서 봐야 할 부분은 Mode 0 과 Mode 2 부분(굵은 박스로 표시한 부분)입니다. Mode 1  Mode 3 은 모두 PWM 관련 부분이므로여기서는 Mode 0  Mode 2 에 대해서만 살펴보도록 하겠습니다.

 

먼저 위 표에 보이는 항목들이 뭔지 하나씩 살펴보도록 하죠.

WGM01 와 WGM00 은 TCCR0 에 있는 비트들로서 각 비트들을 위 표처럼 설정하면 그 옆에 있는 Timer/Counter Mode of Operation 항목처럼 파형이 생성되어 동작한다는 뜻입니다.

 

그 옆에 있는 TOP 항목은 타이머/카운터가 TCNT0 레지스터에 최대 카운트할 수 있는 값을 뜻합니다쉽게 말해Overflow 인터럽트나 Output Compare Match 인터럽트가 발생될 때의 TCNT0 레지스터 값이라고 생각하시면 됩니다.따라서인터럽트가 발생했을 때 TCNT0 레지스터의 값이 0xFF 일 때가 Overflow 인터럽트일 것이고인터럽트가 발생했을 때 비교의 대상이 되는 레지스터인 OCR0 일 때가 Output Compare Match 인터럽트가 발생할 때일 것입니다바꿔 말하자면 Overflow 인터럽트를 사용하여 타이머/카운터를 제어하고자 한다면 WGM01 값에 “0WGM00 값에 “0” 을 입력하고, Output Compare Match 인터럽트를 사용하여 타이머/카운터를 제어하고자 한다면 WGM01 값에 “1”WGM00값에 “0” 을 입력하라는 뜻입니다이해되시죠? ^^

 

참고로 레지스터의 특정 비트에 “1” 값을 입력하는 것을 보통 “set”“0” 값을 입력하는 것을 “clear” 라고 합니다가끔 데이터시트에 set 이나 clear 란 표현이 나오면 해당 비트 값을 1 이나 0 값으로 입력하나 부다.. 하고 이해하시면 됩니다. ^^;;;

 

 

3)    Bit 5, 4 : COM01, COM00 (Compare Match Output Mode)

5, 4번 비트인 COM01 과 COM00 비트들은 앞서 7번 비트인 FOC0 비트를 “1” 값으로 설정(set) 했을 때 Output Compare, 파형의 출력 비교를 위해 사용되는 OC0 핀의 동작 방식을 설정하는 비트들로이번 강좌에서처럼 단순히 시간을 측정하기 위해선 사용되지 않는 비트들입니다역시 패~~~~~

 

참고로 OC0 핀은 다음 <그림 7-6>와 같이 ATmega128의 경우 14번 핀의 Alternate Function 핀입니다. ^^

 

 

<그림 7-6> ATmega128 의 OC0 

 

 

4)    Bit 2 ~ 0 : CS02, CS01, CS00 (Clock Select)

타이머/카운터제어를 위한 TCCR0 레지스터의 마지막 3개의 비트들, 2번부터 0번 비트들은 앞서 설명했던 Prescaler 를 설정하는 비트들입니다다음 표를 볼까요?

 

 

 

AVR ATmega128  10비트 Prescaler 를 제공한다고 하였으므로 위 표에 보면 최대 1024 분주까지 나눠지는 걸 볼 수 있습니다진동 수가 원래의 진동 수 보다 1/1024 만큼 줄어들게 되므로 시간클럭의 주기 시간은 반대로 1024배만큼 길어지게 되는 것이죠.

 

이후 다루게 될 예제 소스에서는 1/64 Prescaler 를 사용하였기에CS02, CS01, CS00 비트 설정을 1, 0, 0 값으로 설정해 주어야 합니다실제 설정해주는 내용은 소스 코드에서 살펴보기로 해요. ^^;;;

 

 

타이머/카운터제어를 위해 가장 중요하다고 할 수 있는 TCCR0 레지스터에 대해 알아보았습니다이제 다음 레지스터를 살펴보도록 하죠.

 

 

3.2 TCNT0 : Timer/Counter Register

 

앞에서도 몇 번씩 설명이 나왔던 레지스터라 더 이상 설명이 필요 없겠네요.

 

<그림 7-7> TCNT0 레지스터

 

 <그림 7-7>에서도 보이다시피 TCNT0 레지스터는 8비트 비트들이 모두 R/W 가 가능한 데이터 레지스터입니다타이머/카운터에 (미리 설정해놓은) Prescaler 에 의해 변형된 클럭들을 카운트한 횟수들을 기록해놓기 위한 일종의 버퍼(Buffer)와 같은 셈이죠.

 

 

 

3.3 OCR0 : Output Compare Register

 

이 레지스터 역시 TCNT0 레지스터처럼 이미 앞서 몇 번 설명되었던 레지스터입니다.

 

<그림 7-8> OCR0 레지스터

 

Output Compare Match 인터럽트를 사용하여 타이머/카운터를 제어하고자 할 때 TCNT0 레지스터와 비교하는 레지스터로,앞서 설명해 드렸던 공식에서 구한 n 값을 카운트하기 위해 실제 입력해주는 값은 “n-1” 값인 거아직 잊지 않으셨죠? ^^;;;

 

 

3.4 TIMSK : Timer/Counter Interrupt Mask Register

 

우리가 타이머/카운터를 이용하여 시간을 측정하기 위해 살펴봐야 할 마지막 레지스터는 Overflow 인터럽트를 이용할 것인지아니면 Output Compare Match 인터럽트를 사용할 것인지 결정하기 위해 사용되는 TIMSK 레지스터입니다말 그래도 내가 원하는 비트 자리에 “1” 값을 마스킹(masking)하면 됩니다~~ 쉽죠잉? ^^;;

 

<그림 7-9> TIMSK 레지스터

 

AVR ATmega128 은 타이머/카운터가 총 4개 있고각각의 타이머/카운터마다 원하는 시간 값을 알려주기 위해 Overflow 인터럽트, Output Compare Match 인터럽트이렇게 2가지의 인터럽트를 사용한다고 하였으니 총 8(= 4 x 2)의 비트가 필요하여 하나의 레지스터인 TIMSK 레지스터를 별도로 사용하고 있는 것입니다.

 

이번 강좌에서는 단순히 시간을 측정하기 위한 방법을 다루고 있으므로 <그림 7-9>에 표시한 것처럼 1번 비트와 0번 비트인 OCIE0 와 TOIE0 비트에 대한 내용만 알면 되겠습니다여러분들이 레지스터 이름이나 각 비트들의 이름들을 자주 보다 보면 대충 이름만 보고도 뜻을 알 수 있을 겁니다예를 들어인터럽트를 활성화시켜주기 위한 비트들은 대개 “-IE” (- Interrupt Enable) 을 이름 끝에 붙이게 됩니다“OCIE0” 비트는 Timer/Counter0 Output Compare Match Interrupt Enable 의 약자며“TOIE0” 비트는 Timer/Counter0 Overflow Interrupt Enable 의 약자입니다만약에 Overflow 인터럽트를 이용하여 타이머/카운터를 제어하고자 한다면 “OCIE0” 비트 값은 “0” 값으로“TOIE0” 비트 값은 “1” 값으로 설정해야 합니다왜냐하면 두 개의 인터럽트를 모두 사용할 순 없기 때문에반드시 둘 중 하나의 인터럽트를 지정하여 사용해야 하기 때문이죠.

 

 

 

이제 모든 레지스터에 대한 설명이 끝났습니다.

 

이제 실제 예제 소스 코드에 대한 설명만 남겨 놓고 있는데여기에서도 다룰 내용들이 조금 길 듯 합니다여기까지만 해도 상당한 스크롤 압박이었을 거라 생각되는데앞으로도 조금 더 압박이 계속될 듯 싶네요그러나늦은 이 밤에 밤 잠 줄여가며 작성하고 있는 뻔뻔강사의 노력을 봐서라도 우리 조금만 더 힘내기로 해요아셨죠? ^^;;;

 

 

 

4  AVR 프로세서로 1초에 한번씩 LED를 깜빡거려보자!

 

이제 실제 예제 소스 코드를 살펴보면서 타이머/카운터를 사용하여 시간을 측정하는 내용을 마무리하도록 하겠습니다다음 예제는 1초에 한번씩 LED를 깜빡거리는 예제 소스입니다.

 

 

ex7_1.h

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

/*

********************************************************************************

* File :         EX7_1.H

********************************************************************************

*/

 

#include <avr/io.h>

#include <avr/signal.h>                // 인터럽트 서비스를 구현하기 위해 반드시 선언

#include <avr/interrupt.h>            // 인터럽트 서비스를 구현하기 위해 반드시 선언

 

// PF0 ~ PF7 61 ~ 54 

#define DDR_LED               DDRF

#define PORT_LED              PORTF

#define PIN_LED               PINF

 

#define CPU_CLOCK      16000000        // CPU Clock : 16MHz

#define TICKS_PER_SEC  1000             // (1/1000)

 

ex7_1.c

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

/*

********************************************************************************

* File :         EX7_1.C

********************************************************************************

*/

 

#include "ex7_1.h"

 

// 인터럽트 서비스 루틴에 사용될 전역 변수 선언

volatile unsigned int tic_time;

 

// timer0 오버플로우 함수

SIGNAL(SIG_OVERFLOW0)

{

        tic_time++;

       

        // timer 시작  초기화  

        TCNT0 = 256 - (CPU_CLOCK / TICKS_PER_SEC / 64);     

}

 

// ms단위의 delay함수

void delay_ms(unsigned int msec)

{

        tic_time = 0;

 

        while (msec > tic_time);

}

 

int main(void)

{

        unsigned char led_status = 0xFF;

 

        DDR_LED = 0xFF;               // LED 포트를 출력 모드로 설정

        PORT_LED = 0xFF;        // LED 포트 초기화

 

        // clk/64

        TCCR0 = (0 << WGM01) | (0 << WGM00) | (1 << CS02) | (0 << CS01) | (0 << CS00);

        // timer 시작값 초기화

        TCNT0 = 256 - (CPU_CLOCK / TICKS_PER_SEC / 64);

        // 타이머/카운터오버플로우 인터럽트 활성화

        TIMSK = (0 << OCIE0) | (1 << TOIE0);

       

        sei();

              

        for (;;)

        {

               // LED toggle 시킴

               led_status = ~led_status;

               PORT_LED = led_status;

              

               // 1000ms 동안 시간 지연

               delay_ms(1000);                                                           

        }

       

        return 1;

}

 

 

예제 소스가 이 보다 길 경우엔 앞으로 전체 소스를 위와 같이 보여줘 가며 강좌를 작성하는 게 쉽진 않겠단 생각이 드네요.일일이 라인 수 타이핑하는 것도 노가다(?)네요.

 

여하튼 이제 실제 소스 코드를 살펴보도록 합시다.

 

먼저 헤더 파일부터 살펴보도록 할게요.

헤더 파일 “ex7_1.h” 파일을 보면 이전 입출력(I/O) 포트를 제어할 때 보였던 헤더 파일과 약간 다른 부분이 눈에 띄는 걸 쉽게 알 수 있습니다일단 “#include <avr/io.h>” 부분은 AVR-GCC 기반의 컴파일러(. WinAVR)를 사용하기 위해선 반드시 선언해야 한다고 앞 강의에서 수 차례 강조한바 있으니 여기선 생략하도록 하겠습니다여기서 눈 여겨 봐야 할 부분은“#include <avr/signal.h>” 부분과 “#include <avr/interrupt.h>” 부분입니다.

 

AVR-GCC 기반의 컴파일러(. WinAVR)에서 만약 인터럽트 관련된 소스 코드를 구현할 때에는 반드시 이 두 개의 헤더 파일을 선언해주어야 합니다.

 

인터럽트가 발생될 때 실행되는 코드를 우리는 인터럽트 서비스 루틴(ISR, Interrupt Service Routine)이라고 합니다그리고,이러한 인터럽트 서비스 루틴 역시 소프트웨어이기 때문에 반드시 소스 코드에 선언과 정의가 되어 있어야 합니다위 예제 소스 코드 “ex7_1.c” 파일을 보면 14번째 라인에 “SIGNAL(SIG_OVERFLOW0)” 란 부분이 나오는데 바로 이 부분이 인터럽트 서비스 루틴입니다바로 이 “SIGNAL(SIG_OVERFLOW0)” 이란 함수 매크로 관련된 내용들이 “#include <avr/signal.h>” 파일과“#include <avr/interrupt.h>” 파일에 선언 및 정의가 되어 있으므로여러분들이 AVR-GCC 기반의 컴파일러(. WinAVR)를 사용하고 계시다면 반드시 이 두 개의 헤더 파일들을 선언해 주어야 합니다.

 

만약 다른 AVR 컴파일러를 사용하고 있다면 어찌해야 할까요?

이전 강의에서도 몇 번 설명 드렸다시피컴파일러가 바뀔(다를때마다 반드시 소스 코드에서 수정해주어야 하는 부분이 있는데그 중 하나가 바로 헤더 파일들에 대한 선언이었고다른 부분이 바로 인터럽트 서비스 루틴을 선언하는 방법이었습니다.헤더 파일들과 인터럽트 관련된 선언 부분들은 컴파일러가 바뀌면 해당 컴파일러에 맞도록 반드시 수정해주어야 하는 부분들입니다.

 

LED AVR ATmega128의 입출력(I/O) F 포트(PF0 ~ PF7) 8개 핀을 사용하여 제어할 생각이므로 “ex7_1.h” 파일에서 F 포트를 사용하고 있음을 알 수 있습니다.

 

마지막으로 AVR ATmega128 외부에 별도의 16MHz Oscillator 를 장착하였으므로이를 공식에 적용하기 위해 CPU_CLOCK 이란 값을 16000000 값으로 #define 하고 있음을 볼 수 있으며그 밑에 있는 TICKS_PER_SEC 란 값은 우리가 구하고자 하는 시간 값이 1msec 이므로 1/1,000 이라는 값을 앞서 설명 드린 공식의 좌변에 표현하기 위해 분모 값이 되는 1,000 값을 별도의 이름으로 #define 한 것에 불과합니다만약 여러분들이 10msec 단위의 시간을 구하고 싶으면 TICKS_PER_SEC 값을 100 으로 수정하면 되겠죠? ^^..

 

★ 여기서 잠깐!

사실 TICKS_PER_SEC 란 변수로 선언한 데에는 뻔뻔강사의 깊고 깊은 숨은 뜻(?)이 있습니다.

 

AVR ATmega128 은 여러분들이 생각하시는 것보다 훨씬 더 다양한 RTOS(Real-Time OS)들이 포팅(porting)되어 있는 막강한(?) 8비트 프로세서입니다예를 들어, uC/OS-II 라는 RTOS 역시 포팅되어 있으며 이에 대해선 향후 별도 강좌를 통해 다룰 예정입니다어쨌든 이러한 RTOS들은 자신들이 관리하는 여러 개의 태스크(Task)들을 스케줄링 하기 위해 자신들만의 타이머(Timer)를 하나씩 가지고 있는데 이러한 운영체제(OS) 전용 타이머들은 일정 시간마다 발생되는 인터럽트 수를 가지고 시간을 측정하고 있습니다마치 우리가 이제껏 살펴봤던 타이머/카운터처럼 말이죠.

 

이때 운영체제(OS) 내에서 일정 시간마다 발생되는 인터럽트를 Tick() 이라 하고, 1초에 몇 번 이러한 Tick 이 발생했는지 그 수를 측정하기 위한 변수로 TICKS_PER_SEC 등과 같은 식의 이름을 변수에 사용하고 있습니다여러분들이 TICKS_PER_SEC 란 변수의 이름에 대해 익숙해지시면 향후 운영체제(OS)를 공부할 때 많은 도움이 될 듯 싶어 일부러 이와 같은 변수 이름을 사용하였으니 참고하시기 바랍니다. ^^;;;

 

일단 헤더 파일에 대한 설명은 그 정도로 하고 실제 C 소스 파일 “ex7_1.c” 로 넘어가 봅시다.

사실 여기서 해드릴 얘기들이 무척이나 많답니다. ^^;;;

 

보통 AVR 같은 임베디드 소프트웨어를 공부하다 보면 입출력(I/O) 제어까지는 잘 따라옵니다.

LED 몇 번 깜빡이고 나면 난 역시 대단하구나그 어렵다는 임베디드.. 별거 아닌걸?’ 하는 생각이 무럭무럭 싹트기 시작하죠그러다가 타이머/카운터를 만나면서 급 좌절을 하게 됩니다이거 뭐야뭐지왜 한글인데 영어처럼 해석이 안 되는거야아냐내 머리 문제는 아니라고아냐~’ 하고 도리질을 치면서 그 대단했던 머리가 어느 순간 강바닥에 굴러다니는 그 무엇과 비슷하다는 생각을 하게 되는 경지까지 다다르게 되는 것이죠.

 

그러나이는 비단 머리의 문제는 아닙니다.

누구나 처음 접하게 되는 난관이 바로 이 타이머/카운터 부분이죠.

왜냐하면 입출력(I/O) 제어와 달리 레지스터의 각 비트들이 서로 다른 기능들을 하기에 각 비트들에 대해 따로 따로 설정하는 방법을 알아야만 합니다.

 

아울러 말로만 듣던 인터럽트 서비스 루틴(ISR)을 처음으로 접하게 됩니다.

이왕 말이 나온 김에 한번 볼까요앞서 언급했던 것처럼 14번째 라인에 보이는“SIGNAL(SIG_OVERFLOW0)” 부분이 바로 이번 예제에서 사용된 인터럽트 서비스 루틴입니다형태를 보니 우리가 이제껏 보아왔던 함수와 약간 형태는 다르지만 어쨌든 함수 같은 형태로 보여집니다. C 언어에서 함수를 호출(Call)하여 사용하려면 이미 알고 계시듯이 [선언 è 정의 è 호출] 이라는 3단계를 거치게 됩니다이제 다시 소스 코드 “ex7_1.c” 로 돌아가서 차근차근 살펴보도록 하죠.“SIGNAL(SIG_OVERFLOW0)” 이란 (인터럽트 서비스 루틴함수가 다른 함수에서 호출되는 경우가 있나요잘 살펴보시면 이번 예제 소스 코드에서 사용된 함수는 총 3“SIGNAL(SIG_OVERFLOW0)” 와 “delay_ms(unsigned int msec)” “main(void)” 입니다이들 중 어디에서도 “SIGNAL(SIG_OVERFLOW0)” 가 호출되는 경우를 찾아볼 수가 없습니다그런데만약 “SIGNAL(SIG_OVERFLOW0)” 가 실행되지 않으면 “delay_ms(unsigned int msec)” 함수에 있는 “while(msec > tic_time);” 루프는 절대 빠져나올 수 없습니다왜냐하면 “0” 값으로 초기화된 “tic_time” 값 보다 지연(delay)시키고자 하는 시간 값 “1,000 msec” 값이 언제나 크기 때문에 while 문의 조건이 언제나 참(True)이어서 이 부분은 빠져나올 수 없는 무한루프가 되고 말 겁니다그러나위 예제 소스를 컴파일하여 실제 실행시켜보면 1(= 1,000msec) 마다 LED 8개가 전부 켜졌다 꺼졌다 하면서 아무런 문제없이 잘 실행될 것입니다왜냐하면 “SIGNAL(SIG_OVERFLOW0)” 가 호출되어 실행되기 때문입니다이상하죠이상합니다ㅎㅎ

 

그래서할 얘기들이 많다는 얘기입니다아울러 할 얘기가 많다는 얘기인즉 여러분들이 알고 있어야 할 내용들도 많다는 얘기이니 이제부터 다시금 눈 크게 집중해야 되겠죠?

(* 오늘 눈 여러 차례 크게 뜨게 해드려 죄송합니다.)

 

일단 C 소스 코드 “ex7_1.c” 파일을 분석하려면 당연히 가장 먼저 “main(void)” 함수부터 살펴봐야 합니다.

 

“main(void)” 함수에 보니 “DDR_LED” 와 “PORT_LED” 에 각각 “0xFF” 값을 입력시키고 있는 걸 봐서일단 LED 와 연결된 입출력 포트 “F” 포트에 해당되는 8개의 핀들을 모두 출력(output) 핀들로 설정시킨 후 모두 High 신호를 출력하라는 뜻이라고 해석이 됩니다이번 예제에서 사용된 LED 회로는 다음과 같습니다.

 

<그림 7-10> (DK128) LED 제어 회로

 

<그림 7-10>의 왼편에 보이는 J15 커넥터가 AVR 프로세서에 연결될 커넥터입니다가만 보니 오른편에 +5V, , High 신호가 있으므로 중간에 있는 LED(D4 ~ D11)이 켜지려면 J15 커넥터에는 Low 신호가 걸려야겠군요그런데예제 소스에서 이 부분에 High 신호를 출력하라고 했으니 일단 LED 를 꺼놓으라는 뜻인 것 같습니다. LED, FND 같은 발광 부품들은 보통 꺼놓는 것으로 초기화 과정을 대신하기에 그렇게 해놓은 것 입니다.

 

그 밑에 40번째 라인을 보면 다음과 같은 부분이 나옵니다.

 

TCCR0 = (0 << WGM01) | (0 << WGM00) | (1 << CS02) | (0 << CS01) | (0 << CS00);

 

정말 정말 중요한 내용이며정말 정말 중요한 부분입니다.

이번에 보여드리는 예제 소스는 Overflow 인터럽트를 사용하여 타이머/카운터를 제어하는 예제 소스라고 앞서 설명 드렸습니다따라서앞에서 TCCR0 레지스터를 설명했던 것처럼 WGM01 비트와 WGM00 비트는 Mode 0(Normal) 동작으로 설정해야 하므로각각 “0” 값을 입력해야 한다고 앞서 설명했던 부분을 다시금 살펴보시면 그리 되어 있을 겁니다.

 

 

그리고, Prescaler  1/64 분주를 선택하기 위해 CS02, CS01, CS00 비트들은 각각 “1”, “0”, “0” 값을 입력하라고 되어 있었고요.

 

 

이 경우 대부분의 서적들과 인터넷 상에 떠도는 예제 소스들은 아래와 같이 레지스터를 설정하고 있을 겁니다.

 

TCCR0 = 0x04;

 

틀린 내용은 아닙니다만제가 강의를 할 때엔 전 저렇게 작성하지 말라고 가르칩니다.

이유인즉 저렇게 작성할 경우 굳이 C 언어로 작성할 필요가 없기 때문입니다!

 

우리가 어셈블리어 대신 C 언어를 사용하는 이유는 사람(개발자)들이 보다 더 쉽게 이해하고자 하기 때문입니다. 유식한 표현을 빌리자면 코드의 가독성 이 좋기 때문입니다.

 

사람은 숫자 보다는 문자를 보다 더 쉽게 읽고 이해할 수 있습니다따라서220.73.161.60 이라는 숫자 대신 www.fun-market.co.kr 라는 문자를 보다 더 쉽고 빠르고 이해할 수 있기에 DNS(Domain Name Service) 라는 인터넷 프로토콜이 만들어진 거죠.

(* 은근슬쩍 회사 홈페이지 홍보하는 뻔뻔강사속 보여~  -_-;;;)

 

언어도 마찬가지입니다다시 아까 코드 얘기로 돌아가 볼까요?

TCCR0 = 0x04; 라는 부분을 보면 니블(nibble) 표기법에 의해 2번 비트, 3번째 비트 값만 “1” 이고 나머지는 모두 “0” 값 임을 알 수 있습니다다음과 같겠죠.

 

TCCR0 è 0000 0100

 

그러나이 코드를 예를 들어 한 달 뒤에 보게 되면 어떻게 해석이 될까요?

‘2번 비트만 “1” 로 설정(set)하고 나머지는 모두 “0” 으로 클리어(clear)시키는 코드군그래이해하겠어근데, 2번 비트가 뭐였드라?’

이렇게 되는 것이죠.

 

여러분들이 작성하는 코드는 반드시 언젠가 다시 보게 됩니다.

기업에서는 출시한 제품의 기능을 업그레이드 시키기 위해 다시금 기존 코드를 수정하라는 지시가 내려오는 경우가 대부분일 테고최소한 여러분들이 퇴사를 하게 될 경우 인수인계를 위해서라도 반드시 언젠가는 꼭 보게 될 겁니다.

 

그때 과연 저 코드 내용이 무슨 내용이었는지 기억할 수 있을까요?

 

반면 이번 강좌의 예제 소스 코드를 보면,

 

TCCR0 = (0 << WGM01) | (0 << WGM00) | (1 << CS02) | (0 << CS01) | (0 << CS00);

 

WGM01, WGM00 비트들과 CS02, CS01, CS00 비트들이 각각 TCCR0 레지스터의 몇 번 비트들인지 위 코드만 봐서는 전혀 알 수 없습니다그러나WGM01, WGM00 비트들에는 각각 “0” 과 “0” 값을CS02, CS01, CS00 비트들에는 각각 “1”, “0”, “0”값을 설정하고 있음은 쉽게 알 수 있습니다왜냐고요여러분들이 AVR 소스를 작성하기 위해선 가장 먼저 해줘야 할 일이#include <avr/io.h> 헤더 파일들을 선언하는 것이었으며이 헤더 파일에 의해 프로세서(CPU) 별로 별도의 헤더 파일가령AVR ATmega128 의 경우 #include <avr/iom128.h> 헤더 파일이 선언됨을 알고 있을 겁니다이 헤더 파일을 열어 보면 아래와 같이 이미 각 레지스터의 각 비트들의 이름들이 각 비트 번호 값으로 #define 되어 있음을 알 수 있습니다.

 

 

만약 #include <avr/io.h> 선언을 하지 않았더라면그래서#include <avr/iom128.h> 헤더 파일이 선언되어 있지 않았더라면 여러분들이 LED 를 켜고 끌 때 사용했던 입출력(I/O) 관련 레지스터들 DDRF, PORTF, PINF 레지스터들에 직접 0xFF 란 값들을 입력시킬 수가 없습니다왜냐하면 레지스터는 말 그대로 프로세서(CPU) 내부에 마련된 메모리 이기 때문에 주소(address)로 접근해야 하는데혹시 DDRF, PORTF, PINF 레지스터들의 주소 값이 얼마였는지 알고 계시나요? AVR ATmega128 데이터시트 목차(index)를 주욱내려가다 보면 “Register Summary” (364 page) 라는 부분이 나오는데 364 ~ 366 페이지에 걸쳐 나오는 레지스터들이 ATmega128 내부에 있는 모든 레지스터들이며거기에 각 레지스터들의 주소 값이 나옵니다참고로 DDRF 레지스터의 주소 값은 0x61 입니다따라서만약 입출력 F 포트의 핀들을 모두 출력 핀으로 설정하고자 한다면 본래는 &(0x61) 이라는 주소 값 내의 8비트 공간에 0xFF 라는 값을 입력시켜야 하겠지만우리는 그럴 필요 없이 그냥DDRF 레지스터의 이름에 직접 값을 입력합니다헤더 파일을 선언했기 때문이죠.

 

마찬가지입니다.

 389 페이지나 되는 AVR ATmega128 데이터시트 내에 나와 있는 모든 레지스터들과 각 레지스터들의 비트 이름들은 모두 컴파일러에서 제공하는 별도의 헤더 파일 내에 모두 선언이 되어 있습니다레지스터의 주소 값을 찾아서 주소에 해당되는 8비트 공간에 값을 입력하도록 이미 어셈블리어 기반의 함수 매크로가 선언되어 있고각 비트들의 이름들은 위에서 봤듯이#define 으로 각 비트 번호와 함께 선언되어 있습니다참고로 AVR-GCC 기반의 컴파일러에서는 #include <avr/io.h> 에 의해 선언된 #include <avr/sfr_defs.h> 헤더 파일에 정의된 #define _SFR_IO8(io_addr) ((io_addr) + __SFR_OFFSET) 에 의해 우리는 손쉽게 이름만으로도 프로그래밍을 할 수가 있게 되는 것이죠참고로 우리가 간혹 사용하는 cbi(), sbi() 함수 역시 #include <avr/sfr_defs.h> 헤더 파일에 다음과 같이 선언 되어 있습니다.

 

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))

#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

 

또한 outp(), inp() 함수 역시 #include <avr/sfr_defs.h> 헤더 파일에 선언되어 있으니 관심 있으신 분들은 한번씩 찾아 보세요.

 

TCCR0 = (0 << WGM01) | (0 << WGM00) | (1 << CS02) | (0 << CS01) | (0 << CS00);

 

앞서 언급한 위 코드는 어차피 선언한 #include <avr/io.h> 선언을 최대한 활용하는 좋은 예이자 우리가 C 언어를 사용하는 목적이기도 합니다가령 (1 << CS02) 라는 부분은 다음과 같이 해석될 수 있습니다.

 

CS02 비트가   비트인지는 모르겠지만 값을 “1” 설정(set)하라!

 

실제로 그렇게 됩니다왜냐하면 #include <avr/io.h> 선언에 의해 CS02 비트는 “2” 라는 값으로 #define 되어 있으므로,(1 << CS02) 는 “1 값을 왼쪽으로 2 만큼 Shift 시켜라 라는 뜻이 되죠. 1 값을 두 번 좌측으로 옮기면 2번 비트 자리로 1 값이 옮겨지고레지스터 제어 시 모든 변수들은 보통 양(+)의 정수 값(unsigned)을 사용하고 있으므로부호 비트를 인식하는Arithmetic Shift 방식이 아닌지나 간 자리엔 무조건 “0” 값을 입력하는 Logical Shift 방식을 사용하므로 결국 0x4 (0b 100)값이 됩니다.

 

따라서위 코드는,

 

WGM01 라는 비트가   비트인지는 모르겠으나  값을 “0” 값으로 설정하고(비트 OR 이므로), WGM00 라는 비트가   비트인지는 모르겠으나  값을 “0” 값으로 설정하여 결국 Mode 0 (Normal) 방식으로 타이머/카운터를 설정해라그리고, CS02, CS01, CS00 값을 각각 “1”, “0”, “0” 으로 설정하여 1/64 Prescaler  선택해라.

 

란 뜻으로 해석될 수 있습니다실제 “0” 이라는 값을 왼쪽으로 몇 번 Shift 시키는 것은 프로세서(CPU) 동작 상으로는 아무 의미도 없지만코드를 작성하는 우리(개발자)에게는 의미가 있는 거죠해당 비트 값을 “0” 으로 설정(clear)하라는 의미니까요.

 

이렇게 숫자 보다는 문자로 프로그래밍 하는 것이 보다 C 언어 다운 표현이며나중에 다시 이 코드를 보아도 쉽게 해석될 수 있으므로저는 강의 시간마다 이에 대한 강조를 하고 있습니다.

 

한 마디만 더 하자면이렇게 문자로 프로그래밍 한다는 생각은 비단 제가 똑똑해서가 아닙니다전 그저 AVR ATmega128데이터시트에 있는 대로 열심히 보고 작성한 것 밖에 없습니다일례로 ATmega128  TWI(I2C) 제어를 위해 TWCR(TWI Control Register) 제어를 하는 예제 소스가 데이터시트 212 페이지에 다음과 같이 나옵니다.

 

 

제 얘기라면 믿지 못하실 수도 있지만 AVR 프로세서를 개발한 ATMEL 얘기라면 믿어 볼만하지 않을까요? ^^;;; 실제 AVR 의 시리얼 통신(USART)도 예제 소스 코드가 있는데도 불구하고 대부분의 서적들과 예제 소스들은 예전에 작성했던 코드 스타일대로 나와 있더군요.

 

여하튼 앞으로 뻔뻔강사의 모든 예제 소스들은 위와 같이 숫자가 아닌 문자 방식으로 레지스터의 각 비트들을 설정하도록 되어 있을 겁니다참고하시기 바랍니다.

 

이제 다시 소스 코드로 돌아가서 다음 부분을 살펴볼까요?

 

TCNT0 = 256 - (CPU_CLOCK / TICKS_PER_SEC / 64);

 

이번 예제에서는 Overflow 인터럽트 방식을 사용한다고 했기 때문에우리가 계산했던 250번 마다 Overflow 인터럽트가 발생하려면 TCNT0 레지스터가 “0” 값부터 시작하는 게 아니라 반드시 “256-n” 값부터 시작해야 한다고 앞서 강조한 바 있습니다바로 그것을 소스 코드로 표현한 게 윗 부분 코드입니다(CPU_CLOCK / TICKS_PER_SEC / 64) 부분이 “n” 값이 되겠죠? ^^

 

그 다음에 나오는,

 

TIMSK = (0 << OCIE0) | (1 << TOIE0);

 

부분은 이번 예제에서는 Output Compare Match 인터럽트 대신 Overflow 인터럽트를 사용하겠단 뜻입니다여기까지가Timer/Counter0  Overflow 인터럽트를 사용하여 1msec 마다 시간을 측정하겠다고 설정한 내용이 되겠습니다여기까지 따라오셨으면 숨이 목 끝까지 올라오셨을 테니 잠깐 숨 고르기 하고 다음 라인으로 넘어가도록 하겠습니다후욱후욱후욱~

 

숨 좀 쉬고 나서 그 다음 라인으로 넘어가 보니,

 

sei();

 

라는 아주 짤막한 함수가 눈에 띕니다.

앞서 몇 차례나 강조한 바 있지만 컴파일러 마다 인터럽트를 지원하는 방식들이 전부 다릅니다.

따라서인터럽트 서비스 루틴의 선언 방식이나 인터럽트 서비스 루틴을 지원하기 위한 함수들의 이름은 제각기 다르죠.sei() 함수는 AVR-GCC 기반의 컴파일러에서 인터럽트 서비스 루틴을 지원하기 위해 제공된 함수이며지원하는 기능은 글로벌(global) 인터럽트를 허용 해주는 역할을 합니다.

 

~~ 여러 군데서 온갖 원성들이 들려오는 듯 합니다.

정말 이번 장에서는 뭐 이리 얘기들이 많은 건가요?

인터럽트는 뭐고 글로벌 인터럽트는 또 뭔가요?

 

흑흑저한테 뭐라고 하지 마세요저라고 그러고 싶었겠습니까.

그래도 어쩌겠어요나온 얘기니 짚고 넘어가긴 해야겠죠?

 

이번 강의에서 다루고 있는 타이머/카운터 말고 다음 강의에서 다루게 될 외부 인터럽트(External Interrupt)” 의 경우엔 프로세서(CPU) 외부에 있는 주변 부품(디바이스)으로부터 특정 신호(Trigger Signal)가 입력될 때 마다 인터럽트를 발생시키는 방식으로 제어하게 됩니다이 경우 (CPU) 외부에 있는 디바이스로부터 신호를 받아들여야 하기 때문에 디바이스와 연결된 CPU핀은 자연스레 입력(input) 핀일 수밖에 없겠죠.

 

이러한 외부 인터럽트를 이용하여 한 가지 가정을 해보도록 하죠.

마이크로프로세서(CPU)에 전원이 처음으로 들어오게 되면, CPU는 내부에 있는 모든 레지스터들을 “0” 혹은 “1” 값으로 초기화하게 됩니다그런데, CPU 내부에는 많은 수의 레지스터들이 있기 때문에 이들을 초기화하는데 아주 약간의(?) 시간이 필요할 겁니다그런데만약 CPU 가 리셋(Reset) 되기 전에 외부 인터럽트를 설정해놓은 상태에서 CPU 가 리셋(혹은 전원이 새로 입력)되고 CPU 내부에 있는 모든 레지스터들이 초기화되기 전에 때마침 외부 인터럽트를 발생시킬 수 있는 특정 신호(Trigger Signal)가 입력된다면 어찌될까요인터럽트란 현재 하던 일을 반드시 멈추고 다른 일을 하도록 하는 게 인터럽트입니다따라서현재 하던 CPU 내에 있는 레지스터들 초기화를 미처 다 처리하지 못했기 때문에 결국 CPU 자체가 제대로 동작되지 않을 수 있을 겁니다.

 

실제로 이런 일이 발생될 일은 거의 없을 겁니다그럼에도 불구하고 CPU 를 설계할 때에는 여러 가지 상황들을 고려해야 하기 때문에 일반적으로 특별한 설정을 해주지 않는 한 CPU  CPU 전체적으로 인터럽트가 발생되지 않도록 CPU 전체(Global) Lock 을 걸게 됩니다바꿔 말하자면 이렇게 걸려있는 Lock 을 풀지 않으면 아무리 (타이머/카운터인터럽트 설정을 잘해줘도 (Lock 이 걸려 있어인터럽트 서비스 루틴이 실행되지 않는다는 뜻입니다sei() 함수는 바로 이렇게 걸려있는Lock 을 풀어주는 함수인 것입니다. IAR  에서 개발한 AVR 컴파일러인 EWAVR 에서는 sei() 함수 대신__enable_interrupt() 라는 함수가 이러한 일을 해주고 있습니다물론 다른 컴파일러에서는 또 다른 이름의 함수들이 이러한 일들을 해주고 있겠죠.

 

참고로 sei() 함수의 이름은 SEI 라는 AVR 명령어(Instruction)에서 따온 것입니다.

AVR Instruction Set 문서를 보면 SEI(Set Global Interrupt Flag) 명령어에 대한 설명이 나오고 있는데 내용인즉SREG(Status Register) 라는 레지스터에 있는 I 비트 값을 “1” 값으로 설정(set)하라는 내용입니다SREG(Status Register) 라는 레지스터는 AVR Core 에 있는 레지스터로 CPU Core 내에 있는 ALU 연산의 결과가 N(Negative) 인지,Z(Zero) 인지C(Carry) 인지V(Overflow) 인지 그 결과 (상태값을 보여주기 위한 레지스터로서, AVR 뿐만 아니라 모든CPU 에는 CPU Core 가 있고 그 CPU Core 안에는 ALU 가 있으므로 N, Z, C, V 값은 비트의 위치만 서로 다를 뿐 CPU Core내에 있는 Status Register 에 늘 있는 값들입니다.

 


 

<그림 7-11> AVR Core 내에 있는 SREG(Status Register) 레지스터

 

동그라미로 표시한 마지막 7번 비트에 있는 I 비트가 Global Interrupt Enable 비트로 평상 시엔 <그림 7-11>처럼 “0”값으로 설정되어 있다가 인터럽트를 사용하고자 할 경우엔 “1” 값으로 설정(set)해주어야 합니다따라서앞서 배웠던 Shift 표기법(?)으로 작성하자면 다음과 같이 표현할 수 있습니다.

 

SREG |= (1 << I);

 

비트 OR 를 처리해준 이유는 I 비트가 몇 번 비트인지 간에 “1” 값이 지나간 자리엔 모두 “0” 값으로 채워주어야 하는데,SREG 레지스터는 CPU Core 의 상태를 표시하면서 동시에 I 비트처럼 CPU 전체에 대한 특별한 설정을 해줄 수 있는 기능을 가지고 있으므로 다른 비트들을 함부로 “0” 값으로 처리해주어서는 안 되는 레지스터입니다따라서기존 SREG 레지스터에 설정된 값들은 유지하면서 I 비트만 “1” 값으로 설정하려면 위와 같이 비트 OR 처리를 해주어야만 하는 것이죠그런데이러한 비트 OR 처리를 대부분의 개발자들이 빼먹을 수 있기 때문에 보통은 저렇게 직접 SREG 레지스터를 설정하지 않고 sei() 함수나__enable_interrupt() 함수처럼 컴파일러에서 제공하는 글로벌 인터럽트 활성화 함수 를 사용하는 것입니다이제 글로벌 인터럽트를 활성화시킨다는 표현이 어떤 의미인지 다들 아셨을 테니 다시금 숨 한번 고르고 소스로 돌아가도록 합시다.

 

~

 

NOT(~) 연산자를 사용하여 LED 를 켜고 끄는(Toggle 시키는소스는 이미 앞서 입출력(I/O) 강좌에서 설명을 했으니 넘어가도록 하고그 다음 라인을 살펴보도록 하죠.

 

delay_ms(1000);

 

6강과 7, 7강의 경우엔 A4 용지 30여장 가까이 될 정도로 할 얘기가 많았던 이유가 바로 이 한 줄을 설명하기 위함이었습니다우리가 원하는 시간만큼 측정하려면 어찌해야 되는가.. 바로 이에 대한 설명이 이토록 긴 이야기가 되었던 것이죠.delay_ms() 함수는 인자 값으로 넘겨진 “1000” msec 만큼 시간을 질질 끌라는(delay) 함수입니다, 1초 동안 잠시 쉬었다가 LED 를 켜고 끄는 예제가 이번 강의에 보여드린 예제 소스가 되는 셈이죠그럼 delay_ms() 함수의 정의를 살펴볼까요?

 

void delay_ms(unsigned int msec)

{

        tic_time = 0;

 

        while (msec > tic_time);

}

 

보면 알겠지만 delay_ms() 함수는 함수 내에 사용된 while() 문이 종료되어야 delay_ms() 함수 역시 종료되도록 구현되어 있습니다그럼while() 문은 언제 종료될까요?

 

보통 msec <= tic_time 일거라 생각하는 경우가 많은데 실제론 msec = tic_time 될 때 while() 문은 종료하게 됩니다.msec 값과 tic_time 값이 서로 같아질 때 while() 문이 종료되면서 delay_ms() 함수 역시 종료되게 되는 것이죠왜냐하면 tic_time 값은 while() 문이 시작되기 전에 “0” 값으로 초기화가 되어 있기 때문입니다우리가 delay_ms() 함수를 사용하는 이유는 최소한 몇 msec 라도 지연(delay)시키기 위해 사용할 것이기 때문에 msec 값은 기본적으로 “0” 값보다 큰 양수(+)일 테니 tic_time 값이 어떤 이유(?)에 의해 증가하여 최초로 msec 값과 같아져 while() 문의 조건식인 (msec > tic_time) 에 위배될 때 while() 문의 조건식은 거짓(False)이 되고 그로 인해 while() 문은 종료하게 되는 것이죠.

 

그런데tic_time 값을 보니 unsigned int msec 라고 선언된 msec 값과 달리 별다른 선언이 없는데도 곧바로 사용되고 있네요그렇단 얘기는 tic_time 값은 전역변수 라는 뜻이겠죠아니나다를까소스 코드 위쪽을 살펴보니 다음과 같이 전역변수로 선언이 되어 있음을 알 수 있습니다.

 

volatile unsigned int tic_time;

 

그런데전역변수 선언하는 곳에 volatile 이라는 다소 생소한 글자가 보입니다이건 또 뭘까요? @.@

 

이를 설명하기 위해선 그 아래에 있는 인터럽트 서비스 루틴(ISR)부터 설명을 해야 하니 궁금해도 조금만 기다려 주세요.

 

SIGNAL(SIG_OVERFLOW0)

{

      tic_time++;

     

      TCNT0 = 256 - (CPU_CLOCK / TICKS_PER_SEC / 64);

}

 

앞서 잠깐 언급한 바 있는 것처럼 이번 예제에 사용된 인터럽트 서비스 루틴(ISR)은 위와 같으며이때 사용된 SIGNAL() 함수는 일반적인 C 언어 함수와 달리 호출(Call)되지 않고도 실행되는 함수라고 언급한 바 있습니다실제로 SIGNAL() 함수가 실행되지 않는다면 tic_time 값이 증가되지 않아 결과적으로 delay_ms() 함수가 종료될 수 없기 때문에 SIGNAL() 함수는 일단 실행된다고 봐야 합니다아래 그림을 잠깐 볼까요?