Migração do LCD
Esta seção aborda a migração do código relacionado ao LCD do NXT para o EV3.
Diferenças Principais
No RobotC, o LCD do NXT é acessado através de funções específicas, como nxtDisplayString()
para exibir texto e nxtDrawLine()
para desenhar linhas. Essas funções são diretas e utilizam coordenadas simples para posicionamento.
No EV3 temos duas opções, printar na tela pelo serial padrão, ou modificar o LCD. O LCD é manipulado através de um framebuffer, que é uma representação em memória da tela.
Printar no Serial Padrão
No EV3, você pode usar a saída padrão para imprimir texto na tela do LCD. Isso é feito utilizando as funções padrão de C++ como std::cout
. Aqui está um exemplo simples:
#include <iostream>
#include "ev3dev.h"
using namespace ev3dev;
int main() {
std::cout << "Hello, EV3!" << std::endl;
return 0;
}
Essa maneira é mais simples e recomendada para a maioria dos casos, especialmente para depuração e mensagens simples.
Framebuffer no EV3
O framebuffer é a camada abaixo disso. É o método de mais baixo nível (sem ser o driver do kernel) que o Linux usa para desenhar na tela.
É uma abordagem mais complexa, mas oferece controle total sobre cada pixel na tela.
O Que é o Framebuffer?
Pense no framebuffer como um grande mapa de bits (bitmap) na RAM que representa diretamente cada pixel da tela.
- É um buffer (um pedaço de memória) contínuo.
- Cada célula nesse buffer corresponde a um pixel (ou um conjunto de pixels).
- O hardware de vídeo do EV3 está configurado para, constantemente, ler essa área da memória e exibi-la na tela.
- Se você escrever dados diretamente nessa área da memória, a imagem na tela muda instantaneamente (no próximo ciclo de atualização).
No EV3, o framebuffer é de 176x128 pixels, com 1 bit por pixel (preto e branco).
Como Usar o Framebuffer
Para manipular o framebuffer diretamente, você pode abrir o dispositivo /dev/fb0
e escrever dados nele. Aqui está um exemplo básico de como fazer isso:
#include "ev3dev.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <iostream>
bool set_console_bind(bool bind)
{
// O arquivo de controle pode ser vtcon0 ou vtcon1.
// No ev3dev, geralmente é o vtcon0.
std::ofstream f("/sys/class/vtconsole/vtcon0/bind");
if (!f.is_open()) {
// Tenta o vtcon1 como fallback
f.open("/sys/class/vtconsole/vtcon1/bind");
}
if (!f.is_open()) {
std::cerr << "Erro: Nao foi possivel abrir /sys/class/vtconsole/..." << std::endl;
return false;
}
// Escreve "0" para desvincular ou "1" para vincular
f << (bind ? "1" : "0");
f.close();
return true;
}
int main()
{
// --- 1. Abrir o Framebuffer ---
int fb_fd = open("/dev/fb0", O_RDWR);
if (fb_fd == -1) { /* erro */ }
if (!set_console_bind(false)) {
return 1; // Falha
}
// --- 2. Obter informações da tela (ESPECIALMENTE o line_length) ---
fb_fix_screeninfo finfo;
if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo) == -1) {
// finfo.line_length nos dirá o "stride" (provavelmente 24 bytes)
/* erro */
}
long screen_size_bytes = finfo.smem_len; // Tamanho total do buffer
int line_length_bytes = finfo.line_length; // "Stride" (bytes por linha)
// --- 3. Mapear para a Memória ---
unsigned char* fb_ptr = (unsigned char*)mmap(
0,
screen_size_bytes,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fb_fd,
0
);
if (fb_ptr == (void*)-1) { /* erro */ }
// --- 4. Desenhar! ---
// Limpar a tela (definir todos os bytes como 0x00 = branco)
memset(fb_ptr, 0x00, screen_size_bytes);
// Desenhar um pixel em (x=10, y=5)
int x = 10;
int y = 5;
// Calcular o endereço do byte
// Pula 'y' linhas (cada uma com 'line_length_bytes')
// e avança 'x / 8' bytes na linha atual
unsigned char* byte_ptr = fb_ptr + (y * line_length_bytes) + (x / 8);
// Calcular o bit dentro desse byte
// (o bit 0 é o mais à esquerda, ou o mais à direita?
// No EV3, é little-endian, então o bit 0 é o da direita)
int bit_index = x % 8;
// Ligar o pixel (preto)
*byte_ptr |= (1 << bit_index);
// Esperar um pouco para ver
std::this_thread::sleep_for(std::chrono::seconds(5));
// --- 5. Limpar ---
munmap(fb_ptr, screen_size_bytes);
close(fb_fd);
// Lembre-se de reativar o console se você o desligou!
set_console_bind(true);
return 0;
}