Vastaanotin v1 lähdekoodi: Difference between revisions

From Pessin randon wiki
Created page with "Lähdekoodi V1<syntaxhighlight lang="c#" line="1"> #include <RH_ASK.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 32 #define OLED_RESET -1 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // Radiovastaanotin RH_ASK driver(1000, 12, 11, 10); // RX = D12 // Ajastukset const unsigned long ENTRY_TIMEOUT = 30 * 60 * 1000UL; // 30 min const unsigned long DISPLAY_DURATION =..."
 
No edit summary
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
Lähdekoodi V1<syntaxhighlight lang="c#" line="1">
Lähdekoodi V1
 
Tiedetyt bugit:
 
Ei lue ID 6:sta tai ID 12:sta<syntaxhighlight lang="c#" line="1">
#include <RH_ASK.h>
#include <RH_ASK.h>
#include <Wire.h>
#include <Wire.h>
Line 253: Line 257:
}
}
</syntaxhighlight>
</syntaxhighlight>
=== Vastaanottimen käyttö ===
Tämä laite vastaanottaa 433 MHz -radioviestejä, joissa on kiinteitä DIP-koodeja. Jokaisella DIP-koodilla on pysyvä '''ID-numero (1–16)'''. Näytöllä näkyy aina yksi koodi kerrallaan.
[[File:Vastaanotin-oled.jpg|thumb|Vastaanottimen oled näyttö]]
==== Mitä näyttö kertoo? ====
Näyttö on jaettu kahteen osaan:
* Vasemmassa reunassa (suurena):
** '''ID-numero''' (esim. <code>5</code>)
** '''Huutomerkki <code>!</code>''' näkyy, jos koodi on '''aktiivinen''' (viesti saatu viimeisen 5 minuutin aikana)
* Oikeassa reunassa (pienellä tekstillä):
# '''Ylärivi:'''  Esim. <code>2/(3)/[5]</code>
#* <code>2</code> = aktiivisten lähetysten määrä
#* <code>(3)</code> = passiivisten lähetysten määrä (viesti yli 5 min vanha)
#* <code>[5]</code> = kaikkien vastaanotettujen lähetyksien määrä
# '''Toinen rivi (vain jos koodi on passiivinen):'''
#* Aika viimeisestä viestistä minuutteina (esim. <code>17m</code>)
# '''Kolmas rivi (vain jos passiivinen):'''
#* Sana <code>PASSIVE</code>
# '''Alarivi:'''
#* DIP-koodi (esim. <code>0100</code>)

Latest revision as of 15:11, 3 October 2025

Lähdekoodi V1

Tiedetyt bugit:

Ei lue ID 6:sta tai ID 12:sta

#include <RH_ASK.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Radiovastaanotin
RH_ASK driver(1000, 12, 11, 10); // RX = D12

// Ajastukset
const unsigned long ENTRY_TIMEOUT = 30 * 60 * 1000UL; // 30 min
const unsigned long DISPLAY_DURATION = 2500;         // 2.5 s

// Seuraava ruutu nappi
#define BUTTON_PIN 2

// Kiinteät DIP-koodit (16 kpl)
const char* dipIdMap[16] = {
  "0000", "0001", "0010", "0011",
  "0100", "0101", "0110", "0111",
  "1000", "1001", "1010", "1011",
  "1100", "1101", "1110", "1111"
};

//Vilkku
bool blinkState = false;
unsigned long lastBlink = 0;
const unsigned long BLINK_INTERVAL = 500;


// Tallennetaan viimeisin aikaleima DIP-koodeille
unsigned long dipSeen[16] = {0};

// Painallusmuuttujat
bool buttonPressed = false;
unsigned long lastDisplaySwitch = 0;

// CRC8 Dallas/Maxim
byte crc8_dallas(const char* data, uint8_t len) {
  byte crc = 0x00;
  for (uint8_t i = 0; i < len; i++) {
    crc ^= data[i];
    for (uint8_t j = 0; j < 8; j++) {
      crc = (crc & 0x80) ? (crc << 1) ^ 0x31 : (crc << 1);
    }
  }
  return crc;
}

// Palauttaa ID:n 1–16 tai 0 jos tuntematon
int getDipId(const char* dip) {
  for (int i = 0; i < 16; i++) {
    if (strncmp(dipIdMap[i], dip, 4) == 0) {
      return i + 1;
    }
  }
  return 0;
}

void setup() {
  // Serial.begin(9600);
  // delay(1000);

  pinMode(BUTTON_PIN, INPUT_PULLUP);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    display.clearDisplay();
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.println(F("OLED ei vastaa"));
    display.display();
    while (1); // Pysäyttää ohjelman
  }

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println(F("Odotetaan..."));
  display.display();

  
  if (!driver.init()) {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println(F("Radio ei vastaa"));
    display.display();
    while (1); // 
  }
  

  pinMode(12, INPUT);
}

void loop() {
  receiveRadio();
  cleanExpiredEntries();
  checkButton();
  updateDisplay();
  delay(10);
}

void checkButton() {
  static bool prevState = HIGH;
  bool state = digitalRead(BUTTON_PIN);

  if (prevState == HIGH && state == LOW) {
    buttonPressed = true;
  }

  prevState = state;
}

void receiveRadio() {
  uint8_t buf[32];
  uint8_t buflen = sizeof(buf);

  if (driver.recv(buf, &buflen)) {
    if (buflen < 8 || buf[0] != 'S' || buf[5] != 'E') return;

    byte expectedCrc = crc8_dallas((char*)buf, 6);
    char crcStr[3] = { (char)buf[6], (char)buf[7], '\0' };
    byte receivedCrc = strtoul(crcStr, NULL, 16);
    if (expectedCrc != receivedCrc) return;

    char dip[5];
    memcpy(dip, &buf[1], 4);
    dip[4] = '\0';

    int dipId = getDipId(dip);
    
    if (dipId <= 0) {
      return;
    }

    dipSeen[dipId - 1] = millis(); // Päivitä aikaleima
  }
}

void cleanExpiredEntries() {
  unsigned long now = millis();
  for (int i = 0; i < 16; i++) {
    if (dipSeen[i] != 0 && now - dipSeen[i] > ENTRY_TIMEOUT) {
      dipSeen[i] = 0; // Nollaa aikaleima = ei enää aktiivinen
    }
  }
}

void updateDisplay() {
  static int currentActiveIndex = -1;
  unsigned long now = millis();

  int allSeenIndices[16];
  int seenCount = 0;
  int activeCount = 0;
  int passiveCount = 0;

  // Kerätään vastaanotetut DIP:t ja lasketaan aktiiviset/passiiviset
  for (int i = 0; i < 16; i++) {
    if (dipSeen[i] != 0) {
      allSeenIndices[seenCount++] = i;
      unsigned long ageMin = (now - dipSeen[i]) / 60000UL;
      if (ageMin <= 5) {
        activeCount++;
      } else {
        passiveCount++;
      }
    }
  }

  display.clearDisplay();

  if (seenCount <= 0) {
    // Jos ei ole aktiivisia koodeja
    currentActiveIndex = -1;
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.println(F("Kuunnellaan radiota..."));

    // Vilkku aina näkyviin
    if (now - lastBlink >= BLINK_INTERVAL) {
      blinkState = !blinkState;
      lastBlink = now;
    }
    if (blinkState) {
      display.fillRect(SCREEN_WIDTH - 3, SCREEN_HEIGHT - 3, 2, 2, SSD1306_WHITE);
    }

    display.display();
    return;
  }

  // Päivitä ruutu vain tarvittaessa
  if (now - lastDisplaySwitch >= DISPLAY_DURATION || buttonPressed) {
    currentActiveIndex = (currentActiveIndex + 1) % seenCount;
    lastDisplaySwitch = now;
    buttonPressed = false;
  }

  // Haetaan näytettävä DIP
  int dipIndex = allSeenIndices[currentActiveIndex];
  int id = dipIndex + 1;

  unsigned long ageMin = (now - dipSeen[dipIndex]) / 60000UL;
  bool isPassive = (ageMin > 5);

  // Vasemmalle iso ID-numero
  display.setTextSize(4);
  display.setCursor(0, 0);
  display.print(id);
  if (!isPassive) {
    display.print("!");
  }

  // Oikealle tilastorivi
  display.setTextSize(1);
  int xTextStart = SCREEN_WIDTH - 6 * 10;
  char indexStr[20];
  snprintf(indexStr, sizeof(indexStr), "%d/(%d)/[%d]", activeCount, passiveCount, seenCount);
  display.setCursor(xTextStart, 0);
  display.print(indexStr);

  // PASSIVE-merkinnät jos yli 5 min vanha
  if (isPassive) {
    char timeStr[10];
    snprintf(timeStr, sizeof(timeStr), "%lum", ageMin);
    display.setCursor(xTextStart, 8);
    display.print(timeStr);

    display.setCursor(xTextStart, 16);
    display.print(F("PASSIVE"));
  }

  // DIP-koodi alariville
  display.setCursor(xTextStart, SCREEN_HEIGHT - 8);
  display.print(dipIdMap[dipIndex]);

  // Vilkku (aina näkyvissä)
  if (now - lastBlink >= BLINK_INTERVAL) {
    blinkState = !blinkState;
    lastBlink = now;
  }
  if (blinkState) {
    display.fillRect(SCREEN_WIDTH - 3, SCREEN_HEIGHT - 3, 2, 2, SSD1306_WHITE);
  }

  display.display();
}

Vastaanottimen käyttö

Tämä laite vastaanottaa 433 MHz -radioviestejä, joissa on kiinteitä DIP-koodeja. Jokaisella DIP-koodilla on pysyvä ID-numero (1–16). Näytöllä näkyy aina yksi koodi kerrallaan.

Vastaanottimen oled näyttö

Mitä näyttö kertoo?

Näyttö on jaettu kahteen osaan:

  • Vasemmassa reunassa (suurena):
    • ID-numero (esim. 5)
    • Huutomerkki ! näkyy, jos koodi on aktiivinen (viesti saatu viimeisen 5 minuutin aikana)
  • Oikeassa reunassa (pienellä tekstillä):
  1. Ylärivi: Esim. 2/(3)/[5]
    • 2 = aktiivisten lähetysten määrä
    • (3) = passiivisten lähetysten määrä (viesti yli 5 min vanha)
    • [5] = kaikkien vastaanotettujen lähetyksien määrä
  2. Toinen rivi (vain jos koodi on passiivinen):
    • Aika viimeisestä viestistä minuutteina (esim. 17m)
  3. Kolmas rivi (vain jos passiivinen):
    • Sana PASSIVE
  4. Alarivi:
    • DIP-koodi (esim. 0100)