Archive for the ‘Programming’ Category

AVR 프로그래밍에서 유의할 점 몇 가지

Atmel사에서 나온 AVR이라는 MCU(Micro Controller Unit)으로

저렴한 가격에도 강력한 역할을 한다.

주로 Atmega128 이라는 칩을 사용하는데, 적절히 많은 수의 입출력 단자와 다양한 기능을 갖추고 있기 때문이다.

필자는 학사학위 논문에서 Atmega8 이라는 좀 더 작은 칩을 사용했는데, 기능은 적지만 가격도 저렴하고 싸이즈가 작아서 편했다.

뒤에 붙는 숫자 자체는 들어가는 프로그램 용량으로 알고 있는데 확실하지는 않다. (어쨌든 Atmega8은 8KB를 쓸 수 있다.)

AVR시리즈는 Atmel사에서 제공하는 AVR Studio 프로그램을 설치하고 WinAVR에서 AVR-GCC 컴파일러가 제공되기때문에

C언어로 작성할 수 있어서 매우 편하다.

하지만 C언어를 어느 정도 사용하는 사람이라도 몇 가지 유의할 점이 필요하다.

1. Win AVR 이라는 라이브러리를 설치해야 제대로 사용할 수 있다.

2. Preference 항목에서 MCU 클락 및 Optimization Level을 설정해야 한다.

3. 인터럽트 루틴 작성 방법을 배워야 한다.

4. 보통의 C언어와는 달리 이진수를 사용할 수 있다.

5. 보통의 C언어와는 달리 bool 타입 변수를 사용할 수 없다.

6. 인터럽트 루틴은 가능하면 짧게 작성해야한다.

7. 인터럽트 루틴은 기본적으로는 중첩(인터럽트 루틴 실행시 인터럽트가 또 생겨 다른 인터럽트 루틴으로 이동)이 불가하지만 가능하게 할 수도 있다.

8. 포트 입력 사용시 내부 풀업(Pull Up)은 제공되는 반면 풀다운(Pull Down)은 안되므로 하드웨어적으로 구현해야 한다.

9. 전원은 안전하게 공급되도록 한다. 전압을 9V등에서 다운시켜 사용하는 경우 꼭 레귤레이터를 쓰도록 한다.

10. 인터럽트 루틴안에 쓰이는 변수들은 꼭 volatile 키워드를 붙여서 사용한다.

11. 기타 AVR의 특징


AVR을 자유자재로 사용하기 위해선 AVR 문서(모델명을 구글링 하면 맨 위에 pdf문서가 뜬다)의 구석구석을 다 읽어서 전체적으로 파악하는 것이 좋다.

중간중간에 나오는 하드웨어 다이어그램도 종종 도움이 된다.

AVR을 잘 다루기 위해선

1) 어셈블리어에 관한 기본 지식

2) 인터럽트의 동작에 관련된 지식

3) 회로를 구성하는 방법에 대한 지식

이 필요하다고 생각한다.

위 세 가지는 보통 컴퓨터공학과 및 전기과에서 배울 수 있는 지식이지만

필자와 같은 타과생들도 이런 내용을 알아야 한다는 것만 알고 있다면 쉽게 익혀서 사용할 수 있다.(별로 어려운 내용도 아니다.)

아무튼 앞에서 다루었던 11가지 내용에 대해 조금 더 자세히 알아보자.

1. Win AVR 이라는 라이브러리를 설치해야 제대로 사용할 수 있다.

AVR Studio와는 별개로 Win AVR 에서는 각 AVR칩들에 대한 라이브러리 및 AVR-GCC 컴파일러를 제공한다.

이를 설치하지 않으면 어셈블리어로 짜는 엄청난 작업을 해야한다.

개인적으로 AVR-GCC가 성능이 그렇게 좋지는 않다고 생각하는데, 종종 컴파일 타임 오류도 잘 못 잡아내기 때문이다.

하지만 계속 발전해와서 요새는 꽤 쓸만하다고 생각한다. 어쨌거나 C언어로 짤 수 있다는 것은 축복이다.

2. Preference 항목에서 MCU 클락 및 Optimization Level을 설정해야 한다.

AVR Studio에서 Preference 항목을 들어가면 MCU와 그 클락, Optimization Level을 설정하는 곳이 있다.

필자의 경우 MCU로 Atmega8, 클락은 16000000hz(16Mhz), Op Level은 0레벨(-O0 ) 으로 설정해서 사용한다.

클락은 AVR보드에 외부 클락 소스를 부착시키면 바뀔 수 있다.(필자도 붙인 경우)

Op레벨은 컴파일러 최적화 단계일텐데 0레벨로 하는게 이곳저곳 마음대로 이동시키지 않고 보이는대로 컴파일 될거라는 생각에 이렇게 사용한다.

(하지만 더 높은 최적화 설정으로 해도 무방하리라 생각한다. 어디서 주워들은 얘기일 뿐이다.)

3. 인터럽트 루틴 작성 방법을 배워야 한다.

인터럽트 루틴이란 AVR에서 사용되는 여러가지 인터럽트들(외부 인터럽트, 타이머 인터럽트, USART송수신 완료 인터럽트 등)을 처리하는 구문을 말한다.

인터럽트 루틴은 기본적으로 함수를 쓰는 것과 유사한데, 단지 정의 부분이 약간 다르고 return이 없으며, 함수를 호출하는 부분이 main함수안에 없다는 것이다.

인터럽트는 AVR을 구동시키는데 있어서 가장 중요한 역할을 하므로 조금 자세히 설명할 것이다. 인터럽트를 완벽히 이해하고 있으면 AVR의 80%는 정복했다고 보면 된다.

다음과 같은 형태이다.

외부 인터럽트 0번을 처리하는 경우


#include "avr/interrupt.h"

SIGNAL(SIG_INTERRUPT0){

//contents

}

와 같은 식으로 인터럽트 루틴을 정의한다.

보통 main함수 앞에 적고, avr/interrupt.h 헤더파일를 포함해야 한다. (보통의 경우 헤더파일은 두 개정도 필요한데 avr/interrupt.h와 avr/io.h이다.)

모든 인터럽트 루틴은 SIGNAL이 그 이름이고 뒤의 인자가 다를 뿐이다.

이 인자에는 인터럽트 종류가 오는데 이는 Atmega8의 경우 iom8.h 헤더파일에서 확인할 수 있다.

AVR Studio에서 좌측 프로젝트 폴더 트리에서 External Dependencies안에 iom8.h 파일이 있는 것을 볼 수 있다.(다른 칩들의 경우 이름이 조금씩 다를 것이다.)

여기서 Ctrl+F로 SIG_INTERRUPT0 을 찾아보라. 찬찬히 읽어보면 다른 인터럽트 이름도 쉽게 파악할 수 있을 것이다.

이제 루틴 작성을 마쳤지만, 인터럽트 루틴을 작성했다고 인터럽트가 실행되는 것은 아니다.

인터럽트를 사용하겠다고 선언해주어야한다.

Reference문서에서 해당 인터럽트 관련 레지스터를 찾아보면 Interrupt Enable을 담당하는 레지스터가 있을 것이다.

main 함수에서 적절하게 Enable 구문을 쓰고 꼭 sei() 함수를 호출해준다.

위에서 언급했던 각 인터럽트에 해당되는 레지스터 비트는 개별적인 인터럽트를 켜고 끄는 역할을 해주고

SREG 라는 레지스터의 I번 비트는 개별적으로 켜진 인터럽트 모두를 최종적으로 사용가능하게 해준다.

이 SREG-I를 켜는 역할을 sei()함수가 해준다.

(즉 개별 인터럽트를 아무리 켜도 sei()를 해주지 않으면 어떠한 인터럽트도 실행이 안되고, 그렇다고 sei()를 실행했다해서 모든 인터럽트가 켜지는 것이 아니라 개별적으로 켜놓은 모든 것이 켜진다고 보면 된다.)

예를들어 Atmega8의 외부 인터럽트 0번의 경우


int main(){

MCUCR |= 0b0011;// 외부인터럽트0번의 추가 셋팅(Rising Edge)

GICR |= 0x40;//개별적으로 켜는 부분. 끌 때는 GICR &= ~0x40; 을 사용

sei();//개별적으로 켠 인터럽트를 최종적으로 다 실행가능하게 만들어주는 부분

...

return 0;

}

와 같다.

4. 보통의 C언어와는 달리 이진수를 사용할 수 있다.

보통 C언어에서는 숫자 12를

10진수로 12

8진수로 012

16진수로 0x0c

와 같이 표현하는데 2진수는 불가능한다.

하지만 레지스터를 많이 다루는 AVR의 특성상 2진수 표현도 제공하는데

2진수로 0b1100 으로 표현하면 되겠다.

5. 보통의 C언어와는 달리 bool 타입 변수를 사용할 수 없다.

보통의 C언어에서는 true 또는 false만을 나타내는 bool변수를 사용하는데

AVR에서는 구현상 불편함 때문인지 bool을 지원하지 않고 int형의 0, 1로 대체해야한다.

true = 1, false = 0 이라고 보면 된다.

while(true){} 구문도 while(1){} 과 같이 해주면 된다.

6. 인터럽트 루틴은 가능하면 짧게 작성해야한다.

인터럽트 루틴은 가능하면 짧게 작성하는 것이 좋다.

특히나 타이머 오버플로우 인터럽트를 사용할 때는 인터럽트가 1초에도 수 백번이나 발생하므로 조심해야한다.

만일 인터럽트 루틴에서 실행되는 내용이 매우 많을 경우

한 인터럽트 루틴이 오래 수행되고, 수행되는 동안 새로운 인터럽트가 발생할 수 있다.

이렇게 되면 뒤에 들어오는 인터럽트는 계속 실행되지 못하고 무시된다.

(Flag 기반의 인터럽트들은 후에 들어온 인터럽트 중 가장 최근 것 까지는 실행한다. 하지만 원하는 대로의 결과를 내기는 힘들다.)

따라서, 인터럽트 발생시 어떤 긴 작업을 해야 한다면 인터럽트 루틴에서 다 실행하지말고

인터럽트 루틴에서는 개시만 하고, 실제 수행은 main에서 처리하는 기법을 사용한다.

다음과 같이 전역변수를 이용해 구현한다.


volatile int start = 0;

SIGNAL(SIG_INTERRUPT0){

start = 1;

}

main(){

...

while(1){

if(start == 1){

//work to do

}

}

...

}

7. 인터럽트 루틴은 기본적으로는 중첩(인터럽트 루틴 실행시 인터럽트가 또 생겨 다른 인터럽트 루틴으로 이동)이 불가하지만 가능하게 할 수도 있다.

말 그대로이다.

앞에서 설명한대로 기본적으로 한 인터럽트 루틴을 실행중에는 다른 인터럽트를 처리할 수 없는데

이는 AVR에서 인터럽트를 처리하는 구조때문이다.

작성한 인터럽트 루틴은 해당 인터럽트가 발생할 때, 해당 실행을 멈추고 루틴 부분으로 넘어간다.

즉, main함수에서 무슨 작업을 하고 있더라도 인터럽트가 발생하면 그 작업을 멈추고 해당 루틴을 실행하기 시작한다.

실제로는 MCU 내부적으로 해당 작업을 저장하는데 4클락정도 소모되고 인터럽트루틴으로 넘어간다. (빠져나올때도 복구하는데 4클락정도 소모)

이 4클락 중에는 AVR이 내부적으로 SREG-I비트를 끄는 것이 포함된다.

이렇게 되면 이후 발생하는 모든 인터럽트는 해제되는데 인터럽트 루틴이 끝나고 돌아올때(RETI: RETurn from Interrupt)는 자동으로 SREG-I가 다시 켜진다.

따라서 Flag기반 인터럽트들은 다시 인터럽트 루틴이 수행될 수 있는 것이다.(하지만 정확하지는 않다. 여러번 쌓인 것도 한 번만 실행되므로)

중첩 인터럽트 루틴 실행 방법은 별로 추천하고 싶지는 않지만 인위적으로 가능하게 만들 수는 있다.(Reference 문서에도 나와있는 방법이다.)

인터럽트 루틴안에서 sei()를 수동적으로 호출하면 되는 것이다.


SIGNAL(SIG_INTERRUPT0){

sei();

...

}

하지만 타이머 오버플로우 인터럽트 처럼 자주 수행될 인터럽트 루틴을 중첩가능하게 만들어버린다면

계속 인터럽트 루틴이 쌓이기만하고 끝까지 실행되는 것은 영원히 없을지도 모르므로 주의해야한다.

8. 포트 입력 사용시 내부 풀업(Pull Up)은 제공되는 반면 풀다운(Pull Down)은 안되므로 하드웨어적으로 구현해야 한다.

외부 인터럽트를 비롯한 Port 입력 단자는 꼭 풀 업 또는 풀 다운을 해 주어야 한다.

이는 아무런 장치도 없는 경우 해당 포트가 말 그대로 값이 ‘뜬’ 상태에 직면하게 되는데

0V 또는 5V 와 같이 기본값이 들어오는 것이 아니라 2.3V등의 Random한 값이 마구 들어오기 때문이다.

이는 원치않는 결과를 초래한다.

외부 인터럽트의 경우 실제 인터럽트가 일어나지도 않았는데 4V정도가 들어오는 것 처럼 되어 버려서 수시로 인터럽트로 발생할 수도 있다.

이를 막기 위해서 풀 업 또는 풀 다운이 필요한데

풀 업은 기본적으로 5V, 풀 다운은 기본적으로 0V를 만들어 주는 것이다.

AVR에서는 내부적인 레지스터 설정으로 풀 업은 가능한데(Reference의 입출력 부분을 찾아보라)

풀 다운은 직접 회로를 짜야한다.

풀 다운의 경우 간단히 GND(그라운드)와 해당 입력 핀 사이에 큰 저항 하나를 연결해주면 된다.

보통 1k옴 ~ 10k옴을 사용하는 것으로 알고 있는데 주로 4.7k옴을 사용한다.

암튼 위의 범위 저항 중 굴러다니는 아무거나 매달면 된다.

9. 전원은 안전하게 공급되도록 한다. 전압을 9V등에서 다운시켜 사용하는 경우 꼭 레귤레이터를 쓰도록 한다.

이 것은 단순한 것인데 중요하다.

전압은 항상 안전하게 공급되어야한다.

만일 일정 전압 이하로 내려가면 AVR이 순간적으로 꺼졌다가 다시 켜지는 경우가 있는데

전원여부를 LED로 알 수 있다해도 순간적으로 끊어지는 것은 잡아내기가 힘들고,

결정적으로 껐다 켜지면 프로그램이 처음부터 실행되므로 예기치 않은 결과를 불러온다.

따라서 처음에 완성된 프로그램이 아니라 계속 만들어 가는 중이려서 오류가 발생할 수도 있는 상황이면

되도록 플러그를 꼽아 사용하는 전원 장치로 전원공급하기를 추천한다.

보통의 건전지는 용량이 작아서 조금 쓰면 금방 다 닳아 버려서 불편하다. 특히 쓰면 쓸 수록 전압이 떨어진다.

프로그램이 완성이 되면 그 때 건전지를 연결해서 해봐도 늦지 않다.

또한 여러가 센서를 사용하면서 높은 전압에서 다운을 시켜야 하는 경우도 있는데

어줍잖게 저항을 이용해서 분압을 하면 절대로 안된다.

반드시 7805 등의 레귤레이터를 사용하도록 하자.

저항을 이용해서 분압하면 출력에 따라서 전압이 불안정하다.

10. 인터럽트 루틴안에 쓰이는 변수들은 꼭 volatile 키워드를 붙여서 사용한다.

전역변수들은 volatile키워드를 붙이는 것이 안전하다.

특히 인터럽트 루틴안에 사용되는 변수들은 무조건 volatile을 붙이도록 한다.

volatile을 붙이지 않으면 컴파일러가 최적화를 하면서 선언부의 위치를 마음대로 옮겨 버릴 수가 있기 때문에

원하는 대로 동작을 하지 않을 수도 있다.


volatile int start;

volatile char c;

와 같이 선언한다.

11. 기타 AVR의 특징

AVR은 Harvard Architecture로 Instruction Memory와 Data Memory가 분리 되어있다.

2단계 Pipelining을 사용한다.

위의 11가지 유의사항을 잘 이해하고 지킨다면, C언어의 기본적인 지식만 있는 사람이라도 왠만큼 부드럽게 동작하는 AVR 프로그램을 짤 수 있을 것이다.

많은 도움이 되기를 바란다.

Perl 기본 문법

아래 글은 처음에 Simon Cozens의 Beginning Perl 이라는 책으로

공부를 시작하면서 나름대로 정리해놓은 것이다.

Perl은 문법이 워낙 다양한 만큼 자주 까먹어서 정리해놓고 Ctrl+F로 찾는 것이

도움이 많이 된다.

 

처음

ord(‘#’);   # returns ascii code of ‘#’

‘ adsfadfa’ # 아무것도 처리하지 않는다 /t /n 등… 하지만 //와 /. 만은 처리한다

q/ / , qq< > 등으로 바꿔서 쓸 수 있다.

print “ba”x3; # ba를 세번 출력한다

“afds”.”123″ # 문자열 합치기 연산자 (afds123 리턴)

변수:

use strict 사용을 하지 않으면

전역 멤버 변수 각각 뭐 잘 지정됨

만일 use strict 사용하면

전역은 our 멤버는 my로 명시해주어야함

기본적으로 단일 변수는 $, 배열은 @, 해쉬는 %로 시작한다. 그러나 이는 변수 형을 뜻하지 않고 리턴형을 말한다.

$name=”js”; #일때

“asf $name”; #은 asf js 를 리턴한다

스트링 변수 뒤에 바로 붙여 써야할 때는

${name}th # prints jsth

와 같이 사용

입력 받기:

$comment=<STDIN>;


3장 리스트와 해쉬

(12, 34, 1) #3개 원소를 가진 리스트이다.

qw/ / 등으로 쓸 수 있는데 원소의 구분은 comma가 아닌 공백으로 한다. qw/12 34 1/ 와 같이..

(3, 4, 5, 7) 이나 (3, (4, 5), 7) 은 서로 같다

리스트 원소의 접근은 대괄호로 한다.

@aa=(3, 4, 5, 7);

@aa[2]; #는 5를 리턴한다. 음의 인덱스는 뒤에서 부터 센다. aa[-1]은 7을 리턴한다.

@aa[(2,3)] 또는 @aa[2,3] 을 통해 부분 리스트를 구할 수 있다. 이는 (5, 7) 리스트를 리턴한다.

(1 .. 4) 는 (1, 2, 3, 4) 를 리턴한다. 정수가 아닐 때에는 버림한다. (1.3 .. 4.9) 도 준식과 같은 결과를 리턴한다.

(‘a’ .. ‘k’) 는 문자열 순서대로 리스트가 생긴다. 원소를 뒤집고 싶다면 reverse() 함수를 사용한다.

@at 과 $at 은 동시에 선언 가능하다( 각각 다른 변수이다.)

@at=(3, 4, 5);

$len=@at; # 이렇게 한 경우 $len 에는 자동으로 at의 길이인 3이 저장된다.

print @at; # 345 로 출력한다

print “@at”; # 3 4 5 로 출력한다

$a=(@at)[2]; 로 접근하면 $a에는 5가 저장된다

$a=$at[2]; 로 표현해도 같다 $ @ 기호는 본체의 타입이 아니라 리턴 값의 타입을 나타낸다.

my $ele;

for $ele (@at){ print $ele, “\t” } 하면 3    4    5 와 같이 출력된다. (모든 원소 출력)

# $ele 가 없다면 perl 이 알아서 $_ 라는 변수를 사용한다.

$#at 은 @at 리스트의 가장 높은 인덱스를 리턴한다. 즉 2 를 리턴함

리스트를 스택처럼 쓸 수 있다. pop @at 을 하면 가장 마지막 원소가 리턴되면서 리스트에서 제거된다

push @at, “asdf”; # asdf 스트링을 푸시

앞의 원소 쪽에서 push pop을 위해서는 unshift, shift 를 사용하면된다.

sort @at 을 하면 정렬된다.

해쉬:

%aa =(

amy => “good”,

bob => “good”,

chris => “bad”,

david => “nice”

);

화살표 좌측이 key값

배열과 호환이 되지만 key가 분간이 안가므로 조심해야한다

%aa=@bb;

@bb=%aa;

등의 연산이 된다는 소리다. (“amy”, “good”, “bob”, …) 과 같은 순서로 변환된다.

해쉬 접근은 $aa{david} 과 같이 한다. david는 따옴표를 붙여도 안붙여도 다 된다.


Loops and Decisions

변수 여러개 한방에 정의:

my ($a, $b); # 괄호 빼먹으면 안된다

chomp(어떤 스트링,[또 스트링]); 은 입력시에 캐리지 리턴을 하면서 생기는 개행문자를 없애준다.

사실 chomp는 우측 trim의 애칭이다.

if( not exists $aa{$i}){} # 이 것은 %aa 해쉬에 $i 이름의 key가 존재하는 않는 지를 검사한다

die “asdfafd”; # 에러 출력후 프로그램이 멈춤

defined $a # $a가 선언된 후에 초기화가 되었는지 판별한다

위의 if문은 다음과 같이 표현가능하다

die “asdfafd” exists $aa{$i};

또는

exists $aa{$i} or die “asdfafd”;

elseif 가 아니라 elsif를 사용해야 한다

중요 for문에서 $_ 는 단순 대입이 아니라 별칭이다 (C언어에서 &) 즉, $_을 변화시키면 해당 변수들이 같이 변한다.

작업 뒤에 for문을 써도 된다.

@ARGV는 실행시의 argument 배열이다.

last는 C언의 break; 이다

next는 C언어의 continue; 이다


Regular Expressions

split “asd adf”; # 띄어쓰기로 구분된 문장을 나누어진 배열로 리턴한다.

if($_ =~ /adf/) # 기본변수에 adf가 포함되어있나. if(/adf/)로 해도 됨

if($_ !~ /adf/) # 기본변수에 adf가 포함안되어있나

if(/adf/i) # insensitive matching 이다 일단 대소문자 구분은 안하는데 다른 것은 잘 모르겠다.

Perl Regex에서 특별한 기능을하는 Metacharacter는

. * ? + [ ] ( ) { } ^ $ | \   의 12개 이다.

기능을 없애고 싶다면 \Q 와 \E 의 짝으로 묶어버리면 된다.

if(/\Q$pattern\E/) 와 같이 사용하면 pattern 변수안에 들어있는 metacharacter들은 무시된다.

while(<>){} # 이 순환문은 실행시 던져진 아규먼트 이름을 가진 파일을 열어서 한 줄씩 $_로 읽어들인다

[^aeo] 는 aeo를 포함하지 않은 것

[1-3a-d] 와 같이 이어 붙이면 1-3또는 a-d라는 소리

\d 는 숫자 \w는 단어(문자또는 숫자) \s 는 공백에대한 shortcut이다. 각각 대문자로 쓰면 그것을 제외한다는 뜻이다.

\b 는 boundary로 공백이나 ” 등의 문자 또는 문자열의 시작 및 끝을 뜻한다. 즉 한 문장에서 단어단위로 자를 때 유용.

a? 라고 쓰면 a가 있을 수도 있고 없을 수도 있다는 것이다. s?he 는 she or he를 뜻한다

a+ 라고 쓰면 a가 하나 일수도 있고 연속 여러개일 수도 있다는 것이다.

a* 라고 쓰면 a가 없을 수도 있고 있을 수도 있고 여러개일 수도 있다는 것이다.

a{2,4} 라고 쓰면 a가 2번 3번 4번 반복될 수 있다는 것이다.

a{3,} 라고 쓰면 a가 3번 이상 반복될 수 있다는 것이다.

s/asdf/ase/; #처음 찾은 asdf 하나를 ase로 변환

s/asdf/ase/g; #모든곳에서 변환

유닉스 등에서 경로를 넘겨줄 때 \/usr\/bin 과 같은식으로 불편한데 s#/usr/bin/#으로 사용가능함

/m /s 등은 http://gypark.pe.kr/wiki/Perl/정규표현식#H_1_1_10 참고

/x 는 너무 드러운 정규식이 나왔을 때 공백 무시하게 하여 정리해서 볼 수 있게 해줌

split join 알아서 잘하면되고

transliteration은 substitute를 여러개 동시에 한다.

tr/asdf/0123/; 과 같이 쓰면 af는 03으로 바뀔 것이다. 여기서 질문은 $_ 이외의 다른 변수의 문자열은 어찌 바꾸냐인데?

$a =~ tr/asdf/0123/; 은 $a 내부에서 바뀐 횟수를 리턴하므로

$cnt= $a =~ tr/asdf//; 를 통해 asdf가 등장한 횟수를 셀 수 있다. 이렇게하면 아무 일도 발생하지 않지만

$a =~ tr/asdf//d; 를 쓰면 발생한 곳은 다 지워진다.

More Advanced Topic는 일단 뛰어넘기ㅋ


파일

<>는 <ARGV>의 약자

$/ 는 separator를 결정함. 기본값은 \n 임. 만일 빈 것 “”으로 지정하면 아무 공백도 없는 newline을 선택한 것(문단 단위)

undef로 지정하면 separator 없이 모든 문자를 한 변수에 대입하게됨

rand(숫자) 는 0에서 숫자 사이의 무작위 수 리턴

< $filename : 파일에서 읽어오기(STDIN 으로 입력 받는 것임)

> $filename : 원본 없애고 쓰기(위험)

>> $filename : 이어쓰기

숫자의 경우 <=> 문자의 경우 cmp 비교는 단순 == 또는 eq 와는 다르다.

왼쪽이 크면 1 같으면 0 오른쪽이 크면 -1을 리턴한다.

sort{$a <=> $b} 로 비교 방법을 지정해 줄 수 있다. $a, $b는 perldoc 검색해보니 sort에서만 쓰이는 특수변수라 한다.

handle을 대체하려고 할 때 *문자를 사용한다.

*INPUT=*STDIN 을 통해 파일 입출력을 하려고 만든 핸들을 STDIN으로 대체할 수 있다.

*을 이용하면 별칭으로 지정하는 것이다. (하나를 변경하면 다른 것도 같이 바뀐다.)

binmode FILEHANDLE; 을 사용하면 개행및 EOF 처리를 하지 않는다.(보통 문서들은 OS마다 각각 처리해준다)

만일 파일핸들을 많이 사용한다면 print FILEHANDLE “asdfa” 를 매번 써주기 귀찮으므로

select FILEHANDLE; 을 한번 써주면 그 이후의 print는 모두 STDOUT이 아닌 그 핸들로 간다.

다시 복구해주는 것을 잊으면 안된다.

localtime 함수는 로컬타임을 리턴 자세한건 perldoc 참조하면 될듯..

기본적으로 perl은 read write시에 버퍼링을 한다. 이것을 끄려면 $|=1; 로하면 되고 켜려면 0으로 하라

unix등의 시스템에서 file permission 은 umask(expr) 로 설정할 수 있다

piping: 어떤 프로그램의 출력을 다른 프로그램의 입력으로 사용 : ‘|’ 기호를 이용하면 됨

먼저오는 프로그램 | 뒤에 오는 프로그램 형식으로 됨

File test: 파일을 열기 전에 상태 테스트를 해봄 if(-d $filename) 등으로 할 수 있음 -d 대신 다른 것도 많음


References

$asdf=\@array; # 같이 사용하면 array에 대한 reference라고 할 수 있는데 여기서 단순 포인터가 아니라 별칭과 같은 개념이라서 값을 변화시키면 같이 변한다.

배열의 경우 $as=[2,3,4] 과 같이 () 대신 []로 사용하면 바로 익명reference를 생성 할 수 있다.

해쉬의 경우 $as={a=>”as”, b=>”bs”}; 와 같이 () 대신 {}로 사용하면 바로 익명 reference를 생성할 수 있다.

접근은 @{$as} 또는 %{$as} 등으로 할 수 있다.

배열의 reference의 경우 ${$as[0]} 와 같이 접근해야 할 경우가 있는데 귀찮으므로 $as->[0]으로 표기한다.


Subroutines

서브루틴은 C언어의 함수와 같은 것

sub asdf{

} 와 같이 정의하고 사용하면 된다.

하지만 정의보다 위쪽에서 호출이 되면 안되는데 이를 대비해 C언어처럼 먼저 선언만 해준다.

이는

asdf(); 로 할 수도

sub asdf; 로 할 수도 있고 두 개 이상인 경우

sub asdf; sub sdf; 와 같이할 수도 있고

use subs qw(asdf sdf); 와 같이 할 수도 있다.

sub routine 에 들어가는 변수들은 @_ 배열에 저장된다.

묵시적 return 값은 subroutine 마지막 행에 작성하면 된다.

명시적 return을 위해서는 subroutine안에 return $asd; 등으로 작성하면 된다.

sub의 실행속도를 높이기 위해 한번 계산한 값은 캐싱 하는 기법이 있는데

my %cache;

sub first_line {

my $filename=shift;

return $cache{$filename} if exists $cache{$filename};

open FILE, $filename or return “”;

my $line=<FILE>;

$cache{filename}=$line;

return $line;

}

과 같다.

함수 오버로딩이 가능한데

함수 내에서 리턴 타입을 판별할 수도 있다.

subroutine 내부에서 wantarray 라는 함수를 호출하면 array형의 return인지 아닌지를 판별해준다.

MPlayer를 이용한 동영상 음원 추출

MPlayer는 원래 오픈 소스 동영상 재생기이지만

커맨드 라인을 통한 간단한 포멧 변환을 지원하기 때문에

다음과 같은 명령어로 test.avi 에서 test.mp3 로 음원을 추출할 수 있다.

mplayer -vo null -dumpaudio test.avi -dumpfile test.mp3

이 작업을 폴더 내의 모든 avi 파일에 적용하기 위해서

Perl 스크립트로 짜 보면

#!/usr/bin/perl
#avi2mp3.plx
use strict;
use warnings;

opendir(DIR, ".") or die "$!\n";
my @files = readdir(DIR);
closedir DIR;

foreach(@files){
	my $filename = $_;
	next if $_ = /^\.\.?$/;

	$_ = $filename;
	next unless (-f $_);

	$_ = $filename;
	next unless $_ = /^(.*)\.avi$/;

	$filename = $1;

	print "Extracting mp3 from $filename\.avi\n";
	my $cmd = "mplayer -vo null -dumpaudio $filename\.avi -dumpfile $filename\.mp3";
	system($cmd);
}

와 같이 쓸 수 있다.