Немного предыстории...
Если у кого то есть или был Москвич 2141-45 именуемый как Святогор, да и без разницы даже пусть 2141, наверняка сталкивались с проблемой охлаждения. Вентилятор ни когда не включается во время, а то и вообще не включается, из-за чего постоянно кипим. Чтож меня это так сказать достало, в прошлом году сделал девайс простенький. Вместо штатного датчика температуры поставил в радиатор DS18B20(раскурочил штатный датчик, оставив только корпус без внутренностей, поставил в него DS18B20, залил эпоксидной смолой и вкрутил в радиатор). Написал программку измерения температуры и вывод её на дисплей. Добавил к схеме реле(как оо используется объясню позже). Короче при достижение заданной температуры в программе вкл. вентилятор. Всё отлично работало, но решил модернизировать девайс и добавить часы, принудительное включение вентилятора с помощью одной кнопки без фиксации(используя прерывания в программе), установку температуры(настраивается через меню и записывается в EEPROM мк) при которой будет вкл. и выкл. вентилятор... Вообщем вот, фотки ниже.
Теперь о том как это работает. Сначала о реле. Штатный датчик работал так. При достижение температуры 97 градусов он замыкал свои контакты. После чего включался вентилятор на радиаторе. Два контакта реле подключены именно в то место куда был подключён штатный датчик температуры. Соответственно когда они замыкаются вкл. вентилятор.
При первом запуске программы следует настроить часы и температуру срабатывания вентилятора(хотя срабатывает реле, а вентилятор всё таки на машине а не на девайсе)) ). Для настройки имеется 4 кнопки (меню, ввод, вверх, вниз) и ещё 2 - одна отвечает за RESET другая за вкл. реле. Нажимаем клавишу меню. На экране дисплея появится надпись выбора температуры вкл., после выбора температуры(для этого используем кнопки вверх и вниз) нажимаем клавишу ввод, появляется след. надпись с выбором температуры выкл. и т. д. Всего в меню таких настроек 7: температура вкл., температура выкл., год, месяц, число, часы, минуты. Когда все настройки выполнены на экране появятся все введённые вами данные(кроме температуры вкл. и выкл.). Также в программе сделано так, что если необходимо вкл. реле принудительно(не дожидаясь пока температура достигнет заданного значения в меню) то удерживаем кнопку отвечающую за вкл. реле.
Не много подробней про эту кнопку. В программе два цикла. В-первом цикле реле вкл. при достижение заданной температуры. Во-втором цикле реле вкл. и выкл. при нажатие на клавишу. Чтобы перейти из 1-ого цикла во-второй нужно удержать клавишу. И также обратно. За этот момент кстати спасибо galex1981, подкинул идею(здесь обсуждалось) как реализовать такое, чтобы не было конфликта между вкл. реле от температуры и вкл. реле от нажатия клавиши.
Ну иссходик конечно выложил. Также выложил разводку платы и схему(программа Eagle). Смотреть всё в архиве "Time"
Программа разделена на два файла. Файл Time основной, файл Subs-в нём все процедуры программы.
Код из файла Time:
- Код: Выделить всё • Развернуть
'*******************************************************************************
' Автор: Space *
' Сайт: www.enore.ucoz.ru *
' Дата начала: 25.06.2011 г. *
' CPU: ATmega8 *
' Тактовая частота: 8000000 Hz *
' Компилятор: BASCOM-AVR 1.11.9.0 *
'*******************************************************************************
' Программируемые Fuse:
' CKSEL0, CKSEL1, CKSEL3
' EESAVE
' SPIEN
'*******************************************************************************
'***************************Тип_микроконтроллера********************************
$regfile = "m8def.dat" 'Указываем используемый мк
$crystal = 8000000 'Задаём рабочую частоту мк
'***********************Дополнительные_библиотеки*******************************
$lib "mcsbyte.lbx"
'$lib "ds1307clock.lib" - здесь эта библиотека не нужна
'****************************Конфигурация_ЖКИ***********************************
Config Lcdbus = 4 ' 4-х битное подключение дисплея
Config Lcdpin = Pin , Rs = Portb.1 , E = Portb.2 , Db4 = Portb.0 , Db5 = Portd.7 , Db6 = Portd.6 , Db7 = Portd.5
Config Lcd = 16 * 2 ' Дисплей 16 сисмволов, 2 строки
Cursor Off 'Отключаем курсор
Cls 'Очистка экрана
'********************************Порты******************************************
'Командой "Set" подключаем внутренний резисмтор на +
Set Portc.0 : Вниз Alias Pinc.0 'Кнопка вниз
Set Portc.1 : Вверх Alias Pinc.1 'Кнопка вверх
Set Portc.2 : Меню Alias Pinc.2 'Кнопка меню
Set Portc.3 : Ввод Alias Pinc.3 'Кнопка ввод
'*********************************I2C*******************************************
Config Sda = Portc.4
Config Scl = Portc.5
'*******************************************************************************
Config Portd.0 = Output : Speaker Alias Portd.0 'Пин, на котором висит Speaker
Config 1wire = Portd.1 'Пин, на который повешан DS18B20
Set Portd.2 : Вкл_выкл Alias Pind.2 'Клавиша для принудительного вкл. и выкл. реле
Config Portd.4 = Output : Реле Alias Portd.4
'*******************************************************************************
Config Clock = User
Config Date = Dmy , Separator = .
'********************************Константы**************************************
Const Ds1307w = &HD0
Const Ds1307r = &HD1
'*******************************Прерывания**************************************
Config Int0 = Falling 'Разрешаем прерывания по спаду напряжения On Int0
On Int0 Вклвыкл_Реле 'Задаём метку перехода по прерыванию
Enable Interrupts 'Разрешаем прерывания
Config Debounce = 100 'Опрос клавиши каждые 100 мс
'******************************Переменные***************************************
'*********************************Byte******************************************
Dim J1 As Byte 'Объявить байтовую переменную J1
Dim M1 As Byte 'Объявить байтовую переменную M1
Dim D1 As Byte 'Объявить байтовую переменную D1
Dim H1 As Byte 'Объявить байтовую переменную H1
Dim X1 As Byte 'Объявить байтовую переменную X1
Dim T2 As Byte 'Объявить байтовую переменную T1
Dim Aa As Byte 'Объявить байтовую переменную Aa
Dim Pos As Byte 'Объявить байтовую переменную Pos
Dim Min1 As Byte 'Объявить байтовую переменную Min1
Dim Temp As Byte 'Объявить байтовую переменную Temp
Dim Digit As Byte 'Объявить байтовую переменную Digit
Dim Byte0 As Byte 'Объявить байтовую переменную Byte0
Dim Byte1 As Byte 'Объявить байтовую переменную Byte1
Dim Faren As Byte 'Объявить байтовую переменную Faren
Dim Weekday As Byte 'Объявить байтовую переменную Weekday
'********************************Integer****************************************
Dim A As Integer 'Объявить целую переменную A
Dim B As Integer 'Объявить целую переменную B
Dim Tem1 As Integer 'Объявить целую переменную Tem1
Dim Tem2 As Integer 'Объявить целую переменную Tem2
'*********************************Single****************************************
Dim Faren0 As Single 'Объявить десятичную (число с плавающей точкой) переменную Faren0
'*********************************String****************************************
Dim Celsium As String * 5 'Объявить символьную переменную Celsium
Dim Fahrenhei As String * 5 'Объявить символьную переменную Fahrenhei
Dim Signtemperatura As String * 1 'Объявить символьную переменную Signtemperatura
'******************************Переменные Eeprom********************************
Dim Ae As Eram Integer 'Объявить целую переменную в EEPROM Ae
Dim Be As Eram Integer 'Объявить целую переменную в EEPROM Be
A = Ae
B = Be
'************************************Процедуры**********************************
Declare Sub Ввод_даты_времени() 'Объявить процедуру Ввод_даты_времени()
Declare Sub Вверх_вниз_ввод() 'Объявить процедуру Вверх_вниз_ввод()
Declare Sub Температура 'Объявить процедуру Температура
Declare Sub МенюП() 'Объявить процедуру МенюП()
Declare Sub Вов() 'Объявить процедуру Вов()
'*******************************************************************************
'*****************************Оcновной_цикл_программы***************************
Вкл._от_перемены_температуры:
Disable Int0 'Запрещаем прерывания на Int0
Sound Speaker , 3000 , 100
'*******************************************************************************
'В этом цикле реле вкл. и выкл. только по достижению заданного значения температуры.
'При удержании клавиши Вкл_выкл осущевствляется переход на метку Вкл._от_перемены_температуры
Do
Call Температура 'Вызвать подпрограмму(процедуру) "Температура"
Call Вов 'Вызвать подпрограмму(процедуру) "Вов"
Locate 1 , 1 'Вывод данных на дисплей, 1 строчка, 1 знакоместо
Lcd Time$ ; "**" ; Celsium ; "***" 'На дисплее выводим время, затем температуру
Locate 2 , 1 'Вывод данных на дисплей, 2 строчка, 1 знакоместо
Lcd Date$ ; "**" ; Fahrenhei ; "**" 'На дисплее выводим дату, затем температуру
If Меню = 0 Then : Gosub МенюП : End If 'При нажатие клавиши меню, переходим на метку МенюП
Debounce Вкл_выкл , 0 , Вкл._от_клавиши 'При нажатие клавиши Вкл_выкл переходим в цикл Вкл._от_клавиши
Loop
'*******************************************************************************
Вкл._от_клавиши:
Enable Int0 'Разрешаем прерывания на Int0
'*******************************************************************************
'В этом цикле реле вкл. и выкл. только по нажатию клавиши Вкл_выкл.
'При удержании этой же клавиши осущевствляется переход на метку Вкл._от_перемены_температуры
Do
Call Температура 'Вызвать подпрограмму(процедуру) "Температура"
Locate 1 , 1 'Вывод данных на дисплей, 1 строчка, 1 знакоместо
Lcd Time$ ; "**" ; Celsium ; "***" 'На дисплее выводим время, затем температуру
Locate 2 , 1 'Вывод данных на дисплей, 2 строчка, 1 знакоместо
Lcd Date$ ; "**" ; Fahrenhei ; "**" 'На дисплее выводим дату, затем температуру
If Меню = 0 Then : Gosub МенюП : End If 'При нажатие клавиши меню, переходим на метку МенюП
Debounce Вкл_выкл , 0 , Вкл._от_перемены_температуры 'При нажатие клавиши Вкл_выкл переходим в цикл Вкл._от_перемены_температуры
Loop
'*******************************************************************************
Getdatetime:
I2cstart ' Generate start code
I2cwbyte Ds1307w 'Отправка адреса
I2cwbyte 0 'Стартовый адрес в 1307
I2cstart ' Generate start code
I2cwbyte Ds1307r 'Отправка адреса
I2crbyte _sec , Ack 'Секунды
I2crbyte _min , Ack 'Минуты
I2crbyte _hour , Ack 'Часы
I2crbyte Weekday , Ack 'День недели
I2crbyte _day , Ack 'День
I2crbyte _month , Ack 'Месяц
I2crbyte _year , Nack 'Год
I2cstop
_sec = Makedec(_sec) : _min = Makedec(_min) : _hour = Makedec(_hour)
_day = Makedec(_day) : _month = Makedec(_month) : _year = Makedec(_year)
Return
Настройка_даты:
_day = Makebcd(_day) : _month = Makebcd(_month) : _year = Makebcd(_year)
I2cstart ' Generate start code
I2cwbyte Ds1307w ' send address
I2cwbyte 4 ' starting address in 1307
I2cwbyte _day ' Send Data to SECONDS
I2cwbyte _month ' MINUTES
I2cwbyte _year ' Hours
I2cstop
Return
Настройка_времени:
_sec = Makebcd(_sec) : _min = Makebcd(_min) : _hour = Makebcd(_hour)
I2cstart ' Generate start code
I2cwbyte Ds1307w ' send address
I2cwbyte 0 ' starting address in 1307
I2cwbyte _sec ' Send Data to SECONDS
I2cwbyte _min ' MINUTES
I2cwbyte _hour ' Hours
I2cstop
Return
Сохраение_данных:
Writeeeprom A , Ae ' сохраняем переменную A в энергонезависимую память мк
Writeeeprom B , Be ' сохраняем переменную B в энергонезависимую память мк
Return
Вклвыкл_Реле:
Toggle Реле 'Инверсия логического уровня на ножке PORTD.4
Return 'Возврат из подпрограммы в точку где произошло прерывание
'*******************************************************************************
$include "Subs.bas" 'Подключаем в процесс компиляции внешний файл с процедурами
'Если вам так не удобно, просто скопируйте весь код в файле Subs.bas и вставьте его вместо $include "Subs.bas"
'*******************************************************************************
End 'Конец программы
'*******************************************************************************
Код из файла Subs:
- Код: Выделить всё • Развернуть
'**********************************Процедуры************************************
Sub Ввод_даты_времени()
'Выбор и последующее сохранение в eeprom мк, температуры вкл. реле
Cls
Aa = 0
X1 = A
Do
If X1 > 120 Then X1 = 70
If X1 < 70 Then X1 = 120
Locate 1 , 1
Lcd "[>BГІop їeјѕ.<]"
Locate 2 , 1
Lcd "Teјѕ. іє».: " ; X1 ; " "
Вверх_вниз_ввод
Tem1 = X1
Loop Until Aa = 1
A = Tem1
'*******************************************************************************
'Выбор и последующее сохранение в eeprom мк, температуры выкл. реле
Cls
Aa = 0
X1 = B
Do
If X1 > 120 Then X1 = 60
If X1 < 60 Then X1 = 120
Locate 1 , 1
Lcd "[>BГІop їeјѕ.<]"
Locate 2 , 1
Lcd "Teјѕ. іГє».: " ; X1 ; " "
Вверх_вниз_ввод
Tem2 = X1
Loop Until Aa = 1
B = Tem2
Gosub Сохраение_данных
'*******************************************************************************
'Выбор и последующее сохранение в память(энергозависимую) ds1307, года
Cls
Aa = 0
X1 = _year
Do
If X1 > 99 Then X1 = 9
If X1 < 9 Then X1 = 99
Locate 1 , 1
Lcd "[>аaїa<]"
Locate 2 , 1
Lcd "Ўoг: " ; X1 ; " "
Вверх_вниз_ввод
J1 = X1
Loop Until Aa = 1
'*******************************************************************************
'Выбор и последующее сохранение в память(энергозависимую) ds1307, месяца
Cls
Aa = 0
X1 = _month
Do
If X1 > 12 Then X1 = 1
If X1 < 1 Then X1 = 12
Locate 1 , 1
Lcd "[>аaїa<]"
Locate 2 , 1
Lcd "MecЗе: " ; X1 ; " "
Вверх_вниз_ввод
M1 = X1
Loop Until Aa = 1
'*******************************************************************************
'Выбор и последующее сохранение в память(энергозависимую) ds1307, дня
Cls
Aa = 0
X1 = _day
Do
If X1 > 31 Then X1 = 1
If X1 < 1 Then X1 = 31
Locate 1 , 1
Lcd "[>аaїa<]"
Locate 2 , 1
Lcd "аeЅД: " ; X1 ; " "
Вверх_вниз_ввод
D1 = X1
Loop Until Aa = 1
_year = J1
_month = M1
_day = D1
Gosub Настройка_даты
'*******************************************************************************
'Выбор и последующее сохранение в память(энергозависимую) ds1307, часов
Cls
Aa = 0
X1 = _hour
Do
If X1 > 23 Then X1 = 0
If X1 < 0 Then X1 = 23
Locate 1 , 1
Lcd "[>BpeјЗ<]"
Locate 2 , 1
Lcd "«acГ: " ; X1 ; " "
Вверх_вниз_ввод
H1 = X1
Loop Until Aa = 1
'*******************************************************************************
'Выбор и последующее сохранение в память(энергозависимую) ds1307, минут
Cls
Aa = 0
X1 = _min
Do
If X1 > 59 Then X1 = 0
If X1 < 1 Then X1 = 59
Locate 1 , 1
Lcd "[>BpeјЗ<]"
Locate 2 , 1
Lcd "MёЅyїГ: " ; X1 ; " "
Вверх_вниз_ввод
Min1 = X1
Loop Until Aa = 1
_hour = H1
_min = Min1
_sec = 0
Gosub Настройка_времени
End Sub
'*******************************************************************************
'Процедура отвечающая за ввод данных, увеличение и уменьшение значения
Sub Вверх_вниз_ввод()
Waitms 300
If Вверх = 0 Then Incr X1
If Вниз = 0 Then Decr X1
If Ввод = 0 Then : Aa = 1 : Else : : Aa = 0 : End If
End Sub
'*******************************************************************************
'Процедура отвечающая за открытие меню для каждого вводимого значения
Sub МенюП()
Sound Speaker , 100 , 800
Aa = 0
X1 = 0
Вверх_вниз_ввод
Ввод_даты_времени
Cls
End Sub
End
'*******************************************************************************
'Процедура отвечающая за показания датчика температуры DS18B20
Sub Температура
1wreset
1wwrite &HCC ' Выдаем команду чтения ПЗУ
1wwrite &H44 ' Запуск измерения
Waitms 750 ' Ждем окончания преобразования
1wreset
1wwrite &HCC
1wwrite &HBE ' Команда чтения ОЗУ датчика
Byte0 = 1wread() ' Читаем нулевой байт
Byte1 = 1wread() ' Читаем первый байт
If Byte1 >= 248 Then ' Проверяем на отрицательную температуру.248 в десятичном - 11111000 в двоичном. Если температура отрицательная - вычитаем из &HFF
Byte0 = &HFF - Byte0
Byte1 = &HFF - Byte1
Signtemperatura = "-"
Else
Signtemperatura = "+"
End If
Temp = Byte0 / 16 ' Сдвигаем нулевой байт вправо на 4 бита (2*2*2*2=16)
T2 = Byte1 * 16 ' Сдвигаем первый байт влево на 4 бита (2*2*2*2=16)
Temp = Temp + T2 ' Формирмируем результам и выдаем его на индикатор. Команда LCD сама преобразует его в десятичный вид
Faren0 = Temp * 1.8
Faren = Faren0 + 32
Celsium = Signtemperatura + Str(temp) + "C"
Fahrenhei = Signtemperatura + Str(faren) + "F"
End Sub
'*******************************************************************************
'Процедура отвечающая за вкл. и выкл. реле при заданной в настрокйках, температуре
Sub Вов
Tem1 = A
Tem2 = B
If Temp => Tem1 Then : Реле = 1 : End If
If Temp <= Tem2 Then : Реле = 0 : End If
End Sub
Программа занимает 53% памяти мк, поэтому при желание можно программу дополнить.