2017年4月29日 星期六

[NodeMCU] Lab1 點亮 8-Bit 2812 RGB LED

之前我們介紹過如何用 Arduino 點亮 8-Bit 2812 RGB LED 燈板,詳

http://pizgchen.blogspot.tw/2017/04/ws2812-8-bit-2812-rgb-led.html

這兒我們要改用 NodeMCU 點亮它。



準備材料

1. 8-Bit 2812 RGB LED 燈板 *1
2. 公排針(間距2.54mm) 4P *1
請先依 http://pizgchen.blogspot.tw/2017/04/ws2812-8-bit-2812-rgb-led.html 文中描述焊妥排針。
3. NodeMCU 開發板 *1
4. 杜邦線母母頭 3P *1


電路接線

用杜邦線依下表將 NodeMCU 與燈板連接起來:

NodeMCU      燈板
5V                   VDC
Gnd                 Gnd
D1                   DI


下載函式庫

1. 點選右側網址下載函式庫 https://github.com/adafruit/Adafruit_NeoPixel
2. 將下載的檔案解壓縮,複製到 Arduino IDE 的 libraries 資料夾裏。
3. 更改名稱為「Adafruit_NeoPixel」。


程式碼

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN D1  //GPIO5

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(8, PIN, NEO_GRB + NEO_KHZ800);

// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel.  Avoid connecting
// on a live circuit...if you must, connect GND first.

void setup() {
  // This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket
  #if defined (__AVR_ATtiny85__)
    if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  #endif
  // End of trinket special code


  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}

void loop() {
  // Some example procedures showing how to display to the pixels:
  colorWipe(strip.Color(255, 0, 0), 50); // Red
  colorWipe(strip.Color(0, 255, 0), 50); // Green
  colorWipe(strip.Color(0, 0, 255), 50); // Blue
//colorWipe(strip.Color(0, 0, 0, 255), 50); // White RGBW
  // Send a theater pixel chase in...
  theaterChase(strip.Color(127, 127, 127), 50); // White
  theaterChase(strip.Color(127, 0, 0), 50); // Red
  theaterChase(strip.Color(0, 0, 127), 50); // Blue

  rainbow(20);
  rainbowCycle(20);
  theaterChaseRainbow(50);
}

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
  for (int j=0; j<10; j++) {  //do 10 cycles of chasing
    for (int q=0; q < 3; q++) {
      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, c);    //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}

//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) {
  for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
    for (int q=0; q < 3; q++) {
      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}


相關連結

NodeMCU 文件 https://nodemcu.readthedocs.io/en/master/en/modules/pwm/
Adafruit https://www.adafruit.com/product/1426


採購資訊

1. 8-Bit 2812 RGB LED http://goods.ruten.com.tw/item/show?21715791439863
2. NodeMCU Lua Wifi 開發板 http://goods.ruten.com.tw/item/show?21716910606278
3. 公排針 http://goods.ruten.com.tw/item/show?21646385415847
4. 杜邦線 母母頭 http://goods.ruten.com.tw/item/show?21629159825718


[NodeMCU] Lab0 安裝與設定

有別於 Arduino 開發板,NodeMCU 開發套件本身就可以連網,它是一款以 ESP8266 模塊作為基礎的開發板,它將 ESP8266 所有的腳位分別引出,可以讓您作為多種用途使用。



NodeMCU 與 ESP8266 的主要差異

  • NodeMCU 包含一個 USB to serial 晶片,可隨插即用
  • NodeMCU firmware 可使用 Lua script 撰寫程式

NodeMCU 開發板使用 Lua 來程式設計,而 ESP8266 的使用者,只要把 firmware 更新為 NodeMCU,也可以使用 Lua 來撰寫程式。


如果你是首次使用 NodeMCU,在您將 NodeMCU 插入電腦時,它會要求你安裝 CP2102 驅動程式,因為它使用 CP2102 晶片當作 USB 與 UART 的溝通橋樑。

下載 CP2102 驅動程式 http://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers

下載後解壓縮,並且依照您的作業系統分別執行

CP210xVCPInstaller_x86.exe (32位元)

CP210xVCPInstaller_x64.exe (64位元)


檢查 NodeMCU 是否已和電腦正確連接

開啟「控制台」>「裝置管理員」>「連接埠(COM 和 LPT)」。
檢視序列埠是否有被啟用(你我的埠可能會不同),如下圖



使用 Arduino IDE 撰寫程式

為了讓我們可以使用 Arduino IDE 來編寫程式,需要做一些設定,這個步驟只需做一次即可,以後啟動 Arduino IDE 都無需重覆設定。

Step1 開啟 Arduino IDE。

Step2 點擊「檔案」>「偏好設定」,將底下那一行字貼到「Additional Boards Manager URLs:」右側欄位內

http://arduino.esp8266.com/stable/package_esp8266com_index.json

Step3 點擊「確定」鈕,並關閉 Arduino IDE。

Step4 再次開啟 Arduino IDE。

Step5 安裝 ESP8266 工具,點擊「工具」>「板子」>「Boards Manager...」。
(出現「Boards Manager」對話窗)

Step6 捲動右側拉桿到下方,點擊「esp8266 by ESP8266 Community」那一欄,再點擊「Install」鈕。

Step7 點擊「關閉」鈕。



開啟範例程式

在自己編寫程式之前,我們先來執行內建的範例程式。這個程式會讓 NodeMCU 板載的 LED 閃爍。

Step1 開啟 Arduino IDE。

Step2 點擊「工具」>「板子」,選擇「NodeMCU 1.0 (ESP-12E Module)」。

Step3 點擊「序列埠」,選擇正確的埠。

Step4 點擊「檔案」>「範例」>「ESP8266」>「Blink」。

Step5 點擊「上傳」。

此時你可以看到 Arduino IDE 下方的訊息欄有陸續出現許多紅點與上傳的百分比,等待顯示上傳完畢,你就可以看到 NodeMCU 板子上面的 LED 閃爍。




程式說明

1. 我們可以看到 NodeMCU 板子上面的 LED 在閃爍,可是為什麼我們在程式中的腳位是寫著 "LED_BUILTIN" 呢? 這是因為 "LED_BUILTIN" 是 ESP8266 的關鍵字,它其實是等於 "D0",也就是 D0 腳。


接著我們來看看底下這張 NodeMCU 的腳位圖


由圖中我們可以看到 D0 就是 GPIO16,所以如果我們把程式中的「LED_BUILTIN」改成「GPIO16」,你猜 LED 還會正常閃爍嗎?

答案是否定的。正確的寫法如下:

int ledPin = 16; // GPIO16

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  digitalWrite(ledPin, LOW);
  delay(1000);
  digitalWrite(ledPin, HIGH);
  delay(2000);
}


2. 不知您是否有發現 LED 閃爍的頻率有點怪怪的,程式中明明寫著 LOW 的時間是 1秒,HIGH 的時間是 2 秒,可為什麼 LED 卻是亮 1 秒、暗 2 秒?那是因為 NodeMCU 板子在電路設計上就是 LOW 時才可以點亮該腳位的 LED。

3. D9 腳位可以點亮 ESP8266 板載 LED,但它也是輸出 LOW 時被點亮,HIGH 就熄滅。


Lua 編輯器

除了使用 Arduino IDE 來編寫程式之外,我們也可以在 ESPlorer 編輯器上用 Lua 語言來寫程式。

點擊右側網址下載並安裝 ESPlorer http://esp8266.ru/esplorer-latest/?f=ESPlorer.zip

用滑鼠右鍵點擊「ESPlorer.bat」。此時會出現命令列畫面,隨後就出現 ESPlorer IDE 視窗。



選擇正確的 COM 埠,並設定 UART 通訊的 Baudrate 為 9600。


點擊「Open」鈕







下方清單框內會出現連線訊息,



我的第一支 Lua 程式

NodeMCU 的特色之一,就是能使用 Lua 來撰寫程式。在 ESPlorer 畫面左側的編輯區,輸入第一個 Hello World 程式碼如下:

print("hello world")

完成後,按下 Send to ESP 按紐,即可將程式碼傳送至 NodeMCU 上執行。


相關連結

NodeMCU 官網 http://nodemcu.com/index_cn.html
NodeMCU 參考文件 https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_cn
Instruceables http://www.instructables.com/id/Programming-ESP8266-ESP-12E-NodeMCU-Using-Arduino-/
ESPlorer 編輯器 http://esp8266.ru/esplorer/
Lua 編譯器的用法 http://yhhuang1966.blogspot.tw/2015/07/lua.html


採購資訊

NodeMCU Lua Wifi 開發板 http://goods.ruten.com.tw/item/show?21716910606278








2017年4月13日 星期四

[WS2812] 8-Bit 2812 RGB LED

傳統方式要控制多顆 RGB LED 在電路接線和程式控制方面是非常煩雜的,然而使用內建 WS2812 晶片的 RGB LED 卻是簡單又方便,不管你要控制幾顆 RGB LED,都只要使用 Arduino 3 支腳位就足夠了。

在這兒我使用 2 串 8-Bit RGB LED 燈條來作示範



準備材料

1. 8-Bit 2812 RGB LED *2



2. 排針 4P(腳距2.54mm) *2
3. 排母 4P(腳距2.54mm) *2


4. 杜邦線母母頭 3P *1
5. Arduino Uno or Nano *1


焊接

1. 將排針焊到燈條的 DI 端。
2. 將排母焊到燈條的 DO 端。
3. 如步驟1 & 2 焊接另一燈條。



電路接線

1. 將兩只燈條連接起來,也就是將燈條的公排針插入另一燈條的母排針。
2. 用杜邦線依下表將 Arduino 與燈條連接起來:

Arduino      燈條
5V               VDC
Gnd             Gnd
D6               DI


下載函式庫

1. 點選右側網址下載函式庫 https://github.com/adafruit/Adafruit_NeoPixel
2. 將下載的檔案解壓縮,複製到 Arduino IDE 的 libraries 資料夾裏。
3. 更改名稱為「Adafruit_NeoPixel」。


執行範例程式

1. 啟動 Arduino IDE。
2. 點擊「檔案」>「範例」>「Adafruit_NeoPixel」>「strandtest」。
3. 找到這一行
Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);
修改為
Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, PIN, NEO_GRB + NEO_KHZ800);

4. 上傳程式。


影片

video


採購資訊

1. 8-Bit 2812 RGB LED http://goods.ruten.com.tw/item/show?21715791439863
2. 排針 http://goods.ruten.com.tw/item/show?21646385415847
3. 排母 http://goods.ruten.com.tw/item/show?21646384889087
4. 杜邦線 母母頭 http://goods.ruten.com.tw/item/show?21629159825718
5. Arduino Nano http://goods.ruten.com.tw/item/show?21642069565073
6. Arduino Nano & Uno 兩用擴展板 http://goods.ruten.com.tw/item/show?21628077602506


















2017年3月17日 星期五

[玩轉光立方] LED Cube 4x4x4 for Arduino Nano -- 組裝教學

本文要介紹的這是 Arduino Nano 版本的光立方,優點是體積更小更簡潔,但功能比起 Arduino UNO 卻毫不遜色。


來看看影片先

video



準備材料與工具


材料:
1. LED Cube PCB底板 *1
2. 3mm LED * 64
3. M3 25+6mm 尼龍柱 * 4
4. M3x8mm 螺絲 * 4
5. 圓孔排針 * 20
6. 15P排母 * 2
7. 10cm長電線 * 4

另需準備:
1. Arduino Nano 開發板 * 1
2. USB mini 數據線 * 1

工具:
1. 烙鐵 + 焊錫
2. 斜口鉗
3. 尖嘴鉗
4. 鑷子
5. 厚紙板
6. 電鑽 + 3mm 鑽頭
7. 原子筆或細簽字筆
8. 橡皮筋
9. 電阻 100~220R
10. 麵包板


開始動手做

一、檢查所有的 LED 是否有正常發亮

您購買的 LED 即使廠商如何口沫橫飛地述說它們品質是如何地好,建議您也必須要自己詳細查驗,否則您可能有機會遇到懊惱的時候。

1. 計算限流電阻。

藍色 LED 順向電壓約 3.0~3.4V (注意:顏色不同,可承受的電壓也不同),我們取 3.2V 來計算:

(5 - 3.2) / 15mA = 120R

可採用 100R 或 110R 電阻。

2. 將電阻與 5V 電源插入麵包板,逐一插入 LED,檢查 LED 是否正常發光。
將 LED 插入麵包板時要注意 LED 的正負極。



二、彎折 LED

1. 先來看看我們要做出怎樣的東西



2. 取出尖嘴鉗輔助彎折 LED,我們需要彎折出 3 種型式的 LED,下圖右側是未彎折前。
在彎折時須注意 LED 的正負腳,正腳在彎 2 折後仍保持與燈珠同方向,並且每一彎折應盡量保持90度角,如下:

Type A * 48只


Type B * 12只


Type C * 4只


小聲地說...這個工作我是一邊看電視一邊彎折的,不然要彎折 64 只 LED 還真是挺無聊的事情。


三、製作固定 LED 的模板

這個模板可以用來插入 LED,如此可以讓 LED 排列整齊,在焊接時不會移位。

1. 準備一張厚約 1~3mm 的硬紙板。我隨手找了個 68x68mm 的蛋糕盒。



2. 在上面畫上間距 14mm 的九宮格。14mm * 3 = 42mm,九宮格邊長是 42mm。
我先畫上交叉線找出盒子中心點,再由中心點往外畫出九宮格。


3. 用電鑽在交點處鑽出 16 個 3mm 圓孔。


四、焊接 LED

我把紙模寫上座標以利辨識


1. 將 Type A 插到座標(0,0)~(2,2)之間區塊,共 12 只。
注意 LED 的腳位方向。


2. 將 Type B 插到座標(0,3)~(2,3)之間直線,共 3 只。
注意 LED 的腳位方向。



3. 將 Type C 插到座標(3,3),共 1 只。
注意 LED 的腳位方向。


4. 將 LED 所有的負腳全部焊接在一起。
圖片中是焊接好取出的樣子。


5. 您需要做 4 組(L0~L3)上面圖片的 LED 層面。

6. 將 4 組 LED 層面的正腳都焊起來。
注意正腳搭接長度大約是 8mm 左右,盡量讓你的 LED 排列呈現出正方形。



五、將圓孔母排針焊到電路板上

1. 取出 Cube 底板,將 20 支圓孔母排針插到電路板上的 A0~A15 和 D1~D4 位置。
板子有兩面,要注意方向。



2. 為了焊接前翻轉電路板時避免排針掉落,我隨手取一塊 5x7cm 的電路板蓋住排針,小心地用橡皮筋將他們綁在一起。
然後可用鑷子調整排針,讓排針垂直站立,避免歪斜。



3. 翻面,準備焊接。


4. 焊好後移除橡皮筋與電路板。


六、焊接15P排母

1. 將 2 只 15P 排母插入 Cube 底板





2. 為了讓 15P 排母垂直站立,並且以後讓 Arduino Nano 容易插入排母,在此我們將 Arduino Nano 開發板插到排母。
請注意,Arduino Nano 的 USB 頭須朝外。


3. 翻面焊接排母。


七、組立 LED Cube

1. 在 Cube 底板四個角落用 M3 螺絲鎖住尼龍柱。


2. 將 LED 腳謹慎插入 A0~A15 排針圓孔。
可用鑷子或尖嘴鉗輔助,夾住 LED 腳插入排針圓孔。


3. 在 4 個層焊上電線,並將電線另一端分別插入 D1~D4 排針圓孔。
同樣地,可用鑷子或尖嘴鉗輔助,夾住電線末端插入排針圓孔。



程式

//2017-01-01 LED_Cube4_01.ino
//從頂層到底層逐一點亮 LED

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

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 led = 0; led < PLANE_SIZE; led++)
    {
      digitalWrite(LEDPin[led], HIGH);
      delay(LED_TIME);
      digitalWrite(LEDPin[led], LOW);
    }
    digitalWrite(PlanePin[plane], HIGH);
    delay(PLANE_TIME);
  }
}


程式說明

1. UNO 腳位 D0~D13 & A0~A1 分別控制每一顆 LED,D0 控制的 LED 是靠近 D0 腳位那一顆,A1 腳位則是控制距離 D0 最遠的那一顆 LED。A2 控制頂層 LED,A5 則是控制底層 LED。

2. 把所有的腳位都設定成 OUTPUT,才可以指定它要 HIGH 或 LOW。當指定它為 HIGH 時電位是 5V;當指定它為 LOW時電位是 0V,相對於 5V 而言可以把它視為是 GND。

3. 在初始階段為了讓所有的 LED 都不亮,所以在 setup() 階段將 16只 LED 腳位都設為 LOW,並且將控制層面的 4 只腳位都設為 HIGH。



相關連結

1. LED 限流電阻計算 http://gc.digitw.com/Program/Resistor4LED/Resistor4LED.htm
2. Arduino UNO 開發板 https://www.arduino.cc/en/Main/ArduinoBoardUno
3. 玩轉光立方 LED Cube 4x4x4 -- 程式2 http://pizgchen.blogspot.tw/2017/01/led-led-cube-4x4x4-2.html
4. 圖形編輯器 https://www.robota.nl/en/blog/led-cube-4x4x4-pattern-designer/led-cube-simulation-and-pattern-generator.html
5. 免費的專業圖形編輯器 http://www.solderlab.de/index.php/software/glediator


採購資訊

光立方 LED Cube 4x4x4 for Arduino Nano http://goods.ruten.com.tw/item/show?21711527533658



2017年3月13日 星期一

[Arduino] 淺談記憶體2 -- PROGRAM

在前篇文中( http://pizgchen.blogspot.tw/2017/03/arduino-1.html )我們說明了 Arduino 有哪些類型的記憶體,其中有提到一個關鍵字「PROGRAM」,本文旨在說明如何使用 PROGRAM 這個變數修飾符。


使用 PROGRAM 的時機

Arduno UNO 只有 2k bytes 的 SRAM 空間讓您存放及運作變數,若是您要將大量的訊息送到序列監控視窗顯示出來,或是您要設置一個供給查表法使用的大資料量表格,這時您有可能會使用超過 2k bytes 的空間。

在您使用超過 2k bytes 的 SRAM 空間時,也許編譯時沒有異狀,但這並不表示您的程式能夠正常運作。

要解決 SRAM 空間不足的問題,我們可以將這些大量資料從 SRAM "搬到" Flash (程式碼就是儲存在 Flash),在需要運作變數時再將這些資料從 Flash "搬回" SRAM 內。那麼如何讓 Arduino 知道哪些資料將會被這樣使用,答案就是使用 PROGRAM 這個變數修飾符來宣告。


如何使用 PROGRAM

PROGRAM 變數修飾符是被定義在 pgmspace.h 之中,它是 AVR 架構中 pgmspace.h 函式庫眾多函式的其中之一。所以您要使用 PROGRAM 之前,必須在程式的開頭包含入這個函式庫,如下:

#include <avr/pgmspace.h>

然後,使用下列句法給值

const dataType variableName [ ] PROGRAM = {data0, data1, data2...};

dataType - 表資料型態。
variableName - 表變數名稱。


PROGRAM 只是一個變數修飾符,它沒有被規定應該放在哪個位置,所以下列三種宣告方式都可以通過編譯器的解析:

const dataType variableName [ ] PROGRAM = {data0, data1, data2...};
const PROGRAM dataType variableName [ ] = {data0, data1, data2...};
const dataType PROGRAM variableName [ ] = {data0, data1, data2...};

雖然 PROGRAM 可以使用在單一變數上,但大多情況我們會用它來處理大量的資料,尤其是大量的陣列資料。下列表格讓您瞭解與比較不同的資料型態會佔用多少記憶體:



再提醒您一次,我們需要兩個步驟來使用 PROGRAM,首先用 PROGRAM 宣告一個變數並給值,然後要使用這些變數的值時再將它從 Flash 讀回到 SRAM。


範例

下列程式片段在示範如何讀寫 char (1 byte) 和 int (2 bytes) 到 PROGRAM。

#include <avr/pgmspace.h>


// save some unsigned ints
const PROGMEM  uint16_t charSet[]  = { 65000, 32796, 16843, 10, 11234};

// save some chars
const char signMessage[] PROGMEM  = {"I AM PREDATOR,  UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART"};

unsigned int displayInt;
int k;    // counter variable
char myChar;


void setup() {
  Serial.begin(9600);
  while (!Serial);

  // put your setup code here, to run once:
  // read back a 2-byte int
  for (= 0; k < 5; k++)
  {
    displayInt = pgm_read_word_near(charSet + k);
    Serial.println(displayInt);
  }
  Serial.println();

  // read back a char
  int len = strlen_P(signMessage);
  for (= 0; k < len; k++)
  {
    myChar =  pgm_read_byte_near(signMessage + k);
    Serial.print(myChar);
  }

  Serial.println();
}

void loop() {
  // put your main code here, to run repeatedly:

}


字串陣列


將資料設置為字串陣列通常是最方便使用的,尤其是要將大量的文字顯示到 LCD 之中時。因為字串本身就是一個字元陣列,而字串陣列實際上就是一個二維的字元陣列。

傾向於將大型的結構化資料放到 Flash 之中,往往是比較好的方式。下列程式碼就在說明這樣的概念:

#include <avr/pgmspace.h>


// save some unsigned ints
const PROGMEM  uint16_t charSet[]  = { 65000, 32796, 16843, 10, 11234};

// save some chars
const char signMessage[] PROGMEM  = {"I AM PREDATOR,  UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART"};

unsigned int displayInt;
int k;    // counter variable
char myChar;


void setup() {
  Serial.begin(9600);
  while (!Serial);

  // put your setup code here, to run once:
  // read back a 2-byte int
  for (= 0; k < 5; k++)
  {
    displayInt = pgm_read_word_near(charSet + k);
    Serial.println(displayInt);
  }
  Serial.println();

  // read back a char
  int len = strlen_P(signMessage);
  for (= 0; k < len; k++)
  {
    myChar =  pgm_read_byte_near(signMessage + k);
    Serial.print(myChar);
  }

  Serial.println();
}

void loop() {
  // put your main code here, to run repeatedly:

}


注意

請注意,為了要使用 PROGRAM,您必須將變數指定為全域變數(Global)或靜態變數(Static)。

下列程式碼若是被放在函式裏面,它將不會運作

const char long_str[] PROGMEM = "Hi, I would like to tell you a bit about myself.\n";

下列程式碼若是被放在函式裏面,它也會運作

const static char long_str[] PROGMEM = "Hi, I would like to tell you a bit about myself.\n"


F() 函式

如果您在程式中有使用這樣的句法

Serial.print("Write something on  the Serial Monitor");

這串要印出的文字通常是被存放在記憶體之中,如果您印出非常大量這樣的文字到 Serial Monitor,將會很容易把記憶體耗光。如果您有閒置的 Flash 記憶體空間,您可以很輕易地將要印出的文字存放到 Flash 裏,如下:

Serial.print(F("Write something on the Serial Monitor that is stored in FLASH"));


相關連結

淺談記憶體1 -- Memory http://pizgchen.blogspot.tw/2017/03/arduino-1.html

Arduino PROGRAM https://www.arduino.cc/en/Reference/PROGMEM