Vastaanottimen lähdekoodi V2: Difference between revisions
From Pessin randon wiki
No edit summary |
|||
| Line 13: | Line 13: | ||
* Yhdistetty IDs ja ID last seen samaan muuttujataulukkoon vähentääksemme muistin käyttöä | * Yhdistetty IDs ja ID last seen samaan muuttujataulukkoon vähentääksemme muistin käyttöä | ||
* Muita muistinoptimointeja, kuten checksummin tallentaminen unit8_t muuttujaan unit16_t sijaan. | * Muita muistinoptimointeja, kuten checksummin tallentaminen unit8_t muuttujaan unit16_t sijaan. | ||
<syntaxhighlight lang="c#"> | <syntaxhighlight lang="c#" line="1"> | ||
#include <SPI.h> | #include <SPI.h> | ||
#include <Wire.h> | #include <Wire.h> | ||
| Line 234: | Line 234: | ||
} | } | ||
</syntaxhighlight> | |||
==== V2.2 ==== | |||
Ei testattu. Yhdennetty CRC paketti ja datapaketti samaan läjään.<syntaxhighlight lang="c#" line="1"> | |||
#include <SPI.h> | |||
#include <Wire.h> | |||
#include <Adafruit_GFX.h> | |||
#include <Adafruit_SSD1306.h> | |||
#include <RH_ASK.h> | |||
#include <CRC16.h> | |||
#define OLED_RESET -1 | |||
#define SCREEN_WIDTH 128 | |||
#define SCREEN_HEIGHT 32 | |||
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); | |||
// RX pin on 12 (tarkista kytkentä: Sender TX -> Receiver RX) | |||
RH_ASK driver(1000, 12, 11, 10); | |||
const int MAX_IDS = 16; | |||
struct IdData { | |||
uint8_t id; | |||
unsigned long time; | |||
}; | |||
IdData idData[MAX_IDS]; | |||
int numIds = 0; | |||
const unsigned long DISPLAY_DURATION = 2500; | |||
int selectedId = 0; | |||
unsigned long lastSelectedTime = 0; | |||
const unsigned long INACTIVE_TIME = 3600000; // 1 tunti | |||
// Näytön vilkkuminen | |||
const unsigned long BLINK_INTERVAL = 500; | |||
bool indicatorOn = false; | |||
unsigned long indicatorTime = 0; | |||
void setup() { | |||
Serial.begin(9600); | |||
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { | |||
for (;;); | |||
} | |||
display.clearDisplay(); | |||
display.setTextColor(SSD1306_WHITE); | |||
display.setTextSize(1); | |||
display.setCursor(0, 0); | |||
display.println(F("Initializing...")); | |||
display.display(); | |||
if (!driver.init()) { | |||
display.clearDisplay(); | |||
display.setCursor(0, 0); | |||
display.println(F("Radio error!")); | |||
display.display(); | |||
while (1); | |||
} | |||
} | |||
void loop() { | |||
handleRadioReceiver(); | |||
removeInactiveIds(); | |||
// Päivitä näyttö tietyn väliajoin | |||
if (millis() - lastSelectedTime >= DISPLAY_DURATION) { | |||
selectedId = (selectedId + 1) % (numIds > 0 ? numIds : 1); | |||
lastSelectedTime = millis(); | |||
displayData(); | |||
} | |||
} | |||
void handleRadioReceiver() { | |||
uint8_t buf[RH_ASK_MAX_MESSAGE_LEN]; | |||
uint8_t buflen = sizeof(buf); | |||
if (driver.recv(buf, &buflen)) { | |||
// Tarkistetaan, onko paketti oikean pituinen (6 tavua: 2 CRC + 4 Data) | |||
if (buflen == 6) { | |||
uint16_t receivedChecksum; | |||
// Palautetaan CRC alkuperäiseen muotoon (endianness) | |||
receivedChecksum = buf[0] | (buf[1] << 8); | |||
uint8_t incomingData[4]; | |||
memcpy(incomingData, &buf[2], 4); | |||
// Lasketaan uusi CRC datalle | |||
CRC16 crc; | |||
crc.add(incomingData, 4); | |||
uint16_t calculatedChecksum = crc.calc(); | |||
if (calculatedChecksum == receivedChecksum) { | |||
uint8_t id = processPacket(incomingData, 4); | |||
updateIdList(id); | |||
Serial.print("Valid ID received: "); | |||
Serial.println(id); | |||
} else { | |||
Serial.println("CRC Mismatch!"); | |||
} | |||
} | |||
} | |||
} | |||
void updateIdList(uint8_t id) { | |||
// Päivitetään olemassa oleva tai lisätään uusi | |||
for (int i = 0; i < numIds; i++) { | |||
if (idData[i].id == id) { | |||
idData[i].time = millis(); | |||
return; | |||
} | |||
} | |||
if (numIds < MAX_IDS) { | |||
idData[numIds].id = id; | |||
idData[numIds].time = millis(); | |||
numIds++; | |||
} | |||
} | |||
uint8_t processPacket(uint8_t *data, uint8_t dataLength) { | |||
uint8_t id = 0; | |||
for (uint8_t i = 0; i < dataLength; i++) { | |||
id |= data[i] << i; | |||
} | |||
return id; | |||
} | |||
void removeInactiveIds() { | |||
for (int i = numIds - 1; i >= 0; i--) { | |||
if (millis() - idData[i].time > INACTIVE_TIME) { | |||
for (int j = i; j < numIds - 1; j++) { | |||
idData[j] = idData[j + 1]; | |||
} | |||
numIds--; | |||
} | |||
} | |||
} | |||
void displayData() { | |||
display.clearDisplay(); | |||
if (numIds == 0) { | |||
display.setCursor(0, 10); | |||
display.println(F("Waiting...")); | |||
} else { | |||
int textSize = (numIds < 4) ? 3 : (numIds < 8 ? 2 : 1); | |||
int idsPerRow = (numIds < 4) ? 2 : (numIds < 8 ? 3 : 6); | |||
display.setTextSize(textSize); | |||
const int idBoxWidth = 15 * textSize; | |||
int rowHeight = 10 * textSize; | |||
for (int i = 0; i < numIds; i++) { | |||
int row = i / idsPerRow; | |||
int col = i % idsPerRow; | |||
int x = col * idBoxWidth; | |||
int y = row * rowHeight; | |||
if (i == selectedId) { | |||
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Inverted | |||
} else { | |||
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK); | |||
} | |||
display.setCursor(x, y); | |||
display.print(idData[i].id); | |||
} | |||
// Aikaleima (minuutit edellisestä näkemisestä) | |||
display.setTextSize(1); | |||
display.setTextColor(SSD1306_WHITE); | |||
int lastSeenMins = (millis() - idData[selectedId].time) / 60000; | |||
display.setCursor(0, SCREEN_HEIGHT - 8); | |||
display.print(F("Active: ")); | |||
display.print(lastSeenMins); | |||
display.print(F("m")); | |||
} | |||
// Vilkkuva piste | |||
indicatorOn = !indicatorOn; | |||
display.setCursor(SCREEN_WIDTH - 8, SCREEN_HEIGHT - 8); | |||
if (indicatorOn) display.print("."); else display.print(" "); | |||
display.display(); | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Latest revision as of 19:00, 9 June 2026
Versiohistoria
V2.0
- Muutettu täysin näytön näyttötapaa.
- Parannettu vastaanotetun tiedon varmistamista käyttäen CRC-16 funktiota.
- Tiedetyt ongelmat. Rekisteröi uuden vastaanotetun koodin vasta kun näyttö on piirtänyt KAIKKI ID:t.
V2.1
- Lisätty näytön tummennus, kun ei näytettäviä ID:tä.
- Poistettu ylimääräiset muuttujat
- Yhdistetty IDs ja ID last seen samaan muuttujataulukkoon vähentääksemme muistin käyttöä
- Muita muistinoptimointeja, kuten checksummin tallentaminen unit8_t muuttujaan unit16_t sijaan.
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RH_ASK.h>
#include <CRC16.h>
#define OLED_RESET -1
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
RH_ASK driver(1000, 12, 11, 10); // RX = D12
// ID storage structure
const int MAX_IDS = 16;
struct IdData {
uint8_t id;
unsigned long time;
};
IdData idData[MAX_IDS];
int numIds = 0;
// Screen indicator
const unsigned long BLINK_INTERVAL = 500;
bool indicatorOn = false;
unsigned long indicatorTime = 0;
// ID activity & deactivity
const unsigned long INACTIVE_TIME = 3600000; // time threshold for inactive IDs (1 hour)
// Screen rotation time
const unsigned long DISPLAY_DURATION = 2500; // 2.5 s
int selectedId = 0;
unsigned long lastSelectedTime = 0;
static uint8_t receivedChecksum[2];
void setup() {
// initialize the OLED screen
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(2);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(F("Initializing..."));
display.display();
if (!driver.init()) {
display.clearDisplay();
display.setCursor(0, 0);
display.println(F("Radio module error!"));
display.display();
while (1); //
}
}
void loop() {
handleRadioReceiver(); // receive packages
// update the selected ID every X seconds to show different ID's timestamp and draw the screen
if (millis() - lastSelectedTime >= DISPLAY_DURATION) {
selectedId = (selectedId + 1) % numIds;
lastSelectedTime = millis();
displayData();
}
void removeInactiveIds();
}
// Receive the radio message
void handleRadioReceiver() {
uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
uint8_t buflen = sizeof(buf);
static bool checksumReceived = false;
uint16_t checksumValue;
uint8_t data[4];
if (driver.recv(buf, &buflen)) { // Non-blocking
if (buflen == 2 && !checksumReceived) {
// Received checksum packet
memcpy(receivedChecksum, buf, sizeof(receivedChecksum));
checksumReceived = true;
} else if (buflen == 4 && checksumReceived) {
// Received data packet, with preceding valid checksum packet
memcpy(data, buf, sizeof(data));
CRC16 crc;
crc.add(data, sizeof(data)); // add the DIP switch values to the CRC calculation
checksumValue = crc.calc();
if (memcmp(&checksumValue, receivedChecksum, sizeof(receivedChecksum)) == 0) {
uint8_t id = processPacket(data, sizeof(data) / sizeof(data[0]));
// Check if ID value is valid
if (id >= 0 && id < MAX_IDS) {
bool found = false;
for (int i = 0; i < numIds; i++) {
if (idData[i].id == id) {
found = true;
idData[i].time = millis(); // Update the last time this ID was received
break;
}
}
if (!found && numIds < MAX_IDS) {
idData[numIds].id = id;
idData[numIds].time = millis();
numIds++;
}
}
checksumReceived = false;
} else {
checksumReceived = false;
}
} else {
// Invalid packet length or out-of-order transmission
checksumReceived = false;
}
}
}
uint8_t processPacket(uint8_t *data, uint8_t dataLength) {
uint8_t id = 0;
for (uint8_t i = 0; i < dataLength; i++) {
id |= data[i] << i; // convert DIP code to ID
}
return id;
}
void displayData() {
display.clearDisplay();
if (numIds == 0) {
display.setCursor(0, 10);
display.println("Waiting for");
display.print("message...");
setContrast(1);
} else {
// Dynamically adjust font size based on the number of IDs received
int textSize;
int idsPerRow = 4;
if (numIds < 4) {
textSize = 3;
} else if (numIds < 8) {
textSize = 2;
} else {
textSize = 1;
idsPerRow = 6;
}
setContrast(255);
display.setTextSize(textSize);
const int idBoxWidth = 15 * textSize;
int rowHeight = 8 * textSize;
// Display IDs in rows and columns
for (int i = 0; i < numIds; i++) {
int row = i / idsPerRow;
int col = i % idsPerRow;
int x = col * idBoxWidth;
int y = row * rowHeight;
if (i == selectedId) {
display.setTextColor(BLACK, WHITE); // inverted
} else {
display.setTextColor(WHITE, BLACK);
}
display.setCursor(x, y);
display.print(idData[i].id);
}
// Display last seen time for the selected ID
display.setTextSize(1);
display.setTextColor(WHITE);
int lastSeenMins = (millis() - idData[selectedId].time) / 60000;
display.setCursor(SCREEN_WIDTH - 24, SCREEN_HEIGHT - 8);
display.print(lastSeenMins);
display.print("m");
}
// Blinking indicator
indicatorOn = !indicatorOn;
indicatorTime = millis();
display.setCursor(0, SCREEN_HEIGHT - 8);
if (indicatorOn) {
display.print(".");
} else {
display.print(" ");
}
display.display();
}
void removeInactiveIds() {
if (numIds == 0) {
return;
}
for (int i = numIds - 1; i >= 0; i--) {
if (millis() - idData[i].time > INACTIVE_TIME) {
// Shift the remaining IDs and last seen times down by one position to overwrite the inactive ID
for (int j = i + 1; j < numIds; j++) {
idData[j - 1] = idData[j];
}
numIds--;
}
}
}
void setContrast(uint8_t newContrast) {
display.ssd1306_command(SSD1306_SETCONTRAST);
display.ssd1306_command(newContrast);
}
V2.2
Ei testattu. Yhdennetty CRC paketti ja datapaketti samaan läjään.
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RH_ASK.h>
#include <CRC16.h>
#define OLED_RESET -1
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// RX pin on 12 (tarkista kytkentä: Sender TX -> Receiver RX)
RH_ASK driver(1000, 12, 11, 10);
const int MAX_IDS = 16;
struct IdData {
uint8_t id;
unsigned long time;
};
IdData idData[MAX_IDS];
int numIds = 0;
const unsigned long DISPLAY_DURATION = 2500;
int selectedId = 0;
unsigned long lastSelectedTime = 0;
const unsigned long INACTIVE_TIME = 3600000; // 1 tunti
// Näytön vilkkuminen
const unsigned long BLINK_INTERVAL = 500;
bool indicatorOn = false;
unsigned long indicatorTime = 0;
void setup() {
Serial.begin(9600);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
for (;;);
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println(F("Initializing..."));
display.display();
if (!driver.init()) {
display.clearDisplay();
display.setCursor(0, 0);
display.println(F("Radio error!"));
display.display();
while (1);
}
}
void loop() {
handleRadioReceiver();
removeInactiveIds();
// Päivitä näyttö tietyn väliajoin
if (millis() - lastSelectedTime >= DISPLAY_DURATION) {
selectedId = (selectedId + 1) % (numIds > 0 ? numIds : 1);
lastSelectedTime = millis();
displayData();
}
}
void handleRadioReceiver() {
uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
uint8_t buflen = sizeof(buf);
if (driver.recv(buf, &buflen)) {
// Tarkistetaan, onko paketti oikean pituinen (6 tavua: 2 CRC + 4 Data)
if (buflen == 6) {
uint16_t receivedChecksum;
// Palautetaan CRC alkuperäiseen muotoon (endianness)
receivedChecksum = buf[0] | (buf[1] << 8);
uint8_t incomingData[4];
memcpy(incomingData, &buf[2], 4);
// Lasketaan uusi CRC datalle
CRC16 crc;
crc.add(incomingData, 4);
uint16_t calculatedChecksum = crc.calc();
if (calculatedChecksum == receivedChecksum) {
uint8_t id = processPacket(incomingData, 4);
updateIdList(id);
Serial.print("Valid ID received: ");
Serial.println(id);
} else {
Serial.println("CRC Mismatch!");
}
}
}
}
void updateIdList(uint8_t id) {
// Päivitetään olemassa oleva tai lisätään uusi
for (int i = 0; i < numIds; i++) {
if (idData[i].id == id) {
idData[i].time = millis();
return;
}
}
if (numIds < MAX_IDS) {
idData[numIds].id = id;
idData[numIds].time = millis();
numIds++;
}
}
uint8_t processPacket(uint8_t *data, uint8_t dataLength) {
uint8_t id = 0;
for (uint8_t i = 0; i < dataLength; i++) {
id |= data[i] << i;
}
return id;
}
void removeInactiveIds() {
for (int i = numIds - 1; i >= 0; i--) {
if (millis() - idData[i].time > INACTIVE_TIME) {
for (int j = i; j < numIds - 1; j++) {
idData[j] = idData[j + 1];
}
numIds--;
}
}
}
void displayData() {
display.clearDisplay();
if (numIds == 0) {
display.setCursor(0, 10);
display.println(F("Waiting..."));
} else {
int textSize = (numIds < 4) ? 3 : (numIds < 8 ? 2 : 1);
int idsPerRow = (numIds < 4) ? 2 : (numIds < 8 ? 3 : 6);
display.setTextSize(textSize);
const int idBoxWidth = 15 * textSize;
int rowHeight = 10 * textSize;
for (int i = 0; i < numIds; i++) {
int row = i / idsPerRow;
int col = i % idsPerRow;
int x = col * idBoxWidth;
int y = row * rowHeight;
if (i == selectedId) {
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Inverted
} else {
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
}
display.setCursor(x, y);
display.print(idData[i].id);
}
// Aikaleima (minuutit edellisestä näkemisestä)
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
int lastSeenMins = (millis() - idData[selectedId].time) / 60000;
display.setCursor(0, SCREEN_HEIGHT - 8);
display.print(F("Active: "));
display.print(lastSeenMins);
display.print(F("m"));
}
// Vilkkuva piste
indicatorOn = !indicatorOn;
display.setCursor(SCREEN_WIDTH - 8, SCREEN_HEIGHT - 8);
if (indicatorOn) display.print("."); else display.print(" ");
display.display();
}