Posted by 살레시오
,
Posted by 살레시오
,

  아두이노에서는 기본적으로 printf()함수를 지원하지 않는데 그 기능이 아쉬울 때가 있다. 그런데 다음과 같이 vsprintf() 와 vsnprintf() 함수를 이용하면 쉽게 printf() 기능을 구현할 수 있다. 아두이노 setup()함수 위에 다음과 같이 _printf()함수를 정의한다.


#include <stdio.h>

#include <stdarg.h>


void _printf(const char *s, ...){

   va_list args;

   va_start(args, s);

   int n = vsnprintf(NULL, 0, s, args);//문자열 길이를 먼저 구함

   char *str = new char[n+1]; //메모리 할당

   vsprintf(str, s, args);//실제 내용을 복사

   va_end(args);

   Serial.print(str);

   delete [] str; //메모리 해제

}


그런데 이렇게만 하면 _printf() 함수 내에서 실수를 표시하는 서식문자 %f, %g, %e를  사용할 수 없다는 문제가 있다. 이 문제를 해결하려면 다음 파일을 열어서 수정해야 한다.


{아두이노 설치 폴더}\hardware\arduino\avr\platform.txt

윈도우의 경우 C:\Program Files\Arduino\hardware\arduino\avr\platform.txt


이 파일에서 다음 줄을 찾아서


compiler.c.elf.extra_flags=


다음과 같이 끝에 추가한다.


compiler.c.elf.extra_flags=-Wl,-u,vfprintf -lprintf_flt -lm


이제 아두이노 IDE를 다시 실행하면 된다. 전체 프로그램은 다음과 같다.


#include <stdio.h>

#include <stdarg.h>


void _printf(const char *s,...){

   va_list args;

   va_start(args, s);

     int n = vsnprintf(NULL, 0, s, args);

     char *str = new char[n+1];

     vsprintf(str, s, args);

   va_end(args);

   Serial.print(str);

   delete [] str;

}


void setup() {

 Serial.begin(9600);

 _printf("%d+%d=%d\n",1,2,3);

 _printf("float var %.4f\n",1.234);

 _printf("hello %s\n", "world");

}


void loop() {

}


시리얼 모니터를 통해서 볼 수 있는 실행 결과는 다음과 같다.


1+2=3

float var 1.2340

hello world


 한 가지 더 지적할 것은 아두이노에서는 문자열 상수를 전역변수로 저장하기 때문에 RAM을 차지한다. 그러니까 위의 프로그램에서 그냥 큰따옴표로 묶인 문자열들은 전부 램에 저장된다. 램용량이 많지 않은 아두이노에서는 문자열 상수는 보통 F() 매크로로 플래시메모리 영역에 저장하여 RAM을 아낄 수 있다. 위의 _printf() 함수의 첫 번째 인자를 F()매크로로 저장한 문자열로 받을 수 있도록 수정하려면 내부에서 vsnprintf()함수 대신 vsnprintf_P()을, 그리고 vsprintf()함수 대신 vsprintf_P()함수를 사용해야 하는데 다음과 같다.


#include <stdio.h>

#include <stdarg.h>


void _printf(const __FlashStringHelper *s, ...){

   va_list args;

   va_start(args, s);

     int n = vsnprintf_P(NULL, 0, (const char*)s, args);

     char *str = new char[n];

     vsprintf_P(str, (const char*)s, args);

   va_end(args);

   Serial.print(str);

   delete [] str;

}


void setup() {

 Serial.begin(9600);

 

 _printf(F("%d+%d=%d\n"),1,2,3);

 _printf(F("float var %.4f\n"),1.234);

 _printf(F("hello %S\n"), F("world"));

}


void loop() {

}


서식문자열 내부에서 플래시 문자열을 표시하려면 대문자 S를 사용한 ‘%S’ 서식문자를 사용해야 한다는 것에 유의하자. 실행 결과는 앞의 경우와 동일하다.



Posted by 살레시오
,

  Visual Stdudio Code(VSC)에 PlatformIO 플러그인을 깔고 아두이노 우노에 프로그램을 업로드해 보았다. (Atom에디터에도 플러그인이 있는데 Clang을 추가로 설치해 주어야 해서 설치 편의성은 VSC가 더 낫다.) 자동완성이 지원되는 등 VSC자체가 뛰어난 에디터이다 보니 개발 편의성은 높다.


  하지만 아두이노IDE로 프로그램할 때와 달리 c++ 문법을 strict하게 지켜야 한다.


#include <Arduino.h>

void blink();

void setup() {
// put your setup code here, to run once:
pinMode(13,OUTPUT);
}

void loop() {
blink();
}

void blink() {
digitalWrite(13,HIGH);
delay(100);
digitalWrite(13,LOW);
delay(100);
}


프로그램명도 main.cpp이다.(ino파일이 아님.) 위와 같이 Arduino.h를 명시적으로 인클루드시켜야 한다던지 함수의 선언도 반드시 해줘야 한다.


  컴파일은 문제 없고 업로드도 자동으로 우노가 연결된 포트를 인식해서 수행되었다.

Posted by 살레시오
,
Posted by 살레시오
,
Posted by 살레시오
,

javacc 버전 6.0에서 bin 디렉토리에는 javacc를 실행하는 스크립트가 없습니다. 그래서 Windows 명령 프롬프트에서 오류가 발생합니다. 있는 것은 lib 디렉토리에있는 jar 파일 javacc.jar입니다. 클래스 패스에 jar 파일을 추가하고 java.exe를 실행하고 javacc를 실행하는 기본 클래스를 전달하면 나중에 javacc라는 이름이 지정되므로 javacc를 실행하면됩니다.

cmd> java -cp C : \ javacc-6.0 \ bin \ lib \ javacc.jar javacc

최신 버전에서는 패키지의 bin 폴더에 스크립트를 추가하는 것을 잊어 버린 것 같다. 버전 5.0을 다운로드 할 수 있다. 필요한 모든 스크립트 파일을 포함하고 있다. javacc.bat라는 파일을 포함하고 있다.이 파일은 창 쉼표 프롬프트가 찾고있는 파일이며 사용자가 찾지 못한 파일이다.

좀 더 편한 방법은 5.0 버전의 스크립트를 6.0 버전의 bin 디렉토리에 복사하면 된다. C : \ javacc-6.0 \ bin을 포함하도록 경로를 설정 했으므로 명령 프롬프트 창을 닫지 않거나 전체 컴퓨터를 다시 시작하지 않고 전에 시도한 것처럼 실행할 수 있다.

Posted by 살레시오
,
Posted by 살레시오
,
Posted by 살레시오
,
7세그먼트, 이차원 배열, analogReference()함수 등
Posted by 살레시오
,