Не для коммерческого использования. Все содержание публикации "для свободного использования". Возможны любые изменения в конструкции и программе. Свободное изготовление для личного пользования, но не для третьих лиц без согласования с автором. Автор и администрация сайта снимает с себя ответственность за любые последствия самостоятельного воспроизведения нижеизложенного.
Неудобная и тупиковая концепция >>> БРОШЕНО В ПРОПАСТЬ
Управление с помощью джойстика и экрана мне показалось скучной темой, к тому же было интересно смотреть в реальном времени график температур, иметь статистику по перегонкам, а также куча всяких возможных плюх, которые я еще не придумал))).
Этот скетч и скриптик я написал еще год назад, вроде оттестил, но никак времени не хватает попробовать на перегонке. Концепция следующая: скрипт разово отправляет строкой все параметры в ардуину, через ком-порт, ардуина распирсивает вывод и меняет свои переменные на полученные. В свое время ардуина отдает через каждых сколько-то секунд все параметры, которые у нее в работе, компу, который также все распарсивает и показывает что происходит. Все параметры при получении записываются в текстовый файлик. Есть вариант с sqlite3. Есть возможность включить постоянное получение данных со стороны компа.
Повторюсь, что времени на "покопаться" сайчас нет от слова совсем. В данном варианте не предусмотрено управление джойстиком и экранчик тоже удран совсем. Вся переферия подключается также как и здесь версия3.
GUI для управления выглядит так:
Просьба сильно не пинать, выкладываю недоделку исключительно по просьбе.
Скетч для ардуино
#include <OneWire.h>
int WarmUp[] = {2,3,2,4,3,2,3,4,2,4,3,2}; //массив зависимости значений нагрева ТЭНа от номера режима
int WarmDown[] = {5,7,4,7,5,3,4,5,2,3,2,1}; //массив зависимости значений пауз в работе ТЭНа от номера режима
int TempUpSlow = 0;
unsigned long tDr = 0;
unsigned long tUr = 0;
int WarmDevice = 13; //тэн подключен к 13му пину
int tD;
int tU;
float ThisTempVar;
int flagTemp = 0; // переменная отслеживания опроса датчика температуры
OneWire ds (14);
byte data[12];
byte addr1[8] = {0x28, 0xFF, 0x82, 0x03, 0xB4, 0x16, 0x03, 0x0E}; //сухопарник выход
byte addr2[8] = {0x28, 0xFF, 0x56, 0x5A,0xB4, 0x16, 0x03, 0x04}; //сухопарник вход
byte addr3[8] = {0x28, 0xFF, 0xFF, 0x56,0xB4, 0x16, 0x03, 0xD6}; //куб
unsigned int raw;
float T1, T2, T3;
int thisAddr = 0;
unsigned long AllTime; // переменная для записи времени прошедшего со старта программы
unsigned long MemTime; // переменная для записи времени начала события относительно времени прошедшего с начала программы
unsigned long AllTempTime; // переменная для записи времени прошедшего со старта программы для опроса DALLAS DS18 (температуры)
unsigned long MemTempTime; // переменная для записи времени начала события относительно времени прошедшего с начала программы для опроса DALLAS DS18 (температуры)
int tTempTemp = 0; // временная переменная для записи расчета времени с последнего опроса датчика, не совсем верно, но по коду можно разобраться зачем)))
//int Ttmp;
int FanDevice = 12; //вентилятор подключен к 12му пину
float Tend = 36.60; // тестовая температура
char incoming;
char str[6];
String str1;
int i;
int OnOff = 0; // переменная On/Off
int Mode = 0; // переменная full/manual/auto
int AMode = 1; // переменная обозначающая номер режима нагрева
int FlagSerial = 0;
//byte data[12];
//unsigned long data = 0;
unsigned long TimeSendSerial = 500;
unsigned long MemTimeSerial = 0;
unsigned long RunTimeSerial = 0;
// === START FUNCTIONS ===
void DataSendSerial () {
if (FlagSerial == 0) {
FlagSerial = 1;
MemTimeSerial = millis();
} else if (FlagSerial == 1) {
RunTimeSerial = millis();
if (TimeSendSerial < RunTimeSerial - MemTimeSerial) {
Serial.print(":");
Serial.print(OnOff);
Serial.print(Mode);
Serial.print(AMode);
Serial.print(int(Tend*10));
Serial.print(int(T1*100));
Serial.print(int(T2*100));
Serial.print(int(T3*100));
Serial.println(";");
// Serial.print(Temp2);
// Serial.println(Temp1);
FlagSerial = 0;
}
}
}
//*** ф-ия вкл\выкл на tU tD ТЭНА
void WarmControlPause(){
if (TempUpSlow == 0){ //цикл вкл\выкл не начался
TempUpSlow = 1; // говорим что запустили плавный режим
MemTime = millis(); // засекаем время
digitalWrite(WarmDevice, 0);
//###########################################
}else{
AllTime = millis(); //
if(tD > AllTime-MemTime){
tUr = 0;
tDr = AllTime-MemTime;
digitalWrite(WarmDevice, 0); // выключаем реле
//###########################################
}else if(tU > AllTime-MemTime-tD){
tDr = 0;
tUr = AllTime-MemTime-tD;
digitalWrite(WarmDevice, 1);
//###########################################
}else{
TempUpSlow = 0;
digitalWrite(WarmDevice, 0);
}
}
}
void FanControlPower(){
ThisTempVar =(float)tU/(float)tD;
if(ThisTempVar >= 0.5){ // значение соотношения температуры tU/tD для включения вентилятора
digitalWrite(FanDevice, 1); //при 5 вольтах все равно большие обороты, поэтому включаем через цикл
}else{
digitalWrite(FanDevice, 0);
}
}
// === END FUNCTIONS ===
void setup(){
Serial.begin(9600); //initialize serial COM at 9600 baudrate
pinMode(WarmDevice, OUTPUT); //make the LED pin (13) as output
digitalWrite (WarmDevice, 0);
pinMode(FanDevice, OUTPUT);
digitalWrite(FanDevice, 0);
}
//функция опроса датчика часть 1 (до паузы)
float DS18B20_1(byte *adres){
ds.reset();
ds.select(adres);
ds.write(0x44);
}
//функция опроса датчика часть 2 (после паузы)
float DS18B20_2(byte *adres){
ds.reset();
ds.select(adres);
ds.write(0xBE); // Read Scratchpad
for (byte i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read ();
}
raw = (data[1] << 8) | data[0];//=======Пересчитываем в температуру
float celsius = (float)raw / 16.0;
return celsius;
}
//функция назначения номера опрашиваемого датчика
void AddrAssign(){
thisAddr = thisAddr+1;
if (thisAddr>3){
thisAddr=1;
}
}
void loop() {
DataSendSerial();
// === Start SerialAvailable ===
while (Serial.available())
{
incoming = Serial.read();
//Serial.println(incoming);
if (incoming < '0' || incoming > '9')break;
{
str[i] = incoming;
Serial.print(i);
Serial.print("==>>");
Serial.println(str[i]);
i++;
}
if (i > 5) //на данные отводим 6 знака
{
str[i] = 0;
i=0;
}
}
OnOff = int(str[0]- '0');
Mode = int(str[1]- '0');
AMode = int(str[2]- '0');
str1 = "";
for (int i = 3; i < 6; i++){
str1 = str1 + (str[i]- '0');
}
// === End SerialAvailable ===
// *** НАЧАЛО ТЕМПЕРАТУРА
if (flagTemp == 0){
AddrAssign();
flagTemp = 1; // выставляем флаг на пропуск этого блока, пока не пройдет 1000 мс
if(thisAddr == 1){
DS18B20_1(addr1);
}else if(thisAddr == 2){
DS18B20_1(addr2);
}else if(thisAddr == 3){
DS18B20_1(addr3);
}
MemTempTime = millis(); // засекаем время
}else{
AllTempTime = millis(); //
tTempTemp = AllTempTime - MemTempTime;
if (tTempTemp < 750){
flagTemp = 1;
}else{
flagTemp = 0;
if(thisAddr == 1){
T1=DS18B20_2(addr1);
// Serial.print("T1 ");
// Serial.println(T1);
}else if(thisAddr == 2){
T2=DS18B20_2(addr2);
// Serial.print("T2 ");
// Serial.println(T2);
}else if(thisAddr == 3){
T3=DS18B20_2(addr3);
// Serial.print("T3 ");
// Serial.println(T3);
// Serial.println("---------------------------------------");
}
}
}
// *** КОНЕЦ ТЕМПЕРАТУРЫ
Tend = (float)str1.toInt()/(float)10;
//T = String (T1)+String (T2)+String (T3);
//Serial.print(":");
//Serial.println(incoming);
// *** УПРАВЛЕНИЕ ТЭНОМ
tU=(WarmUp[AMode])*100; //считаем промежуток включения тэна в зависимости от режима Ymem[3]
tD=(WarmDown[AMode])*100; //считаем промежуток выключения тэна в зависимости от режима Ymem[3]
// OnOff = Ymem[0]; //***/ используем старый, отработанный кусок программы,
// ModeVar = Ymem[1]; // поэтому приводим все к тем же переменным /***
//=======================================================================================================
if (OnOff == 0){ // если выключено, то нас больше ничего не интересует - все выключено
digitalWrite(WarmDevice, 0);
digitalWrite(FanDevice, 0);
// BeeperOneBeep(20,50,0,5000);
//=======================================================================================================
}else if (OnOff != 0){ // если включено - смотрим что дальше
if (Mode == 0){ // режим постоянного нагрева
digitalWrite(WarmDevice, 1);
// digitalWrite(FanDevice, !digitalRead(FanDevice)); //при 5 вольтах все равно большие обороты, поэтому включаем через цикл
digitalWrite(FanDevice, 1);
//=======================================================================================================
}else if(Mode == 1){ // режим ручного регулирования нагрева
{
FanControlPower();
WarmControlPause();
//###########################################
}
//=======================================================================================================
}else if(Mode == 2){ // автоматический режим работы
if (T2 <= 50.0 && T1 < Tend){ // автоматический режим постоянный нагрев до 50 град
digitalWrite(WarmDevice, 1);
digitalWrite(FanDevice, 1);
}else if (T2 > 50.0 && T1 < Tend){ // автоматический режим управление после 50 град
if ((T1-T2)>=20.0){
digitalWrite(WarmDevice, 1);
digitalWrite(FanDevice, 1);
}
else if ((T2-T3)<20.0 && (T2-T3)>=7.0){
AMode=8;
FanControlPower();
WarmControlPause();
}
else if ((T2-T3)<7.0 && (T2-T3)>=5.0){
AMode=5;
FanControlPower();
WarmControlPause();
}
else if ((T2-T3)<5.0 && (T2-T3)>=3.0){
AMode=4;
FanControlPower();
WarmControlPause();
}
else if ((T2-T3)<3.0){
AMode=3;
FanControlPower();
WarmControlPause();
}
}else if (T2 > 50.0 && T1 >= Tend){ // выключаем все при температуре TempEnd
digitalWrite(FanDevice, 0);
OnOff = 0;
AMode = 0;
digitalWrite(WarmDevice, 0);
}
}
}
//====== --- УПРАВЛЕНИЕ ТЭНОМ =========
//if(OnOff == 1){
//digitalWrite (LED_BUILTIN, HIGH);
//}else{
// digitalWrite (LED_BUILTIN, LOW);
//}
}
GUI для управления с компа
#! /usr/bin/python3
# coding: utf-8
import time
import serial
import os
from tkinter import *
from tkinter import ttk
from tkinter.ttk import Combobox
import glob
class Box_create():
def __init__(self, text_lable, list_add, col, row):
self.text_lable = text_lable
self.list_add = list_add
self.col = col
self.row = row
lbl = Label(window, text=self.text_lable)
lbl.grid(column=self.col - 1, row=self.row)
self.combo = Combobox(window)
self.combo['values'] = (self.list_add)
self.combo.current(0)
self.combo.grid(column=self.col, row=self.row)
@property
def print_get(self):
return self.combo.get()
class Button_create():
def __init__(self, text_lable, command, col, row):
self.text_lable = text_lable
self.command = command
self.col = col
self.row = row
self.button = Button(window)
self.button['text'] = (self.text_lable)
self.button['command'] = (self.command)
self.button.grid(column=self.col, row=self.row)
@property
def print_get(self):
print(self.button.get())
return self.button.get()
###class lable start
class Lable_create():
def __init__(self, text_lable, col, row):
self.text_lable = text_lable
self.col = col
self.row = row
self.lable = Label(window)
self.lable['text'] = (self.text_lable)
self.lable.grid(column=self.col, row=self.row)
def label_text_configure(self, text_lable):
self.text_lable = text_lable
self.lable['text'] = (self.text_lable)
@property
def print_get(self):
print(self.lable.get())
return self.lable.get()
def port_search():
ports = []
if sys.platform.startswith('win'):
ports = ['COM%s' % (i + 1) for i in range(25)]
elif sys.platform.startswith('linux'):
ports = glob.glob('/dev/tty[A-Za-z]*')
else:
raise EnvironmentError('Unsupported platform')
return ports
def serial_port_select():
global serial_port_name
global serial_port_speed
serial_port_name = port_search_box.print_get
serial_port_speed = 9600
port_select_label.label_text_configure(serial_port_name)
os.system('sudo chmod 0666 ' + serial_port_name)
send_data_to_arduino()
def send_data_to_arduino(symb=0):
out_label.label_text_configure('FAIL')
# symb = str(re.sub(r'[\(\)\[\]\ ,\.rbn_dictvalues;:\'\\]', "", str(set_mode.values())))
symb = str(set_mode['onoff']) + str(set_mode['mode']) + str(set_mode['amode']) + str(set_mode['temp'])
ser = serial.Serial(serial_port_name, serial_port_speed, timeout=5)
print(serial_port_name, serial_port_speed)
print('Отправили:', symb)
symb1=':'
ser.write(symb.encode())
for i in range(5000):
window.update()
if str(symb1) in str(ser.readline()):
out_label.label_text_configure('OK')
print('Получили:', str(ser.readline()))
resive_data_from_arduino()
break
else:
out_label.label_text_configure('undefined')
def resive_data_from_arduino():
#data:
#:001366;
ser = serial.Serial(serial_port_name, serial_port_speed, timeout=5)
print(serial_port_name, serial_port_speed)
symb = str(':')
for i in range(50):
window.update()
if symb in str(ser.readline()):
out_label.label_text_configure('OK')
print('Получили:', ser.readline())
read_data = re.sub(r'[rbn;:\'\\]', "", str(ser.readline()))
#set_mode_label.label_text_configure(time.strftime("%Y/%m/%d-%H:%M:%S") + ' --- ' + read_data)
read_serial_data_list.append(read_data)
read_data_to_file(read_data)
# read_serial_data_list_label.label_text_configure(read_serial_data_list[-1])
read_serial_data_list_label.label_text_configure('Вкл/Выкл: ' + str(read_serial_data_list[-1])[0] + ';\nРежим автоматики: ' + str(read_serial_data_list[-1])[1] + ';\nРежим нагрева: ' + str(read_serial_data_list[-1])[2] + ';\nТемпература отключения в кубе: ' + str(read_serial_data_list[-1])[3:5] + ',' + str(read_serial_data_list[-1])[5])
read_serial_temp_label.label_text_configure('Температура в кубе: ' + str(read_serial_data_list[-1])[6:8] + ',' + str(read_serial_data_list[-1])[8:10] + ';\nТемп до сухопарника: ' + str(read_serial_data_list[-1])[10:12] + ',' + str(read_serial_data_list[-1])[12:14] + ';\nТемп после сухопарника: ' + str(read_serial_data_list[-1])[14:16] + ',' + str(read_serial_data_list[-1])[16] + str(read_serial_data_list[-1])[17])
break
else:
out_label.label_text_configure('Получаем данные')
def read_data_to_file(data_string):
read_data_file = open('data_string.txt', 'a')
read_data_file.write('\n' + time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime()) + ':' + data_string)
read_data_file.close()
def run_select_0():
global run
run = '0'
run_label.label_text_configure(run)
window.update()
def run_select_1():
global run
run = '1'
run_label.label_text_configure(run)
window.update()
def at_func_run():
global run
if run == '1':
global flag_run
if flag_run == 0:
flag_run = 1
global time_to_run
global start
start = time.time()
else:
if time.time() > start + time_to_run:
resive_data_from_arduino()
flag_run = 0
from_func_run_label.label_text_configure(run)
window.update()
else:
pass
window.update()
else:
from_func_run_label.label_text_configure(run)
window.update()
window.update()
def run_function_sleep():
pass
def add_onoff_to_list():
set_mode.update({'onoff': onoff_select_box.print_get})
set_mode_label.label_text_configure(set_mode)
def add_mode_to_list():
set_mode.update({'mode': mode_select_box.print_get})
set_mode_label.label_text_configure(set_mode)
def add_amode_to_list():
set_mode.update({'amode': amode_select_box.print_get})
set_mode_label.label_text_configure(set_mode)
def add_temp_to_list():
set_mode.update({'temp': temp_select_box.print_get})
set_mode_label.label_text_configure(set_mode)
#всякая херня скопом
global serial_port_name
serial_port_name = ''
read_serial_data_list = [] #in resive_data_from_arduino() append
set_mode = {'onoff': 1, 'mode': 2, 'amode': 0, 'temp': 987}
onoff = [0, 1]
mode = [0, 1, 2]
temp = []
temp_select = []
run = 0 # относится к запуску по времени функции
flag_run = 0 # относится к запуску по времени функции
start = 0 # в этой переменной засекаем время запуска
time_to_run = 3 # запуск раз в N секунд
for i in range(970, 999): # здесь создаем список для выбора конечной температуры в боксе
temp.append(i)
temp_select.append(i/10)
amode_list = []
for i in range(9):
amode_list.append(i)
print(temp)
window = Tk()
window.title("DISTSYS.RU")
window.geometry("850x600")
port_select_label = Lable_create('/serial/port/select', 1, 2)
out_label = Lable_create('output test', 2, 2)
set_mode_label = Lable_create(set_mode, 3, 2)
port_search_box = Box_create('Serial port', port_search(), 1, 3)
port_search_btn = Button_create('Подключиться', serial_port_select, 2, 3)
onoff_select_box = Box_create('On/Off', onoff, 1, 4)
onoff_select_btn = Button_create('Сохранить', add_onoff_to_list, 2, 4)
mode_select_box = Box_create('Режим', mode, 1, 5)
mode_select_btn = Button_create('Сохранить', add_mode_to_list, 2, 5)
amode_select_box = Box_create('Нагрев', amode_list, 1, 6)
amode_select_btn = Button_create('Сохранить', add_amode_to_list, 2, 6)
temp_select_box = Box_create('Конечная\nтемпература', temp_select, 1, 7)
temp_select_btn = Button_create('Сохранить', add_temp_to_list, 2, 7)
temp_resive_data_btn = Button_create('Получить данные', resive_data_from_arduino, 2, 8)
temp_resive_data_btn = Button_create('Отправить данные', send_data_to_arduino, 3, 8)
read_serial_data_list_label = Lable_create('READ SERIAL DATA LIST', 1, 10)
read_serial_temp_label = Lable_create('READ SERIAL DATA LIST TEMPs', 1, 11)
run_label = Lable_create(run, 2, 12)
from_func_run_label = Lable_create(run, 3, 12)
run_label_info = Lable_create('Получение данных', 1, 13)
run_select_btn1 = Button_create('включить', run_select_1, 2, 13)
run_select_btn2 = Button_create('выключить', run_select_0, 3, 13)
n=0
while n == 0:
at_func_run()
window.mainloop()