Arduino LED 제어하기





모든 제어동작할 때 항상 기본적으로 시작하는 LED제어를 해보았다.




LED의 회로는 항상 간단하다.


소스

void setup() {

//LED 핀 설정을 해줍니다.

pinMode(11,OUTPUT);

}

 

void loop() {

//1개씩 순차적으로 켭니다.

digitalWrite(11,HIGH);

delay(500);

 

//1개씩 순차적으로 끕니다.

digitalWrite(11,LOW);

delay(500);

}

 

이 함수들을 간단히 이용한다면 사용자가 원하는 다양한 패턴을 사용할 수 있다.



=========================================================================


pinmode() : Arduino 보드의 pin을 입력 핀으로 사용할지 아니면 출력 핀으로 사용할지 설정하기 위하여 사용한다.

 

아두이노 우노에서는 20개의 디지털 입/출력 핀들이 제공되고 있습니다. 디지털 14 (D0 ~ D13), 아나로그 6(A0 ~ A5) 20개를 지원합니다. 즉 디지털 입출력 핀이 모자라면, 아나로그 핀들도 디지털 핀들로 사용 가능하다는 것입니다.

우선 사용할 핀들을 어떻게 사용할 것인지를 결정하는 명령이 바로 pinMode입니다.

문법

void pinMode(pin, mode)

pin은 디지털 입출력으로 사용할 핀 번호이며, modeINPUT, INPUT_PULLUP, OUTPUT과 같이 동작할 모드 값입니다.

설명

pin 값으로 디지털 핀들은 0 ~ 13 값으로 할당되고, 아나로그 A0 ~ A5 핀들은 14 ~ 19로 할당되어 사용됩니다. A0A5는 상수로 정의되어 있어 mode 값으로 같이 사용할 수 있습니다. A0 혹은 14를 사용하여도 같은 결과를 얻을 수 있습니다.

modeINPUT, INPUT_PULLUP, OUTPUT 3가지 모드를 지원하고 있습니다. OUTPUT은 핀을 출력 용으로 사용하고자 할 때 , INPUTINPUT_PULLUP은 둘 모두 입력 용으로 사용하고자 할 때 필요한 것이며, INPUT_PULLUP은 내부적으로 PULLUP 저항을 사용하여 외부에서 신호 값을 넣지 않을 경우에는 PULLUP 저항을 통하여 +5V가 공급되어 "1"로 읽히게 됩니다. 이를 간단한 회로도를 통하여 설명하는 것이 이해가 쉬울 것입니다.



digitalWrite() : digitalWrite(pin, value)는 디지털 출력 핀 pin에 정수 0(LOW) 혹은 정수 1(HIGH) 값을 써 출력 핀의 전압을 0V 혹은 아두이노 보드의 동작 전압에 따라 +3.3V 혹은 +5V로 만드는 함수

 

문법

아두이노에서 사용되는 모든 디지털 핀들의 번호 값을 pin에 넣고, 핀의 출력 전압을 0로 하고자 하면, 0 혹은 LOWvalue에 넣고, 출력 전압을 VCC로 하고자 하면 1 혹은 HIGH를 넣고 호출하면 됩니다. 아날로그 A0 ~A5 핀들도 디지털 핀들로 사용될 수 있으며, pinA0와 같은 값을 넣으면 됩니다.

void digitalWrite(uint8_t pin, uint8_t value)

주의하여야 할 사항으로 먼저 pinMode(...) 함수를 사용하여 핀의 동작 모드를 출력 모드로 설정한 후에 digitalWrite(...) 함수를 사용하여야 원하는 동작 결과를 얻을 수 있습니다. 물론 내부 풀업 저항으로 사용하기 위한 용도일 경우, 필요치 않습니다:

// 사용하는 3, 4, A0, A1 핀들을 출력 핀으로 설정합니다:

pinMode(3, OUTPUT);

pinMode(4, OUTPUT);

pinMode(A0, OUTPUT);

pinMode(A1, OUTPUT);

 

digitalWrite(3, HIGH); // HIGH1과 같습니다

digitalWrite(4, 1); // 출력 핀을 VCC로 만듭니다

digitalWrite(5, HIGH); // 내부 풀업 저항으로 사용

// pinMode(5, INPUT_PULLUP)과 같은 효과

digitalWrite(A0, LOW); // LOW0와 같습니다

digitalWrite(A1, 0); // 출력 핀을 0volt로 만듭니다

또한 analogWrite(pin, value) 함수로 PWM을 신호를 발생하고 있는 출력 핀에 사용하면 당연히 PWM 신호 발생이 중단되게 됩니다.

 


Arduino 온도센서(LM35) 사용


아두이노를 접하면 기본적인 센서 중 하나가 온도센서 LM35이다.

작동전압은 작동 전압은 2.7V ~ 5.5V 이다.

0~100도까지 측정가능하다고 한다.

 

아래 이미지의 순서대로 연결하면 센서가 작동한다.


Source

float temperature;

int reading;

int lm35Pin = A0;

 

void setup()

{

analogReference(DEFAULT); // param

Serial.begin(9600);

}

 

void loop()

{

reading = analogRead(lm35Pin);

//temperature = reading/9.31; //1.1기준전압인 INTERNAL로 할 때 적용 식

temperature = (5.0 * analogRead(lm35Pin) * 100.0) / 1024;

Serial.println(temp);

delay(1000);

}

 

LM35센서에 적용되어 전압을 온도로 변환시키는 공식이 설명되어있다.


http://playground.arduino.cc/Main/LM35HigherResolution


temp = (5.0 * analogRead(tempPin) * 100.0) / 1024;

 

결과

analogReference(INTERNAL)


analogReference(DEFAULT)





====================================================

analogReference() : ADC의 기준전압을 설정하는 함수

param

-DEFAULT: analogReference() 함수를 사용하지 않고 analogRead() 함수를 사용하면 기본으로 동작하는 모드이며, analogReference(DEFAULT) 함수를 사용하면 5V 전압을 사용하는 아두이노 보드들에서는 5 볼트, 3.3V 전압을 사용하는 아두이노 보드들은 3.3 볼트를 아날로그 기준 전압 값으로 사용한다.

 

-INTERNAL: 내장 기준 전압을 사용한다는 의미이며, ATmega168ATmega328 MCU를 사용한 아두이노 보드에서는 1.1 볼트, ATmega8 MCU를 사용한 보드에서는 2.56 볼트가 아날로그 기준 전압이 된다. 이 설정은 아두이노 메가에서는 사용할 수 없다.

 

-INTERNAL1V1 (아두이노 메가 보드 전용): 내장 1.1 볼트를 아날로그 입력 기준 전압으로 사용한다는 의미다. 아두이노 메가 보드에서만 사용 가능하다.

 

-INTERAL2V56 (아두이노 메가 보드 전용): 내장 2.56 볼트를 아날로그 입력 기준 전압으로 사용한다는 의미이며, 아두이노 메가 보드에서만 사용 가능하다.

 

-EXTERNAL: AREF 핀에 외부 전원(0에서 5V 사이의 전압만 사용하여야 함)을 연결하여 기준 전압으로 사용할 수 있다.

경고

===

0V 보다 작거나 5V 보다 높은 외부 전압을 AREF 핀에 연결하지 안됨. AREF 핀에 외부 기준 전압을 연결하여 사용하고자 하면, analogRead() 함수를 사용하기 전에 꼭 EXTERNAL로 기준 전압을 설정해야 한다. 이렇게 하지 않으면, 내부에서 만들어낸 기준 전압과 외부에서 AREF 핀으로 공급되는 전압이 합선되어(short) 아두이노 보드의 마이크로컨트롤러를 손상시킬 수 있다.

 

다른 방법으로서, 외부와 내부 기준 전압을 번갈아 가며 사용할 수 있도록 외부 기준 전압을 5K 저항을 통하여 AREF 핀에 연결할 수 있다. 이렇게 저항을 통하여 외부 기준 전압을 공급하면 AREF 핀에 내부 저항 32K가 연결되어 있어 외부 기준 전압과 다른 전압이 AREF 핀에 공급되게 된다. 두 저항이 전압 분배기와 같이 동작하기 때문이며, 예를 들어 2.5V가 저항을 통하여 AREF 핀에 공급되면, AREF 핀의 전압은 2.5 * 32 / (32 + 5) = ~2.2V가 된다.

 

 



Arduino Tool 설치

 

www.arduino.org 접속한다.


다운로드 탭에서 PC설정에 맞는 설치파일로 받는다. 나는 Window라 Window로 받았다.


설치파일 실행하면 이런 창이 뜬다 "I Agree"


기본설정으로 설치하였다. "Next"


Driver들을 설치해주어야한다. "항상 신뢰 후 설치"


설치 된 항목을 확인할 수 있다.




장치관리자에서 설치가 되었는지 확인할 수 있다.


처음 실행한 Arduino Sketch 모습이다.


사용하고자하는 Board 설정을 해준다.


아까 장치관리자에서 확인한 컴포트 넘버링을 설정해준다.


기본적으로 예제들을 제공하고 있어 손쉽게 다룰 수 있다.


졸업작품을 준비할 때 썼던 assert 함수에 대해 기록하고자한다.


assert 함수는 assert.h 헤더를 추가해 주어야 사용 할 수 있다고 인터넷 설명에 나와있지만


기본적인 사용 (예로 설명하겠다.) 을 하고자 한다면 assert.h없이 그냥 사용하여도 무방하다고 한다.


assert는 조건에 따라 에러메세지를 띄우고 종료되므로 어떠한 가정하에 점검하기 좋은 방법이다. (Debug 모드에서만)

 -> Release 모드에서는 코딩하지 않음.



원리는 간단하다.


assert(parm) 인데 파라미터 값이 1이 된다면 에러없이 코딩 될 것이고

                                          0이 된다면 에러로 코딩이 종료될 것이다.

( 조건문을 떠올리면 이해하기 쉽다. )

--> 그렇다면 어디서 Err난지도모르고 쓸모 없지 않는가 싶다.


어디서 에러난지 구분하기위해 메세지를 넣어야겠다.


a=1;

assert(a!=1 && "a는 1이지");

//assert의 인자값은 거짓(FALSE) 이므로 "a는 1이지"란 메세지를 띄우며 종료 된다.




정리하자면

- assert 매크로는 코드상 과정을 철저하게 점검하기 위해 간단히 사용 할 수 있다.

- 프로그램을 방어적으로 만들어줌.

- Release 모드시 assert 매크로는 컴파일되지 않는다 => 코드완료 후 일일이 안지워도 됨)

여기서 주의할점은

 *** Release 모드일때는 컴파일 되지 않기 때문에 사용되는 데이터는 변경해서는 안된다.



  


메모리 누수에 대해 알아보다가 좋은 글이 있어 담아왔습니다.

(URL) http://powergi.tistory.com/entry/embedded%EC%97%90%EC%84%9C-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B4%80%EB%A6%AC

댓글에도 많은 의견이 있으므로 참고하면 좋겠습니다.

==================================================================

1. 개요

이 문서는 ESP-NS에서 동작하는 응용 프로그램을 
작성할때 메모리 할당과 해제및 메모리 처리에 
대한 주의점을 소개합니다. 

작성자 : 유영창 frog@falinux.com
작성일 : 2004년 9월 17일 
수정일 : 

관련된 ADK( Application Developer Kit ) 디렉토리 

adk/sample/check_index
adk/sample/assert


2. 임베디드에서 메모리 관련 문제 

임베디드 시스템은 사용시간에 따라서 크게 두가지로 
나누어 볼수 있읍니다. 

첫번째는 필요한 경우만 전원을 넣고 동작시켜 사용하는 경우로 
동작 시간이 짧은 경우입니다. (참으로 고마운 시스템입니다.)

두번째는 모니터링 시스템같이 지속적인 제어가 필요하여 
1년 365일 전원이 절대로 나가면 안되는 경우 입니다. 

프로그래머 입장에서 보면 첫번째 방식을 좋아 하게 됩니다. 
이건 무정전 시스템에 사용되는 프로그램을 작성하신분들이라면
온몸으로 느끼는 감정입니다. ( 해본 사람들은 압니다. ㅜㅜ )


시스템이 무정전으로 동작한다는 것은 여러가지를 고려 해야 합니다.
그중 으뜸은 메모리 누수 입니다. 

C 로 작성하는 프로그램은 반드시 메모리에 관련된 문제 때문에 
한번 이상은 반드시 고생하게 됩니다. 

더구나 C 언어에 익숙하지 않으신 분이라면 포인터 참조에 관련된
수 많은 버그로 엄..청..난... 고생을 합니다. 

그래도 

납품하기전에 메모리 관련된 버그 문제점을 알게 되면 그나마 
다행입니다.

그러나 프로그래머 입장에서 두고 두고 속썩이는 것중 하나가 
장기간 동작하다 멈추는 경우입니다.

프로그램을 수정해서 버그를 잡았는지 확인하려고 하면 
몇일씩이나 걸리기 때문에 프로그래머들을 미치기 일보 
직전까지 만듭니다. ( 대부분의 경우 어디에서 발생했는지도 
잘 모르죠.. )

이런 경험을 여러번 하다보면 나름대로의 방법론이 생깁니다.

이런 경험과 관련되어 메모리를 다루는 방법에 대한 몇(?)가지와
메모리 할당과 해제에 관련된 함수를 소개하려고 합니다. 


3. 배열을 사용하라....

PC 프로그램을 작성하시던 분들이 임베디드 시스템에서
프로그램을 작성할때 가장 걱정되는 습관 중 하나가 
메모리 할당과 해제를 아주 좋아 한다는 겁니다. 

PC 시스템에서 작성하는 프로그램은 실장된 메모리가 
많기 때문에 메모리 할당과 해제를 이용하면 
유연한 프로그램이 가능해 집니다. 

그..러..나..

임베디드에는 메모리 할당과 해제를 자주 이용하는 습관은
절대적으로 말리고 싶은 것 습관중 하나입니다. 

보통 제품을 설계하는 분들이 개발자들에게 요구하는 것중 
하나가 만능제품이죠...

그런데 이 만능은 프로그래머가 만능이 되어야 합니다.
이런 경우에도 적용될수 있고 저런 경우에도 적용될수 있고 

마음약한 개발자들은 이런 요구를 수용합니다.

그러다 보니 개발해야 하는 프로그램 구조가 요구 사항에 
가변적인 구조를 가지게 되죠..

결국 메모리 할당 구조와 리스트와 같은 자료 구조를 사용하게
됩니다. 

이때부터 개발자는 머리털 빠지기 시작합니다. 
( 제가 속빈 인간이 된 사연이 여기에 있읍니다. )
리스트구조와 메모리 할당은 시스템의 버그 원인 순위에 
가장 상위 순위를 차지 합니다. 

오랜 연륜을 가지는 개발자들은 일단 이런 영업 요구에 
적절히 대항합니다. 

그리고 어느정도 제품이 필요한 요구 사항을 제한합니다.
그리고 그에 맞게 프로그램을 개발합니다. 

이때 이 분들이 작성한 프로그램을 보면 ( 무정전 제품에 
들어가는 프로그램일수록 ) 전역변수와 배열을 많이 사용하게
됩니다. 

이 전역변수와 배열을 사용하는 것은 
프로그램을 처음 배울때 회피하라고 들었던 것인데 
의외로 고수일수록 많이 사용합니다.
(심지어 goto 문을 남발하시는 고수도 많습니다. )

배열을 사용한다는 것은 일정한 크기를 갖기 때문에 
확장성에 용이하지 않을 것 같은데 
환경 파일로 모든 확장성을 고려하는 것은 임베디드 
제품에 크게 의미가 없읍니다. 

이미 한정된 크기의 메모리를 가지고 있는 시스템에 
확장할수 있는 크기를 가지도록 프로그램을 작성한다는 것은 
의미가 없읍니다. 


배열을 사용하게 되면 다음과 같은 장점이 있읍니다 

1) 메모리 할당과 해제와 관련된 버그가 없다. 
2) 메모리 할당과 해제에 소모되는 시간 소모가 없다. 
3) 인덱스 방식의 참조가 가능하므로 잘못된 포인터 
참조에 의한 버그 가능성이 작다. 
4) 시스템의 메모리를 효율적으로 사용할수 있다. 
5) 참조 속도가 매우 빠르다.
6) 프로그램 소스 코드가 직관적이다. 
( 포인터 참조 연산자가 얼마나 어려운 코드 형식을 
작는지 다들 아시죠? )

등등의 장점이외에 더 있지만 생각이 안 나는 군요...

어쩄든 임베디드 장비에 사용되는 프로그램은 가급적 배열을 
사용하시는 것이 좋습니다. 

3. 가급적 상수를 매크로로 정의해서 사용하라

메모리 이야기에 왠 매크로 상수?

뭐 이렇게 궁금하게 생각하시는 분들이 있을 것 같은데...
이래야 고수 소리를 듣습니다. 소스에 숫자가 적게 보일수록 고수 입니다 


예를 들어 보죠...

어떤 분은 프로그램을 이렇게 작성합니다. 

char check_ids[300];

고수는 이렇게 작성합니다. 

#define MAX_CHECK_IDS 300
char check_ids[MAX_CHECK_IDS];


이것은 나중에 확장성을 가지는 효과가 있고 
접근하는 인덱스의 검사를 할 경우에 유용합니다. 


또한 인데스 검사를 하는 경우에 유용합니다.
보통 프로그램을 작성할때 인덱스 접근에 대하여
다음과 같이 처리하면 좋습니다. 


char get_date( int index )
{
#ifndef NO_CHECK_INDEX_FLAG
if( (index < 0) || (index >= MAX_CHECK_IDS ) )
{
dlp( "index over\n" );
exit(0); 
}
#endif
return check_ids[index];
}

또는 아예 인덱스 검사를 하는 함수를 매크로로 만들어서 사용하는 경우도 있읍니다. 

선언예)

#ifndef NO_CHECK_INDEX_FLAG
#define check_index(idx,max) {\
if( (index < 0) || (index >= MAX_CHECK_IDS ) ) \
{ \
dlp( "index over\n" ); \
exit(0); \
} \

#else 
#define check_index(idx,max) {}
#endif 


사용예)

char get_date( int index )
{
check_index(index,MAX_CHECK_IDS);
return check_ids[index];
}

3. 초기화를 꼭 하라

변수를 사용할때 특히 전역 변수를 사용할때 
초기화를 하는 습관은 버그를 예방하는 효과가 있읍니다. 
특히 포인터 형식의 필드변수를 포함하는 구조체가 있을 경우에는 특히나 그렇습니다.

초기화 값은 0으로 사용하는 것이 좋습니다. 
포인터의 

4. sizeof 함수를 즐겨 사용하라 

메모리 복사나 초기화를 사용할 경우와 같이 배열이나 구조체의 크기를 구할 필요가 
있을때 sizeof 를 자주 사용합니다.

귀찮아서 그냥 숫자를 주는 습관을 가진 분들이 있는데 
이런 분들에게 sizeof 함수의 사용을 강력하게 권장합니다. 

앞의 배열에서 초기화를 처리할때 다음과 같은 형식으로 처리하는 것이 좋죠...

memset( check_ids, 0, sizoef( check_ids ) );

복사할 경우에 역시 이런 식으로 사용하는 것이 좋습니다. 
하지만 복사할 경우에 크기는 어느 것을 사용하는 것이 좋을까요?
권장하는 것은 앞에것을 사용 하는 것입니다 

void copy_item( struct a *bdata )
{
struct a adata;

// 권장하는 예 
memcpy( &adata, bdata, sizeof( adata ) ); 

// 별로 권장하지 않지만 좋은 예 
memcpy( &adata, bdata, sizeof( struct a ) ); 


}


5. 포인터의 간접 인덱스를 사용할 때는 주의하라...

포인터 변수를 사용할때 포인터의 초보자들이 실수하는 큰 것 
중에 하나는 다음입니다. 
특히 하드웨어를 다룰때 많이들 실수 합니다. 

char *app;
int *bpp;

app++;
bpp++:

이것은 1씩 증가 시키는 겁니다. 
그런데 app 나 bpp 에 0x300000 이라는 주소값이 있다면
app는 0x30000 이 되지만 bpp 는 0x300004 가 된다는 것을 
까먹습니다. 

이것이 나중에 속썩일 경우가 많다는 점을 기억하십시오

(app+ 1) 과 (bpp+ 1) 도 마찬가지 입니다. 
이런것은 매크로를 사용해서 선언할 경우 많이들 실수하는 겁니다. 

예를 들어 하드웨어 레지스터를 접근하는 경우에 

#define REG_A(x) (x + 1)
#define REG_B(x) (x + 2)

이런식으로 처리할때 매크로는 단순히 문자열 치환이기 때문에 
위와 같은 문제가 발생할수 있다는 것입니다.


6. 스택변수 즉 로컬 변수를 조심하자 

함수안에 선언하는 로컬 변수는 두가지 장점이 있읍니다. 

선언이 간단하고 할당에 걸리는 시간이 없다는 것입니다. 
그러나 이 로컬 변수는 버그의 온상이 되므로 주의할 필요가 있습니다. 

예를 들어 다음과 같은 경우를 생각해 봅시다. 

int test_func( char *tmpstr )
{
char buff[32];
int p;

p = strlen( tmpstr) ;

sprintf( buff, "ID:%s", tmpstr );
write_func( buff );

return p;
}

이 함수를 소스상에서 본다면 아무런 문제가 발생하지 않는 함수입니다.
그런데 이 함수는 두가지 문제점을 가지고 있읍니다. 

만약 tmpstr 이 NUL 코드를 포함하지 않는다면?
또는 tmpstr 이 28 자 이상이 된다면 ?

아...

프로그램은 어떻게 동작할지 아무도 장담할 수 없읍니다. 

다행히 세그먼트 폴트라도 발생해서 미리 알수있다면 좋지만
스택을 접근 할 경우에는 세그먼트 폴트가 잘 발생하지 않습니다. 

경우에 따라서는 스택이 깨지기 때문에 엄한 곳으로 프로그램이 점프할수도 있고 
다른 변수들이 수정될수도 있읍니다.

더구나 특별한 경우에는 두번 호출되어 도착한 함수가 꺼꾸로 리턴될때 
중간 함수를 거치지 않고 리턴되거나 진행 루틴이 실행되지 않을 경우도 있읍니다. 

또는 뒤에 선언된 변수들 값이 수정될수도 있읍니다. 

이런 경우에는 스택 변수의 크기를 아끼지 않는 것이 가장 최선의 예방책입니다. 
(물론 주의해서 작성하는 것이 더 큰 최선의 에방책이죠.. )

예를 들어 넘어온 크기보다 2 배나 3 배정도의 크기를 잡는 겁니다. 

위의 경우에는 char buff[128] 정도로 선언하는 것이 안전합니다. 

또는 버퍼의 뒷쪽에 임의 변수를 하나 두는 것도 요령인데 
별로 추천은 하고 싶지 않군요


7. 자료구조를 사용한다면 검증된 라이브러리를 사용하라..

프로그램을 작성하다보면 배열보다 리스트와 같은 자료구조를 
이용하는 것이 효율적일때가 있읍니다. 

대표적인 것들이 

스택이나 , 큐, 더블 링크드 리스트 , 리스트, 이진 트리 리스트
등등이 있읍니다. 

이때 많은 분들은 직접 만들어 사용합니다. 

그런데 이런 처리는 포인터를 사용해야 하고 저같이 논리에 약한
사람들이 만들면 버그가 살기에 좋은 환경을 제공합니다. 

그래서 저는 인터넷에 관련 자료 구조용 공개된 소스를 이용하기를 
권장합니다. 

특히 소스포지에 가면 이런 자료 구조체 라이브러리들이 많이 있읍니다.
가급적 이렇게 공개되고 여러사람이 사용하고 있는 것을 이용하기를 
바랍니다.

직접 만들면 피 봅니다... ㅜㅜ

8. 메모리 할당 함수들 

C 에서 메모리를 할당하기 위해서 사용하는 함수들은 다음과 같습니다. 

void *calloc(size_t nmemb, size_t size); // 할당 + 메모리 클리어 
void *malloc(size_t size); // 할당
void free(void *ptr); // 해제 
void *realloc(void *ptr, size_t size); // 재 할당 + 메모리 복사 

이 중에서 가장 많이 사용하는 함수는 

malloc 함수와 free죠...

하지만 malloc 함수보다는 calloc 함수를 사용하기를 권장합니다.
(저역시 malloc 함수를 자주 사용합니다만 ㅜㅜ )
그래도 malloc 함수를 자주 사용하게 되면 다음과 같은 처리를 꼭 해주시기를 바랍니다. 

char *buff = NULL;

buff = malloc( 1000 );
if( buff != NULL )
{
memset( buff, 0, 1000 );
}
else
{
// 에러 처리 ( 보통은 프로그램을 죽인다. )
}

if( buff != NULL ) free( buff );


9. assert 함수


앞에서 malloc 함수를 처리할때 에러가 난 경우에 대한 처리가 귀찮죠?
이런 경우 사용하거나 기타 등등에 사용하면 좋은 함수가 assert 함수입니다.


이 함수는 #include <assert.h> 를 포함하고 사용하면 되는데 
사용 문법은 간단합니다. 

assert( 논리식 );

이 함수는 논리식이 참이면 특별한 것을 하지 않습니다. 
그러나 거짓이면 에러를 표현 합니다. 
파일명과 함수명 그리고 라인번호와 함께 문제가 된 값을 표현합니다. 
그리고 프로그램을 죽입니다.( 으으 살벌.. )

보통은 포인터 변수의 값이 0이 되는 것을 방지하기 위해서 사용합니다. 

assert 함수는 NDEBUG 가 정의 되어 있으면 아무런 것도 하지 않는 
함수이므로 소스를 수정하지 않고서도 함수의 에러 처리를 무효화 
할 수 있는 무척 좋은 함수 입니다.



modaless의 경우 대화상자가 떠있는 상태에서 얼마든지 다른 작업을 할 수 있다.

modal의 경우 대화상자가 닫히기 전까지 다른 작업을 할 수 없다.


modal 형태로 창을 띄우는 것은 


CShapeDlg dlg;

dlg.DoModal(); // 이런 형태로 창을 띄우는 것이다.


modal로 창을 띄우는 경우, 이 창을 먼저 해결해야 부모 창으로 돌아갈 수 있다.




그리고 modaless 형태로 창을 띄우는 것은


CShapeDlg *dlg;


dlg = new CShapeDlg(); //혹은 CShapeDlg(this); 등으로 초기화 한 후

dlg->Create(IDD_SHAPE, NULL) //혹은 Create(IDD_SHAPE, DesktopWindow()); 등을 써서 만들어주고,

dlg->ShowWindow(SW_SHOW) //혹은 dlg->ShowWindow(SW_SHOWNA); 등등 으로 창을 띄워주면 된다.


//initDialog등을 처리해주고싶다면 

dlg->PostMessage(WM_INITDIALOG)

dlg->SendMessage(WM_CLOSE) //등을 넣어서 창을 닫아 줄 수 있다.




CDialog에 있는 OnTimer


OnTimer라는 메세지 핸들러는 SetTimer(타이머ID, 발생간격, 실행하려는 함수명)​과 함께 사용한다

// ​여기서 함수명에 NULL을 넣어주면 OnTimer를 사용


일정 시간 뒤에 원하는 업무를 처리하기 사용한다.

 

비슷한 기능으로 Sleep( millisecond ) 를 입력하는데

Sleep을 이용할 경우 해당 쓰레드 전체가 멈추어 버리고 그 멈춤에 따라 외부 인터럽트입력(키보드, 마우스, 등등)이

주어지게 되면 버퍼에 쌓였다가 한번에 처리되는 일이 발생하게 된다.

 

그래서 그걸 방지하기 위해 Timer를 사용하는데 사용방법은 다음과 같다.

 

 

 

등록

 BEGIN_MESSAGE_MAP(CGroupChatWindow, CDialog)

...

ON_WM_TIMER()

...

 END_MESSAGE_MAP()

메세지 맵에 'ON_WM_TIMER()'를 등록

 

 

타이머 시작

 SetTimer(1394,1000,NULL);

  파라매터

1) Timer의 ID값

2) SetTimer후 몇 millisecond후 마다 실행 (반복실행)

3) 함수명, NULL 사용시 오버라이드 함수 'OnTimer()'로 작동된다.

  반환값 : 핸들러

 

 

 

선언

 afx_msg void OnTimer(UINT nIDEvent);

헤더파일에 선언

 

 

 

오버라이드 함수 내부

 void CGroupChatWindow::OnTimer(UINT nIDEvent)
 {
    switch(nIDEvent)
    {
        case 1394:

             limitLatencyClickAble = TRUE;   
             mCheckSendVoice.EnableWindow(TRUE);

             break;
    }

    KillTimer(1394);
}

switch문을 사용하여 Timer의 ID를 구분하여 처리

SetTimer에 첫 파라매터에 1394를 적었기에 OnTimer( )에서는 switch문에 case로 1394

 

 

 

타이머 중지

 KillTimer(1394);

타이머 아이디를 입력하면 끝


virtual BOOL CWnd::OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult );


리턴

이 메시지를 처리한다면 어플리케이션은 0이 아닌 값을 리턴하며, 그 외는 0을 리턴한다.


인수

wParam : 메시지가 컨트롤로부터 왔다면 그 메시지를 보내는 컨트롤을 식별한다. 그 외는 0값을 가진다.

lParam : 신호 코드와 부가적인 정보를 가진 기 메시지 (NMHDR) 구조체의 포인터. 어떤 기호 메시지들에서, 이 인수는 그것의 첫째 멤버처럼 NMHDR 구조체를 가지는 더 큰 구조체를 가르킨다.

pResult : 메시지가 핸들되었다면 결과 코트를 저장할 LRESULT 변수의 포인터


설명

프레임워크는 컨트롤 이벤트가 일어나거나 그 컨트롤이 어떤 종류의 정보를 요구하는 컨트롤의 부모 윈도우에게 알리기 위해 이 멤버 함수를 호출한다.


OnNotify는 컨트롤 신호에 대한 메시지 맵을 처리한다.

 

 

Example

 

- header file 부문

// ClassWizard generated virtual function overrides

virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);

 

- implementation file 부문

BOOL CIconExDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
{
     // TODO: Add your specialized code here and/or call the base class

     NMHDR* pNMHDR = (NMHDR*)lParam;

     switch (wParam)
     {
     case IDC_R:
          if(pNMHDR->code == TCN_SELCHANGE)
          {
               // IDC_R을 눌렀을 경우 행해지는 소스 입력
          }
          else
          {

               // IDC_R을 땟을 경우 행해지는 소스 입력
          }
          break;

     case IDC_RIGHT:
          // IDC_RIGHT을 눌렀을 경우 행해지는 소스 입력
          break;
     }


     return CDialog::OnNotify(wParam, lParam, pResult);
}

 

 

1. 라즈베리파이 업데이트 및 업그레이드 실시

 

  sudo apt-get update

  sudo apt-get upgrade 

 

2. 소스관리툴 git 를 다운로드 (오픈소스 https://github.com/WiringPi/WiringPi 의 소스를 가져오기위해)

 

  sudo apt-get install git-core

 

3. “wiringPi” 프로젝트를 받아온다.

 

  git clone git://git.drogon.net/wiringPi

 

4. 빌드 및 설치

 

  cd wiringPi
  ./build

 

5. 아래의 명령어로 설치 확인

  gpio -v gpio readall

  

gpio readall을 해서

 

핀 구조가 나오면 wiringPi 라이브러리 설치 완료가 된것이다.

 

 

LED 회로를 간단하게 구성

 

 

vi에디터를 이용해 C언어를 제작

#include <stdio.h>
#include <wiringPi.h> // 라즈베리파이의 GPIO를 하기위해 아까 받아놓은 라이브러리를 사용

 

#define LED1 4         // GPIO 23 의 핀번호를 정의하기위해 #define 사용

 

int main(void)
{

 if (wiringPiSetup () == -1)
 return 1;                        

 // wiringPisetup() 함수는 라즈베리파이에서 현재 핀 번호가 제대로 다 매핑되어 GPIO기능을 할 수 있는지 검사하는 함수 [-1일땐 GPIO 작업 불능]

 

 pinMode (LED1, OUTPUT); // pinMode()는 보통 센서를 정의하고 어디에 사용 될건지 명시

 

 for(;;)
 {
  digitalWrite(LED1, 1);  // digitalWrite() 혹은 digitalRead()로 센서로 부터 데이터를 읽거나 출력

  delay(1000);

  digitalWrite(LED1, 0);  // 1은 ON 2는 OFF

  delay(1000);
 }
 return 0;
}
 

 

프로그램 컴파일

 

gcc -o gpio-test1 gpio-test1.c -lwiringPi

 

 

위의 컴파일 명령을 실행해 주면 gpio-test1 이라는 실행 파일이 생성

 

5. 프로그램 실행

 GPIO 관련 프로그램 실행은 항상 루트 권한으로 실행 (sudo 명령어)

GPIO23에 연결된 LED가 켜진 후, 1초 대기, 그리고 두 LED가 모두 꺼지는 작업을 반복 수행

프로그램 종료는 Ctrl + C 로 종료

 

 

 

sudo ./gpio-test1

.

 

 

라즈베리파이 원격 연결하기 위해 많은 정보를 찾아보았지만 블루투스 키보드, 무선 wifi 동글이 없는 상태라

 

남들 정보를 이용해서 하기엔 많은 어려움이 있었다.

 

이걸 성공하는데 오래 걸렸지만 어렵지는 않았다.

 

 

1. (iptime을 이용하였음) 랜 선을 라즈베리파이에 연결해주었다.

 

2. http://192.168.0.1 로 접속을하면 iptime 설정 사이트에 들어갈 수 있다.

 

 

들어 갔을 때 관리자명과 비밀번호를 입력하라는 메세지가 떠서

 

wifi단말기 뒤에잇는 rst 버튼을 15초 꾹 눌러 리셋 시켜주었다. 다시 비밀번호를 묻지 않았다.

 

 

3. 관리도구에서

 

 

 

고급설정 - 내부 네트워크 정보를 보면 아이피 정보를 얻을 수 있다.

 

4. putty 혹은 xshell 등 원격 접속 프로그램을 이용해 접속한다.

 

나는 xshell 을 사용 해왔어서 xshell을 이용해 접속 했다.

 

라즈베리파이의 기존 아이디와 비밀번호는

pi/raspberry 로 설정 되어있다.

 

 

 

 

 

5. 기본 설정

 

$ sudo raspi-config

 

이명령어를 치면 언어, 시간, 키보드 등 설정을 할 수 있다.

 

 

6. 원격제어 설치

 

접속 후 라즈비안 xrdp를 설치

 

$sudo apt-get update

$sudo apt-get install xrdp

 

 

7. 원격 접속

윈도우 보조프로그램의 원격 데스크톱 연결을 실행

 

 

라즈베리파이2의 ip를 입력 후

위의 id/pwd 를 입력 하게 되면

라즈베리가 보입니다. 

 

완성!

 

 

 

+ Recent posts