Introdução
Neste artigo, vamos aprender como exibir textos e imagens Bitmap em um display OLED utilizando a placa Franzininho C0. Para alcançar esse objetivo, realizaremos a configuração da interface I2C usando a ferramenta CubeMX e depois ajustaremos o código necessário para que o display funcione.
Componentes necessários
- 1 Franzininho C0
- 1 Display OLED ssd1306
Esquemático para montagem circuito
Os pinos da Franzininho C0 para comunicação I2C são:
- SDA: C14
- SCL: B6
A Interface I2C
O protocolo I2C, desenvolvido pela Philips, foi criado para facilitar a comunicação entre periféricos dentro de um mesmo circuito, como mostrado na imagem abaixo. Este protocolo síncrono utiliza apenas duas linhas: SDA (linha de dados) e SCL (linha de clock). Sua simplicidade e eficiência tornam o I2C uma escolha popular para a comunicação entre microcontroladores e diversos dispositivos periféricos, como sensores e displays.
Para entender mais sobre essa comunicação recomendo a leitura do seguinte artigo: Comunicação I2C.: https://embarcados.com.br/comunicacao-i2c/.
O STM32 suporta esse protocolo tendo como características principais:
- Linhas de Comunicação: SDA (Serial Data) e SCL (Serial Clock).
- Endereçamento: Cada dispositivo no barramento I2C possui um endereço exclusivo, permitindo a comunicação direcionada.
- Modos de Operação: Suporta modos mestre, escravo e multi-mestre.
- Velocidade: Opera em diferentes modos de velocidade, incluindo padrão (até 100 kHz), rápido (até 400 kHz) e rápido plus (até 1 MHz).
O Display OLED
Displays OLED são painéis visuais eletrônicos que utilizam diodos emissores de luz orgânicos como sua fonte de iluminação central. Uma matriz OLED pode ser usada para apresentar imagens, texto, vídeo e muito mais em uma tela ou painel de quase qualquer tamanho. Nesse tutorial estamos utilizando o Display OLED ssd1306 com as seguintes características:
- Tecnologia do Display: OLED (LED orgânico)
- Interface MCU: I2C
- Tamanho da tela: 0,96 polegadas de lado a lado
- Resolução: 128×64 pixels
- Voltagem operacional: 3,3 V – 5 V
- Corrente operacional: 20 mA (max)
- Ângulo máximo de visibilidade: 160º
- Caracteres por linha: 21
- Número de linhas de caracteres: 7
Configuração CubeMX
- Abra STM32Cube , crie um novo projeto e selecione o microcontrolador de destino “STM32C011F6P6”.
- Vá para a página de configurações de relógio e em HCLK digite 48 MHz para a frequência de saída desejada do sistema. Pressione a tecla “Enter” e deixe o aplicativo resolver os divisores/multiplicadores PLL necessários para atingir a taxa de clock desejada. Depois volte para a página de configuração dos pinos, selecione “Trace and Debug” e habilite “Serial Wire.
- Selecione o pino PB6 e escolha “I2C1_SCL”. Depois selecione o pino PC14 e escolha “I2C1_SDA”.
- Em seguida, clique em “Connectivity” > I2C1 e habilite o I2C. As demais configurações, para esse exemplo, podemos deixar padrão.
- Por fim, gere o código em “Project” > “Generate Code”.
Implementando o código
- Para começar, faça o download dos arquivos da biblioteca para o display OLED. Está disponível em: Repositório da biblioteca OLED para Franzininho C0.
- Após baixar os arquivos os inclua em seu projeto:
- Os arquivos de cabeçalho (.h) devem ser colocados na pasta Inc.
- Os arquivos de implementação (.c) devem ser colocados na pasta Src.
- Abra o arquivo ssd1306.h. Nele temos algumas configurações que podem ser ajustadas.

Configuração de Fontes
Os #define para diferentes fontes que permitem habilitar apenas aquelas que serão usadas no seu projeto. Comente as que não forem necessárias para economizar espaço de memória. Isso garante que apenas as fontes essenciais sejam compiladas e disponíveis para uso no código.
Configuração I2C
- SSD1306_I2C_PORT: Define a porta I2C utilizada pelo display OLED (por exemplo, hi2c1).
- SSD1306_I2C_ADDR: Define o endereço I2C do dispositivo conectado (por exemplo, (0x3C << 1) equivale a 0x78 após a operação de deslocamento de bit à esquerda. Verifique o valor correto do endereço no próprio dispositivo.
Resolução do Display OLED
- SSD1306_HEIGHT: Define a altura do display OLED em pixels.
- SSD1306_WIDTH: Define a largura do display OLED em pixels.
- Agora vamos modificar nosso arquivo main.c. Acesse-o e inclua as seguintes bibliotecas:
#include "ssd1306.h"
#include "ssd1306_fonts.h"- Primeiro, vamos exibir um texto no display. Modifique seu código principal, int main, com o seguinte:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
ssd1306_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
ssd1306_Fill(Black);
ssd1306_SetCursor(4, 4);
ssd1306_WriteString("Portal", Font_11x18, White);
ssd1306_SetCursor(4, 24);
ssd1306_WriteString("Embarcados", Font_11x18, White);
ssd1306_UpdateScreen();
}
/* USER CODE END 3 */
}
Nesse código, estamos inicializando a comunicação I2C e configurando o display OLED com as funções MX_I2C1_Init() e ssd1306_Init(). No loop principal do programa, executamos uma série de operações para preparar e exibir informações no display.
Primeiramente, utilizamos ssd1306_Fill(Black) para preencher toda a tela do display com a cor preta, preparando-a para receber novos conteúdos. Em seguida, posicionamos o cursor na tela utilizando ssd1306_SetCursor(4, 4) para indicar onde começaremos a escrever.
Para demonstrar um exemplo, escrevemos a palavra “Portal” no display usando ssd1306_WriteString(“Portal”, Font_11x18, White). Nesta função, especificamos a string que queremos exibir (“Portal”), o tamanho da fonte (11×18 pixels) e a cor do texto (branca). Fazemos o mesmo para escrever “Embarcados”, mudando a posição do cursor.
Finalizando, chamamos ssd1306_UpdateScreen() para atualizar o conteúdo exibido no display. Essa função é crucial para garantir que todas as operações de desenho e escrita realizadas anteriormente sejam visíveis para o usuário no display OLED.
- Compile o código e caso não haja erro grave em sua placa. O resultado esperado após a gravação é:
- Agora, vamos modificar o código para carregar uma imagem bitmap. Para isso é necessário transformar uma imagem em matrizes de bytes. Sugiro fazer essa etapa por esse site: https://javl.github.io/image2cpp/.
- Vamos exibir a logo do Franzininho. Para isso, crie a matriz de bytes no início do código do arquivo main.c. No site, carregue a imagem desejada e configure as opções de conversão para gerar a matriz de bytes adequada para o display OLED. Após gerar a matriz, copie o código resultante e cole no início do arquivo main.c.
const unsigned char franzininho_128x64 [] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x87, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0xe1, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x32, 0x38, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xc7, 0x81, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xc3, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x0c, 0xff, 0x0f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3c, 0x3f, 0xff, 0xfc, 0x31, 0xfc, 0x3f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0x1f, 0xff, 0xf1, 0xc7, 0xf0, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xc7, 0xff, 0xc3, 0x1f, 0xc3, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xe1, 0xff, 0x0c, 0x7f, 0x0f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xf8, 0x7e, 0x11, 0xfc, 0x7f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xfe, 0x7e, 0x07, 0xf1, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0xe1, 0xc7, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xe3, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x83, 0x3f, 0xff, 0xff, 0xff, 0xcf, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfe, 0x1f, 0x8f, 0xff, 0xff, 0xff, 0x9f, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xf0, 0xff, 0xe3, 0xff, 0xff, 0xff, 0x3e, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xc3, 0xff, 0xf8, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xfe, 0x0f, 0xff, 0xfe, 0x03, 0xff, 0xfe, 0x07, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xf0, 0x07, 0xff, 0xfe, 0x38, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xc3, 0xe3, 0xff, 0xfe, 0x7e, 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xc3, 0xf9, 0xff, 0xff, 0x7c, 0x7f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xf1, 0xfc, 0x7f, 0xff, 0x81, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xfc, 0x7f, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xfe, 0x1f, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x87, 0xf3, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xe3, 0xf8, 0x63, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xf1, 0xff, 0x07, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfc, 0x7f, 0xe3, 0xcf, 0xff, 0xff, 0xc0, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfe, 0x1f, 0xf8, 0x3f, 0xff, 0xff, 0x1e, 0x7f, 0xfc, 0x1f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xc3, 0xff, 0x3f, 0x3f, 0xf0, 0x7f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0x00, 0xff, 0x9e, 0x7f, 0x83, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xfe, 0x3e, 0x7f, 0xc1, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xfe, 0x3c, 0x7f, 0xe3, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xfc, 0x00, 0xff, 0xc7, 0x83, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xe1, 0xff, 0xff, 0x1e, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x87, 0xff, 0xf8, 0x70, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xe3, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0x1e, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xf8, 0x70, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xe3, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x70, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x60, 0x07, 0x00, 0xc7, 0xcc, 0x01, 0x91, 0xf9, 0x39, 0xf9, 0x9f, 0x98, 0x03, 0xff,
0xff, 0x3f, 0xc7, 0xe4, 0x7c, 0xc1, 0xcf, 0xe7, 0x90, 0x79, 0x38, 0x79, 0x9f, 0x99, 0xf9, 0xff,
0xff, 0x20, 0xc0, 0x0c, 0x7c, 0xce, 0x4f, 0x9f, 0x93, 0x99, 0x3b, 0x89, 0x80, 0x13, 0xfd, 0xff,
0xff, 0x3f, 0xc6, 0x1c, 0x00, 0xcf, 0x0e, 0x3f, 0x93, 0xc1, 0x3b, 0xe1, 0x9f, 0x99, 0xf9, 0xff,
0xff, 0x3f, 0xef, 0x8c, 0xfe, 0xcf, 0xcc, 0x01, 0x93, 0xf3, 0xbb, 0xfb, 0x9f, 0xbc, 0x03, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
- Depois modifique a função principal, int main , com o seguinte:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
ssd1306_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
ssd1306_Fill(Black);
ssd1306_DrawBitmap(0,0,franzininho_128x64,128,64, White);
ssd1306_UpdateScreen();
}
/* USER CODE END 3 */
}
Usamos a função ssd1306_DrawBitmap() para carregar a imagem na tela do display. São passados como parâmetros : posição x, y, a matriz de byte, altura, largura e a cor.
- Compile o código e caso não haja erro grave em sua placa. O resultado esperado após a gravação é:
Conclusão
Nesse artigo configuramos a interface I2C na Franzininho C0 para utilização de um display OLED SSD1306. Ao seguir os passos descritos neste artigo, aprendemos a configurar tanto hardware quanto software, utilizando o CubeMX para simplificar a configuração inicial e ajustes de código para comunicação com o display.





