# _*_ coding: utf8 _*_
import time # В этом модуле - задержки
import smbus # В этом модуле - средства для работы с шиной i2c
import math # В этом модуле математические функции (sqrt, в частности)
import Adafruit_BMP.BMP085 as bmp # Обслуживание датчика давления
from Tkinter import * # Инструментарий для GUI
import tkMessageBox as mbox # Чтобы ругаться
import matplotlib # Библиотека для построения графиков
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
#-------------------------------------------------------------------------------
# Тестирование всей системы
# OldBean, 01.03.2018
#-------------------------------------------------------------------------------
# Адреса устройств
addrR = 0x11 # Адрес датчика RMS
addrC = 0x12 # Адрес контроллера контактора
addrT = 0x13 # Адрес контроллера ТЭНа
addrV = 0x14 # Адрес контроллера клапана отбора на шине i2c
addrD = 0x15 # Адрес цифрового модуля
#-------------------------------------------------------------------------------
# Параметры и вспомогательные переменные
a = 0.3838 # Калибровочный коэффициент для перевода кода в вольты
buf = [0]*16 # Буфер для приема байтов от цифрового модуля
pdm = 0 # Уровень pdm-модуляции для контроллера ТЭНа
pwm = 0 # Уровень pwm-модуляции для контроллера клапана отбора
# Кольцевые массивы для построения графиков температурных трендов
gLen = 100 # Длина кольцевых массивов
t = range(gLen) # Массив дискретных веренных отсчетов
Tkub = [0.0]*gLen # Массив для значений температуры в кубе
Tcol = [0.0]*gLen # Массив для значений температуры в колонне
Tdef = [0.0]*gLen # Массив для значений температуры в дефлегматоре
Ttsa = [0.0]*gLen # Массив для значений температуры в ТСА
#-------------------------------------------------------------------------------
def fC(): # Вызывается при изменении состояния чекбокса
global vC
bus.write_byte(addrC, vC.get());
#-------------------------------------------------------------------------------
def fT(): # Вызывается при изменении состояния спинбокса ТЭНа
global sbT, pdm
pdm = int(sbT.get())
bus.write_byte(addrT, pdm);
#-------------------------------------------------------------------------------
def fV(): # Вызывается при изменении состояния спинбокса клапана отбора
global sbV, pwm
pwm = int(sbV.get())*10
if(bus.read_byte(addrV) == 0xff):
bus.write_byte(addrV, (pwm & 0xff))
bus.write_byte(addrV, ((pwm >> 8) & 0xff))
else:mbox.showerror('Ошибка', 'Ошибка контроллера клапана отбора')
#-------------------------------------------------------------------------------
def wclose(): # Вызывается перед закрытием главного окна приложения
bus.read_byte(addrV) # Выключить клапан
bus.write_byte(addrV, 0)
bus.write_byte(addrV, 0)
bus.write_byte(addrT, 0) # Выключаем ТЭН
bus.write_byte(addrC, 0) # Выключаем контактор
root.destroy() # Закроем главное окно
#-------------------------------------------------------------------------------
def meas(): # Получение и вывод информации с датчиков
# Измеряем и выводим RMS
bus.write_byte(addrR, 0); # Установка индекса байтов в датчике RMS на 0
crms = bus.read_byte(addrR) # Читаем 4 байта с датчика RMS (начиная с
crms |= bus.read_byte(addrR) << 8 # младшего и собираем 32-разрядное слово
crms |= bus.read_byte(addrR) << 16 # В этом слове - сумма квадратов кода АЦП
crms |= bus.read_byte(addrR) << 24 # за 1 сек (5000 отсчетов)
v = a*math.sqrt(crms*0.0002) # Вычисляем RMS (0.0002 это 1/5000)
txts[0].configure(text = formats[0] % (v)) # Выводим значение RMS
# Измеряем и выводим атмосферное давление
p = ps.read_pressure()/133.322
txts[1].configure(text = formats[1] % (p)) # Выводим значение давления
# Измеряем и выводим данные с цифрового модуля (температуры и контакты)
tries = 100 # Максимальное количество попыток доступа к данным модуля
while tries > 0: # Ограничиваем количество попыток обращения к модулю
try: # Попытаемся получить данные
bus.write_byte(addrD, 0x00) # Сбрасываем индекс байтов в буфере модуля
for i in range(16): # Считываем байты буфера последовательно
buf[i] = bus.read_byte(addrD)
break # Если все нормально - выходим из цикла
except IOError: # Устройство еще не готово - подождем 0.1 сек
time.sleep(0.1) # и сделаем еще попытку
tries -= 1 # Уменьшим на единичку счетчик попыток
if tries <= 0: # Однако, что-то серьезно не так...
print 'Цифровой модуль не доступен по i2c. Завершение работы.'
sys.exit(1)
for i in range(8): # Выводим информацию, полученную от цифрового модуля
w = buf[2*i]*256 + buf[2*i + 1] # Формируем словf из пар байтов
if w <= 2000 and w > 0: # Это явно DS18B20 - формируем значение температуры
w *= 0.0625
elif w > 2000: w = 1 # Разомкнутый контакт
else: w = 0 # Замкнутый контакт
# Обновляем кольцевые массивы для построения графиков температурных трендов
if i == 0: # Температура в кубе
del Tkub[0]; Tkub.append(w)
elif i == 1: # Температура в колонне
del Tcol[0]; Tcol.append(w);
elif i == 2: # Температура в колонне
del Tdef[0]; Tdef.append(w);
elif i == 3: # Температура в колонне
del Ttsa[0]; Ttsa.append(w);
# Выводим температуры в соответствующие окошечки главного окна
txts[2 + i].configure(text = formats[2 + i] % (w))
print formats[2 + i] % (w), # и еще - на терминал для контроля...
print
# Перестраиваем графики температурных трендов
ax.clear()
ax.plot(t, Tkub, 'b', Tcol, 'r', Tdef, 'g', Ttsa, 'c')
ax.grid(True, linestyle='--')
ax.tick_params(labelsize='small')
# ax.set_xlabel(u'Время, отн.ед')
# ax.xaxis.label.set_size(9)
ax.set_xlim(0, 100)
ax.set_ylabel(u'Температура,°C')
ax.yaxis.label.set_size(9)
ax.set_ylim(20, 50)
fig.canvas.draw()
txts[0].after(1000, meas) # Все, но через 1 сек (1000 мс) опять вызовем meas
#-------------------------------------------------------------------------------
bus = smbus.SMBus(1) # Создаем объект "шина i2c"
ps = bmp.BMP085() # Создаем объект - датчик давления
root = Tk() # Создаем и настраиваем главное окно
root.geometry('660x266+300+200') # Размер и положение
root.wm_title('LITE: Тест всей периферии') # Заголовок
root.resizable(width = False, height = False) # Фиксированные размеры окна
root.protocol('WM_DELETE_WINDOW', wclose) # В wclose - обработка закрытия окна
# Создаем объект - чекбокс для управления контактором
vC = IntVar() # В переменной vC - состояние чекбокса (контактора)
chC = Checkbutton(text = 'Контактор', command = fC, variable = vC)
lpdm = Label(text = 'ТЭН (%) ', width = 13, anchor = 'w') # Метка PDM
# Создаем объект - спинбокс
sbT = Spinbox(from_ = 0, to = 100, width = 3, command = fT, justify = RIGHT)
lpwm = Label(text = 'Клапан (%) = ', width = 13, anchor = 'w') # Метка ШИМ
# Создаем объект - спинбокс
sbV = Spinbox(from_ = 0, to = 100, width = 3, command = fV, justify = RIGHT)
fr1 = Frame(width = 134, height = 1, bg = 'grey')
fr2 = Frame(width = 134, height = 1, bg = 'grey')
fr3 = Frame(width = 134, height = 1, bg = 'grey')
# Создаем метки и поля выводов для остальных параметров (RMS, атм.давление,
# температуры и состояние контактов)
labels = ['RMS (В) ', 'P(мм.рт.ст)', 'Tкуб (°C)', 'Tкол (°C)', 'Tдеф (°C)',
'Tтса (°C)', 'Контакт 1', 'Контакт 2', 'Контакт 3', 'Контакт 4']
formats = ['%.1f ', '%.1f ', '% 7.3f', '% 7.3f', '% 7.3f', '% 7.3f',
'%d', '%d', '%d', '%d']
fgcol = ['black', 'black', 'blue', 'red', 'dark green', 'dark cyan', 'black',
'black', 'black', 'black', 'black']
labs = []; txts = []
for i in range(10):
labs.append(Label(text = labels[i], width = 13, anchor = 'w', fg = fgcol[i]))
txts.append(Label(width = 6, anchor = 'e', fg = fgcol[i]))
# Теперь размещаем виджеты в главном окне приложения
chC.place(x = -6, y = 0) # Чекбокс контактора
lpdm.place(x = 0, y = 20) # Метка спинбокса RMS
sbT.place(x = 92, y = 20) # Спинбокс RMS
lpwm.place(x = 0, y = 40) # Метака спинбокса клапана отбора
sbV.place(x = 92, y = 40) # Спинбокс клапана отбора
fr1.place(x = 0, y = 62) # Просто разделительная черта
offs = 63 # Текущее смещение по y
for i in range(10): # Размещаем метки и поля вывода остальных параметров
labs[i].place(x = 0, y = offs + 20*i)
txts[i].place(x = 85, y = offs + 20*i)
if i == 1: # Поставим дополнительный разделитель
fr2.place(x = 0, y = offs + 20*(i + 1))
offs += 2
if i == 5: # Еще один разделитель
fr3.place(x = 0, y = offs + 20*(i + 1))
offs += 2
# Внедряем в главное окно Tkinter-а канву графиков от matplotlib
fig = Figure(figsize = (5.5, 2.85))
ax = fig.add_subplot(111)
canvas = FigureCanvasTkAgg(fig, master = root)
canvas.get_tk_widget().place(x = 140, y = -20)
txts[0].after(1000, meas) # Через 1 сек (1000 мс) будет вызов функции meas
root.mainloop() # Главный цикл приложения