Início
/
Software
/
Comunicação Serial Profissional no Arduino: char[], Buffer e Controle de Memória
Comunicação Serial Profissional no Arduino: char[], Buffer e Controle de Memória
Angelo Luis Ferreira | 25/02/2026
Acessos: 38
Comunicação Serial Profissional no Arduino: uso do char[]
Objetivo
O objetivo deste artigo é aprofundar o estudo da comunicação serial no Arduino, apresentando uma abordagem mais robusta e profissional utilizando char[] (arrays de caracteres) e leitura não bloqueante.

Partindo dos conceitos já apresentados no artigo anterior, aqui iremos explorar técnicas que oferecem maior controle de memória, previsibilidade de execução e estabilidade em sistemas embarcados.
Ao final desta leitura, você será capaz de:
-
Implementar leitura serial não bloqueante utilizando Serial.available() e Serial.read()
-
Manipular strings no padrão C utilizando char[]
-
Utilizar funções da biblioteca <string.h>, como strcmp(), strncmp(), strcpy(), strcat() e strlen()
-
Entender o papel do terminador nulo '\0' no funcionamento das strings em C
-
Definir corretamente o tamanho de buffers para evitar desperdício de memória
-
Proteger o sistema contra overflow (estouro de buffer)
-
Compreender os riscos de fragmentação de heap ao usar String
-
Desenvolver interpretadores de comandos mais previsíveis e seguros
Este conteúdo é voltado para quem deseja evoluir da prototipagem simples para uma abordagem mais próxima da prática profissional em sistemas embarcados.
Ao final do artigo, você terá não apenas um código funcional, mas também compreensão técnica suficiente para projetar sistemas de comunicação serial mais estáveis, eficientes e adequados a aplicações de maior complexidade.
Referência
Este artigo é a continuação do conteúdo apresentado em:
Comunicação Serial no Arduino com Monitor Serial – Fundamentos e Uso com String
Recomenda-se a leitura prévia para melhor compreensão dos conceitos básicos abordados aqui.
Definições
Comunicação Serial
Comunicação serial é a transmissão sequencial de dados, bit a bit, entre dois dispositivos. No Arduino Uno e Mega, essa comunicação ocorre pela interface UART (Universal Asynchronous Receiver Transmitter) e é acessada através do objeto Serial.
Monitor Serial
O Monitor Serial da Arduino IDE é a interface que permite enviar e receber dados pela porta USB. Ele funciona como um terminal bidirecional para testes, depuração e simulação de comandos.
Baud Rate
Baud Rate é a velocidade da comunicação serial, medida em bits por segundo (bps). O valor configurado em Serial.begin() deve ser o mesmo selecionado no Monitor Serial, caso contrário os dados aparecerão corrompidos.
Observação sobre os pinos 0 e 1 no Arduino UNO
No Arduino Uno, os pinos 0 (RX) e 1 (TX) são compartilhados com a USB. Dispositivos conectados nesses pinos podem interferir no upload do código.
Objeto Serial – Contextualização Rápida
No Arduino, Serial é um objeto global responsável pela comunicação serial entre o microcontrolador e o computador.
Ele é uma instância da classe HardwareSerial, criada automaticamente pelo núcleo da plataforma, e fornece métodos que permitem:
-
Inicializar a comunicação (Serial.begin())
-
Enviar dados (Serial.print() / Serial.println())
-
Verificar dados recebidos (Serial.available())
-
Ler dados do buffer (Serial.read())
- Enviar dados para a porta serial (
Serial.write())
No Arduino Uno, esse objeto opera sobre a UART interna do microcontrolador, conectada ao conversor USB-Serial da placa.
Neste artigo, utilizaremos o objeto Serial principalmente para:
-
Implementar leitura não bloqueante
-
Manipular dados byte a byte
-
Controlar manualmente o armazenamento em buffers (char[])
Buffer no Contexto do Objeto Serial
O objeto Serial utiliza dois buffers internos:
No Arduino Uno, cada buffer possui normalmente 64 bytes.
Fluxo simplificado:
A leitura correta desses buffers é fundamental para:
No artigo anterior, utilizamos métodos como Serial.readStringUntil().
Neste artigo, adotaremos a abordagem mais profissional:
while (Serial.available() > 0) {
char c = Serial.read();
}
Essa técnica evita bloqueios e oferece maior controle sobre o processamento dos dados.
Serial.available() e Serial.read() na Comunicação com char[]
Quando utilizamos char[] para montar comandos manualmente, dois métodos se tornam centrais:
-
Serial.available()
-
Serial.read()
Eles permitem implementar uma leitura não bloqueante, byte a byte, com controle total do buffer.
Serial.available()
Sintax:
Serial.available();
-
Retorna a quantidade de bytes disponíveis no buffer de recepção (RX).
-
No Monitor Serial da Arduino IDE, cada caractere enviado corresponde a 1 byte (com valor de 0 a 255).
-
No Arduino Uno, esse buffer possui normalmente 64 bytes.
Por exemplo, quando digitamos o comando LEDON do Monitor Serial, internamente chega assim no buffer:

Portanto, Serial.available(); retornará 6 (antes de qualquer leitura).
Serial.read()
Sintax:
int valor = Serial.read();
-
Retorna um byte (tipo int) por vez, sendo:
- Um byte válido (0 a 255 - código ASCII)
- Ou -1 caso não haja dados
-
Como o tipo char não pode representar -1 corretamente em todos os contextos, o retorno é int.
- Como o tipo
char pode ser assinado (signed) ou não (unsigned), dependendo da arquitetura, ele não é adequado para representar o valor especial -1 de forma segura.
Em uma abordagem profissional, podemos chamar Serial.read() quando existe a certeza que há dados, usando:
while (Serial.available() > 0) {
char c = Serial.read();
}
-
Significa que enquanto houver dados no buffer, continue lendo. Isso garante que sempre teremos dados disponíveis.
-
Então o retorno nunca será -1.
-
Portanto, é seguro converter para char.
No código acima ocorre:
Se digitarmos "LEDON" no campo mensagem do Monitor Serial, teremos a seguinte sequência de leituras:

Qual o conteúdo da variável c
Se você rodar este código no seu Arduino e digitar a letra L no monitor, verá que o char é um número "disfarçado":
void loop() {
if (Serial.available() > 0) {
char c = Serial.read(); // Lê o byte e guarda como caractere
Serial.print("Lido como caractere: ");
Serial.println(c); // O Monitor Serial vê 'char' e mostra: L
Serial.print("Lido como número (ASCII): ");
Serial.println((int)c); // Forçamos o Arduino a mostrar o número: 76
}
}
Serial.write()
Sintax:
Serial.write(valor);
Comunicação Serial Usando char[] (Forma Robusta e Profissional)
Após trabalhar com a classe String, vamos evoluir para a abordagem tradicional da linguagem C: arrays de caracteres (char[]).
Essa técnica oferece:
✔ Controle total de memória
✔ Ausência de fragmentação do heap
✔ Maior previsibilidade
✔ Melhor desempenho em sistemas embarcados
No Arduino Uno, que possui apenas 2 KB de SRAM e mesmo o Arduino Mega que possui 8 KB de SRAM, essa abordagem é considerada mais segura para aplicações profissionais.
O que é char[]?
Um char[] é um vetor de caracteres que representa uma string no padrão C (compatível com C++).
Exemplo:
char texto[20];
Isso significa:
-
Pode armazenar até 19 caracteres
-
O último espaço é reservado para '\0' (terminador nulo)
-
O '\0' é o caractere nulo (null terminator). Ele representa o valor numérico 0 na tabela ASCII.
-
Em C e C++, uma string não é apenas um conjunto de caracteres.
-
Ela é um array de char que termina obrigatoriamente com '\0'.
-
⚠ Toda string em C e C++ deve terminar com '\0'
-
Funções como: strcmp(), strlen(), strcpy(), strcat() não conhecem o tamanho do array. Portanto, elas percorrem os caracteres até encontrar '\0'.
Principais Métodos da Biblioteca <string.h>
Para manipular char[], utilizamos funções da biblioteca <string.h> padrão C++ e nativa na IDE do Arduino:
#include <string.h>
1. strcmp()
Compara duas strings.
strcmp(str1, str2);
Retorna:
2. strcpy()
Copia uma string para outra.
strcpy(destino, origem);
3. strcat()
Concatena strings.
strcat(destino, origem);
4. strlen()
Retorna o tamanho da string (sem contar '\0').
strlen(texto);
5. strncmp()
Compara apenas os primeiros caracteres. Muito útil para comandos com parâmetros.
strncmp(buffer, "NOME ", 5)
6. itoa()
O nome significa "Integer TO Ascii". Ela converte um valor numérico inteiro em uma sequência de caracteres (string)
itoa(valor, buffer, base);
valor: O número inteiro que você quer converter.
-
buffer: O array de char onde o texto será armazenado. Certifique-se de que o tamanho do array seja suficiente para o número e o caractere nulo (\0).
-
base: A base numérica (10 para decimal, 16 para hexadecimal, 2 para binário, etc.).
int tamanho = strlen("Angelo Luis Ferreira"); // 20 caracteres sem \0
char tamanhoStr[6];
itoa(tamanho, tamanhoStr, 10);
// Agora tamanhoStr contém a string "20"
7. atoi()
O nome significa "Ascii TO Integer". Converte uma string em um número inteiro
char texto[] = "1024";
int valor = atoi(texto);
// Agora 'valor' é o número 1024 (inteiro)

Comunicação Serial Profissional com char[] - Código Documentado
O exemplo abaixo mostra uso do char[] e da biblioteca <string.h> para manipulação de comandos na comunicação serial:
#include <string.h>
// Biblioteca padrão da linguagem C
// Contém funções como strcmp, strcpy, strcat, strlen, strncmp
// =======================================================
// BUFFER PRINCIPAL
// =======================================================
// buffer armazenará o comando digitado pelo usuário.
// 40 posições = 39 caracteres úteis + 1 posição para '\0'
char buffer[40];
// indice controla a posição atual de escrita no buffer.
// Ele avança a cada caractere recebido.
byte indice = 0;
// Variáveis auxiliares
char nome[20]; // armazenará o nome recebido após "NOME "
char resposta[60]; // armazenará a mensagem montada dinamicamente
// =======================================================
// SETUP
// =======================================================
void setup() {
Serial.begin(9600); // Inicializa comunicação serial (9600 bps)
pinMode(13, OUTPUT); // Configura LED onboard como saída
Serial.println("Sistema pronto.");
Serial.println("Digite: LEDON ou LEDOFF");
Serial.println("ou");
Serial.println("Digite: NOME SeuNome");
// Linha separadora visual no Monitor Serial
Serial.println("-------------------");
}
// =======================================================
// LOOP PRINCIPAL
// =======================================================
void loop() {
// Leitura NÃO BLOQUEANTE
// O código só entra aqui se houver dados disponíveis
while (Serial.available() > 0) {
char c = Serial.read();
// Lê um único byte do buffer de recepção.
// Cada chamada remove 1 byte do buffer.
// ---------------------------------------------------
// Se o caractere for ENTER ('\n'),
// significa que o usuário terminou o comando
// ---------------------------------------------------
if (c == '\n') {
buffer[indice] = '\0';
// Finaliza a string manualmente.
// Essencial para que strcmp, strlen etc funcionem.
indice = 0;
// Reinicia o índice para o próximo comando.
processaComando();
// Chama função que interpreta o texto recebido.
}
else {
buffer[indice++] = c;
// Armazena o caractere na posição atual
// e incrementa o índice.
// -------------------------------------------------
// PROTEÇÃO CONTRA OVERFLOW
// -------------------------------------------------
if (indice >= 39) {
indice = 39;
// Garante que nunca ultrapasse o limite do buffer.
// 39 é o último índice válido antes do '\0'.
}
}
}
// Aqui poderiam existir outras tarefas simultâneas,
// como leitura de sensores ou controle de motores,
// sem risco de bloqueio.
}
// =======================================================
// FUNÇÃO QUE INTERPRETA O COMANDO RECEBIDO
// =======================================================
void processaComando() {
// ---------------------------------------------------
// COMPARAÇÃO EXATA: LEDON
// ---------------------------------------------------
if (strcmp(buffer, "LEDON") == 0) {
// strcmp retorna 0 quando as strings são iguais
digitalWrite(13, HIGH);
Serial.println("LED ligado.");
}
// ---------------------------------------------------
// COMPARAÇÃO EXATA: LEDOFF
// ---------------------------------------------------
else if (strcmp(buffer, "LEDOFF") == 0) {
digitalWrite(13, LOW);
Serial.println("LED desligado.");
}
// ---------------------------------------------------
// COMANDO COM PARÂMETRO: NOME Angelo
// ---------------------------------------------------
else if (strncmp(buffer, "NOME ", 5) == 0) {
// strncmp compara apenas os 5 primeiros caracteres
// Permite aceitar "NOME Angelo", "NOME Maria", etc.
strcpy(nome, buffer + 5);
// buffer + 5 ignora os primeiros 5 caracteres ("NOME ")
// Copia apenas o nome digitado
strcpy(resposta, "Olá ");
// Inicializa resposta com texto fixo
strcat(resposta, nome);
// Concatena o nome
strcat(resposta, " (");
int tamanho = strlen(nome);
// strlen conta caracteres até encontrar '\0'
char tamanhoStr[6];
itoa(tamanho, tamanhoStr, 10);
// Converte número inteiro para string (base decimal)
strcat(resposta, tamanhoStr);
strcat(resposta, " letras)");
Serial.println(resposta);
}
// ---------------------------------------------------
// CASO NÃO RECONHECIDO
// ---------------------------------------------------
else {
Serial.println("Comando inválido.");
}
}
O que aparece no Monitor Serial?
Veja no exemplo abaixo os dados que aparecem no Monitor Serial, sendo que foi digitado primeiro o comando LEDON, depois LEDOFF e finalmente o comando com parâmetro NOME Angelo Luis Ferreira.

Informações técnicas sobre o código
Leitura Não Bloqueante
while (Serial.available() > 0) {
O código só executa leitura se houver dados.
Isso significa que:
-
O microcontrolador nunca “para esperando”.
-
Outras tarefas podem rodar normalmente.
-
Ideal para sistemas multitarefa simples.
Controle que deverá ser feito ao usar char[]
Um char[] exige que você:
✔ Controle tamanho do buffer
✔ Finalize com '\0'
✔ Evite overflow
Definição do tamanho do buffer
char buffer[40];
Isso significa:
-
O array possui 40 posições na memória.
-
Podemos armazenar até 39 caracteres reais.
-
A última posição é reservada para '\0'.
O tamanho do buffer é uma decisão de projeto:
Ele deve ser:
-
Grande o suficiente para conter o maior comando esperado mais uma posição para '\0'.
-
Pequeno o suficiente para não desperdiçar RAM.
-
O Arduino Uno possui 2 KB de SRAM disponíveis para variáveis em tempo de execução.. Um buffer[200], por exemplo, irá consumir imediatamente 200 bytes, quase 10% da memória total. Mesmo no Arduino Mega, com 8 KB de SRAM, esse valor seria alto.
Finalização manual de uma string
buffer[indice] = '\0';
Proteção Contra Overflow (Estouro de Buffer)
Para o buffer definido com 40 caracteres (39 caracteres úteis e 1 posição para "\0"), podemos protejê-lo com:
if (indice >= 39) {
indice = 39;
}
Isso garante que:
String vs char[] – Quando usar cada um?
Ao longo da série, vimos duas abordagens para comunicação serial no Arduino:
Ambas funcionam — mas cada uma é mais adequada para um contexto específico.
Use String quando:
✔ Estiver aprendendo comunicação serial
✔ Quiser código mais simples e legível
✔ Estiver prototipando rapidamente
✔ O projeto for pequeno e não crítico
✔ Não houver restrição severa de memória
Essa abordagem foi apresentada no artigo anterior:
Comunicação Serial no Arduino com Monitor Serial – Fundamentos e Uso com String
Ela prioriza clareza e produtividade.
Use char[] quando:
✔ Precisar de leitura não bloqueante
✔ Quiser controle total de memória
✔ Estiver desenvolvendo sistema embarcado robusto
✔ O projeto rodar por longos períodos (24/7)
✔ Houver múltiplas tarefas concorrentes
✔ Precisar implementar protocolo próprio
Aqui o foco é previsibilidade, estabilidade e controle.
Comparação Direta

Conclusão
Com este segundo artigo, concluímos uma visão completa sobre comunicação serial no Arduino — desde a abordagem didática com String até a implementação profissional com char[] e leitura não bloqueante.
No primeiro artigo, Comunicação Serial no Arduino com Monitor Serial – Fundamentos e Uso com String, estabelecemos a base conceitual e prática da comunicação serial, priorizando clareza e simplicidade.
Neste segundo momento, evoluímos para uma abordagem mais próxima da engenharia embarcada, explorando controle manual de memória, manipulação de buffers e construção de interpretadores de comandos robustos.
A comunicação serial é a base para integrações com outras linguagens, desenvolvimento de protocolos próprios e interação com módulos externos. Dominar essas duas abordagens não significa apenas saber enviar dados ao Monitor Serial — significa compreender como os dados são armazenados, processados e controlados dentro do microcontrolador.
O anúncio abaixo ajuda a manter o Squids Arduino funcionando
Comentários