Esta é a continuação de um
vídeo que já fiz utilizando o display TFT de 1.8 polegadas, que é um display
gráfico de 128 pixels por 160, que eu gosto demais. Desta vez, nosso circuito vai
utilizar um adaptador e um microSD de 32 giga.
Demonstração
Recursos usados
- ESP32-WROOM
- Display TFT Lcd 1.8’’
- Protoboard
- Jumpers
- Cartão SD
- Botão
- Resistor 10k ohm
Montagem
Display TFT 1.8’’ Pinout
Montagem ESP-WROOM32 com Display TFT1.8’’
Tabela de ligações ESP-WROOM32 e Display TFT1.8’’
Formatação SD card para FAT32 (Recomendação)
·
Formate o cartão SD como FAT32, utilize um
adaptador USB como este:
·
Utilize um programa para formatar, como o
GUIformat:
Biblioteca necessária
Baixe a biblioteca mySD:
Instale a biblioteca
1. Clique
em Incluir Biblioteca -> Adicionar biblioteca .ZIP
2. Na
tela de pesquisa procure pelo ZIP baixado e clique em abrir
Código
Código ESP-WROOM 32
Declarações e variáveis
#include <Adafruit_GFX.h> // Biblioteca de gráficos
#include <Adafruit_ST7735.h> // Biblioteca do hardware ST7735
#include <SPI.h> // Biblioteca para comunicação SPI
#include <Fonts/FreeSerif9pt7b.h> // Fonte Serif que é usada no display
#include "SD_File_Record.h" // Biblioteca com as funções referentes ao SD card
// ESP32-WROOM
#define TFT_DC 12 // A0
#define TFT_CS 13 // CS
#define TFT_MOSI 14 // SDA
#define TFT_CLK 27 // SCK
#define TFT_RST 0 // RESET
#define TFT_MISO 0 // MISO
// Objeto do display tft
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST);
// Variável que guarda uma mensagem de erro caso aconteça algum problema com o display ou SD card
String errorMsg;
// Botão usado para excluir o arquivo do cartão SD
const int buttonPin = 33;
// Flag que impede que o display pisque quando o botão estiver pressionado
bool flag = false;
// Altura da fonte que é usada no display
int fontHeight = 7;
const int MICROSD_PIN_CHIP_SELECT = 21; // Pino serial
const int MICROSD_PIN_MOSI = 19; // Pino serial
const int MICROSD_PIN_MISO = 18; // Pino serial
const int MICROSD_PIN_SCK = 22; // Clock pin
// Instancia um objeto SD_File_Record enviando o nome do arquivo e o tamanho máximo dos registros (sem contar o \r\r) no construtor, ou seja, o tamanho real será de 3+2 = 5
SD_File_Record ObjSD("test.txt", 3);
Setup
void setup()
{
// Inicia a serial com velocidade de 9600
Serial.begin(115200);
// Seta botão como entrada (INPUT)
pinMode(buttonPin, INPUT);
// Inicia display TFT com a tela preta
tft.initR(INITR_BLACKTAB);
// Limpa display, seta a fonte e posiciona cursor no início
resetDisplay();
// Exibe na serial "Starting..."
Serial.print("Starting...");
// Inicializa cartão SD
if(!ObjSD.init(MICROSD_PIN_CHIP_SELECT, MICROSD_PIN_MOSI, MICROSD_PIN_MISO, MICROSD_PIN_SCK))
{
// Se não obteve sucesso, exibe no display e reinicia o ESP
tft.println("\nSD begin fail\n");
Serial.println("SD begin fail");
delay(1000);
ESP.restart();
}
// Se obteve sucesso exibe no display
Serial.println("SD card ok");
// Escreve no arquivo os números sequenciais
writeNewRecord();
// Lê o arquivo e exibe no display
showFile();
// Função que busca um registro
// String reg = ObjSD.findRecord(10); // 10 é a posição do registro
}
Limpando display e Exibindo dados
// Limpa o display e posiciona o cursor no início
void resetDisplay()
{
tft.setFont(&FreeSerif9pt7b);
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST7735_WHITE);
tft.setCursor(0,fontHeight+5);
tft.setTextSize(1);
}
// Lê e exibe o arquivo
void showFile()
{
// Variável usada para guardar a linha lida do arquivo txt
String linha;
// Contador usado para limpar o display quando o texto não couber mais
int count = 0;
// Exibe no display e na serial o início do arquivo
Serial.println("# Begin of file #");
tft.println("# Begin of file #");
// Enquanto for possível ler a próxima linha do arquivo
ObjSD.rewind();
while(ObjSD.readFileNextLine(&linha, &errorMsg))
{
// Se ocorreu algum erro durante a leitura
if(errorMsg != "")
{
// Exibe o erro no display e aborta o while
tft.println(errorMsg);
break;
}
// Incrementa contador
count++;
// Se o contador for divisivel por 6 (qtde de linhas que cabem no display com esta fonte)
if(count % 6 == 0)
{
//Exibe "..." sinalizando que ainda não é o fim do arquivo
tft.println("...");
// Aguarda 1.5s para poder visualizar os valores
delay(1500);
// Limpa display
resetDisplay();
}
Exibindo display e Escrevendo no arquivo
// Exibe a linha obtida no display e na Serial
tft.println(linha);
Serial.println(linha);
} //Fim do while
// Exibe no display e na serial indicando fim do arquivo
Serial.println("# End of file #");
tft.println("# End of file #");
}
// Escreve os números sequencias no arquivo
void writeNewRecord()
{
// String que será escrita no arquivo txt
String line;
// Inteiro que receberá o número da última linha registrada
int nLine;
// Se o arquivo não existe
if(!ObjSD.fileExists())
ObjSD.newFile(); // Cria o arquivo
// Lê a última linha do arquivo
if(!ObjSD.readFileLastLine(&line,&errorMsg) && errorMsg != "")
tft.println(errorMsg);
else
if(errorMsg == "") // Se foi possível ler o arquivo
{
// Se o arquivo estiver vazio
if(line == "")
line = "001"; // Atribui para a String o primeiro valor da sequência (1)
else // Se o arquivo não estiver vazio
{
// Converte String para int e incrementa 1
nLine = atoi(line.c_str())+1;
// Insere zeros à esquerda conforme o número atual do registro
if(nLine < 10)
line = "00";
else
if(nLine < 100)
line = "0";
// Converte o novamente o valor para String
line += String(nLine);
}
// Escreve no arquivo a String "line"
if(!ObjSD.writeFile(line, &errorMsg))
tft.println(errorMsg); // Se existir um erro durante a escrita, exibe no display
}
else
tft.println(errorMsg); // Se existir um erro, exibe no display
}
Loop
void loop()
{
// Se o botão foi pressionado e a flag estiver "false"
if(digitalRead(buttonPin) == HIGH && !flag)
{
// Tenta excluir o arquivo
if(ObjSD.destroyFile())
showFileDeleted(true); // Se obteve sucesso, chama a função "showFileDeleted" enviando valor "true"
else
showFileDeleted(false); // Se não obteve sucesso, chama a função "showFileDeleted" enviando valor "false"
// Impede que o display pisque e que o ESP tente excluir o arquivo mais de uma vez
flag = true;
}
else
if(digitalRead(buttonPin) == LOW && flag) // Se o botão foi solto e a flag estiver "true"
{
// Limpa display
resetDisplay();
// Exibe arquivo
showFile();
// Impede que o display pisque e que o ESP tente excluir o arquivo mais de uma vez
flag = false;
}
// Aguarda 10ms
delay(10);
}
Biblioteca SD_File_Record - Header
// ifndef evita erros de duplicação ao chamar esta lib mais de uma vez
#ifndef SD_File_Record_h
#define SD_File_Record_h
#include <Arduino.h> //Biblioteca Arduino (opcional)
#include <mySD.h> // Biblioteca referente ao cartão SD
// Classe SD_File_Record e suas funções
class SD_File_Record
{
// Todas as funções desta lib são publicas, mais detalhes em SD_File_Record.cpp
public:
SD_File_Record(String, int);
SD_File_Record(String);
bool init(int, int, int, int);
bool readFileLastLine(String *, String *);
bool destroyFile();
String findRecord(int);
void rewind();
bool writeFile(String, String *);
bool seekFile(int);
bool readFileNextLine(String *, String *);
String getFileName();
void setFileName(String);
int getSizeRecord();
void setSizeRecord(int);
void newFile();
bool fileExists();
};
Declarações e variáveis, Construtores e init
// Importamos o header referente a lib SD_File_Record
#include "SD_File_Record.h"
// Nome do arquivo em que os registros serão salvos
String fileName;
// Ponteiro do arquivo
File pFile;
/* ############################## Importante ##############################
O registro tem tamanho FIXO de 3 caracteres e seus valores são de:
001
002
003
004
005
...
999
########################################################################## */
// Tamanho do registro (default 3)
int sizeOfRecord = 5;
// Exemplo:
// 001\r\n = 5 caracteres
// Construtor que seta o nome do arquivo e o tamanho do registro
SD_File_Record::SD_File_Record(String _fileName, int _sizeOfRecord)
{
fileName = _fileName;
sizeOfRecord = _sizeOfRecord+2;
}
// Construtor que seta somente o nome do arquivo deixando o tam do registro default
SD_File_Record::SD_File_Record(String _fileName){ fileName = _fileName; }
// Funcao de inicialização que configura o Cartão SD com os pinos recebidos por parametro
bool SD_File_Record::init(int _MICROSD_PIN_CHIP_SELECT, int _MICROSD_PIN_MOSI, int _MICROSD_PIN_MISO, int _MICROSD_PIN_SCK)
{ return SD.begin(_MICROSD_PIN_CHIP_SELECT, _MICROSD_PIN_MOSI, _MICROSD_PIN_MISO, _MICROSD_PIN_SCK); }
Lendo o arquivo
// Lê a próxima linha do arquivo
bool SD_File_Record::readFileNextLine(String *line, String *errorMsg)
{
// Se o ponteiro estiver nulo
if(!pFile)
{
// Abre arquivo para leitura
pFile = SD.open(fileName.c_str(), FILE_READ);
// Se aconteceu algum erro
if(!pFile)
{
// Guarda msg de erro
*errorMsg = "Failed to open the file";
// Retorna falso
return false;
}
}
// Se for possível ler o arquivo
if(pFile.available())
{
// Lê arquivo
*line = pFile.readStringUntil('\n');
// Retorna true
return true;
}
// Se não for possível ler o arquivo retorna falso
return false;
}
Posicionamento de ponteiro e escrita no arquivo
//Posiciona ponteiro do arquivo na posição "pos"
bool SD_File_Record::seekFile(int pos)
{
// Se o ponteiro estiver nulo
if(!pFile)
pFile = SD.open(fileName.c_str(), FILE_READ); // Abre o arquivo para leitura
// Posiciona o ponteiro na posição multiplicando pelo tamanho do registro
return pFile.seek(sizeOfRecord*pos);
}
// Escreve no arquivo
bool SD_File_Record::writeFile(String line, String *errorMsg)
{
// Abre arquivo para escrita
pFile = SD.open(fileName.c_str(), FILE_WRITE);
// Se foi possível abrir
if (pFile)
{
// Escreve registro
pFile.println(line);
// Fecha arquivo
pFile.close();
// Retorna true
return true;
}
// Se não foi possível abrir guarda mensagem de erro e retorna false
*errorMsg = "Failed to open the file: "+String(fileName);
return false;
}
Posicionando no início do arquivo e leitura de última linha
// Posiciona ponteiro no início do arquivo
void SD_File_Record::rewind()
{
pFile.seek(0);
}
// Lê o último registro do arquivo
bool SD_File_Record::readFileLastLine(String *line, String *errorMsg)
{
// Variável que guardará o tamanho do arquivo
int sizeArq;
// Limpa string
*errorMsg = "";
// Se o arquivo está aberto, fecha
if(pFile)
pFile.close();
// Abre o arquivo para leitura
pFile = SD.open(fileName.c_str(), FILE_READ);
// Se não foi possível abrir o arquivo
if(!pFile)
{
// Guarda mensagem de erro e retorna false
*errorMsg = "Failed to open the file: "+String(fileName);
return false;
}
// Obtém o tamanho do arquivo
sizeArq = pFile.size();
// Se existe ao menos um registro
if(sizeArq >= sizeOfRecord)
pFile.seek(sizeArq-sizeOfRecord); // Posiciona o ponteiro no final do arquivo menos o tamanho de um registro (sizeOfRecord)
// Lê registro retornando o resultado da função "readFileNextLine"
return readFileNextLine(*&line, *&errorMsg);
}
Exclusão de arquivo e busca
// Exclui arquivo
bool SD_File_Record::destroyFile()
{
// Se o arquivo estiver aberto, fecha
if(pFile)
pFile.close();
// Exclui arquivo e retorna o resultado da função "remove"
return SD.remove((char*)fileName.c_str());
}
// Função que busca um registro
// "pos" é a posição referente ao registro buscado
String SD_File_Record::findRecord(int pos)
{
// Linha que receberá o valor do registro buscado
String line = "", errorMsg = "";
// Posiciona na posição desejada
// Obs. A posição se inicia com zero "0"
if(!seekFile(pos))
return "Seek error";
// Lê o registro
if(!readFileNextLine(&line, &errorMsg))
return errorMsg;
return line;
}
Arquivo existe, novo arquivo e funções get e set
// Verifica se o arquivo existe
bool SD_File_Record::fileExists()
{
return SD.exists((char*)fileName.c_str());
}
// Cria um novo arquivo, se já existir o arquivo será removido antes
void SD_File_Record::newFile()
{
if(pFile)
pFile.close();
SD.remove((char*)fileName.c_str());
pFile = SD.open(fileName.c_str(), FILE_WRITE);
pFile.close();
}
// Obtém o nome do arquivo
String getFileName()
{ return fileName; }
// Seta o nome do arquivo
void setFileName(String _fileName)
{ fileName = _fileName; }
// Obtém o tamanho do registro
int getSizeRecord()
{ return sizeOfRecord-2; }
// Seta o tamanho do registro
void setSizeRecord(int _sizeOfRecord)
{ sizeOfRecord = _sizeOfRecord+2; }
Faça o download dos arquivos:











2 Comentários
Muito agradecido. Apenas percebi que a Tabela de ligações ESP-WROOM32 e Display TFT1.8’’ possui para SD_MISO a GPIO28, sendo que penso ser a correta GPIO18, conforme código e imagem Montagem ESP-WROOM32 com Display TFT1.8’’.
ResponderExcluirReitero meus agradecimentos.
Bom dia, gostaria de saber qual é a velocidade em que os eventos são salvos, gostaria de saber se consigo salvalos em uma taxa de 400Hz ou mais ?
ResponderExcluir