body:
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?

title: ESP8266 exception on Array access

Answers: 0


body:
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:

 1. Somehow modify/append the hex file to include data that goes to EEPROM and then burn it
 2. Add a script to PlatformIO that lets me edit/compile/upload/whatever to EEPROM (I do not speak Python, so I'd need help)
 3. 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)
 4. Somehow do this with AVRDude

title: Managing configurations via EEPROM by writing it with the hex file

Answers: 1

body:
`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][1] 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

  [1]: https://www.nongnu.org/avrdude/user-manual/avrdude_4.html


body:
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!
[![enter image description here][1]][1]

  [1]: https://i.stack.imgur.com/ki3Ga.png

title: Arduino TFT LCD Data Logger

Answers: 0


body: 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.

title: Does using multiple HX711 amplifiers change the supply voltage of an Arduino?

Answers: 1

body:
> Will that change the supply voltage

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


body:
serial monitor output[![empty file generated][1]][1]
<!-- language-all: lang-cpp -->

    #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[![serial monitor output][2]][2]**

  [1]: https://i.stack.imgur.com/esZLc.png
  [2]: https://i.stack.imgur.com/fHAlq.png

---

    #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**

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

Answers: 0


body:
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.

title: Designing RGB leds

Answers: 1

body:
>  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).


body:
I am trying to write some data to SD card and read it back to serial monitor as well as display it to the OLED.

Both the sd card and oled work separately but they seem to be interfering with each other when combined. I have used Arduino SD and Adafruit OLED libraries.

Connections from Arduino Uno to Micro SD card module-

    5V to SD VCC
    GND TO SD GND
    PIN 10 TO SD Chip Select
    PIN 11 TO SD MOSI
    PIN 12 TO SD MISO
    PIN 13 TO SD SCK

Connections to OLED-

    3.3V to OLED VCC
    GND TO OLED GND
    A4 TO OLED SDA
    A5 TO OLED SCK

Here is the code -

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

    File myFile;

    #include <Wire.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306.h>

    #define SCREEN_WIDTH 128 // OLED display width, in pixels
    #define SCREEN_HEIGHT 64 // OLED display height, in pixels

    // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
    #define OLED_RESET     -1
    Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
      while(!Serial) {
        ;
      }

      if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
        Serial.println(F("SSD1306 allocation failed"));
        for(;;); // CODE GETS STUCK HERE. DISPLAY NEVER INITIALISES
      }
      display.clearDisplay();
      display.setTextSize(1);
      display.setTextColor(WHITE);
      display.setCursor(29,29);
      display.print("INITIALISING");
      display.display();
      delay(5000);

      if (!SD.begin(10)) {
        Serial.println("initialization failed!");
        while (1);
      }
      Serial.println("initialization done.");

      myFile = SD.open("test.txt", FILE_WRITE);

      if (myFile) {
        Serial.print("Writing to test.txt...");
        myFile.println("testing 1, 2, 3.");
        // close the file:
        myFile.close();
        Serial.println("done.");
      } else {
        // if the file didn't open, print an error:
        Serial.println("error opening test.txt");
      }

      display.clearDisplay();

      myFile = SD.open("test.txt");
      if (myFile) {
        Serial.println("test.txt:");
        while (myFile.available()) {
          Serial.write(myFile.read());
          display.setCursor(0,0);
          display.print(myFile.read());
          display.display();
          delay(5000);
        }
        // close the file:
        myFile.close();
      } else {
        // if the file didn't open, print an error:
        Serial.println("error opening test.txt");
      }
    }

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

    }

Code gets stuck at OLED initialization as mentiontioned above. If I replace these lines-

    if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
        Serial.println(F("SSD1306 allocation failed"));
        for(;;); // CODE GETS STUCK HERE. DISPLAY NEVER INITIALISES
        }

To this-

    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

I have run I2C scanner code on OLED so the address "0X3C" is correct.

The OLED still doesn't work and SD card initialises but arduino is writing wrong data to TXT file on SD card like this-

    teóting 1,à2, ó®

Instead of -

    testing 1, 2, 3.

I have also tried using U8G2 library's sketches with SD card in case Arduino was running out of RAM but it still doesn't work. I have also changed SD chip select to Arduino digital pin 4 but still same results.

On browsing and experimenting more,I found MISO OR MOSI PIN of SD maybe interfering with SDA/SCL pins of OLED. Maybe wiring needs to change.

**ANY SUGGESTIONS???**

title: OLED (I2C) and Micro SD card module not working together in Arduino

Answers: 1

body: A pullup resistor is needed for I2C, and adding them might fix some errors.


body:
I am new to ESP8266 and found an example about turning a LED ON/OFF using web interface. It works well but after some time (few minutes) i cannot open the web page (in my case it is http://192.168.100.23 and i made it static IP). It keeps 'waiting for 192.168.100.23'. I can ping the IP. Can someone please help to find what the problem is? Thank you very much!

Below is the code:

```````````````
#include <ESP8266WiFi.h>
#define LED D2
const char* ssid = "myAP";
const char* password = "32133213";
unsigned char status_led=0;
WiFiServer server(80);

void setup() {
  Serial.begin(115200);
  pinMode(LED, OUTPUT);
  /*WiFi.persistent( false );
  WiFi.setAutoConnect(true);
  WiFi.mode(WIFI_STA);*/
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  server.begin();
  Serial.println("Server started");
  Serial.println(WiFi.localIP());
}

void loop() {
  WiFiClient client = server.available();
  if (!client) {
    return;
  }

  Serial.println("new client");
  while(!client.available())
  {
    delay(1);
  }
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();
  if (req.indexOf("/ledoff") != -1)
  {
    status_led=0;
    digitalWrite(LED,LOW);
    Serial.println("LED OFF");
  }
  else if(req.indexOf("/ledon") != -1)
  {
    status_led=1;
    digitalWrite(LED,HIGH);
    Serial.println("LED ON");
  }
  String web = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
  web += "<html>\r\n";
  web += "<body>\r\n";
  web += "<h1>LED Status</h1>\r\n";
  web += "<p>\r\n";
  if(status_led==1)
      web += "LED On\r\n";
  else
      web += "LED Off\r\n";
  web += "</p>\r\n";
  web += "</p>\r\n";
  web += "<a href=\"/ledon\">\r\n";
  web += "<button>LED On</button >\r\n";
  web += "</a>\r\n";
  web += "</p>\r\n";

  web += "<a href=\"/ledoff\">\r\n";
  web += "<button>LED Off</button >\r\n";
  web += "</a>\r\n";

  web += "</body>\r\n";
  web += "</html>\r\n";

  client.print(web);
}
`````````````````

title: cannot connect ESP8266 web server after some time

Answers: 2

body:
The esp8266 enters modem sleep in STA mode without WiFi traffic. You can turn off the sleep mode with WiFi.[setSleepMode][1]. The possible parameters are WIFI_NONE_SLEEP, WIFI_LIGHT_SLEEP or WIFI_MODEM_SLEEP.

After some longer time the servers on esp8266 with arduino core usually get inaccessible even it the esp8266 connects as client to other servers or still sends UDP messages. It is a [known issue][2] with some possible workaround documented.

  [1]: https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/generic-class.html#wifi-power-management-dtim
  [2]: https://github.com/esp8266/Arduino/issues/2330

body:
I added WiFi.setSleepMode(WIFI_NONE_SLEEP); but it does not help. I found another script that is working well so far (after 1 day). I am new so i do not know what problem is but i think it needs to free memory and close connection. Below is the new code for those who get the same problem!
`````````````````````
// Load Wi-Fi library
#include <ESP8266WiFi.h>
#define LED D2
// Replace with your network credentials
const char* ssid     = "myAP";
const char* password = "32133213";
// Set web server port number to 80
WiFiServer server(80);
// Variable to store the HTTP request
String header;
// Auxiliar variables to store the current output state
String outputState = "off";
// Assign output variables to GPIO pins

// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;
void setup() {
  Serial.begin(115200);
  // Initialize the output variables as outputs
  pinMode(LED, OUTPUT);
  // Set outputs to LOW
  digitalWrite(LED, LOW);

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}
void loop(){
  WiFiClient client = server.available();   // Listen for incoming clients
  if (client) {                             // If a new client connects,
    Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    currentTime = millis();
    previousTime = currentTime;
    while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
      currentTime = millis();
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            // turns the GPIOs on and off
            if (header.indexOf("GET /on") >= 0) {
              Serial.println("light on");
              outputState = "on";
              digitalWrite(LED, HIGH);
            } else if (header.indexOf("GET /off") >= 0) {
              Serial.println("light off");
              outputState = "off";
              digitalWrite(LED, LOW);
            }

            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            // CSS to style the on/off buttons
            // Feel free to change the background-color and font-size attributes to fit your preferences
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
            client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            client.println(".button2 {background-color: #77878A;}</style></head>");

            // Web Page Heading
            client.println("<body><h1>ESP8266 Web Server</h1>");

            // Display current state, and ON/OFF buttons for GPIO 5
            client.println("<p>State " + outputState + "</p>");
            // If the output5State is off, it displays the ON button
            if (outputState=="off") {
              client.println("<p><a href=\"/on\"><button class=\"button button2\">TURN ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/off\"><button class=\"button\">TURN OFF</button></a></p>");
            }

            client.println("</body></html>");

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


body:
I am doing a project 'arduino based switch operation'. Here the user needs to set a time to turn on relay and set time to turn it off. The problem is that I want to supply power to arduino using adapter connected to the ac supply (where the relay will also be connected). When the on time is set and if power goes off for some time then this system doesn't work. I want to save the data in arduino so that it will retain the data if power comes back.. So that my relay is operated on time..
How to do it guys???

title: How to save data in arduino when it's power goes off

Answers: 3

body:
Look up EEPROM. it is a memory that saves content even though power is off.

You can write data in EEPROM and when power comes back read it back.

there are safe ways to write in EEPROM without corrupting it.

body:
Beside Georgi's answer, I would like to tell  you some details.

## First :
a microcontroller **can** have a built-in EEPROM like the ATMega328 inside an Arduino UNO/Nano/mini, if not you would need to attach an external one, it can have may interfaces like SPI or IIC etc...

## Second :
 an EEPROM can hold only a specified amount of data, it can be 512byte like one on the ATMega328 microcontrollers, it can be only 64byte on others.

## Third :
an EEPROM have **addresses** so for example in 8-bit EEPROM one address can hold only 8bits so values from (0-255) like on the ATMega328

## Fourth : how to use it

In the beginning of your code you should first include the eeprom library

    #include <EEPROM.h>

Then you would for example assign value "24" to one of the address on the EEPROM let's say address "1"

So you will use

    EEPROM.write(1,24);

Of course you can power off you board and repower it again and that particular address will have the assigned 8-bit value "24".

To read back

    EEPROM.read(24);

I hope that might help you or anyone else.

And as a side note an EEPROM have defined write and read cycles ~10000 maybe ~100000 after that amount it May not work.

Original documentation : [here][1]

  [1]: https://www.arduino.cc/en/Reference/EEPROM

body: You Can do that by using RTC (Real Time Clock Module ) in your project.


body:
Using STM32Duino on Nucleo F429ZI:

    #include <LwIP.h>
    #include <STM32Ethernet.h>
    #define UDP_TX_PACKET_MAX_SIZE 512
    #include <EthernetUdp.h>

    IPAddress remoteIP;
    unsigned int remotePort;

    EthernetUDP Udp;
    uint8_t packetBuffer[UDP_TX_PACKET_MAX_SIZE];

    void setup()
    {
      Serial.begin(115200);
      IPAddress localIP = /***/;
      IPAddress netmask = /***/;
      IPAddress dns = /***/;
      IPAddress gateway = /***/;

      Ethernet.begin(localIP, netmask, dns, gateway);
      uint8_t *mac = Ethernet.macAddress();

      int port = 8888;
      Udp.begin(port);
    }

    void loop()
    {
      processUDPMessage();
    }

    void processUDPMessage(void)
    {
      while (int size = Udp.parsePacket())
      {
        if (size > 0) parsePacket(size);
      }
    }

    void parsePacket(int size)
    {
      remoteIP = Udp.remoteIP();
      remotePort = Udp.remotePort();

      Udp.read(packetBuffer, size);
      Serial.println((char *) packetBuffer);
    }

If I received at least 4 packets at the same time, one of them is not received. Each packet is less than 50 byte long.

Is there anything I could do to improve the reliability of my code?

title: STM32Ethernet UDP misses some packets

Answers: 0


body:
If I code like this:
```c
motor.write(0);
Serial.println("Before");
motor.write(180);
Serial.println("After");
```
Both "Before" and "After" is instantly printed, while the motor is still rotating.
I want "After" or whatever statement to be executed AFTER the motor
reaches 180 degree.
How can I implement this? Is it possible to read Servo's statement?

Btw, I don't want to put delay after write(), so other than that strategy.

title: How to stop program while Servo is rotating

Answers: 2

body:
> How can I implement this? Is it possible to read Servo's statement?

No, it is not possible. When you do a `servo.write()` it just changes the PWM duty cycle. It's then up to the servo to use that to set its position. The Arduino has no concept at all of the *current* position of the servo.

> Btw, I don't want to put delay after write(), so other than that strategy.

The only other way, besides delaying or otherwise using `millis()` to wait for a predefined period after your `write` would be to implement some form of feedback between the shaft of the servo and the Arduino. Maybe a potentiometer, or rotary encoder would do the job.

body:
It's not possible with the servo alone, but you could add feedback. Some options:

 - An encoder (may be expensive or not available for your servo) will tell you the position.
 - You could also make your own encoder by connecting a potentiometer to the axis. The resistance of the pot will be related to the position of the servo.
 - if you don't need to be exact something simple like a switch at the limit you want to reach.
 - If it doesn't have to be exactly when the position is reached, you
   could measure the average time it takes (under load) to move from the
   minimum angle to the maximum angle. This will be the longest it ever
   takes to move. Then in your code wait 150% of that time before
   proceeding (to give a bit of a buffer "just in case").

As Majenko said, if you don't want to use a delay, use millis() or micros() to track the current and previous times a line in the loop executed; if the difference is larger than the required delay, the time has elapsed and you can proceed with the rest of the loop. This way you can track time without having to "block" the rest of the loop while you wait.


body:
I have an old monochrome LCD panel that I removed from a calculator. The LCD panel has no standard input pins, because it's directly connected to a driver on which the calculator software runs.

Is it possible to run the LCD without the calculator software? All pins of the LCD would be available (marked in blue). The pins marked in red were connected to the keyboard of the calculator.

[![Image shows old calculator monochrome LCD circuit][1]][1]

  [1]: https://i.stack.imgur.com/gRG0t.jpg

title: Is it possible to run a monochrome LCD without driver circuit with an Arduino Uno?

Answers: 2

body:
In theory, maybe yes, in practice it will be hard job.

Some things you need to find out:

- Find the exact model of the LCD
- Find its datasheet
- I see an enormous amount of pins (especially the blue ones), so you need (a lot of) multiplexers or shift registers.
- Speed of the Arduino, is it enough to drive this LCD?
- You have to solder this to test.

body:
Normally such LCDs are custom designed, mass produced displays especially for this calculator product. Thus it is very unlikely to find a datasheet or even a meaningful part number for it.

Most likely the pins on the LCD are directly connected to the corresponding fields on the LCD. In an LCD you have liquid crystals between two electrodes, which change their orientation, when a voltage is applied to the electrodes, which changes the light absorption of the layer. You need to apply the correct voltage to a pair of pins to activate their field. Most likely all of the fields or a few groups of them have a common electrode (which would be 1 pin). Without any documentation you are bound to experiment with the display, until you have found the correct voltages and pin arrangements. You might break the display in the process (for example through excess voltage).

I haven't done this myself, but googling gives an interesting result:

- [This project][1], where they hacked the LCD of a cheap calculator for a waveform generator (though the display seems to be way less complex than yours) They seem to use 1.5V as voltage, so this might be a good starting point.

Your display has many pins. Depending on the Arduino model, that you use, you will fast run out of pins to use. You can try arranging the pins into a matrix, which would mean multiplexing the fields (turning them on and off fast one after another). Or you can buy additional parts to extent your pin count, for example shift registers.

---

As jsotola wrote in the comments (and as several forum threads on web web state), you should not put a constant voltage onto the display, since this will damage it. (I guess the liquid crystals will degrade fast because of their polarity, which make the work in the first place). Instead you have to place an alternating voltage at the pins, which changes it's polarity. The  net voltage (The integrated voltage over time) must be zero. Thus you need to alternate the applied voltage. If you provide a span of 1.5V, you need to change between +0.75V and -0.75V.

As the display shouldn't need too much current and the voltage requirement is relative to the LCD ground, you might get way by setting the LCDs ground with a voltage divider to 2.5V and then operating around that. Though I'm not sure about that.

Otherwise you might need to actually change the polarity. This would also just need 1 extra digital output pin as the ground pin. One polarity would be the LCDs ground pin to Arduino's ground (outputting LOW at the digital pin) and the other pins to the needed positive voltage (HIGH divided down over a voltage divider or similar). The other polarity would be LCDs ground pin to the needed positive voltage (HIGH divided down over voltage divider) and the other pins to ground (outputting LOW).

---

As described above, hooking this bare LCD to the Arduino is not done fast and easy. You can try it, if you like to do it. But if you want to get your project (whatever it is) done fast, you should instead buy a LCD with integrated controller, which are mostly ready to use, and for which there are already libraries.

  [1]: https://hackaday.io/project/12756-a-feature-rich-arduino-waveform-generator
  [2]: https://www.electro-tech-online.com/threads/trying-to-hack-a-calculator-lcd-screen.89499/


body:
I have an ESP8266 program that used to work but is now failing to compile with this error:

    C:\...\Arduino\libraries\WiFiManager/WiFiManager.h:25:24: note: in expansion of macro 'PROGMEM'

     const char HTTP_HEAD[] PROGMEM            = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"/><title>{v}</title>";

                            ^

    In file included from C:\...\MyEsp.ino:14:0:

    C:\...AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\libraries\ESP8266WebServer\src/ESP8266WebServer.h:33:39: error: previous declaration of 'HTTPMethod HTTP_HEAD'

     enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_HEAD, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS };
                                       ^

I don't recall changing anything, except maybe updating some libraries. Any ideas what could be causing this?  Here are my includes from the ESP8266 program:

    #include <Arduino.h>

    #include <ESP8266WiFi.h>
    #include <ESP8266WiFiMulti.h>
    #include <ESP8266HTTPClient.h>
    #include <WiFiClient.h>

    #include <DNSServer.h>            //Local DNS Server used for redirecting all requests to the configuration portal
    #include <ESP8266WebServer.h>     //Local WebServer used to serve the configuration portal
    #include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager WiFi Configuration Magic

    #define SERIAL_BUFFER_SIZE 256

title: ESP8266 compilation error: "previous declaration of 'HTTPMethod HTTP_HEAD'"

Answers: 1

body: You need a newer version of the WiFiManager.h library. This issue was [fixed August last year.](https://github.com/tzapu/WiFiManager/commit/ff26ed4e4c1c34465e182af1cde0eb9e8dda6c4a)


body:
I purchased [one of these 4 digit 7 segment displays][1] using a TM1637.

I installed the [TM1637 display library][2] from the libraries manager and included it:

`(#include <TM1637Display.h>)`.

I am trying to display the time, and I would like, preferably, to display 3 digit times with a colon, but without the leading zero.

[I found this great reference online for using the library.][3], and saw the usage for numbers with colons:

`showNumberDecEx(number, dots, leading_zeros, length, position)`

according to the guide, to have the colon in the center, you would pass `0b01000000` as the `dots` parameter.

And I figured that if I then want to display, for example, the time `1:36`, then my `number` parameter would be 136, my `leading_zeros` parameter would be `0` (false), my length would be `3` for a 3 digit number, and my position would by `1` to start the number in the zero-indexed second position:

`display.showNumberDecEx(136, 0b01000000, false, 3, 1); //displays 5136`

But this displayed `5136` with no colon.

I tried a number of other things, including:

`display.showNumberDecEx(136, 0b01000000, true, 3, 0); //displays 13:66`
`display.showNumberDecEx(136, 0b01000000, false, 3, 0); //displays 13:6A`

I finally found [code from this site][4], which works to display the time (albeit with a leading zero), but I don't fully understand it:

`display.showNumberDecEx(1*100+36, 0x80 >> 1, 1, 4, 0);`

I get that 1*100+36 represents number of hours plus minutes, but I don't get the 0x80 >> 1 bit. I'm assuming the rest of it is just saying make it a 4 digit number and add a leading zero.

Can anyone possibly:
* help me understand the above working code
* tell me an easier way to construct a time so that I can ideally just pass a 3 or 4 digit number and have it automatically render out a clock time with separating colon
* tell me why my previous attempts were incorrect

  [1]: https://www.velleman.eu/products/view/?id=439208
  [2]: https://github.com/avishorp/TM1637
  [3]: https://www.makerguides.com/tm1637-arduino-tutorial/
  [4]: https://thestempedia.com/tutorials/making-digital-clock-using-tm1637-4-digit-display/

title: displaying a 3 digit clock time on a 4 digit 7 segment display

Answers: 2

body:
I tested your first code line and it outputs a right aligned 136 without colon at my display. (Said I have only a colon at the middle and no decimal points)

The 5 at the fist digit (and also the A at your third code line) must have been set somewhere beforehand. The function does not change the unused digit, so it will stay whatever you set it to beforehand (Even from before the last reset of the Arduino. The display doesn't reset with the Arduino). You can set the segments for that digit to zero (or set all segments to zero, to clear the complete display) before you show the decimal number.

About the colon: Here it is important on which position you start the printing of the number. The colon/decimal point bitmask, that you provide the function with, is seen from the starting position, that you provide. The middle colon of a 4 digit display is wired to the second digit. When providing `1` as the starting position, you start with the second digit. Thus the colon bitmask must set the most significant ("first") bit, to enable the middle colon, since it belongs to the first digit, that is processed by the function. Meaning:

    position = 0 and bitmask = 0b10000000 --> colon/decimal point at first digit on
    position = 0 and bitmask = 0b01000000 --> colon/decimal point at second digit on
    position = 0 and bitmask = 0b00100000 --> colon/decimal point at third digit on
    position = 1 and bitmask = 0b10000000 --> colon/decimal point at second digit on
    position = 1 and bitmask = 0b01000000 --> colon/decimal point at third digit on
    position = 2 and bitmask = 0b10000000 --> colon/decimal point at third digit on
    position = 2 and bitmask = 0b01000000 --> colon/decimal point at fourth digit on

The `0x80 >> 1` is just a different representation of your binary number. `0x80` is the hexadecimal form of the binary `0b10000000`. The `>>` operator shifts the byte to the right, here by one digit. Thus:

    0x80 >> 1 = 0b10000000 >> 1 = 0x40 = 0b01000000

So the code, that you found, enables the colon/decimal point at the second digit.

>  tell me an easier way to construct a time

Easier it relative. I used such a display in a project to display a time and used two `showNumberDecEx()` calls; one for the minutes and one for the seconds:

    display.showNumberDecEx(seconds, 0x00, true, 2, 2);
    display.showNumberDecEx(minutes, 0x40, true, 2, 0);

Having directly minutes and seconds may make it easier for you. About the no-leading-zeros: Since the library always prints left to right, you need to handle that by yourself. But that is rather easy. One if statement to check, if the minutes are greater than 9 or not. Depending on that you set the position to 0 or 1.

    display.showNumberDecEx(seconds, 0x00, true, 2, 2);
    if(minutes > 9){
        display.showNumberDecEx(minutes, 0x40, false, 2, 0);
    } else {
        display.showNumberDecEx(minutes, 0x80, false, 1, 1);
    }

You could put that into a function, so that you don't have to write this code multiple times.

Note: For my last code snippet to work, you should first clear the display (or optionally only the first digit), so that no number from before will be displayed there.

body:
Always start by reading the docs. The README of the TM1637 display
library gives a short summary of the available functions, then states
“Please refer to TM1637Display.h for more information.” It would thus
seem the authoritative documentation is the header file itself, which is
indeed rich ins structured comments. [According to it][doc], the
signature of `showNumberDecEx()` is

```c++
void showNumberDecEx(int num,
                     uint8_t dots = 0,
                     bool leading_zero = false,
                     uint8_t length = 4,
                     uint8_t pos = 0);
```

where the parameters have the following meanings (emphasis mine):

* `num`: the number to be shown
* `dots`: dot/colon enable [...]
* `leading_zero`: when true, leading zeros are displayed, otherwise
  **unnecessary digits are blank**
* `length`: **the number of digits to set**
* `pos`: the position of the most significant digit
  (0 - leftmost, 3 - rightmost)

The `length` and `pos` parameters control which digits are set. It is
important to note that any digits that are not set _are left as is_.
Note also that, if you are setting more digits than needed to display
the number, the leftmost digits are either zeros _or blank_, depending
on the value of `leading_zero`. And that is exactly what you want: you
want the leftmost digit to be blank.

Here are some examples of what various calls display:

```c++
display.showNumberDecEx(136, 0x40, true,  3, 1)  →  "X1:36"
display.showNumberDecEx(136, 0x40, false, 3, 1)  →  "X1:36"
display.showNumberDecEx(136, 0x40, true,  3, 0)  →  "13:6X"
display.showNumberDecEx(136, 0x40, false, 3, 0)  →  "13:6X"
display.showNumberDecEx(136, 0x40, true,  4, 0)  →  "01:36"
display.showNumberDecEx(136, 0x40, false, 4, 0)  →  " 1:36"
```

In the examples above, “X” means “whatever was previously left there”,
as the corresponding digit is not updated by the call. The last example
is the one you want. Incidentally, the last three parameters of this
example have their default values. You can thus achieve this simply
with:

```c++
display.showNumberDecEx(136, 0x40);
```

You can also follow chrisl's advice and display the hours and minutes
separately:

```c++
int hours = 1;
int minutes = 36;
display.showNumberDecEx(hours, 0x40, false, 2, 0);
display.showNumberDecEx(minutes,  0, true,  2, 2);
```

No need to separately handle the case where `hours` is larger than 9.

[doc]: https://github.com/avishorp/TM1637/blob/v1.2.0/TM1637Display.h#L83-L106


body:
Good day everyone,

           I am facing a problem when trying to use nodemcu  (Nodemcu ESP8266 Lolin V3) to communicate with an RS485 device. I sent an enquiry frame to the device and got the response in bytes. However, the response is not meaningful as it cannot be converted to readable ASCII characters.

           I used the built in Serial for this purpose. Hence i debug the program by sending the program flow state and data received to a server as shown in the Web UI below :-

[![Activity state and response][1]][1]

The response that i expect is the ASCII bytes:-

```
AFC54D48355CC030B14ED8D4B459
```

which is completely different than what is shown in the Web UI above.

Here is the connection and the code that i have tried so far:-

[![enter image description here][2]][2]

  [1]: https://i.stack.imgur.com/DFY0W.png
  [2]: https://i.stack.imgur.com/fLIWw.png

The code :-

```cpp
#include<ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

int enable_pin = 5; //DE and RE pin is jumped together to Nodemcu D1 pin.

String link = "http://someserver.ngrok.io"; //the server

void setup() {
  pinMode(enable_pin,OUTPUT);
  sendActivity("baud_rate_is_set");
  Serial.begin(9600);
  delay(2000);
  digitalWrite(enable_pin,HIGH); //mcu - master : meter - slave
}

void loop() {
  int timeout = 5000;
  int delay_unit = 100;
  byte request[] = {0xb7,0xb7,0xaf,0x3f,0x30,0xb7,0xb4,0xb4,0x36,0x33,0x35,0xb1,0x21,0x8d,0x0a};
  sendActivity("send_enquiry_frame");

  //write
  Serial.write(request,sizeof(request) / sizeof(request[0]));
  digitalWrite(enable_pin,LOW);

  //delay & timeout
  sendActivity("start_waiting_5s");
  int current_delay = 0;
  while(current_delay <= timeout)
  {
    current_delay = current_delay + delay_unit;
    delay(delay_unit);
  }
  sendActivity("done_waiting_5s");

  //get the response part
  if(Serial.available())
  {
    sendActivity("serial_data_available");
    byte serial_receive_buff[200];
    Serial.readBytes(serial_receive_buff,200);
    char buff[200];
    array_to_string(serial_receive_buff,200,buff);
    sendResponse(buff);
  }
  else{
    sendActivity("serial_data_not_available");
  }
  delay(3000);

}

void sendActivity(String act)
{
  HTTPClient http;
  http.begin(link+"/api/activity/"+act);
  int code = http.GET();
}

void sendResponse(String data)
{
  HTTPClient http;
  http.begin(link+"/api/data/"+data);
  int code = http.GET();
}

void array_to_string(byte array[], unsigned int len, char buffer[])
{

    for (unsigned int i = 0; i < len; i++)
    {
        byte nib1 = (array[i] >> 4) & 0x0F;
        byte nib2 = (array[i] >> 0) & 0x0F;
        buffer[i*2+0] = nib1  < 0xA ? '0' + nib1  : 'A' + nib1  - 0xA;
        buffer[i*2+1] = nib2  < 0xA ? '0' + nib2  : 'A' + nib2  - 0xA;
    }
    buffer[len*2] = '\0';
}
```

Can anyone point out what i messed up ? I am stuck on this problem for few days. Thanks a lot.

title: NodeMcu Communication to RS485 Device using TTL to RS485 converter

Answers: 0


body:
I have been working on monitoring an aquaculture , where I log the environment variables (temp. , humidity, gas sensor data) to firebase and control feeding mechanism via an app(where data can also be viewed)

The setup has all sensors connected to Uno Board, which transmits data serially to esp8266.

Pin 2 of Uno is connected to Pin 2 of esp8266

Pin 3 of Uno is connected to Pin 3 of esp8266

Right now the boards are being powered by USB ports in the computer.

My understanding is that, once all the data are read, the ```Serial.available()``` becomes 0 and the ```while()``` loop will not execute again, but it worked again and reads data.. to  avoid sending same data over and over again(to FireBase), I used Boolean values to take care of.

The data should be available only once per 30 seconds, so after a string is fully read, I was able to see that pgm entered into ```while()``` loop and reads one/two values

```C

// uploaded to esp8266 Lolin(wemos) d1 r2 and mini

#include<ESP8266WiFi.h>
#include<FirebaseArduino.h>
#include<SoftwareSerial.h>

// Set these to run example.
#define FIREBASE_HOST "@#$%^.firebaseio.com"
#define FIREBASE_AUTH "********"

#define WIFI_SSID "###########"
#define WIFI_PASSWORD "&^*^*%$#"

SoftwareSerial esp(D2,D3);

float temp_fb;
float gas_fb;
float hum_fb;

unsigned long last_chk = 0 ;
unsigned long time_elapsed;

bool t_ar , h_ar , g_ar = false ; //chk arrival of all data b4 sending

char r;
String cu_st = "c";

int found = 1;

void setup() {
  Serial.begin(9600);
  esp.begin(4800);

  // connect to wifi.
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("connecting");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.println("connected: ");
  Serial.println(WiFi.localIP());

  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
}

void loop()
{
  time_elapsed = millis();
  if(time_elapsed - last_chk > 5000){
    Serial.print("checking for data from arduino...\tfeeder state\t");
    Serial.println(cu_st);
    last_chk = time_elapsed;
    time_elapsed = millis();
  }
   while(esp.available()>0)
  {
     if(found == 1)
     {
      Serial.println("................found data...............") ;
      found = 0;
     }
     r = esp.read();
     //Serial.print("first char\t"); just for debugging purposes
     //Serial.println(r);
     switch(r)
     {

      case 't':
      {
        Serial.println("got t...") ;
        t_ar = true;
        temp_fb = esp.readStringUntil(',').toFloat();
        break ;
      }

      case 'g':
      {
          Serial.println("got g...") ;
          g_ar = true;

          gas_fb = esp.readStringUntil(',').toFloat();;
          break ;
      }

      case 'h':
      {
        Serial.println("got h...") ;
        h_ar = true;

        hum_fb = esp.readStringUntil(',').toFloat();
        break ;
      }

      case 'c':
      {
        cu_st = "c" ;
        Firebase.setString("feeder" ,"c");
      }
      default: break;

     }

  }

  found = 1 ;

  if(g_ar and t_ar and h_ar)
  {
     //writing to firebase
     Serial.println("got the set.. to fb now");
     Firebase.setFloat("GAS SENSORinst" ,gas_fb);
     Firebase.setFloat("HUMIDITY SENSORinst" ,hum_fb);
     Firebase.setFloat("TEMP SENSORinst" ,temp_fb);
     Firebase.pushFloat("GAS SENSOR" ,gas_fb);
     Firebase.pushFloat("HUMIDITY SENSOR" ,hum_fb);
     Firebase.pushFloat("TEMP SENSOR" ,temp_fb);
  }

  t_ar , h_ar , g_ar = false ;

  cu_st = Firebase.getString("feeder");

   if (cu_st == "o")
   {
    Serial.println("\t\trecd req to feed");
    esp.print('o');
   }

}

```
The arduino sends data every 30 Sec.
The servo connected to Arduino was having jitters every time the data was being sent(apparently due to not enough power to supply for all devices connected and both Softwareserial and servo having same timer) so I have added a LED just for trial
For some reason, ```if``` block in ```close_feed()``` is always executed.

```
//uploaded to arduino Uno
#include <SoftwareSerial.h>
#include<TimerOne.h>

SoftwareSerial ArduinoUno(3,2);
#include<Servo.h>
#include "DHT.h"

//Servo feeder;

int send_rate = 30000; //every 30 secs send data
unsigned long last_time_stamp = 0;
unsigned long cur_time = 0;

String sen_vals = "";
#define led 13
int feeding = 0 ;
const int gas = 0;//gas sensor o/p
#define DHTPIN 8
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(9600);
  ArduinoUno.begin(4800);
  pinMode(led,OUTPUT);
  //feeder.attach(11);
  //feeder.write(85);
  Timer1.initialize(10000); //every 10 millisecond check for arrival of feed command
  Timer1.attachInterrupt(feed_cmd); //chk feed_cmd for every 10 mS
   dht.begin();

  pinMode (3,INPUT); //recieve from esp
  pinMode (2,OUTPUT); //transmit to esp

}

void feed_cmd()
{
  while(ArduinoUno.available())
  {
    char valve = ArduinoUno.read();

    if(valve=='o')
    {
       digitalWrite(led, HIGH);
       //feeder.write(0);
       feeding = 1;
       ArduinoUno.print("c");
       valve = "";
    }
  }
}

void close_feed()
{
  if(feeding == 1)
  {

    feeding = 0;
    delay(5000);
    //feeder.write(85);
    digitalWrite(led,LOW);
    Serial.println("I am closing feeder");

   }
}

void send_data()
{
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  String ht = String('h')+String(h)+String(',')+String('t')+String(t)+String(',');

  float raw_v = analogRead(gas);
  String g = String('g')+String(raw_v)+String(',');

  sen_vals = ht + g ;

  Serial.println(sen_vals);
  ArduinoUno.print(sen_vals);
}

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

  close_feed();
  cur_time = millis();
  if(cur_time > last_time_stamp + send_rate)
  {

    last_time_stamp = cur_time;
    send_data();

  }

}

```
Some how some blocks are executed even when they shouldn't be.. I wrote the code, but I cant figure out where the code fails, used a lot of serial prints to see how the flow of the code, but it only confused me further!

If somebody can take a look at this code and point out the flaws..I'll greatly appreciate it.

EDIT: I have changed he code as suggested below, but now the Arduino is receiving random things as input(pic attached)
I have added the changed code too(I know this post is getting bigger and bigger, but i thought making changes to already existing code here won't be good for readability )

``` //uploaded to esp
void setup() {
  Serial.begin(9600);
  esp.begin(4800);

  // connect to wifi.
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("connecting");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.println("connected: ");
  Serial.println(WiFi.localIP());

  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
}

void loop()
{
  time_elapsed = millis();
  if(time_elapsed - last_chk > 5000){
    Serial.print("checking for data from arduino...\tfeeder state\t");
    Serial.println(cu_st);
    last_chk = time_elapsed;
    time_elapsed = millis();
  }
   while(esp.available()>0)
  {
     if(found == 1)
     {
      Serial.println("................found data...............") ;
      found = 0;
     }
     r = esp.read();
     //Serial.print("first char\t");
     //Serial.println(r);
     switch(r)
     {

      case 't':
      {
        Serial.println("got t...") ;
        t_ar = true;
        temp_fb = esp.parseFloat();
        break ;
      }

      case 'g':
      {
          Serial.println("got g...") ;
          g_ar = true;

          gas_fb = esp.parseFloat();;
          break ;
      }

      case 'h':
      {
        Serial.println("got h...") ;
        h_ar = true;
        hum_fb = esp.parseFloat();
        break ;
      }
      default: break;

     }

  }

  found = 1 ;

  if(g_ar and t_ar and h_ar)
  {
     //writing to firebase
     Serial.println("got the set.. to fb now");
     Firebase.setFloat("GAS SENSORinst" ,gas_fb);
     Firebase.setFloat("HUMIDITY SENSORinst" ,hum_fb);
     Firebase.setFloat("TEMP SENSORinst" ,temp_fb);
     Firebase.pushFloat("GAS SENSOR" ,gas_fb);
     Firebase.pushFloat("HUMIDITY SENSOR" ,hum_fb);
     Firebase.pushFloat("TEMP SENSOR" ,temp_fb);
  }

  t_ar , h_ar , g_ar = false ;
  if (cu_st == "c")
  {
    sent = 0;
  }
  cu_st = Firebase.getString("feeder");
   if (cu_st == "o")
   {
    Serial.println("\t\trecd req to feed");
    if(sent == 0)
    {
      esp.print('o');
      sent =1;
      cu_st = "c";
      Serial.println("setting feeder to close in firebase");
      Firebase.setString("feeder" ,"c");

   }

  }
}

```

```//to arduino
#include <SoftwareSerial.h>

SoftwareSerial ArduinoUno(3,2);
#include<Servo.h>
#include "DHT.h"

//Servo feeder;

int send_rate = 30000; //every 30 secs send data
unsigned long last_time_stamp = 0;
unsigned long cur_time = 0;
unsigned long close_time = 0;
unsigned long open_time = 0;
#define led 13
int feeder = 0 ;
const int gas = 0;//gas sensor o/p
#define DHTPIN 8
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(9600);
  ArduinoUno.begin(4800);
  pinMode(led,OUTPUT);
  //feeder.attach(11);
  //feeder.write(85); //closing position
   dht.begin();

  pinMode (3,INPUT); //recieve from esp
  pinMode (2,OUTPUT); //transmit to esp

}

void feed_cmd()
{
  while(ArduinoUno.available())
  {
    char valve = ArduinoUno.read();
    Serial.print("feeder cmd recd ");
    Serial.println(valve);
    if(valve=='o')
    {
       digitalWrite(led, HIGH);
       //feeder.write(0); //open position
       open_time = millis();
       feeder = 1 ;
       Serial.println("I am opening feeder");
    }
  }
}

void close_feed()
{

  if(feeder == 1)
  {
   close_time = millis();
   if(close_time - open_time > 5000)
  {
    feeder = 0;
    digitalWrite(led , LOW);
    Serial.println("I am closing feeder") ;
  }
  }
}

void send_data()
{
  float h = dht.readHumidity();

  float t = dht.readTemperature();

  float raw_v = analogRead(gas);

  ArduinoUno.print("h");
  ArduinoUno.print(h);
  ArduinoUno.print(",t");
  ArduinoUno.print(t);
  ArduinoUno.print(",g");
  ArduinoUno.print(raw_v);
  ArduinoUno.print(",\n");
}

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

  feed_cmd();
  close_feed();
  cur_time = millis();
  if(cur_time - last_time_stamp > send_rate)
  {

    last_time_stamp = cur_time;
    send_data();

  }

}
```
[![here's a pic showing random char][1]][1]
Thanks for your time!!!

  [1]: https://i.stack.imgur.com/kGQBF.jpg

title: Fixing serial communication , condition for serial data available checks out even after reading all the data sent

Answers: 1

body:
I cannot really narrow down the source of your observed problems, since the problem descriptions are not clear enough. But there are some obvious problems/potential for making it better in your code.

In the Uno Code:

- It is totally unnecessary to use a timer interrupt for reading the SoftwareSerial interface. Instead you should write your `loop()` function non-blocking, meaning, that it does not wait for something to happen, but it will execute other code in the meantime (so no delay in `close_feed()`). Then you can just read the serial data in the loop function. You are saving a timer this way.

- In `send_data()` you are using the `String` class to concat a string of human readable data together and then send it. Using the `String` class in that way is evil, since on every concat operation it will allocate a new buffer for the string, deleting the old one. That makes Swiss cheese out of your heap memory (called heap fragmentation). That can lead to instability. Look at [Majenko's blog entry about the Evils of Arduino Strings][1] for more information. Instead of concatting you should simply print the information one after another:

        Serial.print("h");
        Serial.print(h);
        Serial.print(",t");
        Serial.print(t);

    and so forth.

- Your handling of the `millis()` function should be different. It will roll over after 52 days. To prevent, that your code misfunctions at that time, you need to always take the time difference:

        if(cur_time - last_time_stamp > send_rate)

    instead of

        if(cur_time > last_time_stamp + send_rate)

In the ESP Code:

- Your SoftwareSerial read code seems weird to me, but I think it should work. I would introduce a message protocol to the data stream, meaning to mark the end of a full message (a message containing one frame with all relevant data) with a special delimiter character, for example a newline character `\n`. Then you can read the message until this character into a buffer and then process the message as a whole.

---

That's about what I can say to this point. If you need a more focused answer, you have you describe further and more detailed the symptoms (what behavior you are seeing and what you expected).

  [1]: https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/


body:
I want to try making big electrodes 20cm*1 cm
but i got an effect i dont understand.
In the picture red and blue are the diffrent electrodes
at first touch the blue  one and it rises.
then i touched the red  one and it rises.
when i touch both electrodes both signals dropps ??
when itouch both with gloves both rise ??

i think its not allowed to touch the pure cooper

 Also i would like to know whats the output from the mesure funktion of the  free touch libary  (physical dimension ,like time or voltage??)

    #include "Adafruit_FreeTouch.h"

    Adafruit_FreeTouch qt_2 = Adafruit_FreeTouch(A1, OVERSAMPLE_4, RESISTOR_50K, FREQ_MODE_NONE);
    Adafruit_FreeTouch qt_3 = Adafruit_FreeTouch(A2, OVERSAMPLE_4, RESISTOR_50K, FREQ_MODE_NONE);

    void setup() {
      Serial.begin(115200);

      while (!Serial);
      Serial.println("FreeTouch test");
      // initialize digital pin LED_BUILTIN as an output.
      pinMode(LED_BUILTIN, OUTPUT);

      if (! qt_2.begin())
        Serial.println("Failed to begin qt on pin A1");
      if (! qt_3.begin())
        Serial.println("Failed to begin qt on pin A2");

    }

    void loop() {
      int counter,result2,result3, result = 0;

      counter = millis();
      result = qt_2.measure();
      result2=result;

      counter = millis();
      result = qt_3.measure();
      result3=result;
        Serial.print(result2);
        Serial.print(" ");
        Serial.println(result3);
      delay(200);
    }

[![enter image description here][1]][1]

[![enter image description here][2]][2]

  [1]: https://i.stack.imgur.com/QDMdp.png
  [2]: https://i.stack.imgur.com/gOTmF.png

---

the problem was that i touch de the electrodes on the copperside instead for the rearside

title: Free touch big electrodes (arduino zero)

Answers: 0


body:
I'm building a thermostat control with a Wemos D1 Mini. The ILI9341 display uses almost all the pins, and all I have left are the RX, TX, A0 and D0 pins. However I can't get any valid readings from these pins. [According to the various wemos pinouts][1], I should be able to use RX/TX as onewire pins. As soon as I set the pin to a different one, and replace the wire there, I have correct readings. What am I missing with using these pins?

I'm connecting the display as stated in this arcticle: [link][2]

I also found [this site][3] which shows that I should be able to set these two pins as IO pins.

    #include <ESP8266WiFi.h>
    #include <WiFiClient.h>
    #include <ESP8266WebServer.h>
    #include <OneWire.h>
    #include <DallasTemperature.h>

    #ifndef STASSID
    #define STASSID "wifiname"
    #define STAPSK  "password"
    #endif

    const char* ssid = STASSID;
    const char* password = STAPSK;

    ESP8266WebServer server(80);

    OneWire oneWire(1);
    DallasTemperature sensors(&oneWire);

    void handleRoot() {
      sensors.requestTemperatures();
      server.send(200, "text/plain", String(sensors.getTempCByIndex(0)));
    }

    void setup() {
      pinMode(1, FUNCTION_3);
      WiFi.mode(WIFI_STA);
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
      }

      server.on("/", handleRoot);
      server.begin();
      sensors.begin();
    }

    void loop() {
      server.handleClient();
    }

  [1]: https://www.luisllamas.es/wp-content/uploads/2018/09/pinout-wemos-mini-d1.png
  [2]: https://www.instructables.com/id/ILI9341-Touch-Shield-for-Wemos-D1-Mini/
  [3]: https://www.esp8266.com/wiki/doku.php?id=esp8266_gpio_pin_allocations

title: How can I use Wemos D1's TX pin as OneWire?

Answers: 0


body:
I am new to this Arduino community
I noticed on youtube that while the prototype is complete people purchase new ATmega328p chips and flash bootloaders into them using in-system-programmers so that the chip could actually understand and interpret the instructions that are written in the high-level language if I am right(No I was wrong, it's actually the compiler that sits on Arduino). so I thought what if we could burn the atmega328p bootloader into any other microcontroller. So that we could program it in Arduino programming language(C/C++). Is this possible? sorry if I am dumb, but I wanted to know. And can anyone tell me whether could we use ATmega328p for production purposes(consumer electronics)? Thanks in advance.

title: Can we burn Arduino bootloader into any microcontroller chip?

Answers: 2

body:
You cannot just load a sketch into any microcontroller, because every microcontroller has different memory layout, peripherals, ways of uploading, FLASH size etc.

You can use the atMega (or any microcontroller) for production purposes though. Of course each MCU type has operation conditions (like min/max temperature), so in e.g. automotive or military environments not all MCUs are allowed to be used, but for consumer electronics, afaik all MCUs can be used (meaning they will pass by themselves the needed certifications, which may not be true for components added and the circuit/enclosure resulting out of it).

body:
The answer needs to have multiple parts:

**Yes, in principle you can create a bootloader for any microcontroller, which acts like the Arduino's.**

Please be aware that there are different bootloaders, not just the common STK500 compatible one. Each of these bootloaders implements a certain protocol to transfer the binary code to the target system.

Additionally, some protocols also include commands to restart the microcontroller, to set configuration registers, and maybe more.

You need to read the bootloader's documentation to become familiar with its capabilities.

But it is your decision whether such a bootloader on a non-AVR system or an non-Arduino-AVR system is good for you.

**No, the bootloader does *not* enable the microcontroller to "understand" the high-level language.**

The standard Arduino IDE uses the specific compiler for the target microcontroller to translate the C++ source code to machine language. The resulting binary commonly runs on this target microcontroller only.

The bootloader just implements the protocol. In general, it is completely unaware of the meaning of the transferred data.

Microcontrollers in general use different processors with possibly different machine languages, contain different kinds of memory of different sizes, include different sets of different peripherals. But you know this for sure. You need to write and compile your source code for the specific part you're targeting.

**Yes, you can use ATmega328P for a consumer product, as Michel already said.**

You need to take the common measures that you take with *any* part of your product, though.