|
Форумец
Сообщений: 1,532
Регистрация: 19.02.2009
Возраст: 54
Не в сети
|
Термостат. Работает так. В верхней строке выводится текущая температура, в нижней уставка (целые градусы, шаг в один градус), в конце нижней строки выводится "0" (нагреватель выключен) или "1" (нагреватель включен). После прошивки и первом включении уставка - 25 градусов. Кнопка "Выше" увеличивает на 1 град, "Ниже" - уменьшает на 1 градус. После выключения уставка сохраняется в EEPROM. Уставка ограничена диапазоном 0-125 град, с шагом 1 градус. Если текущая температура меньше уставки на RA3 лог. "1" (на ЖКИ тоже "1") - включается исполнительное устройство, если текущая температура выше уставки на RA3 лог. "0" (на ЖКИ тоже "0") - исполнительное устройство выключается. Сравнение идет с целой частью текущей температуры.
Код:
const unsigned short TEMP_RESOLUTION = 12;
unsigned short SetTemp, old_SetTemp;
char *text = "000.0000";
char *set = "000";
unsigned temp;
void Display_Temperature(unsigned int temp2write) {
const unsigned short RES_SHIFT = TEMP_RESOLUTION - 8;
char temp_whole;
unsigned int temp_fraction;
// преобразование отрицательной температуры
if (temp2write & 0x8000) {
text[0] = '-';
temp2write = ~temp2write + 1;
}
// извлечение целой части
temp_whole = temp2write >> RES_SHIFT ;
// преобразование целой части температуры в символы
text[0] = temp_whole/100 + 48; // извлечение сотен
text[1] = (temp_whole/10)%10 + 48; // извлечение десятков
text[2] = temp_whole%10 + 48; // извлечение единиц
// извлечение и преобразование дробной части
temp_fraction = temp2write << (4-RES_SHIFT);
temp_fraction &= 0x000F;
temp_fraction *= 625;
// преобразование дробной части в символы
text[4] = temp_fraction/1000 + 48; // extract thousands digit
text[5] = (temp_fraction/100)%10 + 48; // extract hundreds digit
text[6] = (temp_fraction/10)%10 + 48; // extract tens digit
text[7] = temp_fraction%10 + 48; // extract ones digit
// вывод температуры на ЖКИ
Lcd_Out(1, 7, text);
set[0]=SetTemp/100+48;
set[1]=(SetTemp/10)%10+48;
set[2]=SetTemp%10+48;
Lcd_Out(2,7,set);
if (SetTemp>temp_whole){ // если уставка выше
PORTA=8; // то включение
Lcd_Chr(2,14,'1'); // и отображение "1"
}
else{ // если нет
PORTA=0; // выключение
Lcd_Chr(2,14,'0'); // и отображение "0"
}
}//~
void main() {
CMCON = 7; // Все выводы цифровые входы-выходы
TRISA=0b11110111; // все выводы PORTA на вход, RA3 - выход
Lcd_Config(&PORTB, 4, 5, 6, 3, 2, 1, 0); // назначение выводов ЖКИ - PIC
Lcd_Cmd(LCD_CURSOR_OFF);
Lcd_Out(1, 1, "Temp:");
Lcd_Chr(1,15,223); // вывод символа точки и "С" как единицы измерения
Lcd_Chr(1,16,'C');
Lcd_Out(2,1,"Set :");
Lcd_Chr(2,10,223);
Lcd_Chr(2,11,'C');
SetTemp=Eeprom_Read(0); // читаем уставку из EEPROM
if (SetTemp>125){
SetTemp=25;
old_SetTemp=SetTemp;
delay_ms(50);
Eeprom_Write(0,SetTemp);
delay_ms(50);
}
//--- главный цикл
do {
//--- чтение температуры из DS18B20
Ow_Reset(&PORTA,2); // сигнал сброса
Ow_Write(&PORTA,2,0xCC); // команда SKIP_ROM
Ow_Write(&PORTA,2,0x44); // команда CONVERT_T
Delay_us(120);
Ow_Reset(&PORTA,2);
Ow_Write(&PORTA,2,0xCC); // команда SKIP_ROM
Ow_Write(&PORTA,2,0xBE); // команда READ_SCRATCHPAD
temp = Ow_Read(&PORTA,2);
temp = (Ow_Read(&PORTA,2) << 8) + temp;
if (Button(&PORTA, 0,1,0)){ // нажимаем кнопку на RA0 ("уставка выше")
SetTemp++;
if (SetTemp>125)
SetTemp=125;
}
if (Button(&PORTA, 1,1,0)){ // нажимаем кнопку на RA1 ("уставка ниже")
SetTemp-- ;
if (setTemp==255)
SetTemp=0;
}
if (old_SetTemp!= SetTemp) { // если было изменение уставки
Eeprom_Write(0,SetTemp); // то сохраняем в EEPROM новое значение уставки
delay_ms(50);
old_SetTemp = SetTemp; // и сохраняем для текущей работы
}
//--- форматирование, вывод на ЖКИ температуры и уставки, включение-выключение
Display_Temperature(temp);
Delay_ms(500);
} while (1);
}
Термостат с алгоритмом как в TRM10 от ОВЕНа. Суть такова - ловится момент, когда температура падает на OFFSET градусов (в данном примере OFFSET=2 градуса) ниже уставки и только тогда включается. Реализация в виде state-машины (автомат конечных состояний).
Код:
const unsigned short TEMP_RESOLUTION = 12, OFFSET = 2;
unsigned short SetTemp, old_SetTemp, state;
char *text = "000.0000";
char *set = "000";
unsigned temp;
void Display_Temperature(unsigned int temp2write) {
const unsigned short RES_SHIFT = TEMP_RESOLUTION - 8;
char temp_whole;
unsigned int temp_fraction;
// преобразование отрицательной температуры
if (temp2write & 0x8000) {
text[0] = '-';
temp2write = ~temp2write + 1;
}
// извлечение целой части
temp_whole = temp2write >> RES_SHIFT ;
// преобразование целой части температуры в символы
text[0] = temp_whole/100 + 48; // извлечение сотен
text[1] = (temp_whole/10)%10 + 48; // извлечение десятков
text[2] = temp_whole%10 + 48; // извлечение единиц
// извлечение и преобразование дробной части
temp_fraction = temp2write << (4-RES_SHIFT);
temp_fraction &= 0x000F;
temp_fraction *= 625;
// преобразование дробной части в символы
text[4] = temp_fraction/1000 + 48; // extract thousands digit
text[5] = (temp_fraction/100)%10 + 48; // extract hundreds digit
text[6] = (temp_fraction/10)%10 + 48; // extract tens digit
text[7] = temp_fraction%10 + 48; // extract ones digit
// вывод температуры на ЖКИ
Lcd_Out(1, 7, text);
set[0]=SetTemp/100+48;
set[1]=(SetTemp/10)%10+48;
set[2]=SetTemp%10+48;
Lcd_Out(2,7,set);
// далее код стейт-машины (автомат конечных состояний)
switch(state){
case 0: {
if(temp_whole<SetTemp){
PORTA=8;
Lcd_Chr(2,14,'1');
}
else {
PORTA=0;
Lcd_Chr(2,14,'0');
state=1;
}
}; break;
case 1: {
if(temp_whole<(SetTemp-OFFSET)){
PORTA=8;
Lcd_Chr(2,14,'1');
state=0;
}
else {
PORTA=0;
Lcd_Chr(2,14,'0');
}
}; break;
}
// окончание стейт-машины
}//~
void main() {
state=0;
CMCON = 7; // Все выводы цифровые входы-выходы
TRISA=0b11110111; // все выводы PORTA на вход, RA3 - выход
Lcd_Config(&PORTB, 4, 5, 6, 3, 2, 1, 0); // назначение выводов ЖКИ - PIC
Lcd_Cmd(LCD_CURSOR_OFF);
Lcd_Out(1, 1, "Temp:");
Lcd_Chr(1,15,223); // вывод символа точки и "С" как единицы измерения
Lcd_Chr(1,16,'C');
Lcd_Out(2,1,"Set :");
Lcd_Chr(2,10,223);
Lcd_Chr(2,11,'C');
SetTemp=Eeprom_Read(0); // читаем уставку из EEPROM
if (SetTemp>125){
SetTemp=25;
old_SetTemp=SetTemp;
delay_ms(50);
Eeprom_Write(0,SetTemp);
delay_ms(50);
}
//--- главный цикл
do {
//--- чтение температуры из DS18B20
Ow_Reset(&PORTA,2); // сигнал сброса
Ow_Write(&PORTA,2,0xCC); // команда SKIP_ROM
Ow_Write(&PORTA,2,0x44); // команда CONVERT_T
Delay_us(120);
Ow_Reset(&PORTA,2);
Ow_Write(&PORTA,2,0xCC); // команда SKIP_ROM
Ow_Write(&PORTA,2,0xBE); // команда READ_SCRATCHPAD
temp = Ow_Read(&PORTA,2);
temp = (Ow_Read(&PORTA,2) << 8) + temp;
if (Button(&PORTA, 0,1,0)){ // нажимаем кнопку на RA0 ("уставка выше")
SetTemp++;
if (SetTemp>125)
SetTemp=125;
}
if (Button(&PORTA, 1,1,0)){ // нажимаем кнопку на RA1 ("уставка ниже")
SetTemp-- ;
if (setTemp==255)
SetTemp=0;
}
if (old_SetTemp!= SetTemp) { // если было изменение уставки
Eeprom_Write(0,SetTemp); // то сохраняем в EEPROM новое значение уставки
delay_ms(50);
old_SetTemp = SetTemp; // и сохраняем для текущей работы
}
//--- форматирование, вывод на ЖКИ температуры и уставки, включение-выключение
Display_Temperature(temp);
Delay_ms(500);
} while (1);
}
Работа программы в железе проверена. Как поведет себя на реальном объекте надо будет смотреть.
Последний раз редактировалось petrd; 28.04.2009 в 15:38.
Причина: исправил код, ошибка при отображении сотен градусов
|