user37827: I think this is my last post about this specific project, but I got a really weird curveball right now
I managed to do the webpage I wanted, and pass the string along. Now, when a LED lights up, it sends the corresponding letter to the LCD.
The problem now is that somehow, when I send a long string, the LCD somehow "knows" and display the overflow on the second row, which makes no sense to me. All I can think of is that the Ethernet Shield is using the same connections as my I2C that connects to the LCD.
That being said, here is my code:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <Ethernet.h>
#define latchPin 5
#define clockPin 7
#define dataPin 6

LiquidCrystal_I2C lcd(0x27,16,2);
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 
EthernetServer server(80);
String text; 
char readHttp[100];
int i;
boolean temtexto;
char lcdtext[16];
void setup() {
  Serial.begin(9600);
  for (int i = 2; i < 7; i++) {
    if (i != 4) {
      pinMode(i, OUTPUT);
    }
   }
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);
  lcd.init();
  lcd.setBacklight(HIGH);
  lcd.setCursor(0,0);
  lcd.print("INICIANDO");
  Serial.println("Iniciando");
  if (Ethernet.begin(mac) == 0) {
    lcd.clear();
    lcd.setCursor(1,0);
    lcd.print("FALHA AO PEGAR");
    Serial.println("FALHA");
    lcd.setCursor(7,1);
    lcd.print("IP");
    delay(5000);
    return;
  }

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("PRONTO");
  lcd.setCursor(0,1);
  lcd.print(Ethernet.localIP());
  lcd.setCursor(0,0);
  Serial.println(Ethernet.localIP());
  server.begin();
  brilho(255);
  inicializationEffect();
}

void loop(){
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        lcd.setBacklight(LOW);
        lcd.clear();
        char c = client.read();
        if (c == ';') { temtexto = false; readHttp[i] = '\n';}
        if (temtexto) {
          if(i < 100) {
            readHttp[i] = toupper(c);
            i++;
          } 
        }
        if (c == '?') { temtexto = true; }
        if (c == '\n') {
          client.println("HTTP/1.1 200 OK"); // Envia nova pagina
          client.println("Content-Type: text/html");
          client.println("Connection: close"); 
          client.println();
          client.println("<HTML>");
          client.println("<HEAD>");
          client.println("<TITLE>Parede Stranger Things</TITLE>");
          client.println("</HEAD>");
          client.println("<BODY>");
          client.println("<H1>Qual texto deseja enviar?</H1>");
          client.println("<input type=text id=texto style=width:295px  maxlength=50><br>");
          client.println("<input type=submit value='Enviar' style=width:150px;height:45px onClick=location.href='/?'+document.getElementById('texto').value+';'>");
          client.println("</BODY>");
          client.println("</HTML>");
          client.println("<string>");

          
          client.println("</string>");          
          delay(1);
          client.stop();
          char *leader = readHttp;
          char *follower = leader;
          
          // While we're not at the end of the string (current character not NULL)
          while (*leader) {
              // Check to see if the current character is a %
              if (*leader == '%') {
          
                  // Grab the next two characters and move leader forwards
                  leader++;
                  char high = *leader;
                  leader++;
                  char low = *leader;
          
                  // Convert ASCII 0-9A-F to a value 0-15
                  if (high > 0x39) high -= 7;
                  high &= 0x0f;
          
                  // Same again for the low byte:
                  if (low > 0x39) low -= 7;
                  low &= 0x0f;
          
                  // Combine the two into a single byte and store in follower:
                  *follower = (high << 4) | low;
              } else {
                  // All other characters copy verbatim
                  *follower = *leader;
              }
          
              // Move both pointers to the next character:
              leader++;
              follower++;
          }
          // Terminate the new string with a NULL character to trim it off
          *follower = 0;
          lcd.clear();
          executeEffect(readHttp);
          memset(readHttp, 0, sizeof readHttp);
          i = 0;
        }
      }
    }
  }
}




void lineActivation(int line, int keepalive) {
  if (keepalive == 0) {
    for (int i = 2; i <= 4; i++) {
      if (i == 4) { i = 8; } //porta 4 usada pelo SD do Ethernet
      digitalWrite(i, LOW);
    }
  }
  if (line >= 1 && line <=3){
    if (line == 3) { line = 7; } //porta 4 usada pelo SD do Ethernet
    digitalWrite(line+1, HIGH); //coloca a linha 1 em estado lógico alto
  }
}

void activateLetter(char letter, int on, int off) {
  int lt;
  lt = (((int)letter - 64) % 9);
  if (((int)letter - 64) > 8) {
    lt = lt + 1;
  }
  if (on) {
    callCol(1<<lt-1);
    delay(on);
  }
  if (off) {
    callCol(0);
    delay(off);
  }
}

void callCol(int col){
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, highByte(col));
  shiftOut(dataPin, clockPin, MSBFIRST, lowByte(col));
  digitalWrite(latchPin, HIGH);
}

void executeEffect(char text[]) {
  if (strlen(text) > 0) {
    brilho(255);
    lcd.setBacklight(HIGH);
    memset(lcdtext, ' ', sizeof lcdtext);  
  }
  for (int i = 0; i < strlen(text); i++) {
    if (text[i] == ' ') {
      lcdScreen(' ');
      delay(1000);
    } else if (((int)text[i] < -58 && (int)text[i] > -65) || ((int)text[i] < -28 && (int)text[i] > -33)) {
      text[i] = 'A';
    } else if (((int)text[i] < -47 && (int)text[i] > -41) || ((int)text[i] < -9 && (int)text[i] > -14)) {
      text[i] = 'O';
    } else if (((int)text[i] < -52 && (int)text[i] > -57) || ((int)text[i] < -20 && (int)text[i] > -25)) {
      text[i] = 'E';
    } else if (((int)text[i] < -49 && (int)text[i] > -53) || ((int)text[i] < -16 && (int)text[i] > -21)) {
      text[i] = 'I';
    } else if (((int)text[i] < -35 && (int)text[i] > -40) || ((int)text[i] < -3 && (int)text[i] > -8)) {
      text[i] = 'U';
    } else if (((int)text[i] == -25 || (int)text[i] == -57)) {
      text[i] = 'C';
    }
    if ((int)text[i] < 65 or (int)text[i] > 90) {
    } else {
      lineActivation(int(((int)text[i] - 64) / 9) + 1, 0);
      //Serial.println(text[i]);
      lcdScreen(text[i]);
      activateLetter(text[i], 1000, 200);
    }
  }
  for (int i = 0; i < 16; i++){
    lcdScreen(' ');
    delay(500);
  }
  lcd.setBacklight(LOW);
  lcd.clear();
}

void lcdScreen(char ltc) {
  Serial.println(ltc);
  memcpy(lcdtext, &lcdtext[1], sizeof(lcdtext) - sizeof(char));
  lcdtext[15] =  ltc;
  lcd.setCursor(0,0);
  lcd.print(lcdtext);
}

void inicializationEffect() {
  Serial.println("LineByLine");
  for (int i = 1; i < 27; i++) {
    lineActivation(int(i / 9) + 1, 0);//ativa a linha
    activateLetter(char(64 + i), 100, 10); //ativa a letra
  }
}

void waveEffect() {
  Serial.println("Wave");
  for (int i = 1; i < 4; i++) {
    lineActivation(i, 1);//ativa a linha
  }
  for (int i = 1; i < 10; i++) {
    activateLetter(char(72 + i), 100, 0);
  }

  for (int i = 1; i < 10; i++) {
    activateLetter(char(72 + i), 0, 100);
  }
  lineActivation(0, 0);
}

void blink() {
  Serial.println("Blink");
  callCol(511);
  lineActivation(1,1);
  lineActivation(2,1);
  lineActivation(3,1);
  for (int i = 0; i < 256; i++){
    brilho(i);
    delay(1);
  }
  delay(100);
  for (int i = 255; i >= 0; i--){
    brilho(i);
    delay(1);
  }
}

void brilho(byte brt) {
  analogWrite(9, 255-brt);
}

I am using a W5100 Ethernet Shield, a I2C to LCD adapter and a 16x2 LCD. The I2C is connected to the pins A4(SDA) and A5(SCL).
Here is a picture of how the LCD appears when I send "This is a really long string":

On the first line the text scrolls, one character at a time, as intended. However, on the second line there is an overflow of the text that, as far as I can tell, I never sent to the LCD in the first place. Even if I try to lcd.clear() after every character sent, it still persists with the end of the string on the second line.

user70020: I think what you're seeing is the result of:
lcd.print(lcdtext);

and the fact that lcdtext is not null-terminated.  print() is expecting
a string, that is some sequence of zero or more non-'\0' characters followed by a '\0' character.  Not having null-terminated it yourself, in practice it will continue reading memory after your the location of lcdtext in memory until it finds a '\0'.  Somewhere in there it is probably finding the extra character(s) that you're seeing.
You could make a point of having '\0' at the end of it always, making lcdtext one character larger if necessary in order to do that.  Or you could:
lcd.write(lcdtext, sizeof lcdtext);

In this form with the length/size as a second argument, write doesn't expect a string, just an arbitrary chunk of characters whether they contain '\0' or not and knows to stop at whatever count of characters was specified.
As an aside memmove should be used rather than memcpy when the input and output destinations overlap.  What happens with memcpy when they do overlap is undefined:
memmove(lcdtext, &lcdtext[1], sizeof(lcdtext) - 1);

memmove is outwardly the same thing, only designed for this scenario.  The difference between them is a matter of which optimizations are enabled by the knowledge that the source and destination may or may not overlap. It may not be a source of a problem on your current platform, depending on how memcpy was written, but it may later or when you switch platforms.

37827: <p>I think this is my last post about this specific project, but I got a really weird curveball right now</p>
<p>I managed to do the webpage I wanted, and pass the string along. Now, when a LED lights up, it sends the corresponding letter to the LCD.</p>
<p>The problem now is that somehow, when I send a long string, the LCD somehow &quot;knows&quot; and display the overflow on the second row, which makes no sense to me. All I can think of is that the Ethernet Shield is using the same connections as my I2C that connects to the LCD.</p>
<p>That being said, here is my code:</p>
<pre><code>#include &lt;Wire.h&gt;
#include &lt;LiquidCrystal_I2C.h&gt;
#include &lt;SPI.h&gt;
#include &lt;Ethernet.h&gt;
#define latchPin 5
#define clockPin 7
#define dataPin 6

LiquidCrystal_I2C lcd(0x27,16,2);
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 
EthernetServer server(80);
String text; 
char readHttp[100];
int i;
boolean temtexto;
char lcdtext[16];
void setup() {
  Serial.begin(9600);
  for (int i = 2; i &lt; 7; i++) {
    if (i != 4) {
      pinMode(i, OUTPUT);
    }
   }
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);
  lcd.init();
  lcd.setBacklight(HIGH);
  lcd.setCursor(0,0);
  lcd.print(&quot;INICIANDO&quot;);
  Serial.println(&quot;Iniciando&quot;);
  if (Ethernet.begin(mac) == 0) {
    lcd.clear();
    lcd.setCursor(1,0);
    lcd.print(&quot;FALHA AO PEGAR&quot;);
    Serial.println(&quot;FALHA&quot;);
    lcd.setCursor(7,1);
    lcd.print(&quot;IP&quot;);
    delay(5000);
    return;
  }

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(&quot;PRONTO&quot;);
  lcd.setCursor(0,1);
  lcd.print(Ethernet.localIP());
  lcd.setCursor(0,0);
  Serial.println(Ethernet.localIP());
  server.begin();
  brilho(255);
  inicializationEffect();
}

void loop(){
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        lcd.setBacklight(LOW);
        lcd.clear();
        char c = client.read();
        if (c == ';') { temtexto = false; readHttp[i] = '\n';}
        if (temtexto) {
          if(i &lt; 100) {
            readHttp[i] = toupper(c);
            i++;
          } 
        }
        if (c == '?') { temtexto = true; }
        if (c == '\n') {
          client.println(&quot;HTTP/1.1 200 OK&quot;); // Envia nova pagina
          client.println(&quot;Content-Type: text/html&quot;);
          client.println(&quot;Connection: close&quot;); 
          client.println();
          client.println(&quot;&lt;HTML&gt;&quot;);
          client.println(&quot;&lt;HEAD&gt;&quot;);
          client.println(&quot;&lt;TITLE&gt;Parede Stranger Things&lt;/TITLE&gt;&quot;);
          client.println(&quot;&lt;/HEAD&gt;&quot;);
          client.println(&quot;&lt;BODY&gt;&quot;);
          client.println(&quot;&lt;H1&gt;Qual texto deseja enviar?&lt;/H1&gt;&quot;);
          client.println(&quot;&lt;input type=text id=texto style=width:295px  maxlength=50&gt;&lt;br&gt;&quot;);
          client.println(&quot;&lt;input type=submit value='Enviar' style=width:150px;height:45px onClick=location.href='/?'+document.getElementById('texto').value+';'&gt;&quot;);
          client.println(&quot;&lt;/BODY&gt;&quot;);
          client.println(&quot;&lt;/HTML&gt;&quot;);
          client.println(&quot;&lt;string&gt;&quot;);

          
          client.println(&quot;&lt;/string&gt;&quot;);          
          delay(1);
          client.stop();
          char *leader = readHttp;
          char *follower = leader;
          
          // While we're not at the end of the string (current character not NULL)
          while (*leader) {
              // Check to see if the current character is a %
              if (*leader == '%') {
          
                  // Grab the next two characters and move leader forwards
                  leader++;
                  char high = *leader;
                  leader++;
                  char low = *leader;
          
                  // Convert ASCII 0-9A-F to a value 0-15
                  if (high &gt; 0x39) high -= 7;
                  high &amp;= 0x0f;
          
                  // Same again for the low byte:
                  if (low &gt; 0x39) low -= 7;
                  low &amp;= 0x0f;
          
                  // Combine the two into a single byte and store in follower:
                  *follower = (high &lt;&lt; 4) | low;
              } else {
                  // All other characters copy verbatim
                  *follower = *leader;
              }
          
              // Move both pointers to the next character:
              leader++;
              follower++;
          }
          // Terminate the new string with a NULL character to trim it off
          *follower = 0;
          lcd.clear();
          executeEffect(readHttp);
          memset(readHttp, 0, sizeof readHttp);
          i = 0;
        }
      }
    }
  }
}




void lineActivation(int line, int keepalive) {
  if (keepalive == 0) {
    for (int i = 2; i &lt;= 4; i++) {
      if (i == 4) { i = 8; } //porta 4 usada pelo SD do Ethernet
      digitalWrite(i, LOW);
    }
  }
  if (line &gt;= 1 &amp;&amp; line &lt;=3){
    if (line == 3) { line = 7; } //porta 4 usada pelo SD do Ethernet
    digitalWrite(line+1, HIGH); //coloca a linha 1 em estado lógico alto
  }
}

void activateLetter(char letter, int on, int off) {
  int lt;
  lt = (((int)letter - 64) % 9);
  if (((int)letter - 64) &gt; 8) {
    lt = lt + 1;
  }
  if (on) {
    callCol(1&lt;&lt;lt-1);
    delay(on);
  }
  if (off) {
    callCol(0);
    delay(off);
  }
}

void callCol(int col){
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, highByte(col));
  shiftOut(dataPin, clockPin, MSBFIRST, lowByte(col));
  digitalWrite(latchPin, HIGH);
}

void executeEffect(char text[]) {
  if (strlen(text) &gt; 0) {
    brilho(255);
    lcd.setBacklight(HIGH);
    memset(lcdtext, ' ', sizeof lcdtext);  
  }
  for (int i = 0; i &lt; strlen(text); i++) {
    if (text[i] == ' ') {
      lcdScreen(' ');
      delay(1000);
    } else if (((int)text[i] &lt; -58 &amp;&amp; (int)text[i] &gt; -65) || ((int)text[i] &lt; -28 &amp;&amp; (int)text[i] &gt; -33)) {
      text[i] = 'A';
    } else if (((int)text[i] &lt; -47 &amp;&amp; (int)text[i] &gt; -41) || ((int)text[i] &lt; -9 &amp;&amp; (int)text[i] &gt; -14)) {
      text[i] = 'O';
    } else if (((int)text[i] &lt; -52 &amp;&amp; (int)text[i] &gt; -57) || ((int)text[i] &lt; -20 &amp;&amp; (int)text[i] &gt; -25)) {
      text[i] = 'E';
    } else if (((int)text[i] &lt; -49 &amp;&amp; (int)text[i] &gt; -53) || ((int)text[i] &lt; -16 &amp;&amp; (int)text[i] &gt; -21)) {
      text[i] = 'I';
    } else if (((int)text[i] &lt; -35 &amp;&amp; (int)text[i] &gt; -40) || ((int)text[i] &lt; -3 &amp;&amp; (int)text[i] &gt; -8)) {
      text[i] = 'U';
    } else if (((int)text[i] == -25 || (int)text[i] == -57)) {
      text[i] = 'C';
    }
    if ((int)text[i] &lt; 65 or (int)text[i] &gt; 90) {
    } else {
      lineActivation(int(((int)text[i] - 64) / 9) + 1, 0);
      //Serial.println(text[i]);
      lcdScreen(text[i]);
      activateLetter(text[i], 1000, 200);
    }
  }
  for (int i = 0; i &lt; 16; i++){
    lcdScreen(' ');
    delay(500);
  }
  lcd.setBacklight(LOW);
  lcd.clear();
}

void lcdScreen(char ltc) {
  Serial.println(ltc);
  memcpy(lcdtext, &amp;lcdtext[1], sizeof(lcdtext) - sizeof(char));
  lcdtext[15] =  ltc;
  lcd.setCursor(0,0);
  lcd.print(lcdtext);
}

void inicializationEffect() {
  Serial.println(&quot;LineByLine&quot;);
  for (int i = 1; i &lt; 27; i++) {
    lineActivation(int(i / 9) + 1, 0);//ativa a linha
    activateLetter(char(64 + i), 100, 10); //ativa a letra
  }
}

void waveEffect() {
  Serial.println(&quot;Wave&quot;);
  for (int i = 1; i &lt; 4; i++) {
    lineActivation(i, 1);//ativa a linha
  }
  for (int i = 1; i &lt; 10; i++) {
    activateLetter(char(72 + i), 100, 0);
  }

  for (int i = 1; i &lt; 10; i++) {
    activateLetter(char(72 + i), 0, 100);
  }
  lineActivation(0, 0);
}

void blink() {
  Serial.println(&quot;Blink&quot;);
  callCol(511);
  lineActivation(1,1);
  lineActivation(2,1);
  lineActivation(3,1);
  for (int i = 0; i &lt; 256; i++){
    brilho(i);
    delay(1);
  }
  delay(100);
  for (int i = 255; i &gt;= 0; i--){
    brilho(i);
    delay(1);
  }
}

void brilho(byte brt) {
  analogWrite(9, 255-brt);
}
</code></pre>
<p>I am using a W5100 Ethernet Shield, a I2C to LCD adapter and a 16x2 LCD. The I2C is connected to the pins A4(SDA) and A5(SCL).</p>
<p>Here is a picture of how the LCD appears when I send &quot;This is a really long string&quot;:</p>
<p><a href="https://i.stack.imgur.com/omqht.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/omqht.jpg" alt="enter image description here" /></a></p>
<p>On the first line the text scrolls, one character at a time, as intended. However, on the second line there is an overflow of the text that, as far as I can tell, I never sent to the LCD in the first place. Even if I try to lcd.clear() after every character sent, it still persists with the end of the string on the second line.</p>
 70020: <p>I think what you're seeing is the result of:</p>
<pre><code>lcd.print(lcdtext);
</code></pre>
<p>and the fact that lcdtext is not null-terminated.  <code>print()</code> is expecting
a string, that is some sequence of zero or more non-'\0' characters followed by a <code>'\0'</code> character.  Not having null-terminated it yourself, in practice it will continue reading memory after your the location of lcdtext in memory until it finds a <code>'\0'</code>.  Somewhere in there it is probably finding the extra character(s) that you're seeing.</p>
<p>You could make a point of having <code>'\0'</code> at the end of it always, making lcdtext one character larger if necessary in order to do that.  Or you could:</p>
<pre><code>lcd.write(lcdtext, sizeof lcdtext);
</code></pre>
<p>In this form with the length/size as a second argument, <code>write</code> doesn't expect a string, just an arbitrary chunk of characters whether they contain <code>'\0'</code> or not and knows to stop at whatever count of characters was specified.</p>
<p>As an aside <code>memmove</code> should be used rather than <code>memcpy</code> when the input and output destinations overlap.  What happens with <code>memcpy</code> when they do overlap is undefined:</p>
<pre><code>memmove(lcdtext, &amp;lcdtext[1], sizeof(lcdtext) - 1);
</code></pre>
<p><code>memmove</code> is outwardly the same thing, only designed for this scenario.  The difference between them is a matter of which optimizations are enabled by the knowledge that the source and destination may or may not overlap. It may not be a source of a problem on your current platform, depending on how memcpy was written, but it may later or when you switch platforms.</p>
