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:

No comments:

Post a Comment