Nahrát soubory do „pwm-modul“
This commit is contained in:
536
pwm-modul/modbus-pwm-2.2.ino
Normal file
536
pwm-modul/modbus-pwm-2.2.ino
Normal file
@@ -0,0 +1,536 @@
|
||||
/*************************************************************
|
||||
* ARDUINO NANO – MODBUS SLAVE 6× PWM + LED + EEPROM + CRC
|
||||
* -----------------------------------------------------------
|
||||
* Verze FW: 2.2
|
||||
*
|
||||
* TODO:
|
||||
* - případné rozšíření registrů a chybových kódů
|
||||
*
|
||||
* Funkce:
|
||||
* - 6× slow PWM pro termo hlavice (SSR)
|
||||
* - LED D13 řízená přes Modbus (LED_SWITCH)
|
||||
* - Alive LED (pin 10)
|
||||
* - EEPROM uložení konfigurace (perioda, duty, typy, skupiny)
|
||||
* - CRC kontrola konfigurace
|
||||
* - Versioning konfigurace (CONFIG_VERSION)
|
||||
* - Last-Modbus-Age registr (čas od poslední OK Modbus komunikace)
|
||||
* - Test mode (sekvenční blikání 6 PWM)
|
||||
* - Skupiny PWM:
|
||||
* - Každý PWM kanál má svoji skupinu (0–4), nastavovanou z ESPHome
|
||||
* - Každá skupina má svůj "virtuální" PWM duty registr
|
||||
* - Zápis do GROUPx_PWM se propíše do všech PWM, které mají danou skupinu
|
||||
*
|
||||
* -----------------------------------------------------------
|
||||
* MODBUS – MAPA REGISTRŮ (Holding Registers)
|
||||
* -----------------------------------------------------------
|
||||
* Index Adresa Název R/W Popis
|
||||
* ----- ------ ---------------- --- ---------------------------------------
|
||||
* 0 0 PWM_PERIOD R/W Společná perioda PWM (v sekundách), min. 1 s
|
||||
* 1 1 TEST_MODE R/W 0 = normální režim, !=0 = test sekvence PWM
|
||||
* 2 2 STATUS_FLAGS R Stavové bity:
|
||||
* bit0 = config načten (platná konfigurace v RAM)
|
||||
* bit1 = CRC OK (1) / CRC chyba (0)
|
||||
* bit2 = verze configu nesouhlasila (použity defaulty)
|
||||
* 3 3 LAST_ERROR R Rezervováno (zatím 0)
|
||||
* 4 4 LAST_MODBUS_AGE R Čas od poslední korektní Modbus komunikace (ms / 65k wrap)
|
||||
* 5 5 TEMPERATURE1 R Teplotní čidlo DS18B20 1
|
||||
* 6 6 TEMPERATURE2 R Teplotní čidlo DS18B20 2
|
||||
* 7 7 TEMPERATURE3 R Teplotní čidlo DS18B20 3
|
||||
* 8 8 TEMPERATURE4 R Teplotní čidlo DS18B20 4
|
||||
* 9 9 LED_SWITCH R/W 0 = LED D13 vyp, !=0 = LED D13 zap
|
||||
* 10 10 REZERVA1 R Rezerva 1
|
||||
*
|
||||
* -- "virtuální" skupinové PWM (NEUKLÁDAJÍ se do EEPROM) --
|
||||
*
|
||||
* 11 11 GROUP1_PWM R/W Duty (%) pro skupinu 1:
|
||||
* zápis se propíše do všech PWM,
|
||||
* které mají PWMx_GROUP == 1
|
||||
* 12 12 GROUP2_PWM R/W Stejně jako GROUP1_PWM, pro skupinu 2
|
||||
* 13 13 GROUP3_PWM R/W Stejně jako GROUP1_PWM, pro skupinu 3
|
||||
* 14 14 GROUP4_PWM R/W Stejně jako GROUP1_PWM, pro skupinu 4
|
||||
* 15 15 REZERVA2 R Rezerva2
|
||||
*
|
||||
* -- Per-kanál konfigurace PWM (duty, typ, skupina) --
|
||||
*
|
||||
* 16 16 PWM1_DUTY R/W PWM1 - výkon v % (0–100)
|
||||
* 17 17 PWM1_TYPE R/W Typ výstupu PWM1: 0 = NC (normálně vyp.), 1 = NO (invert)
|
||||
* 18 18 PWM1_GROUP R/W Skupina PWM1: 0 = žádná, 1–4 = GROUPx_PWM
|
||||
* 19 19 PWM2_DUTY R/W
|
||||
* 20 20 PWM2_TYPE R/W
|
||||
* 21 21 PWM2_GROUP R/W
|
||||
* 22 22 PWM3_DUTY R/W
|
||||
* 23 23 PWM3_TYPE R/W
|
||||
* 24 24 PWM3_GROUP R/W
|
||||
* 25 25 PWM4_DUTY R/W
|
||||
* 26 26 PWM4_TYPE R/W
|
||||
* 27 27 PWM4_GROUP R/W
|
||||
* 28 28 PWM5_DUTY R/W
|
||||
* 29 29 PWM5_TYPE R/W
|
||||
* 30 30 PWM5_GROUP R/W
|
||||
* 31 31 PWM6_DUTY R/W
|
||||
* 32 32 PWM6_TYPE R/W
|
||||
* 33 33 PWM6_GROUP R/W
|
||||
*
|
||||
* Celkový počet registrů: TOTAL_REGS_SIZE (34)
|
||||
*
|
||||
* EEPROM:
|
||||
* - Ukládají se registry:
|
||||
* PWM_PERIOD (0)
|
||||
* PWM1–PWM6_DUTY (16–31, po 3 skoky)
|
||||
* PWM1–PWM6_TYPE
|
||||
* PWM1–PWM6_GROUP
|
||||
* - Neukládají se:
|
||||
* GROUPx_PWM, TEST_MODE, LED_SWITCH, teploty, status, atd.
|
||||
*
|
||||
* EEPROM layout (uint16_t):
|
||||
* adresa 0–1 : CONFIG_VERSION
|
||||
* adresa 2–3 : CRC konfiguračních registrů
|
||||
* adresa 4–... : hodnoty registrů z pole CONFIG_REGS[] (každý 2 bajty)
|
||||
*************************************************************/
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
#include <EEPROM.h>
|
||||
#include <SimpleModbusSlaveSoftwareSerial.h>
|
||||
#include <GyverDS18.h>
|
||||
|
||||
// ================= PINY ======================
|
||||
#define PIN_RX 3
|
||||
#define PIN_TX 2
|
||||
#define LED_PIN 13
|
||||
#define ALIVE_PIN 10
|
||||
#define PWM1_PIN 4
|
||||
#define PWM2_PIN 5
|
||||
#define PWM3_PIN 6
|
||||
#define PWM4_PIN 7
|
||||
#define PWM5_PIN 8
|
||||
#define PWM6_PIN 9
|
||||
|
||||
#define DALLAS1 A2
|
||||
#define DALLAS2 A3
|
||||
#define DALLAS3 A4
|
||||
#define DALLAS4 A5
|
||||
|
||||
// =============== MODBUS ======================
|
||||
#define DEVICE_ID 3
|
||||
#define BAUD_RATE 9600
|
||||
#define RS485_EN -1 // -1 = nepoužíváme DE/RE řízení (přímo RX/TX RS485 převodníku)
|
||||
|
||||
// =============== DS18B20 ======================
|
||||
#define DALLAS_RESOLUTION 9
|
||||
#define DALLAS_PERIOD 5000
|
||||
|
||||
GyverDS18Single ds1(DALLAS1);
|
||||
GyverDS18Single ds2(DALLAS2);
|
||||
GyverDS18Single ds3(DALLAS3);
|
||||
GyverDS18Single ds4(DALLAS4);
|
||||
|
||||
// =============== EEPROM CONFIG ===============
|
||||
// Pozn.: změna CONFIG_VERSION zajistí ignorování staré EEPROM
|
||||
#define CONFIG_VERSION 1 // verze layoutu konfigurace v EEPROM
|
||||
#define EEPROM_WRITE_DELAY 200 // ms – po změně configu počkáme a pak uložíme celý blok
|
||||
|
||||
// Příznak, že se nějaký konfigurační registr změnil (pro odložený zápis)
|
||||
bool configDirty = false;
|
||||
unsigned long lastConfigChange = 0;
|
||||
|
||||
// =============== REGISTR MAPA ===============
|
||||
#define TOTAL_REGISTERS 34
|
||||
|
||||
enum {
|
||||
PWM_PERIOD = 0, // 0
|
||||
TEST_MODE, // 1
|
||||
STATUS_FLAGS, // 2
|
||||
LAST_ERROR, // 3
|
||||
LAST_MODBUS_AGE, // 4
|
||||
TEMPERATURE1, // 5
|
||||
TEMPERATURE2, // 6
|
||||
TEMPERATURE3, // 7
|
||||
TEMPERATURE4, // 8
|
||||
LED_SWITCH, // 9
|
||||
REZERVA1, // 10
|
||||
GROUP1_PWM, // 11
|
||||
GROUP2_PWM, // 12
|
||||
GROUP3_PWM, // 13
|
||||
GROUP4_PWM, // 14
|
||||
REZERVA2, // 15
|
||||
|
||||
// PWM 1
|
||||
PWM1_DUTY, // 16
|
||||
PWM1_TYPE, // 17
|
||||
PWM1_GROUP, // 18
|
||||
|
||||
// PWM 2
|
||||
PWM2_DUTY, // 19
|
||||
PWM2_TYPE, // 20
|
||||
PWM2_GROUP, // 21
|
||||
|
||||
// PWM 3
|
||||
PWM3_DUTY, // 22
|
||||
PWM3_TYPE, // 23
|
||||
PWM3_GROUP, // 24
|
||||
|
||||
// PWM 4
|
||||
PWM4_DUTY, // 25
|
||||
PWM4_TYPE, // 26
|
||||
PWM4_GROUP, // 27
|
||||
|
||||
// PWM 5
|
||||
PWM5_DUTY, // 28
|
||||
PWM5_TYPE, // 29
|
||||
PWM5_GROUP, // 30
|
||||
|
||||
// PWM 6
|
||||
PWM6_DUTY, // 31
|
||||
PWM6_TYPE, // 32
|
||||
PWM6_GROUP, // 33
|
||||
|
||||
TOTAL_REGS_SIZE // 34
|
||||
};
|
||||
|
||||
unsigned int holdingRegs[TOTAL_REGS_SIZE];
|
||||
|
||||
// Seznam registrů, které patří do konfigurace (EEPROM)
|
||||
const uint8_t CONFIG_REGS[] = {
|
||||
// PWM duty
|
||||
PWM1_DUTY,
|
||||
PWM2_DUTY,
|
||||
PWM3_DUTY,
|
||||
PWM4_DUTY,
|
||||
PWM5_DUTY,
|
||||
PWM6_DUTY,
|
||||
// společná perioda
|
||||
PWM_PERIOD,
|
||||
// typy
|
||||
PWM1_TYPE,
|
||||
PWM2_TYPE,
|
||||
PWM3_TYPE,
|
||||
PWM4_TYPE,
|
||||
PWM5_TYPE,
|
||||
PWM6_TYPE,
|
||||
// skupiny
|
||||
PWM1_GROUP,
|
||||
PWM2_GROUP,
|
||||
PWM3_GROUP,
|
||||
PWM4_GROUP,
|
||||
PWM5_GROUP,
|
||||
PWM6_GROUP
|
||||
};
|
||||
const uint8_t CONFIG_REGS_COUNT = sizeof(CONFIG_REGS) / sizeof(CONFIG_REGS[0]);
|
||||
|
||||
// =============== MODBUS SERIAL ===============
|
||||
SoftwareSerial modbusSerial(PIN_RX, PIN_TX);
|
||||
unsigned long cycleStart = 0;
|
||||
unsigned long lastModbusTime = 0;
|
||||
|
||||
// =============== EEPROM MAPA ==================
|
||||
int eeAddrVersion = 0; // uint16_t verze configu
|
||||
int eeAddrCRC = 2; // uint16_t CRC
|
||||
int eeAddrRegs = 4; // začátek oblasti s registry (2 bajty na každý reg z CONFIG_REGS[])
|
||||
|
||||
// =============== CRC16 PRO KONFIG =============
|
||||
// Standardní Modbus CRC16 (polynom 0xA001)
|
||||
uint16_t crc16_update(uint16_t crc, uint8_t a) {
|
||||
crc ^= a;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
if (crc & 1)
|
||||
crc = (crc >> 1) ^ 0xA001;
|
||||
else
|
||||
crc = (crc >> 1);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
// Výpočet CRC přes všechny konfigurační registry z CONFIG_REGS[]
|
||||
uint16_t calcConfigCRC() {
|
||||
uint16_t crc = 0xFFFF;
|
||||
for (uint8_t i = 0; i < CONFIG_REGS_COUNT; i++) {
|
||||
uint16_t v = holdingRegs[CONFIG_REGS[i]];
|
||||
crc = crc16_update(crc, v & 0xFF);
|
||||
crc = crc16_update(crc, (v >> 8) & 0xFF);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
// Uložení konfigurace do EEPROM (jen pokud se změní / voláno z kódu)
|
||||
void saveConfigToEEPROM() {
|
||||
uint16_t version = CONFIG_VERSION;
|
||||
EEPROM.put(eeAddrVersion, version);
|
||||
|
||||
// uložit všechny config registry postupně za sebou
|
||||
for (uint8_t i = 0; i < CONFIG_REGS_COUNT; i++) {
|
||||
uint16_t v = holdingRegs[CONFIG_REGS[i]];
|
||||
EEPROM.put(eeAddrRegs + i * 2, v);
|
||||
}
|
||||
|
||||
uint16_t crc = calcConfigCRC();
|
||||
EEPROM.put(eeAddrCRC, crc);
|
||||
|
||||
// nastavit příznaky – konfigurace je platná a CRC sedí
|
||||
holdingRegs[STATUS_FLAGS] |= (1 << 0); // bit0 = config načten/platný
|
||||
holdingRegs[STATUS_FLAGS] |= (1 << 1); // bit1 = CRC OK
|
||||
// bit2 (verze nesouhlasila) případně ponecháme beze změny jako "historii"
|
||||
}
|
||||
|
||||
// Načtení konfigurace z EEPROM
|
||||
// Vrací true = konfigurace z EEPROM byla úspěšně načtena a CRC sedí
|
||||
// Vrací false = verze nesedí NEBO CRC nesedí -> v setup() se použijí defaulty a přepíšou EEPROM
|
||||
bool loadConfigFromEEPROM() {
|
||||
uint16_t storedVersion;
|
||||
uint16_t storedCRC;
|
||||
|
||||
EEPROM.get(eeAddrVersion, storedVersion);
|
||||
EEPROM.get(eeAddrCRC, storedCRC);
|
||||
|
||||
// Kontrola verze layoutu
|
||||
if (storedVersion != CONFIG_VERSION) {
|
||||
// Verze nesouhlasí – uložená data ignorujeme, v setupu se použijí defaulty
|
||||
holdingRegs[STATUS_FLAGS] |= (1 << 2); // bit2 = verze configu nesouhlasila
|
||||
return false;
|
||||
}
|
||||
|
||||
// Načíst registry z EEPROM do RAM
|
||||
for (uint8_t i = 0; i < CONFIG_REGS_COUNT; i++) {
|
||||
uint16_t v;
|
||||
EEPROM.get(eeAddrRegs + i * 2, v);
|
||||
holdingRegs[CONFIG_REGS[i]] = v;
|
||||
}
|
||||
|
||||
// Kontrola CRC
|
||||
uint16_t calc = calcConfigCRC();
|
||||
if (calc != storedCRC) {
|
||||
// CRC chyba – konfiguraci považujeme za neplatnou
|
||||
holdingRegs[STATUS_FLAGS] &= ~(1 << 1); // bit1 = 0 (CRC error)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Úspěšně načteno
|
||||
holdingRegs[STATUS_FLAGS] |= (1 << 0); // bit0 = config načten
|
||||
holdingRegs[STATUS_FLAGS] |= (1 << 1); // bit1 = CRC OK
|
||||
holdingRegs[STATUS_FLAGS] &= ~(1 << 2); // bit2 = verze v pořádku
|
||||
return true;
|
||||
}
|
||||
|
||||
// =============== DEFAULTY =====================
|
||||
void loadDefaults() {
|
||||
// Perioda v sekundách
|
||||
holdingRegs[PWM_PERIOD] = 30; // 30 s
|
||||
|
||||
// Typy výstupů: výchozí NC (0)
|
||||
holdingRegs[PWM1_TYPE] = 0;
|
||||
holdingRegs[PWM2_TYPE] = 0;
|
||||
holdingRegs[PWM3_TYPE] = 0;
|
||||
holdingRegs[PWM4_TYPE] = 0;
|
||||
holdingRegs[PWM5_TYPE] = 0;
|
||||
holdingRegs[PWM6_TYPE] = 0;
|
||||
|
||||
// Výchozí PWM duty = 0 %
|
||||
holdingRegs[PWM1_DUTY] = 0;
|
||||
holdingRegs[PWM2_DUTY] = 0;
|
||||
holdingRegs[PWM3_DUTY] = 0;
|
||||
holdingRegs[PWM4_DUTY] = 0;
|
||||
holdingRegs[PWM5_DUTY] = 0;
|
||||
holdingRegs[PWM6_DUTY] = 0;
|
||||
|
||||
// Skupiny: výchozí = 0 (žádná skupina)
|
||||
holdingRegs[PWM1_GROUP] = 0;
|
||||
holdingRegs[PWM2_GROUP] = 0;
|
||||
holdingRegs[PWM3_GROUP] = 0;
|
||||
holdingRegs[PWM4_GROUP] = 0;
|
||||
holdingRegs[PWM5_GROUP] = 0;
|
||||
holdingRegs[PWM6_GROUP] = 0;
|
||||
|
||||
// Test mode, LED, group PWM, status atd.
|
||||
holdingRegs[TEST_MODE] = 0;
|
||||
holdingRegs[LED_SWITCH] = 0;
|
||||
|
||||
holdingRegs[STATUS_FLAGS] = 0;
|
||||
holdingRegs[LAST_ERROR] = 0;
|
||||
holdingRegs[LAST_MODBUS_AGE] = 0;
|
||||
|
||||
holdingRegs[GROUP1_PWM] = 0;
|
||||
holdingRegs[GROUP2_PWM] = 0;
|
||||
holdingRegs[GROUP3_PWM] = 0;
|
||||
holdingRegs[GROUP4_PWM] = 0;
|
||||
}
|
||||
|
||||
// =============== SLOW PWM ======================
|
||||
void slowPwm(int pin, int duty, int typeNO, unsigned long periodMs, unsigned long offset) {
|
||||
bool on;
|
||||
|
||||
if (duty <= 0) {
|
||||
on = false;
|
||||
} else if (duty >= 100) {
|
||||
on = true;
|
||||
} else {
|
||||
on = offset < (periodMs * (unsigned long)duty) / 100UL;
|
||||
}
|
||||
|
||||
// typeNO = 1 → NO (invertované chování)
|
||||
if (typeNO) on = !on;
|
||||
|
||||
digitalWrite(pin, on);
|
||||
}
|
||||
|
||||
// =============== TEST MODE ======================
|
||||
// Sekvenční test 6 PWM výstupů – každý má 1/6 periody ON
|
||||
void testModeRun(unsigned long offset, unsigned long periodMs) {
|
||||
const uint8_t pwmCount = 6;
|
||||
unsigned long segment = periodMs / pwmCount;
|
||||
|
||||
uint8_t active = offset / segment;
|
||||
if (active >= pwmCount) active = pwmCount - 1;
|
||||
|
||||
digitalWrite(PWM1_PIN, active == 0);
|
||||
digitalWrite(PWM2_PIN, active == 1);
|
||||
digitalWrite(PWM3_PIN, active == 2);
|
||||
digitalWrite(PWM4_PIN, active == 3);
|
||||
digitalWrite(PWM5_PIN, active == 4);
|
||||
digitalWrite(PWM6_PIN, active == 5);
|
||||
}
|
||||
|
||||
// =============== SETUP =========================
|
||||
void setup() {
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
pinMode(ALIVE_PIN, OUTPUT);
|
||||
|
||||
pinMode(PWM1_PIN, OUTPUT);
|
||||
pinMode(PWM2_PIN, OUTPUT);
|
||||
pinMode(PWM3_PIN, OUTPUT);
|
||||
pinMode(PWM4_PIN, OUTPUT);
|
||||
pinMode(PWM5_PIN, OUTPUT);
|
||||
pinMode(PWM6_PIN, OUTPUT);
|
||||
|
||||
// Nejprve nastavíme defaulty do RAM
|
||||
loadDefaults();
|
||||
|
||||
// Pokus o načtení konfigurace z EEPROM
|
||||
bool ok = loadConfigFromEEPROM();
|
||||
|
||||
if (!ok) {
|
||||
// Pokud verze neseděla (bit2 = 1), máme už v RAM defaulty a jen je uložíme.
|
||||
// Pokud verze seděla, ale CRC nesedělo, znovu nahrajeme defaulty.
|
||||
if (!(holdingRegs[STATUS_FLAGS] & (1 << 2))) {
|
||||
// žádná verze-mismatch vlajka -> CRC chyba nebo prázdná EEPROM
|
||||
loadDefaults();
|
||||
}
|
||||
// V obou případech teď v RAM jsou defaulty -> zapíšeme je do EEPROM
|
||||
saveConfigToEEPROM();
|
||||
}
|
||||
|
||||
ds1.setResolution(DALLAS_RESOLUTION);
|
||||
ds2.setResolution(DALLAS_RESOLUTION);
|
||||
ds3.setResolution(DALLAS_RESOLUTION);
|
||||
ds4.setResolution(DALLAS_RESOLUTION);
|
||||
|
||||
ds1.setPeriod(DALLAS_PERIOD);
|
||||
ds2.setPeriod(DALLAS_PERIOD);
|
||||
ds3.setPeriod(DALLAS_PERIOD);
|
||||
ds4.setPeriod(DALLAS_PERIOD);
|
||||
|
||||
modbusSerial.begin(BAUD_RATE);
|
||||
modbus_configure(&modbusSerial, BAUD_RATE, DEVICE_ID, RS485_EN, TOTAL_REGS_SIZE);
|
||||
}
|
||||
|
||||
// =============== LOOP ==========================
|
||||
void loop() {
|
||||
// Čtení teplot (GyverDS18Single – tick() spouští měření, po doběhu vrací false)
|
||||
if (!ds1.tick()) {
|
||||
holdingRegs[TEMPERATURE1] = ds1.getTemp() * 100;
|
||||
}
|
||||
if (!ds2.tick()) {
|
||||
holdingRegs[TEMPERATURE2] = ds2.getTemp() * 100;
|
||||
}
|
||||
if (!ds3.tick()) {
|
||||
holdingRegs[TEMPERATURE3] = ds3.getTemp() * 100;
|
||||
}
|
||||
if (!ds4.tick()) {
|
||||
holdingRegs[TEMPERATURE4] = ds4.getTemp() * 100;
|
||||
}
|
||||
|
||||
unsigned long now = millis();
|
||||
holdingRegs[LAST_MODBUS_AGE] = (uint16_t)(now - lastModbusTime);
|
||||
|
||||
// Alive LED – cca 1 Hz
|
||||
digitalWrite(ALIVE_PIN, (now / 500) % 2);
|
||||
|
||||
// Kopie registrů před Modbusem – pro zjištění změn
|
||||
uint16_t before[TOTAL_REGS_SIZE];
|
||||
memcpy(before, holdingRegs, sizeof(holdingRegs));
|
||||
|
||||
int errors = modbus_update(holdingRegs);
|
||||
if (errors == 0) {
|
||||
lastModbusTime = now;
|
||||
}
|
||||
|
||||
// ==========================================================
|
||||
// SKUPINOVÉ PWM – obsluha GROUP1..4
|
||||
// Pokud se změní GROUPx_PWM, přepíše se PWMx_DUTY
|
||||
// všech kanálů se stejnou hodnotou PWMx_GROUP
|
||||
// ==========================================================
|
||||
for (uint8_t group = 1; group <= 4; group++) {
|
||||
uint8_t groupReg = GROUP1_PWM + (group - 1);
|
||||
|
||||
// Skupinový registr se změnil?
|
||||
if (holdingRegs[groupReg] != before[groupReg]) {
|
||||
uint16_t duty = holdingRegs[groupReg];
|
||||
if (duty > 100) duty = 100;
|
||||
holdingRegs[groupReg] = duty; // ořez na 0–100 %
|
||||
|
||||
// Projdi všech 6 PWM kanálů
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
uint8_t chGroupReg = PWM1_GROUP + i * 3;
|
||||
uint8_t chDutyReg = PWM1_DUTY + i * 3;
|
||||
|
||||
// Kanál patří do této skupiny?
|
||||
if (holdingRegs[chGroupReg] == group) {
|
||||
holdingRegs[chDutyReg] = duty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// DETEKCE ZMĚNY KONFIGURAČNÍCH REGISTRŮ PRO EEPROM
|
||||
// (porovnání aktuálních hodnot s "before" po obsluze skupin)
|
||||
// ----------------------------------------------------------
|
||||
for (uint8_t i = 0; i < CONFIG_REGS_COUNT; i++) {
|
||||
uint8_t r = CONFIG_REGS[i];
|
||||
if (holdingRegs[r] != before[r]) {
|
||||
configDirty = true;
|
||||
lastConfigChange = now;
|
||||
}
|
||||
}
|
||||
|
||||
// Odložený zápis konfigurace do EEPROM
|
||||
if (configDirty && (now - lastConfigChange > EEPROM_WRITE_DELAY)) {
|
||||
saveConfigToEEPROM();
|
||||
configDirty = false;
|
||||
}
|
||||
|
||||
// LED D13 řízená přes Modbus
|
||||
digitalWrite(LED_PIN, holdingRegs[LED_SWITCH] ? HIGH : LOW);
|
||||
|
||||
// Perioda v ms – registr je v sekundách
|
||||
unsigned long periodMs = (unsigned long)holdingRegs[PWM_PERIOD] * 1000UL;
|
||||
if (periodMs < 1000UL) periodMs = 1000UL; // aspoň 1 s
|
||||
|
||||
unsigned long offset = now - cycleStart;
|
||||
if (offset >= periodMs) {
|
||||
cycleStart = now;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
// Test mode
|
||||
if (holdingRegs[TEST_MODE]) {
|
||||
testModeRun(offset, periodMs);
|
||||
return;
|
||||
}
|
||||
|
||||
// Normální režim – slow PWM
|
||||
slowPwm(PWM1_PIN, holdingRegs[PWM1_DUTY], holdingRegs[PWM1_TYPE], periodMs, offset);
|
||||
slowPwm(PWM2_PIN, holdingRegs[PWM2_DUTY], holdingRegs[PWM2_TYPE], periodMs, offset);
|
||||
slowPwm(PWM3_PIN, holdingRegs[PWM3_DUTY], holdingRegs[PWM3_TYPE], periodMs, offset);
|
||||
slowPwm(PWM4_PIN, holdingRegs[PWM4_DUTY], holdingRegs[PWM4_TYPE], periodMs, offset);
|
||||
slowPwm(PWM5_PIN, holdingRegs[PWM5_DUTY], holdingRegs[PWM5_TYPE], periodMs, offset);
|
||||
slowPwm(PWM6_PIN, holdingRegs[PWM6_DUTY], holdingRegs[PWM6_TYPE], periodMs, offset);
|
||||
}
|
||||
Reference in New Issue
Block a user