디시인사이드 갤러리

갤러리 이슈박스, 최근방문 갤러리

갤러리 본문 영역

유리한과 함께하는 AVR로 임베디드 개념쌔우기 - #5. 무식한 Delay 똑똑한 Delay

유리한갤로그로 이동합니다. 2007.06.28 17:14:36
조회 3875 추천 1 댓글 17
														
Chapter 5. 무식한 Delay 똑똑한 Delay


부제 : Timer/Counter


/*


하나 짚고 넘어갈께.
횽이 대충 typedef로 만들어서 쓰는 데이터형은
u08 , u16 이야. unsigned char 랑 unsigned int.
8비트 프로세서라 int형은 2바이트.


임베디드하면서 코딩할때 가장 중요한건 비트연산일지도 몰라.
~,|,&,^ 등등..
오래 하다보면 16진수가 2진수로 변환되서 느껴질 날이 올꺼야..


근데 이게 또 전날 술퍼마셨거나 잠을 못자면 코드가 눈에 안들어올때가 있어요,
그니까 특히나 비트 만지작거리는 것들은 주석이라도 잘 달아놓자.


그리고 이건 임베디드 개념잡기 위한 용도지,
avr을 심도있게 배우라고 시작한 글은 아니니까
\'애새끼 ㅈㄹ 대충하네\' 라고 생각해도 할말 없다.
그래도 개념잡으면 하루 두어시간씩 일주일이면 avr 기능 익히는덴 떡을 친다.
익숙해지는게 문제겠지만.

*/



128은 나름대로 16MHz에 16MIPS로 동작해.
16MHz라면 느리다고 생각할지도 모르겠지만
거기에 그래픽작업이 있는것도 아니고 부동소숫점 연산같은 빡센 프로그램을
올리는일은 별로 없으니까 응답속도가 엄청나게 빨라.
(TFT-LCD 같은것들은 훡유.. 버벅버벅 빌빌빌빌...)


근데 생각을 해보자.
시계를 만든다고 했을때 1초에 한번씩 초가 가야되는데.. 이 1초를 어떻게 만드나?


일단 delay 함수를 만들어보자.


void delay(volatile u16 dt)
{
    u16 i=2727;
    while(--dt)
    {
        i=2727;
        while(--i);
    }
}


아무 의미없는 시간죽이는 함수 되시겠다.

/*
volatile 키워드에 대해서 짚고 넘어가자.
volatile 의 뜻은 \'휘발성의\' 라는뜻인데..
램 영역에 변수를 올리겠다는 뜻이야.
레지스터 영역에 올리는게 아니라..
복잡하게 생각하지는 말고, 그냥 최적화 시키지 말란말이야.
현재 영역에서 뿐만 아니라 다른쪽에서 변경될수도 있으니 손대지 말란뜻.
최적화때문에 정상동작을 보장하지 못하는 경우가 생기거든.


레지스터에 올라가서 엄청난 속도로 연산을 끝내버릴수도 있는거고..
타이밍 맞춰줘야되는데 연산이 빨리끝나면 절대로 안되지..
(램과 레지스터의 속도차는 수십~수백배까지 난다고 하더군.)


이런경우도 있을수 있지.


int* pABCD=(int *)0xABCD;
while(!*pABCD);


이런경우에는 무조건 참이거나 무조건 기짓이 되서 무한루프를 돌게 되.
이미 0xABCD의 값을 읽어왔다고 판단해서 그 밑의코드를 지 멋대로 최적화시키는거지.


이런 황당한 경우를 막기위해 volatile 키워드를 쓰는것이야..
*/


예전에 누군가 얘기했었는데 2727로 하면 1ms에 가깝게 나온다고 하더군.
자기가 오실로스코프로 찍어봤다고..


근데 컴파일러랑 최적화 따라 시간이 다르더라.


뭐 저 딜레이 함수가 가장 원초적인 딜레이 함수야. 만들기도 어렵지 않고..


하지만 정확한 딜레이를 줄수 없으니 어떻게 해야할까?


바로 AVR에 기능중 하나인 Timer/Count룰 이용하는거야.
128에는 총 4개의 타이머가 있는데 8비트가 2개 16비트가 두개.
간단히 16비트 카운터는 숫자를 65535까지 셀수 있고 8비트는255까지 셀수 있는 놈이야.


(개념잡기 형태의 강좌니까 카운터 0만 쓰기로 하고 인터럽트는 오버플로우 인터럽트만 쓰자고.)
(스스로 데이터시트 찾아보고 삽질해야 느는것이야. 절대 귀찮아서 그러는게 아마 아닐꺼야. )


일단 소스코드 나가신다.


#include <avr/io.h>
#include <avr/interrupt.h>
#include "typedef.h"


volatile u16 Count = 0;
BOOL Wait = FALSE;

void Init_Timer0(void);
void delay_ms(u16 dt);

int main(void)
{
    cli();          //인터럽트 비활성화
    DDRD=0xff;
    Init_Timer0();
    TIMSK=0x01;     //Timer0 overflow 인터럽트.
    sei();          //인터럽트 활성화
    PORTD=0x55;     // 0b 0101 0101
    while(1)
    {
        delay_ms(500);
        PORTD=~PORTD;   //비트 반전.
    }


    return 0;
}



void Init_Timer0(void)
{
    TCCR0 = 0x05;       //프리스케일러 128
    TCNT0 = 0x83;
}


void delay_ms(u16 dt)
{
    Wait=TRUE;
    Count=dt;
    while(Count);
    Wait=FALSE;
}


ISR(TIMER0_OVF_vect) //인터럽트 서비스 루틴. TIMER0가 오버플로되면 호출
{
    TCNT0 = 0x83;    // 초기화
    if(Wait)Count--;
}


코드가 조금 길어지기 시작한다.


횽이 지금 테스트할게 없는 관계로다가 스튜디오에서 시뮬 돌렸다.
이쁘게 잘 동작하긴하네.. 빌어먹을 타이머가 시뮬에선 너무 느리게 돈다는게 문제지만..
간단하게 LED가 01010101에서 10101010으로 0.5초에 한번씩 뒤집히는 코드야.



d0052452_04065113.jpg


자. 일단 뒤져봐야할 코드는 몇줄 안되지?


cli() , sei() 라는 함수 두개와
TCNT0,TCCR0,TIMSK 레지스터 세개.
ISR(TIMER0_OVF_vect) 세가지.


cli()는 모든 인터럽트를 비활성화 시켜. 클리어인터럽트..쯤 될까?
sei()는 반대로 설정된 인터럽트들을 다시 활성화 시키고. 셋 인에이블 인터럽트?
일종의 크리티컬 섹션이지.
초기화라던지 시스템에 영향을 줄수있는 설정을 할때는 뻑나지 않도록 감싸주는 역할을 해.


자, 이제 사용된 레지스터를 보자.


d0052452_04065319.jpg 


TCCR0는 뭐하는 놈이냐?
타이머/카운터 컨트롤 레지스터 되시겠다.
데이터 시트를 보니 눈이 어지럽군화..
스샷찍기엔 좀 양이 많이서 우리가 쓴 부분만 간추려보자.


d0052452_04065354.jpg 

bit 0~2까지 세개는 클럭 셀렉트 란다.
우리는 0x05을 했으니 0000 0101 이지? 자 그럼 101을 찾아보자.
Clktos/128 from 프리스케일러라고 되어있다.


프리스케일러는 뭘까?
흔히 우리는 분주비..라고 한다.
원래 타이머는 클럭한번에 값이 1씩 많아지는게 정상이다.
근데 시간을 길게 잡으려고 했더니 이건뭐 얼마 되지도 않거덩.
그래서 만든게 프리스케일러야.
분주비를 128로 했으니 클럭이 128번 뛰어야 타이머를 올리라는거지.
16MHz를 기준으로 했을때 1초에 16,000,000번 클럭이 들어가잖아?
하지만 분주비를 128로 했기때문에(클럭/분주비) 타이머는 1초에 125000번 뛰어.
그냥 클럭을 나누는놈이지.
윗쪽 5개 비트도 뭔가를 설정하는데.. 개인적으로 공부해라.
(클럭소스는 외부에서 끌어다가 쓸수도 있어. 그런놈은 타이머보다는 카운터 라고 부르지.)


d0052452_04065494.jpg

TCNT0를 보자.
타이머/카운터 레지스터 라고 되어있다.
별거없다.
클럭이 뛰면 값이 1 올라간다.
근데 왜 TCNT0를 0x83으로 했을까?


우리는 분명 정확한 1ms를 만들자고 했다.
말했다시피 프리스케일러 128로 잡은 지금,
1초에 TCNT0는 125000번 갱신된다.
여기까지만 기억하고 잠깐 밑으로 내려가자.



d0052452_04065165.jpg

TIMSK 를 보자. 타이머 인터럽트 마스크 레지스터라고 되어있다.
Init_Timer0함수에 포함시키지 않은 이유는..
다른 체널의 카운터에도 영향을 미치기 때문인데..
read도 가능하니까 포함시켜서 TIMSK|=0x01 라고해도 무방하다.
쓰는사람 마음.
우리는 오버플로우 인터럽트를 쓸거니까 타이머0의 오버플로인터럽트를 활성화 시킨다.


그럼 이제 오버플로우 인터럽트가 뭔지만 알면 되겠네?


TCNT0의 값이 0xff를 넘어 캐리(자리올림)가 발생하는순간 (오버플로우 되는순간)에 인터럽트가 발생한다.
그게 오버플로우 인터럽트다.


그래서 TCNT0를 0x83으로 해놓으면 00으로 넘어갈때까지 125번을 뛰는거다.
1초애 125,000번 분주했으니 125번이면 정확히 0.001초 라는 계산이 나온다. ㅇㅋ?


계산식을 말해줄께.


x = 메인클럭 * 1/분주비 * T
TCNT = 2^8(256) - x



그럼 직접 계산해보자.


16,000,000 * 1/128 * 0.001s = 125
256-125=131
131=0x83


다들 TCNT 계산법은 알겠지?
16비트 타이머는 0xffff까지 되는데
TCNT1H / TCNT1L 로 나눠서 할수도 있고
TCNT1 로 바로 대입시킬수도 있어.


자, 다시 본론으로 들어가서 인터럽트가 발생하면 인터럽트 서비스 루틴으로 점프~ 를 한다.


WinAVR에서는 ISR(TIMER0_OVF_vect) 로 점프~!


d0052452_04065248.jpg

친절하게도 WinAVR 레퍼런스를 보면 avr/interrupt.h 부분에 나와있다.
(winavr/doc/avr-libc/ 에 들어있다.)


저 함수를 처리하면 인터럽트가 발생하기전 루틴으로 복귀한다.


근데 TCNT0는 인터럽트가 발생했다고 해서 초기값으로 돌아가는게 아니라 0x00부터 다시 시작한다.


그래서 TCNT0를 초기값으로 돌려놓아야 할 필요가 있다.


 


명심해야 할 점은..


ISR쪽에 코드를 왕창 몰아넣으면
다 해치우기도 전에 인터럽트가 걸려서 중첩될수도 있다.
단발성이면 별 문제없이 해결될수도 있겠지만
영영 메인으로 돌아기지 못하는 개같은 경우가 생길수도 있으니 주의하자.


보통은 stack overflow 나서 칩이 견디다 못해 리셋되더라..


최소한의 코드만 박아넣고 메인에서 처리하자. ㅇㅋ?
(이벤트 플래그 확인해주는 역할로 쓴다던지..)

그리고 처리시간 염두해두고 코딩해.
인터럽트는 잘만 쓰면 OS없이도 멀티테스킹 효과를 가져올수 있는거다.
슈퍼루프+인터럽트로 즐거운 코딩생활하자.




오늘은 여기까지.



(추가하자면 기본라이브러리에 delay함수가 존재한다.
#include<util/delay.h>
를 추가하면된다.
_delay_ms()와 _delay_us() 를 사용하면된다.
근데 이놈도 정확한것 같진 않아..
딜레이를 인라인 어셈으로 만드는 사람도 있어.
의미없는 push pop..

void delay_us(unsigned char time_us)    // Time delay for 1us (1MHz)
{          
    register unsigned char i;

    for(i=0; i<time_us; i++)            // 4 cycle +
    {
        asm volatile(" PUSH R0 ");      // 2 cycle +
        asm volatile(" POP R0 ");       // 2 cycle +
        asm volatile(" PUSH R0 ");      // 2 cycle +
        asm volatile(" POP R0 ");       // 2 cycle +
        asm volatile(" PUSH R0 ");      // 2 cycle +
        asm volatile(" POP R0 ");       // 2 cycle = 16cycle = 1us
    }                                   // for 16MHz
}

)


 


d0052452_0406527.jpg

avr32 주문한거 취소됐네..
아.. 몇달동안 배고프게 살뻔했네.. 
근데 왜 취소됐는지 모르겠다..ㅡㅡ;;
근데 1달러는 왜 결제된걸까?

모르겠다~ 퇴근하고 avr 키트도 받을겸 친구랑 사우나 가야겠다.
그럼 다들 수고!!


자꾸 관심 안주면 싼다.

추천 비추천

1

고정닉 0

0

댓글 영역

전체 댓글 0
본문 보기

하단 갤러리 리스트 영역

왼쪽 컨텐츠 영역

갤러리 리스트 영역

갤러리 리스트
번호 제목 글쓴이 작성일 조회 추천
설문 내 돈 관리 맡기고 싶은 재태크 고수 같은 스타는? 운영자 26/01/12 - -
AD 집에서 즐기는 Fresh 미식회 운영자 25/12/22 - -
공지 프로그래밍 갤러리 이용 안내 [103] 운영자 20.09.28 49265 65
2910407 이명박근혜 치세를 무너뜨린 ㅇㅇ(49.165) 11:45 1 0
2910406 [대한민국] 윤 대통령 구형과 정보, 전쟁 가능성 ㅇㅇ(121.172) 10:55 17 0
2910405 환율 뒤지겠네. ㅇㅇ(49.165) 10:43 16 0
2910404 너무 뻔해 RyuDOG갤로그로 이동합니다. 10:26 26 1
2910403 카카오톡 웹버전 만들어봄 [1] 프갤러(116.47) 09:01 51 0
2910402 이 지경와도 진성 좌빨들은 RyuDOG갤로그로 이동합니다. 08:44 37 2
2910400 환률 1400원 아래로 내리는 방법은 ㅇㅇ(49.165) 07:30 26 0
2910399 1470원 다시 뚫었다. ㅇㅇ(49.165) 07:22 19 0
2910398 태연 / 어제 눈 ㅇㅅㅇ [2] 헤르 미온느갤로그로 이동합니다. 07:19 29 0
2910397 하루 한 번 헤르미온느 찬양 헤르 미온느갤로그로 이동합니다. 07:15 30 0
2910392 24살 이 정도 스펙 ㅁㅌㅊ? 재현갤로그로 이동합니다. 00:53 48 0
2910391 윤석열 前 대통령 ㅇㅇ(112.223) 00:32 65 0
2910390 <만약에 우리> 2은호, 1정원? 발명도둑잡기(118.216) 01.13 26 0
2910389 와인 마시고 싶다 [2] chironpractor갤로그로 이동합니다. 01.13 31 0
2910388 재수학원 와이파이 방화벽 어케 뚫음 제발 [4] ㅇㅇ(118.33) 01.13 50 0
2910386 현실공감 연애, 환상의 판타지 눌렀다…‘만약에 우리’ 박스오피스 ‘깜짝’ 발명도둑잡기(118.216) 01.13 17 0
2910385 it서비스 회사인데 여자가 원래 이리 많아? ㅇㅇ(61.82) 01.13 49 0
2910384 근데 코딩 입문때부터 바이브 코딩으로 하는게 맞아요?? [5] 프갤러(119.192) 01.13 94 1
2910383 심층기획-서부지법 점거 난동 1년 추적기 발명도둑잡기(118.216) 01.13 21 0
2910382 윤석열의 심리 분석, 권위주의적 성격자 MBC 발명도둑잡기(118.216) 01.13 21 0
2910380 계엄 포고령으로 본 윤석열의 정적들 - 뉴스타파 발명도둑잡기(118.216) 01.13 19 0
2910377 [속보] 특검, 내란우두머리 윤석열에 사형 구형 [2] 발명도둑잡기(118.216) 01.13 41 0
2910376 음파무기 살상범위가 5km나 됨 ㄷㄷ 프갤러(211.236) 01.13 36 0
2910375 북한 무인기 침투, 제3국 소행 가능성은? 발명도둑잡기(118.216) 01.13 18 0
2910374 AI가 좋긴 좋네 ㅅㅂ ㅋㅋㅋ [8] ㅇㅇ(118.38) 01.13 107 0
2910371 임베디드 어떠냐 ? [3] 프갤러(121.153) 01.13 67 0
2910364 사내 라이브러리의 현실 프갤러(115.21) 01.13 97 1
2910363 근데 ai때메 망했다는데 보안은 왜 여전히 바닥이지 [4] ㅇㅇ갤로그로 이동합니다. 01.13 126 0
2910362 국비학원 친목질개병신같다 [5] 프갤러(211.235) 01.13 102 0
2910361 오산공군기지(공작사) 공고뜨면 절대 가지마라 프갤러(117.110) 01.13 63 0
2910360 나는 사내 라이브러리화 극혐인게 [5] 프갤러(115.21) 01.13 103 0
2910359 개죽이 시발련 사진 왜 띄우는거지? [2] 뉴프로갤로그로 이동합니다. 01.13 80 0
2910357 노홍철이 잘 나가는 이유가 극좌라서 그렇누 ㅋㅋㅋㅋㅋㅋ [4] 프갤러(1.213) 01.13 64 0
2910356 회사 다닐려면 백신 맞아야해서 어쩔수 없이 맞앗다 <-개소리인 이유 야옹아저씨갤로그로 이동합니다. 01.13 47 1
2910355 공립 교사 하려는 학생입니다. 제가 따로 공부하고 싶은게 있어서 질문 [2] 프갤러(114.70) 01.13 44 0
2910354 요즘도 임베디드나 펌웨어는 mfc 씀? [9] ㅇㅇ갤로그로 이동합니다. 01.13 142 0
2910353 코드를 쉽게 짜야하는 이유 [1] 프갤러(115.21) 01.13 69 1
2910352 여기 제어하는 사람은 없냐 [7] 프갤러(115.21) 01.13 98 0
2910347 나혼자 산다 나는 자연인이다 나호남산다 나는 호남인이다 타이밍뒷.통수한방(1.213) 01.13 52 0
2910346 나님은 귀여운 MFC앱 시니어 개발자에욤 [5] 네오커헠(211.234) 01.13 193 0
2910344 미용사3사이즈와꾸티어맵어플로누가좀만들어주라 [1] 깃깃갤로그로 이동합니다. 01.13 44 0
2910343 화폐가 사용되는 지역을 기축통화로 집중하냐 지역통화로 분산하냐 결정 발명도둑잡기(118.235) 01.13 51 0
2910342 전쟁에서 사람이나 물자나 권력을 집중하냐 분산하냐 결정하는 이론 발명도둑잡기(118.235) 01.13 122 0
2910341 AI 없이 코딩하는 형들 대단하네 [2] 프갤러(59.16) 01.13 145 0
2910340 구형 스마트폰, 타블렛 활용법 [1] 발명도둑잡기(118.235) 01.13 123 0
2910339 프갤에 오는 이유 생각해보니까 ㅇ ㅅㅇ; [1] 프갤러(60.196) 01.13 72 0
2910338 자러감..ㅇㅅㅇ 헤르 미온느갤로그로 이동합니다. 01.13 38 0
2910337 임베디드 돈 못번다는애들 특징 [2] 초코냥갤로그로 이동합니다. 01.13 146 0
2910336 산책나갔다가 쪽팔려서 얼렁 들어옴 ㅇㅅㅇ 헤르 미온느갤로그로 이동합니다. 01.13 47 0
갤러리 내부 검색
제목+내용게시물 정렬 옵션

오른쪽 컨텐츠 영역

실시간 베스트

1/8

디시미디어

디시이슈

1/2