Showing posts with label Arduino. Show all posts
Showing posts with label Arduino. Show all posts

Tuesday, November 16, 2021

Arduino Nano RP2040 Connect generate QR Code and display on ST7735 TFT - software SPI

This post show how to generate QR Code with Nano RP2040 Connect (Arduino Framework) using QRCode library by Richard Moore, also display on ST7735 SPI TFT, and finally adapt to WiFiNINA > AP_SimpleWebServer example to control onboard LED.

Library

Install QRCode library by Richard Moore in Arduino IDE's Libraries Manager.


And, "Adafruit ST7735 and ST7789 Library" and "Adafruit GFX Library" are needed to display with ST7735 SPI TFT.

Connection

The hardware SPI of Arduino Nano RP2040 Connect are:
- (CIPO/MISO) - D12
- (COPI/MOSI) - D11
- (SCK) - D13
- (CS/SS) - Any GPIO (except for A6/A7)


In this exercise, we have to control the onboard LED connected to D13. it's conflict with SCK. So the exercise code here use software SPI.
/************************************************
 * TFT_ST7735 nano RP2040 Connect
 * ------------------------------
 * VCC        3V3
 * GND        GND
 * CS         10
 * RESET      9
 * A0(DC)     8
 * SDA        11
 * SCK        12
 * LED        3V3
 * **********************************************/
Exercise code

nanoRP2040_QRCode.ino
/**
 *  Arduino nano RP2040 Connect exercise to generate QR Code,
 *  with display on Serial Monitor and ST7735 SPI TFT.
 *  Modified from QRCode example.
 *  
 *  Library: QRCode by Richard  Moore
 *  https://github.com/ricmoo/qrcode/
 *  
 */
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include "qrcode.h"

/************************************************
 * TFT_ST7735 nano RP2040 Connect
 * ------------------------------
 * VCC        3V3
 * GND        GND
 * CS         10
 * RESET      9
 * A0(DC)     8
 * SDA        11
 * SCK        12
 * LED        3V3
 * **********************************************/
// TFT display use software SPI interface.
#define TFT_MOSI 11  // Data out
#define TFT_SCLK 12  // Clock out

#define TFT_CS  10  // Chip select line for TFT display
#define TFT_DC   8  // Data/command line for TFT
#define TFT_RST  9  // Reset line for TFT (or connect to VCC)
Adafruit_ST7735 tft_ST7735 = Adafruit_ST7735(TFT_CS, TFT_DC, 
                                  TFT_MOSI, TFT_SCLK, TFT_RST);

void setup() {
    delay(1000);
    Serial.begin(115200);
    delay(1000);
    Serial.println("- setup() started -");
    tft_ST7735.initR(INITR_BLACKTAB);
    tft_ST7735.setRotation(2);
    
    // tft display RGB to make sure it's work properly
    tft_ST7735.fillScreen(ST7735_BLACK);
    delay(300);
    tft_ST7735.fillScreen(ST7735_RED);
    delay(300);
    tft_ST7735.fillScreen(ST7735_GREEN);
    delay(300);
    tft_ST7735.fillScreen(ST7735_BLUE);
    delay(300);
    tft_ST7735.fillScreen(ST7735_WHITE);
    delay(300);

    // Start time
    uint32_t dt = millis();
  
    // Create the QR code
    QRCode qrcode;

    const char *data = "http://arduino-er.blogspot.com/";
    const uint8_t ecc = 0;  //lowest level of error correction
    const uint8_t version = 3;

    uint8_t qrcodeData[qrcode_getBufferSize(version)];
    qrcode_initText(&qrcode, 
                    qrcodeData, 
                    version, ecc, 
                    data);
  
    // Delta time
    dt = millis() - dt;
    Serial.print("QR Code Generation Time: ");
    Serial.print(dt);
    Serial.print("\n\n");
    
    Serial.println(data);
    Serial.print("qrcode.version: ");
    Serial.println(qrcode.version);
    Serial.print("qrcode.ecc: ");
    Serial.println(qrcode.ecc);
    Serial.print("qrcode.size: ");
    Serial.println(qrcode.size);
    Serial.print("qrcode.mode: ");
    Serial.println(qrcode.mode);
    Serial.print("qrcode.mask: ");
    Serial.println(qrcode.mask);
    Serial.println();

    const int xy_scale = 3;
    const int x_offset = (tft_ST7735.width() - xy_scale*qrcode.size)/2;
    const int y_offset = (tft_ST7735.height() - xy_scale*qrcode.size)/2;
    
    
    // Top quiet zone
    Serial.print("\n\n\n\n");
    for (uint8_t y = 0; y < qrcode.size; y++) {

        // Left quiet zone
        Serial.print("        ");

        // Each horizontal module
        for (uint8_t x = 0; x < qrcode.size; x++) {

            // Print each module (UTF-8 \u2588 is a solid block)
            bool mod = qrcode_getModule(&qrcode, x, y);
            //Serial.print(mod ? "\u2588\u2588": "  ");
            if(mod){
              Serial.print("██"); //same as "\u2588\u2588"
                                  //direct paste "██" copied from Serial Monitor
              int px = x_offset + (x * xy_scale);
              int py = y_offset + (y * xy_scale);
              tft_ST7735.fillRect(px, py, xy_scale, xy_scale, ST7735_BLACK);
              
            }else{
              Serial.print("  ");
            }
        }

        Serial.print("\n");
    }

    // Bottom quiet zone
    Serial.print("\n\n\n\n");
}

void loop() {

}


nanoRP2040_QRCode_web.ino
/**
 *  Arduino nano RP2040 Connect exercise to generate QR Code,
 *  WiFiWebServer with QRCode on ST7735 SPI TFT
 *  
 *  Library: QRCode by Richard  Moore
 *  https://github.com/ricmoo/qrcode/
 *  
 */
#include <WiFiNINA.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include "qrcode.h"

/************************************************
 * TFT_ST7735 nano RP2040 Connect
 * ------------------------------
 * VCC        3V3
 * GND        GND
 * CS         10
 * RESET      9
 * A0(DC)     8
 * SDA        11
 * SCK        12
 * LED        3V3
 * **********************************************/
// TFT display use software SPI interface.
//
// Hardware SPI pins are specific to the Arduino board type and
// cannot be remapped to alternate pins.
//
// In this exercise, we are going to implement a web server to
// turn ON/OFF on board LED, which is connected to D13. It's
// conflict with hardware SPI SCK.
// So we cannot use hardware SPI to controll ST7735.
#define TFT_MOSI 11  // Data out
#define TFT_SCLK 12  // Clock out

#define TFT_CS  10  // Chip select line for TFT display
#define TFT_DC   8  // Data/command line for TFT
#define TFT_RST  9  // Reset line for TFT (or connect to VCC)
Adafruit_ST7735 tft_ST7735 = Adafruit_ST7735(TFT_CS, TFT_DC,
                                  TFT_MOSI, TFT_SCLK, TFT_RST);

char ssid[] = "ssid";       // your network SSID (name)
char pass[] = "password";   // your network password (use for WPA, or use as key for WEP)

int status = WL_IDLE_STATUS;
WiFiServer server(80);

void setup() {
    
    delay(1000);
    Serial.begin(115200);
    delay(1000);
    Serial.println("- setup() started -");
    Serial.print("LED_BUILTIN: ");
    Serial.println(LED_BUILTIN);
    pinMode(LED_BUILTIN, OUTPUT);      // set the LED pin mode
    tft_ST7735.initR(INITR_BLACKTAB);
    tft_ST7735.setRotation(2);
    tft_ST7735.setTextWrap(true);
    tft_ST7735.setTextColor(ST77XX_BLACK);
    
    // tft display RGB to make sure it's work properly
    digitalWrite(LED_BUILTIN, HIGH);
    tft_ST7735.fillScreen(ST7735_BLACK);
    delay(300);
    digitalWrite(LED_BUILTIN, LOW);
    tft_ST7735.fillScreen(ST7735_RED);
    delay(300);
    digitalWrite(LED_BUILTIN, HIGH);
    tft_ST7735.fillScreen(ST7735_GREEN);
    delay(300);
    digitalWrite(LED_BUILTIN, LOW);
    tft_ST7735.fillScreen(ST7735_BLUE);
    delay(300);
    digitalWrite(LED_BUILTIN, HIGH);
    tft_ST7735.fillScreen(ST7735_WHITE);
    delay(300);

    // check for the WiFi module:
    if (WiFi.status() == WL_NO_MODULE) {
      Serial.println("Communication with WiFi module failed!");
      tft_ST7735.setCursor(0, 0);
      tft_ST7735.print("Communication with WiFi module failed!");
      // don't continue
      while (true);
    }

    Serial.print("WiFi.firmwareVersion(): ");
    Serial.println(WiFi.firmwareVersion());

    // attempt to connect to WiFi network:
    while (status != WL_CONNECTED) {
      Serial.print("Attempting to connect to SSID: ");
      Serial.println(ssid);
      // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
      status = WiFi.begin(ssid, pass);
      
      // wait 10 seconds for connection:
      delay(10000);
    }
    server.begin();
    // you're connected now, so print out the status:
    printWifiStatus();

    // Start time
    uint32_t dt = millis();
  
    // Create the QR code
    QRCode qrcode;

    char myIpQrData[30] ="http://";
    prepareIpQrData(myIpQrData);
    
    const uint8_t ecc = 0;  //lowest level of error correction
    const uint8_t version = 3;

    uint8_t qrcodeData[qrcode_getBufferSize(version)];
    qrcode_initText(&qrcode, 
                    qrcodeData, 
                    version, ecc, 
                    myIpQrData);
  
    // Delta time
    dt = millis() - dt;
    Serial.print("QR Code Generation Time: ");
    Serial.print(dt);
    Serial.print("\n\n");
    
    Serial.println(myIpQrData);
    Serial.print("qrcode.version: ");
    Serial.println(qrcode.version);
    Serial.print("qrcode.ecc: ");
    Serial.println(qrcode.ecc);
    Serial.print("qrcode.size: ");
    Serial.println(qrcode.size);
    Serial.print("qrcode.mode: ");
    Serial.println(qrcode.mode);
    Serial.print("qrcode.mask: ");
    Serial.println(qrcode.mask);
    Serial.println();

    const int xy_scale = 3;
    const int x_offset = (tft_ST7735.width() - xy_scale*qrcode.size)/2;
    const int y_offset = (tft_ST7735.height() - xy_scale*qrcode.size)/2;
    
    // Top quiet zone
    Serial.print("\n\n\n\n");
    for (uint8_t y = 0; y < qrcode.size; y++) {

        // Left quiet zone
        Serial.print("        ");

        // Each horizontal module
        for (uint8_t x = 0; x < qrcode.size; x++) {

            // Print each module (UTF-8 \u2588 is a solid block)
            bool mod = qrcode_getModule(&qrcode, x, y);
            //Serial.print(mod ? "\u2588\u2588": "  ");
            if(mod){
              Serial.print("██"); //same as "\u2588\u2588"
                                  //direct paste "██" copied from Serial Monitor
              int px = x_offset + (x * xy_scale);
              int py = y_offset + (y * xy_scale);
              tft_ST7735.fillRect(px, py, xy_scale, xy_scale, ST7735_BLACK);
              
            }else{
              Serial.print("  ");
            }
        }

        Serial.print("\n");
    }

    // Bottom quiet zone
    Serial.print("\n\n\n\n");
    digitalWrite(LED_BUILTIN, LOW);
}

//prepare ip address in char *,
//to pass to qrcode_initText()
char * prepareIpQrData(char *dest){
  Serial.println("***********************");
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
  Serial.println(ip[0]);
  Serial.println(ip[1]);
  Serial.println(ip[2]);
  Serial.println(ip[3]);

  Serial.println("-------------");
  char buffer0[3];
  char buffer1[3];
  char buffer2[3];
  char buffer3[3];
  itoa(ip[0], buffer0, 10);
  itoa(ip[1], buffer1, 10);
  itoa(ip[2], buffer2, 10);
  itoa(ip[3], buffer3, 10);

  char str[15] = "";
  char dot[] = ".";

  strcat(dest, buffer0);
  strcat(dest, dot);
  strcat(dest, buffer1);
  strcat(dest, dot);
  strcat(dest, buffer2);
  strcat(dest, dot);
  strcat(dest, buffer3);
  
  Serial.println(dest);
  Serial.println("***********************");
  
}

//The web page part is mainly modified 
//from WiFiNINA example > AP_SimpleWebServer
//that lets you blink an LED via the web.
void loop() {
  // compare the previous status to the current status
  if (status != WiFi.status()) {
    // it has changed update the variable
    status = WiFi.status();

    if (status == WL_AP_CONNECTED) {
      // a device has connected to the AP
      Serial.println("Device connected to AP");
    } else {
      // a device has disconnected from the AP, and we are back in listening mode
      Serial.println("Device disconnected from AP");
    }
  }
  
  WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
    Serial.println("new client");           // print a message out the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      delayMicroseconds(10);                // This is required for the Arduino Nano RP2040 Connect 
                                            // - otherwise it will loop so fast that SPI will 
                                            // never be served.
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            client.println("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            
            // the content of the HTTP response follows the header:
            client.print("Click <a href=\"/H\">here</a> turn the LED on<br>");
            client.print("Click <a href=\"/L\">here</a> turn the LED off<br>");

            // The HTTP response ends with another blank line:
            client.println();
            // break out of the while loop:
            break;
          }
          else {      // if you got a newline, then clear currentLine:
            currentLine = "";
          }
        }
        else if (c != '\r') {    // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }

        // Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /H")) {
          Serial.println("\n===> GET /H");
          digitalWrite(LED_BUILTIN, HIGH);               // GET /H turns the LED on
        }
        if (currentLine.endsWith("GET /L")) {
          Serial.println("\n===> GET /L");
          digitalWrite(LED_BUILTIN, LOW);                // GET /L turns the LED off
        }
      }
    }
    // close the connection:
    client.stop();
    Serial.println("client disconnected");
  }
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

Related:

Tuesday, November 9, 2021

Arduino Nano RP2040 Connect + ST7735 SPI TFT with SD Card, read and display bitmap, using hardware SPI.

Exercises run on Arduino Nano RP2040 Connect (in Arduino framework) work with 1.8" 128x160 ST7735 SPI TFT/SD Card Module, to:
- simple display something on ST7735 SPI TFT
- Display files in SD Card, and read txt file from SD Card.
- Read bmp from SD Card and display on ST7735 SPI TFT
- Try example of Adafruit_ImageReader
- Simplified version display bitmap from SD and display on TFT using Adafruit_ImageReader.

In the following exercise Hardware SPI is used for ST7735 and SD Card SPI interface. refer to last post, SPI pins in Arduino Nano RP2040 Connect is:
- MISO    - D12
- MOSI    - D11
- SCK      - D13

Connection:
 * Nano RP2040 Connect drive ST7735 SPI and SD using hardware SPI
 * 
 * TFT_ST7735 nano RP2040 Connect
 * ------------------------------
 * VCC        3V3
 * GND        GND
 * CS         10
 * RESET      9
 * A0(DC)     8
 * SDA        11
 * SCK        13
 * LED        3V3
 * 
 * TFT_ST7735 nano RP2040 Connect
 * ------------------------------
 * SD_CS      4
 * SD_MOSI    11
 * SD_MISO    12
 * SD_SCK     13
 ****************************************************/

Exercise code:

Please notice that  "Adafruit ST7735 and ST7789 Library" and "Adafruit GFX Library" are needed, make sure it's installed in Arduino IDE's Libraries Manager.

nanoRP2040_ST7735.ino, a simple exercise to display something on ST7735 SPI TFT.

/***************************************************
 * nano RP2040 Connect exercise
 * + ST7745/SD
 * 
 * On Arduino nanp RP2040 Connect:
 * (CIPO/MISO)  - D12
 * (COPI/MOSI)  - D11
 * (SCK)        - D13
 * (CS/SS) - Any GPIO (except for A6/A7
 * 
 * This example drive ST7735 SPI and SD using hardware SPI
 * 
 * TFT_ST7735 nano RP2040 Connect
 * ------------------------------
 * VCC        3V3
 * GND        GND
 * CS         10
 * RESET      9
 * A0(DC)     8
 * SDA        11
 * SCK        13
 * LED        3V3
 * 
 ****************************************************/

#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SD.h>
#include <SPI.h>

// TFT display using hardware SPI interface.
// Hardware SPI pins are specific to the Arduino board type and
// cannot be remapped to alternate pins.
#define TFT_CS  10  // Chip select line for TFT display
#define TFT_DC   8  // Data/command line for TFT
#define TFT_RST  9  // Reset line for TFT (or connect to +5V)

Adafruit_ST7735 tft_ST7735 = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

void setup(void) {
  delay(1000);
  Serial.begin(115200);
  delay(1000);
  Serial.println("=====================");
  Serial.println("- setup() -");
  tft_ST7735.initR(INITR_BLACKTAB);
  Serial.println("tft: " 
                  + String(tft_ST7735.width()) + " : " 
                  + String(tft_ST7735.height()));

  tft_ST7735.fillScreen(ST7735_BLACK);
  tft_ST7735.setTextWrap(true);
  tft_ST7735.setTextColor(ST77XX_WHITE);
  tft_ST7735.setCursor(0, 0);
  tft_ST7735.print("Arduino nano RP2040 Connect");
  tft_ST7735.println("\n");

  //----------------------------------------
  delay(2000);

  tft_ST7735.setRotation(3);
  tft_ST7735.setCursor(0, 30);
  tft_ST7735.print("rotation: " + String(tft_ST7735.getRotation()));
  tft_ST7735.setCursor(0, 40);
  tft_ST7735.print(String(tft_ST7735.width()) + " x " + String(tft_ST7735.height()));
  
  delay(2000);

  tft_ST7735.fillScreen(ST77XX_RED);
  tft_ST7735.setCursor(50, 50);
  tft_ST7735.print("RED");
  delay(1000);
  tft_ST7735.fillScreen(ST77XX_GREEN);
  tft_ST7735.setCursor(50, 50);
  tft_ST7735.print("GREEN");
  delay(1000);
  tft_ST7735.fillScreen(ST77XX_BLUE);
  tft_ST7735.setCursor(50, 50);
  tft_ST7735.print("BLUE");
  delay(1000);

  delay(1000);
  
  //----------------------------------------

  Serial.println("\n- End of setup() -\n");
}


void loop() {

  tft_ST7735.fillScreen(ST77XX_BLUE);
  for(int offset=0; offset<tft_ST7735.height()/2; offset++){
    int col;
    if(offset%5 == 0)
      col = ST77XX_WHITE;
    else
      col = ST77XX_BLACK;
      
    tft_ST7735.drawRect(offset, offset, 
                 tft_ST7735.width()-2*offset, tft_ST7735.height()-2*offset,
                 col);
    delay(100);
  }

  delay(2000);

  tft_ST7735.fillScreen(ST77XX_BLACK);
  int cx = tft_ST7735.width()/2;
  int cy = tft_ST7735.height()/2;
  for(int r=0; r<tft_ST7735.height()/2; r=r+10){

    tft_ST7735.drawCircle(cx, cy, 
                 r,
                 ST77XX_WHITE);
    delay(200);
  }

  delay(2000);
  delay(2000);
}


nanoRP2040_ST7735_SD.ino, list files in SD card and read the text file hello.txt.
/***************************************************
 * nano RP2040 Connect exercise
 * + ST7745/SD
 * 
 * On Arduino nanp RP2040 Connect:
 * (CIPO/MISO) - D12
 * (COPI/MOSI) - D11
 * (SCK) - D13
 * (CS/SS) - Any GPIO (except for A6/A7
 * 
 * This example drive ST7735 SPI and SD using hardware SPI
 * 
 * TFT_ST7735 nano RP2040 Connect
 * ------------------------------
 * VCC        3V3
 * GND        GND
 * CS         10
 * RESET      9
 * A0(DC)     8
 * SDA        11
 * SCK        13
 * LED        3V3
 * 
 * TFT_ST7735 nano RP2040 Connect
 * ------------------------------
 * SD_CS      4
 * SD_MOSI    11
 * SD_MISO    12
 * SD_SCK     13
 ****************************************************/

#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SD.h>
#include <SPI.h>

// TFT display and SD card will share the hardware SPI interface.
// Hardware SPI pins are specific to the Arduino board type
#define SD_CS    4  // Chip select line for SD card
#define TFT_CS  10  // Chip select line for TFT display
#define TFT_DC   8  // Data/command line for TFT
#define TFT_RST  9  // Reset line for TFT (or connect to +5V)

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

File root;
File myFile;

void setup(void) {
  delay(1000);
  Serial.begin(115200);
  delay(1000);
  Serial.println("=====================");
  Serial.println("- setup() -");
  tft.initR(INITR_BLACKTAB);
  Serial.println("tft: " 
                  + String(tft.width()) + " : " 
                  + String(tft.height()));

  tft.fillScreen(ST7735_BLACK);
  tft.setTextWrap(true);
  tft.setTextColor(ST77XX_WHITE);
  tft.setCursor(0, 0);
  tft.print("Arduino nano RP2040 Connect");
  tft.println("\n");

  //----------------------------------------
  Serial.println("Initializing SD card...");
  if (!SD.begin(SD_CS)){
    Serial.println("SD.begin() failed!");
  }
  else{
    Serial.println("SD.begin() Success.");

    root = SD.open("/");
    printDirectory(root, 0);

    Serial.println("===============================");
    // open the file for reading:
    myFile = SD.open("hello.txt");
    if (myFile) {
      Serial.println("test.txt:");
      Serial.println("-------------------------------");
      // read from the file until there's nothing else in it:
      while (myFile.available()) {
      //Serial.write(myFile.read());
      byte b = myFile.read();
      Serial.write(b);
      tft.print((char)b);
      }
      // close the file:
      myFile.close();
    } else {
      // if the file didn't open, print an error:
      Serial.println("error opening test.txt");
    }
    Serial.println("\n===============================\n");

    
  }


  //----------------------------------------

  Serial.println("\n- End of setup() -\n");
}


void loop() {

  delay(100);
}

//
// printDirectory() copy from:
// Examples > SD > listfiles
//

void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}


nanoRP2040_ST7735_SD_bmp.ino, read bmp files in SD Card, test.bmp, test2.bmp and test3.bmp, and display on ST7735 SPI TFT. It can be noted in bmpDraw(), copy from examples under "Adafruit ST7735 and ST7789 Library" > shieldtest, bmpDepth must be 24. To prepare bmp for this using GIMP, refer to the above video, ~ 6:38.
/***************************************************
 * nano RP2040 Connect exercise
 * + ST7745/SD
 * 
 * On Arduino nanp RP2040 Connect:
 * (CIPO/MISO) - D12
 * (COPI/MOSI) - D11
 * (SCK) - D13
 * (CS/SS) - Any GPIO (except for A6/A7
 * 
 * This example drive ST7735 SPI and SD using hardware SPI
 * 
 * TFT_ST7735 nano RP2040 Connect
 * ------------------------------
 * VCC        3V3
 * GND        GND
 * CS         10
 * RESET      9
 * A0(DC)     8
 * SDA        11
 * SCK        13
 * LED        3V3
 * 
 * TFT_ST7735 nano RP2040 Connect
 * ------------------------------
 * SD_CS      4
 * SD_MOSI    11
 * SD_MISO    12
 * SD_SCK     13
 ****************************************************/

#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SD.h>
#include <SPI.h>

// TFT display and SD card will share the hardware SPI interface.
// Hardware SPI pins are specific to the Arduino board type.
#define SD_CS    4  // Chip select line for SD card
#define TFT_CS  10  // Chip select line for TFT display
#define TFT_DC   8  // Data/command line for TFT
#define TFT_RST  9  // Reset line for TFT (or connect to +5V)

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

File root;
File myFile;

void setup(void) {
  delay(1000);
  Serial.begin(115200);
  delay(1000);
  
  Serial.println("=====================");
  Serial.println("- setup() -");
  tft.initR(INITR_BLACKTAB);
  Serial.println("tft: " 
                  + String(tft.width()) + " : " 
                  + String(tft.height()));

  tft.fillScreen(ST7735_BLACK);
  tft.setTextWrap(true);
  tft.setTextColor(ST77XX_WHITE);
  tft.setCursor(0, 0);
  tft.print("Arduino nano RP2040 Connect");

  //----------------------------------------
  Serial.println("Initializing SD card...");
  if (!SD.begin(SD_CS)){
    Serial.println("SD.begin() failed!");
  }
  else{
    Serial.println("SD.begin() Success.");

    root = SD.open("/");
    printDirectory(root, 0);

  }


  //----------------------------------------

  Serial.println("\n- End of setup() -\n");
}

const int NO_OF_BMP = 3;
char* bmpFiles[NO_OF_BMP] = {"/test.bmp", "/test2.bmp",  "/test3.bmp"};

void loop() {
  for(int i=0; i<NO_OF_BMP; i++){
    bmpDraw(bmpFiles[i], 0, 0);
    delay(2000);
  }
}

//
// printDirectory() copy from:
// Examples > SD > listfiles
//

void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

//
// bmpDraw() copy from:
// Examples under "Adafruit ST7735 and ST7789 Library" > shieldtest
//
// This function opens a Windows Bitmap (BMP) file and
// displays it at the given coordinates.  It's sped up
// by reading many pixels worth of data at a time
// (rather than pixel by pixel).  Increasing the buffer
// size takes more of the Arduino's precious RAM but
// makes loading a little faster.  20 pixels seems a
// good balance.

#define BUFFPIXEL 20

void bmpDraw(char *filename, uint8_t x, uint8_t y) {

  File     bmpFile;
  int      bmpWidth, bmpHeight;   // W+H in pixels
  uint8_t  bmpDepth;              // Bit depth (currently must be 24)
  uint32_t bmpImageoffset;        // Start of image data in file
  uint32_t rowSize;               // Not always = bmpWidth; may have padding
  uint8_t  sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel)
  uint8_t  buffidx = sizeof(sdbuffer); // Current position in sdbuffer
  boolean  goodBmp = false;       // Set to true on valid header parse
  boolean  flip    = true;        // BMP is stored bottom-to-top
  int      w, h, row, col;
  uint8_t  r, g, b;
  uint32_t pos = 0, startTime = millis();

  if((x >= tft.width()) || (y >= tft.height())) return;

  Serial.println();
  Serial.print("Loading image '");
  Serial.print(filename);
  Serial.println('\'');

  // Open requested file on SD card
  if ((bmpFile = SD.open(filename)) == NULL) {
    Serial.print("File not found");
    return;
  }

  // Parse BMP header
  if(read16(bmpFile) == 0x4D42) { // BMP signature
    Serial.print("File size: "); Serial.println(read32(bmpFile));
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile); // Start of image data
    Serial.print("Image Offset: "); Serial.println(bmpImageoffset, DEC);
    // Read DIB header
    Serial.print("Header size: "); Serial.println(read32(bmpFile));
    bmpWidth  = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if(read16(bmpFile) == 1) { // # planes -- must be '1'
      bmpDepth = read16(bmpFile); // bits per pixel
      Serial.print("Bit Depth: "); Serial.println(bmpDepth);
      if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed

        goodBmp = true; // Supported BMP format -- proceed!
        Serial.print("Image size: ");
        Serial.print(bmpWidth);
        Serial.print('x');
        Serial.println(bmpHeight);

        // BMP rows are padded (if needed) to 4-byte boundary
        rowSize = (bmpWidth * 3 + 3) & ~3;

        // If bmpHeight is negative, image is in top-down order.
        // This is not canon but has been observed in the wild.
        if(bmpHeight < 0) {
          bmpHeight = -bmpHeight;
          flip      = false;
        }

        // Crop area to be loaded
        w = bmpWidth;
        h = bmpHeight;
        if((x+w-1) >= tft.width())  w = tft.width()  - x;
        if((y+h-1) >= tft.height()) h = tft.height() - y;

        // Set TFT address window to clipped image bounds
        tft.startWrite();
        tft.setAddrWindow(x, y, w, h);

        for (row=0; row<h; row++) { // For each scanline...

          // Seek to start of scan line.  It might seem labor-
          // intensive to be doing this on every line, but this
          // method covers a lot of gritty details like cropping
          // and scanline padding.  Also, the seek only takes
          // place if the file position actually needs to change
          // (avoids a lot of cluster math in SD library).
          if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
            pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
          else     // Bitmap is stored top-to-bottom
            pos = bmpImageoffset + row * rowSize;
          if(bmpFile.position() != pos) { // Need seek?
            tft.endWrite();
            bmpFile.seek(pos);
            buffidx = sizeof(sdbuffer); // Force buffer reload
          }

          for (col=0; col<w; col++) { // For each pixel...
            // Time to read more pixel data?
            if (buffidx >= sizeof(sdbuffer)) { // Indeed
              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0; // Set index to beginning
              tft.startWrite();
            }

            // Convert pixel from BMP to TFT format, push to display
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            tft.pushColor(tft.color565(r,g,b));
          } // end pixel
        } // end scanline
        tft.endWrite();
        Serial.print("Loaded in ");
        Serial.print(millis() - startTime);
        Serial.println(" ms");
      } // end goodBmp
    }
  }

  bmpFile.close();
  if(!goodBmp) Serial.println("BMP format not recognized.");
}

// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.

uint16_t read16(File f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

uint32_t read32(File f) {
  uint32_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read();
  ((uint8_t *)&result)[2] = f.read();
  ((uint8_t *)&result)[3] = f.read(); // MSB
  return result;
}


nanoRP2040_ST7735_SD_ImageReader.ino, a simplified version to display bitmaps using Adafruit_ImageReader, make sure it's installed.
// Adafruit_ImageReader test for Adafruit ST7735 TFT Breakout for Arduino.
// Demonstrates loading images from SD card or flash memory to the screen,
// to RAM, and how to query image file dimensions.
// Requires three BMP files in root directory of SD card:
// test.bmp, test2.bmp and test3.bmp.
// As written, this uses the microcontroller's SPI interface for the screen
// (not 'bitbang') and must be wired to specific pins.

#include <Adafruit_GFX.h>         // Core graphics library
#include <Adafruit_ST7735.h>      // Hardware-specific library
#include <SdFat.h>                // SD card & FAT filesystem library
#include <Adafruit_ImageReader.h> // Image-reading functions

// TFT display and SD card share the hardware SPI interface, using
// 'select' pins for each to identify the active device on the bus.

#define SD_CS    4 // SD card select pin
#define TFT_CS  10 // TFT select pin
#define TFT_DC   8 // TFT display/command pin
#define TFT_RST  9 // Or set to -1 and connect to Arduino RESET pin

SdFat                SD;         // SD card filesystem
Adafruit_ImageReader reader(SD); // Image-reader object, pass in SD filesys

Adafruit_ST7735      tft    = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
Adafruit_Image       img;        // An image loaded into RAM
int32_t              width  = 0, // BMP image dimensions
                     height = 0;

void setup(void) {

  ImageReturnCode stat; // Status from image-reading functions

  Serial.begin(115200);

  tft.initR(INITR_BLACKTAB); // Initialize screen

  // The Adafruit_ImageReader constructor call (above, before setup())
  // accepts an uninitialized SdFat or FatFileSystem object. This MUST
  // BE INITIALIZED before using any of the image reader functions!
  Serial.print(F("Initializing filesystem..."));

  // SD card is pretty straightforward, a single call...
  if(!SD.begin(SD_CS, SD_SCK_MHZ(10))) { // Breakouts require 10 MHz limit due ...
    Serial.println(F("SD begin() failed"));
    for(;;); // Fatal error, do not continue
  }

  Serial.println(F("OK!"));

  // Fill screen blue. Not a required step, this just shows that we're
  // successfully communicating with the screen.
  tft.fillScreen(ST7735_BLUE);

  // Load full-screen BMP file 'test.bmp' at position (0,0) (top left).
  // Notice the 'reader' object performs this, with 'tft' as an argument.
  Serial.print(F("Loading test.bmp to screen..."));
  stat = reader.drawBMP("/test.bmp", tft, 0, 0);
  reader.printStatus(stat);   // How'd we do?

  // Query the dimensions of image 'test2.bmp' WITHOUT loading to screen:
  Serial.print(F("Querying test2.bmp image size..."));
  stat = reader.bmpDimensions("/test2.bmp", &width, &height);
  reader.printStatus(stat);   // How'd we do?
  if(stat == IMAGE_SUCCESS) { // If it worked, print image size...
    Serial.print(F("Image dimensions: "));
    Serial.print(width);
    Serial.write('x');
    Serial.println(height);
  }

  // Load small BMP 'test3.bmp' into a GFX canvas in RAM.
  Serial.print(F("Loading test3.bmp to canvas..."));
  stat = reader.loadBMP("/test3.bmp", img);
  reader.printStatus(stat); // How'd we do?

  delay(2000); // Pause 2 seconds before moving on to loop()
}

void loop() {

  for(int r=0; r<4; r++) { // For each of 4 rotations...
    tft.setRotation(r);    // Set rotation
    tft.fillScreen(0);     // and clear screen

    reader.drawBMP("/test2.bmp", tft, 0, 0);

    delay(1000); // Pause 1 sec.

    img.draw(tft,                                    // Pass in tft object
        0 ,  // Horiz pos.
        0); // Vert pos

    delay(2000); // Pause 2 sec.
  }

}

Related:


Thursday, June 24, 2021

Arduino Nano RP2040 Connect + ILI9341 SPI TFT, using adafruit_ILI9341 library.

To drive ILI9341 SPI TFT on Arduino Nano RP2040 Connect (Arduino framework), Adafruit_ILI9341 library can be used.

Install Library:

In Arduino IDE, open Library Manager, search and install Adafruit ILI9341, Adafruit GFX library is needed also.


You will be asked to install extra libraries needed, click Install All.

Connection:

Connection:
ILI9341 TFT	Nano RP2040 Connect
-------------------------------
VCC		3V3
GND		GND
CS		D10
RESET		RESET
DC		D9
SDI(MOSI)	D11 (SPI0 TX)
SCK		D13 (SPI0 SCK)
LED		3V3
SDA(MISO)	D12 (SPI0 RX)
After then, you can try Adafruit_ILI9341 example graphicstest.

~ More exercise of Arduino Nano RP2040 Connect.

Wednesday, June 23, 2021

BLE Communication between Nano RP2040 Connect (Peripheral) and ESP32 (Central), in Arduino framework.

Exercise of BLE Communication between Nano RP2040 Connect (Peripheral) and ESP32 (Central), in Arduino framework.

nanoRP2040_BLE_Peripheral_20210623a.ino run on Arduino Nano RP2040 Connect, act as BLE Peripheral (server), wait to be connected.

/*
 * Arduino nano RP2040 Connect exercise:
 * as BLE Peripheral 
 * 
 * reference:
 * ArduinoBLE library-
 * https://www.arduino.cc/en/Reference/ArduinoBLE
 * 
 * In my implementation:
 * BLEByteCharacteristic written event checked by polling.
 * BLEStringCharacteristic/BLEIntCharacteristic using event haandler.
 * 
 */
 #include <ArduinoBLE.h>

/*  Visit Online GUID / UUID Generator
 *  (https://www.guidgenerator.com/)
 *  to generate your uuid
 */
const char* serviceUUID =    "20a07a95-8c12-484c-94fa-b828c4465a3c";
const char* byteCharUUID =   "d34dda3b-7b4a-4ce3-9666-a8338db4e604";
const char* stringCharUUID = "41281b9c-8dc4-4649-8cbe-c39fa01513e2";
const char* intCharUUID =    "c7d27dc6-f4d8-4523-b060-3e2e4c187808";

const char* myLocalName = "MyBLE";
 
BLEService myBLEService(serviceUUID);
BLEByteCharacteristic myBLEByteCharacteristic(byteCharUUID, 
                              BLERead|BLEWrite);
BLEStringCharacteristic myBLEStringCharacteristic(stringCharUUID, 
                              BLERead|BLEWrite|BLENotify, 24);  //max length = 10
BLEIntCharacteristic myBLEIntCharacteristic(intCharUUID,
                              BLERead|BLEWrite);


void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  Serial.begin(115200);
  delay(100);
  digitalWrite(LED_BUILTIN, HIGH);

  //Started, connect Serial to begin
  while(!Serial);
  Serial.println("\n---Start ---");
  digitalWrite(LED_BUILTIN, LOW);

  Serial.println("Initialize BLE...");
  if(!BLE.begin()){
    Serial.println("Starting BLE failed!");
    while(1);
  }
  Serial.println("BLE initialized.");
  Serial.print("MAC: ");
  Serial.println(BLE.address());
  Serial.println("Service UUIID: \t\t\t" + String(serviceUUID));
  Serial.println("Byte Characteristic UUIID: \t" + String(byteCharUUID));
  Serial.println("String Characteristic UUIID: \t" + String(stringCharUUID));
  Serial.println("Int Characteristic UUIID: \t" + String(intCharUUID));
  
  Serial.println();

  BLE.setLocalName(myLocalName);
  BLE.setAdvertisedService(myBLEService);
  myBLEService.addCharacteristic(myBLEByteCharacteristic);
  myBLEService.addCharacteristic(myBLEStringCharacteristic);
  myBLEService.addCharacteristic(myBLEIntCharacteristic);
  BLE.addService(myBLEService);

  myBLEStringCharacteristic.setEventHandler(BLEWritten, myBLEString_Written_Hndl);
  myBLEIntCharacteristic.setEventHandler(BLEWritten, myBLEInt_Written_Hndl);

  BLE.advertise();

}

void loop() {
  BLEDevice central = BLE.central();

  if(central){
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.print("Connected: ");
    Serial.println(central.address());

    while(central.connected()){

      if(myBLEByteCharacteristic.written()){
        byte valByte = myBLEByteCharacteristic.value();
        Serial.print("myBLEByteCharacteristic received: ");
        Serial.println(valByte, HEX);
      }
    }

    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("Disconnected.");
  }
}

// Event Handler for myBLEStringCharacteristic Written
// Print received Sring, and write back in upper case.
void myBLEString_Written_Hndl(BLEDevice central, BLECharacteristic characteristic) {
  Serial.print("BLEStringCharacteristic event, written: ");

  Serial.println("myBLEStringCharacteristic received: len=" + 
                  String(myBLEStringCharacteristic.valueLength()));
  String valString = myBLEStringCharacteristic.value();
  Serial.println(valString);
  valString.toUpperCase();
  Serial.println(valString);
  myBLEStringCharacteristic.setValue(valString);
}

// Event Handler for myBLEIntCharacteristic Written
void myBLEInt_Written_Hndl(BLEDevice central, BLECharacteristic characteristic) {
  Serial.print("BLEIntCharacteristic event, written: ");
  
  int valInt = myBLEIntCharacteristic.value();
  Serial.println(valInt);
  
}


ESP32_BLE_Central_20210623a.ino run on ESP32 Dev. Board, act as Central (client), scan and connect to Peripheral, and send something.
/*
 * ESP32 BLE exercise, as Central (Client)
 * connect to nanoRP2040 BLE Peripheral
 * 
 */

 #include "BLEDevice.h"

const String targetName = "MyBLE";

// The remote service/characteristic we wish to connect to.
// UUID(s) have to match with Peripheral side.
const char* serviceUUID =    "20a07a95-8c12-484c-94fa-b828c4465a3c";
const char* byteCharUUID =   "d34dda3b-7b4a-4ce3-9666-a8338db4e604";
const char* stringCharUUID = "41281b9c-8dc4-4649-8cbe-c39fa01513e2";
const char* intCharUUID =    "c7d27dc6-f4d8-4523-b060-3e2e4c187808";

static BLEUUID BLEUUID_service(serviceUUID);
static BLEUUID BLEUUID_byteChar(byteCharUUID);
static BLEUUID BLEUUID_stringChar(stringCharUUID);
static BLEUUID BLEUUID_intChar(intCharUUID);

static BLERemoteCharacteristic* pRemoteChar_byte;
static BLERemoteCharacteristic* pRemoteChar_string;
static BLERemoteCharacteristic* pRemoteChar_int;

static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;

static BLEAdvertisedDevice* myDevice;

int notifyDur;

static void notifyCallback(
  BLERemoteCharacteristic* pBLERemoteCharacteristic,
  uint8_t* pData,
  size_t length,
  bool isNotify) {
    Serial.println("pRemoteChar_string notify callback -");
    Serial.println(pBLERemoteCharacteristic->getUUID().toString().c_str());
    Serial.print(" of data length ");
    Serial.println(length);
    Serial.print("data: ");
    Serial.println((char*)pData);
}

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
  }

  void onDisconnect(BLEClient* pclient) {
    connected = false;
    Serial.println("onDisconnect");
  }
};

bool connectToServer() {
    Serial.print("Forming a connection to ");
    Serial.println(myDevice->getAddress().toString().c_str());
    
    BLEClient*  pClient  = BLEDevice::createClient();
    Serial.println(" - Created client");

    pClient->setClientCallbacks(new MyClientCallback());

    // Connect to the remove BLE Server.
    pClient->connect(myDevice);
    Serial.println(" - Connected to server");

    // Obtain a reference to the service we are after in the remote BLE server.
    BLERemoteService* pRemoteService = pClient->getService(BLEUUID_service);
    if (pRemoteService == nullptr) {
      Serial.print("Failed to find our service UUID: ");
      Serial.println(BLEUUID_service.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found our service");


    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pRemoteChar_byte = pRemoteService->getCharacteristic(BLEUUID_byteChar);
    pRemoteChar_string = pRemoteService->getCharacteristic(BLEUUID_stringChar);
    pRemoteChar_int = pRemoteService->getCharacteristic(BLEUUID_intChar);

    //assume all characteristics found, skip checking
    /*
    if (pRemoteChar_string == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(BLEUUID_stringChar.toString().c_str());
      pClient->disconnect();
      return false;
    }
    */
    Serial.println(" - Found our characteristic");

    // Read the value of the characteristic.
    if(pRemoteChar_string->canRead()) {
      std::string value = pRemoteChar_string->readValue();
      Serial.print("The characteristic value was: ");
      Serial.println(value.c_str());
    }

    if(pRemoteChar_string->canNotify()){
      Serial.println("pRemoteChar_string CAN Notify");
      pRemoteChar_string->registerForNotify(notifyCallback);
    }else{
      Serial.println("pRemoteChar_string CANNOT Notify");
    }

    connected = true;
    return true;
}

/**
 * Scan for BLE servers and find the first one matched advertises service
 */
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
 /**
   * Called for each advertising BLE server.
   */
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    //Serial.print("BLE Advertised Device found: ");
    //Serial.println(advertisedDevice.toString().c_str());
    String devName = advertisedDevice.getName().c_str();
    //Serial.println(devName);

    if(devName == targetName){
      Serial.println("Target found-");
      // We have found a device,
      // let us now see if it contains the service we are looking for.
      Serial.println(advertisedDevice.getServiceUUID().toString().c_str());
      
      if (advertisedDevice.haveServiceUUID() && 
            advertisedDevice.isAdvertisingService(BLEUUID_service)) {
        Serial.println("BLEUUID_service match -");
        BLEDevice::getScan()->stop();
        myDevice = new BLEAdvertisedDevice(advertisedDevice);
        doConnect = true;
        doScan = true;
      } // Found our server
    }
  } // onResult
}; // MyAdvertisedDeviceCallbacks



void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("\n--- ESP32 Start ---");

  BLEDevice::init("");

  // Retrieve a Scanner and set the callback we want to use to be informed when we
  // have detected a new device.  Specify that we want active scanning and start the
  // scan to run for 5 seconds.
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setInterval(1349);
  pBLEScan->setWindow(449);
  pBLEScan->setActiveScan(true);
  pBLEScan->start(5, false);
}

// This is the Arduino main loop function.
void loop() {

  // If the flag "doConnect" is true then we have scanned for and found the desired
  // BLE Server with which we wish to connect.  Now we connect to it.  Once we are 
  // connected we set the connected flag to be true.
  if (doConnect == true) {
    if (connectToServer()) {
      Serial.println("We are now connected to the BLE Server.");
    } else {
      Serial.println("We have failed to connect to the server; there is nothin more we will do.");
    }
    doConnect = false;
  }

  // If we are connected to a peer BLE Server, update the characteristic each time we are reached
  // with the current time since boot.
  if (connected) {
    notifyDur = millis();
    String newValue = "time since boot: " + String(notifyDur/1000);
    
    // Set the characteristic's value to be the array of bytes that is actually a string.
    pRemoteChar_string->writeValue(newValue.c_str(), newValue.length());
    pRemoteChar_int->writeValue(notifyDur, true);
  }else if(doScan){
    BLEDevice::getScan()->start(0);
  }
  
  delay(1000); // Delay a second between loops.
} // End of loop




~ More exercise of Arduino Nano RP2040 Connect.

Monday, June 21, 2021

ArduinoBLE exercise on Nano RP2040 Connect: BLE Peripheral

ArduinoBLE exercise run on Nano RP2040 Connect, act as BLE Peripheral. Tested with nRF Connect app on Android.


nanoRP2040_BLE_Peripheral_20210622a.ino
/*
 * Arduino nano RP2040 Connect exercise:
 * as BLE Peripheral 
 * 
 * reference:
 * ArduinoBLE library-
 * https://www.arduino.cc/en/Reference/ArduinoBLE
 * 
 * In my implementation:
 * BLEByteCharacteristic written event checked by polling.
 * BLEStringCharacteristic/BLEIntCharacteristic using event haandler.
 * 
 */
 #include <ArduinoBLE.h>

/*  Visit Online GUID / UUID Generator
 *  (https://www.guidgenerator.com/)
 *  to generate your uuid
 */
const char* serviceUUID =    "20a07a95-8c12-484c-94fa-b828c4465a3c";
const char* byteCharUUID =   "d34dda3b-7b4a-4ce3-9666-a8338db4e604";
const char* stringCharUUID = "41281b9c-8dc4-4649-8cbe-c39fa01513e2";
const char* intCharUUID =    "c7d27dc6-f4d8-4523-b060-3e2e4c187808";

const char* myLocalName = "MyBLE";
 
BLEService myBLEService(serviceUUID);
BLEByteCharacteristic myBLEByteCharacteristic(byteCharUUID, 
                              BLERead|BLEWrite);
BLEStringCharacteristic myBLEStringCharacteristic(stringCharUUID, 
                              BLERead|BLEWrite, 10);  //max length = 10
BLEIntCharacteristic myBLEIntCharacteristic(intCharUUID,
                              BLERead|BLEWrite);


void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  Serial.begin(115200);
  delay(100);
  digitalWrite(LED_BUILTIN, HIGH);

  //Started, connect Serial to begin
  while(!Serial);
  Serial.println("\n---Start ---");
  digitalWrite(LED_BUILTIN, LOW);

  Serial.println("Initialize BLE...");
  if(!BLE.begin()){
    Serial.println("Starting BLE failed!");
    while(1);
  }
  Serial.println("BLE initialized.");
  Serial.print("MAC: ");
  Serial.println(BLE.address());
  Serial.println("Service UUIID: \t\t\t" + String(serviceUUID));
  Serial.println("Byte Characteristic UUIID: \t" + String(byteCharUUID));
  Serial.println("String Characteristic UUIID: \t" + String(stringCharUUID));
  Serial.println("Int Characteristic UUIID: \t" + String(intCharUUID));
  
  Serial.println();

  BLE.setLocalName(myLocalName);
  BLE.setAdvertisedService(myBLEService);
  myBLEService.addCharacteristic(myBLEByteCharacteristic);
  myBLEService.addCharacteristic(myBLEStringCharacteristic);
  myBLEService.addCharacteristic(myBLEIntCharacteristic);
  BLE.addService(myBLEService);

  myBLEStringCharacteristic.setEventHandler(BLEWritten, myBLEString_Written_Hndl);
  myBLEIntCharacteristic.setEventHandler(BLEWritten, myBLEInt_Written_Hndl);

  BLE.advertise();

}

void loop() {
  BLEDevice central = BLE.central();

  if(central){
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.print("Connected: ");
    Serial.println(central.address());

    while(central.connected()){

      if(myBLEByteCharacteristic.written()){
        byte valByte = myBLEByteCharacteristic.value();
        Serial.print("myBLEByteCharacteristic received: ");
        Serial.println(valByte, HEX);
      }
    }

    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("Disconnected.");
  }
}

// Event Handler for myBLEStringCharacteristic Written
// Print received Sring, and write back in upper case.
void myBLEString_Written_Hndl(BLEDevice central, BLECharacteristic characteristic) {
  Serial.print("BLEStringCharacteristic event, written: ");

  Serial.println("myBLEStringCharacteristic received: len=" + 
                  String(myBLEStringCharacteristic.valueLength()));
  String valString = myBLEStringCharacteristic.value();
  Serial.println(valString);
  valString.toUpperCase();
  Serial.println(valString);
  myBLEStringCharacteristic.setValue(valString);
}

// Event Handler for myBLEIntCharacteristic Written
void myBLEInt_Written_Hndl(BLEDevice central, BLECharacteristic characteristic) {
  Serial.print("BLEIntCharacteristic event, written: ");
  
  int valInt = myBLEIntCharacteristic.value();
  Serial.println(valInt);
  
}



~ More exercises for Arduino Nano RP2040 Connect

Sunday, June 13, 2021

Raspberry Pi/Python BLE Central + Arduino Nano RP2040 Connect BLE Peripheral

This exercise implement Python 3 code run on Raspberry Pi act as BLE Central, connect to Arduino Nano RP2040 Connect act as BLE Peripheral. And send data (0x01/0x00) to turn the Nano RP2040 Connect's onboard LED ON/OFF.


Arduino Nano RP2040 Connect act as BLE Peripheral side:

- Make sure ArduinoBLE library is installed.

- The Arduino code is modified from ArduinoBLE Examples > Peripheral > CallbackLED. With MAC, Service UUID, Characteristic UUID, and BLE written data displayed. Such that we can program Central side accordingly.

nanoRP2040_BLE_CallbackLED.ino
/*
  Callback LED

  This example creates a BLE peripheral with service that contains a
  characteristic to control an LED. The callback features of the
  library are used.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.

  You can use a generic BLE central app, like LightBlue (iOS and Android) or
  nRF Connect (Android), to interact with the services and characteristics
  created in this sketch.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // create service

// create switch characteristic and allow remote device to read and write
BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);

const int ledPin = LED_BUILTIN; // pin to use for the LED

void setup() {
  Serial.begin(9600);
  while (!Serial);
  delay(1000);
  Serial.println("\n--- Start---");
  
  pinMode(ledPin, OUTPUT); // use the LED pin as an output

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  Serial.print("My BLE MAC:\t\t ");
  Serial.println(BLE.address());
  Serial.print("Service UUID:\t\t ");
  Serial.println(ledService.uuid());
  Serial.print("Characteristic UUID:\t ");
  Serial.println(switchCharacteristic.uuid());
  Serial.println();

  // set the local name peripheral advertises
  BLE.setLocalName("LEDCallback");
  // set the UUID for the service this peripheral advertises
  BLE.setAdvertisedService(ledService);

  // add the characteristic to the service
  ledService.addCharacteristic(switchCharacteristic);

  // add service
  BLE.addService(ledService);

  // assign event handlers for connected, disconnected to peripheral
  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);

  // assign event handlers for characteristic
  switchCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten);
  // set an initial value for the characteristic
  switchCharacteristic.setValue(0);

  // start advertising
  BLE.advertise();

  Serial.println(("Bluetooth device active, waiting for connections..."));
}

void loop() {
  // poll for BLE events
  BLE.poll();
}

void blePeripheralConnectHandler(BLEDevice central) {
  // central connected event handler
  Serial.print("Connected event, central: ");
  Serial.println(central.address());
}

void blePeripheralDisconnectHandler(BLEDevice central) {
  // central disconnected event handler
  Serial.print("Disconnected event, central: ");
  Serial.println(central.address());
}

void switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
  // central wrote new value to characteristic, update LED
  Serial.println("Characteristic event, written: ");

  byte charValue = switchCharacteristic.value();
  Serial.println(charValue);

  if (charValue) {
    Serial.println("LED on");
    digitalWrite(ledPin, HIGH);
  } else {
    Serial.println("LED off");
    digitalWrite(ledPin, LOW);
  }
}

Raspberry Pi/Python BLE Central Side:
- bluepy library is used to control Bluetooth BLE.

To install bluepy for Python3, enter the command:
$ sudo pip3 install bluepy

- tkinter is used for GUI.

py_BLE_Central_LedControl.py connect to Peripheral with matched MAC, and search for service/characteristic with match UUID. Then send 0x01/0x00 to turn ON/OFF the Nano RP2040 Connect's onboard LED.

"""
Python/Raspberry Pi BluetoothLE exercise:
using bluepy library

Work with Arduino Nano RP2040 Connect example:
ArduinoBLE > Peripheral > CallbackLED

Connect to Peripheral with matched MAC.
Check for service uuid and characteristic uuid,
if matched found: send bytes 0x01 and 0x00 for three time
to turn Nano RP2040 Connect onboard LED ON/OFF.
"""

from bluepy import btle
import time

#Have to match with Peripheral
MAC = "84:cc:a8:2e:8d:76"
SERVICE_UUID = "19b10000-e8f2-537e-4f6c-d104768a1214"
CHARACTERISTIC_UUID = "19b10001-e8f2-537e-4f6c-d104768a1214"

nanoRP2040_Char = None

print("Hello")

print("Connect to:" + MAC)
dev = btle.Peripheral(MAC)
print("\n--- dev ----------------------------")
print(type(dev))
print(dev)

print("\n--- dev.services -------------------")
for svc in dev.services:
    print(str(svc))
    
print("\n------------------------------------")
print("Get Serice By UUID: " + SERVICE_UUID)
service_uuid = btle.UUID(SERVICE_UUID)
service = dev.getServiceByUUID(service_uuid)

print(service)
print("\n--- service.getCharacteristics() ---")
print(type(service.getCharacteristics()))
print(service.getCharacteristics())

#----------------------------------------------
characteristics = dev.getCharacteristics()
print("\n--- dev.getCharacteristics() -------")
print(type(characteristics))
print(characteristics)
    
for char in characteristics:
    print("----------")
    print(type(char))
    print(char)
    print(char.uuid)
    if(char.uuid == CHARACTERISTIC_UUID ):
        print("=== !CHARACTERISTIC_UUID matched! ==")
        nanoRP2040_Char = char
        print(char)
        print(dir(char))
        #print(char.getDescriptors)
        #print(char.propNames)
        #print(char.properties)
        #print(type(char.read()))
        print(char.read())
        
bytes_ON = b'\x01'
bytes_OFF = b'\x00'

if nanoRP2040_Char != None:
    print("\nnanoRP2040_Char found")
    print(nanoRP2040_Char)
    for i in range(3):
        nanoRP2040_Char.write(bytes_ON, True)
        print(nanoRP2040_Char.read())
        time.sleep(1.0)
        nanoRP2040_Char.write(bytes_OFF, True)
        print(nanoRP2040_Char.read())
        time.sleep(1.0)
else:
    print("\nnanoRP2040_Char NOT found!")
#=============================================
dev.disconnect()
print("\n--- bye ---\n")
pyTk_BLE_Central_LedControl.py implement GUI with tkinter, user click on button to turn ON/OFF LED.
"""
Python/Raspberry Pi BluetoothLE exercise:
using bluepy library

Work with Arduino Nano RP2040 Connect example:
ArduinoBLE > Peripheral > CallbackLED

Connect to Peripheral with matched MAC.
Check for service uuid and characteristic uuid,
if matched found:
    Start GUI to control Nano RP2040 Connect onboard LED
"""

from bluepy import btle
import time
import tkinter as tk

#Have to match with Peripheral
MAC = "84:cc:a8:2e:8d:76"
SERVICE_UUID = "19b10000-e8f2-537e-4f6c-d104768a1214"
CHARACTERISTIC_UUID = "19b10001-e8f2-537e-4f6c-d104768a1214"

nanoRP2040_Char = None

def toggle():
    if toggle_btn.config('relief')[-1] == 'sunken':
        toggle_btn.config(relief="raised")
        nanoRP2040_Char.write(bytes_OFF, True)
        toggle_btn['text'] = 'Turn LED ON'
    else:
        toggle_btn.config(relief="sunken")
        nanoRP2040_Char.write(bytes_ON, True)
        toggle_btn['text'] = 'Turn LED OFF'

print("Hello")

print("Connect to:" + MAC)
dev = btle.Peripheral(MAC)
print("\n--- dev ----------------------------")
print(type(dev))
print(dev)

print("\n--- dev.services -------------------")
for svc in dev.services:
    print(str(svc))
    
print("\n------------------------------------")
print("Get Serice By UUID: " + SERVICE_UUID)
service_uuid = btle.UUID(SERVICE_UUID)
service = dev.getServiceByUUID(service_uuid)

print(service)
print("\n--- service.getCharacteristics() ---")
print(type(service.getCharacteristics()))
print(service.getCharacteristics())

#----------------------------------------------
characteristics = dev.getCharacteristics()
print("\n--- dev.getCharacteristics() -------")
print(type(characteristics))
print(characteristics)
    
for char in characteristics:
    print("----------")
    print(type(char))
    print(char)
    print(char.uuid)
    if(char.uuid == CHARACTERISTIC_UUID ):
        print("=== !CHARACTERISTIC_UUID matched! ==")
        nanoRP2040_Char = char
        print(char)
        print(dir(char))
        #print(char.getDescriptors)
        #print(char.propNames)
        #print(char.properties)
        #print(type(char.read()))
        print(char.read())
        
bytes_ON = b'\x01'
bytes_OFF = b'\x00'

if nanoRP2040_Char != None:
    print("\nnanoRP2040_Char found")
    print(nanoRP2040_Char)
    
    root = tk.Tk()
    label = tk.Label( root, text="Toggle button to Turn ON/OFF the nano RP040 Connect LED")
    label.pack(pady=10)
    toggle_btn = tk.Button(text="Turn LED ON", width=12, relief="raised", command=toggle)

    toggle_btn.pack(pady=10)
    root.geometry("500x200")

    #Place tkinter window center
    root.eval('tk::PlaceWindow %s center' % root.winfo_pathname(root.winfo_id()))
    root.title("arduino-er.blogspot.com")
    root.mainloop()
else:
    print("\nnanoRP2040_Char NOT found!")
#=============================================
dev.disconnect()
print("\n--- bye ---\n")


~ More exercises of Arduino Nano RP2040 Connect.

Friday, June 11, 2021

Arduino Nano RP2040 Connect exercise: control onboard RGB LED

The Nano RP2040 Connect onboard RGB LED is connected through the W-102 module, so the WiFiNINA library needs to be installed and included in sketch.

Exercise to control onboard RGB LED.

#include <WiFiNINA.h>

void setup() {

  delay(2000);

  Serial.begin(9600);
  Serial.println(LEDR);
  Serial.println(LEDG);
  Serial.println(LEDB);
  
  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);

  digitalWrite(LEDR, HIGH); //RED
  digitalWrite(LEDG, HIGH); //GREEN
  digitalWrite(LEDB, HIGH); //BLUE

}

void loop() {
  delay(1000);
  digitalWrite(LEDR, LOW); //RED
  digitalWrite(LEDG, LOW); //GREEN
  digitalWrite(LEDB, LOW); //BLUE

  delay(1000);
  digitalWrite(LEDR, HIGH); //RED
  digitalWrite(LEDG, LOW); //GREEN
  digitalWrite(LEDB, LOW); //BLUE


  delay(1000);
  digitalWrite(LEDR, LOW); //RED
  digitalWrite(LEDG, HIGH); //GREEN
  digitalWrite(LEDB, LOW); //BLUE

  delay(1000);
  digitalWrite(LEDR, LOW); //RED
  digitalWrite(LEDG, LOW); //GREEN
  digitalWrite(LEDB, HIGH); //BLUE
}


update@20211-06-28:

After WiFiNINA library updated, the code Serial.println(LEDR) (also LEDG and LEDB) throw error of :

error: call to 'NinaPin::operator int' declared with attribute error: Change me to a #define Serial.println(LEDR);

Just comment the codes to make it work.

Thursday, June 10, 2021

Arduino Nano RP2040 Connect example: read onboard LSM6DSOX IMU module (accelerometer and gyroscope)

Examples to read Nano RP2040 Connect onboard LSM6DSOX IMU module (accelerometer and gyroscope), in Arduino framework.

Install LSM6DSOX library:

- Open Library Manager in Arduino IDE:
Click on Menu Sketch > Include Library > Manager Libraries...

- Search and install Arduino_LSM6DSOX library.


LSM6DSOX examples:

Now you can try LSM6DSOX examples to read accelerometer and gyroscope data from Nano RP2040 Connect onboard LSM6DSOX IMU module.


with graphical view using Menu > Tools > Serial Plotter.

SimpleAccelerometer

SimpleGyroscope




Saturday, October 12, 2013

Getting Started with Arduino

A casual video give an overview about how they work, what you can do with them, and how the varying models differ from each other. No scary programming involved!



Read our practical starter guide from Tested to the most popular Arduino kits here: http://www.tested.com/tech/robots/456466-know-your-arduino-guide-most-common-boards/

Friday, July 12, 2013

Exploring Arduino: Tools and Techniques for Engineering Wizardry

Exploring Arduino: Tools and Techniques for Engineering Wizardry
Exploring Arduino: Tools and Techniques for Engineering Wizardry
Learn to easily build gadgets, gizmos, robots, and more using Arduino

Written by Arduino expert Jeremy Blum, this unique book uses the popular Arduino microcontroller platform as an instrument to teach you about topics in electrical engineering, programming, and human-computer interaction. Whether you're a budding hobbyist or an engineer, you'll benefit from the perfectly paced lessons that walk you through useful, artistic, and educational exercises that gradually get more advanced. In addition to specific projects, the book shares best practices in programming and design that you can apply to your own projects. Code snippets and schematics will serve as a useful reference for future projects even after you've mastered all the topics in the book.
  • Includes a number of projects that utilize different capabilities of the Arduino, while interfacing with external hardware
  • Features chapters that build upon each other, tying in concepts from previous chapters to illustrate new ones
  • Includes aspects that are accompanied by video tutorials and other multimedia content 
  • Covers electrical engineering and programming concepts, interfacing with the world through analog and digital sensors, communicating with a computer and other devices, and internet connectivity
  • Explains how to combine smaller topics into more complex projects
  • Shares downloadable materials and source code for everything covered in the book
Exploring Arduino takes you on an adventure and provides you with exclusive access to materials not found anywhere else!






Tuesday, June 25, 2013

Communication between Arduino and PC running Java, with JavaFX UI

Last posts "Setup RxTx for Arduino and Java example" and "Create Java project using librxtx-java in Netbeans, work with Arduino" describe basic setup to program Java with RxTx library in Netbeans, to receive data from Arduino Due. In this post, I will show bi-direction communication between Arduino Due and PC running Java, with JavaFX user interface.

Communication between Arduino and PC running Java, with JavaFX UI
Communication between Arduino and PC running Java, with JavaFX UI
User enter message in JavaFX and click the button, the message will be sent to Arduino via Serial. In Arduino side, it loop back the message to PC. Then, if received in PC side, it will be displayed in JavaFX.



It's a very simple code in Arduino side:
void setup() {
  Serial.begin(9600);
}

void loop() {
  if(Serial.available() > 0){
    Serial.print((char)Serial.read());
  }
}


In PC side, it's modified from last post, implement in JavaFX, with bi-direction communication.
package javafx_arduinotestserial;

import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 * @web arduino-er.blogspot.com
 */
public class JavaFX_ArduinoTestSerial extends Application {

    MyRxTx myRxTx;
    Label textInfo, textIn;

    @Override
    public void start(Stage primaryStage) {

        final TextField textOut = new TextField();
        textOut.setText("Hello Arduino-er!");

        textInfo = new Label();
        textIn = new Label();

        Button btn = new Button();
        btn.setText("Say 'Hello World'");
        btn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                String stringOut = textOut.getText() + "\r\n";

                try {
                    myRxTx.output.write(stringOut.getBytes());
                } catch (IOException ex) {
                    Logger.getLogger(
                            JavaFX_ArduinoTestSerial.class.getName())
                            .log(Level.SEVERE, null, ex);
                }
            }
        });

        VBox panel = new VBox(10);
        panel.setPadding(new Insets(10, 10, 10, 10));
        panel.getChildren().addAll(textInfo, textOut, btn, textIn);

        StackPane root = new StackPane();
        root.getChildren().add(panel);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();

        myRxTx = new MyRxTx();
        myRxTx.initialize();
    }

    public static void main(String[] args) {
        launch(args);
    }

    class MyRxTx implements SerialPortEventListener {

        SerialPort serialPort;
        /**
         * The port we're normally going to use.
         */
        private final String PORT_NAMES[] = {
            "/dev/ttyACM0", //for Ubuntu
            "/dev/tty.usbserial-A9007UX1", // Mac OS X
            "/dev/ttyUSB0", // Linux
            "COM3", // Windows
        };
        private BufferedReader input;
        private OutputStream output;
        private static final int TIME_OUT = 2000;
        private static final int DATA_RATE = 9600;

        public void initialize() {
            CommPortIdentifier portId = null;
            Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();

            //First, Find an instance of serial port as set in PORT_NAMES.
            while (portEnum.hasMoreElements()) {
                CommPortIdentifier currPortId =
                        (CommPortIdentifier) portEnum.nextElement();
                for (String portName : PORT_NAMES) {
                    if (currPortId.getName().equals(portName)) {
                        portId = currPortId;
                        break;
                    }
                }
            }
            if (portId == null) {
                System.out.println("Could not find COM port.");
                return;
            } else {
                textInfo.setText("Port Name: " + portId.getName() + "\n"
                        + "Current Owner: " + portId.getCurrentOwner() + "\n"
                        + "Port Type: " + portId.getPortType());
            }

            try {
                // open serial port, and use class name for the appName.
                serialPort = (SerialPort) portId.open(this.getClass().getName(),
                        TIME_OUT);

                // set port parameters
                serialPort.setSerialPortParams(DATA_RATE,
                        SerialPort.DATABITS_8,
                        SerialPort.STOPBITS_1,
                        SerialPort.PARITY_NONE);

                // open the streams
                input = new BufferedReader(
                        new InputStreamReader(serialPort.getInputStream()));
                output = serialPort.getOutputStream();

                // add event listeners
                serialPort.addEventListener(this);
                serialPort.notifyOnDataAvailable(true);
            } catch (Exception e) {
                System.err.println(e.toString());
            }
        }

        @Override
        public void serialEvent(SerialPortEvent spe) {
            if (spe.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
                try {
                    final String inputLine = input.readLine();

                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            textIn.setText(inputLine);
                        }
                    });

                    System.out.println(inputLine);
                } catch (Exception e) {
                    System.err.println(e.toString());
                }
            }
        }

        /**
         * This should be called when you stop using the port. This will prevent
         * port locking on platforms like Linux.
         */
        public synchronized void close() {
            if (serialPort != null) {
                serialPort.removeEventListener();
                serialPort.close();
            }
        }
    }
}

Sunday, June 23, 2013

Create Java project using librxtx-java in Netbeans, work with Arduino

remark: This example work on Ubuntu.

Before create our Java project using librxtx-java, we have to setup something in our PC, refer to lastr post "Setup RxTx for Arduino and Java example".

Create Netbeans Java Project:

- Start Netbeans, Click File -> New Project..., to create a project of Java Application in Java categories.


- with Project Name of SerialTest


Modify the code:

Basically, it's same as the example code in Arduino Playground of Arduino and Java, except the package, and PORT_NAMES of "/dev/ttyACM0".

package serialtest;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import gnu.io.CommPortIdentifier; 
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent; 
import gnu.io.SerialPortEventListener; 
import java.util.Enumeration;


public class SerialTest implements SerialPortEventListener {
 SerialPort serialPort;
        /** The port we're normally going to use. */
 private static final String PORT_NAMES[] = { 
                        "/dev/ttyACM0", //for Ubuntu
   "/dev/tty.usbserial-A9007UX1", // Mac OS X
   "/dev/ttyUSB0", // Linux
   "COM3", // Windows
 };
 /**
 * A BufferedReader which will be fed by a InputStreamReader 
 * converting the bytes into characters 
 * making the displayed results codepage independent
 */
 private BufferedReader input;
 /** The output stream to the port */
 private OutputStream output;
 /** Milliseconds to block while waiting for port open */
 private static final int TIME_OUT = 2000;
 /** Default bits per second for COM port. */
 private static final int DATA_RATE = 9600;

 public void initialize() {
  CommPortIdentifier portId = null;
  Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();

  //First, Find an instance of serial port as set in PORT_NAMES.
  while (portEnum.hasMoreElements()) {
   CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();
   for (String portName : PORT_NAMES) {
    if (currPortId.getName().equals(portName)) {
     portId = currPortId;
     break;
    }
   }
  }
  if (portId == null) {
   System.out.println("Could not find COM port.");
   return;
  }

  try {
   // open serial port, and use class name for the appName.
   serialPort = (SerialPort) portId.open(this.getClass().getName(),
     TIME_OUT);

   // set port parameters
   serialPort.setSerialPortParams(DATA_RATE,
     SerialPort.DATABITS_8,
     SerialPort.STOPBITS_1,
     SerialPort.PARITY_NONE);

   // open the streams
   input = new BufferedReader(new InputStreamReader(serialPort.getInputStream()));
   output = serialPort.getOutputStream();

   // add event listeners
   serialPort.addEventListener(this);
   serialPort.notifyOnDataAvailable(true);
  } catch (Exception e) {
   System.err.println(e.toString());
  }
 }

 /**
  * This should be called when you stop using the port.
  * This will prevent port locking on platforms like Linux.
  */
 public synchronized void close() {
  if (serialPort != null) {
   serialPort.removeEventListener();
   serialPort.close();
  }
 }

 /**
  * Handle an event on the serial port. Read the data and print it.
  */
 public synchronized void serialEvent(SerialPortEvent oEvent) {
  if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
   try {
    String inputLine=input.readLine();
    System.out.println(inputLine);
   } catch (Exception e) {
    System.err.println(e.toString());
   }
  }
  // Ignore all the other eventTypes, but you should consider the other ones.
 }

 public static void main(String[] args) throws Exception {
  SerialTest main = new SerialTest();
  main.initialize();
  Thread t=new Thread() {
   public void run() {
    //the following line will keep this app alive for 1000 seconds,
    //waiting for events to occur and responding to them (printing incoming messages to console).
    try {Thread.sleep(1000000);} catch (InterruptedException ie) {}
   }
  };
  t.start();
  System.out.println("Started");
 }
}

In order to access Serial port in Ubuntu, you have to setup the right of the port. Refer to the post Fixed the problem of "No device found on COM1" for /dev/ttyACM0. You have to enter the following command before run the code:

$sudo chmod a+rw /dev/ttyACM0

If everything OK, you can run the program as shown below, the message "Hello world" will be printed every second in Output windows.



Next:
- Communication between Arduino and PC running Java, with JavaFX UI