#include <Arduino.h>
#define DATA_PIN 11
#define CLOCK_PIN 12
#define LATCH_PIN 10
#define STROBE_PIN 13
char display_text[10] = "RADMOR ";
const uint8_t segment_bits[17] = {
14, // a
13, // j
12, // h
11, // k
10, // b
9, // f
8, // g
7, // m
6, // c
5, // e
4, // v
3, // n
2, // p
1, // d
0, // c1
15, // c2
0 // dp
};
// To mapowanie DAŁO "ROMDAR" (działało od pozycji 4)
const uint8_t grid_bits[9] = {
20, // G1
21, // G2
22, // G3
23, // G4
24, // G5
25, // G6
26, // G7
27, // G8
28 // G9
};
typedef struct {
char ch;
uint8_t seg[17];
} vfd_char_t;
const vfd_char_t vfdFont[] = {
// A J H K B F G M C E V N P D C1 C2 DP
{ '!', { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } },
{ ' ', { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ '0', { 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0 } },
{ '1', { 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ '2', { 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0 } },
{ '3', { 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0 } },
{ '4', { 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 } },
{ '5', { 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0 } },
{ '6', { 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0 } },
{ '7', { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } },
{ '8', { 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0 } },
{ '9', { 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0 } },
{ 'A', { 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0 } },
{ 'B', { 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0 } },
{ 'C', { 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 } },
{ 'D', { 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0 } },
{ 'E', { 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0 } },
{ 'F', { 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 } },
{ 'G', { 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0 } },
{ 'H', { 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0 } },
{ 'I', { 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 } },
{ 'J', { 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0 } },
{ 'K', { 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0 } },
{ 'L', { 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 } },
{ 'M', { 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0 } },
{ 'N', { 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0 } },
{ 'O', { 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0 } },
{ 'P', { 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 } },
{ 'Q', { 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0 } },
{ 'R', { 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0 } },
{ 'S', { 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0 } },
{ 'T', { 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ 'U', { 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0 } },
{ 'V', { 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 } },
{ 'W', { 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0 } },
{ 'X', { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0 } },
{ 'Y', { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ 'Z', { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0 } },
{ '-', { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 } },
{ '+', { 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 } },
{ '_', { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 } },
{ '/', { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } },
{ 'x', { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0 } },
{ '.', { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 } },
{ ',', { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0 } },
{ ':', { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 } },
};
const int FONT_SIZE = sizeof(vfdFont) / sizeof(vfdFont[0]);
volatile uint32_t seg_masks[9] = {0};
volatile uint8_t current_pos = 0;
volatile bool need_update = false;
volatile uint8_t next_pos = 0;
hw_timer_t *timer = NULL;
uint32_t get_char_mask(char c) {
for (int i = 0; i < FONT_SIZE; i++) {
if (vfdFont[i].ch == c) {
uint32_t mask = 0;
for (int s = 0; s < 17; s++) {
if (vfdFont[i].seg[s]) {
mask |= (1UL << segment_bits[s]);
}
}
return mask;
}
}
return 0;
}
void send_data(uint32_t data) {
for (int i = 31; i >= 0; i--) {
digitalWrite(CLOCK_PIN, LOW);
digitalWrite(DATA_PIN, (data >> i) & 1);
delayMicroseconds(1);
digitalWrite(CLOCK_PIN, HIGH);
delayMicroseconds(1);
}
}
void write_vfd(uint32_t seg_mask, uint8_t pos) {
uint32_t data = seg_mask | (1UL << grid_bits[pos]);
digitalWrite(STROBE_PIN, HIGH);
digitalWrite(LATCH_PIN, LOW);
send_data(data);
digitalWrite(LATCH_PIN, HIGH);
delayMicroseconds(1);
digitalWrite(LATCH_PIN, LOW);
digitalWrite(STROBE_PIN, LOW);
}
void IRAM_ATTR on_timer() {
next_pos = current_pos;
current_pos = (current_pos + 1) % 9;
need_update = true;
}
void vfd_set_text(const char *str) {
// ODWRÓC KOLEJNOŚĆ ZNAKÓW (bo VFD wyświetla od prawej)
for (int i = 0; i < 9; i++) {
int src_pos = 8 - i;
if (src_pos < 9 && str[src_pos]) {
seg_masks[i] = get_char_mask(str[src_pos]);
} else {
seg_masks[i] = get_char_mask(' ');
}
}
}
void setup() {
Serial.begin(115200);
pinMode(DATA_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(LATCH_PIN, OUTPUT);
pinMode(STROBE_PIN, OUTPUT);
digitalWrite(DATA_PIN, LOW);
digitalWrite(CLOCK_PIN, LOW);
digitalWrite(LATCH_PIN, LOW);
digitalWrite(STROBE_PIN, HIGH);
timer = timerBegin(1000000);
timerAttachInterrupt(timer, &on_timer);
timerAlarm(timer, 2000, true, 0);
vfd_set_text("RADMOR ");
Serial.println("VFD SN75518N started");
}
void loop() {
if (need_update) {
need_update = false;
write_vfd(seg_masks[next_pos], next_pos);
}
static unsigned long last = 0;
static int mode = 0;
const char *texts[] = {"RADMOR ", "VOLUME 5 ", "TUNER ", "CD "};
if (millis() - last > 1000) {
last = millis();
mode = (mode + 1) % 4;
vfd_set_text(texts[mode]);
Serial.printf("Zmiana na: %s\n", texts[mode]);
}
}