Cистема климат-контроля "madBCC1.1"

 madBath

У меня на даче батя отгрохал здоровенный трехэтажный дом с тремя туалетами и двумя ванными душевыми комнатами. Вторую душевую обычно используют "дачники", которые арендуют у родителей пару помещений, а в основной душевой есть одна злоебучая проблема, которая меня просто, сука, бесит. Каждый раз после умывания там надо щелкать специальной кнопочкой, чтобы включить вентилятор, удаляющий лишнюю влагу, если забыть то потом можно получить "леща" за невнимательность. Мне каждый раз ужасно лень тыкать эту чертову кнопку и, тем более, держать такие вещи в уме. Короче, настопиздело. Решил сделать плату на основе микроконтроллера Attiny85, которая будет следить за температурой и влажностью сама. Я уже занимался системами климат-контроля для выращивания грибочков, так что здесь у меня уже проторенная дорожка... Но, все же, это уже новый уровень, не какой-нибудь деребас, собранный из говна и палок, а реально коммерческий продукт, изготовленный на китайском заводе по мому PCB-проекту.

madBathPCB

Мне почему-то ужасно лень рисовать электронные схемы, я обычно начинаю с рисунка платы. Схему доделаю потом, в ходе программирования. Это будет необходимо сделать, поскольку в ходе производства и доставке прошло столько времени, что я уже забыл, как там все устроено, и чтобы не путаться при написании программы, лучше будет все-таки озадачиться данным вопросом.

Как всегда, после изготовления платы, едва ее получил, сразу же заметил косяки. Резистор R3 оказался лишним. По идее, это должна была быть часть системы перезагрузки микроконтроллера или система установки нормы температуры и влажности, которая будет задана исходя из данных с датчика, актуальных на момент нажатия кнопки. Я, конечно, уже не помню где подглядел такую схему, но тут явно косяк. Возможно, эта часть придумывалась с бодуна. Кроме того, конкретно здесь отсутствует "декап", то есть, фильтрующие конденсаторы по питанию, а так же подпись 16A не соответствует действительности. Надеюсь, эта плата не попадет в руки дураку, который поймет ее буквально и подключит такую нагрузку... Хоть компоненты и рассчитаны на такой ток, но дорожки слишком узкие и будут сильно греться. Здесь при 3-х Амперах будет повышение температуры 20 градусов Цельсия при комнатной температуре 20. В пределах 2-х Ампер можно вообще не париться.  Теоретически, если обеспечить достаточное охлаждение, то можно подключить что-нибудь мощное, но я не бы не советовал, мягко говоря. В крайнем случае, если уж очень надо, в качестве промежуточного звена между силовой нагрузкой и модулем можно использовать контакторы или реле.

Ну и вот я накатал программку... Такой прикол: пытался сделать ее под новый год - и нихрена не получилось. А тут, уже летом, с утра сел и накатал быстренько еще до обеда:

/*
ATtiny85 +--------+ Reset/ PB5 -|1 8 |- Vcc (ADC0) PB3 -|2 7 |- PB2 (SCK/ADC1/T0) (ADC3) PB4 -|3 6 |- PB1 (MISO/OC0B/INT0/PCINT1) GND -|4 5 |- PB0 (MOSI/DI/SDA/OC0A/AREF/PCINT0) +--------+ */ #define F_CPU 8000000UL #include <avr/io.h> #include <util/delay.h> #include #define SOFT_UART_TX_PIN PB4 // Определения для программного UART #define SOFT_UART_BAUDRATE 9600 #define SOFT_UART_DELAY (104) // Задержка в микросекундах для 9600 бод //#define R1 PB4 #define R2 PB3 #define DHT11_PIN PB2 // Определение для DHT11 #define SET_BIT(PORT, PIN) (PORT |= (1 << PIN)) #define CLEAR_BIT(PORT, PIN) (PORT &= ~(1 << PIN)) uint8_t temperature = 0, humidity = 0; char temperatureStr[6]; char humidityStr[6]; // Преобразование числа в строку char* itoa(int value, char* str, int base) { char* rc; char* ptr; char* low; static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; if (base < 2 || base > 36) { *str = '\0'; return str; } rc = ptr = str; if (base == 10 && value < 0) { *ptr++ = '-'; value = -value; } low = ptr; do { *ptr++ = digits[value % base]; value /= base; } while (value); *ptr-- = '\0'; while (low < ptr) { char tmp = *low; *low++ = *ptr; *ptr-- = tmp; } return rc; } // Инициализация программного UART void soft_uart_init(void) { DDRB |= (1 << SOFT_UART_TX_PIN); // Настроить TX_PIN как выход PORTB |= (1 << SOFT_UART_TX_PIN); // Установить TX_PIN в высокий уровень } // Функция для отправки одного байта по программному UART void soft_uart_send_byte(uint8_t byte) { // Стартовый бит CLEAR_BIT(PORTB, SOFT_UART_TX_PIN); _delay_us(SOFT_UART_DELAY); // Отправка данных for (uint8_t i = 0; i < 8; ++i) { if (byte & (1 << i)) { SET_BIT(PORTB, SOFT_UART_TX_PIN); } else { CLEAR_BIT(PORTB, SOFT_UART_TX_PIN); } _delay_us(SOFT_UART_DELAY); } // Стоповый бит SET_BIT(PORTB, SOFT_UART_TX_PIN); _delay_us(SOFT_UART_DELAY); } // Функция для отправки строки по программному UART void soft_uart_send_string(const char* str) { while (*str) { soft_uart_send_byte(*str++); } } // Чтение данных с DHT11 void DHT11_start() { DDRB |= (1 << DHT11_PIN); // Настроить DHT11_PIN как выход PORTB &= ~(1 << DHT11_PIN); // Потянуть линию вниз _delay_ms(18); // Держим линию вниз не менее 18 мс PORTB |= (1 << DHT11_PIN); // Потянуть линию вверх _delay_us(20); // Ждем 20-40 мкс DDRB &= ~(1 << DHT11_PIN); // Настроить DHT11_PIN как вход } uint8_t DHT11_check_response() { _delay_us(40); if (!(PINB & (1 << DHT11_PIN))) { _delay_us(80); if (PINB & (1 << DHT11_PIN)) { _delay_us(40); return 1; } } return 0; } uint8_t DHT11_read_byte() { uint8_t data = 0; for (int i = 0; i < 8; i++) { while (!(PINB & (1 << DHT11_PIN))); // Ждем пока линия не станет высокой _delay_us(30); if (PINB & (1 << DHT11_PIN)) { data |= (1 << (7 - i)); } while (PINB & (1 << DHT11_PIN)); // Ждем пока линия не станет низкой } return data; } void DHT11_read(uint8_t* temperature, uint8_t* humidity) { DHT11_start(); if (DHT11_check_response()) { *humidity = DHT11_read_byte(); DHT11_read_byte(); // Пропустить второй байт влажности *temperature = DHT11_read_byte(); DHT11_read_byte(); // Пропустить второй байт температуры DHT11_read_byte(); // Пропустить контрольную сумму } else { *humidity = 0; *temperature = 0; } } void setup() { soft_uart_init(); // Инициализация программного UART soft_uart_send_string("\r\n"); soft_uart_send_string("madmentat.ru"); soft_uart_send_string("\n"); soft_uart_send_string("madBCC climate controller initialized!"); soft_uart_send_string("\n"); DDRB |= (1 << PB4) | (1 << PB3); PORTB &= ~(1 << PB4) | (1 << PB3); } void loop() { while (1) { DHT11_read(&temperature, &humidity); // Диагностика этапов чтения soft_uart_send_string("Reading from DHT11...\r\n"); if (temperature == 0 && humidity == 0) { soft_uart_send_string("Failed to read from DHT11\r\n"); } else { itoa(temperature, temperatureStr, 10); itoa(humidity, humidityStr, 10); soft_uart_send_string("\r\n"); soft_uart_send_string("Current temperature is "); soft_uart_send_string(temperatureStr); soft_uart_send_string(" C"); soft_uart_send_byte(0xC2); // первый байт символа градуса soft_uart_send_byte(0xB0); // второй байт символа градуса soft_uart_send_string("\n"); if(temperature < 27){ PORTB |= (1 << PB3);// | (1 << PB3); soft_uart_send_string("Relay ON"); } if(temperature > 26){ PORTB &= ~(1 << PB3);// | (1 << PB3); soft_uart_send_string("Relay OFF"); } soft_uart_send_string("\r\n"); soft_uart_send_string("Current humidity is "); soft_uart_send_string(humidityStr); soft_uart_send_string("\r\n"); } _delay_ms(2000); // Считывание каждые 2 секунды } } int main(void) { setup(); loop(); return 0; }