Термостат на PIC16F684

Thermo3Проект электронного термостата, описанный далее является логическим продолжением и в чем-то объединением двух предыдущих устройств: Терморегулятор на микроконтроллере PIC16F676 и Термосигнализатор с батарейным питанием.  Схема выполнялась по заказу и была изготовлена в количестве 2 экземпляров. Время наработки пока не большое, но работает все исправно.

В основу термостата положен микроконтроллер фирмы Microchip PIC16F684. Главным критерием его выбора стал объем памяти программ в 2К слов, что позволило реализовать некоторые дополнительные функции.  В частности прошивка позволяет изменить уставку и гистерезис срабатывания выходного реле, а также задать тип срабатывания – нагрев или охлаждение.

Shem
Принципиальная схема термостата

Для измерения температуры применен датчик MCP9800. Отображение температуры выполняется на светодиодном индикаторе в динамическом режиме. При положительных значениях отображаются два целых разряда и один после запятой. В диапазоне отрицательных температур происходит индикация только двух цифр целого значения и знака минус.

В конструкции термостата использованы в основном элементы поверхностного монтажа. В итоге получилась простая и относительно компактная конструкция. Для заливки готовой прошивки в микроконтроллер применялась специальная клипса, что позволило избежать разводки дополнительных цепей внутрисхемного программирования.

 

Board
Печатная плата
BoardTop BoartBot
Схема расположения элементов. Вид сверху. Схема расположения элементов. Вид снизу.

Управляющая программа термостата написана на языке mikroPascal. Алгоритм стандартный. В цикле производится опрос датчика и обработка показаний. Для увеличения периода опроса применена задержка. Одновременно с этим работает таймер, генерирующий прерывания по переполнению. В прерывании выполнен алгоритм динамической индикации и опрос кнопки изменения уставки S2. В случае ее нажатия вызывается подпрограмма изменения задания и запускается второй таймер. Он используется для выхода из режима задания, в случае отсутствия длительного нажатия на какую-либо кнопку. Смена уставки производится поразрядно, с помощью кнопки S1. Повторные нажатия кнопки S2 приведут к сдвигу изменяемого разряда. Вначале задается температура в пределе от 0 до 99.9 градуса, потом устанавливается гистерезис от 0 до 9.9 градуса. Для отличия от температуры, при индикации гистерезиса дополнительно выводится символ h. Последним задается тип срабатывания. Он может принимать два значения: нагрев (индицируется символом H) или охлаждение (Символ L). При нагреве, выходное реле включено, когда температура ниже значения уставки. В режиме охлаждения наоборот, напряжение на реле подается при превышении измеренным значением, задания.

 

program ThermoStat;var i,dig:byte;
    dig1,dig2,dig3:byte;
    rm,rs:byte;
    set_mm,set_ss:byte;
    button_cnt1:byte;
    rezim,blank,heat:byte;
    //Temp,Temp_set:word;
    Soft_I2C_Scl     : sbit at RC2_bit;
    Soft_I2C_Sda     : sbit at RC1_bit;
    Soft_I2C_Scl_Direction : sbit at TRISC2_bit;
    Soft_I2C_Sda_Direction : sbit at TRISC1_bit;
    Tzad0,Tzad1,Tzad2,H1,H2,button1,button2,inter,tmrout:byte;
    Themperature,ZadHi,ZadLo:word;
 procedure Read_T();    {Чтение температуры из MCP9800}
  begin
    clrwdt;
    Soft_I2C_Start();
    Soft_I2C_Write(0x90);
    Soft_I2C_Write(0x00);
    Soft_I2C_Start();
    Soft_I2C_Write(0x91);
    rm := Soft_I2C_Read(1);
    rs := Soft_I2C_Read(0);
    Soft_I2C_Stop();
  end;
 function mask(num: byte): byte;  {Преобразование чисел в код индикатора}

begin clrwdt; if num>15 then num:=0; case num of //bfgacpde 0 : result:= %11011011; 1 : result:= %10001000; 2 : result:= %10110011; 3 : result:= %10111010; 4 : result:= %11101000; 5 : result:= %01111010; 6 : result:= %01111011; 7 : result:= %10011000; 8 : result:= %11111011; 9 : result:= %11111010; 10 : result:= %00000000; 11 : result:= %11101001; 12 : result:= %01000011; 13 : result:= %01100011; 14 : result:= %01101001; 15 : result:= %00000010; end; //case endend;//~  procedure Digit_Reg(digit:byte); {Передача кода в регистр сдвига}

begin clrwdt; for i:=1 to 8 do begin clearbit(PortC,0); if testbit(digit,0) then setbit(PortC,0); Setbit(portA,2); clrwdt; Clearbit(portA,2); digit:=digit shr 1; end;end;  procedure interrupt; {Обработка прерывания от таймера}

begin clrwdt; // прерывание по таймеру 1 if tmr1if_bit=1 then begin tmrout:=tmrout+1; if tmrout>30 then begin rezim:=0; //Сброс режима настройки при переполнении таймера tmr1on_bit:=0; tmr1ie_bit:=0; end; tmr1if_bit:=0; end else begin blank:=blank+1; {Обработка кнопки Set} if (rezim=0) and (testbit(portC,3)) then begin clrwdt; if button_cnt1<15 then begin button_cnt1:=button_cnt1+1; if button_cnt1>=14 then begin rezim:=6; tmr1h:=0; tmr1l:=0; tmr1on_bit:=1; inter:=1; tmr1ie_bit:=1; tmrout:=0; end; end; end else button_cnt1:=0;   dig:=dig+1; if dig>3 then dig:=1; clrwdt; case dig of 1: begin {Переключение цифры на индикаторе} clearbit(portC,5); Digit_Reg(dig3); setbit(portA,5); end; 2: begin {Переключение цифры на индикаторе} clearbit(portA,5); Digit_Reg(dig2); setbit(portA,4); end; 3: begin {Переключение цифры на индикаторе} clearbit(portA,4); Digit_Reg(dig1); setbit(portC,5); end; end; end; clrwdt; INTCON := %10100000; // Сброс флага прерывания

end;    procedure settings; //Установка задания begin while (rezim>0) do begin clrwdt; if rezim>6 then rezim:=0; // Обработка кнопки 1 (режим) if portC.3=1 then begin delay_ms(50); tmrout:=0; if portc.3=1 then button1:=1; end; if (portc.3=0) and (button1=1) then begin button1:=0; if inter=1 Then inter:=0 else rezim:=rezim-1; end; //Обработка кнопки 2 (настройка) clrwdt; if portc.4=1 then begin delay_ms(50); tmrout:=0; if portc.4=1 then button2:=1; end; if (portc.4=0) and (button2=1) then begin button2:=2; end; clrwdt;   //Работа с десятыми уставки clrwdt; if rezim=6 then begin //Настройка отображения цифр   dig2:=mask(Tzad1)+4; dig3:=mask(Tzad0); if blank.6=1 then dig1:=mask(15) else dig1:=mask(Tzad2); //мигание по таймеру if button2=2 then //установка нужной цифры begin Tzad2:=tzad2+1; if Tzad2>9 then Tzad2:=0; button2:=0; end; end; //Работа с единицами уставки if rezim=5 then begin dig1:=mask(Tzad2); if blank.6=1 then dig2:=mask(15)+4 else dig2:=mask(Tzad1)+4; if button2=2 then begin Tzad1:=tzad1+1; if Tzad1>9 then Tzad1:=0; button2:=0; end; end; //Работа с десятками уставки if rezim=4 then begin dig2:=mask(Tzad1)+4; if blank.6=1 then dig3:=mask(15) else dig3:=mask(Tzad0); if button2=2 then begin Tzad0:=tzad0+1; if Tzad0>9 then Tzad0:=0; button2:=0; end; end; clrwdt; //Работа с десятыми гистерезиса if rezim=3 then begin dig3:=mask(14);   dig2:=mask(h1)+4; if blank.6=1 then dig1:=mask(15) else dig1:=mask(h2); if button2=2 then begin h2:=h2+1; if h2>9 then h2:=0; button2:=0; end; end; //Работа с единицами гистерезиса if rezim=2 then begin dig3:=mask(14); dig1:=mask(h2);   if blank.6=1 then dig2:=mask(15)+4 else dig2:=mask(h1)+4; if button2=2 then begin h1:=h1+1; if h1>9 then h1:=0; button2:=0; end; end; //переключение типа выхода if rezim=1 then begin dig3:=mask(13); dig2:=mask(10); if heat=0 then dig1:=mask(11) else dig1:=mask(12);   if button2=2 then begin heat:=heat+1; if heat>1 then heat:=0; button2:=0; end; end; end; clrwdt; //Запись уставки в EEPROM EEPROM_Write(0x02,Tzad2); EEPROM_Write(0x03,Tzad1); EEPROM_Write(0x04,Tzad0); EEPROM_Write(0x05,h2); EEPROM_Write(0x06,h1); EEPROM_Write(0x07,heat); //Вычисление целого уставки clrwdt; ZadHi:=(Tzad2+h2)+((Tzad1+h1)*10); ZadHi:=ZadHi+(Tzad0*100); ZadLo:=Tzad0*100; ZadLo:=ZadLo+((Tzad1)*10); ZadLo:=ZadLo+Tzad2; clrwdt; while (portc.3=1) do delay_ms(20); tmr1on_bit:=0; //Останов таймера 1 tmr1ie_bit:=0; //Запрет прерывания таймера 1 tmr1if_bit:=0; //Запрет прерывания таймера 1 end;  procedure Calc_Temperature(temp1,temp2: byte;);var i2,temp:byte; tmp:word;begin clrwdt; if (temp1 and $80) = 0x80 then begin temp1 := not temp1 + 1; dig3:=%00100000; dig2:=mask((temp1 / 10) mod 10); dig1:=mask(temp1 mod 10); end else begin temp:=temp2 shr 4;   dig3:=mask((temp1 / 10) mod 10); dig2:=mask(temp1 mod 10)+4; tmp:=0; i2:=0; while i2 < temp do begin tmp:=tmp+625; i2:=i2+1; end; clrwdt; dig1:=mask((tmp /1000) mod 10); Themperature:=temp1*10+((tmp /1000) mod 10);   end;end; //~Calc_Temperature      {Программа}begin {Первоначальные настройки} osccon := %01100001; OPTION_REG := %00000011; intcon := %11100000; //Настройка прерываний t1con := %00110100; ansel := 0; cmcon0 := 0x07; TRISA := %00000000; TRISC := %00011000; PORTA := 0; PORTC := 0;   dig:=1; button_cnt1:=0; button1:=0; button2:=0; rezim:=0;   //Чтение задания из EEPROM Tzad2:=EEPROM_Read(0x02); Tzad1:=EEPROM_Read(0x03); Tzad0:=EEPROM_Read(0x04); H2:=EEPROM_Read(0x05); H1:=EEPROM_Read(0x06); heat:=EEPROM_Read(0x07); //Вычисление задания clrwdt; ZadHi:=(Tzad2+h2)+((Tzad1+h1)*10); ZadHi:=ZadHi+(Tzad0*100); ZadLo:=Tzad0*100; ZadLo:=ZadLo+((Tzad1)*10); ZadLo:=ZadLo+Tzad2; {Настройка MCP9800} clrwdt; Soft_I2C_Init(); clrwdt; Soft_I2C_Start(); Soft_I2C_Write(0x90); clrwdt; Soft_I2C_Write(0x01); clrwdt; Soft_I2C_Write(%01100000); Soft_I2C_Stop();     {Основной цикл} while 1 do begin clrwdt; {Индикация установки (цифры)} if rezim>0 then settings else {Индикация в рабочем режиме} begin clrwdt; clearbit(intcon,gie); Read_T(); setbit(intcon,gie); Calc_Temperature(rm,rs); //Вычисление температуры {Включение реле} clrwdt; if Themperature > ZadHi then begin if heat=1 then begin setbit(PortA,1); //Установка выхода при превышении уставки setbit(PortA,0); end else begin clearbit(PortA,1); //Сброс выхода при если t меньше уставки clearbit(PortA,0); end   end;   if Themperature < ZadLo then begin if heat=1 then begin clearbit(PortA,1); //Сброс выхода при если t меньше уставки clearbit(PortA,0); end else begin setbit(PortA,1); //Установка выхода при превышении уставки setbit(PortA,0); end   end;   delay_ms(1000); end; delay_ms(1000); end;

end.

Добавить комментарий