//
//
#include <WiFi.h>
#include <Wire.h>
#include <I2cDiscreteIoExpander.h> // PCF85xx library
//#include <Adafruit_PWMServoDriver.h> // PWMservo library
//#include <FastLED.h> // kvuli objemne knihovne nprobehne odladeni - je pres free limit
#define NUM_LEDS 16
#define DATA_PIN 15
//CRGB leds[NUM_LEDS];
#define NTP_SERVER "pool.ntp.org"
#define UTC_OFFSET 0
#define UTC_OFFSET_DST 0
#include <LiquidCrystal_I2C.h> // Importa a biblioteca para o LCD I2C.
LiquidCrystal_I2C lcd(0x27, 16, 2); // Define o endereço I2C do LCD e seu tamanho.
#define Add0 32 // PCF chip1 INToutput read
#define LEDPIN 25
#define DEBOUNCE_DELAY 50 // puvodni 200 - debouncing isr
/*
bool interrupt = false; // true on interrupt
bool ledState = false;
uint32_t lastInterruptTime = 0;
*/
volatile bool interrupt = false; // true on interrupt
volatile bool ledState = false;
volatile uint32_t lastInterruptTime = 0;
volatile uint16_t ISRVector;
uint16_t ISR_Xvector;
uint8_t ISRdev = 6; // ISR vector device
/*volatile */ uint8_t error, address, reg, data;
uint8_t dev_addr = 0x40; //0x40 - 12C Address
uint8_t mode1 = 0; //0x00 location for Mode1 register address
uint8_t mode2 = 1; //0x01 location for Mode2 register address
uint16_t PRE_SCALE =30;
uint8_t led0 = 6; //0x06 location for start LED0 registers
uint8_t rst = 1; //0x01 reset device
uint8_t rval = 0; //read register value
uint16_t led_on;
uint16_t led_off;
uint8_t ledN;
uint8_t led_stat[16];
/**********************************************************************/
// create I2cDiscreteIoExpander objects
I2cDiscreteIoExpander device[8] = {0,1,2,3,4,5,6,7}; // [8=total number]
uint8_t PCF_addr[8] = {0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27};
/********************************** ISR *********************************/
void IRAM_ATTR doISR(){
//void ARDUINO_ISR_ATTR doISR() {
/* ///
uint32_t currentTime = millis();
if (currentTime - lastInterruptTime > DEBOUNCE_DELAY) { // <<<---- tady je to kouzlo
interrupt = false;
lastInterruptTime = currentTime;
ISR_Xvector = device[ISRdev].getPorts();
if (interrupt) {
Serial.println("ON"); // to jeste zvlada bez havarie
} else {
Serial.println("OFF"); // to jeste zvlada bez havarie
}
ledState = !ledState; // jen střídavě přepíná
// digitalWrite(LEDPIN, ledState); // POZOR - dlouhá loop - dlouhá odezva - ošetřit jinak
// digitalWrite(LEDPIN, interrupt); // POZOR - dlouhá loop - dlouhá odezva - ošetřit jinak
}
*/ ///
/* //Serial to jednoznačně kousne
for(uint8_t idx = 6; idx<7; idx++){
Serial.print("whe isr - inputs on device : ");
Serial.print(idx, HEX);
Serial.print(" bin : ");
Serial.println(getChangedInputValue(idx), BIN);
}
*/
interrupt = true;
ISR_Xvector = device[ISRdev].getPorts(); // tady to simulace stihala
}
void setup() {
pinMode(Add0, INPUT_PULLUP);
pinMode(34, INPUT_PULLUP);
pinMode(LEDPIN, OUTPUT);
Serial.begin(115200);
Serial2.begin(9600, SERIAL_8N1, 16, 17); // Nextion serial
// Serial2.begin(9600); // Nextion serial2
Serial.println("\nI2C Scanner");
Serial2.println("Serial 2 NEX");
Wire.begin();
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" I2C scan ");
lcd.setCursor(0, 1);
lcd.print(" > scanning > ");
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ ) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.println(address,HEX);
nDevices++;
}
else if (error==4) {
Serial.print("Unknow error at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.println(address,HEX);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found\n");
}
else {
Serial.println("done\n");
// LCD_displ(" I2C scan ", " > finished > ");
// lcd.setCursor(0, 0);
// lcd.print(" I2C scan ");
lcd.setCursor(0, 1);
lcd.print(" finished ");
}
lcd.clear();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Connecting to ");
lcd.setCursor(0, 1);
lcd.print("WiFi ");
WiFi.begin("Wokwi-GUEST", "", 6);
while (WiFi.status() != WL_CONNECTED) {
delay(250);
spinner();
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
lcd.clear();
lcd.setCursor(0, 0);
lcd.println("Online");
lcd.setCursor(0, 1);
lcd.println("Updating time...");
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
setTimezone("CET-1CEST,M3.5.0,M10.5.0/3");
// initTime("CET-1CEST,M3.5.0,M10.5.0/3"); // TZ-String for Europe/Berlin
/************************************************************************/
// prime ovladani PCA 0x40 pro LED
//set for auto-increnent
///reg = mode1;
data = 160; // 0b10100000 viz Mode register 1 PCA9685 str.13 RESTART a AUTOINCREMENT
//data = 176; // 0b11100000 viz Mode register 1 PCA9685 str.13 RESTART, SLEEP a AUTOINCREMENT
//data = 32; // 0b00100000 viz bit 5 Mode register 1 PCA9685 str.13
data = 160; // 0b10100000 viz Mode register 1 PCA9685 str.13 RESTART a AUTOINCREMENT
//data = 176; // 0b11100000 viz Mode register 1 PCA9685 str.13 RESTART, SLEEP a AUTOINCREMENT
//data = 32; // 0b00100000 viz bit 5 Mode register 1 PCA9685 str.13
WRITE_REG(0x40, mode1, data); //mode1 register
delay(50);
// Choose below the desired output mode
//Direct LED connection
// -- set to outpud mode INVRT= 1 OUTDRV =0
///reg = mode2;
data = 16;
WRITE_REG(0x40, mode2, data); //mode2 register
delay(50);
// The PRE_SCALE register can only be set when the SLEEP bit of MODE1 register is set to logic 1.
// mode1 | 0b00001000
WRITE_REG(0x40, mode1, 176); //mode1 SLEEP bit
delay(50);
uint16_t prescale = 121; // => 50 Hz
WRITE_REG(0xFE, PRE_SCALE, prescale); //prescale factor
delay(50);
// mode1 & 0b11110111
WRITE_REG(0x40, mode1, data); //mode1 register
delay(50);
/************************************************************************/
// PCF init preset
// bez nasled disable to nehraje
for(uint8_t i = 0; i<6; i++){
device[i].disableBitwiseInversion();
}
/***===================================================================***/
/******************** Nextion init *************/
// Serial2.begin(9600, SERIAL_8N1, 16, 17); // Nextion serial
// sendNumberData("n0", 255);
attachInterrupt(Add0, doISR, CHANGE); // INT signal je aktivni stavem L, vynuluje se prectenim nebo zapisem do portu
// vynuluje se i vracenim vstupu do puv.stavu
printLocalTime();
delay(500);
}
/**************************************************************/
/********** MAIN LOOP - MAIN LOOP - MAIN LOOP ***************/
/**************************************************************/
void loop() {
delay(10); // recommended for "faster" simulation
/*
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Main loop ");
lcd.setCursor(0, 1);
lcd.print(" > in progress >");
*/
/*
digitalWrite(LEDPIN, ledState); // POZOR - dlouhá loop - dlouhá odezva - ošetřit jinak
Serial.print("var ledState : ");
Serial.println(ledState);
digitalWrite(LEDPIN, ledState); // POZOR - dlouhá loop - dlouhá odezva - ošetřit jinak
*/
/* zpracovat flag if(interrupt=true) a pak ho vynulovat */
if(interrupt) {
digitalWrite(LEDPIN, interrupt); // POZOR - dlouhá loop - dlouhá odezva - ošetřit jinak
Serial.print("var interrupt true : ");
Serial.println(interrupt);
// ISR_Xvector = XreadInputs(ISRdev); // az precteni PCF s aktivnim INT schodi vystup int PCF // tohle je asi pomalejsi - cca 2 millis
Serial.print("ISR_Xvector from isr : ");
Serial.println(ISR_Xvector, HEX); // ISR?Xvector je nacteni z isr
// {..........................................}
// nasledujici zpracovani = precteni portu PCF schodi vystupy INT do LOW ( HIGH je aktivni)
for(uint8_t idx = 0; idx<7; idx++){ // nectu isr port abych ho "nesmazal"
Serial.print("inputs on device : ");
Serial.print(idx, HEX);
Serial.print(" bin : ");
Serial.println(getChangedInputValue(idx), BIN);
}
interrupt = false;
Serial.print("var interrupt false : ");
Serial.println(interrupt);
}
vTaskDelay(100 / portTICK_PERIOD_MS);
// delay(200);
// detachInterrupt(Add0);
/// Serial.println("===== mirror 1 =====");
//delay(20);
mirrorInputOntoOutputs(0); // pozn: zrcadli se LowByte do HighByte, ISR funguje
delay(20);
/// Serial.println("===== mirror 2 =====");
//delay(20);
mirrorInputOntoOutputs(1);
// Serial.println("===== mirror 3 =====");
delay(20);
/// mirrorInputOntoOutputs(2);
// Serial.println("===== mirror 4 =====");
//delay(20);
/// mirrorInputOntoOutputs(3);
// Serial.println("===== mirror 5 =====");
//delay(20);
/// mirrorInputOntoOutputs(4);
// Serial.println("===== mirror 6 =====");
//delay(20);
/// mirrorInputOntoOutputs(5);
/*
Serial.println("ISR vectors on device(7)");
//delay(20);
readInputs(7);
/// mirrorInputOntoOutputs(7);
*/
delay(100);
}
/*************** END OF MAIN LOOP - END OF MAIN LOOP ***************/
void READREG(uint8_t dev_addr) {
Wire.beginTransmission( dev_addr );
Wire.write(reg);
error = Wire.endTransmission();
Wire.beginTransmission( dev_addr );
Wire.requestFrom(dev_addr,1); //start a transaction to read 1 byte
rval = Wire.read(); //read the byte
error = Wire.endTransmission();
}
void WRITE_REG(uint8_t dev_addr, uint8_t reg, uint8_t data ){
Wire.beginTransmission( dev_addr );
Wire.write(reg);
Wire.write(data);
error = Wire.endTransmission();
}
/**************************************************************************/
uint16_t getChangedInputValue(uint8_t idx) {
Serial.print("Get Input ");
Serial.println(device[idx].digitalRead(),BIN);
return device[idx].getPorts();
}
void mirrorInputOntoOutputs(uint8_t idx) {
uint16_t bothports = getChangedInputValue(idx);
uint16_t inputs = lowByte(bothports);
// Mirror the inputs to the outputs
// leave the inputs, as inputs (i.e. writing high)
uint16_t newValue = word(inputs, 0xff) ; // (inputs << 8) | 0xff;
/* Serial.print("Inputs read as 0x");
Serial.print(inputs, HEX);
*/ //Serial.println(" being mirrored to out");
device[idx].digitalWrite(newValue);
/* Serial.print("Wrote 2 bytes: port0 -> 0x");
Serial.print(lowByte(newValue), HEX);
Serial.print(" port1 -> 0x");
Serial.print(highByte(newValue), HEX);
Serial.print(" to device ");
Serial.println((int)idx);
*/ }
void readInputs(uint8_t idx) { // pouze posle na ser.port
uint16_t newValue = getChangedInputValue(idx);
Serial.print("Inputs read 0x");
Serial.print(newValue, HEX);
Serial.print(" on device ");
Serial.println((int)idx);
// if(newValue < 0xFFFE)
// device[idx].digitalWrite (0xFFFE);
// else device[idx].digitalWrite (0xFFFF);
}
uint16_t XreadInputs(uint8_t idx) { // funkce, vraci stav vstupu
uint16_t newValue = getChangedInputValue(idx);
Serial.print("Inputs Xread 0x");
Serial.print(newValue, HEX);
Serial.print(" on device ");
Serial.println((int)idx);
// if(newValue < 0xFFFE)
// device[idx].digitalWrite (0xFFFE);
// else device[idx].digitalWrite (0xFFFF);
// delay(50);
return newValue;
}
/********************* NEX ***** NEX ******* NEX ******************/
void sendTermination() {
Serial2.write(0xFF);
Serial2.write(0xFF);
Serial2.write(0xFF);
}
void sendWaveformData(int waveformId, int channel, int value) {
// Serial.println(value);
Serial2.print("add ");
Serial2.print(waveformId);
Serial2.print(",");
Serial2.print(channel);
Serial2.print(",");
Serial2.print(value);
sendTermination();
}
void sendTextData(const char* componentName, int value) {
Serial2.print(componentName);
Serial2.print(".txt=\"");
Serial2.print(value);
Serial2.print("\"");
sendTermination();
}
void sendNumberData(const char* componentName, int value) {
Serial2.print(componentName);
Serial2.print(".val=");
Serial2.print(value);
sendTermination();
}
void sendGaugeData(const char* componentName, int value) {
Serial2.print(componentName);
Serial2.print(".val=");
Serial2.print(value);
sendTermination();
}
void sendProgressBarData(const char* componentName, int value) {
Serial2.print(componentName);
Serial2.print(".val=");
Serial2.print(value);
sendTermination();
}
void spinner() {
static int8_t counter = 0;
const char* glyphs = "\xa1\xa5\xdb";
lcd.setCursor(15, 1);
lcd.print(glyphs[counter++]);
if (counter == strlen(glyphs)) {
counter = 0;
}
}
void printLocalTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
lcd.setCursor(0, 1);
lcd.println("Connection Err ");
Serial.println("Connection Err");
return;
}
lcd.setCursor(8, 0);
lcd.println(&timeinfo, "%H:%M:%S");
Serial.println(&timeinfo, "%H:%M:%S");
lcd.setCursor(0, 1);
lcd.println(&timeinfo, "%Y-%m-%d %Z");
Serial.println(&timeinfo, "%Y-%m-%d %Z");
}
void setTimezone(String timezone){
Serial.printf(" Setting Timezone to %s\n",timezone.c_str());
setenv("TZ",timezone.c_str(),1); // Now adjust the TZ. Clock settings are adjusted to show the new local time
tzset();
}
void setTime(int yr, int month, int mday, int hr, int minute, int sec, int isDst){
struct tm tm;
tm.tm_year = yr - 1900; // Set date
tm.tm_mon = month-1;
tm.tm_mday = mday;
tm.tm_hour = hr; // Set time
tm.tm_min = minute;
tm.tm_sec = sec;
tm.tm_isdst = isDst; // 1 or 0
time_t t = mktime(&tm);
Serial.printf("Setting time: %s", asctime(&tm));
struct timeval now = { .tv_sec = t };
settimeofday(&now, NULL);
}
pwm1 - 00000
Sample time 20ms - diagram.json
0x27 ISR vect
pwm1 - 00000