feat(ssd1306): add the 4-pin I2C OLED module + examples on Uno/ESP32/Pico/STM32
Adds `velxio-ssd1306-i2c-4pin`, a native 4-pin SSD1306 OLED module (GND/VCC/SCL/SDA) — the cheap 0.96" I2C board most beginners actually have, matching Wokwi's board-ssd1306. The 8-pin `wokwi-ssd1306` breakout stays; this is the distinct 4-pin part (issue #215). Same SSD1306Core render pipeline (imageData/redraw) so the display paints identically; I2C-only, address via the i2cAddress property (default 0x3C). Styled after the existing 8-pin element (blue PCB, dark screen, corner holes, star). Ships four "SSD1306 OLED (4-pin I2C)" gallery examples wiring it over I2C on Arduino Uno (A4/A5), ESP32 (21/22), Raspberry Pi Pico (GP4/GP5) and STM32 Blue Pill (PB7/PB6).
This commit is contained in:
parent
95e9fe9716
commit
d7f4e8e966
|
|
@ -4451,6 +4451,34 @@
|
|||
"motion",
|
||||
"sensor"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ssd1306-i2c-4pin",
|
||||
"tagName": "velxio-ssd1306-i2c-4pin",
|
||||
"name": "SSD1306 OLED (I2C, 4-pin)",
|
||||
"category": "displays",
|
||||
"pinCount": 4,
|
||||
"tags": [
|
||||
"ssd1306",
|
||||
"oled",
|
||||
"display",
|
||||
"i2c",
|
||||
"4-pin",
|
||||
"0x3c"
|
||||
],
|
||||
"thumbnail": "<svg width=\"64\" height=\"64\" xmlns=\"http://www.w3.org/2000/svg\"><rect width=\"64\" height=\"64\" fill=\"#025caf\" rx=\"6\"/><rect x=\"9\" y=\"24\" width=\"46\" height=\"24\" fill=\"#141414\"/><text x=\"32\" y=\"14\" text-anchor=\"middle\" font-size=\"5\" font-family=\"monospace\" fill=\"#fff\">GND VCC SCL SDA</text><circle cx=\"18\" cy=\"19\" r=\"1.6\" fill=\"#b4aeab\"/><circle cx=\"27\" cy=\"19\" r=\"1.6\" fill=\"#c08540\"/><circle cx=\"37\" cy=\"19\" r=\"1.6\" fill=\"#009e9b\"/><circle cx=\"46\" cy=\"19\" r=\"1.6\" fill=\"#007adb\"/><text x=\"32\" y=\"39\" text-anchor=\"middle\" font-size=\"7\" font-family=\"monospace\" fill=\"#9be1ff\" font-weight=\"bold\">SSD1306</text><text x=\"32\" y=\"46\" text-anchor=\"middle\" font-size=\"4.5\" font-family=\"monospace\" fill=\"#9be1ff\">I2C 4-pin</text></svg>",
|
||||
"properties": [
|
||||
{
|
||||
"name": "i2cAddress",
|
||||
"type": "string",
|
||||
"defaultValue": "0x3c",
|
||||
"control": "text",
|
||||
"description": "I2C address"
|
||||
}
|
||||
],
|
||||
"defaultValues": {
|
||||
"i2cAddress": "0x3c"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ import { Attiny85 } from './velxio-components/Attiny85';
|
|||
import './velxio-components/Esp32Element'; // registers velxio-esp32
|
||||
import './velxio-components/PiPicoWElement'; // registers velxio-pi-pico-w
|
||||
import './velxio-components/Stm32BluePillElement'; // registers velxio-stm32-bluepill
|
||||
import './velxio-components/Ssd1306I2cElement'; // registers velxio-ssd1306-i2c-4pin
|
||||
// Register every wokwi tag that the picker might try to instantiate as a
|
||||
// thumbnail. The picker calls `document.createElement(tagName)`, so any tag
|
||||
// that isn't already a registered custom element renders as an empty
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import { getBoardLogicFamily } from '../simulation/LogicFamilies';
|
|||
// <velxio-instr-voltmeter>) that don't exist upstream.
|
||||
import '@wokwi/elements';
|
||||
import '../velxio-elements';
|
||||
import './velxio-components/Ssd1306I2cElement'; // registers velxio-ssd1306-i2c-4pin (4-pin I2C OLED)
|
||||
|
||||
// Map metadataId → [pinA, pinB] for 2-terminal passives.
|
||||
// "Tracing through" means: if the caller arrived on pinA, continue from pinB
|
||||
|
|
|
|||
|
|
@ -0,0 +1,160 @@
|
|||
/**
|
||||
* Ssd1306I2cElement — `<velxio-ssd1306-i2c-4pin>` Web Component.
|
||||
*
|
||||
* The common cheap 0.96" SSD1306 OLED **I2C module with only 4 pins**
|
||||
* (GND / VCC / SCL / SDA) — the counterpart to the 8-pin `wokwi-ssd1306`
|
||||
* breakout, and the layout most beginners actually have on their desk
|
||||
* (matches Wokwi's `board-ssd1306`). A velxio-local element because
|
||||
* `@wokwi/elements` only ships the 8-pin variant. See issue #215.
|
||||
*
|
||||
* Same rendering surface as `wokwi-ssd1306` so `SSD1306Core.syncElement`
|
||||
* (simulation/parts/ProtocolParts.ts) drives it unchanged:
|
||||
* - `element.imageData` — a 128×64 ImageData (RGBA)
|
||||
* - `element.redraw()` — flushes imageData to the internal canvas
|
||||
*
|
||||
* Per CLAUDE.md §6a this MUST be a real Web Component — the wire system reads
|
||||
* `pinInfo` from the DOM node to place wire endpoints on the pin tips.
|
||||
*/
|
||||
|
||||
const SCREEN_W = 128;
|
||||
const SCREEN_H = 64;
|
||||
|
||||
// Body geometry (CSS px). Kept visually in the same family as wokwi-ssd1306
|
||||
// (blue PCB, dark screen, corner mounting holes, star) but narrower — a 4-pin
|
||||
// header instead of 8. Screen sits at (SCREEN_X, SCREEN_Y).
|
||||
const BODY_W = 150;
|
||||
const BODY_H = 108;
|
||||
const SCREEN_X = 11;
|
||||
const SCREEN_Y = 30;
|
||||
|
||||
// 4-pin 0.1" header, centred along the top edge. `x`/`y` are the pin tips the
|
||||
// wire system snaps to.
|
||||
const PIN_Y = 11;
|
||||
const PIN_SPACING = 15;
|
||||
const PIN_NAMES = ['GND', 'VCC', 'SCL', 'SDA'] as const;
|
||||
const PIN_X0 = BODY_W / 2 - ((PIN_NAMES.length - 1) * PIN_SPACING) / 2;
|
||||
// Ring colours echo the wokwi-ssd1306 pin styling.
|
||||
const PIN_RING = ['#B4AEAB', '#C08540', '#009E9B', '#007ADB'];
|
||||
|
||||
function signalsFor(name: string) {
|
||||
if (name === 'GND') return [{ type: 'power', signal: 'GND' }];
|
||||
if (name === 'VCC') return [{ type: 'power', signal: 'VCC' }];
|
||||
if (name === 'SCL') return [{ type: 'i2c', signal: 'SCL' }];
|
||||
if (name === 'SDA') return [{ type: 'i2c', signal: 'SDA' }];
|
||||
return [];
|
||||
}
|
||||
|
||||
class Ssd1306I2cElement extends HTMLElement {
|
||||
private _imageData: ImageData = new ImageData(SCREEN_W, SCREEN_H);
|
||||
private ctx: CanvasRenderingContext2D | null = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: 'open' });
|
||||
}
|
||||
|
||||
connectedCallback(): void {
|
||||
this.render();
|
||||
this.initContext();
|
||||
}
|
||||
|
||||
/** Wire system reads this from the DOM — do NOT memoize. */
|
||||
get pinInfo() {
|
||||
return PIN_NAMES.map((name, i) => ({
|
||||
name,
|
||||
x: PIN_X0 + i * PIN_SPACING,
|
||||
y: PIN_Y,
|
||||
number: i + 1,
|
||||
signals: signalsFor(name),
|
||||
}));
|
||||
}
|
||||
|
||||
get canvas(): HTMLCanvasElement | null {
|
||||
return this.shadowRoot?.querySelector('canvas') ?? null;
|
||||
}
|
||||
|
||||
/** Accepts the ImageData pushed by SSD1306Core; ignores anything else (e.g. a
|
||||
* stray string property assignment from the loader). */
|
||||
set imageData(v: ImageData) {
|
||||
if (v instanceof ImageData) this._imageData = v;
|
||||
}
|
||||
get imageData(): ImageData {
|
||||
return this._imageData;
|
||||
}
|
||||
|
||||
/** Flush the current imageData to the canvas (called by SSD1306Core). */
|
||||
redraw(): void {
|
||||
if (!this.ctx) this.initContext();
|
||||
try {
|
||||
this.ctx?.putImageData(this._imageData, 0, 0);
|
||||
} catch {
|
||||
/* canvas not ready yet */
|
||||
}
|
||||
}
|
||||
|
||||
private initContext(): void {
|
||||
const c = this.canvas;
|
||||
this.ctx = c?.getContext('2d') ?? null;
|
||||
this.ctx?.putImageData(this._imageData, 0, 0);
|
||||
}
|
||||
|
||||
private render(): void {
|
||||
if (!this.shadowRoot) return;
|
||||
const holes = [
|
||||
[8, 8],
|
||||
[BODY_W - 8, 8],
|
||||
[8, BODY_H - 8],
|
||||
[BODY_W - 8, BODY_H - 8],
|
||||
];
|
||||
this.shadowRoot.innerHTML = `
|
||||
<style>
|
||||
:host { display: inline-block; line-height: 0; position: relative; }
|
||||
svg { display: block; user-select: none; -webkit-user-select: none; }
|
||||
canvas {
|
||||
position: absolute;
|
||||
left: ${SCREEN_X}px;
|
||||
top: ${SCREEN_Y}px;
|
||||
image-rendering: pixelated;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
<svg width="${BODY_W}" height="${BODY_H}" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Blue PCB -->
|
||||
<rect stroke="#BE9B72" fill="#025CAF" x=".5" y=".5"
|
||||
width="${BODY_W - 1}" height="${BODY_H - 1}" rx="10" />
|
||||
|
||||
<!-- Corner mounting holes -->
|
||||
<g fill="#59340A" stroke="#BE9B72" stroke-width="0.6">
|
||||
${holes.map(([cx, cy]) => `<circle cx="${cx}" cy="${cy}" r="4.5" />`).join('')}
|
||||
</g>
|
||||
|
||||
<!-- 128 x 64 screen (the <canvas> paints on top of this) -->
|
||||
<rect x="${SCREEN_X}" y="${SCREEN_Y}" width="${SCREEN_W}" height="${SCREEN_H}" fill="#1A1A1A" />
|
||||
|
||||
<!-- Star decoration, echoing the 8-pin part -->
|
||||
<path fill="#FFF" stroke="#FFF"
|
||||
d="M133 6.5l-1.4 2.6-3 .4 2.2 2-.53 2.83 2.75-1.34 2.75 1.34-.53-2.83 2.2-2-3-.4-1.4-2.6z" />
|
||||
|
||||
<!-- 4-pin header + labels -->
|
||||
<g font-family="monospace" font-size="6" font-weight="300" fill="#FFF" text-anchor="middle">
|
||||
${PIN_NAMES.map(
|
||||
(name, i) => `<text x="${PIN_X0 + i * PIN_SPACING}" y="${PIN_Y + 12}">${name}</text>`,
|
||||
).join('')}
|
||||
</g>
|
||||
<g fill="#9D9D9A" stroke-width="0.4">
|
||||
${PIN_NAMES.map(
|
||||
(_, i) =>
|
||||
`<circle stroke="${PIN_RING[i]}" cx="${PIN_X0 + i * PIN_SPACING}" cy="${PIN_Y}" r="3.5" />`,
|
||||
).join('')}
|
||||
</g>
|
||||
</svg>
|
||||
<canvas width="${SCREEN_W}" height="${SCREEN_H}"></canvas>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
if (!customElements.get('velxio-ssd1306-i2c-4pin')) {
|
||||
customElements.define('velxio-ssd1306-i2c-4pin', Ssd1306I2cElement);
|
||||
}
|
||||
|
||||
export type { Ssd1306I2cElement };
|
||||
|
|
@ -91,6 +91,249 @@ export interface ExampleProject {
|
|||
}
|
||||
|
||||
const legacyExamples: ExampleProject[] = [
|
||||
// ── SSD1306 OLED — 4-pin I2C module (velxio-ssd1306-i2c-4pin) across boards.
|
||||
// The cheap GND/VCC/SCL/SDA module beginners actually own (issue #215). ──
|
||||
{
|
||||
id: 'uno-oled-4pin-i2c',
|
||||
title: 'Arduino Uno: SSD1306 OLED (4-pin I2C)',
|
||||
description:
|
||||
'Drive the cheap 4-pin SSD1306 OLED module (GND/VCC/SCL/SDA) over I2C from an Arduino Uno (SDA=A4, SCL=A5). Shows "Hello Velxio!" with a live counter.',
|
||||
libraries: ['Adafruit SSD1306', 'Adafruit GFX Library'],
|
||||
category: 'displays',
|
||||
difficulty: 'intermediate',
|
||||
boardFilter: 'arduino-uno',
|
||||
boards: [
|
||||
{
|
||||
boardKind: 'arduino-uno',
|
||||
x: 60,
|
||||
y: 60,
|
||||
code: `// Arduino Uno — SSD1306 128x64 OLED (4-pin I2C module)
|
||||
// Wiring: SDA -> A4 | SCL -> A5 | VCC -> 5V | GND -> GND
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
|
||||
Adafruit_SSD1306 display(128, 64, &Wire, -1);
|
||||
int n = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Wire.begin();
|
||||
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
|
||||
Serial.println("SSD1306 not found!");
|
||||
while (true) delay(10);
|
||||
}
|
||||
display.clearDisplay();
|
||||
Serial.println("OLED ready");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
n++;
|
||||
display.clearDisplay();
|
||||
display.setTextSize(2);
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
display.setCursor(0, 0);
|
||||
display.println("Hello");
|
||||
display.println("Velxio!");
|
||||
display.setTextSize(1);
|
||||
display.setCursor(0, 48);
|
||||
display.print("Count: ");
|
||||
display.print(n);
|
||||
display.display();
|
||||
delay(500);
|
||||
}`,
|
||||
},
|
||||
],
|
||||
code: '',
|
||||
components: [{ type: 'velxio-ssd1306-i2c-4pin', id: 'oled', x: 470, y: 100, properties: {} }],
|
||||
wires: [
|
||||
{ id: 'w-vcc', start: { componentId: 'arduino-uno', pinName: '5V' }, end: { componentId: 'oled', pinName: 'VCC' }, color: '#ff4444' },
|
||||
{ id: 'w-gnd', start: { componentId: 'arduino-uno', pinName: 'GND.2' }, end: { componentId: 'oled', pinName: 'GND' }, color: '#000000' },
|
||||
{ id: 'w-sda', start: { componentId: 'arduino-uno', pinName: 'A4' }, end: { componentId: 'oled', pinName: 'SDA' }, color: '#22aaff' },
|
||||
{ id: 'w-scl', start: { componentId: 'arduino-uno', pinName: 'A5' }, end: { componentId: 'oled', pinName: 'SCL' }, color: '#ff8800' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'esp32-oled-4pin-i2c',
|
||||
title: 'ESP32: SSD1306 OLED (4-pin I2C)',
|
||||
description:
|
||||
'Drive the cheap 4-pin SSD1306 OLED module (GND/VCC/SCL/SDA) over I2C from an ESP32 (SDA=21, SCL=22).',
|
||||
libraries: ['Adafruit SSD1306', 'Adafruit GFX Library'],
|
||||
category: 'displays',
|
||||
difficulty: 'intermediate',
|
||||
boardFilter: 'esp32',
|
||||
boards: [
|
||||
{
|
||||
boardKind: 'esp32',
|
||||
x: 60,
|
||||
y: 60,
|
||||
code: `// ESP32 — SSD1306 128x64 OLED (4-pin I2C module)
|
||||
// Wiring: SDA -> 21 | SCL -> 22 | VCC -> 3V3 | GND -> GND
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
|
||||
Adafruit_SSD1306 display(128, 64, &Wire, -1);
|
||||
int n = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Wire.begin(21, 22);
|
||||
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
|
||||
Serial.println("SSD1306 not found!");
|
||||
while (true) delay(10);
|
||||
}
|
||||
display.clearDisplay();
|
||||
Serial.println("OLED ready");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
n++;
|
||||
display.clearDisplay();
|
||||
display.setTextSize(2);
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
display.setCursor(0, 0);
|
||||
display.println("Hello");
|
||||
display.println("Velxio!");
|
||||
display.setTextSize(1);
|
||||
display.setCursor(0, 48);
|
||||
display.printf("Count: %d", n);
|
||||
display.display();
|
||||
delay(500);
|
||||
}`,
|
||||
},
|
||||
],
|
||||
code: '',
|
||||
components: [{ type: 'velxio-ssd1306-i2c-4pin', id: 'oled', x: 470, y: 100, properties: {} }],
|
||||
wires: [
|
||||
{ id: 'w-vcc', start: { componentId: 'esp32', pinName: '3V3' }, end: { componentId: 'oled', pinName: 'VCC' }, color: '#ff4444' },
|
||||
{ id: 'w-gnd', start: { componentId: 'esp32', pinName: 'GND' }, end: { componentId: 'oled', pinName: 'GND' }, color: '#000000' },
|
||||
{ id: 'w-sda', start: { componentId: 'esp32', pinName: '21' }, end: { componentId: 'oled', pinName: 'SDA' }, color: '#22aaff' },
|
||||
{ id: 'w-scl', start: { componentId: 'esp32', pinName: '22' }, end: { componentId: 'oled', pinName: 'SCL' }, color: '#ff8800' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'pico-oled-4pin-i2c',
|
||||
title: 'Raspberry Pi Pico: SSD1306 OLED (4-pin I2C)',
|
||||
description:
|
||||
'Drive the cheap 4-pin SSD1306 OLED module (GND/VCC/SCL/SDA) over I2C from a Raspberry Pi Pico (SDA=GP4, SCL=GP5).',
|
||||
libraries: ['Adafruit SSD1306', 'Adafruit GFX Library'],
|
||||
category: 'displays',
|
||||
difficulty: 'intermediate',
|
||||
boardFilter: 'raspberry-pi-pico',
|
||||
boards: [
|
||||
{
|
||||
boardKind: 'raspberry-pi-pico',
|
||||
x: 60,
|
||||
y: 60,
|
||||
code: `// Raspberry Pi Pico — SSD1306 128x64 OLED (4-pin I2C module)
|
||||
// Wiring: SDA -> GP4 | SCL -> GP5 | VCC -> 3V3 | GND -> GND
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
|
||||
Adafruit_SSD1306 display(128, 64, &Wire, -1);
|
||||
int n = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Wire.setSDA(4);
|
||||
Wire.setSCL(5);
|
||||
Wire.begin();
|
||||
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
|
||||
Serial.println("SSD1306 not found!");
|
||||
while (true) delay(10);
|
||||
}
|
||||
display.clearDisplay();
|
||||
Serial.println("OLED ready");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
n++;
|
||||
display.clearDisplay();
|
||||
display.setTextSize(2);
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
display.setCursor(0, 0);
|
||||
display.println("Hello");
|
||||
display.println("Velxio!");
|
||||
display.setTextSize(1);
|
||||
display.setCursor(0, 48);
|
||||
display.print("Count: ");
|
||||
display.print(n);
|
||||
display.display();
|
||||
delay(500);
|
||||
}`,
|
||||
},
|
||||
],
|
||||
code: '',
|
||||
components: [{ type: 'velxio-ssd1306-i2c-4pin', id: 'oled', x: 470, y: 100, properties: {} }],
|
||||
wires: [
|
||||
{ id: 'w-vcc', start: { componentId: 'raspberry-pi-pico', pinName: '3V3' }, end: { componentId: 'oled', pinName: 'VCC' }, color: '#ff4444' },
|
||||
{ id: 'w-gnd', start: { componentId: 'raspberry-pi-pico', pinName: 'GND.3' }, end: { componentId: 'oled', pinName: 'GND' }, color: '#000000' },
|
||||
{ id: 'w-sda', start: { componentId: 'raspberry-pi-pico', pinName: 'GP4' }, end: { componentId: 'oled', pinName: 'SDA' }, color: '#22aaff' },
|
||||
{ id: 'w-scl', start: { componentId: 'raspberry-pi-pico', pinName: 'GP5' }, end: { componentId: 'oled', pinName: 'SCL' }, color: '#ff8800' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'stm32-oled-4pin-i2c',
|
||||
title: 'STM32 Blue Pill: SSD1306 OLED (4-pin I2C)',
|
||||
description:
|
||||
'Drive the cheap 4-pin SSD1306 OLED module (GND/VCC/SCL/SDA) over I2C1 from an STM32 Blue Pill (SDA=PB7, SCL=PB6).',
|
||||
libraries: ['Adafruit SSD1306', 'Adafruit GFX Library'],
|
||||
category: 'displays',
|
||||
difficulty: 'intermediate',
|
||||
boardFilter: 'stm32-bluepill',
|
||||
boards: [
|
||||
{
|
||||
boardKind: 'stm32-bluepill',
|
||||
x: 60,
|
||||
y: 60,
|
||||
code: `// STM32 Blue Pill (F103) — SSD1306 128x64 OLED (4-pin I2C module)
|
||||
// Wiring: SDA -> PB7 | SCL -> PB6 | VCC -> 3V3 | GND -> GND
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
|
||||
Adafruit_SSD1306 display(128, 64, &Wire, -1);
|
||||
int n = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Wire.begin();
|
||||
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
|
||||
Serial.println("SSD1306 not found!");
|
||||
while (true) delay(10);
|
||||
}
|
||||
display.clearDisplay();
|
||||
Serial.println("OLED ready");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
n++;
|
||||
display.clearDisplay();
|
||||
display.setTextSize(2);
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
display.setCursor(0, 0);
|
||||
display.println("Hello");
|
||||
display.println("Velxio!");
|
||||
display.setTextSize(1);
|
||||
display.setCursor(0, 48);
|
||||
display.print("Count: ");
|
||||
display.print(n);
|
||||
display.display();
|
||||
delay(500);
|
||||
}`,
|
||||
},
|
||||
],
|
||||
code: '',
|
||||
components: [{ type: 'velxio-ssd1306-i2c-4pin', id: 'oled', x: 470, y: 100, properties: {} }],
|
||||
wires: [
|
||||
{ id: 'w-vcc', start: { componentId: 'stm32-bluepill', pinName: '3V3' }, end: { componentId: 'oled', pinName: 'VCC' }, color: '#ff4444' },
|
||||
{ id: 'w-gnd', start: { componentId: 'stm32-bluepill', pinName: 'GND' }, end: { componentId: 'oled', pinName: 'GND' }, color: '#000000' },
|
||||
{ id: 'w-sda', start: { componentId: 'stm32-bluepill', pinName: 'PB7' }, end: { componentId: 'oled', pinName: 'SDA' }, color: '#22aaff' },
|
||||
{ id: 'w-scl', start: { componentId: 'stm32-bluepill', pinName: 'PB6' }, end: { componentId: 'oled', pinName: 'SCL' }, color: '#ff8800' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'ky-040-rotary-encoder',
|
||||
title: 'KY-040 Rotary Encoder',
|
||||
|
|
|
|||
|
|
@ -413,6 +413,20 @@ PartSimulationRegistry.register('ssd1306', {
|
|||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* SSD1306 OLED (I2C, 4-pin) — the cheap `velxio-ssd1306-i2c` module (GND/VCC/
|
||||
* SCL/SDA). Same display core as the 8-pin part but I2C-only by construction,
|
||||
* so there's no protocol to detect. Issue #215.
|
||||
*/
|
||||
PartSimulationRegistry.register('ssd1306-i2c-4pin', {
|
||||
attachEvents: (element, simulator, getPin, componentId) => {
|
||||
const { components } = useSimulatorStore.getState();
|
||||
const comp = components.find((c) => c.id === componentId);
|
||||
const i2cAddr = parseI2cAddress(comp?.properties?.i2cAddress, 0x3c);
|
||||
return attachSSD1306(element, simulator, getPin, 'i2c', i2cAddr);
|
||||
},
|
||||
});
|
||||
|
||||
// ─── DS1307 RTC ──────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2455,6 +2455,35 @@
|
|||
"2004",
|
||||
"liquidcrystal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"$comment": "4-pin I2C-only SSD1306 module (GND/VCC/SCL/SDA) — the cheap 0.96\" OLED most beginners have; velxio-ssd1306-i2c native element. Counterpart to the 8-pin wokwi-ssd1306. Issue #215.",
|
||||
"id": "ssd1306-i2c-4pin",
|
||||
"tagName": "velxio-ssd1306-i2c-4pin",
|
||||
"name": "SSD1306 OLED (I2C, 4-pin)",
|
||||
"category": "displays",
|
||||
"pinCount": 4,
|
||||
"tags": [
|
||||
"ssd1306",
|
||||
"oled",
|
||||
"display",
|
||||
"i2c",
|
||||
"4-pin",
|
||||
"0x3c"
|
||||
],
|
||||
"thumbnail": "<svg width=\"64\" height=\"64\" xmlns=\"http://www.w3.org/2000/svg\"><rect width=\"64\" height=\"64\" fill=\"#025caf\" rx=\"6\"/><rect x=\"9\" y=\"24\" width=\"46\" height=\"24\" fill=\"#141414\"/><text x=\"32\" y=\"14\" text-anchor=\"middle\" font-size=\"5\" font-family=\"monospace\" fill=\"#fff\">GND VCC SCL SDA</text><circle cx=\"18\" cy=\"19\" r=\"1.6\" fill=\"#b4aeab\"/><circle cx=\"27\" cy=\"19\" r=\"1.6\" fill=\"#c08540\"/><circle cx=\"37\" cy=\"19\" r=\"1.6\" fill=\"#009e9b\"/><circle cx=\"46\" cy=\"19\" r=\"1.6\" fill=\"#007adb\"/><text x=\"32\" y=\"39\" text-anchor=\"middle\" font-size=\"7\" font-family=\"monospace\" fill=\"#9be1ff\" font-weight=\"bold\">SSD1306</text><text x=\"32\" y=\"46\" text-anchor=\"middle\" font-size=\"4.5\" font-family=\"monospace\" fill=\"#9be1ff\">I2C 4-pin</text></svg>",
|
||||
"properties": [
|
||||
{
|
||||
"name": "i2cAddress",
|
||||
"type": "string",
|
||||
"defaultValue": "0x3c",
|
||||
"control": "text",
|
||||
"description": "I2C address"
|
||||
}
|
||||
],
|
||||
"defaultValues": {
|
||||
"i2cAddress": "0x3c"
|
||||
}
|
||||
}
|
||||
],
|
||||
"led": {
|
||||
|
|
|
|||
Loading…
Reference in New Issue