Показ дописів із міткою PCF8574. Показати всі дописи
Показ дописів із міткою PCF8574. Показати всі дописи

вівторок, 25 вересня 2018 р.

MyHomeIoT: Рівень води Water Level шина I2C

MyHomeIoT Water Level

Рівень води MyHomeIoT Water Level призначений для контролю рівня води, та керуванням впускним і випускним клапаном по шині I2C з мікроконтролера. Приєднавши цю плату до Sonoff Basic (TH), або до будь якого пристрою на ESP8266, схемно сумісного з Sonoff basic (TH) та прошитого прошивкою MyHomeIoT починаючи з версії 1.1.4 і вище, до шини I2C, отримуєте контроль рівня води (чотири рівня: пустий, 1/4, 1/2, 3/4 і повний) плюс керування впускним і випускним клапаном зі світлодіодною індикацією і зворотнім зв'язком, як з додатку blynk app, так і з кнопки на самій платі. В додачу два тижневих планувальника для встановлення потрібного рівня води.
Також цей Water Level можна використовувати з будь яким мікроконтролером для своїх поробок автоматики і систем розумного будинку написавши програмну підтримку до свого мікроконтролеру який будете використовувати.

Схема пристрою

Схема рівня води (тицяйте в зображення для збільшення)
Схема складається з мікросхеми PCF8574P, яка є двонаправленим розширювачем портів вводу/виводу з керуванням по I2C шині і має адресу 0x21. Та мікросхеми ULN2803A, яка є масивом транзисторів Дарлінгтона і має 8 транзисторів з загальним емітером та внутрішніми діодами для індуктивних навантажень (реле).
Перші чотири входи IN1 - IN4 мікросхеми ULN2803A використовуються для визначення рівня води. Виходи OUT5 і OUT6 мікросхеми ULN2803A керують впускним і випускним клапаном. А OUT7 керує світлодіодним індикатором режиму роботи. OUT8 не використовується (резерв), тому можна замість мікросхеми ULN2803A застосувати UNL2003.

Мікросхема PCF8574P - двонаправлений розширювач портів вводу/виводу з шиною I2C
Кнопка S1 - встановлення потрібного рівня води.
Світлодіод D2 - для індикації режимів роботи та помилок сенсору.
Реле К1, К2 - керування впускним і випускним клапаном
Транзистор Q1 - захист від переливу води у випадку, якщо мікроконтролер "завис" або не працює з якихось причин. Можна без транзистору, тоді OUT5 мікросхеми ULN2803A з'єднати на пряму з реле К1 (вивід 2 на схемі).

Демонстраційний код


/*
 Name:  pcf8574_water_level.ino
 Created: 7/16/2018 8:59:19 AM
 Author: Andriy
*/
#include <Ticker.h>
#include <Wire.h>
#include <pcf8574_esp.h>


#define ADDRESS_WATER_LEVEL  0x21 // Address PCF8574 on the I2C bus
#define SDA    4 // Pin SDA wire 
#define SCL    5 // Pin SCL wire

typedef enum {
 empty  = 0x00,
 quarter  = 0x40,
 half  = 0x80,
 threeQuarters = 0xC0,
 full  = 0xFE,
 errorSensor = 0xFF
}WaterLevelEnum;

typedef enum {
 sensor_0,
 sensor_1,
 sensor_2,
 sensor_3,
 intake_pump,
 outlet_pump,
 led_indicator,
 button
}WaterLevelPortEnum;

typedef struct
{
 bool triggerInit  = false;   // трігер чи є такий пристрій в системі
 bool triggerButton  = false;   // трігер натискання і відпускання кнопки
 bool triggerStart  = false;   // трігер старту встановлення рівня води 
 bool stateLed   = false;   // стан світлодіодного індікатора увімк/вимкн 
 bool stateRelay[2]  = { false, false }; // стан впускного і випускного реле 
 uint8_t requiredWaterLevel = full;
 uint8_t currentWaterLevel = empty;
}WaterLevelTypeDef;

WaterLevelTypeDef waterLevelStruct;

PCF857x waterLevelDevice(ADDRESS_WATER_LEVEL, &Wire, false);

Ticker tickerWaterLevel;

static void wl_Run(bool setOutletPump);
static uint8_t wl_GetWaterLevel(void);
static void wl_SetWaterLevel(uint8_t level);
static void wl_ReadKey(void);
static void wl_Control(bool setOutletPump);
static void wl_ErrorLedStatus(void);
static void wl_Action(bool state, bool stateIntakePump, bool stateOutletPump, String str);

// the setup function runs once when you press reset or power the board
void setup()
{
 Serial.begin(115200);

 Wire.begin(SDA, SCL);
 // ініціалізуємо рівень води
 waterLevelDevice.begin(0x8F);
 // встановлюємо потрібний рівень
 wl_SetWaterLevel(half);
 // взнаємо поточний рівень води і заносимо до структури
 waterLevelStruct.currentWaterLevel = wl_GetWaterLevel();

 if (waterLevelStruct.currentWaterLevel != errorSensor)
 {
  wl_Action(false, false, false, "Device water level is OK!");

  if (tickerWaterLevel.active())
  {
   tickerWaterLevel.detach();
   waterLevelDevice.write(led_indicator, LOW);
  }
 }
 else
 {
  wl_Action(false, false, false, "Device water level is sensor error!");
  
  if (!tickerWaterLevel.active())
  {
   tickerWaterLevel.attach(0.2, wl_ErrorLedStatus);
  }  
 }
}

// the loop function runs over and over again until power down or reset
void loop() 
{ 
 wl_Run(true);
}

static void wl_Run(bool setOutletPump)
{
 wl_ReadKey();
 wl_Control(setOutletPump);  
}

static void wl_ReadKey(void)
{
 if (!waterLevelDevice.read(button) && !waterLevelStruct.triggerButton)
 {
  waterLevelStruct.triggerButton = true;
  waterLevelStruct.triggerStart = !waterLevelStruct.triggerStart; 
 }
 else if (waterLevelDevice.read(button) && waterLevelStruct.triggerButton)
 {
  waterLevelStruct.triggerButton = false;  
 }
}

static void wl_Control(bool setOutletPump)
{
 if (waterLevelStruct.triggerStart) 
 {  
  waterLevelStruct.currentWaterLevel = wl_GetWaterLevel();

  if (waterLevelStruct.currentWaterLevel == errorSensor)
  {  
   wl_Action(false, false, false, "Error water sensor");
   
   if (!tickerWaterLevel.active())
   {
    tickerWaterLevel.attach(0.2, wl_ErrorLedStatus);
   }   
  }
  else
  {      
   if (tickerWaterLevel.active())
   {
    tickerWaterLevel.detach();
    waterLevelDevice.write(led_indicator, LOW);
   }
   
   if (waterLevelStruct.currentWaterLevel == waterLevelStruct.requiredWaterLevel)
   {    
    wl_Action(false, false, false, "The tank has already reached the required level");    
   }
   else if (waterLevelStruct.currentWaterLevel < waterLevelStruct.requiredWaterLevel)
   {
    if (!waterLevelStruct.stateRelay[0])
    {     
     wl_Action(true, true, false, "Intake Pump ON");
    }
   }
   else if (waterLevelStruct.currentWaterLevel > waterLevelStruct.requiredWaterLevel)
   {
    if (setOutletPump)
    {     
     if (!waterLevelStruct.stateRelay[1])
     {
      wl_Action(true, false, true, "Outlet Pump ON");
     }
    }
   }
  }  
 }
 else
 {
  if (waterLevelStruct.stateRelay[0])
  {   
   wl_Action(false, false, false, "Intake Pump OFF");
  }
  
  if (waterLevelStruct.stateRelay[1])
  {
   wl_Action(false, false, false, "Outlet Pump OFF");
  }
 } 
}

static void wl_Action(bool state, bool stateIntakePump, bool stateOutletPump, String str)
{ 
 waterLevelStruct.triggerStart = state;
 waterLevelStruct.stateLed = state;
 waterLevelStruct.stateRelay[0] = stateIntakePump;
 waterLevelStruct.stateRelay[1] = stateOutletPump; 
 Serial.println(str);
 Serial.print("Current water level is ");
 switch (waterLevelStruct.currentWaterLevel)
 {
 case empty:
  Serial.println("empty");
  break;
 case quarter:
  Serial.println("1/4");
  break;
 case half:
  Serial.println("1/2");
  break;
 case threeQuarters:
  Serial.println("3/4");
  break;
 case full:
  Serial.println("full");
  break;
 case errorSensor:
  Serial.println("error");
  break;
 default:
  break;
 } 

 waterLevelDevice.write(led_indicator, waterLevelStruct.stateLed);
 waterLevelDevice.write(intake_pump, waterLevelStruct.stateRelay[0]);
 waterLevelDevice.write(outlet_pump, waterLevelStruct.stateRelay[1]); 
}

static void wl_ErrorLedStatus(void)
{
 waterLevelDevice.toggle(led_indicator);
}

static uint8_t wl_GetWaterLevel(void)
{ 
 uint8_t level = (waterLevelDevice.read8() & 0xF) ^ 0x0F;
 
 if (level != 0b0000 && level != 0b0001 &&\
  level != 0b0011 && level != 0b0111 && level != 0b1111)
 {
  return errorSensor;
 }
 else
 {
  if (level == 0b0000)
   return empty;
  else if (level == 0b0001)
   return quarter;
  else if (level == 0b0011)
   return half;
  else if (level == 0b0111)
   return threeQuarters;
  else if (level == 0b1111)
   return full;  
 } 
}

static void wl_SetWaterLevel(uint8_t level)
{
 waterLevelStruct.requiredWaterLevel = level;
}

четвер, 31 травня 2018 р.

MyHomeIoT: Розширювач портів Expander 4x4 шина I2C

MyHomeIoT Expander 4x4

Розширювач портів MyHomeIoT Expander 4х4 призначений для керування додатковими чотирма реле по шині I2C з мікроконтролера. Приєднавши цю плату до Sonoff Basic (TH), або до будь якого пристрою на ESP8266 схемно сумісного з Sonoff basic (TH) прошитого прошивкою MyHomeIoT починаючи з версії 1.1.1 і вище до шини I2C, отримуєте керування додатковими, чотирма, реле зі світлодіодною індикацією і зворотнім зв'язком, як з додатку blynk app, так і з кнопок на самій платі. В додачу на кожне додаткове реле по одному планувальнику на тиждень.

Схема розширювача

Принципова схема розширювача MyHomeIoT Expander 4x4
Схема складається з мікросхеми PCF8574P, яка є двонаправленим розширювачем портів вводу/виводу з керуванням по I2C шині і має адресу 0x20. Та мікросхеми ULN2803A, яка є масивом транзисторів Дарлінгтона і має 8 транзисторів з загальним емітером та внутрішніми діодами для індуктивних навантажень (реле). 

Мікросхема U1 (стабілізатор напруги) може бути як на 3.3 вольта, так і на 5 вольт. В залежності від ваших потреб.

Якщо поставити перемичку на J2 то мікросхема U2 PCF8574 буде живитись від свого внутрішнього живлення, а також ці 3.3 вольта, або 5 вольт буде подано на роз'єм J5 і можна буде живити плату з мікроконтролером. 

Якщо перемичку не ставити, то для мікросхеми U2 PCF8574 живлення 3.3 вольта, або 5 вольт очікується з плати мікроконтролеру. І в такому разі стабілізатор напруги на мікросхемі U1 можна не встановлювати. 

Комутувати навантаження на контактах реле можна до 5 ампер. Якщо потрібно комутувати навантаження з більшим струмом, потрібно запаяти на доріжки додаткові дроти.

Печатна плата

Печатна плата з елементами
Плата вид зверху
Плата вид з низу
Плата в зборі
Добре по розміру підходить така коробочка:
107*87*59mm Plastic Electronics Box Project Case DIN Rail PLC Junction Box DIY
Замовити можна, наприклад, тут, або тут, або ще деінде. Отвори в платі під кріплення в цій коробочці прийдеться висвердлити самому.

Варіанти підключення

Плата розширювача з Sonoff basic

Підключення розширювача до Sonoff Basic

Плата розширювача з NodeMCU та іншими ESP8266

Підключення розширювача до NodeMCU

Демонстраційний код

Хто хоче використовувати цей розширювач портів в своїх розробках, то ось для прикладу демонстраційний код для системи Blynk:

/*
 Name:  Blynk_pcf8574_demo.ino
 Created: 7/11/2018 10:17:12 AM
 Author: Andriy Honcharenko
*/

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <Wire.h>
#include <pcf8574_esp.h>

#define ADDRESS_PCF8574   0x20 // Address PCF8574 on the I2C bus
#define SDA    4 // Pin SDA wire 
#define SCL    5 // Pin SCL wire

#define BUTTON_1   V1 // Expander I/O 4x4 relay1
#define BUTTON_2   V2 // Expander I/O 4x4 relay2
#define BUTTON_3   V3 // Expander I/O 4x4 relay3
#define BUTTON_4   V4 // Expander I/O 4x4 relay4

// Macros to work with bits
#define BIT_SET(reg, bit) reg |= 1 << bit
#define BIT_RESET(reg, bit) reg &= ~(1 << bit)
#define BIT_TOGGLE(reg, bit) reg ^= 1 << bit
#define BIT_IS_SET(reg, bit) (reg & (1 << bit)) != 0
#define BIT_IS_RESET(reg, bit) (reg & (1 << bit)) == 0
//--------------------------

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "auth";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "ssid";
char pass[] = "pass";

//----------------------------------
//PCF8574
//----------------------------------
typedef struct {  
 bool triggerButton[4] = { false, false, false, false };
 bool stateButton[4] = { false, false, false, false };
}PCF8574TypeDef;

PCF8574TypeDef pcf8574Struct;

PCF857x pcf8574(ADDRESS_PCF8574, &Wire, false);

// Prototypes of functions
static void readExpanderKey(void);  // Read the state of the buttons
static void writeStateExpanderRelay(void); // Write the state of the relay
//-----------------------------------

void setup()
{
 // Debug console
 Serial.begin(115200);

 Wire.begin(SDA, SCL);
 
 pcf8574.begin(0xF0);

 Blynk.begin(auth, ssid, pass);
 // You can also specify server:
 //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 8442);
 //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8442);
}

void loop()
{
 Blynk.run();
 // You can inject your own code or combine it with other sketches.
 // Check other examples on how to communicate with Blynk. Remember
 // to avoid delay() function!

 // Read the state of the buttons on the PCF8574
 readExpanderKey();
}

BLYNK_CONNECTED()
{
 Blynk.notify("Demo PCF8574 online!");
 
 Blynk.syncAll();
}

BLYNK_WRITE(BUTTON_1)
{
 pcf8574Struct.stateButton[0] = param.asInt(); 
 //Let's record the state of the relay on PCF8574
 writeStateExpanderRelay();
}

BLYNK_WRITE(BUTTON_2)
{
 pcf8574Struct.stateButton[1] = param.asInt();
 //Let's record the state of the relay on PCF8574
 writeStateExpanderRelay();
}

BLYNK_WRITE(BUTTON_3)
{
 pcf8574Struct.stateButton[2] = param.asInt();
 //Let's record the state of the relay on PCF8574
 writeStateExpanderRelay();
}

BLYNK_WRITE(BUTTON_4)
{
 pcf8574Struct.stateButton[3] = param.asInt();
 //Let's record the state of the relay on PCF8574
 writeStateExpanderRelay();
}

static void readExpanderKey(void)
{ 
 // Read all 8 bits at once
 uint8_t buff_in = pcf8574.read8();
 // We are only interested in 4 high bits (button state)
 buff_in >>= 4;
 // Analyze the state of high bits
 for (int i = 0; i < 4; i++)
 {
  if (BIT_IS_RESET(buff_in, (i)) && !pcf8574Struct.triggerButton[i])
  {
   pcf8574Struct.triggerButton[i] = true;
   pcf8574Struct.stateButton[i] = !pcf8574Struct.stateButton[i];

   if (Blynk.connected())
   {
    switch (i)
    {
    case 0:
     Blynk.virtualWrite(BUTTON_1, pcf8574Struct.stateButton[i]);
     break;
    case 1:
     Blynk.virtualWrite(BUTTON_2, pcf8574Struct.stateButton[i]);
     break;
    case 2:
     Blynk.virtualWrite(BUTTON_3, pcf8574Struct.stateButton[i]);
     break;
    case 3:
     Blynk.virtualWrite(BUTTON_4, pcf8574Struct.stateButton[i]);
     break;
    default:
     break;
    }    
   }
  }
  else if (BIT_IS_SET(buff_in, (i)) && pcf8574Struct.triggerButton[i])
  {
   pcf8574Struct.triggerButton[i] = false;
  }
 }
 // Let's record the new state of the relay
 writeStateExpanderRelay();
}

static void writeStateExpanderRelay(void)
{ 
 uint8_t buff_out = 0xFF;

 for (int i = 0; i < 4; i++)
 {

  if (pcf8574Struct.stateButton[i])
  {   
   BIT_SET(buff_out, i);
  }
  else
  {
   BIT_RESET(buff_out, i);
  }
 }

 pcf8574.write8(buff_out);
}
Отримайте "AUTH TOKEN" для свого пристрою, та вставте його в демонстраційний код замість "auth". А також вставте в демокод "SSID" і "PASS" вашої WiFi мережі.

Демонстраційний проект

До проекту Blynk додайте 4 кнопки і назначте їм і'я, колір - за вашим смаком. А також назначте кнопкам віртуальні шпильки: V1, V2, V3, V4. Режим всіх кнопок "SWITCH".
Додайте віджет "Notification".

Або скануйте цей код і отримаєте готовий демо-проект на свій смартфон:

Замовлення

  • Плата - 3$ (у.о)
  • Плата + деталі для самостійного збирання - 9$ (у.о)
  • Плата зібрана і протестована -  12$ (у.о)
Щодо придбання плат пишіть на taburyak@gmail.com

Файли

Відео демонстрація