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 difference)
|
Revision as of 14:34, 3 October 2025
Lähdekoodi V1
#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();
}