打印
[资料干货]

自制PIC16F677+DS18B20温度控制仪

[复制链接]
862|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
#申请原创#

最近温度气温较高,公司样品测试放房又要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
}

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

4

帖子

0

粉丝