text:
HC-12 modules stopped receiving, cannot understand why
I've created a simple transmitter with an HC-12 and an Arduino Nano (clone), where I send the values of DHT11 and LM35 sensors to a receiver unit made only of a Wemos D1 and another HC-12.
Setup is really simple and worked fine for a couple of days (transmitter in the cellar 2 floors down, receiver in my living room, it was POSTing data to my own server correctly), then I unplugged the receiver and modified the transmitter to add a JSON library; when I plugged them back again the receiver is not getting anything anymore.
Transmitter seems to be working fine, at least it prints the number of bytes written in the Serial Monitor.
I tried:

reverting back to the working version (no JSON), but still the same
tested each of the HC12 modules with a simple test code and AT commands, they all responds and are all set to factory configuration, like it was before actually (AT+DEFAULT)
made another receiver with an Arduino Uno and a lcd screen - a setup that I was successfully using before changing to the Wemos. Strangely, now this setup doesn't work too...
Switched the modules and what I got? The transmitter still transmits, the receiver doesn't receive, nothing changed.

Tried sending a simple string "Test", still no results.

Relevant code:
Transmitter:
#include <ArduinoJson.h>
#include <DHT_U.h>            // just Adafruit Library
#include <DHT.h>
#include <SoftwareSerial.h>
#define DHTTYPE DHT11   // DHT 11
SoftwareSerial HC12(10, 11); // HC-12 TX Pin, HC-12 RX Pin
int DHTPIN = 4;
int LMPIN = 5;
DHT dht(DHTPIN, DHTTYPE);
StaticJsonDocument<80> doc;

void setup() {
  analogReference(INTERNAL);
  Serial.begin(9600);             // Serial port to computer
  HC12.begin(9600);               // Serial port to HC12
  dht.begin();
}

void loop() {
  delay(5000);
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  int reading = analogRead(LMPIN);
  float lmt = reading/9.31;
  doc["dht_h"] = h;
  doc["dht_t"] = t;
  doc["ds_t"] = lmt;
  char result[50];
  serializeJson(doc, result);
  Serial.println(result);
  int written = HC12.print(result);
  Serial.println(written);    // it's 39 chars
}

Receiver (all wifi sections are removed):
#include <ESP8266WiFi.h>
#include <SoftwareSerial.h>
#define STASSID "....."
#define STAPSK  "....."
SoftwareSerial HC12(D13, D15); // HC-12 TX Pin, HC-12 RX Pin

const char* ssid     = STASSID;
const char* password = STAPSK;
const char* host = "...........";
const uint16_t port = 3000;

void setup() {
  Serial.begin(9600);
  HC12.begin(9600);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500); Serial.print(".");
  }
}

void loop() {

  String content = HC12.readString();
  Serial.println(content);
  if(content.length()) {
    // This will send a string to the server
    Serial.println("sending data to server");
    if (client.connected()) {
      //....
    }
  }
  delay(1000);
}

I'm pretty stumped by the fact that it stopped working, and that both the HC-12 modules seem to be working fine (at least they respond to all the AT commands).
I even tried purging arduino from the system and reinstalling (I now have the very latest IDE release) but nothing....
Am I missing something obvious? (I've a weak electronic background, I'm a web developer by trade).
Is there a way to check if data is actually sent?
How can I debug these modules?

why not just run the DHT11 and LM35 from the ESP and save the debug effort? You should also use the server.on handlers instead of the painfully low-level client.connected stuff.

@dandavis Because there's no wifi connection where I put the sensors (it's floor -1th, I live at 2nd), and also I plan to add other devices to the receiver. But please don't focus on the ESP, the issue seems to be another

Did you check that your receiver connects to the WiFi?

@gbg Forget the WIFI (anyway, yes, it does), I cannot receive anymore with the HC-12 (it worked before)

For what it's worth, I manage to make them working again by playing a bit with the settings of both modules.
Using a simple test sketch I issued some AT commands to both modules; I had already tried setting them to the DEFAULT setup with AT+DEFAULT, but that was fruitless. I decided to left the mode as is (FU3), same for the serial rate (B9600), but I tried switching channel so I set both modules with AT+C002.
That did the trick, maybe was some sort of external interference, or a lack of precision in the channel settings - I just know that's a week now they've been communicating just fine and that's what matters.
So, if they fail to communicate, first try to adjust their settings, don't assume the DEFAULT ones are surely working.

For long range, better using FU4 , even if it's sloooooow.


text:
Running a robot with 2 front-facing sensors, but it's stuttering
Here's the run down: I have a small robot with four continuous servo motors and two ultrasonic sensors. It's run by and UNO board with a Sensor Shield V5 on top.
My goal is to program the front right and front left sensors to both be returning distances in inches, and have the robot turn in the direction with the most room when one of the sensors returns a distance less than some minimum.
I am very confident that the motors and sensors aren't the issue, as testing them by themselves shows no issues. However, when I run the below code the robot stutters, mainly just going backwards but stuttering forwards and occasionally turning for a second or two. Any ideas what's going on?
#include <Servo.h>

Servo FL;
Servo FR;
Servo BL;
Servo BR;

const int FRecho = 11;
const int FRtrig = 10;
const int FLecho = 9;
const int FLtrig = 8;

long durationFL;
long durationFR;
int distanceInchR = 24;
int distanceCmR;
int distanceInchL = 24;
int distanceCmL;

const int minDistanceInch = 18;
const int minDistanceCm;

enum movementStates {
 STILL,
 FORWARD,
 BACK,
 TURNFR,
 TURNFL,
 NOTHING
};

enum movementStates movement;

void setup() {

  FL.attach(4);
  FR.attach(5);
  BL.attach(6);
  BR.attach(7);

  pinMode(FRtrig, OUTPUT);
  pinMode(FRecho, INPUT);
 pinMode(FLtrig, OUTPUT);
  pinMode(FLecho, INPUT);

  movement = NOTHING;

  forward();

}

void loop() {

updateDistanceFL();
updateDistanceFR();

updateDirection();

}

void forward () {
  FL.write(180);
  FR.write(0);
  BL.write(180);
  BR.write(0);
  movement = FORWARD;
}

void turnFR () {
  FL.write(180);
  FR.write(180);
  BL.write(180);
  BR.write(180);
  movement = TURNFR;
}

void turnFL () {
  FL.write(0);
  FR.write(0);
  BL.write(0);
  BR.write(0);
  movement = TURNFL;
}

void backUp () {
  FL.write(0);
  FR.write(180);
  BL.write(0);
  BR.write(180);
  movement = BACK;
}

void still () {
  FL.write(90);
  FR.write(90);
  BL.write(90);
  BR.write(90);
  movement = STILL;
}

void updateDirection() {

  if (distanceInchR < minDistanceInch && distanceInchL < minDistanceInch) {
    if (movement != BACK) {
      backUp();
    }
    else if (distanceInchR < minDistanceInch) {
     if (movement != TURNFL) {
      turnFL();
     }
    }
    else if (distanceInchL < minDistanceInch) {
     if (movement != TURNFR) {
      turnFR();
     }
    }
    else if (distanceInchR > minDistanceInch && distanceInchL > minDistanceInch)
    if (movement != FORWARD) {
      forward();
    }
  }
    else {
      if (movement != STILL) {
        still();
      }
    }
}

void updateDistanceFR(){
digitalWrite(FRtrig, LOW);
delayMicroseconds(2);
digitalWrite(FRtrig, HIGH);
delayMicroseconds(10);
digitalWrite(FRtrig, LOW);
durationFR = pulseIn(FRecho, HIGH);
distanceCmR= durationFR*0.034/2;
distanceInchR = durationFR*0.0133/2;
  }

void updateDistanceFL(){
digitalWrite(FLtrig, LOW);
delayMicroseconds(2);
digitalWrite(FLtrig, HIGH);
delayMicroseconds(10);
digitalWrite(FLtrig, LOW);
durationFL = pulseIn(FLecho, HIGH);
distanceCmL= durationFL*0.034/2;
distanceInchL = durationFL*0.0133/2;
  }

the updateDirection() function contains a bunch of redundant logic tests ... it may not be doing what you expect it to do

Add a delay() in your loop(), your code is too busy checking and update the direction constantly without the time for the motor to move in any direction. Add a status variable to hold the current direction status, if the direction remain the same, there is no need to run updateDirection() again and again.

your updateDirection logic doesn't quite work the way you think it does.
after a bit of code formatting and comments it looks like this:
void updateDirection() {

    if (distanceInchR < minDistanceInch && distanceInchL < minDistanceInch) {
        if (movement != BACK) {
            backUp();
        } else if (distanceInchR < minDistanceInch) {
            //always entered if movement == BACK
            if (movement != TURNFL) {
                turnFL();
            }
        } else if (distanceInchL < minDistanceInch) {
            //never entered
            if (movement != TURNFR) {
                turnFR();
            }
        } else if (distanceInchR > minDistanceInch && distanceInchL > minDistanceInch)
            //never entered
            if (movement != FORWARD) {
                forward();
            }
        //endif distanceInchR < minDistanceInch && distanceInchL < minDistanceInch
    } else {
        // entered when distanceInchR > minDistanceInch || distanceInchL > minDistanceInch
        if (movement != STILL) {
            still();
        }
    }
}

it looks like you had a missing closing brace around the first condition. Causing the only movement functions that get called to be backUp, turnFL and still.
If we add the missing braces then it looks much better:
void updateDirection() {

    if (distanceInchR < minDistanceInch && distanceInchL < minDistanceInch) {
        if (movement != BACK) {
            backUp();
        }
    } else if (distanceInchR < minDistanceInch) {
        if (movement != TURNFL) {
            turnFL();
        }
    } else if (distanceInchL < minDistanceInch) {
        if (movement != TURNFR) {
            turnFR();
        }
    } else if (distanceInchR > minDistanceInch && distanceInchL > minDistanceInch) {
        if (movement != FORWARD) {
            forward();
        }
    } else {
        if (movement != STILL) {
            still();
        }
    }
}

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Components required to control the Speed of Wilo Para AC Synchronous Motor
I want to control the speed of the AC motor based on the temperature set on the Nextion  HMI. Right now I have my ESP32 Microcontroller and Solid-state relays which supply the maximum output power of 10 amperes. My Wilo Motor requires the power of 0.03 to 0.66Amps. I am in a state of confusion about what component is required in the middle to connect my ESP32 Controller to send the analog PWM control signals of 0 to 10V to my Wilo Para Motor for the speed control. I searched in Google and I got few data like H-Bridge, PWM Speed control manual module. I'm stuck in this work and I'm looking for help.
Below I have attached the link of the datasheet. On page number 34 is my WILO Para Motor and the model name is Wilo Para 25-180/9-87/IPWM1 in the table
https://wilo.cdn.mediamid.com/cdndoc/wilo164576/1544113/wilo164576.pdf
Thanks in Advance.

What's a Wilo Motor? Links to datasheets please.

@Majenko As far from my knowledge Wilo is a smart AC Synchronous Motor. https://wilo.cdn.mediamid.com/cdndoc/wilo164576/1544113/wilo164576.pdf

This is the link of the datasheet and on page number 34 is my WILO Para Motor and the model name is Wilo Para 25-180/9-87/IPWM1 in the table

Pretty useless datasheet that. It doesn't contain any real information. I hate when companies do that. But one thing I did glean: the phrase used in the datasheet is "0-10V or PWM". The PWM is probably a TTL compatible input, so LOW is 0V and HIGH is >2V. The 0-10V is something completely different.

@Majenko Yes this was the datasheet I  got from the WILO heat pump website. Now I need a component to send the control signal from ESP32 to the Motor.

If it is just a TTL input then you don't need a "component" - the ESP32 can just drive it direct.

@Majenko But I don't think it is TTL input. I just want to send the analog PWM input signal based on the temperature set on the Nextion HMI. For example, If I am setting the room temperature as 25 degrees in Nextion HMI then the control signal should be passed to Motor to run at a particular speed to pump the water to the heater to obtain a room temperature set point.

There is no such thing as an "analog PWM" signal. PWM is digital, not analog.

@AbhishekhAaron, where did you get the current draw specification of 3 A to 87 A ?

@jsotola I am sorry guys the maximum output power required is 0.66 Ampere

You do not want a "0-10V PWM signal". There is no such thing.
There are generally 2 methods of controlling motors like these:

Through a variable analog voltage between 0V and 10V, where the voltage given is proportional to the speed, and
Using a digital PWM signal where the duty cycle is proportional to the speed.

You are getting confused and combining the two together (and to be honest that datasheet, which is really little more than a sales brochure, doesn't help matters).
Typically a PWM input on a motor uses a standard TTL signalling method.  This specific motor, as detailed in this document uses a slight modification on the standard. It requires a minimum of 3.6V for a HIGH, and the ESP32 gives 3.3V maximum.
Because of that you will need to amplify, or "boost" the signal to a slightly higher voltage.  The simplest way to do that is with an off-the-shelf logic level translator (3.3V to 5V). There are cheap MOSFET based ones on eBay etc that will do the job.
If you want to create your own the circuit is quite simple, and requires one N-channel MOSFET and two resistors. I use the BSS138:

simulate this circuit – Schematic created using CircuitLab

I will try and I will let you know.

Sorry, but you are wrong. Wilo explains about their iPWM signal in doc. Lowest voltage is 3.6 volt, not 2, it's greather, than ESP32 VCC.

@gbg Can you reference a page number? I scoured that document looking for that information but it's such a terrible document I failed.

https://2-improve.com/wp-content/uploads/2016/02/Datasheet-Yonos-PARA-ST-7-0-iPWM2_August-2015.pdf
page 6
See my answer

No wonder I couldn't find the info - that's a completely different document.

@gbg Thanks for that info. I have updated my answer accordingly.

@AbhishekhAaron Note: important update in my answer now new information has come to light.

@Majenko I saw it and thanks for your help.

Page 6 of this doc explains, what is iPWM and its electrical characteristics.

So, you need some low-power PNP transistor and the resistor (about 5-10k).

Thanks for the information

Lowest voltage for iPWM is 3.6 volt, so, you need the voltage amplifier.

Yes, the lowest voltage for iPWM required is 3.6 Volt. But the problem is I am not getting the exact information of my motor model Wilo Para 25-180/9-87/IPWM1

You don't need this. Wilo refers to its standard, the iPWM. So, any Wilo device, that use iPWM, will use the same electrical characteristics for it.

Thank you so much

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
4x4 keypad stops reacting
I am having an issue with the a 4×4 keypad. It usually works fine but sometimes the keypad stops reacting or no key is pressed but it still shows a random keypress on the LCD. The only solution is to unplug and plug again. I thought it may be the length of the wires for the keypad. I uses 3 ft wires from the keypad to the Arduino. Has anyone faced similar issues?

3' is not that long really, but the internal pullups of the Arduino are quite weak, and you are in what looks like a noisy (electrically speaking) environment. So maybe it is EMI causing things to happen that you don't want to happen. Consider making the keypad a standalone system with a balanced communication system between that and the main box.

The keypad and the LCD need to be connected to the arduino. I can power 5V to the LCD from a separate source, but the keypad has to be connected to the arduino.

What I am suggesting is have an Arduino (one of the small ones?) connected directly to the keypad (very short wires then), and use a serial protocol (rs232, rs485, etc) to connect that Arduino to the existing Arduino.

Try to test with Arduino, keypad, and LCD only to make sure that other components do not affect them. You can refer to Arduino - Keypad - LCD tutorial


text:
Neopixel code not working on Adafruit Feather board
I have connected a single neopixel to my Adafruit Feather board, running Arduino software.
The power pin is connected to 3V on the Feather. The data-in pin is connected to pin 15 on the Feather.
As soon as power is connected, the light shows blue. But uploading any program has no effect whatsoever. The Neopixel won't respond to anything.
How can I use a Neopixel on the Adafruit Feather?
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif

#define PIN 15
#define NUMPIXELS 1

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

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

void loop() {
  Serial.println("RED");
  pixels.setPixelColor(PIN, pixels.Color(255, 0, 0));
  pixels.show();
  delay(1000);
  Serial.println("GREEN");
  pixels.setPixelColor(PIN, pixels.Color(0, 255, 0));
  pixels.show();
  delay(1000);
}

The neopixel and the Feather board

I think, 3V is not enough for the Neopixels. Can you try providing them with 5V?

Hm, that might be it. I assumed 3V would be good since the Circuit Express Playground uses 3V and has 10 neopixels! But maybe these bigger ones need more power ??? https://www.adafruit.com/product/1734

Adafruit states, that the 3.7V from a LiPo battery is just enough for a few Neopixels

Pin 15 is the serial RX pin which connects to the USB port so you should not use it.  From the Feather pinouts page about pins 15,16 : "These are connected through to the CP2104 USB-to-Serial converter so they should not be connected to or used unless you're super sure you want to because you will also be getting the USB traffic on these!"
So try another pin and it should work.


text:
arduino and esp-1 stop workign after 1 day running
i'm trying to create a system that arduino and esp-1 send an GET request each 2 secs to a server and depend on server reply turns a LED on or off . system works good for 6-7 hours but stops after one day . actually i  checked server logs after one day and i realized no request is sending to serve .
my hardware :
Arduino Uno
ESP-1
LED or Relay
and my arduino codes : ( in know my host is not working now . i turned it off )
#include <ArduinoJson.h>
#include <WiFiEsp.h>
#include <WiFiEspClient.h>
#include <SoftwareSerial.h>

SoftwareSerial Serial1(10,11);

char ssid[] = "AZaz";            // your network SSID (name)
char pass[] = "Az8833394";        // your network password
int status = WL_IDLE_STATUS;     // the Wifi radio's status
int Relay = 13;

char server[] = "azimi.ir";
unsigned long lastConnectionTime = 0;         // last time you connected to the server, in milliseconds
const unsigned long postingInterval = 1000L; // delay between updates, in milliseconds
WiFiEspClient client;

void setup() {
  // put your setup code here, to run once:

  pinMode(Relay, OUTPUT);
  Serial.begin(115200);
  Serial1.begin(9600);
  WiFi.init(&Serial1);
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println(F("WiFi shield not present"));
    // don't continue
    while (true);
  }

  while ( status != WL_CONNECTED) {
    Serial.print(F("Attempting to connect to WPA SSID: "));
    Serial.println(ssid);
    // Connect to WPA/WPA2 network
    status = WiFi.begin(ssid, pass);
  }

  Serial.println(F("You're connected to the network"));
//  printWifiStatus();
}

void loop() {
  while (client.available()) {
  char c = client.read();
  char endOfHeaders[] = "\r\n\r\n";
  if (!client.find(endOfHeaders)) {
    Serial.println(F("Invalid response"));
    return;
  }
  const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 80;
  DynamicJsonDocument doc(capacity);
  DeserializationError error = deserializeJson(doc, client);
  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.c_str());
    return;
  }
      int count = doc["counts"];
      if(count == 1){
        int relay = doc["message"];
        int cmd = doc["val"];
        digitalWrite(relay , cmd);
      }

  }
  if (millis() - lastConnectionTime > postingInterval) {
    httpRequest();

  }
}

void httpRequest()
{

  Serial.println();

  // close any connection before send a new request
  // this will free the socket on the WiFi shield
  client.stop();

  // if there's a successful connection
  if (client.connect(server, 80)) {
    client.println(F("GET /check/ HTTP/1.1"));
    client.println(F("Host: azimi.ir"));
    client.println("Connection: close");
    client.println();

    // note the time that the connection was made
    lastConnectionTime = millis();
  }
  else {
    // if you couldn't make a connection
    Serial.println(F("Connection failed"));
  }
}

now i have some questions :
1- why system stops working after more hours ? what is the problem ? my codes or my hardware ?
2- if problem is my hardware , what kind of wifi module or arduino you think will work ?
3- i want this project to make someone else's home . it will be a long term project so i want my system works for one or two years at least . is arduino suitable for this kind of projects ?! if its not , what hardware is ?

use StaticJsonDocument. DynamicJsonDocument fragments the small memory of Uno until ot is not able to allocate new space. https://arduinojson.org/v6/api/dynamicjsondocument/

I tried it before , no thing changed !

your way of reading the response is not very reliable. you have while (client.available()) but the code in the while block expects to be run once. you should stop() the client after reading the response, not before sending a new request.

i see , but iam trying to do everything like this tutorial :
https://www.arduino.cc/en/Tutorial/WiFiWebClientRepeating
like this :
https://github.com/bportaluri/WiFiEsp/blob/master/examples/WebClientRepeating/WebClientRepeating.ino


text:
Is it possible to program Arduino in transpiled JavaScript?
Coming from JS, I find it very difficult to program Arduino in C++ (not even knowing which version or what features are supported), being bound to the loop and delay, not being able to (easily) use anonymous functions in parameters or async code.
I know JS isn't natively supported by Arduino, but I know languages can be transpiled.
I have seen many solutions, so just to pick few:
JohnnyFive J5, which runs via cable on a host PC,
NectarJS with their arduino-uno target,
or andrei-markeev/ts2c which converts ES3 to C89.
Each of them come with their own limitations and it's very difficult to find the right without prior experience with IoT. Did anyone walk this path already and found a viable solution?

Forgive me if this question is inappropriate for this site. This is my first Q here and I am totally new to IoT. However, outright downwoting, without providing a feedback isn't really constructive and welcoming to new members.

I suggest you look at the boards and components that are supported by these frameworks before you commit to any one. Maybe start here, http://johnny-five.io/api and see if the supported components will cover what you are trying to achieve.

my recommendation is, learn C++

Just dive in and learn C++ while you go. You could also try learning Python so you can program your Teensy in Circuitpython or Micropython (although I now see it might not be easy to get it going on the Teensy).

Even if such a transpiler exists (which I don‘t know) you will still have to deal with the loop structure and the fact that you should avoid using delays. On a microcontroller you have to forget about things like multithreading and even dynamic memory allocation should be used carefully.
Most of those things that make a programmer‘s life easy on bigger systems are usually paid with ram or cpu power, but on a microcontroller with some kB RAM there are only few resources to pay with.
So my recommendation is to learn C++ instead of looking for ways to convert code from another language, which will probably introduce its own problems. You‘ll soon find yourself one layer below and there are exciting things that higher languages hide from you.

Is it possible that some of the C++ constructs are valid, but not working specifically on IoT devices? (In my case the Teensy LC or 3.2.)

With JavaScript, you don't use delay(), nor multithreading: you do non blocking programming, in a single thread running an event loop. That's exactly the approach you would use in C++ on a microcontroller.

Why don't you just start with a microcontroller that supports Javascript?
I find the Adafruit Circuit Playground Express quite fun to work with. You can still connect sensors and other hardware, the same as you can do with Arduino. It also has a bunch of sensors built-in.
You can try it out right now without owning a hardware board at adafruit.makecode.com. Click the Javascript tab on the top of the page.
Using a JS>Arduino transpiler will probably cause a lot of headache, since it often won't do what you expect it to do.

I bought the Teensy specifically because it's best for HID. I want to repurpose an old keyboard, but if I were to do something larger, I would probably choose a board that supports node.js and JavaScript.

There aren't any boards that support node.js sadly. You can run Johnny Five with almost every board, but that runs on your PC. It allows you to read the board through the USB cable.

I had to put the project away for a while, but now that I think of that... The keyboard must be connected to the PC anyway, so I can as well run nodejs to control it. Johny Five may be the best solution for hacking after all. After the PoC works, I may rewrite it in C++.

andrei-markeev/ts2c JavaScript/TypeScript to C transpiler looks promising.
I'll probably give it a go tonight.
According to the github page:
Produces readable C89 code from JS/TS code.
For example, this JavaScript:
console.log("Hello world!");

transpiles to the following C code:
#include <stdio.h>

int main() {
    printf("Hello world!\n");
    return 0;
}

src: https://github.com/andrei-markeev/ts2c


text:
ESP8266-01 Resetting when DC motor runs
DC motor: 3-6v
Servo sg90: 3-7.2v
Esp 8266 01: 3.3v

I have 2 Arduino Uno both has their own ac-dc power adapter.
Lets say, 1st Arduino is Ard1 and 2nd is Ard2.
The Ard1 communicates to a web server (BLYNK) with Esp 01.
Using I2C, Ard1 sends command to Ard2 to power/move the DC motor/Servo.
So far, it has no problem operating with Servo. But,
Whenever the Ard1 commands the Ard2 to power the DC motor.
Right when the DC motor runs(using digitalWrite(motor,HIGH)) the Esp 01 resets.

Tried using analogWrite(motor, 102) though it won't reset instantly, prolong usage randomly resets it anytime.
I also tried to test operating Servo and DC motor simultaneously in Ard2 using Serial commands, without I2C/Esp01. There was no problem at all, both works flawlessly.

Below is the diagram of the wiring.

That‘s an electronic issue. You should post a circuit diagram or move this question to electronics SE

You should check the current rating for motor. It may be the case that your supply is not able to provide it.

How is the ESP-01 powered/?

I've just included a diagram for further understanding. Please pardon me, I have zero knowledge on electronics/electrical.

Despite the fact that you don‘t have pull-ups connected to the I2C lines your circuit looks fine. How do you know that the esp resets, what did you observe?

Using blynk app, as simple as on/off for any of the motor. Once I 'on' the DC motor and it runs, the connection between the esp and server will be cut. Which also means I can't 'off' the DC motor from the Blynk app unless the connection between the server and esp resumes/restarted. I suppose the problem would be the wiring of I2C/GND(ard1 - ard2), as It's the only way these two is linked.

The connection between the Arduinos probably has nothing to do with the esp resetting. From the information you provided I‘m not convinced that the esp really performs a reset, maybe the esp simply doesn’t send anything. Have you added the pull-ups?

Try removing the second arduino and uploading a program to the one connected to the motor that turns the motor on and off, to see if you still have the problem. Try powering the motor from a separate 5 v supply so it is only connected to the arduino by pin 3

Can you clear one thing that you are giving power to dc motor from 5v pin given on Arduino board or from your ac to dc power supply. If you are giving power to the motor from 5v pin of Arduino Uno then there is a high possibility that the motor is not getting sufficient current because 5v supply on Arduino comes from onboard lm1117 5v voltage regulator and cheap clon Arduino has a cheap regulator with less than 1amp capacity.

It was indeed. I then resorted to a 9v battery supply for dc however problem still exist but not that severe, it still cuts the connection. Finally, my latest solution was attaching a 10ko resistor between esp's ch_d to 3.3v of arduino and 1k between gnd and esp's rx and another 1k between esp's rx to arduino's. So far everything went well.

@Kolokoy what are These resistors supposed to do?! Note that a 9V battery is also a bad choose as I can‘t provide much current as well. You better use a proper PSU or e.g a Li-Ion battery

Someone I knew said rx/tx might uses a TTL logic level of 5v instead of 3.3v which the esp 01 can only take. I also found a tutorial on YouTube on the wiring of esp01 to arduino and followed it. The battery was just to test if problem would still exist when the dc motor has different power supply, I will not use it in the final outcome.


text:
7-Segment Display with WS2312B and FastLED
I thought of the idea of using the WS2312B LED strip to drive a custom 7-Segment display. The project will require a large number of these displays, and driving them with a single Arduino (I'm thinking of an Arduino MEGA). For driving the LEDs I am using the FastLED library.

I wrote some code that drives a single display, It works, but I think It's possible to make it simpler, the code I wrote stores the digits in arrays, and uses these arrays in functions customized to each digit. here is an example:
//Digit Arrays:
byte digit0[]     = {0,1,2,3,4,5};
byte digit1[]     = {1,2};
byte digit2[]     = {0,1,3,4,6};
byte digit3[]     = {0,1,2,3,6};
byte digit4[]     = {1,2,5,6};
byte digit5[]     = {0,2,3,5,6};
byte digit6[]     = {0,2,3,4,5,6};
byte digit7[]     = {0,1,2};
byte digit8[]     = {0,1,2,3,4,5,6};
byte digit9[]     = {0,1,2,3,5,6};

The functions are something like this:
void AllOff(){
//Switch off All the LEDs in the segment. Should be off for 1 second
  for(int i=0; i<7; i++){
    leds[i] = CRGB::Black;
    FastLED.show();
  }
  //delay(1000);
}
void AllOn(CRGB myColor){
  //Switch on All the LEDs in the segment (should display 8)
  //The color of choice is #1E78A0
  for(int i=0; i<7; i++){
    leds[i] = CRGB (30,120,160);
    FastLED.show();
  }
  delay(1000);
}
void Print0(CRGB myColor){
  //Prints the digit 0:
  AllOff();
  ArraySize = sizeof(digit0);     //get the size of the array
  for(int i=0; i<ArraySize; i++){
    LED_Number  = digit0[i];      //get the LED number from the array
    leds[LED_Number]    = CRGB (myColor);  //Switch the LED on
    FastLED.show();
  }
}

When I call it in the code, I simply do something like this:
Print0(CRGB::Purple);
delay(500);

I have tried for the best part of the past two days to find a better way to go about this, but I couldn't. What I'm thinking is perhaps to create a function that would store all the digits instead of storing every one as an array, and then call it maybe within a for loop? something like
for(int i=0; i<10; i++){
    displaydigit[i];
    FastLED.show();
  }

Do you know of any library that has something similar, or perhaps any idea on how to achieve this?
Your assistance, as always, is greatly appreciated.
Thank You.

First, for all the digits I'd use an 7 value array, indicating for every segment if it's ON or OFF. So for 0 your get byte digit0[] = {1,1,1,1,1,1,0}, where 1 indicates the segment is ON, and 0 indicates it's OFF. Your code then becomes:
void Print0(CRGB myColor){
  //Prints the digit 0:
  for(int i=0; i<7; i++){
    if( digit0[i] )
      leds[i] = CRGB (myColor);  //Switch the LED on
    else
      leds[i] = CRGB::Black; // Switch the LED off
  }
  FastLED.show();
}

The next step would be to create a two dimensional array containing which segments are on for which digits.
byte digits[10][7] = {
     {1,1,1,1,1,1,0} //0
    ,{0,1,1,0,0,0,0} //1
    ,{1,1,0,1,1,0,1} //2
    ,{1,1,1,1,0,0,1} //3
    ,{0,1,1,0,0,1,1} //4
    ,{1,0,1,1,0,1,1} //5
    ,{1,0,1,1,1,1,1} //6
    ,{1,1,1,0,0,0,0} //7
    ,{1,1,1,1,1,1,1} //8
    ,{1,1,1,1,0,1,1} //9
   }

Now you can generalize you Print0 function to accept any number:
void PrintNumber(byte number, CRGB myColor){
  if( number>9 )
    return;
  for(int i=0; i<7; i++){
    if( digit[number][i] )
      leds[i] = CRGB (myColor);  //Switch the LED on
    else
      leds[i] = CRGB::Black; // Switch the LED off
  }
  FastLED.show();
}

Call the new function in your loop; for example PrintNumber(3, CRGB:White);
If you want to put multiple 7-segment displays in series, you could add and offset argument to the PrintNumber function, and use leds[i+offset] instead. Then call the PrintNumber with offset 0 for the first digit/display, 7 for the second, 14 for the third, and so on.

you could add two more rows to the digits array for all off and all on

@Gerben Thank You! I'm testing the code now. I'm thinking that I will do the displays in series for some segments and using different pins for other ones. The leds[i+offset] is something that I was looking for, so you have actually answered two questions with one post.

@Gerben Thank you! works like a charm, and it's a lot prettier than the code I wrote. I will accept your answer!

@jsotola That's actually a good idea. Implemented

@jsotola what's the difference between all on and the number 8 ? q-;

In general, in many engineering efforts, a definition of the feature(s) and constraints need to be considered.  The feature you are creating is a large-7-segment-display.  Now decide what constraints you are working under.  Normally, in embedded programming, this means limited memory, limited power and interacting with people.
Because of limited memory, consider storing 7-segment patterns in a condensed form.  Also consider creating the simplest code possible.  Usually the more data is compressed, the more complex the code needs to be.  If there is a large amount of data (for example, an mp3 compressed sound track) the cost of high compression and complex code can be justified.  But storing 7-segment patters is comparatively simple.  So, consider expanding the array to include all 7 segments for each of the 10 digits.  Store if each segment is on or off.  Then, remove the "all on" and "all off" loops in your code leaving only one loop to read the array and turn off or on each segment.
Adapting the project to facilitate interacting with people can be confusing and difficult.  Possibly the most common problem with displays are delays and flicker.  For this project choosing the WS* line of LEDs should mitigate flicker problems (at the very least it takes it out of your hands) as the PWM feature is the responsibility of each WS* chip. People have been putting up with (expect) small delays when viewing large displays.  And it is expected this approach could update perhaps 10 digits in less than hundreds of milliseconds.

You are absolutely right. Memory is one thing, and the ease of reading and debugging the code is another. SE is a wonderful platform because people get to share thoughts and solve problems together. Well structured problems, that is :)

Thanks @MDChaara.


text:
Can't create a RTC_DATA_ATTR var inside a class
I'm trying to create a deepSleep class for my ESP32 project, but I get this error : section attribute not allowed for 'clock_beforeSleep' The only place it compiles, is outside the class.
How should I declare it ?
EDIT1: Add Code
#include "EEPROM.h"
#include "time.h"
#include "WiFi.h"

RTC_DATA_ATTR long clock_expectedWake = 0;
RTC_DATA_ATTR int bootCounter = 0;
RTC_DATA_ATTR int driftRTC = 0;
RTC_DATA_ATTR long clock_beforeSleep = 0;

class esp32Sleep
{
#define EEPROM_SIZE 16
#define DEV_NAME "ESP32lite"
#define uS_TO_S_FACTOR 1000000ULL /* Conversion micro seconds to seconds */

private:
  char sleepstr[250];
  // RTC_DATA_ATTR long clock_expectedWake = 0;
.
.
.

a class member is only a declaration. it has a space in memory only if an object of that class is created. you could try static keyword. static members are common for all instances of that class

@Juraj but it is a TRV_DATA_ATTR which stores its value and retrieves after awakening.

I know and that is the reason why it can't be a class member. the linker puts it at address in RTC memory

@Juraj - see edit 1. can you please explain about "linker"

linker follows a linker script, which specifies what goes where in memory https://github.com/espressif/arduino-esp32/blob/1977370e6fc069e93ffd8818798fbfda27ae7d99/tools/sdk/ld/esp32.project.ld#L48

You can't put an RTC_DATA_ATTR qualified variable inside a class because the class is stored in normal RAM. The RTC_DATA_ATTR qualified variable is, by definition, stored in RTC RAM.
The definition of RTC_DATA_ATTR includes a section attribute (__attribute__((section(".rtc.data")))) that tells the compiler where abouts in memory the variable should be stored (in this case the 8kiB of "slow" RTC memory). That is mutually exclusive with where the compiler decides to store the class.
It's like you have a diamond necklace which the has to be kept in a safe at all times, but you want to wear it around your neck whilst at the same time storing it in the safe. You can't do it.

I think some explanation about the different allocation schemes could be
useful:

Global variables, as well as static locals and static class members,
are allocated at build time, by the linker, typically in the .data or
.bss section of the program.
Local variables are allocated at run time in the stack. Typically the
compiler issues some instructions to adjust the stack pointer in order
to make room for the variable. As an optimization, the most used
locals can be stored directly in CPU registers, but this optimization
is disabled if you use the address of the variable.
Variables created with new and malloc() are allocated at run time
in the heap. This allocation is handled by a support library.

Note that objects are variables and are allocated in one piece, just
like a C struct. Static class members are not part of the class
instances.
Now, some build chains have extensions that allow you to store
statically allocated variables elsewhere than the RAM. One example is
the PROGMEM storage on AVR. RTC_DATA_ATTR sounds like a similar
extension. You may be able to store a regular class member this way if:

The object is global and stored as RTC_DATA_ATTR as a whole.
It doesn't need a constructor.

Is there a workaround the make such class?


text:
Using millis() to create a timed sequence of events
I was hoping anyone could help me with my problem.
I am trying to play a sequence of tones without using delay. So I am relying on millis(). However I have not been successful yet and after reading multiple tutorials about using millis(), I could not find one that covers sequencies of events.
What I am trying to do is the following:

Play a tone1 for 1 s
After 1 second (duration which tone 1 is played) play tone 2
After 1 second (duration which tone 2 is played) play tone 3
After 1 second (duration which tone 3 is played) play tone 4

With the current code I have, everything seems to be played at the same time and not really considering my IF statements.
Code:

#include "pitches.h"

int notes[]={
NOTE_B1,
NOTE_C2,
NOTE_CS2,
NOTE_D2,
NOTE_DS2,
NOTE_E2,
NOTE_F2,
NOTE_FS2,
NOTE_G2,
NOTE_GS2,
NOTE_A2,
NOTE_AS2,
NOTE_B2,
NOTE_C3,
NOTE_CS3,
NOTE_D3,
NOTE_DS3,
NOTE_E3,
NOTE_F3,
NOTE_FS3,
NOTE_G3,
NOTE_GS3,
NOTE_A3,
NOTE_AS3,
NOTE_B3,
NOTE_C4,
NOTE_CS4,
NOTE_D4,
NOTE_DS4,
NOTE_E4,
NOTE_F4,
NOTE_FS4,
NOTE_G4,
NOTE_GS4,
NOTE_A4,
NOTE_AS4,
NOTE_B4,
NOTE_C5,
NOTE_CS5,
NOTE_D5,
NOTE_DS5,
NOTE_E5,
NOTE_F5,
NOTE_FS5,
NOTE_G5,
NOTE_GS5,
NOTE_A5,
NOTE_AS5,
NOTE_B5,
NOTE_C6,
NOTE_CS6,
NOTE_D6,
NOTE_DS6,
NOTE_E6,
NOTE_F6,
NOTE_FS6,
NOTE_G6,
NOTE_GS6,
NOTE_A6,
NOTE_AS6,
NOTE_B6,
NOTE_C7,
NOTE_CS7,
NOTE_D7,
NOTE_DS7,
NOTE_E7,
NOTE_F7,
NOTE_FS7,
NOTE_G7,
NOTE_GS7,
NOTE_A7,
NOTE_AS7,
NOTE_B7,
NOTE_C8,
NOTE_CS8,
NOTE_D8,
NOTE_DS8
};

int speakerPin = 3;

 #define N_BUTTONS 8

int button_pins[N_BUTTONS] = {6, 7, 8, 9, 10, 11, 12, 13}; // Putting button_pins into an array

int Pitches[N_BUTTONS] = {0}; // Define array to hold the pitch. Setting it to 0.

long Durations[N_BUTTONS]; // Define array to hold the duration of the note. Setting it to 500.

unsigned long startMillis;
unsigned long startMillis_2;
unsigned long startMillis_3;
unsigned long startMillis_4;
unsigned long currentMillis;
unsigned long period = 1000;

void setup() {

Serial.begin(9600);

for(int pin : button_pins) pinMode(pin, INPUT); // Define the input pins for button_pins

startMillis = millis();

}

void loop() {

for (int button=0; button<N_BUTTONS ; button++){
  if(digitalRead(button_pins[button])){
    Pitches[button] = analogRead(A0)/13;   // As we have 77 pitches we divide the max Potentiometer value by 77. This equals 13.
    Durations[button] = analogRead(A1)*4;
   }
  }
////////////////////OUTPUT CODE////////////////////Sound generation code /////////////////////////////////

unsigned long currentMillis = millis(); // Gets the current time

if (currentMillis - startMillis >= period)  // Start event after 1 second
  {
  tone(speakerPin, notes[Pitches[0]], period);
  Serial.print("pitch1= ");
  Serial.println(Pitches[0]);
  Serial.print("duration1= ");
  Serial.println(period);
  Serial.print("millis = ");
  Serial.println(currentMillis);
  startMillis_2 = currentMillis;   // Saves the current time into the variable
  Serial.print("startMillis_2 = ");
  Serial.println(startMillis_2);
  }

if (currentMillis - startMillis_2 >= period)
  {
  tone(speakerPin, notes[Pitches[1]], period);
  Serial.print("pitch2= ");
  Serial.println(Pitches[1]);
  Serial.print("duration2= ");
  Serial.println(period);
  startMillis_3 = currentMillis;
  Serial.print("millis = ");
  Serial.println(currentMillis);
  Serial.print("startMillis_3 = ");
  Serial.println(startMillis_3);
  }

if (currentMillis - startMillis_3>= period)
  {
  tone(speakerPin, notes[Pitches[2]], period);
  Serial.print("pitch3= ");
  Serial.println(Pitches[2]);
  Serial.print("duration3= ");
  Serial.println(period);
  startMillis_4 = currentMillis;
  Serial.print("millis = ");
  Serial.println(currentMillis);
  Serial.print("startMillis_4 = ");
  Serial.println(startMillis_4);
  }

unsigned long startMillis_4;

if (currentMillis - startMillis_4 >= period)
  {
  tone(speakerPin, notes[Pitches[3]], period);
  Serial.print("pitch4= ");
  Serial.println(Pitches[3]);
  Serial.print("duration4= ");
  Serial.println(period);
  startMillis = currentMillis;
  Serial.print("millis = ");
  Serial.println(currentMillis);
  Serial.print("startMillis = ");
  Serial.println(startMillis);
  }

}

I have managed to get my code running on delay. It is working but I am very limited on what I can accomplish if I want more.
I have read through all answers and comments but was still unable to get a millis() solution since my main problem was how to get tone 2 started and so on. I can get the first tone to play on a loop and correct intervals, but I am not understanding how to trigger the start of tone 2.
Here is my code with delay. If anyone has can guide me to use millis() specially to trigger the start the tone 2, it would be very helpful.
EDIT. New Code:
#include "pitches.h"

int notes[]={
0,
NOTE_B1,
NOTE_C2,
NOTE_CS2,
NOTE_D2,
NOTE_DS2,
NOTE_E2,
NOTE_F2,
NOTE_FS2,
NOTE_G2,
NOTE_GS2,
NOTE_A2,
NOTE_AS2,
NOTE_B2,
NOTE_C3,
NOTE_CS3,
NOTE_D3,
NOTE_DS3,
NOTE_E3,
NOTE_F3,
NOTE_FS3,
NOTE_G3,
NOTE_GS3,
NOTE_A3,
NOTE_AS3,
NOTE_B3,
NOTE_C4,
NOTE_CS4,
NOTE_D4,
NOTE_DS4,
NOTE_E4,
NOTE_F4,
NOTE_FS4,
NOTE_G4,
NOTE_GS4,
NOTE_A4,
NOTE_AS4,
NOTE_B4,
NOTE_C5,
NOTE_CS5,
NOTE_D5,
NOTE_DS5,
NOTE_E5,
NOTE_F5,
NOTE_FS5,
NOTE_G5,
NOTE_GS5,
NOTE_A5,
NOTE_AS5,
NOTE_B5,
NOTE_C6,
NOTE_CS6,
NOTE_D6,
NOTE_DS6,
NOTE_E6,
NOTE_F6,
NOTE_FS6,
NOTE_G6,
NOTE_GS6,
NOTE_A6,
NOTE_AS6,
NOTE_B6,
NOTE_C7,
NOTE_CS7,
NOTE_D7,
NOTE_DS7,
NOTE_E7,
NOTE_F7,
NOTE_FS7,
NOTE_G7,
NOTE_GS7,
NOTE_A7,
NOTE_AS7,
NOTE_B7,
NOTE_C8,
NOTE_CS8,
NOTE_D8,
NOTE_DS8
};

int speakerPin = 3;

#define N_BUTTONS 8

// Input variables definitions

int button_pins[N_BUTTONS] = {6, 7, 8, 9, 10, 11, 12, 13}; // Putting button_pins into an array

int Pitches[N_BUTTONS] = {0}; // Define array to hold the pitch. Setting it to 0.

long Durations[N_BUTTONS]; // Define array to hold the duration of the note. Setting it to 500.

void setup() {

Serial.begin(9600);

for(int pin : button_pins) pinMode(pin, INPUT); // Define the input pins for button_pins

}

void loop() {
int tempo = analogRead(A2);
for (int button=0; button<N_BUTTONS ; button++){
  if(digitalRead(button_pins[button])){
    Pitches[button] = analogRead(A0)/13;   // As we have 78 pitches we divide the max Potentiometer value by 77. This equals 13.
    Durations[button] = (analogRead(A1)*4) + tempo;
   }
  }
////////////////////OUTPUT CODE////////////////////Sound generation code /////////////////////////////////
  for (int button=0; button <N_BUTTONS ; button++){
  tone(speakerPin, notes[Pitches[button]], Durations[button]);
  delay(tempo);
  Serial.print("Pitch");
  Serial.print(button);
  Serial.print(" = ");
  Serial.println(Pitches[button]);
  Serial.print("Duration");
  Serial.print(button);
  Serial.print(" = ");
  Serial.println(Durations[button]);
  Serial.println(tempo);
  }
}

take a close look at the if statements

your description of sequence of events is convoluted ... it is simply Play a tone1 for 1 s,  Play a tone2 for 1 s, Play a tone3 for 1 s, Play a tone4 for 1 s

I am still very new at this. It would be easier to explain what I want like this: Play tone1 for 1s, after finishing playing start play tone 2 for 1s.... and so on. I still don't fully know how to use if statements.

the if statement is fairly simple ... look at the expression inside the brackets () ... if that expresdion is true, then execute the commands that are inside the curly braces {}

You are overcomplicating the program. There is no point in remembering
when each of the notes started. You just have to remember:

what note is currently playing
when you started playing this note

Then the logic of loop() becomes simply: “if we are done with the
current note, then start playing the next one.” In code:
Edit: Changed the code to include your button-scanning loop.
int current_button;
uint32_t note_started;

void loop() {
    // Adjust the notes on button presses.
    for (int button = 0; button < N_BUTTONS; button++) {
        if (digitalRead(button_pins[button])) {
            // As we have 78 pitches we divide the max Potentiometer
            // value by 77. This equals 13.
            Pitches[button] = analogRead(A0)/13;
            Durations[button] = analogRead(A1)*4;
        }
    }

    // Are we done with the current note?
    uint32_t now = millis();
    int tempo = analogRead(A2);
    if (now - note_started >= Durations[current_button] + tempo) {

        // Then move to the next note.
        ++current_button;

        // Finished the tune?
        if (current_button == N_BUTTONS) {
            current_button = 0;  // then restart from the beginning
        }

        // Play the note.
        tone(speakerPin,
                Pitches[current_button], Durations[current_button]);

        // Take note of when this started.
        note_started = now;
    }
}

Thank you for your comment. I have taken some time to understand your code but I cannot understand how to adapt to my code. My pitches array is a variable dependent on a button and potentiometer. Each pitch played is selected my user input. Note duration also is an input variable with potentiometer and button. Take a look at my code below. I have provided the one using delays. Thank you.

Thank you. Your code works as intended. although I would need to adjust some things like how to control the tempo, but overall this is a great solution.

Your code falls through (skips over) the first “if” statement in the output code because its time period has not yet passed.
It then starts to use startMillis_2, which is not yet initialized (and may be any value), in the next “if”.
Initialization of startMillis_2 only happens inside the first “if” statement but that code has not yet been executed.
The same goes for startMillis_3 and 4.
But I think there’s something more fundamentally wrong with your code. You execute all “if” statements inside of a loop that is continuously repeated. There is no sequence. You have to make sure that tone 2 can only be started after tone 1, etcetera.

That is the point I am not able. How to make sure tone 2 only starts after tone1 finishes. I can achieve this goal with delay, but I will be very limited on my code. Right now my code is doing exactly what I wanted except the delays interfere with my potentiometers inputs. I have updated my code on my post.


text:
ESP8266 exception on Array access
I have code to run an SH1106 display that works perfectly fine on a Mega328 (basic Uno clone) and Sparkfun Redboard Artemis (ARM M4).  The code for the ESP8266 (NodeMCU v1 clone) should be pretty similar to the ARM (i.e. bypassing the PROGMEM/memcpy_P stuff).  However, I've found that the ESP8266 goes into an infinite reboot loop with the following error message seen on the serial monitor:

 ets Jan  8 2013,rst cause:2, boot mode:(3,6)

load 0x4010f000, len 1392, room 16
tail 0
chksum 0xd0
csum 0xd0
v3d128e5c
~ld

I've tracked down the crash to the line where the Font Array data is accessed in my PutBigChar function in my My_SSH1106.h.  In fact, any attempt to access the array using a variable index causes an immediate reboot.  Using a constant literal index with the array does not cause the reboot.  Hence the horrible, ugly hack workaround in the code below.
Main sketch:

#include"My_SH1106.h"

void setup() {
  pinMode(LED_BUILTIN,OUTPUT);
  digitalWrite(LED_BUILTIN,HIGH);
  MySH1106_Init();
  MySH1106_Clear();
}

void loop() {

  MySH1106_PutBigString("I'm an arduino!",2,0);
  MySH1106_PutBigString("I'm an arduino!",2,14);

  delay(200);
}

My_SH1106.h
#include<Wire.h>
#include"lcdfont.h"

#define SH1106_SLAVE_ADDR 0x3c

#define CTRL_LAST_CMD 0x00
#define CTRL_NEXT_CMD 0x80
#define CTRL_LAST_RAM 0x40
#define CTRL_NEXT_RAM 0xC0

#define SH1106_OPT_INVERT 0x01
#define SH1106_OPT_UNDERL 0x02
#define SH1106_BIG_ROWS 4
#define SH1106_BIG_COLS 16

unsigned char MySH1106_workingBuffer[132];
unsigned char MySH1106_X, MySH1106_Y, MySH1106_options;

void MySH1106_Init() {
#ifdef ESP8266
    Wire.begin(D1,D2);  //sda, scl
#else
    Wire.begin();
#endif
    Wire.beginTransmission(SH1106_SLAVE_ADDR);
    Wire.write(CTRL_NEXT_CMD);
    Wire.write(0xaf); //display on
    Wire.write(CTRL_LAST_CMD);
    Wire.write(0xa5); //all on.
    //Wire.write(0xa4); //normal
    Wire.endTransmission(1);
    delay(200);
    Wire.beginTransmission(SH1106_SLAVE_ADDR);
    Wire.write(CTRL_LAST_CMD);
    Wire.write(0xa4);  //normal display
    Wire.endTransmission(1);
    MySH1106_X=0;
    MySH1106_Y=0;

}

void MySH1106_SetCol(unsigned char col) {
    Wire.beginTransmission(SH1106_SLAVE_ADDR);
    Wire.write(CTRL_NEXT_CMD);
    Wire.write(col & 0x0f);
    Wire.write(CTRL_LAST_CMD);
    Wire.write(0x10 | ((col>>4)&0xf));
    Wire.endTransmission(1);
}

void MySH1106_SetPage(unsigned char page) {
    Wire.beginTransmission(SH1106_SLAVE_ADDR);
    Wire.write(CTRL_LAST_CMD);
    Wire.write(0xb0 | (page & 0xf));
    Wire.endTransmission(1);
}

void MySH1106_SetPageCol(unsigned char page, unsigned char col) {
    Wire.beginTransmission(SH1106_SLAVE_ADDR);
    Wire.write(CTRL_NEXT_CMD);
    Wire.write(0xb0 | (page & 0xf));
    Wire.write(CTRL_NEXT_CMD);
    Wire.write(col & 0x0f);
    Wire.write(CTRL_LAST_CMD);
    Wire.write(0x10 | ((col>>4)&0xf));
    Wire.endTransmission(1);
}

void MySH1106_Clear() {
    for(unsigned char page=0;page<8;page++) {
        MySH1106_SetPage(page);
        MySH1106_SetCol(1);
        for(unsigned char x=0;x<129;x++) {
#ifdef ESP8266
            yield();
#endif
            Wire.beginTransmission(SH1106_SLAVE_ADDR);
            Wire.write(CTRL_LAST_RAM);
            Wire.write(0x00);
            Wire.endTransmission(1);
        } //of all columns

    }//of all pages
}

void MySH1106_PutBigChar(char c, unsigned char x, unsigned char y) {
    unsigned char remainder, offset, startPage, endPage, filldat, currentPage;
    unsigned char temp, curY, curX;

#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
    unsigned char glyphBuf[CHAR_HEIGHT];
//#elif defined(ESP8266)
//    const unsigned char* glyphBuf;
#else
    unsigned char glyphBuf[CHAR_HEIGHT];
#endif

    unsigned char glyphRow=0, glyphCol,glyphByte;
    unsigned char args[4];

    offset = y % 8;
    remainder =(y+CHAR_HEIGHT) % 8;
    startPage = y/8;
    endPage = (y+CHAR_HEIGHT)/8;
    currentPage = startPage;
#ifdef ESP8266
    yield();
#endif

    //memcpy_P is for AVR8 based processors.
    //when running on Artemis, use a regular copy.
    //#ifdef __AVR__ would cover other AVRs.

#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
    memcpy_P(glyphBuf, (unsigned char *)pgm_read_word(&(FontArray[c])),CHAR_HEIGHT);
#elif defined(ESP8266)
    //oddly, any attempt to dereference glyphBuf or use it as an array results in an exception.
    //glyphBuf = FontArray[c];

    //horrible, brutal hack.
    switch(c) {
        case ' ':
            glyphBuf[0]=NullArray[0];
            glyphBuf[1]=NullArray[1];
            glyphBuf[2]=NullArray[2];
            glyphBuf[3]=NullArray[3];
            glyphBuf[4]=NullArray[4];
            glyphBuf[5]=NullArray[5];
            glyphBuf[6]=NullArray[6];
            glyphBuf[7]=NullArray[7];
            glyphBuf[8]=NullArray[8];
            glyphBuf[9]=NullArray[9];
            glyphBuf[10]=NullArray[10];
            glyphBuf[11]=NullArray[11];
            glyphBuf[12]=NullArray[12];
            glyphBuf[13]=NullArray[13];
            break;
        case 'I':
            glyphBuf[0]=IArray[0];
            glyphBuf[1]=IArray[1];
            glyphBuf[2]=IArray[2];
            glyphBuf[3]=IArray[3];
            glyphBuf[4]=IArray[4];
            glyphBuf[5]=IArray[5];
            glyphBuf[6]=IArray[6];
            glyphBuf[7]=IArray[7];
            glyphBuf[8]=IArray[8];
            glyphBuf[9]=IArray[9];
            glyphBuf[10]=IArray[10];
            glyphBuf[11]=IArray[11];
            glyphBuf[12]=IArray[12];
            glyphBuf[13]=IArray[13];

            break;
        case 'a':
            glyphBuf[0]=aArray[0];
            glyphBuf[1]=aArray[1];
            glyphBuf[2]=aArray[2];
            glyphBuf[3]=aArray[3];
            glyphBuf[4]=aArray[4];
            glyphBuf[5]=aArray[5];
            glyphBuf[6]=aArray[6];
            glyphBuf[7]=aArray[7];
            glyphBuf[8]=aArray[8];
            glyphBuf[9]=aArray[9];
            glyphBuf[10]=aArray[10];
            glyphBuf[11]=aArray[11];
            glyphBuf[12]=aArray[12];
            glyphBuf[13]=aArray[13];
            break;
        case 'm':
            glyphBuf[0]=mArray[0];
            glyphBuf[1]=mArray[1];
            glyphBuf[2]=mArray[2];
            glyphBuf[3]=mArray[3];
            glyphBuf[4]=mArray[4];
            glyphBuf[5]=mArray[5];
            glyphBuf[6]=mArray[6];
            glyphBuf[7]=mArray[7];
            glyphBuf[8]=mArray[8];
            glyphBuf[9]=mArray[9];
            glyphBuf[10]=mArray[10];
            glyphBuf[11]=mArray[11];
            glyphBuf[12]=mArray[12];
            glyphBuf[13]=mArray[13];
            break;
        case 'n':
            glyphBuf[0]=nArray[0];
            glyphBuf[1]=nArray[1];
            glyphBuf[2]=nArray[2];
            glyphBuf[3]=nArray[3];
            glyphBuf[4]=nArray[4];
            glyphBuf[5]=nArray[5];
            glyphBuf[6]=nArray[6];
            glyphBuf[7]=nArray[7];
            glyphBuf[8]=nArray[8];
            glyphBuf[9]=nArray[9];
            glyphBuf[10]=nArray[10];
            glyphBuf[11]=nArray[11];
            glyphBuf[12]=nArray[12];
            glyphBuf[13]=nArray[13];
            break;
        default:
            glyphBuf[0]=NullArray[0];
            glyphBuf[1]=NullArray[1];
            glyphBuf[2]=NullArray[2];
            glyphBuf[3]=NullArray[3];
            glyphBuf[4]=NullArray[4];
            glyphBuf[5]=NullArray[5];
            glyphBuf[6]=NullArray[6];
            glyphBuf[7]=NullArray[7];
            glyphBuf[8]=NullArray[8];
            glyphBuf[9]=NullArray[9];
            glyphBuf[10]=NullArray[10];
            glyphBuf[11]=NullArray[11];
            glyphBuf[12]=NullArray[12];
            glyphBuf[13]=NullArray[13];
    }//of switch

#else
//this should work for ESP, but doesn't
    for(int i=0;i<CHAR_HEIGHT;i++) {
        glyphBuf[i]=FontArray[c][i];
    }
#endif

    MySH1106_SetPageCol(startPage,x);
    Wire.beginTransmission(SH1106_SLAVE_ADDR);//set up for ram read
    Wire.write(CTRL_LAST_RAM);
    Wire.endTransmission(1);

    Wire.requestFrom(SH1106_SLAVE_ADDR, 9, 1);
    while(Wire.available()<9) {
#ifdef ESP8266
        yield();
#endif
    };
    Wire.read(); //dummy read
    for(curX=x;curX<(x+CHAR_WIDTH);curX++) {
        MySH1106_workingBuffer[curX] = Wire.read(); //real read.
    }
#ifdef ESP8266
    yield();
#endif

    for(curY=offset;curY<8;curY++) {
        glyphByte = glyphBuf[glyphRow++];
        glyphCol=0;
        for(curX=x;curX<(x+CHAR_WIDTH);curX++) {
#ifdef ESP8266
            yield();
#endif
            if ((0x80>>glyphCol) & glyphByte) {
                MySH1106_workingBuffer[curX] |= (0x01<<curY);
            } else {
                MySH1106_workingBuffer[curX] &= ~(0x01<<curY);
            }

            glyphCol++;
#ifdef ESP8266
            yield();
#endif
        }

    }//of y offsets in first page.

    MySH1106_SetCol(x);
    Wire.beginTransmission(SH1106_SLAVE_ADDR);
    Wire.write(CTRL_LAST_RAM);
    for(curX=x;curX<(x+CHAR_WIDTH);curX++) {
        Wire.write(MySH1106_workingBuffer[curX] );
    }
    Wire.endTransmission(1);
    currentPage++;

    //middle page
    if(currentPage<endPage) {
        MySH1106_SetPageCol(currentPage,x);
        Wire.beginTransmission(SH1106_SLAVE_ADDR);//set up for ram read
        Wire.write(CTRL_LAST_RAM);
        Wire.endTransmission(1);

        Wire.requestFrom(SH1106_SLAVE_ADDR, 9, 1);
        while(Wire.available()<9){
#ifdef ESP8266
            yield();
#endif
        };
        Wire.read(); //dummy read
        for(curX=x;curX<(x+CHAR_WIDTH);curX++) {
            MySH1106_workingBuffer[curX] = Wire.read(); //real read.
        }

        for(curY=0;curY<8;curY++) {
            glyphByte = glyphBuf[glyphRow++];
            glyphCol=0;
            for(curX=x;curX<(x+CHAR_WIDTH);curX++) {
                if(glyphByte & (0x80>>glyphCol)) {
                    MySH1106_workingBuffer[curX] |= (0x01<<curY);
                } else {
                    MySH1106_workingBuffer[curX] &= ~(0x01<<curY);
                }
                glyphCol++;
            }
#ifdef ESP8266
            yield();
#endif
        }//of y offsets in intermediate page

        MySH1106_SetCol(x);
        Wire.beginTransmission(SH1106_SLAVE_ADDR);
        Wire.write(CTRL_LAST_RAM);
        for(curX=x;curX<(x+CHAR_WIDTH);curX++) {
            Wire.write(MySH1106_workingBuffer[curX] );
        }
        Wire.endTransmission(1);
        currentPage++;
    }

    MySH1106_SetPageCol(currentPage,x);
    Wire.beginTransmission(SH1106_SLAVE_ADDR);//set up for ram read
    Wire.write(CTRL_LAST_RAM);
    Wire.endTransmission(1);

    Wire.requestFrom(SH1106_SLAVE_ADDR, 9, 1);
    while(Wire.available()<9){
#ifdef ESP8266
        yield();
#endif
    };
    Wire.read(); //dummy read
    for(curX=x;curX<(x+CHAR_WIDTH);curX++) {
        MySH1106_workingBuffer[curX] = Wire.read(); //real read.
    }

    for(curY=0;curY<remainder;curY++) {
        glyphByte = glyphBuf[glyphRow++];
        glyphCol=0;
        for(curX=x;curX<(x+CHAR_WIDTH);curX++) {
            if(glyphByte & (0x80>>glyphCol)) {
                MySH1106_workingBuffer[curX] |= (0x01<<curY);
            } else {
                MySH1106_workingBuffer[curX] &= ~(0x01<<curY);
            }
            glyphCol++;
        }
#ifdef ESP8266
        yield();
#endif
    }//of y offsets in last page

    MySH1106_SetCol(x);
    Wire.beginTransmission(SH1106_SLAVE_ADDR);
    Wire.write(CTRL_LAST_RAM);
    for(curX=x;curX<(x+CHAR_WIDTH);curX++) {
        Wire.write(MySH1106_workingBuffer[curX] );
    }
    Wire.endTransmission(1);

}//of PutBigChar

void MySH1106_PutBigString(const char* c, unsigned char x, unsigned char y) {
    int8_t stringIndex=0;

    while(c[stringIndex]) {
        MySH1106_PutBigChar(c[stringIndex++],x,y);

        x+=CHAR_WIDTH;
    }
}

lcdfont.h
/*
 * File:
 * Author:
 * Comments:
 * Revision history:
 */

//the font is shamelessly extracted from the "BIOS" of DosBox.

// This is a guard condition so that contents of this file are not included
// more than once.
#ifndef LCD_FONT_DATA_H
#define  LCD_FONT_DATA_H

#define CHAR_HEIGHT 14
#define CHAR_WIDTH 8
// TODO Insert appropriate #include <>

// TODO Insert C++ class definitions if appropriate

// TODO Insert declarations
const unsigned char NullArray[] PROGMEM = { // 0x20
0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned char BangArray[] PROGMEM = { // 0x21
0x0, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00};
const unsigned char DquoteArray[] PROGMEM = { // 0x22
0x0, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned char HashArray[] PROGMEM = { // 0x23
0x0, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00};
const unsigned char DollarArray[] PROGMEM = { // 0x24
0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00};
const unsigned char PercentArray[] PROGMEM = { // 0x25
0x0, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x66, 0xc6, 0x00, 0x00, 0x00};
const unsigned char AmpersandArray[] PROGMEM = { // 0x26
0x0, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00};
const unsigned char SquoteArray[] PROGMEM = { // 0x27
0x0, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned char LparenArray[] PROGMEM = { // 0x28
0x0, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00};
const unsigned char RparenArray[] PROGMEM = { // 0x29
0x0, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00};
const unsigned char AsteriskArray[] PROGMEM = { // 0x2a
0x0, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned char PlusArray[] PROGMEM = { // 0x2b
0x0, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned char CommaArray[] PROGMEM = { // 0x2c
0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00};
const unsigned char DashArray[] PROGMEM = { // 0x2d
0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned char PeriodArray[] PROGMEM = { // 0x2e
0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00};
const unsigned char SlashArray[] PROGMEM = { // 0x2f
0x0, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00};
const unsigned char n0Array[] PROGMEM = { // 0x30
0x0, 0x00, 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00};
const unsigned char n1Array[] PROGMEM = { // 0x31
0x0, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00};
const unsigned char n2Array[] PROGMEM = { // 0x32
0x0, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00};
const unsigned char n3Array[] PROGMEM = { // 0x33
0x0, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00};
const unsigned char n4Array[] PROGMEM = { // 0x34
0x0, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00};
const unsigned char n5Array[] PROGMEM = { // 0x35
0x0, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00};
const unsigned char n6Array[] PROGMEM = { // 0x36
0x0, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00};
const unsigned char n7Array[] PROGMEM = { // 0x37
0x0, 0x00, 0xfe, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00};
const unsigned char n8Array[] PROGMEM = { // 0x38
0x0, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00};
const unsigned char n9Array[] PROGMEM = { // 0x39
0x0, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00};
const unsigned char ColonArray[] PROGMEM = { // 0x3a
0x0, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00};
const unsigned char SemicolonArray[] PROGMEM = { // 0x3b
0x0, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00};
const unsigned char LtArray[] PROGMEM = { // 0x3c
0x0, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00};
const unsigned char EqualArray[] PROGMEM = { // 0x3d
0x0, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned char GtArray[] PROGMEM = { // 0x3e
0x0, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00};
const unsigned char QuestionArray[] PROGMEM = { // 0x3f
0x0, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00};
const unsigned char AtArray[] PROGMEM = { // 0x40
0x0, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00};
const unsigned char AArray[] PROGMEM = { // 0x41
0x0, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00};
const unsigned char BArray[] PROGMEM = { // 0x42
0x0, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00};
const unsigned char CArray[] PROGMEM = { // 0x43
0x0, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00};
const unsigned char DArray[] PROGMEM = { // 0x44
0x0, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00};
const unsigned char EArray[] PROGMEM = { // 0x45
0x0, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00};
const unsigned char FArray[] PROGMEM = { // 0x46
0x0, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00};
const unsigned char GArray[] PROGMEM = { // 0x47
0x0, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00};
const unsigned char HArray[] PROGMEM = { // 0x48
0x0, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00};
const unsigned char IArray[] PROGMEM = { // 0x49
0x0, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00};
const unsigned char JArray[] PROGMEM = { // 0x4a
0x0, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00};
const unsigned char KArray[] PROGMEM = { // 0x4b
0x0, 0x00, 0xe6, 0x66, 0x6c, 0x6c, 0x78, 0x6c, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00};
const unsigned char LArray[] PROGMEM = { // 0x4c
0x0, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00};
const unsigned char MArray[] PROGMEM = { // 0x4d
0x0, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00};
const unsigned char NArray[] PROGMEM = { // 0x4e
0x0, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00};
const unsigned char OArray[] PROGMEM = { // 0x4f
0x0, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00};
const unsigned char PArray[] PROGMEM = { // 0x50
0x0, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00};
const unsigned char QArray[] PROGMEM = { // 0x51
0x0, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00};
const unsigned char RArray[] PROGMEM = { // 0x52
0x0, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00};
const unsigned char SArray[] PROGMEM = { // 0x53
0x0, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00};
const unsigned char TArray[] PROGMEM = { // 0x54
0x0, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00};
const unsigned char UArray[] PROGMEM = { // 0x55
0x0, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00};
const unsigned char VArray[] PROGMEM = { // 0x56
0x0, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00};
const unsigned char WArray[] PROGMEM = { // 0x57
0x0, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x7c, 0x6c, 0x00, 0x00, 0x00};
const unsigned char XArray[] PROGMEM = { // 0x58
0x0, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00};
const unsigned char YArray[] PROGMEM = { // 0x59
0x0, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00};
const unsigned char ZArray[] PROGMEM = { // 0x5a
0x0, 0x00, 0xfe, 0xc6, 0x8c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00};
const unsigned char LbracketArray[] PROGMEM = { // 0x5b
0x0, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00};
const unsigned char BslashArray[] PROGMEM = { // 0x5c
0x0, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00};
const unsigned char RbracketArray[] PROGMEM = { // 0x5d
0x0, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00};
const unsigned char CaretArray[] PROGMEM = { // 0x5e
0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned char _Array[] PROGMEM = { // 0x5f
0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00};
const unsigned char BquoteArray[] PROGMEM = { // 0x60
0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned char aArray[] PROGMEM = { // 0x61
0x0, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00};
const unsigned char bArray[] PROGMEM = { // 0x62
0x0, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00};
const unsigned char cArray[] PROGMEM = { // 0x63
0x0, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00};
const unsigned char dArray[] PROGMEM = { // 0x64
0x0, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00};
const unsigned char eArray[] PROGMEM = { // 0x65
0x0, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00};
const unsigned char fArray[] PROGMEM = { // 0x66
0x0, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00};
const unsigned char gArray[] PROGMEM = { // 0x67
0x0, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00};
const unsigned char hArray[] PROGMEM = { // 0x68
0x0, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00};
const unsigned char iArray[] PROGMEM = { // 0x69
0x0, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00};
const unsigned char jArray[] PROGMEM = { // 0x6a
0x0, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00};
const unsigned char kArray[] PROGMEM = { // 0x6b
0x0, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00};
const unsigned char lArray[] PROGMEM = { // 0x6c
0x0, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00};
const unsigned char mArray[] PROGMEM = { // 0x6d
0x0, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00};
const unsigned char nArray[] PROGMEM = { // 0x6e
0x0, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00};
const unsigned char oArray[] PROGMEM = { // 0x6f
0x0, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00};
const unsigned char pArray[] PROGMEM = { // 0x70
0x0, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00};
const unsigned char qArray[] PROGMEM = { // 0x71
0x0, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00};
const unsigned char rArray[] PROGMEM = { // 0x72
0x0, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00};
const unsigned char sArray[] PROGMEM = { // 0x73
0x0, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x70, 0x1c, 0xc6, 0x7c, 0x00, 0x00, 0x00};
const unsigned char tArray[] PROGMEM = { // 0x74
0x0, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00};
const unsigned char uArray[] PROGMEM = { // 0x75
0x0, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00};
const unsigned char vArray[] PROGMEM = { // 0x76
0x0, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00};
const unsigned char wArray[] PROGMEM = { // 0x77
0x0, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00};
const unsigned char xArray[] PROGMEM = { // 0x78
0x0, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00};
const unsigned char yArray[] PROGMEM = { // 0x79
0x0, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00};
const unsigned char zArray[] PROGMEM = { // 0x7a
0x0, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x66, 0xfe, 0x00, 0x00, 0x00};
const unsigned char LbraceArray[] PROGMEM = { // 0x7b
0x0, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00};
const unsigned char PipeArray[] PROGMEM = { // 0x7c
0x0, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00};
const unsigned char RbraceArray[] PROGMEM = { // 0x7d
0x0, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00};
const unsigned char TildeArray[] PROGMEM = { // 0x7e
0x0, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/*I'll say Kana is allowed to use one more row since there are no descenders.*/
/*on second thought, I don't want to have to come up with a separate 8x8 font*/
/*on third thought, 8x8 would be ugly.*/

const unsigned char dummy[] PROGMEM = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0};

const unsigned char *const FontArray[] PROGMEM = {
dummy,  // 0x00
dummy,  // 0x01
dummy,  // 0x02
dummy,  // 0x03
dummy,  // 0x04
dummy,  // 0x05
dummy,  // 0x06
dummy,  // 0x07
dummy,  // 0x08
dummy,  // 0x09
dummy,  // 0x0a
dummy,  // 0x0b
dummy,  // 0x0c
dummy,  // 0x0d
dummy,  // 0x0e
dummy,  // 0x0f
dummy,  // 0x10
dummy,  // 0x11
dummy,  // 0x12
dummy,  // 0x13
dummy,  // 0x14
dummy,  // 0x15
dummy,  // 0x16
dummy,  // 0x17
dummy,  // 0x18
dummy,  // 0x19
dummy,  // 0x1a
dummy,  // 0x1b
dummy,  // 0x1c
dummy,  // 0x1d
dummy,  // 0x1e
dummy,  // 0x1f
NullArray, // 0x20
BangArray, // 0x21
DquoteArray, // 0x22
HashArray, // 0x23
DollarArray, // 0x24
PercentArray, // 0x25
AmpersandArray, // 0x26
SquoteArray, // 0x27
LparenArray, // 0x28
RparenArray, // 0x29
AsteriskArray, // 0x2a
PlusArray, // 0x2b
CommaArray, // 0x2c
DashArray, // 0x2d
PeriodArray, // 0x2e
SlashArray, // 0x2f
n0Array, // 0x30
n1Array, // 0x31
n2Array, // 0x32
n3Array, // 0x33
n4Array, // 0x34
n5Array, // 0x35
n6Array, // 0x36
n7Array, // 0x37
n8Array, // 0x38
n9Array, // 0x39
ColonArray, // 0x3a
SemicolonArray, // 0x3b
LtArray, // 0x3c
EqualArray, // 0x3d
GtArray, // 0x3e
QuestionArray, // 0x3f
AtArray, // 0x40
AArray, // 0x41
BArray, // 0x42
CArray, // 0x43
DArray, // 0x44
EArray, // 0x45
FArray, // 0x46
GArray, // 0x47
HArray, // 0x48
IArray, // 0x49
JArray, // 0x4a
KArray, // 0x4b
LArray, // 0x4c
MArray, // 0x4d
NArray, // 0x4e
OArray, // 0x4f
PArray, // 0x50
QArray, // 0x51
RArray, // 0x52
SArray, // 0x53
TArray, // 0x54
UArray, // 0x55
VArray, // 0x56
WArray, // 0x57
XArray, // 0x58
YArray, // 0x59
ZArray, // 0x5a
LbracketArray, // 0x5b
BslashArray, // 0x5c
RbracketArray, // 0x5d
CaretArray, // 0x5e
_Array, // 0x5f
BquoteArray, // 0x60
aArray, // 0x61
bArray, // 0x62
cArray, // 0x63
dArray, // 0x64
eArray, // 0x65
fArray, // 0x66
gArray, // 0x67
hArray, // 0x68
iArray, // 0x69
jArray, // 0x6a
kArray, // 0x6b
lArray, // 0x6c
mArray, // 0x6d
nArray, // 0x6e
oArray, // 0x6f
pArray, // 0x70
qArray, // 0x71
rArray, // 0x72
sArray, // 0x73
tArray, // 0x74
uArray, // 0x75
vArray, // 0x76
wArray, // 0x77
xArray, // 0x78
yArray, // 0x79
zArray, // 0x7a
LbraceArray, // 0x7b
PipeArray, // 0x7c
RbraceArray, // 0x7d
TildeArray, // 0x7e

};

#endif

The horrible, ugly hack should not be necessary.  Is this some shortcoming of the ESP, or am I misusing the tool in some way?  Is there a simpler way to make this work?

Could it be a power issue? Reset cause 2 is a power reset (https://www.espressif.com/sites/default/files/documentation/esp8266_reset_causes_and_common_fatal_exception_causes_en.pdf). From my experience the esp is much more sensitive than the atmegas.

I don't have any issues running any other script, and I made sure the SH1106 was powered off of a separate supply.  I added additional storage caps to the 3.3V rail for good measure.  It doesn't feel like a power issue.  Other sketches that draw to the SH106 without accessing the font routine also have no problem.


text:
Managing configurations via EEPROM by writing it with the hex file
I've been looking into I2C bootloaders for an ATTINY coprocessor on a board I'm developing, and I ran into a bit of a snag. I have the need to detect what board the main processor's code is running on, since there are a number of write-only peripherals I can't probe for presence or configuration (WS2812-series LEDs and a SSD1306 screen, among a few others), and I was going to manage that via a configuration blob stored on the ATTINY.
Unfortunately, this was coded into the firmware, and pushing out any sort of update for the coprocessor would then require that I build, label, and provide each version, and then have the user choose the correct one.
So, the solution would seemingly be EEPROM, since that can be set to persist over programming attempts (there's even a fuse setting to keep it, although in the other case how the AVR knows if it's been programmed [in the era of bootloaders] I'm not sure).
The issue is now that I need a way to set the EEPROM configuration when I create the original program, and then have future updates not touch it. The existing way is that I add a stub to my code that checks if there's a config and sets it (unfortunately per-unique-board-design, so I'd need lots of different copies again) and then never touches it again. Future firmwares could then just not include any stub at all.
However, this annoys me, especially since if something goes wrong it could mess up the EEPROM.
Does anyone know of a way to use a ICSP programmer to set EEPROM, ideally as part of the firmware upload?
I am using a usbasp with PlatformIO to do the chip programming, so I should have enough access on the first burning to change the EEPROM. Does anyone know how I could add in an EEPROM configuration to go with the flash one?
Some thoughts I have had:

Somehow modify/append the hex file to include data that goes to EEPROM and then burn it
Add a script to PlatformIO that lets me edit/compile/upload/whatever to EEPROM (I do not speak Python, so I'd need help)
Use an existing feature of PlatformIO/the build process/the AVR toolchain to set an EEPROM configuration (I have to suspect there is one, but Googling does not seem to have pointed one out)
Somehow do this with AVRDude

AVRDUDE can program EEPROM. I usually do this as part of the firmware burn - the operator can pick which config block should go into the board while running the programming cycle. In some cases the EEPROM info is even generated programmatically during the cycle to contain dynamic info like unit serial number and commision date.
Here is an example command line that will program the file filename.hex into EEPROM...
avrdude -c stk500v2 -P COM6 -p atmega328p -U eeprom:w:filename.hex:i

The AVRDUDE write command (U) has many options to do almost anything you want...
-U memtype:op:filename[:format]
Perform a memory operation. Multiple ‘-U’ options can be specified in order to operate on multiple memories on the same command-line invocation. The memtype field specifies the memory type to operate on. Use the ‘-v’ option on the command line or the part command from terminal mode to display all the memory types supported by a particular device. Typically, a device’s memory configuration at least contains the memory types flash and eeprom. All memory types currently known are:
(...)
MEMTYPE:
eeprom
The EEPROM of the device.
(...)

OP:
w
read the specified file and write it to the specified device memory

(...)

FILENAME:
The filename field indicates the name of the file to read or write. The format field is optional and contains the format of the file to read or write. Possible values are:

i
Intel Hex

s
Motorola S-record

r
raw binary; little-endian byte order, in the case of the flash ROM data

e
ELF (Executable and Linkable Format), the final output file from the linker; currently only accepted as an input file

m
immediate mode; actual byte values specified on the command line, separated by commas or spaces in place of the filename field of the ‘-U’ option. This is useful for programming fuse bytes without having to create a single-byte file or enter terminal mode. If the number specified begins with 0x, it is treated as a hex value. If the number otherwise begins with a leading zero (0) it is treated as octal. Otherwise, the value is treated as decimal.

a
auto detect; valid for input only, and only if the input is not provided at stdin.

d
decimal; this and the following formats are only valid on output. They generate one line of output for the respective memory section, forming a comma-separated list of the values. This can be particularly useful for subsequent processing, like for fuse bit settings.

h
hexadecimal; each value will get the string 0x prepended.

o
octal; each value will get a 0 prepended unless it is less than 8 in which case it gets no prefix.

b
binary; each value will get the string 0b prepended.

The default is to use auto detection for input files, and raw binary format for output files.

Note that if filename contains a colon, the format field is no longer optional since the filename part following the colon would otherwise be misinterpreted as format.

As an abbreviation, the form -U filename is equivalent to specifying -U flash:w:filename:a. This will only work if filename does not have a colon in it.

Any of these files types can be used depending on what kind of data you are writing to the EEPROM and how it is being generated.
More info here...
https://www.pololu.com/docs/0J67/5.8

Can you elaborate on how I'd make the hex file that goes to EEPROM (for that matter, does it support other types of file and how does that work) or how I might generate the file on-the-fly as listed? Adding a build date or similar would probably be a good idea...

AVRDUDE supports Intel Hex, Motorola S-Record, and raw binary files. Arduino uses Intel Hex as far as I know.

@RDragonrydr answer updated with an excerpt from the AVRDUDE documentatio showing  all the kinds of data use can use.


text:
Arduino TFT LCD Data Logger
Can I use Arduino TFT LCD Module ILI9341 as a data logger? It has an SD card slot at the back, I wonder if the data will be saved on the SD card? Thanks!

yes, you certainly can

Sure. If you plug it in to your Arduino and write a sketch to do data logging using the SD card on the TFT screen.


text:
Does using multiple HX711 amplifiers change the supply voltage of an Arduino?
I’m creating essentially a load cell using an Arduino Nano and an HX711 amplifier. However, I want to have two HX711 amplifiers running off the same Arduino. Will that change the supply voltage since I’m using two (ex. Does it change from 5V to 2.5V)? I need an accurate supply voltage for the Wheatstone bridge equations to determine strain from the strain gauge readings, but I’m unsure what adding another amplifier will do to the supply voltage.

how are you connecting them?

Sorry - should have specified that. They all share a single clock line and use different data lines. I’m using the HX711 multi library.

your question is all about the supply voltage, but you did not say anything about any connections to the power supply

Power supply module connected to a 9V battery, on the breadboard with the Arduino nano.

It sounds like you want to power the HX711's to the 5V line on the Arduino. As long as you don't exceed the current limits on the Arduino's voltage regulator, that should be fine. (connect each to 5V and to ground. Don't try to run them in series.)

Will that change the supply voltage

No. Components and circuits connected in parallel add together their current requirements, but the voltage stays the same.


text:
I want to save the value of the scanned barcode on an SD Card (in a text file may do)
serial monitor output

#include <usbhid.h>
#include <usbhub.h>
#include <hiduniversal.h>
#include <hidboot.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>

/*
  SD card read/write
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)
 */

File myFile;
//SPIClass spiSD(HSPI);
String data = "";
class MyParser : public HIDReportParser {
  public:
    MyParser();
    void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
  protected:
    uint8_t KeyToAscii(bool upper, uint8_t mod, uint8_t key);
    virtual void OnKeyScanned(bool upper, uint8_t mod, uint8_t key);
    virtual void OnScanFinished();
};

MyParser::MyParser() {}

void MyParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
  // If error or empty, return
  if (buf[2] == 1 || buf[2] == 0) return;

  for (uint8_t i = 7; i >= 2; i--) {
    // If empty, skip
    if (buf[i] == 0) continue;

    // If enter signal emitted, scan finished
    if (buf[i] == UHS_HID_BOOT_KEY_ENTER) {
      OnScanFinished();
    }

    // If not, continue normally
    else {
      // If bit position not in 2, it's uppercase words
      OnKeyScanned(i > 2, buf, buf[i]);
    }

    return;
  }
}

uint8_t MyParser::KeyToAscii(bool upper, uint8_t mod, uint8_t key) {
  // Letters
  if (VALUE_WITHIN(key, 0x04, 0x1d)) {
    if (upper) return (key - 4 + 'A');
    else return (key - 4 + 'a');
  }

  // Numbers
  else if (VALUE_WITHIN(key, 0x1e, 0x27)) {
    return ((key == UHS_HID_BOOT_KEY_ZERO) ? '0' : key - 0x1e + '1');
  }

  return 0;
}

void MyParser::OnKeyScanned(bool upper, uint8_t mod, uint8_t key) {
  uint8_t ascii = KeyToAscii(upper, mod, key);
  char c = (char)ascii;
  data += c;
  Serial.print((char)ascii);
  //myFile.print((char)ascii);
}

void MyParser::OnScanFinished() {
   digitalWrite(10, HIGH);
  digitalWrite(4, LOW);
   delay(100);
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");}
  myFile = SD.open("barcode.txt",FILE_WRITE);
  myFile.println(data);
  Serial.println(data);
   data = "";
  Serial.println(" - Finished");
//  myFile.print('\n');
  //myFile.print('\0');
  myFile.close();
  digitalWrite(4, HIGH);
  digitalWrite(10, LOW);
   delay(100);

    }

USB          Usb;
USBHub       Hub(&Usb);
HIDUniversal Hid(&Usb);
MyParser     Parser;

void setup() {
  pinMode(4, OUTPUT);
  pinMode(10, OUTPUT);
   SPI.begin();
   digitalWrite(4, HIGH);
   digitalWrite(10, HIGH);
  Serial.begin( 9600 );
  delay(100);

  digitalWrite(4, LOW);

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
   delay(100);
  digitalWrite(4, HIGH);
   delay(100);
  digitalWrite(10, LOW);
  //Serial.println("Start");

  if (Usb.Init() == -1) {
    Serial.println("OSC did not start.");
  }
  delay( 200 );
  Hid.SetReportParser(0, &Parser);
   if (!SD.begin(4)) {
    Serial.println("initialization failed!");
}}

void loop() {
  // SPI.begin();
  Usb.Task();
}

I am using a QuickScan Lite Qw210 Datalogic USB Barcode Reader, USB Host Shield and Arduino Uno
I have coded everything and file is generating and barcode being scanned properly but prob is that file which is being generated is empty . Can anyone point out where the prob is happeining in my code why even after printing in file data is not getting saved

#include <usbhid.h>
#include <usbhub.h>
#include <hiduniversal.h>
#include <hidboot.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
File myFile;
String data = "";
class MyParser : public HIDReportParser {
public:
MyParser();
void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
protected:
uint8_t KeyToAscii(bool upper, uint8_t mod, uint8_t key);
virtual void OnKeyScanned(bool upper, uint8_t mod, uint8_t key);
virtual void OnScanFinished();
};
MyParser::MyParser() {}

void MyParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
{
// If error or empty, return
if (buf[2] == 1 || buf[2] == 0) return;

for (uint8_t i = 7; i >= 2; i--) {
// If empty, skip
if (buf[i] == 0) continue;

// If enter signal emitted, scan finished
if (buf[i] == UHS_HID_BOOT_KEY_ENTER) {
  OnScanFinished();
}

// If not, continue normally
else {
  // If bit position not in 2, it's uppercase words
  OnKeyScanned(i > 2, buf, buf[i]);
}

return;
 }
 }

  uint8_t MyParser::KeyToAscii(bool upper, uint8_t mod, uint8_t key) {
  // Letters
   if (VALUE_WITHIN(key, 0x04, 0x1d)) {
    if (upper) return (key - 4 + 'A');
     else return (key - 4 + 'a');
     }

     // Numbers
   else if (VALUE_WITHIN(key, 0x1e, 0x27)) {
     return ((key == UHS_HID_BOOT_KEY_ZERO) ? '0' : key - 0x1e + '1');
     }

    return 0;
     }

   void MyParser::OnKeyScanned(bool upper, uint8_t mod, uint8_t key) {
    uint8_t ascii = KeyToAscii(upper, mod, key);
    char c = (char)ascii;
     data += c;
     Serial.print((char)ascii);
     //myFile.print((char)ascii);
     }

      void MyParser::OnScanFinished() {
          myFile = SD.open("barcode.txt",FILE_WRITE);
         myFile.println(data);
       Serial.println(data);
       data = "";
       Serial.println(" - Finished");
           myFile.close();
                }

          USB          Usb;
       USBHub       Hub(&Usb);
      HIDUniversal Hid(&Usb);
      MyParser     Parser;

          void setup() {
        pinMode(4, OUTPUT);
           pinMode(10, OUTPUT);
            // SPI.begin();
               //digitalWrite(4, HIGH);
           //digitalWrite(10, HIGH);
           Serial.begin( 9600 );
            //delay(100);

                //digitalWrite(4, LOW);

               if (!SD.begin()) {
        Serial.println("initialization failed!");
         return;
               }
             delay(100);
            //digitalWrite(4, HIGH);
        //  delay(100);
     // digitalWrite(10, LOW);
       //Serial.println("Start");

            if (Usb.Init() == -1) {
              Serial.println("OSC did not start.");
            }
        delay( 200 );
         Hid.SetReportParser(0, &Parser);
        }

       void loop() {
          Usb.Task();
         }

Did you mean this Juraj Pls have a look on changes and let me know

put SD.begin() only in setup. don't call SPI.begin(). don't set the CS pin of the SD card. let the library handle it.

thanks for the suggestion . I just wanted to know then how my library will know that i have connected my sd card module on 4th pin of arduino and im using usb host shield also which is using the 10 pin i think. Thanks in advance

And what about making pins high and low for chip select? shall I remove all of those digital write things from everywhere

yes SD.begin(4). but in setup(), only once. the CS pin is handled by the SD library

in setup() SD.begin(4)


text:
Designing RGB leds
I am interested in creating a string of ~80 RGB LEDs run on an Arduino Uno. Each LED is to have its own on/off timing and color and the distance from one LED to the next about 4-5 feet.
Since I want to program each LED separately can I do that with strings like the Adafruit Pixels (https://www.adafruit.com/product/322) or do I have to set it up with separate RGB LEDs and daisy chain them?
Thanks for your help with this.

Because of the distances, I'm tempted to suggest going with DotsStars instead of NeoPixels. Those have a separate clock line, so you could run them slower, if there's too much interference.

Since you'd have to change the wires anyway, https://www.adafruit.com/product/4356 might be better than the ones you linked.

Good recommendation Gerben. I will definitely consider that and would probably be cheaper then the ones I was looking at given the fact that I need 80 ish.

do I have to set it up with separate RGB LEDs and daisy chain them?

That's exactly, what the string of Neopixels, that you linked, is: Separate WS2801 RGB LED chips, which are daisy chained together. Since the distance of the LEDs on the string is not 4-5 feet, you cannot use the string directly.
You can either cut the string and extent the cables, as you need to. Or you can buy single LEDs and use completely your own cables. That's up to you; technically it is completely the same.
But since 80 LEDs, each 4 feet apart, will give you about 100m/330feet, you get a problem with the resistance of the wire. First about power supply:
You whole strip would need up to 4.8A of power, with every pixel at full white. You need to transport that current from your source, down to the very last LED. Make sure, that the used wire has very low resistance and is rated for such a current. If the resistance is to high, you will loose voltage over every meter of the cable and the last LEDs might be off color or not working.
I think the signal lines will be fine despite the distance, since every LED outputs them again to the next LED, so the signal should be kind of refined on every LED (though I don't know, how the WS2801 chips work internally).

Re “I think [...] the signal should be kind of refined on every LED”: this has indeed been observed.

It wasn't clear to me that that is what the neopixels do. That is super! Can you point me to code that illustrates how to manage each pixel separately? The only examples I have seen  create overall patterns. I want one pattern that loops per pixel and separate from the group. Thanks also for the power and signal comments they are good to bear in mind.

@ChinaBlue The code for iterating over each pixel depends on the library used. I've had success using FastLED with a Neopixel WS2811. Here's a code example setting each LED in a loop.