#申请原创#
最近温度气温较高,公司样品测试放房又要24H连续工作,有部分是发热量较大的仪器在运行,且近段时间各地高温引起的火灾频发,所以萌生了做个温控仪的想法,
平时有用PIC16F677这款IC,虽然型号较老,但公司有些老产品一直在用,客人又不允许换,所以就用这个手头的型号做平台吧。
基本要求是:
平时显示测试房室温+仪器通电运行的天数+温度超35度的次数(累计达到3次时停止AC供电给仪器,以防气温较高时仪器运行产生的高温引起安全隐患);
温度显示时长30秒(大约值)--运行天数显示时长5秒--超温次数显示时长5秒----
循环显示;运行天数和超温次数参数具有断电保持功能。
正常温度下,状态指示灯绿色常亮,当超温次数小于3次,且遇到超温35度时,则立刻吸合继电器以断开AC供电,状态指示灯红色常亮,30分钟后恢复AC供电,状态指示灯恢复绿色常亮;
当超温次数达到3次时,数码管显示t_EE,状态指示灯红色,且隔1秒闪1秒,继电器吸合,断开AC供电,要手动才能复位,以及检查有无其他产生高温的隐患,(这样设置是因为考虑到平时室外气温38~40度左右时,室内温度一般都35度以内,若产生高温出发,一般都会连续发生,为了安全,所以设为3次)
正常运行时,仪器进行计时,一个月断开AC供电一次,时长100分钟,数码管正常显示数据,状态指示灯绿色隔1秒闪1秒(因为测试的样品大部分有镍镉电池存在,要求一个月进行放电一次,以保持电池的活性),然后恢复供电。
产品可能有些不足,分享出来给大家可以互相学习学习。
[温度值]赶上天气热,机器都启动30分钟断电操作了
[运行天数显示]
[报警次数显示]
高温警报
![原理图]
以下是源程序,在MPLAB IDE v8.92平台下开发(18B20获取温度部分有参考了学习板的例程,还是有点不明白为什么这么操作)
#include<pic.h>
#define uchar unsigned char
#define uint unsigned int
__CONFIG(0x00ec);//0000 0000 1110 1100
__IDLOC (1907);//20210907
const uchar table[]={0x00,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x40};
const uchar table1[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x40};
const uchar table2[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,
0x87,0xff,0xef};
void init();
void delay(uint x);
void delayus(uint,uchar);
void al_n();
void day_n();
uchar reset(void);
void write_byte(uchar val);
uchar read_byte(void);
void convert_T(void);
void read_T(void);
void T_err();
uint t0=0,t1=0,m=0,alarm_time=0,alarm=0;
uint t_fu,temp1,temp2,cuncu;
uchar alarm_n=0;
void main()
{
OSCCON=0X6C;//4M时钟频率0110 1100
uint buf,xunhuan_n=0;
uchar ML_m;
init();
ML_m=eeprom_read(0x11);//读历史计时分钟数的EEPROM高8位
cuncu=ML_m;
cuncu=cuncu<<8;//左移8位
ML_m=eeprom_read(0x10);//读历史计时分钟数的EEPROM低8位
cuncu=cuncu|ML_m;//与读出的低8位相或,得出历史分钟数
m=cuncu;//存入寄存器m
if(m>=43800)
m=0;
ML_m=eeprom_read(0x12);//读历史保存的alarm_n
alarm_n=ML_m;//存入寄存器alarm_n
if(alarm_n>=3)
alarm_n=0;
while(1) //死循环,单片机初始化后,将一直运行这个死循环
{
CLRWDT();//喂狗
GIE=0;
convert_T(); //启动温度转换
delayus(25,250); //延时
read_T();
GIE=1;
if((t_fu&0xF8)==0)
{
if(temp1>=35)//温度达到35度出发警报
{
if(alarm==0)
alarm=1;
}
}
if((alarm==1)&(alarm_n<3))//高温警报,系统设定为>=35度时高温报警
{
if(RA5==0)
{
t0=0;
RA0=0;
RA1=1;
RA5=1;
}
if(t0>=1139)//1139
{
t0=0;
alarm_time++;
if(alarm_time>=30)//alarm_time=30minun,断开AC30分钟后恢复供电
{
RA0=1;
RA1=0;
RA5=0;//释放继电器,恢复AC通电
alarm=0;//警报标志清零
alarm_time=0;//警报断电计时清零
alarm_n++;//警报次数+1
if(alarm_n>=3)
delay(1000);
ML_m=alarm_n;
eeprom_write(0x12,ML_m);//保存报警次数
}
}
}
if(alarm_n>=3)
{
RA0=0;//出现3次高温异常指示灯,绿色熄灭,红色闪烁
RA5=1;//吸合继电器,断开AC供电
T0IE=0;//关T0
TMR1IE=1;//开T1
if((t1>=0)&(t1<=18))
{
RA0=0;
RA1=1;
T_err();//显示高温异常t-EE
}
if(t1>18)
{
RA0=0;
RA1=0;
PORTC=0X00;
if(t1>36)
{
t1=0;
RA0=0;
RA1=1;
}
}
}
if(alarm_n<3)
xunhuan_n++;
if(((xunhuan_n>0)&(xunhuan_n<=1500))&(alarm_n<3))
{
if((t_fu&0xF8)==0)//正温度显示
{
if(temp1>99)
temp1=99;
if(temp2>15)
temp2=0;
buf=temp1/10;
PORTC=table[buf];//显示第一个数码管
PORTB=0xE0;//1110 0000
delay(4);
buf=temp1%10;
PORTC=table2[buf];//显示第二个数码管
PORTB=0xD0;//1101 0000
delay(4);
buf=temp2*625/1000;
PORTC=table1[buf];//显示第三个数码管
PORTB=0xB0;//1011 0000
delay(4);
PORTC=0X58;//显示第四个数码管C
PORTB=0x70;//0111 0000
}
if((t_fu&0xF8)==0xf8)//负温度显示
{
PORTC=0x40;//显示第一个数码管
PORTB=0xE0;//1110 0000
delay(4);
buf=temp1/10;
PORTC=table[buf];//显示第二个数码管
PORTB=0xD0;//1101 0000
delay(4);
buf=temp1%10;
PORTC=table2[buf];//显示第三个数码管
PORTB=0xB0;//1011 0000
delay(4);
buf=temp2*625/1000;
PORTC=table1[buf];//显示第四个数码管C
PORTB=0x70;//0111 0000
}
if(alarm==0)
{
if(m>43700)//43700,无高温异常时,计时30天放电100分钟=365/12=30.417天=43800分钟/平均月
{
TMR1IE=1;
RA5=1; //开放电//累计计时达30天
if(m>43800)//43800,放电100分钟累加计时
{
TMR1IE=0;
RA0=1;
RA5=0;//达到100分钟计时关闭放电,重新计时
m=0;
}
}
}
if(xunhuan_n==1500)//大约每30秒存储一次数据
{
cuncu=m;//读取当前分钟数m
ML_m=cuncu&0x00ff;//滤除高8位
eeprom_write(0x10,ML_m);//存入EEPROM低8位
cuncu=cuncu>>8;//右移8位
ML_m=cuncu&0x00ff;//滤除高8位,并存入寄存器ML_m
eeprom_write(0x11,ML_m);//存入EEPROM高8位
}
}
if(((xunhuan_n>1500)&(xunhuan_n<=1750))&(alarm_n<3))
{
cuncu=m;
day_n();
}
if((xunhuan_n>1750)&(alarm_n<3))
{
al_n();
if(xunhuan_n>2000)
xunhuan_n=0;
}
}
}
//中断函数
void interrupt ISP()
{
//定时器0定时中断
if(T0IF&T0IE)
{
T0IF=0;//标志清零
TMR0=61;//T0赋初值
t0++; //T0中断计数+1=49.92ms==52.7MS
if((t0>=1139)&(alarm==0))//每月放电100分钟,m=每60s+1
{
t0=0;
m++;
}
}
//T1用于控制故障信号的闪烁
if(TMR1IF&TMR1IE)
{
TMR1IF=0; //T1标志位清零
TMR1H=61; //高位赋初值
TMR1L=256; //低位赋初值
t1++; //T1中断计数:t1+1=49.92ms==55.73MS
if(m>43700)//m为计算运行的分钟数
{
if((t1>=0)&(t1<=18))
{
RA0=0;
RA1=0;
}
if(t1>18)
{
RA0=1;
RA1=0;
if(t1>36)
{
t1=0;
RA0=0;
RA1=0;
}
}
}
}
}
//初始化函数
void init()
{
ANSEL=0X00;
ANSELH=0X00;
WPUA=0XFF;
WPUB=0XFF;
TRISA0=0;
TRISA1=0;
TRISA3=1;
TRISA5=0;
RA0=1;//绿色状态灯
RA1=0;//红色状态灯
RA5=0;
ANS2=0;
WPUA2=1;
TRISC=0X00;
TRISB=0X00;//
PORTC=0X00;
PORTB=0X00;
//T0 init//
OPTION=0X07;//0000 0111,RABPW=0,INTEDG=0,T0CS=0,T0SE=0;PSA=0,PS=111(1:256)
INTCON=0XA0;//1010 0000,GIE=1,PEIE=0,T0IE=1,INTE=0,RABIE=0,T0IF=0,INTF=0,RABIF=0
T0IE=1;
TMR0=61;
//T1 init//
T1CON=0X01;//0000 0001,p5p4=00=1:1
TMR1IE=0;
TMR1IF=0;
TMR1H=61;
TMR1L=256;
GIE=1;
PEIE=1;
//看门狗初始化
WDTCON=0X16;//***1 0110//1:65536=2.048S
}
void delay(uint x)//mS延时函数
{
uint a,b;
for(a=x;a>0;a--)
for(b=110;b>0;b--);
}
//uS延时函数
void delayus(uint x,uchar y)
{
uint i;
uchar j;
for(i=x;i>0;i--);
for(j=y;j>0;j--);
}
//18B20复位
uchar reset(void)
{
uchar outbit;
TRISA2=0; //设置RA4位输出口
RA2=0; //设置RA4=0;
delayus(2,70); //延时503us
TRISA2=1; //设置RA4为输入口,以释放总线等电阻拉高总线
delayus(2,8); //延时70us
if(RA2==1)
outbit=0; //没有接收到应答信号,继续复位
else
outbit=1; //接收到应答信号
delayus(2,60); //延时430us
return outbit; //带参数返回,如果接收到应答,返回1,否则返回0
}
void write_byte(uchar val)
{
uchar i;
uchar temp;
for(i=8;i>0;i--)
{
temp=val&0x01; //最低位移出
TRISA2=0; //设置RA2位输出口
RA2=0; //设置RA2=0;
NOP();
NOP();
NOP();
NOP();
NOP(); //从高拉至低电平,产生写时间隙
if(temp==1)
TRISA2=1; //如果写1,拉高电平
delayus(2,7); //延时63us
TRISA2=1; //设置RA2为输入口,以释放总线等电阻拉高总线
NOP();
NOP();
val=val>>1; //右移一位
}
}
uchar read_byte(void)
{
uchar i;
uchar value=0; //读出温度
for(i=8;i>0;i--)
{
value>>=1;
TRISA2=0; //设置RA2位输出口
RA2=0; //设置RA2=0;
NOP();
NOP();
NOP();
NOP();
NOP();
NOP(); //6us
TRISA2=1; //设置RA2为输入口
NOP();
NOP();
NOP();
NOP(); //4us
if(RA2==1)
value|=0x80; //如果接收到数据为1,从最高位往右移
delayus(2,7); //63us
}
return(value);
}
void convert_T(void)
{
if(reset()==1) //如果复位成功
{
write_byte(0xcc); // 跳过多器件识别
write_byte(0x44); // 启动温度转换
}
}
void read_T(void)
{
uchar Lsb,Msb;
if(reset()==1)
{
write_byte(0xcc); // 跳过多器件识别
write_byte(0xbe); // 读暂存器
Lsb=read_byte(); // 低字节
Msb=read_byte(); // 高字节
t_fu=Msb&0xF8; //取出符号位
if((t_fu&0xF8)==0)//如果温度>0时,温度值的整数和小数处理
{
temp2=Lsb&0X0F; //去除LSB的高4位变成正温度的小数部分
temp1=Msb<<4|Lsb>>4;//LSB的高4位和MSB拼成正温度的整数部分
}
if((t_fu&0xF8)==0xf8)//如果温度<0时,温度值的整数和小数处理
{
temp2=Lsb&0X0F; //去除LSB的高4位变成正温度的小数部分
temp2=~temp2; //小数部分取反
temp2=temp2&0x0f;//只保留低4位数据
temp2=temp2+1;
temp1=Msb<<4|Lsb>>4;
temp1=~temp1;
if(temp2>15)
{
temp2=0;
temp1=temp1+1;
}
}
}
}
void T_err()//高温异常报警显示
{
PORTC=0x78;//显示第一个数码管 t
PORTB=0xE0;//1110 0000
delay(4);
PORTC=0x40;//显示第二个数码管 -
PORTB=0xD0;//1101 0000
delay(4);
PORTC=0x79;//显示第三个数码管 E
PORTB=0xB0;//1011 0000
delay(4);
PORTC=0x79;//显示第四个数码管 E
PORTB=0x70;//0111 0000
}
void day_n()//运行天数显示:**d.y
{
uint day;
day=cuncu/1440/10;
PORTC=table[day];//显示第一个数码管1~3
PORTB=0xE0;//1110 0000
delay(4);
day=cuncu/1440%10;
PORTC=table1[day];//显示第二个数码管0~9
PORTB=0xD0;//1101 0000
delay(4);
PORTC=0xDE;//显示第三个数码管 d.
PORTB=0xB0;//1011 0000
delay(4);
PORTC=0x6E;//显示第四个数码管 y
PORTB=0x70;//0111 0000
}
void al_n()//报警次数显示,AL=*
{
PORTC=0x77;//显示第一个数码管A,0111 0111
PORTB=0xE0;//1110 0000
delay(4);
PORTC=0x38;//显示第二个数码管L,0011 1000
PORTB=0xD0;//1101 0000
delay(4);
PORTC=0x48;//显示第三个数码管 = , 0100 1000
PORTB=0xB0;//1011 0000
delay(4);
PORTC=table1[alarm_n];//显示第四个数码管 0~3
PORTB=0x70;//0111 0000
}
|
|