old codes
This commit is contained in:
519
old/STM32-03/STM32-03.ino
Normal file
519
old/STM32-03/STM32-03.ino
Normal file
@@ -0,0 +1,519 @@
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include <Adafruit_SHT31.h>
|
||||
#include <BH1750.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// -------------------- پیکربندی حافظه SPI Flash --------------------
|
||||
#define FLASH_CS PA4
|
||||
#define FLASH_MOSI PA7
|
||||
#define FLASH_MISO PA6
|
||||
#define FLASH_SCK PA5
|
||||
|
||||
// کتابخانه جایگزین برای حافظه SPI
|
||||
#include <SerialFlash.h>
|
||||
|
||||
// -------------------- پیکربندی OLED --------------------
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 64
|
||||
#define OLED_RESET -1
|
||||
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
||||
|
||||
// -------------------- پیکربندی سنسورها --------------------
|
||||
#define SOIL_PIN PA1
|
||||
#define MQ7_PIN PA2
|
||||
#define SDA_PIN PB9
|
||||
#define SCL_PIN PB8
|
||||
|
||||
BH1750 lightMeter;
|
||||
Adafruit_SHT31 sht31 = Adafruit_SHT31();
|
||||
|
||||
// -------------------- پیکربندی EC200U --------------------
|
||||
#define PWRKEY_PIN PB5
|
||||
HardwareSerial EC200U(USART3);
|
||||
|
||||
// -------------------- پارامترهای قابل تنظیم --------------------
|
||||
#define SENSOR_READ_INTERVAL 60000 // خواندن سنسورها هر 1 دقیقه
|
||||
|
||||
// -------------------- ساختار تنظیمات --------------------
|
||||
struct DeviceConfig {
|
||||
char signature[4];
|
||||
char apn[32];
|
||||
char serverUrl[64];
|
||||
char deviceName[16];
|
||||
char smsNumber[16];
|
||||
unsigned long webInterval; // دقیقه
|
||||
unsigned long smsInterval; // دقیقه
|
||||
unsigned long saveInterval; // ثانیه - فاصله ذخیره در قطعی
|
||||
bool smsEnabled;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
// -------------------- ساختار داده سنسورها --------------------
|
||||
struct SensorData {
|
||||
float temperature;
|
||||
float humidity;
|
||||
int soilMoisture;
|
||||
float coPPM;
|
||||
float lightLux;
|
||||
unsigned long timestamp;
|
||||
};
|
||||
|
||||
// -------------------- متغیرهای سراسری --------------------
|
||||
DeviceConfig config;
|
||||
SensorData currentData;
|
||||
SensorData storedData;
|
||||
|
||||
unsigned long lastSensorRead = 0;
|
||||
unsigned long lastUpload = 0;
|
||||
unsigned long lastSMS = 0;
|
||||
unsigned long lastSave = 0;
|
||||
bool networkConnected = false;
|
||||
bool dataStored = false;
|
||||
int displayMode = 0;
|
||||
unsigned long lastDisplayChange = 0;
|
||||
|
||||
// -------------------- توابع حافظه SPI Flash --------------------
|
||||
void initFlash() {
|
||||
SPI.setMOSI(FLASH_MOSI);
|
||||
SPI.setMISO(FLASH_MISO);
|
||||
SPI.setSCLK(FLASH_SCK);
|
||||
SPI.begin();
|
||||
|
||||
pinMode(FLASH_CS, OUTPUT);
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
|
||||
delay(100);
|
||||
|
||||
// مقداردهی اولیه SerialFlash
|
||||
if (!SerialFlash.begin(FLASH_CS)) {
|
||||
Serial1.println("❌ Flash init failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial1.println("✅ Flash OK");
|
||||
|
||||
// نمایش اطلاعات حافظه
|
||||
SerialFlash::ID id;
|
||||
SerialFlash.readID(&id);
|
||||
Serial1.print("Flash ID: ");
|
||||
Serial1.print(id.id, HEX);
|
||||
Serial1.print(" Size: ");
|
||||
Serial1.print(SerialFlash.capacity(id) / 1024);
|
||||
Serial1.println("KB");
|
||||
}
|
||||
|
||||
void readConfig() {
|
||||
// ابتدا از EEPROM داخلی بخوان
|
||||
EEPROM.get(0, config);
|
||||
|
||||
// اگر تنظیمات معتبر نیست، از حافظه SPI بخوان
|
||||
if (strcmp(config.signature, "CFG") != 0) {
|
||||
if (SerialFlash.exists("config.bin")) {
|
||||
SerialFlashFile file = SerialFlash.open("config.bin");
|
||||
if (file) {
|
||||
file.read(&config, sizeof(DeviceConfig));
|
||||
file.close();
|
||||
Serial1.println("✅ Config read from SPI Flash");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// اگر هنوز تنظیمات معتبر نیست، مقادیر پیشفرض
|
||||
if (strcmp(config.signature, "CFG") != 0) {
|
||||
strcpy(config.signature, "CFG");
|
||||
strcpy(config.apn, "mcinet");
|
||||
strcpy(config.serverUrl, "https://ghback.nabaksoft.ir/api/Telemetry/AddData");
|
||||
strcpy(config.smsNumber, "+989120000000");
|
||||
strcpy(config.deviceName, "ST-");
|
||||
config.webInterval = 1;
|
||||
config.smsInterval = 5;
|
||||
config.saveInterval = 60; // پیشفرض 60 ثانیه
|
||||
config.smsEnabled = false;
|
||||
config.valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
void saveConfig() {
|
||||
config.valid = true;
|
||||
|
||||
// در EEPROM داخلی ذخیره کن
|
||||
EEPROM.put(0, config);
|
||||
EEPROM.commit();
|
||||
|
||||
// در حافظه SPI هم ذخیره کن
|
||||
if (SerialFlash.exists("config.bin")) {
|
||||
SerialFlash.remove("config.bin");
|
||||
}
|
||||
|
||||
SerialFlashFile file = SerialFlash.create("config.bin", sizeof(DeviceConfig));
|
||||
if (file) {
|
||||
file.write((byte*)&config, sizeof(DeviceConfig));
|
||||
file.close();
|
||||
Serial1.println("✅ Config saved to SPI Flash");
|
||||
}
|
||||
}
|
||||
|
||||
void saveDataToFlash() {
|
||||
if (!dataStored) {
|
||||
if (SerialFlash.exists("data.bin")) {
|
||||
SerialFlash.remove("data.bin");
|
||||
}
|
||||
dataStored = true;
|
||||
}
|
||||
|
||||
currentData.timestamp = millis();
|
||||
|
||||
SerialFlashFile file = SerialFlash.open("data.bin");
|
||||
if (!file) {
|
||||
file = SerialFlash.create("data.bin", sizeof(SensorData));
|
||||
}
|
||||
|
||||
if (file) {
|
||||
file.seek(0);
|
||||
file.write((byte*)¤tData, sizeof(SensorData));
|
||||
file.close();
|
||||
Serial1.println("💾 Data saved to flash");
|
||||
}
|
||||
}
|
||||
|
||||
void readDataFromFlash() {
|
||||
if (SerialFlash.exists("data.bin")) {
|
||||
SerialFlashFile file = SerialFlash.open("data.bin");
|
||||
if (file) {
|
||||
file.read(&storedData, sizeof(SensorData));
|
||||
file.close();
|
||||
|
||||
// بررسی اعتبار داده
|
||||
if (storedData.timestamp > 0) {
|
||||
Serial1.println("📖 Stored data found");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clearStoredData() {
|
||||
if (SerialFlash.exists("data.bin")) {
|
||||
SerialFlash.remove("data.bin");
|
||||
storedData.timestamp = 0;
|
||||
dataStored = false;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- توابع EC200U --------------------
|
||||
bool sendAT(String cmd, uint16_t wait = 2000) {
|
||||
Serial1.print(">> ");
|
||||
Serial1.println(cmd);
|
||||
EC200U.println(cmd);
|
||||
|
||||
String response = "";
|
||||
unsigned long start = millis();
|
||||
|
||||
while (millis() - start < wait) {
|
||||
while (EC200U.available()) {
|
||||
char c = EC200U.read();
|
||||
response += c;
|
||||
Serial1.write(c);
|
||||
}
|
||||
if (response.indexOf("OK") != -1) return true;
|
||||
if (response.indexOf("ERROR") != -1) return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool waitForResponse(String expected, unsigned long timeout = 10000) {
|
||||
unsigned long startTime = millis();
|
||||
String response = "";
|
||||
|
||||
while (millis() - startTime < timeout) {
|
||||
while (EC200U.available()) {
|
||||
char c = EC200U.read();
|
||||
response += c;
|
||||
Serial1.write(c);
|
||||
if (response.indexOf(expected) != -1) return true;
|
||||
if (response.indexOf("ERROR") != -1) return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sendSMS(String number, String message) {
|
||||
if (!sendAT("AT+CMGF=1", 2000)) return false;
|
||||
|
||||
String cmd = "AT+CMGS=\"" + number + "\"";
|
||||
if (!sendAT(cmd, 2000)) return false;
|
||||
|
||||
delay(100);
|
||||
EC200U.print(message);
|
||||
EC200U.write(26);
|
||||
return waitForResponse("+CMGS:", 10000);
|
||||
}
|
||||
|
||||
void initEC200U() {
|
||||
Serial1.println("🚀 Starting EC200U...");
|
||||
|
||||
digitalWrite(PWRKEY_PIN, HIGH);
|
||||
delay(2000);
|
||||
digitalWrite(PWRKEY_PIN, LOW);
|
||||
delay(5000);
|
||||
|
||||
if (!sendAT("AT", 3000)) {
|
||||
Serial1.println("❌ EC200U not responding!");
|
||||
return;
|
||||
}
|
||||
|
||||
String apnCmd = "AT+CGDCONT=1,\"IP\",\"" + String(config.apn) + "\"";
|
||||
sendAT(apnCmd, 2000);
|
||||
|
||||
if (sendAT("AT+QIACT=1", 15000)) {
|
||||
networkConnected = true;
|
||||
Serial1.println("✅ Network connected");
|
||||
|
||||
// اگر داده ذخیره شده وجود دارد، ارسال کن
|
||||
if (storedData.timestamp > 0) {
|
||||
Serial1.println("📤 Sending stored data...");
|
||||
sendStoredData();
|
||||
}
|
||||
} else {
|
||||
networkConnected = false;
|
||||
Serial1.println("❌ Network failed");
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- توابع سنسورها --------------------
|
||||
void readSensors() {
|
||||
currentData.temperature = sht31.readTemperature();
|
||||
currentData.humidity = sht31.readHumidity();
|
||||
currentData.soilMoisture = readSoil();
|
||||
currentData.coPPM = MQ7_ReadPPM();
|
||||
currentData.lightLux = lightMeter.readLightLevel();
|
||||
|
||||
if (isnan(currentData.temperature)) currentData.temperature = -999;
|
||||
if (isnan(currentData.humidity)) currentData.humidity = -999;
|
||||
if (isnan(currentData.lightLux)) currentData.lightLux = 0;
|
||||
|
||||
lastSensorRead = millis();
|
||||
}
|
||||
|
||||
int readSoil() {
|
||||
int adcValue = analogRead(SOIL_PIN);
|
||||
const int adcDry = 4095;
|
||||
const int adcWet = 1200;
|
||||
|
||||
float soilPercent = (float)(adcDry - adcValue) / (adcDry - adcWet) * 100.0;
|
||||
if (soilPercent > 100.0) soilPercent = 100.0;
|
||||
if (soilPercent < 0.0) soilPercent = 0.0;
|
||||
|
||||
return (int)soilPercent;
|
||||
}
|
||||
|
||||
float MQ7_ReadPPM() {
|
||||
long sum = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
sum += analogRead(MQ7_PIN);
|
||||
delay(5);
|
||||
}
|
||||
float adcValue = sum / 10.0;
|
||||
float voltage = (adcValue / 4095.0) * 3.3;
|
||||
|
||||
float ppm;
|
||||
if (voltage < 0.1) ppm = 0;
|
||||
else if (voltage < 0.2) ppm = 10 * (voltage / 0.2);
|
||||
else if (voltage < 0.5) ppm = 50 + (voltage - 0.2) * 300;
|
||||
else if (voltage < 1.0) ppm = 140 + (voltage - 0.5) * 800;
|
||||
else if (voltage < 2.0) ppm = 500 + (voltage - 1.0) * 1500;
|
||||
else ppm = 2000 + (voltage - 2.0) * 2000;
|
||||
|
||||
if (ppm < 0) ppm = 0;
|
||||
if (ppm > 10000) ppm = 10000;
|
||||
|
||||
return ppm;
|
||||
}
|
||||
|
||||
// -------------------- توابع ارسال داده --------------------
|
||||
bool sendData(SensorData data) {
|
||||
if (data.temperature == -999 || data.humidity == -999) return false;
|
||||
|
||||
String dataStr = "temperatureC=" + String(data.temperature, 1) +
|
||||
"&humidityPercent=" + String(data.humidity, 1) +
|
||||
"&soilPercent=" + String(data.soilMoisture) +
|
||||
"&gasPPM=" + String(data.coPPM, 0) +
|
||||
"&lux=" + String(data.lightLux, 1);
|
||||
|
||||
String url = String(config.serverUrl) + "?deviceName=" + String(config.deviceName) + "&" + dataStr;
|
||||
|
||||
String httpCmd = "AT+QHTTPURL=" + String(url.length()) + ",80";
|
||||
if (!sendAT(httpCmd, 5000)) return false;
|
||||
|
||||
delay(100);
|
||||
EC200U.print(url);
|
||||
|
||||
if (!waitForResponse("OK", 5000)) return false;
|
||||
|
||||
return sendAT("AT+QHTTPGET=60", 15000);
|
||||
}
|
||||
|
||||
void sendStoredData() {
|
||||
if (sendData(storedData)) {
|
||||
Serial1.println("✅ Stored data sent successfully");
|
||||
clearStoredData();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- توابع نمایش OLED --------------------
|
||||
void updateDisplay() {
|
||||
if (millis() - lastDisplayChange > 5000) {
|
||||
displayMode = (displayMode + 1) % 3;
|
||||
lastDisplayChange = millis();
|
||||
}
|
||||
|
||||
display.clearDisplay();
|
||||
display.setTextSize(1);
|
||||
|
||||
switch(displayMode) {
|
||||
case 0:
|
||||
display.setTextSize(2);
|
||||
display.setCursor(20, 10);
|
||||
display.println("DEVICE");
|
||||
display.setCursor(30, 35);
|
||||
display.println(config.deviceName);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
display.setCursor(0, 0);
|
||||
display.print("T:");
|
||||
display.print(currentData.temperature, 1);
|
||||
display.print("C ");
|
||||
display.print("H:");
|
||||
display.print(currentData.humidity, 1);
|
||||
display.println("%");
|
||||
|
||||
display.setCursor(0, 16);
|
||||
display.print("S:");
|
||||
display.print(currentData.soilMoisture);
|
||||
display.print("% ");
|
||||
display.print("C:");
|
||||
display.print(currentData.coPPM, 0);
|
||||
display.println("P");
|
||||
|
||||
display.setCursor(0, 32);
|
||||
display.print("L:");
|
||||
display.print(currentData.lightLux, 0);
|
||||
display.println("Lx");
|
||||
|
||||
display.setCursor(0, 48);
|
||||
display.print(networkConnected ? "ONLINE" : "OFFLINE");
|
||||
if (dataStored) display.print(" *");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
display.setTextSize(3);
|
||||
display.setCursor(10, 25);
|
||||
display.print(currentData.temperature, 1);
|
||||
display.setTextSize(2);
|
||||
display.setCursor(100, 30);
|
||||
display.print("C");
|
||||
break;
|
||||
}
|
||||
display.display();
|
||||
}
|
||||
|
||||
// -------------------- setup --------------------
|
||||
void setup() {
|
||||
Serial1.begin(115200);
|
||||
delay(1000);
|
||||
|
||||
Serial1.println("\n\n🚀 System Starting...");
|
||||
|
||||
pinMode(PWRKEY_PIN, OUTPUT);
|
||||
pinMode(SOIL_PIN, INPUT);
|
||||
pinMode(MQ7_PIN, INPUT);
|
||||
digitalWrite(PWRKEY_PIN, LOW);
|
||||
|
||||
Wire.setSDA(SDA_PIN);
|
||||
Wire.setSCL(SCL_PIN);
|
||||
Wire.begin();
|
||||
|
||||
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
|
||||
Serial1.println("❌ OLED failed!");
|
||||
}
|
||||
|
||||
sht31.begin(0x44);
|
||||
lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE);
|
||||
|
||||
// مقداردهی حافظه
|
||||
initFlash();
|
||||
readConfig();
|
||||
readDataFromFlash();
|
||||
|
||||
// اگر نام دستگاه تنظیم نشده، از UID استفاده کن
|
||||
if (strlen(config.deviceName) < 3) {
|
||||
uint32_t uid0 = *(uint32_t*)0x1FFFF7E8;
|
||||
uint32_t uid1 = *(uint32_t*)0x1FFFF7EC;
|
||||
uint32_t uid2 = *(uint32_t*)0x1FFFF7F0;
|
||||
|
||||
sprintf(config.deviceName, "ST-%08X", (unsigned int)(uid0 ^ uid1 ^ uid2));
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
EC200U.begin(115200);
|
||||
if (config.valid) {
|
||||
initEC200U();
|
||||
}
|
||||
|
||||
Serial1.println("✅ System Ready");
|
||||
}
|
||||
|
||||
// -------------------- loop --------------------
|
||||
void loop() {
|
||||
// خواندن سنسورها در بازه زمانی مشخص
|
||||
if (millis() - lastSensorRead > SENSOR_READ_INTERVAL) {
|
||||
readSensors();
|
||||
Serial1.println("📊 Sensors read");
|
||||
|
||||
// اگر شبکه وصل است، داده را ارسال کن
|
||||
if (networkConnected) {
|
||||
if (millis() - lastUpload > config.webInterval * 60000) {
|
||||
if (sendData(currentData)) {
|
||||
Serial1.println("✅ Web data sent");
|
||||
lastUpload = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
// اگر شبکه قطع است، داده را ذخیره کن
|
||||
else {
|
||||
if (config.saveInterval > 0) {
|
||||
if (millis() - lastSave > config.saveInterval * 1000) {
|
||||
saveDataToFlash();
|
||||
lastSave = millis();
|
||||
}
|
||||
}
|
||||
|
||||
// ارسال SMS در صورت فعال بودن
|
||||
if (config.smsEnabled && millis() - lastSMS > config.smsInterval * 60000) {
|
||||
String smsMsg = String(config.deviceName) +
|
||||
" T:" + String(currentData.temperature, 1) +
|
||||
" H:" + String(currentData.humidity, 1) +
|
||||
" S:" + String(currentData.soilMoisture) + "%";
|
||||
|
||||
if (sendSMS(config.smsNumber, smsMsg)) {
|
||||
Serial1.println("✅ SMS sent");
|
||||
lastSMS = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateDisplay();
|
||||
|
||||
// تلاش برای اتصال مجدد شبکه
|
||||
static unsigned long lastReconnect = 0;
|
||||
if (!networkConnected && millis() - lastReconnect > 60000) {
|
||||
initEC200U();
|
||||
lastReconnect = millis();
|
||||
}
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
Reference in New Issue
Block a user