У Вас nrf использует аппаратный SPI (это зашито в библиотеке) с ногами 11 12 13.
А дисплей у Вас использует програмный SPI (Ваша строка инициализации Ucglib_ILI9341_18x240x320_SWSPI ucg(/*sclk=*/13, /*data=*/11, /*cd=*/9 , /*cs=*/10, /*reset=*/8);) и тоже с ногами 11 13. Как то не красиво получается. На одних ногах живуи разные SPI.
Замените для дисплея инициализацию Ucglib_ILI9341_18x240x320_HWSPI ucg(/*cd=*/PIN_CD, /*cs=*/PIN_CS, /*reset=*/PIN_RESET); // Аппаратный SPI на дисплей ILI9341 ) и проверьте соответсвие ног.
я пробовал вашу строку со своими пинами, в обще дисплей не работает да же без кода nrf да и с этой строкой пины 11,13 все равно останутся как у nrf я пересадил все пины со своей срокой на другие, заработало но жутко тормозит отрисовка на дисплее и код весь из за этого.
я пробовал вашу строку со своими пинами, в обще дисплей не работает да же без кода nrf да и с этой строкой пины 11,13 все равно останутся как у nrf я пересадил все пины со своей срокой на другие, заработало но жутко тормозит отрисовка на дисплее и код весь из за этого.
1. Тормозит дисплей потому что программный spi.
2. У Вас дисплей подключен через преобразователь уровней (резисторы)? У меня сначал была микросхема и работал только программный spi я поменял на резисторы и все зарабоатло . Только на дисплей.
3. Общие пины 11 12 13 на хард spi допустимы (так и задумывалось, протокол позволяет вешать несколько приемников на одну шину) , главное что бы пины CS CD были разные и библиотека корректно с ними работала.
4. Нобходимо добится работы отдельно дисплея с моей строкой и моими ногами. Может перепутаны ноги для дисплея cs и cd?
// НОГИ к которым прицеплена переферия (SPI используется для TFT и NRF24 - 11,12,13)
#define PIN_CS 10 // TFT дисплей spi CS
#define PIN_CD 9 // TFT дисплей spi CD
#define PIN_RESET 8 // TFT дисплей spi Reset дисплей
#define PIN_CE 7 // nrf24 ce
#define PIN_CSN 6 // nrf24 cs
Ucglib_ILI9341_18x240x320_HWSPI ucg(/*cd=*/PIN_CD, /*cs=*/PIN_CS, /*reset=*/PIN_RESET); // Аппаратный SPI на дисплей ILI9341
RF24 radio(PIN_CE, PIN_CSN); // определение управляющих ног
хорошо когда резисторы есть (((( у меня в наличии есть 1к, 4.7к, 10к, 100к и так если я возьму два подряд 1к получу 2к, а вот место 4к можно взять 4.7к ??
и ещё вопрос как вы столько много кода запехнули в про мини? у меня только вот это занимает 30кб из 32кб ((( да же шрифт не сменить на более большой не влезает просто
Я использую библиотеку не ПОЗНЕЕ 1.01. В более старших версиях изменен механизм вывода шрифта - применяют сжатие при хранении - места меньше скорость меньше. Я не использовал функциюSetScale2x2.
У меня тоже вывод не быстр но не 6 секунд. Для проверки залейте скейчт из этой ветки и оцените скорость.
2. По месту - особого криминала не вижу. Я не пользовался библиотекой часов, может она много места занимает. Отключайте отдельные куски и выясните что жрет место. Дисплей съедает 10-12 кБ радио 2-3 кб начальный код 2 кБ. Так я выяснил что sprintf съедает 12-15 кБ места.
Возможно подгружает лишние шрифты (хотя этого не должно быть)
3. Разработка сетевого головного блока. К сожалению времени сейчас не много, плюс еще есть проекты. Для меня сейчас главным проектом являетя блок контроля за тепловым насосом (сейчас его в основном пилю). Но про головной блок не забыл. Уже все спаял и откорпусил, освоил рисование графиков. Сейчас размышляю как наиболее правильно хранить html код в программе. Для затравки картинка (на значения не смотрим так демо работает):
4. В новогодние каникулы у нас стояли морозы (до -25). Наконец прикрутил твердотельное реле на обогреватель. А то в погребе температура была близак +2. У у меня там домашние заготовки и картошка хранится. Как оказалось, во время-)).
При подключении обогревателя понял что немного надо доработать код - при включении блока добавить проверку физической работы вентилятора и обогревателя, что бы пользователь убедился в их работоспособности. Код добавил и выкладываю.
/*
Описание
1. Часы реального времени. Данные приходят от головного блока. Потом обновлются по таймеру (). Пришедшие данные имеют более высокий приоритет
1.1 Установить библиотеку Time library - https://github.com/PaulStoffregen/Time
У нее не удачное имя (винды регистронезависимы и имя совпадает с системным -- среда глючит)
переименовать в stmTime директорию, файлы и ссылки в них !!!
*/
#pragma GCC optimize ("-Os")
//#pragma pack(push, 1) // выравнивание по одному байту ????????
#include <SPI.h>
#include <EEPROM.h>
#include <avr/wdt.h>
#include <leOS.h> // Шедуллер задач
#include <dht.h> // Дачик влажности и температуры
#include "Ucglib.h" // ВНИМАНИЕ использовать библиотеку не познее 1.01 справка https://code.google.com/p/ucglib/wiki/
#include "rusFont.h" // Русские шрифты
#include "nRF24L01.h" // Беcпроводной модуль надо использовать библиотеку http://tmrh20.github.io/RF24
#include "RF24.h" // Беcпроводной модуль используются не стандартные функции https://github.com/TMRh20
// - ОПЦИИ -------------------------------
//#define DEBUG // Отладочную информацию в ком порт посылает
//#define DEMO // Признак демонстрации - данные с датчиков генерятся рандом
#define BEEP // Использовать пищалку
#define RADIO // Признак использования радио модуля
#define VERSION "Ver. 0.75 05/01/16" // Текущая версия
#define ID 0x22 // уникально Идентификатор устройства (тип) - старшие 4 бита, вторые (младшие) 4 бита серийный номер устройства
#if ID == 0x21 // Место установки блока - отоображается как заголовок колонки в таблице. Не более 6 символов а то не влезает
#define LABEL "Подпол"
#elif ID == 0x22
#define LABEL "Подвал"
#else
#define LABEL "none"
#endif
// Макросы для работы с портами скорость и место
#define SetOutput(port,bit) DDR ## port |= _BV(bit)
#define SetInput(port,bit) DDR ## port &= ~_BV(bit)
#define SetBit(port,bit) PORT ## port |= _BV(bit)
#define ClearBit(port,bit) PORT ## port &= ~_BV(bit)
#define WritePort(port,bit,value) PORT ## port = (PORT ## port & ~_BV(bit)) | ((value & 1) << bit)
#define ReadPort(port,bit) (PIN ## port >> bit) & 1
#define PullUp(port,bit) { SetInput(port,bit); SetBit(port,bit); }
#define Release(port,bit) { SetInput(port,bit); ClearBit(port,bit); }
// Мои макросы
#define MOTOR_BIT 0 // бит мотора в packet.flags
#define HEAT_BIT 1 // бит калорифера в packet.flags
#define ABS_H_BIT 2 // бит кодирования влажности абс или % в packet.flags
#define MODE_BIT 5 // первый бит режима в packet.flags
//#define MASK_MODE_BITS 0xe0 // маска для выделения номера режима в packet.flags
#define SET_MODE_BITS packet.flags |= (settingRAM.mode<<MODE_BIT) // запись номера режима в packet.flags
#define FLAG_ABS_H_ON packet.flags |= (1<<ABS_H_BIT) // бит ABS_H_BIT установить в 1
#define FLAG_ABS_H_OFF packet.flags &= ~(1<<ABS_H_BIT) // бит ABS_H_BIT установить в 0
#define FLAG_ABS_H_CHECK packet.flags & (1<<ABS_H_BIT) // бит ABS_H_BIT проверить на 1
#define FLAG_MOTOR_ON packet.flags |= (1<<MOTOR_BIT) // бит мотора установить в 1
#define FLAG_MOTOR_OFF packet.flags &= ~(1<<MOTOR_BIT) // бит мотора установить в 0
#define FLAG_MOTOR_CHECK packet.flags & (1<<MOTOR_BIT) // бит мотора проверить на 1
#define MOTOR_ON { WritePort(C,0,HIGH); FLAG_MOTOR_ON; } // включить мотор
#define MOTOR_OFF { WritePort(C,0,LOW) ; FLAG_MOTOR_OFF; } // выключить мотор
#define FLAG_HEAT_ON packet.flags |= (1<<HEAT_BIT) // бит калорифера установить в 1
#define FLAG_HEAT_OFF packet.flags &= ~(1<<HEAT_BIT) // бит калорифера установить в 0
#define FLAG_HEAT_CHECK packet.flags & (1<<HEAT_BIT) // бит калорифера проверить на 1
#define HEAT_ON { WritePort(C,2,HIGH); FLAG_HEAT_ON; } // включить калорифер
#define HEAT_OFF { WritePort(C,2,LOW); FLAG_HEAT_OFF; } // выключить калорифер
// - КОНСТАНТЫ --------------------------------------
#define dH_OFF 5 // Гистерезис абсолютной влажности в сотых грамма на куб
#define dT_OFF 11 // Гистерезис температуры в сотых градуса
#define TEMP_LOW 150 // Температура подвала критическая - может быть замораживание (в сотых градуса) - система выключается и включается нагреватель
// СИСТЕМАТИЧЕСКИЕ ОШИБКИ ДАТЧИКОВ для каждого ID свой. ОШИБКИ ДОБАВЛЯЮТСЯ!!
#if ID == 0x21 // ОТКАЛИБРОВАНО не менять
#define TOUT_ERR +10 // Ошибка уличного датчика температуры в сотых долях градуса
#define TIN_ERR +50 // Ошибка домового датчика температуры в сотых долях градуса
#define HOUT_ERR -0 // Ошибка уличного датчика влажности в сотых долях %
#define HIN_ERR +50 // Ошибка домового датчика влажности в сотых долях %
#elif ID == 0x22 // ОТКАЛИБРОВАНО не менять
#define TOUT_ERR +50 // Ошибка уличного датчика температуры в сотых долях градуса +50
#define TIN_ERR +50 // Ошибка домового датчика температуры в сотых долях градуса +50
#define HOUT_ERR -230+60 // Ошибка уличного датчика влажности в сотых долях % -260
#define HIN_ERR +490 // Ошибка домового датчика влажности в сотых долях % +480
#else
#define TOUT_ERR 0 // Ошибка уличного датчика температуры в сотых долях градуса
#define TIN_ERR 0 // Ошибка домового датчика температуры в сотых долях градуса
#define HOUT_ERR 0 // Ошибка уличного датчика влажности в сотых долях %
#define HIN_ERR 0 // Ошибка домового датчика влажности в сотых долях %
#endif
// - ВРЕМЕНА ---------------------------------------
#ifdef DEMO // Для демо все быстрее и случайным образом
#define NUM_SAMPLES 2 // Число усреднений измерений датчика ТОЛЬКО целые тысячи для точности часов
#define TIME_SCAN_SENSOR 2000 // Время опроса датчиков мсек, для демки быстрее
#define TIME_PRINT_CHART 4000 // Время вывода точки графика мсек, для демки быстрее
#define TIME_HOUR 50000 // Число мсек в часе, для демки быстрее
#else
#define NUM_SAMPLES 10 // Число усреднений измерений датчика
#define TIME_SCAN_SENSOR 3000 // Время опроса датчиков мсек ТОЛЬКО целые тысячи для точности часов
#define TIME_PRINT_CHART 300000 // Время вывода точки графика мсек
#define TIME_HOUR 3600000 // Число мсек в часе
#endif
#define RESET_TFT_KEY 9999 // Очень длительное нажатие на клавишу мсек, сброс контроллера дисплея и появляется основной экран данные сохраняются
#define LONG_KEY 2000 // Длительное нажатие кнопки мсек, появляется Экран инфо
#define SHORT_KEY 100 // Короткое нажатие кнопки более мсек
#define RESET_TEMP_KEY 4000 // Время нажатия кнопки более мсек для сброса температур
#define NRF24_CHANEL 100 // Номер канала nrf24
// НОГИ к которым прицеплена переферия (SPI используется для TFT и NRF24 - 11,12,13)
#define PIN_HEAT 16 // Ножка куда повешен калорифер A2 (port C2)
#ifdef BEEP
#define PIN_BEEP 15 // Ножка куда повешена пищалка A1 (port C1)
#endif
#define PIN_RELAY 14 // Ножка на которую повешено реле (SSR) вентилятора - аналоговый вход A0 через резистор 470 ом (port C0)
#define PIN_CS 10 // TFT дисплей spi CS
#define PIN_CD 9 // TFT дисплей spi CD
#define PIN_RESET 8 // TFT дисплей spi Reset дисплей
#define PIN_CE 7 // nrf24 ce
#define PIN_CSN 6 // nrf24 cs
#define PIN_DHT22a 5 // Первый датчик DHT22 IN ДОМ
#define PIN_DHT22b 4 // Второй датчик DHT22 OUT УЛИЦА
#define PIN_KEY 3 // Кнопка, повешена на прерывание, что бы ресурсов не тратить (port D3)
#define PIN_IRQ_NRF24 2 // Ножка куда заведено прерывание от NRF24 (пока не используется)
// Настройки
#define NUM_SETTING 7 // Число вариантов настроек
#define BLOCK_OFF 0 // Выключено (вариант настроек)
#define HOOD_ON 1 // Режим вытяжки (вариант настроек)
#define COOLING 2 // Режим охлаждение (вариант настроек)
#include "stmTime.h" // Time library - https://github.com/PaulStoffregen/Time
//#define TZ "UTC+3" // Часовой пояс
unsigned long tt=0; // Время пришедшее от головного блока если 0 то вроемя не приходило ничего не выводим
// АЦП ----------------------------------------
const long ConstADC=1126400; // Калибровка встроенного АЦП (встроенный ИОН) по умолчанию 1126400 дальше измеряем питание и смотрим на дисплей
Ucglib_ILI9341_18x240x320_HWSPI ucg(/*cd=*/PIN_CD, /*cs=*/PIN_CS, /*reset=*/PIN_RESET); // Аппаратный SPI на дисплей ILI9341
leOS myOS; // многозадачность
dht DHT; // Датчики температура влажность
bool infoScreen=false; // Признак отображениея иформационного экрана 1 - на экран ничего не выводится кроме информационного экрана
bool flagKey=false; // Флаг нажатия клавиши
bool pressKey=false; // Флаг необходимости обработки кнопки
unsigned long time_key=0; // Время нажатия копки
long time_key_res_temp=-1; // время нажатия кнопки для сброса температур -1 кнопка не нажата
long time_key_res_tft=-1; // время нажатия кнопки для сброса дисплея -1 кнопка не нажата
byte last_error=100; // Предыдущая ошибка чтения датчиков
struct type_setting_eeprom // Структура для сохранения данных в eeprom
{
byte mode = 0; // Какой режим работы блока
unsigned long hour_unit=0; // мото часы блок измеряется в интервалах вывода данных = NUM_SAMPLES*TIME_SCAN_SENSOR
unsigned long hour_motor=0; // мото часы мотора измеряется в интервалах вывода данных = NUM_SAMPLES*TIME_SCAN_SENSOR
unsigned long hour_heat=0; // мото часы нагревателя измеряется в интервалах вывода данных = NUM_SAMPLES*TIME_SCAN_SENSOR
int16_t tOutMin=5555,tInMin=5555; // Минимальные температуры за период температуры в сотых градуса !!! место экономим
int16_t tOutMax,tInMax=-5555; // Максимальные температуры за период температуры в сотых градуса. (Наблюдаю глюк при tOutMax=-5000)
int16_t tick_eeprom=0; // Переменная для хранения времени записи статистики раз в один час хранится в NUM_SAMPLES*TIME_SCAN_SENSOR сравнение с TIME_HOUR
};
type_setting_eeprom settingRAM; // Рабочая копия счетчиков в памяти
type_setting_eeprom settingEEPROM EEMEM; // Копия счетчиков в eeprom - туда пишем
// Пакет передаваемый, используется также для хранения результатов.
struct type_packet_NRF24 // Версия 2.4!! адаптация для stm32 Структура передаваемого пакета 32 байта - 32 максимум
{
byte id=ID; // Идентификатор типа устройства - старшие 4 бита, вторые (младшие) 4 бита серийный номер устройства
byte DHT_error; // Ошибка разряды: 0-1 первый датчик (00-ок) 2-3 второй датчик (00-ок) 4 - радиоканал
int16_t tOut=-500,tIn=500; // Текущие температуры в сотых градуса !!! место экономим
uint16_t absHOut=123,absHIn=123; // Абсолютные влажности в сотых грамма на м*3 !!! место экономим
uint16_t relHOut=123,relHIn=123; // Относительные влажности сотых процента !!! место экономим
uint8_t flags=0x00; // байт флагов
// 0 бит - мотор включен/выключен
// 1 бит - нагреватель включен/выключен
// 2 бит -[1 - dH_min задается в сотых грамма на м*3] [0 - dH_min задается в ДЕСЯТЫХ процента от absHIn]
// 3-4 - пока пусто
// 5-7 - номер настройки = settingRAM.mode до 8 настроек, надо передавать, что бы на приемнике восстановить
uint8_t dH_min; // Порог включения вентилятора по РАЗНИЦЕ абсолютной влажности в сотых грамма на м*3 или в ДЕСЯТЫХ % см flags:2
uint8_t T_min; // Порог выключения вентилятора по температуре в ДЕСЯТЫХ долях градуса, только положительные значения
uint8_t count=0; // циклический счетчик отправленных пакетов нужен что бы на приемнике проверять качество связи
char note[14] = LABEL; // Примечание не более 13 байт + "0" байт Русские буквы в два раза меньше т.к. UTF-8
} packet;
struct type_sensors // структура для усреднения измерений
{
int num=0; // сколько отсчетов уже сложили не болле NUM_SAMPLES
long sum_tOut=0,sum_tIn=0; // Сумма для усреднения Текущие температуры в сотых градуса !!! место экономим
long sum_relHOut=0,sum_relHIn=0; // Сумма для усреднения Относительные влажности сотых процента !!! место экономим
int tOut=-5000,tIn=5000; // Текущие температуры в сотых градуса !!! место экономим
int absHOut=55555,absHIn=55555; // Абсолютные влажности в сотых грамма на м*3 !!! место экономим
int relHOut=55555,relHIn=55555; // Относительные влажности сотых процента !!! место экономим
} sensors;
// Массивы для графиков
uint8_t tOutChart[120];
uint8_t tInChart[120];
uint8_t absHOutChart[120];
uint8_t absHInChart[120];
uint8_t posChart=0; // Позиция в массиве графиков - начало вывода от 0 до 120-1
uint8_t TimeChart=0; // Время до вывода очередной точки на график.
bool ChartMotor=false; // Признак работы мотора во время интервала графика если мотор был включен на любое время (даже одно измерение) то на графике фон меняется в этом месте
bool ChartHeat=false; // Признак работы нагревателя во время интервала графика если нагреватель был включен на любое время (даже одно измерение) то на графике фон меняется в этом месте
#ifdef RADIO // Радио модуль NRF42l
RF24 radio(PIN_CE, PIN_CSN); // определение управляющих ног
bool send_packet_ok=false; // признак удачной отправки последнего пакета
unsigned long err_ask=0; // число не полученных ответов
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// ПРОГРАММА
///////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup(){
#ifdef DEBUG
Serial.begin(9600);
Serial.println(F("DEBUG MODE"));
#ifdef BEEP
Serial.println(F("BEEP ON"));
#else
Serial.println(F("BEEP OFF"));
#endif
#ifdef RADIO
Serial.println(F("RADIO ON"));
#else
Serial.println(F("RADIO OFF"));
#endif
#endif
reset_sum();
#ifdef RADIO // Радио модуль NRF42l первичная настройка
radio.begin();
radio.setDataRate(RF24_250KBPS); // выбор скорости RF24_250KBPS RF24_1MBPS RF24_2MBPS
radio.setPALevel(RF24_PA_MAX); // выходная мощность передатчика
radio.setChannel(NRF24_CHANEL); //тут установка канала
radio.setCRCLength(RF24_CRC_16); // использовать контрольную сумму в 16 бит
radio.setAutoAck(true); // выключить аппаратное потверждение
// radio.enableDynamicPayloads(); // разрешить Dynamic Payloads
radio.enableAckPayload(); // Разрешить ответ приемника AckPayload
radio.setRetries(50,10); // Количество пауза и количество повторов
// Рекомендуют первые 2-4 байта адреса устанавливать в E7 или 18 он проще детектируется чипом
radio.openWritingPipe(0xE7E7E7E7E1LL); // передатчик
radio.openReadingPipe(1,0xE7E7E7E7D2LL); // приемник
radio.startListening();
#endif
#ifdef BEEP
SetOutput(C,1); // Настройка ноги для динамика
WritePort(C,1,LOW);
#endif
SetInput(D,3); // Включена кнопка
WritePort(D,3,HIGH);
SetOutput(C,0); // Подключить Реле
WritePort(C,0,LOW);
SetOutput(C,2); // Подключить Калорифер
WritePort(C,2,LOW);
pinMode(PIN_DHT22a, OUTPUT); // Датчик DHT22 #1
digitalWrite(PIN_DHT22a, HIGH);
pinMode(PIN_DHT22b, OUTPUT); // Датчик DHT22 #2
digitalWrite(PIN_DHT22b, HIGH);
reset_ili9341(); // сброс дисплея
readEeprom(); // Прочитать настройки
byte i=ReadPort(D,3);
if (i==0) // Если при включении нажата кнопка то стираем Eeprom
{
settingRAM.mode=0;
settingRAM.hour_unit=0;
settingRAM.hour_motor=0;
settingRAM.hour_heat=0;
settingRAM.tOutMin=5000;
settingRAM.tInMin=5000;
settingRAM.tOutMax=-5000;
settingRAM.tInMax=-5000;
ucg.setColor(255, 255, 255);
print_StrXY(10,50,F("Сброс настроек и счетчиков"));
for(i=0;i<3;i++)
{
delay(1000);
ucg.print(F(" ."));
}
writeEeprom(); // Запись в EEPROM
delay(1000);
ucg.clearScreen();
}
boot_test(); // Тестирование исполнительных устройств
wdt_enable(WDTO_8S); // Сторожевой таймер Для тестов не рекомендуется устанавливать значение менее 8 сек.
// Запуск задач по таймеру
myOS.begin();
myOS.addTask(measurement,TIME_SCAN_SENSOR); // Измерение
attachInterrupt(1, scanKey, CHANGE); // КНОПКА Прерывания по обоим фронтам
print_static(); // распечатать таблицу
Setting(); // Применить настройки
measurement(); // Считать данные
#ifdef BEEP
beep(300);
delay(300);
beep(600);
#endif
resetKey();
}
void loop()
{
wdt_reset(); // Сбросить сторожевой таймер
// Обработка нажатия кнопки
// 1. Высший приоритет - сброс контроллера дисплея если он зависнeт - держать долго сброс пройдет отпустить кнопку
if ((flagKey==true)&&(pressKey!=true))
{
if (time_key_res_tft==-1) time_key_res_tft=millis(); // первый вход - нажата кнопка запомнить время нажатия
else if (millis()>time_key_res_tft+RESET_TFT_KEY) // кнопка нажата более RESET_TFT_KEY сек сбрасываем дисплей
{
reset_ili9341(); // сброс дисплея
ucg.setColor(255, 255, 255);
print_StrXY(10,100,F("Сброс контроллера дисплея ILI9341 . . ."));
print_StrXY(10,129,F("Кнопку нужно отпустить"));
delay(1000);
reset_ili9341(); // сброс дисплея
print_static(); // распечатать таблицу
Setting(); // Применить настройки
print_data(); // вывод усредненных значений
print_status(); // панель состояния
printChart(); // показать график
infoScreen=false; // нет информационного экрана
#ifdef BEEP
beep(400); // Звук нажатия на клавишу
#endif
resetKey();
}
}
// 2. Второй приоритет - сброс памяти температур работает только в информационном экране
if ((flagKey==true)&&(pressKey!=true)&&(infoScreen==true)) // Во время информационнного экрана нажата кнопка - подготовка и стирание температур min max
{
if (time_key_res_temp==-1) time_key_res_temp=millis(); // первый вход - нажата кнопка для стирания температур
else if (millis()>time_key_res_temp+RESET_TEMP_KEY) // кнопка нажата более RESET_TEMP_KEY сек сбрасываем температуры
{
settingRAM.tOutMin= 5000;
settingRAM.tInMin= 5000;
settingRAM.tOutMax=-5000;
settingRAM.tInMax= -5000;
writeEeprom(); // Сбросили температуры сохраняем в EEPROM
#ifdef BEEP
beep(500); // Звук нажатия на клавишу
#endif
printInfo(); // Обновить экран с новыми температурами
resetKey();
}
}
else // 3. Остальной обработчик нажатия на кнопок - Кнопку надо нажать и отпустить
if ((flagKey!=false)&&(pressKey==true)) // Кнопка была нажата и отпущена
{
// if (flagKey!=false) // Обработчик кнопки
if ((time_key>=LONG_KEY)&&(infoScreen!=true)) // Длительное нажатие кнопки и информационный экран не показан
printInfo(); // Вывод информационного экрана
else
if (time_key >= SHORT_KEY) // Короткое нажатие кнопки все остальное игнорируется
{
#ifdef BEEP
beep(30); // Звук нажатия на клавишу
#endif
if (infoScreen==true) clearInfo(); // если информационный экран показан то стереть его
else {if (settingRAM.mode >= NUM_SETTING) settingRAM.mode=0; // Кольцевой счетчик настроек
else settingRAM.mode++; // В противном случае следующая настройка
Setting(); }
}
resetKey(); // Сброс состояния кнопки
}
}
void resetKey(void) // Сброс состояния кнопки
{
flagKey=false;
pressKey=false;
time_key_res_temp=-1; // сброс состояния сброса температур
time_key_res_tft=-1; // сброс состояния сброса дисплея
}
void print_static() // Печать статической картинки
{
int i;
cli();
// Заголовок
ucg.setColor(0, 0, 180); //
ucg.drawBox(0, 0, 320-1, 23);
ucg.setColor(250, 250, 250);
ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT);
print_StrXY(2,19,F("ОСУШИТЕЛЬ ID: 0x"));
ucg.print( hex(packet.id >> 4));
ucg.print( hex(packet.id&0x0f));
#ifdef DEMO
ucg.print(F(" demo"));
#endif
// Таблица для данных
ucg.setColor(0, 200, 0);
for (i=0;i<5;i++) ucg.drawHLine(0,25+23*i,320-1);
ucg.drawVLine(200-4,25,24+23*3);
ucg.drawVLine(260,25,24+23*3);
// Заголовки таблиц
ucg.setColor(255, 255, 0);
// В зависимости от id разные надписи - привязка местоположения блока к ID
// print_StrXY(180+30-9,25+0+18,F(LABEL));
ucg.setPrintPos(180+30-9,25+0+18);
ucg.print(packet.note);
print_StrXY(250+20,25+0+18,F("Улица"));
print_StrXY(0,25+23*1+18,F("Температура градусы C"));
print_StrXY(0,25+23*2+18,F("Относительная влаж. %"));
print_StrXY(0,25+23*3+18,F("Абсолют. влаж. г/м*3"));
// Графики
ucg.setColor(210, 210, 210);
// ucg.drawHLine(1,240-2,130);
// ucg.drawVLine(1,135,105);
// ucg.drawHLine(10+154,240-2,130);
// ucg.drawVLine(10+154,135,105);
print_StrXY(10,135+0,F("Температура"));
print_StrXY(20+154,135+0,F("Абс. влажность"));
// надписи на графиках
print_StrXY(128,154,F("+20"));
print_StrXY(135,194,F("0"));
print_StrXY(128,233,F("-20"));
print_StrXY(296,164,F("15"));
print_StrXY(296,194,F("10"));
print_StrXY(296,223,F("5"));
// Горизонтальная шкала по часам
// ucg.setColor(255, 255, 0);
for(i=0;i<=120;i=i+12)
{
ucg.drawPixel(4+i,239);
ucg.drawPixel(4+i,238);
ucg.drawPixel(167+i,239);
ucg.drawPixel(167+i,238);
}
sei();
}
void print_status(void) // Печать панели статуса Значки на статус панели
{
byte temp;
if (infoScreen==true) return; // если отображен информационный экран то ничего не выводим
cli();
// 1. печать ошибки чтения датчиков
print_error_DHT();
// 2. Признак включения мотора или нагревателя
if (FLAG_MOTOR_CHECK) ucg.setColor(0, 240, 0);
else if (FLAG_HEAT_CHECK) ucg.setColor(240, 0, 0);
else ucg.setColor(0, 40, 0);
ucg.drawBox(290-32, 5, 14, 14);
#ifdef RADIO
// 3. Признак удачной передачи информации по радиоканалу - получение квитанции
if (send_packet_ok==true) ucg.setColor(0, 240, 0);
else ucg.setColor(0, 40, 0);
ucg.setPrintDir(3);
ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT);
print_StrXY(290-40,20,F(">>"));
ucg.setPrintDir(0);
// ucg.setFontMode(UCG_FONT_MODE_SOLID);
// 4. Вывод времени на экран
if (tt>0) // выводим если было первоначальная установка от головного блока
{
ucg.setColor(0, 0, 180); //
ucg.drawBox(180, 0, 45, 23);
ucg.setColor(250, 250, 0);
ucg.setPrintPos(180,19);
temp=hour(tt);
if (temp<10) ucg.print("0");
ucg.print(temp);
ucg.print(":");
temp=minute(tt);
if (temp<10) ucg.print("0");
ucg.print(temp);
}
#endif
sei();
}
void print_error_DHT(void) // Печать ошибки чтения датчиков выводится при каждом чтении датчика
{
if (infoScreen==true) return; // если отображен информационный экран то ничего не выводим
// 1. печать ошибки чтения датчиков
if (packet.DHT_error!=last_error) // если статус ошибки поменялся то надо вывести если нет то не выводим - экономия время и нет мерцания
{
cli();
last_error=packet.DHT_error;
ucg.setColor(0, 0, 180); // Сначала стереть
ucg.drawBox(280, 0, 36, 18);
ucg.setPrintPos(280,18);
ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT);
if (packet.DHT_error>0)
{
ucg.setColor(255, 100, 100);
print_StrXY(280,18,F("0x"));
ucg.print( hex(packet.DHT_error >> 4));
ucg.print( hex(packet.DHT_error & 0x0f));
}
else { ucg.setColor(200, 240, 0); ucg.print(F(" ok ")); }
sei();
}
}
// вывод на экран данных (то что меняется)
void print_data()
{
// Статистика по моточасам, время ведется в интервалах вывода данных = NUM_SAMPLES*TIME_SCAN_SENSOR а потом пересчитывается в часы при выводе.
settingRAM.hour_unit++;
if (FLAG_MOTOR_CHECK) settingRAM.hour_motor++; // если мотор включен
if (FLAG_HEAT_CHECK) settingRAM.hour_heat++; // если нагреватель включен
if (infoScreen==true) return; // если отображен информационный экран то ничего не выводим
cli();
// Печать значений
ucg.setFontMode(UCG_FONT_MODE_SOLID);
ucg.setColor(250, 0, 100); // Цвет ДОМА
print_floatXY(200+0,25+23*1+18,((float)packet.tIn)/100);
print_floatXY(200+0,25+23*2+18,((float)packet.relHIn)/100);
print_floatXY(200+0,25+23*3+18,((float)packet.absHIn)/100);
ucg.setColor(0, 250, 100); // Цвет УЛИЦЫ
print_floatXY(260+4,25+23*1+18,((float)packet.tOut)/100);
print_floatXY(260+6,25+23*2+18,((float)packet.relHOut)/100);
print_floatXY(260+6,25+23*3+18,((float)packet.absHOut)/100);
sei();
}
// Печать графика на экране, добавляется одна точка и график сдвигается
void printChart()
{
byte i,x=0;
uint8_t tmp;
// Работаем через кольцевой буфер
// Добавить новую точку в кольцевой буфер
// Температура в доме. диапазон -25 . . . +25 растягиваем на 100 точек
if (packet.tIn<=-2500) tInChart[posChart]=0; // Если температура меньше -25 то округляем до -25
else if (packet.tIn>=2500) tInChart[posChart]=100-1; // Если температура больше 25 то округляем до 25
else tInChart[posChart]=(packet.tIn+2500)/50; // внутри -25...+25 растягиваем в два раза
if (ChartMotor==true) tInChart[posChart]|=0x80; // Признак включения мотора- старший бит в 1 - цвет фона на графике меняется
ChartMotor=false;
// Температура на улице. диапазон -25 . . . +25 растягиваем на 100 точек
if (packet.tOut<=-2500) tOutChart[posChart]=0; // Если температура меньше -25 то округляем до -25
else if (packet.tOut>=2500) tOutChart[posChart]=100-1; // Если температура больше 25 то округляем до 25
else tOutChart[posChart]=(packet.tOut+2500)/50; // внутри -25...+25 растягиваем в два раза
if (ChartHeat==true) tOutChart[posChart]|=0x80; // Признак включения нагревателя- старший бит в 1 - цвет фона на графике меняется
ChartHeat=false;
// Абсолютная влажность в доме диапазон от 0 до 20 грамм на кубометр, растягиваем на 100 точек
if (packet.absHIn>=2000) absHInChart[posChart]=100-1;
else absHInChart[posChart]=packet.absHIn/20; // внутри 0...20 растягиваем в пять раз в сотых % по этому делем не на 100 а на 20
// Абсолютная влажность на улицу диапазон от 0 до 20 грамм на кубометр, растягиваем на 100 точек
if (packet.absHOut>=2000) absHOutChart[posChart]=100-1;
else absHOutChart[posChart]=packet.absHOut/20; // внутри 0...20 растягиваем в пять раз, в сотых % по этому делем не на 100 а на 20
if (infoScreen==false) // если отображен информационный экран то ничего не выводим
{
cli();
for(i=0;i<120;i++) // График слева на право
{
// Вычислить координаты текущей точки x в кольцевом буфере. Изменяются от 0 до 120-1
if (posChart<i) x=120+posChart-i; else x=posChart-i;
// нарисовать фон в зависимости от статуса мотора
if (tOutChart[x]>=0x80) ucg.setColor(90, 60, 0); // Нагреватель был ключен - бледно желтый
else if (tInChart[x]>=0x80) ucg.setColor(0, 60, 90); // Мотор был ключен - бледно синий
else ucg.setColor(0, 0, 0); // все выключено
ucg.drawVLine(5+120-i,237-100,100);
ucg.drawVLine(5+120-i+162,237-100,100);
ucg.setColor(180, 180, 180);
if (i%5==0) // Пунктирные линии графика
{
ucg.drawPixel(5+120-i,236-10-1);
ucg.drawPixel(5+120-i,236-50-1);
ucg.drawPixel(5+120-i,236-90-1);
ucg.drawPixel(5+120-i+162,236-25-1);
ucg.drawPixel(5+120-i+162,236-50-1);
ucg.drawPixel(5+120-i+162,236-75-1);
}
// Вывести новую точку
tmp=tInChart[x]&0x7f; // Отбросить старший разряд - признак включения мотора
if ((tmp==0)||(tmp==100)) ucg.setColor(255, 255, 255); else ucg.setColor(255, 100, 100);
ucg.drawPixel(5+120-i,236-tmp);
tmp=tOutChart[x]&0x7f; // Отбросить старший разряд - признак включения калорифера
if ((tmp==0) || (tmp==100)) ucg.setColor(255, 255, 255); else ucg.setColor(100, 255, 100);
ucg.drawPixel(5+120-i,236-tmp);
if (absHInChart[x]==100) ucg.setColor(255, 255, 255); else ucg.setColor(255, 100, 100);
ucg.drawPixel(5+120-i+162,236-absHInChart[x]);
if (absHOutChart[x]==100) ucg.setColor(255, 255, 255); else ucg.setColor(100, 255, 100);
ucg.drawPixel(5+120-i+162,236-absHOutChart[x]);
}
sei();
}
if (posChart<120-1) posChart++; else posChart=0; // Изменили положение в буфере и Замкнули буфер
}
// ---ПЕРЕДАЧА ДАННЫХ ЧЕРЕЗ РАДИОМОДУЛЬ -----------------------------
#ifdef RADIO // Радио модуль NRF42l
void send_packet()
{ radio.powerUp();
radio.stopListening(); // Остановить приемник
delay(2);
cli();
radio.writeBlocking(&packet,sizeof(packet),200); // Writes 1 payload to the buffers
send_packet_ok=radio.txStandBy();
if ( radio.isAckPayloadAvailable() ) // Ждем получения -- основной блок передает текущее время
radio.read(&tt,sizeof(tt)); //... и имеем переменную tt с временем от приемника.
sei();
if (send_packet_ok!=true) err_ask++; // квитанция не получена добавить счетчик
#ifdef BEEP
if (send_packet_ok==true) beep(30); // Пакет передан успешно
#endif
#ifdef DEBUG
if (send_packet_ok==true) Serial.println(F("Packet sending ++++++++++"));
else Serial.println(F("Packet NOT sending -----------"));
#endif
radio.startListening(); // Включить приемник
packet.count++; // при переполнении сам сбросится
}
#endif
// Чтение датчика возвращает код ошибки:
// DHTLIB_OK 0
// DHTLIB_ERROR_CHECKSUM 1
// DHTLIB_ERROR_TIMEOUT 2
// DHTLIB_ERROR_CONNECT 3
// DHTLIB_ERROR_ACK_L 4
// DHTLIB_ERROR_ACK_H 5
byte readDHT(byte pin)
{
//delay(5);
cli();
byte err=-1*DHT.read22(pin); // Чтение датчика
sei();
return err;
}
// Измерение и обработка данных чтение датчиков --------------------------------------------------------------------------------
void measurement()
{
myOS.pauseTask(measurement); // Обязательно здесь, а то датчики плохо читаются мешает leos
wdt_reset(); // Сбросить сторожевой таймер
packet.DHT_error=readDHT(PIN_DHT22a); // ПЕРВЫЙ ДАТЧИК ДОМ Новый пакет, сбросить все ошибки и прочитать первый датчик
#ifdef DEMO
DHT.temperature=packet.tIn/100+random(-20,30)/10.0;
if (DHT.temperature>20) DHT.temperature=19;
if (DHT.temperature<-10) DHT.temperature=-9;
DHT.humidity=packet.relHIn/100+(float)random(-5,8);
if (DHT.humidity>96) DHT.humidity=90;
if (DHT.humidity<1) DHT.humidity=10;
packet.DHT_error=0; // в Демо режиме
// DHT.temperature=3.0;
// DHT.humidity=21.0;
#endif
sensors.tIn=(int)(DHT.temperature*100.0)+TIN_ERR; // Запомнить результаты для суммирования с учетом ошибок
sensors.relHIn=(int)(DHT.humidity*100.0)+HIN_ERR;
#ifdef DEBUG
Serial.print(F("Sensor read samples:")); Serial.println(sensors.num);
Serial.print(F("IN T="));Serial.print(sensors.tIn);Serial.print(F(" H=")); Serial.print(sensors.relHIn); Serial.print(F(" error=")); Serial.println(packet.DHT_error);
#endif
packet.DHT_error=packet.DHT_error+16*readDHT(PIN_DHT22b);// ВТОРОЙ ДАТЧИК УЛИЦА ошибки в старшие четыре бита
#ifdef DEMO
DHT.temperature=packet.tOut/100+random(-20,30)/10.0;
if (DHT.temperature>30) DHT.temperature=19;
if (DHT.temperature<-30) DHT.temperature=-9;
DHT.humidity=packet.relHOut/100+(float)random(-5,8);
if (DHT.humidity>96) DHT.humidity=90;
if (DHT.humidity<1) DHT.humidity=10;
packet.DHT_error=0; // в Демо режиме
// DHT.temperature=-10.0;
// DHT.humidity=40.0;
#endif
sensors.tOut=(int)(DHT.temperature*100.0)+TOUT_ERR; // Запомнить результаты для суммирования с учетом ошибок
sensors.relHOut=(int)(DHT.humidity*100.0)+HOUT_ERR;
#ifdef DEBUG
Serial.print(F("OUT T="));Serial.print(sensors.tOut);Serial.print(F(" H=")); Serial.print(sensors.relHOut); Serial.print(F(" error=")); Serial.println(packet.DHT_error);
#endif
print_error_DHT(); // Вывод ошибки чтения датчика при каждом чтении контроль за качеством связи с датчиками
if (packet.DHT_error==0)// Если чтение без ошибок у ДВУХ датчиков копим сумму для усреднения
{
sensors.sum_tIn=sensors.sum_tIn+sensors.tIn;
sensors.sum_relHIn=sensors.sum_relHIn+sensors.relHIn;
sensors.sum_tOut=sensors.sum_tOut+sensors.tOut;
sensors.sum_relHOut=sensors.sum_relHOut+sensors.relHOut;
sensors.num++;
}
// набрали в сумме нужное число отсчетов рассчитываем усреднение и выводим
if (sensors.num>=NUM_SAMPLES) // Пора усреднять и выводить значения
{
// вычисление средних значений
packet.tIn=sensors.sum_tIn/NUM_SAMPLES;
packet.relHIn=sensors.sum_relHIn/NUM_SAMPLES;
packet.tOut=sensors.sum_tOut/NUM_SAMPLES;
packet.relHOut=sensors.sum_relHOut/NUM_SAMPLES;
reset_sum(); // Сброс счетчиков и сумм
// вычисление абсолютной влажности
packet.absHIn=(int)(calculationAbsH((float)(packet.tIn/100.0),(float)(packet.relHIn/100.0))*100.0);
packet.absHOut=(int)(calculationAbsH((float)(packet.tOut/100.0),(float)(packet.relHOut/100.0))*100.0);
#ifdef DEBUG
Serial.println(F("Average value >>>>>>>>>>"));
Serial.print(F("IN T="));Serial.print(packet.tIn);Serial.print(F(" H=")); Serial.print(packet.relHIn); Serial.print(F(" abs H=")); Serial.println(packet.absHIn);
Serial.print(F("OUT T="));Serial.print(packet.tOut);Serial.print(F(" H=")); Serial.print(packet.relHOut); Serial.print(F(" abs H=")); Serial.println(packet.absHOut);
#endif
#ifdef RADIO // Радио модуль NRF42l
send_packet(); // Послать данные
#endif
CheckON(); // Проверка статуса вентилятора
print_data(); // вывод усредненных значений
print_status(); // панель состояния
// Обновляем максимум и минимум температур в EEPROM
// Cделано не честно - обновляем раз в 30 секунд (NUM_SAMPLES*TIME_SCAN_SENSOR) а пишем раз в час, могут пропасть данные при сбросе
if (settingRAM.tInMax<packet.tIn) settingRAM.tInMax=packet.tIn;
else if (settingRAM.tInMin>packet.tIn) settingRAM.tInMin=packet.tIn;
if (settingRAM.tOutMax<packet.tOut) settingRAM.tOutMax=packet.tOut;
else if (settingRAM.tOutMin>packet.tOut) settingRAM.tOutMin=packet.tOut;
// Пишем в EEPROM не каждый раз!! экономим ресурс записей 100000 мин.
settingRAM.tick_eeprom++;
if (((long)settingRAM.tick_eeprom*NUM_SAMPLES*TIME_SCAN_SENSOR)>=(long)TIME_HOUR) // пора писать eeprom
{ writeEeprom(); settingRAM.tick_eeprom=0; }
// Запись статистики в EEPROM
if (FLAG_MOTOR_CHECK) ChartMotor=true; // Признак того что надо показывать включение мотора на графике
if (FLAG_HEAT_CHECK) ChartHeat=true; // Признак того что надо показывать включение нагревателя на графике
TimeChart++;
if ((long)((long)TimeChart*TIME_SCAN_SENSOR*NUM_SAMPLES)>=(long)TIME_PRINT_CHART) // проврека не пора ли выводить график
{ printChart(); TimeChart=0; // Сдвиг графика и вывод новой точки
#ifdef DEBUG
Serial.println(F("Point add chart ++++++++++++++++++++"));
#endif
#ifdef BEEP
// beep(50);
#endif
}
}
#ifdef RADIO // Радио модуль NRF42l
// Часы работают если только был получено время от головного блока (хотя бы один раз) в противном случае они даже не показываются на экране
if (tt>0) tt=tt+TIME_SCAN_SENSOR/1000; // Обновить текущее время - что бы часы шли и без связи с базовым блоком
#endif
myOS.restartTask(measurement); // Пустить задачи
}
// Функция переводит относительную влажность в абсолютную
// t-температура в градусах Цельсия h-относительная влажность в процентах
float calculationAbsH(float t, float h)
{
float temp;
temp=pow(2.718281828,(17.67*t)/(t+243.5));
return (6.112*temp*h*2.1674)/(273.15+t);
}
// Сканирование клавиш ------------------------------------------
void scanKey()
{
byte key,key1;
cli();
key=ReadPort(D,3); // Прочитать кнопку 0 - нажата
delay(25); // Задержка для подавления дребезга контактов
key1=ReadPort(D,3); // читаем еще раз кнопку
if (key!=key1) {resetKey();return;} // если значения не равны то ложное срабатывание выходим
if ((key==0)&&(flagKey==false)) // Если кнопка была нажата запомнить время и поставить флаг нажатия
{
flagKey=true; // Кнопка нажата ждем обратного фронта
time_key=millis(); // Время нажатия запомнили
}
if ((key==1)&&(flagKey==true)) // Если кнопка была отжата
{
time_key=millis()-time_key; // Рассчитать время нажатия
pressKey=true; // Поставить признак обработки кнопки
}
sei();
}
// Проверка статуса вытяжки, не пора ли переключится
void CheckON(void)
{
int tmp=0;
// 0. Проверить замораживание подвала НАГРЕВАТЕЛЬ
if (packet.tIn<=TEMP_LOW) { MOTOR_OFF; HEAT_ON; return;} // Контроль от промораживания подвала по идеи здесь надо включать калорифер
if ((FLAG_HEAT_CHECK)&&(packet.tIn>TEMP_LOW+dT_OFF+50)) HEAT_OFF; // Выключить калорифер когда температура поднимится на 0.5 градуса
// 1. Режимы не зависящие от влажности и температуры ВЫСШИЙ приоритет
if ((settingRAM.mode==BLOCK_OFF)&&(~FLAG_MOTOR_CHECK)) return;
if ((settingRAM.mode==BLOCK_OFF)&&(FLAG_MOTOR_CHECK)) { MOTOR_OFF ; return;}
if ((settingRAM.mode==HOOD_ON )&&(FLAG_MOTOR_CHECK)) return;
if ((settingRAM.mode==HOOD_ON )&&(~FLAG_MOTOR_CHECK)) { MOTOR_ON ; return;}
// 2. Режим охлаждения (второй приоритет) температура внутри больше 10 градусов темература снаружи меньше на 2 градуса чем внутри, на влажность не смотрим
if (settingRAM.mode==COOLING) // Режим охлаждение
{
if ((~FLAG_MOTOR_CHECK)&&(packet.tIn>(packet.T_min*10))&&((packet.tIn-packet.tOut)>packet.dH_min)) // dH_min используется не штатно для температуры
{MOTOR_ON; return;} // мотор выключен, температура выше установленной и снаружи температура ниже на 2 градуса то ВКЛЮЧЕНИЕ мотора
if ((FLAG_MOTOR_CHECK)&&(packet.tIn<=packet.tOut))
{MOTOR_OFF; return;} // мотор включен и темература внутри ниже наружней то ВЫКЛЮЧЕННИЕ мотора
return; // изменений нет выходим
}
// 3. В режиме осушения - проверка на достижение минимальной температуры помещения в режиме осушения - СРОЧНО ВЫКЛЮЧИТЬ третий приоритет
if (packet.tIn<=(packet.T_min*10))
{
if (~FLAG_MOTOR_CHECK) return; // Мотор уже выключен, выходим
else { MOTOR_OFF; return;} // выключить и выйти
}
// 4. Режимы зависящие от температуры и влажности низший приоритет (что осталось)
// Расчитываем разность срабатывания по влажности
if (FLAG_ABS_H_CHECK) tmp=packet.dH_min; // Если режимы используют абсолютную разность в сотых грамма на куб
else tmp=(int)(packet.absHIn*(packet.dH_min/10)/100); // Если режимы используют ДЕСЯТЫЕ % от абсолютной разности внутренней температуры
if ((~FLAG_MOTOR_CHECK)&&(packet.tIn>(packet.T_min*10))&&((packet.absHIn-tmp)>packet.absHOut))
{MOTOR_ON; return;} // мотор выключен, темература выше критической, абс влажность с наружи меньше то ВКЛЮЧЕНИЕ мотора
if ((FLAG_MOTOR_CHECK)&&((packet.tIn<=(tmp+dT_OFF))||(packet.absHIn<(packet.absHOut+dH_OFF))))
{MOTOR_OFF; return;} // мотор включен и темература ниже критической или абс влажность внутри ниже то ВЫКЛЮЧЕННИЕ мотора
}
// Вывод информации о настройках и сохрание индекса настроек в eeprom ---------------------------------
void Setting()
{ // Настройка
cli();
ucg.setColor(0, 100, 255);
ucg.setFontMode(UCG_FONT_MODE_SOLID);
ucg.setPrintPos(0,25+18);
switch (settingRAM.mode)
{
case BLOCK_OFF: ucg.print(F("Выключено ")); packet.dH_min=255; packet.T_min=255; FLAG_ABS_H_ON; break;
case HOOD_ON: ucg.print(F("Режим вытяжки ")); packet.dH_min=0; packet.T_min=0; FLAG_ABS_H_ON; break;
case COOLING: ucg.print(F("Охлаждение T>10 dT>2")); packet.dH_min=200; packet.T_min=100; FLAG_ABS_H_ON; break; // dH_min используется не штатно для температуры
case 3: ucg.print(F("Осушение T>+3 dH>0.3 ")); packet.dH_min=30; packet.T_min=30; FLAG_ABS_H_ON; break;
case 4: ucg.print(F("Осушение T>+3 dH>5% ")); packet.dH_min=50; packet.T_min=30; FLAG_ABS_H_OFF; break;
case 5: ucg.print(F("Осушение T>+4 dH>0.6 ")); packet.dH_min=60; packet.T_min=40; FLAG_ABS_H_ON; break;
case 6: ucg.print(F("Осушение T>+4 dH>10% ")); packet.dH_min=100; packet.T_min=40; FLAG_ABS_H_OFF; break;
case 7: ucg.print(F("Осушение T>+5 dH>0.8 ")); packet.dH_min=80; packet.T_min=50; FLAG_ABS_H_ON; break;
}
writeEeprom(); // Запись в EEPROM новых настроек
SET_MODE_BITS; // В пакет для передачи добавили смену режима
MOTOR_OFF; // Поменяли настройки - отключить мотор, пусть заново настройки сработают если потребуется
CheckON(); // Возможно надо включить мотор
print_status(); // Показать панель состояния (смена настроек)
sei();
}
// Вывод float с двумя десятичными знаком в координаты x y // для экономии места
void print_floatXY(int x,int y, float v)
{
ucg.setPrintPos(x,y);
ucg.print(v,2);
ucg.print(F(" ")); // Стереть хвост от предыдущего числа
}
// Вывод строки константы в координаты x y // для экономии места
void print_StrXY(int x,int y, const __FlashStringHelper* b)
{
ucg.setPrintPos(x,y);
ucg.print(b);
}
void printInfo() // Окно с информацией о блоке, появляется при длительном нажатии на кнопку и ее отпускании
{
infoScreen=true;
cli();
ucg.setColor(250, 250, 250); //
ucg.drawBox(5, 5, 320-1-10, 240-1-10);
ucg.setColor(0, 50, 250);
ucg.drawFrame(5+5, 5+5, 320-1-20, 240-1-20);
ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT);
ucg.setColor(0, 200, 10);
print_StrXY(35,12+16,F("ОСУШИТЕЛЬ на Arduino Pro Mini"));
ucg.setColor(0, 50, 50);
print_StrXY(5+10,15+16*2,F("1 Напряжение питания В."));
print_floatXY(5+222,15+16*2,readVcc()/1000.0);
print_StrXY(5+10,15+16*3,F("2 Температура блока гр."));
print_floatXY(5+222,15+16*3,GetTemp());
print_StrXY(5+10,15+16*4,F("3 Мото часы блока"));
ucg.setPrintPos(5+222,15+16*4);
ucg.print(settingRAM.hour_unit/(TIME_HOUR/(NUM_SAMPLES*TIME_SCAN_SENSOR)));
print_StrXY(5+10,15+16*5,F("4 Мото часы вентилятора"));
ucg.setPrintPos(5+222,15+16*5);
ucg.print(settingRAM.hour_motor/(TIME_HOUR/(NUM_SAMPLES*TIME_SCAN_SENSOR)));
print_StrXY(5+10,15+16*6,F("5 Мото часы нагревателя"));
ucg.setPrintPos(5+222,15+16*6);
ucg.print(settingRAM.hour_heat/(TIME_HOUR/(NUM_SAMPLES*TIME_SCAN_SENSOR)));
print_StrXY(5+10,15+16*7,F("6 Мах температуры in/out"));
ucg.setPrintPos(5+222,15+16*7);
ucg.print((float)settingRAM.tInMax/100,1);
ucg.print(F("/"));
ucg.print((float)settingRAM.tOutMax/100,1);
print_StrXY(5+10,15+16*8,F("7 Мin температуры in/out"));
ucg.setPrintPos(5+222,15+16*8);
ucg.print((float)settingRAM.tInMin/100,1);
ucg.print(F("/"));
ucg.print((float)settingRAM.tOutMin/100,1);
print_StrXY(5+10,15+16*9,F("8 Канал NRF24l01+"));
ucg.setPrintPos(5+222,15+16*9);
ucg.print(NRF24_CHANEL);
print_StrXY(5+10,15+16*10,F("9 Гистерезис T/absH "));
ucg.print((float)dT_OFF/100.0);
ucg.print(F("/"));
ucg.print((float)dH_OFF/100.0);
#ifndef DEMO // Уже места не хватает в DEMO. В DEMO кусок ниже не показывается и код сокращается
print_StrXY(5+10,15+16*11,F("10 ERR Т/Н in:"));
ucg.print(TIN_ERR);
ucg.print(F("/"));
ucg.print(HIN_ERR);
ucg.print(F(" out:"));
ucg.print(TOUT_ERR);
ucg.print(F("/"));
ucg.print(HOUT_ERR);
ucg.drawHLine(40,18+16*11,320-1-80);
ucg.setColor(0, 0, 150);
print_StrXY(5+10,19+16*12,F("СБРОС - Вкл. при нажатой кнопке."));
ucg.setColor(250,80,80);
print_StrXY(5+10,19+16*13,F(VERSION));
#ifdef RADIO // Радио модуль NRF42l вывести число ошибок ask
ucg.setColor(0, 150, 10);
ucg.print(F(" AskErr:"));
ucg.print(err_ask);
#endif
sei();
#endif // Сокращение кода
#ifdef BEEP
beep(40);
#endif
}
void clearInfo() // Стереть информационный экран
{
infoScreen=false;
last_error=100; // Признак обновления ошибки
cli();
ucg.setColor(0, 0, 0); // залить черным
ucg.drawBox(5, 5, 320-1-10, 240-1-10);
print_static();
Setting();
print_data();
printChart();
sei();
}
// Чтение свободной памяти --------------------------------------------------------------------
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
// Чтение внутреннего датчика температуры ---------------------------------------
double GetTemp(void)
{
unsigned int wADC;
double t;
sei(); // Должны быть разрешены прерывания
ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3));
ADCSRA |= _BV(ADEN);
delay(20);
ADCSRA |= _BV(ADSC);
while (bit_is_set(ADCSRA,ADSC));
wADC = ADCW;
t = (wADC - 324.31 ) / 1.22;
return (t);
}
// Чтение напряжения питания ----------------------------------------------
long readVcc() {
long result;
// Read 1.1V reference against AVcc
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = ConstADC / result; // Back-calculate AVcc in mV
return result;
}
// Запись счетчиков в Eeprom --------------------------------------------------
void writeEeprom()
{
cli();
eeprom_write_block((const void*)&settingRAM, (void*) &settingEEPROM, sizeof(settingRAM));
sei();
}
// Чтение счетчиков из Eeprom --------------------------------------------------
void readEeprom()
{
cli();
eeprom_read_block((void*)&settingRAM, (const void*) &settingEEPROM, sizeof(settingRAM));
if ((settingRAM.mode>(NUM_SETTING-1))||(settingRAM.mode<0)) settingRAM.mode=0; // гарантированно попадаем в диапазон
sei();
}
void reset_sum() // Сброс счетчиков накоплений
{
sensors.num=0;
sensors.sum_tOut=0;
sensors.sum_tIn=0;
sensors.sum_relHOut=0;
sensors.sum_relHIn=0;
}
char hex(byte x) // Функция для вывода в hex
{
if(x >= 0 && x <= 9 ) return (char)(x + '0');
else return (char)('a'+x-10);
}
// Сброс дисплея --------------------------------------
bool reset_ili9341(void)
{
pinMode(PIN_RESET, OUTPUT); // Сброс дисплея сигнал активным является LOW
digitalWrite(PIN_RESET, LOW);
delay(100);
digitalWrite(PIN_RESET, HIGH);
ucg.begin(UCG_FONT_MODE_TRANSPARENT);
ucg.setFont(my14x10rus);
// ucg.setRotate90();
ucg.setRotate270();
ucg.clearScreen();
}
#ifdef BEEP
void beep(int x) // Пищать х мсек
{
WritePort(C,1,HIGH);
delay(x);
WritePort(C,1,LOW);
}
#endif
void boot_test(void)
{
int i;
ucg.clearScreen();
ucg.setColor(255, 255, 255);
print_StrXY(10,50,F("Тест вентилятора"));
MOTOR_ON;
for(i=0;i<5;i++)
{
delay(1000);
ucg.print(F(" ."));
}
MOTOR_OFF;
delay(1000);
#if ID == 0x21 // Только у 21 блока установлен нагреватель
ucg.setColor(255, 255, 255);
print_StrXY(10,70,F("Тест нагревателя"));
HEAT_ON;
for(i=0;i<5;i++)
{
delay(1000);
ucg.print(F(" ."));
}
HEAT_OFF;
#endif
ucg.clearScreen();
}
Внимание! Тест обогревателя делается только для id 0х21 (у меня в подвале нет обогревателя 0х22).
Ну какая там схема? Все понятно из назначений пинов в программе.
Спасибо за схему miaua. А то на листочке рисовать не кошерно, а в программу надо осваивать. И в моем понимании надо схему сразу с разводчиком плат (что то типа орла). Но до орла пока руки не доходят.
Thunderix пишет:
Вот смастерил платку. Питание одно на 3.3 вольта. Три дня тестирую вроде все нормально.
Хорошо получилось -)), осталось только откорпусить.
Вопросы по реализации
1. Питание 3.3 Ардуино работает на 8 мГц или разогнали до 16 мГц (такое возможно, но выходит за рамки даташита, может пострадать стабильность)?
2. Источник питания будет встроенный или выносной?
Маленькое замечание. Судя по первой картинке Вы используете мои калибровочные коэффициенты датчиков. Их надо как минимум обнулить, а лучше откалиброваться. Описание процедуры было на второй странице.
BogAD пишет:
Pav2000, твои строки расчета абсолютной влажности из программы:
Почему расходятся - потому что это эмпирическая формула и она может выглядеть поразному. Формула должна описывать определенную кривую. Точной формулы нет.
А смысл использования насыщенног пара. Дополнительный параметр?
BogAD пишет:
И последнее.
На STM32 не рассматривал возможность реализации?
Хочу реализовать на одном камне в гараже сразу на 3 объекта контроля (Гараж, цоколь и погреб)
Имеется Stm32f103rbt6 с 2,8 Tft сенсорным экраном
Осталось добавить связь (если необходимо) и несколько оптореле.
Да и согласование с 3,3В не требуется...
ps От сервомашинок для вращения шибкерных заслонок не хочу отказываться.
Нет на STM32 реализацию не рассмаривал. Хотя сейчас плавно переползаю на maple mini.
Сейчас сделано один объект - один блок. Но есть головное устройство (maple mini) куда стекаются все данные. У меня сейчас работает два блока (подпол и подвал) и на головном блоке можно смотреть оба объекта. В структуре передаваемого пакета есть идентификатор блока.
По мне проще блок сделать чем провода тянуть и надежность повысится. Может ног не хватить.
Уж если портировать то на esp8266 с управлением через web. Но куда эти блоки тогда деть -))
Сейчас тоже думаю для подпола закрытие приточки при выключении вытяжного вентилятора (много тепла выдувает). ИХМО б.у. привод белимо с возвратной пружиной с авито (около 2 тыс рублей) будет интереснее и надежнее чем сервомашинки. Вешать параллельно вентилятору.
stmTime\stmTime.cpp.o: In function `breakTime(unsigned long, tmElements_t&)': C:\Program Files\Arduino\libraries\stmTime/stmTime.cpp:151: multiple definition of `breakTime(unsigned long, tmElements_t&)' stmTime\DateStrings.cpp.o:C:\Program Files\Arduino\libraries\stmTime/DateStrings.cpp:151: first defined here stmTime\stmTime.cpp.o: In function `breakTime(unsigned long, tmElements_t&)': C:\Program Files\Arduino\libraries\stmTime/stmTime.cpp:151: multiple definition of `refreshCache(unsigned long)' stmTime\DateStrings.cpp.o:C:\Program Files\Arduino\libraries\stmTime/DateStrings.cpp:151: first defined here stmTime\stmTime.cpp.o: In function `breakTime(unsigned long, tmElements_t&)': C:\Program Files\Arduino\libraries\stmTime/stmTime.cpp:151: multiple definition of `hour(unsigned long)' stmTime\DateStrings.cpp.o:C:\Program Files\Arduino\libraries\stmTime/DateStrings.cpp:151: first defined here
Добрый день. Та же беда - как вы побороли? У меня список еще длинее.
там было установлено твердотельное реле шарп S202S02
Добрый день!
Подскажите пожалуйста, как правильно подключить данное реле к arduino, я так понял, что управляющее напряжение этого реле 1.2-1.4. Из фотографий устройства я не смог понять.
Добрался до паяльника. Поставил RC цепь на кнопку. После этого кнопка стала работать хорошо.
Почему дребезг контактов не реализован программно? Это ж вроде основа разработки микроэлектроники? Пару-тройку байтов на переменные, конечно, съест, зато цена - условный 0. Можно реализовать нажатие и отпускание, можно оперативно менять период подавления.
Есть у меня градусник Лт-300. Из нескольких штук выбрал самый лучший. с точностью 0.01 градуса в диапазоне от -50 до +150 град. Решил я им дома померить температуру воздеха. На уровне стола она была 25 град. опустил я градусник на 20 см вниз температура изменилась на 0.5 градуса. Поскольку я своему градуснику могу верить решил проверить то же самое с водой в ведре нагретом до 60 град. Там гуляние температуры оказалось еще больше.
Теперь к данной теме.
Вы уверены , что температурный датчик у вас линеен? И всем ли циферкам у вас можно верить? А по влажности еще больше проблем. Если откроем психометричекую таблицу то изменение в показаниях сухого и влажного термометра на 0.5 град. даст нам погрешность по влажности порядка 5 проц. А вы выводите с точностью до 0.01 Это получается что показания могут врать в пределах 500 единиц младшего разряда. Ну обычно так не делают. Выводите температуру для точного термометра с точностью 0.1 град для неточного с точностью 1 град. А влажность так тем более с точностью 1 процент. Ну не может она измеряться более точно простыми датчиками.
Первый абзац повящен неравномерности температуры в объеме. Это понятно и очевидно. Методы получения "правильной" температуры известны или усреднение многих датчиков или размещение датчика где то по середине объема.
Кажется в этой ветке упоминалось порядок размещения датчиков.
Второй абзац это точность датчика. Конечно датчик не может мерить с такой точностью которая выводится, это понятно. Но эту точность можно повысить калибровкой, что было обсуждено. И она с запасом достаточна для задачи.
Разаботан блок для бытового использования. Точность пол градуса сойдет.Главная задача блока уменьшение абсолютной влажности, это обеспечивается гистерезисом включения и выключением блока.
Понимаете округлять мотивируя что есть ошибка тоже не верно, т.к ошибка содержит большую систематическую составляющую.
Здравствуйте!
Для реализации проекта по автоматизации и мониторингу климатических условий (температура, влажность) мы ищем разработчика с опытом. Если Вам интересно - пишите alenka_x@inbox.ru.
Здравствуйте,работаю на этом поприще с 16 лет,ориентируюсь во всех средах и языках программирования.Сейчас интересны проекты на платах Arduino(вся линейка).Портфолио насыщенно сильными и интересными заказами,впрочем, за дело!На данном vlad.spbstu@mail.ru почтовом адресе либо при личной переписке ВК вам будут даны бесплатные консультации по любым интересующимся вам вопросам,не только лично мною,но и моими коллегами,соответственно заказы будут также обрабатываться по мере поступления,вам вскоре будет прислан ответ,и соответственно уже нами произведённый анализ вашего ТЗ , после чего обговаривается условия нашего долгосрочного сотрудничества.
Ждём с нетерпением,готов приступить к выполнению 24/7.
Здравствуйте,работаю на этом поприще с 16 лет,ориентируюсь во всех средах и языках программирования.Сейчас интересны проекты на платах Arduino(вся линейка).Портфолио насыщенно сильными и интересными заказами,впрочем, за дело!На данном vlad.spbstu@mail.ru почтовом адресе либо при личной переписке ВК вам будут даны бесплатные консультации по любым интересующимся вам вопросам,не только лично мною,но и моими коллегами,соответственно заказы будут также обрабатываться по мере поступления,вам вскоре будет прислан ответ,и соответственно уже нами произведённый анализ вашего ТЗ , после чего обговаривается условия нашего долгосрочного сотрудничества.
Ждём с нетерпением,готов приступить к выполнению 24/7.
Ну выложите интересный проэкт подобного направления. Вам 17 лет? Пока это только слова рекламы. И не флудите в чужих темах.
Дали бы хоть начало листинга, хоть до строки на которую на первую ругается. Почему вообще не ограничиться просто, -- здравствуйте, у меня не компилируется проект, скажите почему. --
вы подключили библиотеку (#include "DHT.h")?
покажите строку, в которой вы рассказываете, на каком пине ваш датчик (DHT dht(DHTPIN, DHTTYPE);)
// Connect pin 1 (on the left) of the sensor to +5V
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
// to 3.3V instead of 5V!
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor
// Initialize DHT sensor.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors. This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs. DHT dht(DHTPIN, DHTTYPE);
Не вникал, топик читал год назад, на что обратил внимание - выделил жирным
Доброго времени суток, уважаемые мастера! Подскажите какие модули небходимы для реализации проекта: контроль температуры в помещении и передача данных по радиоканалу (wi-fi) на ПК (сервер). Первый пункт собрал на ардуино нано 3 с dht12. А вот какой модуль для передачи данных и как это все прикрутить? Подскажите начинающему. Заранее благодарен.
Нам нужно или сделать или организовать изготовление аналогичной установки. С Вас программная часть и его отладка. Просим Вас помочь. Работа оплачиваемая. Пишите 9217175@gmail.com/
Здравствуйте. Хочу предложить Вам вынести все шрифты и текстовые константы, а так же данные ЕЕПРОМ во внешнюю ЕЕПРОМ большего объема. Например 24lc256. Подгружаться данные бelen непосредственно перед использованием в массив 32 байта. Что очень экономит место как на самой флешь контроллера, так и оперативку. Адреса начала констант по #define. Будет марока с планированием памяти и записью всего объема в ЕЕПРОм при прошивке , но при работе программы сложностей нет.
Приведу пример кода где это используется.
#include <Wire.h>
#include <DallasTemperature.h>
#include <SoftwareSerial.h>
#include "RTClib.h"
#include <MsTimer2.h>
#define EEPROM_I2C 0x50 // Адрес памяти 24LC256
#define MASTER "+79635431264"
// 0-1 Для подключения компьютера или синезуба. Управление и диагностика.
#define DS18B20 2
#define PLAY 3
#define VOX_OFF 4
#define CH_UP1 5
#define CH_DN1 6
#define MAIN_POWER 7
#define M_RX 8
#define M_TX 9
#define OPEN_DET 10
#define RELAY_1 11
#define BATTERY A1
// 18-19 i2c RTC для определения времени.
// now.dayOfTheWeek() 6 и 7 выходные дни.
// DateTime now = rtc.now();
// Разбивка ЕЕПРОМ
#define ALARM_TEMP 1 // 4
#define LOW_TEMP 5 // 4
#define ATI 64 // 3 ATI
#define CSQ 67 // 6 AT+CSQ
#define CLIP 73 // 9 AT+CLIP=1
#define CMGF 82 // 9 AT+CMGF=1
#define CSCS 91 // 13 AT+CSCS="GSM"
#define CNMI 104 // 11 AT+CNMI=2,2
#define PB 115 // 8 +PBREADY
#define CMT 126 // 4 +CMT
#define CMGS 130 // 9 AT+CMGS="
#define CMGS1 140 // 1 "
#define CUSD 141 // 9 AT+CUSD=1
#define ATD 150 // 3 ATD
#define CMGD 153 // 11 AT+CMGD=0,4
#define CSQ1 168 // 4 +CSQ
#define RING 172 // 4 RING
#define INFO 176 // 4 info
#define BALANCE 180 // 5 #105#
#define MOVE 185 // 4 move
#define MAX_TEMP 189 // 8 maxtemp:
#define MIN_TEMP 197 // 8 mintemp:
#define MSG1 205 // 17 Couldn't find RTC
#define MSG2 222 // 22 Find RTC, start timing
#define INIT_MODEM 1047 // 11 INIT MODEM
// ------------------------------------------------------------
SoftwareSerial mGSM(M_RX, M_TX); // Цепляем софт UART для модема на пины
OneWire oneWire(DS18B20); // Цепляем датчик температуры
DallasTemperature ds(&oneWire); // -//-
RTC_DS1307 rtc; // Цепляем часики
DateTime now; // Тут данные с часиков
boolean MAIN_POWER_FLAG = true;
boolean LOW_BATTERY_FLAG = true;
boolean OPEN_FLAG = true;
boolean TEMP_FLAG = true;
int voltage;
int ch = 0;
String val = "";
unsigned char rdata[32];
float temperature;
void setup() {
// while (!Serial); // for Leonardo/Micro/Zero
analogReference(EXTERNAL); // Опорное будет 2,5в с TL431.
Serial.begin(9600);
mGSM.begin(9600);
pinMode(PLAY, OUTPUT);
pinMode(VOX_OFF, OUTPUT);
pinMode(CH_UP1, OUTPUT);
pinMode(CH_DN1, OUTPUT);
pinMode(RELAY_1, OUTPUT);
pinMode(OPEN_DET, INPUT);
pinMode(MAIN_POWER, INPUT);
while (!rtc.begin()) {
readEEPROM(EEPROM_I2C, MSG1, rdata, 17);
Serial.println((char*)rdata);
memset(rdata, 0, sizeof(rdata));
_delay_ms(2000);
}
ds.begin();
MsTimer2::set(60000, get_interupt); // 1 min period
MsTimer2::start();
readEEPROM(EEPROM_I2C, MSG2, rdata, 22);
Serial.println((char*)rdata);
memset(rdata, 0, sizeof(rdata));
_delay_ms(1000);
initModem();
get_interupt();
// Получаем напряжение
detect_low_power();
}
void loop() {
detect_power_off();
detect_low_power();
detect_uart();
detect_open();
}
// ----------- Получение текущего времени и температуры-----
void get_interupt() {
now = rtc.now();
ds.requestTemperatures();
temperature = ds.getTempCByIndex(0);
Serial.println(F("Temp: "));
Serial.println(temperature);
}
//-----------------------------------------------------------
void detect_open() {
if (digitalRead(OPEN_DET) == HIGH && OPEN_FLAG == false)
{
// тут отправка SMS
sms(F("OTKRITIE KRISHKI!!!"), MASTER);
}
if (digitalRead(OPEN_DET) == LOW && OPEN_FLAG == true)
{
OPEN_FLAG = false;
}
}
void detect_temp() {
char str;
readEEPROM(EEPROM_I2C, ALARM_TEMP, rdata, 4);
str = (char*)rdata;
if (temperature > ((float)str) && TEMP_FLAG == false) {
sms("Visokaya temperatura!", MASTER);
TEMP_FLAG = true;
}
memset(rdata, 0, sizeof(rdata));
readEEPROM(EEPROM_I2C, LOW_TEMP, rdata, 4);
str = (char*)rdata;
if (temperature < ((float)str) && TEMP_FLAG == true)
TEMP_FLAG = false;
str = "";
memset(rdata, 0, sizeof(rdata));
}
void detect_power_off() {
// --------- Проверка питания от сети --------------------
if (digitalRead(MAIN_POWER) == LOW && MAIN_POWER_FLAG == false)
{
// тут отправка SMS
sms(F("OTKLUCHENIE PITANIYA!!!"), MASTER);
}
if (digitalRead(MAIN_POWER) == HIGH && MAIN_POWER_FLAG == true)
{
MAIN_POWER_FLAG = false;
}
}
// -------------------------------------------------------
//--------- Определить состояние питания батареи ------------
void detect_low_power() {
voltage = analogRead(A1);
map(voltage, 0, 1023, 0, 4.2);
// Проверяем питание, устанавливаем флаг
if (digitalRead(MAIN_POWER) == HIGH) {
MAIN_POWER_FLAG = false;
} else {
MAIN_POWER_FLAG = true;
if (voltage < 3.1 && LOW_BATTERY_FLAG == false) {
LOW_BATTERY_FLAG = true;
sms(F("NIZKIY ZARYAD!!!"), MASTER);
}
if (voltage > 3.1 && LOW_BATTERY_FLAG == true) {
LOW_BATTERY_FLAG = false;
}
}
}
//-----------------------------------------------------------
//--------------- Инициализация модема ----------------------
void initModem() {
readEEPROM(EEPROM_I2C, INIT_MODEM, rdata, 11);
Serial.println((char*)rdata);
memset(rdata, 0, sizeof(rdata));
readEEPROM(EEPROM_I2C, ATI, rdata, 3);
mGSM.println((char*)rdata);
memset(rdata, 0, sizeof(rdata));
_delay_ms(100);
readEEPROM(EEPROM_I2C, CSQ, rdata, 6);
mGSM.println((char*)rdata);
memset(rdata, 0, sizeof(rdata));
_delay_ms(100);
readEEPROM(EEPROM_I2C, CLIP, rdata, 9);
mGSM.println((char*)rdata);
memset(rdata, 0, sizeof(rdata));
_delay_ms(100);
readEEPROM(EEPROM_I2C, CMGF, rdata, 9);
mGSM.println((char*)rdata);
memset(rdata, 0, sizeof(rdata));
_delay_ms(100);
readEEPROM(EEPROM_I2C, CSCS, rdata, 13);
mGSM.println((char*)rdata);
memset(rdata, 0, sizeof(rdata));
_delay_ms(100);
readEEPROM(EEPROM_I2C, CNMI, rdata, 11);
mGSM.println((char*)rdata); //отображение смс в терминале сразу после приема (без этого сообщения молча падают в память) "AT+CNMI=2,2"
memset(rdata, 0, sizeof(rdata));
}
//-------------------------------------------------------------
/*
Очистка СМС на модеме
*/
void clearsms() {
readEEPROM(EEPROM_I2C, CMGD, rdata, 11);
mGSM.println((char*)rdata);
memset(rdata, 0, sizeof(rdata));
}
/*
Функция постраничного чтения строк в EEPROM 24LC256
*/
void readEEPROM(int deviceaddress, unsigned int eeaddress,
unsigned char* data, unsigned int num_chars)
{
unsigned char i = 0;
Wire.beginTransmission(deviceaddress);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(deviceaddress, num_chars);
while (Wire.available()) data[i++] = Wire.read();
}
/*
Функция 1 байтовой записи в EEPROM 24LC256
*/
void writeEEPROMbyte(int deviceaddress, unsigned int eeaddress, byte data )
{
Wire.beginTransmission(deviceaddress);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.write(data);
Wire.endTransmission();
_delay_ms(6);
}
byte readEEPROMbyte(int deviceaddress, unsigned int eeaddress )
{
byte rdata = 0xFF;
Wire.beginTransmission(deviceaddress);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(deviceaddress, 1);
if (Wire.available()) rdata = Wire.read();
return rdata;
}
/*
Функция отправки СМС
*/
void sms(String text, String phone) //процедура отправки СМС
{
readEEPROM(EEPROM_I2C, CMGS, rdata, 9);
mGSM.println((char*)rdata);
mGSM.print(phone);
memset(rdata, 0, sizeof(rdata));
readEEPROM(EEPROM_I2C, CMGS1, rdata, 1);
mGSM.println((char*)rdata);
memset(rdata, 0, sizeof(rdata));
_delay_ms(500);
mGSM.print(text);
_delay_ms(500);
mGSM.print((char)26);
_delay_ms(1000);
}
void detect_uart() {
if (mGSM.available()) { //есть данные от GSM модуля
_delay_ms(200); //выждем, чтобы строка успела попасть в порт целиком раньше чем будет считана
while (mGSM.available()) { //сохраняем входную строку в переменную val
ch = mGSM.read();
val += char(ch);
_delay_ms(10);
}
Serial.println(val); // дублируем сообщение в терминал
readEEPROM(EEPROM_I2C, PB, rdata, 8);
if (val.indexOf((char*)rdata) > -1) initModem(); // Если модем вдруг ребутнулся - проинициализируем снова.
memset(rdata, 0, sizeof(rdata)); // Стираем массив
/* ----- определение факта приема СМС и сравнение номера(ов) с заданным(и)*/
readEEPROM(EEPROM_I2C, CMT, rdata, 4);
if (val.indexOf((char*)rdata) > -1) { //если обнаружен СМС (для определения звонка вместо "+CMT" вписать "RING")
memset(rdata, 0, sizeof(rdata)); // Стираем массив
if (val.indexOf(MASTER) > -1) { //если СМС от хозяина
// Сообщение от нашего номера
readEEPROM(EEPROM_I2C, INFO, rdata, 4);
if (val.indexOf((char*)rdata) > -1) { // если обнаружено кодовое слово info
memset(rdata, 0, sizeof(rdata));
info(); // дествия при обнаружении ключевого info
}
// тут другие условия
} else {
// Сообщение не от нашего номера
}
//----------------------- поиск кодового слова в СМС (вообще эту часть надо поместить внутрь предыдущей, но если использовать кодовое слово не совпадающее с сообщениями модема, то не обязательно)
val = ""; // стираем буфер
}
}
}
void info() {
}
Всем привет.
Проект реально затрагивает за живое... Для многих эта тема актуальна.
Виноват. Возможно, кто-нибудь из Вас может показать принципиальную схему для полноты изложенного? Ну, чтобы "архив для потомков был полным" :)
Заранее спасибо.
Не подскажите может есть кокой секрет, но мне не удается запустить сразу и NRF и дисплей ISP TFT вот для примера скетч простой
по отдельности все работает как только в скетч совмещаю так все экран не показывает ((
У Вас nrf использует аппаратный SPI (это зашито в библиотеке) с ногами 11 12 13.
А дисплей у Вас использует програмный SPI (Ваша строка инициализации
Ucglib_ILI9341_18x240x320_SWSPI ucg(
/*sclk=*/
13,
/*data=*/
11,
/*cd=*/
9 ,
/*cs=*/
10,
/*reset=*/
8);
) и тоже с ногами 11 13. Как то не красиво получается. На одних ногах живуи разные SPI.Замените для дисплея инициализацию Ucglib_ILI9341_18x240x320_HWSPI ucg(/*cd=*/PIN_CD, /*cs=*/PIN_CS, /*reset=*/PIN_RESET); // Аппаратный SPI на дисплей ILI9341 ) и проверьте соответсвие ног.
Должно заработать
я пробовал вашу строку со своими пинами, в обще дисплей не работает да же без кода nrf да и с этой строкой пины 11,13 все равно останутся как у nrf я пересадил все пины со своей срокой на другие, заработало но жутко тормозит отрисовка на дисплее и код весь из за этого.
я пробовал вашу строку со своими пинами, в обще дисплей не работает да же без кода nrf да и с этой строкой пины 11,13 все равно останутся как у nrf я пересадил все пины со своей срокой на другие, заработало но жутко тормозит отрисовка на дисплее и код весь из за этого.
1. Тормозит дисплей потому что программный spi.
2. У Вас дисплей подключен через преобразователь уровней (резисторы)? У меня сначал была микросхема и работал только программный spi я поменял на резисторы и все зарабоатло . Только на дисплей.
3. Общие пины 11 12 13 на хард spi допустимы (так и задумывалось, протокол позволяет вешать несколько приемников на одну шину) , главное что бы пины CS CD были разные и библиотека корректно с ними работала.
4. Нобходимо добится работы отдельно дисплея с моей строкой и моими ногами. Может перепутаны ноги для дисплея cs и cd?
А потом подключить nrf
2 у меня подключен по через резисторы 10к вот по такой схеме http://1.bp.blogspot.com/-0Zmb2xr-uEI/U8ZCaSnNQEI/AAAAAAAAMEE/eeV1dRPckL...
может из за этого и не работает апаратный spi, а пока жду такие http://ru.aliexpress.com/item/1PCS-IIC-I2C-Logic-Level-Converter-Bi-Dire...
Я такие преобразователи покупал, а потом плюнул и переделал всё на 3.3 вольта.
2 у меня подключен по через резисторы 10к вот по такой схеме http://1.bp.blogspot.com/-0Zmb2xr-uEI/U8ZCaSnNQEI/AAAAAAAAMEE/eeV1dRPckLs/s1600/schema_conectare_ILI9341_Arduino_ver1m0.png
может из за этого и не работает апаратный spi, а пока жду такие http://ru.aliexpress.com/item/1PCS-IIC-I2C-Logic-Level-Converter-Bi-Directional-Module-5V-to-3-3V/32417113805.html
Мне поледовательные резисторы не нравятся, как то сремно. У меня сделано вот так
"Для согласования уровней 5 вольт ардуино и дисплея используются делители из резисторов 2к+4к. Согласвоания уровне й для nrf24 не требуется."
И еще возможно заказаные детали не помогут (скорости у spi гораздо выше чем у i2c. Фронты будут выглядеть очень страшно)
Почитайте http://forum.arduino.cc/index.php?topic=181679.120 там на картинке все нарисовано.
еще вариант http://dangerousprototypes.com/2015/07/28/2-2-or-2-4-or-2-8-inch-spi-tft... только номиналы резисторов мне не нравятся
"Для согласования уровней 5 вольт ардуино и дисплея используются делители из резисторов 2к+4к. Согласвоания уровне й для nrf24 не требуется."
И еще возможно заказаные детали не помогут (скорости у spi гораздо выше чем у i2c. Фронты будут выглядеть очень страшно)
Почитайте http://forum.arduino.cc/index.php?topic=181679.120 там на картинке все нарисовано.
еще вариант http://dangerousprototypes.com/2015/07/28/2-2-or-2-4-or-2-8-inch-spi-tft... только номиналы резисторов мне не нравятся
хорошо когда резисторы есть (((( у меня в наличии есть 1к, 4.7к, 10к, 100к и так если я возьму два подряд 1к получу 2к, а вот место 4к можно взять 4.7к ??
Можно 1+1 и 4.7 к
Или 1 и 1 к если паять линиво. Тоже должно получиться. Нужно спаять 5 делителей
pav2000 боюсь спросить, когда будет сервер с етхернетом?, Пора запчастюлички покупать.
Можно 1+1 и 4.7 к
Или 1 и 1 к если паять линиво. Тоже должно получиться. Нужно спаять 5 делителей
Попробовал так и так, оба варианта работают, то есть диплей аппарантно работает.
Но тормоза остались просто жуть вот этот код исполняется 6 секунд
и ещё вопрос как вы столько много кода запехнули в про мини? у меня только вот это занимает 30кб из 32кб ((( да же шрифт не сменить на более большой не влезает просто
1. По скорости.
Я использую библиотеку не ПОЗНЕЕ 1.01. В более старших версиях изменен механизм вывода шрифта - применяют сжатие при хранении - места меньше скорость меньше. Я не использовал функцию
SetScale2x2.
У меня тоже вывод не быстр но не 6 секунд. Для проверки залейте скейчт из этой ветки и оцените скорость.
2. По месту - особого криминала не вижу. Я не пользовался библиотекой часов, может она много места занимает. Отключайте отдельные куски и выясните что жрет место. Дисплей съедает 10-12 кБ радио 2-3 кб начальный код 2 кБ. Так я выяснил что sprintf съедает 12-15 кБ места.
Возможно подгружает лишние шрифты (хотя этого не должно быть)
3. Разработка сетевого головного блока. К сожалению времени сейчас не много, плюс еще есть проекты. Для меня сейчас главным проектом являетя блок контроля за тепловым насосом (сейчас его в основном пилю). Но про головной блок не забыл. Уже все спаял и откорпусил, освоил рисование графиков. Сейчас размышляю как наиболее правильно хранить html код в программе. Для затравки картинка (на значения не смотрим так демо работает):
4. В новогодние каникулы у нас стояли морозы (до -25). Наконец прикрутил твердотельное реле на обогреватель. А то в погребе температура была близак +2. У у меня там домашние заготовки и картошка хранится. Как оказалось, во время-)).
При подключении обогревателя понял что немного надо доработать код - при включении блока добавить проверку физической работы вентилятора и обогревателя, что бы пользователь убедился в их работоспособности. Код добавил и выкладываю.
Внимание! Тест обогревателя делается только для id 0х21 (у меня в подвале нет обогревателя 0х22).
Привет. Проект действительно шикарный! Но вот такая просьба,
раз уж он в таких муках рождался с тяжелой отладкой и настройкой,
нельзя ли хоть на эскизик схемы взгянуть?
Ну какая там схема? Все понятно из назначений пинов в программе.
Вот такая ...
Вот смастерил платку. Питание одно на 3.3 вольта. Три дня тестирую вроде все нормально.
РЕСПЕКТ за проект!
Давно мысля мучает реализовать сие устройство, но...нет практики программирования МК.
Можно нетоторые воросы по проекту?
Pav2000, твои строки расчета абсолютной влажности из программы:
Хочу реализовать на одном камне в гараже сразу на 3 объекта контроля (Гараж, цоколь и погреб)
Ну какая там схема? Все понятно из назначений пинов в программе.
Спасибо за схему miaua. А то на листочке рисовать не кошерно, а в программу надо осваивать. И в моем понимании надо схему сразу с разводчиком плат (что то типа орла). Но до орла пока руки не доходят.
Вот смастерил платку. Питание одно на 3.3 вольта. Три дня тестирую вроде все нормально.
Хорошо получилось -)), осталось только откорпусить.
Вопросы по реализации
1. Питание 3.3 Ардуино работает на 8 мГц или разогнали до 16 мГц (такое возможно, но выходит за рамки даташита, может пострадать стабильность)?
2. Источник питания будет встроенный или выносной?
Маленькое замечание. Судя по первой картинке Вы используете мои калибровочные коэффициенты датчиков. Их надо как минимум обнулить, а лучше откалиброваться. Описание процедуры было на второй странице.
Pav2000, твои строки расчета абсолютной влажности из программы:
Интересует, почему не использовать понятие "давление насыщенного пара". Я даже гратик проинтерполировал...
Хочу реализовать на одном камне в гараже сразу на 3 объекта контроля (Гараж, цоколь и погреб)
1. Ардуино про 16 мгц. Перепрошил загрузчик и пины. Работает на 3.3 вольта. Проверяю стабильность еще не зависал ни разу.
2. Источник питания будет встроенный.
Калибровками еще не игрался т.к. силовую часть еще не доделал, заодно датчики "приработаются".
Не компилица чтото.
stmTime\stmTime.cpp.o: In function `breakTime(unsigned long, tmElements_t&)': C:\Program Files\Arduino\libraries\stmTime/stmTime.cpp:151: multiple definition of `breakTime(unsigned long, tmElements_t&)' stmTime\DateStrings.cpp.o:C:\Program Files\Arduino\libraries\stmTime/DateStrings.cpp:151: first defined here stmTime\stmTime.cpp.o: In function `breakTime(unsigned long, tmElements_t&)': C:\Program Files\Arduino\libraries\stmTime/stmTime.cpp:151: multiple definition of `refreshCache(unsigned long)' stmTime\DateStrings.cpp.o:C:\Program Files\Arduino\libraries\stmTime/DateStrings.cpp:151: first defined here stmTime\stmTime.cpp.o: In function `breakTime(unsigned long, tmElements_t&)': C:\Program Files\Arduino\libraries\stmTime/stmTime.cpp:151: multiple definition of `hour(unsigned long)' stmTime\DateStrings.cpp.o:C:\Program Files\Arduino\libraries\stmTime/DateStrings.cpp:151: first defined here
Добрый день. Та же беда - как вы побороли? У меня список еще длинее.
Я отключил эту библиотеку и усё.
Отлично. Все получилось. Проект отличный, но есть пара вопросов к спецам:
1.На каком питании стоит остановиться 5 или 3,3В.
2.есть ли у кого схема в более крупном масштабе.
Заранее спасибо.
1. Разницы я не обнаружил.
2. Я схему не рисовал. Она вся в скетче есть.
Добрый день!
Подскажите пожалуйста, как правильно подключить данное реле к arduino, я так понял, что управляющее напряжение этого реле 1.2-1.4. Из фотографий устройства я не смог понять.
Спасибо!
Ловите : http://www.mikrocontroller.net/topic/214135
И почитайте где-то как задают ток через диоды ( про закон Ома)
Ловите : http://www.mikrocontroller.net/topic/214135
И почитайте где-то как задают ток через диоды ( про закон Ома)
Спасибо, это видел, но как то не доверился, похоже достаточно сопротивления на 330-390 Ом.
Тут через 1кОм подключают:
http://hobby-experiment.blogspot.ru/2014/08/sso-1-solid-state-ac-outlet....
Добрался до паяльника. Поставил RC цепь на кнопку. После этого кнопка стала работать хорошо.
Почему дребезг контактов не реализован программно? Это ж вроде основа разработки микроэлектроники? Пару-тройку байтов на переменные, конечно, съест, зато цена - условный 0. Можно реализовать нажатие и отпускание, можно оперативно менять период подавления.
Маленький вопрос , если можно.
Есть у меня градусник Лт-300. Из нескольких штук выбрал самый лучший. с точностью 0.01 градуса в диапазоне от -50 до +150 град. Решил я им дома померить температуру воздеха. На уровне стола она была 25 град. опустил я градусник на 20 см вниз температура изменилась на 0.5 градуса. Поскольку я своему градуснику могу верить решил проверить то же самое с водой в ведре нагретом до 60 град. Там гуляние температуры оказалось еще больше.
Теперь к данной теме.
Вы уверены , что температурный датчик у вас линеен? И всем ли циферкам у вас можно верить? А по влажности еще больше проблем. Если откроем психометричекую таблицу то изменение в показаниях сухого и влажного термометра на 0.5 град. даст нам погрешность по влажности порядка 5 проц. А вы выводите с точностью до 0.01 Это получается что показания могут врать в пределах 500 единиц младшего разряда. Ну обычно так не делают. Выводите температуру для точного термометра с точностью 0.1 град для неточного с точностью 1 град. А влажность так тем более с точностью 1 процент. Ну не может она измеряться более точно простыми датчиками.
А почему СТРОЕМ не ходите :)
Первый абзац повящен неравномерности температуры в объеме. Это понятно и очевидно. Методы получения "правильной" температуры известны или усреднение многих датчиков или размещение датчика где то по середине объема.
Кажется в этой ветке упоминалось порядок размещения датчиков.
Второй абзац это точность датчика. Конечно датчик не может мерить с такой точностью которая выводится, это понятно. Но эту точность можно повысить калибровкой, что было обсуждено. И она с запасом достаточна для задачи.
Разаботан блок для бытового использования. Точность пол градуса сойдет.Главная задача блока уменьшение абсолютной влажности, это обеспечивается гистерезисом включения и выключением блока.
Понимаете округлять мотивируя что есть ошибка тоже не верно, т.к ошибка содержит большую систематическую составляющую.
Как то так.
Здравствуйте!
Для реализации проекта по автоматизации и мониторингу климатических условий (температура, влажность) мы ищем разработчика с опытом. Если Вам интересно - пишите alenka_x@inbox.ru.
Ну выложите интересный проэкт подобного направления. Вам 17 лет? Пока это только слова рекламы. И не флудите в чужих темах.
Здравствуйте! Не компилится проект, выдает ошибки:
Здравствуйте! Не компилится проект, выдает ошибки:
Дали бы хоть начало листинга, хоть до строки на которую на первую ругается. Почему вообще не ограничиться просто, -- здравствуйте, у меня не компилируется проект, скажите почему. --
вы подключили библиотеку (#include "DHT.h")?
покажите строку, в которой вы рассказываете, на каком пине ваш датчик (DHT dht(DHTPIN, DHTTYPE);)
Добрый день! Тоже не компилируется. .Выложил ссылку на скрин.Помогите,не могу понять в чем дело. Не компилируется DHT
https://yadi.sk/i/9qFQV5QqxTtHL
Кто нибудь дайте переработанную библиотеку DHT,А то по ходу у меня из за нее не компилируется
HELP!!!Не компилируется. Дайте ссылку на правильную библиотеку DHT
#include "DHT.h"
#define DHTPIN 2 // what digital pin we're connected to
// Uncomment whatever type you're using!
//#define DHTTYPE DHT11 // DHT 11
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
// Connect pin 1 (on the left) of the sensor to +5V
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
// to 3.3V instead of 5V!
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor
// Initialize DHT sensor.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors. This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs.
DHT dht(DHTPIN, DHTTYPE);
Не вникал, топик читал год назад, на что обратил внимание - выделил жирным
На перевый взгляд, думаю это дисплей такой: https://www.itead.cc/display/nextion.html
Это не такой дисплей, используется простой дисплей 2.8 дюйма на чипе ili9341. Со spi выходом.
Библиотека днт вроде стандартная. Ничего не дорабатывал в ней.
Доброго времени суток, уважаемые мастера! Подскажите какие модули небходимы для реализации проекта: контроль температуры в помещении и передача данных по радиоканалу (wi-fi) на ПК (сервер). Первый пункт собрал на ардуино нано 3 с dht12. А вот какой модуль для передачи данных и как это все прикрутить? Подскажите начинающему. Заранее благодарен.
Для передачи по вай-фай - ESP-8266.
Для измерения температуры и её передачи достаточно одного этого модуля, нано будет лишним.
Спасибо, но данного модуля нет в FLProg. Как его программировать?
Спасибо, но данного модуля нет в FLProg. Как его программировать?
Попробуйте начать с этого:
https://esp8266.ru/arduino-ide-esp8266/
Здравствуйте.
Нам нужно или сделать или организовать изготовление аналогичной установки. С Вас программная часть и его отладка. Просим Вас помочь. Работа оплачиваемая. Пишите 9217175@gmail.com/
Спасибо
Здравствуйте. Хочу предложить Вам вынести все шрифты и текстовые константы, а так же данные ЕЕПРОМ во внешнюю ЕЕПРОМ большего объема. Например 24lc256. Подгружаться данные бelen непосредственно перед использованием в массив 32 байта. Что очень экономит место как на самой флешь контроллера, так и оперативку. Адреса начала констант по #define. Будет марока с планированием памяти и записью всего объема в ЕЕПРОм при прошивке , но при работе программы сложностей нет.
Приведу пример кода где это используется.
По моему уже пора на https://geektimes.ru/post/277928/ переходить,
не нужно колхозить с уровнями напряжений и памяти хватит на расширение проекта
цена 2 бакса
Код не компелируется ругается на dht.h, делаеш его с большей буквы DHT, новые ошибки сыпяться, где копать?
Добрый день. Есть ли что то подобное работающие на одной ардуино и на 2 или 4 строчном десплее