2017年3月13日 星期一

[Arduino] 淺談記憶體1 -- Memory

要善用 Arduino 就必須要徹底了解它的硬體架構與記憶體管理。本章旨在說明 Arduino 的記憶體,硬體架構則是在其它地方說明。

在基於 AVR 的 Arduino 板子上有三種可以儲存資料的地方:
1.快閃記憶體(Flash)。程式碼是儲存在這個地方。
2.靜態隨機存取記憶體(SRAM)。程式在運行時創建和操作變數的地方。
3.EEPROM。這個地方可以讓程式設計師長期存放資料。

儲存在 Flash 和 EEPROM 裏的資料,即使關閉電源它也不會消失;但儲存在 SRAM 裏的資料,一旦關閉電源它就會消失。

Arduino UNO 上面的 ATmega328 晶片有下列記憶體容量:
Flash           32k bytes (但其中 5k 已被使用於 bootloader)
SRAM        2k bytes
EEPROM   1k bytes


由上表可以知道,您的程式碼有 27k bytes 的記憶空間可用,但用來處理變數的記憶空間(SRAM)只有 2k bytes,假如我們在程式之中宣告一個字串變數

char message[] = "I support the Cape Wind project.";

這個字串有 32 個字元,每一個字元會占用 1 byte 的 SRAM,32 個字元將會占用 32 bytes 的 SRAM,再加上一個看不見的結尾字元 "\0",總共占用掉 33 bytes 的 SRAM。

2k bytes 等於 2048 bytes,2048 減 33 還剩 2015 bytes,或許這在你看來並非用掉了很多 SRAM,但是當你有一大篇字串要顯示或處理時,特別是在使用查表法時,這 2k bytes 的空間將會很快地被用完。

如果你把 SRAM 用完了,你的程序可能會以意想不到的方式失敗:它會顯示上傳成功,但不會運行,或者運行奇怪。要檢查這是否發生,你可以嘗試註釋掉或縮短程式中的字串或其他數據結構(在不更改程式碼情況下)。然後,如果它運行成功了,就表示你可能已用完了 SRAM。

您可以做一些事情來解決上述問題:

如果你是使用桌上型電腦或筆記型電腦來跟 Arduino 作溝通,那麼你可以嘗試將數據或需要計算的資料這樣的工作轉移到電腦上面,藉以減少 Arduino 的負擔。

如果有用到查表法或有大型資料,請使用存儲所需值的最小資料型態來宣告:例如 int 會佔用 2 個 bytes,而 byte 只會占用 1 個 byte (但是只能存儲較小範圍的值)。

如果程式在運行時不需要修改字符串或數據,則可以將它們存儲在 Flash (程式) 記憶體中,而不是 SRAM ;要做到這一點,可以使用 PROGMEM 關鍵字(註A)。


註A:LED_Cube 程式碼中使用大量的查表資料用來顯示 LED 圖案,此時就用到了 PROGRAM 關鍵字。


相關連結

淺談記憶體2 -- PROGRAM http://pizgchen.blogspot.tw/2017/03/arduino-2-program.html

Arduino Memory https://www.arduino.cc/en/tutorial/memory

各類型 Arduino 板子的記憶體大小 http://playground.arduino.cc/Learning/Memory

葉難 http://yehnan.blogspot.tw/2013/08/arduino.html

Adafruit https://cdn-learn.adafruit.com/downloads/pdf/memories-of-an-arduino.pdf

2017年3月12日 星期日

[玩轉光立方] LED Cube 4x4x4 for Arduino UNO -- 程式4 點點繁星

在使用查表法做出圖案之前,我們要中途來玩一個小東西,模擬天上的一閃一閃的星星,或是也可以說是模擬一閃一閃的螢火蟲。

要隨機點亮 LED 會用到 Arduino 的亂數相關函式,基本認識及用法請詳 http://pizgchen.blogspot.tw/2017/03/arduino.html


程式碼1

//2017-03-12 LED_Cube4_04.ino
//以層方式,隨機點亮 LED

#define CUBE_SIZE 4
#define PLANE_SIZE CUBE_SIZE*CUBE_SIZE
#define PLANE_TIME 0
#define LED_TIME 2

int LEDPin[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, A0, A1};
int PlanePin[] = {A2 , A3, A4, A5};

void setup()
{
  int pin;
  for (pin = 0; pin < PLANE_SIZE; pin++) {
    pinMode(LEDPin[pin], OUTPUT);
    digitalWrite(LEDPin[pin], LOW);
  }
  for (pin = 0; pin < CUBE_SIZE; pin++) {
    pinMode(PlanePin[pin], OUTPUT);
    digitalWrite(PlanePin[pin], HIGH);
  }
  randomSeed(A0);
}

void loop()
{
  for (int plane = 0; plane < CUBE_SIZE; plane++) {
    digitalWrite(PlanePin[plane], LOW);
    for (int col = 0; col < CUBE_SIZE; col++) {
      for (int row = 0; row < CUBE_SIZE; row++)
      {
        int k = random(100);
        if (k < 50) {
          digitalWrite(LEDPin[col * CUBE_SIZE + row], HIGH);
          delay(LED_TIME);
          digitalWrite(LEDPin[col * CUBE_SIZE + row], LOW);
        }
      }
    }
    delay(PLANE_TIME);
    digitalWrite(PlanePin[plane], HIGH);
  }
}

來看一下影片




您可以改變一下 LED_TIME 的值,觀察是不是有不同的顯示效果。


程式碼2

程式也可以改成下列這樣,顯示的順序會與上方程式不同。

//2017-03-12 LED_Cube4_05.ino
//以柱方式,隨機點亮 LED

#define CUBE_SIZE 4
#define PLANE_SIZE CUBE_SIZE*CUBE_SIZE
#define PLANE_TIME 0
#define LED_TIME 20

int LEDPin[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, A0, A1};
int PlanePin[] = {A2 , A3, A4, A5};

void setup()
{
  int pin;
  for (pin = 0; pin < PLANE_SIZE; pin++) {
    pinMode(LEDPin[pin], OUTPUT);
    digitalWrite(LEDPin[pin], LOW);
  }
  for (pin = 0; pin < CUBE_SIZE; pin++) {
    pinMode(PlanePin[pin], OUTPUT);
    digitalWrite(PlanePin[pin], HIGH);
  }
  randomSeed(A0);
}

void loop()
{
  for (int col = 0; col < CUBE_SIZE; col++) {
    for (int row = 0; row < CUBE_SIZE; row++) {
      for (int plane = 0; plane < CUBE_SIZE; plane++) {
        digitalWrite(PlanePin[plane], LOW);
        int k = random(100);
        if (k < 50) {
          digitalWrite(LEDPin[col * CUBE_SIZE + row], HIGH);
          delay(LED_TIME);
          digitalWrite(LEDPin[col * CUBE_SIZE + row], LOW);
        }
        delay(PLANE_TIME);
        digitalWrite(PlanePin[plane], HIGH);
      }
    }
  }
}


程式碼3

很明顯地,上面 2 支程式都讓 LED 顯示的太快了,一點兒也不像星星或螢火蟲閃爍。這回我們將更進一步讓它更接近真實,將原本順序顯示的層改為隨機,我把原本的程式碼 Mark 起來沒有刪除,目的是讓您參考比對。

//2017-03-12 LED_Cube4_06.ino
//以隨機柱方式,隨機點亮 LED

#define CUBE_SIZE 4
#define PLANE_SIZE CUBE_SIZE*CUBE_SIZE
#define PLANE_TIME 200
#define LED_TIME 50

int LEDPin[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, A0, A1};
int PlanePin[] = {A2 , A3, A4, A5};

void setup()
{
  int pin;
  for (pin = 0; pin < PLANE_SIZE; pin++) {
    pinMode(LEDPin[pin], OUTPUT);
    digitalWrite(LEDPin[pin], LOW);
  }
  for (pin = 0; pin < CUBE_SIZE; pin++) {
    pinMode(PlanePin[pin], OUTPUT);
    digitalWrite(PlanePin[pin], HIGH);
  }
  randomSeed(A0);
}

void loop()
{
  for (int col = 0; col < CUBE_SIZE; col++) {
    for (int row = 0; row < CUBE_SIZE; row++) {
      // for (int plane = 0; plane < CUBE_SIZE; plane++) {
      int plane = random(CUBE_SIZE);
      digitalWrite(PlanePin[plane], LOW);
      int k = random(100);
      if (k < 50) {
        digitalWrite(LEDPin[col * CUBE_SIZE + row], HIGH);
        delay(LED_TIME);
        digitalWrite(LEDPin[col * CUBE_SIZE + row], LOW);
      }
      delay(PLANE_TIME);
      digitalWrite(PlanePin[plane], HIGH);
      // }
    }
  }
}


程式碼4

下列程式是把上面程式精簡化,它們倆顯示的效果看起來相同。

//2017-03-12 LED_Cube4_07.ino
//精簡以隨機柱方式,隨機點亮 LED

#define CUBE_SIZE 4
#define PLANE_SIZE CUBE_SIZE*CUBE_SIZE
#define PLANE_TIME 200
#define LED_TIME 50

int LEDPin[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, A0, A1};
int PlanePin[] = {A2 , A3, A4, A5};

void setup()
{
  int pin;
  for (pin = 0; pin < PLANE_SIZE; pin++) {
    pinMode(LEDPin[pin], OUTPUT);
    digitalWrite(LEDPin[pin], LOW);
  }
  for (pin = 0; pin < CUBE_SIZE; pin++) {
    pinMode(PlanePin[pin], OUTPUT);
    digitalWrite(PlanePin[pin], HIGH);
  }
  randomSeed(A0);
}

void loop()
{
  int plane = random(CUBE_SIZE);
  int cube = random(PLANE_SIZE);
  int k = random(100);
  digitalWrite(PlanePin[plane], LOW);
  if (k < 50) {
    digitalWrite(cube, HIGH);
    delay(LED_TIME);
    digitalWrite(cube, LOW);
  }
  delay(PLANE_TIME);
  digitalWrite(PlanePin[plane], HIGH);
}


程式碼5

這是最終版本,在這兒將所有的數值全部隨機取出,顯示效果比前面幾個版本更佳了。

//2017-03-12 LED_Cube4_08.ino
//將所有數值亂數化,隨機點亮 LED

#define CUBE_SIZE 4
#define PLANE_SIZE CUBE_SIZE*CUBE_SIZE
int PLANE_TIME = 100;
int LED_TIME = 1000;

int LEDPin[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, A0, A1};
int PlanePin[] = {A2 , A3, A4, A5};

void setup()
{
  int pin;
  for (pin = 0; pin < PLANE_SIZE; pin++) {
    pinMode(LEDPin[pin], OUTPUT);
    digitalWrite(LEDPin[pin], LOW);
  }
  for (pin = 0; pin < CUBE_SIZE; pin++) {
    pinMode(PlanePin[pin], OUTPUT);
    digitalWrite(PlanePin[pin], HIGH);
  }
  randomSeed(A0);
}

void loop()
{
  int plane = random(CUBE_SIZE);
  int cube = random(PLANE_SIZE);
  int k = random(100);
  digitalWrite(PlanePin[plane], LOW);
  if (k < 50) {
    digitalWrite(cube, HIGH);
    delay(random(LED_TIME));
    digitalWrite(cube, LOW);
  }
  delay(random(PLANE_TIME));
  digitalWrite(PlanePin[plane], HIGH);
}

來看一下影片




相關連結


[Arduino] 亂數

我們常常會需要用隨機的方式處理一件事情,最常見的就是樂透開獎。不同的是,樂透開獎採用機械式產生亂數,它是用風吹亂漂浮的球,當閘門打開時球順著管道飛出並掉落到盤中,完成隨機取樣的工作;而在 Arduino 的互動裝置中,我們也可以隨機產生一個數值,讓這個互動裝置隨機做出不同的反應。

如果您會 C 語言的亂數用法,那麼用 Arduino 隨機取出一個數值自然就難不倒您。


Arduino 提供兩個亂數相關的函式:random 、randomSeed

random 有兩個用法:

1. random(最大值)
random(100); 表最小值是 0,最大值是 100。但這個實際上只會產生 0~99 的整數。

2. random(最小值,最大值)
random(20, 50); 表最小值是 20,最大值是 50。但這個實際上只會產生 20~49 的整數。


程式碼

我們可以將下列程式碼 Upload 到 Arduino 裏,藉以觀察它產生的亂數是哪些。

void setup() {
  Serial.begin(9600);
}

void loop() {
  int i = random(100);
  Serial.println(i);
  delay(1000);
}

您可以打開序列埠監控視窗(Serial monitor),將可以看到如下畫面:


但是,如果您重覆關閉並開啟這個視窗,您會發現到它雖然有隨機產生一些數值,但這些數值在出現的順序上並沒有改變。這是因為 random 這個函式初始會以一個所謂的亂數種子(Random Seed)來產生產生亂數,在我們並未改變這個亂數種子之前,亂數會以一定的順序產生。然而,這並非我們真正需要的亂數,因為它數值的出現是可預期的。

要改變上述狀況,在使用 random 函式之前,可以先使用 randomSeed 函式指定
一個亂數種子。我們從類比腳位取出一個數值(它的值介於 0~1023 之間)當作亂數種子。所以程式可以改成這樣

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(A0));
}

void loop() {
  int i = random(100);
  Serial.println(i);
  delay(1000);
}

您可以多次開關序列埠監控視窗(Serial monitor),將可以發現到每次開啟視窗時產生的數值都不一樣了,這才是我們真正需要的。


產生 0~100 之間 2 的倍數的亂數

將每次隨機產生的數值乘以 2,就可以產生 2 的倍數的亂數,程式碼如下:

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(A0));
}

void loop() {
  int i = random(50) * 2;
  Serial.println(i);
  delay(1000);
}


延伸問題

1.如何模擬普克牌洗排,隨機排列1~13的順序。
2.如何模擬普克牌洗排,隨機排列4種花色1~13的順序,花色可以A~D表示,例如A12表黑桃Q,B7表紅心7...。


相關連結

Arduino Reference Random https://www.arduino.cc/en/Reference/Random


2017年3月3日 星期五

[聲音] 用蜂鳴器播放超級瑪莉(Mario)音樂

一只無源蜂鳴器和一些小零件就能讓您的 Arduino 發出美妙的聲音。



蜂鳴器大略區分為有源與無源,有源蜂鳴器指的是通電它就會自己發出聲音;而無源蜂鳴器指的是雖然有通電,但它不會自己發出聲音,需要外部裝置傳送特定頻率的方波給它才會發出聲音。

這個專案會讓 Arduino 連續播放瑪莉歐曲子。


零件清單

1. Arduino UNO or nano *1
2. 蜂鳴器 *1
3. NPN電晶體(2N2222...) *1
4. 1K電阻 *1
5. 麵包板 *1
6. 杜邦線若干


電路圖

簡易接線如圖一。比較完善的接線如圖二。

(圖一)


(圖二)

電路接線

請注意蜂鳴器有正負極之分,蜂鳴器負極需接電晶體的C腳(集極)。
電晶體的B腳(基極)接 Arduino D3 腳位。


程式碼

#define NOTE_B0  31
#define NOTE_C1  33
#define NOTE_CS1 35
#define NOTE_D1  37
#define NOTE_DS1 39
#define NOTE_E1  41
#define NOTE_F1  44
#define NOTE_FS1 46
#define NOTE_G1  49
#define NOTE_GS1 52
#define NOTE_A1  55
#define NOTE_AS1 58
#define NOTE_B1  62
#define NOTE_C2  65
#define NOTE_CS2 69
#define NOTE_D2  73
#define NOTE_DS2 78
#define NOTE_E2  82
#define NOTE_F2  87
#define NOTE_FS2 93
#define NOTE_G2  98
#define NOTE_GS2 104
#define NOTE_A2  110
#define NOTE_AS2 117
#define NOTE_B2  123
#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define NOTE_C6  1047
#define NOTE_CS6 1109
#define NOTE_D6  1175
#define NOTE_DS6 1245
#define NOTE_E6  1319
#define NOTE_F6  1397
#define NOTE_FS6 1480
#define NOTE_G6  1568
#define NOTE_GS6 1661
#define NOTE_A6  1760
#define NOTE_AS6 1865
#define NOTE_B6  1976
#define NOTE_C7  2093
#define NOTE_CS7 2217
#define NOTE_D7  2349
#define NOTE_DS7 2489
#define NOTE_E7  2637
#define NOTE_F7  2794
#define NOTE_FS7 2960
#define NOTE_G7  3136
#define NOTE_GS7 3322
#define NOTE_A7  3520
#define NOTE_AS7 3729
#define NOTE_B7  3951
#define NOTE_C8  4186
#define NOTE_CS8 4435
#define NOTE_D8  4699
#define NOTE_DS8 4978

#define melodyPin 3
#define ledPin 13

//Mario main theme melody
int melody[] = {
  NOTE_E7, NOTE_E7, 0, NOTE_E7,
  0, NOTE_C7, NOTE_E7, 0,
  NOTE_G7, 0, 0,  0,
  NOTE_G6, 0, 0, 0,

  NOTE_C7, 0, 0, NOTE_G6,
  0, 0, NOTE_E6, 0,
  0, NOTE_A6, 0, NOTE_B6,
  0, NOTE_AS6, NOTE_A6, 0,

  NOTE_G6, NOTE_E7, NOTE_G7,
  NOTE_A7, 0, NOTE_F7, NOTE_G7,
  0, NOTE_E7, 0, NOTE_C7,
  NOTE_D7, NOTE_B6, 0, 0,

  NOTE_C7, 0, 0, NOTE_G6,
  0, 0, NOTE_E6, 0,
  0, NOTE_A6, 0, NOTE_B6,
  0, NOTE_AS6, NOTE_A6, 0,

  NOTE_G6, NOTE_E7, NOTE_G7,
  NOTE_A7, 0, NOTE_F7, NOTE_G7,
  0, NOTE_E7, 0, NOTE_C7,
  NOTE_D7, NOTE_B6, 0, 0
};

//Mario main them tempo
int tempo[] = {
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,

  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,

  9, 9, 9,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,

  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,

  9, 9, 9,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,
};

//Underworld melody
int underworld_melody[] = {
  NOTE_C4, NOTE_C5, NOTE_A3, NOTE_A4,
  NOTE_AS3, NOTE_AS4, 0,
  0,
  NOTE_C4, NOTE_C5, NOTE_A3, NOTE_A4,
  NOTE_AS3, NOTE_AS4, 0,
  0,
  NOTE_F3, NOTE_F4, NOTE_D3, NOTE_D4,
  NOTE_DS3, NOTE_DS4, 0,
  0,
  NOTE_F3, NOTE_F4, NOTE_D3, NOTE_D4,
  NOTE_DS3, NOTE_DS4, 0,
  0, NOTE_DS4, NOTE_CS4, NOTE_D4,
  NOTE_CS4, NOTE_DS4,
  NOTE_DS4, NOTE_GS3,
  NOTE_G3, NOTE_CS4,
  NOTE_C4, NOTE_FS4, NOTE_F4, NOTE_E3, NOTE_AS4, NOTE_A4,
  NOTE_GS4, NOTE_DS4, NOTE_B3,
  NOTE_AS3, NOTE_A3, NOTE_GS3,
  0, 0, 0
};

//Underwolrd tempo
int underworld_tempo[] = {
  12, 12, 12, 12,
  12, 12, 6,
  3,
  12, 12, 12, 12,
  12, 12, 6,
  3,
  12, 12, 12, 12,
  12, 12, 6,
  3,
  12, 12, 12, 12,
  12, 12, 6,
  6, 18, 18, 18,
  6, 6,
  6, 6,
  6, 6,
  18, 18, 18, 18, 18, 18,
  10, 10, 10,
  10, 10, 10,
  3, 3, 3
};

void setup(void)
{
  pinMode(melodyPin, OUTPUT);//buzzer
  pinMode(ledPin, OUTPUT);//led indicator when singing a note

}
void loop()
{
  //sing the tunes
  sing(1);
  sing(1);
  sing(2);
}
int song = 0;

void sing(int s) {
  // iterate over the notes of the melody:
  song = s;
  if (song == 2) {
    Serial.println(" 'Underworld Theme'");
    int size = sizeof(underworld_melody) / sizeof(int);
    for (int thisNote = 0; thisNote < size; thisNote++) {

      // to calculate the note duration, take one second
      // divided by the note type.
      //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
      int noteDuration = 1000 / underworld_tempo[thisNote];

      buzz(melodyPin, underworld_melody[thisNote], noteDuration);

      // to distinguish the notes, set a minimum time between them.
      // the note's duration + 30% seems to work well:
      int pauseBetweenNotes = noteDuration * 1.30;
      delay(pauseBetweenNotes);

      // stop the tone playing:
      buzz(melodyPin, 0, noteDuration);

    }

  } else {

    Serial.println(" 'Mario Theme'");
    int size = sizeof(melody) / sizeof(int);
    for (int thisNote = 0; thisNote < size; thisNote++) {

      // to calculate the note duration, take one second
      // divided by the note type.
      //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
      int noteDuration = 1000 / tempo[thisNote];

      buzz(melodyPin, melody[thisNote], noteDuration);

      // to distinguish the notes, set a minimum time between them.
      // the note's duration + 30% seems to work well:
      int pauseBetweenNotes = noteDuration * 1.30;
      delay(pauseBetweenNotes);

      // stop the tone playing:
      buzz(melodyPin, 0, noteDuration);

    }
  }
}

void buzz(int targetPin, long frequency, long length) {
  digitalWrite(13, HIGH);
  long delayValue = 1000000 / frequency / 2; // calculate the delay value between transitions
  //// 1 second's worth of microseconds, divided by the frequency, then split in half since
  //// there are two phases to each cycle
  long numCycles = frequency * length / 1000; // calculate the number of cycles for proper timing
  //// multiply frequency, which is really cycles per second, by the number of seconds to
  //// get the total number of cycles to produce
  for (long i = 0; i < numCycles; i++) { // for the calculated length of time...
    digitalWrite(targetPin, HIGH); // write the buzzer pin high to push out the diaphram
    delayMicroseconds(delayValue); // wait for the calculated delay value
    digitalWrite(targetPin, LOW); // write the buzzer pin low to pull back the diaphram
    delayMicroseconds(delayValue); // wait again or the calculated delay value
  }
  digitalWrite(13, LOW);

}


採購資訊

Arduino nano 開發板 http://goods.ruten.com.tw/item/show?21642069565073
Arduino UNO & nano 兩用擴展板 http://goods.ruten.com.tw/item/show?21628077602506
無源蜂鳴器 http://goods.ruten.com.tw/item/show?21709402547944
NPN電晶體 2N2222 http://goods.ruten.com.tw/item/show?21649653098711
1K電阻 http://goods.ruten.com.tw/item/show?21650756477303
麵包板 http://goods.ruten.com.tw/item/show?21643156259891
杜邦線 http://goods.ruten.com.tw/item/show?21629160028063



[Servo] 舵機(伺服馬達)使用前的檢查

舵機品質良莠不齊,如果專揀便宜的購買,買到山寨版的機率更是大。山寨版的舵機不是不能用,端看你怎麼用,才能夠不會燒掉,可以讓它「永保安康」。



剛拿到手的舵機不要急著將它安裝到機構件上,您應該先檢查它是否可以正常運作,檢查的項目如下:

1.外觀是否完整? 外殼是否破損? 電線是否破損? 轉軸是否正常? 零件是否齊全?
2.轉軸旁的塑膠殼上有一個小突起,可以用刀子將它削平,以免妨礙舵機轉動。
3.通電是否會轉動? (程式碼在本文下方)
4.如果馬達有轉動,而轉軸沒有轉動,有可能內部齒輪崩齒。
5.觀察舵機是來回轉 180 度,還是只有 90 度(有些舵機只能轉 90 度)。這款 SG90 舵機通常都無法轉足 180 度,請找出它可以轉動的最小和最大角度。建議轉動角度設定為 10~170度。
6.用手觸摸外殼,感覺溫度是否升高? 如果會燙手,請趕快拔除電源,以免舵機燒毀。


程式碼

您可以將舵機插到 Arduino 板子的 D2~D13 任一埠,舵機轉軸會160度來回轉動。

#include <Servo.h>
Servo myservo[12];

void setup()
{
  for (int i = 0; i < 12; i++)
    myservo[i].attach(i + 2);
}

void loop()
{
  int i, pos;
  for (pos = 10; pos <= 170; pos += 1)
  {
    for (i = 0; i < 12; i++)
      myservo[i].write(pos);
    delay(15);
  }
  for (pos = 170; pos >= 10; pos -= 1)
  {
    for (i = 0; i < 12; i++)
      myservo[i].write(pos);
    delay(15);
  }
}




採購資訊


2017年1月22日 星期日

[DIY] 釘層板

我這個老 Maker 有太多零件沒地方放,許多大大小小的紙箱把書桌底下堆疊地像福德坑垃圾山一樣。為避免讓老婆大人繼續叨唸,剛好也快過年了,也得除舊布新一下,就去特力屋買了 2 片美耐面 E1 層板,尺寸 1.8x90x30cm。廠商有生產白色、淺木紋和深棕色木紋等 3 種顏色,我挑選了「淺木紋」這一款,回家安裝好之後感覺是挑對了,淺灰色的木紋跟乳白的牆壁還蠻搭的。

廢話不多說,我們就開始來說明如何釘層板。




準備工具

1.電鑽
2.L形90度角尺(沒有也沒關係)
3.捲尺
4.長鐵尺
5.筆
6.水準尺(或是手機下載 APP)



準備施工圖

依照層板材料的尺寸與支架的孔位,我畫出如下施工圖


圖中某些數據有誤,2.5cm 應修正為 1.8cm。


Step1 將支架鎖到層板

1.準備筆、尺和捲尺。



2.依照施工圖在層板上畫出 4 個孔位。


3.用直徑 3~4mm 的鑽頭鑽出深約1.0~1.2cm 的孔。
提醒您:電鑽請不要使用震動模式。

4.準備支架*2和短螺絲*4(圖片中下方螺絲)。


5.用短螺絲將支架鎖到層板。



Step2 在牆壁上鑽 4 個孔

1.因支架距離層板為 10cm,為避免牆壁沒有垂直或平整,以及人為誤差,我從右側避面往左量出 10.5cm 的距離做一個記號,讓層板跟牆壁有一個 0.5cm 的縫隙,這個 0.5cm 的縫隙不會太小到影響層板安裝,也不會大到讓東西從縫隙掉下去。

2.用一條綁著重物(可以是一根螺絲)長約 30cm 的線,自記號處自然垂下,在線的底部再做一個記號,用鉛筆在這 2 個記號畫出一條垂線。

這條線是垂直地面的。

3.將長尺右端靠住上記號,盡量不讓它可以移動。再將水準尺放在長尺上面,移動長尺左端,讓水準尺氣泡居中,此時可以畫出一條水平線。


提示:如果您是使用手機 APP 水準尺,記得要脫除手機套與保護殼,以避免影響水平精準度。

4.從右端的垂線順著水平線往左量出 70cm 的距離,做一記號。

5.重覆步驟 2,再畫出一條左垂線。

6.先決定上孔位置後,再往下量 14cm 就是下孔位置。

7.在孔的下方用紙膠帶黏住攤平的塑膠袋,用來承接待會兒鑽孔時落下的塵土。



8.用直徑 6mm 的水泥鑽頭鑽出深約 2.5cm 的孔。
提示:您可以利用電鑽上面的桿尺來量測鑽孔深度。
提醒您:電鑽請切換到震動模式。



9.將 4 只塑膠套塞入孔內,塑膠套須與牆壁面平整,最好不要太深入或外凸。


10.移除紙膠帶與塑膠袋,並稍作擦拭與清潔。

11.將層板抵住牆面,用 4 只長螺絲鎖固。我總共安裝了 2 片層板。


12.將置物箱放入層板。至此大功告成。



後記

如果您也是安裝 2 片層板,在計算上下層板之間的距離時,應該要考量到上層板支架的厚度,如果忽略了這個厚度,在事後放入置物箱時,置物箱有可能會被上層板支架卡住而無法放進去。









2017年1月2日 星期一

[玩轉光立方] LED Cube 4x4x4 for Arduino UNO -- 程式3

在前兩篇貼文中,我們介紹了如何從頂端到底端以及從前面到背面點亮 LED,

玩轉光立方 LED Cube 4x4x4 for Arduino UNO http://pizgchen.blogspot.tw/2016/12/led-4x4x4-for-arduino-uno.html

玩轉光立方 LED Cube 4x4x4 for Arduino UNO -- 程式2 http://pizgchen.blogspot.tw/2017/01/led-led-cube-4x4x4-2.html

以上兩種方式只能逐一點亮 LED,無法做出多樣式的顯示圖案。本篇旨在為以後使用查表法做出動態顯示圖案做準備,在程式結構方面稍做修改。


程式碼

//2017-01-01 LED_Cube4_03.ino
//為了之後的動態顯示,用另一種方式來點亮全部 LED

#define CUBE_SIZE 4
#define PLANE_SIZE CUBE_SIZE*CUBE_SIZE
#define PLANE_TIME 0
#define LED_TIME 0

int LEDPin[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, A0, A1};
int PlanePin[] = {A2 , A3, A4, A5};

void setup()
{
  int pin;
  for (pin = 0; pin < PLANE_SIZE; pin++) {
    pinMode(LEDPin[pin], OUTPUT);
    digitalWrite(LEDPin[pin], LOW);
  }
  for (pin = 0; pin < CUBE_SIZE; pin++) {
    pinMode(PlanePin[pin], OUTPUT);
    digitalWrite(PlanePin[pin], HIGH);
  }
}

void loop()
{
  for (int plane = 0; plane < CUBE_SIZE; plane++) {
    digitalWrite(PlanePin[plane], LOW);
    for (int col = 0; col < CUBE_SIZE; col++) {
      for (int row = 0; row < CUBE_SIZE; row++)
      {
        digitalWrite(LEDPin[col * CUBE_SIZE + row], HIGH);
        delay(LED_TIME);
        digitalWrite(LEDPin[col * CUBE_SIZE + row], LOW);
      }
    }
    delay(PLANE_TIME);
    digitalWrite(PlanePin[plane], HIGH);
  }
}


來看看影片



延伸閱讀

玩轉光立方上一篇 http://pizgchen.blogspot.tw/2017/01/led-led-cube-4x4x4-2.html
玩轉光立方下一篇 http://pizgchen.blogspot.tw/2017/03/led-led-cube-4x4x4-for-arduino-uno-4.html