RP2040은 라즈베리 파이가 자체 설계한 듀얼 코어 ARM Cortex-M0+ 기반의 마이크로컨트롤러로, 133MHz(후에 200MHz 인증) 클럭 속도를 자랑합니다. 264KB의 SRAM을 내장하고 있지만 자체 플래시나 EEPROM은 없으며, 외부 플래시 메모리에서 펌웨어를 로드하는 구조입니다.

30개의 GPIO 핀(아날로그 입력 포함), USB 1.1 호스트 및 디바이스 지원, 2개의 UART, 2개의 SPI, 2개의 I2C 컨트롤러, 16채널 PWM, 4채널 12비트 ADC, 그리고 프로그래밍이 가능 PIO(Programmable Input/Output) 8개를 갖추고 있습니다. 이 PIO는 정교한 입출력 제어가 가능해 다양한 주변장치와의 통신에 매우 유용합니다. 40nm 공정으로 제작되어 낮은 전력 소비와 고성능을 동시에 실현했으며, 다양한 저전력 모드도 지원해 배터리 구동 환경에도 적합합니다. RP2040은 교육용, IoT, 임베디드 시스템 등 다방면에서 활용되며 다양한 파생 보드와 함께 아두이노 환경에서도 지원되어 폭넓은 개발 생태계를 갖추고 있습니다.

Posted by 살레시오
,

아두이노(Arduino)가 반도체 거인 퀄컴(Qualcomm)에 인수된 소식은 단순한 기업 뉴스 그 이상이다. 임베디드 분야에서 ‘메이커 운동(Maker Movement)’의 상징이자, 오픈소스 하드웨어의 대명사로 자리 잡은 아두이노의 방향성이 거대 자본의 품에 안긴다는 점에서, 커뮤니티 전반에 미묘한 긴장감이 감돈다.

퀄컴은 명실상부 글로벌 반도체 시장의 리더로, 대규모 SoC(시스템 온 칩)와 무선 통신 기술을 기반으로 한다. 반면 아두이노는 교육·프로토타이핑·창의적 실험의 영역에서 오픈소스 하드웨어의 이상을 추구해 왔다. 이 둘의 문화적 간극은 명확하다 — **‘폐쇄형 혁신 구조’ 대 ‘개방형 협력 생태계’**라는 대조적 모델의 만남이다.

1. 오픈소스 라이선스의 지속 가능성
우선 아두이노 하드웨어와 소프트웨어는 GNU GPL, LGPL 등 명확한 오픈소스 라이선스 아래 배포되고 있다. 퀄컴이 인수했다 하더라도 과거에 공개된 오픈소스 자산을 회수하는 것은 현실적으로 불가능하다. 그러나 향후 출시될 신규 보드나 IDE 플랫폼이 과연 동일한 수준의 개방성을 유지할지는 미지수다.

퀄컴은 자사 칩셋과 기술이 결합된 고성능 아두이노 보드를 출시할 가능성이 높지만, 해당 플랫폼의 펌웨어나 드라이버 계층이 ‘부분 공개’ 형태에 그칠 우려가 있다. 이렇게 되면 오픈소스 커뮤니티가 아두이노의 미래를 함께 설계하던 구조가 점진적으로 약화될 수 있다.

2. 커뮤니티 중심의 개발 문화 변화
아두이노 생태계의 핵심은 코드가 아니라 사람이었다. 전 세계 개발자와 학생, 예술가들이 자유롭게 프로젝트를 공유하며 협업하던 방식이, 대기업 중심의 속도·수익 중심 체계로 대체될 가능성도 있다.
특히 포럼, 라이브러리 저장소, 서드파티 호환 보드 개발사들은 향후 기술 연계 과정에서 API나 하드웨어 사양 접근 제한을 겪을 수 있다. 이렇게 되면 오픈소스 하드웨어의 다양성과 자율성이 줄어들고, 커뮤니티의 자발적 혁신 동력이 약해질 수 있다.

3. 긍정적인 측면도 있다
한편 퀄컴의 기술력과 자본력은 아두이노에 새로운 가능성을 열어줄 수도 있다.

AI 엣지 컴퓨팅, IoT, 5G 기반 프로젝트가 보다 쉽게 구현될 수 있으며,

산업용 또는 상용 프로토타이핑 단계에서 실용적 확장이 쉬워질 수도 있다.

결국, 퀄컴이 아두이노의 철학을 얼마나 존중하느냐가 모든 것을 결정한다. 단순히 브랜드를 흡수해 IoT 플랫폼의 입문용 도구로 축소시키는 방향이라면, 이는 전 세계 수백만 명의 메이커와 연구자에게 실망을 안길 것이다. 반대로 퀄컴이 아두이노를 ‘열린 기술 실험실’의 중심으로 육성한다면, 양쪽 모두 새로운 시너지를 만들 수 있을 것이다.

결론: 아두이노의 미래는 여전히 커뮤니티에 달려 있다
아두이노는 기업의 소유일 수 있지만, 그 정신은 커뮤니티의 것이다. 퀄컴의 인수가 단기적으로는 기술적 자원을 확장시키겠지만, 궁극적인 방향은 여전히 전 세계 개발자들의 자발적 협력과 개방적 참여 위에 달려 있다.
오픈소스의 가치를 지키려는 노력이 이어질 때만이, 아두이노는 단순한 하드웨어 키트가 아닌 지속 가능한 창의 생태계로 남을 수 있다.

Posted by 살레시오
,

몇 년 전에 만든 아두이노 강의 교재를 공유하고자 한다.

아래 표지를 클릭하면 다운로드 가능하다.

교재 표지

Posted by 살레시오
,

teensy audio design GUI

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioPlaySdWav           playSdWav3;     //xy=74,367
AudioPlaySdWav           playSdWav1;     //xy=77,241
AudioPlaySdWav           playSdWav7;     //xy=78,597
AudioPlaySdWav           playSdWav4;     //xy=80,425
AudioPlaySdWav           playSdWav2;     //xy=81,303
AudioPlaySdWav           playSdWav6;     //xy=82,535
AudioPlaySdWav           playSdWav5;     //xy=86,476
AudioMixer4              mixer1;         //xy=291,316
AudioMixer4              mixer2;         //xy=449,424
AudioOutputI2S           i2s1;           //xy=626,430
AudioConnection          patchCord1(playSdWav3, 0, mixer1, 2);
AudioConnection          patchCord2(playSdWav1, 0, mixer1, 0);
AudioConnection          patchCord3(playSdWav7, 0, mixer2, 3);
AudioConnection          patchCord4(playSdWav4, 0, mixer1, 3);
AudioConnection          patchCord5(playSdWav2, 0, mixer1, 1);
AudioConnection          patchCord6(playSdWav6, 0, mixer2, 2);
AudioConnection          patchCord7(playSdWav5, 0, mixer2, 1);
AudioConnection          patchCord8(mixer1, 0, mixer2, 0);
AudioConnection          patchCord9(mixer2, 0, i2s1, 0);
AudioConnection          patchCord10(mixer2, 0, i2s1, 1);
// GUItool: end automatically generated code

AudioControlSGTL5000     sgtl5000_1;

// 오디오보드의 sd카드 슬롯을 이용
//#define SDCARD_CS_PIN    10
//#define SDCARD_MOSI_PIN  7
//#define SDCARD_SCK_PIN   14

// Teensy4.1보드의 sd카드 슬롯을 이용
#define SDCARD_CS_PIN    BUILTIN_SDCARD
#define SDCARD_MOSI_PIN  11  // not actually used
#define SDCARD_SCK_PIN   13  // not actually used


//기타와 관련된 상수들
#define TOUCHED 1
#define UNTOUCHED 0

#define STRING1 24
#define STRING2 25
#define STRING3 26
#define STRING4 27
#define STRING5 28
#define STRING6 29


void setup() {
  Serial.begin(115200);
  delay(1000);

  // put your setup code here, to run once:
  AudioMemory(8);
  sgtl5000_1.enable();
  sgtl5000_1.volume(1.0);
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);

 
  if (!(SD.begin(SDCARD_CS_PIN))) {
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
  
  
  Serial.println("Ready.");
  
  pinMode(STRING1,INPUT);
  pinMode(STRING2,INPUT);
  pinMode(STRING3,INPUT);
  pinMode(STRING4,INPUT);
  pinMode(STRING5,INPUT);
  pinMode(STRING6,INPUT);
  
}


bool prevString1 = UNTOUCHED;
bool prevString2 = UNTOUCHED;
bool prevString3 = UNTOUCHED;
bool prevString4 = UNTOUCHED;
bool prevString5 = UNTOUCHED;
bool prevString6 = UNTOUCHED;

///*
#define TIME_WAIT_TO_PLAY 2
void forcePlay(AudioPlaySdWav *ptrPlaySdWav, const char *wav){
  ptrPlaySdWav->stop();
  do{
    ptrPlaySdWav->play(wav);
    delay(TIME_WAIT_TO_PLAY);
  } while(!ptrPlaySdWav->isPlaying());
}
//*/

void loop() {

  int tm=millis();
///*
  bool str1 = digitalRead(STRING1);
  if (prevString1==UNTOUCHED and str1==TOUCHED){
    forcePlay(&playSdWav1, "g100E.wav");
  }

  bool str2 = digitalRead(STRING2);
  if (prevString2==UNTOUCHED and str2==TOUCHED){
    forcePlay(&playSdWav2, "g200B.wav");
  }

  bool str3 = digitalRead(STRING3);
  if (prevString3==UNTOUCHED and str3==TOUCHED){
    forcePlay(&playSdWav3, "g300G.wav");
  }

  bool str4 = digitalRead(STRING4);
  if (prevString4==UNTOUCHED and str4==TOUCHED){
    forcePlay(&playSdWav4, "g400D.wav");
  }


  bool str5 = digitalRead(STRING5);
  if (prevString5==UNTOUCHED and str5==TOUCHED){
    forcePlay(&playSdWav5, "g500A.wav");
  }

  bool str6 = digitalRead(STRING6);
  if (prevString6==UNTOUCHED and str6==TOUCHED){
    forcePlay(&playSdWav6, "g600E.wav");
  }

  
  prevString1=str1;
  prevString2=str2;
  prevString3=str3;
  prevString4=str4;
  prevString5=str5;
  prevString6=str6;
//*/
  

/*
  playSdWav1.stop();
  do{
    playSdWav1.play("g600E.wav");
    delay(TIME_WAIT_TO_PLAY);
  } while(!playSdWav1.isPlaying());
*/
  
  Serial.print(millis()-tm);
  Serial.print(", S1:");Serial.print(str1);
  Serial.print(", S2:");Serial.print(str2);
  Serial.print(", S3:");Serial.print(str3);
  Serial.print(", S4:");Serial.print(str4);
  Serial.print(", S5:");Serial.print(str5);
  Serial.print(", S6:");Serial.print(str6);
  Serial.println();
  delay(10);
}

Posted by 살레시오
,

// 2021/11/8: Lolin32+OLED final

//#define DEBUG_SERIAL

#include <WiFi.h>
#include <driver/adc.h> // for adc_power_off()


#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 oled(128, 64, &Wire, -1);

// 한 번만 샘플링하면 1~2%의 확률로 0에 가까운 값이 읽힌다고 한다(잡음)
// 따라서 여러번 샘플링하여 평균값으로 판단하는 것이 안정적이다.
// SAMPLES가 20이면 loop()함수 한 번 실행 시간이 76ms 정도이다.
// 30이면 113ms 정도이다.
#define SAMPLES 20


// touchRead() 평균값이 아래 문턱값 이하이면 터치된 걸로 판단
#define THRESHOLD 20


#define PAD1    36 //(1) C#
#define PAD2    39 //(2) C
#define PAD3    34 //(3) D#
#define PAD4    35 //(4) D
#define PAD5    25 //(5) E
#define PAD6    26 //(6) F#
#define PAD7    19 //(7) F
#define PAD8    23 //(8) G#
#define PAD9    18 //(9) G
#define TPAD10  T9 //(10)A#
#define TPAD11  T8 //(11)A
#define TPAD12  T7 //(12)B
#define TPAD13  T6 //(13)
#define TPAD14  T5 //(14)
#define TPAD15  T4 //(15)

#define OUT_1  5
#define OUT_2  17
#define OUT_3  16
#define OUT_4  4
#define OUT_A  0
#define OUT_B  2
#define OUT_C  15

void setup() {

  // 소모전력을 줄이기 위해서 WiFi와 bt는 끈다.
  // ADC도 사용하지 않으므로 꺼야 한다.
  adc_power_off();
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
  btStop();

  // put your setup code here, to run once:
  
  ///*
  pinMode(PAD1, INPUT);
  pinMode(PAD2, INPUT);
  pinMode(PAD3, INPUT);
  pinMode(PAD4, INPUT);
  pinMode(PAD5, INPUT);
  pinMode(PAD6, INPUT);
  pinMode(PAD7, INPUT);
  pinMode(PAD8, INPUT);
  pinMode(PAD9, INPUT);
  
  pinMode(OUT_1, OUTPUT); //LED_BUILTIN
  pinMode(OUT_2, OUTPUT);
  pinMode(OUT_3, OUTPUT);
  pinMode(OUT_4, OUTPUT);
  pinMode(OUT_A, OUTPUT);
  pinMode(OUT_B, OUTPUT);
  pinMode(OUT_C, OUTPUT);

  // Address 0x3D for 128x64
  boolean isDisplayReady = oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);

#ifdef DEBUG_SERIAL //#######################
  Serial.begin(115200);
  delay(100);
  if(!isDisplayReady) { 
    Serial.println(F("OLED(SSD1306) diaplay detection failed"));
  }
#endif //####################################

  oled.clearDisplay();
  oled.display();
}


byte getTouchAverage(byte tN){
  int totalRead = 0;
  for(byte n=0; n<SAMPLES; n++){
    totalRead += touchRead(tN);
  }
  return totalRead/SAMPLES;
}

char notes[] = {' ', 'C', 'D', 'E', 'F', 'G', 'A', 'B'};
char *chords[] = {
    "",  //CBA:000
    "7", //CBA:001
    "m", //CBA:010
    "m7",//CBA:011
    "M", //CBA:100
    "M7",//CBA:101
    "sus4", //CBA:110
    "dim7", //CBA:111
};
byte idNote=0;
boolean isHalfHigh=false;
byte idChord=0;
byte prevChordByte=0;



void loop() {

  
#ifdef DEBUG_SERIAL //#######################
  int tm = millis();//(2)
#endif //####################################

  byte chordByte;

  boolean p1=digitalRead(PAD1);
  boolean p2=digitalRead(PAD2);
  boolean p3=digitalRead(PAD3);
  boolean p4=digitalRead(PAD4);
  boolean p5=digitalRead(PAD5);
  boolean p6=digitalRead(PAD6);
  boolean p7=digitalRead(PAD7);
  boolean p8=digitalRead(PAD8);
  boolean p9=digitalRead(PAD9);

  byte tp10=getTouchAverage(TPAD10);
  byte tp11=getTouchAverage(TPAD11);
  byte tp12=getTouchAverage(TPAD12);
  byte tp13=getTouchAverage(TPAD13);
  byte tp14=getTouchAverage(TPAD14);
  byte tp15=getTouchAverage(TPAD15);
  
  boolean p10 = tp10 < THRESHOLD;
  boolean p11 = tp11 < THRESHOLD;
  boolean p12 = tp12 < THRESHOLD;
  boolean p13 = tp13 < THRESHOLD;
  boolean p14 = tp14 < THRESHOLD;
  boolean p15 = tp15 < THRESHOLD;


  if(p1==HIGH){ //C#
    
    digitalWrite(OUT_1, 1);
    digitalWrite(OUT_2, 0);
    digitalWrite(OUT_3, 0);
    digitalWrite(OUT_4, 0);
    digitalWrite(OUT_A, p4); //gpio0
    digitalWrite(OUT_B, p5);
    digitalWrite(OUT_C, p7);   

    idNote=1;
    isHalfHigh = true; 
    idChord = p4+p5*2+p7*4;

    chordByte = 1+idChord*16;
    
  } else if (p2==HIGH){ //C
    
    digitalWrite(OUT_1, 0);
    digitalWrite(OUT_2, 1);
    digitalWrite(OUT_3, 0);
    digitalWrite(OUT_4, 0);
    digitalWrite(OUT_A, p4); //gpio0
    digitalWrite(OUT_B, p5);
    digitalWrite(OUT_C, p7);  

    idNote=1;
    isHalfHigh = false; 
    idChord = p4+p5*2+p7*4;

    chordByte = 2+idChord*16;

  } else if (p3==HIGH){ //D#

    digitalWrite(OUT_1, 1);
    digitalWrite(OUT_2, 1);
    digitalWrite(OUT_3, 0);
    digitalWrite(OUT_4, 0);
    digitalWrite(OUT_A, p5); //gpio0
    digitalWrite(OUT_B, p7);
    digitalWrite(OUT_C, p9);  

    idNote=2;
    isHalfHigh = true; 
    idChord = p5+p7*2+p9*4;

    chordByte = 3+idChord*16;

  } else if (p4==HIGH){ //D

    digitalWrite(OUT_1, 0);
    digitalWrite(OUT_2, 0);
    digitalWrite(OUT_3, 1);
    digitalWrite(OUT_4, 0);
    digitalWrite(OUT_A, p5); //gpio0
    digitalWrite(OUT_B, p7);
    digitalWrite(OUT_C, p9);  

    idNote=2;
    isHalfHigh = false; 
    idChord = p5+p7*2+p9*4;

    chordByte = 4+idChord*16;

  } else if (p5==HIGH){ //E

    digitalWrite(OUT_1, 1);
    digitalWrite(OUT_2, 0);
    digitalWrite(OUT_3, 1);
    digitalWrite(OUT_4, 0);
    digitalWrite(OUT_A, p7); //gpio0
    digitalWrite(OUT_B, p9);
    digitalWrite(OUT_C, p11);  

    idNote=3;
    isHalfHigh = false; 
    idChord = p7+p9*2+p11*4;

    chordByte = 5+idChord*16;
    
  } else if (p6==HIGH){ //F#

    digitalWrite(OUT_1, 0);
    digitalWrite(OUT_2, 1);
    digitalWrite(OUT_3, 1);
    digitalWrite(OUT_4, 0);
    digitalWrite(OUT_A, p9); //gpio0
    digitalWrite(OUT_B, p11);
    digitalWrite(OUT_C, p12);

    idNote=4;
    isHalfHigh = true; 
    idChord = p9 + p11*2 + p12*4;

    chordByte = 6+idChord*16;

  } else if (p7==HIGH){ //F

    digitalWrite(OUT_1, 1);
    digitalWrite(OUT_2, 1);
    digitalWrite(OUT_3, 1);
    digitalWrite(OUT_4, 0);
    digitalWrite(OUT_A, p9); //gpio0
    digitalWrite(OUT_B, p11);
    digitalWrite(OUT_C, p12);  

    idNote=4;
    isHalfHigh = false; 
    idChord = p9+p11*2+p12*4;

    chordByte = 7+idChord*16;


  } else if (p8==HIGH){ //G#

    digitalWrite(OUT_1, 0);
    digitalWrite(OUT_2, 0);
    digitalWrite(OUT_3, 0);
    digitalWrite(OUT_4, 1);
    digitalWrite(OUT_A, p11); //gpio0
    digitalWrite(OUT_B, p12);
    digitalWrite(OUT_C, p13);  

    idNote=5;
    isHalfHigh = true; 
    idChord = p11 + p12*2 + p13*4;

    chordByte = 8+idChord*16;

  } else if (p9==HIGH){ //G

    digitalWrite(OUT_1, 1);
    digitalWrite(OUT_2, 0);
    digitalWrite(OUT_3, 0);
    digitalWrite(OUT_4, 1);
    digitalWrite(OUT_A, p11); //gpio0
    digitalWrite(OUT_B, p12);
    digitalWrite(OUT_C, p13);  

    idNote=5;
    isHalfHigh = false; 
    idChord = p11 + p12*2 + p13*4;

    chordByte = 9+idChord*16;

  } else if (p10==HIGH){ //A#

    digitalWrite(OUT_1, 0);
    digitalWrite(OUT_2, 1);
    digitalWrite(OUT_3, 0);
    digitalWrite(OUT_4, 1);
    digitalWrite(OUT_A, p12); //gpio0
    digitalWrite(OUT_B, p13);
    digitalWrite(OUT_C, p14);  

    idNote=6;
    isHalfHigh = true; 
    idChord = p12 + p13*2 + p14*4;

    chordByte = 10+idChord*16;

  } else if (p11==HIGH){ //A

    digitalWrite(OUT_1, 1);
    digitalWrite(OUT_2, 1);
    digitalWrite(OUT_3, 0);
    digitalWrite(OUT_4, 1);
    digitalWrite(OUT_A, p12); //gpio0
    digitalWrite(OUT_B, p13);
    digitalWrite(OUT_C, p14);  

    idNote=6;
    isHalfHigh = false; 
    idChord = p12 + p13*2 + p14*4;

    chordByte = 11+idChord*16;

  } else if (p12==HIGH){ //B

    digitalWrite(OUT_1, 0);
    digitalWrite(OUT_2, 0);
    digitalWrite(OUT_3, 1);
    digitalWrite(OUT_4, 1);
    digitalWrite(OUT_A, p13); //gpio0
    digitalWrite(OUT_B, p14);
    digitalWrite(OUT_C, p15);  

    idNote=7;
    isHalfHigh = false; 
    idChord = p13 + p14*2 + p15*4;

    chordByte = 12+idChord*16;

  } else { //아무 코드도 짚지 않았을 때
  
    digitalWrite(OUT_1, 0);
    digitalWrite(OUT_2, 0);
    digitalWrite(OUT_3, 0);
    digitalWrite(OUT_4, 0);
    digitalWrite(OUT_A, 0);
    digitalWrite(OUT_B, 0);
    digitalWrite(OUT_C, 0);      

    idNote=0;
    isHalfHigh = false; 
    idChord = 0;

    chordByte = 0;
  }


  // 만약 oled가 갱신된다면 87ms 가 소요되고
  // 갱신되지 않는다면 58ms가 소요된다.
  // (OLED에 코드를 새로 표시하는데 30ms정도가 소요됨)
  
  if (chordByte != prevChordByte) {

    oled.clearDisplay();
    oled.setTextColor(WHITE);
    if (idNote>0) {
      oled.setCursor(0, 5);
      oled.setTextSize(8);
      oled.print( notes[idNote] );
    }
    if (isHalfHigh){
      oled.setCursor(48, 0);
      oled.setTextSize(4);
      oled.print("#");
    }
    if (idChord>0){
      oled.setCursor(48, 32);
      oled.setTextSize(4);
      oled.print( chords[idChord] );
    }
    oled.display(); //display the text on the screen


    prevChordByte = chordByte;
  }


#ifdef DEBUG_SERIAL
  Serial.print(millis()-tm);//(3)소요 시간 표시
  Serial.print("ms per 1 loop :");Serial.print(p1);
  Serial.print(':');Serial.print(p2);
  Serial.print(':');Serial.print(p3);
  Serial.print(':');Serial.print(p4);
  Serial.print(':');Serial.print(p5);
  Serial.print(':');Serial.print(p6);
  Serial.print(':');Serial.print(p7);
  Serial.print(':');Serial.print(p8);
  Serial.print(':');Serial.print(p9);
  Serial.print(':');Serial.print(tp10);
  Serial.print(':');Serial.print(tp11);
  Serial.print(':');Serial.print(tp12);
  Serial.print(':');Serial.print(tp13);
  Serial.print(':');Serial.print(tp14);
  Serial.print(':');Serial.print(tp15);
  Serial.println();
#endif


}

Posted by 살레시오
,

//2021년10월29일:Wemos LOLIN32 Lite 보드 실험

#include <WiFi.h>
#include <driver/adc.h> // for adc_power_off()

// 터치입력핀(8개)과 출력핀번호(8개)를 저장한 배열들
// gpio22핀은 내부적으로 LED에 연결되어 LOW 값에 켜진다.(역동작)
// gpio22핀을 출력핀으로 사용하는 데에는 문제가 없다.
byte inTouch[8] ={T0, T2, T3, T4, T5, T6, T7, T8};
byte outPin[8] = {22, 19, 23, 18, 17, 16, 26, 25};


// 한 번만 샘플링하면 1~2%의 확률로 0에 가까운 값이 읽히는 것 같다.
// 따라서 여러번 샘플링하여 평균값으로 판단하는 것이 안정적이다.
// SAMPLES가 20이면 loop()함수 한 번 실행 시간이 76ms 정도이다.
// 30이면 113ms 정도이다.
#define SAMPLES 20


// touchRead() 평균값이 아래 문턱값 이하이면 터치된 걸로 판단
#define THRESHOLD 20


void setup() {
  
  // 소모전력을 줄이기 위해서 WiFi와 bt는 끈다.
  // ADC도 사용하지 않으므로 꺼야 한다.
  adc_power_off();
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
  btStop();
    
  // 출력핀들을 OUTPUT으로 설정한다.
  for(byte k=0;k<8;k++){
    pinMode(outPin[k], OUTPUT);
  }

  //아래의 (1),(2),(3)은 소요시간을 확인하기 위한 코드
  //Serial.begin(115200); delay(100);//(1)
}


void loop() {
  //int tm = millis();//(2)

  for(byte k=0;k<8;k++) {
    int totalRead = 0;
    for(byte n=0; n<SAMPLES; n++) {
      totalRead += touchRead(inTouch[k]);
    }
    int averageRead = totalRead/SAMPLES;
    digitalWrite(outPin[k], averageRead<THRESHOLD);
  }

  //Serial.println(millis()-tm);//(3)소요 시간 표시
}

Posted by 살레시오
,

위와 같이 생긴 저가(1.5$정도)의 mp3 모듈을 사용해 보았다.

(a) 장점 : 저가,  4MByte 플래시롬 내장(pc에서 usb로 연결해서 mp3파일 복사), 앰프내장으로 스피커에 바로 연결 가능, 다양한 외부 트리거(최대 255곡까지 선택연주 가능), 아두이노로 Serial 제어하는 라이브러리 존재

(b) 단점 : 플래시롬의 용량이 다소 아쉽다. 트리거 신호 이후 mp3파일가 시작되는 delay가 생각보다 크다(느낌상 0.3초 정도) 이 단점들 때문에 내가 진행하는 프로젝트에서는 사용이 불가했다.

(c) 주의점 : 입력 전압은 5V이지만 내부 동작전압은 3.3V이므로 5V로 동작하는 아두이노와 결선할 때는 주의가 필요함. 예를 들어 Serial모드로 제어할 때는 전압레벨 변환기를 통하든가 아니면 적어도 아래와 같이 저항을 통해서 결선해야 한다.

위의 가이드대로 저항을 통해서 연결하지 않고 그냥 직결하면 이 보드가 손상될 가능성이 크다. 

Posted by 살레시오
,

ESP32보드를 아두이노 IDE에서 C++   로 코딩할 수 있는 데 매우 간단하게 세팅할 수 있다.

(1) 아두이노 IDE에서 [파일]>[환경설정] 창의 "추가적인 보드 매니저 URLs"에 아래 주소를 붙여넣기(ctrl+v)로 추가하고 [확인]버튼을 누른다.

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json 

(2) 위 과정이 끝났다면 [툴]>[보드]>[보드 매니저] 창의 검색칸에 ESP32라고 입력하면 보드매니저를 설치할 수 있다. (현재 1.0.4 버전)

(3) 이제 esp32보드를 선택할 수 있다. 통신 포트(serial port)도 맞게 설정한다.



위의 과정을 다 했다면 이제 ESP32보드를 아두이노IDE로 코딩할 수 있다. WeMos LOLIN32 보드의 테스트 LED를 블링킹하려면 다음과 같이 코딩하고 업로드 버튼을 클릭한다.

void setup() {

    pinMode(5,OUTPUT);

}

 void loop() {

    digitalWrite(5,HIGH);

    delay(500);

    digitalWrite(5,LOW);

    delay(500);    

}


참고로 유튜브 관련 영상에 보면 컴파일이 끝나면 BOOT(gpio0)핀이 LOW가 되어야 업로드가 된다고 하는데.. 현재 최신 버전의 esp32매니저와 적어도 LOLIN32 보드에서는 그렇지 않고 자동으로 업로딩되고 업로딩 완료시 리셋까지 되는 것 같다.

Posted by 살레시오
,

  며칠 전에 라즈베리파이 패밀리에 피코(pico)라는 마이크로컨트롤러가 출시되었다.

프로세서가 듀얼코어에다가 133MHz 의 클럭속도를 가진다. C/C++ 뿐만 아니라 마이크로파이썬으로도 코딩이 가능하고 놀라운 점은 가격이 단 4$ 라는 것이다.


이제 제어프로그램을 파이썬으로 작성하기 위해서 메인PC와 마이크로콘트롤러를 어떻게든 연결해서 하드웨어를 구성할 필요가 없어졌다. 왜냐면 ESP32, 마이크로비트, stm32기반의 보드들, 혹은 RPi피코 보드를 이용하여 파이썬으로 제어프로그램을 구동시키는 데 별 무리가 없기 때문이다. (단, 아직은 ESP32 기반의 보드들의 성능이 가장 나아 보인다.)


Posted by 살레시오
,

마이크로:비트의 파이썬 라이브러리 구조가 한 눈에 보이는 게 없어서 여기에 정리해 보고자 한다. (공식문서를 참조했다.)


모듈의 이름은 microbit 이다. 따라서 아래와 같은 함수나 클래스를 사용하려면 


from microbit import * 


명령으로 모두 로드하던가, 아니면 개별적으로 로드해서 사용하면 된다.



① 시스템관련


reset() 함수 : 보드를 리셋한다

panic(n) 함수 : 패닉모드(panic mode)로 들어간다. (보드는 재시작되어야 함)


② 시간 관련


sleep(ms) : 밀리초만큼 (아무 일도 않고) 기다린다.

running_time() : 보드가 (재)가동된 시간을 밀리초로 반환한다.


(외부모듈로는 utime이 있다. 외부모듈이므로 별도로 import 해야함)


③ 시각적인 표시 관련


Image 클래스


display.show(image) 메서드

display.scroll(string) 메서드


display.get_pixel(x, y)

display.set_pixel(x, y, value) : value 는 [0, 9]범위의 정수로 밝기를 설정함

display.clear()


display.on()

display.off()

display.is_on()

display.read_light_level(val)



④ 버튼 관련


미리 정의된 button_a,  button_b 객체를 사용함


button_a.is_pressed() : 현재 눌려졌으면 True 반환

button_a.was_pressed() : 이 함수가 마지막으로 호출된 이후 눌려진 적이 있다면 True반환 하고 상태는 리셋됨

button_a.get_pressed() : 총 몇 번 눌렸는지를 반환(그리고 횟수는 0으로 리셋됨)


※ button_b에 대해서도 동일한 메서드를 사용 가능


④ 핀관련


pin0, pin1, pin2, ... oin16, pin19, pin20 (pin17과 pin18은 사용불가)

(pin5는 button_A, pin11은 button_b에 사용)

pin_logo (V2에 추가)

pin_speaker  (V2에 추가)



pinN.read_digital()

pinN.write_digital(val) : val이 1이면 HIGH, 0이면 LOW


pinN.read_analog() : 0(0V)~1023(3.3V)사이의 정수 반환, (pin3, pin4, pin10 만 가능)

pinN.write_analog(val) : PWM출력 val은 0(0%듀티)~1023(100%듀티) 사이의 정수

pinN.analog_period(ms) : PWM주기 설정(최소갑은 1ms)

pinN.analog_period_microseconds(us) : PWM주기 설정(최소갑은 256 us)

※ 아날로그 입출력은 pin0, pin1, pin2 만 (내부LED를 안 쓸때는 pin3, pin4, pin10 까지) 가능


pinN.is_touched() : 터치되었다면 True 반환 

pinN.set_touch_mode(val) : val은 pinN.CAPACITIVE 혹은 pinN,RESISTIVE

※ 터치 기능은 pin0, pin1, pin2 에만 (V2에는 pin_logo 에도) 있음


⑤ 소리관련


audio.play()

audio.is_playing()

audio.stop()


⑥ 가속도계 관련


accelerometer.get_x()

accelerometer.get_y()

accelerometer.get_z()

accelerometer.get_values()

accelerometer.current_gesture()


⑦ 나침판(compass) 관련


compass.calibrate()

compass.clear_calibration()

compass.get_field_strength()

compass.get_x()

compass.get_y()

compass.get_z()

compass.hearing()



⑧ 내장 마이크 (V2)


microphone


⑨ 내장 스피커 (V2)


speaker.on()

speaker.off()

speaker.is_on()


⑩ 기타: Bluetooth SPI, UART I2C 등은 생략




'하드웨어 > micro:bit' 카테고리의 다른 글

마이크로비트 V2  (0) 2021.01.14
마이크로비트(micro:bit) 첫 코딩  (0) 2021.01.13
Posted by 살레시오
,