Projeto: Conectando Arduino e PC pela porta serial
Profissionais de tecnologia lidam com diversos contextos durante suas carreiras. É relativamente comum surgir uma situação em que precisamos interligar sistemas embarcados com sistemas localizados em outros dispositivos (web, computadores locais, mobile etc.). Este é o cenário que meus alunos estão encarando em 2026 no curso de Tecnologia em Análise e Desenvolvimento de Sistemas.
Enquanto preparava o material para eles desenvolverem os próprios projetos, eu também precisei desenvolver minha versão para entender as nuances que envolvem a proposta. Neste artigo, vou apresentar uma versão simplificada da lógica para enviar dados a partir do arduino e recebê-los no computador.
Ferramentas utilizadas e configurações
Para este projeto, vamos precisar de:
- Placa Arduino Mega 2560 Rev3 + cabo USB
- Arduino IDE
- VS Code IDE
- Node.js:
- Framework Express
- Módulos Serialport e ReadlineParser, obtidas das bibliotecas instaladas pelo
npm.
Começaremos o projeto pelo Arduino, mas já vamos configurar o ambiente JavaScript para “deixar tudo no jeito”. Vá ao diretório Documentos e crie a pasta simula-gateway. Dentro da pasta, inicie o projeto:
npm init -yCom o projeto inciado, você verá que há um arquivo chamado package.json. Abra-o e altere seu conteúdo:
{
"name": "serial-gateway-arduino",
"version": "1.0.0",
"description": "Gateway serial para receber JSON do Arduino e enviar para backend JS",
"type": "module",
"main": "serial-gateway.js",
"scripts": {
"start": "node serial-gateway.js"
},
"dependencies": {
"@serialport/parser-readline": "^13.0.0",
"serialport": "^13.0.0"
}
}Salve e feche o arquivo. Volte ao terminal e digite o comando abaixo para instalar as dependências previstas no package.json:
npm installPor enquanto, instalamos apenas os módulos SerialPort e Readline Parse. Além destes, vamos precisar também do framework Express para a construção do servidor backend. Para complementar, digite o comando:
npm install expressPronto! Agora vamos entender melhor o contexto do projeto.
Modelagem do cenário
O cenário do projeto é simples (em tese): com o Arduino Mega conectado à uma porta USB do computador, queremos enviar dados via comunicação serial. Os dados que usamos são artificiais, mas eles servem para vermos como seria capturar valores de sensores do Arduino e transmiti-los para o computador.
Esses dados serão estruturados no formato JSON para que sejam lidos em tempo real por um código javascript que servirá de gateway, ou seja, uma “porta de ligação” para os dados no computador. Dentro do gateway, o JSON obtido na porta serial será validado e, caso esteja tudo certo, será repassado a outro código javascript que simula o backend de um sistema mais complexo.
Na Figura 1 temos uma representação visual do projeto, descrevendo o fluxo dos dados em nosso sistema.

Fonte: Autoria própria com o auxílio do Napkin AI.
Código do Arduino
Começando pela coleta dos dados, abra o Arduino IDE e digite o algoritmo abaixo. Nele, estamos definindo valores randômicos para construir dados artificiais que serão estruturados no formato JSON e depois enviados para a porta serial.
// sensor-simulado.ino
const int intervaloEnvio = 2000;
unsigned long ultimoEnvio = 0;
int contadorLeitura = 0;
float gerarTemperatura() {
return random(200, 360) / 10.0; // 20.0 até 36.0
}
float gerarUmidade() {
return random(400, 900) / 10.0; // 40.0 até 90.0
}
int gerarLuminosidade() {
return random(0, 1024); // 0 até 1023
}
void setup() {
Serial.begin(9600);
randomSeed(analogRead(A0));
Serial.println("{\"mensagem\":\"Arduino iniciado e enviando dados simulados\"}");
}
void loop() {
unsigned long tempoAtual = millis();
if (tempoAtual - ultimoEnvio >= intervaloEnvio) {
ultimoEnvio = tempoAtual;
contadorLeitura++;
float temperatura = gerarTemperatura();
float umidade = gerarUmidade();
int luminosidade = gerarLuminosidade();
String json = "{";
json += "\"dispositivo\":\"arduino-uno-01\",";
json += "\"numeroLeitura\":" + String(contadorLeitura) + ",";
json += "\"temperatura\":" + String(temperatura, 1) + ",";
json += "\"umidade\":" + String(umidade, 1) + ",";
json += "\"luminosidade\":" + String(luminosidade) + ",";
json += "\"tempoMillis\":" + String(tempoAtual);
json += "}";
Serial.println(json);
}
}Terminou de digitar o algoritmo? Então compile e faça o upload do código para o Arduino conectado no seu computador. Se tudo der certo, abra o Monitor Serial do Arduino IDE e você verá algo similar na saída da porta serial:
{"dispositivo":"arduino-uno-01","numeroLeitura":1,"temperatura":28.4,"umidade":63.2,"luminosidade":512,"tempoMillis":2000}Código do gateway
O Arduino já está encaminhando os dados para a porta serial e precisamos capturá-los. O gateway fará essa função em nosso esquema. Dentro da pasta simula-gateway, crie o arquivo serial-gateway.js e digite o código abaixo:
// serial-gateway.js
import { SerialPort } from 'serialport';
import { ReadlineParser } from '@serialport/parser-readline';
const caminhoPortaSerial = process.env.PORTA_SERIAL || 'COM3';
const velocidadeSerial = Number(process.env.VELOCIDADE_SERIAL || 9600);
const urlBackend = process.env.URL_BACKEND || 'http://localhost:3000/api/leituras-sensores';
const portaSerial = new SerialPort({
path: caminhoPortaSerial,
baudRate: velocidadeSerial
});
const leitorLinha = portaSerial.pipe(
new ReadlineParser({ delimiter: '\n' })
);
function validarDadosSensor(dados) {
if (typeof dados !== 'object' || dados === null) {
return false;
}
if (typeof dados.dispositivo !== 'string') {
return false;
}
if (typeof dados.numeroLeitura !== 'number') {
return false;
}
if (typeof dados.temperatura !== 'number') {
return false;
}
if (typeof dados.umidade !== 'number') {
return false;
}
if (typeof dados.luminosidade !== 'number') {
return false;
}
if (typeof dados.tempoMillis !== 'number') {
return false;
}
return true;
}
async function enviarParaBackend(dadosSensor) {
const resposta = await fetch(urlBackend, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(dadosSensor)
});
if (!resposta.ok) {
throw new Error(`Erro HTTP ao enviar para backend: ${resposta.status}`);
}
return resposta.json();
}
portaSerial.on('open', () => {
console.log(`Porta serial aberta em ${caminhoPortaSerial} com velocidade ${velocidadeSerial}.`);
});
portaSerial.on('error', (erro) => {
console.error('Erro na porta serial:', erro.message);
});
leitorLinha.on('data', async (linhaRecebida) => {
const linha = linhaRecebida.trim();
if (!linha) {
return;
}
console.log('Linha recebida do Arduino:', linha);
try {
const dadosSensor = JSON.parse(linha);
if (!validarDadosSensor(dadosSensor)) {
console.warn('JSON recebido, mas inválido para o formato esperado:', dadosSensor);
return;
}
console.log('JSON validado com sucesso:', dadosSensor);
const respostaBackend = await enviarParaBackend(dadosSensor);
console.log('Dados enviados ao backend com sucesso:', respostaBackend);
} catch (erro) {
console.error('Falha ao processar linha recebida:', erro.message);
}
});O algoritmo começa abrindo a comunicação serial USB com o Arduino e preparando o Node.js para ler os dados linha por linha. Usamos as bibliotecas SerialPort e ReadlineParser (que vêm das bibliotecas instaladas pelo npm) para lermos essas linhas.
Como o println no Arduino envia o texto e, no final, adiciona uma quebra de linha (representada por \n), o ReadlineParser lê os dados recebidos pela serial e só entrega uma mensagem completa quando encontra esse delimitador \n.
Isso é útil porque dados seriais podem chegar “picados”. Nesta situação, o parser junta os pedaços até encontrar \n, e então entrega a linha completa. Parsers como o ReadlineParser são usados justamente para transformar o fluxo bruto da porta serial em unidades de dados mais fáceis de processar, como linhas.
O método pipe(...) é usado porque a porta serial funciona como um fluxo de dados, ou seja, um stream. O pipe conecta a saída de um stream à entrada de outro “sistema processador”. O fluxo acaba ficando assim: portaSerial → ReadlineParser → leitorLinha. Aqui, a portaSerial recebe bytes crus da USB; o ReadlineParser organiza esses bytes em linhas; e o leitorLinha passa a emitir cada JSON completo recebido do Arduino.
Há uma observação a ser feita neste código. Na linha 6, atribuímos o caminho da porta serial como o valor que for lido no process.env.PORTA_SERIAL ou com o valor padrão 'COM3'. Porém, você deve observar em qual porta efetivamente seu Arduino foi conectado (COM3, COM4 etc.) para editar o código conforme sua realidade.
Existe outro problema: a nomenclatura COM é do sistema operacional Windows. Se você estiver usando Linux, a terminologia será algo como /dev/ttyUSB0 ou /dev/ttyACM0. E, no macOS, será algo como /dev/tty.usbmodem. Portanto, atente-se a esta questão quando estiver ajustando o algoritmo para seu contexto!
Enfim, vamos descobrir se nosso gateway está capturando os dados vindos do Arduino. Primeiro, verifique se o arduino está ligado e executando. Segundo, feche o Monitor Serial no Arduino IDE para não bloquear a porta e impedir a leitura do gateway. Por fim, rode a aplicação. Caso você esteja usando Windows, execute:
# altere o valor da porta 'COM3' para o que estiver no seu pc
set PORTA_SERIAL=COM3
npm startOu, se você estiver usando Linux, execute:
# altere o valor da porta '/dev/ttyACM0' para o que estiver no seu pc
PORTA_SERIAL=/dev/ttyACM0 npm startEm caso de sucesso, você observará na tela do terminal os dados transmitidos pelo Arduino.
Código do backend simulado
Chegando na parte final de nosso projeto, está faltando simularmos o backend. No diretório simula-gateway crie o arquivo servidor.js para digitar o código abaixo:
// servidor.js
import express from 'express';
const aplicativo = express();
const porta = 3000;
aplicativo.use(express.json());
aplicativo.post('/api/leituras-sensores', (requisicao, resposta) => {
const dadosSensor = requisicao.body;
console.log('Dados recebidos no backend:', dadosSensor);
resposta.status(201).json({
mensagem: 'Leitura recebida com sucesso',
dados: dadosSensor
});
});
aplicativo.listen(porta, () => {
console.log(`Backend executando em http://localhost:${porta}`);
});Observe que o servidor não valida nada em relação aos dados, pois essa responsabilidade é do gateway. O servidor deve apenas oferecer um endpoint (/api/leituras-sensores) e uma rota (POST /api/leituras-sensores) para receber os dados do gateway e imprimi-los no terminal.
Deixe o arduino e o gateway rodando, abra outra sessão de terminal e execute o comando para iniciar o backend simulado:
node servidor.jsCom o código funcionando, possivelmente você obterá o resultado similar ao disposto abaixo:
Porta serial aberta em COM3 com velocidade 9600.
Linha recebida do Arduino: {"dispositivo":"arduino-uno-01","numeroLeitura":1,"temperatura":28.4,"umidade":63.2,"luminosidade":512,"tempoMillis":2000}
JSON validado com sucesso: {
dispositivo: 'arduino-uno-01',
numeroLeitura: 1,
temperatura: 28.4,
umidade: 63.2,
luminosidade: 512,
tempoMillis: 2000
}
Dados enviados ao backend com sucesso: {
mensagem: 'Leitura recebida com sucesso',
dados: {
dispositivo: 'arduino-uno-01',
numeroLeitura: 1,
temperatura: 28.4,
umidade: 63.2,
luminosidade: 512,
tempoMillis: 2000
}
}Conclusão
Finalizamos nossa versão simplificada da lógica. Esperamos que você tenha conseguido chegar a este ponto da leitura com sucesso, sempre obtendo os resultados previstos para o projeto.
Você pode replicar, ampliar ou modificar as ideias apresentadas aqui como bem quiser. O importante é continuar estudando e aprendendo.
Obrigado pela leitura e bons estudos!


